qubes-linux-kernel/patches.xen/xen-netback-generalize
2011-04-19 22:09:59 +02:00

1318 lines
41 KiB
Plaintext

From: Dongxiao Xu <dongxiao.xu@intel.com>
Subject: [PATCH 1/3] Netback: Generalize static/global variables into 'struct xen_netbk'.
Patch-mainline: n/a
Put all the static/global variables in netback.c into xen_netback
structure. Do some preparations for the support of netback multiple
threads.
Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
jb: various cleanups
Acked-by: jbeulich@novell.com
--- head-2011-02-17.orig/drivers/xen/netback/common.h 2011-01-31 17:56:27.000000000 +0100
+++ head-2011-02-17/drivers/xen/netback/common.h 2011-02-17 10:33:48.000000000 +0100
@@ -219,4 +219,74 @@ static inline int netbk_can_sg(struct ne
return netif->can_sg;
}
+struct pending_tx_info {
+ netif_tx_request_t req;
+ netif_t *netif;
+};
+typedef unsigned int pending_ring_idx_t;
+
+struct netbk_rx_meta {
+ skb_frag_t frag;
+ int id;
+ u8 copy:1;
+};
+
+struct netbk_tx_pending_inuse {
+ struct list_head list;
+ unsigned long alloc_time;
+};
+
+#define MAX_PENDING_REQS (1U << CONFIG_XEN_NETDEV_TX_SHIFT)
+#define MAX_MFN_ALLOC 64
+
+struct xen_netbk {
+ struct tasklet_struct net_tx_tasklet;
+ struct tasklet_struct net_rx_tasklet;
+
+ struct sk_buff_head rx_queue;
+ struct sk_buff_head tx_queue;
+
+ struct timer_list net_timer;
+ struct timer_list tx_pending_timer;
+
+ pending_ring_idx_t pending_prod;
+ pending_ring_idx_t pending_cons;
+ pending_ring_idx_t dealloc_prod;
+ pending_ring_idx_t dealloc_cons;
+
+ struct list_head pending_inuse_head;
+ struct list_head schedule_list;
+
+ spinlock_t schedule_list_lock;
+ spinlock_t release_lock;
+
+ struct page **mmap_pages;
+
+ unsigned int alloc_index;
+
+ struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
+ struct netbk_tx_pending_inuse pending_inuse[MAX_PENDING_REQS];
+ struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+ struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+
+ grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
+ u16 pending_ring[MAX_PENDING_REQS];
+ u16 dealloc_ring[MAX_PENDING_REQS];
+
+ struct multicall_entry rx_mcl[NET_RX_RING_SIZE+3];
+ struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+ struct gnttab_transfer grant_trans_op[NET_RX_RING_SIZE];
+ struct gnttab_copy grant_copy_op[NET_RX_RING_SIZE];
+ DECLARE_BITMAP(rx_notify, NR_DYNIRQS);
+#if !defined(NR_DYNIRQS)
+# error
+#elif NR_DYNIRQS <= 0x10000
+ u16 notify_list[NET_RX_RING_SIZE];
+#else
+ int notify_list[NET_RX_RING_SIZE];
+#endif
+ struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+
+ unsigned long mfn_list[MAX_MFN_ALLOC];
+};
#endif /* __NETIF__BACKEND__COMMON_H__ */
--- head-2011-02-17.orig/drivers/xen/netback/netback.c 2011-01-03 13:30:15.000000000 +0100
+++ head-2011-02-17/drivers/xen/netback/netback.c 2011-03-01 11:53:28.000000000 +0100
@@ -36,6 +36,7 @@
#include "common.h"
#include <linux/if_vlan.h>
+#include <linux/vmalloc.h>
#include <net/tcp.h>
#include <xen/balloon.h>
#include <xen/interface/memory.h>
@@ -43,18 +44,12 @@
/*define NETBE_DEBUG_INTERRUPT*/
-struct netbk_rx_meta {
- skb_frag_t frag;
- int id;
- u8 copy:1;
-};
+static struct xen_netbk *__read_mostly xen_netbk;
+static const unsigned int netbk_nr_groups = 1;
-struct netbk_tx_pending_inuse {
- struct list_head list;
- unsigned long alloc_time;
-};
+#define GET_GROUP_INDEX(netif) (0)
-static void netif_idx_release(u16 pending_idx);
+static void netif_idx_release(struct xen_netbk *, u16 pending_idx);
static void make_tx_response(netif_t *netif,
netif_tx_request_t *txp,
s8 st);
@@ -65,47 +60,56 @@ static netif_rx_response_t *make_rx_resp
u16 size,
u16 flags);
-static void net_tx_action(unsigned long unused);
-static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
-
-static void net_rx_action(unsigned long unused);
-static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
-
-static struct timer_list net_timer;
-static struct timer_list netbk_tx_pending_timer;
+static void net_tx_action(unsigned long group);
+static void net_rx_action(unsigned long group);
-#define MAX_PENDING_REQS (1U << CONFIG_XEN_NETDEV_TX_SHIFT)
-
-static struct sk_buff_head rx_queue;
-
-static struct page **mmap_pages;
-static inline unsigned long idx_to_pfn(unsigned int idx)
+static inline unsigned long idx_to_pfn(struct xen_netbk *netbk, unsigned int idx)
{
- return page_to_pfn(mmap_pages[idx]);
+ return page_to_pfn(netbk->mmap_pages[idx]);
}
-static inline unsigned long idx_to_kaddr(unsigned int idx)
+static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk, unsigned int idx)
{
- return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx));
+ return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
}
/* extra field used in struct page */
-static inline void netif_set_page_index(struct page *pg, unsigned int index)
+union page_ext {
+ struct {
+#if BITS_PER_LONG < 64
+#define GROUP_WIDTH (BITS_PER_LONG - CONFIG_XEN_NETDEV_TX_SHIFT)
+#define MAX_GROUPS ((1U << GROUP_WIDTH) - 1)
+ unsigned int grp:GROUP_WIDTH;
+ unsigned int idx:CONFIG_XEN_NETDEV_TX_SHIFT;
+#else
+#define MAX_GROUPS UINT_MAX
+ unsigned int grp, idx;
+#endif
+ } e;
+ void *mapping;
+};
+
+static inline void netif_set_page_ext(struct page *pg, unsigned int group,
+ unsigned int idx)
{
- *(unsigned long *)&pg->mapping = index;
+ union page_ext ext = { .e = { .grp = group + 1, .idx = idx } };
+
+ BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
+ pg->mapping = ext.mapping;
}
-static inline int netif_page_index(struct page *pg)
+static inline unsigned int netif_page_group(const struct page *pg)
{
- unsigned long idx = (unsigned long)pg->mapping;
+ union page_ext ext = { .mapping = pg->mapping };
- if (!PageForeign(pg))
- return -1;
+ return ext.e.grp - 1;
+}
- if ((idx >= MAX_PENDING_REQS) || (mmap_pages[idx] != pg))
- return -1;
+static inline unsigned int netif_page_index(const struct page *pg)
+{
+ union page_ext ext = { .mapping = pg->mapping };
- return idx;
+ return ext.e.idx;
}
/*
@@ -117,36 +121,13 @@ static inline int netif_page_index(struc
sizeof(struct iphdr) + MAX_IPOPTLEN + \
sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
-static struct pending_tx_info {
- netif_tx_request_t req;
- netif_t *netif;
-} pending_tx_info[MAX_PENDING_REQS];
-static u16 pending_ring[MAX_PENDING_REQS];
-typedef unsigned int PEND_RING_IDX;
#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
-static PEND_RING_IDX pending_prod, pending_cons;
-#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
-
-/* Freed TX SKBs get batched on this ring before return to pending_ring. */
-static u16 dealloc_ring[MAX_PENDING_REQS];
-static PEND_RING_IDX dealloc_prod, dealloc_cons;
-/* Doubly-linked list of in-use pending entries. */
-static struct netbk_tx_pending_inuse pending_inuse[MAX_PENDING_REQS];
-static LIST_HEAD(pending_inuse_head);
-
-static struct sk_buff_head tx_queue;
-
-static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
-static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS];
-static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS];
-
-static struct list_head net_schedule_list;
-static spinlock_t net_schedule_list_lock;
-
-#define MAX_MFN_ALLOC 64
-static unsigned long mfn_list[MAX_MFN_ALLOC];
-static unsigned int alloc_index = 0;
+static inline pending_ring_idx_t nr_pending_reqs(const struct xen_netbk *netbk)
+{
+ return MAX_PENDING_REQS -
+ netbk->pending_prod + netbk->pending_cons;
+}
/* Setting this allows the safe use of this driver without netloop. */
static int MODPARM_copy_skb = 1;
@@ -158,13 +139,13 @@ MODULE_PARM_DESC(permute_returns, "Rando
int netbk_copy_skb_mode;
-static inline unsigned long alloc_mfn(void)
+static inline unsigned long alloc_mfn(struct xen_netbk *netbk)
{
- BUG_ON(alloc_index == 0);
- return mfn_list[--alloc_index];
+ BUG_ON(netbk->alloc_index == 0);
+ return netbk->mfn_list[--netbk->alloc_index];
}
-static int check_mfn(int nr)
+static int check_mfn(struct xen_netbk *netbk, unsigned int nr)
{
struct xen_memory_reservation reservation = {
.extent_order = 0,
@@ -172,24 +153,27 @@ static int check_mfn(int nr)
};
int rc;
- if (likely(alloc_index >= nr))
+ if (likely(netbk->alloc_index >= nr))
return 0;
- set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
- reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
+ set_xen_guest_handle(reservation.extent_start,
+ netbk->mfn_list + netbk->alloc_index);
+ reservation.nr_extents = MAX_MFN_ALLOC - netbk->alloc_index;
rc = HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation);
if (likely(rc > 0))
- alloc_index += rc;
+ netbk->alloc_index += rc;
- return alloc_index >= nr ? 0 : -ENOMEM;
+ return netbk->alloc_index >= nr ? 0 : -ENOMEM;
}
-static inline void maybe_schedule_tx_action(void)
+static inline void maybe_schedule_tx_action(unsigned int group)
{
+ struct xen_netbk *netbk = &xen_netbk[group];
+
smp_mb();
- if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
- !list_empty(&net_schedule_list))
- tasklet_schedule(&net_tx_tasklet);
+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&netbk->schedule_list))
+ tasklet_schedule(&netbk->net_tx_tasklet);
}
static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
@@ -298,6 +282,7 @@ static void tx_queue_callback(unsigned l
int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
+ struct xen_netbk *netbk;
BUG_ON(skb->dev != dev);
@@ -346,8 +331,9 @@ int netif_be_start_xmit(struct sk_buff *
}
}
- skb_queue_tail(&rx_queue, skb);
- tasklet_schedule(&net_rx_tasklet);
+ netbk = &xen_netbk[GET_GROUP_INDEX(netif)];
+ skb_queue_tail(&netbk->rx_queue, skb);
+ tasklet_schedule(&netbk->net_rx_tasklet);
return NETDEV_TX_OK;
@@ -402,19 +388,29 @@ static u16 netbk_gop_frag(netif_t *netif
multicall_entry_t *mcl;
netif_rx_request_t *req;
unsigned long old_mfn, new_mfn;
- int idx = netif_page_index(page);
+ struct xen_netbk *netbk = &xen_netbk[GET_GROUP_INDEX(netif)];
old_mfn = virt_to_mfn(page_address(page));
req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
if (netif->copying_receiver) {
+ unsigned int group, idx;
+
/* The fragment needs to be copied rather than
flipped. */
meta->copy = 1;
copy_gop = npo->copy + npo->copy_prod++;
copy_gop->flags = GNTCOPY_dest_gref;
- if (idx > -1) {
- struct pending_tx_info *src_pend = &pending_tx_info[idx];
+ if (PageForeign(page) &&
+ page->mapping != NULL &&
+ (idx = netif_page_index(page)) < MAX_PENDING_REQS &&
+ (group = netif_page_group(page)) < netbk_nr_groups) {
+ struct pending_tx_info *src_pend;
+
+ netbk = &xen_netbk[group];
+ BUG_ON(netbk->mmap_pages[idx] != page);
+ src_pend = &netbk->pending_tx_info[idx];
+ BUG_ON(group != GET_GROUP_INDEX(src_pend->netif));
copy_gop->source.domid = src_pend->netif->domid;
copy_gop->source.u.ref = src_pend->req.gref;
copy_gop->flags |= GNTCOPY_source_gref;
@@ -430,7 +426,7 @@ static u16 netbk_gop_frag(netif_t *netif
} else {
meta->copy = 0;
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
- new_mfn = alloc_mfn();
+ new_mfn = alloc_mfn(netbk);
/*
* Set the new P2M table entry before
@@ -570,7 +566,7 @@ static void netbk_add_frag_responses(net
}
}
-static void net_rx_action(unsigned long unused)
+static void net_rx_action(unsigned long group)
{
netif_t *netif = NULL;
s8 status;
@@ -584,47 +580,33 @@ static void net_rx_action(unsigned long
int nr_frags;
int count;
unsigned long offset;
-
- /*
- * Putting hundreds of bytes on the stack is considered rude.
- * Static works because a tasklet can only be on one CPU at any time.
- */
- static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+3];
- static mmu_update_t rx_mmu[NET_RX_RING_SIZE];
- static gnttab_transfer_t grant_trans_op[NET_RX_RING_SIZE];
- static gnttab_copy_t grant_copy_op[NET_RX_RING_SIZE];
- static DECLARE_BITMAP(rx_notify, NR_DYNIRQS);
-#if NR_DYNIRQS <= 0x10000
- static u16 notify_list[NET_RX_RING_SIZE];
-#else
- static int notify_list[NET_RX_RING_SIZE];
-#endif
- static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+ struct xen_netbk *netbk = &xen_netbk[group];
struct netrx_pending_operations npo = {
- mmu: rx_mmu,
- trans: grant_trans_op,
- copy: grant_copy_op,
- mcl: rx_mcl,
- meta: meta};
+ .mmu = netbk->rx_mmu,
+ .trans = netbk->grant_trans_op,
+ .copy = netbk->grant_copy_op,
+ .mcl = netbk->rx_mcl,
+ .meta = netbk->meta,
+ };
skb_queue_head_init(&rxq);
count = 0;
- while ((skb = skb_dequeue(&rx_queue)) != NULL) {
+ while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
nr_frags = skb_shinfo(skb)->nr_frags;
*(int *)skb->cb = nr_frags;
if (!xen_feature(XENFEAT_auto_translated_physmap) &&
!((netif_t *)netdev_priv(skb->dev))->copying_receiver &&
- check_mfn(nr_frags + 1)) {
+ check_mfn(netbk, nr_frags + 1)) {
/* Memory squeeze? Back off for an arbitrary while. */
if ( net_ratelimit() )
WPRINTK("Memory squeeze in netback "
"driver.\n");
- mod_timer(&net_timer, jiffies + HZ);
- skb_queue_head(&rx_queue, skb);
+ mod_timer(&netbk->net_timer, jiffies + HZ);
+ skb_queue_head(&netbk->rx_queue, skb);
break;
}
@@ -639,39 +621,39 @@ static void net_rx_action(unsigned long
break;
}
- BUG_ON(npo.meta_prod > ARRAY_SIZE(meta));
+ BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
npo.mmu_mcl = npo.mcl_prod;
if (npo.mcl_prod) {
BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
- BUG_ON(npo.mmu_prod > ARRAY_SIZE(rx_mmu));
+ BUG_ON(npo.mmu_prod > ARRAY_SIZE(netbk->rx_mmu));
mcl = npo.mcl + npo.mcl_prod++;
BUG_ON(mcl[-1].op != __HYPERVISOR_update_va_mapping);
mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
mcl->op = __HYPERVISOR_mmu_update;
- mcl->args[0] = (unsigned long)rx_mmu;
+ mcl->args[0] = (unsigned long)netbk->rx_mmu;
mcl->args[1] = npo.mmu_prod;
mcl->args[2] = 0;
mcl->args[3] = DOMID_SELF;
}
if (npo.trans_prod) {
- BUG_ON(npo.trans_prod > ARRAY_SIZE(grant_trans_op));
+ BUG_ON(npo.trans_prod > ARRAY_SIZE(netbk->grant_trans_op));
mcl = npo.mcl + npo.mcl_prod++;
mcl->op = __HYPERVISOR_grant_table_op;
mcl->args[0] = GNTTABOP_transfer;
- mcl->args[1] = (unsigned long)grant_trans_op;
+ mcl->args[1] = (unsigned long)netbk->grant_trans_op;
mcl->args[2] = npo.trans_prod;
}
if (npo.copy_prod) {
- BUG_ON(npo.copy_prod > ARRAY_SIZE(grant_copy_op));
+ BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
mcl = npo.mcl + npo.mcl_prod++;
mcl->op = __HYPERVISOR_grant_table_op;
mcl->args[0] = GNTTABOP_copy;
- mcl->args[1] = (unsigned long)grant_copy_op;
+ mcl->args[1] = (unsigned long)netbk->grant_copy_op;
mcl->args[2] = npo.copy_prod;
}
@@ -679,7 +661,7 @@ static void net_rx_action(unsigned long
if (!npo.mcl_prod)
return;
- BUG_ON(npo.mcl_prod > ARRAY_SIZE(rx_mcl));
+ BUG_ON(npo.mcl_prod > ARRAY_SIZE(netbk->rx_mcl));
ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
BUG_ON(ret != 0);
@@ -705,13 +687,13 @@ static void net_rx_action(unsigned long
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->frag_list = NULL;
skb_shinfo(skb)->nr_frags = 0;
- netbk_free_pages(nr_frags, meta + npo.meta_cons + 1);
+ netbk_free_pages(nr_frags, netbk->meta + npo.meta_cons + 1);
}
skb->dev->stats.tx_bytes += skb->len;
skb->dev->stats.tx_packets++;
- id = meta[npo.meta_cons].id;
+ id = netbk->meta[npo.meta_cons].id;
flags = nr_frags ? NETRXF_more_data : 0;
switch (skb->ip_summed) {
@@ -723,14 +705,14 @@ static void net_rx_action(unsigned long
break;
}
- if (meta[npo.meta_cons].copy)
+ if (netbk->meta[npo.meta_cons].copy)
offset = 0;
else
offset = offset_in_page(skb->data);
resp = make_rx_response(netif, id, status, offset,
skb_headlen(skb), flags);
- if (meta[npo.meta_cons].frag.size) {
+ if (netbk->meta[npo.meta_cons].frag.size) {
struct netif_extra_info *gso =
(struct netif_extra_info *)
RING_GET_RESPONSE(&netif->rx,
@@ -738,7 +720,7 @@ static void net_rx_action(unsigned long
resp->flags |= NETRXF_extra_info;
- gso->u.gso.size = meta[npo.meta_cons].frag.size;
+ gso->u.gso.size = netbk->meta[npo.meta_cons].frag.size;
gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
gso->u.gso.pad = 0;
gso->u.gso.features = 0;
@@ -748,13 +730,13 @@ static void net_rx_action(unsigned long
}
netbk_add_frag_responses(netif, status,
- meta + npo.meta_cons + 1,
+ netbk->meta + npo.meta_cons + 1,
nr_frags);
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
irq = netif->irq - DYNIRQ_BASE;
- if (ret && !__test_and_set_bit(irq, rx_notify))
- notify_list[notify_nr++] = irq;
+ if (ret && !__test_and_set_bit(irq, netbk->rx_notify))
+ netbk->notify_list[notify_nr++] = irq;
if (netif_queue_stopped(netif->dev) &&
netif_schedulable(netif) &&
@@ -768,38 +750,39 @@ static void net_rx_action(unsigned long
}
if (notify_nr == 1) {
- irq = *notify_list;
- __clear_bit(irq, rx_notify);
+ irq = *netbk->notify_list;
+ __clear_bit(irq, netbk->rx_notify);
notify_remote_via_irq(irq + DYNIRQ_BASE);
} else {
for (count = ret = 0; ret < notify_nr; ++ret) {
- irq = notify_list[ret];
- __clear_bit(irq, rx_notify);
- if (!multi_notify_remote_via_irq(rx_mcl + count,
+ irq = netbk->notify_list[ret];
+ __clear_bit(irq, netbk->rx_notify);
+ if (!multi_notify_remote_via_irq(netbk->rx_mcl + count,
irq + DYNIRQ_BASE))
++count;
}
- if (HYPERVISOR_multicall(rx_mcl, count))
+ if (HYPERVISOR_multicall(netbk->rx_mcl, count))
BUG();
}
/* More work to do? */
- if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
- tasklet_schedule(&net_rx_tasklet);
+ if (!skb_queue_empty(&netbk->rx_queue) &&
+ !timer_pending(&netbk->net_timer))
+ tasklet_schedule(&netbk->net_rx_tasklet);
#if 0
else
xen_network_done_notify();
#endif
}
-static void net_alarm(unsigned long unused)
+static void net_alarm(unsigned long group)
{
- tasklet_schedule(&net_rx_tasklet);
+ tasklet_schedule(&xen_netbk[group].net_rx_tasklet);
}
-static void netbk_tx_pending_timeout(unsigned long unused)
+static void netbk_tx_pending_timeout(unsigned long group)
{
- tasklet_schedule(&net_tx_tasklet);
+ tasklet_schedule(&xen_netbk[group].net_tx_tasklet);
}
static int __on_net_schedule_list(netif_t *netif)
@@ -807,7 +790,7 @@ static int __on_net_schedule_list(netif_
return netif->list.next != NULL;
}
-/* Must be called with net_schedule_list_lock held. */
+/* Must be called with netbk->schedule_list_lock held. */
static void remove_from_net_schedule_list(netif_t *netif)
{
if (likely(__on_net_schedule_list(netif))) {
@@ -817,34 +800,35 @@ static void remove_from_net_schedule_lis
}
}
-static netif_t *poll_net_schedule_list(void)
+static netif_t *poll_net_schedule_list(struct xen_netbk *netbk)
{
netif_t *netif = NULL;
- spin_lock_irq(&net_schedule_list_lock);
- if (!list_empty(&net_schedule_list)) {
- netif = list_first_entry(&net_schedule_list, netif_t, list);
+ spin_lock_irq(&netbk->schedule_list_lock);
+ if (!list_empty(&netbk->schedule_list)) {
+ netif = list_first_entry(&netbk->schedule_list, netif_t, list);
netif_get(netif);
remove_from_net_schedule_list(netif);
}
- spin_unlock_irq(&net_schedule_list_lock);
+ spin_unlock_irq(&netbk->schedule_list_lock);
return netif;
}
static void add_to_net_schedule_list_tail(netif_t *netif)
{
+ struct xen_netbk *netbk = &xen_netbk[GET_GROUP_INDEX(netif)];
unsigned long flags;
if (__on_net_schedule_list(netif))
return;
- spin_lock_irqsave(&net_schedule_list_lock, flags);
+ spin_lock_irqsave(&netbk->schedule_list_lock, flags);
if (!__on_net_schedule_list(netif) &&
likely(netif_schedulable(netif))) {
- list_add_tail(&netif->list, &net_schedule_list);
+ list_add_tail(&netif->list, &netbk->schedule_list);
netif_get(netif);
}
- spin_unlock_irqrestore(&net_schedule_list_lock, flags);
+ spin_unlock_irqrestore(&netbk->schedule_list_lock, flags);
}
/*
@@ -867,15 +851,17 @@ void netif_schedule_work(netif_t *netif)
if (more_to_do) {
add_to_net_schedule_list_tail(netif);
- maybe_schedule_tx_action();
+ maybe_schedule_tx_action(GET_GROUP_INDEX(netif));
}
}
void netif_deschedule_work(netif_t *netif)
{
- spin_lock_irq(&net_schedule_list_lock);
+ struct xen_netbk *netbk = &xen_netbk[GET_GROUP_INDEX(netif)];
+
+ spin_lock_irq(&netbk->schedule_list_lock);
remove_from_net_schedule_list(netif);
- spin_unlock_irq(&net_schedule_list_lock);
+ spin_unlock_irq(&netbk->schedule_list_lock);
}
@@ -906,17 +892,19 @@ static void tx_credit_callback(unsigned
netif_schedule_work(netif);
}
-static inline int copy_pending_req(PEND_RING_IDX pending_idx)
+static inline int copy_pending_req(struct xen_netbk *netbk,
+ pending_ring_idx_t pending_idx)
{
- return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
- &mmap_pages[pending_idx]);
+ return gnttab_copy_grant_page(netbk->grant_tx_handle[pending_idx],
+ &netbk->mmap_pages[pending_idx]);
}
-static void permute_dealloc_ring(PEND_RING_IDX dc, PEND_RING_IDX dp)
+static void permute_dealloc_ring(u16 *dealloc_ring, pending_ring_idx_t dc,
+ pending_ring_idx_t dp)
{
static unsigned random_src = 0x12345678;
unsigned dst_offset;
- PEND_RING_IDX dest;
+ pending_ring_idx_t dest;
u16 tmp;
while (dc != dp) {
@@ -931,67 +919,73 @@ static void permute_dealloc_ring(PEND_RI
}
}
-inline static void net_tx_action_dealloc(void)
+inline static void net_tx_action_dealloc(struct xen_netbk *netbk)
{
struct netbk_tx_pending_inuse *inuse, *n;
gnttab_unmap_grant_ref_t *gop;
u16 pending_idx;
- PEND_RING_IDX dc, dp;
+ pending_ring_idx_t dc, dp;
netif_t *netif;
LIST_HEAD(list);
- dc = dealloc_cons;
- gop = tx_unmap_ops;
+ dc = netbk->dealloc_cons;
+ gop = netbk->tx_unmap_ops;
/*
* Free up any grants we have finished using
*/
do {
- dp = dealloc_prod;
+ dp = netbk->dealloc_prod;
/* Ensure we see all indices enqueued by netif_idx_release(). */
smp_rmb();
if (MODPARM_permute_returns)
- permute_dealloc_ring(dc, dp);
+ permute_dealloc_ring(netbk->dealloc_ring, dc, dp);
while (dc != dp) {
unsigned long pfn;
+ struct netbk_tx_pending_inuse *pending_inuse =
+ netbk->pending_inuse;
- pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
+ pending_idx = netbk->dealloc_ring[MASK_PEND_IDX(dc++)];
list_move_tail(&pending_inuse[pending_idx].list, &list);
- pfn = idx_to_pfn(pending_idx);
+ pfn = idx_to_pfn(netbk, pending_idx);
/* Already unmapped? */
if (!phys_to_machine_mapping_valid(pfn))
continue;
- gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
+ gnttab_set_unmap_op(gop, idx_to_kaddr(netbk, pending_idx),
GNTMAP_host_map,
- grant_tx_handle[pending_idx]);
+ netbk->grant_tx_handle[pending_idx]);
gop++;
}
- } while (dp != dealloc_prod);
+ } while (dp != netbk->dealloc_prod);
- dealloc_cons = dc;
+ netbk->dealloc_cons = dc;
if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
- tx_unmap_ops, gop - tx_unmap_ops))
+ netbk->tx_unmap_ops,
+ gop - netbk->tx_unmap_ops))
BUG();
/* Copy any entries that have been pending for too long. */
if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
- !list_empty(&pending_inuse_head)) {
- list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
+ !list_empty(&netbk->pending_inuse_head)) {
+ list_for_each_entry_safe(inuse, n, &netbk->pending_inuse_head, list) {
+ struct pending_tx_info *pending_tx_info
+ = netbk->pending_tx_info;
+
if (time_after(inuse->alloc_time + HZ / 2, jiffies))
break;
- pending_idx = inuse - pending_inuse;
+ pending_idx = inuse - netbk->pending_inuse;
pending_tx_info[pending_idx].netif->nr_copied_skbs++;
- switch (copy_pending_req(pending_idx)) {
+ switch (copy_pending_req(netbk, pending_idx)) {
case 0:
list_move_tail(&inuse->list, &list);
continue;
@@ -1007,17 +1001,20 @@ inline static void net_tx_action_dealloc
}
list_for_each_entry_safe(inuse, n, &list, list) {
- pending_idx = inuse - pending_inuse;
+ struct pending_tx_info *pending_tx_info =
+ netbk->pending_tx_info;
+ pending_idx = inuse - netbk->pending_inuse;
netif = pending_tx_info[pending_idx].netif;
make_tx_response(netif, &pending_tx_info[pending_idx].req,
NETIF_RSP_OKAY);
/* Ready for next use. */
- gnttab_reset_grant_page(mmap_pages[pending_idx]);
+ gnttab_reset_grant_page(netbk->mmap_pages[pending_idx]);
- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+ netbk->pending_ring[MASK_PEND_IDX(netbk->pending_prod++)] =
+ pending_idx;
netif_put(netif);
@@ -1094,9 +1091,14 @@ static gnttab_map_grant_ref_t *netbk_get
start = ((unsigned long)shinfo->frags[0].page == pending_idx);
for (i = start; i < shinfo->nr_frags; i++, txp++) {
- pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)];
+ struct xen_netbk *netbk = &xen_netbk[GET_GROUP_INDEX(netif)];
+ pending_ring_idx_t index = MASK_PEND_IDX(netbk->pending_cons++);
+ struct pending_tx_info *pending_tx_info =
+ netbk->pending_tx_info;
- gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
+ pending_idx = netbk->pending_ring[index];
+
+ gnttab_set_map_op(mop++, idx_to_kaddr(netbk, pending_idx),
GNTMAP_host_map | GNTMAP_readonly,
txp->gref, netif->domid);
@@ -1109,11 +1111,12 @@ static gnttab_map_grant_ref_t *netbk_get
return mop;
}
-static int netbk_tx_check_mop(struct sk_buff *skb,
- gnttab_map_grant_ref_t **mopp)
+static int netbk_tx_check_mop(struct xen_netbk *netbk, struct sk_buff *skb,
+ gnttab_map_grant_ref_t **mopp)
{
gnttab_map_grant_ref_t *mop = *mopp;
int pending_idx = *((u16 *)skb->data);
+ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
netif_t *netif = pending_tx_info[pending_idx].netif;
netif_tx_request_t *txp;
struct skb_shared_info *shinfo = skb_shinfo(skb);
@@ -1123,14 +1126,16 @@ static int netbk_tx_check_mop(struct sk_
/* Check status of header. */
err = mop->status;
if (unlikely(err != GNTST_okay)) {
+ pending_ring_idx_t index = MASK_PEND_IDX(netbk->pending_prod++);
+
txp = &pending_tx_info[pending_idx].req;
make_tx_response(netif, txp, NETIF_RSP_ERROR);
- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+ netbk->pending_ring[index] = pending_idx;
netif_put(netif);
} else {
- set_phys_to_machine(idx_to_pfn(pending_idx),
+ set_phys_to_machine(idx_to_pfn(netbk, pending_idx),
FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
- grant_tx_handle[pending_idx] = mop->handle;
+ netbk->grant_tx_handle[pending_idx] = mop->handle;
}
/* Skip first skb fragment if it is on same page as header fragment. */
@@ -1138,25 +1143,27 @@ static int netbk_tx_check_mop(struct sk_
for (i = start; i < nr_frags; i++) {
int j, newerr;
+ pending_ring_idx_t index;
pending_idx = (unsigned long)shinfo->frags[i].page;
/* Check error status: if okay then remember grant handle. */
newerr = (++mop)->status;
if (likely(newerr == GNTST_okay)) {
- set_phys_to_machine(idx_to_pfn(pending_idx),
+ set_phys_to_machine(idx_to_pfn(netbk, pending_idx),
FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
- grant_tx_handle[pending_idx] = mop->handle;
+ netbk->grant_tx_handle[pending_idx] = mop->handle;
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err != GNTST_okay))
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
continue;
}
/* Error on this fragment: respond to client with an error. */
txp = &pending_tx_info[pending_idx].req;
make_tx_response(netif, txp, NETIF_RSP_ERROR);
- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+ index = MASK_PEND_IDX(netbk->pending_prod++);
+ netbk->pending_ring[index] = pending_idx;
netif_put(netif);
/* Not the first error? Preceding frags already invalidated. */
@@ -1165,10 +1172,10 @@ static int netbk_tx_check_mop(struct sk_
/* First error: invalidate header and preceding fragments. */
pending_idx = *((u16 *)skb->data);
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
for (j = start; j < i; j++) {
pending_idx = (unsigned long)shinfo->frags[i].page;
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
}
/* Remember the error: invalidate all subsequent fragments. */
@@ -1179,7 +1186,7 @@ static int netbk_tx_check_mop(struct sk_
return err;
}
-static void netbk_fill_frags(struct sk_buff *skb)
+static void netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
int nr_frags = shinfo->nr_frags;
@@ -1192,12 +1199,12 @@ static void netbk_fill_frags(struct sk_b
pending_idx = (unsigned long)frag->page;
- pending_inuse[pending_idx].alloc_time = jiffies;
- list_add_tail(&pending_inuse[pending_idx].list,
- &pending_inuse_head);
+ netbk->pending_inuse[pending_idx].alloc_time = jiffies;
+ list_add_tail(&netbk->pending_inuse[pending_idx].list,
+ &netbk->pending_inuse_head);
- txp = &pending_tx_info[pending_idx].req;
- frag->page = mmap_pages[pending_idx];
+ txp = &netbk->pending_tx_info[pending_idx].req;
+ frag->page = netbk->mmap_pages[pending_idx];
frag->size = txp->size;
frag->page_offset = txp->offset;
@@ -1259,8 +1266,9 @@ static int netbk_set_skb_gso(struct sk_b
}
/* Called after netfront has transmitted */
-static void net_tx_action(unsigned long unused)
+static void net_tx_action(unsigned long group)
{
+ struct xen_netbk *netbk = &xen_netbk[group];
struct sk_buff *skb;
netif_t *netif;
netif_tx_request_t txreq;
@@ -1272,14 +1280,14 @@ static void net_tx_action(unsigned long
unsigned int data_len;
int ret, work_to_do;
- net_tx_action_dealloc();
+ net_tx_action_dealloc(netbk);
- mop = tx_map_ops;
+ mop = netbk->tx_map_ops;
BUILD_BUG_ON(MAX_SKB_FRAGS >= MAX_PENDING_REQS);
- while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&net_schedule_list)) {
+ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->schedule_list)) {
/* Get a netif from the list with work to do. */
- netif = poll_net_schedule_list();
+ netif = poll_net_schedule_list(netbk);
if (!netif)
continue;
@@ -1361,7 +1369,7 @@ static void net_tx_action(unsigned long
continue;
}
- pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+ pending_idx = netbk->pending_ring[MASK_PEND_IDX(netbk->pending_cons)];
data_len = (txreq.size > PKT_PROT_LEN &&
ret < MAX_SKB_FRAGS) ?
@@ -1389,14 +1397,14 @@ static void net_tx_action(unsigned long
}
}
- gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
+ gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
GNTMAP_host_map | GNTMAP_readonly,
txreq.gref, netif->domid);
mop++;
- memcpy(&pending_tx_info[pending_idx].req,
+ memcpy(&netbk->pending_tx_info[pending_idx].req,
&txreq, sizeof(txreq));
- pending_tx_info[pending_idx].netif = netif;
+ netbk->pending_tx_info[pending_idx].netif = netif;
*((u16 *)skb->data) = pending_idx;
__skb_put(skb, data_len);
@@ -1411,20 +1419,20 @@ static void net_tx_action(unsigned long
skb_shinfo(skb)->frags[0].page = (void *)~0UL;
}
- __skb_queue_tail(&tx_queue, skb);
+ __skb_queue_tail(&netbk->tx_queue, skb);
- pending_cons++;
+ netbk->pending_cons++;
mop = netbk_get_requests(netif, skb, txfrags, mop);
netif->tx.req_cons = i;
netif_schedule_work(netif);
- if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
+ if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
break;
}
- if (mop == tx_map_ops)
+ if (mop == netbk->tx_map_ops)
goto out;
/* NOTE: some maps may fail with GNTST_eagain, which could be successfully
@@ -1432,22 +1440,23 @@ static void net_tx_action(unsigned long
* req and let the frontend resend the relevant packet again. This is fine
* because it is unlikely that a network buffer will be paged out or shared,
* and therefore it is unlikely to fail with GNTST_eagain. */
- ret = HYPERVISOR_grant_table_op(
- GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+ netbk->tx_map_ops,
+ mop - netbk->tx_map_ops);
BUG_ON(ret);
- mop = tx_map_ops;
- while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
+ mop = netbk->tx_map_ops;
+ while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
struct net_device *dev;
netif_tx_request_t *txp;
pending_idx = *((u16 *)skb->data);
- netif = pending_tx_info[pending_idx].netif;
+ netif = netbk->pending_tx_info[pending_idx].netif;
dev = netif->dev;
- txp = &pending_tx_info[pending_idx].req;
+ txp = &netbk->pending_tx_info[pending_idx].req;
/* Check the remap error code. */
- if (unlikely(netbk_tx_check_mop(skb, &mop))) {
+ if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
DPRINTK("netback grant failed.\n");
skb_shinfo(skb)->nr_frags = 0;
kfree_skb(skb);
@@ -1457,7 +1466,7 @@ static void net_tx_action(unsigned long
data_len = skb->len;
memcpy(skb->data,
- (void *)(idx_to_kaddr(pending_idx)|txp->offset),
+ (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
data_len);
if (data_len < txp->size) {
/* Append the packet payload as a fragment. */
@@ -1465,7 +1474,7 @@ static void net_tx_action(unsigned long
txp->size -= data_len;
} else {
/* Schedule a response immediately. */
- netif_idx_release(pending_idx);
+ netif_idx_release(netbk, pending_idx);
}
if (txp->flags & NETTXF_csum_blank)
@@ -1475,7 +1484,7 @@ static void net_tx_action(unsigned long
else
skb->ip_summed = CHECKSUM_NONE;
- netbk_fill_frags(skb);
+ netbk_fill_frags(netbk, skb);
/*
* If the initial fragment was < PKT_PROT_LEN then
@@ -1511,36 +1520,39 @@ static void net_tx_action(unsigned long
out:
if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
- !list_empty(&pending_inuse_head)) {
+ !list_empty(&netbk->pending_inuse_head)) {
struct netbk_tx_pending_inuse *oldest;
- oldest = list_entry(pending_inuse_head.next,
+ oldest = list_entry(netbk->pending_inuse_head.next,
struct netbk_tx_pending_inuse, list);
- mod_timer(&netbk_tx_pending_timer, oldest->alloc_time + HZ);
+ mod_timer(&netbk->tx_pending_timer, oldest->alloc_time + HZ);
}
}
-static void netif_idx_release(u16 pending_idx)
+static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
{
- static DEFINE_SPINLOCK(_lock);
unsigned long flags;
- spin_lock_irqsave(&_lock, flags);
- dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
+ spin_lock_irqsave(&netbk->release_lock, flags);
+ netbk->dealloc_ring[MASK_PEND_IDX(netbk->dealloc_prod)] = pending_idx;
/* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
smp_wmb();
- dealloc_prod++;
- spin_unlock_irqrestore(&_lock, flags);
+ netbk->dealloc_prod++;
+ spin_unlock_irqrestore(&netbk->release_lock, flags);
- tasklet_schedule(&net_tx_tasklet);
+ tasklet_schedule(&netbk->net_tx_tasklet);
}
static void netif_page_release(struct page *page, unsigned int order)
{
- int idx = netif_page_index(page);
+ unsigned int idx = netif_page_index(page);
+ unsigned int group = netif_page_group(page);
+ struct xen_netbk *netbk = &xen_netbk[group];
+
BUG_ON(order);
- BUG_ON(idx < 0);
- netif_idx_release(idx);
+ BUG_ON(group >= netbk_nr_groups || idx >= MAX_PENDING_REQS);
+ BUG_ON(netbk->mmap_pages[idx] != page);
+ netif_idx_release(netbk, idx);
}
irqreturn_t netif_be_int(int irq, void *dev_id)
@@ -1548,7 +1560,7 @@ irqreturn_t netif_be_int(int irq, void *
netif_t *netif = dev_id;
add_to_net_schedule_list_tail(netif);
- maybe_schedule_tx_action();
+ maybe_schedule_tx_action(GET_GROUP_INDEX(netif));
if (netif_schedulable(netif) && !netbk_queue_full(netif))
netif_wake_queue(netif->dev);
@@ -1612,33 +1624,38 @@ static netif_rx_response_t *make_rx_resp
#ifdef NETBE_DEBUG_INTERRUPT
static irqreturn_t netif_be_dbg(int irq, void *dev_id)
{
- struct list_head *ent;
netif_t *netif;
- int i = 0;
+ unsigned int i = 0, group;
pr_alert("netif_schedule_list:\n");
- spin_lock_irq(&net_schedule_list_lock);
- list_for_each (ent, &net_schedule_list) {
- netif = list_entry(ent, netif_t, list);
- pr_alert(" %d: private(rx_req_cons=%08x "
- "rx_resp_prod=%08x\n",
- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
- pr_alert(" tx_req_cons=%08x tx_resp_prod=%08x)\n",
- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
- pr_alert(" shared(rx_req_prod=%08x "
- "rx_resp_prod=%08x\n",
- netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
- pr_alert(" rx_event=%08x tx_req_prod=%08x\n",
- netif->rx.sring->rsp_event,
- netif->tx.sring->req_prod);
- pr_alert(" tx_resp_prod=%08x, tx_event=%08x)\n",
- netif->tx.sring->rsp_prod,
- netif->tx.sring->rsp_event);
- i++;
+ for (group = 0; group < netbk_nr_groups; ++group) {
+ struct xen_netbk *netbk = &xen_netbk[group];
+
+ spin_lock_irq(&netbk->schedule_list_lock);
+
+ list_for_each_entry(netif, &netbk->schedule_list, list) {
+ pr_alert(" %d: private(rx_req_cons=%08x "
+ "rx_resp_prod=%08x\n", i,
+ netif->rx.req_cons, netif->rx.rsp_prod_pvt);
+ pr_alert(" tx_req_cons=%08x tx_resp_prod=%08x)\n",
+ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
+ pr_alert(" shared(rx_req_prod=%08x "
+ "rx_resp_prod=%08x\n",
+ netif->rx.sring->req_prod,
+ netif->rx.sring->rsp_prod);
+ pr_alert(" rx_event=%08x tx_req_prod=%08x\n",
+ netif->rx.sring->rsp_event,
+ netif->tx.sring->req_prod);
+ pr_alert(" tx_resp_prod=%08x, tx_event=%08x)\n",
+ netif->tx.sring->rsp_prod,
+ netif->tx.sring->rsp_event);
+ i++;
+ }
+
+ spin_unlock_irq(&netbk->netbk->schedule_list_lock);
}
- spin_unlock_irq(&net_schedule_list_lock);
pr_alert(" ** End of netif_schedule_list **\n");
return IRQ_HANDLED;
@@ -1653,46 +1670,66 @@ static struct irqaction netif_be_dbg_act
static int __init netback_init(void)
{
- int i;
+ unsigned int i, group;
+ int rc;
struct page *page;
if (!is_running_on_xen())
return -ENODEV;
+ xen_netbk = __vmalloc(netbk_nr_groups * sizeof(*xen_netbk),
+ GFP_KERNEL|__GFP_HIGHMEM|__GFP_ZERO,
+ PAGE_KERNEL);
+ if (!xen_netbk) {
+ pr_err("%s: out of memory\n", __func__);
+ return -ENOMEM;
+ }
+
/* We can increase reservation by this much in net_rx_action(). */
- balloon_update_driver_allowance(NET_RX_RING_SIZE);
+ balloon_update_driver_allowance(netbk_nr_groups * NET_RX_RING_SIZE);
- skb_queue_head_init(&rx_queue);
- skb_queue_head_init(&tx_queue);
+ for (group = 0; group < netbk_nr_groups; group++) {
+ struct xen_netbk *netbk = &xen_netbk[group];
- init_timer(&net_timer);
- net_timer.data = 0;
- net_timer.function = net_alarm;
-
- init_timer(&netbk_tx_pending_timer);
- netbk_tx_pending_timer.data = 0;
- netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
-
- mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
- if (mmap_pages == NULL) {
- pr_err("%s: out of memory\n", __FUNCTION__);
- return -ENOMEM;
- }
+ tasklet_init(&netbk->net_tx_tasklet, net_tx_action, group);
+ tasklet_init(&netbk->net_rx_tasklet, net_rx_action, group);
- for (i = 0; i < MAX_PENDING_REQS; i++) {
- page = mmap_pages[i];
- SetPageForeign(page, netif_page_release);
- netif_set_page_index(page, i);
- INIT_LIST_HEAD(&pending_inuse[i].list);
- }
+ skb_queue_head_init(&netbk->rx_queue);
+ skb_queue_head_init(&netbk->tx_queue);
+
+ init_timer(&netbk->net_timer);
+ netbk->net_timer.data = group;
+ netbk->net_timer.function = net_alarm;
+
+ init_timer(&netbk->tx_pending_timer);
+ netbk->tx_pending_timer.data = group;
+ netbk->tx_pending_timer.function =
+ netbk_tx_pending_timeout;
+
+ netbk->pending_prod = MAX_PENDING_REQS;
- pending_cons = 0;
- pending_prod = MAX_PENDING_REQS;
- for (i = 0; i < MAX_PENDING_REQS; i++)
- pending_ring[i] = i;
+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
+ INIT_LIST_HEAD(&netbk->schedule_list);
- spin_lock_init(&net_schedule_list_lock);
- INIT_LIST_HEAD(&net_schedule_list);
+ spin_lock_init(&netbk->schedule_list_lock);
+ spin_lock_init(&netbk->release_lock);
+
+ netbk->mmap_pages =
+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+ if (netbk->mmap_pages == NULL) {
+ pr_err("%s: out of memory\n", __func__);
+ rc = -ENOMEM;
+ goto failed_init;
+ }
+
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
+ page = netbk->mmap_pages[i];
+ SetPageForeign(page, netif_page_release);
+ netif_set_page_ext(page, group, i);
+ netbk->pending_ring[i] = i;
+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
+ }
netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
if (MODPARM_copy_skb) {
@@ -1714,6 +1751,19 @@ static int __init netback_init(void)
#endif
return 0;
+
+failed_init:
+ while (group-- > 0) {
+ struct xen_netbk *netbk = &xen_netbk[group];
+
+ free_empty_pages_and_pagevec(netbk->mmap_pages,
+ MAX_PENDING_REQS);
+ }
+ vfree(xen_netbk);
+ balloon_update_driver_allowance(-(long)netbk_nr_groups
+ * NET_RX_RING_SIZE);
+
+ return rc;
}
module_init(netback_init);