diff options
author | David S. Miller <davem@davemloft.net> | 2013-05-23 18:40:46 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-05-23 18:40:46 -0700 |
commit | 340611ab7f8c95e9638bb8a181cb078e900dc5ec (patch) | |
tree | a39dca4181d43db663b5796335fecbed7b0ed34f /drivers/net/xen-netback/interface.c | |
parent | 8892475386e819aa50856947948c546ccc964d96 (diff) | |
parent | a5560a6c17a4af4e8f45d5c1215ba7d5bb0ff109 (diff) |
Merge branch 'xen_split_event_channels'
Wei Liu says:
====================
This series adds a new feature called split event channels.
In the original implementation, only one event channel is setup between
frontend and backend. This is not ideal as TX notification interferes with RX
notification. Using dedicated event channels for TX and RX solves this issue.
Changes since V2:
* feature_split_event_channels -> separate_tx_rx_irq
* make separate_tx_rx_irq bool
* document this feature in header file
* don't report fatal if writing feature to xenstore fails
* frontend will fall back to single event channel if new feature setup fails
Changes since V1:
* change subject lines of commits to be more specific
* add parameter feature_split_event_channels for xen-netback
* remove two dev_info
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback/interface.c')
-rw-r--r-- | drivers/net/xen-netback/interface.c | 85 |
1 files changed, 70 insertions, 15 deletions
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 82202c2b1bd1..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) return xenvif_schedulable(vif) && !xen_netbk_rx_ring_full(vif); } -static irqreturn_t xenvif_interrupt(int irq, void *dev_id) +static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id) { struct xenvif *vif = dev_id; if (vif->netbk == NULL) - return IRQ_NONE; + return IRQ_HANDLED; xen_netbk_schedule_xenvif(vif); + return IRQ_HANDLED; +} + +static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) +{ + struct xenvif *vif = dev_id; + + if (vif->netbk == NULL) + return IRQ_HANDLED; + if (xenvif_rx_schedulable(vif)) netif_wake_queue(vif->dev); return IRQ_HANDLED; } +static irqreturn_t xenvif_interrupt(int irq, void *dev_id) +{ + xenvif_tx_interrupt(irq, dev_id); + xenvif_rx_interrupt(irq, dev_id); + + return IRQ_HANDLED; +} + static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); @@ -125,13 +143,17 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev) static void xenvif_up(struct xenvif *vif) { xen_netbk_add_xenvif(vif); - enable_irq(vif->irq); + enable_irq(vif->tx_irq); + if (vif->tx_irq != vif->rx_irq) + enable_irq(vif->rx_irq); xen_netbk_check_rx_xenvif(vif); } static void xenvif_down(struct xenvif *vif) { - disable_irq(vif->irq); + disable_irq(vif->tx_irq); + if (vif->tx_irq != vif->rx_irq) + disable_irq(vif->rx_irq); del_timer_sync(&vif->credit_timeout); xen_netbk_deschedule_xenvif(vif); xen_netbk_remove_xenvif(vif); @@ -308,12 +330,13 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, } int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, - unsigned long rx_ring_ref, unsigned int evtchn) + unsigned long rx_ring_ref, unsigned int tx_evtchn, + unsigned int rx_evtchn) { int err = -ENOMEM; /* Already connected through? */ - if (vif->irq) + if (vif->tx_irq) return 0; __module_get(THIS_MODULE); @@ -322,13 +345,37 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, if (err < 0) goto err; - err = bind_interdomain_evtchn_to_irqhandler( - vif->domid, evtchn, xenvif_interrupt, 0, - vif->dev->name, vif); - if (err < 0) - goto err_unmap; - vif->irq = err; - disable_irq(vif->irq); + if (tx_evtchn == rx_evtchn) { + /* feature-split-event-channels == 0 */ + err = bind_interdomain_evtchn_to_irqhandler( + vif->domid, tx_evtchn, xenvif_interrupt, 0, + vif->dev->name, vif); + if (err < 0) + goto err_unmap; + vif->tx_irq = vif->rx_irq = err; + disable_irq(vif->tx_irq); + } else { + /* feature-split-event-channels == 1 */ + snprintf(vif->tx_irq_name, sizeof(vif->tx_irq_name), + "%s-tx", vif->dev->name); + err = bind_interdomain_evtchn_to_irqhandler( + vif->domid, tx_evtchn, xenvif_tx_interrupt, 0, + vif->tx_irq_name, vif); + if (err < 0) + goto err_unmap; + vif->tx_irq = err; + disable_irq(vif->tx_irq); + + snprintf(vif->rx_irq_name, sizeof(vif->rx_irq_name), + "%s-rx", vif->dev->name); + err = bind_interdomain_evtchn_to_irqhandler( + vif->domid, rx_evtchn, xenvif_rx_interrupt, 0, + vif->rx_irq_name, vif); + if (err < 0) + goto err_tx_unbind; + vif->rx_irq = err; + disable_irq(vif->rx_irq); + } xenvif_get(vif); @@ -342,6 +389,9 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, rtnl_unlock(); return 0; +err_tx_unbind: + unbind_from_irqhandler(vif->tx_irq, vif); + vif->tx_irq = 0; err_unmap: xen_netbk_unmap_frontend_rings(vif); err: @@ -375,8 +425,13 @@ void xenvif_disconnect(struct xenvif *vif) atomic_dec(&vif->refcnt); wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); - if (vif->irq) { - unbind_from_irqhandler(vif->irq, vif); + if (vif->tx_irq) { + if (vif->tx_irq == vif->rx_irq) + unbind_from_irqhandler(vif->tx_irq, vif); + else { + unbind_from_irqhandler(vif->tx_irq, vif); + unbind_from_irqhandler(vif->rx_irq, vif); + } /* vif->irq is valid, we had a module_get in * xenvif_connect. */ |