diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2013-07-12 06:34:42 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-07-12 06:34:42 -0400 |
commit | f2006e27396f55276f24434f56e208d86e7f9908 (patch) | |
tree | 71896db916d33888b4286f80117d3cac0da40e6d /drivers/net/xen-netback | |
parent | e399eb56a6110e13f97e644658648602e2b08de7 (diff) | |
parent | 9903883f1dd6e86f286b7bfa6e4b423f98c1cd9e (diff) |
Merge branch 'linus' into timers/urgent
Get upstream changes so we can apply fixes against them
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/net/xen-netback')
-rw-r--r-- | drivers/net/xen-netback/common.h | 14 | ||||
-rw-r--r-- | drivers/net/xen-netback/interface.c | 102 | ||||
-rw-r--r-- | drivers/net/xen-netback/netback.c | 42 | ||||
-rw-r--r-- | drivers/net/xen-netback/xenbus.c | 53 |
4 files changed, 172 insertions, 39 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 9d7f1723dd8f..8a4d77ee9c5b 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
@@ -57,8 +57,12 @@ struct xenvif { | |||
57 | 57 | ||
58 | u8 fe_dev_addr[6]; | 58 | u8 fe_dev_addr[6]; |
59 | 59 | ||
60 | /* Physical parameters of the comms window. */ | 60 | /* When feature-split-event-channels = 0, tx_irq = rx_irq. */ |
61 | unsigned int irq; | 61 | unsigned int tx_irq; |
62 | unsigned int rx_irq; | ||
63 | /* Only used when feature-split-event-channels = 1 */ | ||
64 | char tx_irq_name[IFNAMSIZ+4]; /* DEVNAME-tx */ | ||
65 | char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */ | ||
62 | 66 | ||
63 | /* List of frontends to notify after a batch of frames sent. */ | 67 | /* List of frontends to notify after a batch of frames sent. */ |
64 | struct list_head notify_list; | 68 | struct list_head notify_list; |
@@ -113,13 +117,15 @@ struct xenvif *xenvif_alloc(struct device *parent, | |||
113 | unsigned int handle); | 117 | unsigned int handle); |
114 | 118 | ||
115 | int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | 119 | int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, |
116 | unsigned long rx_ring_ref, unsigned int evtchn); | 120 | unsigned long rx_ring_ref, unsigned int tx_evtchn, |
121 | unsigned int rx_evtchn); | ||
117 | void xenvif_disconnect(struct xenvif *vif); | 122 | void xenvif_disconnect(struct xenvif *vif); |
118 | 123 | ||
119 | void xenvif_get(struct xenvif *vif); | 124 | void xenvif_get(struct xenvif *vif); |
120 | void xenvif_put(struct xenvif *vif); | 125 | void xenvif_put(struct xenvif *vif); |
121 | 126 | ||
122 | int xenvif_xenbus_init(void); | 127 | int xenvif_xenbus_init(void); |
128 | void xenvif_xenbus_fini(void); | ||
123 | 129 | ||
124 | int xenvif_schedulable(struct xenvif *vif); | 130 | int xenvif_schedulable(struct xenvif *vif); |
125 | 131 | ||
@@ -157,4 +163,6 @@ void xenvif_carrier_off(struct xenvif *vif); | |||
157 | /* Returns number of ring slots required to send an skb to the frontend */ | 163 | /* Returns number of ring slots required to send an skb to the frontend */ |
158 | unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb); | 164 | unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb); |
159 | 165 | ||
166 | extern bool separate_tx_rx_irq; | ||
167 | |||
160 | #endif /* __XEN_NETBACK__COMMON_H__ */ | 168 | #endif /* __XEN_NETBACK__COMMON_H__ */ |
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index d98414168485..087d2db0389d 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
@@ -60,21 +60,39 @@ static int xenvif_rx_schedulable(struct xenvif *vif) | |||
60 | return xenvif_schedulable(vif) && !xen_netbk_rx_ring_full(vif); | 60 | return xenvif_schedulable(vif) && !xen_netbk_rx_ring_full(vif); |
61 | } | 61 | } |
62 | 62 | ||
63 | static irqreturn_t xenvif_interrupt(int irq, void *dev_id) | 63 | static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) |
64 | { | 64 | { |
65 | struct xenvif *vif = dev_id; | 65 | struct xenvif *vif = dev_id; |
66 | 66 | ||
67 | if (vif->netbk == NULL) | 67 | if (vif->netbk == NULL) |
68 | return IRQ_NONE; | 68 | return IRQ_HANDLED; |
69 | 69 | ||
70 | xen_netbk_schedule_xenvif(vif); | 70 | xen_netbk_schedule_xenvif(vif); |
71 | 71 | ||
72 | return IRQ_HANDLED; | ||
73 | } | ||
74 | |||
75 | static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) | ||
76 | { | ||
77 | struct xenvif *vif = dev_id; | ||
78 | |||
79 | if (vif->netbk == NULL) | ||
80 | return IRQ_HANDLED; | ||
81 | |||
72 | if (xenvif_rx_schedulable(vif)) | 82 | if (xenvif_rx_schedulable(vif)) |
73 | netif_wake_queue(vif->dev); | 83 | netif_wake_queue(vif->dev); |
74 | 84 | ||
75 | return IRQ_HANDLED; | 85 | return IRQ_HANDLED; |
76 | } | 86 | } |
77 | 87 | ||
88 | static irqreturn_t xenvif_interrupt(int irq, void *dev_id) | ||
89 | { | ||
90 | xenvif_tx_interrupt(irq, dev_id); | ||
91 | xenvif_rx_interrupt(irq, dev_id); | ||
92 | |||
93 | return IRQ_HANDLED; | ||
94 | } | ||
95 | |||
78 | static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) | 96 | static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) |
79 | { | 97 | { |
80 | struct xenvif *vif = netdev_priv(dev); | 98 | struct xenvif *vif = netdev_priv(dev); |
@@ -125,13 +143,17 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev) | |||
125 | static void xenvif_up(struct xenvif *vif) | 143 | static void xenvif_up(struct xenvif *vif) |
126 | { | 144 | { |
127 | xen_netbk_add_xenvif(vif); | 145 | xen_netbk_add_xenvif(vif); |
128 | enable_irq(vif->irq); | 146 | enable_irq(vif->tx_irq); |
147 | if (vif->tx_irq != vif->rx_irq) | ||
148 | enable_irq(vif->rx_irq); | ||
129 | xen_netbk_check_rx_xenvif(vif); | 149 | xen_netbk_check_rx_xenvif(vif); |
130 | } | 150 | } |
131 | 151 | ||
132 | static void xenvif_down(struct xenvif *vif) | 152 | static void xenvif_down(struct xenvif *vif) |
133 | { | 153 | { |
134 | disable_irq(vif->irq); | 154 | disable_irq(vif->tx_irq); |
155 | if (vif->tx_irq != vif->rx_irq) | ||
156 | disable_irq(vif->rx_irq); | ||
135 | del_timer_sync(&vif->credit_timeout); | 157 | del_timer_sync(&vif->credit_timeout); |
136 | xen_netbk_deschedule_xenvif(vif); | 158 | xen_netbk_deschedule_xenvif(vif); |
137 | xen_netbk_remove_xenvif(vif); | 159 | xen_netbk_remove_xenvif(vif); |
@@ -308,25 +330,52 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, | |||
308 | } | 330 | } |
309 | 331 | ||
310 | int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | 332 | int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, |
311 | unsigned long rx_ring_ref, unsigned int evtchn) | 333 | unsigned long rx_ring_ref, unsigned int tx_evtchn, |
334 | unsigned int rx_evtchn) | ||
312 | { | 335 | { |
313 | int err = -ENOMEM; | 336 | int err = -ENOMEM; |
314 | 337 | ||
315 | /* Already connected through? */ | 338 | /* Already connected through? */ |
316 | if (vif->irq) | 339 | if (vif->tx_irq) |
317 | return 0; | 340 | return 0; |
318 | 341 | ||
342 | __module_get(THIS_MODULE); | ||
343 | |||
319 | err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); | 344 | err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); |
320 | if (err < 0) | 345 | if (err < 0) |
321 | goto err; | 346 | goto err; |
322 | 347 | ||
323 | err = bind_interdomain_evtchn_to_irqhandler( | 348 | if (tx_evtchn == rx_evtchn) { |
324 | vif->domid, evtchn, xenvif_interrupt, 0, | 349 | /* feature-split-event-channels == 0 */ |
325 | vif->dev->name, vif); | 350 | err = bind_interdomain_evtchn_to_irqhandler( |
326 | if (err < 0) | 351 | vif->domid, tx_evtchn, xenvif_interrupt, 0, |
327 | goto err_unmap; | 352 | vif->dev->name, vif); |
328 | vif->irq = err; | 353 | if (err < 0) |
329 | disable_irq(vif->irq); | 354 | goto err_unmap; |
355 | vif->tx_irq = vif->rx_irq = err; | ||
356 | disable_irq(vif->tx_irq); | ||
357 | } else { | ||
358 | /* feature-split-event-channels == 1 */ | ||
359 | snprintf(vif->tx_irq_name, sizeof(vif->tx_irq_name), | ||
360 | "%s-tx", vif->dev->name); | ||
361 | err = bind_interdomain_evtchn_to_irqhandler( | ||
362 | vif->domid, tx_evtchn, xenvif_tx_interrupt, 0, | ||
363 | vif->tx_irq_name, vif); | ||
364 | if (err < 0) | ||
365 | goto err_unmap; | ||
366 | vif->tx_irq = err; | ||
367 | disable_irq(vif->tx_irq); | ||
368 | |||
369 | snprintf(vif->rx_irq_name, sizeof(vif->rx_irq_name), | ||
370 | "%s-rx", vif->dev->name); | ||
371 | err = bind_interdomain_evtchn_to_irqhandler( | ||
372 | vif->domid, rx_evtchn, xenvif_rx_interrupt, 0, | ||
373 | vif->rx_irq_name, vif); | ||
374 | if (err < 0) | ||
375 | goto err_tx_unbind; | ||
376 | vif->rx_irq = err; | ||
377 | disable_irq(vif->rx_irq); | ||
378 | } | ||
330 | 379 | ||
331 | xenvif_get(vif); | 380 | xenvif_get(vif); |
332 | 381 | ||
@@ -340,9 +389,13 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
340 | rtnl_unlock(); | 389 | rtnl_unlock(); |
341 | 390 | ||
342 | return 0; | 391 | return 0; |
392 | err_tx_unbind: | ||
393 | unbind_from_irqhandler(vif->tx_irq, vif); | ||
394 | vif->tx_irq = 0; | ||
343 | err_unmap: | 395 | err_unmap: |
344 | xen_netbk_unmap_frontend_rings(vif); | 396 | xen_netbk_unmap_frontend_rings(vif); |
345 | err: | 397 | err: |
398 | module_put(THIS_MODULE); | ||
346 | return err; | 399 | return err; |
347 | } | 400 | } |
348 | 401 | ||
@@ -360,18 +413,37 @@ void xenvif_carrier_off(struct xenvif *vif) | |||
360 | 413 | ||
361 | void xenvif_disconnect(struct xenvif *vif) | 414 | void xenvif_disconnect(struct xenvif *vif) |
362 | { | 415 | { |
416 | /* Disconnect funtion might get called by generic framework | ||
417 | * even before vif connects, so we need to check if we really | ||
418 | * need to do a module_put. | ||
419 | */ | ||
420 | int need_module_put = 0; | ||
421 | |||
363 | if (netif_carrier_ok(vif->dev)) | 422 | if (netif_carrier_ok(vif->dev)) |
364 | xenvif_carrier_off(vif); | 423 | xenvif_carrier_off(vif); |
365 | 424 | ||
366 | atomic_dec(&vif->refcnt); | 425 | atomic_dec(&vif->refcnt); |
367 | wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); | 426 | wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); |
368 | 427 | ||
369 | if (vif->irq) | 428 | if (vif->tx_irq) { |
370 | unbind_from_irqhandler(vif->irq, vif); | 429 | if (vif->tx_irq == vif->rx_irq) |
430 | unbind_from_irqhandler(vif->tx_irq, vif); | ||
431 | else { | ||
432 | unbind_from_irqhandler(vif->tx_irq, vif); | ||
433 | unbind_from_irqhandler(vif->rx_irq, vif); | ||
434 | } | ||
435 | /* vif->irq is valid, we had a module_get in | ||
436 | * xenvif_connect. | ||
437 | */ | ||
438 | need_module_put = 1; | ||
439 | } | ||
371 | 440 | ||
372 | unregister_netdev(vif->dev); | 441 | unregister_netdev(vif->dev); |
373 | 442 | ||
374 | xen_netbk_unmap_frontend_rings(vif); | 443 | xen_netbk_unmap_frontend_rings(vif); |
375 | 444 | ||
376 | free_netdev(vif->dev); | 445 | free_netdev(vif->dev); |
446 | |||
447 | if (need_module_put) | ||
448 | module_put(THIS_MODULE); | ||
377 | } | 449 | } |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 8c20935d72c9..64828de25d9a 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -47,6 +47,13 @@ | |||
47 | #include <asm/xen/hypercall.h> | 47 | #include <asm/xen/hypercall.h> |
48 | #include <asm/xen/page.h> | 48 | #include <asm/xen/page.h> |
49 | 49 | ||
50 | /* Provide an option to disable split event channels at load time as | ||
51 | * event channels are limited resource. Split event channels are | ||
52 | * enabled by default. | ||
53 | */ | ||
54 | bool separate_tx_rx_irq = 1; | ||
55 | module_param(separate_tx_rx_irq, bool, 0644); | ||
56 | |||
50 | /* | 57 | /* |
51 | * This is the maximum slots a skb can have. If a guest sends a skb | 58 | * This is the maximum slots a skb can have. If a guest sends a skb |
52 | * which exceeds this limit it is considered malicious. | 59 | * which exceeds this limit it is considered malicious. |
@@ -783,7 +790,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk) | |||
783 | } | 790 | } |
784 | 791 | ||
785 | list_for_each_entry_safe(vif, tmp, ¬ify, notify_list) { | 792 | list_for_each_entry_safe(vif, tmp, ¬ify, notify_list) { |
786 | notify_remote_via_irq(vif->irq); | 793 | notify_remote_via_irq(vif->rx_irq); |
787 | list_del_init(&vif->notify_list); | 794 | list_del_init(&vif->notify_list); |
788 | xenvif_put(vif); | 795 | xenvif_put(vif); |
789 | } | 796 | } |
@@ -1763,7 +1770,7 @@ static void make_tx_response(struct xenvif *vif, | |||
1763 | vif->tx.rsp_prod_pvt = ++i; | 1770 | vif->tx.rsp_prod_pvt = ++i; |
1764 | RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify); | 1771 | RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify); |
1765 | if (notify) | 1772 | if (notify) |
1766 | notify_remote_via_irq(vif->irq); | 1773 | notify_remote_via_irq(vif->tx_irq); |
1767 | } | 1774 | } |
1768 | 1775 | ||
1769 | static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif, | 1776 | static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif, |
@@ -1883,9 +1890,8 @@ static int __init netback_init(void) | |||
1883 | return -ENODEV; | 1890 | return -ENODEV; |
1884 | 1891 | ||
1885 | if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { | 1892 | if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { |
1886 | printk(KERN_INFO | 1893 | pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", |
1887 | "xen-netback: fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", | 1894 | fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); |
1888 | fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); | ||
1889 | fatal_skb_slots = XEN_NETBK_LEGACY_SLOTS_MAX; | 1895 | fatal_skb_slots = XEN_NETBK_LEGACY_SLOTS_MAX; |
1890 | } | 1896 | } |
1891 | 1897 | ||
@@ -1914,7 +1920,7 @@ static int __init netback_init(void) | |||
1914 | "netback/%u", group); | 1920 | "netback/%u", group); |
1915 | 1921 | ||
1916 | if (IS_ERR(netbk->task)) { | 1922 | if (IS_ERR(netbk->task)) { |
1917 | printk(KERN_ALERT "kthread_create() fails at netback\n"); | 1923 | pr_alert("kthread_create() fails at netback\n"); |
1918 | del_timer(&netbk->net_timer); | 1924 | del_timer(&netbk->net_timer); |
1919 | rc = PTR_ERR(netbk->task); | 1925 | rc = PTR_ERR(netbk->task); |
1920 | goto failed_init; | 1926 | goto failed_init; |
@@ -1940,10 +1946,6 @@ static int __init netback_init(void) | |||
1940 | failed_init: | 1946 | failed_init: |
1941 | while (--group >= 0) { | 1947 | while (--group >= 0) { |
1942 | struct xen_netbk *netbk = &xen_netbk[group]; | 1948 | struct xen_netbk *netbk = &xen_netbk[group]; |
1943 | for (i = 0; i < MAX_PENDING_REQS; i++) { | ||
1944 | if (netbk->mmap_pages[i]) | ||
1945 | __free_page(netbk->mmap_pages[i]); | ||
1946 | } | ||
1947 | del_timer(&netbk->net_timer); | 1949 | del_timer(&netbk->net_timer); |
1948 | kthread_stop(netbk->task); | 1950 | kthread_stop(netbk->task); |
1949 | } | 1951 | } |
@@ -1954,5 +1956,25 @@ failed_init: | |||
1954 | 1956 | ||
1955 | module_init(netback_init); | 1957 | module_init(netback_init); |
1956 | 1958 | ||
1959 | static void __exit netback_fini(void) | ||
1960 | { | ||
1961 | int i, j; | ||
1962 | |||
1963 | xenvif_xenbus_fini(); | ||
1964 | |||
1965 | for (i = 0; i < xen_netbk_group_nr; i++) { | ||
1966 | struct xen_netbk *netbk = &xen_netbk[i]; | ||
1967 | del_timer_sync(&netbk->net_timer); | ||
1968 | kthread_stop(netbk->task); | ||
1969 | for (j = 0; j < MAX_PENDING_REQS; j++) { | ||
1970 | if (netbk->mmap_pages[j]) | ||
1971 | __free_page(netbk->mmap_pages[j]); | ||
1972 | } | ||
1973 | } | ||
1974 | |||
1975 | vfree(xen_netbk); | ||
1976 | } | ||
1977 | module_exit(netback_fini); | ||
1978 | |||
1957 | MODULE_LICENSE("Dual BSD/GPL"); | 1979 | MODULE_LICENSE("Dual BSD/GPL"); |
1958 | MODULE_ALIAS("xen-backend:vif"); | 1980 | MODULE_ALIAS("xen-backend:vif"); |
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 410018c4c528..1fe48fe364ed 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c | |||
@@ -122,6 +122,16 @@ static int netback_probe(struct xenbus_device *dev, | |||
122 | goto fail; | 122 | goto fail; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* | ||
126 | * Split event channels support, this is optional so it is not | ||
127 | * put inside the above loop. | ||
128 | */ | ||
129 | err = xenbus_printf(XBT_NIL, dev->nodename, | ||
130 | "feature-split-event-channels", | ||
131 | "%u", separate_tx_rx_irq); | ||
132 | if (err) | ||
133 | pr_debug("Error writing feature-split-event-channels\n"); | ||
134 | |||
125 | err = xenbus_switch_state(dev, XenbusStateInitWait); | 135 | err = xenbus_switch_state(dev, XenbusStateInitWait); |
126 | if (err) | 136 | if (err) |
127 | goto fail; | 137 | goto fail; |
@@ -135,7 +145,7 @@ abort_transaction: | |||
135 | xenbus_transaction_end(xbt, 1); | 145 | xenbus_transaction_end(xbt, 1); |
136 | xenbus_dev_fatal(dev, err, "%s", message); | 146 | xenbus_dev_fatal(dev, err, "%s", message); |
137 | fail: | 147 | fail: |
138 | pr_debug("failed"); | 148 | pr_debug("failed\n"); |
139 | netback_remove(dev); | 149 | netback_remove(dev); |
140 | return err; | 150 | return err; |
141 | } | 151 | } |
@@ -218,15 +228,14 @@ static void frontend_changed(struct xenbus_device *dev, | |||
218 | { | 228 | { |
219 | struct backend_info *be = dev_get_drvdata(&dev->dev); | 229 | struct backend_info *be = dev_get_drvdata(&dev->dev); |
220 | 230 | ||
221 | pr_debug("frontend state %s", xenbus_strstate(frontend_state)); | 231 | pr_debug("frontend state %s\n", xenbus_strstate(frontend_state)); |
222 | 232 | ||
223 | be->frontend_state = frontend_state; | 233 | be->frontend_state = frontend_state; |
224 | 234 | ||
225 | switch (frontend_state) { | 235 | switch (frontend_state) { |
226 | case XenbusStateInitialising: | 236 | case XenbusStateInitialising: |
227 | if (dev->state == XenbusStateClosed) { | 237 | if (dev->state == XenbusStateClosed) { |
228 | printk(KERN_INFO "%s: %s: prepare for reconnect\n", | 238 | pr_info("%s: prepare for reconnect\n", dev->nodename); |
229 | __func__, dev->nodename); | ||
230 | xenbus_switch_state(dev, XenbusStateInitWait); | 239 | xenbus_switch_state(dev, XenbusStateInitWait); |
231 | } | 240 | } |
232 | break; | 241 | break; |
@@ -393,21 +402,36 @@ static int connect_rings(struct backend_info *be) | |||
393 | struct xenvif *vif = be->vif; | 402 | struct xenvif *vif = be->vif; |
394 | struct xenbus_device *dev = be->dev; | 403 | struct xenbus_device *dev = be->dev; |
395 | unsigned long tx_ring_ref, rx_ring_ref; | 404 | unsigned long tx_ring_ref, rx_ring_ref; |
396 | unsigned int evtchn, rx_copy; | 405 | unsigned int tx_evtchn, rx_evtchn, rx_copy; |
397 | int err; | 406 | int err; |
398 | int val; | 407 | int val; |
399 | 408 | ||
400 | err = xenbus_gather(XBT_NIL, dev->otherend, | 409 | err = xenbus_gather(XBT_NIL, dev->otherend, |
401 | "tx-ring-ref", "%lu", &tx_ring_ref, | 410 | "tx-ring-ref", "%lu", &tx_ring_ref, |
402 | "rx-ring-ref", "%lu", &rx_ring_ref, | 411 | "rx-ring-ref", "%lu", &rx_ring_ref, NULL); |
403 | "event-channel", "%u", &evtchn, NULL); | ||
404 | if (err) { | 412 | if (err) { |
405 | xenbus_dev_fatal(dev, err, | 413 | xenbus_dev_fatal(dev, err, |
406 | "reading %s/ring-ref and event-channel", | 414 | "reading %s/ring-ref", |
407 | dev->otherend); | 415 | dev->otherend); |
408 | return err; | 416 | return err; |
409 | } | 417 | } |
410 | 418 | ||
419 | /* Try split event channels first, then single event channel. */ | ||
420 | err = xenbus_gather(XBT_NIL, dev->otherend, | ||
421 | "event-channel-tx", "%u", &tx_evtchn, | ||
422 | "event-channel-rx", "%u", &rx_evtchn, NULL); | ||
423 | if (err < 0) { | ||
424 | err = xenbus_scanf(XBT_NIL, dev->otherend, | ||
425 | "event-channel", "%u", &tx_evtchn); | ||
426 | if (err < 0) { | ||
427 | xenbus_dev_fatal(dev, err, | ||
428 | "reading %s/event-channel(-tx/rx)", | ||
429 | dev->otherend); | ||
430 | return err; | ||
431 | } | ||
432 | rx_evtchn = tx_evtchn; | ||
433 | } | ||
434 | |||
411 | err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u", | 435 | err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u", |
412 | &rx_copy); | 436 | &rx_copy); |
413 | if (err == -ENOENT) { | 437 | if (err == -ENOENT) { |
@@ -454,11 +478,13 @@ static int connect_rings(struct backend_info *be) | |||
454 | vif->csum = !val; | 478 | vif->csum = !val; |
455 | 479 | ||
456 | /* Map the shared frame, irq etc. */ | 480 | /* Map the shared frame, irq etc. */ |
457 | err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn); | 481 | err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, |
482 | tx_evtchn, rx_evtchn); | ||
458 | if (err) { | 483 | if (err) { |
459 | xenbus_dev_fatal(dev, err, | 484 | xenbus_dev_fatal(dev, err, |
460 | "mapping shared-frames %lu/%lu port %u", | 485 | "mapping shared-frames %lu/%lu port tx %u rx %u", |
461 | tx_ring_ref, rx_ring_ref, evtchn); | 486 | tx_ring_ref, rx_ring_ref, |
487 | tx_evtchn, rx_evtchn); | ||
462 | return err; | 488 | return err; |
463 | } | 489 | } |
464 | return 0; | 490 | return 0; |
@@ -485,3 +511,8 @@ int xenvif_xenbus_init(void) | |||
485 | { | 511 | { |
486 | return xenbus_register_backend(&netback_driver); | 512 | return xenbus_register_backend(&netback_driver); |
487 | } | 513 | } |
514 | |||
515 | void xenvif_xenbus_fini(void) | ||
516 | { | ||
517 | return xenbus_unregister_driver(&netback_driver); | ||
518 | } | ||