[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH V6 net-next 1/5] xen-netback: Factor queue-specific data into queue struct.



From: "Andrew J. Bennieston" <andrew.bennieston@xxxxxxxxxx>

In preparation for multi-queue support in xen-netback, move the
queue-specific data from struct xenvif into struct xenvif_queue, and
update the rest of the code to use this.

Also adds loops over queues where appropriate, even though only one is
configured at this point, and uses alloc_netdev_mq() and the
corresponding multi-queue netif wake/start/stop functions in preparation
for multiple active queues.

Finally, implements a trivial queue selection function suitable for
ndo_select_queue, which simply returns 0 for a single queue and uses
skb_get_hash() to compute the queue index otherwise.

Signed-off-by: Andrew J. Bennieston <andrew.bennieston@xxxxxxxxxx>
Reviewed-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 drivers/net/xen-netback/common.h    |   85 ++++--
 drivers/net/xen-netback/interface.c |  329 ++++++++++++++--------
 drivers/net/xen-netback/netback.c   |  530 ++++++++++++++++++-----------------
 drivers/net/xen-netback/xenbus.c    |   87 ++++--
 4 files changed, 608 insertions(+), 423 deletions(-)

diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index ae413a2..4176539 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -108,17 +108,39 @@ struct xenvif_rx_meta {
  */
 #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE)
 
-struct xenvif {
-       /* Unique identifier for this interface. */
-       domid_t          domid;
-       unsigned int     handle;
+/* Queue name is interface name with "-qNNN" appended */
+#define QUEUE_NAME_SIZE (IFNAMSIZ + 6)
+
+/* IRQ name is queue name with "-tx" or "-rx" appended */
+#define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)
+
+struct xenvif;
+
+struct xenvif_stats {
+       /* Stats fields to be updated per-queue.
+        * A subset of struct net_device_stats that contains only the
+        * fields that are updated in netback.c for each queue.
+        */
+       unsigned int rx_bytes;
+       unsigned int rx_packets;
+       unsigned int tx_bytes;
+       unsigned int tx_packets;
+
+       /* Additional stats used by xenvif */
+       unsigned long rx_gso_checksum_fixup;
+};
+
+struct xenvif_queue { /* Per-queue data for xenvif */
+       unsigned int id; /* Queue ID, 0-based */
+       char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */
+       struct xenvif *vif; /* Parent VIF */
 
        /* Use NAPI for guest TX */
        struct napi_struct napi;
        /* When feature-split-event-channels = 0, tx_irq = rx_irq. */
        unsigned int tx_irq;
        /* Only used when feature-split-event-channels = 1 */
-       char tx_irq_name[IFNAMSIZ+4]; /* DEVNAME-tx */
+       char tx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-tx */
        struct xen_netif_tx_back_ring tx;
        struct sk_buff_head tx_queue;
        struct page *mmap_pages[MAX_PENDING_REQS];
@@ -140,19 +162,34 @@ struct xenvif {
        /* When feature-split-event-channels = 0, tx_irq = rx_irq. */
        unsigned int rx_irq;
        /* Only used when feature-split-event-channels = 1 */
-       char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
+       char rx_irq_name[IRQ_NAME_SIZE]; /* DEVNAME-qN-rx */
        struct xen_netif_rx_back_ring rx;
        struct sk_buff_head rx_queue;
        RING_IDX rx_last_skb_slots;
 
-       /* This array is allocated seperately as it is large */
-       struct gnttab_copy *grant_copy_op;
+       struct gnttab_copy grant_copy_op[MAX_GRANT_COPY_OPS];
 
        /* We create one meta structure per ring request we consume, so
         * the maximum number is the same as the ring size.
         */
        struct xenvif_rx_meta meta[XEN_NETIF_RX_RING_SIZE];
 
+       /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
+       unsigned long   credit_bytes;
+       unsigned long   credit_usec;
+       unsigned long   remaining_credit;
+       struct timer_list credit_timeout;
+       u64 credit_window_start;
+
+       /* Statistics */
+       struct xenvif_stats stats;
+};
+
+struct xenvif {
+       /* Unique identifier for this interface. */
+       domid_t          domid;
+       unsigned int     handle;
+
        u8               fe_dev_addr[6];
 
        /* Frontend feature information. */
@@ -166,15 +203,9 @@ struct xenvif {
        /* Internal feature information. */
        u8 can_queue:1;     /* can queue packets for receiver? */
 
-       /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
-       unsigned long   credit_bytes;
-       unsigned long   credit_usec;
-       unsigned long   remaining_credit;
-       struct timer_list credit_timeout;
-       u64 credit_window_start;
-
-       /* Statistics */
-       unsigned long rx_gso_checksum_fixup;
+       /* Queues */
+       unsigned int num_queues;
+       struct xenvif_queue *queues;
 
        /* Miscellaneous private stuff. */
        struct net_device *dev;
@@ -189,7 +220,9 @@ struct xenvif *xenvif_alloc(struct device *parent,
                            domid_t domid,
                            unsigned int handle);
 
-int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
+void xenvif_init_queue(struct xenvif_queue *queue);
+
+int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
                   unsigned long rx_ring_ref, unsigned int tx_evtchn,
                   unsigned int rx_evtchn);
 void xenvif_disconnect(struct xenvif *vif);
@@ -200,31 +233,31 @@ void xenvif_xenbus_fini(void);
 
 int xenvif_schedulable(struct xenvif *vif);
 
-int xenvif_must_stop_queue(struct xenvif *vif);
+int xenvif_must_stop_queue(struct xenvif_queue *queue);
 
 /* (Un)Map communication rings. */
-void xenvif_unmap_frontend_rings(struct xenvif *vif);
-int xenvif_map_frontend_rings(struct xenvif *vif,
+void xenvif_unmap_frontend_rings(struct xenvif_queue *queue);
+int xenvif_map_frontend_rings(struct xenvif_queue *queue,
                              grant_ref_t tx_ring_ref,
                              grant_ref_t rx_ring_ref);
 
 /* Check for SKBs from frontend and schedule backend processing */
-void xenvif_check_rx_xenvif(struct xenvif *vif);
+void xenvif_check_rx_xenvif(struct xenvif_queue *queue);
 
 /* Prevent the device from generating any further traffic. */
 void xenvif_carrier_off(struct xenvif *vif);
 
-int xenvif_tx_action(struct xenvif *vif, int budget);
+int xenvif_tx_action(struct xenvif_queue *queue, int budget);
 
 int xenvif_kthread(void *data);
-void xenvif_kick_thread(struct xenvif *vif);
+void xenvif_kick_thread(struct xenvif_queue *queue);
 
 /* Determine whether the needed number of slots (req) are available,
  * and set req_event if not.
  */
-bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed);
+bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue, int needed);
 
-void xenvif_stop_queue(struct xenvif *vif);
+void xenvif_carrier_on(struct xenvif *vif);
 
 extern bool separate_tx_rx_irq;
 
diff --git a/drivers/net/xen-netback/interface.c 
b/drivers/net/xen-netback/interface.c
index 7669d49..0297980 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -34,7 +34,6 @@
 #include <linux/ethtool.h>
 #include <linux/rtnetlink.h>
 #include <linux/if_vlan.h>
-#include <linux/vmalloc.h>
 
 #include <xen/events.h>
 #include <asm/xen/hypercall.h>
@@ -42,6 +41,16 @@
 #define XENVIF_QUEUE_LENGTH 32
 #define XENVIF_NAPI_WEIGHT  64
 
+static inline void xenvif_stop_queue(struct xenvif_queue *queue)
+{
+       struct net_device *dev = queue->vif->dev;
+
+       if (!queue->vif->can_queue)
+               return;
+
+       netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id));
+}
+
 int xenvif_schedulable(struct xenvif *vif)
 {
        return netif_running(vif->dev) && netif_carrier_ok(vif->dev);
@@ -49,20 +58,20 @@ int xenvif_schedulable(struct xenvif *vif)
 
 static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id)
 {
-       struct xenvif *vif = dev_id;
+       struct xenvif_queue *queue = dev_id;
 
-       if (RING_HAS_UNCONSUMED_REQUESTS(&vif->tx))
-               napi_schedule(&vif->napi);
+       if (RING_HAS_UNCONSUMED_REQUESTS(&queue->tx))
+               napi_schedule(&queue->napi);
 
        return IRQ_HANDLED;
 }
 
-static int xenvif_poll(struct napi_struct *napi, int budget)
+int xenvif_poll(struct napi_struct *napi, int budget)
 {
-       struct xenvif *vif = container_of(napi, struct xenvif, napi);
+       struct xenvif_queue *queue = container_of(napi, struct xenvif_queue, 
napi);
        int work_done;
 
-       work_done = xenvif_tx_action(vif, budget);
+       work_done = xenvif_tx_action(queue, budget);
 
        if (work_done < budget) {
                int more_to_do = 0;
@@ -86,7 +95,7 @@ static int xenvif_poll(struct napi_struct *napi, int budget)
 
                local_irq_save(flags);
 
-               RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
+               RING_FINAL_CHECK_FOR_REQUESTS(&queue->tx, more_to_do);
                if (!more_to_do)
                        __napi_complete(napi);
 
@@ -98,9 +107,9 @@ static int xenvif_poll(struct napi_struct *napi, int budget)
 
 static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
 {
-       struct xenvif *vif = dev_id;
+       struct xenvif_queue *queue = dev_id;
 
-       xenvif_kick_thread(vif);
+       xenvif_kick_thread(queue);
 
        return IRQ_HANDLED;
 }
@@ -113,15 +122,48 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb,
+                              void *accel_priv, select_queue_fallback_t 
fallback)
+{
+       struct xenvif *vif = netdev_priv(dev);
+       u32 hash;
+       u16 queue_index;
+
+       /* First, check if there is only one queue to optimise the
+        * single-queue or old frontend scenario.
+        */
+       if (vif->num_queues == 1) {
+               queue_index = 0;
+       } else {
+               /* Use skb_get_hash to obtain an L4 hash if available */
+               hash = skb_get_hash(skb);
+               queue_index = (u16) (((u64)hash * vif->num_queues) >> 32);
+       }
+
+       return queue_index;
+}
+
 static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct xenvif *vif = netdev_priv(dev);
+       struct xenvif_queue *queue = NULL;
+       u16 index;
        int min_slots_needed;
 
        BUG_ON(skb->dev != dev);
 
+       /* Drop the packet if queues are not set up */
+       if (vif->num_queues < 1)
+               goto drop;
+
+       /* Obtain the queue to be used to transmit this packet */
+       index = skb_get_queue_mapping(skb);
+       if (index >= vif->num_queues)
+               index = 0; /* Fall back to queue 0 if out of range */
+       queue = &vif->queues[index];
+
        /* Drop the packet if vif is not ready */
-       if (vif->task == NULL || !xenvif_schedulable(vif))
+       if (queue->task == NULL || !xenvif_schedulable(vif))
                goto drop;
 
        /* At best we'll need one slot for the header and one for each
@@ -140,11 +182,11 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct 
net_device *dev)
         * then turn off the queue to give the ring a chance to
         * drain.
         */
-       if (!xenvif_rx_ring_slots_available(vif, min_slots_needed))
-               xenvif_stop_queue(vif);
+       if (!xenvif_rx_ring_slots_available(queue, min_slots_needed))
+               xenvif_stop_queue(queue);
 
-       skb_queue_tail(&vif->rx_queue, skb);
-       xenvif_kick_thread(vif);
+       skb_queue_tail(&queue->rx_queue, skb);
+       xenvif_kick_thread(queue);
 
        return NETDEV_TX_OK;
 
@@ -157,25 +199,58 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct 
net_device *dev)
 static struct net_device_stats *xenvif_get_stats(struct net_device *dev)
 {
        struct xenvif *vif = netdev_priv(dev);
+       struct xenvif_queue *queue = NULL;
+       unsigned long rx_bytes = 0;
+       unsigned long rx_packets = 0;
+       unsigned long tx_bytes = 0;
+       unsigned long tx_packets = 0;
+       unsigned int index;
+
+       /* Aggregate tx and rx stats from each queue */
+       for (index = 0; index < vif->num_queues; ++index) {
+               queue = &vif->queues[index];
+               rx_bytes += queue->stats.rx_bytes;
+               rx_packets += queue->stats.rx_packets;
+               tx_bytes += queue->stats.tx_bytes;
+               tx_packets += queue->stats.tx_packets;
+       }
+
+       vif->dev->stats.rx_bytes = rx_bytes;
+       vif->dev->stats.rx_packets = rx_packets;
+       vif->dev->stats.tx_bytes = tx_bytes;
+       vif->dev->stats.tx_packets = tx_packets;
+
        return &vif->dev->stats;
 }
 
 static void xenvif_up(struct xenvif *vif)
 {
-       napi_enable(&vif->napi);
-       enable_irq(vif->tx_irq);
-       if (vif->tx_irq != vif->rx_irq)
-               enable_irq(vif->rx_irq);
-       xenvif_check_rx_xenvif(vif);
+       struct xenvif_queue *queue = NULL;
+       unsigned int queue_index;
+
+       for (queue_index = 0; queue_index < vif->num_queues; ++queue_index) {
+               queue = &vif->queues[queue_index];
+               napi_enable(&queue->napi);
+               enable_irq(queue->tx_irq);
+               if (queue->tx_irq != queue->rx_irq)
+                       enable_irq(queue->rx_irq);
+               xenvif_check_rx_xenvif(queue);
+       }
 }
 
 static void xenvif_down(struct xenvif *vif)
 {
-       napi_disable(&vif->napi);
-       disable_irq(vif->tx_irq);
-       if (vif->tx_irq != vif->rx_irq)
-               disable_irq(vif->rx_irq);
-       del_timer_sync(&vif->credit_timeout);
+       struct xenvif_queue *queue = NULL;
+       unsigned int queue_index;
+
+       for (queue_index = 0; queue_index < vif->num_queues; ++queue_index) {
+               queue = &vif->queues[queue_index];
+               napi_disable(&queue->napi);
+               disable_irq(queue->tx_irq);
+               if (queue->tx_irq != queue->rx_irq)
+                       disable_irq(queue->rx_irq);
+               del_timer_sync(&queue->credit_timeout);
+       }
 }
 
 static int xenvif_open(struct net_device *dev)
@@ -183,7 +258,7 @@ static int xenvif_open(struct net_device *dev)
        struct xenvif *vif = netdev_priv(dev);
        if (netif_carrier_ok(dev))
                xenvif_up(vif);
-       netif_start_queue(dev);
+       netif_tx_start_all_queues(dev);
        return 0;
 }
 
@@ -192,7 +267,7 @@ static int xenvif_close(struct net_device *dev)
        struct xenvif *vif = netdev_priv(dev);
        if (netif_carrier_ok(dev))
                xenvif_down(vif);
-       netif_stop_queue(dev);
+       netif_tx_stop_all_queues(dev);
        return 0;
 }
 
@@ -232,7 +307,7 @@ static const struct xenvif_stat {
 } xenvif_stats[] = {
        {
                "rx_gso_checksum_fixup",
-               offsetof(struct xenvif, rx_gso_checksum_fixup)
+               offsetof(struct xenvif_stats, rx_gso_checksum_fixup)
        },
 };
 
@@ -249,11 +324,19 @@ static int xenvif_get_sset_count(struct net_device *dev, 
int string_set)
 static void xenvif_get_ethtool_stats(struct net_device *dev,
                                     struct ethtool_stats *stats, u64 * data)
 {
-       void *vif = netdev_priv(dev);
+       struct xenvif *vif = netdev_priv(dev);
        int i;
-
-       for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
-               data[i] = *(unsigned long *)(vif + xenvif_stats[i].offset);
+       unsigned int queue_index;
+       struct xenvif_stats *vif_stats;
+
+       for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) {
+               unsigned long accum = 0;
+               for (queue_index = 0; queue_index < vif->num_queues; 
++queue_index) {
+                       vif_stats = &vif->queues[queue_index].stats;
+                       accum += *(unsigned long *)(vif_stats + 
xenvif_stats[i].offset);
+               }
+               data[i] = accum;
+       }
 }
 
 static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * 
data)
@@ -286,6 +369,7 @@ static const struct net_device_ops xenvif_netdev_ops = {
        .ndo_fix_features = xenvif_fix_features,
        .ndo_set_mac_address = eth_mac_addr,
        .ndo_validate_addr   = eth_validate_addr,
+       .ndo_select_queue = xenvif_select_queue,
 };
 
 struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
@@ -295,10 +379,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t 
domid,
        struct net_device *dev;
        struct xenvif *vif;
        char name[IFNAMSIZ] = {};
-       int i;
 
        snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
-       dev = alloc_netdev(sizeof(struct xenvif), name, ether_setup);
+       dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, 1);
        if (dev == NULL) {
                pr_warn("Could not allocate netdev for %s\n", name);
                return ERR_PTR(-ENOMEM);
@@ -308,24 +391,15 @@ struct xenvif *xenvif_alloc(struct device *parent, 
domid_t domid,
 
        vif = netdev_priv(dev);
 
-       vif->grant_copy_op = vmalloc(sizeof(struct gnttab_copy) *
-                                    MAX_GRANT_COPY_OPS);
-       if (vif->grant_copy_op == NULL) {
-               pr_warn("Could not allocate grant copy space for %s\n", name);
-               free_netdev(dev);
-               return ERR_PTR(-ENOMEM);
-       }
-
        vif->domid  = domid;
        vif->handle = handle;
        vif->can_sg = 1;
        vif->ip_csum = 1;
        vif->dev = dev;
 
-       vif->credit_bytes = vif->remaining_credit = ~0UL;
-       vif->credit_usec  = 0UL;
-       init_timer(&vif->credit_timeout);
-       vif->credit_window_start = get_jiffies_64();
+       /* Start out with no queues */
+       vif->num_queues = 0;
+       vif->queues = NULL;
 
        dev->netdev_ops = &xenvif_netdev_ops;
        dev->hw_features = NETIF_F_SG |
@@ -336,16 +410,6 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t 
domid,
 
        dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
 
-       skb_queue_head_init(&vif->rx_queue);
-       skb_queue_head_init(&vif->tx_queue);
-
-       vif->pending_cons = 0;
-       vif->pending_prod = MAX_PENDING_REQS;
-       for (i = 0; i < MAX_PENDING_REQS; i++)
-               vif->pending_ring[i] = i;
-       for (i = 0; i < MAX_PENDING_REQS; i++)
-               vif->mmap_pages[i] = NULL;
-
        /*
         * Initialise a dummy MAC address. We choose the numerically
         * largest non-broadcast address to prevent the address getting
@@ -355,8 +419,6 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t 
domid,
        memset(dev->dev_addr, 0xFF, ETH_ALEN);
        dev->dev_addr[0] &= ~0x01;
 
-       netif_napi_add(dev, &vif->napi, xenvif_poll, XENVIF_NAPI_WEIGHT);
-
        netif_carrier_off(dev);
 
        err = register_netdev(dev);
@@ -373,85 +435,111 @@ struct xenvif *xenvif_alloc(struct device *parent, 
domid_t domid,
        return vif;
 }
 
-int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
+void xenvif_init_queue(struct xenvif_queue *queue)
+{
+       int i;
+
+       queue->credit_bytes = queue->remaining_credit = ~0UL;
+       queue->credit_usec  = 0UL;
+       init_timer(&queue->credit_timeout);
+       queue->credit_window_start = get_jiffies_64();
+
+       skb_queue_head_init(&queue->rx_queue);
+       skb_queue_head_init(&queue->tx_queue);
+
+       queue->pending_cons = 0;
+       queue->pending_prod = MAX_PENDING_REQS;
+       for (i = 0; i < MAX_PENDING_REQS; ++i) {
+               queue->pending_ring[i] = i;
+               queue->mmap_pages[i] = NULL;
+       }
+
+       netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll,
+                       XENVIF_NAPI_WEIGHT);
+}
+
+void xenvif_carrier_on(struct xenvif *vif)
+{
+       rtnl_lock();
+       if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
+               dev_set_mtu(vif->dev, ETH_DATA_LEN);
+       netdev_update_features(vif->dev);
+       netif_carrier_on(vif->dev);
+       if (netif_running(vif->dev))
+               xenvif_up(vif);
+       rtnl_unlock();
+}
+
+int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
                   unsigned long rx_ring_ref, unsigned int tx_evtchn,
                   unsigned int rx_evtchn)
 {
        struct task_struct *task;
        int err = -ENOMEM;
 
-       BUG_ON(vif->tx_irq);
-       BUG_ON(vif->task);
+       BUG_ON(queue->tx_irq);
+       BUG_ON(queue->task);
 
-       err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
+       err = xenvif_map_frontend_rings(queue, tx_ring_ref, rx_ring_ref);
        if (err < 0)
                goto err;
 
-       init_waitqueue_head(&vif->wq);
+       init_waitqueue_head(&queue->wq);
 
        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);
+                       queue->vif->domid, tx_evtchn, xenvif_interrupt, 0,
+                       queue->name, queue);
                if (err < 0)
                        goto err_unmap;
-               vif->tx_irq = vif->rx_irq = err;
-               disable_irq(vif->tx_irq);
+               queue->tx_irq = queue->rx_irq = err;
+               disable_irq(queue->tx_irq);
        } else {
                /* feature-split-event-channels == 1 */
-               snprintf(vif->tx_irq_name, sizeof(vif->tx_irq_name),
-                        "%s-tx", vif->dev->name);
+               snprintf(queue->tx_irq_name, sizeof(queue->tx_irq_name),
+                        "%s-tx", queue->name);
                err = bind_interdomain_evtchn_to_irqhandler(
-                       vif->domid, tx_evtchn, xenvif_tx_interrupt, 0,
-                       vif->tx_irq_name, vif);
+                       queue->vif->domid, tx_evtchn, xenvif_tx_interrupt, 0,
+                       queue->tx_irq_name, queue);
                if (err < 0)
                        goto err_unmap;
-               vif->tx_irq = err;
-               disable_irq(vif->tx_irq);
+               queue->tx_irq = err;
+               disable_irq(queue->tx_irq);
 
-               snprintf(vif->rx_irq_name, sizeof(vif->rx_irq_name),
-                        "%s-rx", vif->dev->name);
+               snprintf(queue->rx_irq_name, sizeof(queue->rx_irq_name),
+                        "%s-rx", queue->name);
                err = bind_interdomain_evtchn_to_irqhandler(
-                       vif->domid, rx_evtchn, xenvif_rx_interrupt, 0,
-                       vif->rx_irq_name, vif);
+                       queue->vif->domid, rx_evtchn, xenvif_rx_interrupt, 0,
+                       queue->rx_irq_name, queue);
                if (err < 0)
                        goto err_tx_unbind;
-               vif->rx_irq = err;
-               disable_irq(vif->rx_irq);
+               queue->rx_irq = err;
+               disable_irq(queue->rx_irq);
        }
 
        task = kthread_create(xenvif_kthread,
-                             (void *)vif, "%s", vif->dev->name);
+                             (void *)queue, "%s", queue->name);
        if (IS_ERR(task)) {
-               pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
+               pr_warn("Could not allocate kthread for %s\n", queue->name);
                err = PTR_ERR(task);
                goto err_rx_unbind;
        }
 
-       vif->task = task;
+       queue->task = task;
 
-       rtnl_lock();
-       if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
-               dev_set_mtu(vif->dev, ETH_DATA_LEN);
-       netdev_update_features(vif->dev);
-       netif_carrier_on(vif->dev);
-       if (netif_running(vif->dev))
-               xenvif_up(vif);
-       rtnl_unlock();
-
-       wake_up_process(vif->task);
+       wake_up_process(queue->task);
 
        return 0;
 
 err_rx_unbind:
-       unbind_from_irqhandler(vif->rx_irq, vif);
-       vif->rx_irq = 0;
+       unbind_from_irqhandler(queue->rx_irq, queue);
+       queue->rx_irq = 0;
 err_tx_unbind:
-       unbind_from_irqhandler(vif->tx_irq, vif);
-       vif->tx_irq = 0;
+       unbind_from_irqhandler(queue->tx_irq, queue);
+       queue->tx_irq = 0;
 err_unmap:
-       xenvif_unmap_frontend_rings(vif);
+       xenvif_unmap_frontend_rings(queue);
 err:
        module_put(THIS_MODULE);
        return err;
@@ -470,34 +558,53 @@ void xenvif_carrier_off(struct xenvif *vif)
 
 void xenvif_disconnect(struct xenvif *vif)
 {
+       struct xenvif_queue *queue = NULL;
+       unsigned int queue_index;
+
        if (netif_carrier_ok(vif->dev))
                xenvif_carrier_off(vif);
 
-       if (vif->task) {
-               kthread_stop(vif->task);
-               vif->task = NULL;
-       }
+       for (queue_index = 0; queue_index < vif->num_queues; ++queue_index) {
+               queue = &vif->queues[queue_index];
 
-       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);
+               if (queue->task) {
+                       kthread_stop(queue->task);
+                       queue->task = NULL;
                }
-               vif->tx_irq = 0;
+
+               if (queue->tx_irq) {
+                       if (queue->tx_irq == queue->rx_irq)
+                               unbind_from_irqhandler(queue->tx_irq, queue);
+                       else {
+                               unbind_from_irqhandler(queue->tx_irq, queue);
+                               unbind_from_irqhandler(queue->rx_irq, queue);
+                       }
+                       queue->tx_irq = 0;
+               }
+
+               xenvif_unmap_frontend_rings(queue);
        }
 
-       xenvif_unmap_frontend_rings(vif);
+
 }
 
 void xenvif_free(struct xenvif *vif)
 {
-       netif_napi_del(&vif->napi);
+       struct xenvif_queue *queue = NULL;
+       unsigned int queue_index;
 
        unregister_netdev(vif->dev);
 
-       vfree(vif->grant_copy_op);
+       for (queue_index = 0; queue_index < vif->num_queues; ++queue_index) {
+               queue = &vif->queues[queue_index];
+               netif_napi_del(&queue->napi);
+       }
+
+       /* Free the array of queues */
+       vif->num_queues = 0;
+       vfree(vif->queues);
+       vif->queues = NULL;
+
        free_netdev(vif->dev);
 
        module_put(THIS_MODULE);
diff --git a/drivers/net/xen-netback/netback.c 
b/drivers/net/xen-netback/netback.c
index e5284bc..a32abd6 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -75,38 +75,38 @@ module_param(fatal_skb_slots, uint, 0444);
  * one or more merged tx requests, otherwise it is the continuation of
  * previous tx request.
  */
-static inline int pending_tx_is_head(struct xenvif *vif, RING_IDX idx)
+static inline int pending_tx_is_head(struct xenvif_queue *queue, RING_IDX idx)
 {
-       return vif->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
+       return queue->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
 }
 
-static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
+static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
                               u8 status);
 
-static void make_tx_response(struct xenvif *vif,
+static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
                             s8       st);
 
-static inline int tx_work_todo(struct xenvif *vif);
-static inline int rx_work_todo(struct xenvif *vif);
+static inline int tx_work_todo(struct xenvif_queue *queue);
+static inline int rx_work_todo(struct xenvif_queue *queue);
 
-static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
+static struct xen_netif_rx_response *make_rx_response(struct xenvif_queue 
*queue,
                                             u16      id,
                                             s8       st,
                                             u16      offset,
                                             u16      size,
                                             u16      flags);
 
-static inline unsigned long idx_to_pfn(struct xenvif *vif,
+static inline unsigned long idx_to_pfn(struct xenvif_queue *queue,
                                       u16 idx)
 {
-       return page_to_pfn(vif->mmap_pages[idx]);
+       return page_to_pfn(queue->mmap_pages[idx]);
 }
 
-static inline unsigned long idx_to_kaddr(struct xenvif *vif,
+static inline unsigned long idx_to_kaddr(struct xenvif_queue *queue,
                                         u16 idx)
 {
-       return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx));
+       return (unsigned long)pfn_to_kaddr(idx_to_pfn(queue, idx));
 }
 
 /* This is a miniumum size for the linear area to avoid lots of
@@ -131,30 +131,30 @@ static inline pending_ring_idx_t pending_index(unsigned i)
        return i & (MAX_PENDING_REQS-1);
 }
 
-static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
+static inline pending_ring_idx_t nr_pending_reqs(struct xenvif_queue *queue)
 {
        return MAX_PENDING_REQS -
-               vif->pending_prod + vif->pending_cons;
+               queue->pending_prod + queue->pending_cons;
 }
 
-bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed)
+bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue, int needed)
 {
        RING_IDX prod, cons;
 
        do {
-               prod = vif->rx.sring->req_prod;
-               cons = vif->rx.req_cons;
+               prod = queue->rx.sring->req_prod;
+               cons = queue->rx.req_cons;
 
                if (prod - cons >= needed)
                        return true;
 
-               vif->rx.sring->req_event = prod + 1;
+               queue->rx.sring->req_event = prod + 1;
 
                /* Make sure event is visible before we check prod
                 * again.
                 */
                mb();
-       } while (vif->rx.sring->req_prod != prod);
+       } while (queue->rx.sring->req_prod != prod);
 
        return false;
 }
@@ -208,13 +208,13 @@ struct netrx_pending_operations {
        grant_ref_t copy_gref;
 };
 
-static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif,
+static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
                                                 struct 
netrx_pending_operations *npo)
 {
        struct xenvif_rx_meta *meta;
        struct xen_netif_rx_request *req;
 
-       req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
+       req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
 
        meta = npo->meta + npo->meta_prod++;
        meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
@@ -232,7 +232,7 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct 
xenvif *vif,
  * Set up the grant operations for this fragment. If it's a flipping
  * interface, we also set up the unmap request from here.
  */
-static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
+static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff 
*skb,
                                 struct netrx_pending_operations *npo,
                                 struct page *page, unsigned long size,
                                 unsigned long offset, int *head)
@@ -267,7 +267,7 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct 
sk_buff *skb,
                         */
                        BUG_ON(*head);
 
-                       meta = get_next_rx_buffer(vif, npo);
+                       meta = get_next_rx_buffer(queue, npo);
                }
 
                if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
@@ -281,7 +281,7 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct 
sk_buff *skb,
                copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
                copy_gop->source.offset = offset;
 
-               copy_gop->dest.domid = vif->domid;
+               copy_gop->dest.domid = queue->vif->domid;
                copy_gop->dest.offset = npo->copy_off;
                copy_gop->dest.u.ref = npo->copy_gref;
 
@@ -306,8 +306,8 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct 
sk_buff *skb,
                else
                        gso_type = XEN_NETIF_GSO_TYPE_NONE;
 
-               if (*head && ((1 << gso_type) & vif->gso_mask))
-                       vif->rx.req_cons++;
+               if (*head && ((1 << gso_type) & queue->vif->gso_mask))
+                       queue->rx.req_cons++;
 
                *head = 0; /* There must be something in this buffer now. */
 
@@ -327,7 +327,8 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct 
sk_buff *skb,
  * frontend-side LRO).
  */
 static int xenvif_gop_skb(struct sk_buff *skb,
-                         struct netrx_pending_operations *npo)
+                         struct netrx_pending_operations *npo,
+                         struct xenvif_queue *queue)
 {
        struct xenvif *vif = netdev_priv(skb->dev);
        int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -355,7 +356,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
 
        /* Set up a GSO prefix descriptor, if necessary */
        if ((1 << gso_type) & vif->gso_prefix_mask) {
-               req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
+               req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
                meta = npo->meta + npo->meta_prod++;
                meta->gso_type = gso_type;
                meta->gso_size = gso_size;
@@ -363,7 +364,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                meta->id = req->id;
        }
 
-       req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
+       req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
        meta = npo->meta + npo->meta_prod++;
 
        if ((1 << gso_type) & vif->gso_mask) {
@@ -387,13 +388,13 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                if (data + len > skb_tail_pointer(skb))
                        len = skb_tail_pointer(skb) - data;
 
-               xenvif_gop_frag_copy(vif, skb, npo,
+               xenvif_gop_frag_copy(queue, skb, npo,
                                     virt_to_page(data), len, offset, &head);
                data += len;
        }
 
        for (i = 0; i < nr_frags; i++) {
-               xenvif_gop_frag_copy(vif, skb, npo,
+               xenvif_gop_frag_copy(queue, skb, npo,
                                     skb_frag_page(&skb_shinfo(skb)->frags[i]),
                                     skb_frag_size(&skb_shinfo(skb)->frags[i]),
                                     skb_shinfo(skb)->frags[i].page_offset,
@@ -429,7 +430,7 @@ static int xenvif_check_gop(struct xenvif *vif, int 
nr_meta_slots,
        return status;
 }
 
-static void xenvif_add_frag_responses(struct xenvif *vif, int status,
+static void xenvif_add_frag_responses(struct xenvif_queue *queue, int status,
                                      struct xenvif_rx_meta *meta,
                                      int nr_meta_slots)
 {
@@ -450,7 +451,7 @@ static void xenvif_add_frag_responses(struct xenvif *vif, 
int status,
                        flags = XEN_NETRXF_more_data;
 
                offset = 0;
-               make_rx_response(vif, meta[i].id, status, offset,
+               make_rx_response(queue, meta[i].id, status, offset,
                                 meta[i].size, flags);
        }
 }
@@ -459,12 +460,12 @@ struct skb_cb_overlay {
        int meta_slots_used;
 };
 
-void xenvif_kick_thread(struct xenvif *vif)
+void xenvif_kick_thread(struct xenvif_queue *queue)
 {
-       wake_up(&vif->wq);
+       wake_up(&queue->wq);
 }
 
-static void xenvif_rx_action(struct xenvif *vif)
+static void xenvif_rx_action(struct xenvif_queue *queue)
 {
        s8 status;
        u16 flags;
@@ -478,13 +479,13 @@ static void xenvif_rx_action(struct xenvif *vif)
        bool need_to_notify = false;
 
        struct netrx_pending_operations npo = {
-               .copy  = vif->grant_copy_op,
-               .meta  = vif->meta,
+               .copy  = queue->grant_copy_op,
+               .meta  = queue->meta,
        };
 
        skb_queue_head_init(&rxq);
 
-       while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) {
+       while ((skb = skb_dequeue(&queue->rx_queue)) != NULL) {
                RING_IDX max_slots_needed;
                int i;
 
@@ -505,41 +506,41 @@ static void xenvif_rx_action(struct xenvif *vif)
                        max_slots_needed++;
 
                /* If the skb may not fit then bail out now */
-               if (!xenvif_rx_ring_slots_available(vif, max_slots_needed)) {
-                       skb_queue_head(&vif->rx_queue, skb);
+               if (!xenvif_rx_ring_slots_available(queue, max_slots_needed)) {
+                       skb_queue_head(&queue->rx_queue, skb);
                        need_to_notify = true;
-                       vif->rx_last_skb_slots = max_slots_needed;
+                       queue->rx_last_skb_slots = max_slots_needed;
                        break;
                } else
-                       vif->rx_last_skb_slots = 0;
+                       queue->rx_last_skb_slots = 0;
 
                sco = (struct skb_cb_overlay *)skb->cb;
-               sco->meta_slots_used = xenvif_gop_skb(skb, &npo);
+               sco->meta_slots_used = xenvif_gop_skb(skb, &npo, queue);
                BUG_ON(sco->meta_slots_used > max_slots_needed);
 
                __skb_queue_tail(&rxq, skb);
        }
 
-       BUG_ON(npo.meta_prod > ARRAY_SIZE(vif->meta));
+       BUG_ON(npo.meta_prod > ARRAY_SIZE(queue->meta));
 
        if (!npo.copy_prod)
                goto done;
 
        BUG_ON(npo.copy_prod > MAX_GRANT_COPY_OPS);
-       gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod);
+       gnttab_batch_copy(queue->grant_copy_op, npo.copy_prod);
 
        while ((skb = __skb_dequeue(&rxq)) != NULL) {
                sco = (struct skb_cb_overlay *)skb->cb;
 
-               if ((1 << vif->meta[npo.meta_cons].gso_type) &
-                   vif->gso_prefix_mask) {
-                       resp = RING_GET_RESPONSE(&vif->rx,
-                                                vif->rx.rsp_prod_pvt++);
+               if ((1 << queue->meta[npo.meta_cons].gso_type) &
+                   queue->vif->gso_prefix_mask) {
+                       resp = RING_GET_RESPONSE(&queue->rx,
+                                                queue->rx.rsp_prod_pvt++);
 
                        resp->flags = XEN_NETRXF_gso_prefix | 
XEN_NETRXF_more_data;
 
-                       resp->offset = vif->meta[npo.meta_cons].gso_size;
-                       resp->id = vif->meta[npo.meta_cons].id;
+                       resp->offset = queue->meta[npo.meta_cons].gso_size;
+                       resp->id = queue->meta[npo.meta_cons].id;
                        resp->status = sco->meta_slots_used;
 
                        npo.meta_cons++;
@@ -547,10 +548,10 @@ static void xenvif_rx_action(struct xenvif *vif)
                }
 
 
-               vif->dev->stats.tx_bytes += skb->len;
-               vif->dev->stats.tx_packets++;
+               queue->stats.tx_bytes += skb->len;
+               queue->stats.tx_packets++;
 
-               status = xenvif_check_gop(vif, sco->meta_slots_used, &npo);
+               status = xenvif_check_gop(queue->vif, sco->meta_slots_used, 
&npo);
 
                if (sco->meta_slots_used == 1)
                        flags = 0;
@@ -564,22 +565,22 @@ static void xenvif_rx_action(struct xenvif *vif)
                        flags |= XEN_NETRXF_data_validated;
 
                offset = 0;
-               resp = make_rx_response(vif, vif->meta[npo.meta_cons].id,
+               resp = make_rx_response(queue, queue->meta[npo.meta_cons].id,
                                        status, offset,
-                                       vif->meta[npo.meta_cons].size,
+                                       queue->meta[npo.meta_cons].size,
                                        flags);
 
-               if ((1 << vif->meta[npo.meta_cons].gso_type) &
-                   vif->gso_mask) {
+               if ((1 << queue->meta[npo.meta_cons].gso_type) &
+                   queue->vif->gso_mask) {
                        struct xen_netif_extra_info *gso =
                                (struct xen_netif_extra_info *)
-                               RING_GET_RESPONSE(&vif->rx,
-                                                 vif->rx.rsp_prod_pvt++);
+                               RING_GET_RESPONSE(&queue->rx,
+                                                 queue->rx.rsp_prod_pvt++);
 
                        resp->flags |= XEN_NETRXF_extra_info;
 
-                       gso->u.gso.type = vif->meta[npo.meta_cons].gso_type;
-                       gso->u.gso.size = vif->meta[npo.meta_cons].gso_size;
+                       gso->u.gso.type = queue->meta[npo.meta_cons].gso_type;
+                       gso->u.gso.size = queue->meta[npo.meta_cons].gso_size;
                        gso->u.gso.pad = 0;
                        gso->u.gso.features = 0;
 
@@ -587,11 +588,11 @@ static void xenvif_rx_action(struct xenvif *vif)
                        gso->flags = 0;
                }
 
-               xenvif_add_frag_responses(vif, status,
-                                         vif->meta + npo.meta_cons + 1,
+               xenvif_add_frag_responses(queue, status,
+                                         queue->meta + npo.meta_cons + 1,
                                          sco->meta_slots_used);
 
-               RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
+               RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->rx, ret);
 
                need_to_notify |= !!ret;
 
@@ -601,20 +602,20 @@ static void xenvif_rx_action(struct xenvif *vif)
 
 done:
        if (need_to_notify)
-               notify_remote_via_irq(vif->rx_irq);
+               notify_remote_via_irq(queue->rx_irq);
 }
 
-void xenvif_check_rx_xenvif(struct xenvif *vif)
+void xenvif_check_rx_xenvif(struct xenvif_queue *queue)
 {
        int more_to_do;
 
-       RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
+       RING_FINAL_CHECK_FOR_REQUESTS(&queue->tx, more_to_do);
 
        if (more_to_do)
-               napi_schedule(&vif->napi);
+               napi_schedule(&queue->napi);
 }
 
-static void tx_add_credit(struct xenvif *vif)
+static void tx_add_credit(struct xenvif_queue *queue)
 {
        unsigned long max_burst, max_credit;
 
@@ -622,37 +623,37 @@ static void tx_add_credit(struct xenvif *vif)
         * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
         * Otherwise the interface can seize up due to insufficient credit.
         */
-       max_burst = RING_GET_REQUEST(&vif->tx, vif->tx.req_cons)->size;
+       max_burst = RING_GET_REQUEST(&queue->tx, queue->tx.req_cons)->size;
        max_burst = min(max_burst, 131072UL);
-       max_burst = max(max_burst, vif->credit_bytes);
+       max_burst = max(max_burst, queue->credit_bytes);
 
        /* Take care that adding a new chunk of credit doesn't wrap to zero. */
-       max_credit = vif->remaining_credit + vif->credit_bytes;
-       if (max_credit < vif->remaining_credit)
+       max_credit = queue->remaining_credit + queue->credit_bytes;
+       if (max_credit < queue->remaining_credit)
                max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
 
-       vif->remaining_credit = min(max_credit, max_burst);
+       queue->remaining_credit = min(max_credit, max_burst);
 }
 
 static void tx_credit_callback(unsigned long data)
 {
-       struct xenvif *vif = (struct xenvif *)data;
-       tx_add_credit(vif);
-       xenvif_check_rx_xenvif(vif);
+       struct xenvif_queue *queue = (struct xenvif_queue *)data;
+       tx_add_credit(queue);
+       xenvif_check_rx_xenvif(queue);
 }
 
-static void xenvif_tx_err(struct xenvif *vif,
+static void xenvif_tx_err(struct xenvif_queue *queue,
                          struct xen_netif_tx_request *txp, RING_IDX end)
 {
-       RING_IDX cons = vif->tx.req_cons;
+       RING_IDX cons = queue->tx.req_cons;
 
        do {
-               make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+               make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
                if (cons == end)
                        break;
-               txp = RING_GET_REQUEST(&vif->tx, cons++);
+               txp = RING_GET_REQUEST(&queue->tx, cons++);
        } while (1);
-       vif->tx.req_cons = cons;
+       queue->tx.req_cons = cons;
 }
 
 static void xenvif_fatal_tx_err(struct xenvif *vif)
@@ -661,12 +662,12 @@ static void xenvif_fatal_tx_err(struct xenvif *vif)
        xenvif_carrier_off(vif);
 }
 
-static int xenvif_count_requests(struct xenvif *vif,
+static int xenvif_count_requests(struct xenvif_queue *queue,
                                 struct xen_netif_tx_request *first,
                                 struct xen_netif_tx_request *txp,
                                 int work_to_do)
 {
-       RING_IDX cons = vif->tx.req_cons;
+       RING_IDX cons = queue->tx.req_cons;
        int slots = 0;
        int drop_err = 0;
        int more_data;
@@ -678,10 +679,10 @@ static int xenvif_count_requests(struct xenvif *vif,
                struct xen_netif_tx_request dropped_tx = { 0 };
 
                if (slots >= work_to_do) {
-                       netdev_err(vif->dev,
+                       netdev_err(queue->vif->dev,
                                   "Asked for %d slots but exceeds this 
limit\n",
                                   work_to_do);
-                       xenvif_fatal_tx_err(vif);
+                       xenvif_fatal_tx_err(queue->vif);
                        return -ENODATA;
                }
 
@@ -689,10 +690,10 @@ static int xenvif_count_requests(struct xenvif *vif,
                 * considered malicious.
                 */
                if (unlikely(slots >= fatal_skb_slots)) {
-                       netdev_err(vif->dev,
+                       netdev_err(queue->vif->dev,
                                   "Malicious frontend using %d slots, 
threshold %u\n",
                                   slots, fatal_skb_slots);
-                       xenvif_fatal_tx_err(vif);
+                       xenvif_fatal_tx_err(queue->vif);
                        return -E2BIG;
                }
 
@@ -705,7 +706,7 @@ static int xenvif_count_requests(struct xenvif *vif,
                 */
                if (!drop_err && slots >= XEN_NETBK_LEGACY_SLOTS_MAX) {
                        if (net_ratelimit())
-                               netdev_dbg(vif->dev,
+                               netdev_dbg(queue->vif->dev,
                                           "Too many slots (%d) exceeding limit 
(%d), dropping packet\n",
                                           slots, XEN_NETBK_LEGACY_SLOTS_MAX);
                        drop_err = -E2BIG;
@@ -714,7 +715,7 @@ static int xenvif_count_requests(struct xenvif *vif,
                if (drop_err)
                        txp = &dropped_tx;
 
-               memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + slots),
+               memcpy(txp, RING_GET_REQUEST(&queue->tx, cons + slots),
                       sizeof(*txp));
 
                /* If the guest submitted a frame >= 64 KiB then
@@ -728,7 +729,7 @@ static int xenvif_count_requests(struct xenvif *vif,
                 */
                if (!drop_err && txp->size > first->size) {
                        if (net_ratelimit())
-                               netdev_dbg(vif->dev,
+                               netdev_dbg(queue->vif->dev,
                                           "Invalid tx request, slot size %u > 
remaining size %u\n",
                                           txp->size, first->size);
                        drop_err = -EIO;
@@ -738,9 +739,9 @@ static int xenvif_count_requests(struct xenvif *vif,
                slots++;
 
                if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-                       netdev_err(vif->dev, "Cross page boundary, txp->offset: 
%x, size: %u\n",
+                       netdev_err(queue->vif->dev, "Cross page boundary, 
txp->offset: %x, size: %u\n",
                                 txp->offset, txp->size);
-                       xenvif_fatal_tx_err(vif);
+                       xenvif_fatal_tx_err(queue->vif);
                        return -EINVAL;
                }
 
@@ -752,14 +753,14 @@ static int xenvif_count_requests(struct xenvif *vif,
        } while (more_data);
 
        if (drop_err) {
-               xenvif_tx_err(vif, first, cons + slots);
+               xenvif_tx_err(queue, first, cons + slots);
                return drop_err;
        }
 
        return slots;
 }
 
-static struct page *xenvif_alloc_page(struct xenvif *vif,
+static struct page *xenvif_alloc_page(struct xenvif_queue *queue,
                                      u16 pending_idx)
 {
        struct page *page;
@@ -767,12 +768,12 @@ static struct page *xenvif_alloc_page(struct xenvif *vif,
        page = alloc_page(GFP_ATOMIC|__GFP_COLD);
        if (!page)
                return NULL;
-       vif->mmap_pages[pending_idx] = page;
+       queue->mmap_pages[pending_idx] = page;
 
        return page;
 }
 
-static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif,
+static struct gnttab_copy *xenvif_get_requests(struct xenvif_queue *queue,
                                               struct sk_buff *skb,
                                               struct xen_netif_tx_request *txp,
                                               struct gnttab_copy *gop)
@@ -803,7 +804,7 @@ static struct gnttab_copy *xenvif_get_requests(struct 
xenvif *vif,
        for (shinfo->nr_frags = slot = start; slot < nr_slots;
             shinfo->nr_frags++) {
                struct pending_tx_info *pending_tx_info =
-                       vif->pending_tx_info;
+                       queue->pending_tx_info;
 
                page = alloc_page(GFP_ATOMIC|__GFP_COLD);
                if (!page)
@@ -815,7 +816,7 @@ static struct gnttab_copy *xenvif_get_requests(struct 
xenvif *vif,
                        gop->flags = GNTCOPY_source_gref;
 
                        gop->source.u.ref = txp->gref;
-                       gop->source.domid = vif->domid;
+                       gop->source.domid = queue->vif->domid;
                        gop->source.offset = txp->offset;
 
                        gop->dest.domid = DOMID_SELF;
@@ -840,9 +841,9 @@ static struct gnttab_copy *xenvif_get_requests(struct 
xenvif *vif,
                                gop->len = txp->size;
                                dst_offset += gop->len;
 
-                               index = pending_index(vif->pending_cons++);
+                               index = pending_index(queue->pending_cons++);
 
-                               pending_idx = vif->pending_ring[index];
+                               pending_idx = queue->pending_ring[index];
 
                                memcpy(&pending_tx_info[pending_idx].req, txp,
                                       sizeof(*txp));
@@ -851,7 +852,7 @@ static struct gnttab_copy *xenvif_get_requests(struct 
xenvif *vif,
                                 * fields for head tx req will be set
                                 * to correct values after the loop.
                                 */
-                               vif->mmap_pages[pending_idx] = (void *)(~0UL);
+                               queue->mmap_pages[pending_idx] = (void *)(~0UL);
                                pending_tx_info[pending_idx].head =
                                        INVALID_PENDING_RING_IDX;
 
@@ -871,7 +872,7 @@ static struct gnttab_copy *xenvif_get_requests(struct 
xenvif *vif,
                first->req.offset = 0;
                first->req.size = dst_offset;
                first->head = start_idx;
-               vif->mmap_pages[head_idx] = page;
+               queue->mmap_pages[head_idx] = page;
                frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx);
        }
 
@@ -881,18 +882,18 @@ static struct gnttab_copy *xenvif_get_requests(struct 
xenvif *vif,
 err:
        /* Unwind, freeing all pages and sending error responses. */
        while (shinfo->nr_frags-- > start) {
-               xenvif_idx_release(vif,
+               xenvif_idx_release(queue,
                                frag_get_pending_idx(&frags[shinfo->nr_frags]),
                                XEN_NETIF_RSP_ERROR);
        }
        /* The head too, if necessary. */
        if (start)
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+               xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);
 
        return NULL;
 }
 
-static int xenvif_tx_check_gop(struct xenvif *vif,
+static int xenvif_tx_check_gop(struct xenvif_queue *queue,
                               struct sk_buff *skb,
                               struct gnttab_copy **gopp)
 {
@@ -907,7 +908,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
        /* Check status of header. */
        err = gop->status;
        if (unlikely(err))
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+               xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);
 
        /* Skip first skb fragment if it is on same page as header fragment. */
        start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
@@ -917,7 +918,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
                pending_ring_idx_t head;
 
                pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
-               tx_info = &vif->pending_tx_info[pending_idx];
+               tx_info = &queue->pending_tx_info[pending_idx];
                head = tx_info->head;
 
                /* Check error status: if okay then remember grant handle. */
@@ -925,19 +926,19 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
                        newerr = (++gop)->status;
                        if (newerr)
                                break;
-                       peek = vif->pending_ring[pending_index(++head)];
-               } while (!pending_tx_is_head(vif, peek));
+                       peek = queue->pending_ring[pending_index(++head)];
+               } while (!pending_tx_is_head(queue, peek));
 
                if (likely(!newerr)) {
                        /* Had a previous error? Invalidate this fragment. */
                        if (unlikely(err))
-                               xenvif_idx_release(vif, pending_idx,
+                               xenvif_idx_release(queue, pending_idx,
                                                   XEN_NETIF_RSP_OKAY);
                        continue;
                }
 
                /* Error on this fragment: respond to client with an error. */
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+               xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);
 
                /* Not the first error? Preceding frags already invalidated. */
                if (err)
@@ -945,10 +946,10 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
 
                /* First error: invalidate header and preceding fragments. */
                pending_idx = *((u16 *)skb->data);
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+               xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_OKAY);
                for (j = start; j < i; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
-                       xenvif_idx_release(vif, pending_idx,
+                       xenvif_idx_release(queue, pending_idx,
                                           XEN_NETIF_RSP_OKAY);
                }
 
@@ -960,7 +961,7 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
        return err;
 }
 
-static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
+static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb)
 {
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        int nr_frags = shinfo->nr_frags;
@@ -974,46 +975,46 @@ static void xenvif_fill_frags(struct xenvif *vif, struct 
sk_buff *skb)
 
                pending_idx = frag_get_pending_idx(frag);
 
-               txp = &vif->pending_tx_info[pending_idx].req;
-               page = virt_to_page(idx_to_kaddr(vif, pending_idx));
+               txp = &queue->pending_tx_info[pending_idx].req;
+               page = virt_to_page(idx_to_kaddr(queue, pending_idx));
                __skb_fill_page_desc(skb, i, page, txp->offset, txp->size);
                skb->len += txp->size;
                skb->data_len += txp->size;
                skb->truesize += txp->size;
 
                /* Take an extra reference to offset xenvif_idx_release */
-               get_page(vif->mmap_pages[pending_idx]);
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+               get_page(queue->mmap_pages[pending_idx]);
+               xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_OKAY);
        }
 }
 
-static int xenvif_get_extras(struct xenvif *vif,
+static int xenvif_get_extras(struct xenvif_queue *queue,
                                struct xen_netif_extra_info *extras,
                                int work_to_do)
 {
        struct xen_netif_extra_info extra;
-       RING_IDX cons = vif->tx.req_cons;
+       RING_IDX cons = queue->tx.req_cons;
 
        do {
                if (unlikely(work_to_do-- <= 0)) {
-                       netdev_err(vif->dev, "Missing extra info\n");
-                       xenvif_fatal_tx_err(vif);
+                       netdev_err(queue->vif->dev, "Missing extra info\n");
+                       xenvif_fatal_tx_err(queue->vif);
                        return -EBADR;
                }
 
-               memcpy(&extra, RING_GET_REQUEST(&vif->tx, cons),
+               memcpy(&extra, RING_GET_REQUEST(&queue->tx, cons),
                       sizeof(extra));
                if (unlikely(!extra.type ||
                             extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-                       vif->tx.req_cons = ++cons;
-                       netdev_err(vif->dev,
+                       queue->tx.req_cons = ++cons;
+                       netdev_err(queue->vif->dev,
                                   "Invalid extra type: %d\n", extra.type);
-                       xenvif_fatal_tx_err(vif);
+                       xenvif_fatal_tx_err(queue->vif);
                        return -EINVAL;
                }
 
                memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-               vif->tx.req_cons = ++cons;
+               queue->tx.req_cons = ++cons;
        } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
 
        return work_to_do;
@@ -1048,7 +1049,7 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
        return 0;
 }
 
-static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
+static int checksum_setup(struct xenvif_queue *queue, struct sk_buff *skb)
 {
        bool recalculate_partial_csum = false;
 
@@ -1058,7 +1059,7 @@ static int checksum_setup(struct xenvif *vif, struct 
sk_buff *skb)
         * recalculate the partial checksum.
         */
        if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
-               vif->rx_gso_checksum_fixup++;
+               queue->stats.rx_gso_checksum_fixup++;
                skb->ip_summed = CHECKSUM_PARTIAL;
                recalculate_partial_csum = true;
        }
@@ -1070,31 +1071,31 @@ static int checksum_setup(struct xenvif *vif, struct 
sk_buff *skb)
        return skb_checksum_setup(skb, recalculate_partial_csum);
 }
 
-static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
+static bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size)
 {
        u64 now = get_jiffies_64();
-       u64 next_credit = vif->credit_window_start +
-               msecs_to_jiffies(vif->credit_usec / 1000);
+       u64 next_credit = queue->credit_window_start +
+               msecs_to_jiffies(queue->credit_usec / 1000);
 
        /* Timer could already be pending in rare cases. */
-       if (timer_pending(&vif->credit_timeout))
+       if (timer_pending(&queue->credit_timeout))
                return true;
 
        /* Passed the point where we can replenish credit? */
        if (time_after_eq64(now, next_credit)) {
-               vif->credit_window_start = now;
-               tx_add_credit(vif);
+               queue->credit_window_start = now;
+               tx_add_credit(queue);
        }
 
        /* Still too big to send right now? Set a callback. */
-       if (size > vif->remaining_credit) {
-               vif->credit_timeout.data     =
-                       (unsigned long)vif;
-               vif->credit_timeout.function =
+       if (size > queue->remaining_credit) {
+               queue->credit_timeout.data     =
+                       (unsigned long)queue;
+               queue->credit_timeout.function =
                        tx_credit_callback;
-               mod_timer(&vif->credit_timeout,
+               mod_timer(&queue->credit_timeout,
                          next_credit);
-               vif->credit_window_start = next_credit;
+               queue->credit_window_start = next_credit;
 
                return true;
        }
@@ -1102,15 +1103,15 @@ static bool tx_credit_exceeded(struct xenvif *vif, 
unsigned size)
        return false;
 }
 
-static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
+static unsigned xenvif_tx_build_gops(struct xenvif_queue *queue, int budget)
 {
-       struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop;
+       struct gnttab_copy *gop = queue->tx_copy_ops, *request_gop;
        struct sk_buff *skb;
        int ret;
 
-       while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
+       while ((nr_pending_reqs(queue) + XEN_NETBK_LEGACY_SLOTS_MAX
                < MAX_PENDING_REQS) &&
-              (skb_queue_len(&vif->tx_queue) < budget)) {
+              (skb_queue_len(&queue->tx_queue) < budget)) {
                struct xen_netif_tx_request txreq;
                struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
                struct page *page;
@@ -1121,69 +1122,69 @@ static unsigned xenvif_tx_build_gops(struct xenvif 
*vif, int budget)
                unsigned int data_len;
                pending_ring_idx_t index;
 
-               if (vif->tx.sring->req_prod - vif->tx.req_cons >
+               if (queue->tx.sring->req_prod - queue->tx.req_cons >
                    XEN_NETIF_TX_RING_SIZE) {
-                       netdev_err(vif->dev,
+                       netdev_err(queue->vif->dev,
                                   "Impossible number of requests. "
                                   "req_prod %d, req_cons %d, size %ld\n",
-                                  vif->tx.sring->req_prod, vif->tx.req_cons,
+                                  queue->tx.sring->req_prod, 
queue->tx.req_cons,
                                   XEN_NETIF_TX_RING_SIZE);
-                       xenvif_fatal_tx_err(vif);
+                       xenvif_fatal_tx_err(queue->vif);
                        continue;
                }
 
-               work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&vif->tx);
+               work_to_do = RING_HAS_UNCONSUMED_REQUESTS(&queue->tx);
                if (!work_to_do)
                        break;
 
-               idx = vif->tx.req_cons;
+               idx = queue->tx.req_cons;
                rmb(); /* Ensure that we see the request before we copy it. */
-               memcpy(&txreq, RING_GET_REQUEST(&vif->tx, idx), sizeof(txreq));
+               memcpy(&txreq, RING_GET_REQUEST(&queue->tx, idx), 
sizeof(txreq));
 
                /* Credit-based scheduling. */
-               if (txreq.size > vif->remaining_credit &&
-                   tx_credit_exceeded(vif, txreq.size))
+               if (txreq.size > queue->remaining_credit &&
+                   tx_credit_exceeded(queue, txreq.size))
                        break;
 
-               vif->remaining_credit -= txreq.size;
+               queue->remaining_credit -= txreq.size;
 
                work_to_do--;
-               vif->tx.req_cons = ++idx;
+               queue->tx.req_cons = ++idx;
 
                memset(extras, 0, sizeof(extras));
                if (txreq.flags & XEN_NETTXF_extra_info) {
-                       work_to_do = xenvif_get_extras(vif, extras,
+                       work_to_do = xenvif_get_extras(queue, extras,
                                                       work_to_do);
-                       idx = vif->tx.req_cons;
+                       idx = queue->tx.req_cons;
                        if (unlikely(work_to_do < 0))
                                break;
                }
 
-               ret = xenvif_count_requests(vif, &txreq, txfrags, work_to_do);
+               ret = xenvif_count_requests(queue, &txreq, txfrags, work_to_do);
                if (unlikely(ret < 0))
                        break;
 
                idx += ret;
 
                if (unlikely(txreq.size < ETH_HLEN)) {
-                       netdev_dbg(vif->dev,
+                       netdev_dbg(queue->vif->dev,
                                   "Bad packet size: %d\n", txreq.size);
-                       xenvif_tx_err(vif, &txreq, idx);
+                       xenvif_tx_err(queue, &txreq, idx);
                        break;
                }
 
                /* No crossing a page as the payload mustn't fragment. */
                if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-                       netdev_err(vif->dev,
+                       netdev_err(queue->vif->dev,
                                   "txreq.offset: %x, size: %u, end: %lu\n",
                                   txreq.offset, txreq.size,
                                   (txreq.offset&~PAGE_MASK) + txreq.size);
-                       xenvif_fatal_tx_err(vif);
+                       xenvif_fatal_tx_err(queue->vif);
                        break;
                }
 
-               index = pending_index(vif->pending_cons);
-               pending_idx = vif->pending_ring[index];
+               index = pending_index(queue->pending_cons);
+               pending_idx = queue->pending_ring[index];
 
                data_len = (txreq.size > PKT_PROT_LEN &&
                            ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
@@ -1192,9 +1193,9 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, 
int budget)
                skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
                                GFP_ATOMIC | __GFP_NOWARN);
                if (unlikely(skb == NULL)) {
-                       netdev_dbg(vif->dev,
+                       netdev_dbg(queue->vif->dev,
                                   "Can't allocate a skb in start_xmit.\n");
-                       xenvif_tx_err(vif, &txreq, idx);
+                       xenvif_tx_err(queue, &txreq, idx);
                        break;
                }
 
@@ -1205,7 +1206,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, 
int budget)
                        struct xen_netif_extra_info *gso;
                        gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
 
-                       if (xenvif_set_skb_gso(vif, skb, gso)) {
+                       if (xenvif_set_skb_gso(queue->vif, skb, gso)) {
                                /* Failure in xenvif_set_skb_gso is fatal. */
                                kfree_skb(skb);
                                break;
@@ -1213,15 +1214,15 @@ static unsigned xenvif_tx_build_gops(struct xenvif 
*vif, int budget)
                }
 
                /* XXX could copy straight to head */
-               page = xenvif_alloc_page(vif, pending_idx);
+               page = xenvif_alloc_page(queue, pending_idx);
                if (!page) {
                        kfree_skb(skb);
-                       xenvif_tx_err(vif, &txreq, idx);
+                       xenvif_tx_err(queue, &txreq, idx);
                        break;
                }
 
                gop->source.u.ref = txreq.gref;
-               gop->source.domid = vif->domid;
+               gop->source.domid = queue->vif->domid;
                gop->source.offset = txreq.offset;
 
                gop->dest.u.gmfn = virt_to_mfn(page_address(page));
@@ -1233,9 +1234,9 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, 
int budget)
 
                gop++;
 
-               memcpy(&vif->pending_tx_info[pending_idx].req,
+               memcpy(&queue->pending_tx_info[pending_idx].req,
                       &txreq, sizeof(txreq));
-               vif->pending_tx_info[pending_idx].head = index;
+               queue->pending_tx_info[pending_idx].head = index;
                *((u16 *)skb->data) = pending_idx;
 
                __skb_put(skb, data_len);
@@ -1250,45 +1251,45 @@ static unsigned xenvif_tx_build_gops(struct xenvif 
*vif, int budget)
                                             INVALID_PENDING_IDX);
                }
 
-               vif->pending_cons++;
+               queue->pending_cons++;
 
-               request_gop = xenvif_get_requests(vif, skb, txfrags, gop);
+               request_gop = xenvif_get_requests(queue, skb, txfrags, gop);
                if (request_gop == NULL) {
                        kfree_skb(skb);
-                       xenvif_tx_err(vif, &txreq, idx);
+                       xenvif_tx_err(queue, &txreq, idx);
                        break;
                }
                gop = request_gop;
 
-               __skb_queue_tail(&vif->tx_queue, skb);
+               __skb_queue_tail(&queue->tx_queue, skb);
 
-               vif->tx.req_cons = idx;
+               queue->tx.req_cons = idx;
 
-               if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops))
+               if ((gop - queue->tx_copy_ops) >= 
ARRAY_SIZE(queue->tx_copy_ops))
                        break;
        }
 
-       return gop - vif->tx_copy_ops;
+       return gop - queue->tx_copy_ops;
 }
 
 
-static int xenvif_tx_submit(struct xenvif *vif)
+static int xenvif_tx_submit(struct xenvif_queue *queue)
 {
-       struct gnttab_copy *gop = vif->tx_copy_ops;
+       struct gnttab_copy *gop = queue->tx_copy_ops;
        struct sk_buff *skb;
        int work_done = 0;
 
-       while ((skb = __skb_dequeue(&vif->tx_queue)) != NULL) {
+       while ((skb = __skb_dequeue(&queue->tx_queue)) != NULL) {
                struct xen_netif_tx_request *txp;
                u16 pending_idx;
                unsigned data_len;
 
                pending_idx = *((u16 *)skb->data);
-               txp = &vif->pending_tx_info[pending_idx].req;
+               txp = &queue->pending_tx_info[pending_idx].req;
 
                /* Check the remap error code. */
-               if (unlikely(xenvif_tx_check_gop(vif, skb, &gop))) {
-                       netdev_dbg(vif->dev, "netback grant failed.\n");
+               if (unlikely(xenvif_tx_check_gop(queue, skb, &gop))) {
+                       netdev_dbg(queue->vif->dev, "netback grant failed.\n");
                        skb_shinfo(skb)->nr_frags = 0;
                        kfree_skb(skb);
                        continue;
@@ -1296,7 +1297,7 @@ static int xenvif_tx_submit(struct xenvif *vif)
 
                data_len = skb->len;
                memcpy(skb->data,
-                      (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset),
+                      (void *)(idx_to_kaddr(queue, pending_idx)|txp->offset),
                       data_len);
                if (data_len < txp->size) {
                        /* Append the packet payload as a fragment. */
@@ -1304,7 +1305,7 @@ static int xenvif_tx_submit(struct xenvif *vif)
                        txp->size -= data_len;
                } else {
                        /* Schedule a response immediately. */
-                       xenvif_idx_release(vif, pending_idx,
+                       xenvif_idx_release(queue, pending_idx,
                                           XEN_NETIF_RSP_OKAY);
                }
 
@@ -1313,19 +1314,19 @@ static int xenvif_tx_submit(struct xenvif *vif)
                else if (txp->flags & XEN_NETTXF_data_validated)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-               xenvif_fill_frags(vif, skb);
+               xenvif_fill_frags(queue, skb);
 
                if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) {
                        int target = min_t(int, skb->len, PKT_PROT_LEN);
                        __pskb_pull_tail(skb, target - skb_headlen(skb));
                }
 
-               skb->dev      = vif->dev;
+               skb->dev      = queue->vif->dev;
                skb->protocol = eth_type_trans(skb, skb->dev);
                skb_reset_network_header(skb);
 
-               if (checksum_setup(vif, skb)) {
-                       netdev_dbg(vif->dev,
+               if (checksum_setup(queue, skb)) {
+                       netdev_dbg(queue->vif->dev,
                                   "Can't setup checksum in net_tx_action\n");
                        kfree_skb(skb);
                        continue;
@@ -1347,8 +1348,8 @@ static int xenvif_tx_submit(struct xenvif *vif)
                                DIV_ROUND_UP(skb->len - hdrlen, mss);
                }
 
-               vif->dev->stats.rx_bytes += skb->len;
-               vif->dev->stats.rx_packets++;
+               queue->stats.rx_bytes += skb->len;
+               queue->stats.rx_packets++;
 
                work_done++;
 
@@ -1359,53 +1360,53 @@ static int xenvif_tx_submit(struct xenvif *vif)
 }
 
 /* Called after netfront has transmitted */
-int xenvif_tx_action(struct xenvif *vif, int budget)
+int xenvif_tx_action(struct xenvif_queue *queue, int budget)
 {
        unsigned nr_gops;
        int work_done;
 
-       if (unlikely(!tx_work_todo(vif)))
+       if (unlikely(!tx_work_todo(queue)))
                return 0;
 
-       nr_gops = xenvif_tx_build_gops(vif, budget);
+       nr_gops = xenvif_tx_build_gops(queue, budget);
 
        if (nr_gops == 0)
                return 0;
 
-       gnttab_batch_copy(vif->tx_copy_ops, nr_gops);
+       gnttab_batch_copy(queue->tx_copy_ops, nr_gops);
 
-       work_done = xenvif_tx_submit(vif);
+       work_done = xenvif_tx_submit(queue);
 
        return work_done;
 }
 
-static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
+static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
                               u8 status)
 {
        struct pending_tx_info *pending_tx_info;
        pending_ring_idx_t head;
        u16 peek; /* peek into next tx request */
 
-       BUG_ON(vif->mmap_pages[pending_idx] == (void *)(~0UL));
+       BUG_ON(queue->mmap_pages[pending_idx] == (void *)(~0UL));
 
        /* Already complete? */
-       if (vif->mmap_pages[pending_idx] == NULL)
+       if (queue->mmap_pages[pending_idx] == NULL)
                return;
 
-       pending_tx_info = &vif->pending_tx_info[pending_idx];
+       pending_tx_info = &queue->pending_tx_info[pending_idx];
 
        head = pending_tx_info->head;
 
-       BUG_ON(!pending_tx_is_head(vif, head));
-       BUG_ON(vif->pending_ring[pending_index(head)] != pending_idx);
+       BUG_ON(!pending_tx_is_head(queue, head));
+       BUG_ON(queue->pending_ring[pending_index(head)] != pending_idx);
 
        do {
                pending_ring_idx_t index;
                pending_ring_idx_t idx = pending_index(head);
-               u16 info_idx = vif->pending_ring[idx];
+               u16 info_idx = queue->pending_ring[idx];
 
-               pending_tx_info = &vif->pending_tx_info[info_idx];
-               make_tx_response(vif, &pending_tx_info->req, status);
+               pending_tx_info = &queue->pending_tx_info[info_idx];
+               make_tx_response(queue, &pending_tx_info->req, status);
 
                /* Setting any number other than
                 * INVALID_PENDING_RING_IDX indicates this slot is
@@ -1413,50 +1414,50 @@ static void xenvif_idx_release(struct xenvif *vif, u16 
pending_idx,
                 */
                pending_tx_info->head = 0;
 
-               index = pending_index(vif->pending_prod++);
-               vif->pending_ring[index] = vif->pending_ring[info_idx];
+               index = pending_index(queue->pending_prod++);
+               queue->pending_ring[index] = queue->pending_ring[info_idx];
 
-               peek = vif->pending_ring[pending_index(++head)];
+               peek = queue->pending_ring[pending_index(++head)];
 
-       } while (!pending_tx_is_head(vif, peek));
+       } while (!pending_tx_is_head(queue, peek));
 
-       put_page(vif->mmap_pages[pending_idx]);
-       vif->mmap_pages[pending_idx] = NULL;
+       put_page(queue->mmap_pages[pending_idx]);
+       queue->mmap_pages[pending_idx] = NULL;
 }
 
 
-static void make_tx_response(struct xenvif *vif,
+static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
                             s8       st)
 {
-       RING_IDX i = vif->tx.rsp_prod_pvt;
+       RING_IDX i = queue->tx.rsp_prod_pvt;
        struct xen_netif_tx_response *resp;
        int notify;
 
-       resp = RING_GET_RESPONSE(&vif->tx, i);
+       resp = RING_GET_RESPONSE(&queue->tx, i);
        resp->id     = txp->id;
        resp->status = st;
 
        if (txp->flags & XEN_NETTXF_extra_info)
-               RING_GET_RESPONSE(&vif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+               RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
 
-       vif->tx.rsp_prod_pvt = ++i;
-       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify);
+       queue->tx.rsp_prod_pvt = ++i;
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
        if (notify)
-               notify_remote_via_irq(vif->tx_irq);
+               notify_remote_via_irq(queue->tx_irq);
 }
 
-static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
+static struct xen_netif_rx_response *make_rx_response(struct xenvif_queue 
*queue,
                                             u16      id,
                                             s8       st,
                                             u16      offset,
                                             u16      size,
                                             u16      flags)
 {
-       RING_IDX i = vif->rx.rsp_prod_pvt;
+       RING_IDX i = queue->rx.rsp_prod_pvt;
        struct xen_netif_rx_response *resp;
 
-       resp = RING_GET_RESPONSE(&vif->rx, i);
+       resp = RING_GET_RESPONSE(&queue->rx, i);
        resp->offset     = offset;
        resp->flags      = flags;
        resp->id         = id;
@@ -1464,39 +1465,39 @@ static struct xen_netif_rx_response 
*make_rx_response(struct xenvif *vif,
        if (st < 0)
                resp->status = (s16)st;
 
-       vif->rx.rsp_prod_pvt = ++i;
+       queue->rx.rsp_prod_pvt = ++i;
 
        return resp;
 }
 
-static inline int rx_work_todo(struct xenvif *vif)
+static inline int rx_work_todo(struct xenvif_queue *queue)
 {
-       return !skb_queue_empty(&vif->rx_queue) &&
-              xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots);
+       return !skb_queue_empty(&queue->rx_queue) &&
+              xenvif_rx_ring_slots_available(queue, queue->rx_last_skb_slots);
 }
 
-static inline int tx_work_todo(struct xenvif *vif)
+static inline int tx_work_todo(struct xenvif_queue *queue)
 {
 
-       if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) &&
-           (nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
+       if (likely(RING_HAS_UNCONSUMED_REQUESTS(&queue->tx)) &&
+           (nr_pending_reqs(queue) + XEN_NETBK_LEGACY_SLOTS_MAX
             < MAX_PENDING_REQS))
                return 1;
 
        return 0;
 }
 
-void xenvif_unmap_frontend_rings(struct xenvif *vif)
+void xenvif_unmap_frontend_rings(struct xenvif_queue *queue)
 {
-       if (vif->tx.sring)
-               xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
-                                       vif->tx.sring);
-       if (vif->rx.sring)
-               xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
-                                       vif->rx.sring);
+       if (queue->tx.sring)
+               xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif),
+                                       queue->tx.sring);
+       if (queue->rx.sring)
+               xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif),
+                                       queue->rx.sring);
 }
 
-int xenvif_map_frontend_rings(struct xenvif *vif,
+int xenvif_map_frontend_rings(struct xenvif_queue *queue,
                              grant_ref_t tx_ring_ref,
                              grant_ref_t rx_ring_ref)
 {
@@ -1506,67 +1507,72 @@ int xenvif_map_frontend_rings(struct xenvif *vif,
 
        int err = -ENOMEM;
 
-       err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif),
+       err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
                                     tx_ring_ref, &addr);
        if (err)
                goto err;
 
        txs = (struct xen_netif_tx_sring *)addr;
-       BACK_RING_INIT(&vif->tx, txs, PAGE_SIZE);
+       BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE);
 
-       err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif),
+       err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),
                                     rx_ring_ref, &addr);
        if (err)
                goto err;
 
        rxs = (struct xen_netif_rx_sring *)addr;
-       BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE);
+       BACK_RING_INIT(&queue->rx, rxs, PAGE_SIZE);
 
        return 0;
 
 err:
-       xenvif_unmap_frontend_rings(vif);
+       xenvif_unmap_frontend_rings(queue);
        return err;
 }
 
-void xenvif_stop_queue(struct xenvif *vif)
+static inline void xenvif_wake_queue(struct xenvif_queue *queue)
 {
-       if (!vif->can_queue)
-               return;
+       struct net_device *dev = queue->vif->dev;
+       netif_tx_wake_queue(netdev_get_tx_queue(dev, queue->id));
+}
 
-       netif_stop_queue(vif->dev);
+static void xenvif_start_queue(struct xenvif_queue *queue)
+{
+       if (xenvif_schedulable(queue->vif))
+               xenvif_wake_queue(queue);
 }
 
-static void xenvif_start_queue(struct xenvif *vif)
+static int xenvif_queue_stopped(struct xenvif_queue *queue)
 {
-       if (xenvif_schedulable(vif))
-               netif_wake_queue(vif->dev);
+       struct net_device *dev = queue->vif->dev;
+       unsigned int id = queue->id;
+       return netif_tx_queue_stopped(netdev_get_tx_queue(dev, id));
 }
 
 int xenvif_kthread(void *data)
 {
-       struct xenvif *vif = data;
+       struct xenvif_queue *queue = data;
        struct sk_buff *skb;
 
        while (!kthread_should_stop()) {
-               wait_event_interruptible(vif->wq,
-                                        rx_work_todo(vif) ||
+               wait_event_interruptible(queue->wq,
+                                        rx_work_todo(queue) ||
                                         kthread_should_stop());
                if (kthread_should_stop())
                        break;
 
-               if (!skb_queue_empty(&vif->rx_queue))
-                       xenvif_rx_action(vif);
+               if (!skb_queue_empty(&queue->rx_queue))
+                       xenvif_rx_action(queue);
 
-               if (skb_queue_empty(&vif->rx_queue) &&
-                   netif_queue_stopped(vif->dev))
-                       xenvif_start_queue(vif);
+               if (skb_queue_empty(&queue->rx_queue) &&
+                   xenvif_queue_stopped(queue))
+                       xenvif_start_queue(queue);
 
                cond_resched();
        }
 
        /* Bin any remaining skbs */
-       while ((skb = skb_dequeue(&vif->rx_queue)) != NULL)
+       while ((skb = skb_dequeue(&queue->rx_queue)) != NULL)
                dev_kfree_skb(skb);
 
        return 0;
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 7a206cf..f23ea0a 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -19,6 +19,7 @@
 */
 
 #include "common.h"
+#include <linux/vmalloc.h>
 
 struct backend_info {
        struct xenbus_device *dev;
@@ -34,8 +35,9 @@ struct backend_info {
        u8 have_hotplug_status_watch:1;
 };
 
-static int connect_rings(struct backend_info *);
-static void connect(struct backend_info *);
+static int connect_rings(struct backend_info *be, struct xenvif_queue *queue);
+static void connect(struct backend_info *be);
+static int read_xenbus_vif_flags(struct backend_info *be);
 static void backend_create_xenvif(struct backend_info *be);
 static void unregister_hotplug_status_watch(struct backend_info *be);
 static void set_backend_state(struct backend_info *be,
@@ -485,10 +487,9 @@ static void connect(struct backend_info *be)
 {
        int err;
        struct xenbus_device *dev = be->dev;
-
-       err = connect_rings(be);
-       if (err)
-               return;
+       unsigned long credit_bytes, credit_usec;
+       unsigned int queue_index;
+       struct xenvif_queue *queue;
 
        err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
        if (err) {
@@ -496,9 +497,30 @@ static void connect(struct backend_info *be)
                return;
        }
 
-       xen_net_read_rate(dev, &be->vif->credit_bytes,
-                         &be->vif->credit_usec);
-       be->vif->remaining_credit = be->vif->credit_bytes;
+       xen_net_read_rate(dev, &credit_bytes, &credit_usec);
+       read_xenbus_vif_flags(be);
+
+       be->vif->num_queues = 1;
+       be->vif->queues = vzalloc(be->vif->num_queues *
+                       sizeof(struct xenvif_queue));
+
+       for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index) 
{
+               queue = &be->vif->queues[queue_index];
+               queue->vif = be->vif;
+               queue->id = queue_index;
+               snprintf(queue->name, sizeof(queue->name), "%s-q%u",
+                               be->vif->dev->name, queue->id);
+
+               xenvif_init_queue(queue);
+
+               queue->remaining_credit = credit_bytes;
+
+               err = connect_rings(be, queue);
+               if (err)
+                       goto err;
+       }
+
+       xenvif_carrier_on(be->vif);
 
        unregister_hotplug_status_watch(be);
        err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
@@ -507,18 +529,24 @@ static void connect(struct backend_info *be)
        if (!err)
                be->have_hotplug_status_watch = 1;
 
-       netif_wake_queue(be->vif->dev);
+       netif_tx_wake_all_queues(be->vif->dev);
+
+       return;
+
+err:
+       vfree(be->vif->queues);
+       be->vif->queues = NULL;
+       be->vif->num_queues = 0;
+       return;
 }
 
 
-static int connect_rings(struct backend_info *be)
+static int connect_rings(struct backend_info *be, struct xenvif_queue *queue)
 {
-       struct xenvif *vif = be->vif;
        struct xenbus_device *dev = be->dev;
        unsigned long tx_ring_ref, rx_ring_ref;
-       unsigned int tx_evtchn, rx_evtchn, rx_copy;
+       unsigned int tx_evtchn, rx_evtchn;
        int err;
-       int val;
 
        err = xenbus_gather(XBT_NIL, dev->otherend,
                            "tx-ring-ref", "%lu", &tx_ring_ref,
@@ -546,6 +574,27 @@ static int connect_rings(struct backend_info *be)
                rx_evtchn = tx_evtchn;
        }
 
+       /* Map the shared frame, irq etc. */
+       err = xenvif_connect(queue, tx_ring_ref, rx_ring_ref,
+                            tx_evtchn, rx_evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err,
+                                "mapping shared-frames %lu/%lu port tx %u rx 
%u",
+                                tx_ring_ref, rx_ring_ref,
+                                tx_evtchn, rx_evtchn);
+               return err;
+       }
+
+       return 0;
+}
+
+static int read_xenbus_vif_flags(struct backend_info *be)
+{
+       struct xenvif *vif = be->vif;
+       struct xenbus_device *dev = be->dev;
+       unsigned int rx_copy;
+       int err, val;
+
        err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
                           &rx_copy);
        if (err == -ENOENT) {
@@ -621,16 +670,6 @@ static int connect_rings(struct backend_info *be)
                val = 0;
        vif->ipv6_csum = !!val;
 
-       /* Map the shared frame, irq etc. */
-       err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref,
-                            tx_evtchn, rx_evtchn);
-       if (err) {
-               xenbus_dev_fatal(dev, err,
-                                "mapping shared-frames %lu/%lu port tx %u rx 
%u",
-                                tx_ring_ref, rx_ring_ref,
-                                tx_evtchn, rx_evtchn);
-               return err;
-       }
        return 0;
 }
 
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.