commit 823c8f14d46d488294e0f1444350cbef41f052aa
Author: Michael Young <m.a.young(a)durham.ac.uk>
Date: Mon Feb 28 23:18:20 2011 +0000
get updated devel/next-2.6.38
kernel.spec | 3 +
xen.pcifront.next-2.6.38.patch |74926 ++++++++++++++++++++--------------------
2 files changed, 37556 insertions(+), 37373 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 7c72fc7..9d227bb 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -1971,6 +1971,9 @@ fi
# and build.
%changelog
+* Mon Feb 28 2011 Michael Young <m.a.young(a)durham.ac.uk>
+- get updated devel/next-2.6.38
+
* Fri Feb 25 2011 Chuck Ebbert <cebbert(a)redhat.com> 2.6.38-0.rc6.git6.1
- Linux 2.6.38-rc6-git6
- Build in virtio_pci driver so virtio_console will be built-in (#677713)
diff --git a/xen.pcifront.next-2.6.38.patch b/xen.pcifront.next-2.6.38.patch
index a0e7a79..c80ccc1 100644
--- a/xen.pcifront.next-2.6.38.patch
+++ b/xen.pcifront.next-2.6.38.patch
@@ -1,12591 +1,14558 @@
-From 1e13f505ecbc011465783283ebfa05a42f7ce18f Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ijc(a)hellion.org.uk>
-Date: Thu, 3 Dec 2009 22:04:06 +0000
-Subject: [PATCH 001/244] xen: export xen_gsi_from_irq, it is required by modular pciback
+From 03c4949992e2b7e84b7cdeb156d803db3f848b6c Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Mon, 9 Feb 2009 12:05:52 -0800
+Subject: [PATCH 001/203] xen: netback: Initial import of linux-2.6.18-xen.hg netback
driver.
+
+This corresponds to 774:107e10e0e07c in that tree.
Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Cc: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/events.c | 1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
+ drivers/xen/Kconfig | 7 +
+ drivers/xen/Makefile | 1 +
+ drivers/xen/netback/Makefile | 3 +
+ drivers/xen/netback/common.h | 217 ++++++
+ drivers/xen/netback/interface.c | 336 ++++++++
+ drivers/xen/netback/netback.c | 1637 +++++++++++++++++++++++++++++++++++++++
+ drivers/xen/netback/xenbus.c | 454 +++++++++++
+ 7 files changed, 2655 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/xen/netback/Makefile
+ create mode 100644 drivers/xen/netback/common.h
+ create mode 100644 drivers/xen/netback/interface.c
+ create mode 100644 drivers/xen/netback/netback.c
+ create mode 100644 drivers/xen/netback/xenbus.c
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 97612f5..a04da4b 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -778,6 +778,7 @@ int xen_gsi_from_irq(unsigned irq)
- {
- return gsi_from_irq(irq);
- }
-+EXPORT_SYMBOL_GPL(xen_gsi_from_irq);
+diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
+index 5a48ce9..7e83d43 100644
+--- a/drivers/xen/Kconfig
++++ b/drivers/xen/Kconfig
+@@ -37,6 +37,13 @@ config XEN_BACKEND
+ Support for backend device drivers that provide I/O services
+ to other virtual machines.
- int xen_irq_from_pirq(unsigned pirq)
- {
---
-1.7.4
-
-
-From f0885b9401a859bc7bed849925a703c03d00119b Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 8 Nov 2010 14:13:35 -0500
-Subject: [PATCH 002/244] xen/pci: Add xen_[find|register|unregister]_device_domain_owner
functions.
-
-Xen PCI backend performs ownership (MSI/MSI-X) changes on the behalf of
-the guest. This means we need some mechanism to find, set and unset
-the domain id of the guest.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/include/asm/xen/pci.h | 16 +++++++++
- arch/x86/pci/xen.c | 73 ++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 89 insertions(+), 0 deletions(-)
-
-diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
-index 2329b3e..8474b4b 100644
---- a/arch/x86/include/asm/xen/pci.h
-+++ b/arch/x86/include/asm/xen/pci.h
-@@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void)
- #endif
- #if defined(CONFIG_XEN_DOM0)
- void __init xen_setup_pirqs(void);
-+int xen_find_device_domain_owner(struct pci_dev *dev);
-+int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
-+int xen_unregister_device_domain_owner(struct pci_dev *dev);
- #else
- static inline void __init xen_setup_pirqs(void)
- {
- }
-+static inline int xen_find_device_domain_owner(struct pci_dev *dev)
-+{
-+ return -1;
-+}
-+static inline int xen_register_device_domain_owner(struct pci_dev *dev,
-+ uint16_t domain)
++config XEN_NETDEV_BACKEND
++ bool "Xen backend network device"
++ depends on XEN_BACKEND && NET
++ help
++ Implement the network backend driver, which passes packets
++ from the guest domain's frontend drivers to the network.
++
+ config XENFS
+ tristate "Xen filesystem"
+ default y
+diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
+index 533a199..c0e0509 100644
+--- a/drivers/xen/Makefile
++++ b/drivers/xen/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
+ obj-$(CONFIG_XEN_BALLOON) += balloon.o
+ obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
+ obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
++obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
+ obj-$(CONFIG_XENFS) += xenfs/
+ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
+ obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
+diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
+new file mode 100644
+index 0000000..f4a0c51
+--- /dev/null
++++ b/drivers/xen/netback/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
++
++netbk-y := netback.o xenbus.o interface.o
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+new file mode 100644
+index 0000000..9a54d57
+--- /dev/null
++++ b/drivers/xen/netback/common.h
+@@ -0,0 +1,217 @@
++/******************************************************************************
++ * arch/xen/drivers/netif/backend/common.h
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __NETIF__BACKEND__COMMON_H__
++#define __NETIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/wait.h>
++#include <xen/evtchn.h>
++#include <xen/interface/io/netif.h>
++#include <asm/io.h>
++#include <asm/pgalloc.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++#include <xen/xenbus.h>
++
++#define DPRINTK(_f, _a...) \
++ pr_debug("(file=%s, line=%d) " _f, \
++ __FILE__ , __LINE__ , ## _a )
++#define IPRINTK(fmt, args...) \
++ printk(KERN_INFO "xen_net: " fmt, ##args)
++#define WPRINTK(fmt, args...) \
++ printk(KERN_WARNING "xen_net: " fmt, ##args)
++
++typedef struct netif_st {
++ /* Unique identifier for this interface. */
++ domid_t domid;
++ unsigned int handle;
++
++ u8 fe_dev_addr[6];
++
++ /* Physical parameters of the comms window. */
++ grant_handle_t tx_shmem_handle;
++ grant_ref_t tx_shmem_ref;
++ grant_handle_t rx_shmem_handle;
++ grant_ref_t rx_shmem_ref;
++ unsigned int irq;
++
++ /* The shared rings and indexes. */
++ netif_tx_back_ring_t tx;
++ netif_rx_back_ring_t rx;
++ struct vm_struct *tx_comms_area;
++ struct vm_struct *rx_comms_area;
++
++ /* Set of features that can be turned on in dev->features. */
++ int features;
++
++ /* Internal feature information. */
++ u8 can_queue:1; /* can queue packets for receiver? */
++ u8 copying_receiver:1; /* copy packets to receiver? */
++
++ /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
++ RING_IDX rx_req_cons_peek;
++
++ /* 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;
++
++ /* Enforce draining of the transmit queue. */
++ struct timer_list tx_queue_timeout;
++
++ /* Miscellaneous private stuff. */
++ struct list_head list; /* scheduling list */
++ atomic_t refcnt;
++ struct net_device *dev;
++ struct net_device_stats stats;
++
++ unsigned int carrier;
++
++ wait_queue_head_t waiting_to_free;
++} netif_t;
++
++/*
++ * Implement our own carrier flag: the network stack's version causes delays
++ * when the carrier is re-enabled (in particular, dev_activate() may not
++ * immediately be called, which can cause packet loss; also the etherbridge
++ * can be rather lazy in activating its port).
++ */
++#define netback_carrier_on(netif) ((netif)->carrier = 1)
++#define netback_carrier_off(netif) ((netif)->carrier = 0)
++#define netback_carrier_ok(netif) ((netif)->carrier)
++
++enum {
++ NETBK_DONT_COPY_SKB,
++ NETBK_DELAYED_COPY_SKB,
++ NETBK_ALWAYS_COPY_SKB,
++};
++
++extern int netbk_copy_skb_mode;
++
++/* Function pointers into netback accelerator plugin modules */
++struct netback_accel_hooks {
++ struct module *owner;
++ int (*probe)(struct xenbus_device *dev);
++ int (*remove)(struct xenbus_device *dev);
++};
++
++/* Structure to track the state of a netback accelerator plugin */
++struct netback_accelerator {
++ struct list_head link;
++ int id;
++ char *eth_name;
++ atomic_t use_count;
++ struct netback_accel_hooks *hooks;
++};
++
++struct backend_info {
++ struct xenbus_device *dev;
++ netif_t *netif;
++ enum xenbus_state frontend_state;
++
++ /* State relating to the netback accelerator */
++ void *netback_accel_priv;
++ /* The accelerator that this backend is currently using */
++ struct netback_accelerator *accelerator;
++};
++
++#define NETBACK_ACCEL_VERSION 0x00010001
++
++/*
++ * Connect an accelerator plugin module to netback. Returns zero on
++ * success, < 0 on error, > 0 (with highest version number supported)
++ * if version mismatch.
++ */
++extern int netback_connect_accelerator(unsigned version,
++ int id, const char *eth_name,
++ struct netback_accel_hooks *hooks);
++/* Disconnect a previously connected accelerator plugin module */
++extern void netback_disconnect_accelerator(int id, const char *eth_name);
++
++
++extern
++void netback_probe_accelerators(struct backend_info *be,
++ struct xenbus_device *dev);
++extern
++void netback_remove_accelerators(struct backend_info *be,
++ struct xenbus_device *dev);
++extern
++void netif_accel_init(void);
++
++
++#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
++
++void netif_disconnect(netif_t *netif);
++
++netif_t *netif_alloc(domid_t domid, unsigned int handle);
++int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn);
++
++#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define netif_put(_b) \
++ do { \
++ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
++ wake_up(&(_b)->waiting_to_free); \
++ } while (0)
++
++void netif_xenbus_init(void);
++
++#define netif_schedulable(netif) \
++ (netif_running((netif)->dev) && netback_carrier_ok(netif))
++
++void netif_schedule_work(netif_t *netif);
++void netif_deschedule_work(netif_t *netif);
++
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
++struct net_device_stats *netif_be_get_stats(struct net_device *dev);
++irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++
++static inline int netbk_can_queue(struct net_device *dev)
+{
-+ return -1;
++ netif_t *netif = netdev_priv(dev);
++ return netif->can_queue;
+}
-+static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
++
++static inline int netbk_can_sg(struct net_device *dev)
+{
-+ return -1;
++ netif_t *netif = netdev_priv(dev);
++ return netif->features & NETIF_F_SG;
+}
- #endif
-
- #if defined(CONFIG_PCI_MSI)
-diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
-index 117f5b8..6d2a986 100644
---- a/arch/x86/pci/xen.c
-+++ b/arch/x86/pci/xen.c
-@@ -412,3 +412,76 @@ void __init xen_setup_pirqs(void)
- }
- }
- #endif
+
-+struct xen_device_domain_owner {
-+ domid_t domain;
-+ struct pci_dev *dev;
-+ struct list_head list;
-+};
++#endif /* __NETIF__BACKEND__COMMON_H__ */
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+new file mode 100644
+index 0000000..7e67941
+--- /dev/null
++++ b/drivers/xen/netback/interface.c
+@@ -0,0 +1,336 @@
++/******************************************************************************
++ * arch/xen/drivers/netif/backend/interface.c
++ *
++ * Network-device interface management.
++ *
++ * Copyright (c) 2004-2005, Keir Fraser
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
+
-+static DEFINE_SPINLOCK(dev_domain_list_spinlock);
-+static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
++#include "common.h"
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
+
-+static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
++/*
++ * Module parameter 'queue_length':
++ *
++ * Enables queuing in the network stack when a client has run out of receive
++ * descriptors. Although this feature can improve receive bandwidth by avoiding
++ * packet loss, it can also result in packets sitting in the 'tx_queue' for
++ * unbounded time. This is bad if those packets hold onto foreign resources.
++ * For example, consider a packet that holds onto resources belonging to the
++ * guest for which it is queued (e.g., packet received on vif1.0, destined for
++ * vif1.1 which is not activated in the guest): in this situation the guest
++ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
++ * run a timer (tx_queue_timeout) to drain the queue when the interface is
++ * blocked.
++ */
++static unsigned long netbk_queue_length = 32;
++module_param_named(queue_length, netbk_queue_length, ulong, 0);
++
++static void __netif_up(netif_t *netif)
+{
-+ struct xen_device_domain_owner *owner;
++ enable_irq(netif->irq);
++ netif_schedule_work(netif);
++}
+
-+ list_for_each_entry(owner, &dev_domain_list, list) {
-+ if (owner->dev == dev)
-+ return owner;
-+ }
-+ return NULL;
++static void __netif_down(netif_t *netif)
++{
++ disable_irq(netif->irq);
++ netif_deschedule_work(netif);
+}
+
-+int xen_find_device_domain_owner(struct pci_dev *dev)
++static int net_open(struct net_device *dev)
+{
-+ struct xen_device_domain_owner *owner;
-+ int domain = -ENODEV;
++ netif_t *netif = netdev_priv(dev);
++ if (netback_carrier_ok(netif)) {
++ __netif_up(netif);
++ netif_start_queue(dev);
++ }
++ return 0;
++}
+
-+ spin_lock(&dev_domain_list_spinlock);
-+ owner = find_device(dev);
-+ if (owner)
-+ domain = owner->domain;
-+ spin_unlock(&dev_domain_list_spinlock);
-+ return domain;
++static int net_close(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ if (netback_carrier_ok(netif))
++ __netif_down(netif);
++ netif_stop_queue(dev);
++ return 0;
+}
-+EXPORT_SYMBOL(xen_find_device_domain_owner);
+
-+int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
++static int netbk_change_mtu(struct net_device *dev, int mtu)
+{
-+ struct xen_device_domain_owner *owner;
++ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
-+ owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
-+ if (!owner)
-+ return -ENODEV;
++ if (mtu > max)
++ return -EINVAL;
++ dev->mtu = mtu;
++ return 0;
++}
+
-+ spin_lock(&dev_domain_list_spinlock);
-+ if (find_device(dev)) {
-+ spin_unlock(&dev_domain_list_spinlock);
-+ kfree(owner);
-+ return -EEXIST;
++static int netbk_set_sg(struct net_device *dev, u32 data)
++{
++ if (data) {
++ netif_t *netif = netdev_priv(dev);
++
++ if (!(netif->features & NETIF_F_SG))
++ return -ENOSYS;
+ }
-+ owner->domain = domain;
-+ owner->dev = dev;
-+ list_add_tail(&owner->list, &dev_domain_list);
-+ spin_unlock(&dev_domain_list_spinlock);
-+ return 0;
++
++ return ethtool_op_set_sg(dev, data);
+}
-+EXPORT_SYMBOL(xen_register_device_domain_owner);
+
-+int xen_unregister_device_domain_owner(struct pci_dev *dev)
++static int netbk_set_tso(struct net_device *dev, u32 data)
+{
-+ struct xen_device_domain_owner *owner;
++ if (data) {
++ netif_t *netif = netdev_priv(dev);
+
-+ spin_lock(&dev_domain_list_spinlock);
-+ owner = find_device(dev);
-+ if (!owner) {
-+ spin_unlock(&dev_domain_list_spinlock);
-+ return -ENODEV;
++ if (!(netif->features & NETIF_F_TSO))
++ return -ENOSYS;
+ }
-+ list_del(&owner->list);
-+ spin_unlock(&dev_domain_list_spinlock);
-+ kfree(owner);
-+ return 0;
++
++ return ethtool_op_set_tso(dev, data);
+}
-+EXPORT_SYMBOL(xen_unregister_device_domain_owner);
---
-1.7.4
-
-
-From da24916fdf04d7b4a32c5b9d2c09e47775496e1d Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 8 Nov 2010 14:23:17 -0500
-Subject: [PATCH 003/244] xen: Check if the PCI device is owned by a domain different than
DOMID_SELF.
-
-We check if there is a domain owner for the PCI device. In case of failure
-(meaning no domain has registered for this device) we make
-DOMID_SELF the owner.
-
-[v2: deal with rebasing on v2.6.37-1]
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Acked-by: Xiantao Zhang <xiantao.zhang(a)intel.com>
----
- drivers/xen/events.c | 16 +++++++++++++---
- 1 files changed, 13 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index a04da4b..96c93e7 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -40,6 +40,7 @@
- #include <asm/xen/pci.h>
- #include <asm/xen/hypercall.h>
- #include <asm/xen/hypervisor.h>
-+#include <asm/xen/pci.h>
-
- #include <xen/xen.h>
- #include <xen/hvm.h>
-@@ -97,6 +98,7 @@ struct irq_info
- unsigned short gsi;
- unsigned char vector;
- unsigned char flags;
-+ uint16_t domid;
- } pirq;
- } u;
- };
-@@ -158,7 +160,8 @@ static struct irq_info mk_pirq_info(unsigned short evtchn, unsigned
short pirq,
- {
- return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn,
- .cpu = 0,
-- .u.pirq = { .pirq = pirq, .gsi = gsi, .vector = vector } };
-+ .u.pirq = { .pirq = pirq, .gsi = gsi,
-+ .vector = vector, .domid = DOMID_SELF } };
- }
-
- /*
-@@ -688,11 +691,16 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc
*msidesc, int type)
- int irq = -1;
- struct physdev_map_pirq map_irq;
- int rc;
-+ domid_t domid;
- int pos;
- u32 table_offset, bir;
-
-+ domid = rc = xen_find_device_domain_owner(dev);
-+ if (rc < 0)
-+ domid = DOMID_SELF;
-+
- memset(&map_irq, 0, sizeof(map_irq));
-- map_irq.domid = DOMID_SELF;
-+ map_irq.domid = domid;
- map_irq.type = MAP_PIRQ_TYPE_MSI;
- map_irq.index = -1;
- map_irq.pirq = -1;
-@@ -727,6 +735,8 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
- goto out;
- }
- irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index);
-+ if (domid)
-+ irq_info[irq].u.pirq.domid = domid;
-
- set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
- handle_level_irq,
-@@ -753,7 +763,7 @@ int xen_destroy_irq(int irq)
-
- if (xen_initial_domain()) {
- unmap_irq.pirq = info->u.pirq.pirq;
-- unmap_irq.domid = DOMID_SELF;
-+ unmap_irq.domid = info->u.pirq.domid;
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
- if (rc) {
- printk(KERN_WARNING "unmap irq failed %d\n", rc);
---
-1.7.4
-
-
-From 30fecb8166bdd163bdaab795b573cf988f60fbbe Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 8 Nov 2010 14:26:36 -0500
-Subject: [PATCH 004/244] xen: Add support to check if IRQ line is shared with other
domains.
-
-We do this via the PHYSDEVOP_irq_status_query support hypervisor call.
-We will get a positive value if another domain has binded its
-PIRQ to the specified IRQ line.
-
-[v2: Deal with v2.6.37-rc1 rebase fallout]
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 13 +++++++++++++
- include/xen/events.h | 3 +++
- 2 files changed, 16 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 96c93e7..690dfad 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -1398,6 +1398,19 @@ void xen_poll_irq(int irq)
- xen_poll_irq_timeout(irq, 0 /* no timeout */);
- }
-
-+/* Check whether the IRQ line is shared with other guests. */
-+int xen_ignore_irq(int irq)
-+{
-+ struct irq_info *info = info_for_irq(irq);
-+ struct physdev_irq_status_query irq_status = { .irq =
-+ info->u.pirq.gsi };
-+
-+ if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
-+ return 0;
-+ return !(irq_status.flags & XENIRQSTAT_shared);
-+}
-+EXPORT_SYMBOL_GPL(xen_ignore_irq);
-+
- void xen_irq_resume(void)
- {
- unsigned int cpu, irq, evtchn;
-diff --git a/include/xen/events.h b/include/xen/events.h
-index 646dd17..553c664 100644
---- a/include/xen/events.h
-+++ b/include/xen/events.h
-@@ -89,4 +89,7 @@ int xen_vector_from_irq(unsigned pirq);
- /* Return irq from pirq */
- int xen_irq_from_pirq(unsigned pirq);
-
-+/* Determine whether to ignore this IRQ if passed to a guest. */
-+int xen_ignore_irq(int irq);
+
- #endif /* _XEN_EVENTS_H */
---
-1.7.4
-
-
-From 909e45104de4414897cefce2f6bbed07fc4de4b3 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Mon, 9 Feb 2009 12:05:50 -0800
-Subject: [PATCH 005/244] xen: implement bind_interdomain_evtchn_to_irqhandler for backend
drivers
-
-Impact: new Xen-internal API
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/events.c | 38 ++++++++++++++++++++++++++++++++++++++
- include/xen/events.h | 6 ++++++
- 2 files changed, 44 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 690dfad..95eea13 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -849,6 +849,21 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
- return irq;
- }
-
-+static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-+ unsigned int remote_port)
++static struct ethtool_ops network_ethtool_ops =
+{
-+ struct evtchn_bind_interdomain bind_interdomain;
-+ int err;
-+
-+ bind_interdomain.remote_dom = remote_domain;
-+ bind_interdomain.remote_port = remote_port;
-+
-+ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
-+ &bind_interdomain);
-+
-+ return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
-+}
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = ethtool_op_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = netbk_set_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = netbk_set_tso,
++ .get_link = ethtool_op_get_link,
++};
+
-
- int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
- {
-@@ -944,6 +959,29 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
- }
- EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
-
-+int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-+ unsigned int remote_port,
-+ irq_handler_t handler,
-+ unsigned long irqflags,
-+ const char *devname,
-+ void *dev_id)
++netif_t *netif_alloc(domid_t domid, unsigned int handle)
+{
-+ int irq, retval;
++ int err = 0;
++ struct net_device *dev;
++ netif_t *netif;
++ char name[IFNAMSIZ] = {};
+
-+ irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
-+ if (irq < 0)
-+ return irq;
++ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
++ dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
++ if (dev == NULL) {
++ DPRINTK("Could not create netif: out of memory\n");
++ return ERR_PTR(-ENOMEM);
++ }
+
-+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+ if (retval != 0) {
-+ unbind_from_irq(irq);
-+ return retval;
-+ }
++ netif = netdev_priv(dev);
++ memset(netif, 0, sizeof(*netif));
++ netif->domid = domid;
++ netif->handle = handle;
++ atomic_set(&netif->refcnt, 1);
++ init_waitqueue_head(&netif->waiting_to_free);
++ netif->dev = dev;
+
-+ return irq;
-+}
-+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
++ netback_carrier_off(netif);
+
- int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
- irq_handler_t handler,
- unsigned long irqflags, const char *devname, void *dev_id)
-diff --git a/include/xen/events.h b/include/xen/events.h
-index 553c664..2fe1644 100644
---- a/include/xen/events.h
-+++ b/include/xen/events.h
-@@ -23,6 +23,12 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
- unsigned long irqflags,
- const char *devname,
- void *dev_id);
-+int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
-+ unsigned int remote_port,
-+ irq_handler_t handler,
-+ unsigned long irqflags,
-+ const char *devname,
-+ void *dev_id);
-
- /*
- * Common unbind function for all event sources. Takes IRQ to unbind from.
---
-1.7.4
-
-
-From b4f664c8de09ab8537e1cd194df29056f803062e Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 8 Nov 2010 14:46:33 -0500
-Subject: [PATCH 006/244] pci/xen: Make xen_[find|register|unregister]_domain_owner be
_GPL
-
-EXPORT_SYMBOL -> EXPORT_SYMBOL_GPL.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/pci/xen.c | 6 +++---
- 1 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
-index 6d2a986..0fa23c8 100644
---- a/arch/x86/pci/xen.c
-+++ b/arch/x86/pci/xen.c
-@@ -445,7 +445,7 @@ int xen_find_device_domain_owner(struct pci_dev *dev)
- spin_unlock(&dev_domain_list_spinlock);
- return domain;
- }
--EXPORT_SYMBOL(xen_find_device_domain_owner);
-+EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
-
- int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
- {
-@@ -467,7 +467,7 @@ int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t
domain)
- spin_unlock(&dev_domain_list_spinlock);
- return 0;
- }
--EXPORT_SYMBOL(xen_register_device_domain_owner);
-+EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
-
- int xen_unregister_device_domain_owner(struct pci_dev *dev)
- {
-@@ -484,4 +484,4 @@ int xen_unregister_device_domain_owner(struct pci_dev *dev)
- kfree(owner);
- return 0;
- }
--EXPORT_SYMBOL(xen_unregister_device_domain_owner);
-+EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
---
-1.7.4
-
-
-From 443b2aafbdb509f218fcb8f4665f063e3a5e1a92 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:20 -0400
-Subject: [PATCH 007/244] xen-pciback: Initial copy from linux-2.6.18.hg off pciback
driver.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/Makefile | 17 +
- drivers/xen/pciback/conf_space.c | 435 ++++++++
- drivers/xen/pciback/conf_space.h | 126 +++
- drivers/xen/pciback/conf_space_capability.c | 69 ++
- drivers/xen/pciback/conf_space_capability.h | 23 +
- drivers/xen/pciback/conf_space_capability_msi.c | 79 ++
- drivers/xen/pciback/conf_space_capability_pm.c | 126 +++
- drivers/xen/pciback/conf_space_capability_vpd.c | 40 +
- drivers/xen/pciback/conf_space_header.c | 317 ++++++
- drivers/xen/pciback/conf_space_quirks.c | 138 +++
- drivers/xen/pciback/conf_space_quirks.h | 35 +
- drivers/xen/pciback/controller.c | 443 ++++++++
- drivers/xen/pciback/passthrough.c | 176 +++
- drivers/xen/pciback/pci_stub.c | 1316 +++++++++++++++++++++++
- drivers/xen/pciback/pciback.h | 126 +++
- drivers/xen/pciback/pciback_ops.c | 134 +++
- drivers/xen/pciback/slot.c | 187 ++++
- drivers/xen/pciback/vpci.c | 242 +++++
- drivers/xen/pciback/xenbus.c | 710 ++++++++++++
- 19 files changed, 4739 insertions(+), 0 deletions(-)
- create mode 100644 drivers/xen/pciback/Makefile
- create mode 100644 drivers/xen/pciback/conf_space.c
- create mode 100644 drivers/xen/pciback/conf_space.h
- create mode 100644 drivers/xen/pciback/conf_space_capability.c
- create mode 100644 drivers/xen/pciback/conf_space_capability.h
- create mode 100644 drivers/xen/pciback/conf_space_capability_msi.c
- create mode 100644 drivers/xen/pciback/conf_space_capability_pm.c
- create mode 100644 drivers/xen/pciback/conf_space_capability_vpd.c
- create mode 100644 drivers/xen/pciback/conf_space_header.c
- create mode 100644 drivers/xen/pciback/conf_space_quirks.c
- create mode 100644 drivers/xen/pciback/conf_space_quirks.h
- create mode 100644 drivers/xen/pciback/controller.c
- create mode 100644 drivers/xen/pciback/passthrough.c
- create mode 100644 drivers/xen/pciback/pci_stub.c
- create mode 100644 drivers/xen/pciback/pciback.h
- create mode 100644 drivers/xen/pciback/pciback_ops.c
- create mode 100644 drivers/xen/pciback/slot.c
- create mode 100644 drivers/xen/pciback/vpci.c
- create mode 100644 drivers/xen/pciback/xenbus.c
-
-diff --git a/drivers/xen/pciback/Makefile b/drivers/xen/pciback/Makefile
-new file mode 100644
-index 0000000..106dae7
---- /dev/null
-+++ b/drivers/xen/pciback/Makefile
-@@ -0,0 +1,17 @@
-+obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
++ netif->credit_bytes = netif->remaining_credit = ~0UL;
++ netif->credit_usec = 0UL;
++ init_timer(&netif->credit_timeout);
++ /* Initialize 'expires' now: it's used to track the credit window. */
++ netif->credit_timeout.expires = jiffies;
+
-+pciback-y := pci_stub.o pciback_ops.o xenbus.o
-+pciback-y += conf_space.o conf_space_header.o \
-+ conf_space_capability.o \
-+ conf_space_capability_vpd.o \
-+ conf_space_capability_pm.o \
-+ conf_space_quirks.o
-+pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
++ init_timer(&netif->tx_queue_timeout);
+
-+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
-+EXTRA_CFLAGS += -DDEBUG
-+endif
-diff --git a/drivers/xen/pciback/conf_space.c b/drivers/xen/pciback/conf_space.c
-new file mode 100644
-index 0000000..0c76db1
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space.c
-@@ -0,0 +1,435 @@
-+/*
-+ * PCI Backend - Functions for creating a virtual configuration space for
-+ * exported PCI Devices.
-+ * It's dangerous to allow PCI Driver Domains to change their
-+ * device's resources (memory, i/o ports, interrupts). We need to
-+ * restrict changes to certain PCI Configuration registers:
-+ * BARs, INTERRUPT_PIN, most registers in the header...
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
++ dev->hard_start_xmit = netif_be_start_xmit;
++ dev->get_stats = netif_be_get_stats;
++ dev->open = net_open;
++ dev->stop = net_close;
++ dev->change_mtu = netbk_change_mtu;
++ dev->features = NETIF_F_IP_CSUM;
+
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_quirks.h"
++ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+
-+static int permissive;
-+module_param(permissive, bool, 0644);
++ dev->tx_queue_len = netbk_queue_length;
+
-+#define DEFINE_PCI_CONFIG(op,size,type) \
-+int pciback_##op##_config_##size \
-+(struct pci_dev *dev, int offset, type value, void *data) \
-+{ \
-+ return pci_##op##_config_##size (dev, offset, value); \
-+}
++ /*
++ * Initialise a dummy MAC address. We choose the numerically
++ * largest non-broadcast address to prevent the address getting
++ * stolen by an Ethernet bridge for STP purposes.
++ * (FE:FF:FF:FF:FF:FF)
++ */
++ memset(dev->dev_addr, 0xFF, ETH_ALEN);
++ dev->dev_addr[0] &= ~0x01;
+
-+DEFINE_PCI_CONFIG(read, byte, u8 *)
-+DEFINE_PCI_CONFIG(read, word, u16 *)
-+DEFINE_PCI_CONFIG(read, dword, u32 *)
++ rtnl_lock();
++ err = register_netdevice(dev);
++ rtnl_unlock();
++ if (err) {
++ DPRINTK("Could not register new net device %s: err=%d\n",
++ dev->name, err);
++ free_netdev(dev);
++ return ERR_PTR(err);
++ }
+
-+DEFINE_PCI_CONFIG(write, byte, u8)
-+DEFINE_PCI_CONFIG(write, word, u16)
-+DEFINE_PCI_CONFIG(write, dword, u32)
++ DPRINTK("Successfully created netif\n");
++ return netif;
++}
+
-+static int conf_space_read(struct pci_dev *dev,
-+ const struct config_field_entry *entry,
-+ int offset, u32 *value)
++static int map_frontend_pages(
++ netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
+{
-+ int ret = 0;
-+ const struct config_field *field = entry->field;
++ struct gnttab_map_grant_ref op;
+
-+ *value = 0;
++ gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, tx_ring_ref, netif->domid);
+
-+ switch (field->size) {
-+ case 1:
-+ if (field->u.b.read)
-+ ret = field->u.b.read(dev, offset, (u8 *) value,
-+ entry->data);
-+ break;
-+ case 2:
-+ if (field->u.w.read)
-+ ret = field->u.w.read(dev, offset, (u16 *) value,
-+ entry->data);
-+ break;
-+ case 4:
-+ if (field->u.dw.read)
-+ ret = field->u.dw.read(dev, offset, value, entry->data);
-+ break;
++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++ BUG();
++
++ if (op.status) {
++ DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
++ return op.status;
+ }
-+ return ret;
-+}
+
-+static int conf_space_write(struct pci_dev *dev,
-+ const struct config_field_entry *entry,
-+ int offset, u32 value)
-+{
-+ int ret = 0;
-+ const struct config_field *field = entry->field;
++ netif->tx_shmem_ref = tx_ring_ref;
++ netif->tx_shmem_handle = op.handle;
+
-+ switch (field->size) {
-+ case 1:
-+ if (field->u.b.write)
-+ ret = field->u.b.write(dev, offset, (u8) value,
-+ entry->data);
-+ break;
-+ case 2:
-+ if (field->u.w.write)
-+ ret = field->u.w.write(dev, offset, (u16) value,
-+ entry->data);
-+ break;
-+ case 4:
-+ if (field->u.dw.write)
-+ ret = field->u.dw.write(dev, offset, value,
-+ entry->data);
-+ break;
++ gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
++ GNTMAP_host_map, rx_ring_ref, netif->domid);
++
++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++ BUG();
++
++ if (op.status) {
++ DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
++ return op.status;
+ }
-+ return ret;
-+}
+
-+static inline u32 get_mask(int size)
-+{
-+ if (size == 1)
-+ return 0xff;
-+ else if (size == 2)
-+ return 0xffff;
-+ else
-+ return 0xffffffff;
-+}
++ netif->rx_shmem_ref = rx_ring_ref;
++ netif->rx_shmem_handle = op.handle;
+
-+static inline int valid_request(int offset, int size)
-+{
-+ /* Validate request (no un-aligned requests) */
-+ if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
-+ return 1;
+ return 0;
+}
+
-+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
-+ int offset)
++static void unmap_frontend_pages(netif_t *netif)
+{
-+ if (offset >= 0) {
-+ new_val_mask <<= (offset * 8);
-+ new_val <<= (offset * 8);
-+ } else {
-+ new_val_mask >>= (offset * -8);
-+ new_val >>= (offset * -8);
-+ }
-+ val = (val & ~new_val_mask) | (new_val & new_val_mask);
++ struct gnttab_unmap_grant_ref op;
+
-+ return val;
-+}
++ gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, netif->tx_shmem_handle);
+
-+static int pcibios_err_to_errno(int err)
-+{
-+ switch (err) {
-+ case PCIBIOS_SUCCESSFUL:
-+ return XEN_PCI_ERR_success;
-+ case PCIBIOS_DEVICE_NOT_FOUND:
-+ return XEN_PCI_ERR_dev_not_found;
-+ case PCIBIOS_BAD_REGISTER_NUMBER:
-+ return XEN_PCI_ERR_invalid_offset;
-+ case PCIBIOS_FUNC_NOT_SUPPORTED:
-+ return XEN_PCI_ERR_not_implemented;
-+ case PCIBIOS_SET_FAILED:
-+ return XEN_PCI_ERR_access_denied;
-+ }
-+ return err;
++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++ BUG();
++
++ gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
++ GNTMAP_host_map, netif->rx_shmem_handle);
++
++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++ BUG();
+}
+
-+int pciback_config_read(struct pci_dev *dev, int offset, int size,
-+ u32 * ret_val)
++int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn)
+{
-+ int err = 0;
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ const struct config_field_entry *cfg_entry;
-+ const struct config_field *field;
-+ int req_start, req_end, field_start, field_end;
-+ /* if read fails for any reason, return 0 (as if device didn't respond) */
-+ u32 value = 0, tmp_val;
++ int err = -ENOMEM;
++ netif_tx_sring_t *txs;
++ netif_rx_sring_t *rxs;
+
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
-+ pci_name(dev), size, offset);
++ /* Already connected through? */
++ if (netif->irq)
++ return 0;
+
-+ if (!valid_request(offset, size)) {
-+ err = XEN_PCI_ERR_invalid_offset;
-+ goto out;
-+ }
++ netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (netif->tx_comms_area == NULL)
++ return -ENOMEM;
++ netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (netif->rx_comms_area == NULL)
++ goto err_rx;
+
-+ /* Get the real value first, then modify as appropriate */
-+ switch (size) {
-+ case 1:
-+ err = pci_read_config_byte(dev, offset, (u8 *) & value);
-+ break;
-+ case 2:
-+ err = pci_read_config_word(dev, offset, (u16 *) & value);
-+ break;
-+ case 4:
-+ err = pci_read_config_dword(dev, offset, &value);
-+ break;
-+ }
++ err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
++ if (err)
++ goto err_map;
+
-+ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+ field = cfg_entry->field;
++ err = bind_interdomain_evtchn_to_irqhandler(
++ netif->domid, evtchn, netif_be_int, 0,
++ netif->dev->name, netif);
++ if (err < 0)
++ goto err_hypervisor;
++ netif->irq = err;
++ disable_irq(netif->irq);
+
-+ req_start = offset;
-+ req_end = offset + size;
-+ field_start = OFFSET(cfg_entry);
-+ field_end = OFFSET(cfg_entry) + field->size;
++ txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
++ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
+
-+ if ((req_start >= field_start && req_start < field_end)
-+ || (req_end > field_start && req_end <= field_end)) {
-+ err = conf_space_read(dev, cfg_entry, field_start,
-+ &tmp_val);
-+ if (err)
-+ goto out;
++ rxs = (netif_rx_sring_t *)
++ ((char *)netif->rx_comms_area->addr);
++ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
+
-+ value = merge_value(value, tmp_val,
-+ get_mask(field->size),
-+ field_start - req_start);
-+ }
-+ }
++ netif->rx_req_cons_peek = 0;
+
-+ out:
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
-+ pci_name(dev), size, offset, value);
++ netif_get(netif);
+
-+ *ret_val = value;
-+ return pcibios_err_to_errno(err);
++ rtnl_lock();
++ netback_carrier_on(netif);
++ if (netif_running(netif->dev))
++ __netif_up(netif);
++ rtnl_unlock();
++
++ return 0;
++err_hypervisor:
++ unmap_frontend_pages(netif);
++err_map:
++ free_vm_area(netif->rx_comms_area);
++err_rx:
++ free_vm_area(netif->tx_comms_area);
++ return err;
+}
+
-+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
++void netif_disconnect(netif_t *netif)
+{
-+ int err = 0, handled = 0;
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ const struct config_field_entry *cfg_entry;
-+ const struct config_field *field;
-+ u32 tmp_val;
-+ int req_start, req_end, field_start, field_end;
++ if (netback_carrier_ok(netif)) {
++ rtnl_lock();
++ netback_carrier_off(netif);
++ netif_carrier_off(netif->dev); /* discard queued packets */
++ if (netif_running(netif->dev))
++ __netif_down(netif);
++ rtnl_unlock();
++ netif_put(netif);
++ }
+
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG
-+ "pciback: %s: write request %d bytes at 0x%x = %x\n",
-+ pci_name(dev), size, offset, value);
++ atomic_dec(&netif->refcnt);
++ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
+
-+ if (!valid_request(offset, size))
-+ return XEN_PCI_ERR_invalid_offset;
++ del_timer_sync(&netif->credit_timeout);
++ del_timer_sync(&netif->tx_queue_timeout);
+
-+ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+ field = cfg_entry->field;
++ if (netif->irq)
++ unbind_from_irqhandler(netif->irq, netif);
+
-+ req_start = offset;
-+ req_end = offset + size;
-+ field_start = OFFSET(cfg_entry);
-+ field_end = OFFSET(cfg_entry) + field->size;
++ unregister_netdev(netif->dev);
+
-+ if ((req_start >= field_start && req_start < field_end)
-+ || (req_end > field_start && req_end <= field_end)) {
-+ tmp_val = 0;
++ if (netif->tx.sring) {
++ unmap_frontend_pages(netif);
++ free_vm_area(netif->tx_comms_area);
++ free_vm_area(netif->rx_comms_area);
++ }
+
-+ err = pciback_config_read(dev, field_start,
-+ field->size, &tmp_val);
-+ if (err)
-+ break;
++ free_netdev(netif->dev);
++}
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+new file mode 100644
+index 0000000..db629d4
+--- /dev/null
++++ b/drivers/xen/netback/netback.c
+@@ -0,0 +1,1637 @@
++/******************************************************************************
++ * drivers/xen/netback/netback.c
++ *
++ * Back-end of the driver for virtual network devices. This portion of the
++ * driver exports a 'unified' network-device interface that can be accessed
++ * by any operating system that implements a compatible front end. A
++ * reference front-end implementation can be found in:
++ * drivers/xen/netfront/netfront.c
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
+
-+ tmp_val = merge_value(tmp_val, value, get_mask(size),
-+ req_start - field_start);
++#include "common.h"
++#include <xen/balloon.h>
++#include <xen/interface/memory.h>
+
-+ err = conf_space_write(dev, cfg_entry, field_start,
-+ tmp_val);
++/*define NETBE_DEBUG_INTERRUPT*/
+
-+ /* handled is set true here, but not every byte
-+ * may have been written! Properly detecting if
-+ * every byte is handled is unnecessary as the
-+ * flag is used to detect devices that need
-+ * special helpers to work correctly.
-+ */
-+ handled = 1;
-+ }
-+ }
++struct netbk_rx_meta {
++ skb_frag_t frag;
++ int id;
++ u8 copy:1;
++};
+
-+ if (!handled && !err) {
-+ /* By default, anything not specificially handled above is
-+ * read-only. The permissive flag changes this behavior so
-+ * that anything not specifically handled above is writable.
-+ * This means that some fields may still be read-only because
-+ * they have entries in the config_field list that intercept
-+ * the write and do nothing. */
-+ if (dev_data->permissive || permissive) {
-+ switch (size) {
-+ case 1:
-+ err = pci_write_config_byte(dev, offset,
-+ (u8) value);
-+ break;
-+ case 2:
-+ err = pci_write_config_word(dev, offset,
-+ (u16) value);
-+ break;
-+ case 4:
-+ err = pci_write_config_dword(dev, offset,
-+ (u32) value);
-+ break;
-+ }
-+ } else if (!dev_data->warned_on_write) {
-+ dev_data->warned_on_write = 1;
-+ dev_warn(&dev->dev, "Driver tried to write to a "
-+ "read-only configuration space field at offset "
-+ "0x%x, size %d. This may be harmless, but if "
-+ "you have problems with your device:\n"
-+ "1) see permissive attribute in sysfs\n"
-+ "2) report problems to the xen-devel "
-+ "mailing list along with details of your "
-+ "device obtained from lspci.\n", offset, size);
-+ }
-+ }
++struct netbk_tx_pending_inuse {
++ struct list_head list;
++ unsigned long alloc_time;
++};
+
-+ return pcibios_err_to_errno(err);
-+}
++static void netif_idx_release(u16 pending_idx);
++static void make_tx_response(netif_t *netif,
++ netif_tx_request_t *txp,
++ s8 st);
++static netif_rx_response_t *make_rx_response(netif_t *netif,
++ u16 id,
++ s8 st,
++ u16 offset,
++ u16 size,
++ u16 flags);
+
-+void pciback_config_free_dyn_fields(struct pci_dev *dev)
-+{
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ struct config_field_entry *cfg_entry, *t;
-+ const struct config_field *field;
++static void net_tx_action(unsigned long unused);
++static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
+
-+ dev_dbg(&dev->dev,
-+ "free-ing dynamically allocated virtual configuration space fields\n");
-+ if (!dev_data)
-+ return;
++static void net_rx_action(unsigned long unused);
++static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
+
-+ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
-+ field = cfg_entry->field;
++static struct timer_list net_timer;
++static struct timer_list netbk_tx_pending_timer;
+
-+ if (field->clean) {
-+ field->clean((struct config_field *)field);
++#define MAX_PENDING_REQS 256
+
-+ if (cfg_entry->data)
-+ kfree(cfg_entry->data);
++static struct sk_buff_head rx_queue;
+
-+ list_del(&cfg_entry->list);
-+ kfree(cfg_entry);
-+ }
++static struct page **mmap_pages;
++static inline unsigned long idx_to_pfn(unsigned int idx)
++{
++ return page_to_pfn(mmap_pages[idx]);
++}
+
-+ }
++static inline unsigned long idx_to_kaddr(unsigned int idx)
++{
++ return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx));
+}
+
-+void pciback_config_reset_dev(struct pci_dev *dev)
++/* extra field used in struct page */
++static inline void netif_set_page_index(struct page *pg, unsigned int index)
+{
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ const struct config_field_entry *cfg_entry;
-+ const struct config_field *field;
++ *(unsigned long *)&pg->mapping = index;
++}
+
-+ dev_dbg(&dev->dev, "resetting virtual configuration space\n");
-+ if (!dev_data)
-+ return;
++static inline int netif_page_index(struct page *pg)
++{
++ unsigned long idx = (unsigned long)pg->mapping;
+
-+ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+ field = cfg_entry->field;
++ if (!PageForeign(pg))
++ return -1;
+
-+ if (field->reset)
-+ field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
-+ }
++ if ((idx >= MAX_PENDING_REQS) || (mmap_pages[idx] != pg))
++ return -1;
++
++ return idx;
+}
+
-+void pciback_config_free_dev(struct pci_dev *dev)
-+{
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ struct config_field_entry *cfg_entry, *t;
-+ const struct config_field *field;
++#define PKT_PROT_LEN 64
+
-+ dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
-+ if (!dev_data)
-+ return;
++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)
+
-+ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
-+ list_del(&cfg_entry->list);
++/* 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;
+
-+ field = cfg_entry->field;
++/* 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);
+
-+ if (field->release)
-+ field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
++static struct sk_buff_head tx_queue;
+
-+ kfree(cfg_entry);
-+ }
-+}
++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];
+
-+int pciback_config_add_field_offset(struct pci_dev *dev,
-+ const struct config_field *field,
-+ unsigned int base_offset)
-+{
-+ int err = 0;
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ struct config_field_entry *cfg_entry;
-+ void *tmp;
++static struct list_head net_schedule_list;
++static spinlock_t net_schedule_list_lock;
+
-+ cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
-+ if (!cfg_entry) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
++#define MAX_MFN_ALLOC 64
++static unsigned long mfn_list[MAX_MFN_ALLOC];
++static unsigned int alloc_index = 0;
+
-+ cfg_entry->data = NULL;
-+ cfg_entry->field = field;
-+ cfg_entry->base_offset = base_offset;
++/* Setting this allows the safe use of this driver without netloop. */
++static int MODPARM_copy_skb = 1;
++module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
++MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
+
-+ /* silently ignore duplicate fields */
-+ err = pciback_field_is_dup(dev,OFFSET(cfg_entry));
-+ if (err)
-+ goto out;
++int netbk_copy_skb_mode;
+
-+ if (field->init) {
-+ tmp = field->init(dev, OFFSET(cfg_entry));
++static inline unsigned long alloc_mfn(void)
++{
++ BUG_ON(alloc_index == 0);
++ return mfn_list[--alloc_index];
++}
+
-+ if (IS_ERR(tmp)) {
-+ err = PTR_ERR(tmp);
-+ goto out;
-+ }
++static int check_mfn(int nr)
++{
++ struct xen_memory_reservation reservation = {
++ .extent_order = 0,
++ .domid = DOMID_SELF
++ };
++ int rc;
+
-+ cfg_entry->data = tmp;
-+ }
++ if (likely(alloc_index >= nr))
++ return 0;
+
-+ dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
-+ OFFSET(cfg_entry));
-+ list_add_tail(&cfg_entry->list, &dev_data->config_fields);
++ set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
++ reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
++ rc = HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation);
++ if (likely(rc > 0))
++ alloc_index += rc;
+
-+ out:
-+ if (err)
-+ kfree(cfg_entry);
++ return alloc_index >= nr ? 0 : -ENOMEM;
++}
+
-+ return err;
++static inline void maybe_schedule_tx_action(void)
++{
++ smp_mb();
++ if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
++ !list_empty(&net_schedule_list))
++ tasklet_schedule(&net_tx_tasklet);
+}
+
-+/* This sets up the device's virtual configuration space to keep track of
-+ * certain registers (like the base address registers (BARs) so that we can
-+ * keep the client from manipulating them directly.
-+ */
-+int pciback_config_init_dev(struct pci_dev *dev)
++static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+{
-+ int err = 0;
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct skb_shared_info *ninfo;
++ struct sk_buff *nskb;
++ unsigned long offset;
++ int ret;
++ int len;
++ int headlen;
+
-+ dev_dbg(&dev->dev, "initializing virtual configuration space\n");
++ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
+
-+ INIT_LIST_HEAD(&dev_data->config_fields);
++ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(!nskb))
++ goto err;
+
-+ err = pciback_config_header_add_fields(dev);
-+ if (err)
-+ goto out;
++ skb_reserve(nskb, 16 + NET_IP_ALIGN);
++ headlen = nskb->end - nskb->data;
++ if (headlen > skb_headlen(skb))
++ headlen = skb_headlen(skb);
++ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
++ BUG_ON(ret);
+
-+ err = pciback_config_capability_add_fields(dev);
-+ if (err)
-+ goto out;
++ ninfo = skb_shinfo(nskb);
++ ninfo->gso_size = skb_shinfo(skb)->gso_size;
++ ninfo->gso_type = skb_shinfo(skb)->gso_type;
+
-+ err = pciback_config_quirks_init(dev);
++ offset = headlen;
++ len = skb->len - headlen;
+
-+ out:
-+ return err;
-+}
++ nskb->len = skb->len;
++ nskb->data_len = len;
++ nskb->truesize += len;
+
-+int pciback_config_init(void)
-+{
-+ return pciback_config_capability_init();
-+}
-diff --git a/drivers/xen/pciback/conf_space.h b/drivers/xen/pciback/conf_space.h
-new file mode 100644
-index 0000000..fe746ef
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space.h
-@@ -0,0 +1,126 @@
-+/*
-+ * PCI Backend - Common data structures for overriding the configuration space
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
++ while (len) {
++ struct page *page;
++ int copy;
++ int zero;
+
-+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
-+#define __XEN_PCIBACK_CONF_SPACE_H__
++ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
++ dump_stack();
++ goto err_free;
++ }
+
-+#include <linux/list.h>
-+#include <linux/err.h>
++ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
++ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
+
-+/* conf_field_init can return an errno in a ptr with ERR_PTR() */
-+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
-+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
-+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
++ if (unlikely(!page))
++ goto err_free;
+
-+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
-+ void *data);
-+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
-+ void *data);
-+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
-+ void *data);
-+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
-+ void *data);
-+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
-+ void *data);
-+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
-+ void *data);
++ ret = skb_copy_bits(skb, offset, page_address(page), copy);
++ BUG_ON(ret);
+
-+/* These are the fields within the configuration space which we
-+ * are interested in intercepting reads/writes to and changing their
-+ * values.
-+ */
-+struct config_field {
-+ unsigned int offset;
-+ unsigned int size;
-+ unsigned int mask;
-+ conf_field_init init;
-+ conf_field_reset reset;
-+ conf_field_free release;
-+ void (*clean) (struct config_field * field);
-+ union {
-+ struct {
-+ conf_dword_write write;
-+ conf_dword_read read;
-+ } dw;
-+ struct {
-+ conf_word_write write;
-+ conf_word_read read;
-+ } w;
-+ struct {
-+ conf_byte_write write;
-+ conf_byte_read read;
-+ } b;
-+ } u;
-+ struct list_head list;
-+};
++ ninfo->frags[ninfo->nr_frags].page = page;
++ ninfo->frags[ninfo->nr_frags].page_offset = 0;
++ ninfo->frags[ninfo->nr_frags].size = copy;
++ ninfo->nr_frags++;
+
-+struct config_field_entry {
-+ struct list_head list;
-+ const struct config_field *field;
-+ unsigned int base_offset;
-+ void *data;
-+};
++ offset += copy;
++ len -= copy;
++ }
+
-+#define OFFSET(cfg_entry)
((cfg_entry)->base_offset+(cfg_entry)->field->offset)
++ offset = nskb->data - skb->data;
+
-+/* Add fields to a device - the add_fields macro expects to get a pointer to
-+ * the first entry in an array (of which the ending is marked by size==0)
-+ */
-+int pciback_config_add_field_offset(struct pci_dev *dev,
-+ const struct config_field *field,
-+ unsigned int offset);
++ nskb->h.raw = skb->h.raw + offset;
++ nskb->nh.raw = skb->nh.raw + offset;
++ nskb->mac.raw = skb->mac.raw + offset;
+
-+static inline int pciback_config_add_field(struct pci_dev *dev,
-+ const struct config_field *field)
-+{
-+ return pciback_config_add_field_offset(dev, field, 0);
-+}
++ return nskb;
+
-+static inline int pciback_config_add_fields(struct pci_dev *dev,
-+ const struct config_field *field)
-+{
-+ int i, err = 0;
-+ for (i = 0; field[i].size != 0; i++) {
-+ err = pciback_config_add_field(dev, &field[i]);
-+ if (err)
-+ break;
-+ }
-+ return err;
++ err_free:
++ kfree_skb(nskb);
++ err:
++ return NULL;
+}
+
-+static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
-+ const struct config_field *field,
-+ unsigned int offset)
++static inline int netbk_max_required_rx_slots(netif_t *netif)
+{
-+ int i, err = 0;
-+ for (i = 0; field[i].size != 0; i++) {
-+ err = pciback_config_add_field_offset(dev, &field[i], offset);
-+ if (err)
-+ break;
-+ }
-+ return err;
++ if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
++ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
++ return 1; /* all in one */
+}
+
-+/* Read/Write the real configuration space */
-+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
-+ void *data);
-+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
-+ void *data);
-+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
-+ void *data);
-+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
-+ void *data);
-+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
-+ void *data);
-+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
-+ void *data);
-+
-+int pciback_config_capability_init(void);
-+
-+int pciback_config_header_add_fields(struct pci_dev *dev);
-+int pciback_config_capability_add_fields(struct pci_dev *dev);
-+
-+#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */
-diff --git a/drivers/xen/pciback/conf_space_capability.c
b/drivers/xen/pciback/conf_space_capability.c
-new file mode 100644
-index 0000000..50efca4
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_capability.c
-@@ -0,0 +1,69 @@
-+/*
-+ * PCI Backend - Handles the virtual fields found on the capability lists
-+ * in the configuration space.
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
-+
-+static LIST_HEAD(capabilities);
++static inline int netbk_queue_full(netif_t *netif)
++{
++ RING_IDX peek = netif->rx_req_cons_peek;
++ RING_IDX needed = netbk_max_required_rx_slots(netif);
+
-+static const struct config_field caplist_header[] = {
-+ {
-+ .offset = PCI_CAP_LIST_ID,
-+ .size = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */
-+ .u.w.read = pciback_read_config_word,
-+ .u.w.write = NULL,
-+ },
-+ {}
-+};
++ return ((netif->rx.sring->req_prod - peek) < needed) ||
++ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
++}
+
-+static inline void register_capability(struct pciback_config_capability *cap)
++static void tx_queue_callback(unsigned long data)
+{
-+ list_add_tail(&cap->cap_list, &capabilities);
++ netif_t *netif = (netif_t *)data;
++ if (netif_schedulable(netif))
++ netif_wake_queue(netif->dev);
+}
+
-+int pciback_config_capability_add_fields(struct pci_dev *dev)
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
-+ int err = 0;
-+ struct pciback_config_capability *cap;
-+ int cap_offset;
++ netif_t *netif = netdev_priv(dev);
+
-+ list_for_each_entry(cap, &capabilities, cap_list) {
-+ cap_offset = pci_find_capability(dev, cap->capability);
-+ if (cap_offset) {
-+ dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n",
-+ cap->capability, cap_offset);
++ BUG_ON(skb->dev != dev);
+
-+ err = pciback_config_add_fields_offset(dev,
-+ caplist_header,
-+ cap_offset);
-+ if (err)
-+ goto out;
-+ err = pciback_config_add_fields_offset(dev,
-+ cap->fields,
-+ cap_offset);
-+ if (err)
-+ goto out;
-+ }
++ /* Drop the packet if the target domain has no receive buffers. */
++ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
++ goto drop;
++
++ /*
++ * Copy the packet here if it's destined for a flipping interface
++ * but isn't flippable (e.g. extra references to data).
++ * XXX For now we also copy skbuffs whose head crosses a page
++ * boundary, because netbk_gop_skb can't handle them.
++ */
++ if (!netif->copying_receiver ||
++ ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) {
++ struct sk_buff *nskb = netbk_copy_skb(skb);
++ if ( unlikely(nskb == NULL) )
++ goto drop;
++ /* Copy only the header fields we use in this driver. */
++ nskb->dev = skb->dev;
++ nskb->ip_summed = skb->ip_summed;
++ nskb->proto_data_valid = skb->proto_data_valid;
++ dev_kfree_skb(skb);
++ skb = nskb;
+ }
+
-+ out:
-+ return err;
-+}
++ netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
++ !!skb_shinfo(skb)->gso_size;
++ netif_get(netif);
+
-+extern struct pciback_config_capability pciback_config_capability_vpd;
-+extern struct pciback_config_capability pciback_config_capability_pm;
++ if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
++ netif->rx.sring->req_event = netif->rx_req_cons_peek +
++ netbk_max_required_rx_slots(netif);
++ mb(); /* request notification /then/ check & stop the queue */
++ if (netbk_queue_full(netif)) {
++ netif_stop_queue(dev);
++ /*
++ * Schedule 500ms timeout to restart the queue, thus
++ * ensuring that an inactive queue will be drained.
++ * Packets will be immediately be dropped until more
++ * receive buffers become available (see
++ * netbk_queue_full() check above).
++ */
++ netif->tx_queue_timeout.data = (unsigned long)netif;
++ netif->tx_queue_timeout.function = tx_queue_callback;
++ __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
++ }
++ }
+
-+int pciback_config_capability_init(void)
-+{
-+ register_capability(&pciback_config_capability_vpd);
-+ register_capability(&pciback_config_capability_pm);
++ skb_queue_tail(&rx_queue, skb);
++ tasklet_schedule(&net_rx_tasklet);
++
++ return 0;
+
++ drop:
++ netif->stats.tx_dropped++;
++ dev_kfree_skb(skb);
+ return 0;
+}
-diff --git a/drivers/xen/pciback/conf_space_capability.h
b/drivers/xen/pciback/conf_space_capability.h
-new file mode 100644
-index 0000000..823392e
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_capability.h
-@@ -0,0 +1,23 @@
++
++#if 0
++static void xen_network_done_notify(void)
++{
++ static struct net_device *eth0_dev = NULL;
++ if (unlikely(eth0_dev == NULL))
++ eth0_dev = __dev_get_by_name("eth0");
++ netif_rx_schedule(eth0_dev);
++}
+/*
-+ * PCI Backend - Data structures for special overlays for structures on
-+ * the capability list.
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ * Add following to poll() function in NAPI driver (Tigon3 is example):
++ * if ( xen_network_done() )
++ * tg3_enable_ints(tp);
+ */
++int xen_network_done(void)
++{
++ return skb_queue_empty(&rx_queue);
++}
++#endif
+
-+#ifndef __PCIBACK_CONFIG_CAPABILITY_H__
-+#define __PCIBACK_CONFIG_CAPABILITY_H__
++struct netrx_pending_operations {
++ unsigned trans_prod, trans_cons;
++ unsigned mmu_prod, mmu_mcl;
++ unsigned mcl_prod, mcl_cons;
++ unsigned copy_prod, copy_cons;
++ unsigned meta_prod, meta_cons;
++ mmu_update_t *mmu;
++ gnttab_transfer_t *trans;
++ gnttab_copy_t *copy;
++ multicall_entry_t *mcl;
++ struct netbk_rx_meta *meta;
++};
+
-+#include <linux/pci.h>
-+#include <linux/list.h>
++/* Set up the grant operations for this fragment. If it's a flipping
++ interface, we also set up the unmap request from here. */
++static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
++ int i, struct netrx_pending_operations *npo,
++ struct page *page, unsigned long size,
++ unsigned long offset)
++{
++ mmu_update_t *mmu;
++ gnttab_transfer_t *gop;
++ gnttab_copy_t *copy_gop;
++ multicall_entry_t *mcl;
++ netif_rx_request_t *req;
++ unsigned long old_mfn, new_mfn;
++ int idx = netif_page_index(page);
+
-+struct pciback_config_capability {
-+ struct list_head cap_list;
++ old_mfn = virt_to_mfn(page_address(page));
+
-+ int capability;
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
++ if (netif->copying_receiver) {
++ /* 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];
++ copy_gop->source.domid = src_pend->netif->domid;
++ copy_gop->source.u.ref = src_pend->req.gref;
++ copy_gop->flags |= GNTCOPY_source_gref;
++ } else {
++ copy_gop->source.domid = DOMID_SELF;
++ copy_gop->source.u.gmfn = old_mfn;
++ }
++ copy_gop->source.offset = offset;
++ copy_gop->dest.domid = netif->domid;
++ copy_gop->dest.offset = 0;
++ copy_gop->dest.u.ref = req->gref;
++ copy_gop->len = size;
++ } else {
++ meta->copy = 0;
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ new_mfn = alloc_mfn();
+
-+ /* If the device has the capability found above, add these fields */
-+ const struct config_field *fields;
-+};
++ /*
++ * Set the new P2M table entry before
++ * reassigning the old data page. Heed the
++ * comment in pgtable-2level.h:pte_page(). :-)
++ */
++ set_phys_to_machine(page_to_pfn(page), new_mfn);
+
-+#endif
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-new file mode 100644
-index 0000000..762e396
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -0,0 +1,79 @@
-+/*
-+ * PCI Backend -- Configuration overlay for MSI capability
-+ */
-+#include <linux/pci.h>
-+#include <linux/slab.h>
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
-+#include <xen/interface/io/pciif.h>
-+#include "pciback.h"
++ mcl = npo->mcl + npo->mcl_prod++;
++ MULTI_update_va_mapping(mcl,
++ (unsigned long)page_address(page),
++ pfn_pte_ma(new_mfn, PAGE_KERNEL),
++ 0);
+
-+int pciback_enable_msi(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op)
++ mmu = npo->mmu + npo->mmu_prod++;
++ mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
++ MMU_MACHPHYS_UPDATE;
++ mmu->val = page_to_pfn(page);
++ }
++
++ gop = npo->trans + npo->trans_prod++;
++ gop->mfn = old_mfn;
++ gop->domid = netif->domid;
++ gop->ref = req->gref;
++ }
++ return req->id;
++}
++
++static void netbk_gop_skb(struct sk_buff *skb,
++ struct netrx_pending_operations *npo)
+{
-+ int otherend = pdev->xdev->otherend_id;
-+ int status;
++ netif_t *netif = netdev_priv(skb->dev);
++ int nr_frags = skb_shinfo(skb)->nr_frags;
++ int i;
++ int extra;
++ struct netbk_rx_meta *head_meta, *meta;
+
-+ status = pci_enable_msi(dev);
++ head_meta = npo->meta + npo->meta_prod++;
++ head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
++ head_meta->frag.size = skb_shinfo(skb)->gso_size;
++ extra = !!head_meta->frag.size + 1;
+
-+ if (status) {
-+ printk("error enable msi for guest %x status %x\n", otherend, status);
-+ op->value = 0;
-+ return XEN_PCI_ERR_op_failed;
++ for (i = 0; i < nr_frags; i++) {
++ meta = npo->meta + npo->meta_prod++;
++ meta->frag = skb_shinfo(skb)->frags[i];
++ meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
++ meta->frag.page,
++ meta->frag.size,
++ meta->frag.page_offset);
+ }
+
-+ op->value = dev->irq;
-+ return 0;
++ /*
++ * This must occur at the end to ensure that we don't trash skb_shinfo
++ * until we're done. We know that the head doesn't cross a page
++ * boundary because such packets get copied in netif_be_start_xmit.
++ */
++ head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
++ virt_to_page(skb->data),
++ skb_headlen(skb),
++ offset_in_page(skb->data));
++
++ netif->rx.req_cons += nr_frags + extra;
+}
+
-+int pciback_disable_msi(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op)
++static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
+{
-+ pci_disable_msi(dev);
++ int i;
+
-+ op->value = dev->irq;
-+ return 0;
++ for (i = 0; i < nr_frags; i++)
++ put_page(meta[i].frag.page);
+}
+
-+int pciback_enable_msix(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op)
++/* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
++ used to set up the operations on the top of
++ netrx_pending_operations, which have since been done. Check that
++ they didn't give any errors and advance over them. */
++static int netbk_check_gop(int nr_frags, domid_t domid,
++ struct netrx_pending_operations *npo)
+{
-+ int i, result;
-+ struct msix_entry *entries;
-+
-+ if (op->value > SH_INFO_MAX_VEC)
-+ return -EINVAL;
++ multicall_entry_t *mcl;
++ gnttab_transfer_t *gop;
++ gnttab_copy_t *copy_op;
++ int status = NETIF_RSP_OKAY;
++ int i;
+
-+ entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
-+ if (entries == NULL)
-+ return -ENOMEM;
++ for (i = 0; i <= nr_frags; i++) {
++ if (npo->meta[npo->meta_cons + i].copy) {
++ copy_op = npo->copy + npo->copy_cons++;
++ if (copy_op->status != GNTST_okay) {
++ DPRINTK("Bad status %d from copy to DOM%d.\n",
++ copy_op->status, domid);
++ status = NETIF_RSP_ERROR;
++ }
++ } else {
++ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++ mcl = npo->mcl + npo->mcl_cons++;
++ /* The update_va_mapping() must not fail. */
++ BUG_ON(mcl->result != 0);
++ }
+
-+ for (i = 0; i < op->value; i++) {
-+ entries[i].entry = op->msix_entries[i].entry;
-+ entries[i].vector = op->msix_entries[i].vector;
++ gop = npo->trans + npo->trans_cons++;
++ /* Check the reassignment error code. */
++ if (gop->status != 0) {
++ DPRINTK("Bad status %d from grant transfer to DOM%u\n",
++ gop->status, domid);
++ /*
++ * Page no longer belongs to us unless
++ * GNTST_bad_page, but that should be
++ * a fatal error anyway.
++ */
++ BUG_ON(gop->status == GNTST_bad_page);
++ status = NETIF_RSP_ERROR;
++ }
++ }
+ }
+
-+ result = pci_enable_msix(dev, entries, op->value);
-+
-+ for (i = 0; i < op->value; i++) {
-+ op->msix_entries[i].entry = entries[i].entry;
-+ op->msix_entries[i].vector = entries[i].vector;
-+ }
++ return status;
++}
+
-+ kfree(entries);
++static void netbk_add_frag_responses(netif_t *netif, int status,
++ struct netbk_rx_meta *meta, int nr_frags)
++{
++ int i;
++ unsigned long offset;
+
-+ op->value = result;
++ for (i = 0; i < nr_frags; i++) {
++ int id = meta[i].id;
++ int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
+
-+ return result;
++ if (meta[i].copy)
++ offset = 0;
++ else
++ offset = meta[i].frag.page_offset;
++ make_rx_response(netif, id, status, offset,
++ meta[i].frag.size, flags);
++ }
+}
+
-+int pciback_disable_msix(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op)
++static void net_rx_action(unsigned long unused)
+{
++ netif_t *netif = NULL;
++ s8 status;
++ u16 id, irq, flags;
++ netif_rx_response_t *resp;
++ multicall_entry_t *mcl;
++ struct sk_buff_head rxq;
++ struct sk_buff *skb;
++ int notify_nr = 0;
++ int ret;
++ int nr_frags;
++ int count;
++ unsigned long offset;
+
-+ pci_disable_msix(dev);
++ /*
++ * 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 unsigned char rx_notify[NR_IRQS];
++ static u16 notify_list[NET_RX_RING_SIZE];
++ static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+
-+ op->value = dev->irq;
-+ return 0;
-+}
++ struct netrx_pending_operations npo = {
++ mmu: rx_mmu,
++ trans: grant_trans_op,
++ copy: grant_copy_op,
++ mcl: rx_mcl,
++ meta: meta};
+
-diff --git a/drivers/xen/pciback/conf_space_capability_pm.c
b/drivers/xen/pciback/conf_space_capability_pm.c
-new file mode 100644
-index 0000000..e2f99c7
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_capability_pm.c
-@@ -0,0 +1,126 @@
-+/*
-+ * PCI Backend - Configuration space overlay for power management
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
++ skb_queue_head_init(&rxq);
+
-+#include <linux/pci.h>
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
++ count = 0;
+
-+static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
-+ void *data)
-+{
-+ int err;
-+ u16 real_value;
++ while ((skb = skb_dequeue(&rx_queue)) != NULL) {
++ nr_frags = skb_shinfo(skb)->nr_frags;
++ *(int *)skb->cb = nr_frags;
+
-+ err = pci_read_config_word(dev, offset, &real_value);
-+ if (err)
-+ goto out;
++ if (!xen_feature(XENFEAT_auto_translated_physmap) &&
++ !((netif_t *)netdev_priv(skb->dev))->copying_receiver &&
++ check_mfn(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);
++ break;
++ }
+
-+ *value = real_value & ~PCI_PM_CAP_PME_MASK;
++ netbk_gop_skb(skb, &npo);
+
-+ out:
-+ return err;
-+}
++ count += nr_frags + 1;
+
-+/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
-+ * Can't allow driver domain to enable PMEs - they're shared */
-+#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
++ __skb_queue_tail(&rxq, skb);
+
-+static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
-+ void *data)
-+{
-+ int err;
-+ u16 old_value;
-+ pci_power_t new_state, old_state;
++ /* Filled the batch queue? */
++ if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
++ break;
++ }
+
-+ err = pci_read_config_word(dev, offset, &old_value);
-+ if (err)
-+ goto out;
++ BUG_ON(npo.meta_prod > ARRAY_SIZE(meta));
+
-+ old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
-+ new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
++ 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));
++ mcl = npo.mcl + npo.mcl_prod++;
+
-+ new_value &= PM_OK_BITS;
-+ if ((old_value & PM_OK_BITS) != new_value) {
-+ new_value = (old_value & ~PM_OK_BITS) | new_value;
-+ err = pci_write_config_word(dev, offset, new_value);
-+ if (err)
-+ goto out;
-+ }
++ BUG_ON(mcl[-1].op != __HYPERVISOR_update_va_mapping);
++ mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
+
-+ /* Let pci core handle the power management change */
-+ dev_dbg(&dev->dev, "set power state to %x\n", new_state);
-+ err = pci_set_power_state(dev, new_state);
-+ if (err) {
-+ err = PCIBIOS_SET_FAILED;
-+ goto out;
++ mcl->op = __HYPERVISOR_mmu_update;
++ mcl->args[0] = (unsigned long)rx_mmu;
++ mcl->args[1] = npo.mmu_prod;
++ mcl->args[2] = 0;
++ mcl->args[3] = DOMID_SELF;
+ }
+
-+ /*
-+ * Device may lose PCI config info on D3->D0 transition. This
-+ * is a problem for some guests which will not reset BARs. Even
-+ * those that have a go will be foiled by our BAR-write handler
-+ * which will discard the write! Since Linux won't re-init
-+ * the config space automatically in all cases, we do it here.
-+ * Future: Should we re-initialise all first 64 bytes of config space?
-+ */
-+ if (new_state == PCI_D0 &&
-+ (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
-+ !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
-+ pci_restore_bars(dev);
++ if (npo.trans_prod) {
++ BUG_ON(npo.trans_prod > ARRAY_SIZE(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[2] = npo.trans_prod;
++ }
+
-+ out:
-+ return err;
-+}
++ if (npo.copy_prod) {
++ BUG_ON(npo.copy_prod > ARRAY_SIZE(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[2] = npo.copy_prod;
++ }
+
-+/* Ensure PMEs are disabled */
-+static void *pm_ctrl_init(struct pci_dev *dev, int offset)
-+{
-+ int err;
-+ u16 value;
++ /* Nothing to do? */
++ if (!npo.mcl_prod)
++ return;
+
-+ err = pci_read_config_word(dev, offset, &value);
-+ if (err)
-+ goto out;
++ BUG_ON(npo.mcl_prod > ARRAY_SIZE(rx_mcl));
+
-+ if (value & PCI_PM_CTRL_PME_ENABLE) {
-+ value &= ~PCI_PM_CTRL_PME_ENABLE;
-+ err = pci_write_config_word(dev, offset, value);
-+ }
++ ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
++ BUG_ON(ret != 0);
++ /* The mmu_machphys_update() must not fail. */
++ BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
+
-+ out:
-+ return ERR_PTR(err);
-+}
++ while ((skb = __skb_dequeue(&rxq)) != NULL) {
++ nr_frags = *(int *)skb->cb;
+
-+static const struct config_field caplist_pm[] = {
-+ {
-+ .offset = PCI_PM_PMC,
-+ .size = 2,
-+ .u.w.read = pm_caps_read,
-+ },
-+ {
-+ .offset = PCI_PM_CTRL,
-+ .size = 2,
-+ .init = pm_ctrl_init,
-+ .u.w.read = pciback_read_config_word,
-+ .u.w.write = pm_ctrl_write,
-+ },
-+ {
-+ .offset = PCI_PM_PPB_EXTENSIONS,
-+ .size = 1,
-+ .u.b.read = pciback_read_config_byte,
-+ },
-+ {
-+ .offset = PCI_PM_DATA_REGISTER,
-+ .size = 1,
-+ .u.b.read = pciback_read_config_byte,
-+ },
-+ {}
-+};
++ netif = netdev_priv(skb->dev);
++ /* We can't rely on skb_release_data to release the
++ pages used by fragments for us, since it tries to
++ touch the pages in the fraglist. If we're in
++ flipping mode, that doesn't work. In copying mode,
++ we still have access to all of the pages, and so
++ it's safe to let release_data deal with it. */
++ /* (Freeing the fragments is safe since we copy
++ non-linear skbs destined for flipping interfaces) */
++ if (!netif->copying_receiver) {
++ 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);
++ }
+
-+struct pciback_config_capability pciback_config_capability_pm = {
-+ .capability = PCI_CAP_ID_PM,
-+ .fields = caplist_pm,
-+};
-diff --git a/drivers/xen/pciback/conf_space_capability_vpd.c
b/drivers/xen/pciback/conf_space_capability_vpd.c
-new file mode 100644
-index 0000000..920cb4a
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_capability_vpd.c
-@@ -0,0 +1,40 @@
-+/*
-+ * PCI Backend - Configuration space overlay for Vital Product Data
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
++ netif->stats.tx_bytes += skb->len;
++ netif->stats.tx_packets++;
+
-+#include <linux/pci.h>
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
++ status = netbk_check_gop(nr_frags, netif->domid, &npo);
+
-+static int vpd_address_write(struct pci_dev *dev, int offset, u16 value,
-+ void *data)
-+{
-+ /* Disallow writes to the vital product data */
-+ if (value & PCI_VPD_ADDR_F)
-+ return PCIBIOS_SET_FAILED;
-+ else
-+ return pci_write_config_word(dev, offset, value);
-+}
++ id = meta[npo.meta_cons].id;
++ flags = nr_frags ? NETRXF_more_data : 0;
+
-+static const struct config_field caplist_vpd[] = {
-+ {
-+ .offset = PCI_VPD_ADDR,
-+ .size = 2,
-+ .u.w.read = pciback_read_config_word,
-+ .u.w.write = vpd_address_write,
-+ },
-+ {
-+ .offset = PCI_VPD_DATA,
-+ .size = 4,
-+ .u.dw.read = pciback_read_config_dword,
-+ .u.dw.write = NULL,
-+ },
-+ {}
-+};
-+
-+struct pciback_config_capability pciback_config_capability_vpd = {
-+ .capability = PCI_CAP_ID_VPD,
-+ .fields = caplist_vpd,
-+};
-diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
-new file mode 100644
-index 0000000..f794e12
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_header.c
-@@ -0,0 +1,317 @@
-+/*
-+ * PCI Backend - Handles the virtual fields in the configuration space headers.
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
++ if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++ flags |= NETRXF_csum_blank | NETRXF_data_validated;
++ else if (skb->proto_data_valid) /* remote but checksummed? */
++ flags |= NETRXF_data_validated;
+
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
++ if (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);
+
-+struct pci_bar_info {
-+ u32 val;
-+ u32 len_val;
-+ int which;
-+};
++ if (meta[npo.meta_cons].frag.size) {
++ struct netif_extra_info *gso =
++ (struct netif_extra_info *)
++ RING_GET_RESPONSE(&netif->rx,
++ netif->rx.rsp_prod_pvt++);
+
-+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
-+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
++ resp->flags |= NETRXF_extra_info;
+
-+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
-+{
-+ int err;
++ gso->u.gso.size = 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;
+
-+ if (!dev->is_enabled && is_enable_cmd(value)) {
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: enable\n",
-+ pci_name(dev));
-+ err = pci_enable_device(dev);
-+ if (err)
-+ return err;
-+ } else if (dev->is_enabled && !is_enable_cmd(value)) {
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: disable\n",
-+ pci_name(dev));
-+ pci_disable_device(dev);
-+ }
++ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
++ gso->flags = 0;
++ }
+
-+ if (!dev->is_busmaster && is_master_cmd(value)) {
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: set bus master\n",
-+ pci_name(dev));
-+ pci_set_master(dev);
-+ }
++ netbk_add_frag_responses(netif, status,
++ meta + npo.meta_cons + 1,
++ nr_frags);
+
-+ if (value & PCI_COMMAND_INVALIDATE) {
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG
-+ "pciback: %s: enable memory-write-invalidate\n",
-+ pci_name(dev));
-+ err = pci_set_mwi(dev);
-+ if (err) {
-+ printk(KERN_WARNING
-+ "pciback: %s: cannot enable memory-write-invalidate (%d)\n",
-+ pci_name(dev), err);
-+ value &= ~PCI_COMMAND_INVALIDATE;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
++ irq = netif->irq;
++ if (ret && !rx_notify[irq]) {
++ rx_notify[irq] = 1;
++ notify_list[notify_nr++] = irq;
+ }
-+ }
-+
-+ return pci_write_config_word(dev, offset, value);
-+}
+
-+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
-+{
-+ struct pci_bar_info *bar = data;
++ if (netif_queue_stopped(netif->dev) &&
++ netif_schedulable(netif) &&
++ !netbk_queue_full(netif))
++ netif_wake_queue(netif->dev);
+
-+ if (unlikely(!bar)) {
-+ printk(KERN_WARNING "pciback: driver data not found for %s\n",
-+ pci_name(dev));
-+ return XEN_PCI_ERR_op_failed;
++ netif_put(netif);
++ dev_kfree_skb(skb);
++ npo.meta_cons += nr_frags + 1;
+ }
+
-+ /* A write to obtain the length must happen as a 32-bit write.
-+ * This does not (yet) support writing individual bytes
-+ */
-+ if (value == ~PCI_ROM_ADDRESS_ENABLE)
-+ bar->which = 1;
-+ else {
-+ u32 tmpval;
-+ pci_read_config_dword(dev, offset, &tmpval);
-+ if (tmpval != bar->val && value == bar->val) {
-+ /* Allow restoration of bar value. */
-+ pci_write_config_dword(dev, offset, bar->val);
-+ }
-+ bar->which = 0;
++ while (notify_nr != 0) {
++ irq = notify_list[--notify_nr];
++ rx_notify[irq] = 0;
++ notify_remote_via_irq(irq);
+ }
+
-+ /* Do we need to support enabling/disabling the rom address here? */
-+
-+ return 0;
++ /* More work to do? */
++ if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
++ tasklet_schedule(&net_rx_tasklet);
++#if 0
++ else
++ xen_network_done_notify();
++#endif
+}
+
-+/* For the BARs, only allow writes which write ~0 or
-+ * the correct resource information
-+ * (Needed for when the driver probes the resource usage)
-+ */
-+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
++static void net_alarm(unsigned long unused)
+{
-+ struct pci_bar_info *bar = data;
-+
-+ if (unlikely(!bar)) {
-+ printk(KERN_WARNING "pciback: driver data not found for %s\n",
-+ pci_name(dev));
-+ return XEN_PCI_ERR_op_failed;
-+ }
++ tasklet_schedule(&net_rx_tasklet);
++}
+
-+ /* A write to obtain the length must happen as a 32-bit write.
-+ * This does not (yet) support writing individual bytes
-+ */
-+ if (value == ~0)
-+ bar->which = 1;
-+ else {
-+ u32 tmpval;
-+ pci_read_config_dword(dev, offset, &tmpval);
-+ if (tmpval != bar->val && value == bar->val) {
-+ /* Allow restoration of bar value. */
-+ pci_write_config_dword(dev, offset, bar->val);
-+ }
-+ bar->which = 0;
-+ }
++static void netbk_tx_pending_timeout(unsigned long unused)
++{
++ tasklet_schedule(&net_tx_tasklet);
++}
+
-+ return 0;
++struct net_device_stats *netif_be_get_stats(struct net_device *dev)
++{
++ netif_t *netif = netdev_priv(dev);
++ return &netif->stats;
+}
+
-+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
++static int __on_net_schedule_list(netif_t *netif)
+{
-+ struct pci_bar_info *bar = data;
++ return netif->list.next != NULL;
++}
+
-+ if (unlikely(!bar)) {
-+ printk(KERN_WARNING "pciback: driver data not found for %s\n",
-+ pci_name(dev));
-+ return XEN_PCI_ERR_op_failed;
++static void remove_from_net_schedule_list(netif_t *netif)
++{
++ spin_lock_irq(&net_schedule_list_lock);
++ if (likely(__on_net_schedule_list(netif))) {
++ list_del(&netif->list);
++ netif->list.next = NULL;
++ netif_put(netif);
+ }
-+
-+ *value = bar->which ? bar->len_val : bar->val;
-+
-+ return 0;
++ spin_unlock_irq(&net_schedule_list_lock);
+}
+
-+static inline void read_dev_bar(struct pci_dev *dev,
-+ struct pci_bar_info *bar_info, int offset,
-+ u32 len_mask)
++static void add_to_net_schedule_list_tail(netif_t *netif)
+{
-+ pci_read_config_dword(dev, offset, &bar_info->val);
-+ pci_write_config_dword(dev, offset, len_mask);
-+ pci_read_config_dword(dev, offset, &bar_info->len_val);
-+ pci_write_config_dword(dev, offset, bar_info->val);
++ if (__on_net_schedule_list(netif))
++ return;
++
++ spin_lock_irq(&net_schedule_list_lock);
++ if (!__on_net_schedule_list(netif) &&
++ likely(netif_schedulable(netif))) {
++ list_add_tail(&netif->list, &net_schedule_list);
++ netif_get(netif);
++ }
++ spin_unlock_irq(&net_schedule_list_lock);
+}
+
-+static void *bar_init(struct pci_dev *dev, int offset)
++/*
++ * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
++ * If this driver is pipelining transmit requests then we can be very
++ * aggressive in avoiding new-packet notifications -- frontend only needs to
++ * send a notification if there are no outstanding unreceived responses.
++ * If we may be buffer transmit buffers for any reason then we must be rather
++ * more conservative and treat this as the final check for pending work.
++ */
++void netif_schedule_work(netif_t *netif)
+{
-+ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++ int more_to_do;
+
-+ if (!bar)
-+ return ERR_PTR(-ENOMEM);
++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
++ more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
++#else
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++#endif
+
-+ read_dev_bar(dev, bar, offset, ~0);
-+ bar->which = 0;
++ if (more_to_do) {
++ add_to_net_schedule_list_tail(netif);
++ maybe_schedule_tx_action();
++ }
++}
+
-+ return bar;
++void netif_deschedule_work(netif_t *netif)
++{
++ remove_from_net_schedule_list(netif);
+}
+
-+static void *rom_init(struct pci_dev *dev, int offset)
++
++static void tx_add_credit(netif_t *netif)
+{
-+ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++ unsigned long max_burst, max_credit;
+
-+ if (!bar)
-+ return ERR_PTR(-ENOMEM);
++ /*
++ * 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(&netif->tx, netif->tx.req_cons)->size;
++ max_burst = min(max_burst, 131072UL);
++ max_burst = max(max_burst, netif->credit_bytes);
+
-+ read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
-+ bar->which = 0;
++ /* Take care that adding a new chunk of credit doesn't wrap to zero. */
++ max_credit = netif->remaining_credit + netif->credit_bytes;
++ if (max_credit < netif->remaining_credit)
++ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
+
-+ return bar;
++ netif->remaining_credit = min(max_credit, max_burst);
+}
+
-+static void bar_reset(struct pci_dev *dev, int offset, void *data)
++static void tx_credit_callback(unsigned long data)
+{
-+ struct pci_bar_info *bar = data;
-+
-+ bar->which = 0;
++ netif_t *netif = (netif_t *)data;
++ tx_add_credit(netif);
++ netif_schedule_work(netif);
+}
+
-+static void bar_release(struct pci_dev *dev, int offset, void *data)
++static inline int copy_pending_req(PEND_RING_IDX pending_idx)
+{
-+ kfree(data);
++ return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
++ &mmap_pages[pending_idx]);
+}
+
-+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
-+ void *data)
++inline static void net_tx_action_dealloc(void)
+{
-+ *value = (u8) dev->irq;
++ struct netbk_tx_pending_inuse *inuse, *n;
++ gnttab_unmap_grant_ref_t *gop;
++ u16 pending_idx;
++ PEND_RING_IDX dc, dp;
++ netif_t *netif;
++ int ret;
++ LIST_HEAD(list);
+
-+ return 0;
-+}
++ dc = dealloc_cons;
++ gop = tx_unmap_ops;
+
-+static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
-+{
-+ u8 cur_value;
-+ int err;
++ /*
++ * Free up any grants we have finished using
++ */
++ do {
++ dp = dealloc_prod;
+
-+ err = pci_read_config_byte(dev, offset, &cur_value);
-+ if (err)
-+ goto out;
++ /* Ensure we see all indices enqueued by netif_idx_release(). */
++ smp_rmb();
+
-+ if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
-+ || value == PCI_BIST_START)
-+ err = pci_write_config_byte(dev, offset, value);
++ while (dc != dp) {
++ unsigned long pfn;
+
-+ out:
-+ return err;
-+}
++ pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
++ list_move_tail(&pending_inuse[pending_idx].list, &list);
+
-+static const struct config_field header_common[] = {
-+ {
-+ .offset = PCI_COMMAND,
-+ .size = 2,
-+ .u.w.read = pciback_read_config_word,
-+ .u.w.write = command_write,
-+ },
-+ {
-+ .offset = PCI_INTERRUPT_LINE,
-+ .size = 1,
-+ .u.b.read = interrupt_read,
-+ },
-+ {
-+ .offset = PCI_INTERRUPT_PIN,
-+ .size = 1,
-+ .u.b.read = pciback_read_config_byte,
-+ },
-+ {
-+ /* Any side effects of letting driver domain control cache line? */
-+ .offset = PCI_CACHE_LINE_SIZE,
-+ .size = 1,
-+ .u.b.read = pciback_read_config_byte,
-+ .u.b.write = pciback_write_config_byte,
-+ },
-+ {
-+ .offset = PCI_LATENCY_TIMER,
-+ .size = 1,
-+ .u.b.read = pciback_read_config_byte,
-+ },
-+ {
-+ .offset = PCI_BIST,
-+ .size = 1,
-+ .u.b.read = pciback_read_config_byte,
-+ .u.b.write = bist_write,
-+ },
-+ {}
-+};
++ pfn = idx_to_pfn(pending_idx);
++ /* Already unmapped? */
++ if (!phys_to_machine_mapping_valid(pfn))
++ continue;
+
-+#define CFG_FIELD_BAR(reg_offset) \
-+ { \
-+ .offset = reg_offset, \
-+ .size = 4, \
-+ .init = bar_init, \
-+ .reset = bar_reset, \
-+ .release = bar_release, \
-+ .u.dw.read = bar_read, \
-+ .u.dw.write = bar_write, \
-+ }
++ gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
++ GNTMAP_host_map,
++ grant_tx_handle[pending_idx]);
++ gop++;
++ }
+
-+#define CFG_FIELD_ROM(reg_offset) \
-+ { \
-+ .offset = reg_offset, \
-+ .size = 4, \
-+ .init = rom_init, \
-+ .reset = bar_reset, \
-+ .release = bar_release, \
-+ .u.dw.read = bar_read, \
-+ .u.dw.write = rom_write, \
-+ }
++ if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
++ list_empty(&pending_inuse_head))
++ break;
+
-+static const struct config_field header_0[] = {
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
-+ CFG_FIELD_ROM(PCI_ROM_ADDRESS),
-+ {}
-+};
++ /* Copy any entries that have been pending for too long. */
++ list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
++ if (time_after(inuse->alloc_time + HZ / 2, jiffies))
++ break;
+
-+static const struct config_field header_1[] = {
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
-+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
-+ CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
-+ {}
-+};
++ switch (copy_pending_req(inuse - pending_inuse)) {
++ case 0:
++ list_move_tail(&inuse->list, &list);
++ continue;
++ case -EBUSY:
++ list_del_init(&inuse->list);
++ continue;
++ case -ENOENT:
++ continue;
++ }
+
-+int pciback_config_header_add_fields(struct pci_dev *dev)
-+{
-+ int err;
++ break;
++ }
++ } while (dp != dealloc_prod);
+
-+ err = pciback_config_add_fields(dev, header_common);
-+ if (err)
-+ goto out;
++ dealloc_cons = dc;
+
-+ switch (dev->hdr_type) {
-+ case PCI_HEADER_TYPE_NORMAL:
-+ err = pciback_config_add_fields(dev, header_0);
-+ break;
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
++ BUG_ON(ret);
+
-+ case PCI_HEADER_TYPE_BRIDGE:
-+ err = pciback_config_add_fields(dev, header_1);
-+ break;
++ list_for_each_entry_safe(inuse, n, &list, list) {
++ pending_idx = inuse - pending_inuse;
+
-+ default:
-+ err = -EINVAL;
-+ printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
-+ pci_name(dev), dev->hdr_type);
-+ break;
-+ }
++ netif = pending_tx_info[pending_idx].netif;
+
-+ out:
-+ return err;
-+}
-diff --git a/drivers/xen/pciback/conf_space_quirks.c
b/drivers/xen/pciback/conf_space_quirks.c
-new file mode 100644
-index 0000000..244a438
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_quirks.c
-@@ -0,0 +1,138 @@
-+/*
-+ * PCI Backend - Handle special overlays for broken devices.
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ * Author: Chris Bookholt <hap10(a)epoch.ncsc.mil>
-+ */
++ make_tx_response(netif, &pending_tx_info[pending_idx].req,
++ NETIF_RSP_OKAY);
+
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_quirks.h"
++ /* Ready for next use. */
++ gnttab_reset_grant_page(mmap_pages[pending_idx]);
+
-+LIST_HEAD(pciback_quirks);
++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+
-+static inline const struct pci_device_id *
-+match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
-+{
-+ if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
-+ (id->device == PCI_ANY_ID || id->device == dev->device) &&
-+ (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor)
&&
-+ (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device)
&&
-+ !((id->class ^ dev->class) & id->class_mask))
-+ return id;
-+ return NULL;
++ netif_put(netif);
++
++ list_del_init(&inuse->list);
++ }
+}
+
-+struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
++static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
+{
-+ struct pciback_config_quirk *tmp_quirk;
++ RING_IDX cons = netif->tx.req_cons;
+
-+ list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list)
-+ if (match_one_device(&tmp_quirk->devid, dev) != NULL)
-+ goto out;
-+ tmp_quirk = NULL;
-+ printk(KERN_DEBUG
-+ "quirk didn't match any device pciback knows about\n");
-+ out:
-+ return tmp_quirk;
++ do {
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ if (cons >= end)
++ break;
++ txp = RING_GET_REQUEST(&netif->tx, cons++);
++ } while (1);
++ netif->tx.req_cons = cons;
++ netif_schedule_work(netif);
++ netif_put(netif);
+}
+
-+static inline void register_quirk(struct pciback_config_quirk *quirk)
++static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
++ netif_tx_request_t *txp, int work_to_do)
+{
-+ list_add_tail(&quirk->quirks_list, &pciback_quirks);
-+}
++ RING_IDX cons = netif->tx.req_cons;
++ int frags = 0;
+
-+int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg)
-+{
-+ int ret = 0;
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+ struct config_field_entry *cfg_entry;
++ if (!(first->flags & NETTXF_more_data))
++ return 0;
+
-+ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+ if ( OFFSET(cfg_entry) == reg) {
-+ ret = 1;
-+ break;
++ do {
++ if (frags >= work_to_do) {
++ DPRINTK("Need more frags\n");
++ return -frags;
+ }
-+ }
-+ return ret;
-+}
+
-+int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
-+ *field)
-+{
-+ int err = 0;
++ if (unlikely(frags >= MAX_SKB_FRAGS)) {
++ DPRINTK("Too many frags\n");
++ return -frags;
++ }
+
-+ switch (field->size) {
-+ case 1:
-+ field->u.b.read = pciback_read_config_byte;
-+ field->u.b.write = pciback_write_config_byte;
-+ break;
-+ case 2:
-+ field->u.w.read = pciback_read_config_word;
-+ field->u.w.write = pciback_write_config_word;
-+ break;
-+ case 4:
-+ field->u.dw.read = pciback_read_config_dword;
-+ field->u.dw.write = pciback_write_config_dword;
-+ break;
-+ default:
-+ err = -EINVAL;
-+ goto out;
-+ }
++ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
++ sizeof(*txp));
++ if (txp->size > first->size) {
++ DPRINTK("Frags galore\n");
++ return -frags;
++ }
+
-+ pciback_config_add_field(dev, field);
++ first->size -= txp->size;
++ frags++;
+
-+ out:
-+ return err;
++ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
++ DPRINTK("txp->offset: %x, size: %u\n",
++ txp->offset, txp->size);
++ return -frags;
++ }
++ } while ((txp++)->flags & NETTXF_more_data);
++
++ return frags;
+}
+
-+int pciback_config_quirks_init(struct pci_dev *dev)
++static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
++ struct sk_buff *skb,
++ netif_tx_request_t *txp,
++ gnttab_map_grant_ref_t *mop)
+{
-+ struct pciback_config_quirk *quirk;
-+ int ret = 0;
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ skb_frag_t *frags = shinfo->frags;
++ unsigned long pending_idx = *((u16 *)skb->data);
++ int i, start;
+
-+ quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC);
-+ if (!quirk) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
++ /* Skip first skb fragment if it is on same page as header fragment. */
++ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+
-+ quirk->devid.vendor = dev->vendor;
-+ quirk->devid.device = dev->device;
-+ quirk->devid.subvendor = dev->subsystem_vendor;
-+ quirk->devid.subdevice = dev->subsystem_device;
-+ quirk->devid.class = 0;
-+ quirk->devid.class_mask = 0;
-+ quirk->devid.driver_data = 0UL;
++ for (i = start; i < shinfo->nr_frags; i++, txp++) {
++ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)];
+
-+ quirk->pdev = dev;
++ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
++ GNTMAP_host_map | GNTMAP_readonly,
++ txp->gref, netif->domid);
+
-+ register_quirk(quirk);
-+ out:
-+ return ret;
-+}
++ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
++ netif_get(netif);
++ pending_tx_info[pending_idx].netif = netif;
++ frags[i].page = (void *)pending_idx;
++ }
+
-+void pciback_config_field_free(struct config_field *field)
-+{
-+ kfree(field);
++ return mop;
+}
+
-+int pciback_config_quirk_release(struct pci_dev *dev)
++static int netbk_tx_check_mop(struct sk_buff *skb,
++ gnttab_map_grant_ref_t **mopp)
+{
-+ struct pciback_config_quirk *quirk;
-+ int ret = 0;
++ gnttab_map_grant_ref_t *mop = *mopp;
++ int pending_idx = *((u16 *)skb->data);
++ netif_t *netif = pending_tx_info[pending_idx].netif;
++ netif_tx_request_t *txp;
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ int nr_frags = shinfo->nr_frags;
++ int i, err, start;
+
-+ quirk = pciback_find_quirk(dev);
-+ if (!quirk) {
-+ ret = -ENXIO;
-+ goto out;
++ /* Check status of header. */
++ err = mop->status;
++ if (unlikely(err)) {
++ txp = &pending_tx_info[pending_idx].req;
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++ netif_put(netif);
++ } else {
++ set_phys_to_machine(
++ __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
++ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
++ grant_tx_handle[pending_idx] = mop->handle;
+ }
+
-+ list_del(&quirk->quirks_list);
-+ kfree(quirk);
++ /* Skip first skb fragment if it is on same page as header fragment. */
++ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+
-+ out:
-+ return ret;
-+}
-diff --git a/drivers/xen/pciback/conf_space_quirks.h
b/drivers/xen/pciback/conf_space_quirks.h
-new file mode 100644
-index 0000000..acd0e1a
---- /dev/null
-+++ b/drivers/xen/pciback/conf_space_quirks.h
-@@ -0,0 +1,35 @@
-+/*
-+ * PCI Backend - Data structures for special overlays for broken devices.
-+ *
-+ * Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ * Chris Bookholt <hap10(a)epoch.ncsc.mil>
-+ */
++ for (i = start; i < nr_frags; i++) {
++ int j, newerr;
+
-+#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
-+#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++ pending_idx = (unsigned long)shinfo->frags[i].page;
+
-+#include <linux/pci.h>
-+#include <linux/list.h>
++ /* Check error status: if okay then remember grant handle. */
++ newerr = (++mop)->status;
++ if (likely(!newerr)) {
++ set_phys_to_machine(
++ __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
++ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
++ grant_tx_handle[pending_idx] = mop->handle;
++ /* Had a previous error? Invalidate this fragment. */
++ if (unlikely(err))
++ netif_idx_release(pending_idx);
++ continue;
++ }
+
-+struct pciback_config_quirk {
-+ struct list_head quirks_list;
-+ struct pci_device_id devid;
-+ struct pci_dev *pdev;
-+};
++ /* 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;
++ netif_put(netif);
+
-+struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev);
++ /* Not the first error? Preceding frags already invalidated. */
++ if (err)
++ continue;
+
-+int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
-+ *field);
++ /* First error: invalidate header and preceding fragments. */
++ pending_idx = *((u16 *)skb->data);
++ netif_idx_release(pending_idx);
++ for (j = start; j < i; j++) {
++ pending_idx = (unsigned long)shinfo->frags[i].page;
++ netif_idx_release(pending_idx);
++ }
+
-+int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg);
++ /* Remember the error: invalidate all subsequent fragments. */
++ err = newerr;
++ }
+
-+int pciback_config_quirks_init(struct pci_dev *dev);
++ *mopp = mop + 1;
++ return err;
++}
+
-+void pciback_config_field_free(struct config_field *field);
++static void netbk_fill_frags(struct sk_buff *skb)
++{
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ int nr_frags = shinfo->nr_frags;
++ int i;
+
-+int pciback_config_quirk_release(struct pci_dev *dev);
++ for (i = 0; i < nr_frags; i++) {
++ skb_frag_t *frag = shinfo->frags + i;
++ netif_tx_request_t *txp;
++ unsigned long pending_idx;
+
-+int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg);
++ pending_idx = (unsigned long)frag->page;
+
-+#endif
-diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
-new file mode 100644
-index 0000000..294e48f
---- /dev/null
-+++ b/drivers/xen/pciback/controller.c
-@@ -0,0 +1,443 @@
-+/*
-+ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
-+ * Alex Williamson <alex.williamson(a)hp.com>
-+ *
-+ * PCI "Controller" Backend - virtualize PCI bus topology based on PCI
-+ * controllers. Devices under the same PCI controller are exposed on the
-+ * same virtual domain:bus. Within a bus, device slots are virtualized
-+ * to compact the bus.
-+ *
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ */
++ pending_inuse[pending_idx].alloc_time = jiffies;
++ list_add_tail(&pending_inuse[pending_idx].list,
++ &pending_inuse_head);
+
-+#include <linux/acpi.h>
-+#include <linux/list.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
++ txp = &pending_tx_info[pending_idx].req;
++ frag->page = virt_to_page(idx_to_kaddr(pending_idx));
++ frag->size = txp->size;
++ frag->page_offset = txp->offset;
+
-+#define PCI_MAX_BUSSES 255
-+#define PCI_MAX_SLOTS 32
++ skb->len += txp->size;
++ skb->data_len += txp->size;
++ skb->truesize += txp->size;
++ }
++}
+
-+struct controller_dev_entry {
-+ struct list_head list;
-+ struct pci_dev *dev;
-+ unsigned int devfn;
-+};
++int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
++ int work_to_do)
++{
++ struct netif_extra_info extra;
++ RING_IDX cons = netif->tx.req_cons;
+
-+struct controller_list_entry {
-+ struct list_head list;
-+ struct pci_controller *controller;
-+ unsigned int domain;
-+ unsigned int bus;
-+ unsigned int next_devfn;
-+ struct list_head dev_list;
-+};
++ do {
++ if (unlikely(work_to_do-- <= 0)) {
++ DPRINTK("Missing extra info\n");
++ return -EBADR;
++ }
+
-+struct controller_dev_data {
-+ struct list_head list;
-+ unsigned int next_domain;
-+ unsigned int next_bus;
-+ spinlock_t lock;
-+};
++ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
++ sizeof(extra));
++ if (unlikely(!extra.type ||
++ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++ netif->tx.req_cons = ++cons;
++ DPRINTK("Invalid extra type: %d\n", extra.type);
++ return -EINVAL;
++ }
+
-+struct walk_info {
-+ struct pciback_device *pdev;
-+ int resource_count;
-+ int root_num;
-+};
++ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
++ netif->tx.req_cons = ++cons;
++ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn)
-+{
-+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+ struct controller_dev_entry *dev_entry;
-+ struct controller_list_entry *cntrl_entry;
-+ struct pci_dev *dev = NULL;
-+ unsigned long flags;
++ return work_to_do;
++}
+
-+ spin_lock_irqsave(&dev_data->lock, flags);
-+
-+ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+ if (cntrl_entry->domain != domain ||
-+ cntrl_entry->bus != bus)
-+ continue;
-+
-+ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
-+ if (devfn == dev_entry->devfn) {
-+ dev = dev_entry->dev;
-+ goto found;
-+ }
-+ }
-+ }
-+found:
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
-+
-+ return dev;
-+}
-+
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
-+ int devid, publish_pci_dev_cb publish_cb)
++static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
+{
-+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+ struct controller_dev_entry *dev_entry;
-+ struct controller_list_entry *cntrl_entry;
-+ struct pci_controller *dev_controller = PCI_CONTROLLER(dev);
-+ unsigned long flags;
-+ int ret = 0, found = 0;
-+
-+ spin_lock_irqsave(&dev_data->lock, flags);
++ if (!gso->u.gso.size) {
++ DPRINTK("GSO size must not be zero.\n");
++ return -EINVAL;
++ }
+
-+ /* Look to see if we already have a domain:bus for this controller */
-+ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+ if (cntrl_entry->controller == dev_controller) {
-+ found = 1;
-+ break;
-+ }
++ /* Currently only TCPv4 S.O. is supported. */
++ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
++ DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
++ return -EINVAL;
+ }
+
-+ if (!found) {
-+ cntrl_entry = kmalloc(sizeof(*cntrl_entry), GFP_ATOMIC);
-+ if (!cntrl_entry) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
++ skb_shinfo(skb)->gso_size = gso->u.gso.size;
++ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
-+ cntrl_entry->controller = dev_controller;
-+ cntrl_entry->next_devfn = PCI_DEVFN(0, 0);
++ /* Header must be checked, and gso_segs computed. */
++ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++ skb_shinfo(skb)->gso_segs = 0;
+
-+ cntrl_entry->domain = dev_data->next_domain;
-+ cntrl_entry->bus = dev_data->next_bus++;
-+ if (dev_data->next_bus > PCI_MAX_BUSSES) {
-+ dev_data->next_domain++;
-+ dev_data->next_bus = 0;
-+ }
++ return 0;
++}
+
-+ INIT_LIST_HEAD(&cntrl_entry->dev_list);
++/* Called after netfront has transmitted */
++static void net_tx_action(unsigned long unused)
++{
++ struct list_head *ent;
++ struct sk_buff *skb;
++ netif_t *netif;
++ netif_tx_request_t txreq;
++ netif_tx_request_t txfrags[MAX_SKB_FRAGS];
++ struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++ u16 pending_idx;
++ RING_IDX i;
++ gnttab_map_grant_ref_t *mop;
++ unsigned int data_len;
++ int ret, work_to_do;
+
-+ list_add_tail(&cntrl_entry->list, &dev_data->list);
-+ }
++ if (dealloc_cons != dealloc_prod)
++ net_tx_action_dealloc();
+
-+ if (PCI_SLOT(cntrl_entry->next_devfn) > PCI_MAX_SLOTS) {
-+ /*
-+ * While it seems unlikely, this can actually happen if
-+ * a controller has P2P bridges under it.
-+ */
-+ xenbus_dev_fatal(pdev->xdev, -ENOSPC, "Virtual bus %04x:%02x "
-+ "is full, no room to export %04x:%02x:%02x.%x",
-+ cntrl_entry->domain, cntrl_entry->bus,
-+ pci_domain_nr(dev->bus), dev->bus->number,
-+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-+ ret = -ENOSPC;
-+ goto out;
-+ }
++ mop = tx_map_ops;
++ while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ !list_empty(&net_schedule_list)) {
++ /* Get a netif from the list with work to do. */
++ ent = net_schedule_list.next;
++ netif = list_entry(ent, netif_t, list);
++ netif_get(netif);
++ remove_from_net_schedule_list(netif);
+
-+ dev_entry = kmalloc(sizeof(*dev_entry), GFP_ATOMIC);
-+ if (!dev_entry) {
-+ if (list_empty(&cntrl_entry->dev_list)) {
-+ list_del(&cntrl_entry->list);
-+ kfree(cntrl_entry);
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
++ if (!work_to_do) {
++ netif_put(netif);
++ continue;
+ }
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ dev_entry->dev = dev;
-+ dev_entry->devfn = cntrl_entry->next_devfn;
+
-+ list_add_tail(&dev_entry->list, &cntrl_entry->dev_list);
-+
-+ cntrl_entry->next_devfn += PCI_DEVFN(1, 0);
-+
-+out:
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
++ i = netif->tx.req_cons;
++ rmb(); /* Ensure that we see the request before we copy it. */
++ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
+
-+ /* TODO: Publish virtual domain:bus:slot.func here. */
++ /* Credit-based scheduling. */
++ if (txreq.size > netif->remaining_credit) {
++ unsigned long now = jiffies;
++ unsigned long next_credit =
++ netif->credit_timeout.expires +
++ msecs_to_jiffies(netif->credit_usec / 1000);
+
-+ return ret;
-+}
++ /* Timer could already be pending in rare cases. */
++ if (timer_pending(&netif->credit_timeout)) {
++ netif_put(netif);
++ continue;
++ }
+
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+ struct controller_list_entry *cntrl_entry;
-+ struct controller_dev_entry *dev_entry = NULL;
-+ struct pci_dev *found_dev = NULL;
-+ unsigned long flags;
++ /* Passed the point where we can replenish credit? */
++ if (time_after_eq(now, next_credit)) {
++ netif->credit_timeout.expires = now;
++ tx_add_credit(netif);
++ }
+
-+ spin_lock_irqsave(&dev_data->lock, flags);
++ /* Still too big to send right now? Set a callback. */
++ if (txreq.size > netif->remaining_credit) {
++ netif->credit_timeout.data =
++ (unsigned long)netif;
++ netif->credit_timeout.function =
++ tx_credit_callback;
++ __mod_timer(&netif->credit_timeout,
++ next_credit);
++ netif_put(netif);
++ continue;
++ }
++ }
++ netif->remaining_credit -= txreq.size;
+
-+ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+ if (cntrl_entry->controller != PCI_CONTROLLER(dev))
-+ continue;
++ work_to_do--;
++ netif->tx.req_cons = ++i;
+
-+ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
-+ if (dev_entry->dev == dev) {
-+ found_dev = dev_entry->dev;
-+ break;
++ memset(extras, 0, sizeof(extras));
++ if (txreq.flags & NETTXF_extra_info) {
++ work_to_do = netbk_get_extras(netif, extras,
++ work_to_do);
++ i = netif->tx.req_cons;
++ if (unlikely(work_to_do < 0)) {
++ netbk_tx_err(netif, &txreq, i);
++ continue;
+ }
+ }
-+ }
+
-+ if (!found_dev) {
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
-+ return;
-+ }
++ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
++ if (unlikely(ret < 0)) {
++ netbk_tx_err(netif, &txreq, i - ret);
++ continue;
++ }
++ i += ret;
+
-+ list_del(&dev_entry->list);
-+ kfree(dev_entry);
++ if (unlikely(txreq.size < ETH_HLEN)) {
++ DPRINTK("Bad packet size: %d\n", txreq.size);
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
+
-+ if (list_empty(&cntrl_entry->dev_list)) {
-+ list_del(&cntrl_entry->list);
-+ kfree(cntrl_entry);
-+ }
++ /* No crossing a page as the payload mustn't fragment. */
++ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
++ DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
++ txreq.offset, txreq.size,
++ (txreq.offset &~PAGE_MASK) + txreq.size);
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
+
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
-+ pcistub_put_pci_dev(found_dev);
-+}
++ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+
-+int pciback_init_devices(struct pciback_device *pdev)
-+{
-+ struct controller_dev_data *dev_data;
++ data_len = (txreq.size > PKT_PROT_LEN &&
++ ret < MAX_SKB_FRAGS) ?
++ PKT_PROT_LEN : txreq.size;
+
-+ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
-+ if (!dev_data)
-+ return -ENOMEM;
++ skb = alloc_skb(data_len + 16 + NET_IP_ALIGN,
++ GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(skb == NULL)) {
++ DPRINTK("Can't allocate a skb in start_xmit.\n");
++ netbk_tx_err(netif, &txreq, i);
++ break;
++ }
+
-+ spin_lock_init(&dev_data->lock);
++ /* Packets passed to netif_rx() must have some headroom. */
++ skb_reserve(skb, 16 + NET_IP_ALIGN);
+
-+ INIT_LIST_HEAD(&dev_data->list);
++ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
++ struct netif_extra_info *gso;
++ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
-+ /* Starting domain:bus numbers */
-+ dev_data->next_domain = 0;
-+ dev_data->next_bus = 0;
++ if (netbk_set_skb_gso(skb, gso)) {
++ kfree_skb(skb);
++ netbk_tx_err(netif, &txreq, i);
++ continue;
++ }
++ }
+
-+ pdev->pci_dev_data = dev_data;
++ gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
++ GNTMAP_host_map | GNTMAP_readonly,
++ txreq.gref, netif->domid);
++ mop++;
+
-+ return 0;
-+}
++ memcpy(&pending_tx_info[pending_idx].req,
++ &txreq, sizeof(txreq));
++ pending_tx_info[pending_idx].netif = netif;
++ *((u16 *)skb->data) = pending_idx;
+
-+static acpi_status write_xenbus_resource(struct acpi_resource *res, void *data)
-+{
-+ struct walk_info *info = data;
-+ struct acpi_resource_address64 addr;
-+ acpi_status status;
-+ int i, len, err;
-+ char str[32], tmp[3];
-+ unsigned char *ptr, *buf;
++ __skb_put(skb, data_len);
+
-+ status = acpi_resource_to_address64(res, &addr);
++ skb_shinfo(skb)->nr_frags = ret;
++ if (data_len < txreq.size) {
++ skb_shinfo(skb)->nr_frags++;
++ skb_shinfo(skb)->frags[0].page =
++ (void *)(unsigned long)pending_idx;
++ } else {
++ /* Discriminate from any valid pending_idx value. */
++ skb_shinfo(skb)->frags[0].page = (void *)~0UL;
++ }
+
-+ /* Do we care about this range? Let's check. */
-+ if (!ACPI_SUCCESS(status) ||
-+ !(addr.resource_type == ACPI_MEMORY_RANGE ||
-+ addr.resource_type == ACPI_IO_RANGE) ||
-+ !addr.address_length || addr.producer_consumer != ACPI_PRODUCER)
-+ return AE_OK;
++ if (skb->data_len < skb_shinfo(skb)->gso_size) {
++ skb_shinfo(skb)->gso_size = 0;
++ skb_shinfo(skb)->gso_type = 0;
++ }
+
-+ /*
-+ * Furthermore, we really only care to tell the guest about
-+ * address ranges that require address translation of some sort.
-+ */
-+ if (!(addr.resource_type == ACPI_MEMORY_RANGE &&
-+ addr.info.mem.translation) &&
-+ !(addr.resource_type == ACPI_IO_RANGE &&
-+ addr.info.io.translation))
-+ return AE_OK;
-+
-+ /* Store the resource in xenbus for the guest */
-+ len = snprintf(str, sizeof(str), "root-%d-resource-%d",
-+ info->root_num, info->resource_count);
-+ if (unlikely(len >= (sizeof(str) - 1)))
-+ return AE_OK;
++ __skb_queue_tail(&tx_queue, skb);
+
-+ buf = kzalloc((sizeof(*res) * 2) + 1, GFP_KERNEL);
-+ if (!buf)
-+ return AE_OK;
++ pending_cons++;
+
-+ /* Clean out resource_source */
-+ res->data.address64.resource_source.index = 0xFF;
-+ res->data.address64.resource_source.string_length = 0;
-+ res->data.address64.resource_source.string_ptr = NULL;
++ mop = netbk_get_requests(netif, skb, txfrags, mop);
+
-+ ptr = (unsigned char *)res;
++ netif->tx.req_cons = i;
++ netif_schedule_work(netif);
+
-+ /* Turn the acpi_resource into an ASCII byte stream */
-+ for (i = 0; i < sizeof(*res); i++) {
-+ snprintf(tmp, sizeof(tmp), "%02x", ptr[i]);
-+ strncat(buf, tmp, 2);
++ if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
++ break;
+ }
+
-+ err = xenbus_printf(XBT_NIL, info->pdev->xdev->nodename,
-+ str, "%s", buf);
-+
-+ if (!err)
-+ info->resource_count++;
++ if (mop == tx_map_ops)
++ return;
+
-+ kfree(buf);
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
++ BUG_ON(ret);
+
-+ return AE_OK;
-+}
++ mop = tx_map_ops;
++ while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
++ netif_tx_request_t *txp;
+
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+ publish_pci_root_cb publish_root_cb)
-+{
-+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+ struct controller_list_entry *cntrl_entry;
-+ int i, root_num, len, err = 0;
-+ unsigned int domain, bus;
-+ char str[64];
-+ struct walk_info info;
++ pending_idx = *((u16 *)skb->data);
++ netif = pending_tx_info[pending_idx].netif;
++ txp = &pending_tx_info[pending_idx].req;
+
-+ spin_lock(&dev_data->lock);
++ /* Check the remap error code. */
++ if (unlikely(netbk_tx_check_mop(skb, &mop))) {
++ DPRINTK("netback grant failed.\n");
++ skb_shinfo(skb)->nr_frags = 0;
++ kfree_skb(skb);
++ continue;
++ }
+
-+ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+ /* First publish all the domain:bus info */
-+ err = publish_root_cb(pdev, cntrl_entry->domain,
-+ cntrl_entry->bus);
-+ if (err)
-+ goto out;
++ data_len = skb->len;
++ memcpy(skb->data,
++ (void *)(idx_to_kaddr(pending_idx)|txp->offset),
++ data_len);
++ if (data_len < txp->size) {
++ /* Append the packet payload as a fragment. */
++ txp->offset += data_len;
++ txp->size -= data_len;
++ } else {
++ /* Schedule a response immediately. */
++ netif_idx_release(pending_idx);
++ }
+
+ /*
-+ * Now figure out which root-%d this belongs to
-+ * so we can associate resources with it.
++ * Old frontends do not assert data_validated but we
++ * can infer it from csum_blank so test both flags.
+ */
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+ "root_num", "%d", &root_num);
-+
-+ if (err != 1)
-+ goto out;
-+
-+ for (i = 0; i < root_num; i++) {
-+ len = snprintf(str, sizeof(str), "root-%d", i);
-+ if (unlikely(len >= (sizeof(str) - 1))) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+ str, "%x:%x", &domain, &bus);
-+ if (err != 2)
-+ goto out;
-+
-+ /* Is this the one we just published? */
-+ if (domain == cntrl_entry->domain &&
-+ bus == cntrl_entry->bus)
-+ break;
++ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++ skb->proto_data_valid = 1;
++ } else {
++ skb->ip_summed = CHECKSUM_NONE;
++ skb->proto_data_valid = 0;
+ }
++ skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
+
-+ if (i == root_num)
-+ goto out;
++ netbk_fill_frags(skb);
+
-+ info.pdev = pdev;
-+ info.resource_count = 0;
-+ info.root_num = i;
++ skb->dev = netif->dev;
++ skb->protocol = eth_type_trans(skb, skb->dev);
+
-+ /* Let ACPI do the heavy lifting on decoding resources */
-+ acpi_walk_resources(cntrl_entry->controller->acpi_handle,
-+ METHOD_NAME__CRS, write_xenbus_resource,
-+ &info);
++ netif->stats.rx_bytes += skb->len;
++ netif->stats.rx_packets++;
+
-+ /* No resouces. OK. On to the next one */
-+ if (!info.resource_count)
++ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
++ unlikely(skb_linearize(skb))) {
++ DPRINTK("Can't linearize skb in net_tx_action.\n");
++ kfree_skb(skb);
+ continue;
-+
-+ /* Store the number of resources we wrote for this root-%d */
-+ len = snprintf(str, sizeof(str), "root-%d-resources", i);
-+ if (unlikely(len >= (sizeof(str) - 1))) {
-+ err = -ENOMEM;
-+ goto out;
+ }
+
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+ "%d", info.resource_count);
-+ if (err)
-+ goto out;
++ netif_rx(skb);
++ netif->dev->last_rx = jiffies;
+ }
+
-+ /* Finally, write some magic to synchronize with the guest. */
-+ len = snprintf(str, sizeof(str), "root-resource-magic");
-+ if (unlikely(len >= (sizeof(str) - 1))) {
-+ err = -ENOMEM;
-+ goto out;
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !list_empty(&pending_inuse_head)) {
++ struct netbk_tx_pending_inuse *oldest;
++
++ oldest = list_entry(pending_inuse_head.next,
++ struct netbk_tx_pending_inuse, list);
++ mod_timer(&netbk_tx_pending_timer, oldest->alloc_time + HZ);
+ }
++}
+
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+ "%lx", (sizeof(struct acpi_resource) * 2) + 1);
++static void netif_idx_release(u16 pending_idx)
++{
++ static DEFINE_SPINLOCK(_lock);
++ unsigned long flags;
+
-+out:
-+ spin_unlock(&dev_data->lock);
++ spin_lock_irqsave(&_lock, flags);
++ dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
++ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
++ smp_wmb();
++ dealloc_prod++;
++ spin_unlock_irqrestore(&_lock, flags);
+
-+ return err;
++ tasklet_schedule(&net_tx_tasklet);
+}
+
-+void pciback_release_devices(struct pciback_device *pdev)
++static void netif_page_release(struct page *page, unsigned int order)
+{
-+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+ struct controller_list_entry *cntrl_entry, *c;
-+ struct controller_dev_entry *dev_entry, *d;
++ int idx = netif_page_index(page);
++ BUG_ON(order);
++ BUG_ON(idx < 0);
++ netif_idx_release(idx);
++}
+
-+ list_for_each_entry_safe(cntrl_entry, c, &dev_data->list, list) {
-+ list_for_each_entry_safe(dev_entry, d,
-+ &cntrl_entry->dev_list, list) {
-+ list_del(&dev_entry->list);
-+ pcistub_put_pci_dev(dev_entry->dev);
-+ kfree(dev_entry);
-+ }
-+ list_del(&cntrl_entry->list);
-+ kfree(cntrl_entry);
-+ }
++irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ netif_t *netif = dev_id;
+
-+ kfree(dev_data);
-+ pdev->pci_dev_data = NULL;
++ add_to_net_schedule_list_tail(netif);
++ maybe_schedule_tx_action();
++
++ if (netif_schedulable(netif) && !netbk_queue_full(netif))
++ netif_wake_queue(netif->dev);
++
++ return IRQ_HANDLED;
+}
+
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-+ struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++static void make_tx_response(netif_t *netif,
++ netif_tx_request_t *txp,
++ s8 st)
+{
-+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+ struct controller_dev_entry *dev_entry;
-+ struct controller_list_entry *cntrl_entry;
-+ unsigned long flags;
-+ int found = 0;
-+ spin_lock_irqsave(&dev_data->lock, flags);
-+
-+ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
-+ if ( (dev_entry->dev->bus->number ==
-+ pcidev->bus->number) &&
-+ (dev_entry->dev->devfn ==
-+ pcidev->devfn) &&
-+ (pci_domain_nr(dev_entry->dev->bus) ==
-+ pci_domain_nr(pcidev->bus)))
-+ {
-+ found = 1;
-+ *domain = cntrl_entry->domain;
-+ *bus = cntrl_entry->bus;
-+ *devfn = dev_entry->devfn;
-+ goto out;
-+ }
-+ }
-+ }
-+out:
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
-+ return found;
-+
-+}
-+
-diff --git a/drivers/xen/pciback/passthrough.c b/drivers/xen/pciback/passthrough.c
-new file mode 100644
-index 0000000..9e7a0c4
---- /dev/null
-+++ b/drivers/xen/pciback/passthrough.c
-@@ -0,0 +1,176 @@
-+/*
-+ * PCI Backend - Provides restricted access to the real PCI bus topology
-+ * to the frontend
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
-+
-+#include <linux/list.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
++ RING_IDX i = netif->tx.rsp_prod_pvt;
++ netif_tx_response_t *resp;
++ int notify;
+
-+struct passthrough_dev_data {
-+ /* Access to dev_list must be protected by lock */
-+ struct list_head dev_list;
-+ spinlock_t lock;
-+};
++ resp = RING_GET_RESPONSE(&netif->tx, i);
++ resp->id = txp->id;
++ resp->status = st;
+
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn)
-+{
-+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+ struct pci_dev_entry *dev_entry;
-+ struct pci_dev *dev = NULL;
-+ unsigned long flags;
++ if (txp->flags & NETTXF_extra_info)
++ RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
+
-+ spin_lock_irqsave(&dev_data->lock, flags);
++ netif->tx.rsp_prod_pvt = ++i;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
++ if (notify)
++ notify_remote_via_irq(netif->irq);
+
-+ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
-+ if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
-+ && bus == (unsigned int)dev_entry->dev->bus->number
-+ && devfn == dev_entry->dev->devfn) {
-+ dev = dev_entry->dev;
-+ break;
-+ }
++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
++ if (i == netif->tx.req_cons) {
++ int more_to_do;
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++ if (more_to_do)
++ add_to_net_schedule_list_tail(netif);
+ }
-+
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
-+
-+ return dev;
++#endif
+}
+
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
-+ int devid, publish_pci_dev_cb publish_cb)
++static netif_rx_response_t *make_rx_response(netif_t *netif,
++ u16 id,
++ s8 st,
++ u16 offset,
++ u16 size,
++ u16 flags)
+{
-+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+ struct pci_dev_entry *dev_entry;
-+ unsigned long flags;
-+ unsigned int domain, bus, devfn;
-+ int err;
-+
-+ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
-+ if (!dev_entry)
-+ return -ENOMEM;
-+ dev_entry->dev = dev;
++ RING_IDX i = netif->rx.rsp_prod_pvt;
++ netif_rx_response_t *resp;
+
-+ spin_lock_irqsave(&dev_data->lock, flags);
-+ list_add_tail(&dev_entry->list, &dev_data->dev_list);
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
++ resp = RING_GET_RESPONSE(&netif->rx, i);
++ resp->offset = offset;
++ resp->flags = flags;
++ resp->id = id;
++ resp->status = (s16)size;
++ if (st < 0)
++ resp->status = (s16)st;
+
-+ /* Publish this device. */
-+ domain = (unsigned int)pci_domain_nr(dev->bus);
-+ bus = (unsigned int)dev->bus->number;
-+ devfn = dev->devfn;
-+ err = publish_cb(pdev, domain, bus, devfn, devid);
++ netif->rx.rsp_prod_pvt = ++i;
+
-+ return err;
++ return resp;
+}
+
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++#ifdef NETBE_DEBUG_INTERRUPT
++static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
+{
-+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+ struct pci_dev_entry *dev_entry, *t;
-+ struct pci_dev *found_dev = NULL;
-+ unsigned long flags;
++ struct list_head *ent;
++ netif_t *netif;
++ int i = 0;
+
-+ spin_lock_irqsave(&dev_data->lock, flags);
++ printk(KERN_ALERT "netif_schedule_list:\n");
++ spin_lock_irq(&net_schedule_list_lock);
+
-+ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
-+ if (dev_entry->dev == dev) {
-+ list_del(&dev_entry->list);
-+ found_dev = dev_entry->dev;
-+ kfree(dev_entry);
-+ }
++ list_for_each (ent, &net_schedule_list) {
++ netif = list_entry(ent, netif_t, list);
++ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
++ "rx_resp_prod=%08x\n",
++ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
++ printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n",
++ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
++ printk(KERN_ALERT " shared(rx_req_prod=%08x "
++ "rx_resp_prod=%08x\n",
++ netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
++ printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n",
++ netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
++ printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n",
++ netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
++ i++;
+ }
+
-+ spin_unlock_irqrestore(&dev_data->lock, flags);
++ spin_unlock_irq(&net_schedule_list_lock);
++ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
+
-+ if (found_dev)
-+ pcistub_put_pci_dev(found_dev);
++ return IRQ_HANDLED;
+}
++#endif
+
-+int pciback_init_devices(struct pciback_device *pdev)
++static int __init netback_init(void)
+{
-+ struct passthrough_dev_data *dev_data;
++ int i;
++ struct page *page;
+
-+ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
-+ if (!dev_data)
-+ return -ENOMEM;
++ if (!is_running_on_xen())
++ return -ENODEV;
+
-+ spin_lock_init(&dev_data->lock);
++ /* We can increase reservation by this much in net_rx_action(). */
++ balloon_update_driver_allowance(NET_RX_RING_SIZE);
+
-+ INIT_LIST_HEAD(&dev_data->dev_list);
++ skb_queue_head_init(&rx_queue);
++ skb_queue_head_init(&tx_queue);
+
-+ pdev->pci_dev_data = dev_data;
++ init_timer(&net_timer);
++ net_timer.data = 0;
++ net_timer.function = net_alarm;
+
-+ return 0;
-+}
++ init_timer(&netbk_tx_pending_timer);
++ netbk_tx_pending_timer.data = 0;
++ netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
+
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+ publish_pci_root_cb publish_root_cb)
-+{
-+ int err = 0;
-+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+ struct pci_dev_entry *dev_entry, *e;
-+ struct pci_dev *dev;
-+ int found;
-+ unsigned int domain, bus;
++ mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
++ if (mmap_pages == NULL) {
++ printk("%s: out of memory\n", __FUNCTION__);
++ return -ENOMEM;
++ }
+
-+ spin_lock(&dev_data->lock);
++ 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);
++ }
+
-+ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
-+ /* Only publish this device as a root if none of its
-+ * parent bridges are exported
-+ */
-+ found = 0;
-+ dev = dev_entry->dev->bus->self;
-+ for (; !found && dev != NULL; dev = dev->bus->self) {
-+ list_for_each_entry(e, &dev_data->dev_list, list) {
-+ if (dev == e->dev) {
-+ found = 1;
-+ break;
-+ }
-+ }
-+ }
++ pending_cons = 0;
++ pending_prod = MAX_PENDING_REQS;
++ for (i = 0; i < MAX_PENDING_REQS; i++)
++ pending_ring[i] = i;
+
-+ domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
-+ bus = (unsigned int)dev_entry->dev->bus->number;
++ spin_lock_init(&net_schedule_list_lock);
++ INIT_LIST_HEAD(&net_schedule_list);
+
-+ if (!found) {
-+ err = publish_root_cb(pdev, domain, bus);
-+ if (err)
-+ break;
-+ }
++ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
++ if (MODPARM_copy_skb) {
++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
++ NULL, 0))
++ netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
++ else
++ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ }
+
-+ spin_unlock(&dev_data->lock);
-+
-+ return err;
-+}
++ netif_accel_init();
+
-+void pciback_release_devices(struct pciback_device *pdev)
-+{
-+ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+ struct pci_dev_entry *dev_entry, *t;
++ netif_xenbus_init();
+
-+ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
-+ list_del(&dev_entry->list);
-+ pcistub_put_pci_dev(dev_entry->dev);
-+ kfree(dev_entry);
-+ }
++#ifdef NETBE_DEBUG_INTERRUPT
++ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
++ 0,
++ netif_be_dbg,
++ SA_SHIRQ,
++ "net-be-dbg",
++ &netif_be_dbg);
++#endif
+
-+ kfree(dev_data);
-+ pdev->pci_dev_data = NULL;
++ return 0;
+}
+
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++module_init(netback_init);
+
-+{
-+ *domain = pci_domain_nr(pcidev->bus);
-+ *bus = pcidev->bus->number;
-+ *devfn = pcidev->devfn;
-+ return 1;
-+}
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
new file mode 100644
-index 0000000..c481a73
+index 0000000..d7faeb6
--- /dev/null
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -0,0 +1,1316 @@
-+/*
-+ * PCI Stub Driver - Grabs devices in backend to be exported later
-+ *
-+ * Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ * Chris Bookholt <hap10(a)epoch.ncsc.mil>
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/rwsem.h>
-+#include <linux/list.h>
-+#include <linux/spinlock.h>
-+#include <linux/kref.h>
-+#include <linux/pci.h>
-+#include <linux/wait.h>
-+#include <asm/atomic.h>
-+#include <xen/evtchn.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_quirks.h"
++++ b/drivers/xen/netback/xenbus.c
+@@ -0,0 +1,454 @@
++/* Xenbus code for netif backend
++ Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
++ Copyright (C) 2005 XenSource Ltd
+
-+static char *pci_devs_to_hide = NULL;
-+wait_queue_head_t aer_wait_queue;
-+/*Add sem for sync AER handling and pciback remove/reconfigue ops,
-+* We want to avoid in middle of AER ops, pciback devices is being removed
-+*/
-+static DECLARE_RWSEM(pcistub_sem);
-+module_param_named(hide, pci_devs_to_hide, charp, 0444);
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
+
-+struct pcistub_device_id {
-+ struct list_head slot_list;
-+ int domain;
-+ unsigned char bus;
-+ unsigned int devfn;
-+};
-+static LIST_HEAD(pcistub_device_ids);
-+static DEFINE_SPINLOCK(device_ids_lock);
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
+
-+struct pcistub_device {
-+ struct kref kref;
-+ struct list_head dev_list;
-+ spinlock_t lock;
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++*/
+
-+ struct pci_dev *dev;
-+ struct pciback_device *pdev; /* non-NULL if struct pci_dev is in use */
-+};
++#include <stdarg.h>
++#include <linux/module.h>
++#include <xen/xenbus.h>
++#include "common.h"
+
-+/* Access to pcistub_devices & seized_devices lists and the initialize_devices
-+ * flag must be locked with pcistub_devices_lock
-+ */
-+static DEFINE_SPINLOCK(pcistub_devices_lock);
-+static LIST_HEAD(pcistub_devices);
++#if 0
++#undef DPRINTK
++#define DPRINTK(fmt, args...) \
++ printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__,
__LINE__, ##args)
++#endif
+
-+/* wait for device_initcall before initializing our devices
-+ * (see pcistub_init_devices_late)
-+ */
-+static int initialize_devices = 0;
-+static LIST_HEAD(seized_devices);
+
-+static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
-+{
-+ struct pcistub_device *psdev;
++static int connect_rings(struct backend_info *);
++static void connect(struct backend_info *);
++static void backend_create_netif(struct backend_info *be);
+
-+ dev_dbg(&dev->dev, "pcistub_device_alloc\n");
++static int netback_remove(struct xenbus_device *dev)
++{
++ struct backend_info *be = dev->dev.driver_data;
+
-+ psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC);
-+ if (!psdev)
-+ return NULL;
++ netback_remove_accelerators(be, dev);
+
-+ psdev->dev = pci_dev_get(dev);
-+ if (!psdev->dev) {
-+ kfree(psdev);
-+ return NULL;
++ if (be->netif) {
++ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++ netif_disconnect(be->netif);
++ be->netif = NULL;
+ }
-+
-+ kref_init(&psdev->kref);
-+ spin_lock_init(&psdev->lock);
-+
-+ return psdev;
++ kfree(be);
++ dev->dev.driver_data = NULL;
++ return 0;
+}
+
-+/* Don't call this directly as it's called by pcistub_device_put */
-+static void pcistub_device_release(struct kref *kref)
-+{
-+ struct pcistub_device *psdev;
+
-+ psdev = container_of(kref, struct pcistub_device, kref);
++/**
++ * Entry point to this code when a new device is created. Allocate the basic
++ * structures and switch to InitWait.
++ */
++static int netback_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ const char *message;
++ struct xenbus_transaction xbt;
++ int err;
++ int sg;
++ struct backend_info *be = kzalloc(sizeof(struct backend_info),
++ GFP_KERNEL);
++ if (!be) {
++ xenbus_dev_fatal(dev, -ENOMEM,
++ "allocating backend structure");
++ return -ENOMEM;
++ }
+
-+ dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
++ be->dev = dev;
++ dev->dev.driver_data = be;
+
-+ /* Clean-up the device */
-+ pciback_reset_device(psdev->dev);
-+ pciback_config_free_dyn_fields(psdev->dev);
-+ pciback_config_free_dev(psdev->dev);
-+ kfree(pci_get_drvdata(psdev->dev));
-+ pci_set_drvdata(psdev->dev, NULL);
++ sg = 1;
++ if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
++ sg = 0;
+
-+ pci_dev_put(psdev->dev);
++ do {
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ goto fail;
++ }
+
-+ kfree(psdev);
-+}
++ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
sg);
++ if (err) {
++ message = "writing feature-sg";
++ goto abort_transaction;
++ }
+
-+static inline void pcistub_device_get(struct pcistub_device *psdev)
-+{
-+ kref_get(&psdev->kref);
-+}
++ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
++ "%d", sg);
++ if (err) {
++ message = "writing feature-gso-tcpv4";
++ goto abort_transaction;
++ }
+
-+static inline void pcistub_device_put(struct pcistub_device *psdev)
-+{
-+ kref_put(&psdev->kref, pcistub_device_release);
-+}
++ /* We support rx-copy path. */
++ err = xenbus_printf(xbt, dev->nodename,
++ "feature-rx-copy", "%d", 1);
++ if (err) {
++ message = "writing feature-rx-copy";
++ goto abort_transaction;
++ }
+
-+static struct pcistub_device *pcistub_device_find(int domain, int bus,
-+ int slot, int func)
-+{
-+ struct pcistub_device *psdev = NULL;
-+ unsigned long flags;
++ /*
++ * We don't support rx-flip path (except old guests who don't
++ * grok this feature flag).
++ */
++ err = xenbus_printf(xbt, dev->nodename,
++ "feature-rx-flip", "%d", 0);
++ if (err) {
++ message = "writing feature-rx-flip";
++ goto abort_transaction;
++ }
+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ err = xenbus_transaction_end(xbt, 0);
++ } while (err == -EAGAIN);
+
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (psdev->dev != NULL
-+ && domain == pci_domain_nr(psdev->dev->bus)
-+ && bus == psdev->dev->bus->number
-+ && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
-+ pcistub_device_get(psdev);
-+ goto out;
-+ }
++ if (err) {
++ xenbus_dev_fatal(dev, err, "completing transaction");
++ goto fail;
+ }
+
-+ /* didn't find it */
-+ psdev = NULL;
++ netback_probe_accelerators(be, dev);
+
-+ out:
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+ return psdev;
-+}
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto fail;
+
-+static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
-+ struct pcistub_device *psdev)
-+{
-+ struct pci_dev *pci_dev = NULL;
-+ unsigned long flags;
-+
-+ pcistub_device_get(psdev);
-+
-+ spin_lock_irqsave(&psdev->lock, flags);
-+ if (!psdev->pdev) {
-+ psdev->pdev = pdev;
-+ pci_dev = psdev->dev;
-+ }
-+ spin_unlock_irqrestore(&psdev->lock, flags);
++ /* This kicks hotplug scripts, so do it immediately. */
++ backend_create_netif(be);
+
-+ if (!pci_dev)
-+ pcistub_device_put(psdev);
++ return 0;
+
-+ return pci_dev;
++abort_transaction:
++ xenbus_transaction_end(xbt, 1);
++ xenbus_dev_fatal(dev, err, "%s", message);
++fail:
++ DPRINTK("failed");
++ netback_remove(dev);
++ return err;
+}
+
-+struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
-+ int domain, int bus,
-+ int slot, int func)
++
++/**
++ * Handle the creation of the hotplug script environment. We add the script
++ * and vif variables to the environment, for the benefit of the vif-* hotplug
++ * scripts.
++ */
++static int netback_uevent(struct xenbus_device *xdev, char **envp,
++ int num_envp, char *buffer, int buffer_size)
+{
-+ struct pcistub_device *psdev;
-+ struct pci_dev *found_dev = NULL;
-+ unsigned long flags;
++ struct backend_info *be = xdev->dev.driver_data;
++ netif_t *netif = be->netif;
++ int i = 0, length = 0;
++ char *val;
+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ DPRINTK("netback_uevent");
+
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (psdev->dev != NULL
-+ && domain == pci_domain_nr(psdev->dev->bus)
-+ && bus == psdev->dev->bus->number
-+ && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
-+ found_dev = pcistub_device_get_pci_dev(pdev, psdev);
-+ break;
-+ }
++ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
++ if (IS_ERR(val)) {
++ int err = PTR_ERR(val);
++ xenbus_dev_fatal(xdev, err, "reading script");
++ return err;
++ }
++ else {
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
++ &length, "script=%s", val);
++ kfree(val);
+ }
+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+ return found_dev;
-+}
-+
-+struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
-+ struct pci_dev *dev)
-+{
-+ struct pcistub_device *psdev;
-+ struct pci_dev *found_dev = NULL;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++ "vif=%s", netif->dev->name);
+
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (psdev->dev == dev) {
-+ found_dev = pcistub_device_get_pci_dev(pdev, psdev);
-+ break;
-+ }
-+ }
++ envp[i] = NULL;
+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+ return found_dev;
++ return 0;
+}
+
-+void pcistub_put_pci_dev(struct pci_dev *dev)
++
++static void backend_create_netif(struct backend_info *be)
+{
-+ struct pcistub_device *psdev, *found_psdev = NULL;
-+ unsigned long flags;
++ int err;
++ long handle;
++ struct xenbus_device *dev = be->dev;
+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ if (be->netif != NULL)
++ return;
+
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (psdev->dev == dev) {
-+ found_psdev = psdev;
-+ break;
-+ }
++ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
++ if (err != 1) {
++ xenbus_dev_fatal(dev, err, "reading handle");
++ return;
+ }
+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+
-+ /*hold this lock for avoiding breaking link between
-+ * pcistub and pciback when AER is in processing
-+ */
-+ down_write(&pcistub_sem);
-+ /* Cleanup our device
-+ * (so it's ready for the next domain)
-+ */
-+ pciback_reset_device(found_psdev->dev);
-+ pciback_config_free_dyn_fields(found_psdev->dev);
-+ pciback_config_reset_dev(found_psdev->dev);
-+
-+ spin_lock_irqsave(&found_psdev->lock, flags);
-+ found_psdev->pdev = NULL;
-+ spin_unlock_irqrestore(&found_psdev->lock, flags);
++ be->netif = netif_alloc(dev->otherend_id, handle);
++ if (IS_ERR(be->netif)) {
++ err = PTR_ERR(be->netif);
++ be->netif = NULL;
++ xenbus_dev_fatal(dev, err, "creating interface");
++ return;
++ }
+
-+ pcistub_device_put(found_psdev);
-+ up_write(&pcistub_sem);
++ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+}
+
-+static int __devinit pcistub_match_one(struct pci_dev *dev,
-+ struct pcistub_device_id *pdev_id)
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state)
+{
-+ /* Match the specified device by domain, bus, slot, func and also if
-+ * any of the device's parent bridges match.
-+ */
-+ for (; dev != NULL; dev = dev->bus->self) {
-+ if (pci_domain_nr(dev->bus) == pdev_id->domain
-+ && dev->bus->number == pdev_id->bus
-+ && dev->devfn == pdev_id->devfn)
-+ return 1;
++ struct backend_info *be = dev->dev.driver_data;
+
-+ /* Sometimes topmost bridge links to itself. */
-+ if (dev == dev->bus->self)
-+ break;
-+ }
++ DPRINTK("%s", xenbus_strstate(frontend_state));
+
-+ return 0;
-+}
++ be->frontend_state = frontend_state;
+
-+static int __devinit pcistub_match(struct pci_dev *dev)
-+{
-+ struct pcistub_device_id *pdev_id;
-+ unsigned long flags;
-+ int found = 0;
++ switch (frontend_state) {
++ case XenbusStateInitialising:
++ if (dev->state == XenbusStateClosed) {
++ printk(KERN_INFO "%s: %s: prepare for reconnect\n",
++ __FUNCTION__, dev->nodename);
++ xenbus_switch_state(dev, XenbusStateInitWait);
++ }
++ break;
+
-+ spin_lock_irqsave(&device_ids_lock, flags);
-+ list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
-+ if (pcistub_match_one(dev, pdev_id)) {
-+ found = 1;
++ case XenbusStateInitialised:
++ break;
++
++ case XenbusStateConnected:
++ if (dev->state == XenbusStateConnected)
+ break;
++ backend_create_netif(be);
++ if (be->netif)
++ connect(be);
++ break;
++
++ case XenbusStateClosing:
++ if (be->netif) {
++ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++ netif_disconnect(be->netif);
++ be->netif = NULL;
+ }
-+ }
-+ spin_unlock_irqrestore(&device_ids_lock, flags);
++ xenbus_switch_state(dev, XenbusStateClosing);
++ break;
+
-+ return found;
-+}
++ case XenbusStateClosed:
++ xenbus_switch_state(dev, XenbusStateClosed);
++ if (xenbus_dev_is_online(dev))
++ break;
++ /* fall through if not online */
++ case XenbusStateUnknown:
++ device_unregister(&dev->dev);
++ break;
+
-+static int __devinit pcistub_init_device(struct pci_dev *dev)
-+{
-+ struct pciback_dev_data *dev_data;
-+ int err = 0;
++ default:
++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++ frontend_state);
++ break;
++ }
++}
+
-+ dev_dbg(&dev->dev, "initializing...\n");
+
-+ /* The PCI backend is not intended to be a module (or to work with
-+ * removable PCI devices (yet). If it were, pciback_config_free()
-+ * would need to be called somewhere to free the memory allocated
-+ * here and then to call kfree(pci_get_drvdata(psdev->dev)).
-+ */
-+ dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
-+ if (!dev_data) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+ pci_set_drvdata(dev, dev_data);
++static void xen_net_read_rate(struct xenbus_device *dev,
++ unsigned long *bytes, unsigned long *usec)
++{
++ char *s, *e;
++ unsigned long b, u;
++ char *ratestr;
+
-+ dev_dbg(&dev->dev, "initializing config\n");
++ /* Default to unlimited bandwidth. */
++ *bytes = ~0UL;
++ *usec = 0;
+
-+ init_waitqueue_head(&aer_wait_queue);
-+ err = pciback_config_init_dev(dev);
-+ if (err)
-+ goto out;
++ ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
++ if (IS_ERR(ratestr))
++ return;
+
-+ /* HACK: Force device (& ACPI) to determine what IRQ it's on - we
-+ * must do this here because pcibios_enable_device may specify
-+ * the pci device's true irq (and possibly its other resources)
-+ * if they differ from what's in the configuration space.
-+ * This makes the assumption that the device's resources won't
-+ * change after this point (otherwise this code may break!)
-+ */
-+ dev_dbg(&dev->dev, "enabling device\n");
-+ err = pci_enable_device(dev);
-+ if (err)
-+ goto config_release;
++ s = ratestr;
++ b = simple_strtoul(s, &e, 10);
++ if ((s == e) || (*e != ','))
++ goto fail;
+
-+ /* Now disable the device (this also ensures some private device
-+ * data is setup before we export)
-+ */
-+ dev_dbg(&dev->dev, "reset device\n");
-+ pciback_reset_device(dev);
++ s = e + 1;
++ u = simple_strtoul(s, &e, 10);
++ if ((s == e) || (*e != '\0'))
++ goto fail;
+
-+ return 0;
++ *bytes = b;
++ *usec = u;
+
-+ config_release:
-+ pciback_config_free_dev(dev);
++ kfree(ratestr);
++ return;
+
-+ out:
-+ pci_set_drvdata(dev, NULL);
-+ kfree(dev_data);
-+ return err;
++ fail:
++ WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
++ kfree(ratestr);
+}
+
-+/*
-+ * Because some initialization still happens on
-+ * devices during fs_initcall, we need to defer
-+ * full initialization of our devices until
-+ * device_initcall.
-+ */
-+static int __init pcistub_init_devices_late(void)
++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
-+ struct pcistub_device *psdev;
-+ unsigned long flags;
-+ int err = 0;
-+
-+ pr_debug("pciback: pcistub_init_devices_late\n");
-+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
-+
-+ while (!list_empty(&seized_devices)) {
-+ psdev = container_of(seized_devices.next,
-+ struct pcistub_device, dev_list);
-+ list_del(&psdev->dev_list);
++ char *s, *e, *macstr;
++ int i;
+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++ if (IS_ERR(macstr))
++ return PTR_ERR(macstr);
+
-+ err = pcistub_init_device(psdev->dev);
-+ if (err) {
-+ dev_err(&psdev->dev->dev,
-+ "error %d initializing device\n", err);
-+ kfree(psdev);
-+ psdev = NULL;
++ for (i = 0; i < ETH_ALEN; i++) {
++ mac[i] = simple_strtoul(s, &e, 16);
++ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++ kfree(macstr);
++ return -ENOENT;
+ }
-+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
-+
-+ if (psdev)
-+ list_add_tail(&psdev->dev_list, &pcistub_devices);
++ s = e+1;
+ }
+
-+ initialize_devices = 1;
-+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+
++ kfree(macstr);
+ return 0;
+}
+
-+static int __devinit pcistub_seize(struct pci_dev *dev)
++static void connect(struct backend_info *be)
+{
-+ struct pcistub_device *psdev;
-+ unsigned long flags;
-+ int err = 0;
-+
-+ psdev = pcistub_device_alloc(dev);
-+ if (!psdev)
-+ return -ENOMEM;
-+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
-+
-+ if (initialize_devices) {
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+
-+ /* don't want irqs disabled when calling pcistub_init_device */
-+ err = pcistub_init_device(psdev->dev);
++ int err;
++ struct xenbus_device *dev = be->dev;
+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ err = connect_rings(be);
++ if (err)
++ return;
+
-+ if (!err)
-+ list_add(&psdev->dev_list, &pcistub_devices);
-+ } else {
-+ dev_dbg(&dev->dev, "deferring initialization\n");
-+ list_add(&psdev->dev_list, &seized_devices);
++ err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
++ return;
+ }
+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ xen_net_read_rate(dev, &be->netif->credit_bytes,
++ &be->netif->credit_usec);
++ be->netif->remaining_credit = be->netif->credit_bytes;
+
-+ if (err)
-+ pcistub_device_put(psdev);
++ xenbus_switch_state(dev, XenbusStateConnected);
+
-+ return err;
++ netif_wake_queue(be->netif->dev);
+}
+
-+static int __devinit pcistub_probe(struct pci_dev *dev,
-+ const struct pci_device_id *id)
++
++static int connect_rings(struct backend_info *be)
+{
-+ int err = 0;
++ struct xenbus_device *dev = be->dev;
++ unsigned long tx_ring_ref, rx_ring_ref;
++ unsigned int evtchn, rx_copy;
++ int err;
++ int val;
+
-+ dev_dbg(&dev->dev, "probing...\n");
++ DPRINTK("");
+
-+ if (pcistub_match(dev)) {
++ err = xenbus_gather(XBT_NIL, dev->otherend,
++ "tx-ring-ref", "%lu", &tx_ring_ref,
++ "rx-ring-ref", "%lu", &rx_ring_ref,
++ "event-channel", "%u", &evtchn, NULL);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "reading %s/ring-ref and event-channel",
++ dev->otherend);
++ return err;
++ }
+
-+ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
-+ && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
-+ dev_err(&dev->dev, "can't export pci devices that "
-+ "don't have a normal (0) or bridge (1) "
-+ "header type!\n");
-+ err = -ENODEV;
-+ goto out;
-+ }
++ err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy",
"%u",
++ &rx_copy);
++ if (err == -ENOENT) {
++ err = 0;
++ rx_copy = 0;
++ }
++ if (err < 0) {
++ xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
++ dev->otherend);
++ return err;
++ }
++ be->netif->copying_receiver = !!rx_copy;
+
-+ dev_info(&dev->dev, "seizing device\n");
-+ err = pcistub_seize(dev);
-+#ifdef CONFIG_PCI_GUESTDEV
-+ } else if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-+ if (!pci_is_guestdev(dev)) {
-+ err = -ENODEV;
-+ goto out;
-+ }
++ if (be->netif->dev->tx_queue_len != 0) {
++ if (xenbus_scanf(XBT_NIL, dev->otherend,
++ "feature-rx-notify", "%d", &val) < 0)
++ val = 0;
++ if (val)
++ be->netif->can_queue = 1;
++ else
++ /* Must be non-zero for pfifo_fast to work. */
++ be->netif->dev->tx_queue_len = 1;
++ }
+
-+ dev_info(&dev->dev, "seizing device\n");
-+ err = pcistub_seize(dev);
-+#endif /* CONFIG_PCI_GUESTDEV */
-+ } else
-+ /* Didn't find the device */
-+ err = -ENODEV;
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d",
&val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features |= NETIF_F_SG;
++ be->netif->dev->features |= NETIF_F_SG;
++ }
+
-+ out:
-+ return err;
-+}
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
"%d",
++ &val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features |= NETIF_F_TSO;
++ be->netif->dev->features |= NETIF_F_TSO;
++ }
+
-+static void pcistub_remove(struct pci_dev *dev)
-+{
-+ struct pcistub_device *psdev, *found_psdev = NULL;
-+ unsigned long flags;
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
++ "%d", &val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features &= ~NETIF_F_IP_CSUM;
++ be->netif->dev->features &= ~NETIF_F_IP_CSUM;
++ }
+
-+ dev_dbg(&dev->dev, "removing\n");
++ /* Map the shared frame, irq etc. */
++ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "mapping shared-frames %lu/%lu port %u",
++ tx_ring_ref, rx_ring_ref, evtchn);
++ return err;
++ }
++ return 0;
++}
+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
+
-+ pciback_config_quirk_release(dev);
++/* ** Driver Registration ** */
+
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (psdev->dev == dev) {
-+ found_psdev = psdev;
-+ break;
-+ }
-+ }
+
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++static const struct xenbus_device_id netback_ids[] = {
++ { "vif" },
++ { "" }
++};
+
-+ if (found_psdev) {
-+ dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
-+ found_psdev->pdev);
+
-+ if (found_psdev->pdev) {
-+ printk(KERN_WARNING "pciback: ****** removing device "
-+ "%s while still in-use! ******\n",
-+ pci_name(found_psdev->dev));
-+ printk(KERN_WARNING "pciback: ****** driver domain may "
-+ "still access this device's i/o resources!\n");
-+ printk(KERN_WARNING "pciback: ****** shutdown driver "
-+ "domain before binding device\n");
-+ printk(KERN_WARNING "pciback: ****** to other drivers "
-+ "or domains\n");
++static struct xenbus_driver netback = {
++ .name = "vif",
++ .owner = THIS_MODULE,
++ .ids = netback_ids,
++ .probe = netback_probe,
++ .remove = netback_remove,
++ .uevent = netback_uevent,
++ .otherend_changed = frontend_changed,
++};
+
-+ pciback_release_pci_dev(found_psdev->pdev,
-+ found_psdev->dev);
-+ }
+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
-+ list_del(&found_psdev->dev_list);
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+
-+ /* the final put for releasing from the list */
-+ pcistub_device_put(found_psdev);
-+ }
-+}
-+
-+static const struct pci_device_id pcistub_ids[] = {
-+ {
-+ .vendor = PCI_ANY_ID,
-+ .device = PCI_ANY_ID,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ },
-+ {0,},
-+};
-+
-+static void kill_domain_by_device(struct pcistub_device *psdev)
-+{
-+ struct xenbus_transaction xbt;
-+ int err;
-+ char nodename[1024];
-+
-+ if (!psdev)
-+ dev_err(&psdev->dev->dev,
-+ "device is NULL when do AER recovery/kill_domain\n");
-+ sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
-+ psdev->pdev->xdev->otherend_id);
-+ nodename[strlen(nodename)] = '\0';
-+
-+again:
-+ err = xenbus_transaction_start(&xbt);
-+ if (err)
-+ {
-+ dev_err(&psdev->dev->dev,
-+ "error %d when start xenbus transaction\n", err);
-+ return;
-+ }
-+ /*PV AER handlers will set this flag*/
-+ xenbus_printf(xbt, nodename, "aerState" , "aerfail" );
-+ err = xenbus_transaction_end(xbt, 0);
-+ if (err)
-+ {
-+ if (err == -EAGAIN)
-+ goto again;
-+ dev_err(&psdev->dev->dev,
-+ "error %d when end xenbus transaction\n", err);
-+ return;
-+ }
-+}
-+
-+/* For each aer recovery step error_detected, mmio_enabled, etc, front_end and
-+ * backend need to have cooperation. In pciback, those steps will do similar
-+ * jobs: send service request and waiting for front_end response.
-+*/
-+static pci_ers_result_t common_process(struct pcistub_device *psdev,
-+ pci_channel_state_t state, int aer_cmd, pci_ers_result_t result)
-+{
-+ pci_ers_result_t res = result;
-+ struct xen_pcie_aer_op *aer_op;
-+ int ret;
-+
-+ /*with PV AER drivers*/
-+ aer_op = &(psdev->pdev->sh_info->aer_op);
-+ aer_op->cmd = aer_cmd ;
-+ /*useful for error_detected callback*/
-+ aer_op->err = state;
-+ /*pcifront_end BDF*/
-+ ret = pciback_get_pcifront_dev(psdev->dev, psdev->pdev,
-+ &aer_op->domain, &aer_op->bus, &aer_op->devfn);
-+ if (!ret) {
-+ dev_err(&psdev->dev->dev,
-+ "pciback: failed to get pcifront device\n");
-+ return PCI_ERS_RESULT_NONE;
-+ }
-+ wmb();
-+
-+ dev_dbg(&psdev->dev->dev,
-+ "pciback: aer_op %x dom %x bus %x devfn %x\n",
-+ aer_cmd, aer_op->domain, aer_op->bus, aer_op->devfn);
-+ /*local flag to mark there's aer request, pciback callback will use this
-+ * flag to judge whether we need to check pci-front give aer service
-+ * ack signal
-+ */
-+ set_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
-+
-+ /*It is possible that a pcifront conf_read_write ops request invokes
-+ * the callback which cause the spurious execution of wake_up.
-+ * Yet it is harmless and better than a spinlock here
-+ */
-+ set_bit(_XEN_PCIB_active,
-+ (unsigned long *)&psdev->pdev->sh_info->flags);
-+ wmb();
-+ notify_remote_via_irq(psdev->pdev->evtchn_irq);
-+
-+ ret = wait_event_timeout(aer_wait_queue, !(test_bit(_XEN_PCIB_active,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)), 300*HZ);
-+
-+ if (!ret) {
-+ if (test_bit(_XEN_PCIB_active,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
-+ dev_err(&psdev->dev->dev,
-+ "pcifront aer process not responding!\n");
-+ clear_bit(_XEN_PCIB_active,
-+ (unsigned long *)&psdev->pdev->sh_info->flags);
-+ aer_op->err = PCI_ERS_RESULT_NONE;
-+ return res;
-+ }
-+ }
-+ clear_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
-+
-+ if ( test_bit( _XEN_PCIF_active,
-+ (unsigned long*)&psdev->pdev->sh_info->flags)) {
-+ dev_dbg(&psdev->dev->dev,
-+ "schedule pci_conf service in pciback \n");
-+ test_and_schedule_op(psdev->pdev);
-+ }
-+
-+ res = (pci_ers_result_t)aer_op->err;
-+ return res;
-+}
-+
-+/*
-+* pciback_slot_reset: it will send the slot_reset request to pcifront in case
-+* of the device driver could provide this service, and then wait for pcifront
-+* ack.
-+* @dev: pointer to PCI devices
-+* return value is used by aer_core do_recovery policy
-+*/
-+static pci_ers_result_t pciback_slot_reset(struct pci_dev *dev)
++void netif_xenbus_init(void)
+{
-+ struct pcistub_device *psdev;
-+ pci_ers_result_t result;
-+
-+ result = PCI_ERS_RESULT_RECOVERED;
-+ dev_dbg(&dev->dev, "pciback_slot_reset(bus:%x,devfn:%x)\n",
-+ dev->bus->number, dev->devfn);
-+
-+ down_write(&pcistub_sem);
-+ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
-+ dev->bus->number,
-+ PCI_SLOT(dev->devfn),
-+ PCI_FUNC(dev->devfn));
-+
-+ if ( !psdev || !psdev->pdev )
-+ {
-+ dev_err(&dev->dev,
-+ "pciback device is not found/assigned\n");
-+ goto end;
-+ }
-+
-+ if ( !psdev->pdev->sh_info )
-+ {
-+ dev_err(&dev->dev, "pciback device is not connected or owned"
-+ " by HVM, kill it\n");
-+ kill_domain_by_device(psdev);
-+ goto release;
-+ }
-+
-+ if ( !test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-+ dev_err(&dev->dev,
-+ "guest with no AER driver should have been killed\n");
-+ goto release;
-+ }
-+ result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result);
-+
-+ if (result == PCI_ERS_RESULT_NONE ||
-+ result == PCI_ERS_RESULT_DISCONNECT) {
-+ dev_dbg(&dev->dev,
-+ "No AER slot_reset service or disconnected!\n");
-+ kill_domain_by_device(psdev);
-+ }
-+release:
-+ pcistub_device_put(psdev);
-+end:
-+ up_write(&pcistub_sem);
-+ return result;
-+
++ xenbus_register_backend(&netback);
+}
+--
+1.7.4
+
+
+From 5b30803bf5f58ee980edd8d88a2d73dda995ee93 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Mon, 9 Feb 2009 12:05:52 -0800
+Subject: [PATCH 002/203] xen: netback: first cut at porting to upstream and cleaning up
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/Kconfig | 2 +-
+ drivers/xen/netback/Makefile | 2 +-
+ drivers/xen/netback/common.h | 33 +++---
+ drivers/xen/netback/interface.c | 37 +++---
+ drivers/xen/netback/netback.c | 248 ++++++++++++++++++++++++---------------
+ drivers/xen/netback/xenbus.c | 25 ++--
+ 6 files changed, 201 insertions(+), 146 deletions(-)
+
+diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
+index 7e83d43..30290a8 100644
+--- a/drivers/xen/Kconfig
++++ b/drivers/xen/Kconfig
+@@ -38,7 +38,7 @@ config XEN_BACKEND
+ to other virtual machines.
+
+ config XEN_NETDEV_BACKEND
+- bool "Xen backend network device"
++ tristate "Xen backend network device"
+ depends on XEN_BACKEND && NET
+ help
+ Implement the network backend driver, which passes packets
+diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
+index f4a0c51..a01a1a3 100644
+--- a/drivers/xen/netback/Makefile
++++ b/drivers/xen/netback/Makefile
+@@ -1,3 +1,3 @@
+ obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
+
+-netbk-y := netback.o xenbus.o interface.o
++netbk-y := netback.o xenbus.o interface.o
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 9a54d57..65b88f4 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -43,8 +43,7 @@
+ #include <asm/io.h>
+ #include <asm/pgalloc.h>
+ #include <xen/interface/grant_table.h>
+-#include <xen/gnttab.h>
+-#include <xen/driver_util.h>
++#include <xen/grant_table.h>
+ #include <xen/xenbus.h>
+
+ #define DPRINTK(_f, _a...) \
+@@ -55,7 +54,7 @@
+ #define WPRINTK(fmt, args...) \
+ printk(KERN_WARNING "xen_net: " fmt, ##args)
+
+-typedef struct netif_st {
++struct xen_netif {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ unsigned int handle;
+@@ -70,8 +69,8 @@ typedef struct netif_st {
+ unsigned int irq;
+
+ /* The shared rings and indexes. */
+- netif_tx_back_ring_t tx;
+- netif_rx_back_ring_t rx;
++ struct xen_netif_tx_back_ring tx;
++ struct xen_netif_rx_back_ring rx;
+ struct vm_struct *tx_comms_area;
+ struct vm_struct *rx_comms_area;
+
+@@ -103,7 +102,7 @@ typedef struct netif_st {
+ unsigned int carrier;
+
+ wait_queue_head_t waiting_to_free;
+-} netif_t;
++};
+
+ /*
+ * Implement our own carrier flag: the network stack's version causes delays
+@@ -141,7 +140,7 @@ struct netback_accelerator {
+
+ struct backend_info {
+ struct xenbus_device *dev;
+- netif_t *netif;
++ struct xen_netif *netif;
+ enum xenbus_state frontend_state;
+
+ /* State relating to the netback accelerator */
+@@ -174,13 +173,13 @@ extern
+ void netif_accel_init(void);
+
+
+-#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
+-#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
++#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+
+-void netif_disconnect(netif_t *netif);
++void netif_disconnect(struct xen_netif *netif);
+
+-netif_t *netif_alloc(domid_t domid, unsigned int handle);
+-int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++struct xen_netif *netif_alloc(domid_t domid, unsigned int handle);
++int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn);
+
+ #define netif_get(_b) (atomic_inc(&(_b)->refcnt))
+@@ -195,22 +194,22 @@ void netif_xenbus_init(void);
+ #define netif_schedulable(netif) \
+ (netif_running((netif)->dev) && netback_carrier_ok(netif))
+
+-void netif_schedule_work(netif_t *netif);
+-void netif_deschedule_work(netif_t *netif);
++void netif_schedule_work(struct xen_netif *netif);
++void netif_deschedule_work(struct xen_netif *netif);
+
+ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
+ struct net_device_stats *netif_be_get_stats(struct net_device *dev);
+-irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++irqreturn_t netif_be_int(int irq, void *dev_id);
+
+ static inline int netbk_can_queue(struct net_device *dev)
+ {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+ return netif->can_queue;
+ }
+
+ static inline int netbk_can_sg(struct net_device *dev)
+ {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+ return netif->features & NETIF_F_SG;
+ }
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 7e67941..d184ad7 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -34,6 +34,9 @@
+ #include <linux/ethtool.h>
+ #include <linux/rtnetlink.h>
+
++#include <xen/events.h>
++#include <asm/xen/hypercall.h>
+
+ /*
+ * Module parameter 'queue_length':
+ *
+@@ -51,13 +54,13 @@
+ static unsigned long netbk_queue_length = 32;
+ module_param_named(queue_length, netbk_queue_length, ulong, 0);
+
+-static void __netif_up(netif_t *netif)
++static void __netif_up(struct xen_netif *netif)
+ {
+ enable_irq(netif->irq);
+ netif_schedule_work(netif);
+ }
+
+-static void __netif_down(netif_t *netif)
++static void __netif_down(struct xen_netif *netif)
+ {
+ disable_irq(netif->irq);
+ netif_deschedule_work(netif);
+@@ -65,7 +68,7 @@ static void __netif_down(netif_t *netif)
+
+ static int net_open(struct net_device *dev)
+ {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+ if (netback_carrier_ok(netif)) {
+ __netif_up(netif);
+ netif_start_queue(dev);
+@@ -75,7 +78,7 @@ static int net_open(struct net_device *dev)
+
+ static int net_close(struct net_device *dev)
+ {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+ if (netback_carrier_ok(netif))
+ __netif_down(netif);
+ netif_stop_queue(dev);
+@@ -95,7 +98,7 @@ static int netbk_change_mtu(struct net_device *dev, int mtu)
+ static int netbk_set_sg(struct net_device *dev, u32 data)
+ {
+ if (data) {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+
+ if (!(netif->features & NETIF_F_SG))
+ return -ENOSYS;
+@@ -107,7 +110,7 @@ static int netbk_set_sg(struct net_device *dev, u32 data)
+ static int netbk_set_tso(struct net_device *dev, u32 data)
+ {
+ if (data) {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+
+ if (!(netif->features & NETIF_F_TSO))
+ return -ENOSYS;
+@@ -127,15 +130,15 @@ static struct ethtool_ops network_ethtool_ops =
+ .get_link = ethtool_op_get_link,
+ };
+
+-netif_t *netif_alloc(domid_t domid, unsigned int handle)
++struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
+ {
+ int err = 0;
+ struct net_device *dev;
+- netif_t *netif;
++ struct xen_netif *netif;
+ char name[IFNAMSIZ] = {};
+
+ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
+- dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
++ dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
+ if (dev == NULL) {
+ DPRINTK("Could not create netif: out of memory\n");
+ return ERR_PTR(-ENOMEM);
+@@ -194,7 +197,7 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle)
+ }
+
+ static int map_frontend_pages(
+- netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
++ struct xen_netif *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
+ {
+ struct gnttab_map_grant_ref op;
+
+@@ -229,7 +232,7 @@ static int map_frontend_pages(
+ return 0;
+ }
+
+-static void unmap_frontend_pages(netif_t *netif)
++static void unmap_frontend_pages(struct xen_netif *netif)
+ {
+ struct gnttab_unmap_grant_ref op;
+
+@@ -246,12 +249,12 @@ static void unmap_frontend_pages(netif_t *netif)
+ BUG();
+ }
+
+-int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn)
+ {
+ int err = -ENOMEM;
+- netif_tx_sring_t *txs;
+- netif_rx_sring_t *rxs;
++ struct xen_netif_tx_sring *txs;
++ struct xen_netif_rx_sring *rxs;
+
+ /* Already connected through? */
+ if (netif->irq)
+@@ -276,10 +279,10 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
+ netif->irq = err;
+ disable_irq(netif->irq);
+
+- txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
++ txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
+ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
+
+- rxs = (netif_rx_sring_t *)
++ rxs = (struct xen_netif_rx_sring *)
+ ((char *)netif->rx_comms_area->addr);
+ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
+
+@@ -303,7 +306,7 @@ err_rx:
+ return err;
+ }
+
+-void netif_disconnect(netif_t *netif)
++void netif_disconnect(struct xen_netif *netif)
+ {
+ if (netback_carrier_ok(netif)) {
+ rtnl_lock();
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index db629d4..c959075 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -35,9 +35,17 @@
+ */
+
+ #include "common.h"
+
-+/*pciback_mmio_enabled: it will send the mmio_enabled request to pcifront
-+* in case of the device driver could provide this service, and then wait
-+* for pcifront ack.
-+* @dev: pointer to PCI devices
-+* return value is used by aer_core do_recovery policy
-+*/
-+
-+static pci_ers_result_t pciback_mmio_enabled(struct pci_dev *dev)
-+{
-+ struct pcistub_device *psdev;
-+ pci_ers_result_t result;
-+
-+ result = PCI_ERS_RESULT_RECOVERED;
-+ dev_dbg(&dev->dev, "pciback_mmio_enabled(bus:%x,devfn:%x)\n",
-+ dev->bus->number, dev->devfn);
++#include <linux/tcp.h>
++#include <linux/udp.h>
+
-+ down_write(&pcistub_sem);
-+ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
-+ dev->bus->number,
-+ PCI_SLOT(dev->devfn),
-+ PCI_FUNC(dev->devfn));
+ #include <xen/balloon.h>
++#include <xen/events.h>
+ #include <xen/interface/memory.h>
+
++#include <asm/xen/hypercall.h>
++#include <asm/xen/page.h>
+
-+ if ( !psdev || !psdev->pdev )
-+ {
-+ dev_err(&dev->dev,
-+ "pciback device is not found/assigned\n");
-+ goto end;
-+ }
+ /*define NETBE_DEBUG_INTERRUPT*/
+
+ struct netbk_rx_meta {
+@@ -51,11 +59,12 @@ struct netbk_tx_pending_inuse {
+ unsigned long alloc_time;
+ };
+
+
-+ if ( !psdev->pdev->sh_info )
-+ {
-+ dev_err(&dev->dev, "pciback device is not connected or owned"
-+ " by HVM, kill it\n");
-+ kill_domain_by_device(psdev);
-+ goto release;
-+ }
-+
-+ if ( !test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-+ dev_err(&dev->dev,
-+ "guest with no AER driver should have been killed\n");
-+ goto release;
-+ }
-+ result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result);
-+
-+ if (result == PCI_ERS_RESULT_NONE ||
-+ result == PCI_ERS_RESULT_DISCONNECT) {
-+ dev_dbg(&dev->dev,
-+ "No AER mmio_enabled service or disconnected!\n");
-+ kill_domain_by_device(psdev);
-+ }
-+release:
-+ pcistub_device_put(psdev);
-+end:
-+ up_write(&pcistub_sem);
-+ return result;
-+}
-+
-+/*pciback_error_detected: it will send the error_detected request to pcifront
-+* in case of the device driver could provide this service, and then wait
-+* for pcifront ack.
-+* @dev: pointer to PCI devices
-+* @error: the current PCI connection state
-+* return value is used by aer_core do_recovery policy
-+*/
-+
-+static pci_ers_result_t pciback_error_detected(struct pci_dev *dev,
-+ pci_channel_state_t error)
+ static void netif_idx_release(u16 pending_idx);
+-static void make_tx_response(netif_t *netif,
+- netif_tx_request_t *txp,
++static void make_tx_response(struct xen_netif *netif,
++ struct xen_netif_tx_request *txp,
+ s8 st);
+-static netif_rx_response_t *make_rx_response(netif_t *netif,
++static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
+ u16 id,
+ s8 st,
+ u16 offset,
+@@ -108,8 +117,8 @@ static inline int netif_page_index(struct page *pg)
+ #define PKT_PROT_LEN 64
+
+ static struct pending_tx_info {
+- netif_tx_request_t req;
+- netif_t *netif;
++ struct xen_netif_tx_request req;
++ struct xen_netif *netif;
+ } pending_tx_info[MAX_PENDING_REQS];
+ static u16 pending_ring[MAX_PENDING_REQS];
+ typedef unsigned int PEND_RING_IDX;
+@@ -128,8 +137,8 @@ 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 gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
++static struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+
+ static struct list_head net_schedule_list;
+ static spinlock_t net_schedule_list_lock;
+@@ -195,7 +204,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+ goto err;
+
+ skb_reserve(nskb, 16 + NET_IP_ALIGN);
+- headlen = nskb->end - nskb->data;
++ headlen = skb_end_pointer(nskb) - nskb->data;
+ if (headlen > skb_headlen(skb))
+ headlen = skb_headlen(skb);
+ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
+@@ -243,9 +252,9 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+
+ offset = nskb->data - skb->data;
+
+- nskb->h.raw = skb->h.raw + offset;
+- nskb->nh.raw = skb->nh.raw + offset;
+- nskb->mac.raw = skb->mac.raw + offset;
++ nskb->transport_header = skb->transport_header + offset;
++ nskb->network_header = skb->network_header + offset;
++ nskb->mac_header = skb->mac_header + offset;
+
+ return nskb;
+
+@@ -255,14 +264,14 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+ return NULL;
+ }
+
+-static inline int netbk_max_required_rx_slots(netif_t *netif)
++static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
+ {
+ if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
+ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
+ return 1; /* all in one */
+ }
+
+-static inline int netbk_queue_full(netif_t *netif)
++static inline int netbk_queue_full(struct xen_netif *netif)
+ {
+ RING_IDX peek = netif->rx_req_cons_peek;
+ RING_IDX needed = netbk_max_required_rx_slots(netif);
+@@ -273,14 +282,14 @@ static inline int netbk_queue_full(netif_t *netif)
+
+ static void tx_queue_callback(unsigned long data)
+ {
+- netif_t *netif = (netif_t *)data;
++ struct xen_netif *netif = (struct xen_netif *)data;
+ if (netif_schedulable(netif))
+ netif_wake_queue(netif->dev);
+ }
+
+ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+
+ BUG_ON(skb->dev != dev);
+
+@@ -302,7 +311,6 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ /* Copy only the header fields we use in this driver. */
+ nskb->dev = skb->dev;
+ nskb->ip_summed = skb->ip_summed;
+- nskb->proto_data_valid = skb->proto_data_valid;
+ dev_kfree_skb(skb);
+ skb = nskb;
+ }
+@@ -366,25 +374,25 @@ struct netrx_pending_operations {
+ unsigned mcl_prod, mcl_cons;
+ unsigned copy_prod, copy_cons;
+ unsigned meta_prod, meta_cons;
+- mmu_update_t *mmu;
+- gnttab_transfer_t *trans;
+- gnttab_copy_t *copy;
+- multicall_entry_t *mcl;
++ struct mmu_update *mmu;
++ struct gnttab_transfer *trans;
++ struct gnttab_copy *copy;
++ struct multicall_entry *mcl;
+ struct netbk_rx_meta *meta;
+ };
+
+ /* Set up the grant operations for this fragment. If it's a flipping
+ interface, we also set up the unmap request from here. */
+-static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
++static u16 netbk_gop_frag(struct xen_netif *netif, struct netbk_rx_meta *meta,
+ int i, struct netrx_pending_operations *npo,
+ struct page *page, unsigned long size,
+ unsigned long offset)
+ {
+- mmu_update_t *mmu;
+- gnttab_transfer_t *gop;
+- gnttab_copy_t *copy_gop;
+- multicall_entry_t *mcl;
+- netif_rx_request_t *req;
++ struct mmu_update *mmu;
++ struct gnttab_transfer *gop;
++ struct gnttab_copy *copy_gop;
++ struct multicall_entry *mcl;
++ struct xen_netif_rx_request *req;
+ unsigned long old_mfn, new_mfn;
+ int idx = netif_page_index(page);
+
+@@ -426,12 +434,12 @@ static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta
*meta,
+ mcl = npo->mcl + npo->mcl_prod++;
+ MULTI_update_va_mapping(mcl,
+ (unsigned long)page_address(page),
+- pfn_pte_ma(new_mfn, PAGE_KERNEL),
++ mfn_pte(new_mfn, PAGE_KERNEL),
+ 0);
+
+ mmu = npo->mmu + npo->mmu_prod++;
+- mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
+- MMU_MACHPHYS_UPDATE;
++ mmu->ptr = ((phys_addr_t)new_mfn << PAGE_SHIFT) |
++ MMU_MACHPHYS_UPDATE;
+ mmu->val = page_to_pfn(page);
+ }
+
+@@ -446,7 +454,7 @@ static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta
*meta,
+ static void netbk_gop_skb(struct sk_buff *skb,
+ struct netrx_pending_operations *npo)
+ {
+- netif_t *netif = netdev_priv(skb->dev);
++ struct xen_netif *netif = netdev_priv(skb->dev);
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
+ int extra;
+@@ -494,9 +502,9 @@ static inline void netbk_free_pages(int nr_frags, struct
netbk_rx_meta *meta)
+ static int netbk_check_gop(int nr_frags, domid_t domid,
+ struct netrx_pending_operations *npo)
+ {
+- multicall_entry_t *mcl;
+- gnttab_transfer_t *gop;
+- gnttab_copy_t *copy_op;
++ struct multicall_entry *mcl;
++ struct gnttab_transfer *gop;
++ struct gnttab_copy *copy_op;
+ int status = NETIF_RSP_OKAY;
+ int i;
+
+@@ -534,7 +542,7 @@ static int netbk_check_gop(int nr_frags, domid_t domid,
+ return status;
+ }
+
+-static void netbk_add_frag_responses(netif_t *netif, int status,
++static void netbk_add_frag_responses(struct xen_netif *netif, int status,
+ struct netbk_rx_meta *meta, int nr_frags)
+ {
+ int i;
+@@ -555,11 +563,11 @@ static void netbk_add_frag_responses(netif_t *netif, int status,
+
+ static void net_rx_action(unsigned long unused)
+ {
+- netif_t *netif = NULL;
++ struct xen_netif *netif = NULL;
+ s8 status;
+ u16 id, irq, flags;
+- netif_rx_response_t *resp;
+- multicall_entry_t *mcl;
++ struct xen_netif_rx_response *resp;
++ struct multicall_entry *mcl;
+ struct sk_buff_head rxq;
+ struct sk_buff *skb;
+ int notify_nr = 0;
+@@ -572,10 +580,10 @@ static void net_rx_action(unsigned long unused)
+ * 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 struct multicall_entry rx_mcl[NET_RX_RING_SIZE+3];
++ static struct mmu_update rx_mmu[NET_RX_RING_SIZE];
++ static struct gnttab_transfer grant_trans_op[NET_RX_RING_SIZE];
++ static struct gnttab_copy grant_copy_op[NET_RX_RING_SIZE];
+ static unsigned char rx_notify[NR_IRQS];
+ static u16 notify_list[NET_RX_RING_SIZE];
+ static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+@@ -596,7 +604,7 @@ static void net_rx_action(unsigned long unused)
+ *(int *)skb->cb = nr_frags;
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+- !((netif_t *)netdev_priv(skb->dev))->copying_receiver &&
++ !((struct xen_netif *)netdev_priv(skb->dev))->copying_receiver &&
+ check_mfn(nr_frags + 1)) {
+ /* Memory squeeze? Back off for an arbitrary while. */
+ if ( net_ratelimit() )
+@@ -692,9 +700,10 @@ static void net_rx_action(unsigned long unused)
+ id = meta[npo.meta_cons].id;
+ flags = nr_frags ? NETRXF_more_data : 0;
+
+- if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+ flags |= NETRXF_csum_blank | NETRXF_data_validated;
+- else if (skb->proto_data_valid) /* remote but checksummed? */
++ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
++ /* remote but checksummed. */
+ flags |= NETRXF_data_validated;
+
+ if (meta[npo.meta_cons].copy)
+@@ -705,8 +714,8 @@ static void net_rx_action(unsigned long unused)
+ skb_headlen(skb), flags);
+
+ if (meta[npo.meta_cons].frag.size) {
+- struct netif_extra_info *gso =
+- (struct netif_extra_info *)
++ struct xen_netif_extra_info *gso =
++ (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&netif->rx,
+ netif->rx.rsp_prod_pvt++);
+
+@@ -769,16 +778,16 @@ static void netbk_tx_pending_timeout(unsigned long unused)
+
+ struct net_device_stats *netif_be_get_stats(struct net_device *dev)
+ {
+- netif_t *netif = netdev_priv(dev);
++ struct xen_netif *netif = netdev_priv(dev);
+ return &netif->stats;
+ }
+
+-static int __on_net_schedule_list(netif_t *netif)
++static int __on_net_schedule_list(struct xen_netif *netif)
+ {
+ return netif->list.next != NULL;
+ }
+
+-static void remove_from_net_schedule_list(netif_t *netif)
++static void remove_from_net_schedule_list(struct xen_netif *netif)
+ {
+ spin_lock_irq(&net_schedule_list_lock);
+ if (likely(__on_net_schedule_list(netif))) {
+@@ -789,7 +798,7 @@ static void remove_from_net_schedule_list(netif_t *netif)
+ spin_unlock_irq(&net_schedule_list_lock);
+ }
+
+-static void add_to_net_schedule_list_tail(netif_t *netif)
++static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+ {
+ if (__on_net_schedule_list(netif))
+ return;
+@@ -811,7 +820,7 @@ static void add_to_net_schedule_list_tail(netif_t *netif)
+ * If we may be buffer transmit buffers for any reason then we must be rather
+ * more conservative and treat this as the final check for pending work.
+ */
+-void netif_schedule_work(netif_t *netif)
++void netif_schedule_work(struct xen_netif *netif)
+ {
+ int more_to_do;
+
+@@ -827,13 +836,13 @@ void netif_schedule_work(netif_t *netif)
+ }
+ }
+
+-void netif_deschedule_work(netif_t *netif)
++void netif_deschedule_work(struct xen_netif *netif)
+ {
+ remove_from_net_schedule_list(netif);
+ }
+
+
+-static void tx_add_credit(netif_t *netif)
++static void tx_add_credit(struct xen_netif *netif)
+ {
+ unsigned long max_burst, max_credit;
+
+@@ -855,7 +864,7 @@ static void tx_add_credit(netif_t *netif)
+
+ static void tx_credit_callback(unsigned long data)
+ {
+- netif_t *netif = (netif_t *)data;
++ struct xen_netif *netif = (struct xen_netif *)data;
+ tx_add_credit(netif);
+ netif_schedule_work(netif);
+ }
+@@ -869,10 +878,10 @@ static inline int copy_pending_req(PEND_RING_IDX pending_idx)
+ inline static void net_tx_action_dealloc(void)
+ {
+ struct netbk_tx_pending_inuse *inuse, *n;
+- gnttab_unmap_grant_ref_t *gop;
++ struct gnttab_unmap_grant_ref *gop;
+ u16 pending_idx;
+ PEND_RING_IDX dc, dp;
+- netif_t *netif;
++ struct xen_netif *netif;
+ int ret;
+ LIST_HEAD(list);
+
+@@ -954,7 +963,7 @@ inline static void net_tx_action_dealloc(void)
+ }
+ }
+
+-static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
++static void netbk_tx_err(struct xen_netif *netif, struct xen_netif_tx_request *txp,
RING_IDX end)
+ {
+ RING_IDX cons = netif->tx.req_cons;
+
+@@ -969,8 +978,8 @@ static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp,
RING_IDX end)
+ netif_put(netif);
+ }
+
+-static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
+- netif_tx_request_t *txp, int work_to_do)
++static int netbk_count_requests(struct xen_netif *netif, struct xen_netif_tx_request
*first,
++ struct xen_netif_tx_request *txp, int work_to_do)
+ {
+ RING_IDX cons = netif->tx.req_cons;
+ int frags = 0;
+@@ -1009,10 +1018,10 @@ static int netbk_count_requests(netif_t *netif,
netif_tx_request_t *first,
+ return frags;
+ }
+
+-static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
++static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
+ struct sk_buff *skb,
+- netif_tx_request_t *txp,
+- gnttab_map_grant_ref_t *mop)
++ struct xen_netif_tx_request *txp,
++ struct gnttab_map_grant_ref *mop)
+ {
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ skb_frag_t *frags = shinfo->frags;
+@@ -1039,12 +1048,12 @@ static gnttab_map_grant_ref_t *netbk_get_requests(netif_t
*netif,
+ }
+
+ static int netbk_tx_check_mop(struct sk_buff *skb,
+- gnttab_map_grant_ref_t **mopp)
++ struct gnttab_map_grant_ref **mopp)
+ {
+- gnttab_map_grant_ref_t *mop = *mopp;
++ struct gnttab_map_grant_ref *mop = *mopp;
+ int pending_idx = *((u16 *)skb->data);
+- netif_t *netif = pending_tx_info[pending_idx].netif;
+- netif_tx_request_t *txp;
++ struct xen_netif *netif = pending_tx_info[pending_idx].netif;
++ struct xen_netif_tx_request *txp;
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ int nr_frags = shinfo->nr_frags;
+ int i, err, start;
+@@ -1118,7 +1127,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
+
+ for (i = 0; i < nr_frags; i++) {
+ skb_frag_t *frag = shinfo->frags + i;
+- netif_tx_request_t *txp;
++ struct xen_netif_tx_request *txp;
+ unsigned long pending_idx;
+
+ pending_idx = (unsigned long)frag->page;
+@@ -1138,10 +1147,10 @@ static void netbk_fill_frags(struct sk_buff *skb)
+ }
+ }
+
+-int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
++int netbk_get_extras(struct xen_netif *netif, struct xen_netif_extra_info *extras,
+ int work_to_do)
+ {
+- struct netif_extra_info extra;
++ struct xen_netif_extra_info extra;
+ RING_IDX cons = netif->tx.req_cons;
+
+ do {
+@@ -1166,7 +1175,7 @@ int netbk_get_extras(netif_t *netif, struct netif_extra_info
*extras,
+ return work_to_do;
+ }
+
+-static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
++static int netbk_set_skb_gso(struct sk_buff *skb, struct xen_netif_extra_info *gso)
+ {
+ if (!gso->u.gso.size) {
+ DPRINTK("GSO size must not be zero.\n");
+@@ -1189,18 +1198,57 @@ static int netbk_set_skb_gso(struct sk_buff *skb, struct
netif_extra_info *gso)
+ return 0;
+ }
+
++static int skb_checksum_setup(struct sk_buff *skb)
+{
-+ struct pcistub_device *psdev;
-+ pci_ers_result_t result;
++ struct iphdr *iph;
++ unsigned char *th;
++ int err = -EPROTO;
+
-+ result = PCI_ERS_RESULT_CAN_RECOVER;
-+ dev_dbg(&dev->dev, "pciback_error_detected(bus:%x,devfn:%x)\n",
-+ dev->bus->number, dev->devfn);
++ if (skb->protocol != htons(ETH_P_IP))
++ goto out;
+
-+ down_write(&pcistub_sem);
-+ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
-+ dev->bus->number,
-+ PCI_SLOT(dev->devfn),
-+ PCI_FUNC(dev->devfn));
++ iph = (void *)skb->data;
++ th = skb->data + 4 * iph->ihl;
++ if (th >= skb_tail_pointer(skb))
++ goto out;
+
-+ if ( !psdev || !psdev->pdev )
-+ {
-+ dev_err(&dev->dev,
-+ "pciback device is not found/assigned\n");
-+ goto end;
++ skb->csum_start = th - skb->head;
++ switch (iph->protocol) {
++ case IPPROTO_TCP:
++ skb->csum_offset = offsetof(struct tcphdr, check);
++ break;
++ case IPPROTO_UDP:
++ skb->csum_offset = offsetof(struct udphdr, check);
++ break;
++ default:
++ if (net_ratelimit())
++ printk(KERN_ERR "Attempting to checksum a non-"
++ "TCP/UDP packet, dropping a protocol"
++ " %d packet", iph->protocol);
++ goto out;
+ }
+
-+ if ( !psdev->pdev->sh_info )
-+ {
-+ dev_err(&dev->dev, "pciback device is not connected or owned"
-+ " by HVM, kill it\n");
-+ kill_domain_by_device(psdev);
-+ goto release;
-+ }
++ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
++ goto out;
+
-+ /*Guest owns the device yet no aer handler regiested, kill guest*/
-+ if ( !test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-+ dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n");
-+ kill_domain_by_device(psdev);
-+ goto release;
-+ }
-+ result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result);
++ err = 0;
+
-+ if (result == PCI_ERS_RESULT_NONE ||
-+ result == PCI_ERS_RESULT_DISCONNECT) {
-+ dev_dbg(&dev->dev,
-+ "No AER error_detected service or disconnected!\n");
-+ kill_domain_by_device(psdev);
-+ }
-+release:
-+ pcistub_device_put(psdev);
-+end:
-+ up_write(&pcistub_sem);
-+ return result;
++out:
++ return err;
+}
+
-+/*pciback_error_resume: it will send the error_resume request to pcifront
-+* in case of the device driver could provide this service, and then wait
-+* for pcifront ack.
-+* @dev: pointer to PCI devices
-+*/
-+
-+static void pciback_error_resume(struct pci_dev *dev)
-+{
-+ struct pcistub_device *psdev;
-+
-+ dev_dbg(&dev->dev, "pciback_error_resume(bus:%x,devfn:%x)\n",
-+ dev->bus->number, dev->devfn);
+ /* Called after netfront has transmitted */
+ static void net_tx_action(unsigned long unused)
+ {
+ struct list_head *ent;
+ struct sk_buff *skb;
+- netif_t *netif;
+- netif_tx_request_t txreq;
+- netif_tx_request_t txfrags[MAX_SKB_FRAGS];
+- struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++ struct xen_netif *netif;
++ struct xen_netif_tx_request txreq;
++ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
++ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+ u16 pending_idx;
+ RING_IDX i;
+- gnttab_map_grant_ref_t *mop;
++ struct gnttab_map_grant_ref *mop;
+ unsigned int data_len;
+ int ret, work_to_do;
+
+@@ -1212,7 +1260,7 @@ static void net_tx_action(unsigned long unused)
+ !list_empty(&net_schedule_list)) {
+ /* Get a netif from the list with work to do. */
+ ent = net_schedule_list.next;
+- netif = list_entry(ent, netif_t, list);
++ netif = list_entry(ent, struct xen_netif, list);
+ netif_get(netif);
+ remove_from_net_schedule_list(netif);
+
+@@ -1313,7 +1361,7 @@ static void net_tx_action(unsigned long unused)
+ skb_reserve(skb, 16 + NET_IP_ALIGN);
+
+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+- struct netif_extra_info *gso;
++ struct xen_netif_extra_info *gso;
+ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+ if (netbk_set_skb_gso(skb, gso)) {
+@@ -1372,7 +1420,7 @@ static void net_tx_action(unsigned long unused)
+
+ mop = tx_map_ops;
+ while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
+- netif_tx_request_t *txp;
++ struct xen_netif_tx_request *txp;
+
+ pending_idx = *((u16 *)skb->data);
+ netif = pending_tx_info[pending_idx].netif;
+@@ -1403,14 +1451,10 @@ static void net_tx_action(unsigned long unused)
+ * Old frontends do not assert data_validated but we
+ * can infer it from csum_blank so test both flags.
+ */
+- if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
+- skb->ip_summed = CHECKSUM_UNNECESSARY;
+- skb->proto_data_valid = 1;
+- } else {
++ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank))
++ skb->ip_summed = CHECKSUM_PARTIAL;
++ else
+ skb->ip_summed = CHECKSUM_NONE;
+- skb->proto_data_valid = 0;
+- }
+- skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
+
+ netbk_fill_frags(skb);
+
+@@ -1420,6 +1464,14 @@ static void net_tx_action(unsigned long unused)
+ netif->stats.rx_bytes += skb->len;
+ netif->stats.rx_packets++;
+
++ if (skb->ip_summed == CHECKSUM_PARTIAL) {
++ if (skb_checksum_setup(skb)) {
++ DPRINTK("Can't setup checksum in net_tx_action\n");
++ kfree_skb(skb);
++ continue;
++ }
++ }
+
-+ down_write(&pcistub_sem);
-+ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
-+ dev->bus->number,
-+ PCI_SLOT(dev->devfn),
-+ PCI_FUNC(dev->devfn));
+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
+ unlikely(skb_linearize(skb))) {
+ DPRINTK("Can't linearize skb in net_tx_action.\n");
+@@ -1464,9 +1516,9 @@ static void netif_page_release(struct page *page, unsigned int
order)
+ netif_idx_release(idx);
+ }
+
+-irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t netif_be_int(int irq, void *dev_id)
+ {
+- netif_t *netif = dev_id;
++ struct xen_netif *netif = dev_id;
+
+ add_to_net_schedule_list_tail(netif);
+ maybe_schedule_tx_action();
+@@ -1477,12 +1529,12 @@ irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs
*regs)
+ return IRQ_HANDLED;
+ }
+
+-static void make_tx_response(netif_t *netif,
+- netif_tx_request_t *txp,
++static void make_tx_response(struct xen_netif *netif,
++ struct xen_netif_tx_request *txp,
+ s8 st)
+ {
+ RING_IDX i = netif->tx.rsp_prod_pvt;
+- netif_tx_response_t *resp;
++ struct xen_netif_tx_response *resp;
+ int notify;
+
+ resp = RING_GET_RESPONSE(&netif->tx, i);
+@@ -1507,7 +1559,7 @@ static void make_tx_response(netif_t *netif,
+ #endif
+ }
+
+-static netif_rx_response_t *make_rx_response(netif_t *netif,
++static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
+ u16 id,
+ s8 st,
+ u16 offset,
+@@ -1515,7 +1567,7 @@ static netif_rx_response_t *make_rx_response(netif_t *netif,
+ u16 flags)
+ {
+ RING_IDX i = netif->rx.rsp_prod_pvt;
+- netif_rx_response_t *resp;
++ struct xen_netif_rx_response *resp;
+
+ resp = RING_GET_RESPONSE(&netif->rx, i);
+ resp->offset = offset;
+@@ -1534,14 +1586,14 @@ static netif_rx_response_t *make_rx_response(netif_t *netif,
+ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ struct list_head *ent;
+- netif_t *netif;
++ struct xen_netif *netif;
+ int i = 0;
+
+ printk(KERN_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);
++ netif = list_entry(ent, struct xen_netif, list);
+ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
+ "rx_resp_prod=%08x\n",
+ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
+@@ -1569,11 +1621,13 @@ static int __init netback_init(void)
+ int i;
+ struct page *page;
+
+- if (!is_running_on_xen())
++ printk(KERN_CRIT "*** netif_init\n");
+
-+ if ( !psdev || !psdev->pdev )
-+ {
-+ dev_err(&dev->dev,
-+ "pciback device is not found/assigned\n");
-+ goto end;
-+ }
++ if (!xen_domain())
+ return -ENODEV;
+
+ /* We can increase reservation by this much in net_rx_action(). */
+- balloon_update_driver_allowance(NET_RX_RING_SIZE);
++// balloon_update_driver_allowance(NET_RX_RING_SIZE);
+
+ skb_queue_head_init(&rx_queue);
+ skb_queue_head_init(&tx_queue);
+@@ -1616,7 +1670,7 @@ static int __init netback_init(void)
+ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ }
+
+- netif_accel_init();
++ //netif_accel_init();
+
+ netif_xenbus_init();
+
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index d7faeb6..ed7c006 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -37,7 +37,7 @@ static int netback_remove(struct xenbus_device *dev)
+ {
+ struct backend_info *be = dev->dev.driver_data;
+
+- netback_remove_accelerators(be, dev);
++ //netback_remove_accelerators(be, dev);
+
+ if (be->netif) {
+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+@@ -123,7 +123,7 @@ static int netback_probe(struct xenbus_device *dev,
+ goto fail;
+ }
+
+- netback_probe_accelerators(be, dev);
++ //netback_probe_accelerators(be, dev);
+
+ err = xenbus_switch_state(dev, XenbusStateInitWait);
+ if (err)
+@@ -149,12 +149,10 @@ fail:
+ * and vif variables to the environment, for the benefit of the vif-* hotplug
+ * scripts.
+ */
+-static int netback_uevent(struct xenbus_device *xdev, char **envp,
+- int num_envp, char *buffer, int buffer_size)
++static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
+ {
+ struct backend_info *be = xdev->dev.driver_data;
+- netif_t *netif = be->netif;
+- int i = 0, length = 0;
++ struct xen_netif *netif = be->netif;
+ char *val;
+
+ DPRINTK("netback_uevent");
+@@ -166,15 +164,15 @@ static int netback_uevent(struct xenbus_device *xdev, char **envp,
+ return err;
+ }
+ else {
+- add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
+- &length, "script=%s", val);
++ if (add_uevent_var(env, "script=%s", val)) {
++ kfree(val);
++ return -ENOMEM;
++ }
+ kfree(val);
+ }
+
+- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+- "vif=%s", netif->dev->name);
+-
+- envp[i] = NULL;
++ if (add_uevent_var(env, "vif=%s", netif->dev->name))
++ return -ENOMEM;
+
+ return 0;
+ }
+@@ -450,5 +448,6 @@ static struct xenbus_driver netback = {
+
+ void netif_xenbus_init(void)
+ {
+- xenbus_register_backend(&netback);
++ printk(KERN_CRIT "registering netback\n");
++ (void)xenbus_register_backend(&netback);
+ }
+--
+1.7.4
+
+
+From a41a2ab9e1ac4ef8320f69f2719e973e25faff5c Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Date: Mon, 9 Feb 2009 16:39:01 -0800
+Subject: [PATCH 003/203] xen: netback: don't include xen/evtchn.h
+
+Its a usermode header for users of /dev/evtchn
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy(a)goop.org>
+---
+ drivers/xen/netback/common.h | 1 -
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 65b88f4..5665ed1 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -38,7 +38,6 @@
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/wait.h>
+-#include <xen/evtchn.h>
+ #include <xen/interface/io/netif.h>
+ #include <asm/io.h>
+ #include <asm/pgalloc.h>
+--
+1.7.4
+
+
+From f28a7c6148bb979acf99c0cbe3b441d0fb0853d9 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Wed, 18 Feb 2009 15:55:18 -0800
+Subject: [PATCH 004/203] xen: netback: use mod_timer
+
+__mod_timer is no longer a public API.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index c959075..e920703 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -334,7 +334,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ */
+ netif->tx_queue_timeout.data = (unsigned long)netif;
+ netif->tx_queue_timeout.function = tx_queue_callback;
+- __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
++ mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
+ }
+ }
+
+@@ -1299,7 +1299,7 @@ static void net_tx_action(unsigned long unused)
+ (unsigned long)netif;
+ netif->credit_timeout.function =
+ tx_credit_callback;
+- __mod_timer(&netif->credit_timeout,
++ mod_timer(&netif->credit_timeout,
+ next_credit);
+ netif_put(netif);
+ continue;
+--
+1.7.4
+
+
+From 52f97ad360f28762c785343ba5c9f8abb83536f3 Mon Sep 17 00:00:00 2001
+From: Jan Beulich <jbeulich(a)novell.com>
+Date: Fri, 6 Mar 2009 08:29:31 +0000
+Subject: [PATCH 005/203] xen: netback: unmap tx ring gref when mapping of rx ring gref
failed
+
+[ijc-ported from linux-2.6.18-xen.hg 782:51decc39e5e7]
+Signed-off-by: Jan Beulich <jbeulich(a)novell.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index d184ad7..f3d9ea1 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -222,6 +222,12 @@ static int map_frontend_pages(
+ BUG();
+
+ if (op.status) {
++ struct gnttab_unmap_grant_ref unop;
+
-+ if ( !psdev->pdev->sh_info )
-+ {
-+ dev_err(&dev->dev, "pciback device is not connected or owned"
-+ " by HVM, kill it\n");
-+ kill_domain_by_device(psdev);
-+ goto release;
-+ }
++ gnttab_set_unmap_op(&unop,
++ (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, netif->tx_shmem_handle);
++ HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
+ DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
+ return op.status;
+ }
+--
+1.7.4
+
+
+From f9b63790f1404eb03ac824147b2294a46e485643 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)citrix.com>
+Date: Fri, 6 Mar 2009 08:29:32 +0000
+Subject: [PATCH 006/203] xen: netback: add ethtool stat to track copied skbs.
+
+Copied skbs should be rare but we have no way of verifying that.
+
+[ijc-ported from linux-2.6.18-xen.hg 792:db9857bb0320]
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 3 ++
+ drivers/xen/netback/interface.c | 47 +++++++++++++++++++++++++++++++++++++++
+ drivers/xen/netback/netback.c | 6 ++++-
+ 3 files changed, 55 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 5665ed1..6ba804d 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -92,6 +92,9 @@ struct xen_netif {
+ /* Enforce draining of the transmit queue. */
+ struct timer_list tx_queue_timeout;
+
++ /* Statistics */
++ int nr_copied_skbs;
+
-+ if ( !test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-+ dev_err(&dev->dev,
-+ "guest with no AER driver should have been killed\n");
-+ kill_domain_by_device(psdev);
-+ goto release;
-+ }
-+ common_process(psdev, 1, XEN_PCI_OP_aer_resume, PCI_ERS_RESULT_RECOVERED);
-+release:
-+ pcistub_device_put(psdev);
-+end:
-+ up_write(&pcistub_sem);
-+ return;
+ /* Miscellaneous private stuff. */
+ struct list_head list; /* scheduling list */
+ atomic_t refcnt;
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index f3d9ea1..1a99c87 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -119,8 +119,51 @@ static int netbk_set_tso(struct net_device *dev, u32 data)
+ return ethtool_op_set_tso(dev, data);
+ }
+
++static void netbk_get_drvinfo(struct net_device *dev,
++ struct ethtool_drvinfo *info)
++{
++ strcpy(info->driver, "netbk");
+}
+
-+/*add pciback AER handling*/
-+static struct pci_error_handlers pciback_error_handler = {
-+ .error_detected = pciback_error_detected,
-+ .mmio_enabled = pciback_mmio_enabled,
-+ .slot_reset = pciback_slot_reset,
-+ .resume = pciback_error_resume,
-+};
-+
-+/*
-+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
-+ * for a normal device. I don't want it to be loaded automatically.
-+ */
-+
-+static struct pci_driver pciback_pci_driver = {
-+ .name = "pciback",
-+ .id_table = pcistub_ids,
-+ .probe = pcistub_probe,
-+ .remove = pcistub_remove,
-+ .err_handler = &pciback_error_handler,
++static const struct netif_stat {
++ char name[ETH_GSTRING_LEN];
++ u16 offset;
++} netbk_stats[] = {
++ { "copied_skbs", offsetof(struct xen_netif, nr_copied_skbs) },
+};
+
-+static inline int str_to_slot(const char *buf, int *domain, int *bus,
-+ int *slot, int *func)
++static int netbk_get_stats_count(struct net_device *dev)
+{
-+ int err;
-+
-+ err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
-+ if (err == 4)
-+ return 0;
-+ else if (err < 0)
-+ return -EINVAL;
-+
-+ /* try again without domain */
-+ *domain = 0;
-+ err = sscanf(buf, " %x:%x.%x", bus, slot, func);
-+ if (err == 3)
-+ return 0;
-+
-+ return -EINVAL;
++ return ARRAY_SIZE(netbk_stats);
+}
+
-+static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
-+ *slot, int *func, int *reg, int *size, int *mask)
++static void netbk_get_ethtool_stats(struct net_device *dev,
++ struct ethtool_stats *stats, u64 * data)
+{
-+ int err;
++ void *netif = netdev_priv(dev);
++ int i;
+
-+ err =
-+ sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot,
-+ func, reg, size, mask);
-+ if (err == 7)
-+ return 0;
-+ return -EINVAL;
++ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
++ data[i] = *(int *)(netif + netbk_stats[i].offset);
+}
+
-+static int pcistub_device_id_add(int domain, int bus, int slot, int func)
++static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
-+ struct pcistub_device_id *pci_dev_id;
-+ unsigned long flags;
-+
-+ pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
-+ if (!pci_dev_id)
-+ return -ENOMEM;
-+
-+ pci_dev_id->domain = domain;
-+ pci_dev_id->bus = bus;
-+ pci_dev_id->devfn = PCI_DEVFN(slot, func);
-+
-+ pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
-+ domain, bus, slot, func);
-+
-+ spin_lock_irqsave(&device_ids_lock, flags);
-+ list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
-+ spin_unlock_irqrestore(&device_ids_lock, flags);
++ int i;
+
-+ return 0;
++ switch (stringset) {
++ case ETH_SS_STATS:
++ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
++ memcpy(data + i * ETH_GSTRING_LEN,
++ netbk_stats[i].name, ETH_GSTRING_LEN);
++ break;
++ }
+}
+
-+static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
-+{
-+ struct pcistub_device_id *pci_dev_id, *t;
-+ int devfn = PCI_DEVFN(slot, func);
-+ int err = -ENOENT;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&device_ids_lock, flags);
-+ list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
+ static struct ethtool_ops network_ethtool_ops =
+ {
++ .get_drvinfo = netbk_get_drvinfo,
+
-+ if (pci_dev_id->domain == domain
-+ && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
-+ /* Don't break; here because it's possible the same
-+ * slot could be in the list more than once
-+ */
-+ list_del(&pci_dev_id->slot_list);
-+ kfree(pci_dev_id);
-+
-+ err = 0;
-+
-+ pr_debug("pciback: removed %04x:%02x:%02x.%01x from "
-+ "seize list\n", domain, bus, slot, func);
-+ }
-+ }
-+ spin_unlock_irqrestore(&device_ids_lock, flags);
-+
-+ return err;
-+}
-+
-+static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
-+ int size, int mask)
-+{
-+ int err = 0;
-+ struct pcistub_device *psdev;
-+ struct pci_dev *dev;
-+ struct config_field *field;
-+
-+ psdev = pcistub_device_find(domain, bus, slot, func);
-+ if (!psdev || !psdev->dev) {
-+ err = -ENODEV;
-+ goto out;
-+ }
-+ dev = psdev->dev;
-+
-+ field = kzalloc(sizeof(*field), GFP_ATOMIC);
-+ if (!field) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+@@ -128,6 +171,10 @@ static struct ethtool_ops network_ethtool_ops =
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = netbk_set_tso,
+ .get_link = ethtool_op_get_link,
+
-+ field->offset = reg;
-+ field->size = size;
-+ field->mask = mask;
-+ field->init = NULL;
-+ field->reset = NULL;
-+ field->release = NULL;
-+ field->clean = pciback_config_field_free;
++ .get_stats_count = netbk_get_stats_count,
++ .get_ethtool_stats = netbk_get_ethtool_stats,
++ .get_strings = netbk_get_strings,
+ };
+
+ struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index e920703..f59fadb 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -923,7 +923,11 @@ inline static void net_tx_action_dealloc(void)
+ if (time_after(inuse->alloc_time + HZ / 2, jiffies))
+ break;
+
+- switch (copy_pending_req(inuse - pending_inuse)) {
++ pending_idx = inuse - pending_inuse;
+
-+ err = pciback_config_quirks_add_field(dev, field);
-+ if (err)
-+ kfree(field);
-+ out:
-+ return err;
-+}
++ pending_tx_info[pending_idx].netif->nr_copied_skbs++;
+
-+static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
-+ size_t count)
-+{
-+ int domain, bus, slot, func;
-+ int err;
++ switch (copy_pending_req(pending_idx)) {
+ case 0:
+ list_move_tail(&inuse->list, &list);
+ continue;
+--
+1.7.4
+
+
+From c41d8da3d853d4e89ba38693b90c1fe512095704 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)citrix.com>
+Date: Fri, 6 Mar 2009 08:29:33 +0000
+Subject: [PATCH 007/203] xen: netback: make queue length parameter writeable in sysfs
+
+Any changes will only take effect for newly created VIFs.
+
+Also hook up the vif devices to their parent and publish bus info via
+ethtool.
+
+[ijc-ported from linux-2.6.18-xen.hg 793:3aa9b8a7876b]
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 3 ++-
+ drivers/xen/netback/xenbus.c | 1 +
+ 2 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 1a99c87..7706170 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -52,7 +52,7 @@
+ * blocked.
+ */
+ static unsigned long netbk_queue_length = 32;
+-module_param_named(queue_length, netbk_queue_length, ulong, 0);
++module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+
+ static void __netif_up(struct xen_netif *netif)
+ {
+@@ -123,6 +123,7 @@ static void netbk_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+ {
+ strcpy(info->driver, "netbk");
++ strcpy(info->bus_info, dev->dev.parent->bus_id);
+ }
+
+ static const struct netif_stat {
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index ed7c006..dc7b367 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -200,6 +200,7 @@ static void backend_create_netif(struct backend_info *be)
+ xenbus_dev_fatal(dev, err, "creating interface");
+ return;
+ }
++ SET_NETDEV_DEV(be->netif->dev, &dev->dev);
+
+ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+ }
+--
+1.7.4
+
+
+From f204d7567ab11ddb1ff3208ab5ed8921b575af5d Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)citrix.com>
+Date: Mon, 16 Mar 2009 22:05:16 +0000
+Subject: [PATCH 008/203] xen: netback: parent sysfs device should be set before
registering.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 2 +-
+ drivers/xen/netback/interface.c | 4 +++-
+ drivers/xen/netback/xenbus.c | 3 +--
+ 3 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 6ba804d..123a169 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -180,7 +180,7 @@ void netif_accel_init(void);
+
+ void netif_disconnect(struct xen_netif *netif);
+
+-struct xen_netif *netif_alloc(domid_t domid, unsigned int handle);
++struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle);
+ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn);
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 7706170..5e0d26d 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -178,7 +178,7 @@ static struct ethtool_ops network_ethtool_ops =
+ .get_strings = netbk_get_strings,
+ };
+
+-struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
++struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle)
+ {
+ int err = 0;
+ struct net_device *dev;
+@@ -192,6 +192,8 @@ struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
+ return ERR_PTR(-ENOMEM);
+ }
+
++ SET_NETDEV_DEV(dev, parent);
+
-+ err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+ if (err)
-+ goto out;
+ netif = netdev_priv(dev);
+ memset(netif, 0, sizeof(*netif));
+ netif->domid = domid;
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index dc7b367..749931e 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -193,14 +193,13 @@ static void backend_create_netif(struct backend_info *be)
+ return;
+ }
+
+- be->netif = netif_alloc(dev->otherend_id, handle);
++ be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
+ if (IS_ERR(be->netif)) {
+ err = PTR_ERR(be->netif);
+ be->netif = NULL;
+ xenbus_dev_fatal(dev, err, "creating interface");
+ return;
+ }
+- SET_NETDEV_DEV(be->netif->dev, &dev->dev);
+
+ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+ }
+--
+1.7.4
+
+
+From bb606178665ea78b505cb54864899478b6020584 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 12:42:36 -0700
+Subject: [PATCH 009/203] xen: netback: use NET_SKB_PAD rather than "16"
+
+There's a constant for the default skb headroom.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index f59fadb..400f398 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -203,7 +203,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+ if (unlikely(!nskb))
+ goto err;
+
+- skb_reserve(nskb, 16 + NET_IP_ALIGN);
++ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
+ headlen = skb_end_pointer(nskb) - nskb->data;
+ if (headlen > skb_headlen(skb))
+ headlen = skb_headlen(skb);
+@@ -1353,7 +1353,7 @@ static void net_tx_action(unsigned long unused)
+ ret < MAX_SKB_FRAGS) ?
+ PKT_PROT_LEN : txreq.size;
+
+- skb = alloc_skb(data_len + 16 + NET_IP_ALIGN,
++ skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(skb == NULL)) {
+ DPRINTK("Can't allocate a skb in start_xmit.\n");
+@@ -1362,7 +1362,7 @@ static void net_tx_action(unsigned long unused)
+ }
+
+ /* Packets passed to netif_rx() must have some headroom. */
+- skb_reserve(skb, 16 + NET_IP_ALIGN);
++ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+ struct xen_netif_extra_info *gso;
+--
+1.7.4
+
+
+From fe41ab031dfa0c6f9821c2667ce821e7f4f635ed Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 13:31:26 -0700
+Subject: [PATCH 010/203] xen: netback: completely drop flip support
+
+Nobody uses it?
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 1 -
+ drivers/xen/netback/netback.c | 245 ++++-------------------------------------
+ drivers/xen/netback/xenbus.c | 3 +-
+ 3 files changed, 22 insertions(+), 227 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 123a169..06f04c1 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -78,7 +78,6 @@ struct xen_netif {
+
+ /* Internal feature information. */
+ u8 can_queue:1; /* can queue packets for receiver? */
+- u8 copying_receiver:1; /* copy packets to receiver? */
+
+ /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
+ RING_IDX rx_req_cons_peek;
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 400f398..36bea2b 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -51,7 +51,6 @@
+ struct netbk_rx_meta {
+ skb_frag_t frag;
+ int id;
+- u8 copy:1;
+ };
+
+ struct netbk_tx_pending_inuse {
+@@ -160,26 +159,6 @@ static inline unsigned long alloc_mfn(void)
+ return mfn_list[--alloc_index];
+ }
+
+-static int check_mfn(int nr)
+-{
+- struct xen_memory_reservation reservation = {
+- .extent_order = 0,
+- .domid = DOMID_SELF
+- };
+- int rc;
+-
+- if (likely(alloc_index >= nr))
+- return 0;
+-
+- set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
+- reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
+- rc = HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation);
+- if (likely(rc > 0))
+- alloc_index += rc;
+-
+- return alloc_index >= nr ? 0 : -ENOMEM;
+-}
+-
+ static inline void maybe_schedule_tx_action(void)
+ {
+ smp_mb();
+@@ -188,82 +167,6 @@ static inline void maybe_schedule_tx_action(void)
+ tasklet_schedule(&net_tx_tasklet);
+ }
+
+-static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+-{
+- struct skb_shared_info *ninfo;
+- struct sk_buff *nskb;
+- unsigned long offset;
+- int ret;
+- int len;
+- int headlen;
+-
+- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
+-
+- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
+- if (unlikely(!nskb))
+- goto err;
+-
+- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
+- headlen = skb_end_pointer(nskb) - nskb->data;
+- if (headlen > skb_headlen(skb))
+- headlen = skb_headlen(skb);
+- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
+- BUG_ON(ret);
+-
+- ninfo = skb_shinfo(nskb);
+- ninfo->gso_size = skb_shinfo(skb)->gso_size;
+- ninfo->gso_type = skb_shinfo(skb)->gso_type;
+-
+- offset = headlen;
+- len = skb->len - headlen;
+-
+- nskb->len = skb->len;
+- nskb->data_len = len;
+- nskb->truesize += len;
+-
+- while (len) {
+- struct page *page;
+- int copy;
+- int zero;
+-
+- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
+- dump_stack();
+- goto err_free;
+- }
+-
+- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
+- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
+-
+- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
+- if (unlikely(!page))
+- goto err_free;
+-
+- ret = skb_copy_bits(skb, offset, page_address(page), copy);
+- BUG_ON(ret);
+-
+- ninfo->frags[ninfo->nr_frags].page = page;
+- ninfo->frags[ninfo->nr_frags].page_offset = 0;
+- ninfo->frags[ninfo->nr_frags].size = copy;
+- ninfo->nr_frags++;
+-
+- offset += copy;
+- len -= copy;
+- }
+-
+- offset = nskb->data - skb->data;
+-
+- nskb->transport_header = skb->transport_header + offset;
+- nskb->network_header = skb->network_header + offset;
+- nskb->mac_header = skb->mac_header + offset;
+-
+- return nskb;
+-
+- err_free:
+- kfree_skb(nskb);
+- err:
+- return NULL;
+-}
+-
+ static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
+ {
+ if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
+@@ -297,24 +200,6 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
+ goto drop;
+
+- /*
+- * Copy the packet here if it's destined for a flipping interface
+- * but isn't flippable (e.g. extra references to data).
+- * XXX For now we also copy skbuffs whose head crosses a page
+- * boundary, because netbk_gop_skb can't handle them.
+- */
+- if (!netif->copying_receiver ||
+- ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) {
+- struct sk_buff *nskb = netbk_copy_skb(skb);
+- if ( unlikely(nskb == NULL) )
+- goto drop;
+- /* Copy only the header fields we use in this driver. */
+- nskb->dev = skb->dev;
+- nskb->ip_summed = skb->ip_summed;
+- dev_kfree_skb(skb);
+- skb = nskb;
+- }
+-
+ netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
+ !!skb_shinfo(skb)->gso_size;
+ netif_get(netif);
+@@ -388,66 +273,32 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
+ struct page *page, unsigned long size,
+ unsigned long offset)
+ {
+- struct mmu_update *mmu;
+- struct gnttab_transfer *gop;
+ struct gnttab_copy *copy_gop;
+- struct multicall_entry *mcl;
+ struct xen_netif_rx_request *req;
+- unsigned long old_mfn, new_mfn;
++ unsigned long old_mfn;
+ int idx = netif_page_index(page);
+
+ old_mfn = virt_to_mfn(page_address(page));
+
+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
+- if (netif->copying_receiver) {
+- /* 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];
+- copy_gop->source.domid = src_pend->netif->domid;
+- copy_gop->source.u.ref = src_pend->req.gref;
+- copy_gop->flags |= GNTCOPY_source_gref;
+- } else {
+- copy_gop->source.domid = DOMID_SELF;
+- copy_gop->source.u.gmfn = old_mfn;
+- }
+- copy_gop->source.offset = offset;
+- copy_gop->dest.domid = netif->domid;
+- copy_gop->dest.offset = 0;
+- copy_gop->dest.u.ref = req->gref;
+- copy_gop->len = size;
+- } else {
+- meta->copy = 0;
+- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+- new_mfn = alloc_mfn();
+-
+- /*
+- * Set the new P2M table entry before
+- * reassigning the old data page. Heed the
+- * comment in pgtable-2level.h:pte_page(). :-)
+- */
+- set_phys_to_machine(page_to_pfn(page), new_mfn);
+-
+- mcl = npo->mcl + npo->mcl_prod++;
+- MULTI_update_va_mapping(mcl,
+- (unsigned long)page_address(page),
+- mfn_pte(new_mfn, PAGE_KERNEL),
+- 0);
+-
+- mmu = npo->mmu + npo->mmu_prod++;
+- mmu->ptr = ((phys_addr_t)new_mfn << PAGE_SHIFT) |
+- MMU_MACHPHYS_UPDATE;
+- mmu->val = page_to_pfn(page);
+- }
+
+- gop = npo->trans + npo->trans_prod++;
+- gop->mfn = old_mfn;
+- gop->domid = netif->domid;
+- gop->ref = req->gref;
++ 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];
++ copy_gop->source.domid = src_pend->netif->domid;
++ copy_gop->source.u.ref = src_pend->req.gref;
++ copy_gop->flags |= GNTCOPY_source_gref;
++ } else {
++ copy_gop->source.domid = DOMID_SELF;
++ copy_gop->source.u.gmfn = old_mfn;
+ }
++ copy_gop->source.offset = offset;
++ copy_gop->dest.domid = netif->domid;
++ copy_gop->dest.offset = 0;
++ copy_gop->dest.u.ref = req->gref;
++ copy_gop->len = size;
+
-+ err = pcistub_device_id_add(domain, bus, slot, func);
-+
-+ out:
-+ if (!err)
-+ err = count;
-+ return err;
-+}
-+
-+DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
-+
-+static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
-+ size_t count)
-+{
-+ int domain, bus, slot, func;
-+ int err;
-+
-+ err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+ if (err)
-+ goto out;
-+
-+ err = pcistub_device_id_remove(domain, bus, slot, func);
-+
-+ out:
-+ if (!err)
-+ err = count;
-+ return err;
-+}
-+
-+DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
-+
-+static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
-+{
-+ struct pcistub_device_id *pci_dev_id;
-+ size_t count = 0;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&device_ids_lock, flags);
-+ list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
-+ if (count >= PAGE_SIZE)
-+ break;
-+
-+ count += scnprintf(buf + count, PAGE_SIZE - count,
-+ "%04x:%02x:%02x.%01x\n",
-+ pci_dev_id->domain, pci_dev_id->bus,
-+ PCI_SLOT(pci_dev_id->devfn),
-+ PCI_FUNC(pci_dev_id->devfn));
-+ }
-+ spin_unlock_irqrestore(&device_ids_lock, flags);
-+
-+ return count;
-+}
-+
-+DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
-+
-+static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
-+ size_t count)
-+{
-+ int domain, bus, slot, func, reg, size, mask;
-+ int err;
-+
-+ err = str_to_quirk(buf, &domain, &bus, &slot, &func, ®,
&size,
-+ &mask);
-+ if (err)
-+ goto out;
-+
-+ err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
-+
-+ out:
-+ if (!err)
-+ err = count;
-+ return err;
-+}
-+
-+static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
-+{
-+ int count = 0;
-+ unsigned long flags;
-+ extern struct list_head pciback_quirks;
-+ struct pciback_config_quirk *quirk;
-+ struct pciback_dev_data *dev_data;
-+ const struct config_field *field;
-+ const struct config_field_entry *cfg_entry;
-+
-+ spin_lock_irqsave(&device_ids_lock, flags);
-+ list_for_each_entry(quirk, &pciback_quirks, quirks_list) {
-+ if (count >= PAGE_SIZE)
-+ goto out;
-+
-+ count += scnprintf(buf + count, PAGE_SIZE - count,
-+ "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n",
-+ quirk->pdev->bus->number,
-+ PCI_SLOT(quirk->pdev->devfn),
-+ PCI_FUNC(quirk->pdev->devfn),
-+ quirk->devid.vendor, quirk->devid.device,
-+ quirk->devid.subvendor,
-+ quirk->devid.subdevice);
-+
-+ dev_data = pci_get_drvdata(quirk->pdev);
-+
-+ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+ field = cfg_entry->field;
-+ if (count >= PAGE_SIZE)
-+ goto out;
-+
-+ count += scnprintf(buf + count, PAGE_SIZE - count,
-+ "\t\t%08x:%01x:%08x\n",
-+ cfg_entry->base_offset + field->offset,
-+ field->size, field->mask);
-+ }
-+ }
-+
-+ out:
-+ spin_unlock_irqrestore(&device_ids_lock, flags);
-+
-+ return count;
-+}
-+
-+DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
-+
-+static ssize_t permissive_add(struct device_driver *drv, const char *buf,
-+ size_t count)
-+{
-+ int domain, bus, slot, func;
-+ int err;
-+ struct pcistub_device *psdev;
-+ struct pciback_dev_data *dev_data;
-+ err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+ if (err)
-+ goto out;
-+ psdev = pcistub_device_find(domain, bus, slot, func);
-+ if (!psdev) {
-+ err = -ENODEV;
-+ goto out;
-+ }
-+ if (!psdev->dev) {
-+ err = -ENODEV;
-+ goto release;
-+ }
-+ dev_data = pci_get_drvdata(psdev->dev);
-+ /* the driver data for a device should never be null at this point */
-+ if (!dev_data) {
-+ err = -ENXIO;
-+ goto release;
-+ }
-+ if (!dev_data->permissive) {
-+ dev_data->permissive = 1;
-+ /* Let user know that what they're doing could be unsafe */
-+ dev_warn(&psdev->dev->dev,
-+ "enabling permissive mode configuration space accesses!\n");
-+ dev_warn(&psdev->dev->dev,
-+ "permissive mode is potentially unsafe!\n");
-+ }
-+ release:
-+ pcistub_device_put(psdev);
-+ out:
-+ if (!err)
-+ err = count;
-+ return err;
-+}
+ return req->id;
+ }
+
+@@ -502,41 +353,17 @@ static inline void netbk_free_pages(int nr_frags, struct
netbk_rx_meta *meta)
+ static int netbk_check_gop(int nr_frags, domid_t domid,
+ struct netrx_pending_operations *npo)
+ {
+- struct multicall_entry *mcl;
+- struct gnttab_transfer *gop;
+ struct gnttab_copy *copy_op;
+ int status = NETIF_RSP_OKAY;
+ int i;
+
+ for (i = 0; i <= nr_frags; i++) {
+- if (npo->meta[npo->meta_cons + i].copy) {
+ copy_op = npo->copy + npo->copy_cons++;
+ if (copy_op->status != GNTST_okay) {
+ DPRINTK("Bad status %d from copy to DOM%d.\n",
+ copy_op->status, domid);
+ status = NETIF_RSP_ERROR;
+ }
+- } else {
+- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+- mcl = npo->mcl + npo->mcl_cons++;
+- /* The update_va_mapping() must not fail. */
+- BUG_ON(mcl->result != 0);
+- }
+-
+- gop = npo->trans + npo->trans_cons++;
+- /* Check the reassignment error code. */
+- if (gop->status != 0) {
+- DPRINTK("Bad status %d from grant transfer to DOM%u\n",
+- gop->status, domid);
+- /*
+- * Page no longer belongs to us unless
+- * GNTST_bad_page, but that should be
+- * a fatal error anyway.
+- */
+- BUG_ON(gop->status == GNTST_bad_page);
+- status = NETIF_RSP_ERROR;
+- }
+- }
+ }
+
+ return status;
+@@ -551,11 +378,8 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
+ for (i = 0; i < nr_frags; i++) {
+ int id = meta[i].id;
+ int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
+-
+- if (meta[i].copy)
+- offset = 0;
+- else
+- offset = meta[i].frag.page_offset;
++
++ offset = 0;
+ make_rx_response(netif, id, status, offset,
+ meta[i].frag.size, flags);
+ }
+@@ -603,18 +427,6 @@ static void net_rx_action(unsigned long unused)
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ *(int *)skb->cb = nr_frags;
+
+- if (!xen_feature(XENFEAT_auto_translated_physmap) &&
+- !((struct xen_netif *)netdev_priv(skb->dev))->copying_receiver &&
+- check_mfn(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);
+- break;
+- }
+-
+ netbk_gop_skb(skb, &npo);
+
+ count += nr_frags + 1;
+@@ -677,20 +489,6 @@ static void net_rx_action(unsigned long unused)
+ nr_frags = *(int *)skb->cb;
+
+ netif = netdev_priv(skb->dev);
+- /* We can't rely on skb_release_data to release the
+- pages used by fragments for us, since it tries to
+- touch the pages in the fraglist. If we're in
+- flipping mode, that doesn't work. In copying mode,
+- we still have access to all of the pages, and so
+- it's safe to let release_data deal with it. */
+- /* (Freeing the fragments is safe since we copy
+- non-linear skbs destined for flipping interfaces) */
+- if (!netif->copying_receiver) {
+- 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);
+- }
+
+ netif->stats.tx_bytes += skb->len;
+ netif->stats.tx_packets++;
+@@ -706,10 +504,7 @@ static void net_rx_action(unsigned long unused)
+ /* remote but checksummed. */
+ flags |= NETRXF_data_validated;
+
+- if (meta[npo.meta_cons].copy)
+- offset = 0;
+- else
+- offset = offset_in_page(skb->data);
++ offset = 0;
+ resp = make_rx_response(netif, id, status, offset,
+ skb_headlen(skb), flags);
+
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index 749931e..a492288 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -378,7 +378,8 @@ static int connect_rings(struct backend_info *be)
+ dev->otherend);
+ return err;
+ }
+- be->netif->copying_receiver = !!rx_copy;
++ if (!rx_copy)
++ return -EOPNOTSUPP;
+
+ if (be->netif->dev->tx_queue_len != 0) {
+ if (xenbus_scanf(XBT_NIL, dev->otherend,
+--
+1.7.4
+
+
+From 17d465234118873ab4f5a7992feb4ce7b5537cf7 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 15:19:39 -0700
+Subject: [PATCH 011/203] xen: netback: demacro MASK_PEND_IDX
+
+Replace it with a more meaningful inline: pending_index().
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 21 +++++++++++++--------
+ 1 files changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 36bea2b..4095622 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -121,7 +121,12 @@ static struct pending_tx_info {
+ } 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 ssize_t permissive_show(struct device_driver *drv, char *buf)
++static inline PEND_RING_IDX pending_index(unsigned i)
+{
-+ struct pcistub_device *psdev;
-+ struct pciback_dev_data *dev_data;
-+ size_t count = 0;
-+ unsigned long flags;
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (count >= PAGE_SIZE)
-+ break;
-+ if (!psdev->dev)
-+ continue;
-+ dev_data = pci_get_drvdata(psdev->dev);
-+ if (!dev_data || !dev_data->permissive)
-+ continue;
-+ count +=
-+ scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
-+ pci_name(psdev->dev));
-+ }
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+ return count;
++ return i & (MAX_PENDING_REQS-1);
+}
+
-+DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
-+
-+#ifdef CONFIG_PCI_MSI
-+
-+int pciback_get_owner(struct pci_dev *dev)
-+{
-+ struct pcistub_device *psdev;
-+
-+ psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number,
-+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-+
-+ if (!psdev || !psdev->pdev)
-+ return -1;
-+
-+ return psdev->pdev->xdev->otherend_id;
-+}
-+#endif
+ static PEND_RING_IDX pending_prod, pending_cons;
+ #define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
+@@ -695,7 +700,7 @@ inline static void net_tx_action_dealloc(void)
+ while (dc != dp) {
+ unsigned long pfn;
+
+- pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
++ pending_idx = dealloc_ring[pending_index(dc++)];
+ list_move_tail(&pending_inuse[pending_idx].list, &list);
+
+ pfn = idx_to_pfn(pending_idx);
+@@ -754,7 +759,7 @@ inline static void net_tx_action_dealloc(void)
+ /* Ready for next use. */
+ gnttab_reset_grant_page(mmap_pages[pending_idx]);
+
+- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++ pending_ring[pending_index(pending_prod++)] = pending_idx;
+
+ netif_put(netif);
+
+@@ -831,7 +836,7 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
+ 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++)];
++ pending_idx = pending_ring[pending_index(pending_cons++)];
+
+ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+@@ -862,7 +867,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ if (unlikely(err)) {
+ txp = &pending_tx_info[pending_idx].req;
+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
+- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++ pending_ring[pending_index(pending_prod++)] = pending_idx;
+ netif_put(netif);
+ } else {
+ set_phys_to_machine(
+@@ -895,7 +900,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ /* 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;
++ pending_ring[pending_index(pending_prod++)] = pending_idx;
+ netif_put(netif);
+
+ /* Not the first error? Preceding frags already invalidated. */
+@@ -1142,7 +1147,7 @@ static void net_tx_action(unsigned long unused)
+ continue;
+ }
+
+- pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
++ pending_idx = pending_ring[pending_index(pending_cons)];
+
+ data_len = (txreq.size > PKT_PROT_LEN &&
+ ret < MAX_SKB_FRAGS) ?
+@@ -1298,7 +1303,7 @@ static void netif_idx_release(u16 pending_idx)
+ unsigned long flags;
+
+ spin_lock_irqsave(&_lock, flags);
+- dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
++ dealloc_ring[pending_index(dealloc_prod)] = pending_idx;
+ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
+ smp_wmb();
+ dealloc_prod++;
+--
+1.7.4
+
+
+From d47af34f87b2d365c75aa3579ad512619ef3d579 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 15:29:30 -0700
+Subject: [PATCH 012/203] xen: netback: convert PEND_RING_IDX into a proper typedef name
+
+Rename PEND_RING_IDX to pending_ring_idx_t. Its not used that much,
+the extra typing won't kill anyone.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 12 ++++++------
+ 1 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 4095622..8292e96 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -120,19 +120,19 @@ static struct pending_tx_info {
+ struct xen_netif *netif;
+ } pending_tx_info[MAX_PENDING_REQS];
+ static u16 pending_ring[MAX_PENDING_REQS];
+-typedef unsigned int PEND_RING_IDX;
++typedef unsigned int pending_ring_idx_t;
+
+-static inline PEND_RING_IDX pending_index(unsigned i)
++static inline pending_ring_idx_t pending_index(unsigned i)
+ {
+ return i & (MAX_PENDING_REQS-1);
+ }
+
+-static PEND_RING_IDX pending_prod, pending_cons;
++static pending_ring_idx_t 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;
++static pending_ring_idx_t dealloc_prod, dealloc_cons;
+
+ /* Doubly-linked list of in-use pending entries. */
+ static struct netbk_tx_pending_inuse pending_inuse[MAX_PENDING_REQS];
+@@ -669,7 +669,7 @@ static void tx_credit_callback(unsigned long data)
+ netif_schedule_work(netif);
+ }
+
+-static inline int copy_pending_req(PEND_RING_IDX pending_idx)
++static inline int copy_pending_req(pending_ring_idx_t pending_idx)
+ {
+ return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
+ &mmap_pages[pending_idx]);
+@@ -680,7 +680,7 @@ inline static void net_tx_action_dealloc(void)
+ struct netbk_tx_pending_inuse *inuse, *n;
+ struct gnttab_unmap_grant_ref *gop;
+ u16 pending_idx;
+- PEND_RING_IDX dc, dp;
++ pending_ring_idx_t dc, dp;
+ struct xen_netif *netif;
+ int ret;
+ LIST_HEAD(list);
+--
+1.7.4
+
+
+From 56727a43f329d50c2a00fed0316ffd87d6c23ebd Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 15:31:32 -0700
+Subject: [PATCH 013/203] xen: netback: rename NR_PENDING_REQS to nr_pending_reqs()
+
+Use function syntax to show its actually computing a value, rather than
+a constant.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 10 +++++++---
+ 1 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 8292e96..5410a68 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -128,7 +128,11 @@ static inline pending_ring_idx_t pending_index(unsigned i)
+ }
+
+ static pending_ring_idx_t pending_prod, pending_cons;
+-#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
-+static void pcistub_exit(void)
++static inline pending_ring_idx_t nr_pending_reqs(void)
+{
-+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
-+ driver_remove_file(&pciback_pci_driver.driver,
-+ &driver_attr_remove_slot);
-+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
-+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
-+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
-+
-+ pci_unregister_driver(&pciback_pci_driver);
-+ WARN_ON(unregister_msi_get_owner(pciback_get_owner));
++ return MAX_PENDING_REQS - pending_prod + pending_cons;
+}
-+
-+static int __init pcistub_init(void)
+
+ /* Freed TX SKBs get batched on this ring before return to pending_ring. */
+ static u16 dealloc_ring[MAX_PENDING_REQS];
+@@ -167,7 +171,7 @@ static inline unsigned long alloc_mfn(void)
+ static inline void maybe_schedule_tx_action(void)
+ {
+ smp_mb();
+- if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
++ if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&net_schedule_list))
+ tasklet_schedule(&net_tx_tasklet);
+ }
+@@ -1060,7 +1064,7 @@ static void net_tx_action(unsigned long unused)
+ net_tx_action_dealloc();
+
+ mop = tx_map_ops;
+- while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&net_schedule_list)) {
+ /* Get a netif from the list with work to do. */
+ ent = net_schedule_list.next;
+--
+1.7.4
+
+
+From 55b360614f1bd44d0b1395b4aabf41d8f1f13f17 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 15:45:45 -0700
+Subject: [PATCH 014/203] xen: netback: pre-initialize list and spinlocks; use empty list
to indicate not on list
+
+Statically pre-initialize net_schedule_list head and lock.
+
+Use an empty list to mark when a xen_netif is not on the schedule list,
+rather than NULL (which may upset list debugging).
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 1 +
+ drivers/xen/netback/netback.c | 12 ++++--------
+ 2 files changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 5e0d26d..dc4fb53 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -201,6 +201,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ atomic_set(&netif->refcnt, 1);
+ init_waitqueue_head(&netif->waiting_to_free);
+ netif->dev = dev;
++ INIT_LIST_HEAD(&netif->list);
+
+ netback_carrier_off(netif);
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 5410a68..cbd4b03 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -148,8 +148,8 @@ static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
+ static struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+ static struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+
+-static struct list_head net_schedule_list;
+-static spinlock_t net_schedule_list_lock;
++static LIST_HEAD(net_schedule_list);
++static DEFINE_SPINLOCK(net_schedule_list_lock);
+
+ #define MAX_MFN_ALLOC 64
+ static unsigned long mfn_list[MAX_MFN_ALLOC];
+@@ -588,15 +588,14 @@ struct net_device_stats *netif_be_get_stats(struct net_device
*dev)
+
+ static int __on_net_schedule_list(struct xen_netif *netif)
+ {
+- return netif->list.next != NULL;
++ return !list_empty(&netif->list);
+ }
+
+ static void remove_from_net_schedule_list(struct xen_netif *netif)
+ {
+ spin_lock_irq(&net_schedule_list_lock);
+ if (likely(__on_net_schedule_list(netif))) {
+- list_del(&netif->list);
+- netif->list.next = NULL;
++ list_del_init(&netif->list);
+ netif_put(netif);
+ }
+ spin_unlock_irq(&net_schedule_list_lock);
+@@ -1466,9 +1465,6 @@ static int __init netback_init(void)
+ for (i = 0; i < MAX_PENDING_REQS; i++)
+ pending_ring[i] = i;
+
+- spin_lock_init(&net_schedule_list_lock);
+- INIT_LIST_HEAD(&net_schedule_list);
+-
+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+ if (MODPARM_copy_skb) {
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
+--
+1.7.4
+
+
+From e12cf57de7a6c20e4c8900ce7bf4e6924a12f49e Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 15:48:10 -0700
+Subject: [PATCH 015/203] xen: netback: remove CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
+
+Keir says:
+> > Does CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER need to be a config
+> > option? Could/should we always/never set it?
+> It doesn't work well with local delivery into dom0, nor even with IP
+> fragment reassembly. I don't think we would ever turn it on these days.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 21 ---------------------
+ 1 files changed, 0 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index cbd4b03..f00e405 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -615,23 +615,11 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+ spin_unlock_irq(&net_schedule_list_lock);
+ }
+
+-/*
+- * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
+- * If this driver is pipelining transmit requests then we can be very
+- * aggressive in avoiding new-packet notifications -- frontend only needs to
+- * send a notification if there are no outstanding unreceived responses.
+- * If we may be buffer transmit buffers for any reason then we must be rather
+- * more conservative and treat this as the final check for pending work.
+- */
+ void netif_schedule_work(struct xen_netif *netif)
+ {
+ int more_to_do;
+
+-#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
+- more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
+-#else
+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
+-#endif
+
+ if (more_to_do) {
+ add_to_net_schedule_list_tail(netif);
+@@ -1355,15 +1343,6 @@ static void make_tx_response(struct xen_netif *netif,
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
+ if (notify)
+ notify_remote_via_irq(netif->irq);
+-
+-#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
+- if (i == netif->tx.req_cons) {
+- int more_to_do;
+- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
+- if (more_to_do)
+- add_to_net_schedule_list_tail(netif);
+- }
+-#endif
+ }
+
+ static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
+--
+1.7.4
+
+
+From adf542f9c714e3b7c76fcf9e44e0a89cae21a341 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 22:28:52 -0700
+Subject: [PATCH 016/203] xen: netback: make netif_get/put inlines
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 16 ++++++++++------
+ 1 files changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 06f04c1..9056be0 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -183,12 +183,16 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn);
+
+-#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
+-#define netif_put(_b) \
+- do { \
+- if ( atomic_dec_and_test(&(_b)->refcnt) ) \
+- wake_up(&(_b)->waiting_to_free); \
+- } while (0)
++static inline void netif_get(struct xen_netif *netif)
+{
-+ int pos = 0;
-+ int err = 0;
-+ int domain, bus, slot, func;
-+ int parsed;
-+
-+ if (pci_devs_to_hide && *pci_devs_to_hide) {
-+ do {
-+ parsed = 0;
-+
-+ err = sscanf(pci_devs_to_hide + pos,
-+ " (%x:%x:%x.%x) %n",
-+ &domain, &bus, &slot, &func, &parsed);
-+ if (err != 4) {
-+ domain = 0;
-+ err = sscanf(pci_devs_to_hide + pos,
-+ " (%x:%x.%x) %n",
-+ &bus, &slot, &func, &parsed);
-+ if (err != 3)
-+ goto parse_error;
-+ }
-+
-+ err = pcistub_device_id_add(domain, bus, slot, func);
-+ if (err)
-+ goto out;
-+
-+ /* if parsed<=0, we've reached the end of the string */
-+ pos += parsed;
-+ } while (parsed > 0 && pci_devs_to_hide[pos]);
-+ }
-+
-+ /* If we're the first PCI Device Driver to register, we're the
-+ * first one to get offered PCI devices as they become
-+ * available (and thus we can be the first to grab them)
-+ */
-+ err = pci_register_driver(&pciback_pci_driver);
-+ if (err < 0)
-+ goto out;
-+
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_new_slot);
-+ if (!err)
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_remove_slot);
-+ if (!err)
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_slots);
-+ if (!err)
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_quirks);
-+ if (!err)
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_permissive);
-+
-+ if (!err)
-+ err = register_msi_get_owner(pciback_get_owner);
-+ if (err)
-+ pcistub_exit();
-+
-+ out:
-+ return err;
-+
-+ parse_error:
-+ printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at
\"%s\"\n",
-+ pci_devs_to_hide + pos);
-+ return -EINVAL;
++ atomic_inc(&netif->refcnt);
+}
+
-+#ifndef MODULE
-+/*
-+ * fs_initcall happens before device_initcall
-+ * so pciback *should* get called first (b/c we
-+ * want to suck up any device before other drivers
-+ * get a chance by being the first pci device
-+ * driver to register)
-+ */
-+fs_initcall(pcistub_init);
-+#endif
-+
-+static int __init pciback_init(void)
++static inline void netif_put(struct xen_netif *netif)
+{
-+ int err;
++ if (atomic_dec_and_test(&netif->refcnt))
++ wake_up(&netif->waiting_to_free);
++}
+
+ void netif_xenbus_init(void);
+
+--
+1.7.4
+
+
+From f06459a199f953a68f001f06e54dde54e1e16c87 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 19 Mar 2009 22:30:24 -0700
+Subject: [PATCH 017/203] xen: netback: move code around
+
+net_tx_action() into several functions; move variables into
+their innermost scopes; rename "i" to "idx".
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 158 ++++++++++++++++++++++++-----------------
+ 1 files changed, 94 insertions(+), 64 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index f00e405..4d63ff3 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -773,7 +773,8 @@ static void netbk_tx_err(struct xen_netif *netif, struct
xen_netif_tx_request *t
+ netif_put(netif);
+ }
+
+-static int netbk_count_requests(struct xen_netif *netif, struct xen_netif_tx_request
*first,
++static int netbk_count_requests(struct xen_netif *netif,
++ struct xen_netif_tx_request *first,
+ struct xen_netif_tx_request *txp, int work_to_do)
+ {
+ RING_IDX cons = netif->tx.req_cons;
+@@ -1032,30 +1033,58 @@ out:
+ return err;
+ }
+
+-/* Called after netfront has transmitted */
+-static void net_tx_action(unsigned long unused)
++static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
+ {
+- struct list_head *ent;
+- struct sk_buff *skb;
+- struct xen_netif *netif;
+- struct xen_netif_tx_request txreq;
+- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+- u16 pending_idx;
+- RING_IDX i;
+- struct gnttab_map_grant_ref *mop;
+- unsigned int data_len;
+- int ret, work_to_do;
++ unsigned long now = jiffies;
++ unsigned long next_credit =
++ netif->credit_timeout.expires +
++ msecs_to_jiffies(netif->credit_usec / 1000);
+
-+ err = pciback_config_init();
-+ if (err)
-+ return err;
++ /* Timer could already be pending in rare cases. */
++ if (timer_pending(&netif->credit_timeout))
++ return true;
+
-+#ifdef MODULE
-+ err = pcistub_init();
-+ if (err < 0)
-+ return err;
-+#endif
++ /* Passed the point where we can replenish credit? */
++ if (time_after_eq(now, next_credit)) {
++ netif->credit_timeout.expires = now;
++ tx_add_credit(netif);
++ }
+
+- if (dealloc_cons != dealloc_prod)
+- net_tx_action_dealloc();
++ /* Still too big to send right now? Set a callback. */
++ if (size > netif->remaining_credit) {
++ netif->credit_timeout.data =
++ (unsigned long)netif;
++ netif->credit_timeout.function =
++ tx_credit_callback;
++ mod_timer(&netif->credit_timeout,
++ next_credit);
+
-+ pcistub_init_devices_late();
-+ err = pciback_xenbus_register();
-+ if (err)
-+ pcistub_exit();
++ return true;
++ }
+
-+ return err;
++ return false;
+}
+
-+static void __exit pciback_cleanup(void)
++static unsigned net_tx_build_mops(void)
+{
-+ pciback_xenbus_unregister();
-+ pcistub_exit();
-+}
-+
-+module_init(pciback_init);
-+module_exit(pciback_cleanup);
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-new file mode 100644
-index 0000000..6744f45
---- /dev/null
-+++ b/drivers/xen/pciback/pciback.h
-@@ -0,0 +1,126 @@
-+/*
-+ * PCI Backend Common Data Structures & Function Declarations
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
-+#ifndef __XEN_PCIBACK_H__
-+#define __XEN_PCIBACK_H__
-+
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <xen/xenbus.h>
-+#include <linux/list.h>
-+#include <linux/spinlock.h>
-+#include <linux/workqueue.h>
-+#include <asm/atomic.h>
-+#include <xen/interface/io/pciif.h>
-+
-+struct pci_dev_entry {
-+ struct list_head list;
-+ struct pci_dev *dev;
-+};
-+
-+#define _PDEVF_op_active (0)
-+#define PDEVF_op_active (1<<(_PDEVF_op_active))
-+#define _PCIB_op_pending (1)
-+#define PCIB_op_pending (1<<(_PCIB_op_pending))
-+
-+struct pciback_device {
-+ void *pci_dev_data;
-+ spinlock_t dev_lock;
-+
-+ struct xenbus_device *xdev;
-+
-+ struct xenbus_watch be_watch;
-+ u8 be_watching;
-+
-+ int evtchn_irq;
-+
-+ struct vm_struct *sh_area;
-+ struct xen_pci_sharedinfo *sh_info;
-+
-+ unsigned long flags;
-+
-+ struct work_struct op_work;
-+};
-+
-+struct pciback_dev_data {
-+ struct list_head config_fields;
-+ int permissive;
-+ int warned_on_write;
-+};
-+
-+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
-+struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
-+ int domain, int bus,
-+ int slot, int func);
-+struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
-+ struct pci_dev *dev);
-+void pcistub_put_pci_dev(struct pci_dev *dev);
-+
-+/* Ensure a device is turned off or reset */
-+void pciback_reset_device(struct pci_dev *pdev);
++ struct gnttab_map_grant_ref *mop;
++ struct sk_buff *skb;
++ int ret;
+
+ mop = tx_map_ops;
+ while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&net_schedule_list)) {
++ struct xen_netif *netif;
++ struct xen_netif_tx_request txreq;
++ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
++ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++ u16 pending_idx;
++ RING_IDX idx;
++ int work_to_do;
++ unsigned int data_len;
++
+ /* Get a netif from the list with work to do. */
+- ent = net_schedule_list.next;
+- netif = list_entry(ent, struct xen_netif, list);
++ netif = list_first_entry(&net_schedule_list, struct xen_netif, list);
+ netif_get(netif);
+ remove_from_net_schedule_list(netif);
+
+@@ -1065,67 +1094,43 @@ static void net_tx_action(unsigned long unused)
+ continue;
+ }
+
+- i = netif->tx.req_cons;
++ idx = netif->tx.req_cons;
+ rmb(); /* Ensure that we see the request before we copy it. */
+- memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
++ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
+
+ /* Credit-based scheduling. */
+- if (txreq.size > netif->remaining_credit) {
+- unsigned long now = jiffies;
+- unsigned long next_credit =
+- netif->credit_timeout.expires +
+- msecs_to_jiffies(netif->credit_usec / 1000);
+-
+- /* Timer could already be pending in rare cases. */
+- if (timer_pending(&netif->credit_timeout)) {
+- netif_put(netif);
+- continue;
+- }
+-
+- /* Passed the point where we can replenish credit? */
+- if (time_after_eq(now, next_credit)) {
+- netif->credit_timeout.expires = now;
+- tx_add_credit(netif);
+- }
+-
+- /* Still too big to send right now? Set a callback. */
+- if (txreq.size > netif->remaining_credit) {
+- netif->credit_timeout.data =
+- (unsigned long)netif;
+- netif->credit_timeout.function =
+- tx_credit_callback;
+- mod_timer(&netif->credit_timeout,
+- next_credit);
+- netif_put(netif);
+- continue;
+- }
++ if (txreq.size > netif->remaining_credit &&
++ tx_credit_exceeded(netif, txreq.size)) {
++ netif_put(netif);
++ continue;
+ }
+
-+/* Access a virtual configuration space for a PCI device */
-+int pciback_config_init(void);
-+int pciback_config_init_dev(struct pci_dev *dev);
-+void pciback_config_free_dyn_fields(struct pci_dev *dev);
-+void pciback_config_reset_dev(struct pci_dev *dev);
-+void pciback_config_free_dev(struct pci_dev *dev);
-+int pciback_config_read(struct pci_dev *dev, int offset, int size,
-+ u32 * ret_val);
-+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
-+
-+/* Handle requests for specific devices from the frontend */
-+typedef int (*publish_pci_dev_cb) (struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn, unsigned int devid);
-+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
-+ unsigned int domain, unsigned int bus);
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
-+ int devid, publish_pci_dev_cb publish_cb);
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn);
-+
-+/**
-+* Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in pciback
-+* before sending aer request to pcifront, so that guest could identify
-+* device, coopearte with pciback to finish aer recovery job if device driver
-+* has the capability
-+*/
-+
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus, unsigned int *devfn);
-+int pciback_init_devices(struct pciback_device *pdev);
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+ publish_pci_root_cb cb);
-+void pciback_release_devices(struct pciback_device *pdev);
-+
-+/* Handles events from front-end */
-+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
-+void pciback_do_op(void *data);
-+
-+int pciback_xenbus_register(void);
-+void pciback_xenbus_unregister(void);
-+
-+#ifdef CONFIG_PCI_MSI
-+int pciback_enable_msi(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op);
+ netif->remaining_credit -= txreq.size;
+
+ work_to_do--;
+- netif->tx.req_cons = ++i;
++ netif->tx.req_cons = ++idx;
+
+ memset(extras, 0, sizeof(extras));
+ if (txreq.flags & NETTXF_extra_info) {
+ work_to_do = netbk_get_extras(netif, extras,
+ work_to_do);
+- i = netif->tx.req_cons;
++ idx = netif->tx.req_cons;
+ if (unlikely(work_to_do < 0)) {
+- netbk_tx_err(netif, &txreq, i);
++ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+ }
+
+ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
+ if (unlikely(ret < 0)) {
+- netbk_tx_err(netif, &txreq, i - ret);
++ netbk_tx_err(netif, &txreq, idx - ret);
+ continue;
+ }
+- i += ret;
++ idx += ret;
+
+ if (unlikely(txreq.size < ETH_HLEN)) {
+ DPRINTK("Bad packet size: %d\n", txreq.size);
+- netbk_tx_err(netif, &txreq, i);
++ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+
+@@ -1134,7 +1139,7 @@ static void net_tx_action(unsigned long unused)
+ DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
+ txreq.offset, txreq.size,
+ (txreq.offset &~PAGE_MASK) + txreq.size);
+- netbk_tx_err(netif, &txreq, i);
++ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+
+@@ -1148,7 +1153,7 @@ static void net_tx_action(unsigned long unused)
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(skb == NULL)) {
+ DPRINTK("Can't allocate a skb in start_xmit.\n");
+- netbk_tx_err(netif, &txreq, i);
++ netbk_tx_err(netif, &txreq, idx);
+ break;
+ }
+
+@@ -1161,7 +1166,7 @@ static void net_tx_action(unsigned long unused)
+
+ if (netbk_set_skb_gso(skb, gso)) {
+ kfree_skb(skb);
+- netbk_tx_err(netif, &txreq, i);
++ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+ }
+@@ -1199,23 +1204,27 @@ static void net_tx_action(unsigned long unused)
+
+ mop = netbk_get_requests(netif, skb, txfrags, mop);
+
+- netif->tx.req_cons = i;
++ netif->tx.req_cons = idx;
+ netif_schedule_work(netif);
+
+ if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
+ break;
+ }
+
+- if (mop == tx_map_ops)
+- return;
++ return mop - tx_map_ops;
++}
+
+- ret = HYPERVISOR_grant_table_op(
+- GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
+- BUG_ON(ret);
++static void net_tx_submit(void)
++{
++ struct gnttab_map_grant_ref *mop;
++ struct sk_buff *skb;
+
+ mop = tx_map_ops;
+ while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
+ struct xen_netif_tx_request *txp;
++ struct xen_netif *netif;
++ u16 pending_idx;
++ unsigned data_len;
+
+ pending_idx = *((u16 *)skb->data);
+ netif = pending_tx_info[pending_idx].netif;
+@@ -1288,6 +1297,27 @@ static void net_tx_action(unsigned long unused)
+ }
+ }
+
++/* Called after netfront has transmitted */
++static void net_tx_action(unsigned long unused)
++{
++ unsigned nr_mops;
++ int ret;
+
-+int pciback_disable_msi(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op);
++ if (dealloc_cons != dealloc_prod)
++ net_tx_action_dealloc();
+
++ nr_mops = net_tx_build_mops();
+
-+int pciback_enable_msix(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op);
++ if (nr_mops == 0)
++ return;
+
-+int pciback_disable_msix(struct pciback_device *pdev,
-+ struct pci_dev *dev, struct xen_pci_op *op);
-+#endif
-+extern int verbose_request;
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
++ tx_map_ops, nr_mops);
++ BUG_ON(ret);
+
-+void test_and_schedule_op(struct pciback_device *pdev);
-+#endif
++ net_tx_submit();
++}
+
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-new file mode 100644
-index 0000000..b85b2db
---- /dev/null
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -0,0 +1,134 @@
+ static void netif_idx_release(u16 pending_idx)
+ {
+ static DEFINE_SPINLOCK(_lock);
+--
+1.7.4
+
+
+From cec84ff81d9f6ca882908572b984215529b4117b Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Fri, 20 Mar 2009 23:18:12 -0700
+Subject: [PATCH 018/203] xen: netback: document PKT_PROT_LEN
+
+Document the rationale for the existence and value of PKT_PROT_LEN.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 4d63ff3..80b424f 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -113,6 +113,15 @@ static inline int netif_page_index(struct page *pg)
+ return idx;
+ }
+
+/*
-+ * PCI Backend Operations - respond to PCI requests from Frontend
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ * This is the amount of packet we copy rather than map, so that the
++ * guest can't fiddle with the contents of the headers while we do
++ * packet processing on them (netfilter, routing, etc). This could
++ * probably do with being larger, since 1) 64-bytes isn't necessarily
++ * long enough to cover a full christmas-tree ip+tcp header, let alone
++ * packet contents, and 2) the data is probably in cache anyway
++ * (though perhaps some other cpu's cache).
+ */
-+#include <linux/module.h>
-+#include <linux/wait.h>
-+#include <asm/bitops.h>
-+#include <xen/evtchn.h>
-+#include "pciback.h"
-+
-+int verbose_request = 0;
-+module_param(verbose_request, int, 0644);
+ #define PKT_PROT_LEN 64
+
+ static struct pending_tx_info {
+--
+1.7.4
+
+
+From a9402ee935757e8facebc6e886f9912c2c523da7 Mon Sep 17 00:00:00 2001
+From: Christophe Saout <chtephan(a)leto.intern.saout.de>
+Date: Sun, 12 Apr 2009 13:40:27 +0200
+Subject: [PATCH 019/203] xen: netback: use dev_name() instead of removed ->bus_id.
+
+Signed-off-by: Christophe Saout <chtephan(a)leto.intern.saout.de>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index dc4fb53..3bb5c20 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -123,7 +123,7 @@ static void netbk_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+ {
+ strcpy(info->driver, "netbk");
+- strcpy(info->bus_info, dev->dev.parent->bus_id);
++ strcpy(info->bus_info, dev_name(dev->dev.parent));
+ }
+
+ static const struct netif_stat {
+--
+1.7.4
+
+
+From 35de1701fca19d693e9722bffbe7609caf1d5ac6 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Mon, 29 Jun 2009 14:04:23 -0700
+Subject: [PATCH 020/203] xen: netback: convert to net_device_ops
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 17 +++++++++++------
+ 1 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 3bb5c20..21c1f95 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -178,6 +178,15 @@ static struct ethtool_ops network_ethtool_ops =
+ .get_strings = netbk_get_strings,
+ };
+
++static struct net_device_ops netback_ops =
++{
++ .ndo_start_xmit = netif_be_start_xmit,
++ .ndo_get_stats = netif_be_get_stats,
++ .ndo_open = net_open,
++ .ndo_stop = net_close,
++ .ndo_change_mtu = netbk_change_mtu,
++};
+
-+/* Ensure a device is "turned off" and ready to be exported.
-+ * (Also see pciback_config_reset to ensure virtual configuration space is
-+ * ready to be re-exported)
-+ */
-+void pciback_reset_device(struct pci_dev *dev)
+ struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle)
+ {
+ int err = 0;
+@@ -213,12 +222,8 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+
+ init_timer(&netif->tx_queue_timeout);
+
+- dev->hard_start_xmit = netif_be_start_xmit;
+- dev->get_stats = netif_be_get_stats;
+- dev->open = net_open;
+- dev->stop = net_close;
+- dev->change_mtu = netbk_change_mtu;
+- dev->features = NETIF_F_IP_CSUM;
++ dev->netdev_ops = &netback_ops;
++ dev->features = NETIF_F_IP_CSUM;
+
+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+
+--
+1.7.4
+
+
+From c6f3885ef05e96489025e1c1c7299aac7cf43d87 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Fri, 4 Sep 2009 14:55:43 -0700
+Subject: [PATCH 021/203] xen: netback: reinstate missing code
+
+Change c3219dc868fe3e84070d6da2d0759a834b6f7251, "Completely drop flip
+support" was a bit too aggressive in removing code, and removed a chunk
+which was used for not only flip but if a buffer crossed a page boundary.
+Reinstate that code.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 91 +++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 91 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 80b424f..7c0f05b 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -185,6 +185,82 @@ static inline void maybe_schedule_tx_action(void)
+ tasklet_schedule(&net_tx_tasklet);
+ }
+
++static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+{
-+ u16 cmd;
++ struct skb_shared_info *ninfo;
++ struct sk_buff *nskb;
++ unsigned long offset;
++ int ret;
++ int len;
++ int headlen;
+
-+ /* Disable devices (but not bridges) */
-+ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-+ pci_disable_device(dev);
++ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
+
-+ pci_write_config_word(dev, PCI_COMMAND, 0);
++ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(!nskb))
++ goto err;
+
-+ dev->is_enabled = 0;
-+ dev->is_busmaster = 0;
-+ } else {
-+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
-+ if (cmd & (PCI_COMMAND_INVALIDATE)) {
-+ cmd &= ~(PCI_COMMAND_INVALIDATE);
-+ pci_write_config_word(dev, PCI_COMMAND, cmd);
++ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
++ headlen = skb_end_pointer(nskb) - nskb->data;
++ if (headlen > skb_headlen(skb))
++ headlen = skb_headlen(skb);
++ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
++ BUG_ON(ret);
+
-+ dev->is_busmaster = 0;
-+ }
-+ }
-+}
-+extern wait_queue_head_t aer_wait_queue;
-+extern struct workqueue_struct *pciback_wq;
-+/*
-+* Now the same evtchn is used for both pcifront conf_read_write request
-+* as well as pcie aer front end ack. We use a new work_queue to schedule
-+* pciback conf_read_write service for avoiding confict with aer_core
-+* do_recovery job which also use the system default work_queue
-+*/
-+void test_and_schedule_op(struct pciback_device *pdev)
-+{
-+ /* Check that frontend is requesting an operation and that we are not
-+ * already processing a request */
-+ if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
-+ && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
-+ {
-+ queue_work(pciback_wq, &pdev->op_work);
-+ }
-+ /*_XEN_PCIB_active should have been cleared by pcifront. And also make
-+ sure pciback is waiting for ack by checking _PCIB_op_pending*/
-+ if (!test_bit(_XEN_PCIB_active,(unsigned long *)&pdev->sh_info->flags)
-+ &&test_bit(_PCIB_op_pending, &pdev->flags)) {
-+ wake_up(&aer_wait_queue);
-+ }
-+}
++ ninfo = skb_shinfo(nskb);
++ ninfo->gso_size = skb_shinfo(skb)->gso_size;
++ ninfo->gso_type = skb_shinfo(skb)->gso_type;
+
-+/* Performing the configuration space reads/writes must not be done in atomic
-+ * context because some of the pci_* functions can sleep (mostly due to ACPI
-+ * use of semaphores). This function is intended to be called from a work
-+ * queue in process context taking a struct pciback_device as a parameter */
-+void pciback_do_op(void *data)
-+{
-+ struct pciback_device *pdev = data;
-+ struct pci_dev *dev;
-+ struct xen_pci_op *op = &pdev->sh_info->op;
++ offset = headlen;
++ len = skb->len - headlen;
+
-+ dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
++ nskb->len = skb->len;
++ nskb->data_len = len;
++ nskb->truesize += len;
+
-+ if (dev == NULL)
-+ op->err = XEN_PCI_ERR_dev_not_found;
-+ else
-+ {
-+ switch (op->cmd)
-+ {
-+ case XEN_PCI_OP_conf_read:
-+ op->err = pciback_config_read(dev,
-+ op->offset, op->size, &op->value);
-+ break;
-+ case XEN_PCI_OP_conf_write:
-+ op->err = pciback_config_write(dev,
-+ op->offset, op->size, op->value);
-+ break;
-+#ifdef CONFIG_PCI_MSI
-+ case XEN_PCI_OP_enable_msi:
-+ op->err = pciback_enable_msi(pdev, dev, op);
-+ break;
-+ case XEN_PCI_OP_disable_msi:
-+ op->err = pciback_disable_msi(pdev, dev, op);
-+ break;
-+ case XEN_PCI_OP_enable_msix:
-+ op->err = pciback_enable_msix(pdev, dev, op);
-+ break;
-+ case XEN_PCI_OP_disable_msix:
-+ op->err = pciback_disable_msix(pdev, dev, op);
-+ break;
-+#endif
-+ default:
-+ op->err = XEN_PCI_ERR_not_implemented;
-+ break;
++ while (len) {
++ struct page *page;
++ int copy;
++ int zero;
++
++ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
++ dump_stack();
++ goto err_free;
+ }
-+ }
-+ /* Tell the driver domain that we're done. */
-+ wmb();
-+ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
-+ notify_remote_via_irq(pdev->evtchn_irq);
+
-+ /* Mark that we're done. */
-+ smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */
-+ clear_bit(_PDEVF_op_active, &pdev->flags);
-+ smp_mb__after_clear_bit(); /* /before/ final check for work */
++ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
++ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
+
-+ /* Check to see if the driver domain tried to start another request in
-+ * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
-+ */
-+ test_and_schedule_op(pdev);
-+}
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
++ if (unlikely(!page))
++ goto err_free;
+
-+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ struct pciback_device *pdev = dev_id;
++ ret = skb_copy_bits(skb, offset, page_address(page), copy);
++ BUG_ON(ret);
+
-+ test_and_schedule_op(pdev);
++ ninfo->frags[ninfo->nr_frags].page = page;
++ ninfo->frags[ninfo->nr_frags].page_offset = 0;
++ ninfo->frags[ninfo->nr_frags].size = copy;
++ ninfo->nr_frags++;
+
-+ return IRQ_HANDLED;
-+}
-diff --git a/drivers/xen/pciback/slot.c b/drivers/xen/pciback/slot.c
-new file mode 100644
-index 0000000..105a8b6
---- /dev/null
-+++ b/drivers/xen/pciback/slot.c
-@@ -0,0 +1,187 @@
-+/*
-+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
-+ * to the frontend
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil> (vpci.c)
-+ * Author: Tristan Gingold <tristan.gingold(a)bull.net>, from vpci.c
-+ */
++ offset += copy;
++ len -= copy;
++ }
+
-+#include <linux/list.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
++ offset = nskb->data - skb->data;
+
-+/* There are at most 32 slots in a pci bus. */
-+#define PCI_SLOT_MAX 32
++ nskb->transport_header = skb->transport_header + offset;
++ nskb->network_header = skb->network_header + offset;
++ nskb->mac_header = skb->mac_header + offset;
+
-+#define PCI_BUS_NBR 2
++ return nskb;
+
-+struct slot_dev_data {
-+ /* Access to dev_list must be protected by lock */
-+ struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
-+ spinlock_t lock;
-+};
++ err_free:
++ kfree_skb(nskb);
++ err:
++ return NULL;
++}
+
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn)
-+{
-+ struct pci_dev *dev = NULL;
-+ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+ unsigned long flags;
-+
-+ if (domain != 0 || PCI_FUNC(devfn) != 0)
-+ return NULL;
-+
-+ if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
-+ return NULL;
-+
-+ spin_lock_irqsave(&slot_dev->lock, flags);
-+ dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
-+ spin_unlock_irqrestore(&slot_dev->lock, flags);
-+
-+ return dev;
-+}
-+
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
-+ int devid, publish_pci_dev_cb publish_cb)
-+{
-+ int err = 0, slot, bus;
-+ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+ unsigned long flags;
-+
-+ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
-+ err = -EFAULT;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Can't export bridges on the virtual PCI bus");
-+ goto out;
+ static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
+ {
+ if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
+@@ -218,6 +294,21 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
+ goto drop;
+
++ /*
++ * XXX For now we also copy skbuffs whose head crosses a page
++ * boundary, because netbk_gop_skb can't handle them.
++ */
++ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
++ struct sk_buff *nskb = netbk_copy_skb(skb);
++ if ( unlikely(nskb == NULL) )
++ goto drop;
++ /* Copy only the header fields we use in this driver. */
++ nskb->dev = skb->dev;
++ nskb->ip_summed = skb->ip_summed;
++ dev_kfree_skb(skb);
++ skb = nskb;
+ }
+
-+ spin_lock_irqsave(&slot_dev->lock, flags);
-+
-+ /* Assign to a new slot on the virtual PCI bus */
-+ for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ if (slot_dev->slots[bus][slot] == NULL) {
-+ printk(KERN_INFO
-+ "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
-+ pci_name(dev), slot, bus);
-+ slot_dev->slots[bus][slot] = dev;
-+ goto unlock;
-+ }
-+ }
-+
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "No more space on root virtual PCI bus");
-+
-+ unlock:
-+ spin_unlock_irqrestore(&slot_dev->lock, flags);
-+
-+ /* Publish this device. */
-+ if(!err)
-+ err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid);
-+
-+ out:
-+ return err;
-+}
-+
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+ int slot, bus;
-+ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+ struct pci_dev *found_dev = NULL;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&slot_dev->lock, flags);
-+
-+ for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ if (slot_dev->slots[bus][slot] == dev) {
-+ slot_dev->slots[bus][slot] = NULL;
-+ found_dev = dev;
-+ goto out;
-+ }
-+ }
+ netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
+ !!skb_shinfo(skb)->gso_size;
+ netif_get(netif);
+--
+1.7.4
+
+
+From 2e290d790877df4368691180f76206ad27a42505 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Wed, 9 Sep 2009 15:19:15 -0700
+Subject: [PATCH 022/203] xen: netback: remove debug noise
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 2 --
+ 1 files changed, 0 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 7c0f05b..d7d738e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1537,8 +1537,6 @@ static int __init netback_init(void)
+ int i;
+ struct page *page;
+
+- printk(KERN_CRIT "*** netif_init\n");
+-
+ if (!xen_domain())
+ return -ENODEV;
+
+--
+1.7.4
+
+
+From 3ba3bb7d563704c3050de6116aa0a761a5791428 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 8 Oct 2009 13:23:09 -0400
+Subject: [PATCH 023/203] Fix compile warnings: ignoring return value of
'xenbus_register_backend' ..
+
+We neglect to check the return value of xenbus_register_backend
+and take actions when that fails. This patch fixes that and adds
+code to deal with those type of failures.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 2 +-
+ drivers/xen/netback/netback.c | 12 +++++++++++-
+ drivers/xen/netback/xenbus.c | 4 ++--
+ 3 files changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 9056be0..0675946 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -194,7 +194,7 @@ static inline void netif_put(struct xen_netif *netif)
+ wake_up(&netif->waiting_to_free);
+ }
+
+-void netif_xenbus_init(void);
++int netif_xenbus_init(void);
+
+ #define netif_schedulable(netif) \
+ (netif_running((netif)->dev) && netback_carrier_ok(netif))
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index d7d738e..860c61e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1536,6 +1536,7 @@ static int __init netback_init(void)
+ {
+ int i;
+ struct page *page;
++ int rc = 0;
+
+ if (!xen_domain())
+ return -ENODEV;
+@@ -1583,7 +1584,9 @@ static int __init netback_init(void)
+
+ //netif_accel_init();
+
+- netif_xenbus_init();
++ rc = netif_xenbus_init();
++ if (rc)
++ goto failed_init;
+
+ #ifdef NETBE_DEBUG_INTERRUPT
+ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
+@@ -1595,6 +1598,13 @@ static int __init netback_init(void)
+ #endif
+
+ return 0;
+
-+ out:
-+ spin_unlock_irqrestore(&slot_dev->lock, flags);
++failed_init:
++ free_empty_pages_and_pagevec(mmap_pages, MAX_PENDING_REQS);
++ del_timer(&netbk_tx_pending_timer);
++ del_timer(&net_timer);
++ return rc;
+
-+ if (found_dev)
-+ pcistub_put_pci_dev(found_dev);
-+}
+ }
+
+ module_init(netback_init);
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index a492288..c46b235 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -447,8 +447,8 @@ static struct xenbus_driver netback = {
+ };
+
+
+-void netif_xenbus_init(void)
++int netif_xenbus_init(void)
+ {
+ printk(KERN_CRIT "registering netback\n");
+- (void)xenbus_register_backend(&netback);
++ return xenbus_register_backend(&netback);
+ }
+--
+1.7.4
+
+
+From 4bc919e07d5dc48cb95b22cc6e90c6110c229343 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Tue, 27 Oct 2009 12:37:50 -0700
+Subject: [PATCH 024/203] xen: netback: don't screw around with packet gso state
+
+These lines were reverted from 2.6.18 netback as the network stack
+was modified to deal with packets shorter than the gso size, so there's
+no need to fiddle with the gso state in netback.
+
+Taken from linux-2.6.18-xen.hg change 8081d19dce89
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 5 -----
+ 1 files changed, 0 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 860c61e..9a14976 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1293,11 +1293,6 @@ static unsigned net_tx_build_mops(void)
+ skb_shinfo(skb)->frags[0].page = (void *)~0UL;
+ }
+
+- if (skb->data_len < skb_shinfo(skb)->gso_size) {
+- skb_shinfo(skb)->gso_size = 0;
+- skb_shinfo(skb)->gso_type = 0;
+- }
+-
+ __skb_queue_tail(&tx_queue, skb);
+
+ pending_cons++;
+--
+1.7.4
+
+
+From f2b947783c47a721497e5d325c736234f71501e7 Mon Sep 17 00:00:00 2001
+From: Steven Smith <ssmith(a)weybridge.uk.xensource.com>
+Date: Fri, 30 Oct 2009 13:55:23 -0700
+Subject: [PATCH 025/203] xen: netback: make sure that pg->mapping is never NULL for a
page mapped from a foreign domain.
+
+Otherwise, the foreign maps tracking infrastructure gets confused, and
+thinks that the foreign page is local. This means that you can't
+forward that packet to another foreign domain. This leads to very
+high packet drop, and hence very poor performance.
+
+Signed-off-by: Steven Smith <steven.smith(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 9a14976..111fec7 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -97,12 +97,12 @@ static inline unsigned long idx_to_kaddr(unsigned int idx)
+ /* extra field used in struct page */
+ static inline void netif_set_page_index(struct page *pg, unsigned int index)
+ {
+- *(unsigned long *)&pg->mapping = index;
++ *(unsigned long *)&pg->mapping = index + 1;
+ }
+
+ static inline int netif_page_index(struct page *pg)
+ {
+- unsigned long idx = (unsigned long)pg->mapping;
++ unsigned long idx = (unsigned long)pg->mapping - 1;
+
+ if (!PageForeign(pg))
+ return -1;
+--
+1.7.4
+
+
+From df8b27ea0fb2695842104e06caaecb55780577a7 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ijc(a)hellion.org.uk>
+Date: Thu, 3 Dec 2009 21:56:19 +0000
+Subject: [PATCH 026/203] xen: rename netbk module xen-netback.
+
+netbk is rather generic for a modular distro style kernel.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/Makefile | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
+index a01a1a3..e346e81 100644
+--- a/drivers/xen/netback/Makefile
++++ b/drivers/xen/netback/Makefile
+@@ -1,3 +1,3 @@
+-obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
++obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
+
+-netbk-y := netback.o xenbus.o interface.o
++xen-netback-y := netback.o xenbus.o interface.o
+--
+1.7.4
+
+
+From 279097395ad64ae4df15e206a487cd5fd3be39a8 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Tue, 16 Feb 2010 14:40:37 -0800
+Subject: [PATCH 027/203] xen: netback: use dev_get/set_drvdata() inteface
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/xenbus.c | 10 +++++-----
+ 1 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index c46b235..79e6fb0 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -35,7 +35,7 @@ static void backend_create_netif(struct backend_info *be);
+
+ static int netback_remove(struct xenbus_device *dev)
+ {
+- struct backend_info *be = dev->dev.driver_data;
++ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ //netback_remove_accelerators(be, dev);
+
+@@ -45,7 +45,7 @@ static int netback_remove(struct xenbus_device *dev)
+ be->netif = NULL;
+ }
+ kfree(be);
+- dev->dev.driver_data = NULL;
++ dev_set_drvdata(&dev->dev, NULL);
+ return 0;
+ }
+
+@@ -70,7 +70,7 @@ static int netback_probe(struct xenbus_device *dev,
+ }
+
+ be->dev = dev;
+- dev->dev.driver_data = be;
++ dev_set_drvdata(&dev->dev, be);
+
+ sg = 1;
+ if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
+@@ -151,7 +151,7 @@ fail:
+ */
+ static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
+ {
+- struct backend_info *be = xdev->dev.driver_data;
++ struct backend_info *be = dev_get_drvdata(&xdev->dev);
+ struct xen_netif *netif = be->netif;
+ char *val;
+
+@@ -211,7 +211,7 @@ static void backend_create_netif(struct backend_info *be)
+ static void frontend_changed(struct xenbus_device *dev,
+ enum xenbus_state frontend_state)
+ {
+- struct backend_info *be = dev->dev.driver_data;
++ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ DPRINTK("%s", xenbus_strstate(frontend_state));
+
+--
+1.7.4
+
+
+From 31d0b5f5763faf607e32f3b5a0f6b37a34bbbf09 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Tue, 16 Feb 2010 14:41:12 -0800
+Subject: [PATCH 028/203] xen: netback: include linux/sched.h for TASK_* definitions
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 0675946..d8653d3 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -38,6 +38,8 @@
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/wait.h>
++#include <linux/sched.h>
+
-+int pciback_init_devices(struct pciback_device *pdev)
+ #include <xen/interface/io/netif.h>
+ #include <asm/io.h>
+ #include <asm/pgalloc.h>
+--
+1.7.4
+
+
+From cdefc88924b3cdfcac64be737a00a4ec5593cfd5 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 23 Feb 2010 11:52:27 +0000
+Subject: [PATCH 029/203] xen: netback: remove unused xen_network_done code
+
+It has been disabled effectively forever.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 23 -----------------------
+ 1 files changed, 0 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 111fec7..4b24893 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -343,25 +343,6 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ return 0;
+ }
+
+-#if 0
+-static void xen_network_done_notify(void)
+-{
+- static struct net_device *eth0_dev = NULL;
+- if (unlikely(eth0_dev == NULL))
+- eth0_dev = __dev_get_by_name("eth0");
+- netif_rx_schedule(eth0_dev);
+-}
+-/*
+- * Add following to poll() function in NAPI driver (Tigon3 is example):
+- * if ( xen_network_done() )
+- * tg3_enable_ints(tp);
+- */
+-int xen_network_done(void)
+-{
+- return skb_queue_empty(&rx_queue);
+-}
+-#endif
+-
+ struct netrx_pending_operations {
+ unsigned trans_prod, trans_cons;
+ unsigned mmu_prod, mmu_mcl;
+@@ -664,10 +645,6 @@ static void net_rx_action(unsigned long unused)
+ /* More work to do? */
+ if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
+ tasklet_schedule(&net_rx_tasklet);
+-#if 0
+- else
+- xen_network_done_notify();
+-#endif
+ }
+
+ static void net_alarm(unsigned long unused)
+--
+1.7.4
+
+
+From 994be068dd9947cedcee69a7185e54738cda33d4 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 23 Feb 2010 11:58:26 +0000
+Subject: [PATCH 030/203] xen: netback: factor disconnect from backend into new function.
+
+Makes subsequent patches cleaner.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/xenbus.c | 16 ++++++++++++----
+ 1 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index 79e6fb0..1f36b4d4 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -205,6 +205,16 @@ static void backend_create_netif(struct backend_info *be)
+ }
+
+
++static void disconnect_backend(struct xenbus_device *dev)
+{
-+ int slot, bus;
-+ struct slot_dev_data *slot_dev;
-+
-+ slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
-+ if (!slot_dev)
-+ return -ENOMEM;
-+
-+ spin_lock_init(&slot_dev->lock);
-+
-+ for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++)
-+ slot_dev->slots[bus][slot] = NULL;
-+
-+ pdev->pci_dev_data = slot_dev;
-+
-+ return 0;
-+}
++ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+ publish_pci_root_cb publish_cb)
-+{
-+ /* The Virtual PCI bus has only one root */
-+ return publish_cb(pdev, 0, 0);
++ if (be->netif) {
++ netif_disconnect(be->netif);
++ be->netif = NULL;
++ }
+}
+
-+void pciback_release_devices(struct pciback_device *pdev)
-+{
-+ int slot, bus;
-+ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+ struct pci_dev *dev;
-+
-+ for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ dev = slot_dev->slots[bus][slot];
-+ if (dev != NULL)
-+ pcistub_put_pci_dev(dev);
-+ }
-+
-+ kfree(slot_dev);
-+ pdev->pci_dev_data = NULL;
+ /**
+ * Callback received when the frontend's state changes.
+ */
+@@ -238,11 +248,9 @@ static void frontend_changed(struct xenbus_device *dev,
+ break;
+
+ case XenbusStateClosing:
+- if (be->netif) {
++ if (be->netif)
+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+- netif_disconnect(be->netif);
+- be->netif = NULL;
+- }
++ disconnect_backend(dev);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+
+--
+1.7.4
+
+
+From 9dcb4c18e5b29d8862cd7783d5b0040913010563 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 23 Feb 2010 12:10:24 +0000
+Subject: [PATCH 031/203] xen: netback: wait for hotplug scripts to complete before
signalling connected to frontend
+
+Avoid the situation where the frontend is sending packets but the
+domain 0 bridging (or whatever) is not yet configured (because the
+hotplug scripts are too slow) and so packets get dropped.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Steven.Smith(a)citrix.com
+---
+ drivers/xen/netback/common.h | 2 +
+ drivers/xen/netback/xenbus.c | 45 +++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 46 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index d8653d3..1983768 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -145,6 +145,8 @@ struct backend_info {
+ struct xenbus_device *dev;
+ struct xen_netif *netif;
+ enum xenbus_state frontend_state;
++ struct xenbus_watch hotplug_status_watch;
++ int have_hotplug_status_watch:1;
+
+ /* State relating to the netback accelerator */
+ void *netback_accel_priv;
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index 1f36b4d4..d2407cc 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -32,6 +32,7 @@
+ static int connect_rings(struct backend_info *);
+ static void connect(struct backend_info *);
+ static void backend_create_netif(struct backend_info *be);
++static void unregister_hotplug_status_watch(struct backend_info *be);
+
+ static int netback_remove(struct xenbus_device *dev)
+ {
+@@ -39,8 +40,10 @@ static int netback_remove(struct xenbus_device *dev)
+
+ //netback_remove_accelerators(be, dev);
+
++ unregister_hotplug_status_watch(be);
+ if (be->netif) {
+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
+ netif_disconnect(be->netif);
+ be->netif = NULL;
+ }
+@@ -210,6 +213,7 @@ static void disconnect_backend(struct xenbus_device *dev)
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ if (be->netif) {
++ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
+ netif_disconnect(be->netif);
+ be->netif = NULL;
+ }
+@@ -329,6 +333,36 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+ return 0;
+ }
+
++static void unregister_hotplug_status_watch(struct backend_info *be)
++{
++ if (be->have_hotplug_status_watch) {
++ unregister_xenbus_watch(&be->hotplug_status_watch);
++ kfree(be->hotplug_status_watch.node);
++ }
++ be->have_hotplug_status_watch = 0;
+}
+
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++static void hotplug_status_changed(struct xenbus_watch *watch,
++ const char **vec,
++ unsigned int vec_size)
+{
-+ int slot, busnr;
-+ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+ struct pci_dev *dev;
-+ int found = 0;
-+ unsigned long flags;
++ struct backend_info *be = container_of(watch,
++ struct backend_info,
++ hotplug_status_watch);
++ char *str;
++ unsigned int len;
+
-+ spin_lock_irqsave(&slot_dev->lock, flags);
++ str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status",
&len);
++ if (IS_ERR(str))
++ return;
++ if (len == sizeof("connected")-1 && !memcmp(str,
"connected", len)) {
++ xenbus_switch_state(be->dev, XenbusStateConnected);
++ /* Not interested in this watch anymore. */
++ unregister_hotplug_status_watch(be);
++ }
++ kfree(str);
++}
+
-+ for (busnr = 0; busnr < PCI_BUS_NBR; bus++)
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ dev = slot_dev->slots[busnr][slot];
-+ if (dev && dev->bus->number == pcidev->bus->number
-+ && dev->devfn == pcidev->devfn
-+ && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)) {
-+ found = 1;
-+ *domain = 0;
-+ *bus = busnr;
-+ *devfn = PCI_DEVFN(slot,0);
-+ goto out;
-+ }
+ static void connect(struct backend_info *be)
+ {
+ int err;
+@@ -348,7 +382,16 @@ static void connect(struct backend_info *be)
+ &be->netif->credit_usec);
+ be->netif->remaining_credit = be->netif->credit_bytes;
+
+- xenbus_switch_state(dev, XenbusStateConnected);
++ unregister_hotplug_status_watch(be);
++ err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
++ hotplug_status_changed,
++ "%s/%s", dev->nodename, "hotplug-status");
++ if (err) {
++ /* Switch now, since we can't do a watch. */
++ xenbus_switch_state(dev, XenbusStateConnected);
++ } else {
++ be->have_hotplug_status_watch = 1;
++ }
+
+ netif_wake_queue(be->netif->dev);
+ }
+--
+1.7.4
+
+
+From 509cc7f20f866277a8f5d5895bb266b5b68aac6d Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 23 Feb 2010 12:11:51 +0000
+Subject: [PATCH 032/203] xen: netback: Always pull through PKT_PROT_LEN bytes into the
linear part of an skb.
+
+Previously PKT_PROT_LEN would only have an effect on the first fragment.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 10 ++++++++++
+ 1 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 4b24893..d4a7a56 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1334,6 +1334,16 @@ static void net_tx_submit(void)
+
+ netbk_fill_frags(skb);
+
++ /*
++ * If the initial fragment was < PKT_PROT_LEN then
++ * pull through some bytes from the other fragments to
++ * increase the linear region to PKT_PROT_LEN bytes.
++ */
++ if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
++ int target = min_t(int, skb->len, PKT_PROT_LEN);
++ __pskb_pull_tail(skb, target - skb_headlen(skb));
+ }
-+out:
-+ spin_unlock_irqrestore(&slot_dev->lock, flags);
-+ return found;
+
-+}
-diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
-new file mode 100644
-index 0000000..a5b7ece
---- /dev/null
-+++ b/drivers/xen/pciback/vpci.c
-@@ -0,0 +1,242 @@
-+/*
-+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
-+ * to the frontend
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
+ skb->dev = netif->dev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+--
+1.7.4
+
+
+From 673c82b5110cfffafe1e1978bc07d6d10d111d50 Mon Sep 17 00:00:00 2001
+From: Steven Smith <ssmith(a)xensource.com>
+Date: Tue, 23 Feb 2010 11:49:26 +0000
+Subject: [PATCH 033/203] xen: netback: try to pull a minimum of 72 bytes into the skb
data area
+ when receiving a packet into netback.
+
+The previous number, 64, tended to place a fragment boundary in the middle of
+the TCP header options and led to unnecessary fragmentation in Windows <->
+Windows networking.
+
+Signed-off-by: Steven Smith <ssmith(a)xensource.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 9 +++------
+ 1 files changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index d4a7a56..44357d7 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -116,13 +116,10 @@ static inline int netif_page_index(struct page *pg)
+ /*
+ * This is the amount of packet we copy rather than map, so that the
+ * guest can't fiddle with the contents of the headers while we do
+- * packet processing on them (netfilter, routing, etc). This could
+- * probably do with being larger, since 1) 64-bytes isn't necessarily
+- * long enough to cover a full christmas-tree ip+tcp header, let alone
+- * packet contents, and 2) the data is probably in cache anyway
+- * (though perhaps some other cpu's cache).
++ * packet processing on them (netfilter, routing, etc). 72 is enough
++ * to cover TCP+IP headers including options.
+ */
+-#define PKT_PROT_LEN 64
++#define PKT_PROT_LEN 72
+
+ static struct pending_tx_info {
+ struct xen_netif_tx_request req;
+--
+1.7.4
+
+
+From c83bd213efd3ebf700189249c30d987b1cb14d7e Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 23 Feb 2010 11:54:30 +0000
+Subject: [PATCH 034/203] xen: netback: Allow setting of large MTU before rings have
connected.
+
+This allows large MTU to be configured by the VIF hotplug
+script. Previously this would fail because at the point the hotplug
+script runs the VIF features have most likely not been negotiated with
+the frontend and so SG has not yet been enabled. Invert this behaviour
+so that SG is assumed present until negotiations prove otherwise and
+reduce MTU at that point.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 6 +++++-
+ drivers/xen/netback/xenbus.c | 8 +++++---
+ 2 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 21c1f95..b23b14d 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -104,6 +104,9 @@ static int netbk_set_sg(struct net_device *dev, u32 data)
+ return -ENOSYS;
+ }
+
++ if (dev->mtu > ETH_DATA_LEN)
++ dev->mtu = ETH_DATA_LEN;
+
-+#include <linux/list.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
+ return ethtool_op_set_sg(dev, data);
+ }
+
+@@ -207,6 +210,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ memset(netif, 0, sizeof(*netif));
+ netif->domid = domid;
+ netif->handle = handle;
++ netif->features = NETIF_F_SG;
+ atomic_set(&netif->refcnt, 1);
+ init_waitqueue_head(&netif->waiting_to_free);
+ netif->dev = dev;
+@@ -223,7 +227,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ init_timer(&netif->tx_queue_timeout);
+
+ dev->netdev_ops = &netback_ops;
+- dev->features = NETIF_F_IP_CSUM;
++ dev->features = NETIF_F_IP_CSUM|NETIF_F_SG;
+
+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index d2407cc..fcd3c34 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -445,9 +445,11 @@ static int connect_rings(struct backend_info *be)
+
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d",
&val) < 0)
+ val = 0;
+- if (val) {
+- be->netif->features |= NETIF_F_SG;
+- be->netif->dev->features |= NETIF_F_SG;
++ if (!val) {
++ be->netif->features &= ~NETIF_F_SG;
++ be->netif->dev->features &= ~NETIF_F_SG;
++ if (be->netif->dev->mtu > ETH_DATA_LEN)
++ be->netif->dev->mtu = ETH_DATA_LEN;
+ }
+
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
"%d",
+--
+1.7.4
+
+
+From e5cd35b00cb63f3a3fa1651260a58d59bbc134b7 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Fri, 19 Mar 2010 13:09:16 -0700
+Subject: [PATCH 035/203] xen: netback: use get_sset_count rather than obsolete
get_stats_count
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/interface.c | 11 ++++++++---
+ 1 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index b23b14d..086d939 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -136,9 +136,14 @@ static const struct netif_stat {
+ { "copied_skbs", offsetof(struct xen_netif, nr_copied_skbs) },
+ };
+
+-static int netbk_get_stats_count(struct net_device *dev)
++static int netbk_get_sset_count(struct net_device *dev, int string_set)
+ {
+- return ARRAY_SIZE(netbk_stats);
++ switch (string_set) {
++ case ETH_SS_STATS:
++ return ARRAY_SIZE(netbk_stats);
++ default:
++ return -EINVAL;
++ }
+ }
+
+ static void netbk_get_ethtool_stats(struct net_device *dev,
+@@ -176,7 +181,7 @@ static struct ethtool_ops network_ethtool_ops =
+ .set_tso = netbk_set_tso,
+ .get_link = ethtool_op_get_link,
+
+- .get_stats_count = netbk_get_stats_count,
++ .get_sset_count = netbk_get_sset_count,
+ .get_ethtool_stats = netbk_get_ethtool_stats,
+ .get_strings = netbk_get_strings,
+ };
+--
+1.7.4
+
+
+From 0c34835ee66ad641f01a8077a973b7ec1bfdcd86 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 11 May 2010 09:33:42 +0100
+Subject: [PATCH 036/203] xen: netback: correctly setup skb->ip_summed on receive
+
+In 2.6.18 CHECKSUM_PARTIAL and CHECKSUM_UNNECESSARY were both synonyms for
+CHECKSUM_HW. This is no longer the case and we need to select the correct one.
+
+ data_validated csum_blank -> ip_summed
+ 0 0 CHECKSUM_NONE
+ 0 1 CHECKSUM_PARTIAL
+ 1 0 CHECKSUM_UNNECESSARY
+ 1 1 CHECKSUM_PARTIAL
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Tested-by: Matej Zary <zary(a)cvtisr.sk>
+Tested-by: Michael D Labriola <mlabriol(a)gdeb.com>
+---
+ drivers/xen/netback/netback.c | 10 +++-------
+ 1 files changed, 3 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 44357d7..725da0f 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1320,14 +1320,10 @@ static void net_tx_submit(void)
+ netif_idx_release(pending_idx);
+ }
+
+- /*
+- * Old frontends do not assert data_validated but we
+- * can infer it from csum_blank so test both flags.
+- */
+- if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank))
++ if (txp->flags & NETTXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+- else
+- skb->ip_summed = CHECKSUM_NONE;
++ else if (txp->flags & NETTXF_data_validated)
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netbk_fill_frags(skb);
+
+--
+1.7.4
+
+
+From 094944631cc5a9d6e623302c987f78117c0bf7ac Mon Sep 17 00:00:00 2001
+From: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Date: Wed, 19 May 2010 16:58:56 -0700
+Subject: [PATCH 037/203] xen: netback: Move global/static variables into struct
xen_netbk.
+
+Bundle a lot of discrete variables into a single structure.
+
+Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 59 +++++++
+ drivers/xen/netback/netback.c | 360 ++++++++++++++++++++---------------------
+ 2 files changed, 232 insertions(+), 187 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 1983768..00208f4 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -222,4 +222,63 @@ static inline int netbk_can_sg(struct net_device *dev)
+ return netif->features & NETIF_F_SG;
+ }
+
++struct pending_tx_info {
++ struct xen_netif_tx_request req;
++ struct xen_netif *netif;
++};
++typedef unsigned int pending_ring_idx_t;
+
-+#define PCI_SLOT_MAX 32
++struct netbk_rx_meta {
++ skb_frag_t frag;
++ int id;
++};
+
-+struct vpci_dev_data {
-+ /* Access to dev_list must be protected by lock */
-+ struct list_head dev_list[PCI_SLOT_MAX];
-+ spinlock_t lock;
++struct netbk_tx_pending_inuse {
++ struct list_head list;
++ unsigned long alloc_time;
+};
+
-+static inline struct list_head *list_first(struct list_head *head)
-+{
-+ return head->next;
-+}
++#define MAX_PENDING_REQS 256
+
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn)
-+{
-+ struct pci_dev_entry *entry;
-+ struct pci_dev *dev = NULL;
-+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+ unsigned long flags;
++struct xen_netbk {
++ struct tasklet_struct net_tx_tasklet;
++ struct tasklet_struct net_rx_tasklet;
+
-+ if (domain != 0 || bus != 0)
-+ return NULL;
++ struct sk_buff_head rx_queue;
++ struct sk_buff_head tx_queue;
+
-+ if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
-+ spin_lock_irqsave(&vpci_dev->lock, flags);
++ struct timer_list net_timer;
++ struct timer_list netbk_tx_pending_timer;
+
-+ list_for_each_entry(entry,
-+ &vpci_dev->dev_list[PCI_SLOT(devfn)],
-+ list) {
-+ if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
-+ dev = entry->dev;
-+ break;
-+ }
-+ }
++ struct page **mmap_pages;
+
-+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
-+ }
-+ return dev;
-+}
++ pending_ring_idx_t pending_prod;
++ pending_ring_idx_t pending_cons;
++ pending_ring_idx_t dealloc_prod;
++ pending_ring_idx_t dealloc_cons;
+
-+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
-+{
-+ if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
-+ && l->bus == r->bus && PCI_SLOT(l->devfn) ==
PCI_SLOT(r->devfn))
-+ return 1;
++ struct list_head pending_inuse_head;
++ struct list_head net_schedule_list;
+
-+ return 0;
-+}
++ /* Protect the net_schedule_list in netif. */
++ spinlock_t net_schedule_list_lock;
+
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
-+ int devid, publish_pci_dev_cb publish_cb)
-+{
-+ int err = 0, slot, func;
-+ struct pci_dev_entry *t, *dev_entry;
-+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+ unsigned long flags;
-+
-+ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
-+ err = -EFAULT;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Can't export bridges on the virtual PCI bus");
-+ goto out;
-+ }
-+
-+ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
-+ if (!dev_entry) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error adding entry to virtual PCI bus");
-+ goto out;
-+ }
++ 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];
+
-+ dev_entry->dev = dev;
++ grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
++ u16 pending_ring[MAX_PENDING_REQS];
++ u16 dealloc_ring[MAX_PENDING_REQS];
+
-+ spin_lock_irqsave(&vpci_dev->lock, flags);
++ 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];
++ unsigned char rx_notify[NR_IRQS];
++ u16 notify_list[NET_RX_RING_SIZE];
++ struct netbk_rx_meta meta[NET_RX_RING_SIZE];
++};
+
-+ /* Keep multi-function devices together on the virtual PCI bus */
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ if (!list_empty(&vpci_dev->dev_list[slot])) {
-+ t = list_entry(list_first(&vpci_dev->dev_list[slot]),
-+ struct pci_dev_entry, list);
+ #endif /* __NETIF__BACKEND__COMMON_H__ */
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 725da0f..417f497 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -48,16 +48,7 @@
+
+ /*define NETBE_DEBUG_INTERRUPT*/
+
+-struct netbk_rx_meta {
+- skb_frag_t frag;
+- int id;
+-};
+-
+-struct netbk_tx_pending_inuse {
+- struct list_head list;
+- unsigned long alloc_time;
+-};
+-
++static struct xen_netbk *netbk;
+
+ static void netif_idx_release(u16 pending_idx);
+ static void make_tx_response(struct xen_netif *netif,
+@@ -71,22 +62,12 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
+ 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;
+
+-#define MAX_PENDING_REQS 256
+-
+-static struct sk_buff_head rx_queue;
+-
+-static struct page **mmap_pages;
+ static inline unsigned long idx_to_pfn(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)
+@@ -107,7 +88,7 @@ static inline int netif_page_index(struct page *pg)
+ if (!PageForeign(pg))
+ return -1;
+
+- if ((idx >= MAX_PENDING_REQS) || (mmap_pages[idx] != pg))
++ if ((idx >= MAX_PENDING_REQS) || (netbk->mmap_pages[idx] != pg))
+ return -1;
+
+ return idx;
+@@ -121,46 +102,17 @@ static inline int netif_page_index(struct page *pg)
+ */
+ #define PKT_PROT_LEN 72
+
+-static struct pending_tx_info {
+- struct xen_netif_tx_request req;
+- struct xen_netif *netif;
+-} pending_tx_info[MAX_PENDING_REQS];
+-static u16 pending_ring[MAX_PENDING_REQS];
+-typedef unsigned int pending_ring_idx_t;
+-
+ static inline pending_ring_idx_t pending_index(unsigned i)
+ {
+ return i & (MAX_PENDING_REQS-1);
+ }
+
+-static pending_ring_idx_t pending_prod, pending_cons;
+-
+ static inline pending_ring_idx_t nr_pending_reqs(void)
+ {
+- return MAX_PENDING_REQS - pending_prod + pending_cons;
++ return MAX_PENDING_REQS -
++ netbk->pending_prod + netbk->pending_cons;
+ }
+
+-/* Freed TX SKBs get batched on this ring before return to pending_ring. */
+-static u16 dealloc_ring[MAX_PENDING_REQS];
+-static pending_ring_idx_t 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 struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+-static struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+-
+-static LIST_HEAD(net_schedule_list);
+-static DEFINE_SPINLOCK(net_schedule_list_lock);
+-
+-#define MAX_MFN_ALLOC 64
+-static unsigned long mfn_list[MAX_MFN_ALLOC];
+-static unsigned int alloc_index = 0;
+-
+ /* Setting this allows the safe use of this driver without netloop. */
+ static int MODPARM_copy_skb = 1;
+ module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
+@@ -168,18 +120,12 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
+
+ int netbk_copy_skb_mode;
+
+-static inline unsigned long alloc_mfn(void)
+-{
+- BUG_ON(alloc_index == 0);
+- return mfn_list[--alloc_index];
+-}
+-
+ static inline void maybe_schedule_tx_action(void)
+ {
+ smp_mb();
+ if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
+- !list_empty(&net_schedule_list))
+- tasklet_schedule(&net_tx_tasklet);
++ !list_empty(&netbk->net_schedule_list))
++ tasklet_schedule(&netbk->net_tx_tasklet);
+ }
+
+ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+@@ -328,9 +274,8 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
+ }
+ }
+-
+- skb_queue_tail(&rx_queue, skb);
+- tasklet_schedule(&net_rx_tasklet);
++ skb_queue_tail(&netbk->rx_queue, skb);
++ tasklet_schedule(&netbk->net_rx_tasklet);
+
+ return 0;
+
+@@ -372,7 +317,7 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
+ 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];
++ struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
+ copy_gop->source.domid = src_pend->netif->domid;
+ copy_gop->source.u.ref = src_pend->req.gref;
+ copy_gop->flags |= GNTCOPY_source_gref;
+@@ -487,30 +432,19 @@ static void net_rx_action(unsigned long unused)
+ 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 struct multicall_entry rx_mcl[NET_RX_RING_SIZE+3];
+- static struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+- static struct gnttab_transfer grant_trans_op[NET_RX_RING_SIZE];
+- static struct gnttab_copy grant_copy_op[NET_RX_RING_SIZE];
+- static unsigned char rx_notify[NR_IRQS];
+- static u16 notify_list[NET_RX_RING_SIZE];
+- static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+-
+ 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;
+
+@@ -525,39 +459,39 @@ static void net_rx_action(unsigned long unused)
+ 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;
+ }
+
+@@ -565,7 +499,7 @@ static void net_rx_action(unsigned long unused)
+ 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);
+@@ -582,7 +516,7 @@ static void net_rx_action(unsigned long unused)
+
+ status = netbk_check_gop(nr_frags, netif->domid, &npo);
+
+- id = meta[npo.meta_cons].id;
++ id = netbk->meta[npo.meta_cons].id;
+ flags = nr_frags ? NETRXF_more_data : 0;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+@@ -595,7 +529,7 @@ static void net_rx_action(unsigned long unused)
+ 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 xen_netif_extra_info *gso =
+ (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&netif->rx,
+@@ -603,7 +537,7 @@ static void net_rx_action(unsigned long unused)
+
+ 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;
+@@ -613,14 +547,14 @@ static void net_rx_action(unsigned long unused)
+ }
+
+ netbk_add_frag_responses(netif, status,
+- meta + npo.meta_cons + 1,
+- nr_frags);
++ netbk->meta + npo.meta_cons + 1,
++ nr_frags);
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
+ irq = netif->irq;
+- if (ret && !rx_notify[irq]) {
+- rx_notify[irq] = 1;
+- notify_list[notify_nr++] = irq;
++ if (ret && !netbk->rx_notify[irq]) {
++ netbk->rx_notify[irq] = 1;
++ netbk->notify_list[notify_nr++] = irq;
+ }
+
+ if (netif_queue_stopped(netif->dev) &&
+@@ -634,24 +568,25 @@ static void net_rx_action(unsigned long unused)
+ }
+
+ while (notify_nr != 0) {
+- irq = notify_list[--notify_nr];
+- rx_notify[irq] = 0;
++ irq = netbk->notify_list[--notify_nr];
++ netbk->rx_notify[irq] = 0;
+ notify_remote_via_irq(irq);
+ }
+
+ /* 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);
+ }
+
+ static void net_alarm(unsigned long unused)
+ {
+- tasklet_schedule(&net_rx_tasklet);
++ tasklet_schedule(&netbk->net_rx_tasklet);
+ }
+
+ static void netbk_tx_pending_timeout(unsigned long unused)
+ {
+- tasklet_schedule(&net_tx_tasklet);
++ tasklet_schedule(&netbk->net_tx_tasklet);
+ }
+
+ struct net_device_stats *netif_be_get_stats(struct net_device *dev)
+@@ -667,12 +602,12 @@ static int __on_net_schedule_list(struct xen_netif *netif)
+
+ static void remove_from_net_schedule_list(struct xen_netif *netif)
+ {
+- spin_lock_irq(&net_schedule_list_lock);
++ spin_lock_irq(&netbk->net_schedule_list_lock);
+ if (likely(__on_net_schedule_list(netif))) {
+ list_del_init(&netif->list);
+ netif_put(netif);
+ }
+- spin_unlock_irq(&net_schedule_list_lock);
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
+ }
+
+ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+@@ -680,13 +615,13 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+ if (__on_net_schedule_list(netif))
+ return;
+
+- spin_lock_irq(&net_schedule_list_lock);
++ spin_lock_irq(&netbk->net_schedule_list_lock);
+ if (!__on_net_schedule_list(netif) &&
+ likely(netif_schedulable(netif))) {
+- list_add_tail(&netif->list, &net_schedule_list);
++ list_add_tail(&netif->list, &netbk->net_schedule_list);
+ netif_get(netif);
+ }
+- spin_unlock_irq(&net_schedule_list_lock);
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
+ }
+
+ void netif_schedule_work(struct xen_netif *netif)
+@@ -736,8 +671,9 @@ static void tx_credit_callback(unsigned long data)
+
+ static inline int copy_pending_req(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]);
+ }
+
+ inline static void net_tx_action_dealloc(void)
+@@ -750,22 +686,24 @@ inline static void net_tx_action_dealloc(void)
+ int ret;
+ 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();
+
+ while (dc != dp) {
+ unsigned long pfn;
++ struct netbk_tx_pending_inuse *pending_inuse =
++ netbk->pending_inuse;
+
+- pending_idx = dealloc_ring[pending_index(dc++)];
++ pending_idx = netbk->dealloc_ring[pending_index(dc++)];
+ list_move_tail(&pending_inuse[pending_idx].list, &list);
+
+ pfn = idx_to_pfn(pending_idx);
+@@ -773,22 +711,27 @@ inline static void net_tx_action_dealloc(void)
+ if (!phys_to_machine_mapping_valid(pfn))
+ continue;
+
+- gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
+- GNTMAP_host_map,
+- grant_tx_handle[pending_idx]);
++ gnttab_set_unmap_op(gop,
++ idx_to_kaddr(pending_idx),
++ GNTMAP_host_map,
++ netbk->grant_tx_handle[pending_idx]);
+ gop++;
+ }
+
+ if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
+- list_empty(&pending_inuse_head))
++ list_empty(&netbk->pending_inuse_head))
+ break;
+
+ /* Copy any entries that have been pending for too long. */
+- list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
++ list_for_each_entry_safe(inuse, n,
++ &netbk->pending_inuse_head, list) {
++ struct pending_tx_info *pending_tx_info;
++ pending_tx_info = netbk->pending_tx_info;
+
-+ if (match_slot(dev, t->dev)) {
-+ pr_info("pciback: vpci: %s: "
-+ "assign to virtual slot %d func %d\n",
-+ pci_name(dev), slot,
-+ PCI_FUNC(dev->devfn));
-+ list_add_tail(&dev_entry->list,
-+ &vpci_dev->dev_list[slot]);
-+ func = PCI_FUNC(dev->devfn);
-+ goto unlock;
-+ }
-+ }
-+ }
+ 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++;
+
+@@ -805,16 +748,21 @@ inline static void net_tx_action_dealloc(void)
+
+ break;
+ }
+- } while (dp != dealloc_prod);
++ } while (dp != netbk->dealloc_prod);
+
+- dealloc_cons = dc;
++ netbk->dealloc_cons = dc;
+
+ ret = HYPERVISOR_grant_table_op(
+- GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
++ GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
++ gop - netbk->tx_unmap_ops);
+ BUG_ON(ret);
+
+ list_for_each_entry_safe(inuse, n, &list, list) {
+- pending_idx = inuse - pending_inuse;
++ struct pending_tx_info *pending_tx_info;
++ pending_ring_idx_t index;
+
-+ /* Assign to a new slot on the virtual PCI bus */
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ if (list_empty(&vpci_dev->dev_list[slot])) {
-+ printk(KERN_INFO
-+ "pciback: vpci: %s: assign to virtual slot %d\n",
-+ pci_name(dev), slot);
-+ list_add_tail(&dev_entry->list,
-+ &vpci_dev->dev_list[slot]);
-+ func = PCI_FUNC(dev->devfn);
-+ goto unlock;
-+ }
-+ }
-+
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "No more space on root virtual PCI bus");
-+
-+ unlock:
-+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
-+
-+ /* Publish this device. */
-+ if(!err)
-+ err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
-+
-+ out:
-+ return err;
-+}
-+
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+ int slot;
-+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+ struct pci_dev *found_dev = NULL;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&vpci_dev->lock, flags);
++ pending_tx_info = netbk->pending_tx_info;
++ pending_idx = inuse - netbk->pending_inuse;
+
+ netif = pending_tx_info[pending_idx].netif;
+
+@@ -822,9 +770,10 @@ inline static void net_tx_action_dealloc(void)
+ 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[pending_index(pending_prod++)] = pending_idx;
++ index = pending_index(netbk->pending_prod++);
++ netbk->pending_ring[index] = pending_idx;
+
+ netif_put(netif);
+
+@@ -832,7 +781,8 @@ inline static void net_tx_action_dealloc(void)
+ }
+ }
+
+-static void netbk_tx_err(struct xen_netif *netif, struct xen_netif_tx_request *txp,
RING_IDX end)
++static void netbk_tx_err(struct xen_netif *netif,
++ struct xen_netif_tx_request *txp, RING_IDX end)
+ {
+ RING_IDX cons = netif->tx.req_cons;
+
+@@ -902,7 +852,12 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
+ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+
+ for (i = start; i < shinfo->nr_frags; i++, txp++) {
+- pending_idx = pending_ring[pending_index(pending_cons++)];
++ pending_ring_idx_t index;
++ struct pending_tx_info *pending_tx_info =
++ netbk->pending_tx_info;
+
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ struct pci_dev_entry *e, *tmp;
-+ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
-+ list) {
-+ if (e->dev == dev) {
-+ list_del(&e->list);
-+ found_dev = e->dev;
-+ kfree(e);
-+ goto out;
-+ }
-+ }
++ index = pending_index(netbk->pending_cons++);
++ pending_idx = netbk->pending_ring[index];
+
+ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+@@ -922,6 +877,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ {
+ struct gnttab_map_grant_ref *mop = *mopp;
+ int pending_idx = *((u16 *)skb->data);
++ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
+ struct xen_netif *netif = pending_tx_info[pending_idx].netif;
+ struct xen_netif_tx_request *txp;
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+@@ -931,15 +887,17 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ /* Check status of header. */
+ err = mop->status;
+ if (unlikely(err)) {
++ pending_ring_idx_t index;
++ index = pending_index(netbk->pending_prod++);
+ txp = &pending_tx_info[pending_idx].req;
+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
+- pending_ring[pending_index(pending_prod++)] = pending_idx;
++ netbk->pending_ring[index] = pending_idx;
+ netif_put(netif);
+ } else {
+ set_phys_to_machine(
+ __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
+ 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. */
+@@ -947,16 +905,19 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+
+ 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)) {
++ unsigned long addr;
++ addr = idx_to_kaddr(pending_idx);
+ set_phys_to_machine(
+- __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
++ __pa(addr)>>PAGE_SHIFT,
+ 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))
+ netif_idx_release(pending_idx);
+@@ -964,9 +925,10 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ }
+
+ /* Error on this fragment: respond to client with an error. */
+- txp = &pending_tx_info[pending_idx].req;
++ txp = &netbk->pending_tx_info[pending_idx].req;
+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
+- pending_ring[pending_index(pending_prod++)] = pending_idx;
++ index = pending_index(netbk->pending_prod++);
++ netbk->pending_ring[index] = pending_idx;
+ netif_put(netif);
+
+ /* Not the first error? Preceding frags already invalidated. */
+@@ -1002,11 +964,11 @@ static void netbk_fill_frags(struct sk_buff *skb)
+
+ 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;
++ txp = &netbk->pending_tx_info[pending_idx].req;
+ frag->page = virt_to_page(idx_to_kaddr(pending_idx));
+ frag->size = txp->size;
+ frag->page_offset = txp->offset;
+@@ -1145,9 +1107,9 @@ static unsigned net_tx_build_mops(void)
+ struct sk_buff *skb;
+ int ret;
+
+- mop = tx_map_ops;
++ mop = netbk->tx_map_ops;
+ while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+- !list_empty(&net_schedule_list)) {
++ !list_empty(&netbk->net_schedule_list)) {
+ struct xen_netif *netif;
+ struct xen_netif_tx_request txreq;
+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+@@ -1156,9 +1118,11 @@ static unsigned net_tx_build_mops(void)
+ RING_IDX idx;
+ int work_to_do;
+ unsigned int data_len;
++ pending_ring_idx_t index;
+
+ /* Get a netif from the list with work to do. */
+- netif = list_first_entry(&net_schedule_list, struct xen_netif, list);
++ netif = list_first_entry(&netbk->net_schedule_list,
++ struct xen_netif, list);
+ netif_get(netif);
+ remove_from_net_schedule_list(netif);
+
+@@ -1217,7 +1181,8 @@ static unsigned net_tx_build_mops(void)
+ continue;
+ }
+
+- pending_idx = pending_ring[pending_index(pending_cons)];
++ index = pending_index(netbk->pending_cons);
++ pending_idx = netbk->pending_ring[index];
+
+ data_len = (txreq.size > PKT_PROT_LEN &&
+ ret < MAX_SKB_FRAGS) ?
+@@ -1250,9 +1215,9 @@ static unsigned net_tx_build_mops(void)
+ 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);
+@@ -1267,20 +1232,20 @@ static unsigned net_tx_build_mops(void)
+ 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 = idx;
+ 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;
+ }
+
+- return mop - tx_map_ops;
++ return mop - netbk->tx_map_ops;
+ }
+
+ static void net_tx_submit(void)
+@@ -1288,16 +1253,16 @@ static void net_tx_submit(void)
+ struct gnttab_map_grant_ref *mop;
+ struct sk_buff *skb;
+
+- 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 xen_netif_tx_request *txp;
+ struct xen_netif *netif;
+ u16 pending_idx;
+ unsigned data_len;
+
+ pending_idx = *((u16 *)skb->data);
+- netif = pending_tx_info[pending_idx].netif;
+- txp = &pending_tx_info[pending_idx].req;
++ netif = netbk->pending_tx_info[pending_idx].netif;
++ txp = &netbk->pending_tx_info[pending_idx].req;
+
+ /* Check the remap error code. */
+ if (unlikely(netbk_tx_check_mop(skb, &mop))) {
+@@ -1363,12 +1328,13 @@ static void net_tx_submit(void)
+ }
+
+ 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->netbk_tx_pending_timer,
++ oldest->alloc_time + HZ);
+ }
+ }
+
+@@ -1378,7 +1344,7 @@ static void net_tx_action(unsigned long unused)
+ unsigned nr_mops;
+ int ret;
+
+- if (dealloc_cons != dealloc_prod)
++ if (netbk->dealloc_cons != netbk->dealloc_prod)
+ net_tx_action_dealloc();
+
+ nr_mops = net_tx_build_mops();
+@@ -1387,7 +1353,7 @@ static void net_tx_action(unsigned long unused)
+ return;
+
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+- tx_map_ops, nr_mops);
++ netbk->tx_map_ops, nr_mops);
+ BUG_ON(ret);
+
+ net_tx_submit();
+@@ -1397,15 +1363,17 @@ static void netif_idx_release(u16 pending_idx)
+ {
+ static DEFINE_SPINLOCK(_lock);
+ unsigned long flags;
++ pending_ring_idx_t index;
+
+ spin_lock_irqsave(&_lock, flags);
+- dealloc_ring[pending_index(dealloc_prod)] = pending_idx;
++ index = pending_index(netbk->dealloc_prod);
++ netbk->dealloc_ring[index] = pending_idx;
+ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
+ smp_wmb();
+- dealloc_prod++;
++ netbk->dealloc_prod++;
+ spin_unlock_irqrestore(&_lock, flags);
+
+- tasklet_schedule(&net_tx_tasklet);
++ tasklet_schedule(&netbk->net_tx_tasklet);
+ }
+
+ static void netif_page_release(struct page *page, unsigned int order)
+@@ -1481,9 +1449,9 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
+ int i = 0;
+
+ printk(KERN_ALERT "netif_schedule_list:\n");
+- spin_lock_irq(&net_schedule_list_lock);
++ spin_lock_irq(&netbk->net_schedule_list_lock);
+
+- list_for_each (ent, &net_schedule_list) {
++ list_for_each(ent, &netbk->net_schedule_list) {
+ netif = list_entry(ent, struct xen_netif, list);
+ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
+ "rx_resp_prod=%08x\n",
+@@ -1500,7 +1468,7 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
+ i++;
+ }
+
+- spin_unlock_irq(&net_schedule_list_lock);
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
+ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
+
+ return IRQ_HANDLED;
+@@ -1516,37 +1484,53 @@ static int __init netback_init(void)
+ if (!xen_domain())
+ return -ENODEV;
+
++ netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk));
++ if (!netbk) {
++ printk(KERN_ALERT "%s: out of memory\n", __func__);
++ return -ENOMEM;
+ }
+
-+ out:
-+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
-+
-+ if (found_dev)
-+ pcistub_put_pci_dev(found_dev);
-+}
-+
-+int pciback_init_devices(struct pciback_device *pdev)
-+{
-+ int slot;
-+ struct vpci_dev_data *vpci_dev;
+ /* We can increase reservation by this much in net_rx_action(). */
+ // balloon_update_driver_allowance(NET_RX_RING_SIZE);
+
+- skb_queue_head_init(&rx_queue);
+- skb_queue_head_init(&tx_queue);
++ skb_queue_head_init(&netbk->rx_queue);
++ skb_queue_head_init(&netbk->tx_queue);
+
+- init_timer(&net_timer);
+- net_timer.data = 0;
+- net_timer.function = net_alarm;
++ init_timer(&netbk->net_timer);
++ netbk->net_timer.data = 0;
++ netbk->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;
++ init_timer(&netbk->netbk_tx_pending_timer);
++ netbk->netbk_tx_pending_timer.data = 0;
++ netbk->netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
+
+- mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+- if (mmap_pages == NULL) {
+- printk("%s: out of memory\n", __FUNCTION__);
+- return -ENOMEM;
++ netbk->mmap_pages =
++ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
++ if (!netbk->mmap_pages) {
++ printk(KERN_ALERT "%s: out of memory\n", __func__);
++ rc = -ENOMEM;
++ goto failed_init2;
+ }
+
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
+- page = mmap_pages[i];
++ page = netbk->mmap_pages[i];
+ SetPageForeign(page, netif_page_release);
+ netif_set_page_index(page, i);
+- INIT_LIST_HEAD(&pending_inuse[i].list);
++ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
+
+- pending_cons = 0;
+- pending_prod = MAX_PENDING_REQS;
++ netbk->pending_cons = 0;
++ netbk->pending_prod = MAX_PENDING_REQS;
+ for (i = 0; i < MAX_PENDING_REQS; i++)
+- pending_ring[i] = i;
++ netbk->pending_ring[i] = i;
+
-+ vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
-+ if (!vpci_dev)
-+ return -ENOMEM;
++ tasklet_init(&netbk->net_tx_tasklet, net_tx_action, 0);
++ tasklet_init(&netbk->net_rx_tasklet, net_rx_action, 0);
+
-+ spin_lock_init(&vpci_dev->lock);
++ INIT_LIST_HEAD(&netbk->pending_inuse_head);
++ INIT_LIST_HEAD(&netbk->net_schedule_list);
+
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
-+ }
++ spin_lock_init(&netbk->net_schedule_list_lock);
+
+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+ if (MODPARM_copy_skb) {
+@@ -1561,7 +1545,7 @@ static int __init netback_init(void)
+
+ rc = netif_xenbus_init();
+ if (rc)
+- goto failed_init;
++ goto failed_init1;
+
+ #ifdef NETBE_DEBUG_INTERRUPT
+ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
+@@ -1574,10 +1558,12 @@ static int __init netback_init(void)
+
+ return 0;
+
+-failed_init:
+- free_empty_pages_and_pagevec(mmap_pages, MAX_PENDING_REQS);
+- del_timer(&netbk_tx_pending_timer);
+- del_timer(&net_timer);
++failed_init1:
++ free_empty_pages_and_pagevec(netbk->mmap_pages, MAX_PENDING_REQS);
++failed_init2:
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ vfree(netbk);
+ return rc;
+
+ }
+--
+1.7.4
+
+
+From c099c22d8b1c12fc7d68998982eb4ccd4918e813 Mon Sep 17 00:00:00 2001
+From: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Date: Wed, 19 May 2010 16:58:57 -0700
+Subject: [PATCH 038/203] xen: netback: Introduce a new struct type page_ext.
+
+struct page_ext is used to store the group and idx information by
+which a specified page could be identified.
+
+Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 15 +++++++++++++++
+ drivers/xen/netback/netback.c | 28 +++++++++++++++++-----------
+ 2 files changed, 32 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 00208f4..5e0e467 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -240,6 +240,21 @@ struct netbk_tx_pending_inuse {
+
+ #define MAX_PENDING_REQS 256
+
++/* extra field used in struct page */
++union page_ext {
++ struct {
++#if BITS_PER_LONG < 64
++#define IDX_WIDTH 8
++#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
++ unsigned int group:GROUP_WIDTH;
++ unsigned int idx:IDX_WIDTH;
++#else
++ unsigned int group, idx;
++#endif
++ } e;
++ void *mapping;
++};
+
-+ pdev->pci_dev_data = vpci_dev;
+ struct xen_netbk {
+ struct tasklet_struct net_tx_tasklet;
+ struct tasklet_struct net_rx_tasklet;
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 417f497..71ec999 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -76,22 +76,27 @@ static inline unsigned long idx_to_kaddr(unsigned int idx)
+ }
+
+ /* extra field used in struct page */
+-static inline void netif_set_page_index(struct page *pg, unsigned int index)
++static inline void netif_set_page_ext(struct page *pg, unsigned int group,
++ unsigned int idx)
+ {
+- *(unsigned long *)&pg->mapping = index + 1;
++ union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
+
-+ return 0;
++ 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 - 1;
++ union page_ext ext = { .mapping = pg->mapping };
+
+- if (!PageForeign(pg))
+- return -1;
++ return ext.e.group - 1;
+}
-+
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+ publish_pci_root_cb publish_cb)
-+{
-+ /* The Virtual PCI bus has only one root */
-+ return publish_cb(pdev, 0, 0);
-+}
-+
-+void pciback_release_devices(struct pciback_device *pdev)
-+{
-+ int slot;
-+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ struct pci_dev_entry *e, *tmp;
-+ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
-+ list) {
-+ list_del(&e->list);
-+ pcistub_put_pci_dev(e->dev);
-+ kfree(e);
-+ }
-+ }
-+
-+ kfree(vpci_dev);
-+ pdev->pci_dev_data = NULL;
-+}
-+
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
-+{
-+ struct pci_dev_entry *entry;
-+ struct pci_dev *dev = NULL;
-+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+ unsigned long flags;
-+ int found = 0, slot;
-+
-+ spin_lock_irqsave(&vpci_dev->lock, flags);
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ list_for_each_entry(entry,
-+ &vpci_dev->dev_list[slot],
-+ list) {
-+ dev = entry->dev;
-+ if (dev && dev->bus->number == pcidev->bus->number
-+ && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)
-+ && dev->devfn == pcidev->devfn)
-+ {
-+ found = 1;
-+ *domain = 0;
-+ *bus = 0;
-+ *devfn = PCI_DEVFN(slot, PCI_FUNC(pcidev->devfn));
-+ }
-+ }
-+ }
-+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
-+ return found;
-+}
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-new file mode 100644
-index 0000000..4d56c45
---- /dev/null
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -0,0 +1,710 @@
-+/*
-+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
-+ *
-+ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/vmalloc.h>
-+#include <xen/xenbus.h>
-+#include <xen/evtchn.h>
-+#include "pciback.h"
-+
-+#define INVALID_EVTCHN_IRQ (-1)
-+struct workqueue_struct *pciback_wq;
-+
-+static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
-+{
-+ struct pciback_device *pdev;
-+
-+ pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL);
-+ if (pdev == NULL)
-+ goto out;
-+ dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
-+
-+ pdev->xdev = xdev;
-+ xdev->dev.driver_data = pdev;
-+
-+ spin_lock_init(&pdev->dev_lock);
-+
-+ pdev->sh_area = NULL;
-+ pdev->sh_info = NULL;
-+ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
-+ pdev->be_watching = 0;
-+
-+ INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
-+
-+ if (pciback_init_devices(pdev)) {
-+ kfree(pdev);
-+ pdev = NULL;
-+ }
-+ out:
-+ return pdev;
-+}
-+
-+static void pciback_disconnect(struct pciback_device *pdev)
-+{
-+ spin_lock(&pdev->dev_lock);
-+
-+ /* Ensure the guest can't trigger our handler before removing devices */
-+ if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
-+ unbind_from_irqhandler(pdev->evtchn_irq, pdev);
-+ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
-+ }
-+
-+ /* If the driver domain started an op, make sure we complete it
-+ * before releasing the shared memory */
-+ flush_workqueue(pciback_wq);
-+
-+ if (pdev->sh_info != NULL) {
-+ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
-+ pdev->sh_info = NULL;
-+ }
-+
-+ spin_unlock(&pdev->dev_lock);
-+}
-+
-+static void free_pdev(struct pciback_device *pdev)
-+{
-+ if (pdev->be_watching)
-+ unregister_xenbus_watch(&pdev->be_watch);
-+
-+ pciback_disconnect(pdev);
-+
-+ pciback_release_devices(pdev);
-+
-+ pdev->xdev->dev.driver_data = NULL;
-+ pdev->xdev = NULL;
-+
-+ kfree(pdev);
-+}
-+
-+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
-+ int remote_evtchn)
-+{
-+ int err = 0;
-+ struct vm_struct *area;
-+
-+ dev_dbg(&pdev->xdev->dev,
-+ "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
-+ gnt_ref, remote_evtchn);
-+
-+ area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
-+ if (IS_ERR(area)) {
-+ err = PTR_ERR(area);
-+ goto out;
-+ }
-+ pdev->sh_area = area;
-+ pdev->sh_info = area->addr;
-+
-+ err = bind_interdomain_evtchn_to_irqhandler(
-+ pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
-+ SA_SAMPLE_RANDOM, "pciback", pdev);
-+ if (err < 0) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error binding event channel to IRQ");
-+ goto out;
-+ }
-+ pdev->evtchn_irq = err;
-+ err = 0;
-+
-+ dev_dbg(&pdev->xdev->dev, "Attached!\n");
-+ out:
-+ return err;
-+}
-+
-+static int pciback_attach(struct pciback_device *pdev)
+
+- if ((idx >= MAX_PENDING_REQS) || (netbk->mmap_pages[idx] != pg))
+- return -1;
++static inline unsigned int netif_page_index(const struct page *pg)
+{
-+ int err = 0;
-+ int gnt_ref, remote_evtchn;
-+ char *magic = NULL;
-+
-+ spin_lock(&pdev->dev_lock);
-+
-+ /* Make sure we only do this setup once */
-+ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-+ XenbusStateInitialised)
-+ goto out;
-+
-+ /* Wait for frontend to state that it has published the configuration */
-+ if (xenbus_read_driver_state(pdev->xdev->otherend) !=
-+ XenbusStateInitialised)
-+ goto out;
-+
-+ dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
-+
-+ err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
-+ "pci-op-ref", "%u", &gnt_ref,
-+ "event-channel", "%u", &remote_evtchn,
-+ "magic", NULL, &magic, NULL);
-+ if (err) {
-+ /* If configuration didn't get read correctly, wait longer */
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error reading configuration from frontend");
-+ goto out;
-+ }
-+
-+ if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
-+ xenbus_dev_fatal(pdev->xdev, -EFAULT,
-+ "version mismatch (%s/%s) with pcifront - "
-+ "halting pciback",
-+ magic, XEN_PCI_MAGIC);
-+ goto out;
-+ }
-+
-+ err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
-+ if (err)
-+ goto out;
-+
-+ dev_dbg(&pdev->xdev->dev, "Connecting...\n");
-+
-+ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
-+ if (err)
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error switching to connected state!");
-+
-+ dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
-+ out:
-+ spin_unlock(&pdev->dev_lock);
-+
-+ if (magic)
-+ kfree(magic);
++ union page_ext ext = { .mapping = pg->mapping };
+
+- return idx;
++ return ext.e.idx;
+ }
+
+ /*
+@@ -1380,7 +1385,8 @@ static void netif_page_release(struct page *page, unsigned int
order)
+ {
+ int idx = netif_page_index(page);
+ BUG_ON(order);
+- BUG_ON(idx < 0);
++ BUG_ON(idx < 0 || idx >= MAX_PENDING_REQS);
++ BUG_ON(netbk->mmap_pages[idx] != page);
+ netif_idx_release(idx);
+ }
+
+@@ -1515,7 +1521,7 @@ static int __init netback_init(void)
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
+ page = netbk->mmap_pages[i];
+ SetPageForeign(page, netif_page_release);
+- netif_set_page_index(page, i);
++ netif_set_page_ext(page, 0, i);
+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
+
+--
+1.7.4
+
+
+From 9534985c5b9cc3f6238d6cb8bba7d376e82039d3 Mon Sep 17 00:00:00 2001
+From: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Date: Wed, 19 May 2010 17:08:21 -0700
+Subject: [PATCH 039/203] xen: netback: Multiple tasklets support.
+
+Now netback uses one pair of tasklets for Tx/Rx data transaction.
+Netback tasklet could only run at one CPU at a time, and it is
+used to serve all the netfronts. Therefore it has become a
+performance bottle neck. This patch is to use multiple tasklet
+pairs to replace the current single pair in dom0.
+
+Assuming that Dom0 has CPUNR VCPUs, we define CPUNR kinds of
+tasklets pair (CPUNR for Tx, and CPUNR for Rx). Each pare of
+tasklets serve specific group of netfronts. Also for those global
+and static variables, we duplicated them for each group in
+order to avoid the spinlock.
+
+Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 6 +
+ drivers/xen/netback/interface.c | 27 ++++
+ drivers/xen/netback/netback.c | 270 ++++++++++++++++++++++++---------------
+ 3 files changed, 197 insertions(+), 106 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 5e0e467..847ba58 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -58,6 +58,7 @@
+ struct xen_netif {
+ /* Unique identifier for this interface. */
+ domid_t domid;
++ int group;
+ unsigned int handle;
+
+ u8 fe_dev_addr[6];
+@@ -278,6 +279,8 @@ struct xen_netbk {
+ /* Protect the net_schedule_list in netif. */
+ spinlock_t net_schedule_list_lock;
+
++ atomic_t netfront_count;
+
-+ return err;
-+}
+ 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];
+@@ -296,4 +299,7 @@ struct xen_netbk {
+ struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+ };
+
++extern struct xen_netbk *xen_netbk;
++extern int xen_netbk_group_nr;
+
-+static int pciback_publish_pci_dev(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus,
-+ unsigned int devfn, unsigned int devid)
+ #endif /* __NETIF__BACKEND__COMMON_H__ */
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 086d939..172ef4c 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -54,8 +54,33 @@
+ static unsigned long netbk_queue_length = 32;
+ module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+
++static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
++ struct xen_netif *netif)
+{
-+ int err;
-+ int len;
-+ char str[64];
-+
-+ len = snprintf(str, sizeof(str), "vdev-%d", devid);
-+ if (unlikely(len >= (sizeof(str) - 1))) {
-+ err = -ENOMEM;
-+ goto out;
++ int i;
++ int min_netfront_count;
++ int min_group = 0;
++ min_netfront_count = atomic_read(&netbk[0].netfront_count);
++ for (i = 0; i < group_nr; i++) {
++ int netfront_count = atomic_read(&netbk[i].netfront_count);
++ if (netfront_count < min_netfront_count) {
++ min_group = i;
++ min_netfront_count = netfront_count;
++ }
+ }
+
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+ "%04x:%02x:%02x.%02x", domain, bus,
-+ PCI_SLOT(devfn), PCI_FUNC(devfn));
-+
-+ out:
-+ return err;
++ netif->group = min_group;
++ atomic_inc(&netbk[netif->group].netfront_count);
+}
+
-+static int pciback_export_device(struct pciback_device *pdev,
-+ int domain, int bus, int slot, int func,
-+ int devid)
++static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
+{
-+ struct pci_dev *dev;
-+ int err = 0;
-+
-+ dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func
%x\n",
-+ domain, bus, slot, func);
-+
-+ dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
-+ if (!dev) {
-+ err = -EINVAL;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Couldn't locate PCI device "
-+ "(%04x:%02x:%02x.%01x)! "
-+ "perhaps already in-use?",
-+ domain, bus, slot, func);
-+ goto out;
-+ }
-+
-+ err = pciback_add_pci_dev(pdev, dev, devid, pciback_publish_pci_dev);
-+ if (err)
-+ goto out;
-+
-+ /* TODO: It'd be nice to export a bridge and have all of its children
-+ * get exported with it. This may be best done in xend (which will
-+ * have to calculate resource usage anyway) but we probably want to
-+ * put something in here to ensure that if a bridge gets given to a
-+ * driver domain, that all devices under that bridge are not given
-+ * to other driver domains (as he who controls the bridge can disable
-+ * it and stop the other devices from working).
-+ */
-+ out:
-+ return err;
++ atomic_dec(&netbk[netif->group].netfront_count);
+}
+
-+static int pciback_remove_device(struct pciback_device *pdev,
-+ int domain, int bus, int slot, int func)
-+{
-+ int err = 0;
-+ struct pci_dev *dev;
-+
-+ dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func
%x\n",
-+ domain, bus, slot, func);
-+
-+ dev = pciback_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
-+ if (!dev) {
-+ err = -EINVAL;
-+ dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
-+ "(%04x:%02x:%02x.%01x)! not owned by this domain\n",
-+ domain, bus, slot, func);
-+ goto out;
-+ }
+ static void __netif_up(struct xen_netif *netif)
+ {
++ netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
+ enable_irq(netif->irq);
+ netif_schedule_work(netif);
+ }
+@@ -64,6 +89,7 @@ static void __netif_down(struct xen_netif *netif)
+ {
+ disable_irq(netif->irq);
+ netif_deschedule_work(netif);
++ netbk_remove_netif(xen_netbk, netif);
+ }
+
+ static int net_open(struct net_device *dev)
+@@ -214,6 +240,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ netif = netdev_priv(dev);
+ memset(netif, 0, sizeof(*netif));
+ netif->domid = domid;
++ netif->group = -1;
+ netif->handle = handle;
+ netif->features = NETIF_F_SG;
+ atomic_set(&netif->refcnt, 1);
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 71ec999..feefb14 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -48,9 +48,10 @@
+
+ /*define NETBE_DEBUG_INTERRUPT*/
+
+-static struct xen_netbk *netbk;
++struct xen_netbk *xen_netbk;
++int xen_netbk_group_nr;
+
+-static void netif_idx_release(u16 pending_idx);
++static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+ static void make_tx_response(struct xen_netif *netif,
+ struct xen_netif_tx_request *txp,
+ s8 st);
+@@ -61,18 +62,20 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
+ u16 size,
+ u16 flags);
+
+-static void net_tx_action(unsigned long unused);
++static void net_tx_action(unsigned long data);
+
+-static void net_rx_action(unsigned long unused);
++static void net_rx_action(unsigned long data);
+
+-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(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 */
+@@ -112,7 +115,7 @@ 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(void)
++static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk *netbk)
+ {
+ return MAX_PENDING_REQS -
+ netbk->pending_prod + netbk->pending_cons;
+@@ -125,10 +128,10 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
+
+ int netbk_copy_skb_mode;
+
+-static inline void maybe_schedule_tx_action(void)
++static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
+ {
+ smp_mb();
+- if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
++ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&netbk->net_schedule_list))
+ tasklet_schedule(&netbk->net_tx_tasklet);
+ }
+@@ -235,9 +238,15 @@ static void tx_queue_callback(unsigned long data)
+ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct xen_netif *netif = netdev_priv(dev);
++ struct xen_netbk *netbk;
+
+ BUG_ON(skb->dev != dev);
+
++ if (netif->group == -1)
++ goto drop;
+
-+ pciback_release_pci_dev(pdev, dev);
-+
-+ out:
-+ return err;
-+}
++ netbk = &xen_netbk[netif->group];
+
-+static int pciback_publish_pci_root(struct pciback_device *pdev,
-+ unsigned int domain, unsigned int bus)
-+{
-+ unsigned int d, b;
-+ int i, root_num, len, err;
-+ char str[64];
-+
-+ dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
-+
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+ "root_num", "%d", &root_num);
-+ if (err == 0 || err == -ENOENT)
-+ root_num = 0;
-+ else if (err < 0)
-+ goto out;
-+
-+ /* Verify that we haven't already published this pci root */
-+ for (i = 0; i < root_num; i++) {
-+ len = snprintf(str, sizeof(str), "root-%d", i);
-+ if (unlikely(len >= (sizeof(str) - 1))) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
+ /* Drop the packet if the target domain has no receive buffers. */
+ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
+ goto drop;
+@@ -313,6 +322,7 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
+ struct gnttab_copy *copy_gop;
+ struct xen_netif_rx_request *req;
+ unsigned long old_mfn;
++ int group = netif_page_group(page);
+ int idx = netif_page_index(page);
+
+ old_mfn = virt_to_mfn(page_address(page));
+@@ -321,7 +331,8 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
+
+ copy_gop = npo->copy + npo->copy_prod++;
+ copy_gop->flags = GNTCOPY_dest_gref;
+- if (idx > -1) {
++ if (PageForeign(page)) {
++ struct xen_netbk *netbk = &xen_netbk[group];
+ struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
+ copy_gop->source.domid = src_pend->netif->domid;
+ copy_gop->source.u.ref = src_pend->req.gref;
+@@ -422,9 +433,10 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
+ }
+ }
+
+-static void net_rx_action(unsigned long unused)
++static void net_rx_action(unsigned long data)
+ {
+ struct xen_netif *netif = NULL;
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ s8 status;
+ u16 id, irq, flags;
+ struct xen_netif_rx_response *resp;
+@@ -584,13 +596,15 @@ static void net_rx_action(unsigned long unused)
+ tasklet_schedule(&netbk->net_rx_tasklet);
+ }
+
+-static void net_alarm(unsigned long unused)
++static void net_alarm(unsigned long data)
+ {
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ tasklet_schedule(&netbk->net_rx_tasklet);
+ }
+
+-static void netbk_tx_pending_timeout(unsigned long unused)
++static void netbk_tx_pending_timeout(unsigned long data)
+ {
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ tasklet_schedule(&netbk->net_tx_tasklet);
+ }
+
+@@ -607,6 +621,7 @@ static int __on_net_schedule_list(struct xen_netif *netif)
+
+ static void remove_from_net_schedule_list(struct xen_netif *netif)
+ {
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
+ spin_lock_irq(&netbk->net_schedule_list_lock);
+ if (likely(__on_net_schedule_list(netif))) {
+ list_del_init(&netif->list);
+@@ -617,6 +632,7 @@ static void remove_from_net_schedule_list(struct xen_netif *netif)
+
+ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+ {
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
+ if (__on_net_schedule_list(netif))
+ return;
+
+@@ -631,13 +647,14 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+
+ void netif_schedule_work(struct xen_netif *netif)
+ {
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
+ int more_to_do;
+
+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
+
+ if (more_to_do) {
+ add_to_net_schedule_list_tail(netif);
+- maybe_schedule_tx_action();
++ maybe_schedule_tx_action(netbk);
+ }
+ }
+
+@@ -674,14 +691,15 @@ static void tx_credit_callback(unsigned long data)
+ netif_schedule_work(netif);
+ }
+
+-static inline int copy_pending_req(pending_ring_idx_t pending_idx)
++static inline int copy_pending_req(struct xen_netbk *netbk,
++ pending_ring_idx_t pending_idx)
+ {
+ return gnttab_copy_grant_page(
+ netbk->grant_tx_handle[pending_idx],
+ &netbk->mmap_pages[pending_idx]);
+ }
+
+-inline static void net_tx_action_dealloc(void)
++static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
+ {
+ struct netbk_tx_pending_inuse *inuse, *n;
+ struct gnttab_unmap_grant_ref *gop;
+@@ -711,13 +729,13 @@ inline static void net_tx_action_dealloc(void)
+ pending_idx = netbk->dealloc_ring[pending_index(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),
++ idx_to_kaddr(netbk, pending_idx),
+ GNTMAP_host_map,
+ netbk->grant_tx_handle[pending_idx]);
+ gop++;
+@@ -740,7 +758,7 @@ inline static void net_tx_action_dealloc(void)
+
+ 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;
+@@ -843,7 +861,8 @@ static int netbk_count_requests(struct xen_netif *netif,
+ return frags;
+ }
+
+-static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
++static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
++ struct xen_netif *netif,
+ struct sk_buff *skb,
+ struct xen_netif_tx_request *txp,
+ struct gnttab_map_grant_ref *mop)
+@@ -864,7 +883,7 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
+ index = pending_index(netbk->pending_cons++);
+ pending_idx = netbk->pending_ring[index];
+
+- 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,
+ txp->gref, netif->domid);
+
+@@ -877,8 +896,9 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
+ return mop;
+ }
+
+-static int netbk_tx_check_mop(struct sk_buff *skb,
+- struct gnttab_map_grant_ref **mopp)
++static int netbk_tx_check_mop(struct xen_netbk *netbk,
++ struct sk_buff *skb,
++ struct gnttab_map_grant_ref **mopp)
+ {
+ struct gnttab_map_grant_ref *mop = *mopp;
+ int pending_idx = *((u16 *)skb->data);
+@@ -900,7 +920,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ netif_put(netif);
+ } else {
+ set_phys_to_machine(
+- __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
++ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
+ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
+ netbk->grant_tx_handle[pending_idx] = mop->handle;
+ }
+@@ -918,14 +938,14 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ newerr = (++mop)->status;
+ if (likely(!newerr)) {
+ unsigned long addr;
+- addr = idx_to_kaddr(pending_idx);
++ addr = idx_to_kaddr(netbk, pending_idx);
+ set_phys_to_machine(
+ __pa(addr)>>PAGE_SHIFT,
+ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
+ netbk->grant_tx_handle[pending_idx] = mop->handle;
+ /* Had a previous error? Invalidate this fragment. */
+ if (unlikely(err))
+- netif_idx_release(pending_idx);
++ netif_idx_release(netbk, pending_idx);
+ continue;
+ }
+
+@@ -942,10 +962,10 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+
+ /* 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. */
+@@ -956,7 +976,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
+ 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;
+@@ -974,7 +994,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
+ &netbk->pending_inuse_head);
+
+ txp = &netbk->pending_tx_info[pending_idx].req;
+- frag->page = virt_to_page(idx_to_kaddr(pending_idx));
++ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
+ frag->size = txp->size;
+ frag->page_offset = txp->offset;
+
+@@ -1106,14 +1126,14 @@ static bool tx_credit_exceeded(struct xen_netif *netif, unsigned
size)
+ return false;
+ }
+
+-static unsigned net_tx_build_mops(void)
++static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ {
+ struct gnttab_map_grant_ref *mop;
+ struct sk_buff *skb;
+ int ret;
+
+ mop = netbk->tx_map_ops;
+- while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list)) {
+ struct xen_netif *netif;
+ struct xen_netif_tx_request txreq;
+@@ -1215,7 +1235,7 @@ static unsigned net_tx_build_mops(void)
+ }
+ }
+
+- 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++;
+@@ -1241,7 +1261,7 @@ static unsigned net_tx_build_mops(void)
+
+ netbk->pending_cons++;
+
+- mop = netbk_get_requests(netif, skb, txfrags, mop);
++ mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
+
+ netif->tx.req_cons = idx;
+ netif_schedule_work(netif);
+@@ -1253,7 +1273,7 @@ static unsigned net_tx_build_mops(void)
+ return mop - netbk->tx_map_ops;
+ }
+
+-static void net_tx_submit(void)
++static void net_tx_submit(struct xen_netbk *netbk)
+ {
+ struct gnttab_map_grant_ref *mop;
+ struct sk_buff *skb;
+@@ -1270,7 +1290,7 @@ static void net_tx_submit(void)
+ 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);
+@@ -1279,7 +1299,7 @@ static void net_tx_submit(void)
+
+ 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. */
+@@ -1287,7 +1307,7 @@ static void net_tx_submit(void)
+ 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)
+@@ -1295,7 +1315,7 @@ static void net_tx_submit(void)
+ else if (txp->flags & NETTXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+- netbk_fill_frags(skb);
++ netbk_fill_frags(netbk, skb);
+
+ /*
+ * If the initial fragment was < PKT_PROT_LEN then
+@@ -1344,15 +1364,16 @@ static void net_tx_submit(void)
+ }
+
+ /* Called after netfront has transmitted */
+-static void net_tx_action(unsigned long unused)
++static void net_tx_action(unsigned long data)
+ {
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ unsigned nr_mops;
+ int ret;
+
+ if (netbk->dealloc_cons != netbk->dealloc_prod)
+- net_tx_action_dealloc();
++ net_tx_action_dealloc(netbk);
+
+- nr_mops = net_tx_build_mops();
++ nr_mops = net_tx_build_mops(netbk);
+
+ if (nr_mops == 0)
+ return;
+@@ -1361,10 +1382,10 @@ static void net_tx_action(unsigned long unused)
+ netbk->tx_map_ops, nr_mops);
+ BUG_ON(ret);
+
+- net_tx_submit();
++ net_tx_submit(netbk);
+ }
+
+-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;
+@@ -1383,19 +1404,28 @@ static void netif_idx_release(u16 pending_idx)
+
+ static void netif_page_release(struct page *page, unsigned int order)
+ {
++ int group = netif_page_group(page);
+ int idx = netif_page_index(page);
++ struct xen_netbk *netbk = &xen_netbk[group];
+ BUG_ON(order);
++ BUG_ON(group < 0 || group >= xen_netbk_group_nr);
+ BUG_ON(idx < 0 || idx >= MAX_PENDING_REQS);
+ BUG_ON(netbk->mmap_pages[idx] != page);
+- netif_idx_release(idx);
++ netif_idx_release(netbk, idx);
+ }
+
+ irqreturn_t netif_be_int(int irq, void *dev_id)
+ {
+ struct xen_netif *netif = dev_id;
++ struct xen_netbk *netbk;
+
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+ str, "%x:%x", &d, &b);
-+ if (err < 0)
-+ goto out;
-+ if (err != 2) {
-+ err = -EINVAL;
-+ goto out;
-+ }
++ if (netif->group == -1)
++ return IRQ_NONE;
+
-+ if (d == domain && b == bus) {
-+ err = 0;
-+ goto out;
++ netbk = &xen_netbk[netif->group];
+
+ add_to_net_schedule_list_tail(netif);
+- maybe_schedule_tx_action();
++ maybe_schedule_tx_action(netbk);
+
+ if (netif_schedulable(netif) && !netbk_queue_full(netif))
+ netif_wake_queue(netif->dev);
+@@ -1453,28 +1483,40 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
+ struct list_head *ent;
+ struct xen_netif *netif;
+ int i = 0;
++ int group = 0;
+
+ printk(KERN_ALERT "netif_schedule_list:\n");
+- spin_lock_irq(&netbk->net_schedule_list_lock);
+
+- list_for_each(ent, &netbk->net_schedule_list) {
+- netif = list_entry(ent, struct xen_netif, list);
+- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
+- "rx_resp_prod=%08x\n",
+- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
+- printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n",
+- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
+- printk(KERN_ALERT " shared(rx_req_prod=%08x "
+- "rx_resp_prod=%08x\n",
+- netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
+- printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n",
+- netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
+- printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n",
+- netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
+- i++;
++ for (group = 0; group < xen_netbk_group_nr; group++) {
++ struct xen_netbk *netbk = &xen_netbk[group];
++ spin_lock_irq(&netbk->net_schedule_list_lock);
++ printk(KERN_ALERT "xen_netback group number: %d\n", group);
++ list_for_each(ent, &netbk->net_schedule_list) {
++ netif = list_entry(ent, struct xen_netif, list);
++ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
++ "rx_resp_prod=%08x\n",
++ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
++ printk(KERN_ALERT
++ " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
++ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
++ printk(KERN_ALERT
++ " shared(rx_req_prod=%08x "
++ "rx_resp_prod=%08x\n",
++ netif->rx.sring->req_prod,
++ netif->rx.sring->rsp_prod);
++ printk(KERN_ALERT
++ " rx_event=%08x, tx_req_prod=%08x\n",
++ netif->rx.sring->rsp_event,
++ netif->tx.sring->req_prod);
++ printk(KERN_ALERT
++ " tx_resp_prod=%08x, tx_event=%08x)\n",
++ netif->tx.sring->rsp_prod,
++ netif->tx.sring->rsp_event);
++ i++;
+ }
-+ }
-+
-+ len = snprintf(str, sizeof(str), "root-%d", root_num);
-+ if (unlikely(len >= (sizeof(str) - 1))) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+
-+ dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
-+ root_num, domain, bus);
-+
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+ "%04x:%02x", domain, bus);
-+ if (err)
-+ goto out;
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
+ }
+
+- spin_unlock_irq(&netbk->net_schedule_list_lock);
+ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
+
+ return IRQ_HANDLED;
+@@ -1486,12 +1528,15 @@ static int __init netback_init(void)
+ int i;
+ struct page *page;
+ int rc = 0;
++ int group;
+
+ if (!xen_domain())
+ return -ENODEV;
+
+- netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk));
+- if (!netbk) {
++ xen_netbk_group_nr = num_online_cpus();
++ xen_netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk) *
++ xen_netbk_group_nr);
++ if (!xen_netbk) {
+ printk(KERN_ALERT "%s: out of memory\n", __func__);
+ return -ENOMEM;
+ }
+@@ -1499,44 +1544,54 @@ static int __init netback_init(void)
+ /* We can increase reservation by this much in net_rx_action(). */
+ // balloon_update_driver_allowance(NET_RX_RING_SIZE);
+
+- skb_queue_head_init(&netbk->rx_queue);
+- skb_queue_head_init(&netbk->tx_queue);
+-
+- init_timer(&netbk->net_timer);
+- netbk->net_timer.data = 0;
+- netbk->net_timer.function = net_alarm;
+-
+- init_timer(&netbk->netbk_tx_pending_timer);
+- netbk->netbk_tx_pending_timer.data = 0;
+- netbk->netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
++ for (group = 0; group < xen_netbk_group_nr; group++) {
++ struct xen_netbk *netbk = &xen_netbk[group];
++ skb_queue_head_init(&netbk->rx_queue);
++ skb_queue_head_init(&netbk->tx_queue);
+
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
-+ "root_num", "%d", (root_num + 1));
++ init_timer(&netbk->net_timer);
++ netbk->net_timer.data = (unsigned long)netbk;
++ netbk->net_timer.function = net_alarm;
+
-+ out:
-+ return err;
-+}
++ init_timer(&netbk->netbk_tx_pending_timer);
++ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
++ netbk->netbk_tx_pending_timer.function =
++ netbk_tx_pending_timeout;
+
-+static int pciback_reconfigure(struct pciback_device *pdev)
-+{
-+ int err = 0;
-+ int num_devs;
-+ int domain, bus, slot, func;
-+ int substate;
-+ int i, len;
-+ char state_str[64];
-+ char dev_str[64];
-+
-+ spin_lock(&pdev->dev_lock);
-+
-+ dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
-+
-+ /* Make sure we only reconfigure once */
-+ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-+ XenbusStateReconfiguring)
-+ goto out;
-+
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs",
"%d",
-+ &num_devs);
-+ if (err != 1) {
-+ if (err >= 0)
-+ err = -EINVAL;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error reading number of devices");
-+ goto out;
-+ }
-+
-+ for (i = 0; i < num_devs; i++) {
-+ len = snprintf(state_str, sizeof(state_str), "state-%d", i);
-+ if (unlikely(len >= (sizeof(state_str) - 1))) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "String overflow while reading "
-+ "configuration");
-+ goto out;
++ netbk->mmap_pages =
++ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
++ if (!netbk->mmap_pages) {
++ printk(KERN_ALERT "%s: out of memory\n", __func__);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ rc = -ENOMEM;
++ goto failed_init;
+ }
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
-+ "%d", &substate);
-+ if (err != 1)
-+ substate = XenbusStateUnknown;
-+
-+ switch (substate) {
-+ case XenbusStateInitialising:
-+ dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
-+
-+ len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
-+ if (unlikely(len >= (sizeof(dev_str) - 1))) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "String overflow while "
-+ "reading configuration");
-+ goto out;
-+ }
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+ dev_str, "%x:%x:%x.%x",
-+ &domain, &bus, &slot, &func);
-+ if (err < 0) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error reading device "
-+ "configuration");
-+ goto out;
-+ }
-+ if (err != 4) {
-+ err = -EINVAL;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error parsing pci device "
-+ "configuration");
-+ goto out;
-+ }
-+
-+ err = pciback_export_device(pdev, domain, bus, slot,
-+ func, i);
-+ if (err)
-+ goto out;
-+
-+ /* Publish pci roots. */
-+ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
-+ if (err) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error while publish PCI root"
-+ "buses for frontend");
-+ goto out;
-+ }
-+
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
-+ state_str, "%d",
-+ XenbusStateInitialised);
-+ if (err) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error switching substate of "
-+ "dev-%d\n", i);
-+ goto out;
-+ }
-+ break;
-+
-+ case XenbusStateClosing:
-+ dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
-+
-+ len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
-+ if (unlikely(len >= (sizeof(dev_str) - 1))) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "String overflow while "
-+ "reading configuration");
-+ goto out;
-+ }
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+ dev_str, "%x:%x:%x.%x",
-+ &domain, &bus, &slot, &func);
-+ if (err < 0) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error reading device "
-+ "configuration");
-+ goto out;
-+ }
-+ if (err != 4) {
-+ err = -EINVAL;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error parsing pci device "
-+ "configuration");
-+ goto out;
-+ }
-+
-+ err = pciback_remove_device(pdev, domain, bus, slot,
-+ func);
-+ if(err)
-+ goto out;
-+
-+ /* TODO: If at some point we implement support for pci
-+ * root hot-remove on pcifront side, we'll need to
-+ * remove unnecessary xenstore nodes of pci roots here.
-+ */
-+
-+ break;
-+
-+ default:
-+ break;
+
+- netbk->mmap_pages =
+- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+- if (!netbk->mmap_pages) {
+- printk(KERN_ALERT "%s: out of memory\n", __func__);
+- rc = -ENOMEM;
+- goto failed_init2;
+- }
++ 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);
++ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
+
+- for (i = 0; i < MAX_PENDING_REQS; i++) {
+- page = netbk->mmap_pages[i];
+- SetPageForeign(page, netif_page_release);
+- netif_set_page_ext(page, 0, i);
+- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+- }
++ netbk->pending_cons = 0;
++ netbk->pending_prod = MAX_PENDING_REQS;
++ for (i = 0; i < MAX_PENDING_REQS; i++)
++ netbk->pending_ring[i] = i;
+
+- netbk->pending_cons = 0;
+- netbk->pending_prod = MAX_PENDING_REQS;
+- for (i = 0; i < MAX_PENDING_REQS; i++)
+- netbk->pending_ring[i] = i;
++ tasklet_init(&netbk->net_tx_tasklet, net_tx_action,
++ (unsigned long)netbk);
++ tasklet_init(&netbk->net_rx_tasklet, net_rx_action,
++ (unsigned long)netbk);
+
+- tasklet_init(&netbk->net_tx_tasklet, net_tx_action, 0);
+- tasklet_init(&netbk->net_rx_tasklet, net_rx_action, 0);
++ INIT_LIST_HEAD(&netbk->pending_inuse_head);
++ INIT_LIST_HEAD(&netbk->net_schedule_list);
+
+- INIT_LIST_HEAD(&netbk->pending_inuse_head);
+- INIT_LIST_HEAD(&netbk->net_schedule_list);
++ spin_lock_init(&netbk->net_schedule_list_lock);
+
+- spin_lock_init(&netbk->net_schedule_list_lock);
++ atomic_set(&netbk->netfront_count, 0);
+ }
-+
-+ err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
-+ if (err) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error switching to reconfigured state!");
-+ goto out;
+
+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+ if (MODPARM_copy_skb) {
+@@ -1551,25 +1606,28 @@ static int __init netback_init(void)
+
+ rc = netif_xenbus_init();
+ if (rc)
+- goto failed_init1;
++ goto failed_init;
+
+ #ifdef NETBE_DEBUG_INTERRUPT
+ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
+ 0,
+ netif_be_dbg,
+- SA_SHIRQ,
++ IRQF_SHARED,
+ "net-be-dbg",
+ &netif_be_dbg);
+ #endif
+
+ return 0;
+
+-failed_init1:
+- free_empty_pages_and_pagevec(netbk->mmap_pages, MAX_PENDING_REQS);
+-failed_init2:
+- del_timer(&netbk->netbk_tx_pending_timer);
+- del_timer(&netbk->net_timer);
+- vfree(netbk);
++failed_init:
++ for (i = 0; i < group; i++) {
++ struct xen_netbk *netbk = &xen_netbk[i];
++ free_empty_pages_and_pagevec(netbk->mmap_pages,
++ MAX_PENDING_REQS);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
+ }
-+
-+ out:
-+ spin_unlock(&pdev->dev_lock);
++ vfree(xen_netbk);
+ return rc;
+
+ }
+--
+1.7.4
+
+
+From e7317b70c0436c109b605bb377939cb2eaff6a6f Mon Sep 17 00:00:00 2001
+From: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Date: Wed, 19 May 2010 17:08:22 -0700
+Subject: [PATCH 040/203] xen: netback: Use Kernel thread to replace the tasklet.
+
+Kernel thread has more control over QoS, and could improve dom0's
+userspace responseness. This option is defaultly off currently.
+
+Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 13 ++++-
+ drivers/xen/netback/netback.c | 109 ++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 109 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 847ba58..36cb2b9 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -257,8 +257,17 @@ union page_ext {
+ };
+
+ struct xen_netbk {
+- struct tasklet_struct net_tx_tasklet;
+- struct tasklet_struct net_rx_tasklet;
++ union {
++ struct {
++ struct tasklet_struct net_tx_tasklet;
++ struct tasklet_struct net_rx_tasklet;
++ } tasklet;
+
-+ return 0;
-+}
++ struct {
++ wait_queue_head_t netbk_action_wq;
++ struct task_struct *task;
++ } kthread;
++ };
+
+ struct sk_buff_head rx_queue;
+ struct sk_buff_head tx_queue;
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index feefb14..547dcaa 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -38,6 +38,7 @@
+
+ #include <linux/tcp.h>
+ #include <linux/udp.h>
++#include <linux/kthread.h>
+
+ #include <xen/balloon.h>
+ #include <xen/events.h>
+@@ -128,12 +129,31 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
+
+ int netbk_copy_skb_mode;
+
++static int MODPARM_netback_kthread;
++module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
++MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
+
-+static void pciback_frontend_changed(struct xenbus_device *xdev,
-+ enum xenbus_state fe_state)
++/*
++ * Netback bottom half handler.
++ * dir indicates the data direction.
++ * rx: 1, tx: 0.
++ */
++static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
+{
-+ struct pciback_device *pdev = xdev->dev.driver_data;
-+
-+ dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
-+
-+ switch (fe_state) {
-+ case XenbusStateInitialised:
-+ pciback_attach(pdev);
-+ break;
++ if (MODPARM_netback_kthread)
++ wake_up(&netbk->kthread.netbk_action_wq);
++ else if (dir)
++ tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
++ else
++ tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
++}
+
-+ case XenbusStateReconfiguring:
-+ pciback_reconfigure(pdev);
-+ break;
+ static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
+ {
+ smp_mb();
+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&netbk->net_schedule_list))
+- tasklet_schedule(&netbk->net_tx_tasklet);
++ xen_netbk_bh_handler(netbk, 0);
+ }
+
+ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+@@ -289,7 +309,8 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ }
+ }
+ skb_queue_tail(&netbk->rx_queue, skb);
+- tasklet_schedule(&netbk->net_rx_tasklet);
+
-+ case XenbusStateConnected:
-+ /* pcifront switched its state from reconfiguring to connected.
-+ * Then switch to connected state.
-+ */
-+ xenbus_switch_state(xdev, XenbusStateConnected);
-+ break;
++ xen_netbk_bh_handler(netbk, 1);
+
+ return 0;
+
+@@ -593,19 +614,19 @@ static void net_rx_action(unsigned long data)
+ /* More work to do? */
+ if (!skb_queue_empty(&netbk->rx_queue) &&
+ !timer_pending(&netbk->net_timer))
+- tasklet_schedule(&netbk->net_rx_tasklet);
++ xen_netbk_bh_handler(netbk, 1);
+ }
+
+ static void net_alarm(unsigned long data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+- tasklet_schedule(&netbk->net_rx_tasklet);
++ xen_netbk_bh_handler(netbk, 1);
+ }
+
+ static void netbk_tx_pending_timeout(unsigned long data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+- tasklet_schedule(&netbk->net_tx_tasklet);
++ xen_netbk_bh_handler(netbk, 0);
+ }
+
+ struct net_device_stats *netif_be_get_stats(struct net_device *dev)
+@@ -1348,7 +1369,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ continue;
+ }
+
+- netif_rx(skb);
++ netif_rx_ni(skb);
+ netif->dev->last_rx = jiffies;
+ }
+
+@@ -1399,7 +1420,7 @@ static void netif_idx_release(struct xen_netbk *netbk, u16
pending_idx)
+ netbk->dealloc_prod++;
+ spin_unlock_irqrestore(&_lock, flags);
+
+- tasklet_schedule(&netbk->net_tx_tasklet);
++ xen_netbk_bh_handler(netbk, 0);
+ }
+
+ static void netif_page_release(struct page *page, unsigned int order)
+@@ -1523,6 +1544,46 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
+ }
+ #endif
+
++static inline int rx_work_todo(struct xen_netbk *netbk)
++{
++ return !skb_queue_empty(&netbk->rx_queue);
++}
+
-+ case XenbusStateClosing:
-+ pciback_disconnect(pdev);
-+ xenbus_switch_state(xdev, XenbusStateClosing);
-+ break;
++static inline int tx_work_todo(struct xen_netbk *netbk)
++{
++ if (netbk->dealloc_cons != netbk->dealloc_prod)
++ return 1;
+
-+ case XenbusStateClosed:
-+ pciback_disconnect(pdev);
-+ xenbus_switch_state(xdev, XenbusStateClosed);
-+ if (xenbus_dev_is_online(xdev))
-+ break;
-+ /* fall through if not online */
-+ case XenbusStateUnknown:
-+ dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
-+ device_unregister(&xdev->dev);
-+ break;
++ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ !list_empty(&netbk->net_schedule_list))
++ return 1;
+
-+ default:
-+ break;
-+ }
++ return 0;
+}
+
-+static int pciback_setup_backend(struct pciback_device *pdev)
++static int netbk_action_thread(void *data)
+{
-+ /* Get configuration from xend (if available now) */
-+ int domain, bus, slot, func;
-+ int err = 0;
-+ int i, num_devs;
-+ char dev_str[64];
-+ char state_str[64];
-+
-+ spin_lock(&pdev->dev_lock);
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ while (!kthread_should_stop()) {
++ wait_event_interruptible(netbk->kthread.netbk_action_wq,
++ rx_work_todo(netbk)
++ || tx_work_todo(netbk)
++ || kthread_should_stop());
++ cond_resched();
+
-+ /* It's possible we could get the call to setup twice, so make sure
-+ * we're not already connected.
-+ */
-+ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-+ XenbusStateInitWait)
-+ goto out;
++ if (kthread_should_stop())
++ break;
+
-+ dev_dbg(&pdev->xdev->dev, "getting be setup\n");
++ if (rx_work_todo(netbk))
++ net_rx_action((unsigned long)netbk);
+
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs",
"%d",
-+ &num_devs);
-+ if (err != 1) {
-+ if (err >= 0)
-+ err = -EINVAL;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error reading number of devices");
-+ goto out;
++ if (tx_work_todo(netbk))
++ net_tx_action((unsigned long)netbk);
+ }
+
-+ for (i = 0; i < num_devs; i++) {
-+ int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
-+ if (unlikely(l >= (sizeof(dev_str) - 1))) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "String overflow while reading "
-+ "configuration");
-+ goto out;
-+ }
-+
-+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
-+ "%x:%x:%x.%x", &domain, &bus, &slot, &func);
-+ if (err < 0) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error reading device configuration");
-+ goto out;
-+ }
-+ if (err != 4) {
-+ err = -EINVAL;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error parsing pci device "
-+ "configuration");
-+ goto out;
-+ }
++ return 0;
++}
+
-+ err = pciback_export_device(pdev, domain, bus, slot, func, i);
-+ if (err)
-+ goto out;
+ static int __init netback_init(void)
+ {
+ int i;
+@@ -1580,10 +1641,34 @@ static int __init netback_init(void)
+ for (i = 0; i < MAX_PENDING_REQS; i++)
+ netbk->pending_ring[i] = i;
+
+- tasklet_init(&netbk->net_tx_tasklet, net_tx_action,
+- (unsigned long)netbk);
+- tasklet_init(&netbk->net_rx_tasklet, net_rx_action,
+- (unsigned long)netbk);
++ if (MODPARM_netback_kthread) {
++ init_waitqueue_head(&netbk->kthread.netbk_action_wq);
++ netbk->kthread.task =
++ kthread_create(netbk_action_thread,
++ (void *)netbk,
++ "netback/%u", group);
+
-+ /* Switch substate of this device. */
-+ l = snprintf(state_str, sizeof(state_str), "state-%d", i);
-+ if (unlikely(l >= (sizeof(state_str) - 1))) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "String overflow while reading "
-+ "configuration");
-+ goto out;
++ if (!IS_ERR(netbk->kthread.task)) {
++ kthread_bind(netbk->kthread.task, group);
++ wake_up_process(netbk->kthread.task);
++ } else {
++ printk(KERN_ALERT
++ "kthread_run() fails at netback\n");
++ free_empty_pages_and_pagevec(netbk->mmap_pages,
++ MAX_PENDING_REQS);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ rc = PTR_ERR(netbk->kthread.task);
++ goto failed_init;
++ }
++ } else {
++ tasklet_init(&netbk->tasklet.net_tx_tasklet,
++ net_tx_action,
++ (unsigned long)netbk);
++ tasklet_init(&netbk->tasklet.net_rx_tasklet,
++ net_rx_action,
++ (unsigned long)netbk);
+ }
-+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
-+ "%d", XenbusStateInitialised);
-+ if (err) {
-+ xenbus_dev_fatal(pdev->xdev, err, "Error switching "
-+ "substate of dev-%d\n", i);
-+ goto out;
-+ }
-+ }
-+
-+ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
-+ if (err) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error while publish PCI root buses "
-+ "for frontend");
-+ goto out;
-+ }
-+
-+ err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
-+ if (err)
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error switching to initialised state!");
-+
-+ out:
-+ spin_unlock(&pdev->dev_lock);
-+
-+ if (!err)
-+ /* see if pcifront is already configured (if not, we'll wait) */
-+ pciback_attach(pdev);
-+
-+ return err;
-+}
-+
-+static void pciback_be_watch(struct xenbus_watch *watch,
-+ const char **vec, unsigned int len)
-+{
-+ struct pciback_device *pdev =
-+ container_of(watch, struct pciback_device, be_watch);
-+
-+ switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
-+ case XenbusStateInitWait:
-+ pciback_setup_backend(pdev);
-+ break;
-+
-+ default:
-+ break;
-+ }
-+}
-+
-+static int pciback_xenbus_probe(struct xenbus_device *dev,
-+ const struct xenbus_device_id *id)
-+{
-+ int err = 0;
-+ struct pciback_device *pdev = alloc_pdev(dev);
-+
-+ if (pdev == NULL) {
-+ err = -ENOMEM;
-+ xenbus_dev_fatal(dev, err,
-+ "Error allocating pciback_device struct");
-+ goto out;
-+ }
-+
-+ /* wait for xend to configure us */
-+ err = xenbus_switch_state(dev, XenbusStateInitWait);
-+ if (err)
-+ goto out;
-+
-+ /* watch the backend node for backend configuration information */
-+ err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
-+ pciback_be_watch);
-+ if (err)
-+ goto out;
-+ pdev->be_watching = 1;
-+
-+ /* We need to force a call to our callback here in case
-+ * xend already configured us!
-+ */
-+ pciback_be_watch(&pdev->be_watch, NULL, 0);
-+
-+ out:
-+ return err;
-+}
-+
-+static int pciback_xenbus_remove(struct xenbus_device *dev)
-+{
-+ struct pciback_device *pdev = dev->dev.driver_data;
-+
-+ if (pdev != NULL)
-+ free_pdev(pdev);
-+
-+ return 0;
-+}
-+
-+static const struct xenbus_device_id xenpci_ids[] = {
-+ {"pci"},
-+ {{0}},
-+};
-+
-+static struct xenbus_driver xenbus_pciback_driver = {
-+ .name = "pciback",
-+ .owner = THIS_MODULE,
-+ .ids = xenpci_ids,
-+ .probe = pciback_xenbus_probe,
-+ .remove = pciback_xenbus_remove,
-+ .otherend_changed = pciback_frontend_changed,
-+};
-+
-+int __init pciback_xenbus_register(void)
-+{
-+ if (!is_running_on_xen())
-+ return -ENODEV;
-+ pciback_wq = create_workqueue("pciback_workqueue");
-+ if (!pciback_wq) {
-+ printk(KERN_ERR "pciback_xenbus_register: create"
-+ "pciback_workqueue failed\n");
-+ return -EFAULT;
-+ }
-+ return xenbus_register_backend(&xenbus_pciback_driver);
-+}
-+
-+void __exit pciback_xenbus_unregister(void)
-+{
-+ destroy_workqueue(pciback_wq);
-+ xenbus_unregister_driver(&xenbus_pciback_driver);
-+}
---
-1.7.4
-
-
-From cf2a64556286b762ce6a3a9b408ba7ecdcaea03a Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:22 -0400
-Subject: [PATCH 008/244] xen-pciback: Fix include header name change (evtchn.h is now
events.h)
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/pci_stub.c | 2 +-
- drivers/xen/pciback/pciback_ops.c | 2 +-
- drivers/xen/pciback/xenbus.c | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index c481a73..c02f21f 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -13,7 +13,7 @@
- #include <linux/pci.h>
- #include <linux/wait.h>
- #include <asm/atomic.h>
--#include <xen/evtchn.h>
-+#include <xen/events.h>
- #include "pciback.h"
- #include "conf_space.h"
- #include "conf_space_quirks.h"
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index b85b2db..58d09eb 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -6,7 +6,7 @@
- #include <linux/module.h>
- #include <linux/wait.h>
- #include <asm/bitops.h>
--#include <xen/evtchn.h>
-+#include <xen/events.h>
- #include "pciback.h"
-
- int verbose_request = 0;
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index 4d56c45..bbca3fe 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -8,7 +8,7 @@
- #include <linux/list.h>
- #include <linux/vmalloc.h>
- #include <xen/xenbus.h>
--#include <xen/evtchn.h>
-+#include <xen/events.h>
- #include "pciback.h"
- #define INVALID_EVTCHN_IRQ (-1)
+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
+ INIT_LIST_HEAD(&netbk->net_schedule_list);
+@@ -1626,6 +1711,8 @@ failed_init:
+ MAX_PENDING_REQS);
+ del_timer(&netbk->netbk_tx_pending_timer);
+ del_timer(&netbk->net_timer);
++ if (MODPARM_netback_kthread)
++ kthread_stop(netbk->kthread.task);
+ }
+ vfree(xen_netbk);
+ return rc;
--
1.7.4
-From f6222ae41f2fee3f67983f833ee8dcba2c7a1362 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:24 -0400
-Subject: [PATCH 009/244] xen-pciback: Use pci_is_enabled() instead of is_enabled.
+From 6359d5939c5d1f59b794cd02e8cdbd36b9f3434d Mon Sep 17 00:00:00 2001
+From: James Harper <james.harper(a)bendigoit.com.au>
+Date: Fri, 28 May 2010 23:12:56 -0700
+Subject: [PATCH 041/203] xen: netback: avoid null-pointer access in netback_uevent
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Check if drvdata has been set up yet and return if it hasn't.
+
+Signed-off-by: James Harper <james.harper(a)bendigoit.com.au>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/pciback/conf_space_header.c | 4 ++--
- drivers/xen/pciback/pciback_ops.c | 1 -
- 2 files changed, 2 insertions(+), 3 deletions(-)
+ drivers/xen/netback/xenbus.c | 9 +++++++--
+ 1 files changed, 7 insertions(+), 2 deletions(-)
-diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
-index f794e12..5a9e028 100644
---- a/drivers/xen/pciback/conf_space_header.c
-+++ b/drivers/xen/pciback/conf_space_header.c
-@@ -22,14 +22,14 @@ static int command_write(struct pci_dev *dev, int offset, u16 value,
void *data)
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index fcd3c34..e30b0c7 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -154,12 +154,17 @@ fail:
+ */
+ static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
{
- int err;
-
-- if (!dev->is_enabled && is_enable_cmd(value)) {
-+ if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
- if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: enable\n",
- pci_name(dev));
- err = pci_enable_device(dev);
- if (err)
- return err;
-- } else if (dev->is_enabled && !is_enable_cmd(value)) {
-+ } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
- if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: disable\n",
- pci_name(dev));
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 58d09eb..2d570e7 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -26,7 +26,6 @@ void pciback_reset_device(struct pci_dev *dev)
+- struct backend_info *be = dev_get_drvdata(&xdev->dev);
+- struct xen_netif *netif = be->netif;
++ struct backend_info *be;
++ struct xen_netif *netif;
+ char *val;
- pci_write_config_word(dev, PCI_COMMAND, 0);
+ DPRINTK("netback_uevent");
-- dev->is_enabled = 0;
- dev->is_busmaster = 0;
- } else {
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ be = dev_get_drvdata(&xdev->dev);
++ if (!be)
++ return 0;
++ netif = be->netif;
++
+ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
+ if (IS_ERR(val)) {
+ int err = PTR_ERR(val);
--
1.7.4
-From 0d379d03a3284e4b4d890b7e1b8163d485cc72e6 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:25 -0400
-Subject: [PATCH 010/244] xen-pciback: Fix usage of INIT_WORK.
+From 4a818daa044d9d499412e8f6e2e3086c0521e7b3 Mon Sep 17 00:00:00 2001
+From: Keir Fraser <keir.fraser(a)citrix.com>
+Date: Fri, 11 Jun 2010 11:48:30 +0100
+Subject: [PATCH 042/203] xen: netback: Fixes for delayed copy of tx network packets.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+ - Should call net_tx_action_dealloc() even when dealloc ring is
+ empty, as there may in any case be work to do on the
+ pending_inuse list.
+ - Should not exit directly from the middle of the tx_action tasklet,
+ as the tx_pending_timer should always be checked and updated at the
+ end of the tasklet.
+
+Signed-off-by: Keir Fraser <keir.fraser(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+[picked from linux-2.6.18-xen.hg 959:1a97bd686258, ported across a43e2175
"xen/netback: move code around"]
---
- drivers/xen/pciback/pciback.h | 4 ++--
- drivers/xen/pciback/pciback_ops.c | 7 ++++---
- drivers/xen/pciback/xenbus.c | 3 ++-
- 3 files changed, 8 insertions(+), 6 deletions(-)
+ drivers/xen/netback/netback.c | 25 ++++++++++++-------------
+ 1 files changed, 12 insertions(+), 13 deletions(-)
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-index 6744f45..4fb8c05 100644
---- a/drivers/xen/pciback/pciback.h
-+++ b/drivers/xen/pciback/pciback.h
-@@ -99,8 +99,8 @@ int pciback_publish_pci_roots(struct pciback_device *pdev,
- void pciback_release_devices(struct pciback_device *pdev);
-
- /* Handles events from front-end */
--irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
--void pciback_do_op(void *data);
-+irqreturn_t pciback_handle_event(int irq, void *dev_id);
-+void pciback_do_op(struct work_struct *data);
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 547dcaa..58dfbd2 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1372,16 +1372,6 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ netif_rx_ni(skb);
+ netif->dev->last_rx = jiffies;
+ }
+-
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !list_empty(&netbk->pending_inuse_head)) {
+- struct netbk_tx_pending_inuse *oldest;
+-
+- oldest = list_entry(netbk->pending_inuse_head.next,
+- struct netbk_tx_pending_inuse, list);
+- mod_timer(&netbk->netbk_tx_pending_timer,
+- oldest->alloc_time + HZ);
+- }
+ }
- int pciback_xenbus_register(void);
- void pciback_xenbus_unregister(void);
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 2d570e7..6624faf 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -66,9 +66,10 @@ void test_and_schedule_op(struct pciback_device *pdev)
- * context because some of the pci_* functions can sleep (mostly due to ACPI
- * use of semaphores). This function is intended to be called from a work
- * queue in process context taking a struct pciback_device as a parameter */
--void pciback_do_op(void *data)
-+
-+void pciback_do_op(struct work_struct *data)
- {
-- struct pciback_device *pdev = data;
-+ struct pciback_device *pdev = container_of(data, struct pciback_device, op_work);
- struct pci_dev *dev;
- struct xen_pci_op *op = &pdev->sh_info->op;
+ /* Called after netfront has transmitted */
+@@ -1391,19 +1381,28 @@ static void net_tx_action(unsigned long data)
+ unsigned nr_mops;
+ int ret;
-@@ -123,7 +124,7 @@ void pciback_do_op(void *data)
- test_and_schedule_op(pdev);
- }
+- if (netbk->dealloc_cons != netbk->dealloc_prod)
+- net_tx_action_dealloc(netbk);
++ net_tx_action_dealloc(netbk);
--irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
-+irqreturn_t pciback_handle_event(int irq, void *dev_id)
- {
- struct pciback_device *pdev = dev_id;
+ nr_mops = net_tx_build_mops(netbk);
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index bbca3fe..bd52289 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -9,6 +9,7 @@
- #include <linux/vmalloc.h>
- #include <xen/xenbus.h>
- #include <xen/events.h>
-+#include <linux/workqueue.h>
- #include "pciback.h"
+ if (nr_mops == 0)
+- return;
++ goto out;
- #define INVALID_EVTCHN_IRQ (-1)
-@@ -33,7 +34,7 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
- pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
- pdev->be_watching = 0;
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+ netbk->tx_map_ops, nr_mops);
+ BUG_ON(ret);
-- INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
-+ INIT_WORK(&pdev->op_work, pciback_do_op);
+ net_tx_submit(netbk);
++out:
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !list_empty(&netbk->pending_inuse_head)) {
++ struct netbk_tx_pending_inuse *oldest;
++
++ oldest = list_entry(netbk->pending_inuse_head.next,
++ struct netbk_tx_pending_inuse, list);
++ mod_timer(&netbk->netbk_tx_pending_timer,
++ oldest->alloc_time + HZ);
++ }
+ }
- if (pciback_init_devices(pdev)) {
- kfree(pdev);
+ static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
--
1.7.4
-From 57f6c49d0f428f96cca49147d68b0bb6156613a6 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:26 -0400
-Subject: [PATCH 011/244] xen-pciback: Update the calling mechanism for
xenbus_[map|unmap]_ring_valloc functions.
+From 48fa1af97e6c9d304c04f70a75de1340e7d79e18 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 11 Jun 2010 10:51:01 +0100
+Subject: [PATCH 043/203] xen: netback: handle NET_SKBUFF_DATA_USES_OFFSET correctly
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jan Beulich <JBeulich(a)novell.com>
---
- drivers/xen/pciback/pciback.h | 1 -
- drivers/xen/pciback/xenbus.c | 18 +++++++++---------
- 2 files changed, 9 insertions(+), 10 deletions(-)
+ drivers/xen/netback/netback.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-index 4fb8c05..5e8e14e 100644
---- a/drivers/xen/pciback/pciback.h
-+++ b/drivers/xen/pciback/pciback.h
-@@ -36,7 +36,6 @@ struct pciback_device {
-
- int evtchn_irq;
-
-- struct vm_struct *sh_area;
- struct xen_pci_sharedinfo *sh_info;
-
- unsigned long flags;
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index bd52289..5be1350 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -7,6 +7,7 @@
- #include <linux/init.h>
- #include <linux/list.h>
- #include <linux/vmalloc.h>
-+#include <linux/workqueue.h>
- #include <xen/xenbus.h>
- #include <xen/events.h>
- #include <linux/workqueue.h>
-@@ -29,7 +30,6 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
-
- spin_lock_init(&pdev->dev_lock);
-
-- pdev->sh_area = NULL;
- pdev->sh_info = NULL;
- pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
- pdev->be_watching = 0;
-@@ -59,7 +59,7 @@ static void pciback_disconnect(struct pciback_device *pdev)
- flush_workqueue(pciback_wq);
-
- if (pdev->sh_info != NULL) {
-- xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
-+ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
- pdev->sh_info = NULL;
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 58dfbd2..aa094af 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -218,7 +218,11 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+ len -= copy;
}
-@@ -85,23 +85,23 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
- int remote_evtchn)
- {
- int err = 0;
-- struct vm_struct *area;
-+ void *vaddr;
-
- dev_dbg(&pdev->xdev->dev,
- "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
- gnt_ref, remote_evtchn);
-
-- area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
-- if (IS_ERR(area)) {
-- err = PTR_ERR(area);
-+ err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr);
-+ if (err < 0) {
-+ xenbus_dev_fatal(pdev->xdev, err,
-+ "Error mapping other domain page in ours.");
- goto out;
- }
-- pdev->sh_area = area;
-- pdev->sh_info = area->addr;
-+ pdev->sh_info = vaddr;
++#ifdef NET_SKBUFF_DATA_USES_OFFSET
++ offset = 0;
++#else
+ offset = nskb->data - skb->data;
++#endif
- err = bind_interdomain_evtchn_to_irqhandler(
- pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
-- SA_SAMPLE_RANDOM, "pciback", pdev);
-+ 0, "pciback", pdev);
- if (err < 0) {
- xenbus_dev_fatal(pdev->xdev, err,
- "Error binding event channel to IRQ");
+ nskb->transport_header = skb->transport_header + offset;
+ nskb->network_header = skb->network_header + offset;
--
1.7.4
-From 6e86fcb926e41fb55f512972603e5aaf77e2efb8 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:30 -0400
-Subject: [PATCH 012/244] xen-pciback: Add check to load only under priviliged domain.
+From 7d3e6e42251f179e407fa5236f613e5500b3a3ea Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 11 Jun 2010 10:51:01 +0100
+Subject: [PATCH 044/203] xen: netback: drop frag member from struct netbk_rx_meta
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/pci_stub.c | 5 +++++
- drivers/xen/pciback/xenbus.c | 2 --
- 2 files changed, 5 insertions(+), 2 deletions(-)
+It has been unused since c3219dc "xen/netback: completely drop flip
+support", as has netbk_free_pages().
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index c02f21f..d97dac5 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -14,6 +14,8 @@
- #include <linux/wait.h>
- #include <asm/atomic.h>
- #include <xen/events.h>
-+#include <asm/xen/pci.h>
-+#include <asm/xen/hypervisor.h>
- #include "pciback.h"
- #include "conf_space.h"
- #include "conf_space_quirks.h"
-@@ -1286,6 +1288,9 @@ static int __init pciback_init(void)
- {
- int err;
-
-+ if (!xen_initial_domain())
-+ return -ENODEV;
-+
- err = pciback_config_init();
- if (err)
- return err;
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index 5be1350..a85c413 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -693,8 +693,6 @@ static struct xenbus_driver xenbus_pciback_driver = {
-
- int __init pciback_xenbus_register(void)
- {
-- if (!is_running_on_xen())
-- return -ENODEV;
- pciback_wq = create_workqueue("pciback_workqueue");
- if (!pciback_wq) {
- printk(KERN_ERR "pciback_xenbus_register: create"
---
-1.7.4
-
-
-From c1139f912c1336538e51966d56e5905954052cba Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:31 -0400
-Subject: [PATCH 013/244] xen-pciback: Remove usage of pci_restore_bars() as Linux handles
the power-up states correctly now.
-
-Originally this code was pulled from the upstream kernel, and stuck
-in the linux-2.6-sparse tree. At that point of time, the Linux tree (2.6.16?)
-did not know how to handle this. Nowadays the pci_set_power_state routine
-handles this case so we do not need this anymore.
+(Although it now has only a single member struct netbk_rx_meta will
+gain other members in a subsequent patch so there is no point
+reworking to get rid of the struct)
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/conf_space_capability_pm.c | 13 -------------
- 1 files changed, 0 insertions(+), 13 deletions(-)
+ drivers/xen/netback/common.h | 1 -
+ drivers/xen/netback/netback.c | 8 --------
+ 2 files changed, 0 insertions(+), 9 deletions(-)
-diff --git a/drivers/xen/pciback/conf_space_capability_pm.c
b/drivers/xen/pciback/conf_space_capability_pm.c
-index e2f99c7..e1d3af4 100644
---- a/drivers/xen/pciback/conf_space_capability_pm.c
-+++ b/drivers/xen/pciback/conf_space_capability_pm.c
-@@ -58,19 +58,6 @@ static int pm_ctrl_write(struct pci_dev *dev, int offset, u16
new_value,
- goto out;
- }
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 36cb2b9..be4fe91 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -230,7 +230,6 @@ struct pending_tx_info {
+ typedef unsigned int pending_ring_idx_t;
-- /*
-- * Device may lose PCI config info on D3->D0 transition. This
-- * is a problem for some guests which will not reset BARs. Even
-- * those that have a go will be foiled by our BAR-write handler
-- * which will discard the write! Since Linux won't re-init
-- * the config space automatically in all cases, we do it here.
-- * Future: Should we re-initialise all first 64 bytes of config space?
-- */
-- if (new_state == PCI_D0 &&
-- (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
-- !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
-- pci_restore_bars(dev);
--
- out:
- return err;
+ struct netbk_rx_meta {
+- skb_frag_t frag;
+ int id;
+ };
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index aa094af..9f7e489 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -411,14 +411,6 @@ static void netbk_gop_skb(struct sk_buff *skb,
+ netif->rx.req_cons += nr_frags + extra;
}
+
+-static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
+-{
+- int i;
+-
+- for (i = 0; i < nr_frags; i++)
+- put_page(meta[i].frag.page);
+-}
+-
+ /* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
+ used to set up the operations on the top of
+ netrx_pending_operations, which have since been done. Check that
--
1.7.4
-From 721657d92623cfcf2f6f68c14abf97eb40fa6b20 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 13 Oct 2009 17:22:32 -0400
-Subject: [PATCH 014/244] xen-pciback: Enable Xen-PCI-back to be compiled.
+From 1ced27150d0092c40ebbbbb3896192003d433c0e Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 11 Jun 2010 10:51:01 +0100
+Subject: [PATCH 045/203] xen: netback: linearise SKBs as we copy them into guest memory
on guest-RX.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+There's no point in sending lots of little packets to a copying
+receiver if we can instead arrange to copy them all into a single RX
+buffer. We need to copy anyway, so there's no overhead here, and this
+is a little bit easier on the receiving domain's network stack.
+
+Based on a patch by Steven Smith. Fixed to not skip unnecessarily to
+the next buffer which could leave the head fragment of a received
+frame empty if the headlen of an SKB was large (which would crash
+netfront). Instead we only try and pack "small enough" fragments
+together but do not try to coalesce large or whole page fragments.
+
+In previous iterations of this patch we also tried to only include
+2048 bytes per frag because very old netfronts stored other
+information in the second half of the page. It has been determined
+that only frontends which support scatter-gather are going to come
+down this path and that any guest which supports scatter-gather is
+also new enough to allow us to use the full page size for each
+fragment (since this limitation which fixed as part of the SG
+implementation) so we do not need this restriction.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Steven Smith <Steven.Smith(a)eu.citrix.com>
---
- drivers/xen/Kconfig | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
- drivers/xen/Makefile | 1 +
- 2 files changed, 66 insertions(+), 0 deletions(-)
+ drivers/xen/netback/common.h | 15 ++-
+ drivers/xen/netback/netback.c | 282 ++++++++++++++++++++++++++++++-----------
+ 2 files changed, 218 insertions(+), 79 deletions(-)
-diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
-index 6e6180c..d874453 100644
---- a/drivers/xen/Kconfig
-+++ b/drivers/xen/Kconfig
-@@ -29,6 +29,71 @@ config XEN_DEV_EVTCHN
- Support for backend device drivers that provide I/O services
- to other virtual machines.
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index be4fe91..9c0c048 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -82,7 +82,9 @@ struct xen_netif {
+ /* Internal feature information. */
+ u8 can_queue:1; /* can queue packets for receiver? */
-+config XEN_PCIDEV_BACKEND
-+ tristate "PCI-device backend driver"
-+ depends on PCI
-+ depends on XEN_BACKEND
-+ help
-+ The PCI device backend driver allows the kernel to export arbitrary
-+ PCI devices to other guests. If you select this to be a module, you
-+ will need to make sure no other driver has bound to the device(s)
-+ you want to make visible to other guests.
+- /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
++ /* Allow netif_be_start_xmit() to peek ahead in the rx request
++ * ring. This is a prediction of what rx_req_cons will be once
++ * all queued skbs are put on the ring. */
+ RING_IDX rx_req_cons_peek;
+
+ /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
+@@ -231,6 +233,8 @@ typedef unsigned int pending_ring_idx_t;
+
+ struct netbk_rx_meta {
+ int id;
++ int size;
++ int gso_size;
+ };
+
+ struct netbk_tx_pending_inuse {
+@@ -240,6 +244,8 @@ struct netbk_tx_pending_inuse {
+
+ #define MAX_PENDING_REQS 256
+
++#define MAX_BUFFER_OFFSET PAGE_SIZE
+
-+choice
-+ prompt "PCI Backend Mode"
-+ depends on XEN_PCIDEV_BACKEND
-+ default XEN_PCIDEV_BACKEND_VPCI if !IA64
-+ default XEN_PCIDEV_BACKEND_CONTROLLER if IA64
+ /* extra field used in struct page */
+ union page_ext {
+ struct {
+@@ -301,7 +307,12 @@ struct xen_netbk {
+ 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];
++ /*
++ * Each head or fragment can be up to 4096 bytes. Given
++ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
++ * head/fragment uses 2 copy operation.
++ */
++ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
+ unsigned char rx_notify[NR_IRQS];
+ u16 notify_list[NET_RX_RING_SIZE];
+ struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 9f7e489..d53d88e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -259,6 +259,48 @@ static void tx_queue_callback(unsigned long data)
+ netif_wake_queue(netif->dev);
+ }
+
++/* Figure out how many ring slots we're going to need to send @skb to
++ the guest. */
++static unsigned count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
++{
++ unsigned count;
++ unsigned copy_off;
++ unsigned i;
+
-+config XEN_PCIDEV_BACKEND_VPCI
-+ bool "Virtual PCI"
-+ ---help---
-+ This PCI Backend hides the true PCI topology and makes the frontend
-+ think there is a single PCI bus with only the exported devices on it.
-+ For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
-+ second device at 02:1a.1 will be re-assigned to 00:01.1.
++ copy_off = 0;
++ count = 1;
+
-+config XEN_PCIDEV_BACKEND_PASS
-+ bool "Passthrough"
-+ ---help---
-+ This PCI Backend provides a real view of the PCI topology to the
-+ frontend (for example, a device at 06:01.b will still appear at
-+ 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
-+ PCI devices to its driver domains. This may be required for drivers
-+ which depend on finding their hardward in certain bus/slot
-+ locations.
++ BUG_ON(offset_in_page(skb->data) + skb_headlen(skb) > MAX_BUFFER_OFFSET);
+
-+config XEN_PCIDEV_BACKEND_SLOT
-+ bool "Slot"
-+ ---help---
-+ This PCI Backend hides the true PCI topology and makes the frontend
-+ think there is a single PCI bus with only the exported devices on it.
-+ Contrary to the virtual PCI backend, a function becomes a new slot.
-+ For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
-+ second device at 02:1a.1 will be re-assigned to 00:01.0.
++ copy_off = skb_headlen(skb);
+
-+config XEN_PCIDEV_BACKEND_CONTROLLER
-+ bool "Controller"
-+ depends on IA64
-+ ---help---
-+ This PCI backend virtualizes the PCI bus topology by providing a
-+ virtual bus per PCI root device. Devices which are physically under
-+ the same root bus will appear on the same virtual bus. For systems
-+ with complex I/O addressing, this is the only backend which supports
-+ extended I/O port spaces and MMIO translation offsets. This backend
-+ also supports slot virtualization. For example, a device at
-+ 0000:01:02.1 will be re-assigned to 0000:00:00.0. A second device
-+ at 0000:02:05.0 (behind a P2P bridge on bus 0000:01) will be
-+ re-assigned to 0000:00:01.0. A third device at 0000:16:05.0 (under
-+ a different PCI root bus) will be re-assigned to 0000:01:00.0.
++ if (skb_shinfo(skb)->gso_size)
++ count++;
+
-+endchoice
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++ unsigned long size = skb_shinfo(skb)->frags[i].size;
++ unsigned long bytes;
++ while (size > 0) {
++ BUG_ON(copy_off > MAX_BUFFER_OFFSET);
+
-+config XEN_PCIDEV_BE_DEBUG
-+ bool "PCI Backend Debugging"
-+ depends on XEN_PCIDEV_BACKEND
++ /* These checks are the same as in netbk_gop_frag_copy */
++ if (copy_off == MAX_BUFFER_OFFSET
++ || ((copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && copy_off)) {
++ count++;
++ copy_off = 0;
++ }
+
++ bytes = size;
++ if (copy_off + bytes > MAX_BUFFER_OFFSET)
++ bytes = MAX_BUFFER_OFFSET - copy_off;
+
- config XENFS
- tristate "Xen filesystem"
- default y
-diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
-index eb8a78d..3737dee 100644
---- a/drivers/xen/Makefile
-+++ b/drivers/xen/Makefile
-@@ -9,6 +9,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
- obj-$(CONFIG_XEN_BALLOON) += balloon.o
- obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
- obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
-+obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
- obj-$(CONFIG_XENFS) += xenfs/
- obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
- obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
---
-1.7.4
-
-
-From c164cd8577017d1c4e001b475fadddc7d2ff5c78 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 5 Nov 2009 15:25:43 -0500
-Subject: [PATCH 015/244] xen-pciback: Return the physical IRQ number instead of the
allocated IRQ number to pcifront.
-
-The allocation of IRQ numbers in Linux privileged domains is based
-on finding the first unbound IRQ number. After the allocation is done
-a HYPERCALL to Xen is done, which allocates a PIRQ globally.
-That PIRQ->IRQ binding is saved in data structures that are used
-during ISR executions.
-
-Before this patch, for non-privileged domains we would return the local
-IRQ number instead of the PIRQ. The non-privileged domains require the
-PIRQ so that they can attach the their own interrupt handler to it.
-Fortunatly there is a function, 'xen_gsi_from_irq' that returns
-that global IRQ number.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/conf_space_capability_msi.c | 12 ++++++++----
- 1 files changed, 8 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index 762e396..7fb5371 100644
---- a/drivers/xen/pciback/conf_space_capability_msi.c
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -6,6 +6,7 @@
- #include "conf_space.h"
- #include "conf_space_capability.h"
- #include <xen/interface/io/pciif.h>
-+#include <xen/events.h>
- #include "pciback.h"
-
- int pciback_enable_msi(struct pciback_device *pdev,
-@@ -22,7 +23,9 @@ int pciback_enable_msi(struct pciback_device *pdev,
- return XEN_PCI_ERR_op_failed;
++ copy_off += bytes;
++ size -= bytes;
++ }
++ }
++ return count;
++}
++
+ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct xen_netif *netif = netdev_priv(dev);
+@@ -290,8 +332,9 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ skb = nskb;
}
-- op->value = dev->irq;
-+ /* The value the guest needs is actually the IDT vector, not the
-+ * the local domain's IRQ number. */
-+ op->value = xen_gsi_from_irq(dev->irq);
- return 0;
- }
-
-@@ -31,7 +34,7 @@ int pciback_disable_msi(struct pciback_device *pdev,
- {
- pci_disable_msi(dev);
+- netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
+- !!skb_shinfo(skb)->gso_size;
++ /* Reserve ring slots for the worst-case number of
++ * fragments. */
++ netif->rx_req_cons_peek += count_skb_slots(skb, netif);
+ netif_get(netif);
-- op->value = dev->irq;
-+ op->value = xen_gsi_from_irq(dev->irq);
- return 0;
- }
+ if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
+@@ -335,96 +378,165 @@ struct netrx_pending_operations {
+ struct gnttab_copy *copy;
+ struct multicall_entry *mcl;
+ struct netbk_rx_meta *meta;
++ int copy_off;
++ grant_ref_t copy_gref;
+ };
-@@ -57,7 +60,8 @@ int pciback_enable_msix(struct pciback_device *pdev,
+ /* Set up the grant operations for this fragment. If it's a flipping
+ interface, we also set up the unmap request from here. */
+-static u16 netbk_gop_frag(struct xen_netif *netif, struct netbk_rx_meta *meta,
+- int i, struct netrx_pending_operations *npo,
+- struct page *page, unsigned long size,
+- unsigned long offset)
++
++static void netbk_gop_frag_copy(struct xen_netif *netif,
++ struct netrx_pending_operations *npo,
++ struct page *page, unsigned long size,
++ unsigned long offset, int head)
+ {
+ struct gnttab_copy *copy_gop;
+- struct xen_netif_rx_request *req;
+- unsigned long old_mfn;
++ struct netbk_rx_meta *meta;
+ int group = netif_page_group(page);
+ int idx = netif_page_index(page);
++ unsigned long bytes;
++
++ /* Data must not cross a page boundary. */
++ BUG_ON(size + offset > PAGE_SIZE);
- for (i = 0; i < op->value; i++) {
- op->msix_entries[i].entry = entries[i].entry;
-- op->msix_entries[i].vector = entries[i].vector;
-+ op->msix_entries[i].vector =
-+ xen_gsi_from_irq(entries[i].vector);
- }
+- old_mfn = virt_to_mfn(page_address(page));
++ meta = npo->meta + npo->meta_prod - 1;
- kfree(entries);
-@@ -73,7 +77,7 @@ int pciback_disable_msix(struct pciback_device *pdev,
+- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
++ while (size > 0) {
++ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
- pci_disable_msix(dev);
+- copy_gop = npo->copy + npo->copy_prod++;
+- copy_gop->flags = GNTCOPY_dest_gref;
+- if (PageForeign(page)) {
++ /*
++ * Move to a new receive buffer if:
++ *
++ * simple case: we have completely filled the current buffer.
++ *
++ * complex case: the current frag would overflow
++ * the current buffer but only if:
++ * (i) this frag would fit completely in the next buffer
++ * and (ii) there is already some data in the current buffer
++ * and (iii) this is not the head buffer.
++ *
++ * Where:
++ * - (i) stops us splitting a frag into two copies
++ * unless the frag is too large for a single buffer.
++ * - (ii) stops us from leaving a buffer pointlessly empty.
++ * - (iii) stops us leaving the first buffer
++ * empty. Strictly speaking this is already covered
++ * by (ii) but is explicitly checked because
++ * netfront relies on the first buffer being
++ * non-empty and can crash otherwise.
++ *
++ * This means we will effectively linearise small
++ * frags but do not needlessly split large buffers
++ * into multiple copies tend to give large frags their
++ * own buffers as before.
++ */
++ if (npo->copy_off == MAX_BUFFER_OFFSET
++ || ((npo->copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && npo->copy_off && !head)) {
++ struct xen_netif_rx_request *req;
++
++ BUG_ON(head); /* Netfront requires there to be some data in the head buffer. */
++ /* Overflowed this request, go to the next one */
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
++ meta = npo->meta + npo->meta_prod++;
++ meta->size = 0;
++ meta->id = req->id;
++ npo->copy_off = 0;
++ npo->copy_gref = req->gref;
++ }
++
++ bytes = size;
++ if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
++ bytes = MAX_BUFFER_OFFSET - npo->copy_off;
++
++ copy_gop = npo->copy + npo->copy_prod++;
++ copy_gop->flags = GNTCOPY_dest_gref;
++ if (PageForeign(page)) {
+ struct xen_netbk *netbk = &xen_netbk[group];
+ struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
+ copy_gop->source.domid = src_pend->netif->domid;
+ copy_gop->source.u.ref = src_pend->req.gref;
+- copy_gop->flags |= GNTCOPY_source_gref;
+- } else {
+- copy_gop->source.domid = DOMID_SELF;
+- copy_gop->source.u.gmfn = old_mfn;
+- }
+- copy_gop->source.offset = offset;
+- copy_gop->dest.domid = netif->domid;
+- copy_gop->dest.offset = 0;
+- copy_gop->dest.u.ref = req->gref;
+- copy_gop->len = size;
++ copy_gop->flags |= GNTCOPY_source_gref;
++ } else {
++ copy_gop->source.domid = DOMID_SELF;
++ copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
++ }
++ copy_gop->source.offset = offset;
++ copy_gop->dest.domid = netif->domid;
-- op->value = dev->irq;
-+ op->value = xen_gsi_from_irq(dev->irq);
- return 0;
+- return req->id;
++ copy_gop->dest.offset = npo->copy_off;
++ copy_gop->dest.u.ref = npo->copy_gref;
++ copy_gop->len = bytes;
++
++ npo->copy_off += bytes;
++ meta->size += bytes;
++
++ offset += bytes;
++ size -= bytes;
++ head = 0; /* Must be something in this buffer now */
++ }
}
---
-1.7.4
-
-
-From b0b035f1de3282aa96a6dc28007d513e8fce793d Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 5 Nov 2009 15:25:44 -0500
-Subject: [PATCH 016/244] xen-pciback: Fix checkpatch warnings and errors for pciback/
directory.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/conf_space.c | 34 +++---
- drivers/xen/pciback/conf_space.h | 30 ++--
- drivers/xen/pciback/conf_space_capability.c | 5 +-
- drivers/xen/pciback/conf_space_capability.h | 3 +
- drivers/xen/pciback/conf_space_capability_msi.c | 3 +-
- drivers/xen/pciback/conf_space_capability_pm.c | 4 +-
- drivers/xen/pciback/conf_space_capability_vpd.c | 2 +-
- drivers/xen/pciback/conf_space_header.c | 7 +-
- drivers/xen/pciback/conf_space_quirks.c | 16 ++-
- drivers/xen/pciback/controller.c | 15 +-
- drivers/xen/pciback/passthrough.c | 6 +-
- drivers/xen/pciback/pci_stub.c | 165 +++++++++++------------
- drivers/xen/pciback/pciback.h | 28 +++--
- drivers/xen/pciback/pciback_ops.c | 74 +++++------
- drivers/xen/pciback/slot.c | 22 ++--
- drivers/xen/pciback/vpci.c | 28 ++--
- drivers/xen/pciback/xenbus.c | 42 +++---
- 17 files changed, 245 insertions(+), 239 deletions(-)
-
-diff --git a/drivers/xen/pciback/conf_space.c b/drivers/xen/pciback/conf_space.c
-index 0c76db1..370c18e 100644
---- a/drivers/xen/pciback/conf_space.c
-+++ b/drivers/xen/pciback/conf_space.c
-@@ -18,11 +18,11 @@
- static int permissive;
- module_param(permissive, bool, 0644);
+-static void netbk_gop_skb(struct sk_buff *skb,
+- struct netrx_pending_operations *npo)
++/* Prepare an SKB to be transmitted to the frontend. This is
++ responsible for allocating grant operations, meta structures, etc.
++ It returns the number of meta structures consumed. The number of
++ ring slots used is always equal to the number of meta slots used
++ plus the number of GSO descriptors used. Currently, we use either
++ zero GSO descriptors (for non-GSO packets) or one descriptor (for
++ frontend-side LRO). */
++static int netbk_gop_skb(struct sk_buff *skb,
++ struct netrx_pending_operations *npo)
+ {
+ struct xen_netif *netif = netdev_priv(skb->dev);
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
+- int extra;
+- struct netbk_rx_meta *head_meta, *meta;
++ struct xen_netif_rx_request *req;
++ struct netbk_rx_meta *meta;
++ int old_meta_prod;
++
++ old_meta_prod = npo->meta_prod;
--#define DEFINE_PCI_CONFIG(op,size,type) \
-+#define DEFINE_PCI_CONFIG(op, size, type) \
- int pciback_##op##_config_##size \
- (struct pci_dev *dev, int offset, type value, void *data) \
- { \
-- return pci_##op##_config_##size (dev, offset, value); \
-+ return pci_##op##_config_##size(dev, offset, value); \
- }
+- head_meta = npo->meta + npo->meta_prod++;
+- head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
+- head_meta->frag.size = skb_shinfo(skb)->gso_size;
+- extra = !!head_meta->frag.size + 1;
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
++ meta = npo->meta + npo->meta_prod++;
++ meta->gso_size = skb_shinfo(skb)->gso_size;
++ meta->size = 0;
++ meta->id = req->id;
++ npo->copy_off = 0;
++ npo->copy_gref = req->gref;
++
++ netbk_gop_frag_copy(netif,
++ npo, virt_to_page(skb->data),
++ skb_headlen(skb),
++ offset_in_page(skb->data), 1);
++
++ /* Leave a gap for the GSO descriptor. */
++ if (skb_shinfo(skb)->gso_size)
++ netif->rx.req_cons++;
- DEFINE_PCI_CONFIG(read, byte, u8 *)
-@@ -139,14 +139,15 @@ static int pcibios_err_to_errno(int err)
+ for (i = 0; i < nr_frags; i++) {
+- meta = npo->meta + npo->meta_prod++;
+- meta->frag = skb_shinfo(skb)->frags[i];
+- meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
+- meta->frag.page,
+- meta->frag.size,
+- meta->frag.page_offset);
++ netbk_gop_frag_copy(netif, npo,
++ skb_shinfo(skb)->frags[i].page,
++ skb_shinfo(skb)->frags[i].size,
++ skb_shinfo(skb)->frags[i].page_offset,
++ 0);
+ }
+
+- /*
+- * This must occur at the end to ensure that we don't trash skb_shinfo
+- * until we're done. We know that the head doesn't cross a page
+- * boundary because such packets get copied in netif_be_start_xmit.
+- */
+- head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
+- virt_to_page(skb->data),
+- skb_headlen(skb),
+- offset_in_page(skb->data));
+-
+- netif->rx.req_cons += nr_frags + extra;
++ return npo->meta_prod - old_meta_prod;
}
- int pciback_config_read(struct pci_dev *dev, int offset, int size,
-- u32 * ret_val)
-+ u32 *ret_val)
+ /* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
+ used to set up the operations on the top of
+ netrx_pending_operations, which have since been done. Check that
+ they didn't give any errors and advance over them. */
+-static int netbk_check_gop(int nr_frags, domid_t domid,
++static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+ struct netrx_pending_operations *npo)
{
- int err = 0;
- struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
- const struct config_field_entry *cfg_entry;
- const struct config_field *field;
- int req_start, req_end, field_start, field_end;
-- /* if read fails for any reason, return 0 (as if device didn't respond) */
-+ /* if read fails for any reason, return 0
-+ * (as if device didn't respond) */
- u32 value = 0, tmp_val;
-
- if (unlikely(verbose_request))
-@@ -161,10 +162,10 @@ int pciback_config_read(struct pci_dev *dev, int offset, int size,
- /* Get the real value first, then modify as appropriate */
- switch (size) {
- case 1:
-- err = pci_read_config_byte(dev, offset, (u8 *) & value);
-+ err = pci_read_config_byte(dev, offset, (u8 *) &value);
- break;
- case 2:
-- err = pci_read_config_word(dev, offset, (u16 *) & value);
-+ err = pci_read_config_word(dev, offset, (u16 *) &value);
- break;
- case 4:
- err = pci_read_config_dword(dev, offset, &value);
-@@ -192,7 +193,7 @@ int pciback_config_read(struct pci_dev *dev, int offset, int size,
- }
- }
+ struct gnttab_copy *copy_op;
+ int status = NETIF_RSP_OKAY;
+ int i;
-- out:
-+out:
- if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
- pci_name(dev), size, offset, value);
-@@ -276,8 +277,8 @@ int pciback_config_write(struct pci_dev *dev, int offset, int size,
u32 value)
- } else if (!dev_data->warned_on_write) {
- dev_data->warned_on_write = 1;
- dev_warn(&dev->dev, "Driver tried to write to a "
-- "read-only configuration space field at offset "
-- "0x%x, size %d. This may be harmless, but if "
-+ "read-only configuration space field at offset"
-+ " 0x%x, size %d. This may be harmless, but if "
- "you have problems with your device:\n"
- "1) see permissive attribute in sysfs\n"
- "2) report problems to the xen-devel "
-@@ -295,8 +296,8 @@ void pciback_config_free_dyn_fields(struct pci_dev *dev)
- struct config_field_entry *cfg_entry, *t;
- const struct config_field *field;
+- for (i = 0; i <= nr_frags; i++) {
+- copy_op = npo->copy + npo->copy_cons++;
+- if (copy_op->status != GNTST_okay) {
++ for (i = 0; i < nr_meta_slots; i++) {
++ copy_op = npo->copy + npo->copy_cons++;
++ if (copy_op->status != GNTST_okay) {
+ DPRINTK("Bad status %d from copy to DOM%d.\n",
+ copy_op->status, domid);
+ status = NETIF_RSP_ERROR;
+@@ -435,27 +547,35 @@ static int netbk_check_gop(int nr_frags, domid_t domid,
+ }
-- dev_dbg(&dev->dev,
-- "free-ing dynamically allocated virtual configuration space fields\n");
-+ dev_dbg(&dev->dev, "free-ing dynamically allocated virtual "
-+ "configuration space fields\n");
- if (!dev_data)
- return;
+ static void netbk_add_frag_responses(struct xen_netif *netif, int status,
+- struct netbk_rx_meta *meta, int nr_frags)
++ struct netbk_rx_meta *meta,
++ int nr_meta_slots)
+ {
+ int i;
+ unsigned long offset;
-@@ -306,8 +307,7 @@ void pciback_config_free_dyn_fields(struct pci_dev *dev)
- if (field->clean) {
- field->clean((struct config_field *)field);
+- for (i = 0; i < nr_frags; i++) {
+- int id = meta[i].id;
+- int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
+-
++ for (i = 0; i < nr_meta_slots; i++) {
++ int flags;
++ if (i == nr_meta_slots - 1)
++ flags = 0;
++ else
++ flags = NETRXF_more_data;
++
+ offset = 0;
+- make_rx_response(netif, id, status, offset,
+- meta[i].frag.size, flags);
++ make_rx_response(netif, meta[i].id, status, offset,
++ meta[i].size, flags);
+ }
+ }
-- if (cfg_entry->data)
-- kfree(cfg_entry->data);
-+ kfree(cfg_entry->data);
++struct skb_cb_overlay {
++ int meta_slots_used;
++};
++
+ static void net_rx_action(unsigned long data)
+ {
+ struct xen_netif *netif = NULL;
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ s8 status;
+- u16 id, irq, flags;
++ u16 irq, flags;
+ struct xen_netif_rx_response *resp;
+ struct multicall_entry *mcl;
+ struct sk_buff_head rxq;
+@@ -465,6 +585,7 @@ static void net_rx_action(unsigned long data)
+ int nr_frags;
+ int count;
+ unsigned long offset;
++ struct skb_cb_overlay *sco;
- list_del(&cfg_entry->list);
- kfree(cfg_entry);
-@@ -376,7 +376,7 @@ int pciback_config_add_field_offset(struct pci_dev *dev,
- cfg_entry->base_offset = base_offset;
+ struct netrx_pending_operations npo = {
+ .mmu = netbk->rx_mmu,
+@@ -479,10 +600,11 @@ static void net_rx_action(unsigned long data)
+ count = 0;
- /* silently ignore duplicate fields */
-- err = pciback_field_is_dup(dev,OFFSET(cfg_entry));
-+ err = pciback_field_is_dup(dev, OFFSET(cfg_entry));
- if (err)
- goto out;
+ while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
++ netif = netdev_priv(skb->dev);
+ nr_frags = skb_shinfo(skb)->nr_frags;
+- *(int *)skb->cb = nr_frags;
-@@ -395,14 +395,14 @@ int pciback_config_add_field_offset(struct pci_dev *dev,
- OFFSET(cfg_entry));
- list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+- netbk_gop_skb(skb, &npo);
++ sco = (struct skb_cb_overlay *)skb->cb;
++ sco->meta_slots_used = netbk_gop_skb(skb, &npo);
-- out:
-+out:
- if (err)
- kfree(cfg_entry);
+ count += nr_frags + 1;
- return err;
- }
+@@ -541,18 +663,20 @@ static void net_rx_action(unsigned long data)
+ BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
--/* This sets up the device's virtual configuration space to keep track of
-+/* This sets up the device's virtual configuration space to keep track of
- * certain registers (like the base address registers (BARs) so that we can
- * keep the client from manipulating them directly.
- */
-@@ -425,7 +425,7 @@ int pciback_config_init_dev(struct pci_dev *dev)
+ while ((skb = __skb_dequeue(&rxq)) != NULL) {
+- nr_frags = *(int *)skb->cb;
++ sco = (struct skb_cb_overlay *)skb->cb;
- err = pciback_config_quirks_init(dev);
+ netif = netdev_priv(skb->dev);
-- out:
-+out:
- return err;
- }
+ netif->stats.tx_bytes += skb->len;
+ netif->stats.tx_packets++;
-diff --git a/drivers/xen/pciback/conf_space.h b/drivers/xen/pciback/conf_space.h
-index fe746ef..50ebef2 100644
---- a/drivers/xen/pciback/conf_space.h
-+++ b/drivers/xen/pciback/conf_space.h
-@@ -11,21 +11,21 @@
- #include <linux/err.h>
+- status = netbk_check_gop(nr_frags, netif->domid, &npo);
+-
+- id = netbk->meta[npo.meta_cons].id;
+- flags = nr_frags ? NETRXF_more_data : 0;
++ status = netbk_check_gop(sco->meta_slots_used,
++ netif->domid, &npo);
- /* conf_field_init can return an errno in a ptr with ERR_PTR() */
--typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
--typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
--typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
-+typedef void *(*conf_field_init) (struct pci_dev *dev, int offset);
-+typedef void (*conf_field_reset) (struct pci_dev *dev, int offset, void *data);
-+typedef void (*conf_field_free) (struct pci_dev *dev, int offset, void *data);
++ if (sco->meta_slots_used == 1)
++ flags = 0;
++ else
++ flags = NETRXF_more_data;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+ flags |= NETRXF_csum_blank | NETRXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+@@ -560,10 +684,12 @@ static void net_rx_action(unsigned long data)
+ flags |= NETRXF_data_validated;
--typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
-+typedef int (*conf_dword_write) (struct pci_dev *dev, int offset, u32 value,
- void *data);
--typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
-+typedef int (*conf_word_write) (struct pci_dev *dev, int offset, u16 value,
- void *data);
--typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
-+typedef int (*conf_byte_write) (struct pci_dev *dev, int offset, u8 value,
- void *data);
--typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
-+typedef int (*conf_dword_read) (struct pci_dev *dev, int offset, u32 *value,
- void *data);
--typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
-+typedef int (*conf_word_read) (struct pci_dev *dev, int offset, u16 *value,
- void *data);
--typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
-+typedef int (*conf_byte_read) (struct pci_dev *dev, int offset, u8 *value,
- void *data);
+ offset = 0;
+- resp = make_rx_response(netif, id, status, offset,
+- skb_headlen(skb), flags);
++ resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
++ status, offset,
++ netbk->meta[npo.meta_cons].size,
++ flags);
- /* These are the fields within the configuration space which we
-@@ -39,7 +39,7 @@ struct config_field {
- conf_field_init init;
- conf_field_reset reset;
- conf_field_free release;
-- void (*clean) (struct config_field * field);
-+ void (*clean) (struct config_field *field);
- union {
- struct {
- conf_dword_write write;
-@@ -92,8 +92,8 @@ static inline int pciback_config_add_fields(struct pci_dev *dev,
- }
+- if (netbk->meta[npo.meta_cons].frag.size) {
++ if (netbk->meta[npo.meta_cons].gso_size) {
+ struct xen_netif_extra_info *gso =
+ (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&netif->rx,
+@@ -571,7 +697,7 @@ static void net_rx_action(unsigned long data)
- static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
-- const struct config_field *field,
-- unsigned int offset)
-+ const struct config_field *field,
-+ unsigned int offset)
- {
- int i, err = 0;
- for (i = 0; field[i].size != 0; i++) {
-@@ -105,11 +105,11 @@ static inline int pciback_config_add_fields_offset(struct pci_dev
*dev,
- }
+ resp->flags |= NETRXF_extra_info;
- /* Read/Write the real configuration space */
--int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
-+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 *value,
- void *data);
--int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
-+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 *value,
- void *data);
--int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
-+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 *value,
- void *data);
- int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
- void *data);
-diff --git a/drivers/xen/pciback/conf_space_capability.c
b/drivers/xen/pciback/conf_space_capability.c
-index 50efca4..0ea84d6 100644
---- a/drivers/xen/pciback/conf_space_capability.c
-+++ b/drivers/xen/pciback/conf_space_capability.c
-@@ -53,13 +53,10 @@ int pciback_config_capability_add_fields(struct pci_dev *dev)
+- gso->u.gso.size = netbk->meta[npo.meta_cons].frag.size;
++ gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+ gso->u.gso.pad = 0;
+ gso->u.gso.features = 0;
+@@ -580,9 +706,11 @@ static void net_rx_action(unsigned long data)
+ gso->flags = 0;
}
- }
-
-- out:
-+out:
- return err;
- }
--extern struct pciback_config_capability pciback_config_capability_vpd;
--extern struct pciback_config_capability pciback_config_capability_pm;
--
- int pciback_config_capability_init(void)
- {
- register_capability(&pciback_config_capability_vpd);
-diff --git a/drivers/xen/pciback/conf_space_capability.h
b/drivers/xen/pciback/conf_space_capability.h
-index 823392e..8da3ac4 100644
---- a/drivers/xen/pciback/conf_space_capability.h
-+++ b/drivers/xen/pciback/conf_space_capability.h
-@@ -20,4 +20,7 @@ struct pciback_config_capability {
- const struct config_field *fields;
- };
+- netbk_add_frag_responses(netif, status,
+- netbk->meta + npo.meta_cons + 1,
+- nr_frags);
++ if (sco->meta_slots_used > 1) {
++ netbk_add_frag_responses(netif, status,
++ netbk->meta + npo.meta_cons + 1,
++ sco->meta_slots_used - 1);
++ }
-+extern struct pciback_config_capability pciback_config_capability_vpd;
-+extern struct pciback_config_capability pciback_config_capability_pm;
-+
- #endif
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index 7fb5371..b70ea8b 100644
---- a/drivers/xen/pciback/conf_space_capability_msi.c
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -18,7 +18,8 @@ int pciback_enable_msi(struct pciback_device *pdev,
- status = pci_enable_msi(dev);
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
+ irq = netif->irq;
+@@ -597,8 +725,8 @@ static void net_rx_action(unsigned long data)
+ netif_wake_queue(netif->dev);
- if (status) {
-- printk("error enable msi for guest %x status %x\n", otherend, status);
-+ printk(KERN_ERR "error enable msi for guest %x status %x\n",
-+ otherend, status);
- op->value = 0;
- return XEN_PCI_ERR_op_failed;
+ netif_put(netif);
++ npo.meta_cons += sco->meta_slots_used;
+ dev_kfree_skb(skb);
+- npo.meta_cons += nr_frags + 1;
}
-diff --git a/drivers/xen/pciback/conf_space_capability_pm.c
b/drivers/xen/pciback/conf_space_capability_pm.c
-index e1d3af4..0442616 100644
---- a/drivers/xen/pciback/conf_space_capability_pm.c
-+++ b/drivers/xen/pciback/conf_space_capability_pm.c
-@@ -20,7 +20,7 @@ static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
-
- *value = real_value & ~PCI_PM_CAP_PME_MASK;
-
-- out:
-+out:
- return err;
- }
-@@ -77,7 +77,7 @@ static void *pm_ctrl_init(struct pci_dev *dev, int offset)
- err = pci_write_config_word(dev, offset, value);
+ while (notify_nr != 0) {
+--
+1.7.4
+
+
+From 96069b28e612232fb739ef48d9c2c5178b19f562 Mon Sep 17 00:00:00 2001
+From: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Date: Thu, 10 Jun 2010 19:03:15 +0800
+Subject: [PATCH 046/203] xen: netback: Set allocated memory to zero from vmalloc.
+
+This should fix the windows/linux pv driver issue.
+
+Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index d53d88e..c7024d4 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1724,6 +1724,7 @@ static int __init netback_init(void)
+ printk(KERN_ALERT "%s: out of memory\n", __func__);
+ return -ENOMEM;
}
++ memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
-- out:
-+out:
- return ERR_PTR(err);
- }
+ /* We can increase reservation by this much in net_rx_action(). */
+ // balloon_update_driver_allowance(NET_RX_RING_SIZE);
+--
+1.7.4
+
+
+From 109a748d1c11b7eeaaacedb08c48bc65640b0bb8 Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Mon, 14 Jun 2010 13:23:33 +0100
+Subject: [PATCH 047/203] xen: netback: minor code formatting fixup
+
+Don't include redundant casts from allocation.
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index c7024d4..58e920a 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1718,8 +1718,7 @@ static int __init netback_init(void)
+ return -ENODEV;
-diff --git a/drivers/xen/pciback/conf_space_capability_vpd.c
b/drivers/xen/pciback/conf_space_capability_vpd.c
-index 920cb4a..e7b4d66 100644
---- a/drivers/xen/pciback/conf_space_capability_vpd.c
-+++ b/drivers/xen/pciback/conf_space_capability_vpd.c
-@@ -33,7 +33,7 @@ static const struct config_field caplist_vpd[] = {
- },
- {}
- };
--
-+
- struct pciback_config_capability pciback_config_capability_vpd = {
- .capability = PCI_CAP_ID_VPD,
- .fields = caplist_vpd,
-diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
-index 5a9e028..3ae7da1 100644
---- a/drivers/xen/pciback/conf_space_header.c
-+++ b/drivers/xen/pciback/conf_space_header.c
-@@ -51,7 +51,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value,
void *data)
- err = pci_set_mwi(dev);
- if (err) {
- printk(KERN_WARNING
-- "pciback: %s: cannot enable memory-write-invalidate (%d)\n",
-+ "pciback: %s: cannot enable "
-+ "memory-write-invalidate (%d)\n",
- pci_name(dev), err);
- value &= ~PCI_COMMAND_INVALIDATE;
- }
-@@ -206,7 +207,7 @@ static int bist_write(struct pci_dev *dev, int offset, u8 value, void
*data)
- || value == PCI_BIST_START)
- err = pci_write_config_byte(dev, offset, value);
-
-- out:
-+out:
- return err;
- }
-
-@@ -312,6 +313,6 @@ int pciback_config_header_add_fields(struct pci_dev *dev)
- break;
- }
+ xen_netbk_group_nr = num_online_cpus();
+- xen_netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk) *
+- xen_netbk_group_nr);
++ xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
+ if (!xen_netbk) {
+ printk(KERN_ALERT "%s: out of memory\n", __func__);
+ return -ENOMEM;
+--
+1.7.4
+
+
+From 2424b59d68ee6ccdb7e52ab68bdba3a8b742513d Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 30 Jun 2010 10:12:49 +0100
+Subject: [PATCH 048/203] xen: netback: drop more relics of flipping mode
+
+The mmu_update and gnttab_transfer arrays were only used by flipping
+mode. With those gone the multicall now consists of a single call to
+GNTTABOP_copy so drop the multicall as well and just make the one
+hypercall.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: Paul Durrant <paul.durrant(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 3 --
+ drivers/xen/netback/netback.c | 55 +++--------------------------------------
+ 2 files changed, 4 insertions(+), 54 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 9c0c048..08e7a0e 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -304,9 +304,6 @@ struct xen_netbk {
+ u16 pending_ring[MAX_PENDING_REQS];
+ u16 dealloc_ring[MAX_PENDING_REQS];
-- out:
-+out:
- return err;
- }
-diff --git a/drivers/xen/pciback/conf_space_quirks.c
b/drivers/xen/pciback/conf_space_quirks.c
-index 244a438..45c31fb 100644
---- a/drivers/xen/pciback/conf_space_quirks.c
-+++ b/drivers/xen/pciback/conf_space_quirks.c
-@@ -18,8 +18,10 @@ match_one_device(const struct pci_device_id *id, const struct pci_dev
*dev)
- {
- if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
- (id->device == PCI_ANY_ID || id->device == dev->device) &&
-- (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor)
&&
-- (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device)
&&
-+ (id->subvendor == PCI_ANY_ID ||
-+ id->subvendor == dev->subsystem_vendor) &&
-+ (id->subdevice == PCI_ANY_ID ||
-+ id->subdevice == dev->subsystem_device) &&
- !((id->class ^ dev->class) & id->class_mask))
- return id;
- return NULL;
-@@ -35,7 +37,7 @@ struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
- tmp_quirk = NULL;
- printk(KERN_DEBUG
- "quirk didn't match any device pciback knows about\n");
-- out:
-+out:
- return tmp_quirk;
+- 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];
+ /*
+ * Each head or fragment can be up to 4096 bytes. Given
+ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 58e920a..ca65840 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -368,15 +368,9 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
}
-@@ -51,7 +53,7 @@ int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg)
- struct config_field_entry *cfg_entry;
-
- list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-- if ( OFFSET(cfg_entry) == reg) {
-+ if (OFFSET(cfg_entry) == reg) {
- ret = 1;
- break;
- }
-@@ -84,7 +86,7 @@ int pciback_config_quirks_add_field(struct pci_dev *dev, struct
config_field
+ struct netrx_pending_operations {
+- unsigned trans_prod, trans_cons;
+- unsigned mmu_prod, mmu_mcl;
+- unsigned mcl_prod, mcl_cons;
+ unsigned copy_prod, copy_cons;
+ unsigned meta_prod, meta_cons;
+- struct mmu_update *mmu;
+- struct gnttab_transfer *trans;
+ struct gnttab_copy *copy;
+- struct multicall_entry *mcl;
+ struct netbk_rx_meta *meta;
+ int copy_off;
+ grant_ref_t copy_gref;
+@@ -577,7 +571,6 @@ static void net_rx_action(unsigned long data)
+ s8 status;
+ u16 irq, flags;
+ struct xen_netif_rx_response *resp;
+- struct multicall_entry *mcl;
+ struct sk_buff_head rxq;
+ struct sk_buff *skb;
+ int notify_nr = 0;
+@@ -588,10 +581,7 @@ static void net_rx_action(unsigned long data)
+ struct skb_cb_overlay *sco;
- pciback_config_add_field(dev, field);
+ struct netrx_pending_operations npo = {
+- .mmu = netbk->rx_mmu,
+- .trans = netbk->grant_trans_op,
+ .copy = netbk->grant_copy_op,
+- .mcl = netbk->rx_mcl,
+ .meta = netbk->meta,
+ };
-- out:
-+out:
- return err;
- }
+@@ -617,50 +607,13 @@ static void net_rx_action(unsigned long data)
-@@ -110,7 +112,7 @@ int pciback_config_quirks_init(struct pci_dev *dev)
- quirk->pdev = dev;
+ BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
- register_quirk(quirk);
-- out:
-+out:
- return ret;
- }
+- 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(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)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(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)netbk->grant_trans_op;
+- mcl->args[2] = npo.trans_prod;
+- }
+-
+- if (npo.copy_prod) {
+- 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)netbk->grant_copy_op;
+- mcl->args[2] = npo.copy_prod;
+- }
+-
+- /* Nothing to do? */
+- if (!npo.mcl_prod)
++ if (!npo.copy_prod)
+ return;
-@@ -133,6 +135,6 @@ int pciback_config_quirk_release(struct pci_dev *dev)
- list_del(&quirk->quirks_list);
- kfree(quirk);
+- BUG_ON(npo.mcl_prod > ARRAY_SIZE(netbk->rx_mcl));
+-
+- ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
++ BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
++ npo.copy_prod);
+ BUG_ON(ret != 0);
+- /* The mmu_machphys_update() must not fail. */
+- BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
-- out:
-+out:
- return ret;
- }
-diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
-index 294e48f..7f04f11 100644
---- a/drivers/xen/pciback/controller.c
-+++ b/drivers/xen/pciback/controller.c
-@@ -259,7 +259,7 @@ static acpi_status write_xenbus_resource(struct acpi_resource *res,
void *data)
- !(addr.resource_type == ACPI_IO_RANGE &&
- addr.info.io.translation))
- return AE_OK;
--
+ while ((skb = __skb_dequeue(&rxq)) != NULL) {
+ sco = (struct skb_cb_overlay *)skb->cb;
+--
+1.7.4
+
+
+From 673a19d9e2d78939c6dc9c49e7e35ee54b54c8c7 Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Fri, 2 Jul 2010 10:28:11 +0100
+Subject: [PATCH 049/203] xen: netback: Fix basic indentation issue
+
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 11 +++++++----
+ 1 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index ca65840..848503e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -445,10 +445,13 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ copy_gop = npo->copy + npo->copy_prod++;
+ copy_gop->flags = GNTCOPY_dest_gref;
+ if (PageForeign(page)) {
+- struct xen_netbk *netbk = &xen_netbk[group];
+- struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
+- copy_gop->source.domid = src_pend->netif->domid;
+- copy_gop->source.u.ref = src_pend->req.gref;
++ struct xen_netbk *netbk = &xen_netbk[group];
++ struct pending_tx_info *src_pend;
+
- /* Store the resource in xenbus for the guest */
- len = snprintf(str, sizeof(str), "root-%d-resource-%d",
- info->root_num, info->resource_count);
-@@ -314,7 +314,7 @@ int pciback_publish_pci_roots(struct pciback_device *pdev,
- goto out;
-
- /*
-- * Now figure out which root-%d this belongs to
-+ * Now figure out which root-%d this belongs to
- * so we can associate resources with it.
- */
- err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-@@ -407,8 +407,8 @@ void pciback_release_devices(struct pciback_device *pdev)
- pdev->pci_dev_data = NULL;
- }
-
--int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-- struct pciback_device *pdev,
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-+ struct pciback_device *pdev,
- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
- {
- struct controller_dev_data *dev_data = pdev->pci_dev_data;
-@@ -420,13 +420,12 @@ int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-
- list_for_each_entry(cntrl_entry, &dev_data->list, list) {
- list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
-- if ( (dev_entry->dev->bus->number ==
-+ if ((dev_entry->dev->bus->number ==
- pcidev->bus->number) &&
-- (dev_entry->dev->devfn ==
-+ (dev_entry->dev->devfn ==
- pcidev->devfn) &&
- (pci_domain_nr(dev_entry->dev->bus) ==
-- pci_domain_nr(pcidev->bus)))
-- {
-+ pci_domain_nr(pcidev->bus))) {
- found = 1;
- *domain = cntrl_entry->domain;
- *bus = cntrl_entry->bus;
-diff --git a/drivers/xen/pciback/passthrough.c b/drivers/xen/pciback/passthrough.c
-index 9e7a0c4..5386bebf 100644
---- a/drivers/xen/pciback/passthrough.c
-+++ b/drivers/xen/pciback/passthrough.c
-@@ -165,8 +165,10 @@ void pciback_release_devices(struct pciback_device *pdev)
- pdev->pci_dev_data = NULL;
- }
++ src_pend = &netbk->pending_tx_info[idx];
++
++ copy_gop->source.domid = src_pend->netif->domid;
++ copy_gop->source.u.ref = src_pend->req.gref;
+ copy_gop->flags |= GNTCOPY_source_gref;
+ } else {
+ copy_gop->source.domid = DOMID_SELF;
+--
+1.7.4
+
+
+From d08b2d1f2ff4723b335d0fb5b91ffd6cb6a005d3 Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Mon, 5 Jul 2010 11:45:29 +0100
+Subject: [PATCH 050/203] xen: netback: Add a new style of passing GSO packets to
frontends.
+
+feature-gso-tcpv4-prefix uses precedes the packet data passed to
+the frontend with a ring entry that contains the necessary
+metadata. This style of GSO passing is required for Citrix
+Windows PV Drivers.
+
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Cc: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 3 ++-
+ drivers/xen/netback/netback.c | 37 ++++++++++++++++++++++++++++++++++---
+ drivers/xen/netback/xenbus.c | 15 ++++++++++++---
+ include/xen/interface/io/netif.h | 4 ++++
+ 4 files changed, 52 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 08e7a0e..78451ab 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -80,7 +80,8 @@ struct xen_netif {
+ int features;
--int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-+ struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus,
-+ unsigned int *devfn)
+ /* Internal feature information. */
+- u8 can_queue:1; /* can queue packets for receiver? */
++ u8 can_queue:1; /* can queue packets for receiver? */
++ u8 gso_prefix:1; /* use a prefix segment for GSO information */
- {
- *domain = pci_domain_nr(pcidev->bus);
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index d97dac5..28222ee 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -20,7 +20,7 @@
- #include "conf_space.h"
- #include "conf_space_quirks.h"
+ /* Allow netif_be_start_xmit() to peek ahead in the rx request
+ * ring. This is a prediction of what rx_req_cons will be once
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 848503e..e93a62e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -432,6 +432,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ /* Overflowed this request, go to the next one */
+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+ meta = npo->meta + npo->meta_prod++;
++ meta->gso_size = 0;
+ meta->size = 0;
+ meta->id = req->id;
+ npo->copy_off = 0;
+@@ -492,9 +493,23 @@ static int netbk_gop_skb(struct sk_buff *skb,
--static char *pci_devs_to_hide = NULL;
-+static char *pci_devs_to_hide;
- wait_queue_head_t aer_wait_queue;
- /*Add sem for sync AER handling and pciback remove/reconfigue ops,
- * We want to avoid in middle of AER ops, pciback devices is being removed
-@@ -43,7 +43,7 @@ struct pcistub_device {
- spinlock_t lock;
+ old_meta_prod = npo->meta_prod;
- struct pci_dev *dev;
-- struct pciback_device *pdev; /* non-NULL if struct pci_dev is in use */
-+ struct pciback_device *pdev;/* non-NULL if struct pci_dev is in use */
- };
++ /* Set up a GSO prefix descriptor, if necessary */
++ if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
++ meta = npo->meta + npo->meta_prod++;
++ meta->gso_size = skb_shinfo(skb)->gso_size;
++ meta->size = 0;
++ meta->id = req->id;
++ }
++
+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+ meta = npo->meta + npo->meta_prod++;
+- meta->gso_size = skb_shinfo(skb)->gso_size;
++
++ if (!netif->gso_prefix)
++ meta->gso_size = skb_shinfo(skb)->gso_size;
++ else
++ meta->gso_size = 0;
++
+ meta->size = 0;
+ meta->id = req->id;
+ npo->copy_off = 0;
+@@ -506,7 +521,7 @@ static int netbk_gop_skb(struct sk_buff *skb,
+ offset_in_page(skb->data), 1);
- /* Access to pcistub_devices & seized_devices lists and the initialize_devices
-@@ -55,7 +55,7 @@ static LIST_HEAD(pcistub_devices);
- /* wait for device_initcall before initializing our devices
- * (see pcistub_init_devices_late)
- */
--static int initialize_devices = 0;
-+static int initialize_devices;
- static LIST_HEAD(seized_devices);
+ /* Leave a gap for the GSO descriptor. */
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
+ netif->rx.req_cons++;
- static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
-@@ -132,7 +132,7 @@ static struct pcistub_device *pcistub_device_find(int domain, int
bus,
- /* didn't find it */
- psdev = NULL;
+ for (i = 0; i < nr_frags; i++) {
+@@ -623,6 +638,21 @@ static void net_rx_action(unsigned long data)
-- out:
-+out:
- spin_unlock_irqrestore(&pcistub_devices_lock, flags);
- return psdev;
- }
-@@ -321,10 +321,10 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
+ netif = netdev_priv(skb->dev);
- return 0;
++ if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
++ resp = RING_GET_RESPONSE(&netif->rx,
++ netif->rx.rsp_prod_pvt++);
++
++ resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
++
++ resp->offset = netbk->meta[npo.meta_cons].gso_size;
++ resp->id = netbk->meta[npo.meta_cons].id;
++ resp->status = sco->meta_slots_used;
++
++ npo.meta_cons++;
++ sco->meta_slots_used--;
++ }
++
++
+ netif->stats.tx_bytes += skb->len;
+ netif->stats.tx_packets++;
-- config_release:
-+config_release:
- pciback_config_free_dev(dev);
+@@ -633,6 +663,7 @@ static void net_rx_action(unsigned long data)
+ flags = 0;
+ else
+ flags = NETRXF_more_data;
++
+ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+ flags |= NETRXF_csum_blank | NETRXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+@@ -645,7 +676,7 @@ static void net_rx_action(unsigned long data)
+ netbk->meta[npo.meta_cons].size,
+ flags);
-- out:
-+out:
- pci_set_drvdata(dev, NULL);
- kfree(dev_data);
- return err;
-@@ -443,7 +443,7 @@ static int __devinit pcistub_probe(struct pci_dev *dev,
- /* Didn't find the device */
- err = -ENODEV;
+- if (netbk->meta[npo.meta_cons].gso_size) {
++ if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
+ struct xen_netif_extra_info *gso =
+ (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&netif->rx,
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index e30b0c7..cda987f 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -457,16 +457,25 @@ static int connect_rings(struct backend_info *be)
+ be->netif->dev->mtu = ETH_DATA_LEN;
+ }
-- out:
-+out:
- return err;
- }
+- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
"%d",
+- &val) < 0)
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
++ "%d", &val) < 0)
+ val = 0;
+ if (val) {
+ be->netif->features |= NETIF_F_TSO;
+ be->netif->dev->features |= NETIF_F_TSO;
+ }
-@@ -511,26 +511,24 @@ static void kill_domain_by_device(struct pcistub_device *psdev)
- int err;
- char nodename[1024];
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
++ "%d", &val) < 0)
++ val = 0;
++ if (val) {
++ be->netif->features |= NETIF_F_TSO;
++ be->netif->dev->features |= NETIF_F_TSO;
++ be->netif->gso_prefix = 1;
++ }
++
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
+- "%d", &val) < 0)
++ "%d", &val) < 0)
+ val = 0;
+ if (val) {
+ be->netif->features &= ~NETIF_F_IP_CSUM;
+diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
+index 518481c..8309344 100644
+--- a/include/xen/interface/io/netif.h
++++ b/include/xen/interface/io/netif.h
+@@ -131,6 +131,10 @@ struct xen_netif_rx_request {
+ #define _NETRXF_extra_info (3)
+ #define NETRXF_extra_info (1U<<_NETRXF_extra_info)
-- if (!psdev)
-+ if (!psdev)
- dev_err(&psdev->dev->dev,
- "device is NULL when do AER recovery/kill_domain\n");
-- sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
-+ sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
- psdev->pdev->xdev->otherend_id);
- nodename[strlen(nodename)] = '\0';
++/* GSO Prefix descriptor. */
++#define _NETRXF_gso_prefix (4)
++#define NETRXF_gso_prefix (1U<<_NETRXF_gso_prefix)
++
+ struct xen_netif_rx_response {
+ uint16_t id;
+ uint16_t offset; /* Offset in page of start of received packet */
+--
+1.7.4
+
+
+From bd910979612331d60a629c16a49ebeb5efa0f035 Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Fri, 2 Jul 2010 10:28:13 +0100
+Subject: [PATCH 051/203] xen: netback: Make frontend features distinct from netback
feature flags.
+
+Make sure that if a feature flag is disabled by ethtool on netback
+that we do not gratuitously re-enabled it when we check the frontend
+features during ring connection.
+
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Cc: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 14 ++++++--
+ drivers/xen/netback/interface.c | 68 ++++++++++++++++++++++++++++++--------
+ drivers/xen/netback/netback.c | 2 +-
+ drivers/xen/netback/xenbus.c | 44 ++++++++++---------------
+ 4 files changed, 81 insertions(+), 47 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 78451ab..a5f3759 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -76,12 +76,17 @@ struct xen_netif {
+ struct vm_struct *tx_comms_area;
+ struct vm_struct *rx_comms_area;
- again:
- err = xenbus_transaction_start(&xbt);
-- if (err)
-- {
-+ if (err) {
- dev_err(&psdev->dev->dev,
- "error %d when start xenbus transaction\n", err);
- return;
- }
- /*PV AER handlers will set this flag*/
-- xenbus_printf(xbt, nodename, "aerState" , "aerfail" );
-+ xenbus_printf(xbt, nodename, "aerState" , "aerfail");
- err = xenbus_transaction_end(xbt, 0);
-- if (err)
-- {
-+ if (err) {
- if (err == -EAGAIN)
- goto again;
- dev_err(&psdev->dev->dev,
-@@ -541,9 +539,9 @@ again:
+- /* Set of features that can be turned on in dev->features. */
+- int features;
++ /* Flags that must not be set in dev->features */
++ int features_disabled;
++
++ /* Frontend feature information. */
++ u8 can_sg:1;
++ u8 gso:1;
++ u8 gso_prefix:1;
++ u8 csum:1;
- /* For each aer recovery step error_detected, mmio_enabled, etc, front_end and
- * backend need to have cooperation. In pciback, those steps will do similar
-- * jobs: send service request and waiting for front_end response.
-+ * jobs: send service request and waiting for front_end response.
- */
--static pci_ers_result_t common_process(struct pcistub_device *psdev,
-+static pci_ers_result_t common_process(struct pcistub_device *psdev,
- pci_channel_state_t state, int aer_cmd, pci_ers_result_t result)
- {
- pci_ers_result_t res = result;
-@@ -561,12 +559,12 @@ static pci_ers_result_t common_process(struct pcistub_device
*psdev,
- if (!ret) {
- dev_err(&psdev->dev->dev,
- "pciback: failed to get pcifront device\n");
-- return PCI_ERS_RESULT_NONE;
-+ return PCI_ERS_RESULT_NONE;
- }
- wmb();
+ /* Internal feature information. */
+ u8 can_queue:1; /* can queue packets for receiver? */
+- u8 gso_prefix:1; /* use a prefix segment for GSO information */
-- dev_dbg(&psdev->dev->dev,
-- "pciback: aer_op %x dom %x bus %x devfn %x\n",
-+ dev_dbg(&psdev->dev->dev,
-+ "pciback: aer_op %x dom %x bus %x devfn %x\n",
- aer_cmd, aer_op->domain, aer_op->bus, aer_op->devfn);
- /*local flag to mark there's aer request, pciback callback will use this
- * flag to judge whether we need to check pci-front give aer service
-@@ -575,21 +573,21 @@ static pci_ers_result_t common_process(struct pcistub_device
*psdev,
- set_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
+ /* Allow netif_be_start_xmit() to peek ahead in the rx request
+ * ring. This is a prediction of what rx_req_cons will be once
+@@ -187,6 +192,7 @@ void netif_accel_init(void);
- /*It is possible that a pcifront conf_read_write ops request invokes
-- * the callback which cause the spurious execution of wake_up.
-+ * the callback which cause the spurious execution of wake_up.
- * Yet it is harmless and better than a spinlock here
- */
-- set_bit(_XEN_PCIB_active,
-+ set_bit(_XEN_PCIB_active,
- (unsigned long *)&psdev->pdev->sh_info->flags);
- wmb();
- notify_remote_via_irq(psdev->pdev->evtchn_irq);
+ void netif_disconnect(struct xen_netif *netif);
- ret = wait_event_timeout(aer_wait_queue, !(test_bit(_XEN_PCIB_active,
-- (unsigned long *)&psdev->pdev->sh_info->flags)), 300*HZ);
-+ (unsigned long *)&psdev->pdev->sh_info->flags)), 300*HZ);
++void netif_set_features(struct xen_netif *netif);
+ struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle);
+ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn);
+@@ -223,7 +229,7 @@ static inline int netbk_can_queue(struct net_device *dev)
+ static inline int netbk_can_sg(struct net_device *dev)
+ {
+ struct xen_netif *netif = netdev_priv(dev);
+- return netif->features & NETIF_F_SG;
++ return netif->can_sg;
+ }
- if (!ret) {
-- if (test_bit(_XEN_PCIB_active,
-+ if (test_bit(_XEN_PCIB_active,
- (unsigned long *)&psdev->pdev->sh_info->flags)) {
-- dev_err(&psdev->dev->dev,
-+ dev_err(&psdev->dev->dev,
- "pcifront aer process not responding!\n");
- clear_bit(_XEN_PCIB_active,
- (unsigned long *)&psdev->pdev->sh_info->flags);
-@@ -599,16 +597,16 @@ static pci_ers_result_t common_process(struct pcistub_device
*psdev,
- }
- clear_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
+ struct pending_tx_info {
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 172ef4c..2e8508a 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -121,31 +121,69 @@ static int netbk_change_mtu(struct net_device *dev, int mtu)
+ return 0;
+ }
-- if ( test_bit( _XEN_PCIF_active,
-- (unsigned long*)&psdev->pdev->sh_info->flags)) {
-- dev_dbg(&psdev->dev->dev,
-+ if (test_bit(_XEN_PCIF_active,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
-+ dev_dbg(&psdev->dev->dev,
- "schedule pci_conf service in pciback \n");
- test_and_schedule_op(psdev->pdev);
- }
+-static int netbk_set_sg(struct net_device *dev, u32 data)
++void netif_set_features(struct xen_netif *netif)
+ {
+- if (data) {
+- struct xen_netif *netif = netdev_priv(dev);
++ struct net_device *dev = netif->dev;
++ int features = dev->features;
++
++ if (netif->can_sg)
++ features |= NETIF_F_SG;
++ if (netif->gso || netif->gso_prefix)
++ features |= NETIF_F_TSO;
++ if (netif->csum)
++ features |= NETIF_F_IP_CSUM;
++
++ features &= ~(netif->features_disabled);
- res = (pci_ers_result_t)aer_op->err;
- return res;
--}
+- if (!(netif->features & NETIF_F_SG))
++ if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
++ dev->mtu = ETH_DATA_LEN;
++
++ dev->features = features;
+}
-
- /*
- * pciback_slot_reset: it will send the slot_reset request to pcifront in case
-@@ -632,24 +630,22 @@ static pci_ers_result_t pciback_slot_reset(struct pci_dev *dev)
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
-
-- if ( !psdev || !psdev->pdev )
-- {
-- dev_err(&dev->dev,
-+ if (!psdev || !psdev->pdev) {
-+ dev_err(&dev->dev,
- "pciback device is not found/assigned\n");
- goto end;
- }
-
-- if ( !psdev->pdev->sh_info )
-- {
-+ if (!psdev->pdev->sh_info) {
- dev_err(&dev->dev, "pciback device is not connected or owned"
- " by HVM, kill it\n");
- kill_domain_by_device(psdev);
- goto release;
++
++static int netbk_set_tx_csum(struct net_device *dev, u32 data)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (data) {
++ if (!netif->csum)
+ return -ENOSYS;
++ netif->features_disabled &= ~NETIF_F_IP_CSUM;
++ } else {
++ netif->features_disabled |= NETIF_F_IP_CSUM;
}
-- if ( !test_bit(_XEN_PCIB_AERHANDLER,
-- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-- dev_err(&dev->dev,
-+ if (!test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
-+ dev_err(&dev->dev,
- "guest with no AER driver should have been killed\n");
- goto release;
- }
-@@ -657,7 +653,7 @@ static pci_ers_result_t pciback_slot_reset(struct pci_dev *dev)
+- if (dev->mtu > ETH_DATA_LEN)
+- dev->mtu = ETH_DATA_LEN;
++ netif_set_features(netif);
++ return 0;
++}
- if (result == PCI_ERS_RESULT_NONE ||
- result == PCI_ERS_RESULT_DISCONNECT) {
-- dev_dbg(&dev->dev,
-+ dev_dbg(&dev->dev,
- "No AER slot_reset service or disconnected!\n");
- kill_domain_by_device(psdev);
- }
-@@ -670,9 +666,9 @@ end:
+- return ethtool_op_set_sg(dev, data);
++static int netbk_set_sg(struct net_device *dev, u32 data)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (data) {
++ if (!netif->can_sg)
++ return -ENOSYS;
++ netif->features_disabled &= ~NETIF_F_SG;
++ } else {
++ netif->features_disabled |= NETIF_F_SG;
++ }
++
++ netif_set_features(netif);
++ return 0;
}
-
--/*pciback_mmio_enabled: it will send the mmio_enabled request to pcifront
--* in case of the device driver could provide this service, and then wait
--* for pcifront ack.
-+/*pciback_mmio_enabled: it will send the mmio_enabled request to pcifront
-+* in case of the device driver could provide this service, and then wait
-+* for pcifront ack
- * @dev: pointer to PCI devices
- * return value is used by aer_core do_recovery policy
- */
-@@ -692,24 +688,22 @@ static pci_ers_result_t pciback_mmio_enabled(struct pci_dev *dev)
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
-
-- if ( !psdev || !psdev->pdev )
-- {
-- dev_err(&dev->dev,
-+ if (!psdev || !psdev->pdev) {
-+ dev_err(&dev->dev,
- "pciback device is not found/assigned\n");
- goto end;
- }
-
-- if ( !psdev->pdev->sh_info )
-- {
-+ if (!psdev->pdev->sh_info) {
- dev_err(&dev->dev, "pciback device is not connected or owned"
- " by HVM, kill it\n");
- kill_domain_by_device(psdev);
- goto release;
- }
-
-- if ( !test_bit(_XEN_PCIB_AERHANDLER,
-- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-- dev_err(&dev->dev,
-+ if (!test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
-+ dev_err(&dev->dev,
- "guest with no AER driver should have been killed\n");
- goto release;
+ static int netbk_set_tso(struct net_device *dev, u32 data)
+ {
++ struct xen_netif *netif = netdev_priv(dev);
+ if (data) {
+- struct xen_netif *netif = netdev_priv(dev);
+-
+- if (!(netif->features & NETIF_F_TSO))
++ if (!netif->gso && !netif->gso_prefix)
+ return -ENOSYS;
++ netif->features_disabled &= ~NETIF_F_TSO;
++ } else {
++ netif->features_disabled |= NETIF_F_TSO;
}
-@@ -717,7 +711,7 @@ static pci_ers_result_t pciback_mmio_enabled(struct pci_dev *dev)
- if (result == PCI_ERS_RESULT_NONE ||
- result == PCI_ERS_RESULT_DISCONNECT) {
-- dev_dbg(&dev->dev,
-+ dev_dbg(&dev->dev,
- "No AER mmio_enabled service or disconnected!\n");
- kill_domain_by_device(psdev);
- }
-@@ -728,8 +722,8 @@ end:
- return result;
+- return ethtool_op_set_tso(dev, data);
++ netif_set_features(netif);
++ return 0;
}
--/*pciback_error_detected: it will send the error_detected request to pcifront
--* in case of the device driver could provide this service, and then wait
-+/*pciback_error_detected: it will send the error_detected request to pcifront
-+* in case of the device driver could provide this service, and then wait
- * for pcifront ack.
- * @dev: pointer to PCI devices
- * @error: the current PCI connection state
-@@ -752,15 +746,13 @@ static pci_ers_result_t pciback_error_detected(struct pci_dev
*dev,
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
+ static void netbk_get_drvinfo(struct net_device *dev,
+@@ -200,7 +238,7 @@ static struct ethtool_ops network_ethtool_ops =
+ .get_drvinfo = netbk_get_drvinfo,
-- if ( !psdev || !psdev->pdev )
-- {
-- dev_err(&dev->dev,
-+ if (!psdev || !psdev->pdev) {
-+ dev_err(&dev->dev,
- "pciback device is not found/assigned\n");
- goto end;
- }
+ .get_tx_csum = ethtool_op_get_tx_csum,
+- .set_tx_csum = ethtool_op_set_tx_csum,
++ .set_tx_csum = netbk_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = netbk_set_sg,
+ .get_tso = ethtool_op_get_tso,
+@@ -242,7 +280,8 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ netif->domid = domid;
+ netif->group = -1;
+ netif->handle = handle;
+- netif->features = NETIF_F_SG;
++ netif->can_sg = 1;
++ netif->csum = 1;
+ atomic_set(&netif->refcnt, 1);
+ init_waitqueue_head(&netif->waiting_to_free);
+ netif->dev = dev;
+@@ -259,8 +298,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ init_timer(&netif->tx_queue_timeout);
-- if ( !psdev->pdev->sh_info )
-- {
-+ if (!psdev->pdev->sh_info) {
- dev_err(&dev->dev, "pciback device is not connected or owned"
- " by HVM, kill it\n");
- kill_domain_by_device(psdev);
-@@ -768,8 +760,8 @@ static pci_ers_result_t pciback_error_detected(struct pci_dev *dev,
- }
+ dev->netdev_ops = &netback_ops;
+- dev->features = NETIF_F_IP_CSUM|NETIF_F_SG;
+-
++ netif_set_features(netif);
+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
- /*Guest owns the device yet no aer handler regiested, kill guest*/
-- if ( !test_bit(_XEN_PCIB_AERHANDLER,
-- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-+ if (!test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
- dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n");
- kill_domain_by_device(psdev);
- goto release;
-@@ -778,7 +770,7 @@ static pci_ers_result_t pciback_error_detected(struct pci_dev *dev,
+ dev->tx_queue_len = netbk_queue_length;
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index e93a62e..63a771e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -238,7 +238,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
- if (result == PCI_ERS_RESULT_NONE ||
- result == PCI_ERS_RESULT_DISCONNECT) {
-- dev_dbg(&dev->dev,
-+ dev_dbg(&dev->dev,
- "No AER error_detected service or disconnected!\n");
- kill_domain_by_device(psdev);
- }
-@@ -789,8 +781,8 @@ end:
- return result;
+ static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
+ {
+- if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
++ if (netif->can_sg || netif->gso || netif->gso_prefix)
+ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
+ return 1; /* all in one */
}
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index cda987f..17ff5cf 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -404,6 +404,7 @@ static void connect(struct backend_info *be)
--/*pciback_error_resume: it will send the error_resume request to pcifront
--* in case of the device driver could provide this service, and then wait
-+/*pciback_error_resume: it will send the error_resume request to pcifront
-+* in case of the device driver could provide this service, and then wait
- * for pcifront ack.
- * @dev: pointer to PCI devices
- */
-@@ -808,29 +800,28 @@ static void pciback_error_resume(struct pci_dev *dev)
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
-
-- if ( !psdev || !psdev->pdev )
-- {
-- dev_err(&dev->dev,
-+ if (!psdev || !psdev->pdev) {
-+ dev_err(&dev->dev,
- "pciback device is not found/assigned\n");
- goto end;
- }
-
-- if ( !psdev->pdev->sh_info )
-- {
-+ if (!psdev->pdev->sh_info) {
- dev_err(&dev->dev, "pciback device is not connected or owned"
- " by HVM, kill it\n");
- kill_domain_by_device(psdev);
- goto release;
- }
+ static int connect_rings(struct backend_info *be)
+ {
++ struct xen_netif *netif = be->netif;
+ struct xenbus_device *dev = be->dev;
+ unsigned long tx_ring_ref, rx_ring_ref;
+ unsigned int evtchn, rx_copy;
+@@ -437,53 +438,42 @@ static int connect_rings(struct backend_info *be)
+ if (!rx_copy)
+ return -EOPNOTSUPP;
-- if ( !test_bit(_XEN_PCIB_AERHANDLER,
-- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
-- dev_err(&dev->dev,
-+ if (!test_bit(_XEN_PCIB_AERHANDLER,
-+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
-+ dev_err(&dev->dev,
- "guest with no AER driver should have been killed\n");
- kill_domain_by_device(psdev);
- goto release;
+- if (be->netif->dev->tx_queue_len != 0) {
++ if (netif->dev->tx_queue_len != 0) {
+ if (xenbus_scanf(XBT_NIL, dev->otherend,
+ "feature-rx-notify", "%d", &val) < 0)
+ val = 0;
+ if (val)
+- be->netif->can_queue = 1;
++ netif->can_queue = 1;
+ else
+ /* Must be non-zero for pfifo_fast to work. */
+- be->netif->dev->tx_queue_len = 1;
++ netif->dev->tx_queue_len = 1;
}
-- common_process(psdev, 1, XEN_PCI_OP_aer_resume, PCI_ERS_RESULT_RECOVERED);
-+ common_process(psdev, 1, XEN_PCI_OP_aer_resume,
-+ PCI_ERS_RESULT_RECOVERED);
- release:
- pcistub_device_put(psdev);
- end:
-@@ -923,8 +914,8 @@ static int pcistub_device_id_remove(int domain, int bus, int slot,
int func)
- unsigned long flags;
-
- spin_lock_irqsave(&device_ids_lock, flags);
-- list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
--
-+ list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids,
-+ slot_list) {
- if (pci_dev_id->domain == domain
- && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
- /* Don't break; here because it's possible the same
-@@ -976,7 +967,7 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func,
int reg,
- err = pciback_config_quirks_add_field(dev, field);
- if (err)
- kfree(field);
-- out:
-+out:
- return err;
- }
-@@ -992,7 +983,7 @@ static ssize_t pcistub_slot_add(struct device_driver *drv, const char
*buf,
+- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d",
&val) < 0)
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
++ "%d", &val) < 0)
+ val = 0;
+- if (!val) {
+- be->netif->features &= ~NETIF_F_SG;
+- be->netif->dev->features &= ~NETIF_F_SG;
+- if (be->netif->dev->mtu > ETH_DATA_LEN)
+- be->netif->dev->mtu = ETH_DATA_LEN;
+- }
++ netif->can_sg = !!val;
- err = pcistub_device_id_add(domain, bus, slot, func);
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
+- "%d", &val) < 0)
++ "%d", &val) < 0)
+ val = 0;
+- if (val) {
+- be->netif->features |= NETIF_F_TSO;
+- be->netif->dev->features |= NETIF_F_TSO;
+- }
++ netif->gso = !!val;
-- out:
-+out:
- if (!err)
- err = count;
- return err;
-@@ -1012,7 +1003,7 @@ static ssize_t pcistub_slot_remove(struct device_driver *drv, const
char *buf,
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
+- "%d", &val) < 0)
++ "%d", &val) < 0)
+ val = 0;
+- if (val) {
+- be->netif->features |= NETIF_F_TSO;
+- be->netif->dev->features |= NETIF_F_TSO;
+- be->netif->gso_prefix = 1;
+- }
++ netif->gso_prefix = !!val;
- err = pcistub_device_id_remove(domain, bus, slot, func);
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
+- "%d", &val) < 0)
++ "%d", &val) < 0)
+ val = 0;
+- if (val) {
+- be->netif->features &= ~NETIF_F_IP_CSUM;
+- be->netif->dev->features &= ~NETIF_F_IP_CSUM;
+- }
++ netif->csum = !val;
++
++ /* Set dev->features */
++ netif_set_features(netif);
-- out:
-+out:
- if (!err)
- err = count;
- return err;
-@@ -1057,7 +1048,7 @@ static ssize_t pcistub_quirk_add(struct device_driver *drv, const
char *buf,
+ /* Map the shared frame, irq etc. */
+- err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
++ err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
+ if (err) {
+ xenbus_dev_fatal(dev, err,
+ "mapping shared-frames %lu/%lu port %u",
+--
+1.7.4
+
+
+From cf8c20169427de5829e3ec723712b77de52e64ac Mon Sep 17 00:00:00 2001
+From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Date: Thu, 15 Jul 2010 10:46:50 -0700
+Subject: [PATCH 052/203] xen: netback: only initialize for PV domains
+
+HVM domains don't support netback
+
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 63a771e..911c85b 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1701,7 +1701,7 @@ static int __init netback_init(void)
+ int rc = 0;
+ int group;
- err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
+- if (!xen_domain())
++ if (!xen_pv_domain())
+ return -ENODEV;
-- out:
-+out:
- if (!err)
- err = count;
- return err;
-@@ -1067,7 +1058,6 @@ static ssize_t pcistub_quirk_show(struct device_driver *drv, char
*buf)
- {
- int count = 0;
- unsigned long flags;
-- extern struct list_head pciback_quirks;
- struct pciback_config_quirk *quirk;
- struct pciback_dev_data *dev_data;
- const struct config_field *field;
-@@ -1096,12 +1086,13 @@ static ssize_t pcistub_quirk_show(struct device_driver *drv, char
*buf)
+ xen_netbk_group_nr = num_online_cpus();
+--
+1.7.4
+
+
+From dfa4906cfade8541573814c34be82ba02c348317 Mon Sep 17 00:00:00 2001
+From: Owen Smith <owen.smith(a)citrix.com>
+Date: Wed, 22 Dec 2010 15:05:00 +0000
+Subject: [PATCH 053/203] Union the blkif_request request specific fields
+
+Prepare for extending the block device ring to allow request
+specific fields, by moving the request specific fields for
+reads, writes and barrier requests to a union member
+
+Signed-off-by: Owen Smith <owen.smith(a)citrix.com>
+---
+ drivers/block/xen-blkfront.c | 8 ++++----
+ include/xen/interface/io/blkif.h | 16 +++++++++++-----
+ 2 files changed, 15 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
+index d7aa39e..cc4514c 100644
+--- a/drivers/block/xen-blkfront.c
++++ b/drivers/block/xen-blkfront.c
+@@ -281,7 +281,7 @@ static int blkif_queue_request(struct request *req)
+ info->shadow[id].request = req;
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "\t\t%08x:%01x:%08x\n",
-- cfg_entry->base_offset + field->offset,
-- field->size, field->mask);
-+ cfg_entry->base_offset +
-+ field->offset, field->size,
-+ field->mask);
- }
- }
+ ring_req->id = id;
+- ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
++ ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
+ ring_req->handle = info->handle;
-- out:
-+out:
- spin_unlock_irqrestore(&device_ids_lock, flags);
+ ring_req->operation = rq_data_dir(req) ?
+@@ -317,7 +317,7 @@ static int blkif_queue_request(struct request *req)
+ rq_data_dir(req) );
- return count;
-@@ -1137,14 +1128,14 @@ static ssize_t permissive_add(struct device_driver *drv, const
char *buf,
- if (!dev_data->permissive) {
- dev_data->permissive = 1;
- /* Let user know that what they're doing could be unsafe */
-- dev_warn(&psdev->dev->dev,
-- "enabling permissive mode configuration space accesses!\n");
-+ dev_warn(&psdev->dev->dev, "enabling permissive mode "
-+ "configuration space accesses!\n");
- dev_warn(&psdev->dev->dev,
- "permissive mode is potentially unsafe!\n");
- }
-- release:
-+release:
- pcistub_device_put(psdev);
-- out:
-+out:
- if (!err)
- err = count;
- return err;
-@@ -1264,10 +1255,10 @@ static int __init pcistub_init(void)
- if (err)
- pcistub_exit();
+ info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
+- ring_req->seg[i] =
++ ring_req->u.rw.seg[i] =
+ (struct blkif_request_segment) {
+ .gref = ref,
+ .first_sect = fsect,
+@@ -615,7 +615,7 @@ static void blkif_completion(struct blk_shadow *s)
+ {
+ int i;
+ for (i = 0; i < s->req.nr_segments; i++)
+- gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
++ gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL);
+ }
-- out:
-+out:
- return err;
+ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+@@ -932,7 +932,7 @@ static int blkif_recover(struct blkfront_info *info)
+ /* Rewrite any grant references invalidated by susp/resume. */
+ for (j = 0; j < req->nr_segments; j++)
+ gnttab_grant_foreign_access_ref(
+- req->seg[j].gref,
++ req->u.rw.seg[j].gref,
+ info->xbdev->otherend_id,
+ pfn_to_mfn(info->shadow[req->id].frame[j]),
+ rq_data_dir(info->shadow[req->id].request));
+diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
+index c2d1fa4..e4f743c 100644
+--- a/include/xen/interface/io/blkif.h
++++ b/include/xen/interface/io/blkif.h
+@@ -51,11 +51,7 @@ typedef uint64_t blkif_sector_t;
+ */
+ #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
-- parse_error:
-+parse_error:
- printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at
\"%s\"\n",
- pci_devs_to_hide + pos);
- return -EINVAL;
-@@ -1276,7 +1267,7 @@ static int __init pcistub_init(void)
- #ifndef MODULE
- /*
- * fs_initcall happens before device_initcall
-- * so pciback *should* get called first (b/c we
-+ * so pciback *should* get called first (b/c we
- * want to suck up any device before other drivers
- * get a chance by being the first pci device
- * driver to register)
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-index 5e8e14e..98e2912 100644
---- a/drivers/xen/pciback/pciback.h
-+++ b/drivers/xen/pciback/pciback.h
-@@ -49,6 +49,12 @@ struct pciback_dev_data {
- int warned_on_write;
+-struct blkif_request {
+- uint8_t operation; /* BLKIF_OP_??? */
+- uint8_t nr_segments; /* number of segments */
+- blkif_vdev_t handle; /* only for read/write requests */
+- uint64_t id; /* private guest value, echoed in resp */
++struct blkif_request_rw {
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment {
+ grant_ref_t gref; /* reference to I/O buffer frame */
+@@ -65,6 +61,16 @@ struct blkif_request {
+ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
};
-+/* Used by XenBus and pciback_ops.c */
-+extern wait_queue_head_t aer_wait_queue;
-+extern struct workqueue_struct *pciback_wq;
-+/* Used by pcistub.c and conf_space_quirks.c */
-+extern struct list_head pciback_quirks;
++struct blkif_request {
++ uint8_t operation; /* BLKIF_OP_??? */
++ uint8_t nr_segments; /* number of segments */
++ blkif_vdev_t handle; /* only for read/write requests */
++ uint64_t id; /* private guest value, echoed in resp */
++ union {
++ struct blkif_request_rw rw;
++ } u;
++};
+
- /* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
- struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
- int domain, int bus,
-@@ -67,14 +73,14 @@ void pciback_config_free_dyn_fields(struct pci_dev *dev);
- void pciback_config_reset_dev(struct pci_dev *dev);
- void pciback_config_free_dev(struct pci_dev *dev);
- int pciback_config_read(struct pci_dev *dev, int offset, int size,
-- u32 * ret_val);
-+ u32 *ret_val);
- int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
-
- /* Handle requests for specific devices from the frontend */
- typedef int (*publish_pci_dev_cb) (struct pciback_device *pdev,
- unsigned int domain, unsigned int bus,
- unsigned int devfn, unsigned int devid);
--typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
-+typedef int (*publish_pci_root_cb) (struct pciback_device *pdev,
- unsigned int domain, unsigned int bus);
- int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
- int devid, publish_pci_dev_cb publish_cb);
-@@ -83,15 +89,17 @@ struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
- unsigned int domain, unsigned int bus,
- unsigned int devfn);
+ struct blkif_response {
+ uint64_t id; /* copied from request */
+ uint8_t operation; /* copied from request */
+--
+1.7.4
+
+
+From e8bc588ab4c297e3f3d8f61f205b2d2db258907b Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 18 Jan 2011 20:09:41 -0500
+Subject: [PATCH 054/203] xen: Mark all initial reserved pages for the balloon as
INVALID_P2M_ENTRY.
+
+With this patch, we diligently set regions that will be used by the
+balloon driver to be INVALID_P2M_ENTRY and under the ownership
+of the balloon driver. We are OK using the __set_phys_to_machine
+as we do not expect to be allocating any P2M middle or entries pages.
+The set_phys_to_machine has the side-effect of potentially allocating
+new pages and we do not want that at this stage.
+
+We can do this because xen_build_mfn_list_list will have already
+allocated all such pages up to xen_max_p2m_pfn.
+
+We also move the check for auto translated physmap down the
+stack so it is present in __set_phys_to_machine.
+
+[v2: Rebased with mmu->p2m code split]
+Reviewed-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/include/asm/xen/page.h | 1 +
+ arch/x86/xen/mmu.c | 2 +-
+ arch/x86/xen/p2m.c | 9 ++++-----
+ arch/x86/xen/setup.c | 7 ++++++-
+ drivers/xen/balloon.c | 2 +-
+ 5 files changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
+index f25bdf2..8ea9772 100644
+--- a/arch/x86/include/asm/xen/page.h
++++ b/arch/x86/include/asm/xen/page.h
+@@ -41,6 +41,7 @@ extern unsigned int machine_to_phys_order;
--/**
-+/**
- * Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in pciback
--* before sending aer request to pcifront, so that guest could identify
-+* before sending aer request to pcifront, so that guest could identify
- * device, coopearte with pciback to finish aer recovery job if device driver
- * has the capability
- */
+ extern unsigned long get_phys_to_machine(unsigned long pfn);
+ extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
++extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
--int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-- unsigned int *domain, unsigned int *bus, unsigned int *devfn);
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-+ struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus,
-+ unsigned int *devfn);
- int pciback_init_devices(struct pciback_device *pdev);
- int pciback_publish_pci_roots(struct pciback_device *pdev,
- publish_pci_root_cb cb);
-@@ -106,17 +114,17 @@ void pciback_xenbus_unregister(void);
+ extern int m2p_add_override(unsigned long mfn, struct page *page);
+ extern int m2p_remove_override(struct page *page);
+diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
+index 5e92b61..0180ae8 100644
+--- a/arch/x86/xen/mmu.c
++++ b/arch/x86/xen/mmu.c
+@@ -2074,7 +2074,7 @@ static void xen_zap_pfn_range(unsigned long vaddr, unsigned int
order,
+ in_frames[i] = virt_to_mfn(vaddr);
- #ifdef CONFIG_PCI_MSI
- int pciback_enable_msi(struct pciback_device *pdev,
-- struct pci_dev *dev, struct xen_pci_op *op);
-+ struct pci_dev *dev, struct xen_pci_op *op);
+ MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
+- set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
++ __set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
- int pciback_disable_msi(struct pciback_device *pdev,
-- struct pci_dev *dev, struct xen_pci_op *op);
-+ struct pci_dev *dev, struct xen_pci_op *op);
+ if (out_frames)
+ out_frames[i] = virt_to_pfn(vaddr);
+diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
+index ddc81a0..df4e367 100644
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -365,6 +365,10 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+ {
+ unsigned topidx, mididx, idx;
++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
++ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
++ return true;
++ }
+ if (unlikely(pfn >= MAX_P2M_PFN)) {
+ BUG_ON(mfn != INVALID_P2M_ENTRY);
+ return true;
+@@ -384,11 +388,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
- int pciback_enable_msix(struct pciback_device *pdev,
-- struct pci_dev *dev, struct xen_pci_op *op);
-+ struct pci_dev *dev, struct xen_pci_op *op);
+ bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+ {
+- if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
+- BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+- return true;
+- }
+-
+ if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
+ if (!alloc_p2m(pfn))
+ return false;
+diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
+index b5a7f92..7201800 100644
+--- a/arch/x86/xen/setup.c
++++ b/arch/x86/xen/setup.c
+@@ -52,6 +52,8 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
- int pciback_disable_msix(struct pciback_device *pdev,
-- struct pci_dev *dev, struct xen_pci_op *op);
-+ struct pci_dev *dev, struct xen_pci_op *op);
- #endif
- extern int verbose_request;
+ static __init void xen_add_extra_mem(unsigned long pages)
+ {
++ unsigned long pfn;
++
+ u64 size = (u64)pages * PAGE_SIZE;
+ u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 6624faf..bf83dca 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -5,11 +5,11 @@
- */
- #include <linux/module.h>
- #include <linux/wait.h>
--#include <asm/bitops.h>
-+#include <linux/bitops.h>
- #include <xen/events.h>
- #include "pciback.h"
+@@ -66,6 +68,9 @@ static __init void xen_add_extra_mem(unsigned long pages)
+ xen_extra_mem_size += size;
--int verbose_request = 0;
-+int verbose_request;
- module_param(verbose_request, int, 0644);
+ xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
++
++ for (pfn = PFN_DOWN(extra_start); pfn <= xen_max_p2m_pfn; pfn++)
++ __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+ }
- /* Ensure a device is "turned off" and ready to be exported.
-@@ -37,12 +37,10 @@ void pciback_reset_device(struct pci_dev *dev)
+ static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
+@@ -104,7 +109,7 @@ static unsigned long __init xen_release_chunk(phys_addr_t
start_addr,
+ WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
+ start, end, ret);
+ if (ret == 1) {
+- set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
++ __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+ len++;
}
}
- }
--extern wait_queue_head_t aer_wait_queue;
--extern struct workqueue_struct *pciback_wq;
- /*
- * Now the same evtchn is used for both pcifront conf_read_write request
- * as well as pcie aer front end ack. We use a new work_queue to schedule
--* pciback conf_read_write service for avoiding confict with aer_core
-+* pciback conf_read_write service for avoiding confict with aer_core
- * do_recovery job which also use the system default work_queue
- */
- void test_and_schedule_op(struct pciback_device *pdev)
-@@ -50,14 +48,13 @@ void test_and_schedule_op(struct pciback_device *pdev)
- /* Check that frontend is requesting an operation and that we are not
- * already processing a request */
- if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
-- && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
-- {
-+ && !test_and_set_bit(_PDEVF_op_active, &pdev->flags)) {
- queue_work(pciback_wq, &pdev->op_work);
- }
- /*_XEN_PCIB_active should have been cleared by pcifront. And also make
- sure pciback is waiting for ack by checking _PCIB_op_pending*/
-- if (!test_bit(_XEN_PCIB_active,(unsigned long *)&pdev->sh_info->flags)
-- &&test_bit(_PCIB_op_pending, &pdev->flags)) {
-+ if (!test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags)
-+ && test_bit(_PCIB_op_pending, &pdev->flags)) {
- wake_up(&aer_wait_queue);
+diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
+index 43f9f02..b1661cd 100644
+--- a/drivers/xen/balloon.c
++++ b/drivers/xen/balloon.c
+@@ -296,7 +296,7 @@ static int decrease_reservation(unsigned long nr_pages)
+ /* No more mappings: invalidate P2M and add to balloon. */
+ for (i = 0; i < nr_pages; i++) {
+ pfn = mfn_to_pfn(frame_list[i]);
+- set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
++ __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+ balloon_append(pfn_to_page(pfn));
}
- }
-@@ -69,7 +66,8 @@ void test_and_schedule_op(struct pciback_device *pdev)
-
- void pciback_do_op(struct work_struct *data)
- {
-- struct pciback_device *pdev = container_of(data, struct pciback_device, op_work);
-+ struct pciback_device *pdev =
-+ container_of(data, struct pciback_device, op_work);
- struct pci_dev *dev;
- struct xen_pci_op *op = &pdev->sh_info->op;
-
-@@ -77,38 +75,36 @@ void pciback_do_op(struct work_struct *data)
- if (dev == NULL)
- op->err = XEN_PCI_ERR_dev_not_found;
-- else
-- {
-- switch (op->cmd)
-- {
-- case XEN_PCI_OP_conf_read:
-- op->err = pciback_config_read(dev,
-- op->offset, op->size, &op->value);
-- break;
-- case XEN_PCI_OP_conf_write:
-- op->err = pciback_config_write(dev,
-- op->offset, op->size, op->value);
-- break;
-+ else {
-+ switch (op->cmd) {
-+ case XEN_PCI_OP_conf_read:
-+ op->err = pciback_config_read(dev,
-+ op->offset, op->size, &op->value);
-+ break;
-+ case XEN_PCI_OP_conf_write:
-+ op->err = pciback_config_write(dev,
-+ op->offset, op->size, op->value);
-+ break;
- #ifdef CONFIG_PCI_MSI
-- case XEN_PCI_OP_enable_msi:
-- op->err = pciback_enable_msi(pdev, dev, op);
-- break;
-- case XEN_PCI_OP_disable_msi:
-- op->err = pciback_disable_msi(pdev, dev, op);
-- break;
-- case XEN_PCI_OP_enable_msix:
-- op->err = pciback_enable_msix(pdev, dev, op);
-- break;
-- case XEN_PCI_OP_disable_msix:
-- op->err = pciback_disable_msix(pdev, dev, op);
-- break;
-+ case XEN_PCI_OP_enable_msi:
-+ op->err = pciback_enable_msi(pdev, dev, op);
-+ break;
-+ case XEN_PCI_OP_disable_msi:
-+ op->err = pciback_disable_msi(pdev, dev, op);
-+ break;
-+ case XEN_PCI_OP_enable_msix:
-+ op->err = pciback_enable_msix(pdev, dev, op);
-+ break;
-+ case XEN_PCI_OP_disable_msix:
-+ op->err = pciback_disable_msix(pdev, dev, op);
-+ break;
- #endif
-- default:
-- op->err = XEN_PCI_ERR_not_implemented;
-- break;
-+ default:
-+ op->err = XEN_PCI_ERR_not_implemented;
-+ break;
- }
- }
-- /* Tell the driver domain that we're done. */
-+ /* Tell the driver domain that we're done. */
- wmb();
- clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
- notify_remote_via_irq(pdev->evtchn_irq);
-@@ -119,7 +115,7 @@ void pciback_do_op(struct work_struct *data)
- smp_mb__after_clear_bit(); /* /before/ final check for work */
-
- /* Check to see if the driver domain tried to start another request in
-- * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
-+ * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
- */
- test_and_schedule_op(pdev);
- }
-diff --git a/drivers/xen/pciback/slot.c b/drivers/xen/pciback/slot.c
-index 105a8b6..efb922d 100644
---- a/drivers/xen/pciback/slot.c
-+++ b/drivers/xen/pciback/slot.c
-@@ -65,7 +65,8 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev
*dev,
- for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
- if (slot_dev->slots[bus][slot] == NULL) {
- printk(KERN_INFO
-- "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
-+ "pciback: slot: %s: assign to virtual "
-+ "slot %d, bus %d\n",
- pci_name(dev), slot, bus);
- slot_dev->slots[bus][slot] = dev;
- goto unlock;
-@@ -76,14 +77,14 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev
*dev,
- xenbus_dev_fatal(pdev->xdev, err,
- "No more space on root virtual PCI bus");
-
-- unlock:
-+unlock:
- spin_unlock_irqrestore(&slot_dev->lock, flags);
-
- /* Publish this device. */
-- if(!err)
-+ if (!err)
- err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid);
-
-- out:
-+out:
- return err;
- }
-
-@@ -105,7 +106,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct
pci_dev *dev)
- }
- }
-
-- out:
-+out:
- spin_unlock_irqrestore(&slot_dev->lock, flags);
-
- if (found_dev)
-@@ -156,8 +157,10 @@ void pciback_release_devices(struct pciback_device *pdev)
- pdev->pci_dev_data = NULL;
- }
-
--int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-+ struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus,
-+ unsigned int *devfn)
- {
- int slot, busnr;
- struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-@@ -172,11 +175,12 @@ int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct
pciback_device *pdev
- dev = slot_dev->slots[busnr][slot];
- if (dev && dev->bus->number == pcidev->bus->number
- && dev->devfn == pcidev->devfn
-- && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)) {
-+ && pci_domain_nr(dev->bus) ==
-+ pci_domain_nr(pcidev->bus)) {
- found = 1;
- *domain = 0;
- *bus = busnr;
-- *devfn = PCI_DEVFN(slot,0);
-+ *devfn = PCI_DEVFN(slot, 0);
- goto out;
- }
- }
-diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
-index a5b7ece..721b81b 100644
---- a/drivers/xen/pciback/vpci.c
-+++ b/drivers/xen/pciback/vpci.c
-@@ -125,14 +125,14 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev
*dev,
- xenbus_dev_fatal(pdev->xdev, err,
- "No more space on root virtual PCI bus");
-
-- unlock:
-+unlock:
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
-
- /* Publish this device. */
-- if(!err)
-+ if (!err)
- err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
-
-- out:
-+out:
- return err;
- }
-
-@@ -158,7 +158,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct
pci_dev *dev)
- }
- }
-
-- out:
-+out:
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
-
- if (found_dev)
-@@ -176,9 +176,8 @@ int pciback_init_devices(struct pciback_device *pdev)
-
- spin_lock_init(&vpci_dev->lock);
-
-- for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+ for (slot = 0; slot < PCI_SLOT_MAX; slot++)
- INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
-- }
-
- pdev->pci_dev_data = vpci_dev;
-
-@@ -211,8 +210,10 @@ void pciback_release_devices(struct pciback_device *pdev)
- pdev->pci_dev_data = NULL;
- }
-
--int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
-- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
-+int pciback_get_pcifront_dev(struct pci_dev *pcidev,
-+ struct pciback_device *pdev,
-+ unsigned int *domain, unsigned int *bus,
-+ unsigned int *devfn)
- {
- struct pci_dev_entry *entry;
- struct pci_dev *dev = NULL;
-@@ -227,15 +228,16 @@ int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct
pciback_device *pdev
- list) {
- dev = entry->dev;
- if (dev && dev->bus->number == pcidev->bus->number
-- && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)
-- && dev->devfn == pcidev->devfn)
-- {
-+ && pci_domain_nr(dev->bus) ==
-+ pci_domain_nr(pcidev->bus)
-+ && dev->devfn == pcidev->devfn) {
- found = 1;
- *domain = 0;
- *bus = 0;
-- *devfn = PCI_DEVFN(slot, PCI_FUNC(pcidev->devfn));
-+ *devfn = PCI_DEVFN(slot,
-+ PCI_FUNC(pcidev->devfn));
- }
-- }
-+ }
- }
- spin_unlock_irqrestore(&vpci_dev->lock, flags);
- return found;
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index a85c413..efec585 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -40,7 +40,7 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
- kfree(pdev);
- pdev = NULL;
- }
-- out:
-+out:
- return pdev;
- }
-
-@@ -111,7 +111,7 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
- err = 0;
-
- dev_dbg(&pdev->xdev->dev, "Attached!\n");
-- out:
-+out:
- return err;
- }
-
-@@ -166,11 +166,10 @@ static int pciback_attach(struct pciback_device *pdev)
- "Error switching to connected state!");
-
- dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
-- out:
-+out:
- spin_unlock(&pdev->dev_lock);
-
-- if (magic)
-- kfree(magic);
-+ kfree(magic);
-
- return err;
- }
-@@ -193,7 +192,7 @@ static int pciback_publish_pci_dev(struct pciback_device *pdev,
- "%04x:%02x:%02x.%02x", domain, bus,
- PCI_SLOT(devfn), PCI_FUNC(devfn));
-
-- out:
-+out:
- return err;
- }
-
-@@ -230,7 +229,7 @@ static int pciback_export_device(struct pciback_device *pdev,
- * to other driver domains (as he who controls the bridge can disable
- * it and stop the other devices from working).
- */
-- out:
-+out:
- return err;
- }
-
-@@ -253,8 +252,8 @@ static int pciback_remove_device(struct pciback_device *pdev,
- }
-
- pciback_release_pci_dev(pdev, dev);
--
-- out:
-+
-+out:
- return err;
- }
-
-@@ -314,7 +313,7 @@ static int pciback_publish_pci_root(struct pciback_device *pdev,
- err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
- "root_num", "%d", (root_num + 1));
-
-- out:
-+out:
- return err;
- }
-
-@@ -358,7 +357,7 @@ static int pciback_reconfigure(struct pciback_device *pdev)
- }
- err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
- "%d", &substate);
-- if (err != 1)
-+ if (err != 1)
- substate = XenbusStateUnknown;
-
- switch (substate) {
-@@ -389,14 +388,15 @@ static int pciback_reconfigure(struct pciback_device *pdev)
- "configuration");
- goto out;
- }
--
-+
- err = pciback_export_device(pdev, domain, bus, slot,
- func, i);
- if (err)
- goto out;
-
- /* Publish pci roots. */
-- err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
-+ err = pciback_publish_pci_roots(pdev,
-+ pciback_publish_pci_root);
- if (err) {
- xenbus_dev_fatal(pdev->xdev, err,
- "Error while publish PCI root"
-@@ -412,7 +412,7 @@ static int pciback_reconfigure(struct pciback_device *pdev)
- "Error switching substate of "
- "dev-%d\n", i);
- goto out;
-- }
-+ }
- break;
-
- case XenbusStateClosing:
-@@ -445,7 +445,7 @@ static int pciback_reconfigure(struct pciback_device *pdev)
-
- err = pciback_remove_device(pdev, domain, bus, slot,
- func);
-- if(err)
-+ if (err)
- goto out;
-
- /* TODO: If at some point we implement support for pci
-@@ -466,8 +466,8 @@ static int pciback_reconfigure(struct pciback_device *pdev)
- "Error switching to reconfigured state!");
- goto out;
- }
--
-- out:
-+
-+out:
- spin_unlock(&pdev->dev_lock);
-
- return 0;
-@@ -591,7 +591,7 @@ static int pciback_setup_backend(struct pciback_device *pdev)
- xenbus_dev_fatal(pdev->xdev, err, "Error switching "
- "substate of dev-%d\n", i);
- goto out;
-- }
-+ }
- }
-
- err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
-@@ -607,7 +607,7 @@ static int pciback_setup_backend(struct pciback_device *pdev)
- xenbus_dev_fatal(pdev->xdev, err,
- "Error switching to initialised state!");
-
-- out:
-+out:
- spin_unlock(&pdev->dev_lock);
-
- if (!err)
-@@ -663,7 +663,7 @@ static int pciback_xenbus_probe(struct xenbus_device *dev,
- */
- pciback_be_watch(&pdev->be_watch, NULL, 0);
-
-- out:
-+out:
- return err;
- }
-
-@@ -679,7 +679,7 @@ static int pciback_xenbus_remove(struct xenbus_device *dev)
-
- static const struct xenbus_device_id xenpci_ids[] = {
- {"pci"},
-- {{0}},
-+ {""},
- };
-
- static struct xenbus_driver xenbus_pciback_driver = {
--
1.7.4
-From ca1ee0c25b425d9739b1a24cf911de2e041a2514 Mon Sep 17 00:00:00 2001
+From 7b2fc719094440d3eacacd95fa6a1f5ac495396b Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 8 Mar 2010 18:39:15 -0500
-Subject: [PATCH 017/244] xen-pciback: remove driver_data direct access to struct device
-
-The driver core is going to not allow direct access to the
-driver_data pointer in struct device. Instead, the functions
-dev_get_drvdata() and dev_set_drvdata() should be used.
+Date: Tue, 18 Jan 2011 20:15:21 -0500
+Subject: [PATCH 060/203] xen/mmu: Add the notion of identity (1-1) mapping.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/pciback/xenbus.c | 8 ++++----
- 1 files changed, 4 insertions(+), 4 deletions(-)
+Our P2M tree structure is a three-level. On the leaf nodes
+we set the Machine Frame Number (MFN) of the PFN. What this means
+is that when one does: pfn_to_mfn(pfn), which is used when creating
+PTE entries, you get the real MFN of the hardware. When Xen sets
+up a guest it initially populates a array which has descending
+(or ascending) MFN values, as so:
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index efec585..af6c25a 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -26,7 +26,7 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
- dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
-
- pdev->xdev = xdev;
-- xdev->dev.driver_data = pdev;
-+ dev_set_drvdata(&xdev->dev, pdev);
-
- spin_lock_init(&pdev->dev_lock);
-
-@@ -75,7 +75,7 @@ static void free_pdev(struct pciback_device *pdev)
-
- pciback_release_devices(pdev);
-
-- pdev->xdev->dev.driver_data = NULL;
-+ dev_set_drvdata(&pdev->xdev->dev, NULL);
- pdev->xdev = NULL;
-
- kfree(pdev);
-@@ -476,7 +476,7 @@ out:
- static void pciback_frontend_changed(struct xenbus_device *xdev,
- enum xenbus_state fe_state)
- {
-- struct pciback_device *pdev = xdev->dev.driver_data;
-+ struct pciback_device *pdev = dev_get_drvdata(&xdev->dev);
-
- dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
-
-@@ -669,7 +669,7 @@ out:
-
- static int pciback_xenbus_remove(struct xenbus_device *dev)
- {
-- struct pciback_device *pdev = dev->dev.driver_data;
-+ struct pciback_device *pdev = dev_get_drvdata(&dev->dev);
-
- if (pdev != NULL)
- free_pdev(pdev);
---
-1.7.4
+ idx: 0, 1, 2
+ [0x290F, 0x290E, 0x290D, ..]
+so pfn_to_mfn(2)==0x290D. If you start, restart many guests that list
+starts looking quite random.
-From 585f088e6aec3e4514ac2563852961f71c74e47e Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 8 Mar 2010 18:47:55 -0500
-Subject: [PATCH 018/244] xen-pciback: Fix compile error: 'TASK_NORMAL'
undeclared.
+We graft this structure on our P2M tree structure and stick in
+those MFN in the leafs. But for all other leaf entries, or for the top
+root, or middle one, for which there is a void entry, we assume it is
+"missing". So
+ pfn_to_mfn(0xc0000)=INVALID_P2M_ENTRY.
-Both files were missing the #include <linux/sched.h>
+We add the possibility of setting 1-1 mappings on certain regions, so
+that:
+ pfn_to_mfn(0xc0000)=0xc0000
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/pciback/pci_stub.c | 1 +
- drivers/xen/pciback/pciback_ops.c | 1 +
- 2 files changed, 2 insertions(+), 0 deletions(-)
+The benefit of this is, that we can assume for non-RAM regions (think
+PCI BARs, or ACPI spaces), we can create mappings easily b/c we
+get the PFN value to match the MFN.
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 28222ee..6fc0b6e 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -12,6 +12,7 @@
- #include <linux/kref.h>
- #include <linux/pci.h>
- #include <linux/wait.h>
-+#include <linux/sched.h>
- #include <asm/atomic.h>
- #include <xen/events.h>
- #include <asm/xen/pci.h>
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index bf83dca..2b9a93e 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -7,6 +7,7 @@
- #include <linux/wait.h>
- #include <linux/bitops.h>
- #include <xen/events.h>
-+#include <linux/sched.h>
- #include "pciback.h"
-
- int verbose_request;
---
-1.7.4
+For this to work efficiently we introduce one new page p2m_identity and
+allocate (via reserved_brk) any other pages we need to cover the sides
+(1GB or 4MB boundary violations). All entries in p2m_identity are set to
+INVALID_P2M_ENTRY type (Xen toolstack only recognizes that and MFNs,
+no other fancy value).
+On lookup we spot that the entry points to p2m_identity and return the identity
+value instead of dereferencing and returning INVALID_P2M_ENTRY. If the entry
+points to an allocated page, we just proceed as before and return the PFN.
+If the PFN has IDENTITY_FRAME_BIT set we unmask that in appropriate functions
+(pfn_to_mfn).
-From 03dd111c81bad8e69cdb8b5d67381702adb24593 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 9 Dec 2009 17:43:16 -0500
-Subject: [PATCH 019/244] xen-pciback: Remove the vestiges of CONFIG_PCI_GUESTDEV.
+The reason for having the IDENTITY_FRAME_BIT instead of just returning the
+PFN is that we could find ourselves where pfn_to_mfn(pfn)==pfn for a
+non-identity pfn. To protect ourselves against we elect to set (and get) the
+IDENTITY_FRAME_BIT on all identity mapped PFNs.
-The same functionality for this (that used to be called
-pci_is_guestdev) is now via: "pci=resource_alignment="
-command line argument.
+This simplistic diagram is used to explain the more subtle piece of code.
+There is also a digram of the P2M at the end that can help.
+Imagine your E820 looking as so:
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/pci_stub.c | 10 ----------
- 1 files changed, 0 insertions(+), 10 deletions(-)
+ 1GB 2GB
+/-------------------+---------\/----\ /----------\ /---+-----\
+| System RAM | Sys RAM ||ACPI| | reserved | | Sys RAM |
+\-------------------+---------/\----/ \----------/ \---+-----/
+ ^- 1029MB ^- 2001MB
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 6fc0b6e..d30aa7c 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -430,16 +430,6 @@ static int __devinit pcistub_probe(struct pci_dev *dev,
-
- dev_info(&dev->dev, "seizing device\n");
- err = pcistub_seize(dev);
--#ifdef CONFIG_PCI_GUESTDEV
-- } else if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-- if (!pci_is_guestdev(dev)) {
-- err = -ENODEV;
-- goto out;
-- }
--
-- dev_info(&dev->dev, "seizing device\n");
-- err = pcistub_seize(dev);
--#endif /* CONFIG_PCI_GUESTDEV */
- } else
- /* Didn't find the device */
- err = -ENODEV;
---
-1.7.4
+[1029MB = 263424 (0x40500), 2001MB = 512256 (0x7D100), 2048MB = 524288 (0x80000)]
+And dom0_mem=max:3GB,1GB is passed in to the guest, meaning memory past 1GB
+is actually not present (would have to kick the balloon driver to put it in).
-From 30acb3491495a43b59a64612ad92a7a290c59e82 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 9 Dec 2009 17:43:17 -0500
-Subject: [PATCH 020/244] xen-pciback: Remove deprecated routine to find domain owner of
PCI device.
+When we are told to set the PFNs for identity mapping (see patch: "xen/setup:
+Set identity mapping for non-RAM E820 and E820 gaps.") we pass in the start
+of the PFN and the end PFN (263424 and 512256 respectively). The first step is
+to reserve_brk a top leaf page if the p2m[1] is missing. The top leaf page
+covers 512^2 of page estate (1GB) and in case the start or end PFN is not
+aligned on 512^2*PAGE_SIZE (1GB) we loop on aligned 1GB PFNs from start pfn to
+end pfn. We reserve_brk top leaf pages if they are missing (means they point
+to p2m_mid_missing).
-In linux-2.6.18.hg tree the mechanism to find the domain owner was
-for the MSI driver (msi-xen.c) to call in this function to retrieve
-the domain number. This is not the way anymore.
+With the E820 example above, 263424 is not 1GB aligned so we allocate a
+reserve_brk page which will cover the PFNs estate from 0x40000 to 0x80000.
+Each entry in the allocate page is "missing" (points to p2m_missing).
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Next stage is to determine if we need to do a more granular boundary check
+on the 4MB (or 2MB depending on architecture) off the start and end pfn's.
+We check if the start pfn and end pfn violate that boundary check, and if
+so reserve_brk a middle (p2m[x][y]) leaf page. This way we have a much finer
+granularity of setting which PFNs are missing and which ones are identity.
+In our example 263424 and 512256 both fail the check so we reserve_brk two
+pages. Populate them with INVALID_P2M_ENTRY (so they both have "missing"
values)
+and assign them to p2m[1][2] and p2m[1][488] respectively.
+
+At this point we would at minimum reserve_brk one page, but could be up to
+three. Each call to set_phys_range_identity has at maximum a three page
+cost. If we were to query the P2M at this stage, all those entries from
+start PFN through end PFN (so 1029MB -> 2001MB) would return INVALID_P2M_ENTRY
+("missing").
+
+The next step is to walk from the start pfn to the end pfn setting
+the IDENTITY_FRAME_BIT on each PFN. This is done in 'set_phys_range_identity'.
+If we find that the middle leaf is pointing to p2m_missing we can swap it over
+to p2m_identity - this way covering 4MB (or 2MB) PFN space. At this point we
+do not need to worry about boundary aligment (so no need to reserve_brk a middle
+page, figure out which PFNs are "missing" and which ones are identity), as
that
+has been done earlier. If we find that the middle leaf is not occupied by
+p2m_identity or p2m_missing, we dereference that page (which covers
+512 PFNs) and set the appropriate PFN with IDENTITY_FRAME_BIT. In our example
+263424 and 512256 end up there, and we set from p2m[1][2][256->511] and
+p2m[1][488][0->256] with IDENTITY_FRAME_BIT set.
+
+All other regions that are void (or not filled) either point to p2m_missing
+(considered missing) or have the default value of INVALID_P2M_ENTRY (also
+considered missing). In our case, p2m[1][2][0->255] and p2m[1][488][257->511]
+contain the INVALID_P2M_ENTRY value and are considered "missing."
+
+This is what the p2m ends up looking (for the E820 above) with this
+fabulous drawing:
+
+ p2m /--------------\
+ /-----\ | &mfn_list[0],| /-----------------\
+ | 0 |------>| &mfn_list[1],| /---------------\ | ~0, ~0, .. |
+ |-----| | ..., ~0, ~0 | | ~0, ~0, [x]---+----->| IDENTITY [@256] |
+ | 1 |---\ \--------------/ | [p2m_identity]+\ | IDENTITY [@257] |
+ |-----| \ | [p2m_identity]+\\ | .... |
+ | 2 |--\ \-------------------->| ... | \\ \----------------/
+ |-----| \ \---------------/ \\
+ | 3 |\ \ \\ p2m_identity
+ |-----| \ \-------------------->/---------------\ /-----------------\
+ | .. +->+ | [p2m_identity]+-->| ~0, ~0, ~0, ... |
+ \-----/ / | [p2m_identity]+-->| ..., ~0 |
+ / /---------------\ | .... | \-----------------/
+ / | IDENTITY[@0] | /-+-[x], ~0, ~0.. |
+ / | IDENTITY[@256]|<----/ \---------------/
+ / | ~0, ~0, .... |
+ | \---------------/
+ |
+ p2m_missing p2m_missing
+/------------------\ /------------\
+| [p2m_mid_missing]+---->| ~0, ~0, ~0 |
+| [p2m_mid_missing]+---->| ..., ~0 |
+\------------------/ \------------/
+
+where ~0 is INVALID_P2M_ENTRY. IDENTITY is (PFN | IDENTITY_BIT)
+
+[v5: Changed code to use ranges, added ASCII art]
+[v6: Rebased on top of xen->p2m code split]
+[v4: Squished patches in just this one]
+[v7: Added RESERVE_BRK for potentially allocated pages]
+[v8: Fixed alignment problem]
+[v9: Changed 1<<3X to 1<<BITS_PER_LONG-X]
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/pciback/pci_stub.c | 19 -------------------
- 1 files changed, 0 insertions(+), 19 deletions(-)
+ arch/x86/include/asm/xen/page.h | 8 ++-
+ arch/x86/xen/p2m.c | 113 ++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 117 insertions(+), 4 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index d30aa7c..30e7b59 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -1157,22 +1157,6 @@ static ssize_t permissive_show(struct device_driver *drv, char
*buf)
+diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
+index 8ea9772..65fa4f2 100644
+--- a/arch/x86/include/asm/xen/page.h
++++ b/arch/x86/include/asm/xen/page.h
+@@ -29,8 +29,10 @@ typedef struct xpaddr {
- DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
+ /**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
+ #define INVALID_P2M_ENTRY (~0UL)
+-#define FOREIGN_FRAME_BIT (1UL<<31)
++#define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1))
++#define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2))
+ #define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
++#define IDENTITY_FRAME(m) ((m) | IDENTITY_FRAME_BIT)
--#ifdef CONFIG_PCI_MSI
--
--int pciback_get_owner(struct pci_dev *dev)
--{
-- struct pcistub_device *psdev;
--
-- psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number,
-- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
--
-- if (!psdev || !psdev->pdev)
-- return -1;
--
-- return psdev->pdev->xdev->otherend_id;
--}
--#endif
--
- static void pcistub_exit(void)
+ /* Maximum amount of memory we can handle in a domain in pages */
+ #define MAX_DOMAIN_PAGES \
+@@ -42,6 +44,8 @@ extern unsigned int machine_to_phys_order;
+ extern unsigned long get_phys_to_machine(unsigned long pfn);
+ extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
+ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
++extern unsigned long set_phys_range_identity(unsigned long pfn_s,
++ unsigned long pfn_e);
+
+ extern int m2p_add_override(unsigned long mfn, struct page *page);
+ extern int m2p_remove_override(struct page *page);
+@@ -58,7 +62,7 @@ static inline unsigned long pfn_to_mfn(unsigned long pfn)
+ mfn = get_phys_to_machine(pfn);
+
+ if (mfn != INVALID_P2M_ENTRY)
+- mfn &= ~FOREIGN_FRAME_BIT;
++ mfn &= ~(FOREIGN_FRAME_BIT | IDENTITY_FRAME_BIT);
+
+ return mfn;
+ }
+diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
+index df4e367..dd30ec8 100644
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -59,9 +59,15 @@ static RESERVE_BRK_ARRAY(unsigned long **, p2m_top,
P2M_TOP_PER_PAGE);
+ static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
+ static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
+
++static RESERVE_BRK_ARRAY(unsigned long, p2m_identity, P2M_PER_PAGE);
++
+ RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE *
P2M_MID_PER_PAGE)));
+ RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE *
P2M_MID_PER_PAGE)));
+
++/* We might hit two boundary violations at the start and end, at max each
++ * boundary violation will require three middle nodes. */
++RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
++
+ static inline unsigned p2m_top_index(unsigned long pfn)
{
- driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
-@@ -1183,7 +1167,6 @@ static void pcistub_exit(void)
- driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
+ BUG_ON(pfn >= MAX_P2M_PFN);
+@@ -221,6 +227,9 @@ void __init xen_build_dynamic_phys_to_machine(void)
+ p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_top_init(p2m_top);
- pci_unregister_driver(&pciback_pci_driver);
-- WARN_ON(unregister_msi_get_owner(pciback_get_owner));
++ p2m_identity = extend_brk(PAGE_SIZE, PAGE_SIZE);
++ p2m_init(p2m_identity);
++
+ /*
+ * The domain builder gives us a pre-constructed p2m array in
+ * mfn_list for all the pages initially given to us, so we just
+@@ -272,6 +281,14 @@ unsigned long get_phys_to_machine(unsigned long pfn)
+ mididx = p2m_mid_index(pfn);
+ idx = p2m_index(pfn);
+
++ /*
++ * The INVALID_P2M_ENTRY is filled in both p2m_*identity
++ * and in p2m_*missing, so returning the INVALID_P2M_ENTRY
++ * would be wrong.
++ */
++ if (p2m_top[topidx][mididx] == p2m_identity)
++ return IDENTITY_FRAME(pfn);
++
+ return p2m_top[topidx][mididx][idx];
}
+ EXPORT_SYMBOL_GPL(get_phys_to_machine);
+@@ -341,9 +358,11 @@ static bool alloc_p2m(unsigned long pfn)
+ p2m_top_mfn_p[topidx] = mid_mfn;
+ }
- static int __init pcistub_init(void)
-@@ -1241,8 +1224,6 @@ static int __init pcistub_init(void)
- err = driver_create_file(&pciback_pci_driver.driver,
- &driver_attr_permissive);
+- if (p2m_top[topidx][mididx] == p2m_missing) {
++ if (p2m_top[topidx][mididx] == p2m_identity ||
++ p2m_top[topidx][mididx] == p2m_missing) {
+ /* p2m leaf page is missing */
+ unsigned long *p2m;
++ unsigned long *p2m_orig = p2m_top[topidx][mididx];
-- if (!err)
-- err = register_msi_get_owner(pciback_get_owner);
- if (err)
- pcistub_exit();
+ p2m = alloc_p2m_page();
+ if (!p2m)
+@@ -351,7 +370,7 @@ static bool alloc_p2m(unsigned long pfn)
+
+ p2m_init(p2m);
+
+- if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
++ if (cmpxchg(&mid[mididx], p2m_orig, p2m) != p2m_orig)
+ free_p2m_page(p2m);
+ else
+ mid_mfn[mididx] = virt_to_mfn(p2m);
+@@ -360,6 +379,82 @@ static bool alloc_p2m(unsigned long pfn)
+ return true;
+ }
+
++bool __early_alloc_p2m(unsigned long pfn)
++{
++ unsigned topidx, mididx, idx;
++
++ topidx = p2m_top_index(pfn);
++ mididx = p2m_mid_index(pfn);
++ idx = p2m_index(pfn);
++
++ /* Pfff.. No boundary cross-over, lets get out. */
++ if (!idx)
++ return false;
++
++ WARN(p2m_top[topidx][mididx] == p2m_identity,
++ "P2M[%d][%d] == IDENTITY, should be MISSING (or alloced)!\n",
++ topidx, mididx);
++
++ /*
++ * Could be done by xen_build_dynamic_phys_to_machine..
++ */
++ if (p2m_top[topidx][mididx] != p2m_missing)
++ return false;
++
++ /* Boundary cross-over for the edges: */
++ if (idx) {
++ unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
++
++ p2m_init(p2m);
++
++ p2m_top[topidx][mididx] = p2m;
++
++ }
++ return idx != 0;
++}
++unsigned long set_phys_range_identity(unsigned long pfn_s,
++ unsigned long pfn_e)
++{
++ unsigned long pfn;
++
++ if (unlikely(pfn_s >= MAX_P2M_PFN || pfn_e >= MAX_P2M_PFN))
++ return 0;
++
++ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap)))
++ return pfn_e - pfn_s;
++
++ if (pfn_s > pfn_e)
++ return 0;
++
++ for (pfn = (pfn_s & ~(P2M_MID_PER_PAGE * P2M_PER_PAGE - 1));
++ pfn < ALIGN(pfn_e, (P2M_MID_PER_PAGE * P2M_PER_PAGE));
++ pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE)
++ {
++ unsigned topidx = p2m_top_index(pfn);
++ if (p2m_top[topidx] == p2m_mid_missing) {
++ unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
++
++ p2m_mid_init(mid);
++
++ p2m_top[topidx] = mid;
++ }
++ }
++
++ __early_alloc_p2m(pfn_s);
++ __early_alloc_p2m(pfn_e);
++
++ for (pfn = pfn_s; pfn < pfn_e; pfn++)
++ if (!__set_phys_to_machine(pfn, IDENTITY_FRAME(pfn)))
++ break;
++
++ if (!WARN((pfn - pfn_s) != (pfn_e - pfn_s),
++ "Identity mapping failed. We are %ld short of 1-1 mappings!\n",
++ (pfn_e - pfn_s) - (pfn - pfn_s)))
++ printk(KERN_DEBUG "1-1 mapping on %lx->%lx\n", pfn_s, pfn);
++
++ return pfn - pfn_s;
++}
++
+ /* Try to install p2m mapping; fail if intermediate bits missing */
+ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+ {
+@@ -378,6 +473,20 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+ mididx = p2m_mid_index(pfn);
+ idx = p2m_index(pfn);
+
++ /* For sparse holes were the p2m leaf has real PFN along with
++ * PCI holes, stick in the PFN as the MFN value.
++ */
++ if (mfn != INVALID_P2M_ENTRY && (mfn & IDENTITY_FRAME_BIT)) {
++ if (p2m_top[topidx][mididx] == p2m_identity)
++ return true;
++
++ /* Swap over from MISSING to IDENTITY if needed. */
++ if (p2m_top[topidx][mididx] == p2m_missing) {
++ p2m_top[topidx][mididx] = p2m_identity;
++ return true;
++ }
++ }
++
+ if (p2m_top[topidx][mididx] == p2m_missing)
+ return mfn == INVALID_P2M_ENTRY;
--
1.7.4
-From da36c7662d9738ce44c37b4f1f41c045c64d6914 Mon Sep 17 00:00:00 2001
+From 57fafbb798ffde486606244c3392ed6f63050222 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 22 Dec 2009 13:53:41 -0500
-Subject: [PATCH 021/244] xen-pciback: Fix compiler warning in pci_stub.c.
+Date: Wed, 5 Jan 2011 15:46:31 -0500
+Subject: [PATCH 061/203] xen/mmu: Set _PAGE_IOMAP if PFN is an identity PFN.
-warning: the frame size of 1036 bytes is larger than 1024 bytes
+If we find that the PFN is within the P2M as an identity
+PFN make sure to tack on the _PAGE_IOMAP flag.
+Reviewed-by: Ian Campbell <ian.campbell(a)citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/pciback/pci_stub.c | 5 +++--
- 1 files changed, 3 insertions(+), 2 deletions(-)
+ arch/x86/xen/mmu.c | 18 ++++++++++++++++--
+ 1 files changed, 16 insertions(+), 2 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 30e7b59..0b5a16b 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -496,16 +496,17 @@ static const struct pci_device_id pcistub_ids[] = {
- {0,},
- };
-
-+#define PCI_NODENAME_MAX 40
- static void kill_domain_by_device(struct pcistub_device *psdev)
- {
- struct xenbus_transaction xbt;
- int err;
-- char nodename[1024];
-+ char nodename[PCI_NODENAME_MAX];
+diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
+index 0180ae8..9c9e076 100644
+--- a/arch/x86/xen/mmu.c
++++ b/arch/x86/xen/mmu.c
+@@ -416,8 +416,12 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
+ if (val & _PAGE_PRESENT) {
+ unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
+ pteval_t flags = val & PTE_FLAGS_MASK;
+- unsigned long mfn = pfn_to_mfn(pfn);
++ unsigned long mfn;
- if (!psdev)
- dev_err(&psdev->dev->dev,
- "device is NULL when do AER recovery/kill_domain\n");
-- sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
-+ snprintf(nodename, PCI_NODENAME_MAX, "/local/domain/0/backend/pci/%d/0",
- psdev->pdev->xdev->otherend_id);
- nodename[strlen(nodename)] = '\0';
++ if (!xen_feature(XENFEAT_auto_translated_physmap))
++ mfn = get_phys_to_machine(pfn);
++ else
++ mfn = pfn;
+ /*
+ * If there's no mfn for the pfn, then just create an
+ * empty non-present pte. Unfortunately this loses
+@@ -427,8 +431,18 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
+ if (unlikely(mfn == INVALID_P2M_ENTRY)) {
+ mfn = 0;
+ flags = 0;
++ } else {
++ /*
++ * Paramount to do this test _after_ the
++ * INVALID_P2M_ENTRY as INVALID_P2M_ENTRY &
++ * IDENTITY_FRAME_BIT resolves to true.
++ */
++ mfn &= ~FOREIGN_FRAME_BIT;
++ if (mfn & IDENTITY_FRAME_BIT) {
++ mfn &= ~IDENTITY_FRAME_BIT;
++ flags |= _PAGE_IOMAP;
++ }
+ }
+-
+ val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
+ }
--
1.7.4
-From 83484f34b2cc42807c71514fbabbd40e281ec094 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 22 Dec 2009 13:53:42 -0500
-Subject: [PATCH 022/244] xen-pciback: Fix compile warning in vpci.c
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-warning: ‘func’ may be used uninitialized in this function
+From e6f1e7aabca9f9f99ef4fc1c752497b3efa7896c Mon Sep 17 00:00:00 2001
+From: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Date: Mon, 31 Jan 2011 15:18:10 +0000
+Subject: [PATCH 062/203] x86/mm/init: respect memblock reserved regions when destroying
mappings
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/pciback/vpci.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+x86/mm/init: respect memblock reserved regions when destroying mappings
-diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
-index 721b81b..2857ab8 100644
---- a/drivers/xen/pciback/vpci.c
-+++ b/drivers/xen/pciback/vpci.c
-@@ -65,7 +65,7 @@ static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
- int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
- int devid, publish_pci_dev_cb publish_cb)
- {
-- int err = 0, slot, func;
-+ int err = 0, slot, func = -1;
- struct pci_dev_entry *t, *dev_entry;
- struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
- unsigned long flags;
---
-1.7.4
+In init_memory_mapping we are destroying all the mappings between
+_brk_end and _end, no matter if some memory areas in that range have
+been reserved using memblock_x86_reserve_range.
+Besides if _end is not pmd aligned we might destroy the
+mappings for valid memory between _end and the following pmd.
+In order to avoid this problem, before clearing any pmds we check if the
+corresponding memory area has been reserved and we only destroy the
+mapping if it hasn't.
-From 5612e6358835700c49d8be5671823614ace30c94 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ijc(a)hellion.org.uk>
-Date: Thu, 3 Dec 2009 21:56:20 +0000
-Subject: [PATCH 023/244] xen: rename pciback module to xen-pciback.
+We found this problem because under Xen we have a valid mapping at _end,
+and if _end is not pmd aligned the current code destroys the initial
+part of it.
-pciback is rather generic for a modular distro style kernel.
+In practice this fix does not have any impact on native.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Cc: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Signed-off-by: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
---
- drivers/xen/pciback/Makefile | 24 ++++++++++++------------
- 1 files changed, 12 insertions(+), 12 deletions(-)
+ arch/x86/mm/init.c | 13 +++++++++++--
+ 1 files changed, 11 insertions(+), 2 deletions(-)
-diff --git a/drivers/xen/pciback/Makefile b/drivers/xen/pciback/Makefile
-index 106dae7..38bc123 100644
---- a/drivers/xen/pciback/Makefile
-+++ b/drivers/xen/pciback/Makefile
-@@ -1,16 +1,16 @@
--obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
-+obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o
+diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
+index 947f42a..66637bd 100644
+--- a/arch/x86/mm/init.c
++++ b/arch/x86/mm/init.c
+@@ -283,6 +283,8 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
+ if (!after_bootmem && !start) {
+ pud_t *pud;
+ pmd_t *pmd;
++ unsigned long addr;
++ u64 size, memblock_addr;
--pciback-y := pci_stub.o pciback_ops.o xenbus.o
--pciback-y += conf_space.o conf_space_header.o \
-- conf_space_capability.o \
-- conf_space_capability_vpd.o \
-- conf_space_capability_pm.o \
-- conf_space_quirks.o
--pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
--pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
--pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
--pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
--pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
-+xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o
-+xen-pciback-y += conf_space.o conf_space_header.o \
-+ conf_space_capability.o \
-+ conf_space_capability_vpd.o \
-+ conf_space_capability_pm.o \
-+ conf_space_quirks.o
-+xen-pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
-+xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
-+xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
-+xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
-+xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
+ mmu_cr4_features = read_cr4();
- ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
- EXTRA_CFLAGS += -DDEBUG
+@@ -291,11 +293,18 @@ unsigned long __init_refok init_memory_mapping(unsigned long
start,
+ * located on different 2M pages. cleanup_highmap(), however,
+ * can only consider _end when it runs, so destroy any
+ * mappings beyond _brk_end here.
++ * Respect memblock reserved regions.
+ */
+ pud = pud_offset(pgd_offset_k(_brk_end), _brk_end);
+ pmd = pmd_offset(pud, _brk_end - 1);
+- while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1))
+- pmd_clear(pmd);
++ addr = (_brk_end + PMD_SIZE - 1) & PMD_MASK;
++ while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1)) {
++ memblock_addr = memblock_x86_find_in_range_size(__pa(addr),
++ &size, PMD_SIZE);
++ if (memblock_addr == (u64) __pa(addr) && size >= PMD_SIZE)
++ pmd_clear(pmd);
++ addr += PMD_SIZE;
++ }
+ }
+ #endif
+ __flush_tlb_all();
--
1.7.4
-From 245a9ec5ef1f9c8a6bc6b5c0ac1bb616c3c8c979 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 9 Dec 2009 17:43:15 -0500
-Subject: [PATCH 024/244] xen-pciback: Register the owner (domain) of the PCI device.
+From 203b40c0915fc78e9ca1524c887623e7dc86422d Mon Sep 17 00:00:00 2001
+From: Bastian Blank <waldi(a)debian.org>
+Date: Thu, 29 Jul 2010 17:30:18 +0200
+Subject: [PATCH 063/203] xen: netback: Fix null-pointer access in netback_uevent
-When the front-end and back-end start negotiating we register
-the domain that will use the PCI device. Furthermore during shutdown
-of guest or unbinding of the PCI device (and unloading of module)
-from pciback we unregister the domain owner.
+The uevent method of Xen netback does not check if the the network
+device is already setup and tries to dereference a null-pointer if not.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Bastian Blank <waldi(a)debian.org>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/pciback/pci_stub.c | 2 ++
- drivers/xen/pciback/xenbus.c | 13 +++++++++++++
- 2 files changed, 15 insertions(+), 0 deletions(-)
+ drivers/xen/netback/xenbus.c | 10 ++--------
+ 1 files changed, 2 insertions(+), 8 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 0b5a16b..02178e2 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -90,6 +90,8 @@ static void pcistub_device_release(struct kref *kref)
-
- dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
-
-+ xen_unregister_device_domain_owner(psdev->dev);
-+
- /* Clean-up the device */
- pciback_reset_device(psdev->dev);
- pciback_config_free_dyn_fields(psdev->dev);
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index af6c25a..d448bf5 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -10,6 +10,7 @@
- #include <linux/workqueue.h>
- #include <xen/xenbus.h>
- #include <xen/events.h>
-+#include <asm/xen/pci.h>
- #include <linux/workqueue.h>
- #include "pciback.h"
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index 17ff5cf..1fec65a 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -154,17 +154,11 @@ fail:
+ */
+ static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
+ {
+- struct backend_info *be;
+- struct xen_netif *netif;
++ struct backend_info *be = dev_get_drvdata(&xdev->dev);
+ char *val;
-@@ -221,6 +222,15 @@ static int pciback_export_device(struct pciback_device *pdev,
- if (err)
- goto out;
+ DPRINTK("netback_uevent");
-+ dev_dbg(&dev->dev, "registering for %d\n",
pdev->xdev->otherend_id);
-+ if (xen_register_device_domain_owner(dev,
-+ pdev->xdev->otherend_id) != 0) {
-+ dev_err(&dev->dev, "device has been assigned to another " \
-+ "domain! Over-writting the ownership, but beware.\n");
-+ xen_unregister_device_domain_owner(dev);
-+ xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
-+ }
-+
- /* TODO: It'd be nice to export a bridge and have all of its children
- * get exported with it. This may be best done in xend (which will
- * have to calculate resource usage anyway) but we probably want to
-@@ -251,6 +261,9 @@ static int pciback_remove_device(struct pciback_device *pdev,
- goto out;
+- be = dev_get_drvdata(&xdev->dev);
+- if (!be)
+- return 0;
+- netif = be->netif;
+-
+ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
+ if (IS_ERR(val)) {
+ int err = PTR_ERR(val);
+@@ -179,7 +173,7 @@ static int netback_uevent(struct xenbus_device *xdev, struct
kobj_uevent_env *en
+ kfree(val);
}
-+ dev_dbg(&dev->dev, "unregistering for %d\n",
pdev->xdev->otherend_id);
-+ xen_unregister_device_domain_owner(dev);
-+
- pciback_release_pci_dev(pdev, dev);
+- if (add_uevent_var(env, "vif=%s", netif->dev->name))
++ if (be && be->netif && add_uevent_var(env, "vif=%s",
be->netif->dev->name))
+ return -ENOMEM;
- out:
+ return 0;
--
1.7.4
-From cb6c976606d16119e8608c8bcc1ef9265881dd7f Mon Sep 17 00:00:00 2001
-From: Zhao, Yu <yu.zhao(a)intel.com>
-Date: Wed, 3 Mar 2010 13:27:55 -0500
-Subject: [PATCH 025/244] xen-pciback: guest SR-IOV support for PV guest
+From bee16269e5ba79706bdae554013cd14285b4f1ad Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 30 Jul 2010 15:16:47 +0100
+Subject: [PATCH 064/203] xen: netback: check if foreign pages are actually
netback-created foreign pages.
-These changes are for PV guest to use Virtual Function. Because the VF's
-vendor, device registers in cfg space are 0xffff, which are invalid and
-ignored by PCI device scan. Values in 'struct pci_dev' are fixed up by
-SR-IOV code, and using these values will present correct VID and DID to
-PV guest kernel.
+020ba906 "xen/netback: Multiple tasklets support." changed
+netbk_gop_frag_copy to attempt to lookup a pending_tx_info for any
+foreign page, regardless of whether the page was a netback-foreign
+page.
-And command registers in the cfg space are read only 0, which means we
-have to emulate MMIO enable bit (VF only uses MMIO resource) so PV
-kernel can work properly.
+In the case of non-netback pages this can lead to dereferencing a NULL
+src_pend->netif.
-Acked-by: jbeulich(a)novell.com
+Restore the behaviour of netif_page_index prior toa3031942
+"xen/netback: Introduce a new struct type page_ext" by performing
+tests to ensure that page is a netback page and extend the same checks
+to netif_page_group.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Actually combine netif_page_{index,group} in to a single function
+since they are always called together and it saves duplicating all the
+checks.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: Xu, Dongxiao <dongxiao.xu(a)intel.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/pciback/conf_space_header.c | 71 ++++++++++++++++++++++++++++--
- 1 files changed, 66 insertions(+), 5 deletions(-)
+ drivers/xen/netback/netback.c | 56 ++++++++++++++++++++++++++++------------
+ 1 files changed, 39 insertions(+), 17 deletions(-)
-diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
-index 3ae7da1..1f4f86e 100644
---- a/drivers/xen/pciback/conf_space_header.c
-+++ b/drivers/xen/pciback/conf_space_header.c
-@@ -18,6 +18,25 @@ struct pci_bar_info {
- #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
- #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 911c85b..95df223 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -89,18 +89,37 @@ static inline void netif_set_page_ext(struct page *pg, unsigned int
group,
+ pg->mapping = ext.mapping;
+ }
-+static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
-+{
-+ int i;
-+ int ret;
+-static inline unsigned int netif_page_group(const struct page *pg)
++static inline int netif_get_page_ext(struct page *pg, unsigned int *_group, unsigned int
*_idx)
+ {
+ union page_ext ext = { .mapping = pg->mapping };
++ struct xen_netbk *netbk;
++ unsigned int group, idx;
+
+- return ext.e.group - 1;
+-}
++ if (!PageForeign(pg))
++ return 0;
+
+-static inline unsigned int netif_page_index(const struct page *pg)
+-{
+- union page_ext ext = { .mapping = pg->mapping };
++ group = ext.e.group - 1;
+
-+ ret = pciback_read_config_word(dev, offset, value, data);
-+ if (!atomic_read(&dev->enable_cnt))
-+ return ret;
++ if (group < 0 || group >= xen_netbk_group_nr)
++ return 0;
+
-+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
-+ if (dev->resource[i].flags & IORESOURCE_IO)
-+ *value |= PCI_COMMAND_IO;
-+ if (dev->resource[i].flags & IORESOURCE_MEM)
-+ *value |= PCI_COMMAND_MEMORY;
-+ }
++ netbk = &xen_netbk[group];
+
-+ return ret;
-+}
++ if (netbk->mmap_pages == NULL)
++ return 0;
+
+- return ext.e.idx;
++ idx = ext.e.idx;
+
- static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
- {
- int err;
-@@ -142,10 +161,26 @@ static inline void read_dev_bar(struct pci_dev *dev,
- struct pci_bar_info *bar_info, int offset,
- u32 len_mask)
- {
-- pci_read_config_dword(dev, offset, &bar_info->val);
-- pci_write_config_dword(dev, offset, len_mask);
-- pci_read_config_dword(dev, offset, &bar_info->len_val);
-- pci_write_config_dword(dev, offset, bar_info->val);
-+ int pos;
-+ struct resource *res = dev->resource;
++ if ((idx < 0) || (idx >= MAX_PENDING_REQS))
++ return 0;
+
-+ if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
-+ pos = PCI_ROM_RESOURCE;
-+ else {
-+ pos = (offset - PCI_BASE_ADDRESS_0) / 4;
-+ if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
-+ PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
-+ (PCI_BASE_ADDRESS_SPACE_MEMORY |
-+ PCI_BASE_ADDRESS_MEM_TYPE_64))) {
-+ bar_info->val = res[pos - 1].start >> 32;
-+ bar_info->len_val = res[pos - 1].end >> 32;
-+ return;
-+ }
-+ }
++ if (netbk->mmap_pages[idx] != pg)
++ return 0;
+
-+ bar_info->val = res[pos].start |
-+ (res[pos].flags & PCI_REGION_FLAG_MASK);
-+ bar_info->len_val = res[pos].end - res[pos].start + 1;
++ *_group = group;
++ *_idx = idx;
++
++ return 1;
}
- static void *bar_init(struct pci_dev *dev, int offset)
-@@ -186,6 +221,22 @@ static void bar_release(struct pci_dev *dev, int offset, void
*data)
- kfree(data);
- }
+ /*
+@@ -386,8 +405,12 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ {
+ struct gnttab_copy *copy_gop;
+ struct netbk_rx_meta *meta;
+- int group = netif_page_group(page);
+- int idx = netif_page_index(page);
++ /*
++ * These variables a used iff netif_get_page_ext returns true,
++ * in which case they are guaranteed to be initialized.
++ */
++ unsigned int uninitialized_var(group), uninitialized_var(idx);
++ int foreign = netif_get_page_ext(page, &group, &idx);
+ unsigned long bytes;
-+static int pciback_read_vendor(struct pci_dev *dev, int offset,
-+ u16 *value, void *data)
-+{
-+ *value = dev->vendor;
-+
-+ return 0;
-+}
-+
-+static int pciback_read_device(struct pci_dev *dev, int offset,
-+ u16 *value, void *data)
-+{
-+ *value = dev->device;
+ /* Data must not cross a page boundary. */
+@@ -445,7 +468,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+
+ copy_gop = npo->copy + npo->copy_prod++;
+ copy_gop->flags = GNTCOPY_dest_gref;
+- if (PageForeign(page)) {
++ if (foreign) {
+ struct xen_netbk *netbk = &xen_netbk[group];
+ struct pending_tx_info *src_pend;
+
+@@ -1535,14 +1558,13 @@ static void netif_idx_release(struct xen_netbk *netbk, u16
pending_idx)
+
+ static void netif_page_release(struct page *page, unsigned int order)
+ {
+- int group = netif_page_group(page);
+- int idx = netif_page_index(page);
+- struct xen_netbk *netbk = &xen_netbk[group];
++ unsigned int group, idx;
++ int foreign = netif_get_page_ext(page, &group, &idx);
+
-+ return 0;
-+}
++ BUG_ON(!foreign);
+ BUG_ON(order);
+- BUG_ON(group < 0 || group >= xen_netbk_group_nr);
+- BUG_ON(idx < 0 || idx >= MAX_PENDING_REQS);
+- BUG_ON(netbk->mmap_pages[idx] != page);
+- netif_idx_release(netbk, idx);
+
- static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
- void *data)
- {
-@@ -213,9 +264,19 @@ out:
++ netif_idx_release(&xen_netbk[group], idx);
+ }
- static const struct config_field header_common[] = {
- {
-+ .offset = PCI_VENDOR_ID,
-+ .size = 2,
-+ .u.w.read = pciback_read_vendor,
-+ },
-+ {
-+ .offset = PCI_DEVICE_ID,
-+ .size = 2,
-+ .u.w.read = pciback_read_device,
-+ },
-+ {
- .offset = PCI_COMMAND,
- .size = 2,
-- .u.w.read = pciback_read_config_word,
-+ .u.w.read = command_read,
- .u.w.write = command_write,
- },
- {
+ irqreturn_t netif_be_int(int irq, void *dev_id)
--
1.7.4
-From 1d77305c7900f3b6ec5d403d9aba6f0034b0112e Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 3 Mar 2010 13:38:43 -0500
-Subject: [PATCH 026/244] xen-pciback: Disable MSI/MSI-X when reseting device
-
-In cases where the guest is abruptly killed and has not disabled
-MSI/MSI-X interrupts we want to do that.
+From 3f33055e8af9d74e35670c52438e190d54ac5f9e Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 30 Jul 2010 15:16:46 +0100
+Subject: [PATCH 065/203] xen: netback: do not unleash netback threads until
initialisation is complete
-Otherwise when the guest is started up and enables MSI, we would
-get a WARN() that the device already had been enabled.
+Otherwise netbk_action_thread can reference &netbk->net_schedule_list
+(via tx_work_todo) before it is initialised. Until now it was zeroed
+which is probably safe but not exactly robust.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: Xu, Dongxiao <dongxiao.xu(a)intel.com>
+Cc: Paul Durrant <Paul.Durrant(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/pciback/pciback_ops.c | 8 ++++++++
- 1 files changed, 8 insertions(+), 0 deletions(-)
+ drivers/xen/netback/netback.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 2b9a93e..011db67 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -23,6 +23,14 @@ void pciback_reset_device(struct pci_dev *dev)
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 95df223..2646383 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1782,7 +1782,6 @@ static int __init netback_init(void)
- /* Disable devices (but not bridges) */
- if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-+#ifdef CONFIG_PCI_MSI
-+ /* The guest could have been abruptly killed without
-+ * disabling MSI/MSI-X interrupts.*/
-+ if (dev->msix_enabled)
-+ pci_disable_msix(dev);
-+ if (dev->msi_enabled)
-+ pci_disable_msi(dev);
-+#endif
- pci_disable_device(dev);
+ if (!IS_ERR(netbk->kthread.task)) {
+ kthread_bind(netbk->kthread.task, group);
+- wake_up_process(netbk->kthread.task);
+ } else {
+ printk(KERN_ALERT
+ "kthread_run() fails at netback\n");
+@@ -1808,6 +1807,9 @@ static int __init netback_init(void)
+ spin_lock_init(&netbk->net_schedule_list_lock);
- pci_write_config_word(dev, PCI_COMMAND, 0);
+ atomic_set(&netbk->netfront_count, 0);
++
++ if (MODPARM_netback_kthread)
++ wake_up_process(netbk->kthread.task);
+ }
+
+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
--
1.7.4
-From c89edb63b60166fe354493dd465cf5662b2c077d Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 12 Apr 2010 11:46:00 -0400
-Subject: [PATCH 027/244] xen-pciback: Allocate IRQ handler for device that is shared with
guest.
+From 329a17f3dbb9c127d431d09df0ed63ec28b8c702 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ijc(a)hellion.org.uk>
+Date: Thu, 2 Sep 2010 14:36:40 +0100
+Subject: [PATCH 066/203] xen: netback: save interrupt state in
add_to_net_schedule_list_tail
-If the pciback module is loaded with fake_irq_handler=1 we install
-for all devices that are to be passed to the guest domain a IRQ handler.
-The IRQ handler will return IRQ_HANDLED or IRQ_NONE depending on
-on the ack_intr flag.
+add_to_net_schedule_list_tail is called from both hard interrupt context
+(add_to_net_schedule_list_tail) and soft interrupt/process context
+(netif_schedule_work) so use the interrupt state saving spinlock
+variants.
-The trigger to install this IRQ handler is when the enable_isr flag
-is set.
+Fixes:
+ ------------[ cut here ]------------
+ WARNING: at kernel/lockdep.c:2323 trace_hardirqs_on_caller+0xef/0x1a0()
+ Hardware name: PowerEdge 860
+ Modules linked in: rtc_cmos rtc_core rtc_lib
+ Pid: 16, comm: xenwatch Not tainted 2.6.32.18-x86_32p-xen0-00850-ge6b9b2c #98
+ Call Trace:
+ [<c103951c>] warn_slowpath_common+0x6c/0xc0
+ [<c1039585>] warn_slowpath_null+0x15/0x20
+ [<c105f60f>] trace_hardirqs_on_caller+0xef/0x1a0
+ [<c105f6cb>] trace_hardirqs_on+0xb/0x10
+ [<c136cc72>] _spin_unlock_irq+0x22/0x40
+ [<c11ab9ef>] add_to_net_schedule_list_tail+0x5f/0xb0
+ [<c11aba6b>] netif_be_int+0x2b/0x120
+ [<c106dd8e>] handle_IRQ_event+0x2e/0xe0
+ [<c106f98e>] handle_level_irq+0x6e/0xf0
+ [<c1197cdf>] __xen_evtchn_do_upcall+0x16f/0x190
+ [<c11981b8>] xen_evtchn_do_upcall+0x28/0x40
+ [<c100b487>] xen_do_upcall+0x7/0xc
+ [<c119bcf9>] xs_talkv+0x59/0x1a0
+ [<c119bf6a>] xs_single+0x3a/0x50
+ [<c119c6f9>] xenbus_read+0x39/0x60
+ [<c11adf77>] frontend_changed+0x3e7/0x6a0
+ [<c119d35a>] xenbus_otherend_changed+0x8a/0xa0
+ [<c119d572>] frontend_changed+0x12/0x20
+ [<c119b9dc>] xenwatch_thread+0x7c/0x140
+ [<c104ea74>] kthread+0x74/0x80
+ [<c100b433>] kernel_thread_helper+0x7/0x10
+ ---[ end trace 48d73949a8e0909a ]---
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/pciback/pci_stub.c | 13 ++++-
- drivers/xen/pciback/pciback.h | 12 ++++-
- drivers/xen/pciback/pciback_ops.c | 95 ++++++++++++++++++++++++++++++++++++-
- 3 files changed, 115 insertions(+), 5 deletions(-)
+ drivers/xen/netback/netback.c | 6 ++++--
+ 1 files changed, 4 insertions(+), 2 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 02178e2..45bbe99 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -21,6 +21,8 @@
- #include "conf_space.h"
- #include "conf_space_quirks.h"
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 2646383..1d080f6 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -787,17 +787,19 @@ static void remove_from_net_schedule_list(struct xen_netif *netif)
-+#define DRV_NAME "pciback"
+ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+ {
++ unsigned long flags;
+
- static char *pci_devs_to_hide;
- wait_queue_head_t aer_wait_queue;
- /*Add sem for sync AER handling and pciback remove/reconfigue ops,
-@@ -290,13 +292,20 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
- * would need to be called somewhere to free the memory allocated
- * here and then to call kfree(pci_get_drvdata(psdev->dev)).
- */
-- dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
-+ dev_data = kzalloc(sizeof(*dev_data) + strlen(DRV_NAME "[]")
-+ + strlen(pci_name(dev)) + 1, GFP_ATOMIC);
- if (!dev_data) {
- err = -ENOMEM;
- goto out;
- }
- pci_set_drvdata(dev, dev_data);
+ struct xen_netbk *netbk = &xen_netbk[netif->group];
+ if (__on_net_schedule_list(netif))
+ return;
-+ /*
-+ * Setup name for fake IRQ handler. It will only be enabled
-+ * once the device is turned on by the guest.
-+ */
-+ sprintf(dev_data->irq_name, DRV_NAME "[%s]", pci_name(dev));
-+
- dev_dbg(&dev->dev, "initializing config\n");
+- spin_lock_irq(&netbk->net_schedule_list_lock);
++ spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
+ if (!__on_net_schedule_list(netif) &&
+ likely(netif_schedulable(netif))) {
+ list_add_tail(&netif->list, &netbk->net_schedule_list);
+ netif_get(netif);
+ }
+- spin_unlock_irq(&netbk->net_schedule_list_lock);
++ spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
+ }
- init_waitqueue_head(&aer_wait_queue);
-@@ -837,7 +846,7 @@ static struct pci_error_handlers pciback_error_handler = {
- */
+ void netif_schedule_work(struct xen_netif *netif)
+--
+1.7.4
+
+
+From 7edc1ededaaa953877d2a052886db4ea2f69effe Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 8 Oct 2010 17:11:51 +0100
+Subject: [PATCH 067/203] xen: netback: increase size of rx_meta array.
+
+We can end up needing as many of these as we need grant copy operations so
+increase the array size for the same reason.
+
+Crash observed on XenServer:
+kernel: ------------[ cut here ]------------
+kernel: kernel BUG at drivers/xen/netback/netback.c:834!
+kernel: invalid opcode: 0000 [#1] SMP
+kernel: last sysfs file: /sys/devices/xen-backend/vbd-10-768/statistics/rd_usecs
+kernel: Process netback (pid: 1413, ti=ec8a4000 task=ed0a6b70 task.ti=ec8a4000)
+kernel: Stack: 00000000 00000612 00000001 00000000 00020000 00000000 ecfbe000 00000000
+kernel: ec8a5f80 ec8a5f98 ec8a5fac 00000000 c0537220 c0539220 00000000 c0534220
+kernel: cd7afaa0 cd7afaa0 0000000c 00000014 062de396 00000001 00000001 00000014
+kernel: Call Trace:
+kernel: [<c0285f10>] ? netbk_action_thread+0x0/0x1fe0
+kernel: [<c013daf2>] ? kthread+0x42/0x70
+kernel: [<c013dab0>] ? kthread+0x0/0x70
+kernel: [<c010569b>] ? kernel_thread_helper+0x7/0x10
+kernel: =======================
+kernel: Code: 00 00 c7 42 08 20 82 53 c0 8b 85 e4 fe ff ff c7 42 10 00 00 00 00 \
+ c7 42 14 f0 7f 00 00 89 42 0c 8b 8d ec fe ff ff e9 3e e9 ff ff <0f>
\
+ 0b eb fe 0f 0b eb fe 0f 0b eb fe 0f 0b eb fe 31 c0 e8 bf 31
+kernel: EIP: [<c028790a>] netbk_action_thread+0x19fa/0x1fe0 SS:ESP 0069:ec8a5d98
+
+Corresponding to
+ BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index a5f3759..ce0041a 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -319,7 +319,7 @@ struct xen_netbk {
+ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
+ unsigned char rx_notify[NR_IRQS];
+ u16 notify_list[NET_RX_RING_SIZE];
+- struct netbk_rx_meta meta[NET_RX_RING_SIZE];
++ struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
+ };
- static struct pci_driver pciback_pci_driver = {
-- .name = "pciback",
-+ .name = DRV_NAME,
- .id_table = pcistub_ids,
- .probe = pcistub_probe,
- .remove = pcistub_remove,
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-index 98e2912..9d1b0a6 100644
---- a/drivers/xen/pciback/pciback.h
-+++ b/drivers/xen/pciback/pciback.h
-@@ -45,8 +45,13 @@ struct pciback_device {
-
- struct pciback_dev_data {
- struct list_head config_fields;
-- int permissive;
-- int warned_on_write;
-+ unsigned int permissive : 1;
-+ unsigned int warned_on_write : 1;
-+ unsigned int enable_intx : 1;
-+ unsigned int isr_on : 1; /* Whether the IRQ handler is installed. */
-+ unsigned int ack_intr : 1; /* .. and ACK-ing */
-+ unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
-+ char irq_name[0]; /* pciback[000:04:00.0] */
- };
-
- /* Used by XenBus and pciback_ops.c */
-@@ -131,3 +136,6 @@ extern int verbose_request;
- void test_and_schedule_op(struct pciback_device *pdev);
- #endif
-
-+/* Handles shared IRQs that can to device domain and control domain. */
-+void pciback_irq_handler(struct pci_dev *dev, int reset);
-+irqreturn_t pciback_guest_interrupt(int irq, void *dev_id);
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 011db67..cb54893 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -13,6 +13,78 @@
- int verbose_request;
- module_param(verbose_request, int, 0644);
-
-+/* Ensure a device is has the fake IRQ handler "turned on/off" and is
-+ * ready to be exported. This MUST be run after pciback_reset_device
-+ * which does the actual PCI device enable/disable.
-+ */
-+void pciback_control_isr(struct pci_dev *dev, int reset)
-+{
-+ struct pciback_dev_data *dev_data;
-+ int rc;
-+ int enable = 0;
-+
-+ dev_data = pci_get_drvdata(dev);
-+ if (!dev_data)
-+ return;
-+
-+ /* We don't deal with bridges */
-+ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL)
-+ return;
-+
-+ if (reset) {
-+ dev_data->enable_intx = 0;
-+ dev_data->ack_intr = 0;
-+ }
-+ enable = dev_data->enable_intx;
-+
-+ /* Asked to disable, but ISR isn't runnig */
-+ if (!enable && !dev_data->isr_on)
-+ return;
-+
-+ /* Squirrel away the IRQs in the dev_data. We need this
-+ * b/c when device transitions to MSI, the dev->irq is
-+ * overwritten with the MSI vector.
-+ */
-+ if (enable)
-+ dev_data->irq = dev->irq;
-+
-+ dev_dbg(&dev->dev, "%s: #%d %s %s%s %s-> %s\n",
-+ dev_data->irq_name,
-+ dev_data->irq,
-+ pci_is_enabled(dev) ? "on" : "off",
-+ dev->msi_enabled ? "MSI" : "",
-+ dev->msix_enabled ? "MSI/X" : "",
-+ dev_data->isr_on ? "enable" : "disable",
-+ enable ? "enable" : "disable");
-+
-+ if (enable) {
-+ rc = request_irq(dev_data->irq,
-+ pciback_guest_interrupt, IRQF_SHARED,
-+ dev_data->irq_name, dev);
-+ if (rc) {
-+ dev_err(&dev->dev, "%s: failed to install fake IRQ " \
-+ "handler for IRQ %d! (rc:%d)\n", dev_data->irq_name,
-+ dev_data->irq, rc);
-+ goto out;
-+ }
-+ }
-+ else {
-+ free_irq(dev_data->irq, dev);
-+ dev_data->irq = 0;
-+ }
-+ dev_data->isr_on = enable;
-+ dev_data->ack_intr = enable;
-+out:
-+ dev_dbg(&dev->dev, "%s: #%d %s %s%s %s\n",
-+ dev_data->irq_name,
-+ dev_data->irq,
-+ pci_is_enabled(dev) ? "on" : "off",
-+ dev->msi_enabled ? "MSI" : "",
-+ dev->msix_enabled ? "MSI/X" : "",
-+ enable ? (dev_data->isr_on ? "enabled" : "failed to enable") :
-+ (dev_data->isr_on ? "failed to disable" : "disabled"));
-+}
-+
- /* Ensure a device is "turned off" and ready to be exported.
- * (Also see pciback_config_reset to ensure virtual configuration space is
- * ready to be re-exported)
-@@ -21,6 +93,8 @@ void pciback_reset_device(struct pci_dev *dev)
- {
- u16 cmd;
-
-+ pciback_control_isr(dev, 1 /* reset device */);
-+
- /* Disable devices (but not bridges) */
- if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
- #ifdef CONFIG_PCI_MSI
-@@ -78,13 +152,18 @@ void pciback_do_op(struct work_struct *data)
- struct pciback_device *pdev =
- container_of(data, struct pciback_device, op_work);
- struct pci_dev *dev;
-+ struct pciback_dev_data *dev_data = NULL;
- struct xen_pci_op *op = &pdev->sh_info->op;
-+ int test_intx = 0;
-
- dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
-
- if (dev == NULL)
- op->err = XEN_PCI_ERR_dev_not_found;
- else {
-+ dev_data = pci_get_drvdata(dev);
-+ if (dev_data)
-+ test_intx = dev_data->enable_intx;
- switch (op->cmd) {
- case XEN_PCI_OP_conf_read:
- op->err = pciback_config_read(dev,
-@@ -109,10 +188,15 @@ void pciback_do_op(struct work_struct *data)
- break;
- #endif
- default:
-- op->err = XEN_PCI_ERR_not_implemented;
-+ op->err = XEN_PCI_ERR_not_implemented;
- break;
- }
- }
-+ if (!op->err && dev && dev_data) {
-+ /* Transition detected */
-+ if ((dev_data->enable_intx != test_intx))
-+ pciback_control_isr(dev, 0 /* no reset */);
-+ }
- /* Tell the driver domain that we're done. */
- wmb();
- clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
-@@ -137,3 +221,12 @@ irqreturn_t pciback_handle_event(int irq, void *dev_id)
-
- return IRQ_HANDLED;
- }
-+irqreturn_t pciback_guest_interrupt(int irq, void *dev_id)
-+{
-+ struct pci_dev *dev = (struct pci_dev *)dev_id;
-+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+
-+ if (dev_data->isr_on && dev_data->ack_intr)
-+ return IRQ_HANDLED;
-+ return IRQ_NONE;
-+}
+ extern struct xen_netbk *xen_netbk;
--
1.7.4
-From 29a451f41647deedc2fa535520e648c76755568c Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 12 Apr 2010 11:47:15 -0400
-Subject: [PATCH 028/244] xen-pciback: Add SysFS instrumentation for the fake IRQ
handler.
+From 4fbb266d319fcb3349eff2f9c42cdee51c5fcb5f Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 15 Oct 2010 13:41:44 +0100
+Subject: [PATCH 068/203] xen: netback: take net_schedule_list_lock when removing entry
from net_schedule_list
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+There is a race in net_tx_build_mops between checking if
+net_schedule_list is empty and actually dequeuing the first entry on
+the list. If another thread dequeues the only entry on the list during
+this window we crash because list_first_entry expects a non-empty
+list, like so:
+
+[ 0.133127] BUG: unable to handle kernel NULL pointer dereference at 00000008
+[ 0.133132] IP: [<c12aae71>] net_tx_build_mops+0x91/0xa70
+[ 0.133142] *pdpt = 0000000000000000 *pde = 000000000000000f
+[ 0.133147] Oops: 0002 1 SMP
+[ 0.133150] last sysfs file:
+[ 0.133152] Modules linked in:
+[ 0.133154]
+[ 0.133156] Pid: 55, comm: netback/1 Not tainted (2.6.32.12-0.7.1 #1) Latitude E4310
+[ 0.133158] EIP: 0061:[<c12aae71>] EFLAGS: 00010202 CPU: 1
+[ 0.133161] EIP is at net_tx_build_mops+0x91/0xa70
+[ 0.133163] EAX: 00000012 EBX: 00000008 ECX: e112b734 EDX: e112b76c
+[ 0.133165] ESI: ffffff30 EDI: 00000000 EBP: e112b734 ESP: dfe85d98
+[ 0.133167] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0069
+[ 0.133169] Process netback/1 (pid: 55, ti=dfe84000 task=dfe83340 task.ti=dfe84000)
+[ 0.133170] Stack:
+[ 0.133172] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
+[ 0.133177] <0> 00000000 e112b734 e112ec08 e112b7f8 e112ec08 ffffff30 00000000
00000000
+[ 0.133186] <0> 00000000 00000000 00000000 e112b76c dfe85df4 00000001 00000000
aaaaaaaa
+[ 0.133193] Call Trace:
+[ 0.133202] [<c12abc7f>] net_tx_action+0x42f/0xac0
+[ 0.133206] [<c12ac37a>] netbk_action_thread+0x6a/0x1b0
+[ 0.133212] [<c1057444>] kthread+0x74/0x80
+[ 0.133218] [<c10049d7>] kernel_thread_helper+0x7/0x10
+[ 0.133220] Code: c4 00 00 00 89 74 24 58 39 74 24 2c 0f 84 c7 06 00 00 8b 74 24 \
+ 58 8b 5c 24 58 81 ee d0 00 00 00 83 c3 08 89 74 24 34 8b 7c 24 \
+ 58 <f0> ff 47 08 89 f0 e8 b4 f9 ff ff 8b 46 2c 8b 56 34 89 44 24 5c
+[ 0.133261] EIP: [<c12aae71>] net_tx_build_mops+0x91/0xa70 SS:ESP 0069:dfe85d98
+[ 0.133265] CR2: 0000000000000008
+[ 0.133274] --[ end trace e2c5c15f54bd9d93 ]--
+
+Therefore after the initial lock free check for an empty list check
+again with the lock held before dequeueing the entry.
+
+Based on a patch by Tomasz Wroblewski.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Tomasz Wroblewski <tomasz.wroblewski(a)citrix.com>
---
- drivers/xen/pciback/pci_stub.c | 75 +++++++++++++++++++++++++++++++++++++++-
- 1 files changed, 74 insertions(+), 1 deletions(-)
+ drivers/xen/netback/netback.c | 35 ++++++++++++++++++++++++++++-------
+ 1 files changed, 28 insertions(+), 7 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 45bbe99..ee2cd68 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -1038,6 +1038,70 @@ static ssize_t pcistub_slot_show(struct device_driver *drv, char
*buf)
-
- DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 1d080f6..3b03435 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -774,15 +774,34 @@ static int __on_net_schedule_list(struct xen_netif *netif)
+ return !list_empty(&netif->list);
+ }
-+static ssize_t pcistub_irq_handler_show(struct device_driver *drv, char *buf)
-+{
-+ struct pcistub_device *psdev;
-+ struct pciback_dev_data *dev_data;
-+ size_t count = 0;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&pcistub_devices_lock, flags);
-+ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+ if (count >= PAGE_SIZE)
-+ break;
-+ if (!psdev->dev)
-+ continue;
-+ dev_data = pci_get_drvdata(psdev->dev);
-+ if (!dev_data)
-+ continue;
-+ count +=
-+ scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing\n",
-+ pci_name(psdev->dev),
-+ dev_data->isr_on ? "on" : "off",
-+ dev_data->ack_intr ? "ack" : "not ack");
-+ }
-+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+ return count;
++/* Must be called with net_schedule_list_lock held */
+ static void remove_from_net_schedule_list(struct xen_netif *netif)
+ {
+- struct xen_netbk *netbk = &xen_netbk[netif->group];
+- spin_lock_irq(&netbk->net_schedule_list_lock);
+ if (likely(__on_net_schedule_list(netif))) {
+ list_del_init(&netif->list);
+ netif_put(netif);
+ }
+}
+
-+DRIVER_ATTR(irq_handlers, S_IRUSR, pcistub_irq_handler_show, NULL);
-+
-+static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
-+ const char *buf,
-+ size_t count)
++static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
+{
-+ struct pcistub_device *psdev;
-+ struct pciback_dev_data *dev_data;
-+ int domain, bus, slot, func;
-+ int err = -ENOENT;
-+
-+ err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+ if (err)
-+ goto out;
-+
-+ psdev = pcistub_device_find(domain, bus, slot, func);
++ struct xen_netif *netif = NULL;
+
-+ if (!psdev)
++ spin_lock_irq(&netbk->net_schedule_list_lock);
++ if (list_empty(&netbk->net_schedule_list))
+ goto out;
+
-+ dev_data = pci_get_drvdata(psdev->dev);
-+ if (!dev_data)
++ netif = list_first_entry(&netbk->net_schedule_list,
++ struct xen_netif, list);
++ if (!netif)
+ goto out;
+
-+ dev_dbg(&psdev->dev->dev, "%s fake irq handler: %d->%d\n",
-+ dev_data->irq_name, dev_data->isr_on,
-+ !dev_data->isr_on);
++ netif_get(netif);
+
-+ dev_data->isr_on = !(dev_data->isr_on);
-+ if (dev_data->isr_on)
-+ dev_data->ack_intr = 1;
++ remove_from_net_schedule_list(netif);
+out:
-+ if (!err)
-+ err = count;
-+ return err;
-+}
-+DRIVER_ATTR(irq_handler_state, S_IWUSR, NULL, pcistub_irq_handler_switch);
-+
- static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
- size_t count)
+ spin_unlock_irq(&netbk->net_schedule_list_lock);
++ return netif;
+ }
+
+ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+@@ -817,7 +836,10 @@ void netif_schedule_work(struct xen_netif *netif)
+
+ void netif_deschedule_work(struct xen_netif *netif)
{
-@@ -1177,7 +1241,10 @@ static void pcistub_exit(void)
- driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
- driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
- driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
--
-+ driver_remove_file(&pciback_pci_driver.driver,
-+ &driver_attr_irq_handlers);
-+ driver_remove_file(&pciback_pci_driver.driver,
-+ &driver_attr_irq_handler_state);
- pci_unregister_driver(&pciback_pci_driver);
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
++ spin_lock_irq(&netbk->net_schedule_list_lock);
+ remove_from_net_schedule_list(netif);
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
}
-@@ -1236,6 +1303,12 @@ static int __init pcistub_init(void)
- err = driver_create_file(&pciback_pci_driver.driver,
- &driver_attr_permissive);
-+ if (!err)
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_irq_handlers);
-+ if (!err)
-+ err = driver_create_file(&pciback_pci_driver.driver,
-+ &driver_attr_irq_handler_state);
- if (err)
- pcistub_exit();
+@@ -1301,12 +1323,11 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ int work_to_do;
+ unsigned int data_len;
+ pending_ring_idx_t index;
+-
++
+ /* Get a netif from the list with work to do. */
+- netif = list_first_entry(&netbk->net_schedule_list,
+- struct xen_netif, list);
+- netif_get(netif);
+- remove_from_net_schedule_list(netif);
++ netif = poll_net_schedule_list(netbk);
++ if (!netif)
++ continue;
+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
+ if (!work_to_do) {
--
1.7.4
-From 6c7c36d411eeab67192fe0ed96ac1e048b4a1755 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 19 Apr 2010 14:39:10 -0400
-Subject: [PATCH 029/244] xen-pciback: When device transitions to MSI/MSI-X stop ACK-ing
on the
- legacy interrupt.
+From d58a964195f593879cc0160ac0c6f31bc95cdc6e Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Wed, 15 Dec 2010 09:48:12 +0000
+Subject: [PATCH 069/203] xen: netback: Re-define PKT_PROT_LEN to be bigger.
-But don't remove the irq handler from the legacy interrupt. The device
-might still transition back to the legacy interrupts.
+Re-define PKT_PROT_LEN to be big enough to handle maximal IPv4 and TCP options and
phrase
+the definition so that it's reasonably obvious that's what it's for.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/conf_space_capability_msi.c | 17 ++++++++++++++++-
- 1 files changed, 16 insertions(+), 1 deletions(-)
+ drivers/xen/netback/netback.c | 14 +++++++++-----
+ 1 files changed, 9 insertions(+), 5 deletions(-)
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index b70ea8b..a236e2d 100644
---- a/drivers/xen/pciback/conf_space_capability_msi.c
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -12,6 +12,7 @@
- int pciback_enable_msi(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
- {
-+ struct pciback_dev_data *dev_data;
- int otherend = pdev->xdev->otherend_id;
- int status;
-
-@@ -27,21 +28,29 @@ int pciback_enable_msi(struct pciback_device *pdev,
- /* The value the guest needs is actually the IDT vector, not the
- * the local domain's IRQ number. */
- op->value = xen_gsi_from_irq(dev->irq);
-+ dev_data = pci_get_drvdata(dev);
-+ if (dev_data)
-+ dev_data->ack_intr = 0;
- return 0;
- }
-
- int pciback_disable_msi(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
- {
-+ struct pciback_dev_data *dev_data;
- pci_disable_msi(dev);
-
- op->value = xen_gsi_from_irq(dev->irq);
-+ dev_data = pci_get_drvdata(dev);
-+ if (dev_data)
-+ dev_data->ack_intr = 1;
- return 0;
- }
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 3b03435..9bbd230 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -36,9 +36,11 @@
- int pciback_enable_msix(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
- {
-+ struct pciback_dev_data *dev_data;
- int i, result;
- struct msix_entry *entries;
+ #include "common.h"
-@@ -68,6 +77,9 @@ int pciback_enable_msix(struct pciback_device *pdev,
- kfree(entries);
+-#include <linux/tcp.h>
+-#include <linux/udp.h>
+ #include <linux/kthread.h>
++#include <linux/if_vlan.h>
++#include <linux/udp.h>
++
++#include <net/tcp.h>
- op->value = result;
-+ dev_data = pci_get_drvdata(dev);
-+ if (dev_data)
-+ dev_data->ack_intr = 0;
+ #include <xen/balloon.h>
+ #include <xen/events.h>
+@@ -125,10 +127,12 @@ static inline int netif_get_page_ext(struct page *pg, unsigned int
*_group, unsi
+ /*
+ * This is the amount of packet we copy rather than map, so that the
+ * guest can't fiddle with the contents of the headers while we do
+- * packet processing on them (netfilter, routing, etc). 72 is enough
+- * to cover TCP+IP headers including options.
++ * packet processing on them (netfilter, routing, etc).
+ */
+-#define PKT_PROT_LEN 72
++#define PKT_PROT_LEN (ETH_HLEN + \
++ VLAN_HLEN + \
++ sizeof(struct iphdr) + MAX_IPOPTLEN + \
++ sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
- return result;
- }
-@@ -75,10 +87,13 @@ int pciback_enable_msix(struct pciback_device *pdev,
- int pciback_disable_msix(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
+ static inline pending_ring_idx_t pending_index(unsigned i)
{
--
-+ struct pciback_dev_data *dev_data;
- pci_disable_msix(dev);
-
- op->value = xen_gsi_from_irq(dev->irq);
-+ dev_data = pci_get_drvdata(dev);
-+ if (dev_data)
-+ dev_data->ack_intr = 1;
- return 0;
- }
-
--
1.7.4
-From c1cc36c68f096f2b1e796ba84d9c583009939d91 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 19 Apr 2010 14:40:38 -0400
-Subject: [PATCH 030/244] xen-pciback: Enable interrupt handler when device is enabled.
+From 7120999e00f068383bc16d03cceae8d6d511c43a Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Tue, 14 Dec 2010 20:35:19 +0000
+Subject: [PATCH 070/203] xen: netback: Don't count packets we don't actually
receive.
-And also request it to be disabled when the device has been
-disabled.
+Make sure we only bump rx_packets when we're definitely going to call netif_rx_ni().
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/conf_space_header.c | 6 ++++++
- 1 files changed, 6 insertions(+), 0 deletions(-)
+ drivers/xen/netback/netback.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
-diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
-index 1f4f86e..cb450f4 100644
---- a/drivers/xen/pciback/conf_space_header.c
-+++ b/drivers/xen/pciback/conf_space_header.c
-@@ -39,8 +39,10 @@ static int command_read(struct pci_dev *dev, int offset, u16 *value,
void *data)
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 9bbd230..78d3509 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1512,9 +1512,6 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ skb->dev = netif->dev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
- static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
- {
-+ struct pciback_dev_data *dev_data;
- int err;
+- netif->stats.rx_bytes += skb->len;
+- netif->stats.rx_packets++;
+-
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_checksum_setup(skb)) {
+ DPRINTK("Can't setup checksum in net_tx_action\n");
+@@ -1530,6 +1527,9 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ continue;
+ }
-+ dev_data = pci_get_drvdata(dev);
- if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
- if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: enable\n",
-@@ -48,11 +50,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value,
void *data)
- err = pci_enable_device(dev);
- if (err)
- return err;
-+ if (dev_data)
-+ dev_data->enable_intx = 1;
- } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
- if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: disable\n",
- pci_name(dev));
- pci_disable_device(dev);
-+ if (dev_data)
-+ dev_data->enable_intx = 0;
++ netif->stats.rx_bytes += skb->len;
++ netif->stats.rx_packets++;
++
+ netif_rx_ni(skb);
+ netif->dev->last_rx = jiffies;
}
-
- if (!dev->is_busmaster && is_master_cmd(value)) {
--
1.7.4
-From a732e3d6ed4831c460586bd7a16ef7f6b7d28936 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 19 Apr 2010 16:23:06 -0400
-Subject: [PATCH 031/244] xen-pciback: Probe the IRQ line to check if it is not shared.
-
-If it is not shared, we stop ACK-ing the IRQ line as there is
-no need for this irq handler to return IRQ_HANDLED.
+From 3c1f462cb05ad5eb5bb8e65cf6feb9a4e4363ebf Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Tue, 14 Dec 2010 20:35:20 +0000
+Subject: [PATCH 071/203] xen: netback: Remove the 500ms timeout to restart the netif
queue.
-We have to this check once much much later than the pciback
-and pcifront have started talking as guests doing the hypercall
-that would notify the other guest that the IRQ line is shared
-is done asynchronously.
+It is generally unhelpful as it results in a massive tail-drop should a guest become
+unresponsive for a relatively short period of time and no back-pressure (other than
+that caused by a higher layer protocol) is applied to the sender.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/pci_stub.c | 5 +++--
- drivers/xen/pciback/pciback.h | 1 +
- drivers/xen/pciback/pciback_ops.c | 12 +++++++++++-
- 3 files changed, 15 insertions(+), 3 deletions(-)
+ drivers/xen/netback/netback.c | 20 +-------------------
+ 1 files changed, 1 insertions(+), 19 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index ee2cd68..88c7ca1 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -1055,10 +1055,11 @@ static ssize_t pcistub_irq_handler_show(struct device_driver
*drv, char *buf)
- if (!dev_data)
- continue;
- count +=
-- scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing\n",
-+ scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing:%ld\n",
- pci_name(psdev->dev),
- dev_data->isr_on ? "on" : "off",
-- dev_data->ack_intr ? "ack" : "not ack");
-+ dev_data->ack_intr ? "ack" : "not ack",
-+ dev_data->handled);
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 78d3509..2caa5f8 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -275,13 +275,6 @@ static inline int netbk_queue_full(struct xen_netif *netif)
+ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
+ }
+
+-static void tx_queue_callback(unsigned long data)
+-{
+- struct xen_netif *netif = (struct xen_netif *)data;
+- if (netif_schedulable(netif))
+- netif_wake_queue(netif->dev);
+-}
+-
+ /* Figure out how many ring slots we're going to need to send @skb to
+ the guest. */
+ static unsigned count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
+@@ -364,19 +357,8 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ netif->rx.sring->req_event = netif->rx_req_cons_peek +
+ netbk_max_required_rx_slots(netif);
+ mb(); /* request notification /then/ check & stop the queue */
+- if (netbk_queue_full(netif)) {
++ if (netbk_queue_full(netif))
+ netif_stop_queue(dev);
+- /*
+- * Schedule 500ms timeout to restart the queue, thus
+- * ensuring that an inactive queue will be drained.
+- * Packets will be immediately be dropped until more
+- * receive buffers become available (see
+- * netbk_queue_full() check above).
+- */
+- netif->tx_queue_timeout.data = (unsigned long)netif;
+- netif->tx_queue_timeout.function = tx_queue_callback;
+- mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
+- }
}
- spin_unlock_irqrestore(&pcistub_devices_lock, flags);
- return count;
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-index 9d1b0a6..fc31052 100644
---- a/drivers/xen/pciback/pciback.h
-+++ b/drivers/xen/pciback/pciback.h
-@@ -50,6 +50,7 @@ struct pciback_dev_data {
- unsigned int enable_intx : 1;
- unsigned int isr_on : 1; /* Whether the IRQ handler is installed. */
- unsigned int ack_intr : 1; /* .. and ACK-ing */
-+ unsigned long handled;
- unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
- char irq_name[0]; /* pciback[000:04:00.0] */
- };
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index cb54893..5543881 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -226,7 +226,17 @@ irqreturn_t pciback_guest_interrupt(int irq, void *dev_id)
- struct pci_dev *dev = (struct pci_dev *)dev_id;
- struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+ skb_queue_tail(&netbk->rx_queue, skb);
-- if (dev_data->isr_on && dev_data->ack_intr)
-+ if (dev_data->isr_on && dev_data->ack_intr) {
-+ dev_data->handled++;
-+ if ((dev_data->handled % 1000) == 0) {
-+ if (xen_ignore_irq(irq)) {
-+ printk(KERN_INFO "%s IRQ line is not shared "
-+ "with other domains. Turning ISR off\n",
-+ dev_data->irq_name);
-+ dev_data->ack_intr = 0;
-+ }
-+ }
- return IRQ_HANDLED;
-+ }
- return IRQ_NONE;
- }
--
1.7.4
-From 3312c11c3f9c857b2457c293e6b6e15928a32f32 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 20 Apr 2010 20:22:40 -0400
-Subject: [PATCH 032/244] xen-pciback: Add debug statements for the MSI/MSI-X
configuration module.
+From d70d4906c2736dadc5c287caa36c5880947f8688 Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Tue, 14 Dec 2010 20:35:21 +0000
+Subject: [PATCH 072/203] xen: netback: Add a missing test to tx_work_todo.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Adda test so that, when netback is using worker threads, net_tx_action()
+gets called in a timely manner when the pending_inuse list is populated.
+
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/conf_space_capability_msi.c | 11 +++++++++++
- 1 files changed, 11 insertions(+), 0 deletions(-)
+ drivers/xen/netback/netback.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index a236e2d..b15131e 100644
---- a/drivers/xen/pciback/conf_space_capability_msi.c
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -16,6 +16,9 @@ int pciback_enable_msi(struct pciback_device *pdev,
- int otherend = pdev->xdev->otherend_id;
- int status;
-
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: enable MSI\n", pci_name(dev));
-+
- status = pci_enable_msi(dev);
-
- if (status) {
-@@ -31,6 +34,7 @@ int pciback_enable_msi(struct pciback_device *pdev,
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 0;
-+
- return 0;
- }
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 2caa5f8..dd52d01 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1695,6 +1695,10 @@ static inline int tx_work_todo(struct xen_netbk *netbk)
+ if (netbk->dealloc_cons != netbk->dealloc_prod)
+ return 1;
-@@ -38,6 +42,9 @@ int pciback_disable_msi(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
- {
- struct pciback_dev_data *dev_data;
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !list_empty(&netbk->pending_inuse_head))
++ return 1;
+
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: disable MSI\n", pci_name(dev));
- pci_disable_msi(dev);
-
- op->value = xen_gsi_from_irq(dev->irq);
-@@ -54,6 +61,8 @@ int pciback_enable_msix(struct pciback_device *pdev,
- int i, result;
- struct msix_entry *entries;
-
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: enable MSI-X\n", pci_name(dev));
- if (op->value > SH_INFO_MAX_VEC)
- return -EINVAL;
-
-@@ -88,6 +97,8 @@ int pciback_disable_msix(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
- {
- struct pciback_dev_data *dev_data;
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: disable MSI-X\n", pci_name(dev));
- pci_disable_msix(dev);
-
- op->value = xen_gsi_from_irq(dev->irq);
+ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list))
+ return 1;
--
1.7.4
-From 52257d7ad18bd91fd614df5ef960a88af3ed5200 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Fri, 23 Jul 2010 14:35:47 -0400
-Subject: [PATCH 033/244] xen-pciback: Redo spinlock usage.
+From 8811a0cf07ccd1b9f40eaae76de3aa2792c9fd28 Mon Sep 17 00:00:00 2001
+From: Paul Durrant <paul.durrant(a)citrix.com>
+Date: Tue, 14 Dec 2010 20:35:22 +0000
+Subject: [PATCH 073/203] xen: netback: Re-factor net_tx_action_dealloc() slightly.
-We were using coarse spinlocks that could end up with a deadlock.
-This patch fixes that and makes the spinlocks much more fine-grained.
+There is no need for processing of the pending_inuse list to be within the
dealloc_prod/cons
+loop.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/xenbus.c | 34 +++++++++++++++++++++-------------
- 1 files changed, 21 insertions(+), 13 deletions(-)
+ drivers/xen/netback/netback.c | 26 ++++++++++++++------------
+ 1 files changed, 14 insertions(+), 12 deletions(-)
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index d448bf5..f0d5426 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -54,23 +54,31 @@ static void pciback_disconnect(struct pciback_device *pdev)
- unbind_from_irqhandler(pdev->evtchn_irq, pdev);
- pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
- }
-+ spin_unlock(&pdev->dev_lock);
-
- /* If the driver domain started an op, make sure we complete it
- * before releasing the shared memory */
-+
-+ /* Note, the workqueue does not use spinlocks at all.*/
- flush_workqueue(pciback_wq);
-
-+ spin_lock(&pdev->dev_lock);
- if (pdev->sh_info != NULL) {
- xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
- pdev->sh_info = NULL;
- }
--
- spin_unlock(&pdev->dev_lock);
-+
- }
-
- static void free_pdev(struct pciback_device *pdev)
- {
-- if (pdev->be_watching)
-+ spin_lock(&pdev->dev_lock);
-+ if (pdev->be_watching) {
- unregister_xenbus_watch(&pdev->be_watch);
-+ pdev->be_watching = 0;
-+ }
-+ spin_unlock(&pdev->dev_lock);
-
- pciback_disconnect(pdev);
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index dd52d01..53b3a0e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -906,11 +906,20 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
+ gop++;
+ }
-@@ -98,7 +106,10 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
- "Error mapping other domain page in ours.");
- goto out;
- }
+- if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
+- list_empty(&netbk->pending_inuse_head))
+- break;
++ } while (dp != netbk->dealloc_prod);
+
-+ spin_lock(&pdev->dev_lock);
- pdev->sh_info = vaddr;
-+ spin_unlock(&pdev->dev_lock);
++ netbk->dealloc_cons = dc;
- err = bind_interdomain_evtchn_to_irqhandler(
- pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
-@@ -108,7 +119,10 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
- "Error binding event channel to IRQ");
- goto out;
- }
+- /* Copy any entries that have been pending for too long. */
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
++ gop - netbk->tx_unmap_ops);
++ BUG_ON(ret);
+
-+ spin_lock(&pdev->dev_lock);
- pdev->evtchn_irq = err;
-+ spin_unlock(&pdev->dev_lock);
- err = 0;
-
- dev_dbg(&pdev->xdev->dev, "Attached!\n");
-@@ -122,7 +136,6 @@ static int pciback_attach(struct pciback_device *pdev)
- int gnt_ref, remote_evtchn;
- char *magic = NULL;
-
-- spin_lock(&pdev->dev_lock);
-
- /* Make sure we only do this setup once */
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-@@ -168,7 +181,6 @@ static int pciback_attach(struct pciback_device *pdev)
-
- dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
- out:
-- spin_unlock(&pdev->dev_lock);
-
- kfree(magic);
-
-@@ -340,7 +352,6 @@ static int pciback_reconfigure(struct pciback_device *pdev)
- char state_str[64];
- char dev_str[64];
-
-- spin_lock(&pdev->dev_lock);
-
- dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
-
-@@ -481,8 +492,6 @@ static int pciback_reconfigure(struct pciback_device *pdev)
- }
++ /*
++ * Copy any entries that have been pending for too long
++ */
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !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;
+@@ -936,14 +945,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
- out:
-- spin_unlock(&pdev->dev_lock);
+ break;
+ }
+- } while (dp != netbk->dealloc_prod);
-
- return 0;
- }
-
-@@ -539,8 +548,6 @@ static int pciback_setup_backend(struct pciback_device *pdev)
- char dev_str[64];
- char state_str[64];
-
-- spin_lock(&pdev->dev_lock);
+- netbk->dealloc_cons = dc;
-
- /* It's possible we could get the call to setup twice, so make sure
- * we're not already connected.
- */
-@@ -621,8 +628,6 @@ static int pciback_setup_backend(struct pciback_device *pdev)
- "Error switching to initialised state!");
+- ret = HYPERVISOR_grant_table_op(
+- GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
+- gop - netbk->tx_unmap_ops);
+- BUG_ON(ret);
++ }
- out:
-- spin_unlock(&pdev->dev_lock);
--
- if (!err)
- /* see if pcifront is already configured (if not, we'll wait) */
- pciback_attach(pdev);
-@@ -669,7 +674,10 @@ static int pciback_xenbus_probe(struct xenbus_device *dev,
- pciback_be_watch);
- if (err)
- goto out;
-+
-+ spin_lock(&pdev->dev_lock);
- pdev->be_watching = 1;
-+ spin_unlock(&pdev->dev_lock);
+ list_for_each_entry_safe(inuse, n, &list, list) {
+ struct pending_tx_info *pending_tx_info;
+--
+1.7.4
+
+
+From 9481475c92f00d15100d0a5083ef338f1b528506 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 5 Jan 2011 09:57:37 +0000
+Subject: [PATCH 074/203] xen: netback: Drop GSO SKBs which do not have csum_blank.
+
+The Linux network stack expects all GSO SKBs to have ip_summed ==
+CHECKSUM_PARTIAL (which implies that the frame contains a partial
+checksum) and the Xen network ring protocol similarly expects an SKB
+which has GSO set to also have NETRX_csum_blank (which also implies a
+partial checksum). Therefore drop such frames on receive otherwise
+they will trigger the warning in skb_gso_segment.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: xen-devel(a)lists.xensource.com
+---
+ drivers/xen/netback/netback.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 53b3a0e..2766b93 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1502,6 +1502,10 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ kfree_skb(skb);
+ continue;
+ }
++ } else if (skb_is_gso(skb)) {
++ DPRINTK("Dropping GSO but not CHECKSUM_PARTIAL skb\n");
++ kfree_skb(skb);
++ continue;
+ }
- /* We need to force a call to our callback here in case
- * xend already configured us!
-@@ -708,8 +716,8 @@ int __init pciback_xenbus_register(void)
- {
- pciback_wq = create_workqueue("pciback_workqueue");
- if (!pciback_wq) {
-- printk(KERN_ERR "pciback_xenbus_register: create"
-- "pciback_workqueue failed\n");
-+ printk(KERN_ERR "%s: create"
-+ "pciback_workqueue failed\n",__FUNCTION__);
- return -EFAULT;
- }
- return xenbus_register_backend(&xenbus_pciback_driver);
+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
--
1.7.4
-From a9e0cfab0577730e74787b701edc727756a52b11 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 28 Jul 2010 13:28:34 -0400
-Subject: [PATCH 034/244] xen-pciback: Remove spinlock for be->watching state.
+From a45f9a0889210fba5c73994ec2fa1c36f82a435f Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 19 Jan 2011 12:43:38 +0000
+Subject: [PATCH 075/203] xen: netback: completely remove tx_queue_timer
-There is no need to guard this with a spinlock. It
-is already guarded by the xenwatch_thread against multiple
-customers.
+"xen: netback: Remove the 500ms timeout to restart the netif queue." missed
+removing the timer initialisation.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Also remove the related comment which has been obsolete since the default for
+MODPARM_copy_skb was switched to true some time ago.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Paul Durrant <Paul.Durrant(a)citrix.com>
---
- drivers/xen/pciback/xenbus.c | 4 ----
- 1 files changed, 0 insertions(+), 4 deletions(-)
+ drivers/xen/netback/common.h | 3 ---
+ drivers/xen/netback/interface.c | 13 +------------
+ 2 files changed, 1 insertions(+), 15 deletions(-)
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index f0d5426..993b659 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -73,12 +73,10 @@ static void pciback_disconnect(struct pciback_device *pdev)
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index ce0041a..7e03a46 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -99,9 +99,6 @@ struct xen_netif {
+ unsigned long remaining_credit;
+ struct timer_list credit_timeout;
- static void free_pdev(struct pciback_device *pdev)
- {
-- spin_lock(&pdev->dev_lock);
- if (pdev->be_watching) {
- unregister_xenbus_watch(&pdev->be_watch);
- pdev->be_watching = 0;
- }
-- spin_unlock(&pdev->dev_lock);
+- /* Enforce draining of the transmit queue. */
+- struct timer_list tx_queue_timeout;
+-
+ /* Statistics */
+ int nr_copied_skbs;
- pciback_disconnect(pdev);
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 2e8508a..efdc21c 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -41,15 +41,7 @@
+ * Module parameter 'queue_length':
+ *
+ * Enables queuing in the network stack when a client has run out of receive
+- * descriptors. Although this feature can improve receive bandwidth by avoiding
+- * packet loss, it can also result in packets sitting in the 'tx_queue' for
+- * unbounded time. This is bad if those packets hold onto foreign resources.
+- * For example, consider a packet that holds onto resources belonging to the
+- * guest for which it is queued (e.g., packet received on vif1.0, destined for
+- * vif1.1 which is not activated in the guest): in this situation the guest
+- * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
+- * run a timer (tx_queue_timeout) to drain the queue when the interface is
+- * blocked.
++ * descriptors.
+ */
+ static unsigned long netbk_queue_length = 32;
+ module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+@@ -295,8 +287,6 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ /* Initialize 'expires' now: it's used to track the credit window. */
+ netif->credit_timeout.expires = jiffies;
-@@ -675,9 +673,7 @@ static int pciback_xenbus_probe(struct xenbus_device *dev,
- if (err)
- goto out;
+- init_timer(&netif->tx_queue_timeout);
+-
+ dev->netdev_ops = &netback_ops;
+ netif_set_features(netif);
+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+@@ -458,7 +448,6 @@ void netif_disconnect(struct xen_netif *netif)
+ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
-- spin_lock(&pdev->dev_lock);
- pdev->be_watching = 1;
-- spin_unlock(&pdev->dev_lock);
+ del_timer_sync(&netif->credit_timeout);
+- del_timer_sync(&netif->tx_queue_timeout);
- /* We need to force a call to our callback here in case
- * xend already configured us!
+ if (netif->irq)
+ unbind_from_irqhandler(netif->irq, netif);
--
1.7.4
-From c0cae0b36c43e75d4d69c60f5319e6ba802b2233 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 13 Dec 2010 11:06:36 -0500
-Subject: [PATCH 035/244] xen/pciback: Fix checkpatch warnings and errors.
+From 2794a483aeafab1c0765a0478b760978b361bad9 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 28 Jan 2011 13:11:45 +0000
+Subject: [PATCH 076/203] Revert "xen: netback: Drop GSO SKBs which do not have
csum_blank."
-Checkpatch found some extra warnings and errors. This mega
-patch fixes all of them in one swoop.
+This reverts commit 082386b4a581b2ba5a125cc8944a57ceb33ff37c.
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Based on discussion surrounding the netfront equivalent fix
+(http://patchwork.ozlabs.org/patch/80389/) this issue will be fixed
+differently.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- arch/x86/include/asm/xen/pci.h | 2 +-
- drivers/xen/events.c | 38 ++++++++++----------
- drivers/xen/pciback/conf_space.c | 4 +-
- drivers/xen/pciback/conf_space_capability_msi.c | 11 +++---
- drivers/xen/pciback/conf_space_header.c | 42 +++++++++++-----------
- drivers/xen/pciback/controller.c | 2 +-
- drivers/xen/pciback/pci_stub.c | 7 ++--
- drivers/xen/pciback/pciback.h | 16 ++++----
- drivers/xen/pciback/pciback_ops.c | 9 ++---
- drivers/xen/pciback/xenbus.c | 14 ++++----
- 10 files changed, 73 insertions(+), 72 deletions(-)
+ drivers/xen/netback/netback.c | 4 ----
+ 1 files changed, 0 insertions(+), 4 deletions(-)
-diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
-index 8474b4b..7e61d78 100644
---- a/arch/x86/include/asm/xen/pci.h
-+++ b/arch/x86/include/asm/xen/pci.h
-@@ -27,7 +27,7 @@ static inline int xen_find_device_domain_owner(struct pci_dev *dev)
- return -1;
- }
- static inline int xen_register_device_domain_owner(struct pci_dev *dev,
-- uint16_t domain)
-+ uint16_t domain)
- {
- return -1;
- }
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 95eea13..3929c20 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -698,7 +698,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
- domid = rc = xen_find_device_domain_owner(dev);
- if (rc < 0)
- domid = DOMID_SELF;
--
-+
- memset(&map_irq, 0, sizeof(map_irq));
- map_irq.domid = domid;
- map_irq.type = MAP_PIRQ_TYPE_MSI;
-@@ -850,18 +850,18 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
- }
-
- static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-- unsigned int remote_port)
-+ unsigned int remote_port)
- {
-- struct evtchn_bind_interdomain bind_interdomain;
-- int err;
-+ struct evtchn_bind_interdomain bind_interdomain;
-+ int err;
-
-- bind_interdomain.remote_dom = remote_domain;
-- bind_interdomain.remote_port = remote_port;
-+ bind_interdomain.remote_dom = remote_domain;
-+ bind_interdomain.remote_port = remote_port;
-
-- err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
-- &bind_interdomain);
-+ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
-+ &bind_interdomain);
-
-- return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
-+ return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
- }
-
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 2766b93..53b3a0e 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1502,10 +1502,6 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ kfree_skb(skb);
+ continue;
+ }
+- } else if (skb_is_gso(skb)) {
+- DPRINTK("Dropping GSO but not CHECKSUM_PARTIAL skb\n");
+- kfree_skb(skb);
+- continue;
+ }
-@@ -966,19 +966,19 @@ int bind_interdomain_evtchn_to_irqhandler(unsigned int
remote_domain,
- const char *devname,
- void *dev_id)
- {
-- int irq, retval;
-+ int irq, retval;
+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
+--
+1.7.4
+
+
+From 01cd16474ee82db4d958c9cf8e481be897fa4ca6 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 27 Jan 2011 15:43:46 +0000
+Subject: [PATCH 077/203] xen: netback: handle incoming GSO SKBs which are not
CHECKSUM_PARTIAL
+
+The Linux network stack expects all GSO SKBs to have ip_summed ==
+CHECKSUM_PARTIAL (which implies that the frame contains a partial
+checksum) and the Xen network ring protocol similarly expects an SKB
+which has GSO set to also have NETRX_csum_blank (which also implies a
+partial checksum).
+
+However there have been cases of buggy guests which mark a frame as
+GSO but do not set csum_blank. If we detect that we a receiving such a
+frame (which manifests as ip_summed != PARTIAL && skb_is_gso) then
+force the SKB to partial and recalculate the checksum, since we cannot
+rely on the peer having done so if they have not set csum_blank.
+
+Add an ethtool stat to track occurances of this event.
+
+A corresponding fix was made to netfront in e0ce4af920eb028f38bfd680b1d733f4c7a0b7cf.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: xen-devel(a)lists.xensource.com
+---
+ drivers/xen/netback/common.h | 1 +
+ drivers/xen/netback/interface.c | 9 +++++++-
+ drivers/xen/netback/netback.c | 43 ++++++++++++++++++++++++++++++++------
+ 3 files changed, 45 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index 7e03a46..f660eb5 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -101,6 +101,7 @@ struct xen_netif {
-- irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
-- if (irq < 0)
-- return irq;
-+ irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
-+ if (irq < 0)
-+ return irq;
+ /* Statistics */
+ int nr_copied_skbs;
++ int rx_gso_checksum_fixup;
-- retval = request_irq(irq, handler, irqflags, devname, dev_id);
-- if (retval != 0) {
-- unbind_from_irq(irq);
-- return retval;
-- }
-+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+ if (retval != 0) {
-+ unbind_from_irq(irq);
-+ return retval;
-+ }
+ /* Miscellaneous private stuff. */
+ struct list_head list; /* scheduling list */
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index efdc21c..d3af68e 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -189,7 +189,14 @@ static const struct netif_stat {
+ char name[ETH_GSTRING_LEN];
+ u16 offset;
+ } netbk_stats[] = {
+- { "copied_skbs", offsetof(struct xen_netif, nr_copied_skbs) },
++ {
++ "copied_skbs",
++ offsetof(struct xen_netif, nr_copied_skbs)
++ },
++ {
++ "rx_gso_checksum_fixup",
++ offsetof(struct xen_netif, rx_gso_checksum_fixup)
++ },
+ };
-- return irq;
-+ return irq;
+ static int netbk_get_sset_count(struct net_device *dev, int string_set)
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 53b3a0e..8189199 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1222,11 +1222,28 @@ static int netbk_set_skb_gso(struct sk_buff *skb, struct
xen_netif_extra_info *g
+ return 0;
}
- EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
-
-diff --git a/drivers/xen/pciback/conf_space.c b/drivers/xen/pciback/conf_space.c
-index 370c18e..eb6bba0 100644
---- a/drivers/xen/pciback/conf_space.c
-+++ b/drivers/xen/pciback/conf_space.c
-@@ -18,8 +18,8 @@
- static int permissive;
- module_param(permissive, bool, 0644);
-
--#define DEFINE_PCI_CONFIG(op, size, type) \
--int pciback_##op##_config_##size \
-+#define DEFINE_PCI_CONFIG(op, size, type) \
-+int pciback_##op##_config_##size \
- (struct pci_dev *dev, int offset, type value, void *data) \
- { \
- return pci_##op##_config_##size(dev, offset, value); \
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index b15131e..3acda69 100644
---- a/drivers/xen/pciback/conf_space_capability_msi.c
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -16,7 +16,7 @@ int pciback_enable_msi(struct pciback_device *pdev,
- int otherend = pdev->xdev->otherend_id;
- int status;
-
-- if (unlikely(verbose_request))
-+ if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: enable MSI\n", pci_name(dev));
-
- status = pci_enable_msi(dev);
-@@ -43,7 +43,7 @@ int pciback_disable_msi(struct pciback_device *pdev,
- {
- struct pciback_dev_data *dev_data;
-
-- if (unlikely(verbose_request))
-+ if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: disable MSI\n", pci_name(dev));
- pci_disable_msi(dev);
-
-@@ -61,7 +61,7 @@ int pciback_enable_msix(struct pciback_device *pdev,
- int i, result;
- struct msix_entry *entries;
-- if (unlikely(verbose_request))
-+ if (unlikely(verbose_request))
- printk(KERN_DEBUG "pciback: %s: enable MSI-X\n", pci_name(dev));
- if (op->value > SH_INFO_MAX_VEC)
- return -EINVAL;
-@@ -97,8 +97,9 @@ int pciback_disable_msix(struct pciback_device *pdev,
- struct pci_dev *dev, struct xen_pci_op *op)
+-static int skb_checksum_setup(struct sk_buff *skb)
++static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
{
- struct pciback_dev_data *dev_data;
-- if (unlikely(verbose_request))
-- printk(KERN_DEBUG "pciback: %s: disable MSI-X\n", pci_name(dev));
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: disable MSI-X\n",
-+ pci_name(dev));
- pci_disable_msix(dev);
-
- op->value = xen_gsi_from_irq(dev->irq);
-diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
-index cb450f4..22ad0f5 100644
---- a/drivers/xen/pciback/conf_space_header.c
-+++ b/drivers/xen/pciback/conf_space_header.c
-@@ -316,27 +316,27 @@ static const struct config_field header_common[] = {
- {}
- };
-
--#define CFG_FIELD_BAR(reg_offset) \
-- { \
-- .offset = reg_offset, \
-- .size = 4, \
-- .init = bar_init, \
-- .reset = bar_reset, \
-- .release = bar_release, \
-- .u.dw.read = bar_read, \
-- .u.dw.write = bar_write, \
-- }
--
--#define CFG_FIELD_ROM(reg_offset) \
-- { \
-- .offset = reg_offset, \
-- .size = 4, \
-- .init = rom_init, \
-- .reset = bar_reset, \
-- .release = bar_release, \
-- .u.dw.read = bar_read, \
-- .u.dw.write = rom_write, \
-- }
-+#define CFG_FIELD_BAR(reg_offset) \
-+ { \
-+ .offset = reg_offset, \
-+ .size = 4, \
-+ .init = bar_init, \
-+ .reset = bar_reset, \
-+ .release = bar_release, \
-+ .u.dw.read = bar_read, \
-+ .u.dw.write = bar_write, \
-+ }
+ struct iphdr *iph;
+ unsigned char *th;
+ int err = -EPROTO;
++ int recalculate_partial_csum = 0;
+
-+#define CFG_FIELD_ROM(reg_offset) \
-+ { \
-+ .offset = reg_offset, \
-+ .size = 4, \
-+ .init = rom_init, \
-+ .reset = bar_reset, \
-+ .release = bar_release, \
-+ .u.dw.read = bar_read, \
-+ .u.dw.write = rom_write, \
++ /*
++ * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
++ * peers can fail to set NETRXF_csum_blank when sending a GSO
++ * frame. In this case force the SKB to CHECKSUM_PARTIAL and
++ * recalculate the partial checksum.
++ */
++ if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
++ netif->rx_gso_checksum_fixup++;
++ skb->ip_summed = CHECKSUM_PARTIAL;
++ recalculate_partial_csum = 1;
+ }
++
++ /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
++ return 0;
- static const struct config_field header_0[] = {
- CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
-diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
-index 7f04f11..5a7e4cc 100644
---- a/drivers/xen/pciback/controller.c
-+++ b/drivers/xen/pciback/controller.c
-@@ -378,7 +378,7 @@ int pciback_publish_pci_roots(struct pciback_device *pdev,
- }
-
- err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-- "%lx", (sizeof(struct acpi_resource) * 2) + 1);
-+ "%lx", (sizeof(struct acpi_resource) *2) + 1);
-
- out:
- spin_unlock(&dev_data->lock);
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index 88c7ca1..c8f6f29 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -13,7 +13,7 @@
- #include <linux/pci.h>
- #include <linux/wait.h>
- #include <linux/sched.h>
--#include <asm/atomic.h>
-+#include <linux/atomic.h>
- #include <xen/events.h>
- #include <asm/xen/pci.h>
- #include <asm/xen/hypervisor.h>
-@@ -603,7 +603,7 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev,
- if (test_bit(_XEN_PCIF_active,
- (unsigned long *)&psdev->pdev->sh_info->flags)) {
- dev_dbg(&psdev->dev->dev,
-- "schedule pci_conf service in pciback \n");
-+ "schedule pci_conf service in pciback\n");
- test_and_schedule_op(psdev->pdev);
- }
-
-@@ -1055,7 +1055,8 @@ static ssize_t pcistub_irq_handler_show(struct device_driver *drv,
char *buf)
- if (!dev_data)
- continue;
- count +=
-- scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing:%ld\n",
-+ scnprintf(buf + count, PAGE_SIZE - count,
-+ "%s:%s:%sing:%ld\n",
- pci_name(psdev->dev),
- dev_data->isr_on ? "on" : "off",
- dev_data->ack_intr ? "ack" : "not ack",
-diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
-index fc31052..5c14020 100644
---- a/drivers/xen/pciback/pciback.h
-+++ b/drivers/xen/pciback/pciback.h
-@@ -12,7 +12,7 @@
- #include <linux/list.h>
- #include <linux/spinlock.h>
- #include <linux/workqueue.h>
--#include <asm/atomic.h>
-+#include <linux/atomic.h>
- #include <xen/interface/io/pciif.h>
-
- struct pci_dev_entry {
-@@ -20,8 +20,8 @@ struct pci_dev_entry {
- struct pci_dev *dev;
- };
-
--#define _PDEVF_op_active (0)
--#define PDEVF_op_active (1<<(_PDEVF_op_active))
-+#define _PDEVF_op_active (0)
-+#define PDEVF_op_active (1<<(_PDEVF_op_active))
- #define _PCIB_op_pending (1)
- #define PCIB_op_pending (1<<(_PCIB_op_pending))
-
-@@ -45,11 +45,11 @@ struct pciback_device {
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
+@@ -1240,9 +1257,23 @@ static int skb_checksum_setup(struct sk_buff *skb)
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ skb->csum_offset = offsetof(struct tcphdr, check);
++
++ if (recalculate_partial_csum) {
++ struct tcphdr *tcph = (struct tcphdr *)th;
++ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
++ skb->len - iph->ihl*4,
++ IPPROTO_TCP, 0);
++ }
+ break;
+ case IPPROTO_UDP:
+ skb->csum_offset = offsetof(struct udphdr, check);
++
++ if (recalculate_partial_csum) {
++ struct udphdr *udph = (struct udphdr *)th;
++ udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
++ skb->len - iph->ihl*4,
++ IPPROTO_UDP, 0);
++ }
+ break;
+ default:
+ if (net_ratelimit())
+@@ -1496,12 +1527,10 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ skb->dev = netif->dev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
- struct pciback_dev_data {
- struct list_head config_fields;
-- unsigned int permissive : 1;
-- unsigned int warned_on_write : 1;
-- unsigned int enable_intx : 1;
-- unsigned int isr_on : 1; /* Whether the IRQ handler is installed. */
-- unsigned int ack_intr : 1; /* .. and ACK-ing */
-+ unsigned int permissive:1;
-+ unsigned int warned_on_write:1;
-+ unsigned int enable_intx:1;
-+ unsigned int isr_on:1; /* Whether the IRQ handler is installed. */
-+ unsigned int ack_intr:1; /* .. and ACK-ing */
- unsigned long handled;
- unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
- char irq_name[0]; /* pciback[000:04:00.0] */
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 5543881..9a465e9 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -63,12 +63,11 @@ void pciback_control_isr(struct pci_dev *dev, int reset)
- dev_data->irq_name, dev);
- if (rc) {
- dev_err(&dev->dev, "%s: failed to install fake IRQ " \
-- "handler for IRQ %d! (rc:%d)\n", dev_data->irq_name,
-- dev_data->irq, rc);
-+ "handler for IRQ %d! (rc:%d)\n",
-+ dev_data->irq_name, dev_data->irq, rc);
- goto out;
- }
-- }
-- else {
-+ } else {
- free_irq(dev_data->irq, dev);
- dev_data->irq = 0;
- }
-@@ -188,7 +187,7 @@ void pciback_do_op(struct work_struct *data)
- break;
- #endif
- default:
-- op->err = XEN_PCI_ERR_not_implemented;
-+ op->err = XEN_PCI_ERR_not_implemented;
- break;
+- if (skb->ip_summed == CHECKSUM_PARTIAL) {
+- if (skb_checksum_setup(skb)) {
+- DPRINTK("Can't setup checksum in net_tx_action\n");
+- kfree_skb(skb);
+- continue;
+- }
++ if (checksum_setup(netif, skb)) {
++ DPRINTK("Can't setup checksum in net_tx_action\n");
++ kfree_skb(skb);
++ continue;
}
- }
-diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
-index 993b659..70030c4 100644
---- a/drivers/xen/pciback/xenbus.c
-+++ b/drivers/xen/pciback/xenbus.c
-@@ -700,12 +700,12 @@ static const struct xenbus_device_id xenpci_ids[] = {
- };
-
- static struct xenbus_driver xenbus_pciback_driver = {
-- .name = "pciback",
-- .owner = THIS_MODULE,
-- .ids = xenpci_ids,
-- .probe = pciback_xenbus_probe,
-- .remove = pciback_xenbus_remove,
-- .otherend_changed = pciback_frontend_changed,
-+ .name = "pciback",
-+ .owner = THIS_MODULE,
-+ .ids = xenpci_ids,
-+ .probe = pciback_xenbus_probe,
-+ .remove = pciback_xenbus_remove,
-+ .otherend_changed = pciback_frontend_changed,
- };
- int __init pciback_xenbus_register(void)
-@@ -713,7 +713,7 @@ int __init pciback_xenbus_register(void)
- pciback_wq = create_workqueue("pciback_workqueue");
- if (!pciback_wq) {
- printk(KERN_ERR "%s: create"
-- "pciback_workqueue failed\n",__FUNCTION__);
-+ "pciback_workqueue failed\n", __func__);
- return -EFAULT;
- }
- return xenbus_register_backend(&xenbus_pciback_driver);
+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
--
1.7.4
-From 83d24d8dbd9e52a7ac94deae2d9fff6681ce8761 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 13 Dec 2010 11:30:29 -0500
-Subject: [PATCH 036/244] xen/xen-pciback: Swap over to DEFINE_PCI_DEVICE_TABLE
+From 929c2cd7541a48c9ab64af1b25b3e53ed396e0c5 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 18 Jan 2011 11:37:12 +0000
+Subject: [PATCH 078/203] xen: netback: rationalise types used in count_skb_slots
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/pciback/pci_stub.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ drivers/xen/netback/netback.c | 10 +++-------
+ 1 files changed, 3 insertions(+), 7 deletions(-)
-diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
-index c8f6f29..09dd60c 100644
---- a/drivers/xen/pciback/pci_stub.c
-+++ b/drivers/xen/pciback/pci_stub.c
-@@ -497,7 +497,7 @@ static void pcistub_remove(struct pci_dev *dev)
- }
- }
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 8189199..22c1fa5 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -277,14 +277,10 @@ static inline int netbk_queue_full(struct xen_netif *netif)
+
+ /* Figure out how many ring slots we're going to need to send @skb to
+ the guest. */
+-static unsigned count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
++static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
+ {
+- unsigned count;
+- unsigned copy_off;
+- unsigned i;
+-
+- copy_off = 0;
+- count = 1;
++ unsigned int count = 1;
++ int i, copy_off = 0;
+
+ BUG_ON(offset_in_page(skb->data) + skb_headlen(skb) > MAX_BUFFER_OFFSET);
--static const struct pci_device_id pcistub_ids[] = {
-+DEFINE_PCI_DEVICE_TABLE(pcistub_ids) = {
- {
- .vendor = PCI_ANY_ID,
- .device = PCI_ANY_ID,
--
1.7.4
-From 03c4949992e2b7e84b7cdeb156d803db3f848b6c Mon Sep 17 00:00:00 2001
+From 0ded854cc2e58205d857df3d96ef6f9a108a4a66 Mon Sep 17 00:00:00 2001
From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Mon, 9 Feb 2009 12:05:52 -0800
-Subject: [PATCH 037/244] xen: netback: Initial import of linux-2.6.18-xen.hg netback
driver.
-
-This corresponds to 774:107e10e0e07c in that tree.
+Date: Tue, 18 Jan 2011 11:21:35 +0000
+Subject: [PATCH 079/203] xen: netback: refactor logic for moving to a new receive
buffer.
Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/xen/Kconfig | 7 +
- drivers/xen/Makefile | 1 +
- drivers/xen/netback/Makefile | 3 +
- drivers/xen/netback/common.h | 217 ++++++
- drivers/xen/netback/interface.c | 336 ++++++++
- drivers/xen/netback/netback.c | 1637 +++++++++++++++++++++++++++++++++++++++
- drivers/xen/netback/xenbus.c | 454 +++++++++++
- 7 files changed, 2655 insertions(+), 0 deletions(-)
- create mode 100644 drivers/xen/netback/Makefile
- create mode 100644 drivers/xen/netback/common.h
- create mode 100644 drivers/xen/netback/interface.c
- create mode 100644 drivers/xen/netback/netback.c
- create mode 100644 drivers/xen/netback/xenbus.c
+ drivers/xen/netback/netback.c | 80 ++++++++++++++++++++++++-----------------
+ 1 files changed, 47 insertions(+), 33 deletions(-)
-diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
-index 5a48ce9..7e83d43 100644
---- a/drivers/xen/Kconfig
-+++ b/drivers/xen/Kconfig
-@@ -37,6 +37,13 @@ config XEN_BACKEND
- depends on XEN_PCIDEV_BACKEND
-
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 22c1fa5..909e0ef 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -275,8 +275,51 @@ static inline int netbk_queue_full(struct xen_netif *netif)
+ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
+ }
-+config XEN_NETDEV_BACKEND
-+ bool "Xen backend network device"
-+ depends on XEN_BACKEND && NET
-+ help
-+ Implement the network backend driver, which passes packets
-+ from the guest domain's frontend drivers to the network.
-+
- config XENFS
- tristate "Xen filesystem"
- default y
-diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
-index 533a199..c0e0509 100644
---- a/drivers/xen/Makefile
-+++ b/drivers/xen/Makefile
-@@ -9,6 +9,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
- obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
- obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
- obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
-+obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
- obj-$(CONFIG_XENFS) += xenfs/
- obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
- obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
-diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
-new file mode 100644
-index 0000000..f4a0c51
---- /dev/null
-+++ b/drivers/xen/netback/Makefile
-@@ -0,0 +1,3 @@
-+obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
-+
-+netbk-y := netback.o xenbus.o interface.o
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-new file mode 100644
-index 0000000..9a54d57
---- /dev/null
-+++ b/drivers/xen/netback/common.h
-@@ -0,0 +1,217 @@
-+/******************************************************************************
-+ * arch/xen/drivers/netif/backend/common.h
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#ifndef __NETIF__BACKEND__COMMON_H__
-+#define __NETIF__BACKEND__COMMON_H__
-+
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <linux/ip.h>
-+#include <linux/in.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/wait.h>
-+#include <xen/evtchn.h>
-+#include <xen/interface/io/netif.h>
-+#include <asm/io.h>
-+#include <asm/pgalloc.h>
-+#include <xen/interface/grant_table.h>
-+#include <xen/gnttab.h>
-+#include <xen/driver_util.h>
-+#include <xen/xenbus.h>
-+
-+#define DPRINTK(_f, _a...) \
-+ pr_debug("(file=%s, line=%d) " _f, \
-+ __FILE__ , __LINE__ , ## _a )
-+#define IPRINTK(fmt, args...) \
-+ printk(KERN_INFO "xen_net: " fmt, ##args)
-+#define WPRINTK(fmt, args...) \
-+ printk(KERN_WARNING "xen_net: " fmt, ##args)
-+
-+typedef struct netif_st {
-+ /* Unique identifier for this interface. */
-+ domid_t domid;
-+ unsigned int handle;
-+
-+ u8 fe_dev_addr[6];
-+
-+ /* Physical parameters of the comms window. */
-+ grant_handle_t tx_shmem_handle;
-+ grant_ref_t tx_shmem_ref;
-+ grant_handle_t rx_shmem_handle;
-+ grant_ref_t rx_shmem_ref;
-+ unsigned int irq;
-+
-+ /* The shared rings and indexes. */
-+ netif_tx_back_ring_t tx;
-+ netif_rx_back_ring_t rx;
-+ struct vm_struct *tx_comms_area;
-+ struct vm_struct *rx_comms_area;
-+
-+ /* Set of features that can be turned on in dev->features. */
-+ int features;
-+
-+ /* Internal feature information. */
-+ u8 can_queue:1; /* can queue packets for receiver? */
-+ u8 copying_receiver:1; /* copy packets to receiver? */
-+
-+ /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
-+ RING_IDX rx_req_cons_peek;
-+
-+ /* 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;
-+
-+ /* Enforce draining of the transmit queue. */
-+ struct timer_list tx_queue_timeout;
-+
-+ /* Miscellaneous private stuff. */
-+ struct list_head list; /* scheduling list */
-+ atomic_t refcnt;
-+ struct net_device *dev;
-+ struct net_device_stats stats;
-+
-+ unsigned int carrier;
-+
-+ wait_queue_head_t waiting_to_free;
-+} netif_t;
-+
-+/*
-+ * Implement our own carrier flag: the network stack's version causes delays
-+ * when the carrier is re-enabled (in particular, dev_activate() may not
-+ * immediately be called, which can cause packet loss; also the etherbridge
-+ * can be rather lazy in activating its port).
-+ */
-+#define netback_carrier_on(netif) ((netif)->carrier = 1)
-+#define netback_carrier_off(netif) ((netif)->carrier = 0)
-+#define netback_carrier_ok(netif) ((netif)->carrier)
-+
-+enum {
-+ NETBK_DONT_COPY_SKB,
-+ NETBK_DELAYED_COPY_SKB,
-+ NETBK_ALWAYS_COPY_SKB,
-+};
-+
-+extern int netbk_copy_skb_mode;
-+
-+/* Function pointers into netback accelerator plugin modules */
-+struct netback_accel_hooks {
-+ struct module *owner;
-+ int (*probe)(struct xenbus_device *dev);
-+ int (*remove)(struct xenbus_device *dev);
-+};
-+
-+/* Structure to track the state of a netback accelerator plugin */
-+struct netback_accelerator {
-+ struct list_head link;
-+ int id;
-+ char *eth_name;
-+ atomic_t use_count;
-+ struct netback_accel_hooks *hooks;
-+};
-+
-+struct backend_info {
-+ struct xenbus_device *dev;
-+ netif_t *netif;
-+ enum xenbus_state frontend_state;
-+
-+ /* State relating to the netback accelerator */
-+ void *netback_accel_priv;
-+ /* The accelerator that this backend is currently using */
-+ struct netback_accelerator *accelerator;
-+};
-+
-+#define NETBACK_ACCEL_VERSION 0x00010001
-+
+-/* Figure out how many ring slots we're going to need to send @skb to
+- the guest. */
+/*
-+ * Connect an accelerator plugin module to netback. Returns zero on
-+ * success, < 0 on error, > 0 (with highest version number supported)
-+ * if version mismatch.
++ * Returns true if we should start a new receive buffer instead of
++ * adding 'size' bytes to a buffer which currently contains 'offset'
++ * bytes.
+ */
-+extern int netback_connect_accelerator(unsigned version,
-+ int id, const char *eth_name,
-+ struct netback_accel_hooks *hooks);
-+/* Disconnect a previously connected accelerator plugin module */
-+extern void netback_disconnect_accelerator(int id, const char *eth_name);
-+
-+
-+extern
-+void netback_probe_accelerators(struct backend_info *be,
-+ struct xenbus_device *dev);
-+extern
-+void netback_remove_accelerators(struct backend_info *be,
-+ struct xenbus_device *dev);
-+extern
-+void netif_accel_init(void);
-+
-+
-+#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
-+#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
-+
-+void netif_disconnect(netif_t *netif);
-+
-+netif_t *netif_alloc(domid_t domid, unsigned int handle);
-+int netif_map(netif_t *netif, unsigned long tx_ring_ref,
-+ unsigned long rx_ring_ref, unsigned int evtchn);
-+
-+#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
-+#define netif_put(_b) \
-+ do { \
-+ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
-+ wake_up(&(_b)->waiting_to_free); \
-+ } while (0)
-+
-+void netif_xenbus_init(void);
-+
-+#define netif_schedulable(netif) \
-+ (netif_running((netif)->dev) && netback_carrier_ok(netif))
-+
-+void netif_schedule_work(netif_t *netif);
-+void netif_deschedule_work(netif_t *netif);
-+
-+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+struct net_device_stats *netif_be_get_stats(struct net_device *dev);
-+irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
-+
-+static inline int netbk_can_queue(struct net_device *dev)
-+{
-+ netif_t *netif = netdev_priv(dev);
-+ return netif->can_queue;
-+}
-+
-+static inline int netbk_can_sg(struct net_device *dev)
++static bool start_new_rx_buffer(int offset, unsigned long size, int head)
+{
-+ netif_t *netif = netdev_priv(dev);
-+ return netif->features & NETIF_F_SG;
-+}
++ /* simple case: we have completely filled the current buffer. */
++ if (offset == MAX_BUFFER_OFFSET)
++ return true;
+
-+#endif /* __NETIF__BACKEND__COMMON_H__ */
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-new file mode 100644
-index 0000000..7e67941
---- /dev/null
-+++ b/drivers/xen/netback/interface.c
-@@ -0,0 +1,336 @@
-+/******************************************************************************
-+ * arch/xen/drivers/netif/backend/interface.c
-+ *
-+ * Network-device interface management.
-+ *
-+ * Copyright (c) 2004-2005, Keir Fraser
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++ /*
++ * complex case: start a fresh buffer if the current frag
++ * would overflow the current buffer but only if:
++ * (i) this frag would fit completely in the next buffer
++ * and (ii) there is already some data in the current buffer
++ * and (iii) this is not the head buffer.
++ *
++ * Where:
++ * - (i) stops us splitting a frag into two copies
++ * unless the frag is too large for a single buffer.
++ * - (ii) stops us from leaving a buffer pointlessly empty.
++ * - (iii) stops us leaving the first buffer
++ * empty. Strictly speaking this is already covered
++ * by (ii) but is explicitly checked because
++ * netfront relies on the first buffer being
++ * non-empty and can crash otherwise.
++ *
++ * This means we will effectively linearise small
++ * frags but do not needlessly split large buffers
++ * into multiple copies tend to give large frags their
++ * own buffers as before.
++ */
++ if ((offset + size > MAX_BUFFER_OFFSET) &&
++ (size <= MAX_BUFFER_OFFSET) && offset && !head)
++ return true;
+
-+#include "common.h"
-+#include <linux/ethtool.h>
-+#include <linux/rtnetlink.h>
++ return false;
++}
+
+/*
-+ * Module parameter 'queue_length':
-+ *
-+ * Enables queuing in the network stack when a client has run out of receive
-+ * descriptors. Although this feature can improve receive bandwidth by avoiding
-+ * packet loss, it can also result in packets sitting in the 'tx_queue' for
-+ * unbounded time. This is bad if those packets hold onto foreign resources.
-+ * For example, consider a packet that holds onto resources belonging to the
-+ * guest for which it is queued (e.g., packet received on vif1.0, destined for
-+ * vif1.1 which is not activated in the guest): in this situation the guest
-+ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
-+ * run a timer (tx_queue_timeout) to drain the queue when the interface is
-+ * blocked.
++ * Figure out how many ring slots we're going to need to send @skb to
++ * the guest. This function is essentially a dry run of
++ * netbk_gop_frag_copy.
+ */
-+static unsigned long netbk_queue_length = 32;
-+module_param_named(queue_length, netbk_queue_length, ulong, 0);
-+
-+static void __netif_up(netif_t *netif)
-+{
-+ enable_irq(netif->irq);
-+ netif_schedule_work(netif);
-+}
-+
-+static void __netif_down(netif_t *netif)
-+{
-+ disable_irq(netif->irq);
-+ netif_deschedule_work(netif);
-+}
-+
-+static int net_open(struct net_device *dev)
-+{
-+ netif_t *netif = netdev_priv(dev);
-+ if (netback_carrier_ok(netif)) {
-+ __netif_up(netif);
-+ netif_start_queue(dev);
-+ }
-+ return 0;
-+}
-+
-+static int net_close(struct net_device *dev)
-+{
-+ netif_t *netif = netdev_priv(dev);
-+ if (netback_carrier_ok(netif))
-+ __netif_down(netif);
-+ netif_stop_queue(dev);
-+ return 0;
-+}
-+
-+static int netbk_change_mtu(struct net_device *dev, int mtu)
+ static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
+ {
+ unsigned int count = 1;
+@@ -295,9 +338,7 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xen_netif *netif
+ while (size > 0) {
+ BUG_ON(copy_off > MAX_BUFFER_OFFSET);
+
+- /* These checks are the same as in netbk_gop_frag_copy */
+- if (copy_off == MAX_BUFFER_OFFSET
+- || ((copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && copy_off)) {
++ if (start_new_rx_buffer(copy_off, size, 0)) {
+ count++;
+ copy_off = 0;
+ }
+@@ -403,34 +444,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ while (size > 0) {
+ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
+
+- /*
+- * Move to a new receive buffer if:
+- *
+- * simple case: we have completely filled the current buffer.
+- *
+- * complex case: the current frag would overflow
+- * the current buffer but only if:
+- * (i) this frag would fit completely in the next buffer
+- * and (ii) there is already some data in the current buffer
+- * and (iii) this is not the head buffer.
+- *
+- * Where:
+- * - (i) stops us splitting a frag into two copies
+- * unless the frag is too large for a single buffer.
+- * - (ii) stops us from leaving a buffer pointlessly empty.
+- * - (iii) stops us leaving the first buffer
+- * empty. Strictly speaking this is already covered
+- * by (ii) but is explicitly checked because
+- * netfront relies on the first buffer being
+- * non-empty and can crash otherwise.
+- *
+- * This means we will effectively linearise small
+- * frags but do not needlessly split large buffers
+- * into multiple copies tend to give large frags their
+- * own buffers as before.
+- */
+- if (npo->copy_off == MAX_BUFFER_OFFSET
+- || ((npo->copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && npo->copy_off && !head)) {
++ if (start_new_rx_buffer(npo->copy_off, size, head)) {
+ struct xen_netif_rx_request *req;
+
+ BUG_ON(head); /* Netfront requires there to be some data in the head buffer. */
+--
+1.7.4
+
+
+From 9e79b27c9369d25ca86abf66611a700783ce1ef2 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 2 Feb 2011 11:12:39 +0000
+Subject: [PATCH 080/203] xen: netback: refactor code to get next rx buffer into own
function.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 37 ++++++++++++++++++++++++++-----------
+ 1 files changed, 26 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index 909e0ef..a8ee1c2 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -418,6 +418,25 @@ struct netrx_pending_operations {
+ grant_ref_t copy_gref;
+ };
+
++static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
++ struct netrx_pending_operations *npo)
+{
-+ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++ struct netbk_rx_meta *meta;
++ struct xen_netif_rx_request *req;
+
-+ if (mtu > max)
-+ return -EINVAL;
-+ dev->mtu = mtu;
-+ return 0;
-+}
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+
-+static int netbk_set_sg(struct net_device *dev, u32 data)
-+{
-+ if (data) {
-+ netif_t *netif = netdev_priv(dev);
++ meta = npo->meta + npo->meta_prod++;
++ meta->gso_size = 0;
++ meta->size = 0;
++ meta->id = req->id;
+
-+ if (!(netif->features & NETIF_F_SG))
-+ return -ENOSYS;
-+ }
++ npo->copy_off = 0;
++ npo->copy_gref = req->gref;
+
-+ return ethtool_op_set_sg(dev, data);
++ return meta;
+}
+
-+static int netbk_set_tso(struct net_device *dev, u32 data)
-+{
-+ if (data) {
-+ netif_t *netif = netdev_priv(dev);
+ /* Set up the grant operations for this fragment. If it's a flipping
+ interface, we also set up the unmap request from here. */
+
+@@ -445,17 +464,13 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
+
+ if (start_new_rx_buffer(npo->copy_off, size, head)) {
+- struct xen_netif_rx_request *req;
+-
+- BUG_ON(head); /* Netfront requires there to be some data in the head buffer. */
+- /* Overflowed this request, go to the next one */
+- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+- meta = npo->meta + npo->meta_prod++;
+- meta->gso_size = 0;
+- meta->size = 0;
+- meta->id = req->id;
+- npo->copy_off = 0;
+- npo->copy_gref = req->gref;
++ /*
++ * Netfront requires there to be some data in the head
++ * buffer.
++ */
++ BUG_ON(head);
+
-+ if (!(netif->features & NETIF_F_TSO))
-+ return -ENOSYS;
-+ }
-+
-+ return ethtool_op_set_tso(dev, data);
-+}
-+
-+static struct ethtool_ops network_ethtool_ops =
-+{
-+ .get_tx_csum = ethtool_op_get_tx_csum,
-+ .set_tx_csum = ethtool_op_set_tx_csum,
-+ .get_sg = ethtool_op_get_sg,
-+ .set_sg = netbk_set_sg,
-+ .get_tso = ethtool_op_get_tso,
-+ .set_tso = netbk_set_tso,
-+ .get_link = ethtool_op_get_link,
-+};
-+
-+netif_t *netif_alloc(domid_t domid, unsigned int handle)
-+{
-+ int err = 0;
-+ struct net_device *dev;
-+ netif_t *netif;
-+ char name[IFNAMSIZ] = {};
-+
-+ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
-+ dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
-+ if (dev == NULL) {
-+ DPRINTK("Could not create netif: out of memory\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ netif = netdev_priv(dev);
-+ memset(netif, 0, sizeof(*netif));
-+ netif->domid = domid;
-+ netif->handle = handle;
-+ atomic_set(&netif->refcnt, 1);
-+ init_waitqueue_head(&netif->waiting_to_free);
-+ netif->dev = dev;
-+
-+ netback_carrier_off(netif);
-+
-+ netif->credit_bytes = netif->remaining_credit = ~0UL;
-+ netif->credit_usec = 0UL;
-+ init_timer(&netif->credit_timeout);
-+ /* Initialize 'expires' now: it's used to track the credit window. */
-+ netif->credit_timeout.expires = jiffies;
-+
-+ init_timer(&netif->tx_queue_timeout);
-+
-+ dev->hard_start_xmit = netif_be_start_xmit;
-+ dev->get_stats = netif_be_get_stats;
-+ dev->open = net_open;
-+ dev->stop = net_close;
-+ dev->change_mtu = netbk_change_mtu;
-+ dev->features = NETIF_F_IP_CSUM;
-+
-+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-+
-+ dev->tx_queue_len = netbk_queue_length;
-+
-+ /*
-+ * Initialise a dummy MAC address. We choose the numerically
-+ * largest non-broadcast address to prevent the address getting
-+ * stolen by an Ethernet bridge for STP purposes.
-+ * (FE:FF:FF:FF:FF:FF)
-+ */
-+ memset(dev->dev_addr, 0xFF, ETH_ALEN);
-+ dev->dev_addr[0] &= ~0x01;
-+
-+ rtnl_lock();
-+ err = register_netdevice(dev);
-+ rtnl_unlock();
-+ if (err) {
-+ DPRINTK("Could not register new net device %s: err=%d\n",
-+ dev->name, err);
-+ free_netdev(dev);
-+ return ERR_PTR(err);
-+ }
-+
-+ DPRINTK("Successfully created netif\n");
-+ return netif;
-+}
-+
-+static int map_frontend_pages(
-+ netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
-+{
-+ struct gnttab_map_grant_ref op;
-+
-+ gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
-+ GNTMAP_host_map, tx_ring_ref, netif->domid);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+ BUG();
-+
-+ if (op.status) {
-+ DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
-+ return op.status;
-+ }
-+
-+ netif->tx_shmem_ref = tx_ring_ref;
-+ netif->tx_shmem_handle = op.handle;
-+
-+ gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
-+ GNTMAP_host_map, rx_ring_ref, netif->domid);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+ BUG();
-+
-+ if (op.status) {
-+ DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
-+ return op.status;
-+ }
-+
-+ netif->rx_shmem_ref = rx_ring_ref;
-+ netif->rx_shmem_handle = op.handle;
-+
-+ return 0;
-+}
-+
-+static void unmap_frontend_pages(netif_t *netif)
-+{
-+ struct gnttab_unmap_grant_ref op;
-+
-+ gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
-+ GNTMAP_host_map, netif->tx_shmem_handle);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+ BUG();
-+
-+ gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
-+ GNTMAP_host_map, netif->rx_shmem_handle);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+ BUG();
-+}
-+
-+int netif_map(netif_t *netif, unsigned long tx_ring_ref,
-+ unsigned long rx_ring_ref, unsigned int evtchn)
-+{
-+ int err = -ENOMEM;
-+ netif_tx_sring_t *txs;
-+ netif_rx_sring_t *rxs;
-+
-+ /* Already connected through? */
-+ if (netif->irq)
-+ return 0;
-+
-+ netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
-+ if (netif->tx_comms_area == NULL)
-+ return -ENOMEM;
-+ netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
-+ if (netif->rx_comms_area == NULL)
-+ goto err_rx;
-+
-+ err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
-+ if (err)
-+ goto err_map;
-+
-+ err = bind_interdomain_evtchn_to_irqhandler(
-+ netif->domid, evtchn, netif_be_int, 0,
-+ netif->dev->name, netif);
-+ if (err < 0)
-+ goto err_hypervisor;
-+ netif->irq = err;
-+ disable_irq(netif->irq);
-+
-+ txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
-+ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
-+
-+ rxs = (netif_rx_sring_t *)
-+ ((char *)netif->rx_comms_area->addr);
-+ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
-+
-+ netif->rx_req_cons_peek = 0;
-+
-+ netif_get(netif);
-+
-+ rtnl_lock();
-+ netback_carrier_on(netif);
-+ if (netif_running(netif->dev))
-+ __netif_up(netif);
-+ rtnl_unlock();
-+
-+ return 0;
-+err_hypervisor:
-+ unmap_frontend_pages(netif);
-+err_map:
-+ free_vm_area(netif->rx_comms_area);
-+err_rx:
-+ free_vm_area(netif->tx_comms_area);
-+ return err;
-+}
-+
-+void netif_disconnect(netif_t *netif)
-+{
-+ if (netback_carrier_ok(netif)) {
-+ rtnl_lock();
-+ netback_carrier_off(netif);
-+ netif_carrier_off(netif->dev); /* discard queued packets */
-+ if (netif_running(netif->dev))
-+ __netif_down(netif);
-+ rtnl_unlock();
-+ netif_put(netif);
-+ }
-+
-+ atomic_dec(&netif->refcnt);
-+ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
-+
-+ del_timer_sync(&netif->credit_timeout);
-+ del_timer_sync(&netif->tx_queue_timeout);
-+
-+ if (netif->irq)
-+ unbind_from_irqhandler(netif->irq, netif);
-+
-+ unregister_netdev(netif->dev);
-+
-+ if (netif->tx.sring) {
-+ unmap_frontend_pages(netif);
-+ free_vm_area(netif->tx_comms_area);
-+ free_vm_area(netif->rx_comms_area);
-+ }
-+
-+ free_netdev(netif->dev);
-+}
++ meta = get_next_rx_buffer(netif, npo);
+ }
+
+ bytes = size;
+--
+1.7.4
+
+
+From e02c96928e165eb351ded4cc78cce4c615778be3 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 2 Feb 2011 11:14:17 +0000
+Subject: [PATCH 081/203] xen: netback: simplify use of netbk_add_frag_responses
+
+Move all the logic into the function instead of having some in the caller.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/netback.c | 14 +++++++++-----
+ 1 files changed, 9 insertions(+), 5 deletions(-)
+
diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-new file mode 100644
-index 0000000..db629d4
---- /dev/null
+index a8ee1c2..cfe7931 100644
+--- a/drivers/xen/netback/netback.c
+++ b/drivers/xen/netback/netback.c
-@@ -0,0 +1,1637 @@
-+/******************************************************************************
-+ * drivers/xen/netback/netback.c
-+ *
-+ * Back-end of the driver for virtual network devices. This portion of the
-+ * driver exports a 'unified' network-device interface that can be accessed
-+ * by any operating system that implements a compatible front end. A
-+ * reference front-end implementation can be found in:
-+ * drivers/xen/netfront/netfront.c
-+ *
-+ * Copyright (c) 2002-2005, K A Fraser
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#include "common.h"
-+#include <xen/balloon.h>
-+#include <xen/interface/memory.h>
-+
-+/*define NETBE_DEBUG_INTERRUPT*/
-+
-+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;
-+};
-+
-+static void netif_idx_release(u16 pending_idx);
-+static void make_tx_response(netif_t *netif,
-+ netif_tx_request_t *txp,
-+ s8 st);
-+static netif_rx_response_t *make_rx_response(netif_t *netif,
-+ u16 id,
-+ s8 st,
-+ u16 offset,
-+ 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;
-+
-+#define MAX_PENDING_REQS 256
-+
-+static struct sk_buff_head rx_queue;
-+
-+static struct page **mmap_pages;
-+static inline unsigned long idx_to_pfn(unsigned int idx)
-+{
-+ return page_to_pfn(mmap_pages[idx]);
-+}
-+
-+static inline unsigned long idx_to_kaddr(unsigned int idx)
-+{
-+ return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx));
-+}
-+
-+/* extra field used in struct page */
-+static inline void netif_set_page_index(struct page *pg, unsigned int index)
-+{
-+ *(unsigned long *)&pg->mapping = index;
-+}
-+
-+static inline int netif_page_index(struct page *pg)
-+{
-+ unsigned long idx = (unsigned long)pg->mapping;
-+
-+ if (!PageForeign(pg))
-+ return -1;
-+
-+ if ((idx >= MAX_PENDING_REQS) || (mmap_pages[idx] != pg))
-+ return -1;
-+
-+ return idx;
-+}
-+
-+#define PKT_PROT_LEN 64
-+
-+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;
-+
-+/* Setting this allows the safe use of this driver without netloop. */
-+static int MODPARM_copy_skb = 1;
-+module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
-+MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
-+
-+int netbk_copy_skb_mode;
-+
-+static inline unsigned long alloc_mfn(void)
-+{
-+ BUG_ON(alloc_index == 0);
-+ return mfn_list[--alloc_index];
-+}
-+
-+static int check_mfn(int nr)
-+{
-+ struct xen_memory_reservation reservation = {
-+ .extent_order = 0,
-+ .domid = DOMID_SELF
-+ };
-+ int rc;
-+
-+ if (likely(alloc_index >= nr))
-+ return 0;
-+
-+ set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
-+ reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
-+ rc = HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation);
-+ if (likely(rc > 0))
-+ alloc_index += rc;
-+
-+ return alloc_index >= nr ? 0 : -ENOMEM;
-+}
-+
-+static inline void maybe_schedule_tx_action(void)
-+{
-+ smp_mb();
-+ if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
-+ !list_empty(&net_schedule_list))
-+ tasklet_schedule(&net_tx_tasklet);
-+}
-+
-+static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-+{
-+ struct skb_shared_info *ninfo;
-+ struct sk_buff *nskb;
-+ unsigned long offset;
-+ int ret;
-+ int len;
-+ int headlen;
-+
-+ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
-+
-+ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-+ if (unlikely(!nskb))
-+ goto err;
-+
-+ skb_reserve(nskb, 16 + NET_IP_ALIGN);
-+ headlen = nskb->end - nskb->data;
-+ if (headlen > skb_headlen(skb))
-+ headlen = skb_headlen(skb);
-+ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-+ BUG_ON(ret);
-+
-+ ninfo = skb_shinfo(nskb);
-+ ninfo->gso_size = skb_shinfo(skb)->gso_size;
-+ ninfo->gso_type = skb_shinfo(skb)->gso_type;
-+
-+ offset = headlen;
-+ len = skb->len - headlen;
-+
-+ nskb->len = skb->len;
-+ nskb->data_len = len;
-+ nskb->truesize += len;
-+
-+ while (len) {
-+ struct page *page;
-+ int copy;
-+ int zero;
-+
-+ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-+ dump_stack();
-+ goto err_free;
-+ }
-+
-+ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-+ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
-+
-+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-+ if (unlikely(!page))
-+ goto err_free;
-+
-+ ret = skb_copy_bits(skb, offset, page_address(page), copy);
-+ BUG_ON(ret);
-+
-+ ninfo->frags[ninfo->nr_frags].page = page;
-+ ninfo->frags[ninfo->nr_frags].page_offset = 0;
-+ ninfo->frags[ninfo->nr_frags].size = copy;
-+ ninfo->nr_frags++;
-+
-+ offset += copy;
-+ len -= copy;
-+ }
-+
-+ offset = nskb->data - skb->data;
-+
-+ nskb->h.raw = skb->h.raw + offset;
-+ nskb->nh.raw = skb->nh.raw + offset;
-+ nskb->mac.raw = skb->mac.raw + offset;
-+
-+ return nskb;
+@@ -599,6 +599,12 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
+ int i;
+ unsigned long offset;
+
++ /* No fragments used */
++ if (nr_meta_slots <= 1)
++ return;
+
-+ err_free:
-+ kfree_skb(nskb);
-+ err:
-+ return NULL;
-+}
++ nr_meta_slots--;
+
-+static inline int netbk_max_required_rx_slots(netif_t *netif)
-+{
-+ if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
-+ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-+ return 1; /* all in one */
-+}
-+
-+static inline int netbk_queue_full(netif_t *netif)
-+{
-+ RING_IDX peek = netif->rx_req_cons_peek;
-+ RING_IDX needed = netbk_max_required_rx_slots(netif);
-+
-+ return ((netif->rx.sring->req_prod - peek) < needed) ||
-+ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
-+}
-+
-+static void tx_queue_callback(unsigned long data)
-+{
-+ netif_t *netif = (netif_t *)data;
-+ if (netif_schedulable(netif))
-+ netif_wake_queue(netif->dev);
-+}
-+
-+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ netif_t *netif = netdev_priv(dev);
-+
-+ BUG_ON(skb->dev != dev);
-+
-+ /* Drop the packet if the target domain has no receive buffers. */
-+ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
-+ goto drop;
-+
-+ /*
-+ * Copy the packet here if it's destined for a flipping interface
-+ * but isn't flippable (e.g. extra references to data).
-+ * XXX For now we also copy skbuffs whose head crosses a page
-+ * boundary, because netbk_gop_skb can't handle them.
-+ */
-+ if (!netif->copying_receiver ||
-+ ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) {
-+ struct sk_buff *nskb = netbk_copy_skb(skb);
-+ if ( unlikely(nskb == NULL) )
-+ goto drop;
-+ /* Copy only the header fields we use in this driver. */
-+ nskb->dev = skb->dev;
-+ nskb->ip_summed = skb->ip_summed;
-+ nskb->proto_data_valid = skb->proto_data_valid;
-+ dev_kfree_skb(skb);
-+ skb = nskb;
-+ }
-+
-+ netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
-+ !!skb_shinfo(skb)->gso_size;
-+ netif_get(netif);
-+
-+ if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
-+ netif->rx.sring->req_event = netif->rx_req_cons_peek +
-+ netbk_max_required_rx_slots(netif);
-+ mb(); /* request notification /then/ check & stop the queue */
-+ if (netbk_queue_full(netif)) {
-+ netif_stop_queue(dev);
-+ /*
-+ * Schedule 500ms timeout to restart the queue, thus
-+ * ensuring that an inactive queue will be drained.
-+ * Packets will be immediately be dropped until more
-+ * receive buffers become available (see
-+ * netbk_queue_full() check above).
-+ */
-+ netif->tx_queue_timeout.data = (unsigned long)netif;
-+ netif->tx_queue_timeout.function = tx_queue_callback;
-+ __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
-+ }
-+ }
-+
-+ skb_queue_tail(&rx_queue, skb);
-+ tasklet_schedule(&net_rx_tasklet);
-+
-+ return 0;
-+
-+ drop:
-+ netif->stats.tx_dropped++;
-+ dev_kfree_skb(skb);
-+ return 0;
-+}
-+
-+#if 0
-+static void xen_network_done_notify(void)
-+{
-+ static struct net_device *eth0_dev = NULL;
-+ if (unlikely(eth0_dev == NULL))
-+ eth0_dev = __dev_get_by_name("eth0");
-+ netif_rx_schedule(eth0_dev);
-+}
+ for (i = 0; i < nr_meta_slots; i++) {
+ int flags;
+ if (i == nr_meta_slots - 1)
+@@ -727,11 +733,9 @@ static void net_rx_action(unsigned long data)
+ gso->flags = 0;
+ }
+
+- if (sco->meta_slots_used > 1) {
+- netbk_add_frag_responses(netif, status,
+- netbk->meta + npo.meta_cons + 1,
+- sco->meta_slots_used - 1);
+- }
++ netbk_add_frag_responses(netif, status,
++ netbk->meta + npo.meta_cons + 1,
++ sco->meta_slots_used);
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
+ irq = netif->irq;
+--
+1.7.4
+
+
+From 9304651128c7fdc2ffdf36e9fd589a13d5aca35d Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 24 Dec 2010 13:37:04 +0000
+Subject: [PATCH 082/203] xen: netback: cleanup coding style
+
+Fix checkpatch.pl errors plus manual sweep.
+
+Including:
+- remove incorrect and unnecessary filenames from comment headers.
+- do not include <linux/version.h>
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 57 ++----------------------
+ drivers/xen/netback/interface.c | 18 +++----
+ drivers/xen/netback/netback.c | 93 ++++++++++++++++++++-------------------
+ drivers/xen/netback/xenbus.c | 65 ++++++++++++---------------
+ 4 files changed, 89 insertions(+), 144 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index f660eb5..a2455a0 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -1,6 +1,4 @@
+-/******************************************************************************
+- * arch/xen/drivers/netif/backend/common.h
+- *
+/*
-+ * Add following to poll() function in NAPI driver (Tigon3 is example):
-+ * if ( xen_network_done() )
-+ * tg3_enable_ints(tp);
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+@@ -29,19 +27,18 @@
+ #ifndef __NETIF__BACKEND__COMMON_H__
+ #define __NETIF__BACKEND__COMMON_H__
+
+-#include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/slab.h>
+ #include <linux/ip.h>
+ #include <linux/in.h>
++#include <linux/io.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/wait.h>
+ #include <linux/sched.h>
+
+ #include <xen/interface/io/netif.h>
+-#include <asm/io.h>
+ #include <asm/pgalloc.h>
+ #include <xen/interface/grant_table.h>
+ #include <xen/grant_table.h>
+@@ -49,7 +46,7 @@
+
+ #define DPRINTK(_f, _a...) \
+ pr_debug("(file=%s, line=%d) " _f, \
+- __FILE__ , __LINE__ , ## _a )
++ __FILE__ , __LINE__ , ## _a)
+ #define IPRINTK(fmt, args...) \
+ printk(KERN_INFO "xen_net: " fmt, ##args)
+ #define WPRINTK(fmt, args...) \
+@@ -132,66 +129,22 @@ enum {
+
+ extern int netbk_copy_skb_mode;
+
+-/* Function pointers into netback accelerator plugin modules */
+-struct netback_accel_hooks {
+- struct module *owner;
+- int (*probe)(struct xenbus_device *dev);
+- int (*remove)(struct xenbus_device *dev);
+-};
+-
+-/* Structure to track the state of a netback accelerator plugin */
+-struct netback_accelerator {
+- struct list_head link;
+- int id;
+- char *eth_name;
+- atomic_t use_count;
+- struct netback_accel_hooks *hooks;
+-};
+-
+ struct backend_info {
+ struct xenbus_device *dev;
+ struct xen_netif *netif;
+ enum xenbus_state frontend_state;
+ struct xenbus_watch hotplug_status_watch;
+ int have_hotplug_status_watch:1;
+-
+- /* State relating to the netback accelerator */
+- void *netback_accel_priv;
+- /* The accelerator that this backend is currently using */
+- struct netback_accelerator *accelerator;
+ };
+
+-#define NETBACK_ACCEL_VERSION 0x00010001
+-
+-/*
+- * Connect an accelerator plugin module to netback. Returns zero on
+- * success, < 0 on error, > 0 (with highest version number supported)
+- * if version mismatch.
+- */
+-extern int netback_connect_accelerator(unsigned version,
+- int id, const char *eth_name,
+- struct netback_accel_hooks *hooks);
+-/* Disconnect a previously connected accelerator plugin module */
+-extern void netback_disconnect_accelerator(int id, const char *eth_name);
+-
+-
+-extern
+-void netback_probe_accelerators(struct backend_info *be,
+- struct xenbus_device *dev);
+-extern
+-void netback_remove_accelerators(struct backend_info *be,
+- struct xenbus_device *dev);
+-extern
+-void netif_accel_init(void);
+-
+-
+ #define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+ #define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+
+ void netif_disconnect(struct xen_netif *netif);
+
+ void netif_set_features(struct xen_netif *netif);
+-struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle);
++struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
++ unsigned int handle);
+ int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn);
+
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index d3af68e..4622653 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -1,6 +1,4 @@
+-/******************************************************************************
+- * arch/xen/drivers/netif/backend/interface.c
+- *
++/*
+ * Network-device interface management.
+ *
+ * Copyright (c) 2004-2005, Keir Fraser
+@@ -232,8 +230,7 @@ static void netbk_get_strings(struct net_device *dev, u32 stringset,
u8 * data)
+ }
+ }
+
+-static struct ethtool_ops network_ethtool_ops =
+-{
++static struct ethtool_ops network_ethtool_ops = {
+ .get_drvinfo = netbk_get_drvinfo,
+
+ .get_tx_csum = ethtool_op_get_tx_csum,
+@@ -249,8 +246,7 @@ static struct ethtool_ops network_ethtool_ops =
+ .get_strings = netbk_get_strings,
+ };
+
+-static struct net_device_ops netback_ops =
+-{
++static struct net_device_ops netback_ops = {
+ .ndo_start_xmit = netif_be_start_xmit,
+ .ndo_get_stats = netif_be_get_stats,
+ .ndo_open = net_open,
+@@ -258,7 +254,8 @@ static struct net_device_ops netback_ops =
+ .ndo_change_mtu = netbk_change_mtu,
+ };
+
+-struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle)
++struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
++ unsigned int handle)
+ {
+ int err = 0;
+ struct net_device *dev;
+@@ -323,8 +320,9 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
+ return netif;
+ }
+
+-static int map_frontend_pages(
+- struct xen_netif *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
++static int map_frontend_pages(struct xen_netif *netif,
++ grant_ref_t tx_ring_ref,
++ grant_ref_t rx_ring_ref)
+ {
+ struct gnttab_map_grant_ref op;
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index cfe7931..d4aa8ac 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -1,11 +1,9 @@
+-/******************************************************************************
+- * drivers/xen/netback/netback.c
+- *
++/*
+ * Back-end of the driver for virtual network devices. This portion of the
+ * driver exports a 'unified' network-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A
+ * reference front-end implementation can be found in:
+- * drivers/xen/netfront/netfront.c
++ * drivers/net/xen-netfront.c
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ *
+@@ -82,8 +80,8 @@ static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
+ }
+
+ /* extra field used in struct page */
+-static inline void netif_set_page_ext(struct page *pg, unsigned int group,
+- unsigned int idx)
++static inline void netif_set_page_ext(struct page *pg,
++ unsigned int group, unsigned int idx)
+ {
+ union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
+
+@@ -91,7 +89,8 @@ static inline void netif_set_page_ext(struct page *pg, unsigned int
group,
+ pg->mapping = ext.mapping;
+ }
+
+-static inline int netif_get_page_ext(struct page *pg, unsigned int *_group, unsigned int
*_idx)
++static int netif_get_page_ext(struct page *pg,
++ unsigned int *_group, unsigned int *_idx)
+ {
+ union page_ext ext = { .mapping = pg->mapping };
+ struct xen_netbk *netbk;
+@@ -325,7 +324,7 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xen_netif *netif
+ unsigned int count = 1;
+ int i, copy_off = 0;
+
+- BUG_ON(offset_in_page(skb->data) + skb_headlen(skb) > MAX_BUFFER_OFFSET);
++ BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
+
+ copy_off = skb_headlen(skb);
+
+@@ -376,7 +375,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ */
+ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
+ struct sk_buff *nskb = netbk_copy_skb(skb);
+- if ( unlikely(nskb == NULL) )
++ if (unlikely(nskb == NULL))
+ goto drop;
+ /* Copy only the header fields we use in this driver. */
+ nskb->dev = skb->dev;
+@@ -385,8 +384,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ skb = nskb;
+ }
+
+- /* Reserve ring slots for the worst-case number of
+- * fragments. */
++ /* Reserve ring slots for the worst-case number of fragments. */
+ netif->rx_req_cons_peek += count_skb_slots(skb, netif);
+ netif_get(netif);
+
+@@ -437,9 +435,10 @@ static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif
*netif,
+ return meta;
+ }
+
+-/* Set up the grant operations for this fragment. If it's a flipping
+- interface, we also set up the unmap request from here. */
+-
++/*
++ * Set up the grant operations for this fragment. If it's a flipping
++ * interface, we also set up the unmap request from here.
+ */
-+int xen_network_done(void)
-+{
-+ return skb_queue_empty(&rx_queue);
-+}
-+#endif
-+
-+struct netrx_pending_operations {
-+ unsigned trans_prod, trans_cons;
-+ unsigned mmu_prod, mmu_mcl;
-+ unsigned mcl_prod, mcl_cons;
-+ unsigned copy_prod, copy_cons;
-+ unsigned meta_prod, meta_cons;
-+ mmu_update_t *mmu;
-+ gnttab_transfer_t *trans;
-+ gnttab_copy_t *copy;
-+ multicall_entry_t *mcl;
-+ struct netbk_rx_meta *meta;
-+};
-+
-+/* Set up the grant operations for this fragment. If it's a flipping
-+ interface, we also set up the unmap request from here. */
-+static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
-+ int i, struct netrx_pending_operations *npo,
-+ struct page *page, unsigned long size,
-+ unsigned long offset)
-+{
-+ mmu_update_t *mmu;
-+ gnttab_transfer_t *gop;
-+ gnttab_copy_t *copy_gop;
-+ multicall_entry_t *mcl;
-+ netif_rx_request_t *req;
-+ unsigned long old_mfn, new_mfn;
-+ int idx = netif_page_index(page);
-+
-+ old_mfn = virt_to_mfn(page_address(page));
-+
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
-+ if (netif->copying_receiver) {
-+ /* 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];
-+ copy_gop->source.domid = src_pend->netif->domid;
-+ copy_gop->source.u.ref = src_pend->req.gref;
-+ copy_gop->flags |= GNTCOPY_source_gref;
-+ } else {
-+ copy_gop->source.domid = DOMID_SELF;
-+ copy_gop->source.u.gmfn = old_mfn;
-+ }
-+ copy_gop->source.offset = offset;
-+ copy_gop->dest.domid = netif->domid;
-+ copy_gop->dest.offset = 0;
-+ copy_gop->dest.u.ref = req->gref;
-+ copy_gop->len = size;
-+ } else {
-+ meta->copy = 0;
-+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+ new_mfn = alloc_mfn();
-+
-+ /*
-+ * Set the new P2M table entry before
-+ * reassigning the old data page. Heed the
-+ * comment in pgtable-2level.h:pte_page(). :-)
-+ */
-+ set_phys_to_machine(page_to_pfn(page), new_mfn);
-+
-+ mcl = npo->mcl + npo->mcl_prod++;
-+ MULTI_update_va_mapping(mcl,
-+ (unsigned long)page_address(page),
-+ pfn_pte_ma(new_mfn, PAGE_KERNEL),
-+ 0);
-+
-+ mmu = npo->mmu + npo->mmu_prod++;
-+ mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
-+ MMU_MACHPHYS_UPDATE;
-+ mmu->val = page_to_pfn(page);
-+ }
-+
-+ gop = npo->trans + npo->trans_prod++;
-+ gop->mfn = old_mfn;
-+ gop->domid = netif->domid;
-+ gop->ref = req->gref;
-+ }
-+ return req->id;
-+}
-+
-+static void netbk_gop_skb(struct sk_buff *skb,
-+ struct netrx_pending_operations *npo)
-+{
-+ netif_t *netif = netdev_priv(skb->dev);
-+ int nr_frags = skb_shinfo(skb)->nr_frags;
-+ int i;
-+ int extra;
-+ struct netbk_rx_meta *head_meta, *meta;
-+
-+ head_meta = npo->meta + npo->meta_prod++;
-+ head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
-+ head_meta->frag.size = skb_shinfo(skb)->gso_size;
-+ extra = !!head_meta->frag.size + 1;
-+
-+ for (i = 0; i < nr_frags; i++) {
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->frag = skb_shinfo(skb)->frags[i];
-+ meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
-+ meta->frag.page,
-+ meta->frag.size,
-+ meta->frag.page_offset);
-+ }
-+
-+ /*
-+ * This must occur at the end to ensure that we don't trash skb_shinfo
-+ * until we're done. We know that the head doesn't cross a page
-+ * boundary because such packets get copied in netif_be_start_xmit.
+ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ struct netrx_pending_operations *npo,
+ struct page *page, unsigned long size,
+@@ -450,7 +449,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ /*
+ * These variables a used iff netif_get_page_ext returns true,
+ * in which case they are guaranteed to be initialized.
+- */
+ */
-+ head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
-+ virt_to_page(skb->data),
-+ skb_headlen(skb),
-+ offset_in_page(skb->data));
-+
-+ netif->rx.req_cons += nr_frags + extra;
-+}
-+
-+static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
-+{
-+ int i;
-+
-+ for (i = 0; i < nr_frags; i++)
-+ put_page(meta[i].frag.page);
-+}
-+
-+/* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
-+ used to set up the operations on the top of
-+ netrx_pending_operations, which have since been done. Check that
-+ they didn't give any errors and advance over them. */
-+static int netbk_check_gop(int nr_frags, domid_t domid,
-+ struct netrx_pending_operations *npo)
-+{
-+ multicall_entry_t *mcl;
-+ gnttab_transfer_t *gop;
-+ gnttab_copy_t *copy_op;
-+ int status = NETIF_RSP_OKAY;
-+ int i;
-+
-+ for (i = 0; i <= nr_frags; i++) {
-+ if (npo->meta[npo->meta_cons + i].copy) {
-+ copy_op = npo->copy + npo->copy_cons++;
-+ if (copy_op->status != GNTST_okay) {
-+ DPRINTK("Bad status %d from copy to DOM%d.\n",
-+ copy_op->status, domid);
-+ status = NETIF_RSP_ERROR;
-+ }
-+ } else {
-+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+ mcl = npo->mcl + npo->mcl_cons++;
-+ /* The update_va_mapping() must not fail. */
-+ BUG_ON(mcl->result != 0);
-+ }
-+
-+ gop = npo->trans + npo->trans_cons++;
-+ /* Check the reassignment error code. */
-+ if (gop->status != 0) {
-+ DPRINTK("Bad status %d from grant transfer to DOM%u\n",
-+ gop->status, domid);
-+ /*
-+ * Page no longer belongs to us unless
-+ * GNTST_bad_page, but that should be
-+ * a fatal error anyway.
-+ */
-+ BUG_ON(gop->status == GNTST_bad_page);
-+ status = NETIF_RSP_ERROR;
-+ }
-+ }
-+ }
-+
-+ return status;
-+}
-+
-+static void netbk_add_frag_responses(netif_t *netif, int status,
-+ struct netbk_rx_meta *meta, int nr_frags)
-+{
-+ int i;
-+ unsigned long offset;
-+
-+ for (i = 0; i < nr_frags; i++) {
-+ int id = meta[i].id;
-+ int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
-+
-+ if (meta[i].copy)
-+ offset = 0;
-+ else
-+ offset = meta[i].frag.page_offset;
-+ make_rx_response(netif, id, status, offset,
-+ meta[i].frag.size, flags);
-+ }
-+}
-+
-+static void net_rx_action(unsigned long unused)
-+{
-+ netif_t *netif = NULL;
-+ s8 status;
-+ u16 id, irq, flags;
-+ netif_rx_response_t *resp;
-+ multicall_entry_t *mcl;
-+ struct sk_buff_head rxq;
-+ struct sk_buff *skb;
-+ int notify_nr = 0;
-+ int ret;
-+ 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 unsigned char rx_notify[NR_IRQS];
-+ static u16 notify_list[NET_RX_RING_SIZE];
-+ static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
-+
-+ struct netrx_pending_operations npo = {
-+ mmu: rx_mmu,
-+ trans: grant_trans_op,
-+ copy: grant_copy_op,
-+ mcl: rx_mcl,
-+ meta: meta};
-+
-+ skb_queue_head_init(&rxq);
-+
-+ count = 0;
-+
-+ while ((skb = skb_dequeue(&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)) {
-+ /* 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);
-+ break;
-+ }
-+
-+ netbk_gop_skb(skb, &npo);
-+
-+ count += nr_frags + 1;
-+
-+ __skb_queue_tail(&rxq, skb);
-+
-+ /* Filled the batch queue? */
-+ if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
-+ break;
-+ }
-+
-+ BUG_ON(npo.meta_prod > ARRAY_SIZE(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));
-+ 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[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));
-+ 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[2] = npo.trans_prod;
-+ }
-+
-+ if (npo.copy_prod) {
-+ BUG_ON(npo.copy_prod > ARRAY_SIZE(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[2] = npo.copy_prod;
-+ }
-+
-+ /* Nothing to do? */
-+ if (!npo.mcl_prod)
-+ return;
-+
-+ BUG_ON(npo.mcl_prod > ARRAY_SIZE(rx_mcl));
-+
-+ ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
-+ BUG_ON(ret != 0);
-+ /* The mmu_machphys_update() must not fail. */
-+ BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
-+
-+ while ((skb = __skb_dequeue(&rxq)) != NULL) {
-+ nr_frags = *(int *)skb->cb;
-+
-+ netif = netdev_priv(skb->dev);
-+ /* We can't rely on skb_release_data to release the
-+ pages used by fragments for us, since it tries to
-+ touch the pages in the fraglist. If we're in
-+ flipping mode, that doesn't work. In copying mode,
-+ we still have access to all of the pages, and so
-+ it's safe to let release_data deal with it. */
-+ /* (Freeing the fragments is safe since we copy
-+ non-linear skbs destined for flipping interfaces) */
-+ if (!netif->copying_receiver) {
-+ 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);
-+ }
-+
-+ netif->stats.tx_bytes += skb->len;
-+ netif->stats.tx_packets++;
-+
-+ status = netbk_check_gop(nr_frags, netif->domid, &npo);
-+
-+ id = meta[npo.meta_cons].id;
-+ flags = nr_frags ? NETRXF_more_data : 0;
-+
-+ if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
-+ flags |= NETRXF_csum_blank | NETRXF_data_validated;
-+ else if (skb->proto_data_valid) /* remote but checksummed? */
-+ flags |= NETRXF_data_validated;
-+
-+ if (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) {
-+ struct netif_extra_info *gso =
-+ (struct netif_extra_info *)
-+ RING_GET_RESPONSE(&netif->rx,
-+ netif->rx.rsp_prod_pvt++);
-+
-+ resp->flags |= NETRXF_extra_info;
-+
-+ gso->u.gso.size = 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;
-+
-+ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
-+ gso->flags = 0;
-+ }
-+
-+ netbk_add_frag_responses(netif, status,
-+ meta + npo.meta_cons + 1,
-+ nr_frags);
-+
-+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
-+ irq = netif->irq;
-+ if (ret && !rx_notify[irq]) {
-+ rx_notify[irq] = 1;
-+ notify_list[notify_nr++] = irq;
-+ }
-+
-+ if (netif_queue_stopped(netif->dev) &&
-+ netif_schedulable(netif) &&
-+ !netbk_queue_full(netif))
-+ netif_wake_queue(netif->dev);
-+
-+ netif_put(netif);
-+ dev_kfree_skb(skb);
-+ npo.meta_cons += nr_frags + 1;
-+ }
-+
-+ while (notify_nr != 0) {
-+ irq = notify_list[--notify_nr];
-+ rx_notify[irq] = 0;
-+ notify_remote_via_irq(irq);
-+ }
-+
-+ /* More work to do? */
-+ if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
-+ tasklet_schedule(&net_rx_tasklet);
-+#if 0
-+ else
-+ xen_network_done_notify();
-+#endif
-+}
-+
-+static void net_alarm(unsigned long unused)
-+{
-+ tasklet_schedule(&net_rx_tasklet);
-+}
-+
-+static void netbk_tx_pending_timeout(unsigned long unused)
-+{
-+ tasklet_schedule(&net_tx_tasklet);
-+}
-+
-+struct net_device_stats *netif_be_get_stats(struct net_device *dev)
-+{
-+ netif_t *netif = netdev_priv(dev);
-+ return &netif->stats;
-+}
-+
-+static int __on_net_schedule_list(netif_t *netif)
-+{
-+ return netif->list.next != NULL;
-+}
-+
-+static void remove_from_net_schedule_list(netif_t *netif)
-+{
-+ spin_lock_irq(&net_schedule_list_lock);
-+ if (likely(__on_net_schedule_list(netif))) {
-+ list_del(&netif->list);
-+ netif->list.next = NULL;
-+ netif_put(netif);
-+ }
-+ spin_unlock_irq(&net_schedule_list_lock);
-+}
-+
-+static void add_to_net_schedule_list_tail(netif_t *netif)
-+{
-+ if (__on_net_schedule_list(netif))
-+ return;
-+
-+ spin_lock_irq(&net_schedule_list_lock);
-+ if (!__on_net_schedule_list(netif) &&
-+ likely(netif_schedulable(netif))) {
-+ list_add_tail(&netif->list, &net_schedule_list);
-+ netif_get(netif);
-+ }
-+ spin_unlock_irq(&net_schedule_list_lock);
-+}
-+
+ unsigned int uninitialized_var(group), uninitialized_var(idx);
+ int foreign = netif_get_page_ext(page, &group, &idx);
+ unsigned long bytes;
+@@ -489,8 +488,9 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ copy_gop->source.u.ref = src_pend->req.gref;
+ copy_gop->flags |= GNTCOPY_source_gref;
+ } else {
++ void *vaddr = page_address(page);
+ copy_gop->source.domid = DOMID_SELF;
+- copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
++ copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
+ }
+ copy_gop->source.offset = offset;
+ copy_gop->dest.domid = netif->domid;
+@@ -504,17 +504,22 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+
+ offset += bytes;
+ size -= bytes;
+- head = 0; /* Must be something in this buffer now */
++ head = 0; /* There must be something in this buffer now. */
+ }
+ }
+
+-/* Prepare an SKB to be transmitted to the frontend. This is
+- responsible for allocating grant operations, meta structures, etc.
+- It returns the number of meta structures consumed. The number of
+- ring slots used is always equal to the number of meta slots used
+- plus the number of GSO descriptors used. Currently, we use either
+- zero GSO descriptors (for non-GSO packets) or one descriptor (for
+- frontend-side LRO). */
+/*
-+ * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
-+ * If this driver is pipelining transmit requests then we can be very
-+ * aggressive in avoiding new-packet notifications -- frontend only needs to
-+ * send a notification if there are no outstanding unreceived responses.
-+ * If we may be buffer transmit buffers for any reason then we must be rather
-+ * more conservative and treat this as the final check for pending work.
++ * Prepare an SKB to be transmitted to the frontend.
++ *
++ * This function is responsible for allocating grant operations, meta
++ * structures, etc.
++ *
++ * It returns the number of meta structures consumed. The number of
++ * ring slots used is always equal to the number of meta slots used
++ * plus the number of GSO descriptors used. Currently, we use either
++ * zero GSO descriptors (for non-GSO packets) or one descriptor (for
++ * frontend-side LRO).
+ */
-+void netif_schedule_work(netif_t *netif)
-+{
-+ int more_to_do;
-+
-+#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-+ more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
-+#else
-+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-+#endif
-+
-+ if (more_to_do) {
-+ add_to_net_schedule_list_tail(netif);
-+ maybe_schedule_tx_action();
-+ }
-+}
-+
-+void netif_deschedule_work(netif_t *netif)
-+{
-+ remove_from_net_schedule_list(netif);
-+}
-+
-+
-+static void tx_add_credit(netif_t *netif)
-+{
-+ unsigned long max_burst, max_credit;
-+
-+ /*
-+ * 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(&netif->tx, netif->tx.req_cons)->size;
-+ max_burst = min(max_burst, 131072UL);
-+ max_burst = max(max_burst, netif->credit_bytes);
-+
-+ /* Take care that adding a new chunk of credit doesn't wrap to zero. */
-+ max_credit = netif->remaining_credit + netif->credit_bytes;
-+ if (max_credit < netif->remaining_credit)
-+ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
-+
-+ netif->remaining_credit = min(max_credit, max_burst);
-+}
-+
-+static void tx_credit_callback(unsigned long data)
-+{
-+ netif_t *netif = (netif_t *)data;
-+ tx_add_credit(netif);
-+ netif_schedule_work(netif);
-+}
-+
-+static inline int copy_pending_req(PEND_RING_IDX pending_idx)
-+{
-+ return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
-+ &mmap_pages[pending_idx]);
-+}
-+
-+inline static void net_tx_action_dealloc(void)
-+{
-+ struct netbk_tx_pending_inuse *inuse, *n;
-+ gnttab_unmap_grant_ref_t *gop;
-+ u16 pending_idx;
-+ PEND_RING_IDX dc, dp;
-+ netif_t *netif;
-+ int ret;
-+ LIST_HEAD(list);
-+
-+ dc = dealloc_cons;
-+ gop = tx_unmap_ops;
-+
-+ /*
-+ * Free up any grants we have finished using
-+ */
-+ do {
-+ dp = dealloc_prod;
-+
-+ /* Ensure we see all indices enqueued by netif_idx_release(). */
-+ smp_rmb();
-+
-+ while (dc != dp) {
-+ unsigned long pfn;
-+
-+ pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
-+ list_move_tail(&pending_inuse[pending_idx].list, &list);
-+
-+ pfn = idx_to_pfn(pending_idx);
-+ /* Already unmapped? */
-+ if (!phys_to_machine_mapping_valid(pfn))
-+ continue;
-+
-+ gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
-+ GNTMAP_host_map,
-+ grant_tx_handle[pending_idx]);
-+ gop++;
-+ }
-+
-+ if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
-+ list_empty(&pending_inuse_head))
-+ break;
-+
-+ /* Copy any entries that have been pending for too long. */
-+ list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
-+ if (time_after(inuse->alloc_time + HZ / 2, jiffies))
-+ break;
-+
-+ switch (copy_pending_req(inuse - pending_inuse)) {
-+ case 0:
-+ list_move_tail(&inuse->list, &list);
-+ continue;
-+ case -EBUSY:
-+ list_del_init(&inuse->list);
-+ continue;
-+ case -ENOENT:
-+ continue;
-+ }
-+
-+ break;
-+ }
-+ } while (dp != dealloc_prod);
-+
-+ dealloc_cons = dc;
-+
-+ ret = HYPERVISOR_grant_table_op(
-+ GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
-+ BUG_ON(ret);
-+
-+ list_for_each_entry_safe(inuse, n, &list, list) {
-+ pending_idx = inuse - 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]);
-+
-+ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-+
-+ netif_put(netif);
-+
-+ list_del_init(&inuse->list);
-+ }
-+}
-+
-+static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
-+{
-+ RING_IDX cons = netif->tx.req_cons;
-+
-+ do {
-+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ if (cons >= end)
-+ break;
-+ txp = RING_GET_REQUEST(&netif->tx, cons++);
-+ } while (1);
-+ netif->tx.req_cons = cons;
-+ netif_schedule_work(netif);
-+ netif_put(netif);
-+}
-+
-+static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
-+ netif_tx_request_t *txp, int work_to_do)
-+{
-+ RING_IDX cons = netif->tx.req_cons;
-+ int frags = 0;
-+
-+ if (!(first->flags & NETTXF_more_data))
-+ return 0;
-+
-+ do {
-+ if (frags >= work_to_do) {
-+ DPRINTK("Need more frags\n");
-+ return -frags;
-+ }
-+
-+ if (unlikely(frags >= MAX_SKB_FRAGS)) {
-+ DPRINTK("Too many frags\n");
-+ return -frags;
-+ }
-+
-+ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
-+ sizeof(*txp));
-+ if (txp->size > first->size) {
-+ DPRINTK("Frags galore\n");
-+ return -frags;
-+ }
-+
-+ first->size -= txp->size;
-+ frags++;
-+
-+ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-+ DPRINTK("txp->offset: %x, size: %u\n",
-+ txp->offset, txp->size);
-+ return -frags;
-+ }
-+ } while ((txp++)->flags & NETTXF_more_data);
-+
-+ return frags;
-+}
-+
-+static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
-+ struct sk_buff *skb,
-+ netif_tx_request_t *txp,
-+ gnttab_map_grant_ref_t *mop)
-+{
-+ struct skb_shared_info *shinfo = skb_shinfo(skb);
-+ skb_frag_t *frags = shinfo->frags;
-+ unsigned long pending_idx = *((u16 *)skb->data);
-+ int i, start;
-+
-+ /* Skip first skb fragment if it is on same page as header fragment. */
-+ 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++)];
-+
-+ gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
-+ GNTMAP_host_map | GNTMAP_readonly,
-+ txp->gref, netif->domid);
-+
-+ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
-+ netif_get(netif);
-+ pending_tx_info[pending_idx].netif = netif;
-+ frags[i].page = (void *)pending_idx;
-+ }
-+
-+ return mop;
-+}
-+
-+static int netbk_tx_check_mop(struct sk_buff *skb,
-+ gnttab_map_grant_ref_t **mopp)
-+{
-+ gnttab_map_grant_ref_t *mop = *mopp;
-+ int pending_idx = *((u16 *)skb->data);
-+ netif_t *netif = pending_tx_info[pending_idx].netif;
-+ netif_tx_request_t *txp;
-+ struct skb_shared_info *shinfo = skb_shinfo(skb);
-+ int nr_frags = shinfo->nr_frags;
-+ int i, err, start;
-+
-+ /* Check status of header. */
-+ err = mop->status;
-+ if (unlikely(err)) {
-+ txp = &pending_tx_info[pending_idx].req;
-+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-+ netif_put(netif);
+ static int netbk_gop_skb(struct sk_buff *skb,
+ struct netrx_pending_operations *npo)
+ {
+@@ -569,10 +574,12 @@ static int netbk_gop_skb(struct sk_buff *skb,
+ return npo->meta_prod - old_meta_prod;
+ }
+
+-/* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
+- used to set up the operations on the top of
+- netrx_pending_operations, which have since been done. Check that
+- they didn't give any errors and advance over them. */
++/*
++ * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
++ * used to set up the operations on the top of
++ * netrx_pending_operations, which have since been done. Check that
++ * they didn't give any errors and advance over them.
++ */
+ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+ struct netrx_pending_operations *npo)
+ {
+@@ -906,9 +913,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
+ dc = netbk->dealloc_cons;
+ gop = netbk->tx_unmap_ops;
+
+- /*
+- * Free up any grants we have finished using
+- */
++ /* Free up any grants we have finished using. */
+ do {
+ dp = netbk->dealloc_prod;
+
+@@ -1018,7 +1023,8 @@ static void netbk_tx_err(struct xen_netif *netif,
+
+ static int netbk_count_requests(struct xen_netif *netif,
+ struct xen_netif_tx_request *first,
+- struct xen_netif_tx_request *txp, int work_to_do)
++ struct xen_netif_tx_request *txp,
++ int work_to_do)
+ {
+ RING_IDX cons = netif->tx.req_cons;
+ int frags = 0;
+@@ -1058,10 +1064,10 @@ static int netbk_count_requests(struct xen_netif *netif,
+ }
+
+ static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
+- struct xen_netif *netif,
+- struct sk_buff *skb,
+- struct xen_netif_tx_request *txp,
+- struct gnttab_map_grant_ref *mop)
++ struct xen_netif *netif,
++ struct sk_buff *skb,
++ struct xen_netif_tx_request *txp,
++ struct gnttab_map_grant_ref *mop)
+ {
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ skb_frag_t *frags = shinfo->frags;
+@@ -1200,7 +1206,8 @@ static void netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
+ }
+ }
+
+-int netbk_get_extras(struct xen_netif *netif, struct xen_netif_extra_info *extras,
++int netbk_get_extras(struct xen_netif *netif,
++ struct xen_netif_extra_info *extras,
+ int work_to_do)
+ {
+ struct xen_netif_extra_info extra;
+@@ -1228,7 +1235,8 @@ int netbk_get_extras(struct xen_netif *netif, struct
xen_netif_extra_info *extra
+ return work_to_do;
+ }
+
+-static int netbk_set_skb_gso(struct sk_buff *skb, struct xen_netif_extra_info *gso)
++static int netbk_set_skb_gso(struct sk_buff *skb,
++ struct xen_netif_extra_info *gso)
+ {
+ if (!gso->u.gso.size) {
+ DPRINTK("GSO size must not be zero.\n");
+@@ -1365,7 +1373,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ struct xen_netif *netif;
+ struct xen_netif_tx_request txreq;
+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+ u16 pending_idx;
+ RING_IDX idx;
+ int work_to_do;
+@@ -1427,7 +1435,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
+ DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
+ txreq.offset, txreq.size,
+- (txreq.offset &~PAGE_MASK) + txreq.size);
++ (txreq.offset&~PAGE_MASK) + txreq.size);
+ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+@@ -1807,9 +1815,6 @@ static int __init netback_init(void)
+ }
+ memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
+
+- /* We can increase reservation by this much in net_rx_action(). */
+-// balloon_update_driver_allowance(NET_RX_RING_SIZE);
+-
+ for (group = 0; group < xen_netbk_group_nr; group++) {
+ struct xen_netbk *netbk = &xen_netbk[group];
+ skb_queue_head_init(&netbk->rx_queue);
+@@ -1894,8 +1899,6 @@ static int __init netback_init(void)
+ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ }
+
+- //netif_accel_init();
+-
+ rc = netif_xenbus_init();
+ if (rc)
+ goto failed_init;
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index 1fec65a..dd44341 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -1,20 +1,22 @@
+-/* Xenbus code for netif backend
+- Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
+- Copyright (C) 2005 XenSource Ltd
+-
+- This program is free software; you can redistribute it and/or modify
+- it under the terms of the GNU General Public License as published by
+- the Free Software Foundation; either version 2 of the License, or
+- (at your option) any later version.
+-
+- This program is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- GNU General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software
+- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++/*
++ * Xenbus code for netif backend
++ *
++ * Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
++ * Copyright (C) 2005 XenSource Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ #include <stdarg.h>
+@@ -22,13 +24,6 @@
+ #include <xen/xenbus.h>
+ #include "common.h"
+
+-#if 0
+-#undef DPRINTK
+-#define DPRINTK(fmt, args...) \
+- printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__,
__LINE__, ##args)
+-#endif
+-
+-
+ static int connect_rings(struct backend_info *);
+ static void connect(struct backend_info *);
+ static void backend_create_netif(struct backend_info *be);
+@@ -36,9 +31,7 @@ static void unregister_hotplug_status_watch(struct backend_info *be);
+
+ static int netback_remove(struct xenbus_device *dev)
+ {
+- struct backend_info *be = dev_get_drvdata(&dev->dev);
+-
+- //netback_remove_accelerators(be, dev);
++ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ unregister_hotplug_status_watch(be);
+ if (be->netif) {
+@@ -126,8 +119,6 @@ static int netback_probe(struct xenbus_device *dev,
+ goto fail;
+ }
+
+- //netback_probe_accelerators(be, dev);
+-
+ err = xenbus_switch_state(dev, XenbusStateInitWait);
+ if (err)
+ goto fail;
+@@ -147,12 +138,13 @@ fail:
+ }
+
+
+-/**
++/*
+ * Handle the creation of the hotplug script environment. We add the script
+ * and vif variables to the environment, for the benefit of the vif-* hotplug
+ * scripts.
+ */
+-static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
++static int netback_uevent(struct xenbus_device *xdev,
++ struct kobj_uevent_env *env)
+ {
+ struct backend_info *be = dev_get_drvdata(&xdev->dev);
+ char *val;
+@@ -164,8 +156,7 @@ static int netback_uevent(struct xenbus_device *xdev, struct
kobj_uevent_env *en
+ int err = PTR_ERR(val);
+ xenbus_dev_fatal(xdev, err, "reading script");
+ return err;
+- }
+- else {
+ } else {
-+ set_phys_to_machine(
-+ __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
-+ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
-+ grant_tx_handle[pending_idx] = mop->handle;
-+ }
-+
-+ /* Skip first skb fragment if it is on same page as header fragment. */
-+ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
-+
-+ for (i = start; i < nr_frags; i++) {
-+ int j, newerr;
-+
-+ pending_idx = (unsigned long)shinfo->frags[i].page;
-+
-+ /* Check error status: if okay then remember grant handle. */
-+ newerr = (++mop)->status;
-+ if (likely(!newerr)) {
-+ set_phys_to_machine(
-+ __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
-+ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
-+ grant_tx_handle[pending_idx] = mop->handle;
-+ /* Had a previous error? Invalidate this fragment. */
-+ if (unlikely(err))
-+ netif_idx_release(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;
-+ netif_put(netif);
-+
-+ /* Not the first error? Preceding frags already invalidated. */
-+ if (err)
-+ continue;
-+
-+ /* First error: invalidate header and preceding fragments. */
-+ pending_idx = *((u16 *)skb->data);
-+ netif_idx_release(pending_idx);
-+ for (j = start; j < i; j++) {
-+ pending_idx = (unsigned long)shinfo->frags[i].page;
-+ netif_idx_release(pending_idx);
-+ }
-+
-+ /* Remember the error: invalidate all subsequent fragments. */
-+ err = newerr;
-+ }
-+
-+ *mopp = mop + 1;
-+ return err;
-+}
-+
-+static void netbk_fill_frags(struct sk_buff *skb)
-+{
-+ struct skb_shared_info *shinfo = skb_shinfo(skb);
-+ int nr_frags = shinfo->nr_frags;
-+ int i;
-+
-+ for (i = 0; i < nr_frags; i++) {
-+ skb_frag_t *frag = shinfo->frags + i;
-+ netif_tx_request_t *txp;
-+ unsigned long pending_idx;
-+
-+ pending_idx = (unsigned long)frag->page;
-+
-+ pending_inuse[pending_idx].alloc_time = jiffies;
-+ list_add_tail(&pending_inuse[pending_idx].list,
-+ &pending_inuse_head);
-+
-+ txp = &pending_tx_info[pending_idx].req;
-+ frag->page = virt_to_page(idx_to_kaddr(pending_idx));
-+ frag->size = txp->size;
-+ frag->page_offset = txp->offset;
-+
-+ skb->len += txp->size;
-+ skb->data_len += txp->size;
-+ skb->truesize += txp->size;
-+ }
-+}
-+
-+int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
-+ int work_to_do)
-+{
-+ struct netif_extra_info extra;
-+ RING_IDX cons = netif->tx.req_cons;
-+
-+ do {
-+ if (unlikely(work_to_do-- <= 0)) {
-+ DPRINTK("Missing extra info\n");
-+ return -EBADR;
-+ }
-+
-+ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
-+ sizeof(extra));
-+ if (unlikely(!extra.type ||
-+ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-+ netif->tx.req_cons = ++cons;
-+ DPRINTK("Invalid extra type: %d\n", extra.type);
-+ return -EINVAL;
-+ }
-+
-+ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-+ netif->tx.req_cons = ++cons;
-+ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
-+
-+ return work_to_do;
-+}
-+
-+static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
-+{
-+ if (!gso->u.gso.size) {
-+ DPRINTK("GSO size must not be zero.\n");
-+ return -EINVAL;
-+ }
+ if (add_uevent_var(env, "script=%s", val)) {
+ kfree(val);
+ return -ENOMEM;
+@@ -173,10 +164,10 @@ static int netback_uevent(struct xenbus_device *xdev, struct
kobj_uevent_env *en
+ kfree(val);
+ }
+
+- if (be && be->netif && add_uevent_var(env, "vif=%s",
be->netif->dev->name))
+- return -ENOMEM;
++ if (!be || !be->netif)
++ return 0;
+
+- return 0;
++ return add_uevent_var(env, "vif=%s", be->netif->dev->name);
+ }
+
+
+@@ -234,7 +225,7 @@ static void frontend_changed(struct xenbus_device *dev,
+ case XenbusStateInitialising:
+ if (dev->state == XenbusStateClosed) {
+ printk(KERN_INFO "%s: %s: prepare for reconnect\n",
+- __FUNCTION__, dev->nodename);
++ __func__, dev->nodename);
+ xenbus_switch_state(dev, XenbusStateInitWait);
+ }
+ break;
+--
+1.7.4
+
+
+From 7ab35b88fd3b452d8b9aec972ab7d3e9de710894 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 19 Jan 2011 10:51:45 +0000
+Subject: [PATCH 083/203] xen: netback: drop private ?PRINTK macros in favour of pr_*
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/xen/netback/common.h | 10 ++--------
+ drivers/xen/netback/interface.c | 13 +++++++------
+ drivers/xen/netback/netback.c | 38 +++++++++++++++++++-------------------
+ drivers/xen/netback/xenbus.c | 13 +++----------
+ 4 files changed, 31 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+index a2455a0..49dc4cf 100644
+--- a/drivers/xen/netback/common.h
++++ b/drivers/xen/netback/common.h
+@@ -27,6 +27,8 @@
+ #ifndef __NETIF__BACKEND__COMMON_H__
+ #define __NETIF__BACKEND__COMMON_H__
+
++#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
-+ /* Currently only TCPv4 S.O. is supported. */
-+ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-+ DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
-+ return -EINVAL;
-+ }
+ #include <linux/module.h>
+ #include <linux/interrupt.h>
+ #include <linux/slab.h>
+@@ -44,14 +46,6 @@
+ #include <xen/grant_table.h>
+ #include <xen/xenbus.h>
+
+-#define DPRINTK(_f, _a...) \
+- pr_debug("(file=%s, line=%d) " _f, \
+- __FILE__ , __LINE__ , ## _a)
+-#define IPRINTK(fmt, args...) \
+- printk(KERN_INFO "xen_net: " fmt, ##args)
+-#define WPRINTK(fmt, args...) \
+- printk(KERN_WARNING "xen_net: " fmt, ##args)
+-
+ struct xen_netif {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+index 4622653..b429f8c 100644
+--- a/drivers/xen/netback/interface.c
++++ b/drivers/xen/netback/interface.c
+@@ -29,6 +29,7 @@
+ */
+
+ #include "common.h"
+
-+ skb_shinfo(skb)->gso_size = gso->u.gso.size;
-+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+ #include <linux/ethtool.h>
+ #include <linux/rtnetlink.h>
+
+@@ -265,7 +266,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
+ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
+ dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
+ if (dev == NULL) {
+- DPRINTK("Could not create netif: out of memory\n");
++ pr_debug("Could not allocate netdev\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+@@ -310,13 +311,13 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t
domid,
+ err = register_netdevice(dev);
+ rtnl_unlock();
+ if (err) {
+- DPRINTK("Could not register new net device %s: err=%d\n",
+- dev->name, err);
++ pr_debug("Could not register new net device %s: err=%d\n",
++ dev->name, err);
+ free_netdev(dev);
+ return ERR_PTR(err);
+ }
+
+- DPRINTK("Successfully created netif\n");
++ pr_debug("Successfully created netif\n");
+ return netif;
+ }
+
+@@ -333,7 +334,7 @@ static int map_frontend_pages(struct xen_netif *netif,
+ BUG();
+
+ if (op.status) {
+- DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
++ pr_debug("Gnttab failure mapping tx_ring_ref!\n");
+ return op.status;
+ }
+
+@@ -353,7 +354,7 @@ static int map_frontend_pages(struct xen_netif *netif,
+ (unsigned long)netif->tx_comms_area->addr,
+ GNTMAP_host_map, netif->tx_shmem_handle);
+ HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
+- DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
++ pr_debug("Gnttab failure mapping rx_ring_ref!\n");
+ return op.status;
+ }
+
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+index d4aa8ac..b290525 100644
+--- a/drivers/xen/netback/netback.c
++++ b/drivers/xen/netback/netback.c
+@@ -590,8 +590,8 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+ for (i = 0; i < nr_meta_slots; i++) {
+ copy_op = npo->copy + npo->copy_cons++;
+ if (copy_op->status != GNTST_okay) {
+- DPRINTK("Bad status %d from copy to DOM%d.\n",
+- copy_op->status, domid);
++ pr_debug("Bad status %d from copy to DOM%d.\n",
++ copy_op->status, domid);
+ status = NETIF_RSP_ERROR;
+ }
+ }
+@@ -1034,19 +1034,19 @@ static int netbk_count_requests(struct xen_netif *netif,
+
+ do {
+ if (frags >= work_to_do) {
+- DPRINTK("Need more frags\n");
++ pr_debug("Need more frags\n");
+ return -frags;
+ }
+
+ if (unlikely(frags >= MAX_SKB_FRAGS)) {
+- DPRINTK("Too many frags\n");
++ pr_debug("Too many frags\n");
+ return -frags;
+ }
+
+ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
+ sizeof(*txp));
+ if (txp->size > first->size) {
+- DPRINTK("Frags galore\n");
++ pr_debug("Frags galore\n");
+ return -frags;
+ }
+
+@@ -1054,8 +1054,8 @@ static int netbk_count_requests(struct xen_netif *netif,
+ frags++;
+
+ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
+- DPRINTK("txp->offset: %x, size: %u\n",
+- txp->offset, txp->size);
++ pr_debug("txp->offset: %x, size: %u\n",
++ txp->offset, txp->size);
+ return -frags;
+ }
+ } while ((txp++)->flags & NETTXF_more_data);
+@@ -1215,7 +1215,7 @@ int netbk_get_extras(struct xen_netif *netif,
+
+ do {
+ if (unlikely(work_to_do-- <= 0)) {
+- DPRINTK("Missing extra info\n");
++ pr_debug("Missing extra info\n");
+ return -EBADR;
+ }
+
+@@ -1224,7 +1224,7 @@ int netbk_get_extras(struct xen_netif *netif,
+ if (unlikely(!extra.type ||
+ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+ netif->tx.req_cons = ++cons;
+- DPRINTK("Invalid extra type: %d\n", extra.type);
++ pr_debug("Invalid extra type: %d\n", extra.type);
+ return -EINVAL;
+ }
+
+@@ -1239,13 +1239,13 @@ static int netbk_set_skb_gso(struct sk_buff *skb,
+ struct xen_netif_extra_info *gso)
+ {
+ if (!gso->u.gso.size) {
+- DPRINTK("GSO size must not be zero.\n");
++ pr_debug("GSO size must not be zero.\n");
+ return -EINVAL;
+ }
+
+ /* Currently only TCPv4 S.O. is supported. */
+ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+- DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
++ pr_debug("Bad GSO type %d.\n", gso->u.gso.type);
+ return -EINVAL;
+ }
+
+@@ -1426,16 +1426,16 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ idx += ret;
+
+ if (unlikely(txreq.size < ETH_HLEN)) {
+- DPRINTK("Bad packet size: %d\n", txreq.size);
++ pr_debug("Bad packet size: %d\n", txreq.size);
+ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+
+ /* No crossing a page as the payload mustn't fragment. */
+ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
+- DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
+- txreq.offset, txreq.size,
+- (txreq.offset&~PAGE_MASK) + txreq.size);
++ pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
++ txreq.offset, txreq.size,
++ (txreq.offset&~PAGE_MASK) + txreq.size);
+ netbk_tx_err(netif, &txreq, idx);
+ continue;
+ }
+@@ -1450,7 +1450,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(skb == NULL)) {
+- DPRINTK("Can't allocate a skb in start_xmit.\n");
++ pr_debug("Can't allocate a skb in start_xmit.\n");
+ netbk_tx_err(netif, &txreq, idx);
+ break;
+ }
+@@ -1525,7 +1525,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+
+ /* Check the remap error code. */
+ if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
+- DPRINTK("netback grant failed.\n");
++ pr_debug("netback grant failed.\n");
+ skb_shinfo(skb)->nr_frags = 0;
+ kfree_skb(skb);
+ continue;
+@@ -1565,14 +1565,14 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ if (checksum_setup(netif, skb)) {
+- DPRINTK("Can't setup checksum in net_tx_action\n");
++ pr_debug("Can't setup checksum in net_tx_action\n");
+ kfree_skb(skb);
+ continue;
+ }
+
+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
+ unlikely(skb_linearize(skb))) {
+- DPRINTK("Can't linearize skb in net_tx_action.\n");
++ pr_debug("Can't linearize skb in net_tx_action.\n");
+ kfree_skb(skb);
+ continue;
+ }
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
+index dd44341..867dc25 100644
+--- a/drivers/xen/netback/xenbus.c
++++ b/drivers/xen/netback/xenbus.c
+@@ -19,9 +19,6 @@
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+-#include <stdarg.h>
+-#include <linux/module.h>
+-#include <xen/xenbus.h>
+ #include "common.h"
+
+ static int connect_rings(struct backend_info *);
+@@ -132,7 +129,7 @@ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(dev, err, "%s", message);
+ fail:
+- DPRINTK("failed");
++ pr_debug("failed");
+ netback_remove(dev);
+ return err;
+ }
+@@ -149,8 +146,6 @@ static int netback_uevent(struct xenbus_device *xdev,
+ struct backend_info *be = dev_get_drvdata(&xdev->dev);
+ char *val;
+
+- DPRINTK("netback_uevent");
+-
+ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
+ if (IS_ERR(val)) {
+ int err = PTR_ERR(val);
+@@ -217,7 +212,7 @@ static void frontend_changed(struct xenbus_device *dev,
+ {
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+- DPRINTK("%s", xenbus_strstate(frontend_state));
++ pr_debug("frontend state %s", xenbus_strstate(frontend_state));
+
+ be->frontend_state = frontend_state;
+
+@@ -297,7 +292,7 @@ static void xen_net_read_rate(struct xenbus_device *dev,
+ return;
+
+ fail:
+- WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
++ pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
+ kfree(ratestr);
+ }
+
+@@ -396,8 +391,6 @@ static int connect_rings(struct backend_info *be)
+ int err;
+ int val;
+
+- DPRINTK("");
+-
+ err = xenbus_gather(XBT_NIL, dev->otherend,
+ "tx-ring-ref", "%lu", &tx_ring_ref,
+ "rx-ring-ref", "%lu", &rx_ring_ref,
+--
+1.7.4
+
+
+From 34db20ebe74e4ffacda2d42eb9cd92ae9b770970 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 18 Jan 2011 12:54:12 +0000
+Subject: [PATCH 084/203] xen: netback: move under drivers/net/xen-netback/
+
+From the kernel's PoV netback is just another network device driver.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/Kconfig | 7 +
+ drivers/net/Makefile | 1 +
+ drivers/net/xen-netback/Makefile | 3 +
+ drivers/net/xen-netback/common.h | 273 +++++
+ drivers/net/xen-netback/interface.c | 470 +++++++++
+ drivers/net/xen-netback/netback.c | 1934 +++++++++++++++++++++++++++++++++++
+ drivers/net/xen-netback/xenbus.c | 489 +++++++++
+ drivers/xen/Kconfig | 7 -
+ drivers/xen/Makefile | 1 -
+ drivers/xen/netback/Makefile | 3 -
+ drivers/xen/netback/common.h | 273 -----
+ drivers/xen/netback/interface.c | 470 ---------
+ drivers/xen/netback/netback.c | 1934 -----------------------------------
+ drivers/xen/netback/xenbus.c | 489 ---------
+ 14 files changed, 3177 insertions(+), 3177 deletions(-)
+ create mode 100644 drivers/net/xen-netback/Makefile
+ create mode 100644 drivers/net/xen-netback/common.h
+ create mode 100644 drivers/net/xen-netback/interface.c
+ create mode 100644 drivers/net/xen-netback/netback.c
+ create mode 100644 drivers/net/xen-netback/xenbus.c
+ delete mode 100644 drivers/xen/netback/Makefile
+ delete mode 100644 drivers/xen/netback/common.h
+ delete mode 100644 drivers/xen/netback/interface.c
+ delete mode 100644 drivers/xen/netback/netback.c
+ delete mode 100644 drivers/xen/netback/xenbus.c
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index cbf0635..5b088f5 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -2970,6 +2970,13 @@ config XEN_NETDEV_FRONTEND
+ if you are compiling a kernel for a Xen guest, you almost
+ certainly want to enable this.
+
++config XEN_NETDEV_BACKEND
++ tristate "Xen backend network device"
++ depends on XEN_BACKEND
++ help
++ Implement the network backend driver, which passes packets
++ from the guest domain's frontend drivers to the network.
+
-+ /* Header must be checked, and gso_segs computed. */
-+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-+ skb_shinfo(skb)->gso_segs = 0;
+ config ISERIES_VETH
+ tristate "iSeries Virtual Ethernet driver support"
+ depends on PPC_ISERIES
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index b90738d..145dfd7 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -171,6 +171,7 @@ obj-$(CONFIG_SLIP) += slip.o
+ obj-$(CONFIG_SLHC) += slhc.o
+
+ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
++obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
+
+ obj-$(CONFIG_DUMMY) += dummy.o
+ obj-$(CONFIG_IFB) += ifb.o
+diff --git a/drivers/net/xen-netback/Makefile b/drivers/net/xen-netback/Makefile
+new file mode 100644
+index 0000000..e346e81
+--- /dev/null
++++ b/drivers/net/xen-netback/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
+
-+ return 0;
-+}
++xen-netback-y := netback.o xenbus.o interface.o
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+new file mode 100644
+index 0000000..2d727a0
+--- /dev/null
++++ b/drivers/net/xen-netback/common.h
+@@ -0,0 +1,273 @@
++/*
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
+
-+/* Called after netfront has transmitted */
-+static void net_tx_action(unsigned long unused)
-+{
-+ struct list_head *ent;
-+ struct sk_buff *skb;
-+ netif_t *netif;
-+ netif_tx_request_t txreq;
-+ netif_tx_request_t txfrags[MAX_SKB_FRAGS];
-+ struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-+ u16 pending_idx;
-+ RING_IDX i;
-+ gnttab_map_grant_ref_t *mop;
-+ unsigned int data_len;
-+ int ret, work_to_do;
++#ifndef __XEN_NETBACK__COMMON_H__
++#define __XEN_NETBACK__COMMON_H__
+
-+ if (dealloc_cons != dealloc_prod)
-+ net_tx_action_dealloc();
++#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
-+ mop = tx_map_ops;
-+ while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+ !list_empty(&net_schedule_list)) {
-+ /* Get a netif from the list with work to do. */
-+ ent = net_schedule_list.next;
-+ netif = list_entry(ent, netif_t, list);
-+ netif_get(netif);
-+ remove_from_net_schedule_list(netif);
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/io.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
+
-+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
-+ if (!work_to_do) {
-+ netif_put(netif);
-+ continue;
-+ }
++#include <xen/interface/io/netif.h>
++#include <asm/pgalloc.h>
++#include <xen/interface/grant_table.h>
++#include <xen/grant_table.h>
++#include <xen/xenbus.h>
+
-+ i = netif->tx.req_cons;
-+ rmb(); /* Ensure that we see the request before we copy it. */
-+ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
++struct xen_netif {
++ /* Unique identifier for this interface. */
++ domid_t domid;
++ int group;
++ unsigned int handle;
+
-+ /* Credit-based scheduling. */
-+ if (txreq.size > netif->remaining_credit) {
-+ unsigned long now = jiffies;
-+ unsigned long next_credit =
-+ netif->credit_timeout.expires +
-+ msecs_to_jiffies(netif->credit_usec / 1000);
++ u8 fe_dev_addr[6];
+
-+ /* Timer could already be pending in rare cases. */
-+ if (timer_pending(&netif->credit_timeout)) {
-+ netif_put(netif);
-+ continue;
-+ }
++ /* Physical parameters of the comms window. */
++ grant_handle_t tx_shmem_handle;
++ grant_ref_t tx_shmem_ref;
++ grant_handle_t rx_shmem_handle;
++ grant_ref_t rx_shmem_ref;
++ unsigned int irq;
+
-+ /* Passed the point where we can replenish credit? */
-+ if (time_after_eq(now, next_credit)) {
-+ netif->credit_timeout.expires = now;
-+ tx_add_credit(netif);
-+ }
++ /* The shared rings and indexes. */
++ struct xen_netif_tx_back_ring tx;
++ struct xen_netif_rx_back_ring rx;
++ struct vm_struct *tx_comms_area;
++ struct vm_struct *rx_comms_area;
+
-+ /* Still too big to send right now? Set a callback. */
-+ if (txreq.size > netif->remaining_credit) {
-+ netif->credit_timeout.data =
-+ (unsigned long)netif;
-+ netif->credit_timeout.function =
-+ tx_credit_callback;
-+ __mod_timer(&netif->credit_timeout,
-+ next_credit);
-+ netif_put(netif);
-+ continue;
-+ }
-+ }
-+ netif->remaining_credit -= txreq.size;
++ /* Flags that must not be set in dev->features */
++ int features_disabled;
+
-+ work_to_do--;
-+ netif->tx.req_cons = ++i;
++ /* Frontend feature information. */
++ u8 can_sg:1;
++ u8 gso:1;
++ u8 gso_prefix:1;
++ u8 csum:1;
+
-+ memset(extras, 0, sizeof(extras));
-+ if (txreq.flags & NETTXF_extra_info) {
-+ work_to_do = netbk_get_extras(netif, extras,
-+ work_to_do);
-+ i = netif->tx.req_cons;
-+ if (unlikely(work_to_do < 0)) {
-+ netbk_tx_err(netif, &txreq, i);
-+ continue;
-+ }
-+ }
++ /* Internal feature information. */
++ u8 can_queue:1; /* can queue packets for receiver? */
+
-+ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
-+ if (unlikely(ret < 0)) {
-+ netbk_tx_err(netif, &txreq, i - ret);
-+ continue;
-+ }
-+ i += ret;
++ /* Allow netif_be_start_xmit() to peek ahead in the rx request
++ * ring. This is a prediction of what rx_req_cons will be once
++ * all queued skbs are put on the ring. */
++ RING_IDX rx_req_cons_peek;
+
-+ if (unlikely(txreq.size < ETH_HLEN)) {
-+ DPRINTK("Bad packet size: %d\n", txreq.size);
-+ netbk_tx_err(netif, &txreq, i);
-+ continue;
-+ }
++ /* 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;
+
-+ /* No crossing a page as the payload mustn't fragment. */
-+ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-+ DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
-+ txreq.offset, txreq.size,
-+ (txreq.offset &~PAGE_MASK) + txreq.size);
-+ netbk_tx_err(netif, &txreq, i);
-+ continue;
-+ }
++ /* Statistics */
++ int nr_copied_skbs;
++ int rx_gso_checksum_fixup;
+
-+ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
++ /* Miscellaneous private stuff. */
++ struct list_head list; /* scheduling list */
++ atomic_t refcnt;
++ struct net_device *dev;
++ struct net_device_stats stats;
+
-+ data_len = (txreq.size > PKT_PROT_LEN &&
-+ ret < MAX_SKB_FRAGS) ?
-+ PKT_PROT_LEN : txreq.size;
++ unsigned int carrier;
+
-+ skb = alloc_skb(data_len + 16 + NET_IP_ALIGN,
-+ GFP_ATOMIC | __GFP_NOWARN);
-+ if (unlikely(skb == NULL)) {
-+ DPRINTK("Can't allocate a skb in start_xmit.\n");
-+ netbk_tx_err(netif, &txreq, i);
-+ break;
-+ }
++ wait_queue_head_t waiting_to_free;
++};
+
-+ /* Packets passed to netif_rx() must have some headroom. */
-+ skb_reserve(skb, 16 + NET_IP_ALIGN);
++/*
++ * Implement our own carrier flag: the network stack's version causes delays
++ * when the carrier is re-enabled (in particular, dev_activate() may not
++ * immediately be called, which can cause packet loss; also the etherbridge
++ * can be rather lazy in activating its port).
++ */
++#define netback_carrier_on(netif) ((netif)->carrier = 1)
++#define netback_carrier_off(netif) ((netif)->carrier = 0)
++#define netback_carrier_ok(netif) ((netif)->carrier)
+
-+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
-+ struct netif_extra_info *gso;
-+ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++enum {
++ NETBK_DONT_COPY_SKB,
++ NETBK_DELAYED_COPY_SKB,
++ NETBK_ALWAYS_COPY_SKB,
++};
+
-+ if (netbk_set_skb_gso(skb, gso)) {
-+ kfree_skb(skb);
-+ netbk_tx_err(netif, &txreq, i);
-+ continue;
-+ }
-+ }
++extern int netbk_copy_skb_mode;
+
-+ gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
-+ GNTMAP_host_map | GNTMAP_readonly,
-+ txreq.gref, netif->domid);
-+ mop++;
++struct backend_info {
++ struct xenbus_device *dev;
++ struct xen_netif *netif;
++ enum xenbus_state frontend_state;
++ struct xenbus_watch hotplug_status_watch;
++ int have_hotplug_status_watch:1;
++};
+
-+ memcpy(&pending_tx_info[pending_idx].req,
-+ &txreq, sizeof(txreq));
-+ pending_tx_info[pending_idx].netif = netif;
-+ *((u16 *)skb->data) = pending_idx;
++#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+
-+ __skb_put(skb, data_len);
++void netif_disconnect(struct xen_netif *netif);
+
-+ skb_shinfo(skb)->nr_frags = ret;
-+ if (data_len < txreq.size) {
-+ skb_shinfo(skb)->nr_frags++;
-+ skb_shinfo(skb)->frags[0].page =
-+ (void *)(unsigned long)pending_idx;
-+ } else {
-+ /* Discriminate from any valid pending_idx value. */
-+ skb_shinfo(skb)->frags[0].page = (void *)~0UL;
-+ }
++void netif_set_features(struct xen_netif *netif);
++struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
++ unsigned int handle);
++int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn);
+
-+ if (skb->data_len < skb_shinfo(skb)->gso_size) {
-+ skb_shinfo(skb)->gso_size = 0;
-+ skb_shinfo(skb)->gso_type = 0;
-+ }
++static inline void netif_get(struct xen_netif *netif)
++{
++ atomic_inc(&netif->refcnt);
++}
+
-+ __skb_queue_tail(&tx_queue, skb);
++static inline void netif_put(struct xen_netif *netif)
++{
++ if (atomic_dec_and_test(&netif->refcnt))
++ wake_up(&netif->waiting_to_free);
++}
+
-+ pending_cons++;
++int netif_xenbus_init(void);
+
-+ mop = netbk_get_requests(netif, skb, txfrags, mop);
++#define netif_schedulable(netif) \
++ (netif_running((netif)->dev) && netback_carrier_ok(netif))
+
-+ netif->tx.req_cons = i;
-+ netif_schedule_work(netif);
++void netif_schedule_work(struct xen_netif *netif);
++void netif_deschedule_work(struct xen_netif *netif);
+
-+ if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
-+ break;
-+ }
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
++struct net_device_stats *netif_be_get_stats(struct net_device *dev);
++irqreturn_t netif_be_int(int irq, void *dev_id);
+
-+ if (mop == tx_map_ops)
-+ return;
++static inline int netbk_can_queue(struct net_device *dev)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ return netif->can_queue;
++}
+
-+ ret = HYPERVISOR_grant_table_op(
-+ GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
-+ BUG_ON(ret);
++static inline int netbk_can_sg(struct net_device *dev)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ return netif->can_sg;
++}
+
-+ mop = tx_map_ops;
-+ while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
-+ netif_tx_request_t *txp;
++struct pending_tx_info {
++ struct xen_netif_tx_request req;
++ struct xen_netif *netif;
++};
++typedef unsigned int pending_ring_idx_t;
+
-+ pending_idx = *((u16 *)skb->data);
-+ netif = pending_tx_info[pending_idx].netif;
-+ txp = &pending_tx_info[pending_idx].req;
++struct netbk_rx_meta {
++ int id;
++ int size;
++ int gso_size;
++};
+
-+ /* Check the remap error code. */
-+ if (unlikely(netbk_tx_check_mop(skb, &mop))) {
-+ DPRINTK("netback grant failed.\n");
-+ skb_shinfo(skb)->nr_frags = 0;
-+ kfree_skb(skb);
-+ continue;
-+ }
++struct netbk_tx_pending_inuse {
++ struct list_head list;
++ unsigned long alloc_time;
++};
+
-+ data_len = skb->len;
-+ memcpy(skb->data,
-+ (void *)(idx_to_kaddr(pending_idx)|txp->offset),
-+ data_len);
-+ if (data_len < txp->size) {
-+ /* Append the packet payload as a fragment. */
-+ txp->offset += data_len;
-+ txp->size -= data_len;
-+ } else {
-+ /* Schedule a response immediately. */
-+ netif_idx_release(pending_idx);
-+ }
++#define MAX_PENDING_REQS 256
+
-+ /*
-+ * Old frontends do not assert data_validated but we
-+ * can infer it from csum_blank so test both flags.
-+ */
-+ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+ skb->proto_data_valid = 1;
-+ } else {
-+ skb->ip_summed = CHECKSUM_NONE;
-+ skb->proto_data_valid = 0;
-+ }
-+ skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
++#define MAX_BUFFER_OFFSET PAGE_SIZE
+
-+ netbk_fill_frags(skb);
++/* extra field used in struct page */
++union page_ext {
++ struct {
++#if BITS_PER_LONG < 64
++#define IDX_WIDTH 8
++#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
++ unsigned int group:GROUP_WIDTH;
++ unsigned int idx:IDX_WIDTH;
++#else
++ unsigned int group, idx;
++#endif
++ } e;
++ void *mapping;
++};
+
-+ skb->dev = netif->dev;
-+ skb->protocol = eth_type_trans(skb, skb->dev);
++struct xen_netbk {
++ union {
++ struct {
++ struct tasklet_struct net_tx_tasklet;
++ struct tasklet_struct net_rx_tasklet;
++ } tasklet;
+
-+ netif->stats.rx_bytes += skb->len;
-+ netif->stats.rx_packets++;
++ struct {
++ wait_queue_head_t netbk_action_wq;
++ struct task_struct *task;
++ } kthread;
++ };
+
-+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
-+ unlikely(skb_linearize(skb))) {
-+ DPRINTK("Can't linearize skb in net_tx_action.\n");
-+ kfree_skb(skb);
-+ continue;
-+ }
++ struct sk_buff_head rx_queue;
++ struct sk_buff_head tx_queue;
+
-+ netif_rx(skb);
-+ netif->dev->last_rx = jiffies;
-+ }
++ struct timer_list net_timer;
++ struct timer_list netbk_tx_pending_timer;
+
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !list_empty(&pending_inuse_head)) {
-+ struct netbk_tx_pending_inuse *oldest;
++ struct page **mmap_pages;
+
-+ oldest = list_entry(pending_inuse_head.next,
-+ struct netbk_tx_pending_inuse, list);
-+ mod_timer(&netbk_tx_pending_timer, oldest->alloc_time + HZ);
-+ }
-+}
++ pending_ring_idx_t pending_prod;
++ pending_ring_idx_t pending_cons;
++ pending_ring_idx_t dealloc_prod;
++ pending_ring_idx_t dealloc_cons;
+
-+static void netif_idx_release(u16 pending_idx)
-+{
-+ static DEFINE_SPINLOCK(_lock);
-+ unsigned long flags;
++ struct list_head pending_inuse_head;
++ struct list_head net_schedule_list;
+
-+ spin_lock_irqsave(&_lock, flags);
-+ dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
-+ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
-+ smp_wmb();
-+ dealloc_prod++;
-+ spin_unlock_irqrestore(&_lock, flags);
++ /* Protect the net_schedule_list in netif. */
++ spinlock_t net_schedule_list_lock;
+
-+ tasklet_schedule(&net_tx_tasklet);
-+}
++ atomic_t netfront_count;
+
-+static void netif_page_release(struct page *page, unsigned int order)
-+{
-+ int idx = netif_page_index(page);
-+ BUG_ON(order);
-+ BUG_ON(idx < 0);
-+ netif_idx_release(idx);
-+}
++ 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];
+
-+irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ netif_t *netif = dev_id;
++ grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
++ u16 pending_ring[MAX_PENDING_REQS];
++ u16 dealloc_ring[MAX_PENDING_REQS];
+
-+ add_to_net_schedule_list_tail(netif);
-+ maybe_schedule_tx_action();
++ /*
++ * Each head or fragment can be up to 4096 bytes. Given
++ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
++ * head/fragment uses 2 copy operation.
++ */
++ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
++ unsigned char rx_notify[NR_IRQS];
++ u16 notify_list[NET_RX_RING_SIZE];
++ struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
++};
+
-+ if (netif_schedulable(netif) && !netbk_queue_full(netif))
-+ netif_wake_queue(netif->dev);
++extern struct xen_netbk *xen_netbk;
++extern int xen_netbk_group_nr;
+
-+ return IRQ_HANDLED;
-+}
++#endif /* __XEN_NETBACK__COMMON_H__ */
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+new file mode 100644
+index 0000000..b429f8c
+--- /dev/null
++++ b/drivers/net/xen-netback/interface.c
+@@ -0,0 +1,470 @@
++/*
++ * Network-device interface management.
++ *
++ * Copyright (c) 2004-2005, Keir Fraser
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
+
-+static void make_tx_response(netif_t *netif,
-+ netif_tx_request_t *txp,
-+ s8 st)
-+{
-+ RING_IDX i = netif->tx.rsp_prod_pvt;
-+ netif_tx_response_t *resp;
-+ int notify;
++#include "common.h"
+
-+ resp = RING_GET_RESPONSE(&netif->tx, i);
-+ resp->id = txp->id;
-+ resp->status = st;
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
+
-+ if (txp->flags & NETTXF_extra_info)
-+ RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
++#include <xen/events.h>
++#include <asm/xen/hypercall.h>
+
-+ netif->tx.rsp_prod_pvt = ++i;
-+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
-+ if (notify)
-+ notify_remote_via_irq(netif->irq);
++/*
++ * Module parameter 'queue_length':
++ *
++ * Enables queuing in the network stack when a client has run out of receive
++ * descriptors.
++ */
++static unsigned long netbk_queue_length = 32;
++module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+
-+#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-+ if (i == netif->tx.req_cons) {
-+ int more_to_do;
-+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-+ if (more_to_do)
-+ add_to_net_schedule_list_tail(netif);
++static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
++ struct xen_netif *netif)
++{
++ int i;
++ int min_netfront_count;
++ int min_group = 0;
++ min_netfront_count = atomic_read(&netbk[0].netfront_count);
++ for (i = 0; i < group_nr; i++) {
++ int netfront_count = atomic_read(&netbk[i].netfront_count);
++ if (netfront_count < min_netfront_count) {
++ min_group = i;
++ min_netfront_count = netfront_count;
++ }
+ }
-+#endif
++
++ netif->group = min_group;
++ atomic_inc(&netbk[netif->group].netfront_count);
+}
+
-+static netif_rx_response_t *make_rx_response(netif_t *netif,
-+ u16 id,
-+ s8 st,
-+ u16 offset,
-+ u16 size,
-+ u16 flags)
++static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
+{
-+ RING_IDX i = netif->rx.rsp_prod_pvt;
-+ netif_rx_response_t *resp;
-+
-+ resp = RING_GET_RESPONSE(&netif->rx, i);
-+ resp->offset = offset;
-+ resp->flags = flags;
-+ resp->id = id;
-+ resp->status = (s16)size;
-+ if (st < 0)
-+ resp->status = (s16)st;
-+
-+ netif->rx.rsp_prod_pvt = ++i;
-+
-+ return resp;
++ atomic_dec(&netbk[netif->group].netfront_count);
+}
+
-+#ifdef NETBE_DEBUG_INTERRUPT
-+static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
++static void __netif_up(struct xen_netif *netif)
+{
-+ struct list_head *ent;
-+ netif_t *netif;
-+ int i = 0;
++ netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
++ enable_irq(netif->irq);
++ netif_schedule_work(netif);
++}
+
-+ printk(KERN_ALERT "netif_schedule_list:\n");
-+ spin_lock_irq(&net_schedule_list_lock);
++static void __netif_down(struct xen_netif *netif)
++{
++ disable_irq(netif->irq);
++ netif_deschedule_work(netif);
++ netbk_remove_netif(xen_netbk, netif);
++}
+
-+ list_for_each (ent, &net_schedule_list) {
-+ netif = list_entry(ent, netif_t, list);
-+ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-+ "rx_resp_prod=%08x\n",
-+ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-+ printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n",
-+ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-+ printk(KERN_ALERT " shared(rx_req_prod=%08x "
-+ "rx_resp_prod=%08x\n",
-+ netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
-+ printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n",
-+ netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
-+ printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n",
-+ netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
-+ i++;
++static int net_open(struct net_device *dev)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (netback_carrier_ok(netif)) {
++ __netif_up(netif);
++ netif_start_queue(dev);
+ }
++ return 0;
++}
+
-+ spin_unlock_irq(&net_schedule_list_lock);
-+ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
-+
-+ return IRQ_HANDLED;
++static int net_close(struct net_device *dev)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (netback_carrier_ok(netif))
++ __netif_down(netif);
++ netif_stop_queue(dev);
++ return 0;
+}
-+#endif
+
-+static int __init netback_init(void)
++static int netbk_change_mtu(struct net_device *dev, int mtu)
+{
-+ int i;
-+ struct page *page;
++ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
-+ if (!is_running_on_xen())
-+ return -ENODEV;
++ if (mtu > max)
++ return -EINVAL;
++ dev->mtu = mtu;
++ return 0;
++}
+
-+ /* We can increase reservation by this much in net_rx_action(). */
-+ balloon_update_driver_allowance(NET_RX_RING_SIZE);
++void netif_set_features(struct xen_netif *netif)
++{
++ struct net_device *dev = netif->dev;
++ int features = dev->features;
+
-+ skb_queue_head_init(&rx_queue);
-+ skb_queue_head_init(&tx_queue);
++ if (netif->can_sg)
++ features |= NETIF_F_SG;
++ if (netif->gso || netif->gso_prefix)
++ features |= NETIF_F_TSO;
++ if (netif->csum)
++ features |= NETIF_F_IP_CSUM;
+
-+ init_timer(&net_timer);
-+ net_timer.data = 0;
-+ net_timer.function = net_alarm;
++ features &= ~(netif->features_disabled);
+
-+ init_timer(&netbk_tx_pending_timer);
-+ netbk_tx_pending_timer.data = 0;
-+ netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
++ if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
++ dev->mtu = ETH_DATA_LEN;
+
-+ mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-+ if (mmap_pages == NULL) {
-+ printk("%s: out of memory\n", __FUNCTION__);
-+ return -ENOMEM;
-+ }
++ dev->features = features;
++}
+
-+ 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);
++static int netbk_set_tx_csum(struct net_device *dev, u32 data)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (data) {
++ if (!netif->csum)
++ return -ENOSYS;
++ netif->features_disabled &= ~NETIF_F_IP_CSUM;
++ } else {
++ netif->features_disabled |= NETIF_F_IP_CSUM;
+ }
+
-+ pending_cons = 0;
-+ pending_prod = MAX_PENDING_REQS;
-+ for (i = 0; i < MAX_PENDING_REQS; i++)
-+ pending_ring[i] = i;
-+
-+ spin_lock_init(&net_schedule_list_lock);
-+ INIT_LIST_HEAD(&net_schedule_list);
++ netif_set_features(netif);
++ return 0;
++}
+
-+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
-+ if (MODPARM_copy_skb) {
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-+ NULL, 0))
-+ netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
-+ else
-+ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
++static int netbk_set_sg(struct net_device *dev, u32 data)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (data) {
++ if (!netif->can_sg)
++ return -ENOSYS;
++ netif->features_disabled &= ~NETIF_F_SG;
++ } else {
++ netif->features_disabled |= NETIF_F_SG;
+ }
+
-+ netif_accel_init();
-+
-+ netif_xenbus_init();
-+
-+#ifdef NETBE_DEBUG_INTERRUPT
-+ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-+ 0,
-+ netif_be_dbg,
-+ SA_SHIRQ,
-+ "net-be-dbg",
-+ &netif_be_dbg);
-+#endif
-+
++ netif_set_features(netif);
+ return 0;
+}
+
-+module_init(netback_init);
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-new file mode 100644
-index 0000000..d7faeb6
---- /dev/null
-+++ b/drivers/xen/netback/xenbus.c
-@@ -0,0 +1,454 @@
-+/* Xenbus code for netif backend
-+ Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
-+ Copyright (C) 2005 XenSource Ltd
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; either version 2 of the License, or
-+ (at your option) any later version.
++static int netbk_set_tso(struct net_device *dev, u32 data)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ if (data) {
++ if (!netif->gso && !netif->gso_prefix)
++ return -ENOSYS;
++ netif->features_disabled &= ~NETIF_F_TSO;
++ } else {
++ netif->features_disabled |= NETIF_F_TSO;
++ }
+
-+ This program is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ GNU General Public License for more details.
++ netif_set_features(netif);
++ return 0;
++}
+
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software
-+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
++static void netbk_get_drvinfo(struct net_device *dev,
++ struct ethtool_drvinfo *info)
++{
++ strcpy(info->driver, "netbk");
++ strcpy(info->bus_info, dev_name(dev->dev.parent));
++}
+
-+#include <stdarg.h>
-+#include <linux/module.h>
-+#include <xen/xenbus.h>
-+#include "common.h"
++static const struct netif_stat {
++ char name[ETH_GSTRING_LEN];
++ u16 offset;
++} netbk_stats[] = {
++ {
++ "copied_skbs",
++ offsetof(struct xen_netif, nr_copied_skbs)
++ },
++ {
++ "rx_gso_checksum_fixup",
++ offsetof(struct xen_netif, rx_gso_checksum_fixup)
++ },
++};
+
-+#if 0
-+#undef DPRINTK
-+#define DPRINTK(fmt, args...) \
-+ printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__,
__LINE__, ##args)
-+#endif
++static int netbk_get_sset_count(struct net_device *dev, int string_set)
++{
++ switch (string_set) {
++ case ETH_SS_STATS:
++ return ARRAY_SIZE(netbk_stats);
++ default:
++ return -EINVAL;
++ }
++}
+
++static void netbk_get_ethtool_stats(struct net_device *dev,
++ struct ethtool_stats *stats, u64 * data)
++{
++ void *netif = netdev_priv(dev);
++ int i;
+
-+static int connect_rings(struct backend_info *);
-+static void connect(struct backend_info *);
-+static void backend_create_netif(struct backend_info *be);
++ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
++ data[i] = *(int *)(netif + netbk_stats[i].offset);
++}
+
-+static int netback_remove(struct xenbus_device *dev)
++static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
-+ struct backend_info *be = dev->dev.driver_data;
-+
-+ netback_remove_accelerators(be, dev);
++ int i;
+
-+ if (be->netif) {
-+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-+ netif_disconnect(be->netif);
-+ be->netif = NULL;
++ switch (stringset) {
++ case ETH_SS_STATS:
++ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
++ memcpy(data + i * ETH_GSTRING_LEN,
++ netbk_stats[i].name, ETH_GSTRING_LEN);
++ break;
+ }
-+ kfree(be);
-+ dev->dev.driver_data = NULL;
-+ return 0;
+}
+
++static struct ethtool_ops network_ethtool_ops = {
++ .get_drvinfo = netbk_get_drvinfo,
+
-+/**
-+ * Entry point to this code when a new device is created. Allocate the basic
-+ * structures and switch to InitWait.
-+ */
-+static int netback_probe(struct xenbus_device *dev,
-+ const struct xenbus_device_id *id)
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = netbk_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = netbk_set_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = netbk_set_tso,
++ .get_link = ethtool_op_get_link,
++
++ .get_sset_count = netbk_get_sset_count,
++ .get_ethtool_stats = netbk_get_ethtool_stats,
++ .get_strings = netbk_get_strings,
++};
++
++static struct net_device_ops netback_ops = {
++ .ndo_start_xmit = netif_be_start_xmit,
++ .ndo_get_stats = netif_be_get_stats,
++ .ndo_open = net_open,
++ .ndo_stop = net_close,
++ .ndo_change_mtu = netbk_change_mtu,
++};
++
++struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
++ unsigned int handle)
+{
-+ const char *message;
-+ struct xenbus_transaction xbt;
-+ int err;
-+ int sg;
-+ struct backend_info *be = kzalloc(sizeof(struct backend_info),
-+ GFP_KERNEL);
-+ if (!be) {
-+ xenbus_dev_fatal(dev, -ENOMEM,
-+ "allocating backend structure");
-+ return -ENOMEM;
-+ }
++ int err = 0;
++ struct net_device *dev;
++ struct xen_netif *netif;
++ char name[IFNAMSIZ] = {};
+
-+ be->dev = dev;
-+ dev->dev.driver_data = be;
++ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
++ dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
++ if (dev == NULL) {
++ pr_debug("Could not allocate netdev\n");
++ return ERR_PTR(-ENOMEM);
++ }
+
-+ sg = 1;
-+ if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
-+ sg = 0;
++ SET_NETDEV_DEV(dev, parent);
+
-+ do {
-+ err = xenbus_transaction_start(&xbt);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err, "starting transaction");
-+ goto fail;
-+ }
++ netif = netdev_priv(dev);
++ memset(netif, 0, sizeof(*netif));
++ netif->domid = domid;
++ netif->group = -1;
++ netif->handle = handle;
++ netif->can_sg = 1;
++ netif->csum = 1;
++ atomic_set(&netif->refcnt, 1);
++ init_waitqueue_head(&netif->waiting_to_free);
++ netif->dev = dev;
++ INIT_LIST_HEAD(&netif->list);
+
-+ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
sg);
-+ if (err) {
-+ message = "writing feature-sg";
-+ goto abort_transaction;
-+ }
++ netback_carrier_off(netif);
+
-+ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
-+ "%d", sg);
-+ if (err) {
-+ message = "writing feature-gso-tcpv4";
-+ goto abort_transaction;
-+ }
++ netif->credit_bytes = netif->remaining_credit = ~0UL;
++ netif->credit_usec = 0UL;
++ init_timer(&netif->credit_timeout);
++ /* Initialize 'expires' now: it's used to track the credit window. */
++ netif->credit_timeout.expires = jiffies;
+
-+ /* We support rx-copy path. */
-+ err = xenbus_printf(xbt, dev->nodename,
-+ "feature-rx-copy", "%d", 1);
-+ if (err) {
-+ message = "writing feature-rx-copy";
-+ goto abort_transaction;
-+ }
++ dev->netdev_ops = &netback_ops;
++ netif_set_features(netif);
++ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+
-+ /*
-+ * We don't support rx-flip path (except old guests who don't
-+ * grok this feature flag).
-+ */
-+ err = xenbus_printf(xbt, dev->nodename,
-+ "feature-rx-flip", "%d", 0);
-+ if (err) {
-+ message = "writing feature-rx-flip";
-+ goto abort_transaction;
-+ }
++ dev->tx_queue_len = netbk_queue_length;
+
-+ err = xenbus_transaction_end(xbt, 0);
-+ } while (err == -EAGAIN);
++ /*
++ * Initialise a dummy MAC address. We choose the numerically
++ * largest non-broadcast address to prevent the address getting
++ * stolen by an Ethernet bridge for STP purposes.
++ * (FE:FF:FF:FF:FF:FF)
++ */
++ memset(dev->dev_addr, 0xFF, ETH_ALEN);
++ dev->dev_addr[0] &= ~0x01;
+
++ rtnl_lock();
++ err = register_netdevice(dev);
++ rtnl_unlock();
+ if (err) {
-+ xenbus_dev_fatal(dev, err, "completing transaction");
-+ goto fail;
++ pr_debug("Could not register new net device %s: err=%d\n",
++ dev->name, err);
++ free_netdev(dev);
++ return ERR_PTR(err);
+ }
+
-+ netback_probe_accelerators(be, dev);
++ pr_debug("Successfully created netif\n");
++ return netif;
++}
+
-+ err = xenbus_switch_state(dev, XenbusStateInitWait);
-+ if (err)
-+ goto fail;
++static int map_frontend_pages(struct xen_netif *netif,
++ grant_ref_t tx_ring_ref,
++ grant_ref_t rx_ring_ref)
++{
++ struct gnttab_map_grant_ref op;
+
-+ /* This kicks hotplug scripts, so do it immediately. */
-+ backend_create_netif(be);
++ gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, tx_ring_ref, netif->domid);
+
-+ return 0;
++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++ BUG();
+
-+abort_transaction:
-+ xenbus_transaction_end(xbt, 1);
-+ xenbus_dev_fatal(dev, err, "%s", message);
-+fail:
-+ DPRINTK("failed");
-+ netback_remove(dev);
-+ return err;
-+}
++ if (op.status) {
++ pr_debug("Gnttab failure mapping tx_ring_ref!\n");
++ return op.status;
++ }
+
++ netif->tx_shmem_ref = tx_ring_ref;
++ netif->tx_shmem_handle = op.handle;
+
-+/**
-+ * Handle the creation of the hotplug script environment. We add the script
-+ * and vif variables to the environment, for the benefit of the vif-* hotplug
-+ * scripts.
-+ */
-+static int netback_uevent(struct xenbus_device *xdev, char **envp,
-+ int num_envp, char *buffer, int buffer_size)
-+{
-+ struct backend_info *be = xdev->dev.driver_data;
-+ netif_t *netif = be->netif;
-+ int i = 0, length = 0;
-+ char *val;
++ gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
++ GNTMAP_host_map, rx_ring_ref, netif->domid);
+
-+ DPRINTK("netback_uevent");
++ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++ BUG();
+
-+ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
-+ if (IS_ERR(val)) {
-+ int err = PTR_ERR(val);
-+ xenbus_dev_fatal(xdev, err, "reading script");
-+ return err;
-+ }
-+ else {
-+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+ &length, "script=%s", val);
-+ kfree(val);
-+ }
++ if (op.status) {
++ struct gnttab_unmap_grant_ref unop;
+
-+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+ "vif=%s", netif->dev->name);
++ gnttab_set_unmap_op(&unop,
++ (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, netif->tx_shmem_handle);
++ HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
++ pr_debug("Gnttab failure mapping rx_ring_ref!\n");
++ return op.status;
++ }
+
-+ envp[i] = NULL;
++ netif->rx_shmem_ref = rx_ring_ref;
++ netif->rx_shmem_handle = op.handle;
+
+ return 0;
+}
+
-+
-+static void backend_create_netif(struct backend_info *be)
++static void unmap_frontend_pages(struct xen_netif *netif)
+{
-+ int err;
-+ long handle;
-+ struct xenbus_device *dev = be->dev;
++ struct gnttab_unmap_grant_ref op;
+
-+ if (be->netif != NULL)
-+ return;
++ gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
++ GNTMAP_host_map, netif->tx_shmem_handle);
+
-+ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
-+ if (err != 1) {
-+ xenbus_dev_fatal(dev, err, "reading handle");
-+ return;
-+ }
++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++ BUG();
+
-+ be->netif = netif_alloc(dev->otherend_id, handle);
-+ if (IS_ERR(be->netif)) {
-+ err = PTR_ERR(be->netif);
-+ be->netif = NULL;
-+ xenbus_dev_fatal(dev, err, "creating interface");
-+ return;
-+ }
++ gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
++ GNTMAP_host_map, netif->rx_shmem_handle);
+
-+ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++ BUG();
+}
+
-+
-+/**
-+ * Callback received when the frontend's state changes.
-+ */
-+static void frontend_changed(struct xenbus_device *dev,
-+ enum xenbus_state frontend_state)
++int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn)
+{
-+ struct backend_info *be = dev->dev.driver_data;
++ int err = -ENOMEM;
++ struct xen_netif_tx_sring *txs;
++ struct xen_netif_rx_sring *rxs;
+
-+ DPRINTK("%s", xenbus_strstate(frontend_state));
++ /* Already connected through? */
++ if (netif->irq)
++ return 0;
+
-+ be->frontend_state = frontend_state;
++ netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (netif->tx_comms_area == NULL)
++ return -ENOMEM;
++ netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (netif->rx_comms_area == NULL)
++ goto err_rx;
+
-+ switch (frontend_state) {
-+ case XenbusStateInitialising:
-+ if (dev->state == XenbusStateClosed) {
-+ printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-+ __FUNCTION__, dev->nodename);
-+ xenbus_switch_state(dev, XenbusStateInitWait);
-+ }
-+ break;
++ err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
++ if (err)
++ goto err_map;
+
-+ case XenbusStateInitialised:
-+ break;
++ err = bind_interdomain_evtchn_to_irqhandler(
++ netif->domid, evtchn, netif_be_int, 0,
++ netif->dev->name, netif);
++ if (err < 0)
++ goto err_hypervisor;
++ netif->irq = err;
++ disable_irq(netif->irq);
+
-+ case XenbusStateConnected:
-+ if (dev->state == XenbusStateConnected)
-+ break;
-+ backend_create_netif(be);
-+ if (be->netif)
-+ connect(be);
-+ break;
++ txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
++ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
+
-+ case XenbusStateClosing:
-+ if (be->netif) {
-+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-+ netif_disconnect(be->netif);
-+ be->netif = NULL;
-+ }
-+ xenbus_switch_state(dev, XenbusStateClosing);
-+ break;
++ rxs = (struct xen_netif_rx_sring *)
++ ((char *)netif->rx_comms_area->addr);
++ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
+
-+ case XenbusStateClosed:
-+ xenbus_switch_state(dev, XenbusStateClosed);
-+ if (xenbus_dev_is_online(dev))
-+ break;
-+ /* fall through if not online */
-+ case XenbusStateUnknown:
-+ device_unregister(&dev->dev);
-+ break;
++ netif->rx_req_cons_peek = 0;
+
-+ default:
-+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-+ frontend_state);
-+ break;
-+ }
-+}
++ netif_get(netif);
++
++ rtnl_lock();
++ netback_carrier_on(netif);
++ if (netif_running(netif->dev))
++ __netif_up(netif);
++ rtnl_unlock();
+
++ return 0;
++err_hypervisor:
++ unmap_frontend_pages(netif);
++err_map:
++ free_vm_area(netif->rx_comms_area);
++err_rx:
++ free_vm_area(netif->tx_comms_area);
++ return err;
++}
+
-+static void xen_net_read_rate(struct xenbus_device *dev,
-+ unsigned long *bytes, unsigned long *usec)
++void netif_disconnect(struct xen_netif *netif)
+{
-+ char *s, *e;
-+ unsigned long b, u;
-+ char *ratestr;
-+
-+ /* Default to unlimited bandwidth. */
-+ *bytes = ~0UL;
-+ *usec = 0;
++ if (netback_carrier_ok(netif)) {
++ rtnl_lock();
++ netback_carrier_off(netif);
++ netif_carrier_off(netif->dev); /* discard queued packets */
++ if (netif_running(netif->dev))
++ __netif_down(netif);
++ rtnl_unlock();
++ netif_put(netif);
++ }
+
-+ ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
-+ if (IS_ERR(ratestr))
-+ return;
++ atomic_dec(&netif->refcnt);
++ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
+
-+ s = ratestr;
-+ b = simple_strtoul(s, &e, 10);
-+ if ((s == e) || (*e != ','))
-+ goto fail;
++ del_timer_sync(&netif->credit_timeout);
+
-+ s = e + 1;
-+ u = simple_strtoul(s, &e, 10);
-+ if ((s == e) || (*e != '\0'))
-+ goto fail;
++ if (netif->irq)
++ unbind_from_irqhandler(netif->irq, netif);
+
-+ *bytes = b;
-+ *usec = u;
++ unregister_netdev(netif->dev);
+
-+ kfree(ratestr);
-+ return;
++ if (netif->tx.sring) {
++ unmap_frontend_pages(netif);
++ free_vm_area(netif->tx_comms_area);
++ free_vm_area(netif->rx_comms_area);
++ }
+
-+ fail:
-+ WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
-+ kfree(ratestr);
++ free_netdev(netif->dev);
+}
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+new file mode 100644
+index 0000000..b290525
+--- /dev/null
++++ b/drivers/net/xen-netback/netback.c
+@@ -0,0 +1,1934 @@
++/*
++ * Back-end of the driver for virtual network devices. This portion of the
++ * driver exports a 'unified' network-device interface that can be accessed
++ * by any operating system that implements a compatible front end. A
++ * reference front-end implementation can be found in:
++ * drivers/net/xen-netfront.c
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
+
-+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
-+{
-+ char *s, *e, *macstr;
-+ int i;
-+
-+ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
-+ if (IS_ERR(macstr))
-+ return PTR_ERR(macstr);
++#include "common.h"
+
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ mac[i] = simple_strtoul(s, &e, 16);
-+ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
-+ kfree(macstr);
-+ return -ENOENT;
-+ }
-+ s = e+1;
-+ }
++#include <linux/kthread.h>
++#include <linux/if_vlan.h>
++#include <linux/udp.h>
+
-+ kfree(macstr);
-+ return 0;
++#include <net/tcp.h>
++
++#include <xen/balloon.h>
++#include <xen/events.h>
++#include <xen/interface/memory.h>
++
++#include <asm/xen/hypercall.h>
++#include <asm/xen/page.h>
++
++/*define NETBE_DEBUG_INTERRUPT*/
++
++struct xen_netbk *xen_netbk;
++int xen_netbk_group_nr;
++
++static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
++static void make_tx_response(struct xen_netif *netif,
++ struct xen_netif_tx_request *txp,
++ s8 st);
++static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
++ u16 id,
++ s8 st,
++ u16 offset,
++ u16 size,
++ u16 flags);
++
++static void net_tx_action(unsigned long data);
++
++static void net_rx_action(unsigned long data);
++
++static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
++ unsigned int idx)
++{
++ return page_to_pfn(netbk->mmap_pages[idx]);
+}
+
-+static void connect(struct backend_info *be)
++static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
++ unsigned int idx)
+{
-+ int err;
-+ struct xenbus_device *dev = be->dev;
++ return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
++}
+
-+ err = connect_rings(be);
-+ if (err)
-+ return;
++/* extra field used in struct page */
++static inline void netif_set_page_ext(struct page *pg,
++ unsigned int group, unsigned int idx)
++{
++ union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
+
-+ err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
-+ return;
-+ }
++ BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
++ pg->mapping = ext.mapping;
++}
+
-+ xen_net_read_rate(dev, &be->netif->credit_bytes,
-+ &be->netif->credit_usec);
-+ be->netif->remaining_credit = be->netif->credit_bytes;
++static int netif_get_page_ext(struct page *pg,
++ unsigned int *_group, unsigned int *_idx)
++{
++ union page_ext ext = { .mapping = pg->mapping };
++ struct xen_netbk *netbk;
++ unsigned int group, idx;
+
-+ xenbus_switch_state(dev, XenbusStateConnected);
++ if (!PageForeign(pg))
++ return 0;
+
-+ netif_wake_queue(be->netif->dev);
++ group = ext.e.group - 1;
++
++ if (group < 0 || group >= xen_netbk_group_nr)
++ return 0;
++
++ netbk = &xen_netbk[group];
++
++ if (netbk->mmap_pages == NULL)
++ return 0;
++
++ idx = ext.e.idx;
++
++ if ((idx < 0) || (idx >= MAX_PENDING_REQS))
++ return 0;
++
++ if (netbk->mmap_pages[idx] != pg)
++ return 0;
++
++ *_group = group;
++ *_idx = idx;
++
++ return 1;
+}
+
++/*
++ * This is the amount of packet we copy rather than map, so that the
++ * guest can't fiddle with the contents of the headers while we do
++ * packet processing on them (netfilter, routing, etc).
++ */
++#define PKT_PROT_LEN (ETH_HLEN + \
++ VLAN_HLEN + \
++ sizeof(struct iphdr) + MAX_IPOPTLEN + \
++ sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
+
-+static int connect_rings(struct backend_info *be)
++static inline pending_ring_idx_t pending_index(unsigned i)
+{
-+ struct xenbus_device *dev = be->dev;
-+ unsigned long tx_ring_ref, rx_ring_ref;
-+ unsigned int evtchn, rx_copy;
-+ int err;
-+ int val;
++ return i & (MAX_PENDING_REQS-1);
++}
+
-+ DPRINTK("");
++static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk *netbk)
++{
++ return MAX_PENDING_REQS -
++ netbk->pending_prod + netbk->pending_cons;
++}
+
-+ err = xenbus_gather(XBT_NIL, dev->otherend,
-+ "tx-ring-ref", "%lu", &tx_ring_ref,
-+ "rx-ring-ref", "%lu", &rx_ring_ref,
-+ "event-channel", "%u", &evtchn, NULL);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err,
-+ "reading %s/ring-ref and event-channel",
-+ dev->otherend);
-+ return err;
-+ }
++/* Setting this allows the safe use of this driver without netloop. */
++static int MODPARM_copy_skb = 1;
++module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
++MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
+
-+ err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy",
"%u",
-+ &rx_copy);
-+ if (err == -ENOENT) {
-+ err = 0;
-+ rx_copy = 0;
-+ }
-+ if (err < 0) {
-+ xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
-+ dev->otherend);
-+ return err;
-+ }
-+ be->netif->copying_receiver = !!rx_copy;
++int netbk_copy_skb_mode;
+
-+ if (be->netif->dev->tx_queue_len != 0) {
-+ if (xenbus_scanf(XBT_NIL, dev->otherend,
-+ "feature-rx-notify", "%d", &val) < 0)
-+ val = 0;
-+ if (val)
-+ be->netif->can_queue = 1;
-+ else
-+ /* Must be non-zero for pfifo_fast to work. */
-+ be->netif->dev->tx_queue_len = 1;
-+ }
++static int MODPARM_netback_kthread;
++module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
++MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d",
&val) < 0)
-+ val = 0;
-+ if (val) {
-+ be->netif->features |= NETIF_F_SG;
-+ be->netif->dev->features |= NETIF_F_SG;
++/*
++ * Netback bottom half handler.
++ * dir indicates the data direction.
++ * rx: 1, tx: 0.
++ */
++static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
++{
++ if (MODPARM_netback_kthread)
++ wake_up(&netbk->kthread.netbk_action_wq);
++ else if (dir)
++ tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
++ else
++ tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
++}
++
++static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
++{
++ smp_mb();
++ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
++ !list_empty(&netbk->net_schedule_list))
++ xen_netbk_bh_handler(netbk, 0);
++}
++
++static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
++{
++ struct skb_shared_info *ninfo;
++ struct sk_buff *nskb;
++ unsigned long offset;
++ int ret;
++ int len;
++ int headlen;
++
++ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++
++ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(!nskb))
++ goto err;
++
++ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
++ headlen = skb_end_pointer(nskb) - nskb->data;
++ if (headlen > skb_headlen(skb))
++ headlen = skb_headlen(skb);
++ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
++ BUG_ON(ret);
++
++ ninfo = skb_shinfo(nskb);
++ ninfo->gso_size = skb_shinfo(skb)->gso_size;
++ ninfo->gso_type = skb_shinfo(skb)->gso_type;
++
++ offset = headlen;
++ len = skb->len - headlen;
++
++ nskb->len = skb->len;
++ nskb->data_len = len;
++ nskb->truesize += len;
++
++ while (len) {
++ struct page *page;
++ int copy;
++ int zero;
++
++ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
++ dump_stack();
++ goto err_free;
++ }
++
++ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
++ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
++ if (unlikely(!page))
++ goto err_free;
++
++ ret = skb_copy_bits(skb, offset, page_address(page), copy);
++ BUG_ON(ret);
++
++ ninfo->frags[ninfo->nr_frags].page = page;
++ ninfo->frags[ninfo->nr_frags].page_offset = 0;
++ ninfo->frags[ninfo->nr_frags].size = copy;
++ ninfo->nr_frags++;
++
++ offset += copy;
++ len -= copy;
+ }
+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
"%d",
-+ &val) < 0)
-+ val = 0;
-+ if (val) {
-+ be->netif->features |= NETIF_F_TSO;
-+ be->netif->dev->features |= NETIF_F_TSO;
++#ifdef NET_SKBUFF_DATA_USES_OFFSET
++ offset = 0;
++#else
++ offset = nskb->data - skb->data;
++#endif
++
++ nskb->transport_header = skb->transport_header + offset;
++ nskb->network_header = skb->network_header + offset;
++ nskb->mac_header = skb->mac_header + offset;
++
++ return nskb;
++
++ err_free:
++ kfree_skb(nskb);
++ err:
++ return NULL;
++}
++
++static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
++{
++ if (netif->can_sg || netif->gso || netif->gso_prefix)
++ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
++ return 1; /* all in one */
++}
++
++static inline int netbk_queue_full(struct xen_netif *netif)
++{
++ RING_IDX peek = netif->rx_req_cons_peek;
++ RING_IDX needed = netbk_max_required_rx_slots(netif);
++
++ return ((netif->rx.sring->req_prod - peek) < needed) ||
++ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
++}
++
++/*
++ * Returns true if we should start a new receive buffer instead of
++ * adding 'size' bytes to a buffer which currently contains 'offset'
++ * bytes.
++ */
++static bool start_new_rx_buffer(int offset, unsigned long size, int head)
++{
++ /* simple case: we have completely filled the current buffer. */
++ if (offset == MAX_BUFFER_OFFSET)
++ return true;
++
++ /*
++ * complex case: start a fresh buffer if the current frag
++ * would overflow the current buffer but only if:
++ * (i) this frag would fit completely in the next buffer
++ * and (ii) there is already some data in the current buffer
++ * and (iii) this is not the head buffer.
++ *
++ * Where:
++ * - (i) stops us splitting a frag into two copies
++ * unless the frag is too large for a single buffer.
++ * - (ii) stops us from leaving a buffer pointlessly empty.
++ * - (iii) stops us leaving the first buffer
++ * empty. Strictly speaking this is already covered
++ * by (ii) but is explicitly checked because
++ * netfront relies on the first buffer being
++ * non-empty and can crash otherwise.
++ *
++ * This means we will effectively linearise small
++ * frags but do not needlessly split large buffers
++ * into multiple copies tend to give large frags their
++ * own buffers as before.
++ */
++ if ((offset + size > MAX_BUFFER_OFFSET) &&
++ (size <= MAX_BUFFER_OFFSET) && offset && !head)
++ return true;
++
++ return false;
++}
++
++/*
++ * Figure out how many ring slots we're going to need to send @skb to
++ * the guest. This function is essentially a dry run of
++ * netbk_gop_frag_copy.
++ */
++static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
++{
++ unsigned int count = 1;
++ int i, copy_off = 0;
++
++ BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
++
++ copy_off = skb_headlen(skb);
++
++ if (skb_shinfo(skb)->gso_size)
++ count++;
++
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++ unsigned long size = skb_shinfo(skb)->frags[i].size;
++ unsigned long bytes;
++ while (size > 0) {
++ BUG_ON(copy_off > MAX_BUFFER_OFFSET);
++
++ if (start_new_rx_buffer(copy_off, size, 0)) {
++ count++;
++ copy_off = 0;
++ }
++
++ bytes = size;
++ if (copy_off + bytes > MAX_BUFFER_OFFSET)
++ bytes = MAX_BUFFER_OFFSET - copy_off;
++
++ copy_off += bytes;
++ size -= bytes;
++ }
+ }
++ return count;
++}
+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
-+ "%d", &val) < 0)
-+ val = 0;
-+ if (val) {
-+ be->netif->features &= ~NETIF_F_IP_CSUM;
-+ be->netif->dev->features &= ~NETIF_F_IP_CSUM;
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct xen_netif *netif = netdev_priv(dev);
++ struct xen_netbk *netbk;
++
++ BUG_ON(skb->dev != dev);
++
++ if (netif->group == -1)
++ goto drop;
++
++ netbk = &xen_netbk[netif->group];
++
++ /* Drop the packet if the target domain has no receive buffers. */
++ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
++ goto drop;
++
++ /*
++ * XXX For now we also copy skbuffs whose head crosses a page
++ * boundary, because netbk_gop_skb can't handle them.
++ */
++ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
++ struct sk_buff *nskb = netbk_copy_skb(skb);
++ if (unlikely(nskb == NULL))
++ goto drop;
++ /* Copy only the header fields we use in this driver. */
++ nskb->dev = skb->dev;
++ nskb->ip_summed = skb->ip_summed;
++ dev_kfree_skb(skb);
++ skb = nskb;
+ }
+
-+ /* Map the shared frame, irq etc. */
-+ err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err,
-+ "mapping shared-frames %lu/%lu port %u",
-+ tx_ring_ref, rx_ring_ref, evtchn);
-+ return err;
++ /* Reserve ring slots for the worst-case number of fragments. */
++ netif->rx_req_cons_peek += count_skb_slots(skb, netif);
++ netif_get(netif);
++
++ if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
++ netif->rx.sring->req_event = netif->rx_req_cons_peek +
++ netbk_max_required_rx_slots(netif);
++ mb(); /* request notification /then/ check & stop the queue */
++ if (netbk_queue_full(netif))
++ netif_stop_queue(dev);
+ }
-+ return 0;
-+}
++ skb_queue_tail(&netbk->rx_queue, skb);
+
++ xen_netbk_bh_handler(netbk, 1);
+
-+/* ** Driver Registration ** */
++ return 0;
+
++ drop:
++ netif->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 0;
++}
+
-+static const struct xenbus_device_id netback_ids[] = {
-+ { "vif" },
-+ { "" }
++struct netrx_pending_operations {
++ unsigned copy_prod, copy_cons;
++ unsigned meta_prod, meta_cons;
++ struct gnttab_copy *copy;
++ struct netbk_rx_meta *meta;
++ int copy_off;
++ grant_ref_t copy_gref;
+};
+
++static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
++ struct netrx_pending_operations *npo)
++{
++ struct netbk_rx_meta *meta;
++ struct xen_netif_rx_request *req;
+
-+static struct xenbus_driver netback = {
-+ .name = "vif",
-+ .owner = THIS_MODULE,
-+ .ids = netback_ids,
-+ .probe = netback_probe,
-+ .remove = netback_remove,
-+ .uevent = netback_uevent,
-+ .otherend_changed = frontend_changed,
-+};
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+
++ meta = npo->meta + npo->meta_prod++;
++ meta->gso_size = 0;
++ meta->size = 0;
++ meta->id = req->id;
+
-+void netif_xenbus_init(void)
-+{
-+ xenbus_register_backend(&netback);
++ npo->copy_off = 0;
++ npo->copy_gref = req->gref;
++
++ return meta;
+}
---
-1.7.4
-
-
-From 5b30803bf5f58ee980edd8d88a2d73dda995ee93 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Mon, 9 Feb 2009 12:05:52 -0800
-Subject: [PATCH 038/244] xen: netback: first cut at porting to upstream and cleaning up
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/Kconfig | 2 +-
- drivers/xen/netback/Makefile | 2 +-
- drivers/xen/netback/common.h | 33 +++---
- drivers/xen/netback/interface.c | 37 +++---
- drivers/xen/netback/netback.c | 248 ++++++++++++++++++++++++---------------
- drivers/xen/netback/xenbus.c | 25 ++--
- 6 files changed, 201 insertions(+), 146 deletions(-)
-
-diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
-index 7e83d43..30290a8 100644
---- a/drivers/xen/Kconfig
-+++ b/drivers/xen/Kconfig
-@@ -38,7 +38,7 @@ config XEN_BACKEND
- to other virtual machines.
-
- config XEN_NETDEV_BACKEND
-- bool "Xen backend network device"
-+ tristate "Xen backend network device"
- depends on XEN_BACKEND && NET
- help
- Implement the network backend driver, which passes packets
-diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
-index f4a0c51..a01a1a3 100644
---- a/drivers/xen/netback/Makefile
-+++ b/drivers/xen/netback/Makefile
-@@ -1,3 +1,3 @@
- obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
-
--netbk-y := netback.o xenbus.o interface.o
-+netbk-y := netback.o xenbus.o interface.o
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 9a54d57..65b88f4 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -43,8 +43,7 @@
- #include <asm/io.h>
- #include <asm/pgalloc.h>
- #include <xen/interface/grant_table.h>
--#include <xen/gnttab.h>
--#include <xen/driver_util.h>
-+#include <xen/grant_table.h>
- #include <xen/xenbus.h>
-
- #define DPRINTK(_f, _a...) \
-@@ -55,7 +54,7 @@
- #define WPRINTK(fmt, args...) \
- printk(KERN_WARNING "xen_net: " fmt, ##args)
-
--typedef struct netif_st {
-+struct xen_netif {
- /* Unique identifier for this interface. */
- domid_t domid;
- unsigned int handle;
-@@ -70,8 +69,8 @@ typedef struct netif_st {
- unsigned int irq;
-
- /* The shared rings and indexes. */
-- netif_tx_back_ring_t tx;
-- netif_rx_back_ring_t rx;
-+ struct xen_netif_tx_back_ring tx;
-+ struct xen_netif_rx_back_ring rx;
- struct vm_struct *tx_comms_area;
- struct vm_struct *rx_comms_area;
-
-@@ -103,7 +102,7 @@ typedef struct netif_st {
- unsigned int carrier;
-
- wait_queue_head_t waiting_to_free;
--} netif_t;
-+};
-
- /*
- * Implement our own carrier flag: the network stack's version causes delays
-@@ -141,7 +140,7 @@ struct netback_accelerator {
-
- struct backend_info {
- struct xenbus_device *dev;
-- netif_t *netif;
-+ struct xen_netif *netif;
- enum xenbus_state frontend_state;
-
- /* State relating to the netback accelerator */
-@@ -174,13 +173,13 @@ extern
- void netif_accel_init(void);
-
-
--#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
--#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
-+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
-+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-
--void netif_disconnect(netif_t *netif);
-+void netif_disconnect(struct xen_netif *netif);
-
--netif_t *netif_alloc(domid_t domid, unsigned int handle);
--int netif_map(netif_t *netif, unsigned long tx_ring_ref,
-+struct xen_netif *netif_alloc(domid_t domid, unsigned int handle);
-+int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-
- #define netif_get(_b) (atomic_inc(&(_b)->refcnt))
-@@ -195,22 +194,22 @@ void netif_xenbus_init(void);
- #define netif_schedulable(netif) \
- (netif_running((netif)->dev) && netback_carrier_ok(netif))
-
--void netif_schedule_work(netif_t *netif);
--void netif_deschedule_work(netif_t *netif);
-+void netif_schedule_work(struct xen_netif *netif);
-+void netif_deschedule_work(struct xen_netif *netif);
-
- int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
- struct net_device_stats *netif_be_get_stats(struct net_device *dev);
--irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
-+irqreturn_t netif_be_int(int irq, void *dev_id);
-
- static inline int netbk_can_queue(struct net_device *dev)
- {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
- return netif->can_queue;
- }
-
- static inline int netbk_can_sg(struct net_device *dev)
- {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
- return netif->features & NETIF_F_SG;
- }
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 7e67941..d184ad7 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -34,6 +34,9 @@
- #include <linux/ethtool.h>
- #include <linux/rtnetlink.h>
-
-+#include <xen/events.h>
-+#include <asm/xen/hypercall.h>
+
- /*
- * Module parameter 'queue_length':
- *
-@@ -51,13 +54,13 @@
- static unsigned long netbk_queue_length = 32;
- module_param_named(queue_length, netbk_queue_length, ulong, 0);
-
--static void __netif_up(netif_t *netif)
-+static void __netif_up(struct xen_netif *netif)
- {
- enable_irq(netif->irq);
- netif_schedule_work(netif);
- }
-
--static void __netif_down(netif_t *netif)
-+static void __netif_down(struct xen_netif *netif)
- {
- disable_irq(netif->irq);
- netif_deschedule_work(netif);
-@@ -65,7 +68,7 @@ static void __netif_down(netif_t *netif)
-
- static int net_open(struct net_device *dev)
- {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
- if (netback_carrier_ok(netif)) {
- __netif_up(netif);
- netif_start_queue(dev);
-@@ -75,7 +78,7 @@ static int net_open(struct net_device *dev)
-
- static int net_close(struct net_device *dev)
- {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
- if (netback_carrier_ok(netif))
- __netif_down(netif);
- netif_stop_queue(dev);
-@@ -95,7 +98,7 @@ static int netbk_change_mtu(struct net_device *dev, int mtu)
- static int netbk_set_sg(struct net_device *dev, u32 data)
- {
- if (data) {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
-
- if (!(netif->features & NETIF_F_SG))
- return -ENOSYS;
-@@ -107,7 +110,7 @@ static int netbk_set_sg(struct net_device *dev, u32 data)
- static int netbk_set_tso(struct net_device *dev, u32 data)
- {
- if (data) {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
-
- if (!(netif->features & NETIF_F_TSO))
- return -ENOSYS;
-@@ -127,15 +130,15 @@ static struct ethtool_ops network_ethtool_ops =
- .get_link = ethtool_op_get_link,
- };
-
--netif_t *netif_alloc(domid_t domid, unsigned int handle)
-+struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
- {
- int err = 0;
- struct net_device *dev;
-- netif_t *netif;
-+ struct xen_netif *netif;
- char name[IFNAMSIZ] = {};
-
- snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
-- dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
-+ dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
- if (dev == NULL) {
- DPRINTK("Could not create netif: out of memory\n");
- return ERR_PTR(-ENOMEM);
-@@ -194,7 +197,7 @@ netif_t *netif_alloc(domid_t domid, unsigned int handle)
- }
-
- static int map_frontend_pages(
-- netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
-+ struct xen_netif *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
- {
- struct gnttab_map_grant_ref op;
-
-@@ -229,7 +232,7 @@ static int map_frontend_pages(
- return 0;
- }
-
--static void unmap_frontend_pages(netif_t *netif)
-+static void unmap_frontend_pages(struct xen_netif *netif)
- {
- struct gnttab_unmap_grant_ref op;
-
-@@ -246,12 +249,12 @@ static void unmap_frontend_pages(netif_t *netif)
- BUG();
- }
-
--int netif_map(netif_t *netif, unsigned long tx_ring_ref,
-+int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn)
- {
- int err = -ENOMEM;
-- netif_tx_sring_t *txs;
-- netif_rx_sring_t *rxs;
-+ struct xen_netif_tx_sring *txs;
-+ struct xen_netif_rx_sring *rxs;
-
- /* Already connected through? */
- if (netif->irq)
-@@ -276,10 +279,10 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
- netif->irq = err;
- disable_irq(netif->irq);
-
-- txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
-+ txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
- BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
-
-- rxs = (netif_rx_sring_t *)
-+ rxs = (struct xen_netif_rx_sring *)
- ((char *)netif->rx_comms_area->addr);
- BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
-
-@@ -303,7 +306,7 @@ err_rx:
- return err;
- }
-
--void netif_disconnect(netif_t *netif)
-+void netif_disconnect(struct xen_netif *netif)
- {
- if (netback_carrier_ok(netif)) {
- rtnl_lock();
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index db629d4..c959075 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -35,9 +35,17 @@
- */
-
- #include "common.h"
++/*
++ * 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 netbk_gop_frag_copy(struct xen_netif *netif,
++ struct netrx_pending_operations *npo,
++ struct page *page, unsigned long size,
++ unsigned long offset, int head)
++{
++ struct gnttab_copy *copy_gop;
++ struct netbk_rx_meta *meta;
++ /*
++ * These variables a used iff netif_get_page_ext returns true,
++ * in which case they are guaranteed to be initialized.
++ */
++ unsigned int uninitialized_var(group), uninitialized_var(idx);
++ int foreign = netif_get_page_ext(page, &group, &idx);
++ unsigned long bytes;
+
-+#include <linux/tcp.h>
-+#include <linux/udp.h>
++ /* Data must not cross a page boundary. */
++ BUG_ON(size + offset > PAGE_SIZE);
+
- #include <xen/balloon.h>
-+#include <xen/events.h>
- #include <xen/interface/memory.h>
-
-+#include <asm/xen/hypercall.h>
-+#include <asm/xen/page.h>
++ meta = npo->meta + npo->meta_prod - 1;
+
- /*define NETBE_DEBUG_INTERRUPT*/
-
- struct netbk_rx_meta {
-@@ -51,11 +59,12 @@ struct netbk_tx_pending_inuse {
- unsigned long alloc_time;
- };
-
++ while (size > 0) {
++ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
+
- static void netif_idx_release(u16 pending_idx);
--static void make_tx_response(netif_t *netif,
-- netif_tx_request_t *txp,
-+static void make_tx_response(struct xen_netif *netif,
-+ struct xen_netif_tx_request *txp,
- s8 st);
--static netif_rx_response_t *make_rx_response(netif_t *netif,
-+static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
- u16 id,
- s8 st,
- u16 offset,
-@@ -108,8 +117,8 @@ static inline int netif_page_index(struct page *pg)
- #define PKT_PROT_LEN 64
-
- static struct pending_tx_info {
-- netif_tx_request_t req;
-- netif_t *netif;
-+ struct xen_netif_tx_request req;
-+ struct xen_netif *netif;
- } pending_tx_info[MAX_PENDING_REQS];
- static u16 pending_ring[MAX_PENDING_REQS];
- typedef unsigned int PEND_RING_IDX;
-@@ -128,8 +137,8 @@ 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 gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
-+static struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
-
- static struct list_head net_schedule_list;
- static spinlock_t net_schedule_list_lock;
-@@ -195,7 +204,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
- goto err;
-
- skb_reserve(nskb, 16 + NET_IP_ALIGN);
-- headlen = nskb->end - nskb->data;
-+ headlen = skb_end_pointer(nskb) - nskb->data;
- if (headlen > skb_headlen(skb))
- headlen = skb_headlen(skb);
- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-@@ -243,9 +252,9 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-
- offset = nskb->data - skb->data;
-
-- nskb->h.raw = skb->h.raw + offset;
-- nskb->nh.raw = skb->nh.raw + offset;
-- nskb->mac.raw = skb->mac.raw + offset;
-+ nskb->transport_header = skb->transport_header + offset;
-+ nskb->network_header = skb->network_header + offset;
-+ nskb->mac_header = skb->mac_header + offset;
-
- return nskb;
-
-@@ -255,14 +264,14 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
- return NULL;
- }
-
--static inline int netbk_max_required_rx_slots(netif_t *netif)
-+static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
- {
- if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
- return 1; /* all in one */
- }
-
--static inline int netbk_queue_full(netif_t *netif)
-+static inline int netbk_queue_full(struct xen_netif *netif)
- {
- RING_IDX peek = netif->rx_req_cons_peek;
- RING_IDX needed = netbk_max_required_rx_slots(netif);
-@@ -273,14 +282,14 @@ static inline int netbk_queue_full(netif_t *netif)
-
- static void tx_queue_callback(unsigned long data)
- {
-- netif_t *netif = (netif_t *)data;
-+ struct xen_netif *netif = (struct xen_netif *)data;
- if (netif_schedulable(netif))
- netif_wake_queue(netif->dev);
- }
-
- int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
-- netif_t *netif = netdev_priv(dev);
-+ struct xen_netif *netif = netdev_priv(dev);
-
- BUG_ON(skb->dev != dev);
-
-@@ -302,7 +311,6 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- /* Copy only the header fields we use in this driver. */
- nskb->dev = skb->dev;
- nskb->ip_summed = skb->ip_summed;
-- nskb->proto_data_valid = skb->proto_data_valid;
- dev_kfree_skb(skb);
- skb = nskb;
- }
-@@ -366,25 +374,25 @@ struct netrx_pending_operations {
- unsigned mcl_prod, mcl_cons;
- unsigned copy_prod, copy_cons;
- unsigned meta_prod, meta_cons;
-- mmu_update_t *mmu;
-- gnttab_transfer_t *trans;
-- gnttab_copy_t *copy;
-- multicall_entry_t *mcl;
-+ struct mmu_update *mmu;
-+ struct gnttab_transfer *trans;
-+ struct gnttab_copy *copy;
-+ struct multicall_entry *mcl;
- struct netbk_rx_meta *meta;
- };
-
- /* Set up the grant operations for this fragment. If it's a flipping
- interface, we also set up the unmap request from here. */
--static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
-+static u16 netbk_gop_frag(struct xen_netif *netif, struct netbk_rx_meta *meta,
- int i, struct netrx_pending_operations *npo,
- struct page *page, unsigned long size,
- unsigned long offset)
- {
-- mmu_update_t *mmu;
-- gnttab_transfer_t *gop;
-- gnttab_copy_t *copy_gop;
-- multicall_entry_t *mcl;
-- netif_rx_request_t *req;
-+ struct mmu_update *mmu;
-+ struct gnttab_transfer *gop;
-+ struct gnttab_copy *copy_gop;
-+ struct multicall_entry *mcl;
-+ struct xen_netif_rx_request *req;
- unsigned long old_mfn, new_mfn;
- int idx = netif_page_index(page);
-
-@@ -426,12 +434,12 @@ static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta
*meta,
- mcl = npo->mcl + npo->mcl_prod++;
- MULTI_update_va_mapping(mcl,
- (unsigned long)page_address(page),
-- pfn_pte_ma(new_mfn, PAGE_KERNEL),
-+ mfn_pte(new_mfn, PAGE_KERNEL),
- 0);
-
- mmu = npo->mmu + npo->mmu_prod++;
-- mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
-- MMU_MACHPHYS_UPDATE;
-+ mmu->ptr = ((phys_addr_t)new_mfn << PAGE_SHIFT) |
-+ MMU_MACHPHYS_UPDATE;
- mmu->val = page_to_pfn(page);
- }
-
-@@ -446,7 +454,7 @@ static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta
*meta,
- static void netbk_gop_skb(struct sk_buff *skb,
- struct netrx_pending_operations *npo)
- {
-- netif_t *netif = netdev_priv(skb->dev);
-+ struct xen_netif *netif = netdev_priv(skb->dev);
- int nr_frags = skb_shinfo(skb)->nr_frags;
- int i;
- int extra;
-@@ -494,9 +502,9 @@ static inline void netbk_free_pages(int nr_frags, struct
netbk_rx_meta *meta)
- static int netbk_check_gop(int nr_frags, domid_t domid,
- struct netrx_pending_operations *npo)
- {
-- multicall_entry_t *mcl;
-- gnttab_transfer_t *gop;
-- gnttab_copy_t *copy_op;
-+ struct multicall_entry *mcl;
-+ struct gnttab_transfer *gop;
-+ struct gnttab_copy *copy_op;
- int status = NETIF_RSP_OKAY;
- int i;
-
-@@ -534,7 +542,7 @@ static int netbk_check_gop(int nr_frags, domid_t domid,
- return status;
- }
-
--static void netbk_add_frag_responses(netif_t *netif, int status,
-+static void netbk_add_frag_responses(struct xen_netif *netif, int status,
- struct netbk_rx_meta *meta, int nr_frags)
- {
- int i;
-@@ -555,11 +563,11 @@ static void netbk_add_frag_responses(netif_t *netif, int status,
-
- static void net_rx_action(unsigned long unused)
- {
-- netif_t *netif = NULL;
++ if (start_new_rx_buffer(npo->copy_off, size, head)) {
++ /*
++ * Netfront requires there to be some data in the head
++ * buffer.
++ */
++ BUG_ON(head);
++
++ meta = get_next_rx_buffer(netif, npo);
++ }
++
++ bytes = size;
++ if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
++ bytes = MAX_BUFFER_OFFSET - npo->copy_off;
++
++ copy_gop = npo->copy + npo->copy_prod++;
++ copy_gop->flags = GNTCOPY_dest_gref;
++ if (foreign) {
++ struct xen_netbk *netbk = &xen_netbk[group];
++ struct pending_tx_info *src_pend;
++
++ src_pend = &netbk->pending_tx_info[idx];
++
++ copy_gop->source.domid = src_pend->netif->domid;
++ copy_gop->source.u.ref = src_pend->req.gref;
++ copy_gop->flags |= GNTCOPY_source_gref;
++ } else {
++ void *vaddr = page_address(page);
++ copy_gop->source.domid = DOMID_SELF;
++ copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
++ }
++ copy_gop->source.offset = offset;
++ copy_gop->dest.domid = netif->domid;
++
++ copy_gop->dest.offset = npo->copy_off;
++ copy_gop->dest.u.ref = npo->copy_gref;
++ copy_gop->len = bytes;
++
++ npo->copy_off += bytes;
++ meta->size += bytes;
++
++ offset += bytes;
++ size -= bytes;
++ head = 0; /* There must be something in this buffer now. */
++ }
++}
++
++/*
++ * Prepare an SKB to be transmitted to the frontend.
++ *
++ * This function is responsible for allocating grant operations, meta
++ * structures, etc.
++ *
++ * It returns the number of meta structures consumed. The number of
++ * ring slots used is always equal to the number of meta slots used
++ * plus the number of GSO descriptors used. Currently, we use either
++ * zero GSO descriptors (for non-GSO packets) or one descriptor (for
++ * frontend-side LRO).
++ */
++static int netbk_gop_skb(struct sk_buff *skb,
++ struct netrx_pending_operations *npo)
++{
++ struct xen_netif *netif = netdev_priv(skb->dev);
++ int nr_frags = skb_shinfo(skb)->nr_frags;
++ int i;
++ struct xen_netif_rx_request *req;
++ struct netbk_rx_meta *meta;
++ int old_meta_prod;
++
++ old_meta_prod = npo->meta_prod;
++
++ /* Set up a GSO prefix descriptor, if necessary */
++ if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
++ meta = npo->meta + npo->meta_prod++;
++ meta->gso_size = skb_shinfo(skb)->gso_size;
++ meta->size = 0;
++ meta->id = req->id;
++ }
++
++ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
++ meta = npo->meta + npo->meta_prod++;
++
++ if (!netif->gso_prefix)
++ meta->gso_size = skb_shinfo(skb)->gso_size;
++ else
++ meta->gso_size = 0;
++
++ meta->size = 0;
++ meta->id = req->id;
++ npo->copy_off = 0;
++ npo->copy_gref = req->gref;
++
++ netbk_gop_frag_copy(netif,
++ npo, virt_to_page(skb->data),
++ skb_headlen(skb),
++ offset_in_page(skb->data), 1);
++
++ /* Leave a gap for the GSO descriptor. */
++ if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
++ netif->rx.req_cons++;
++
++ for (i = 0; i < nr_frags; i++) {
++ netbk_gop_frag_copy(netif, npo,
++ skb_shinfo(skb)->frags[i].page,
++ skb_shinfo(skb)->frags[i].size,
++ skb_shinfo(skb)->frags[i].page_offset,
++ 0);
++ }
++
++ return npo->meta_prod - old_meta_prod;
++}
++
++/*
++ * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
++ * used to set up the operations on the top of
++ * netrx_pending_operations, which have since been done. Check that
++ * they didn't give any errors and advance over them.
++ */
++static int netbk_check_gop(int nr_meta_slots, domid_t domid,
++ struct netrx_pending_operations *npo)
++{
++ struct gnttab_copy *copy_op;
++ int status = NETIF_RSP_OKAY;
++ int i;
++
++ for (i = 0; i < nr_meta_slots; i++) {
++ copy_op = npo->copy + npo->copy_cons++;
++ if (copy_op->status != GNTST_okay) {
++ pr_debug("Bad status %d from copy to DOM%d.\n",
++ copy_op->status, domid);
++ status = NETIF_RSP_ERROR;
++ }
++ }
++
++ return status;
++}
++
++static void netbk_add_frag_responses(struct xen_netif *netif, int status,
++ struct netbk_rx_meta *meta,
++ int nr_meta_slots)
++{
++ int i;
++ unsigned long offset;
++
++ /* No fragments used */
++ if (nr_meta_slots <= 1)
++ return;
++
++ nr_meta_slots--;
++
++ for (i = 0; i < nr_meta_slots; i++) {
++ int flags;
++ if (i == nr_meta_slots - 1)
++ flags = 0;
++ else
++ flags = NETRXF_more_data;
++
++ offset = 0;
++ make_rx_response(netif, meta[i].id, status, offset,
++ meta[i].size, flags);
++ }
++}
++
++struct skb_cb_overlay {
++ int meta_slots_used;
++};
++
++static void net_rx_action(unsigned long data)
++{
+ struct xen_netif *netif = NULL;
- s8 status;
- u16 id, irq, flags;
-- netif_rx_response_t *resp;
-- multicall_entry_t *mcl;
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ s8 status;
++ u16 irq, flags;
+ struct xen_netif_rx_response *resp;
-+ struct multicall_entry *mcl;
- struct sk_buff_head rxq;
- struct sk_buff *skb;
- int notify_nr = 0;
-@@ -572,10 +580,10 @@ static void net_rx_action(unsigned long unused)
- * 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 struct multicall_entry rx_mcl[NET_RX_RING_SIZE+3];
-+ static struct mmu_update rx_mmu[NET_RX_RING_SIZE];
-+ static struct gnttab_transfer grant_trans_op[NET_RX_RING_SIZE];
-+ static struct gnttab_copy grant_copy_op[NET_RX_RING_SIZE];
- static unsigned char rx_notify[NR_IRQS];
- static u16 notify_list[NET_RX_RING_SIZE];
- static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
-@@ -596,7 +604,7 @@ static void net_rx_action(unsigned long unused)
- *(int *)skb->cb = nr_frags;
-
- if (!xen_feature(XENFEAT_auto_translated_physmap) &&
-- !((netif_t *)netdev_priv(skb->dev))->copying_receiver &&
-+ !((struct xen_netif *)netdev_priv(skb->dev))->copying_receiver &&
- check_mfn(nr_frags + 1)) {
- /* Memory squeeze? Back off for an arbitrary while. */
- if ( net_ratelimit() )
-@@ -692,9 +700,10 @@ static void net_rx_action(unsigned long unused)
- id = meta[npo.meta_cons].id;
- flags = nr_frags ? NETRXF_more_data : 0;
-
-- if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++ struct sk_buff_head rxq;
++ struct sk_buff *skb;
++ int notify_nr = 0;
++ int ret;
++ int nr_frags;
++ int count;
++ unsigned long offset;
++ struct skb_cb_overlay *sco;
++
++ struct netrx_pending_operations npo = {
++ .copy = netbk->grant_copy_op,
++ .meta = netbk->meta,
++ };
++
++ skb_queue_head_init(&rxq);
++
++ count = 0;
++
++ while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
++ netif = netdev_priv(skb->dev);
++ nr_frags = skb_shinfo(skb)->nr_frags;
++
++ sco = (struct skb_cb_overlay *)skb->cb;
++ sco->meta_slots_used = netbk_gop_skb(skb, &npo);
++
++ count += nr_frags + 1;
++
++ __skb_queue_tail(&rxq, skb);
++
++ /* Filled the batch queue? */
++ if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
++ break;
++ }
++
++ BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
++
++ if (!npo.copy_prod)
++ return;
++
++ BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
++ npo.copy_prod);
++ BUG_ON(ret != 0);
++
++ while ((skb = __skb_dequeue(&rxq)) != NULL) {
++ sco = (struct skb_cb_overlay *)skb->cb;
++
++ netif = netdev_priv(skb->dev);
++
++ if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
++ resp = RING_GET_RESPONSE(&netif->rx,
++ netif->rx.rsp_prod_pvt++);
++
++ resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
++
++ resp->offset = netbk->meta[npo.meta_cons].gso_size;
++ resp->id = netbk->meta[npo.meta_cons].id;
++ resp->status = sco->meta_slots_used;
++
++ npo.meta_cons++;
++ sco->meta_slots_used--;
++ }
++
++
++ netif->stats.tx_bytes += skb->len;
++ netif->stats.tx_packets++;
++
++ status = netbk_check_gop(sco->meta_slots_used,
++ netif->domid, &npo);
++
++ if (sco->meta_slots_used == 1)
++ flags = 0;
++ else
++ flags = NETRXF_more_data;
++
+ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
- flags |= NETRXF_csum_blank | NETRXF_data_validated;
-- else if (skb->proto_data_valid) /* remote but checksummed? */
++ flags |= NETRXF_csum_blank | NETRXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed. */
- flags |= NETRXF_data_validated;
-
- if (meta[npo.meta_cons].copy)
-@@ -705,8 +714,8 @@ static void net_rx_action(unsigned long unused)
- skb_headlen(skb), flags);
-
- if (meta[npo.meta_cons].frag.size) {
-- struct netif_extra_info *gso =
-- (struct netif_extra_info *)
++ flags |= NETRXF_data_validated;
++
++ offset = 0;
++ resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
++ status, offset,
++ netbk->meta[npo.meta_cons].size,
++ flags);
++
++ if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
+ struct xen_netif_extra_info *gso =
+ (struct xen_netif_extra_info *)
- RING_GET_RESPONSE(&netif->rx,
- netif->rx.rsp_prod_pvt++);
-
-@@ -769,16 +778,16 @@ static void netbk_tx_pending_timeout(unsigned long unused)
-
- struct net_device_stats *netif_be_get_stats(struct net_device *dev)
- {
-- netif_t *netif = netdev_priv(dev);
++ RING_GET_RESPONSE(&netif->rx,
++ netif->rx.rsp_prod_pvt++);
++
++ resp->flags |= NETRXF_extra_info;
++
++ gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
++ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
++ gso->u.gso.pad = 0;
++ gso->u.gso.features = 0;
++
++ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
++ gso->flags = 0;
++ }
++
++ netbk_add_frag_responses(netif, status,
++ netbk->meta + npo.meta_cons + 1,
++ sco->meta_slots_used);
++
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
++ irq = netif->irq;
++ if (ret && !netbk->rx_notify[irq]) {
++ netbk->rx_notify[irq] = 1;
++ netbk->notify_list[notify_nr++] = irq;
++ }
++
++ if (netif_queue_stopped(netif->dev) &&
++ netif_schedulable(netif) &&
++ !netbk_queue_full(netif))
++ netif_wake_queue(netif->dev);
++
++ netif_put(netif);
++ npo.meta_cons += sco->meta_slots_used;
++ dev_kfree_skb(skb);
++ }
++
++ while (notify_nr != 0) {
++ irq = netbk->notify_list[--notify_nr];
++ netbk->rx_notify[irq] = 0;
++ notify_remote_via_irq(irq);
++ }
++
++ /* More work to do? */
++ if (!skb_queue_empty(&netbk->rx_queue) &&
++ !timer_pending(&netbk->net_timer))
++ xen_netbk_bh_handler(netbk, 1);
++}
++
++static void net_alarm(unsigned long data)
++{
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ xen_netbk_bh_handler(netbk, 1);
++}
++
++static void netbk_tx_pending_timeout(unsigned long data)
++{
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ xen_netbk_bh_handler(netbk, 0);
++}
++
++struct net_device_stats *netif_be_get_stats(struct net_device *dev)
++{
+ struct xen_netif *netif = netdev_priv(dev);
- return &netif->stats;
- }
-
--static int __on_net_schedule_list(netif_t *netif)
++ return &netif->stats;
++}
++
+static int __on_net_schedule_list(struct xen_netif *netif)
- {
- return netif->list.next != NULL;
- }
-
--static void remove_from_net_schedule_list(netif_t *netif)
++{
++ return !list_empty(&netif->list);
++}
++
++/* Must be called with net_schedule_list_lock held */
+static void remove_from_net_schedule_list(struct xen_netif *netif)
- {
- spin_lock_irq(&net_schedule_list_lock);
- if (likely(__on_net_schedule_list(netif))) {
-@@ -789,7 +798,7 @@ static void remove_from_net_schedule_list(netif_t *netif)
- spin_unlock_irq(&net_schedule_list_lock);
- }
-
--static void add_to_net_schedule_list_tail(netif_t *netif)
++{
++ if (likely(__on_net_schedule_list(netif))) {
++ list_del_init(&netif->list);
++ netif_put(netif);
++ }
++}
++
++static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
++{
++ struct xen_netif *netif = NULL;
++
++ spin_lock_irq(&netbk->net_schedule_list_lock);
++ if (list_empty(&netbk->net_schedule_list))
++ goto out;
++
++ netif = list_first_entry(&netbk->net_schedule_list,
++ struct xen_netif, list);
++ if (!netif)
++ goto out;
++
++ netif_get(netif);
++
++ remove_from_net_schedule_list(netif);
++out:
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
++ return netif;
++}
++
+static void add_to_net_schedule_list_tail(struct xen_netif *netif)
- {
- if (__on_net_schedule_list(netif))
- return;
-@@ -811,7 +820,7 @@ static void add_to_net_schedule_list_tail(netif_t *netif)
- * If we may be buffer transmit buffers for any reason then we must be rather
- * more conservative and treat this as the final check for pending work.
- */
--void netif_schedule_work(netif_t *netif)
++{
++ unsigned long flags;
++
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
++ if (__on_net_schedule_list(netif))
++ return;
++
++ spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
++ if (!__on_net_schedule_list(netif) &&
++ likely(netif_schedulable(netif))) {
++ list_add_tail(&netif->list, &netbk->net_schedule_list);
++ netif_get(netif);
++ }
++ spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
++}
++
+void netif_schedule_work(struct xen_netif *netif)
- {
- int more_to_do;
-
-@@ -827,13 +836,13 @@ void netif_schedule_work(netif_t *netif)
- }
- }
-
--void netif_deschedule_work(netif_t *netif)
++{
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
++ int more_to_do;
++
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++
++ if (more_to_do) {
++ add_to_net_schedule_list_tail(netif);
++ maybe_schedule_tx_action(netbk);
++ }
++}
++
+void netif_deschedule_work(struct xen_netif *netif)
- {
- remove_from_net_schedule_list(netif);
- }
-
-
--static void tx_add_credit(netif_t *netif)
++{
++ struct xen_netbk *netbk = &xen_netbk[netif->group];
++ spin_lock_irq(&netbk->net_schedule_list_lock);
++ remove_from_net_schedule_list(netif);
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
++}
++
++
+static void tx_add_credit(struct xen_netif *netif)
- {
- unsigned long max_burst, max_credit;
-
-@@ -855,7 +864,7 @@ static void tx_add_credit(netif_t *netif)
-
- static void tx_credit_callback(unsigned long data)
- {
-- netif_t *netif = (netif_t *)data;
-+ struct xen_netif *netif = (struct xen_netif *)data;
- tx_add_credit(netif);
- netif_schedule_work(netif);
- }
-@@ -869,10 +878,10 @@ static inline int copy_pending_req(PEND_RING_IDX pending_idx)
- inline static void net_tx_action_dealloc(void)
- {
- struct netbk_tx_pending_inuse *inuse, *n;
-- gnttab_unmap_grant_ref_t *gop;
-+ struct gnttab_unmap_grant_ref *gop;
- u16 pending_idx;
- PEND_RING_IDX dc, dp;
-- netif_t *netif;
-+ struct xen_netif *netif;
- int ret;
- LIST_HEAD(list);
-
-@@ -954,7 +963,7 @@ inline static void net_tx_action_dealloc(void)
- }
- }
-
--static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
-+static void netbk_tx_err(struct xen_netif *netif, struct xen_netif_tx_request *txp,
RING_IDX end)
- {
- RING_IDX cons = netif->tx.req_cons;
-
-@@ -969,8 +978,8 @@ static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp,
RING_IDX end)
- netif_put(netif);
- }
-
--static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
-- netif_tx_request_t *txp, int work_to_do)
-+static int netbk_count_requests(struct xen_netif *netif, struct xen_netif_tx_request
*first,
-+ struct xen_netif_tx_request *txp, int work_to_do)
- {
- RING_IDX cons = netif->tx.req_cons;
- int frags = 0;
-@@ -1009,10 +1018,10 @@ static int netbk_count_requests(netif_t *netif,
netif_tx_request_t *first,
- return frags;
- }
-
--static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
-+static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
- struct sk_buff *skb,
-- netif_tx_request_t *txp,
-- gnttab_map_grant_ref_t *mop)
-+ struct xen_netif_tx_request *txp,
-+ struct gnttab_map_grant_ref *mop)
- {
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- skb_frag_t *frags = shinfo->frags;
-@@ -1039,12 +1048,12 @@ static gnttab_map_grant_ref_t *netbk_get_requests(netif_t
*netif,
- }
-
- static int netbk_tx_check_mop(struct sk_buff *skb,
-- gnttab_map_grant_ref_t **mopp)
-+ struct gnttab_map_grant_ref **mopp)
- {
-- gnttab_map_grant_ref_t *mop = *mopp;
++{
++ unsigned long max_burst, max_credit;
++
++ /*
++ * 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(&netif->tx, netif->tx.req_cons)->size;
++ max_burst = min(max_burst, 131072UL);
++ max_burst = max(max_burst, netif->credit_bytes);
++
++ /* Take care that adding a new chunk of credit doesn't wrap to zero. */
++ max_credit = netif->remaining_credit + netif->credit_bytes;
++ if (max_credit < netif->remaining_credit)
++ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
++
++ netif->remaining_credit = min(max_credit, max_burst);
++}
++
++static void tx_credit_callback(unsigned long data)
++{
++ struct xen_netif *netif = (struct xen_netif *)data;
++ tx_add_credit(netif);
++ netif_schedule_work(netif);
++}
++
++static inline int copy_pending_req(struct xen_netbk *netbk,
++ pending_ring_idx_t pending_idx)
++{
++ return gnttab_copy_grant_page(
++ netbk->grant_tx_handle[pending_idx],
++ &netbk->mmap_pages[pending_idx]);
++}
++
++static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
++{
++ struct netbk_tx_pending_inuse *inuse, *n;
++ struct gnttab_unmap_grant_ref *gop;
++ u16 pending_idx;
++ pending_ring_idx_t dc, dp;
++ struct xen_netif *netif;
++ int ret;
++ LIST_HEAD(list);
++
++ dc = netbk->dealloc_cons;
++ gop = netbk->tx_unmap_ops;
++
++ /* Free up any grants we have finished using. */
++ do {
++ dp = netbk->dealloc_prod;
++
++ /* Ensure we see all indices enqueued by netif_idx_release(). */
++ smp_rmb();
++
++ while (dc != dp) {
++ unsigned long pfn;
++ struct netbk_tx_pending_inuse *pending_inuse =
++ netbk->pending_inuse;
++
++ pending_idx = netbk->dealloc_ring[pending_index(dc++)];
++ list_move_tail(&pending_inuse[pending_idx].list, &list);
++
++ 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(netbk, pending_idx),
++ GNTMAP_host_map,
++ netbk->grant_tx_handle[pending_idx]);
++ gop++;
++ }
++
++ } while (dp != netbk->dealloc_prod);
++
++ netbk->dealloc_cons = dc;
++
++ ret = HYPERVISOR_grant_table_op(
++ GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
++ gop - netbk->tx_unmap_ops);
++ BUG_ON(ret);
++
++ /*
++ * Copy any entries that have been pending for too long
++ */
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !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;
++ pending_tx_info = netbk->pending_tx_info;
++
++ if (time_after(inuse->alloc_time + HZ / 2, jiffies))
++ break;
++
++ pending_idx = inuse - netbk->pending_inuse;
++
++ pending_tx_info[pending_idx].netif->nr_copied_skbs++;
++
++ switch (copy_pending_req(netbk, pending_idx)) {
++ case 0:
++ list_move_tail(&inuse->list, &list);
++ continue;
++ case -EBUSY:
++ list_del_init(&inuse->list);
++ continue;
++ case -ENOENT:
++ continue;
++ }
++
++ break;
++ }
++ }
++
++ list_for_each_entry_safe(inuse, n, &list, list) {
++ struct pending_tx_info *pending_tx_info;
++ pending_ring_idx_t index;
++
++ 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(netbk->mmap_pages[pending_idx]);
++
++ index = pending_index(netbk->pending_prod++);
++ netbk->pending_ring[index] = pending_idx;
++
++ netif_put(netif);
++
++ list_del_init(&inuse->list);
++ }
++}
++
++static void netbk_tx_err(struct xen_netif *netif,
++ struct xen_netif_tx_request *txp, RING_IDX end)
++{
++ RING_IDX cons = netif->tx.req_cons;
++
++ do {
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ if (cons >= end)
++ break;
++ txp = RING_GET_REQUEST(&netif->tx, cons++);
++ } while (1);
++ netif->tx.req_cons = cons;
++ netif_schedule_work(netif);
++ netif_put(netif);
++}
++
++static int netbk_count_requests(struct xen_netif *netif,
++ struct xen_netif_tx_request *first,
++ struct xen_netif_tx_request *txp,
++ int work_to_do)
++{
++ RING_IDX cons = netif->tx.req_cons;
++ int frags = 0;
++
++ if (!(first->flags & NETTXF_more_data))
++ return 0;
++
++ do {
++ if (frags >= work_to_do) {
++ pr_debug("Need more frags\n");
++ return -frags;
++ }
++
++ if (unlikely(frags >= MAX_SKB_FRAGS)) {
++ pr_debug("Too many frags\n");
++ return -frags;
++ }
++
++ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
++ sizeof(*txp));
++ if (txp->size > first->size) {
++ pr_debug("Frags galore\n");
++ return -frags;
++ }
++
++ first->size -= txp->size;
++ frags++;
++
++ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
++ pr_debug("txp->offset: %x, size: %u\n",
++ txp->offset, txp->size);
++ return -frags;
++ }
++ } while ((txp++)->flags & NETTXF_more_data);
++
++ return frags;
++}
++
++static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
++ struct xen_netif *netif,
++ struct sk_buff *skb,
++ struct xen_netif_tx_request *txp,
++ struct gnttab_map_grant_ref *mop)
++{
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ skb_frag_t *frags = shinfo->frags;
++ unsigned long pending_idx = *((u16 *)skb->data);
++ int i, start;
++
++ /* Skip first skb fragment if it is on same page as header fragment. */
++ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++
++ for (i = start; i < shinfo->nr_frags; i++, txp++) {
++ pending_ring_idx_t index;
++ struct pending_tx_info *pending_tx_info =
++ netbk->pending_tx_info;
++
++ index = pending_index(netbk->pending_cons++);
++ 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);
++
++ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
++ netif_get(netif);
++ pending_tx_info[pending_idx].netif = netif;
++ frags[i].page = (void *)pending_idx;
++ }
++
++ return mop;
++}
++
++static int netbk_tx_check_mop(struct xen_netbk *netbk,
++ struct sk_buff *skb,
++ struct gnttab_map_grant_ref **mopp)
++{
+ struct gnttab_map_grant_ref *mop = *mopp;
- int pending_idx = *((u16 *)skb->data);
-- netif_t *netif = pending_tx_info[pending_idx].netif;
-- netif_tx_request_t *txp;
++ int pending_idx = *((u16 *)skb->data);
++ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
+ struct xen_netif *netif = pending_tx_info[pending_idx].netif;
+ struct xen_netif_tx_request *txp;
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- int nr_frags = shinfo->nr_frags;
- int i, err, start;
-@@ -1118,7 +1127,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
-
- for (i = 0; i < nr_frags; i++) {
- skb_frag_t *frag = shinfo->frags + i;
-- netif_tx_request_t *txp;
++ struct skb_shared_info *shinfo = skb_shinfo(skb);
++ int nr_frags = shinfo->nr_frags;
++ int i, err, start;
++
++ /* Check status of header. */
++ err = mop->status;
++ if (unlikely(err)) {
++ pending_ring_idx_t index;
++ index = pending_index(netbk->pending_prod++);
++ txp = &pending_tx_info[pending_idx].req;
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ netbk->pending_ring[index] = pending_idx;
++ netif_put(netif);
++ } else {
++ set_phys_to_machine(
++ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
++ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
++ netbk->grant_tx_handle[pending_idx] = mop->handle;
++ }
++
++ /* Skip first skb fragment if it is on same page as header fragment. */
++ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++
++ 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)) {
++ unsigned long addr;
++ addr = idx_to_kaddr(netbk, pending_idx);
++ set_phys_to_machine(
++ __pa(addr)>>PAGE_SHIFT,
++ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
++ netbk->grant_tx_handle[pending_idx] = mop->handle;
++ /* Had a previous error? Invalidate this fragment. */
++ if (unlikely(err))
++ netif_idx_release(netbk, pending_idx);
++ continue;
++ }
++
++ /* Error on this fragment: respond to client with an error. */
++ txp = &netbk->pending_tx_info[pending_idx].req;
++ make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ index = pending_index(netbk->pending_prod++);
++ netbk->pending_ring[index] = pending_idx;
++ netif_put(netif);
++
++ /* Not the first error? Preceding frags already invalidated. */
++ if (err)
++ continue;
++
++ /* First error: invalidate header and preceding fragments. */
++ pending_idx = *((u16 *)skb->data);
++ netif_idx_release(netbk, pending_idx);
++ for (j = start; j < i; j++) {
++ pending_idx = (unsigned long)shinfo->frags[i].page;
++ netif_idx_release(netbk, pending_idx);
++ }
++
++ /* Remember the error: invalidate all subsequent fragments. */
++ err = newerr;
++ }
++
++ *mopp = mop + 1;
++ return err;
++}
++
++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;
++ int i;
++
++ for (i = 0; i < nr_frags; i++) {
++ skb_frag_t *frag = shinfo->frags + i;
+ struct xen_netif_tx_request *txp;
- unsigned long pending_idx;
-
- pending_idx = (unsigned long)frag->page;
-@@ -1138,10 +1147,10 @@ static void netbk_fill_frags(struct sk_buff *skb)
- }
- }
-
--int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
-+int netbk_get_extras(struct xen_netif *netif, struct xen_netif_extra_info *extras,
- int work_to_do)
- {
-- struct netif_extra_info extra;
++ unsigned long pending_idx;
++
++ pending_idx = (unsigned long)frag->page;
++
++ netbk->pending_inuse[pending_idx].alloc_time = jiffies;
++ list_add_tail(&netbk->pending_inuse[pending_idx].list,
++ &netbk->pending_inuse_head);
++
++ txp = &netbk->pending_tx_info[pending_idx].req;
++ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
++ frag->size = txp->size;
++ frag->page_offset = txp->offset;
++
++ skb->len += txp->size;
++ skb->data_len += txp->size;
++ skb->truesize += txp->size;
++ }
++}
++
++int netbk_get_extras(struct xen_netif *netif,
++ struct xen_netif_extra_info *extras,
++ int work_to_do)
++{
+ struct xen_netif_extra_info extra;
- RING_IDX cons = netif->tx.req_cons;
-
- do {
-@@ -1166,7 +1175,7 @@ int netbk_get_extras(netif_t *netif, struct netif_extra_info
*extras,
- return work_to_do;
- }
-
--static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
-+static int netbk_set_skb_gso(struct sk_buff *skb, struct xen_netif_extra_info *gso)
- {
- if (!gso->u.gso.size) {
- DPRINTK("GSO size must not be zero.\n");
-@@ -1189,18 +1198,57 @@ static int netbk_set_skb_gso(struct sk_buff *skb, struct
netif_extra_info *gso)
- return 0;
- }
-
-+static int skb_checksum_setup(struct sk_buff *skb)
++ RING_IDX cons = netif->tx.req_cons;
++
++ do {
++ if (unlikely(work_to_do-- <= 0)) {
++ pr_debug("Missing extra info\n");
++ return -EBADR;
++ }
++
++ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
++ sizeof(extra));
++ if (unlikely(!extra.type ||
++ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++ netif->tx.req_cons = ++cons;
++ pr_debug("Invalid extra type: %d\n", extra.type);
++ return -EINVAL;
++ }
++
++ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
++ netif->tx.req_cons = ++cons;
++ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
++
++ return work_to_do;
++}
++
++static int netbk_set_skb_gso(struct sk_buff *skb,
++ struct xen_netif_extra_info *gso)
++{
++ if (!gso->u.gso.size) {
++ pr_debug("GSO size must not be zero.\n");
++ return -EINVAL;
++ }
++
++ /* Currently only TCPv4 S.O. is supported. */
++ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
++ pr_debug("Bad GSO type %d.\n", gso->u.gso.type);
++ return -EINVAL;
++ }
++
++ skb_shinfo(skb)->gso_size = gso->u.gso.size;
++ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++
++ /* Header must be checked, and gso_segs computed. */
++ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++ skb_shinfo(skb)->gso_segs = 0;
++
++ return 0;
++}
++
++static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ unsigned char *th;
+ int err = -EPROTO;
++ int recalculate_partial_csum = 0;
++
++ /*
++ * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
++ * peers can fail to set NETRXF_csum_blank when sending a GSO
++ * frame. In this case force the SKB to CHECKSUM_PARTIAL and
++ * recalculate the partial checksum.
++ */
++ if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
++ netif->rx_gso_checksum_fixup++;
++ skb->ip_summed = CHECKSUM_PARTIAL;
++ recalculate_partial_csum = 1;
++ }
++
++ /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
++ if (skb->ip_summed != CHECKSUM_PARTIAL)
++ return 0;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
@@ -12599,9 +14566,23 @@ index db629d4..c959075 100644
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ skb->csum_offset = offsetof(struct tcphdr, check);
++
++ if (recalculate_partial_csum) {
++ struct tcphdr *tcph = (struct tcphdr *)th;
++ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
++ skb->len - iph->ihl*4,
++ IPPROTO_TCP, 0);
++ }
+ break;
+ case IPPROTO_UDP:
+ skb->csum_offset = offsetof(struct udphdr, check);
++
++ if (recalculate_partial_csum) {
++ struct udphdr *udph = (struct udphdr *)th;
++ udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
++ skb->len - iph->ihl*4,
++ IPPROTO_UDP, 0);
++ }
+ break;
+ default:
+ if (net_ratelimit())
@@ -12620,2428 +14601,958 @@ index db629d4..c959075 100644
+ return err;
+}
+
- /* Called after netfront has transmitted */
- static void net_tx_action(unsigned long unused)
- {
- struct list_head *ent;
- struct sk_buff *skb;
-- netif_t *netif;
-- netif_tx_request_t txreq;
-- netif_tx_request_t txfrags[MAX_SKB_FRAGS];
-- struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-+ struct xen_netif *netif;
-+ struct xen_netif_tx_request txreq;
-+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
- u16 pending_idx;
- RING_IDX i;
-- gnttab_map_grant_ref_t *mop;
-+ struct gnttab_map_grant_ref *mop;
- unsigned int data_len;
- int ret, work_to_do;
-
-@@ -1212,7 +1260,7 @@ static void net_tx_action(unsigned long unused)
- !list_empty(&net_schedule_list)) {
- /* Get a netif from the list with work to do. */
- ent = net_schedule_list.next;
-- netif = list_entry(ent, netif_t, list);
-+ netif = list_entry(ent, struct xen_netif, list);
- netif_get(netif);
- remove_from_net_schedule_list(netif);
-
-@@ -1313,7 +1361,7 @@ static void net_tx_action(unsigned long unused)
- skb_reserve(skb, 16 + NET_IP_ALIGN);
-
- if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
-- struct netif_extra_info *gso;
-+ struct xen_netif_extra_info *gso;
- gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
-
- if (netbk_set_skb_gso(skb, gso)) {
-@@ -1372,7 +1420,7 @@ static void net_tx_action(unsigned long unused)
-
- mop = tx_map_ops;
- while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
-- netif_tx_request_t *txp;
-+ struct xen_netif_tx_request *txp;
-
- pending_idx = *((u16 *)skb->data);
- netif = pending_tx_info[pending_idx].netif;
-@@ -1403,14 +1451,10 @@ static void net_tx_action(unsigned long unused)
- * Old frontends do not assert data_validated but we
- * can infer it from csum_blank so test both flags.
- */
-- if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
-- skb->ip_summed = CHECKSUM_UNNECESSARY;
-- skb->proto_data_valid = 1;
-- } else {
-+ if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank))
-+ skb->ip_summed = CHECKSUM_PARTIAL;
-+ else
- skb->ip_summed = CHECKSUM_NONE;
-- skb->proto_data_valid = 0;
-- }
-- skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
-
- netbk_fill_frags(skb);
-
-@@ -1420,6 +1464,14 @@ static void net_tx_action(unsigned long unused)
- netif->stats.rx_bytes += skb->len;
- netif->stats.rx_packets++;
-
-+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
-+ if (skb_checksum_setup(skb)) {
-+ DPRINTK("Can't setup checksum in net_tx_action\n");
-+ kfree_skb(skb);
-+ continue;
-+ }
-+ }
-+
- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
- unlikely(skb_linearize(skb))) {
- DPRINTK("Can't linearize skb in net_tx_action.\n");
-@@ -1464,9 +1516,9 @@ static void netif_page_release(struct page *page, unsigned int
order)
- netif_idx_release(idx);
- }
-
--irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
-+irqreturn_t netif_be_int(int irq, void *dev_id)
- {
-- netif_t *netif = dev_id;
-+ struct xen_netif *netif = dev_id;
-
- add_to_net_schedule_list_tail(netif);
- maybe_schedule_tx_action();
-@@ -1477,12 +1529,12 @@ irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs
*regs)
- return IRQ_HANDLED;
- }
-
--static void make_tx_response(netif_t *netif,
-- netif_tx_request_t *txp,
-+static void make_tx_response(struct xen_netif *netif,
-+ struct xen_netif_tx_request *txp,
- s8 st)
- {
- RING_IDX i = netif->tx.rsp_prod_pvt;
-- netif_tx_response_t *resp;
-+ struct xen_netif_tx_response *resp;
- int notify;
-
- resp = RING_GET_RESPONSE(&netif->tx, i);
-@@ -1507,7 +1559,7 @@ static void make_tx_response(netif_t *netif,
- #endif
- }
-
--static netif_rx_response_t *make_rx_response(netif_t *netif,
-+static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
- u16 id,
- s8 st,
- u16 offset,
-@@ -1515,7 +1567,7 @@ static netif_rx_response_t *make_rx_response(netif_t *netif,
- u16 flags)
- {
- RING_IDX i = netif->rx.rsp_prod_pvt;
-- netif_rx_response_t *resp;
-+ struct xen_netif_rx_response *resp;
-
- resp = RING_GET_RESPONSE(&netif->rx, i);
- resp->offset = offset;
-@@ -1534,14 +1586,14 @@ static netif_rx_response_t *make_rx_response(netif_t *netif,
- static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
- {
- struct list_head *ent;
-- netif_t *netif;
-+ struct xen_netif *netif;
- int i = 0;
-
- printk(KERN_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);
-+ netif = list_entry(ent, struct xen_netif, list);
- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
- "rx_resp_prod=%08x\n",
- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-@@ -1569,11 +1621,13 @@ static int __init netback_init(void)
- int i;
- struct page *page;
-
-- if (!is_running_on_xen())
-+ printk(KERN_CRIT "*** netif_init\n");
++static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
++{
++ unsigned long now = jiffies;
++ unsigned long next_credit =
++ netif->credit_timeout.expires +
++ msecs_to_jiffies(netif->credit_usec / 1000);
+
-+ if (!xen_domain())
- return -ENODEV;
-
- /* We can increase reservation by this much in net_rx_action(). */
-- balloon_update_driver_allowance(NET_RX_RING_SIZE);
-+// balloon_update_driver_allowance(NET_RX_RING_SIZE);
-
- skb_queue_head_init(&rx_queue);
- skb_queue_head_init(&tx_queue);
-@@ -1616,7 +1670,7 @@ static int __init netback_init(void)
- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
- }
-
-- netif_accel_init();
-+ //netif_accel_init();
-
- netif_xenbus_init();
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index d7faeb6..ed7c006 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -37,7 +37,7 @@ static int netback_remove(struct xenbus_device *dev)
- {
- struct backend_info *be = dev->dev.driver_data;
-
-- netback_remove_accelerators(be, dev);
-+ //netback_remove_accelerators(be, dev);
-
- if (be->netif) {
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-@@ -123,7 +123,7 @@ static int netback_probe(struct xenbus_device *dev,
- goto fail;
- }
-
-- netback_probe_accelerators(be, dev);
-+ //netback_probe_accelerators(be, dev);
-
- err = xenbus_switch_state(dev, XenbusStateInitWait);
- if (err)
-@@ -149,12 +149,10 @@ fail:
- * and vif variables to the environment, for the benefit of the vif-* hotplug
- * scripts.
- */
--static int netback_uevent(struct xenbus_device *xdev, char **envp,
-- int num_envp, char *buffer, int buffer_size)
-+static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
- {
- struct backend_info *be = xdev->dev.driver_data;
-- netif_t *netif = be->netif;
-- int i = 0, length = 0;
-+ struct xen_netif *netif = be->netif;
- char *val;
-
- DPRINTK("netback_uevent");
-@@ -166,15 +164,15 @@ static int netback_uevent(struct xenbus_device *xdev, char **envp,
- return err;
- }
- else {
-- add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-- &length, "script=%s", val);
-+ if (add_uevent_var(env, "script=%s", val)) {
-+ kfree(val);
-+ return -ENOMEM;
-+ }
- kfree(val);
- }
-
-- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-- "vif=%s", netif->dev->name);
--
-- envp[i] = NULL;
-+ if (add_uevent_var(env, "vif=%s", netif->dev->name))
-+ return -ENOMEM;
-
- return 0;
- }
-@@ -450,5 +448,6 @@ static struct xenbus_driver netback = {
-
- void netif_xenbus_init(void)
- {
-- xenbus_register_backend(&netback);
-+ printk(KERN_CRIT "registering netback\n");
-+ (void)xenbus_register_backend(&netback);
- }
---
-1.7.4
-
-
-From a41a2ab9e1ac4ef8320f69f2719e973e25faff5c Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Date: Mon, 9 Feb 2009 16:39:01 -0800
-Subject: [PATCH 039/244] xen: netback: don't include xen/evtchn.h
-
-Its a usermode header for users of /dev/evtchn
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy(a)goop.org>
----
- drivers/xen/netback/common.h | 1 -
- 1 files changed, 0 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 65b88f4..5665ed1 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -38,7 +38,6 @@
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/wait.h>
--#include <xen/evtchn.h>
- #include <xen/interface/io/netif.h>
- #include <asm/io.h>
- #include <asm/pgalloc.h>
---
-1.7.4
-
-
-From f28a7c6148bb979acf99c0cbe3b441d0fb0853d9 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Wed, 18 Feb 2009 15:55:18 -0800
-Subject: [PATCH 040/244] xen: netback: use mod_timer
-
-__mod_timer is no longer a public API.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 4 ++--
- 1 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index c959075..e920703 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -334,7 +334,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- */
- netif->tx_queue_timeout.data = (unsigned long)netif;
- netif->tx_queue_timeout.function = tx_queue_callback;
-- __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
-+ mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
- }
- }
-
-@@ -1299,7 +1299,7 @@ static void net_tx_action(unsigned long unused)
- (unsigned long)netif;
- netif->credit_timeout.function =
- tx_credit_callback;
-- __mod_timer(&netif->credit_timeout,
-+ mod_timer(&netif->credit_timeout,
- next_credit);
- netif_put(netif);
- continue;
---
-1.7.4
-
-
-From 52f97ad360f28762c785343ba5c9f8abb83536f3 Mon Sep 17 00:00:00 2001
-From: Jan Beulich <jbeulich(a)novell.com>
-Date: Fri, 6 Mar 2009 08:29:31 +0000
-Subject: [PATCH 041/244] xen: netback: unmap tx ring gref when mapping of rx ring gref
failed
-
-[ijc-ported from linux-2.6.18-xen.hg 782:51decc39e5e7]
-Signed-off-by: Jan Beulich <jbeulich(a)novell.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/interface.c | 6 ++++++
- 1 files changed, 6 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index d184ad7..f3d9ea1 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -222,6 +222,12 @@ static int map_frontend_pages(
- BUG();
-
- if (op.status) {
-+ struct gnttab_unmap_grant_ref unop;
++ /* Timer could already be pending in rare cases. */
++ if (timer_pending(&netif->credit_timeout))
++ return true;
+
-+ gnttab_set_unmap_op(&unop,
-+ (unsigned long)netif->tx_comms_area->addr,
-+ GNTMAP_host_map, netif->tx_shmem_handle);
-+ HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
- DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
- return op.status;
- }
---
-1.7.4
-
-
-From f9b63790f1404eb03ac824147b2294a46e485643 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)citrix.com>
-Date: Fri, 6 Mar 2009 08:29:32 +0000
-Subject: [PATCH 042/244] xen: netback: add ethtool stat to track copied skbs.
-
-Copied skbs should be rare but we have no way of verifying that.
-
-[ijc-ported from linux-2.6.18-xen.hg 792:db9857bb0320]
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/common.h | 3 ++
- drivers/xen/netback/interface.c | 47 +++++++++++++++++++++++++++++++++++++++
- drivers/xen/netback/netback.c | 6 ++++-
- 3 files changed, 55 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 5665ed1..6ba804d 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -92,6 +92,9 @@ struct xen_netif {
- /* Enforce draining of the transmit queue. */
- struct timer_list tx_queue_timeout;
-
-+ /* Statistics */
-+ int nr_copied_skbs;
++ /* Passed the point where we can replenish credit? */
++ if (time_after_eq(now, next_credit)) {
++ netif->credit_timeout.expires = now;
++ tx_add_credit(netif);
++ }
+
- /* Miscellaneous private stuff. */
- struct list_head list; /* scheduling list */
- atomic_t refcnt;
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index f3d9ea1..1a99c87 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -119,8 +119,51 @@ static int netbk_set_tso(struct net_device *dev, u32 data)
- return ethtool_op_set_tso(dev, data);
- }
-
-+static void netbk_get_drvinfo(struct net_device *dev,
-+ struct ethtool_drvinfo *info)
-+{
-+ strcpy(info->driver, "netbk");
-+}
++ /* Still too big to send right now? Set a callback. */
++ if (size > netif->remaining_credit) {
++ netif->credit_timeout.data =
++ (unsigned long)netif;
++ netif->credit_timeout.function =
++ tx_credit_callback;
++ mod_timer(&netif->credit_timeout,
++ next_credit);
+
-+static const struct netif_stat {
-+ char name[ETH_GSTRING_LEN];
-+ u16 offset;
-+} netbk_stats[] = {
-+ { "copied_skbs", offsetof(struct xen_netif, nr_copied_skbs) },
-+};
++ return true;
++ }
+
-+static int netbk_get_stats_count(struct net_device *dev)
-+{
-+ return ARRAY_SIZE(netbk_stats);
++ return false;
+}
+
-+static void netbk_get_ethtool_stats(struct net_device *dev,
-+ struct ethtool_stats *stats, u64 * data)
++static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+{
-+ void *netif = netdev_priv(dev);
-+ int i;
++ struct gnttab_map_grant_ref *mop;
++ struct sk_buff *skb;
++ int ret;
+
-+ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-+ data[i] = *(int *)(netif + netbk_stats[i].offset);
-+}
++ mop = netbk->tx_map_ops;
++ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ !list_empty(&netbk->net_schedule_list)) {
++ struct xen_netif *netif;
++ struct xen_netif_tx_request txreq;
++ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
++ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
++ u16 pending_idx;
++ RING_IDX idx;
++ int work_to_do;
++ unsigned int data_len;
++ pending_ring_idx_t index;
+
-+static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
-+{
-+ int i;
++ /* Get a netif from the list with work to do. */
++ netif = poll_net_schedule_list(netbk);
++ if (!netif)
++ continue;
+
-+ switch (stringset) {
-+ case ETH_SS_STATS:
-+ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-+ memcpy(data + i * ETH_GSTRING_LEN,
-+ netbk_stats[i].name, ETH_GSTRING_LEN);
-+ break;
-+ }
-+}
++ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
++ if (!work_to_do) {
++ netif_put(netif);
++ continue;
++ }
+
- static struct ethtool_ops network_ethtool_ops =
- {
-+ .get_drvinfo = netbk_get_drvinfo,
++ idx = netif->tx.req_cons;
++ rmb(); /* Ensure that we see the request before we copy it. */
++ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
+
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
-@@ -128,6 +171,10 @@ static struct ethtool_ops network_ethtool_ops =
- .get_tso = ethtool_op_get_tso,
- .set_tso = netbk_set_tso,
- .get_link = ethtool_op_get_link,
++ /* Credit-based scheduling. */
++ if (txreq.size > netif->remaining_credit &&
++ tx_credit_exceeded(netif, txreq.size)) {
++ netif_put(netif);
++ continue;
++ }
+
-+ .get_stats_count = netbk_get_stats_count,
-+ .get_ethtool_stats = netbk_get_ethtool_stats,
-+ .get_strings = netbk_get_strings,
- };
-
- struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index e920703..f59fadb 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -923,7 +923,11 @@ inline static void net_tx_action_dealloc(void)
- if (time_after(inuse->alloc_time + HZ / 2, jiffies))
- break;
-
-- switch (copy_pending_req(inuse - pending_inuse)) {
-+ pending_idx = inuse - pending_inuse;
++ netif->remaining_credit -= txreq.size;
+
-+ pending_tx_info[pending_idx].netif->nr_copied_skbs++;
++ work_to_do--;
++ netif->tx.req_cons = ++idx;
+
-+ switch (copy_pending_req(pending_idx)) {
- case 0:
- list_move_tail(&inuse->list, &list);
- continue;
---
-1.7.4
-
-
-From c41d8da3d853d4e89ba38693b90c1fe512095704 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)citrix.com>
-Date: Fri, 6 Mar 2009 08:29:33 +0000
-Subject: [PATCH 043/244] xen: netback: make queue length parameter writeable in sysfs
-
-Any changes will only take effect for newly created VIFs.
-
-Also hook up the vif devices to their parent and publish bus info via
-ethtool.
-
-[ijc-ported from linux-2.6.18-xen.hg 793:3aa9b8a7876b]
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/interface.c | 3 ++-
- drivers/xen/netback/xenbus.c | 1 +
- 2 files changed, 3 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 1a99c87..7706170 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -52,7 +52,7 @@
- * blocked.
- */
- static unsigned long netbk_queue_length = 32;
--module_param_named(queue_length, netbk_queue_length, ulong, 0);
-+module_param_named(queue_length, netbk_queue_length, ulong, 0644);
-
- static void __netif_up(struct xen_netif *netif)
- {
-@@ -123,6 +123,7 @@ static void netbk_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
- {
- strcpy(info->driver, "netbk");
-+ strcpy(info->bus_info, dev->dev.parent->bus_id);
- }
-
- static const struct netif_stat {
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index ed7c006..dc7b367 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -200,6 +200,7 @@ static void backend_create_netif(struct backend_info *be)
- xenbus_dev_fatal(dev, err, "creating interface");
- return;
- }
-+ SET_NETDEV_DEV(be->netif->dev, &dev->dev);
-
- kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
- }
---
-1.7.4
-
-
-From f204d7567ab11ddb1ff3208ab5ed8921b575af5d Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)citrix.com>
-Date: Mon, 16 Mar 2009 22:05:16 +0000
-Subject: [PATCH 044/244] xen: netback: parent sysfs device should be set before
registering.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/common.h | 2 +-
- drivers/xen/netback/interface.c | 4 +++-
- drivers/xen/netback/xenbus.c | 3 +--
- 3 files changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 6ba804d..123a169 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -180,7 +180,7 @@ void netif_accel_init(void);
-
- void netif_disconnect(struct xen_netif *netif);
-
--struct xen_netif *netif_alloc(domid_t domid, unsigned int handle);
-+struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle);
- int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 7706170..5e0d26d 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -178,7 +178,7 @@ static struct ethtool_ops network_ethtool_ops =
- .get_strings = netbk_get_strings,
- };
-
--struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
-+struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle)
- {
- int err = 0;
- struct net_device *dev;
-@@ -192,6 +192,8 @@ struct xen_netif *netif_alloc(domid_t domid, unsigned int handle)
- return ERR_PTR(-ENOMEM);
- }
-
-+ SET_NETDEV_DEV(dev, parent);
++ memset(extras, 0, sizeof(extras));
++ if (txreq.flags & NETTXF_extra_info) {
++ work_to_do = netbk_get_extras(netif, extras,
++ work_to_do);
++ idx = netif->tx.req_cons;
++ if (unlikely(work_to_do < 0)) {
++ netbk_tx_err(netif, &txreq, idx);
++ continue;
++ }
++ }
++
++ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
++ if (unlikely(ret < 0)) {
++ netbk_tx_err(netif, &txreq, idx - ret);
++ continue;
++ }
++ idx += ret;
++
++ if (unlikely(txreq.size < ETH_HLEN)) {
++ pr_debug("Bad packet size: %d\n", txreq.size);
++ netbk_tx_err(netif, &txreq, idx);
++ continue;
++ }
++
++ /* No crossing a page as the payload mustn't fragment. */
++ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
++ pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
++ txreq.offset, txreq.size,
++ (txreq.offset&~PAGE_MASK) + txreq.size);
++ netbk_tx_err(netif, &txreq, idx);
++ continue;
++ }
++
++ index = pending_index(netbk->pending_cons);
++ pending_idx = netbk->pending_ring[index];
++
++ data_len = (txreq.size > PKT_PROT_LEN &&
++ ret < MAX_SKB_FRAGS) ?
++ PKT_PROT_LEN : txreq.size;
+
- netif = netdev_priv(dev);
- memset(netif, 0, sizeof(*netif));
- netif->domid = domid;
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index dc7b367..749931e 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -193,14 +193,13 @@ static void backend_create_netif(struct backend_info *be)
- return;
- }
-
-- be->netif = netif_alloc(dev->otherend_id, handle);
-+ be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
- if (IS_ERR(be->netif)) {
- err = PTR_ERR(be->netif);
- be->netif = NULL;
- xenbus_dev_fatal(dev, err, "creating interface");
- return;
- }
-- SET_NETDEV_DEV(be->netif->dev, &dev->dev);
-
- kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
- }
---
-1.7.4
-
-
-From bb606178665ea78b505cb54864899478b6020584 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 12:42:36 -0700
-Subject: [PATCH 045/244] xen: netback: use NET_SKB_PAD rather than "16"
-
-There's a constant for the default skb headroom.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 6 +++---
- 1 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index f59fadb..400f398 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -203,7 +203,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
- if (unlikely(!nskb))
- goto err;
-
-- skb_reserve(nskb, 16 + NET_IP_ALIGN);
-+ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
- headlen = skb_end_pointer(nskb) - nskb->data;
- if (headlen > skb_headlen(skb))
- headlen = skb_headlen(skb);
-@@ -1353,7 +1353,7 @@ static void net_tx_action(unsigned long unused)
- ret < MAX_SKB_FRAGS) ?
- PKT_PROT_LEN : txreq.size;
-
-- skb = alloc_skb(data_len + 16 + NET_IP_ALIGN,
+ skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
- GFP_ATOMIC | __GFP_NOWARN);
- if (unlikely(skb == NULL)) {
- DPRINTK("Can't allocate a skb in start_xmit.\n");
-@@ -1362,7 +1362,7 @@ static void net_tx_action(unsigned long unused)
- }
-
- /* Packets passed to netif_rx() must have some headroom. */
-- skb_reserve(skb, 16 + NET_IP_ALIGN);
++ GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(skb == NULL)) {
++ pr_debug("Can't allocate a skb in start_xmit.\n");
++ netbk_tx_err(netif, &txreq, idx);
++ break;
++ }
++
++ /* Packets passed to netif_rx() must have some headroom. */
+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
-
- if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
- struct xen_netif_extra_info *gso;
---
-1.7.4
-
-
-From fe41ab031dfa0c6f9821c2667ce821e7f4f635ed Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 13:31:26 -0700
-Subject: [PATCH 046/244] xen: netback: completely drop flip support
-
-Nobody uses it?
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 1 -
- drivers/xen/netback/netback.c | 245 ++++-------------------------------------
- drivers/xen/netback/xenbus.c | 3 +-
- 3 files changed, 22 insertions(+), 227 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 123a169..06f04c1 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -78,7 +78,6 @@ struct xen_netif {
-
- /* Internal feature information. */
- u8 can_queue:1; /* can queue packets for receiver? */
-- u8 copying_receiver:1; /* copy packets to receiver? */
-
- /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
- RING_IDX rx_req_cons_peek;
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 400f398..36bea2b 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -51,7 +51,6 @@
- struct netbk_rx_meta {
- skb_frag_t frag;
- int id;
-- u8 copy:1;
- };
-
- struct netbk_tx_pending_inuse {
-@@ -160,26 +159,6 @@ static inline unsigned long alloc_mfn(void)
- return mfn_list[--alloc_index];
- }
-
--static int check_mfn(int nr)
--{
-- struct xen_memory_reservation reservation = {
-- .extent_order = 0,
-- .domid = DOMID_SELF
-- };
-- int rc;
--
-- if (likely(alloc_index >= nr))
-- return 0;
--
-- set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
-- reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
-- rc = HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation);
-- if (likely(rc > 0))
-- alloc_index += rc;
--
-- return alloc_index >= nr ? 0 : -ENOMEM;
--}
--
- static inline void maybe_schedule_tx_action(void)
- {
- smp_mb();
-@@ -188,82 +167,6 @@ static inline void maybe_schedule_tx_action(void)
- tasklet_schedule(&net_tx_tasklet);
- }
-
--static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
--{
-- struct skb_shared_info *ninfo;
-- struct sk_buff *nskb;
-- unsigned long offset;
-- int ret;
-- int len;
-- int headlen;
--
-- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
--
-- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-- if (unlikely(!nskb))
-- goto err;
--
-- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-- headlen = skb_end_pointer(nskb) - nskb->data;
-- if (headlen > skb_headlen(skb))
-- headlen = skb_headlen(skb);
-- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-- BUG_ON(ret);
--
-- ninfo = skb_shinfo(nskb);
-- ninfo->gso_size = skb_shinfo(skb)->gso_size;
-- ninfo->gso_type = skb_shinfo(skb)->gso_type;
--
-- offset = headlen;
-- len = skb->len - headlen;
--
-- nskb->len = skb->len;
-- nskb->data_len = len;
-- nskb->truesize += len;
--
-- while (len) {
-- struct page *page;
-- int copy;
-- int zero;
--
-- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-- dump_stack();
-- goto err_free;
-- }
--
-- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
--
-- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-- if (unlikely(!page))
-- goto err_free;
--
-- ret = skb_copy_bits(skb, offset, page_address(page), copy);
-- BUG_ON(ret);
--
-- ninfo->frags[ninfo->nr_frags].page = page;
-- ninfo->frags[ninfo->nr_frags].page_offset = 0;
-- ninfo->frags[ninfo->nr_frags].size = copy;
-- ninfo->nr_frags++;
--
-- offset += copy;
-- len -= copy;
-- }
--
-- offset = nskb->data - skb->data;
--
-- nskb->transport_header = skb->transport_header + offset;
-- nskb->network_header = skb->network_header + offset;
-- nskb->mac_header = skb->mac_header + offset;
--
-- return nskb;
--
-- err_free:
-- kfree_skb(nskb);
-- err:
-- return NULL;
--}
--
- static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
- {
- if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
-@@ -297,24 +200,6 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
- goto drop;
-
-- /*
-- * Copy the packet here if it's destined for a flipping interface
-- * but isn't flippable (e.g. extra references to data).
-- * XXX For now we also copy skbuffs whose head crosses a page
-- * boundary, because netbk_gop_skb can't handle them.
-- */
-- if (!netif->copying_receiver ||
-- ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) {
-- struct sk_buff *nskb = netbk_copy_skb(skb);
-- if ( unlikely(nskb == NULL) )
-- goto drop;
-- /* Copy only the header fields we use in this driver. */
-- nskb->dev = skb->dev;
-- nskb->ip_summed = skb->ip_summed;
-- dev_kfree_skb(skb);
-- skb = nskb;
-- }
--
- netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
- !!skb_shinfo(skb)->gso_size;
- netif_get(netif);
-@@ -388,66 +273,32 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
- struct page *page, unsigned long size,
- unsigned long offset)
- {
-- struct mmu_update *mmu;
-- struct gnttab_transfer *gop;
- struct gnttab_copy *copy_gop;
-- struct multicall_entry *mcl;
- struct xen_netif_rx_request *req;
-- unsigned long old_mfn, new_mfn;
-+ unsigned long old_mfn;
- int idx = netif_page_index(page);
-
- old_mfn = virt_to_mfn(page_address(page));
-
- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
-- if (netif->copying_receiver) {
-- /* 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];
-- copy_gop->source.domid = src_pend->netif->domid;
-- copy_gop->source.u.ref = src_pend->req.gref;
-- copy_gop->flags |= GNTCOPY_source_gref;
-- } else {
-- copy_gop->source.domid = DOMID_SELF;
-- copy_gop->source.u.gmfn = old_mfn;
-- }
-- copy_gop->source.offset = offset;
-- copy_gop->dest.domid = netif->domid;
-- copy_gop->dest.offset = 0;
-- copy_gop->dest.u.ref = req->gref;
-- copy_gop->len = size;
-- } else {
-- meta->copy = 0;
-- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-- new_mfn = alloc_mfn();
--
-- /*
-- * Set the new P2M table entry before
-- * reassigning the old data page. Heed the
-- * comment in pgtable-2level.h:pte_page(). :-)
-- */
-- set_phys_to_machine(page_to_pfn(page), new_mfn);
--
-- mcl = npo->mcl + npo->mcl_prod++;
-- MULTI_update_va_mapping(mcl,
-- (unsigned long)page_address(page),
-- mfn_pte(new_mfn, PAGE_KERNEL),
-- 0);
--
-- mmu = npo->mmu + npo->mmu_prod++;
-- mmu->ptr = ((phys_addr_t)new_mfn << PAGE_SHIFT) |
-- MMU_MACHPHYS_UPDATE;
-- mmu->val = page_to_pfn(page);
-- }
-
-- gop = npo->trans + npo->trans_prod++;
-- gop->mfn = old_mfn;
-- gop->domid = netif->domid;
-- gop->ref = req->gref;
-+ 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];
-+ copy_gop->source.domid = src_pend->netif->domid;
-+ copy_gop->source.u.ref = src_pend->req.gref;
-+ copy_gop->flags |= GNTCOPY_source_gref;
-+ } else {
-+ copy_gop->source.domid = DOMID_SELF;
-+ copy_gop->source.u.gmfn = old_mfn;
- }
-+ copy_gop->source.offset = offset;
-+ copy_gop->dest.domid = netif->domid;
-+ copy_gop->dest.offset = 0;
-+ copy_gop->dest.u.ref = req->gref;
-+ copy_gop->len = size;
+
- return req->id;
- }
-
-@@ -502,41 +353,17 @@ static inline void netbk_free_pages(int nr_frags, struct
netbk_rx_meta *meta)
- static int netbk_check_gop(int nr_frags, domid_t domid,
- struct netrx_pending_operations *npo)
- {
-- struct multicall_entry *mcl;
-- struct gnttab_transfer *gop;
- struct gnttab_copy *copy_op;
- int status = NETIF_RSP_OKAY;
- int i;
-
- for (i = 0; i <= nr_frags; i++) {
-- if (npo->meta[npo->meta_cons + i].copy) {
- copy_op = npo->copy + npo->copy_cons++;
- if (copy_op->status != GNTST_okay) {
- DPRINTK("Bad status %d from copy to DOM%d.\n",
- copy_op->status, domid);
- status = NETIF_RSP_ERROR;
- }
-- } else {
-- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-- mcl = npo->mcl + npo->mcl_cons++;
-- /* The update_va_mapping() must not fail. */
-- BUG_ON(mcl->result != 0);
-- }
--
-- gop = npo->trans + npo->trans_cons++;
-- /* Check the reassignment error code. */
-- if (gop->status != 0) {
-- DPRINTK("Bad status %d from grant transfer to DOM%u\n",
-- gop->status, domid);
-- /*
-- * Page no longer belongs to us unless
-- * GNTST_bad_page, but that should be
-- * a fatal error anyway.
-- */
-- BUG_ON(gop->status == GNTST_bad_page);
-- status = NETIF_RSP_ERROR;
-- }
-- }
- }
-
- return status;
-@@ -551,11 +378,8 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
- for (i = 0; i < nr_frags; i++) {
- int id = meta[i].id;
- int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
--
-- if (meta[i].copy)
-- offset = 0;
-- else
-- offset = meta[i].frag.page_offset;
-+
-+ offset = 0;
- make_rx_response(netif, id, status, offset,
- meta[i].frag.size, flags);
- }
-@@ -603,18 +427,6 @@ static void net_rx_action(unsigned long unused)
- nr_frags = skb_shinfo(skb)->nr_frags;
- *(int *)skb->cb = nr_frags;
-
-- if (!xen_feature(XENFEAT_auto_translated_physmap) &&
-- !((struct xen_netif *)netdev_priv(skb->dev))->copying_receiver &&
-- check_mfn(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);
-- break;
-- }
--
- netbk_gop_skb(skb, &npo);
-
- count += nr_frags + 1;
-@@ -677,20 +489,6 @@ static void net_rx_action(unsigned long unused)
- nr_frags = *(int *)skb->cb;
-
- netif = netdev_priv(skb->dev);
-- /* We can't rely on skb_release_data to release the
-- pages used by fragments for us, since it tries to
-- touch the pages in the fraglist. If we're in
-- flipping mode, that doesn't work. In copying mode,
-- we still have access to all of the pages, and so
-- it's safe to let release_data deal with it. */
-- /* (Freeing the fragments is safe since we copy
-- non-linear skbs destined for flipping interfaces) */
-- if (!netif->copying_receiver) {
-- 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);
-- }
-
- netif->stats.tx_bytes += skb->len;
- netif->stats.tx_packets++;
-@@ -706,10 +504,7 @@ static void net_rx_action(unsigned long unused)
- /* remote but checksummed. */
- flags |= NETRXF_data_validated;
-
-- if (meta[npo.meta_cons].copy)
-- offset = 0;
-- else
-- offset = offset_in_page(skb->data);
-+ offset = 0;
- resp = make_rx_response(netif, id, status, offset,
- skb_headlen(skb), flags);
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index 749931e..a492288 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -378,7 +378,8 @@ static int connect_rings(struct backend_info *be)
- dev->otherend);
- return err;
- }
-- be->netif->copying_receiver = !!rx_copy;
-+ if (!rx_copy)
-+ return -EOPNOTSUPP;
-
- if (be->netif->dev->tx_queue_len != 0) {
- if (xenbus_scanf(XBT_NIL, dev->otherend,
---
-1.7.4
-
-
-From 17d465234118873ab4f5a7992feb4ce7b5537cf7 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 15:19:39 -0700
-Subject: [PATCH 047/244] xen: netback: demacro MASK_PEND_IDX
-
-Replace it with a more meaningful inline: pending_index().
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 21 +++++++++++++--------
- 1 files changed, 13 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 36bea2b..4095622 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -121,7 +121,12 @@ static struct pending_tx_info {
- } 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))
++ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
++ struct xen_netif_extra_info *gso;
++ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
-+static inline PEND_RING_IDX pending_index(unsigned i)
++ if (netbk_set_skb_gso(skb, gso)) {
++ kfree_skb(skb);
++ netbk_tx_err(netif, &txreq, idx);
++ continue;
++ }
++ }
++
++ gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
++ GNTMAP_host_map | GNTMAP_readonly,
++ txreq.gref, netif->domid);
++ mop++;
++
++ memcpy(&netbk->pending_tx_info[pending_idx].req,
++ &txreq, sizeof(txreq));
++ netbk->pending_tx_info[pending_idx].netif = netif;
++ *((u16 *)skb->data) = pending_idx;
++
++ __skb_put(skb, data_len);
++
++ skb_shinfo(skb)->nr_frags = ret;
++ if (data_len < txreq.size) {
++ skb_shinfo(skb)->nr_frags++;
++ skb_shinfo(skb)->frags[0].page =
++ (void *)(unsigned long)pending_idx;
++ } else {
++ /* Discriminate from any valid pending_idx value. */
++ skb_shinfo(skb)->frags[0].page = (void *)~0UL;
++ }
++
++ __skb_queue_tail(&netbk->tx_queue, skb);
++
++ netbk->pending_cons++;
++
++ mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
++
++ netif->tx.req_cons = idx;
++ netif_schedule_work(netif);
++
++ if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
++ break;
++ }
++
++ return mop - netbk->tx_map_ops;
++}
++
++static void net_tx_submit(struct xen_netbk *netbk)
+{
-+ return i & (MAX_PENDING_REQS-1);
++ struct gnttab_map_grant_ref *mop;
++ struct sk_buff *skb;
++
++ mop = netbk->tx_map_ops;
++ while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
++ struct xen_netif_tx_request *txp;
++ struct xen_netif *netif;
++ u16 pending_idx;
++ unsigned data_len;
++
++ pending_idx = *((u16 *)skb->data);
++ netif = netbk->pending_tx_info[pending_idx].netif;
++ txp = &netbk->pending_tx_info[pending_idx].req;
++
++ /* Check the remap error code. */
++ if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
++ pr_debug("netback grant failed.\n");
++ skb_shinfo(skb)->nr_frags = 0;
++ kfree_skb(skb);
++ continue;
++ }
++
++ data_len = skb->len;
++ memcpy(skb->data,
++ (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
++ data_len);
++ if (data_len < txp->size) {
++ /* Append the packet payload as a fragment. */
++ txp->offset += data_len;
++ txp->size -= data_len;
++ } else {
++ /* Schedule a response immediately. */
++ netif_idx_release(netbk, pending_idx);
++ }
++
++ if (txp->flags & NETTXF_csum_blank)
++ skb->ip_summed = CHECKSUM_PARTIAL;
++ else if (txp->flags & NETTXF_data_validated)
++ skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++ netbk_fill_frags(netbk, skb);
++
++ /*
++ * If the initial fragment was < PKT_PROT_LEN then
++ * pull through some bytes from the other fragments to
++ * increase the linear region to PKT_PROT_LEN bytes.
++ */
++ if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
++ int target = min_t(int, skb->len, PKT_PROT_LEN);
++ __pskb_pull_tail(skb, target - skb_headlen(skb));
++ }
++
++ skb->dev = netif->dev;
++ skb->protocol = eth_type_trans(skb, skb->dev);
++
++ if (checksum_setup(netif, skb)) {
++ pr_debug("Can't setup checksum in net_tx_action\n");
++ kfree_skb(skb);
++ continue;
++ }
++
++ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
++ unlikely(skb_linearize(skb))) {
++ pr_debug("Can't linearize skb in net_tx_action.\n");
++ kfree_skb(skb);
++ continue;
++ }
++
++ netif->stats.rx_bytes += skb->len;
++ netif->stats.rx_packets++;
++
++ netif_rx_ni(skb);
++ netif->dev->last_rx = jiffies;
++ }
+}
+
- static PEND_RING_IDX pending_prod, pending_cons;
- #define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
-
-@@ -695,7 +700,7 @@ inline static void net_tx_action_dealloc(void)
- while (dc != dp) {
- unsigned long pfn;
-
-- pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
-+ pending_idx = dealloc_ring[pending_index(dc++)];
- list_move_tail(&pending_inuse[pending_idx].list, &list);
-
- pfn = idx_to_pfn(pending_idx);
-@@ -754,7 +759,7 @@ inline static void net_tx_action_dealloc(void)
- /* Ready for next use. */
- gnttab_reset_grant_page(mmap_pages[pending_idx]);
-
-- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-+ pending_ring[pending_index(pending_prod++)] = pending_idx;
-
- netif_put(netif);
-
-@@ -831,7 +836,7 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
- 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++)];
-+ pending_idx = pending_ring[pending_index(pending_cons++)];
-
- gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
- GNTMAP_host_map | GNTMAP_readonly,
-@@ -862,7 +867,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- if (unlikely(err)) {
- txp = &pending_tx_info[pending_idx].req;
- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-- pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-+ pending_ring[pending_index(pending_prod++)] = pending_idx;
- netif_put(netif);
- } else {
- set_phys_to_machine(
-@@ -895,7 +900,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- /* 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;
-+ pending_ring[pending_index(pending_prod++)] = pending_idx;
- netif_put(netif);
-
- /* Not the first error? Preceding frags already invalidated. */
-@@ -1142,7 +1147,7 @@ static void net_tx_action(unsigned long unused)
- continue;
- }
-
-- pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
-+ pending_idx = pending_ring[pending_index(pending_cons)];
-
- data_len = (txreq.size > PKT_PROT_LEN &&
- ret < MAX_SKB_FRAGS) ?
-@@ -1298,7 +1303,7 @@ static void netif_idx_release(u16 pending_idx)
- unsigned long flags;
-
- spin_lock_irqsave(&_lock, flags);
-- dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
-+ dealloc_ring[pending_index(dealloc_prod)] = pending_idx;
- /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
- smp_wmb();
- dealloc_prod++;
---
-1.7.4
-
-
-From d47af34f87b2d365c75aa3579ad512619ef3d579 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 15:29:30 -0700
-Subject: [PATCH 048/244] xen: netback: convert PEND_RING_IDX into a proper typedef name
-
-Rename PEND_RING_IDX to pending_ring_idx_t. Its not used that much,
-the extra typing won't kill anyone.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 12 ++++++------
- 1 files changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 4095622..8292e96 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -120,19 +120,19 @@ static struct pending_tx_info {
- struct xen_netif *netif;
- } pending_tx_info[MAX_PENDING_REQS];
- static u16 pending_ring[MAX_PENDING_REQS];
--typedef unsigned int PEND_RING_IDX;
-+typedef unsigned int pending_ring_idx_t;
-
--static inline PEND_RING_IDX pending_index(unsigned i)
-+static inline pending_ring_idx_t pending_index(unsigned i)
- {
- return i & (MAX_PENDING_REQS-1);
- }
-
--static PEND_RING_IDX pending_prod, pending_cons;
-+static pending_ring_idx_t 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;
-+static pending_ring_idx_t dealloc_prod, dealloc_cons;
-
- /* Doubly-linked list of in-use pending entries. */
- static struct netbk_tx_pending_inuse pending_inuse[MAX_PENDING_REQS];
-@@ -669,7 +669,7 @@ static void tx_credit_callback(unsigned long data)
- netif_schedule_work(netif);
- }
-
--static inline int copy_pending_req(PEND_RING_IDX pending_idx)
-+static inline int copy_pending_req(pending_ring_idx_t pending_idx)
- {
- return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
- &mmap_pages[pending_idx]);
-@@ -680,7 +680,7 @@ inline static void net_tx_action_dealloc(void)
- struct netbk_tx_pending_inuse *inuse, *n;
- struct gnttab_unmap_grant_ref *gop;
- u16 pending_idx;
-- PEND_RING_IDX dc, dp;
-+ pending_ring_idx_t dc, dp;
- struct xen_netif *netif;
- int ret;
- LIST_HEAD(list);
---
-1.7.4
-
-
-From 56727a43f329d50c2a00fed0316ffd87d6c23ebd Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 15:31:32 -0700
-Subject: [PATCH 049/244] xen: netback: rename NR_PENDING_REQS to nr_pending_reqs()
-
-Use function syntax to show its actually computing a value, rather than
-a constant.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 10 +++++++---
- 1 files changed, 7 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 8292e96..5410a68 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -128,7 +128,11 @@ static inline pending_ring_idx_t pending_index(unsigned i)
- }
-
- static pending_ring_idx_t pending_prod, pending_cons;
--#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++/* Called after netfront has transmitted */
++static void net_tx_action(unsigned long data)
++{
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ unsigned nr_mops;
++ int ret;
+
-+static inline pending_ring_idx_t nr_pending_reqs(void)
++ net_tx_action_dealloc(netbk);
++
++ nr_mops = net_tx_build_mops(netbk);
++
++ if (nr_mops == 0)
++ goto out;
++
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
++ netbk->tx_map_ops, nr_mops);
++ BUG_ON(ret);
++
++ net_tx_submit(netbk);
++out:
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !list_empty(&netbk->pending_inuse_head)) {
++ struct netbk_tx_pending_inuse *oldest;
++
++ oldest = list_entry(netbk->pending_inuse_head.next,
++ struct netbk_tx_pending_inuse, list);
++ mod_timer(&netbk->netbk_tx_pending_timer,
++ oldest->alloc_time + HZ);
++ }
++}
++
++static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+{
-+ return MAX_PENDING_REQS - pending_prod + pending_cons;
++ static DEFINE_SPINLOCK(_lock);
++ unsigned long flags;
++ pending_ring_idx_t index;
++
++ spin_lock_irqsave(&_lock, flags);
++ index = pending_index(netbk->dealloc_prod);
++ netbk->dealloc_ring[index] = pending_idx;
++ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
++ smp_wmb();
++ netbk->dealloc_prod++;
++ spin_unlock_irqrestore(&_lock, flags);
++
++ xen_netbk_bh_handler(netbk, 0);
+}
-
- /* Freed TX SKBs get batched on this ring before return to pending_ring. */
- static u16 dealloc_ring[MAX_PENDING_REQS];
-@@ -167,7 +171,7 @@ static inline unsigned long alloc_mfn(void)
- static inline void maybe_schedule_tx_action(void)
- {
- smp_mb();
-- if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
-+ if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
- !list_empty(&net_schedule_list))
- tasklet_schedule(&net_tx_tasklet);
- }
-@@ -1060,7 +1064,7 @@ static void net_tx_action(unsigned long unused)
- net_tx_action_dealloc();
-
- mop = tx_map_ops;
-- while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+ while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&net_schedule_list)) {
- /* Get a netif from the list with work to do. */
- ent = net_schedule_list.next;
---
-1.7.4
-
-
-From 55b360614f1bd44d0b1395b4aabf41d8f1f13f17 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 15:45:45 -0700
-Subject: [PATCH 050/244] xen: netback: pre-initialize list and spinlocks; use empty list
to indicate not on list
-
-Statically pre-initialize net_schedule_list head and lock.
-
-Use an empty list to mark when a xen_netif is not on the schedule list,
-rather than NULL (which may upset list debugging).
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/interface.c | 1 +
- drivers/xen/netback/netback.c | 12 ++++--------
- 2 files changed, 5 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 5e0d26d..dc4fb53 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -201,6 +201,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- atomic_set(&netif->refcnt, 1);
- init_waitqueue_head(&netif->waiting_to_free);
- netif->dev = dev;
-+ INIT_LIST_HEAD(&netif->list);
-
- netback_carrier_off(netif);
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 5410a68..cbd4b03 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -148,8 +148,8 @@ static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
- static struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
- static struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
-
--static struct list_head net_schedule_list;
--static spinlock_t net_schedule_list_lock;
-+static LIST_HEAD(net_schedule_list);
-+static DEFINE_SPINLOCK(net_schedule_list_lock);
-
- #define MAX_MFN_ALLOC 64
- static unsigned long mfn_list[MAX_MFN_ALLOC];
-@@ -588,15 +588,14 @@ struct net_device_stats *netif_be_get_stats(struct net_device
*dev)
-
- static int __on_net_schedule_list(struct xen_netif *netif)
- {
-- return netif->list.next != NULL;
-+ return !list_empty(&netif->list);
- }
-
- static void remove_from_net_schedule_list(struct xen_netif *netif)
- {
- spin_lock_irq(&net_schedule_list_lock);
- if (likely(__on_net_schedule_list(netif))) {
-- list_del(&netif->list);
-- netif->list.next = NULL;
-+ list_del_init(&netif->list);
- netif_put(netif);
- }
- spin_unlock_irq(&net_schedule_list_lock);
-@@ -1466,9 +1465,6 @@ static int __init netback_init(void)
- for (i = 0; i < MAX_PENDING_REQS; i++)
- pending_ring[i] = i;
-
-- spin_lock_init(&net_schedule_list_lock);
-- INIT_LIST_HEAD(&net_schedule_list);
--
- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
- if (MODPARM_copy_skb) {
- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
---
-1.7.4
-
-
-From e12cf57de7a6c20e4c8900ce7bf4e6924a12f49e Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 15:48:10 -0700
-Subject: [PATCH 051/244] xen: netback: remove CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-
-Keir says:
-> > Does CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER need to be a config
-> > option? Could/should we always/never set it?
-> It doesn't work well with local delivery into dom0, nor even with IP
-> fragment reassembly. I don't think we would ever turn it on these days.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 21 ---------------------
- 1 files changed, 0 insertions(+), 21 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index cbd4b03..f00e405 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -615,23 +615,11 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
- spin_unlock_irq(&net_schedule_list_lock);
- }
-
--/*
-- * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
-- * If this driver is pipelining transmit requests then we can be very
-- * aggressive in avoiding new-packet notifications -- frontend only needs to
-- * send a notification if there are no outstanding unreceived responses.
-- * If we may be buffer transmit buffers for any reason then we must be rather
-- * more conservative and treat this as the final check for pending work.
-- */
- void netif_schedule_work(struct xen_netif *netif)
- {
- int more_to_do;
-
--#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-- more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
--#else
- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
--#endif
-
- if (more_to_do) {
- add_to_net_schedule_list_tail(netif);
-@@ -1355,15 +1343,6 @@ static void make_tx_response(struct xen_netif *netif,
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
- if (notify)
- notify_remote_via_irq(netif->irq);
--
--#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-- if (i == netif->tx.req_cons) {
-- int more_to_do;
-- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-- if (more_to_do)
-- add_to_net_schedule_list_tail(netif);
-- }
--#endif
- }
-
- static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
---
-1.7.4
-
-
-From adf542f9c714e3b7c76fcf9e44e0a89cae21a341 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 22:28:52 -0700
-Subject: [PATCH 052/244] xen: netback: make netif_get/put inlines
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 16 ++++++++++------
- 1 files changed, 10 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 06f04c1..9056be0 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -183,12 +183,16 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-
--#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
--#define netif_put(_b) \
-- do { \
-- if ( atomic_dec_and_test(&(_b)->refcnt) ) \
-- wake_up(&(_b)->waiting_to_free); \
-- } while (0)
-+static inline void netif_get(struct xen_netif *netif)
++
++static void netif_page_release(struct page *page, unsigned int order)
+{
-+ atomic_inc(&netif->refcnt);
++ unsigned int group, idx;
++ int foreign = netif_get_page_ext(page, &group, &idx);
++
++ BUG_ON(!foreign);
++ BUG_ON(order);
++
++ netif_idx_release(&xen_netbk[group], idx);
+}
+
-+static inline void netif_put(struct xen_netif *netif)
++irqreturn_t netif_be_int(int irq, void *dev_id)
+{
-+ if (atomic_dec_and_test(&netif->refcnt))
-+ wake_up(&netif->waiting_to_free);
++ struct xen_netif *netif = dev_id;
++ struct xen_netbk *netbk;
++
++ if (netif->group == -1)
++ return IRQ_NONE;
++
++ netbk = &xen_netbk[netif->group];
++
++ add_to_net_schedule_list_tail(netif);
++ maybe_schedule_tx_action(netbk);
++
++ if (netif_schedulable(netif) && !netbk_queue_full(netif))
++ netif_wake_queue(netif->dev);
++
++ return IRQ_HANDLED;
+}
-
- void netif_xenbus_init(void);
-
---
-1.7.4
-
-
-From f06459a199f953a68f001f06e54dde54e1e16c87 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 19 Mar 2009 22:30:24 -0700
-Subject: [PATCH 053/244] xen: netback: move code around
-
-net_tx_action() into several functions; move variables into
-their innermost scopes; rename "i" to "idx".
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 158 ++++++++++++++++++++++++-----------------
- 1 files changed, 94 insertions(+), 64 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index f00e405..4d63ff3 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -773,7 +773,8 @@ static void netbk_tx_err(struct xen_netif *netif, struct
xen_netif_tx_request *t
- netif_put(netif);
- }
-
--static int netbk_count_requests(struct xen_netif *netif, struct xen_netif_tx_request
*first,
-+static int netbk_count_requests(struct xen_netif *netif,
-+ struct xen_netif_tx_request *first,
- struct xen_netif_tx_request *txp, int work_to_do)
- {
- RING_IDX cons = netif->tx.req_cons;
-@@ -1032,30 +1033,58 @@ out:
- return err;
- }
-
--/* Called after netfront has transmitted */
--static void net_tx_action(unsigned long unused)
-+static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
- {
-- struct list_head *ent;
-- struct sk_buff *skb;
-- struct xen_netif *netif;
-- struct xen_netif_tx_request txreq;
-- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-- u16 pending_idx;
-- RING_IDX i;
-- struct gnttab_map_grant_ref *mop;
-- unsigned int data_len;
-- int ret, work_to_do;
-+ unsigned long now = jiffies;
-+ unsigned long next_credit =
-+ netif->credit_timeout.expires +
-+ msecs_to_jiffies(netif->credit_usec / 1000);
+
-+ /* Timer could already be pending in rare cases. */
-+ if (timer_pending(&netif->credit_timeout))
-+ return true;
++static void make_tx_response(struct xen_netif *netif,
++ struct xen_netif_tx_request *txp,
++ s8 st)
++{
++ RING_IDX i = netif->tx.rsp_prod_pvt;
++ struct xen_netif_tx_response *resp;
++ int notify;
+
-+ /* Passed the point where we can replenish credit? */
-+ if (time_after_eq(now, next_credit)) {
-+ netif->credit_timeout.expires = now;
-+ tx_add_credit(netif);
-+ }
-
-- if (dealloc_cons != dealloc_prod)
-- net_tx_action_dealloc();
-+ /* Still too big to send right now? Set a callback. */
-+ if (size > netif->remaining_credit) {
-+ netif->credit_timeout.data =
-+ (unsigned long)netif;
-+ netif->credit_timeout.function =
-+ tx_credit_callback;
-+ mod_timer(&netif->credit_timeout,
-+ next_credit);
++ resp = RING_GET_RESPONSE(&netif->tx, i);
++ resp->id = txp->id;
++ resp->status = st;
+
-+ return true;
-+ }
++ if (txp->flags & NETTXF_extra_info)
++ RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
+
-+ return false;
++ netif->tx.rsp_prod_pvt = ++i;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
++ if (notify)
++ notify_remote_via_irq(netif->irq);
+}
+
-+static unsigned net_tx_build_mops(void)
++static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
++ u16 id,
++ s8 st,
++ u16 offset,
++ u16 size,
++ u16 flags)
+{
-+ struct gnttab_map_grant_ref *mop;
-+ struct sk_buff *skb;
-+ int ret;
-
- mop = tx_map_ops;
- while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&net_schedule_list)) {
-+ struct xen_netif *netif;
-+ struct xen_netif_tx_request txreq;
-+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-+ u16 pending_idx;
-+ RING_IDX idx;
-+ int work_to_do;
-+ unsigned int data_len;
-+
- /* Get a netif from the list with work to do. */
-- ent = net_schedule_list.next;
-- netif = list_entry(ent, struct xen_netif, list);
-+ netif = list_first_entry(&net_schedule_list, struct xen_netif, list);
- netif_get(netif);
- remove_from_net_schedule_list(netif);
-
-@@ -1065,67 +1094,43 @@ static void net_tx_action(unsigned long unused)
- continue;
- }
-
-- i = netif->tx.req_cons;
-+ idx = netif->tx.req_cons;
- rmb(); /* Ensure that we see the request before we copy it. */
-- memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
-+ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
-
- /* Credit-based scheduling. */
-- if (txreq.size > netif->remaining_credit) {
-- unsigned long now = jiffies;
-- unsigned long next_credit =
-- netif->credit_timeout.expires +
-- msecs_to_jiffies(netif->credit_usec / 1000);
--
-- /* Timer could already be pending in rare cases. */
-- if (timer_pending(&netif->credit_timeout)) {
-- netif_put(netif);
-- continue;
-- }
--
-- /* Passed the point where we can replenish credit? */
-- if (time_after_eq(now, next_credit)) {
-- netif->credit_timeout.expires = now;
-- tx_add_credit(netif);
-- }
--
-- /* Still too big to send right now? Set a callback. */
-- if (txreq.size > netif->remaining_credit) {
-- netif->credit_timeout.data =
-- (unsigned long)netif;
-- netif->credit_timeout.function =
-- tx_credit_callback;
-- mod_timer(&netif->credit_timeout,
-- next_credit);
-- netif_put(netif);
-- continue;
-- }
-+ if (txreq.size > netif->remaining_credit &&
-+ tx_credit_exceeded(netif, txreq.size)) {
-+ netif_put(netif);
-+ continue;
- }
++ RING_IDX i = netif->rx.rsp_prod_pvt;
++ struct xen_netif_rx_response *resp;
+
- netif->remaining_credit -= txreq.size;
-
- work_to_do--;
-- netif->tx.req_cons = ++i;
-+ netif->tx.req_cons = ++idx;
-
- memset(extras, 0, sizeof(extras));
- if (txreq.flags & NETTXF_extra_info) {
- work_to_do = netbk_get_extras(netif, extras,
- work_to_do);
-- i = netif->tx.req_cons;
-+ idx = netif->tx.req_cons;
- if (unlikely(work_to_do < 0)) {
-- netbk_tx_err(netif, &txreq, i);
-+ netbk_tx_err(netif, &txreq, idx);
- continue;
- }
- }
-
- ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
- if (unlikely(ret < 0)) {
-- netbk_tx_err(netif, &txreq, i - ret);
-+ netbk_tx_err(netif, &txreq, idx - ret);
- continue;
- }
-- i += ret;
-+ idx += ret;
-
- if (unlikely(txreq.size < ETH_HLEN)) {
- DPRINTK("Bad packet size: %d\n", txreq.size);
-- netbk_tx_err(netif, &txreq, i);
-+ netbk_tx_err(netif, &txreq, idx);
- continue;
- }
-
-@@ -1134,7 +1139,7 @@ static void net_tx_action(unsigned long unused)
- DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
- txreq.offset, txreq.size,
- (txreq.offset &~PAGE_MASK) + txreq.size);
-- netbk_tx_err(netif, &txreq, i);
-+ netbk_tx_err(netif, &txreq, idx);
- continue;
- }
-
-@@ -1148,7 +1153,7 @@ static void net_tx_action(unsigned long unused)
- GFP_ATOMIC | __GFP_NOWARN);
- if (unlikely(skb == NULL)) {
- DPRINTK("Can't allocate a skb in start_xmit.\n");
-- netbk_tx_err(netif, &txreq, i);
-+ netbk_tx_err(netif, &txreq, idx);
- break;
- }
-
-@@ -1161,7 +1166,7 @@ static void net_tx_action(unsigned long unused)
-
- if (netbk_set_skb_gso(skb, gso)) {
- kfree_skb(skb);
-- netbk_tx_err(netif, &txreq, i);
-+ netbk_tx_err(netif, &txreq, idx);
- continue;
- }
- }
-@@ -1199,23 +1204,27 @@ static void net_tx_action(unsigned long unused)
-
- mop = netbk_get_requests(netif, skb, txfrags, mop);
-
-- netif->tx.req_cons = i;
-+ netif->tx.req_cons = idx;
- netif_schedule_work(netif);
-
- if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
- break;
- }
-
-- if (mop == tx_map_ops)
-- return;
-+ return mop - tx_map_ops;
++ resp = RING_GET_RESPONSE(&netif->rx, i);
++ resp->offset = offset;
++ resp->flags = flags;
++ resp->id = id;
++ resp->status = (s16)size;
++ if (st < 0)
++ resp->status = (s16)st;
++
++ netif->rx.rsp_prod_pvt = ++i;
++
++ return resp;
+}
-
-- ret = HYPERVISOR_grant_table_op(
-- GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
-- BUG_ON(ret);
-+static void net_tx_submit(void)
++
++#ifdef NETBE_DEBUG_INTERRUPT
++static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
+{
-+ struct gnttab_map_grant_ref *mop;
-+ struct sk_buff *skb;
-
- mop = tx_map_ops;
- while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
- struct xen_netif_tx_request *txp;
-+ struct xen_netif *netif;
-+ u16 pending_idx;
-+ unsigned data_len;
-
- pending_idx = *((u16 *)skb->data);
- netif = pending_tx_info[pending_idx].netif;
-@@ -1288,6 +1297,27 @@ static void net_tx_action(unsigned long unused)
- }
- }
-
-+/* Called after netfront has transmitted */
-+static void net_tx_action(unsigned long unused)
++ struct list_head *ent;
++ struct xen_netif *netif;
++ int i = 0;
++ int group = 0;
++
++ printk(KERN_ALERT "netif_schedule_list:\n");
++
++ for (group = 0; group < xen_netbk_group_nr; group++) {
++ struct xen_netbk *netbk = &xen_netbk[group];
++ spin_lock_irq(&netbk->net_schedule_list_lock);
++ printk(KERN_ALERT "xen_netback group number: %d\n", group);
++ list_for_each(ent, &netbk->net_schedule_list) {
++ netif = list_entry(ent, struct xen_netif, list);
++ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
++ "rx_resp_prod=%08x\n",
++ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
++ printk(KERN_ALERT
++ " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
++ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
++ printk(KERN_ALERT
++ " shared(rx_req_prod=%08x "
++ "rx_resp_prod=%08x\n",
++ netif->rx.sring->req_prod,
++ netif->rx.sring->rsp_prod);
++ printk(KERN_ALERT
++ " rx_event=%08x, tx_req_prod=%08x\n",
++ netif->rx.sring->rsp_event,
++ netif->tx.sring->req_prod);
++ printk(KERN_ALERT
++ " tx_resp_prod=%08x, tx_event=%08x)\n",
++ netif->tx.sring->rsp_prod,
++ netif->tx.sring->rsp_event);
++ i++;
++ }
++ spin_unlock_irq(&netbk->net_schedule_list_lock);
++ }
++
++ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
++
++ return IRQ_HANDLED;
++}
++#endif
++
++static inline int rx_work_todo(struct xen_netbk *netbk)
+{
-+ unsigned nr_mops;
-+ int ret;
++ return !skb_queue_empty(&netbk->rx_queue);
++}
+
-+ if (dealloc_cons != dealloc_prod)
-+ net_tx_action_dealloc();
++static inline int tx_work_todo(struct xen_netbk *netbk)
++{
++ if (netbk->dealloc_cons != netbk->dealloc_prod)
++ return 1;
+
-+ nr_mops = net_tx_build_mops();
++ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++ !list_empty(&netbk->pending_inuse_head))
++ return 1;
+
-+ if (nr_mops == 0)
-+ return;
++ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++ !list_empty(&netbk->net_schedule_list))
++ return 1;
+
-+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-+ tx_map_ops, nr_mops);
-+ BUG_ON(ret);
++ return 0;
++}
+
-+ net_tx_submit();
++static int netbk_action_thread(void *data)
++{
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ while (!kthread_should_stop()) {
++ wait_event_interruptible(netbk->kthread.netbk_action_wq,
++ rx_work_todo(netbk)
++ || tx_work_todo(netbk)
++ || kthread_should_stop());
++ cond_resched();
++
++ if (kthread_should_stop())
++ break;
++
++ if (rx_work_todo(netbk))
++ net_rx_action((unsigned long)netbk);
++
++ if (tx_work_todo(netbk))
++ net_tx_action((unsigned long)netbk);
++ }
++
++ return 0;
+}
+
- static void netif_idx_release(u16 pending_idx)
- {
- static DEFINE_SPINLOCK(_lock);
---
-1.7.4
-
-
-From cec84ff81d9f6ca882908572b984215529b4117b Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Fri, 20 Mar 2009 23:18:12 -0700
-Subject: [PATCH 054/244] xen: netback: document PKT_PROT_LEN
-
-Document the rationale for the existence and value of PKT_PROT_LEN.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 9 +++++++++
- 1 files changed, 9 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 4d63ff3..80b424f 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -113,6 +113,15 @@ static inline int netif_page_index(struct page *pg)
- return idx;
- }
-
-+/*
-+ * This is the amount of packet we copy rather than map, so that the
-+ * guest can't fiddle with the contents of the headers while we do
-+ * packet processing on them (netfilter, routing, etc). This could
-+ * probably do with being larger, since 1) 64-bytes isn't necessarily
-+ * long enough to cover a full christmas-tree ip+tcp header, let alone
-+ * packet contents, and 2) the data is probably in cache anyway
-+ * (though perhaps some other cpu's cache).
-+ */
- #define PKT_PROT_LEN 64
-
- static struct pending_tx_info {
---
-1.7.4
-
-
-From a9402ee935757e8facebc6e886f9912c2c523da7 Mon Sep 17 00:00:00 2001
-From: Christophe Saout <chtephan(a)leto.intern.saout.de>
-Date: Sun, 12 Apr 2009 13:40:27 +0200
-Subject: [PATCH 055/244] xen: netback: use dev_name() instead of removed ->bus_id.
-
-Signed-off-by: Christophe Saout <chtephan(a)leto.intern.saout.de>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/interface.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index dc4fb53..3bb5c20 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -123,7 +123,7 @@ static void netbk_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
- {
- strcpy(info->driver, "netbk");
-- strcpy(info->bus_info, dev->dev.parent->bus_id);
-+ strcpy(info->bus_info, dev_name(dev->dev.parent));
- }
-
- static const struct netif_stat {
---
-1.7.4
-
-
-From 35de1701fca19d693e9722bffbe7609caf1d5ac6 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Mon, 29 Jun 2009 14:04:23 -0700
-Subject: [PATCH 056/244] xen: netback: convert to net_device_ops
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/interface.c | 17 +++++++++++------
- 1 files changed, 11 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 3bb5c20..21c1f95 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -178,6 +178,15 @@ static struct ethtool_ops network_ethtool_ops =
- .get_strings = netbk_get_strings,
- };
-
-+static struct net_device_ops netback_ops =
++static int __init netback_init(void)
+{
-+ .ndo_start_xmit = netif_be_start_xmit,
-+ .ndo_get_stats = netif_be_get_stats,
-+ .ndo_open = net_open,
-+ .ndo_stop = net_close,
-+ .ndo_change_mtu = netbk_change_mtu,
-+};
++ int i;
++ struct page *page;
++ int rc = 0;
++ int group;
+
- struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle)
- {
- int err = 0;
-@@ -213,12 +222,8 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
-
- init_timer(&netif->tx_queue_timeout);
-
-- dev->hard_start_xmit = netif_be_start_xmit;
-- dev->get_stats = netif_be_get_stats;
-- dev->open = net_open;
-- dev->stop = net_close;
-- dev->change_mtu = netbk_change_mtu;
-- dev->features = NETIF_F_IP_CSUM;
-+ dev->netdev_ops = &netback_ops;
-+ dev->features = NETIF_F_IP_CSUM;
-
- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-
---
-1.7.4
-
-
-From c6f3885ef05e96489025e1c1c7299aac7cf43d87 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Fri, 4 Sep 2009 14:55:43 -0700
-Subject: [PATCH 057/244] xen: netback: reinstate missing code
-
-Change c3219dc868fe3e84070d6da2d0759a834b6f7251, "Completely drop flip
-support" was a bit too aggressive in removing code, and removed a chunk
-which was used for not only flip but if a buffer crossed a page boundary.
-Reinstate that code.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 91 +++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 91 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 80b424f..7c0f05b 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -185,6 +185,82 @@ static inline void maybe_schedule_tx_action(void)
- tasklet_schedule(&net_tx_tasklet);
- }
-
-+static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-+{
-+ struct skb_shared_info *ninfo;
-+ struct sk_buff *nskb;
-+ unsigned long offset;
-+ int ret;
-+ int len;
-+ int headlen;
++ if (!xen_pv_domain())
++ return -ENODEV;
+
-+ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++ xen_netbk_group_nr = num_online_cpus();
++ xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
++ if (!xen_netbk) {
++ printk(KERN_ALERT "%s: out of memory\n", __func__);
++ return -ENOMEM;
++ }
++ memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
+
-+ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-+ if (unlikely(!nskb))
-+ goto err;
++ for (group = 0; group < xen_netbk_group_nr; group++) {
++ struct xen_netbk *netbk = &xen_netbk[group];
++ skb_queue_head_init(&netbk->rx_queue);
++ skb_queue_head_init(&netbk->tx_queue);
+
-+ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-+ headlen = skb_end_pointer(nskb) - nskb->data;
-+ if (headlen > skb_headlen(skb))
-+ headlen = skb_headlen(skb);
-+ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-+ BUG_ON(ret);
++ init_timer(&netbk->net_timer);
++ netbk->net_timer.data = (unsigned long)netbk;
++ netbk->net_timer.function = net_alarm;
+
-+ ninfo = skb_shinfo(nskb);
-+ ninfo->gso_size = skb_shinfo(skb)->gso_size;
-+ ninfo->gso_type = skb_shinfo(skb)->gso_type;
++ init_timer(&netbk->netbk_tx_pending_timer);
++ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
++ netbk->netbk_tx_pending_timer.function =
++ netbk_tx_pending_timeout;
+
-+ offset = headlen;
-+ len = skb->len - headlen;
++ netbk->mmap_pages =
++ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
++ if (!netbk->mmap_pages) {
++ printk(KERN_ALERT "%s: out of memory\n", __func__);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ rc = -ENOMEM;
++ goto failed_init;
++ }
+
-+ nskb->len = skb->len;
-+ nskb->data_len = len;
-+ nskb->truesize += len;
++ 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);
++ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
++ }
+
-+ while (len) {
-+ struct page *page;
-+ int copy;
-+ int zero;
++ netbk->pending_cons = 0;
++ netbk->pending_prod = MAX_PENDING_REQS;
++ for (i = 0; i < MAX_PENDING_REQS; i++)
++ netbk->pending_ring[i] = i;
+
-+ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-+ dump_stack();
-+ goto err_free;
++ if (MODPARM_netback_kthread) {
++ init_waitqueue_head(&netbk->kthread.netbk_action_wq);
++ netbk->kthread.task =
++ kthread_create(netbk_action_thread,
++ (void *)netbk,
++ "netback/%u", group);
++
++ if (!IS_ERR(netbk->kthread.task)) {
++ kthread_bind(netbk->kthread.task, group);
++ } else {
++ printk(KERN_ALERT
++ "kthread_run() fails at netback\n");
++ free_empty_pages_and_pagevec(netbk->mmap_pages,
++ MAX_PENDING_REQS);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ rc = PTR_ERR(netbk->kthread.task);
++ goto failed_init;
++ }
++ } else {
++ tasklet_init(&netbk->tasklet.net_tx_tasklet,
++ net_tx_action,
++ (unsigned long)netbk);
++ tasklet_init(&netbk->tasklet.net_rx_tasklet,
++ net_rx_action,
++ (unsigned long)netbk);
+ }
+
-+ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-+ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++ INIT_LIST_HEAD(&netbk->pending_inuse_head);
++ INIT_LIST_HEAD(&netbk->net_schedule_list);
+
-+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-+ if (unlikely(!page))
-+ goto err_free;
++ spin_lock_init(&netbk->net_schedule_list_lock);
+
-+ ret = skb_copy_bits(skb, offset, page_address(page), copy);
-+ BUG_ON(ret);
++ atomic_set(&netbk->netfront_count, 0);
+
-+ ninfo->frags[ninfo->nr_frags].page = page;
-+ ninfo->frags[ninfo->nr_frags].page_offset = 0;
-+ ninfo->frags[ninfo->nr_frags].size = copy;
-+ ninfo->nr_frags++;
++ if (MODPARM_netback_kthread)
++ wake_up_process(netbk->kthread.task);
++ }
+
-+ offset += copy;
-+ len -= copy;
++ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
++ if (MODPARM_copy_skb) {
++ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
++ NULL, 0))
++ netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
++ else
++ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ }
+
-+ offset = nskb->data - skb->data;
++ rc = netif_xenbus_init();
++ if (rc)
++ goto failed_init;
+
-+ nskb->transport_header = skb->transport_header + offset;
-+ nskb->network_header = skb->network_header + offset;
-+ nskb->mac_header = skb->mac_header + offset;
++#ifdef NETBE_DEBUG_INTERRUPT
++ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
++ 0,
++ netif_be_dbg,
++ IRQF_SHARED,
++ "net-be-dbg",
++ &netif_be_dbg);
++#endif
+
-+ return nskb;
++ return 0;
++
++failed_init:
++ for (i = 0; i < group; i++) {
++ struct xen_netbk *netbk = &xen_netbk[i];
++ free_empty_pages_and_pagevec(netbk->mmap_pages,
++ MAX_PENDING_REQS);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ if (MODPARM_netback_kthread)
++ kthread_stop(netbk->kthread.task);
++ }
++ vfree(xen_netbk);
++ return rc;
+
-+ err_free:
-+ kfree_skb(nskb);
-+ err:
-+ return NULL;
+}
+
- static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
- {
- if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
-@@ -218,6 +294,21 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
- goto drop;
-
-+ /*
-+ * XXX For now we also copy skbuffs whose head crosses a page
-+ * boundary, because netbk_gop_skb can't handle them.
-+ */
-+ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
-+ struct sk_buff *nskb = netbk_copy_skb(skb);
-+ if ( unlikely(nskb == NULL) )
-+ goto drop;
-+ /* Copy only the header fields we use in this driver. */
-+ nskb->dev = skb->dev;
-+ nskb->ip_summed = skb->ip_summed;
-+ dev_kfree_skb(skb);
-+ skb = nskb;
++module_init(netback_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
+new file mode 100644
+index 0000000..867dc25
+--- /dev/null
++++ b/drivers/net/xen-netback/xenbus.c
+@@ -0,0 +1,489 @@
++/*
++ * Xenbus code for netif backend
++ *
++ * Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
++ * Copyright (C) 2005 XenSource Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++*/
++
++#include "common.h"
++
++static int connect_rings(struct backend_info *);
++static void connect(struct backend_info *);
++static void backend_create_netif(struct backend_info *be);
++static void unregister_hotplug_status_watch(struct backend_info *be);
++
++static int netback_remove(struct xenbus_device *dev)
++{
++ struct backend_info *be = dev_get_drvdata(&dev->dev);
++
++ unregister_hotplug_status_watch(be);
++ if (be->netif) {
++ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
++ netif_disconnect(be->netif);
++ be->netif = NULL;
+ }
++ kfree(be);
++ dev_set_drvdata(&dev->dev, NULL);
++ return 0;
++}
+
- netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
- !!skb_shinfo(skb)->gso_size;
- netif_get(netif);
---
-1.7.4
-
-
-From 2e290d790877df4368691180f76206ad27a42505 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Wed, 9 Sep 2009 15:19:15 -0700
-Subject: [PATCH 058/244] xen: netback: remove debug noise
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 2 --
- 1 files changed, 0 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 7c0f05b..d7d738e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1537,8 +1537,6 @@ static int __init netback_init(void)
- int i;
- struct page *page;
-
-- printk(KERN_CRIT "*** netif_init\n");
--
- if (!xen_domain())
- return -ENODEV;
-
---
-1.7.4
-
-
-From 3ba3bb7d563704c3050de6116aa0a761a5791428 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 8 Oct 2009 13:23:09 -0400
-Subject: [PATCH 059/244] Fix compile warnings: ignoring return value of
'xenbus_register_backend' ..
-
-We neglect to check the return value of xenbus_register_backend
-and take actions when that fails. This patch fixes that and adds
-code to deal with those type of failures.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 2 +-
- drivers/xen/netback/netback.c | 12 +++++++++++-
- drivers/xen/netback/xenbus.c | 4 ++--
- 3 files changed, 14 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 9056be0..0675946 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -194,7 +194,7 @@ static inline void netif_put(struct xen_netif *netif)
- wake_up(&netif->waiting_to_free);
- }
-
--void netif_xenbus_init(void);
-+int netif_xenbus_init(void);
-
- #define netif_schedulable(netif) \
- (netif_running((netif)->dev) && netback_carrier_ok(netif))
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index d7d738e..860c61e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1536,6 +1536,7 @@ static int __init netback_init(void)
- {
- int i;
- struct page *page;
-+ int rc = 0;
-
- if (!xen_domain())
- return -ENODEV;
-@@ -1583,7 +1584,9 @@ static int __init netback_init(void)
-
- //netif_accel_init();
-
-- netif_xenbus_init();
-+ rc = netif_xenbus_init();
-+ if (rc)
-+ goto failed_init;
-
- #ifdef NETBE_DEBUG_INTERRUPT
- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-@@ -1595,6 +1598,13 @@ static int __init netback_init(void)
- #endif
-
- return 0;
+
-+failed_init:
-+ free_empty_pages_and_pagevec(mmap_pages, MAX_PENDING_REQS);
-+ del_timer(&netbk_tx_pending_timer);
-+ del_timer(&net_timer);
-+ return rc;
++/**
++ * Entry point to this code when a new device is created. Allocate the basic
++ * structures and switch to InitWait.
++ */
++static int netback_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ const char *message;
++ struct xenbus_transaction xbt;
++ int err;
++ int sg;
++ struct backend_info *be = kzalloc(sizeof(struct backend_info),
++ GFP_KERNEL);
++ if (!be) {
++ xenbus_dev_fatal(dev, -ENOMEM,
++ "allocating backend structure");
++ return -ENOMEM;
++ }
+
- }
-
- module_init(netback_init);
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index a492288..c46b235 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -447,8 +447,8 @@ static struct xenbus_driver netback = {
- };
-
-
--void netif_xenbus_init(void)
-+int netif_xenbus_init(void)
- {
- printk(KERN_CRIT "registering netback\n");
-- (void)xenbus_register_backend(&netback);
-+ return xenbus_register_backend(&netback);
- }
---
-1.7.4
-
-
-From 4bc919e07d5dc48cb95b22cc6e90c6110c229343 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Tue, 27 Oct 2009 12:37:50 -0700
-Subject: [PATCH 060/244] xen: netback: don't screw around with packet gso state
-
-These lines were reverted from 2.6.18 netback as the network stack
-was modified to deal with packets shorter than the gso size, so there's
-no need to fiddle with the gso state in netback.
-
-Taken from linux-2.6.18-xen.hg change 8081d19dce89
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 5 -----
- 1 files changed, 0 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 860c61e..9a14976 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1293,11 +1293,6 @@ static unsigned net_tx_build_mops(void)
- skb_shinfo(skb)->frags[0].page = (void *)~0UL;
- }
-
-- if (skb->data_len < skb_shinfo(skb)->gso_size) {
-- skb_shinfo(skb)->gso_size = 0;
-- skb_shinfo(skb)->gso_type = 0;
-- }
--
- __skb_queue_tail(&tx_queue, skb);
-
- pending_cons++;
---
-1.7.4
-
-
-From f2b947783c47a721497e5d325c736234f71501e7 Mon Sep 17 00:00:00 2001
-From: Steven Smith <ssmith(a)weybridge.uk.xensource.com>
-Date: Fri, 30 Oct 2009 13:55:23 -0700
-Subject: [PATCH 061/244] xen: netback: make sure that pg->mapping is never NULL for a
page mapped from a foreign domain.
-
-Otherwise, the foreign maps tracking infrastructure gets confused, and
-thinks that the foreign page is local. This means that you can't
-forward that packet to another foreign domain. This leads to very
-high packet drop, and hence very poor performance.
-
-Signed-off-by: Steven Smith <steven.smith(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 4 ++--
- 1 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 9a14976..111fec7 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -97,12 +97,12 @@ static inline unsigned long idx_to_kaddr(unsigned int idx)
- /* extra field used in struct page */
- static inline void netif_set_page_index(struct page *pg, unsigned int index)
- {
-- *(unsigned long *)&pg->mapping = index;
-+ *(unsigned long *)&pg->mapping = index + 1;
- }
-
- static inline int netif_page_index(struct page *pg)
- {
-- unsigned long idx = (unsigned long)pg->mapping;
-+ unsigned long idx = (unsigned long)pg->mapping - 1;
-
- if (!PageForeign(pg))
- return -1;
---
-1.7.4
-
-
-From df8b27ea0fb2695842104e06caaecb55780577a7 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ijc(a)hellion.org.uk>
-Date: Thu, 3 Dec 2009 21:56:19 +0000
-Subject: [PATCH 062/244] xen: rename netbk module xen-netback.
-
-netbk is rather generic for a modular distro style kernel.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/Makefile | 4 ++--
- 1 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
-index a01a1a3..e346e81 100644
---- a/drivers/xen/netback/Makefile
-+++ b/drivers/xen/netback/Makefile
-@@ -1,3 +1,3 @@
--obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
-+obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
-
--netbk-y := netback.o xenbus.o interface.o
-+xen-netback-y := netback.o xenbus.o interface.o
---
-1.7.4
-
-
-From 279097395ad64ae4df15e206a487cd5fd3be39a8 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Tue, 16 Feb 2010 14:40:37 -0800
-Subject: [PATCH 063/244] xen: netback: use dev_get/set_drvdata() inteface
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/xenbus.c | 10 +++++-----
- 1 files changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index c46b235..79e6fb0 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -35,7 +35,7 @@ static void backend_create_netif(struct backend_info *be);
-
- static int netback_remove(struct xenbus_device *dev)
- {
-- struct backend_info *be = dev->dev.driver_data;
-+ struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- //netback_remove_accelerators(be, dev);
-
-@@ -45,7 +45,7 @@ static int netback_remove(struct xenbus_device *dev)
- be->netif = NULL;
- }
- kfree(be);
-- dev->dev.driver_data = NULL;
-+ dev_set_drvdata(&dev->dev, NULL);
- return 0;
- }
-
-@@ -70,7 +70,7 @@ static int netback_probe(struct xenbus_device *dev,
- }
-
- be->dev = dev;
-- dev->dev.driver_data = be;
++ be->dev = dev;
+ dev_set_drvdata(&dev->dev, be);
-
- sg = 1;
- if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
-@@ -151,7 +151,7 @@ fail:
- */
- static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
- {
-- struct backend_info *be = xdev->dev.driver_data;
++
++ sg = 1;
++ if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
++ sg = 0;
++
++ do {
++ err = xenbus_transaction_start(&xbt);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "starting transaction");
++ goto fail;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
sg);
++ if (err) {
++ message = "writing feature-sg";
++ goto abort_transaction;
++ }
++
++ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
++ "%d", sg);
++ if (err) {
++ message = "writing feature-gso-tcpv4";
++ goto abort_transaction;
++ }
++
++ /* We support rx-copy path. */
++ err = xenbus_printf(xbt, dev->nodename,
++ "feature-rx-copy", "%d", 1);
++ if (err) {
++ message = "writing feature-rx-copy";
++ goto abort_transaction;
++ }
++
++ /*
++ * We don't support rx-flip path (except old guests who don't
++ * grok this feature flag).
++ */
++ err = xenbus_printf(xbt, dev->nodename,
++ "feature-rx-flip", "%d", 0);
++ if (err) {
++ message = "writing feature-rx-flip";
++ goto abort_transaction;
++ }
++
++ err = xenbus_transaction_end(xbt, 0);
++ } while (err == -EAGAIN);
++
++ if (err) {
++ xenbus_dev_fatal(dev, err, "completing transaction");
++ goto fail;
++ }
++
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto fail;
++
++ /* This kicks hotplug scripts, so do it immediately. */
++ backend_create_netif(be);
++
++ return 0;
++
++abort_transaction:
++ xenbus_transaction_end(xbt, 1);
++ xenbus_dev_fatal(dev, err, "%s", message);
++fail:
++ pr_debug("failed");
++ netback_remove(dev);
++ return err;
++}
++
++
++/*
++ * Handle the creation of the hotplug script environment. We add the script
++ * and vif variables to the environment, for the benefit of the vif-* hotplug
++ * scripts.
++ */
++static int netback_uevent(struct xenbus_device *xdev,
++ struct kobj_uevent_env *env)
++{
+ struct backend_info *be = dev_get_drvdata(&xdev->dev);
- struct xen_netif *netif = be->netif;
- char *val;
-
-@@ -211,7 +211,7 @@ static void backend_create_netif(struct backend_info *be)
- static void frontend_changed(struct xenbus_device *dev,
- enum xenbus_state frontend_state)
- {
-- struct backend_info *be = dev->dev.driver_data;
-+ struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- DPRINTK("%s", xenbus_strstate(frontend_state));
-
---
-1.7.4
-
-
-From 31d0b5f5763faf607e32f3b5a0f6b37a34bbbf09 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Tue, 16 Feb 2010 14:41:12 -0800
-Subject: [PATCH 064/244] xen: netback: include linux/sched.h for TASK_* definitions
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 0675946..d8653d3 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -38,6 +38,8 @@
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/wait.h>
-+#include <linux/sched.h>
++ char *val;
++
++ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
++ if (IS_ERR(val)) {
++ int err = PTR_ERR(val);
++ xenbus_dev_fatal(xdev, err, "reading script");
++ return err;
++ } else {
++ if (add_uevent_var(env, "script=%s", val)) {
++ kfree(val);
++ return -ENOMEM;
++ }
++ kfree(val);
++ }
++
++ if (!be || !be->netif)
++ return 0;
++
++ return add_uevent_var(env, "vif=%s", be->netif->dev->name);
++}
++
++
++static void backend_create_netif(struct backend_info *be)
++{
++ int err;
++ long handle;
++ struct xenbus_device *dev = be->dev;
++
++ if (be->netif != NULL)
++ return;
++
++ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
++ if (err != 1) {
++ xenbus_dev_fatal(dev, err, "reading handle");
++ return;
++ }
++
++ be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
++ if (IS_ERR(be->netif)) {
++ err = PTR_ERR(be->netif);
++ be->netif = NULL;
++ xenbus_dev_fatal(dev, err, "creating interface");
++ return;
++ }
++
++ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
++}
++
+
- #include <xen/interface/io/netif.h>
- #include <asm/io.h>
- #include <asm/pgalloc.h>
---
-1.7.4
-
-
-From cdefc88924b3cdfcac64be737a00a4ec5593cfd5 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 23 Feb 2010 11:52:27 +0000
-Subject: [PATCH 065/244] xen: netback: remove unused xen_network_done code
-
-It has been disabled effectively forever.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 23 -----------------------
- 1 files changed, 0 insertions(+), 23 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 111fec7..4b24893 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -343,25 +343,6 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- return 0;
- }
-
--#if 0
--static void xen_network_done_notify(void)
--{
-- static struct net_device *eth0_dev = NULL;
-- if (unlikely(eth0_dev == NULL))
-- eth0_dev = __dev_get_by_name("eth0");
-- netif_rx_schedule(eth0_dev);
--}
--/*
-- * Add following to poll() function in NAPI driver (Tigon3 is example):
-- * if ( xen_network_done() )
-- * tg3_enable_ints(tp);
-- */
--int xen_network_done(void)
--{
-- return skb_queue_empty(&rx_queue);
--}
--#endif
--
- struct netrx_pending_operations {
- unsigned trans_prod, trans_cons;
- unsigned mmu_prod, mmu_mcl;
-@@ -664,10 +645,6 @@ static void net_rx_action(unsigned long unused)
- /* More work to do? */
- if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
- tasklet_schedule(&net_rx_tasklet);
--#if 0
-- else
-- xen_network_done_notify();
--#endif
- }
-
- static void net_alarm(unsigned long unused)
---
-1.7.4
-
-
-From 994be068dd9947cedcee69a7185e54738cda33d4 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 23 Feb 2010 11:58:26 +0000
-Subject: [PATCH 066/244] xen: netback: factor disconnect from backend into new function.
-
-Makes subsequent patches cleaner.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/xenbus.c | 16 ++++++++++++----
- 1 files changed, 12 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index 79e6fb0..1f36b4d4 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -205,6 +205,16 @@ static void backend_create_netif(struct backend_info *be)
- }
-
-
+static void disconnect_backend(struct xenbus_device *dev)
+{
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ if (be->netif) {
++ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
+ netif_disconnect(be->netif);
+ be->netif = NULL;
+ }
+}
+
- /**
- * Callback received when the frontend's state changes.
- */
-@@ -238,11 +248,9 @@ static void frontend_changed(struct xenbus_device *dev,
- break;
-
- case XenbusStateClosing:
-- if (be->netif) {
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void frontend_changed(struct xenbus_device *dev,
++ enum xenbus_state frontend_state)
++{
++ struct backend_info *be = dev_get_drvdata(&dev->dev);
++
++ pr_debug("frontend state %s", xenbus_strstate(frontend_state));
++
++ be->frontend_state = frontend_state;
++
++ switch (frontend_state) {
++ case XenbusStateInitialising:
++ if (dev->state == XenbusStateClosed) {
++ printk(KERN_INFO "%s: %s: prepare for reconnect\n",
++ __func__, dev->nodename);
++ xenbus_switch_state(dev, XenbusStateInitWait);
++ }
++ break;
++
++ case XenbusStateInitialised:
++ break;
++
++ case XenbusStateConnected:
++ if (dev->state == XenbusStateConnected)
++ break;
++ backend_create_netif(be);
+ if (be->netif)
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-- netif_disconnect(be->netif);
-- be->netif = NULL;
-- }
++ connect(be);
++ break;
++
++ case XenbusStateClosing:
++ if (be->netif)
++ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+ disconnect_backend(dev);
- xenbus_switch_state(dev, XenbusStateClosing);
- break;
-
---
-1.7.4
-
-
-From 9dcb4c18e5b29d8862cd7783d5b0040913010563 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 23 Feb 2010 12:10:24 +0000
-Subject: [PATCH 067/244] xen: netback: wait for hotplug scripts to complete before
signalling connected to frontend
-
-Avoid the situation where the frontend is sending packets but the
-domain 0 bridging (or whatever) is not yet configured (because the
-hotplug scripts are too slow) and so packets get dropped.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Steven.Smith(a)citrix.com
----
- drivers/xen/netback/common.h | 2 +
- drivers/xen/netback/xenbus.c | 45 +++++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 46 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index d8653d3..1983768 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -145,6 +145,8 @@ struct backend_info {
- struct xenbus_device *dev;
- struct xen_netif *netif;
- enum xenbus_state frontend_state;
-+ struct xenbus_watch hotplug_status_watch;
-+ int have_hotplug_status_watch:1;
-
- /* State relating to the netback accelerator */
- void *netback_accel_priv;
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index 1f36b4d4..d2407cc 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -32,6 +32,7 @@
- static int connect_rings(struct backend_info *);
- static void connect(struct backend_info *);
- static void backend_create_netif(struct backend_info *be);
-+static void unregister_hotplug_status_watch(struct backend_info *be);
-
- static int netback_remove(struct xenbus_device *dev)
- {
-@@ -39,8 +40,10 @@ static int netback_remove(struct xenbus_device *dev)
-
- //netback_remove_accelerators(be, dev);
-
-+ unregister_hotplug_status_watch(be);
- if (be->netif) {
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-+ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
- netif_disconnect(be->netif);
- be->netif = NULL;
- }
-@@ -210,6 +213,7 @@ static void disconnect_backend(struct xenbus_device *dev)
- struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- if (be->netif) {
-+ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
- netif_disconnect(be->netif);
- be->netif = NULL;
- }
-@@ -329,6 +333,36 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
- return 0;
- }
-
-+static void unregister_hotplug_status_watch(struct backend_info *be)
-+{
-+ if (be->have_hotplug_status_watch) {
-+ unregister_xenbus_watch(&be->hotplug_status_watch);
-+ kfree(be->hotplug_status_watch.node);
++ xenbus_switch_state(dev, XenbusStateClosing);
++ break;
++
++ case XenbusStateClosed:
++ xenbus_switch_state(dev, XenbusStateClosed);
++ if (xenbus_dev_is_online(dev))
++ break;
++ /* fall through if not online */
++ case XenbusStateUnknown:
++ device_unregister(&dev->dev);
++ break;
++
++ default:
++ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++ frontend_state);
++ break;
+ }
-+ be->have_hotplug_status_watch = 0;
+}
+
-+static void hotplug_status_changed(struct xenbus_watch *watch,
-+ const char **vec,
-+ unsigned int vec_size)
++
++static void xen_net_read_rate(struct xenbus_device *dev,
++ unsigned long *bytes, unsigned long *usec)
+{
-+ struct backend_info *be = container_of(watch,
-+ struct backend_info,
-+ hotplug_status_watch);
-+ char *str;
-+ unsigned int len;
++ char *s, *e;
++ unsigned long b, u;
++ char *ratestr;
+
-+ str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status",
&len);
-+ if (IS_ERR(str))
++ /* Default to unlimited bandwidth. */
++ *bytes = ~0UL;
++ *usec = 0;
++
++ ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
++ if (IS_ERR(ratestr))
+ return;
-+ if (len == sizeof("connected")-1 && !memcmp(str,
"connected", len)) {
++
++ s = ratestr;
++ b = simple_strtoul(s, &e, 10);
++ if ((s == e) || (*e != ','))
++ goto fail;
++
++ s = e + 1;
++ u = simple_strtoul(s, &e, 10);
++ if ((s == e) || (*e != '\0'))
++ goto fail;
++
++ *bytes = b;
++ *usec = u;
++
++ kfree(ratestr);
++ return;
++
++ fail:
++ pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
++ kfree(ratestr);
++}
++
++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
++{
++ char *s, *e, *macstr;
++ int i;
++
++ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++ if (IS_ERR(macstr))
++ return PTR_ERR(macstr);
++
++ for (i = 0; i < ETH_ALEN; i++) {
++ mac[i] = simple_strtoul(s, &e, 16);
++ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++ kfree(macstr);
++ return -ENOENT;
++ }
++ s = e+1;
++ }
++
++ kfree(macstr);
++ return 0;
++}
++
++static void unregister_hotplug_status_watch(struct backend_info *be)
++{
++ if (be->have_hotplug_status_watch) {
++ unregister_xenbus_watch(&be->hotplug_status_watch);
++ kfree(be->hotplug_status_watch.node);
++ }
++ be->have_hotplug_status_watch = 0;
++}
++
++static void hotplug_status_changed(struct xenbus_watch *watch,
++ const char **vec,
++ unsigned int vec_size)
++{
++ struct backend_info *be = container_of(watch,
++ struct backend_info,
++ hotplug_status_watch);
++ char *str;
++ unsigned int len;
++
++ str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status",
&len);
++ if (IS_ERR(str))
++ return;
++ if (len == sizeof("connected")-1 && !memcmp(str,
"connected", len)) {
+ xenbus_switch_state(be->dev, XenbusStateConnected);
+ /* Not interested in this watch anymore. */
+ unregister_hotplug_status_watch(be);
@@ -15049,14 +15560,25 @@ index 1f36b4d4..d2407cc 100644
+ kfree(str);
+}
+
- static void connect(struct backend_info *be)
- {
- int err;
-@@ -348,7 +382,16 @@ static void connect(struct backend_info *be)
- &be->netif->credit_usec);
- be->netif->remaining_credit = be->netif->credit_bytes;
-
-- xenbus_switch_state(dev, XenbusStateConnected);
++static void connect(struct backend_info *be)
++{
++ int err;
++ struct xenbus_device *dev = be->dev;
++
++ err = connect_rings(be);
++ if (err)
++ return;
++
++ err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
++ if (err) {
++ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
++ return;
++ }
++
++ xen_net_read_rate(dev, &be->netif->credit_bytes,
++ &be->netif->credit_usec);
++ be->netif->remaining_credit = be->netif->credit_bytes;
++
+ unregister_hotplug_status_watch(be);
+ err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
+ hotplug_status_changed,
@@ -15067,11734 +15589,4415 @@ index 1f36b4d4..d2407cc 100644
+ } else {
+ be->have_hotplug_status_watch = 1;
+ }
-
- netif_wake_queue(be->netif->dev);
- }
---
-1.7.4
-
-
-From 509cc7f20f866277a8f5d5895bb266b5b68aac6d Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 23 Feb 2010 12:11:51 +0000
-Subject: [PATCH 068/244] xen: netback: Always pull through PKT_PROT_LEN bytes into the
linear part of an skb.
-
-Previously PKT_PROT_LEN would only have an effect on the first fragment.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 10 ++++++++++
- 1 files changed, 10 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 4b24893..d4a7a56 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1334,6 +1334,16 @@ static void net_tx_submit(void)
-
- netbk_fill_frags(skb);
-
-+ /*
-+ * If the initial fragment was < PKT_PROT_LEN then
-+ * pull through some bytes from the other fragments to
-+ * increase the linear region to PKT_PROT_LEN bytes.
-+ */
-+ if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
-+ int target = min_t(int, skb->len, PKT_PROT_LEN);
-+ __pskb_pull_tail(skb, target - skb_headlen(skb));
-+ }
+
- skb->dev = netif->dev;
- skb->protocol = eth_type_trans(skb, skb->dev);
-
---
-1.7.4
-
-
-From 673c82b5110cfffafe1e1978bc07d6d10d111d50 Mon Sep 17 00:00:00 2001
-From: Steven Smith <ssmith(a)xensource.com>
-Date: Tue, 23 Feb 2010 11:49:26 +0000
-Subject: [PATCH 069/244] xen: netback: try to pull a minimum of 72 bytes into the skb
data area
- when receiving a packet into netback.
-
-The previous number, 64, tended to place a fragment boundary in the middle of
-the TCP header options and led to unnecessary fragmentation in Windows <->
-Windows networking.
-
-Signed-off-by: Steven Smith <ssmith(a)xensource.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 9 +++------
- 1 files changed, 3 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index d4a7a56..44357d7 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -116,13 +116,10 @@ static inline int netif_page_index(struct page *pg)
- /*
- * This is the amount of packet we copy rather than map, so that the
- * guest can't fiddle with the contents of the headers while we do
-- * packet processing on them (netfilter, routing, etc). This could
-- * probably do with being larger, since 1) 64-bytes isn't necessarily
-- * long enough to cover a full christmas-tree ip+tcp header, let alone
-- * packet contents, and 2) the data is probably in cache anyway
-- * (though perhaps some other cpu's cache).
-+ * packet processing on them (netfilter, routing, etc). 72 is enough
-+ * to cover TCP+IP headers including options.
- */
--#define PKT_PROT_LEN 64
-+#define PKT_PROT_LEN 72
-
- static struct pending_tx_info {
- struct xen_netif_tx_request req;
---
-1.7.4
-
-
-From c83bd213efd3ebf700189249c30d987b1cb14d7e Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 23 Feb 2010 11:54:30 +0000
-Subject: [PATCH 070/244] xen: netback: Allow setting of large MTU before rings have
connected.
-
-This allows large MTU to be configured by the VIF hotplug
-script. Previously this would fail because at the point the hotplug
-script runs the VIF features have most likely not been negotiated with
-the frontend and so SG has not yet been enabled. Invert this behaviour
-so that SG is assumed present until negotiations prove otherwise and
-reduce MTU at that point.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/interface.c | 6 +++++-
- drivers/xen/netback/xenbus.c | 8 +++++---
- 2 files changed, 10 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 21c1f95..b23b14d 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -104,6 +104,9 @@ static int netbk_set_sg(struct net_device *dev, u32 data)
- return -ENOSYS;
- }
-
-+ if (dev->mtu > ETH_DATA_LEN)
-+ dev->mtu = ETH_DATA_LEN;
++ netif_wake_queue(be->netif->dev);
++}
+
- return ethtool_op_set_sg(dev, data);
- }
-
-@@ -207,6 +210,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- memset(netif, 0, sizeof(*netif));
- netif->domid = domid;
- netif->handle = handle;
-+ netif->features = NETIF_F_SG;
- atomic_set(&netif->refcnt, 1);
- init_waitqueue_head(&netif->waiting_to_free);
- netif->dev = dev;
-@@ -223,7 +227,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- init_timer(&netif->tx_queue_timeout);
-
- dev->netdev_ops = &netback_ops;
-- dev->features = NETIF_F_IP_CSUM;
-+ dev->features = NETIF_F_IP_CSUM|NETIF_F_SG;
-
- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index d2407cc..fcd3c34 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -445,9 +445,11 @@ static int connect_rings(struct backend_info *be)
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d",
&val) < 0)
- val = 0;
-- if (val) {
-- be->netif->features |= NETIF_F_SG;
-- be->netif->dev->features |= NETIF_F_SG;
-+ if (!val) {
-+ be->netif->features &= ~NETIF_F_SG;
-+ be->netif->dev->features &= ~NETIF_F_SG;
-+ if (be->netif->dev->mtu > ETH_DATA_LEN)
-+ be->netif->dev->mtu = ETH_DATA_LEN;
- }
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
"%d",
---
-1.7.4
-
-
-From e5cd35b00cb63f3a3fa1651260a58d59bbc134b7 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Fri, 19 Mar 2010 13:09:16 -0700
-Subject: [PATCH 071/244] xen: netback: use get_sset_count rather than obsolete
get_stats_count
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/interface.c | 11 ++++++++---
- 1 files changed, 8 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index b23b14d..086d939 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -136,9 +136,14 @@ static const struct netif_stat {
- { "copied_skbs", offsetof(struct xen_netif, nr_copied_skbs) },
- };
-
--static int netbk_get_stats_count(struct net_device *dev)
-+static int netbk_get_sset_count(struct net_device *dev, int string_set)
- {
-- return ARRAY_SIZE(netbk_stats);
-+ switch (string_set) {
-+ case ETH_SS_STATS:
-+ return ARRAY_SIZE(netbk_stats);
-+ default:
-+ return -EINVAL;
++
++static int connect_rings(struct backend_info *be)
++{
++ struct xen_netif *netif = be->netif;
++ struct xenbus_device *dev = be->dev;
++ unsigned long tx_ring_ref, rx_ring_ref;
++ unsigned int evtchn, rx_copy;
++ int err;
++ int val;
++
++ err = xenbus_gather(XBT_NIL, dev->otherend,
++ "tx-ring-ref", "%lu", &tx_ring_ref,
++ "rx-ring-ref", "%lu", &rx_ring_ref,
++ "event-channel", "%u", &evtchn, NULL);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "reading %s/ring-ref and event-channel",
++ dev->otherend);
++ return err;
+ }
- }
-
- static void netbk_get_ethtool_stats(struct net_device *dev,
-@@ -176,7 +181,7 @@ static struct ethtool_ops network_ethtool_ops =
- .set_tso = netbk_set_tso,
- .get_link = ethtool_op_get_link,
-
-- .get_stats_count = netbk_get_stats_count,
-+ .get_sset_count = netbk_get_sset_count,
- .get_ethtool_stats = netbk_get_ethtool_stats,
- .get_strings = netbk_get_strings,
- };
---
-1.7.4
-
-
-From 0c34835ee66ad641f01a8077a973b7ec1bfdcd86 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 11 May 2010 09:33:42 +0100
-Subject: [PATCH 072/244] xen: netback: correctly setup skb->ip_summed on receive
-
-In 2.6.18 CHECKSUM_PARTIAL and CHECKSUM_UNNECESSARY were both synonyms for
-CHECKSUM_HW. This is no longer the case and we need to select the correct one.
-
- data_validated csum_blank -> ip_summed
- 0 0 CHECKSUM_NONE
- 0 1 CHECKSUM_PARTIAL
- 1 0 CHECKSUM_UNNECESSARY
- 1 1 CHECKSUM_PARTIAL
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Tested-by: Matej Zary <zary(a)cvtisr.sk>
-Tested-by: Michael D Labriola <mlabriol(a)gdeb.com>
----
- drivers/xen/netback/netback.c | 10 +++-------
- 1 files changed, 3 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 44357d7..725da0f 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1320,14 +1320,10 @@ static void net_tx_submit(void)
- netif_idx_release(pending_idx);
- }
-
-- /*
-- * Old frontends do not assert data_validated but we
-- * can infer it from csum_blank so test both flags.
-- */
-- if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank))
-+ if (txp->flags & NETTXF_csum_blank)
- skb->ip_summed = CHECKSUM_PARTIAL;
-- else
-- skb->ip_summed = CHECKSUM_NONE;
-+ else if (txp->flags & NETTXF_data_validated)
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-
- netbk_fill_frags(skb);
-
---
-1.7.4
-
-
-From 094944631cc5a9d6e623302c987f78117c0bf7ac Mon Sep 17 00:00:00 2001
-From: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Date: Wed, 19 May 2010 16:58:56 -0700
-Subject: [PATCH 073/244] xen: netback: Move global/static variables into struct
xen_netbk.
-
-Bundle a lot of discrete variables into a single structure.
-
-Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 59 +++++++
- drivers/xen/netback/netback.c | 360 ++++++++++++++++++++---------------------
- 2 files changed, 232 insertions(+), 187 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 1983768..00208f4 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -222,4 +222,63 @@ static inline int netbk_can_sg(struct net_device *dev)
- return netif->features & NETIF_F_SG;
- }
-
-+struct pending_tx_info {
-+ struct xen_netif_tx_request req;
-+ struct xen_netif *netif;
-+};
-+typedef unsigned int pending_ring_idx_t;
+
-+struct netbk_rx_meta {
-+ skb_frag_t frag;
-+ int id;
-+};
++ err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy",
"%u",
++ &rx_copy);
++ if (err == -ENOENT) {
++ err = 0;
++ rx_copy = 0;
++ }
++ if (err < 0) {
++ xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
++ dev->otherend);
++ return err;
++ }
++ if (!rx_copy)
++ return -EOPNOTSUPP;
+
-+struct netbk_tx_pending_inuse {
-+ struct list_head list;
-+ unsigned long alloc_time;
-+};
++ if (netif->dev->tx_queue_len != 0) {
++ if (xenbus_scanf(XBT_NIL, dev->otherend,
++ "feature-rx-notify", "%d", &val) < 0)
++ val = 0;
++ if (val)
++ netif->can_queue = 1;
++ else
++ /* Must be non-zero for pfifo_fast to work. */
++ netif->dev->tx_queue_len = 1;
++ }
+
-+#define MAX_PENDING_REQS 256
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
++ "%d", &val) < 0)
++ val = 0;
++ netif->can_sg = !!val;
+
-+struct xen_netbk {
-+ struct tasklet_struct net_tx_tasklet;
-+ struct tasklet_struct net_rx_tasklet;
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
++ "%d", &val) < 0)
++ val = 0;
++ netif->gso = !!val;
+
-+ struct sk_buff_head rx_queue;
-+ struct sk_buff_head tx_queue;
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
++ "%d", &val) < 0)
++ val = 0;
++ netif->gso_prefix = !!val;
+
-+ struct timer_list net_timer;
-+ struct timer_list netbk_tx_pending_timer;
++ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
++ "%d", &val) < 0)
++ val = 0;
++ netif->csum = !val;
+
-+ struct page **mmap_pages;
++ /* Set dev->features */
++ netif_set_features(netif);
+
-+ pending_ring_idx_t pending_prod;
-+ pending_ring_idx_t pending_cons;
-+ pending_ring_idx_t dealloc_prod;
-+ pending_ring_idx_t dealloc_cons;
++ /* Map the shared frame, irq etc. */
++ err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
++ if (err) {
++ xenbus_dev_fatal(dev, err,
++ "mapping shared-frames %lu/%lu port %u",
++ tx_ring_ref, rx_ring_ref, evtchn);
++ return err;
++ }
++ return 0;
++}
+
-+ struct list_head pending_inuse_head;
-+ struct list_head net_schedule_list;
+
-+ /* Protect the net_schedule_list in netif. */
-+ spinlock_t net_schedule_list_lock;
++/* ** Driver Registration ** */
+
-+ 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];
++static const struct xenbus_device_id netback_ids[] = {
++ { "vif" },
++ { "" }
++};
+
-+ 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];
-+ unsigned char rx_notify[NR_IRQS];
-+ u16 notify_list[NET_RX_RING_SIZE];
-+ struct netbk_rx_meta meta[NET_RX_RING_SIZE];
++
++static struct xenbus_driver netback = {
++ .name = "vif",
++ .owner = THIS_MODULE,
++ .ids = netback_ids,
++ .probe = netback_probe,
++ .remove = netback_remove,
++ .uevent = netback_uevent,
++ .otherend_changed = frontend_changed,
+};
+
- #endif /* __NETIF__BACKEND__COMMON_H__ */
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 725da0f..417f497 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -48,16 +48,7 @@
-
- /*define NETBE_DEBUG_INTERRUPT*/
++
++int netif_xenbus_init(void)
++{
++ printk(KERN_CRIT "registering netback\n");
++ return xenbus_register_backend(&netback);
++}
+diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
+index 30290a8..5a48ce9 100644
+--- a/drivers/xen/Kconfig
++++ b/drivers/xen/Kconfig
+@@ -37,13 +37,6 @@ config XEN_BACKEND
+ Support for backend device drivers that provide I/O services
+ to other virtual machines.
--struct netbk_rx_meta {
-- skb_frag_t frag;
-- int id;
--};
--
--struct netbk_tx_pending_inuse {
-- struct list_head list;
-- unsigned long alloc_time;
+-config XEN_NETDEV_BACKEND
+- tristate "Xen backend network device"
+- depends on XEN_BACKEND && NET
+- help
+- Implement the network backend driver, which passes packets
+- from the guest domain's frontend drivers to the network.
+-
+ config XENFS
+ tristate "Xen filesystem"
+ default y
+diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
+index c0e0509..533a199 100644
+--- a/drivers/xen/Makefile
++++ b/drivers/xen/Makefile
+@@ -9,7 +9,6 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
+ obj-$(CONFIG_XEN_BALLOON) += balloon.o
+ obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
+ obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
+-obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
+ obj-$(CONFIG_XENFS) += xenfs/
+ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
+ obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o
+diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
+deleted file mode 100644
+index e346e81..0000000
+--- a/drivers/xen/netback/Makefile
++++ /dev/null
+@@ -1,3 +0,0 @@
+-obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
+-
+-xen-netback-y := netback.o xenbus.o interface.o
+diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
+deleted file mode 100644
+index 49dc4cf..0000000
+--- a/drivers/xen/netback/common.h
++++ /dev/null
+@@ -1,273 +0,0 @@
+-/*
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License version 2
+- * as published by the Free Software Foundation; or, when distributed
+- * separately from the Linux kernel or incorporated into other
+- * software packages, subject to the following license:
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining a copy
+- * of this source file (the "Software"), to deal in the Software without
+- * restriction, including without limitation the rights to use, copy, modify,
+- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+- * and to permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be included in
+- * all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+- * IN THE SOFTWARE.
+- */
+-
+-#ifndef __NETIF__BACKEND__COMMON_H__
+-#define __NETIF__BACKEND__COMMON_H__
+-
+-#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+-
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/slab.h>
+-#include <linux/ip.h>
+-#include <linux/in.h>
+-#include <linux/io.h>
+-#include <linux/netdevice.h>
+-#include <linux/etherdevice.h>
+-#include <linux/wait.h>
+-#include <linux/sched.h>
+-
+-#include <xen/interface/io/netif.h>
+-#include <asm/pgalloc.h>
+-#include <xen/interface/grant_table.h>
+-#include <xen/grant_table.h>
+-#include <xen/xenbus.h>
+-
+-struct xen_netif {
+- /* Unique identifier for this interface. */
+- domid_t domid;
+- int group;
+- unsigned int handle;
+-
+- u8 fe_dev_addr[6];
+-
+- /* Physical parameters of the comms window. */
+- grant_handle_t tx_shmem_handle;
+- grant_ref_t tx_shmem_ref;
+- grant_handle_t rx_shmem_handle;
+- grant_ref_t rx_shmem_ref;
+- unsigned int irq;
+-
+- /* The shared rings and indexes. */
+- struct xen_netif_tx_back_ring tx;
+- struct xen_netif_rx_back_ring rx;
+- struct vm_struct *tx_comms_area;
+- struct vm_struct *rx_comms_area;
+-
+- /* Flags that must not be set in dev->features */
+- int features_disabled;
+-
+- /* Frontend feature information. */
+- u8 can_sg:1;
+- u8 gso:1;
+- u8 gso_prefix:1;
+- u8 csum:1;
+-
+- /* Internal feature information. */
+- u8 can_queue:1; /* can queue packets for receiver? */
+-
+- /* Allow netif_be_start_xmit() to peek ahead in the rx request
+- * ring. This is a prediction of what rx_req_cons will be once
+- * all queued skbs are put on the ring. */
+- RING_IDX rx_req_cons_peek;
+-
+- /* 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;
+-
+- /* Statistics */
+- int nr_copied_skbs;
+- int rx_gso_checksum_fixup;
+-
+- /* Miscellaneous private stuff. */
+- struct list_head list; /* scheduling list */
+- atomic_t refcnt;
+- struct net_device *dev;
+- struct net_device_stats stats;
+-
+- unsigned int carrier;
+-
+- wait_queue_head_t waiting_to_free;
-};
-
-+static struct xen_netbk *netbk;
-
- static void netif_idx_release(u16 pending_idx);
- static void make_tx_response(struct xen_netif *netif,
-@@ -71,22 +62,12 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
- 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);
+-/*
+- * Implement our own carrier flag: the network stack's version causes delays
+- * when the carrier is re-enabled (in particular, dev_activate() may not
+- * immediately be called, which can cause packet loss; also the etherbridge
+- * can be rather lazy in activating its port).
+- */
+-#define netback_carrier_on(netif) ((netif)->carrier = 1)
+-#define netback_carrier_off(netif) ((netif)->carrier = 0)
+-#define netback_carrier_ok(netif) ((netif)->carrier)
-
--static struct timer_list net_timer;
--static struct timer_list netbk_tx_pending_timer;
-
--#define MAX_PENDING_REQS 256
+-enum {
+- NETBK_DONT_COPY_SKB,
+- NETBK_DELAYED_COPY_SKB,
+- NETBK_ALWAYS_COPY_SKB,
+-};
-
--static struct sk_buff_head rx_queue;
+-extern int netbk_copy_skb_mode;
-
--static struct page **mmap_pages;
- static inline unsigned long idx_to_pfn(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)
-@@ -107,7 +88,7 @@ static inline int netif_page_index(struct page *pg)
- if (!PageForeign(pg))
- return -1;
-
-- if ((idx >= MAX_PENDING_REQS) || (mmap_pages[idx] != pg))
-+ if ((idx >= MAX_PENDING_REQS) || (netbk->mmap_pages[idx] != pg))
- return -1;
-
- return idx;
-@@ -121,46 +102,17 @@ static inline int netif_page_index(struct page *pg)
- */
- #define PKT_PROT_LEN 72
-
--static struct pending_tx_info {
-- struct xen_netif_tx_request req;
+-struct backend_info {
+- struct xenbus_device *dev;
- struct xen_netif *netif;
--} pending_tx_info[MAX_PENDING_REQS];
--static u16 pending_ring[MAX_PENDING_REQS];
--typedef unsigned int pending_ring_idx_t;
+- enum xenbus_state frontend_state;
+- struct xenbus_watch hotplug_status_watch;
+- int have_hotplug_status_watch:1;
+-};
-
- static inline pending_ring_idx_t pending_index(unsigned i)
- {
- return i & (MAX_PENDING_REQS-1);
- }
-
--static pending_ring_idx_t pending_prod, pending_cons;
+-#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+-#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-
- static inline pending_ring_idx_t nr_pending_reqs(void)
- {
-- return MAX_PENDING_REQS - pending_prod + pending_cons;
-+ return MAX_PENDING_REQS -
-+ netbk->pending_prod + netbk->pending_cons;
- }
-
--/* Freed TX SKBs get batched on this ring before return to pending_ring. */
--static u16 dealloc_ring[MAX_PENDING_REQS];
--static pending_ring_idx_t dealloc_prod, dealloc_cons;
+-void netif_disconnect(struct xen_netif *netif);
-
--/* 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);
+-void netif_set_features(struct xen_netif *netif);
+-struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
+- unsigned int handle);
+-int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+- unsigned long rx_ring_ref, unsigned int evtchn);
-
--static struct sk_buff_head tx_queue;
+-static inline void netif_get(struct xen_netif *netif)
+-{
+- atomic_inc(&netif->refcnt);
+-}
-
--static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
--static struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
--static struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+-static inline void netif_put(struct xen_netif *netif)
+-{
+- if (atomic_dec_and_test(&netif->refcnt))
+- wake_up(&netif->waiting_to_free);
+-}
-
--static LIST_HEAD(net_schedule_list);
--static DEFINE_SPINLOCK(net_schedule_list_lock);
+-int netif_xenbus_init(void);
-
--#define MAX_MFN_ALLOC 64
--static unsigned long mfn_list[MAX_MFN_ALLOC];
--static unsigned int alloc_index = 0;
+-#define netif_schedulable(netif) \
+- (netif_running((netif)->dev) && netback_carrier_ok(netif))
-
- /* Setting this allows the safe use of this driver without netloop. */
- static int MODPARM_copy_skb = 1;
- module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
-@@ -168,18 +120,12 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
-
- int netbk_copy_skb_mode;
-
--static inline unsigned long alloc_mfn(void)
+-void netif_schedule_work(struct xen_netif *netif);
+-void netif_deschedule_work(struct xen_netif *netif);
+-
+-int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-struct net_device_stats *netif_be_get_stats(struct net_device *dev);
+-irqreturn_t netif_be_int(int irq, void *dev_id);
+-
+-static inline int netbk_can_queue(struct net_device *dev)
-{
-- BUG_ON(alloc_index == 0);
-- return mfn_list[--alloc_index];
+- struct xen_netif *netif = netdev_priv(dev);
+- return netif->can_queue;
-}
-
- static inline void maybe_schedule_tx_action(void)
- {
- smp_mb();
- if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
-- !list_empty(&net_schedule_list))
-- tasklet_schedule(&net_tx_tasklet);
-+ !list_empty(&netbk->net_schedule_list))
-+ tasklet_schedule(&netbk->net_tx_tasklet);
- }
-
- static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-@@ -328,9 +274,8 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
- }
- }
+-static inline int netbk_can_sg(struct net_device *dev)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- return netif->can_sg;
+-}
+-
+-struct pending_tx_info {
+- struct xen_netif_tx_request req;
+- struct xen_netif *netif;
+-};
+-typedef unsigned int pending_ring_idx_t;
+-
+-struct netbk_rx_meta {
+- int id;
+- int size;
+- int gso_size;
+-};
+-
+-struct netbk_tx_pending_inuse {
+- struct list_head list;
+- unsigned long alloc_time;
+-};
+-
+-#define MAX_PENDING_REQS 256
+-
+-#define MAX_BUFFER_OFFSET PAGE_SIZE
+-
+-/* extra field used in struct page */
+-union page_ext {
+- struct {
+-#if BITS_PER_LONG < 64
+-#define IDX_WIDTH 8
+-#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
+- unsigned int group:GROUP_WIDTH;
+- unsigned int idx:IDX_WIDTH;
+-#else
+- unsigned int group, idx;
+-#endif
+- } e;
+- void *mapping;
+-};
+-
+-struct xen_netbk {
+- union {
+- struct {
+- struct tasklet_struct net_tx_tasklet;
+- struct tasklet_struct net_rx_tasklet;
+- } tasklet;
+-
+- struct {
+- wait_queue_head_t netbk_action_wq;
+- struct task_struct *task;
+- } kthread;
+- };
+-
+- struct sk_buff_head rx_queue;
+- struct sk_buff_head tx_queue;
+-
+- struct timer_list net_timer;
+- struct timer_list netbk_tx_pending_timer;
+-
+- struct page **mmap_pages;
+-
+- 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 net_schedule_list;
+-
+- /* Protect the net_schedule_list in netif. */
+- spinlock_t net_schedule_list_lock;
+-
+- atomic_t netfront_count;
+-
+- 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];
-
-- skb_queue_tail(&rx_queue, skb);
-- tasklet_schedule(&net_rx_tasklet);
-+ skb_queue_tail(&netbk->rx_queue, skb);
-+ tasklet_schedule(&netbk->net_rx_tasklet);
-
- return 0;
-
-@@ -372,7 +317,7 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
- 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];
-+ struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
- copy_gop->source.domid = src_pend->netif->domid;
- copy_gop->source.u.ref = src_pend->req.gref;
- copy_gop->flags |= GNTCOPY_source_gref;
-@@ -487,30 +432,19 @@ static void net_rx_action(unsigned long unused)
- 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.
+- * Each head or fragment can be up to 4096 bytes. Given
+- * MAX_BUFFER_OFFSET of 4096 the worst case is that each
+- * head/fragment uses 2 copy operation.
- */
-- static struct multicall_entry rx_mcl[NET_RX_RING_SIZE+3];
-- static struct mmu_update rx_mmu[NET_RX_RING_SIZE];
-- static struct gnttab_transfer grant_trans_op[NET_RX_RING_SIZE];
-- static struct gnttab_copy grant_copy_op[NET_RX_RING_SIZE];
-- static unsigned char rx_notify[NR_IRQS];
-- static u16 notify_list[NET_RX_RING_SIZE];
-- static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
+- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
+- unsigned char rx_notify[NR_IRQS];
+- u16 notify_list[NET_RX_RING_SIZE];
+- struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
+-};
-
- 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;
-
-@@ -525,39 +459,39 @@ static void net_rx_action(unsigned long unused)
- 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;
- }
-
-@@ -565,7 +499,7 @@ static void net_rx_action(unsigned long unused)
- 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);
-@@ -582,7 +516,7 @@ static void net_rx_action(unsigned long unused)
-
- status = netbk_check_gop(nr_frags, netif->domid, &npo);
-
-- id = meta[npo.meta_cons].id;
-+ id = netbk->meta[npo.meta_cons].id;
- flags = nr_frags ? NETRXF_more_data : 0;
-
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
-@@ -595,7 +529,7 @@ static void net_rx_action(unsigned long unused)
- 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 xen_netif_extra_info *gso =
- (struct xen_netif_extra_info *)
- RING_GET_RESPONSE(&netif->rx,
-@@ -603,7 +537,7 @@ static void net_rx_action(unsigned long unused)
-
- 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;
-@@ -613,14 +547,14 @@ static void net_rx_action(unsigned long unused)
- }
-
- netbk_add_frag_responses(netif, status,
-- meta + npo.meta_cons + 1,
-- nr_frags);
-+ netbk->meta + npo.meta_cons + 1,
-+ nr_frags);
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
- irq = netif->irq;
-- if (ret && !rx_notify[irq]) {
-- rx_notify[irq] = 1;
-- notify_list[notify_nr++] = irq;
-+ if (ret && !netbk->rx_notify[irq]) {
-+ netbk->rx_notify[irq] = 1;
-+ netbk->notify_list[notify_nr++] = irq;
- }
-
- if (netif_queue_stopped(netif->dev) &&
-@@ -634,24 +568,25 @@ static void net_rx_action(unsigned long unused)
- }
-
- while (notify_nr != 0) {
-- irq = notify_list[--notify_nr];
-- rx_notify[irq] = 0;
-+ irq = netbk->notify_list[--notify_nr];
-+ netbk->rx_notify[irq] = 0;
- notify_remote_via_irq(irq);
- }
-
- /* 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);
- }
-
- static void net_alarm(unsigned long unused)
- {
-- tasklet_schedule(&net_rx_tasklet);
-+ tasklet_schedule(&netbk->net_rx_tasklet);
- }
-
- static void netbk_tx_pending_timeout(unsigned long unused)
- {
-- tasklet_schedule(&net_tx_tasklet);
-+ tasklet_schedule(&netbk->net_tx_tasklet);
- }
-
- struct net_device_stats *netif_be_get_stats(struct net_device *dev)
-@@ -667,12 +602,12 @@ static int __on_net_schedule_list(struct xen_netif *netif)
-
- static void remove_from_net_schedule_list(struct xen_netif *netif)
- {
-- spin_lock_irq(&net_schedule_list_lock);
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
- if (likely(__on_net_schedule_list(netif))) {
- list_del_init(&netif->list);
- netif_put(netif);
- }
-- spin_unlock_irq(&net_schedule_list_lock);
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
- }
-
- static void add_to_net_schedule_list_tail(struct xen_netif *netif)
-@@ -680,13 +615,13 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
- if (__on_net_schedule_list(netif))
- return;
-
-- spin_lock_irq(&net_schedule_list_lock);
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
- if (!__on_net_schedule_list(netif) &&
- likely(netif_schedulable(netif))) {
-- list_add_tail(&netif->list, &net_schedule_list);
-+ list_add_tail(&netif->list, &netbk->net_schedule_list);
- netif_get(netif);
- }
-- spin_unlock_irq(&net_schedule_list_lock);
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
- }
-
- void netif_schedule_work(struct xen_netif *netif)
-@@ -736,8 +671,9 @@ static void tx_credit_callback(unsigned long data)
-
- static inline int copy_pending_req(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]);
- }
-
- inline static void net_tx_action_dealloc(void)
-@@ -750,22 +686,24 @@ inline static void net_tx_action_dealloc(void)
- int ret;
- 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();
-
- while (dc != dp) {
- unsigned long pfn;
-+ struct netbk_tx_pending_inuse *pending_inuse =
-+ netbk->pending_inuse;
-
-- pending_idx = dealloc_ring[pending_index(dc++)];
-+ pending_idx = netbk->dealloc_ring[pending_index(dc++)];
- list_move_tail(&pending_inuse[pending_idx].list, &list);
-
- pfn = idx_to_pfn(pending_idx);
-@@ -773,22 +711,27 @@ inline static void net_tx_action_dealloc(void)
- if (!phys_to_machine_mapping_valid(pfn))
- continue;
-
-- gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
-- GNTMAP_host_map,
-- grant_tx_handle[pending_idx]);
-+ gnttab_set_unmap_op(gop,
-+ idx_to_kaddr(pending_idx),
-+ GNTMAP_host_map,
-+ netbk->grant_tx_handle[pending_idx]);
- gop++;
- }
-
- if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
-- list_empty(&pending_inuse_head))
-+ list_empty(&netbk->pending_inuse_head))
- break;
-
- /* Copy any entries that have been pending for too long. */
-- list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
-+ list_for_each_entry_safe(inuse, n,
-+ &netbk->pending_inuse_head, list) {
-+ struct pending_tx_info *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++;
-
-@@ -805,16 +748,21 @@ inline static void net_tx_action_dealloc(void)
-
- break;
- }
-- } while (dp != dealloc_prod);
-+ } while (dp != netbk->dealloc_prod);
-
-- dealloc_cons = dc;
-+ netbk->dealloc_cons = dc;
-
- ret = HYPERVISOR_grant_table_op(
-- GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
-+ GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
-+ gop - netbk->tx_unmap_ops);
- BUG_ON(ret);
-
- list_for_each_entry_safe(inuse, n, &list, list) {
-- pending_idx = inuse - pending_inuse;
-+ struct pending_tx_info *pending_tx_info;
-+ pending_ring_idx_t index;
-+
-+ pending_tx_info = netbk->pending_tx_info;
-+ pending_idx = inuse - netbk->pending_inuse;
-
- netif = pending_tx_info[pending_idx].netif;
-
-@@ -822,9 +770,10 @@ inline static void net_tx_action_dealloc(void)
- 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[pending_index(pending_prod++)] = pending_idx;
-+ index = pending_index(netbk->pending_prod++);
-+ netbk->pending_ring[index] = pending_idx;
-
- netif_put(netif);
-
-@@ -832,7 +781,8 @@ inline static void net_tx_action_dealloc(void)
- }
- }
-
--static void netbk_tx_err(struct xen_netif *netif, struct xen_netif_tx_request *txp,
RING_IDX end)
-+static void netbk_tx_err(struct xen_netif *netif,
-+ struct xen_netif_tx_request *txp, RING_IDX end)
- {
- RING_IDX cons = netif->tx.req_cons;
-
-@@ -902,7 +852,12 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
-
- for (i = start; i < shinfo->nr_frags; i++, txp++) {
-- pending_idx = pending_ring[pending_index(pending_cons++)];
-+ pending_ring_idx_t index;
-+ struct pending_tx_info *pending_tx_info =
-+ netbk->pending_tx_info;
-+
-+ index = pending_index(netbk->pending_cons++);
-+ pending_idx = netbk->pending_ring[index];
-
- gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
- GNTMAP_host_map | GNTMAP_readonly,
-@@ -922,6 +877,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- {
- struct gnttab_map_grant_ref *mop = *mopp;
- int pending_idx = *((u16 *)skb->data);
-+ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
- struct xen_netif *netif = pending_tx_info[pending_idx].netif;
- struct xen_netif_tx_request *txp;
- struct skb_shared_info *shinfo = skb_shinfo(skb);
-@@ -931,15 +887,17 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- /* Check status of header. */
- err = mop->status;
- if (unlikely(err)) {
-+ pending_ring_idx_t index;
-+ index = pending_index(netbk->pending_prod++);
- txp = &pending_tx_info[pending_idx].req;
- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-- pending_ring[pending_index(pending_prod++)] = pending_idx;
-+ netbk->pending_ring[index] = pending_idx;
- netif_put(netif);
- } else {
- set_phys_to_machine(
- __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
- 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. */
-@@ -947,16 +905,19 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
-
- 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)) {
-+ unsigned long addr;
-+ addr = idx_to_kaddr(pending_idx);
- set_phys_to_machine(
-- __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
-+ __pa(addr)>>PAGE_SHIFT,
- 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))
- netif_idx_release(pending_idx);
-@@ -964,9 +925,10 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- }
-
- /* Error on this fragment: respond to client with an error. */
-- txp = &pending_tx_info[pending_idx].req;
-+ txp = &netbk->pending_tx_info[pending_idx].req;
- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-- pending_ring[pending_index(pending_prod++)] = pending_idx;
-+ index = pending_index(netbk->pending_prod++);
-+ netbk->pending_ring[index] = pending_idx;
- netif_put(netif);
-
- /* Not the first error? Preceding frags already invalidated. */
-@@ -1002,11 +964,11 @@ static void netbk_fill_frags(struct sk_buff *skb)
-
- 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;
-+ txp = &netbk->pending_tx_info[pending_idx].req;
- frag->page = virt_to_page(idx_to_kaddr(pending_idx));
- frag->size = txp->size;
- frag->page_offset = txp->offset;
-@@ -1145,9 +1107,9 @@ static unsigned net_tx_build_mops(void)
- struct sk_buff *skb;
- int ret;
-
-- mop = tx_map_ops;
-+ mop = netbk->tx_map_ops;
- while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-- !list_empty(&net_schedule_list)) {
-+ !list_empty(&netbk->net_schedule_list)) {
- struct xen_netif *netif;
- struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-@@ -1156,9 +1118,11 @@ static unsigned net_tx_build_mops(void)
- RING_IDX idx;
- int work_to_do;
- unsigned int data_len;
-+ pending_ring_idx_t index;
-
- /* Get a netif from the list with work to do. */
-- netif = list_first_entry(&net_schedule_list, struct xen_netif, list);
-+ netif = list_first_entry(&netbk->net_schedule_list,
-+ struct xen_netif, list);
- netif_get(netif);
- remove_from_net_schedule_list(netif);
-
-@@ -1217,7 +1181,8 @@ static unsigned net_tx_build_mops(void)
- continue;
- }
-
-- pending_idx = pending_ring[pending_index(pending_cons)];
-+ index = pending_index(netbk->pending_cons);
-+ pending_idx = netbk->pending_ring[index];
-
- data_len = (txreq.size > PKT_PROT_LEN &&
- ret < MAX_SKB_FRAGS) ?
-@@ -1250,9 +1215,9 @@ static unsigned net_tx_build_mops(void)
- 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);
-@@ -1267,20 +1232,20 @@ static unsigned net_tx_build_mops(void)
- 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 = idx;
- 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;
- }
-
-- return mop - tx_map_ops;
-+ return mop - netbk->tx_map_ops;
- }
-
- static void net_tx_submit(void)
-@@ -1288,16 +1253,16 @@ static void net_tx_submit(void)
- struct gnttab_map_grant_ref *mop;
- struct sk_buff *skb;
-
-- 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 xen_netif_tx_request *txp;
- struct xen_netif *netif;
- u16 pending_idx;
- unsigned data_len;
-
- pending_idx = *((u16 *)skb->data);
-- netif = pending_tx_info[pending_idx].netif;
-- txp = &pending_tx_info[pending_idx].req;
-+ netif = netbk->pending_tx_info[pending_idx].netif;
-+ txp = &netbk->pending_tx_info[pending_idx].req;
-
- /* Check the remap error code. */
- if (unlikely(netbk_tx_check_mop(skb, &mop))) {
-@@ -1363,12 +1328,13 @@ static void net_tx_submit(void)
- }
-
- 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->netbk_tx_pending_timer,
-+ oldest->alloc_time + HZ);
- }
- }
-
-@@ -1378,7 +1344,7 @@ static void net_tx_action(unsigned long unused)
- unsigned nr_mops;
- int ret;
-
-- if (dealloc_cons != dealloc_prod)
-+ if (netbk->dealloc_cons != netbk->dealloc_prod)
- net_tx_action_dealloc();
-
- nr_mops = net_tx_build_mops();
-@@ -1387,7 +1353,7 @@ static void net_tx_action(unsigned long unused)
- return;
-
- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-- tx_map_ops, nr_mops);
-+ netbk->tx_map_ops, nr_mops);
- BUG_ON(ret);
-
- net_tx_submit();
-@@ -1397,15 +1363,17 @@ static void netif_idx_release(u16 pending_idx)
- {
- static DEFINE_SPINLOCK(_lock);
- unsigned long flags;
-+ pending_ring_idx_t index;
-
- spin_lock_irqsave(&_lock, flags);
-- dealloc_ring[pending_index(dealloc_prod)] = pending_idx;
-+ index = pending_index(netbk->dealloc_prod);
-+ netbk->dealloc_ring[index] = pending_idx;
- /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
- smp_wmb();
-- dealloc_prod++;
-+ netbk->dealloc_prod++;
- spin_unlock_irqrestore(&_lock, flags);
-
-- tasklet_schedule(&net_tx_tasklet);
-+ tasklet_schedule(&netbk->net_tx_tasklet);
- }
-
- static void netif_page_release(struct page *page, unsigned int order)
-@@ -1481,9 +1449,9 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
- int i = 0;
-
- printk(KERN_ALERT "netif_schedule_list:\n");
-- spin_lock_irq(&net_schedule_list_lock);
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
-
-- list_for_each (ent, &net_schedule_list) {
-+ list_for_each(ent, &netbk->net_schedule_list) {
- netif = list_entry(ent, struct xen_netif, list);
- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
- "rx_resp_prod=%08x\n",
-@@ -1500,7 +1468,7 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
- i++;
- }
-
-- spin_unlock_irq(&net_schedule_list_lock);
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
- printk(KERN_ALERT " ** End of netif_schedule_list **\n");
-
- return IRQ_HANDLED;
-@@ -1516,37 +1484,53 @@ static int __init netback_init(void)
- if (!xen_domain())
- return -ENODEV;
-
-+ netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk));
-+ if (!netbk) {
-+ printk(KERN_ALERT "%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);
-
-- skb_queue_head_init(&rx_queue);
-- skb_queue_head_init(&tx_queue);
-+ skb_queue_head_init(&netbk->rx_queue);
-+ skb_queue_head_init(&netbk->tx_queue);
-
-- init_timer(&net_timer);
-- net_timer.data = 0;
-- net_timer.function = net_alarm;
-+ init_timer(&netbk->net_timer);
-+ netbk->net_timer.data = 0;
-+ netbk->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;
-+ init_timer(&netbk->netbk_tx_pending_timer);
-+ netbk->netbk_tx_pending_timer.data = 0;
-+ netbk->netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
-
-- mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-- if (mmap_pages == NULL) {
-- printk("%s: out of memory\n", __FUNCTION__);
-- return -ENOMEM;
-+ netbk->mmap_pages =
-+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-+ if (!netbk->mmap_pages) {
-+ printk(KERN_ALERT "%s: out of memory\n", __func__);
-+ rc = -ENOMEM;
-+ goto failed_init2;
- }
-
- for (i = 0; i < MAX_PENDING_REQS; i++) {
-- page = mmap_pages[i];
-+ page = netbk->mmap_pages[i];
- SetPageForeign(page, netif_page_release);
- netif_set_page_index(page, i);
-- INIT_LIST_HEAD(&pending_inuse[i].list);
-+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
- }
-
-- pending_cons = 0;
-- pending_prod = MAX_PENDING_REQS;
-+ netbk->pending_cons = 0;
-+ netbk->pending_prod = MAX_PENDING_REQS;
- for (i = 0; i < MAX_PENDING_REQS; i++)
-- pending_ring[i] = i;
-+ netbk->pending_ring[i] = i;
-+
-+ tasklet_init(&netbk->net_tx_tasklet, net_tx_action, 0);
-+ tasklet_init(&netbk->net_rx_tasklet, net_rx_action, 0);
-+
-+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
-+ INIT_LIST_HEAD(&netbk->net_schedule_list);
-+
-+ spin_lock_init(&netbk->net_schedule_list_lock);
-
- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
- if (MODPARM_copy_skb) {
-@@ -1561,7 +1545,7 @@ static int __init netback_init(void)
-
- rc = netif_xenbus_init();
- if (rc)
-- goto failed_init;
-+ goto failed_init1;
-
- #ifdef NETBE_DEBUG_INTERRUPT
- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-@@ -1574,10 +1558,12 @@ static int __init netback_init(void)
-
- return 0;
-
--failed_init:
-- free_empty_pages_and_pagevec(mmap_pages, MAX_PENDING_REQS);
-- del_timer(&netbk_tx_pending_timer);
-- del_timer(&net_timer);
-+failed_init1:
-+ free_empty_pages_and_pagevec(netbk->mmap_pages, MAX_PENDING_REQS);
-+failed_init2:
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ vfree(netbk);
- return rc;
-
- }
---
-1.7.4
-
-
-From c099c22d8b1c12fc7d68998982eb4ccd4918e813 Mon Sep 17 00:00:00 2001
-From: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Date: Wed, 19 May 2010 16:58:57 -0700
-Subject: [PATCH 074/244] xen: netback: Introduce a new struct type page_ext.
-
-struct page_ext is used to store the group and idx information by
-which a specified page could be identified.
-
-Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 15 +++++++++++++++
- drivers/xen/netback/netback.c | 28 +++++++++++++++++-----------
- 2 files changed, 32 insertions(+), 11 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 00208f4..5e0e467 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -240,6 +240,21 @@ struct netbk_tx_pending_inuse {
-
- #define MAX_PENDING_REQS 256
-
-+/* extra field used in struct page */
-+union page_ext {
-+ struct {
-+#if BITS_PER_LONG < 64
-+#define IDX_WIDTH 8
-+#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
-+ unsigned int group:GROUP_WIDTH;
-+ unsigned int idx:IDX_WIDTH;
-+#else
-+ unsigned int group, idx;
-+#endif
-+ } e;
-+ void *mapping;
-+};
-+
- struct xen_netbk {
- struct tasklet_struct net_tx_tasklet;
- struct tasklet_struct net_rx_tasklet;
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 417f497..71ec999 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -76,22 +76,27 @@ static inline unsigned long idx_to_kaddr(unsigned int idx)
- }
-
- /* extra field used in struct page */
--static inline void netif_set_page_index(struct page *pg, unsigned int index)
-+static inline void netif_set_page_ext(struct page *pg, unsigned int group,
-+ unsigned int idx)
- {
-- *(unsigned long *)&pg->mapping = index + 1;
-+ union page_ext ext = { .e = { .group = 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 - 1;
-+ union page_ext ext = { .mapping = pg->mapping };
-
-- if (!PageForeign(pg))
-- return -1;
-+ return ext.e.group - 1;
-+}
-
-- if ((idx >= MAX_PENDING_REQS) || (netbk->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;
- }
-
- /*
-@@ -1380,7 +1385,8 @@ static void netif_page_release(struct page *page, unsigned int
order)
- {
- int idx = netif_page_index(page);
- BUG_ON(order);
-- BUG_ON(idx < 0);
-+ BUG_ON(idx < 0 || idx >= MAX_PENDING_REQS);
-+ BUG_ON(netbk->mmap_pages[idx] != page);
- netif_idx_release(idx);
- }
-
-@@ -1515,7 +1521,7 @@ static int __init netback_init(void)
- for (i = 0; i < MAX_PENDING_REQS; i++) {
- page = netbk->mmap_pages[i];
- SetPageForeign(page, netif_page_release);
-- netif_set_page_index(page, i);
-+ netif_set_page_ext(page, 0, i);
- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
- }
-
---
-1.7.4
-
-
-From 9534985c5b9cc3f6238d6cb8bba7d376e82039d3 Mon Sep 17 00:00:00 2001
-From: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Date: Wed, 19 May 2010 17:08:21 -0700
-Subject: [PATCH 075/244] xen: netback: Multiple tasklets support.
-
-Now netback uses one pair of tasklets for Tx/Rx data transaction.
-Netback tasklet could only run at one CPU at a time, and it is
-used to serve all the netfronts. Therefore it has become a
-performance bottle neck. This patch is to use multiple tasklet
-pairs to replace the current single pair in dom0.
-
-Assuming that Dom0 has CPUNR VCPUs, we define CPUNR kinds of
-tasklets pair (CPUNR for Tx, and CPUNR for Rx). Each pare of
-tasklets serve specific group of netfronts. Also for those global
-and static variables, we duplicated them for each group in
-order to avoid the spinlock.
-
-Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 6 +
- drivers/xen/netback/interface.c | 27 ++++
- drivers/xen/netback/netback.c | 270 ++++++++++++++++++++++++---------------
- 3 files changed, 197 insertions(+), 106 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 5e0e467..847ba58 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -58,6 +58,7 @@
- struct xen_netif {
- /* Unique identifier for this interface. */
- domid_t domid;
-+ int group;
- unsigned int handle;
-
- u8 fe_dev_addr[6];
-@@ -278,6 +279,8 @@ struct xen_netbk {
- /* Protect the net_schedule_list in netif. */
- spinlock_t net_schedule_list_lock;
-
-+ atomic_t netfront_count;
-+
- 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];
-@@ -296,4 +299,7 @@ struct xen_netbk {
- struct netbk_rx_meta meta[NET_RX_RING_SIZE];
- };
-
-+extern struct xen_netbk *xen_netbk;
-+extern int xen_netbk_group_nr;
-+
- #endif /* __NETIF__BACKEND__COMMON_H__ */
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 086d939..172ef4c 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -54,8 +54,33 @@
- static unsigned long netbk_queue_length = 32;
- module_param_named(queue_length, netbk_queue_length, ulong, 0644);
-
-+static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
-+ struct xen_netif *netif)
-+{
-+ int i;
-+ int min_netfront_count;
-+ int min_group = 0;
-+ min_netfront_count = atomic_read(&netbk[0].netfront_count);
-+ for (i = 0; i < group_nr; i++) {
-+ int netfront_count = atomic_read(&netbk[i].netfront_count);
-+ if (netfront_count < min_netfront_count) {
-+ min_group = i;
-+ min_netfront_count = netfront_count;
-+ }
-+ }
-+
-+ netif->group = min_group;
-+ atomic_inc(&netbk[netif->group].netfront_count);
-+}
-+
-+static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
-+{
-+ atomic_dec(&netbk[netif->group].netfront_count);
-+}
-+
- static void __netif_up(struct xen_netif *netif)
- {
-+ netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
- enable_irq(netif->irq);
- netif_schedule_work(netif);
- }
-@@ -64,6 +89,7 @@ static void __netif_down(struct xen_netif *netif)
- {
- disable_irq(netif->irq);
- netif_deschedule_work(netif);
-+ netbk_remove_netif(xen_netbk, netif);
- }
-
- static int net_open(struct net_device *dev)
-@@ -214,6 +240,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- netif = netdev_priv(dev);
- memset(netif, 0, sizeof(*netif));
- netif->domid = domid;
-+ netif->group = -1;
- netif->handle = handle;
- netif->features = NETIF_F_SG;
- atomic_set(&netif->refcnt, 1);
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 71ec999..feefb14 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -48,9 +48,10 @@
-
- /*define NETBE_DEBUG_INTERRUPT*/
-
--static struct xen_netbk *netbk;
-+struct xen_netbk *xen_netbk;
-+int xen_netbk_group_nr;
-
--static void netif_idx_release(u16 pending_idx);
-+static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
- static void make_tx_response(struct xen_netif *netif,
- struct xen_netif_tx_request *txp,
- s8 st);
-@@ -61,18 +62,20 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
- u16 size,
- u16 flags);
-
--static void net_tx_action(unsigned long unused);
-+static void net_tx_action(unsigned long data);
-
--static void net_rx_action(unsigned long unused);
-+static void net_rx_action(unsigned long data);
-
--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(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 */
-@@ -112,7 +115,7 @@ 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(void)
-+static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk *netbk)
- {
- return MAX_PENDING_REQS -
- netbk->pending_prod + netbk->pending_cons;
-@@ -125,10 +128,10 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
-
- int netbk_copy_skb_mode;
-
--static inline void maybe_schedule_tx_action(void)
-+static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
- {
- smp_mb();
-- if ((nr_pending_reqs() < (MAX_PENDING_REQS/2)) &&
-+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
- !list_empty(&netbk->net_schedule_list))
- tasklet_schedule(&netbk->net_tx_tasklet);
- }
-@@ -235,9 +238,15 @@ static void tx_queue_callback(unsigned long data)
- int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct xen_netif *netif = netdev_priv(dev);
-+ struct xen_netbk *netbk;
-
- BUG_ON(skb->dev != dev);
-
-+ if (netif->group == -1)
-+ goto drop;
-+
-+ netbk = &xen_netbk[netif->group];
-+
- /* Drop the packet if the target domain has no receive buffers. */
- if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
- goto drop;
-@@ -313,6 +322,7 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
- struct gnttab_copy *copy_gop;
- struct xen_netif_rx_request *req;
- unsigned long old_mfn;
-+ int group = netif_page_group(page);
- int idx = netif_page_index(page);
-
- old_mfn = virt_to_mfn(page_address(page));
-@@ -321,7 +331,8 @@ static u16 netbk_gop_frag(struct xen_netif *netif, struct
netbk_rx_meta *meta,
-
- copy_gop = npo->copy + npo->copy_prod++;
- copy_gop->flags = GNTCOPY_dest_gref;
-- if (idx > -1) {
-+ if (PageForeign(page)) {
-+ struct xen_netbk *netbk = &xen_netbk[group];
- struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
- copy_gop->source.domid = src_pend->netif->domid;
- copy_gop->source.u.ref = src_pend->req.gref;
-@@ -422,9 +433,10 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
- }
- }
-
--static void net_rx_action(unsigned long unused)
-+static void net_rx_action(unsigned long data)
- {
- struct xen_netif *netif = NULL;
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
- s8 status;
- u16 id, irq, flags;
- struct xen_netif_rx_response *resp;
-@@ -584,13 +596,15 @@ static void net_rx_action(unsigned long unused)
- tasklet_schedule(&netbk->net_rx_tasklet);
- }
-
--static void net_alarm(unsigned long unused)
-+static void net_alarm(unsigned long data)
- {
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
- tasklet_schedule(&netbk->net_rx_tasklet);
- }
-
--static void netbk_tx_pending_timeout(unsigned long unused)
-+static void netbk_tx_pending_timeout(unsigned long data)
- {
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
- tasklet_schedule(&netbk->net_tx_tasklet);
- }
-
-@@ -607,6 +621,7 @@ static int __on_net_schedule_list(struct xen_netif *netif)
-
- static void remove_from_net_schedule_list(struct xen_netif *netif)
- {
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
- spin_lock_irq(&netbk->net_schedule_list_lock);
- if (likely(__on_net_schedule_list(netif))) {
- list_del_init(&netif->list);
-@@ -617,6 +632,7 @@ static void remove_from_net_schedule_list(struct xen_netif *netif)
-
- static void add_to_net_schedule_list_tail(struct xen_netif *netif)
- {
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
- if (__on_net_schedule_list(netif))
- return;
-
-@@ -631,13 +647,14 @@ static void add_to_net_schedule_list_tail(struct xen_netif *netif)
-
- void netif_schedule_work(struct xen_netif *netif)
- {
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
- int more_to_do;
-
- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-
- if (more_to_do) {
- add_to_net_schedule_list_tail(netif);
-- maybe_schedule_tx_action();
-+ maybe_schedule_tx_action(netbk);
- }
- }
-
-@@ -674,14 +691,15 @@ static void tx_credit_callback(unsigned long data)
- netif_schedule_work(netif);
- }
-
--static inline int copy_pending_req(pending_ring_idx_t pending_idx)
-+static inline int copy_pending_req(struct xen_netbk *netbk,
-+ pending_ring_idx_t pending_idx)
- {
- return gnttab_copy_grant_page(
- netbk->grant_tx_handle[pending_idx],
- &netbk->mmap_pages[pending_idx]);
- }
-
--inline static void net_tx_action_dealloc(void)
-+static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
- {
- struct netbk_tx_pending_inuse *inuse, *n;
- struct gnttab_unmap_grant_ref *gop;
-@@ -711,13 +729,13 @@ inline static void net_tx_action_dealloc(void)
- pending_idx = netbk->dealloc_ring[pending_index(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),
-+ idx_to_kaddr(netbk, pending_idx),
- GNTMAP_host_map,
- netbk->grant_tx_handle[pending_idx]);
- gop++;
-@@ -740,7 +758,7 @@ inline static void net_tx_action_dealloc(void)
-
- 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;
-@@ -843,7 +861,8 @@ static int netbk_count_requests(struct xen_netif *netif,
- return frags;
- }
-
--static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netif *netif,
-+static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
-+ struct xen_netif *netif,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
- struct gnttab_map_grant_ref *mop)
-@@ -864,7 +883,7 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
- index = pending_index(netbk->pending_cons++);
- pending_idx = netbk->pending_ring[index];
-
-- 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,
- txp->gref, netif->domid);
-
-@@ -877,8 +896,9 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netif *netif,
- return mop;
- }
-
--static int netbk_tx_check_mop(struct sk_buff *skb,
-- struct gnttab_map_grant_ref **mopp)
-+static int netbk_tx_check_mop(struct xen_netbk *netbk,
-+ struct sk_buff *skb,
-+ struct gnttab_map_grant_ref **mopp)
- {
- struct gnttab_map_grant_ref *mop = *mopp;
- int pending_idx = *((u16 *)skb->data);
-@@ -900,7 +920,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- netif_put(netif);
- } else {
- set_phys_to_machine(
-- __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
-+ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
- FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
- netbk->grant_tx_handle[pending_idx] = mop->handle;
- }
-@@ -918,14 +938,14 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- newerr = (++mop)->status;
- if (likely(!newerr)) {
- unsigned long addr;
-- addr = idx_to_kaddr(pending_idx);
-+ addr = idx_to_kaddr(netbk, pending_idx);
- set_phys_to_machine(
- __pa(addr)>>PAGE_SHIFT,
- FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
- netbk->grant_tx_handle[pending_idx] = mop->handle;
- /* Had a previous error? Invalidate this fragment. */
- if (unlikely(err))
-- netif_idx_release(pending_idx);
-+ netif_idx_release(netbk, pending_idx);
- continue;
- }
-
-@@ -942,10 +962,10 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
-
- /* 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. */
-@@ -956,7 +976,7 @@ static int netbk_tx_check_mop(struct sk_buff *skb,
- 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;
-@@ -974,7 +994,7 @@ static void netbk_fill_frags(struct sk_buff *skb)
- &netbk->pending_inuse_head);
-
- txp = &netbk->pending_tx_info[pending_idx].req;
-- frag->page = virt_to_page(idx_to_kaddr(pending_idx));
-+ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
- frag->size = txp->size;
- frag->page_offset = txp->offset;
-
-@@ -1106,14 +1126,14 @@ static bool tx_credit_exceeded(struct xen_netif *netif, unsigned
size)
- return false;
- }
-
--static unsigned net_tx_build_mops(void)
-+static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- {
- struct gnttab_map_grant_ref *mop;
- struct sk_buff *skb;
- int ret;
-
- mop = netbk->tx_map_ops;
-- while (((nr_pending_reqs() + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list)) {
- struct xen_netif *netif;
- struct xen_netif_tx_request txreq;
-@@ -1215,7 +1235,7 @@ static unsigned net_tx_build_mops(void)
- }
- }
-
-- 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++;
-@@ -1241,7 +1261,7 @@ static unsigned net_tx_build_mops(void)
-
- netbk->pending_cons++;
-
-- mop = netbk_get_requests(netif, skb, txfrags, mop);
-+ mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
-
- netif->tx.req_cons = idx;
- netif_schedule_work(netif);
-@@ -1253,7 +1273,7 @@ static unsigned net_tx_build_mops(void)
- return mop - netbk->tx_map_ops;
- }
-
--static void net_tx_submit(void)
-+static void net_tx_submit(struct xen_netbk *netbk)
- {
- struct gnttab_map_grant_ref *mop;
- struct sk_buff *skb;
-@@ -1270,7 +1290,7 @@ static void net_tx_submit(void)
- 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);
-@@ -1279,7 +1299,7 @@ static void net_tx_submit(void)
-
- 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. */
-@@ -1287,7 +1307,7 @@ static void net_tx_submit(void)
- 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)
-@@ -1295,7 +1315,7 @@ static void net_tx_submit(void)
- else if (txp->flags & NETTXF_data_validated)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-- netbk_fill_frags(skb);
-+ netbk_fill_frags(netbk, skb);
-
- /*
- * If the initial fragment was < PKT_PROT_LEN then
-@@ -1344,15 +1364,16 @@ static void net_tx_submit(void)
- }
-
- /* Called after netfront has transmitted */
--static void net_tx_action(unsigned long unused)
-+static void net_tx_action(unsigned long data)
- {
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
- unsigned nr_mops;
- int ret;
-
- if (netbk->dealloc_cons != netbk->dealloc_prod)
-- net_tx_action_dealloc();
-+ net_tx_action_dealloc(netbk);
-
-- nr_mops = net_tx_build_mops();
-+ nr_mops = net_tx_build_mops(netbk);
-
- if (nr_mops == 0)
- return;
-@@ -1361,10 +1382,10 @@ static void net_tx_action(unsigned long unused)
- netbk->tx_map_ops, nr_mops);
- BUG_ON(ret);
-
-- net_tx_submit();
-+ net_tx_submit(netbk);
- }
-
--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;
-@@ -1383,19 +1404,28 @@ static void netif_idx_release(u16 pending_idx)
-
- static void netif_page_release(struct page *page, unsigned int order)
- {
-+ int group = netif_page_group(page);
- int idx = netif_page_index(page);
-+ struct xen_netbk *netbk = &xen_netbk[group];
- BUG_ON(order);
-+ BUG_ON(group < 0 || group >= xen_netbk_group_nr);
- BUG_ON(idx < 0 || idx >= MAX_PENDING_REQS);
- BUG_ON(netbk->mmap_pages[idx] != page);
-- netif_idx_release(idx);
-+ netif_idx_release(netbk, idx);
- }
-
- irqreturn_t netif_be_int(int irq, void *dev_id)
- {
- struct xen_netif *netif = dev_id;
-+ struct xen_netbk *netbk;
-+
-+ if (netif->group == -1)
-+ return IRQ_NONE;
-+
-+ netbk = &xen_netbk[netif->group];
-
- add_to_net_schedule_list_tail(netif);
-- maybe_schedule_tx_action();
-+ maybe_schedule_tx_action(netbk);
-
- if (netif_schedulable(netif) && !netbk_queue_full(netif))
- netif_wake_queue(netif->dev);
-@@ -1453,28 +1483,40 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
- struct list_head *ent;
- struct xen_netif *netif;
- int i = 0;
-+ int group = 0;
-
- printk(KERN_ALERT "netif_schedule_list:\n");
-- spin_lock_irq(&netbk->net_schedule_list_lock);
-
-- list_for_each(ent, &netbk->net_schedule_list) {
-- netif = list_entry(ent, struct xen_netif, list);
-- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-- "rx_resp_prod=%08x\n",
-- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-- printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n",
-- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-- printk(KERN_ALERT " shared(rx_req_prod=%08x "
-- "rx_resp_prod=%08x\n",
-- netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
-- printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n",
-- netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
-- printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n",
-- netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
-- i++;
-+ for (group = 0; group < xen_netbk_group_nr; group++) {
-+ struct xen_netbk *netbk = &xen_netbk[group];
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
-+ printk(KERN_ALERT "xen_netback group number: %d\n", group);
-+ list_for_each(ent, &netbk->net_schedule_list) {
-+ netif = list_entry(ent, struct xen_netif, list);
-+ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-+ "rx_resp_prod=%08x\n",
-+ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-+ printk(KERN_ALERT
-+ " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
-+ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-+ printk(KERN_ALERT
-+ " shared(rx_req_prod=%08x "
-+ "rx_resp_prod=%08x\n",
-+ netif->rx.sring->req_prod,
-+ netif->rx.sring->rsp_prod);
-+ printk(KERN_ALERT
-+ " rx_event=%08x, tx_req_prod=%08x\n",
-+ netif->rx.sring->rsp_event,
-+ netif->tx.sring->req_prod);
-+ printk(KERN_ALERT
-+ " tx_resp_prod=%08x, tx_event=%08x)\n",
-+ netif->tx.sring->rsp_prod,
-+ netif->tx.sring->rsp_event);
-+ i++;
-+ }
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
- }
-
-- spin_unlock_irq(&netbk->net_schedule_list_lock);
- printk(KERN_ALERT " ** End of netif_schedule_list **\n");
-
- return IRQ_HANDLED;
-@@ -1486,12 +1528,15 @@ static int __init netback_init(void)
- int i;
- struct page *page;
- int rc = 0;
-+ int group;
-
- if (!xen_domain())
- return -ENODEV;
-
-- netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk));
-- if (!netbk) {
-+ xen_netbk_group_nr = num_online_cpus();
-+ xen_netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk) *
-+ xen_netbk_group_nr);
-+ if (!xen_netbk) {
- printk(KERN_ALERT "%s: out of memory\n", __func__);
- return -ENOMEM;
- }
-@@ -1499,44 +1544,54 @@ static int __init netback_init(void)
- /* We can increase reservation by this much in net_rx_action(). */
- // balloon_update_driver_allowance(NET_RX_RING_SIZE);
-
-- skb_queue_head_init(&netbk->rx_queue);
-- skb_queue_head_init(&netbk->tx_queue);
--
-- init_timer(&netbk->net_timer);
-- netbk->net_timer.data = 0;
-- netbk->net_timer.function = net_alarm;
--
-- init_timer(&netbk->netbk_tx_pending_timer);
-- netbk->netbk_tx_pending_timer.data = 0;
-- netbk->netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
-+ for (group = 0; group < xen_netbk_group_nr; group++) {
-+ struct xen_netbk *netbk = &xen_netbk[group];
-+ skb_queue_head_init(&netbk->rx_queue);
-+ skb_queue_head_init(&netbk->tx_queue);
-+
-+ init_timer(&netbk->net_timer);
-+ netbk->net_timer.data = (unsigned long)netbk;
-+ netbk->net_timer.function = net_alarm;
-+
-+ init_timer(&netbk->netbk_tx_pending_timer);
-+ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
-+ netbk->netbk_tx_pending_timer.function =
-+ netbk_tx_pending_timeout;
-+
-+ netbk->mmap_pages =
-+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-+ if (!netbk->mmap_pages) {
-+ printk(KERN_ALERT "%s: out of memory\n", __func__);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ rc = -ENOMEM;
-+ goto failed_init;
-+ }
-
-- netbk->mmap_pages =
-- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-- if (!netbk->mmap_pages) {
-- printk(KERN_ALERT "%s: out of memory\n", __func__);
-- rc = -ENOMEM;
-- goto failed_init2;
-- }
-+ 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);
-+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
-+ }
-
-- for (i = 0; i < MAX_PENDING_REQS; i++) {
-- page = netbk->mmap_pages[i];
-- SetPageForeign(page, netif_page_release);
-- netif_set_page_ext(page, 0, i);
-- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
-- }
-+ netbk->pending_cons = 0;
-+ netbk->pending_prod = MAX_PENDING_REQS;
-+ for (i = 0; i < MAX_PENDING_REQS; i++)
-+ netbk->pending_ring[i] = i;
-
-- netbk->pending_cons = 0;
-- netbk->pending_prod = MAX_PENDING_REQS;
-- for (i = 0; i < MAX_PENDING_REQS; i++)
-- netbk->pending_ring[i] = i;
-+ tasklet_init(&netbk->net_tx_tasklet, net_tx_action,
-+ (unsigned long)netbk);
-+ tasklet_init(&netbk->net_rx_tasklet, net_rx_action,
-+ (unsigned long)netbk);
-
-- tasklet_init(&netbk->net_tx_tasklet, net_tx_action, 0);
-- tasklet_init(&netbk->net_rx_tasklet, net_rx_action, 0);
-+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
-+ INIT_LIST_HEAD(&netbk->net_schedule_list);
-
-- INIT_LIST_HEAD(&netbk->pending_inuse_head);
-- INIT_LIST_HEAD(&netbk->net_schedule_list);
-+ spin_lock_init(&netbk->net_schedule_list_lock);
-
-- spin_lock_init(&netbk->net_schedule_list_lock);
-+ atomic_set(&netbk->netfront_count, 0);
-+ }
-
- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
- if (MODPARM_copy_skb) {
-@@ -1551,25 +1606,28 @@ static int __init netback_init(void)
-
- rc = netif_xenbus_init();
- if (rc)
-- goto failed_init1;
-+ goto failed_init;
-
- #ifdef NETBE_DEBUG_INTERRUPT
- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
- 0,
- netif_be_dbg,
-- SA_SHIRQ,
-+ IRQF_SHARED,
- "net-be-dbg",
- &netif_be_dbg);
- #endif
-
- return 0;
-
--failed_init1:
-- free_empty_pages_and_pagevec(netbk->mmap_pages, MAX_PENDING_REQS);
--failed_init2:
-- del_timer(&netbk->netbk_tx_pending_timer);
-- del_timer(&netbk->net_timer);
-- vfree(netbk);
-+failed_init:
-+ for (i = 0; i < group; i++) {
-+ struct xen_netbk *netbk = &xen_netbk[i];
-+ free_empty_pages_and_pagevec(netbk->mmap_pages,
-+ MAX_PENDING_REQS);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ }
-+ vfree(xen_netbk);
- return rc;
-
- }
---
-1.7.4
-
-
-From e7317b70c0436c109b605bb377939cb2eaff6a6f Mon Sep 17 00:00:00 2001
-From: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Date: Wed, 19 May 2010 17:08:22 -0700
-Subject: [PATCH 076/244] xen: netback: Use Kernel thread to replace the tasklet.
-
-Kernel thread has more control over QoS, and could improve dom0's
-userspace responseness. This option is defaultly off currently.
-
-Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 13 ++++-
- drivers/xen/netback/netback.c | 109 ++++++++++++++++++++++++++++++++++++----
- 2 files changed, 109 insertions(+), 13 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 847ba58..36cb2b9 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -257,8 +257,17 @@ union page_ext {
- };
-
- struct xen_netbk {
-- struct tasklet_struct net_tx_tasklet;
-- struct tasklet_struct net_rx_tasklet;
-+ union {
-+ struct {
-+ struct tasklet_struct net_tx_tasklet;
-+ struct tasklet_struct net_rx_tasklet;
-+ } tasklet;
-+
-+ struct {
-+ wait_queue_head_t netbk_action_wq;
-+ struct task_struct *task;
-+ } kthread;
-+ };
-
- struct sk_buff_head rx_queue;
- struct sk_buff_head tx_queue;
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index feefb14..547dcaa 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -38,6 +38,7 @@
-
- #include <linux/tcp.h>
- #include <linux/udp.h>
-+#include <linux/kthread.h>
-
- #include <xen/balloon.h>
- #include <xen/events.h>
-@@ -128,12 +129,31 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
-
- int netbk_copy_skb_mode;
-
-+static int MODPARM_netback_kthread;
-+module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
-+MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
-+
-+/*
-+ * Netback bottom half handler.
-+ * dir indicates the data direction.
-+ * rx: 1, tx: 0.
-+ */
-+static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
-+{
-+ if (MODPARM_netback_kthread)
-+ wake_up(&netbk->kthread.netbk_action_wq);
-+ else if (dir)
-+ tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
-+ else
-+ tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
-+}
-+
- static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
- {
- smp_mb();
- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
- !list_empty(&netbk->net_schedule_list))
-- tasklet_schedule(&netbk->net_tx_tasklet);
-+ xen_netbk_bh_handler(netbk, 0);
- }
-
- static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-@@ -289,7 +309,8 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- }
- }
- skb_queue_tail(&netbk->rx_queue, skb);
-- tasklet_schedule(&netbk->net_rx_tasklet);
-+
-+ xen_netbk_bh_handler(netbk, 1);
-
- return 0;
-
-@@ -593,19 +614,19 @@ static void net_rx_action(unsigned long data)
- /* More work to do? */
- if (!skb_queue_empty(&netbk->rx_queue) &&
- !timer_pending(&netbk->net_timer))
-- tasklet_schedule(&netbk->net_rx_tasklet);
-+ xen_netbk_bh_handler(netbk, 1);
- }
-
- static void net_alarm(unsigned long data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- tasklet_schedule(&netbk->net_rx_tasklet);
-+ xen_netbk_bh_handler(netbk, 1);
- }
-
- static void netbk_tx_pending_timeout(unsigned long data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- tasklet_schedule(&netbk->net_tx_tasklet);
-+ xen_netbk_bh_handler(netbk, 0);
- }
-
- struct net_device_stats *netif_be_get_stats(struct net_device *dev)
-@@ -1348,7 +1369,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
- continue;
- }
-
-- netif_rx(skb);
-+ netif_rx_ni(skb);
- netif->dev->last_rx = jiffies;
- }
-
-@@ -1399,7 +1420,7 @@ static void netif_idx_release(struct xen_netbk *netbk, u16
pending_idx)
- netbk->dealloc_prod++;
- spin_unlock_irqrestore(&_lock, flags);
-
-- tasklet_schedule(&netbk->net_tx_tasklet);
-+ xen_netbk_bh_handler(netbk, 0);
- }
-
- static void netif_page_release(struct page *page, unsigned int order)
-@@ -1523,6 +1544,46 @@ static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct
pt_regs *regs)
- }
- #endif
-
-+static inline int rx_work_todo(struct xen_netbk *netbk)
-+{
-+ return !skb_queue_empty(&netbk->rx_queue);
-+}
-+
-+static inline int tx_work_todo(struct xen_netbk *netbk)
-+{
-+ if (netbk->dealloc_cons != netbk->dealloc_prod)
-+ return 1;
-+
-+ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+ !list_empty(&netbk->net_schedule_list))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+static int netbk_action_thread(void *data)
-+{
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ while (!kthread_should_stop()) {
-+ wait_event_interruptible(netbk->kthread.netbk_action_wq,
-+ rx_work_todo(netbk)
-+ || tx_work_todo(netbk)
-+ || kthread_should_stop());
-+ cond_resched();
-+
-+ if (kthread_should_stop())
-+ break;
-+
-+ if (rx_work_todo(netbk))
-+ net_rx_action((unsigned long)netbk);
-+
-+ if (tx_work_todo(netbk))
-+ net_tx_action((unsigned long)netbk);
-+ }
-+
-+ return 0;
-+}
-+
- static int __init netback_init(void)
- {
- int i;
-@@ -1580,10 +1641,34 @@ static int __init netback_init(void)
- for (i = 0; i < MAX_PENDING_REQS; i++)
- netbk->pending_ring[i] = i;
-
-- tasklet_init(&netbk->net_tx_tasklet, net_tx_action,
-- (unsigned long)netbk);
-- tasklet_init(&netbk->net_rx_tasklet, net_rx_action,
-- (unsigned long)netbk);
-+ if (MODPARM_netback_kthread) {
-+ init_waitqueue_head(&netbk->kthread.netbk_action_wq);
-+ netbk->kthread.task =
-+ kthread_create(netbk_action_thread,
-+ (void *)netbk,
-+ "netback/%u", group);
-+
-+ if (!IS_ERR(netbk->kthread.task)) {
-+ kthread_bind(netbk->kthread.task, group);
-+ wake_up_process(netbk->kthread.task);
-+ } else {
-+ printk(KERN_ALERT
-+ "kthread_run() fails at netback\n");
-+ free_empty_pages_and_pagevec(netbk->mmap_pages,
-+ MAX_PENDING_REQS);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ rc = PTR_ERR(netbk->kthread.task);
-+ goto failed_init;
-+ }
-+ } else {
-+ tasklet_init(&netbk->tasklet.net_tx_tasklet,
-+ net_tx_action,
-+ (unsigned long)netbk);
-+ tasklet_init(&netbk->tasklet.net_rx_tasklet,
-+ net_rx_action,
-+ (unsigned long)netbk);
-+ }
-
- INIT_LIST_HEAD(&netbk->pending_inuse_head);
- INIT_LIST_HEAD(&netbk->net_schedule_list);
-@@ -1626,6 +1711,8 @@ failed_init:
- MAX_PENDING_REQS);
- del_timer(&netbk->netbk_tx_pending_timer);
- del_timer(&netbk->net_timer);
-+ if (MODPARM_netback_kthread)
-+ kthread_stop(netbk->kthread.task);
- }
- vfree(xen_netbk);
- return rc;
---
-1.7.4
-
-
-From 6359d5939c5d1f59b794cd02e8cdbd36b9f3434d Mon Sep 17 00:00:00 2001
-From: James Harper <james.harper(a)bendigoit.com.au>
-Date: Fri, 28 May 2010 23:12:56 -0700
-Subject: [PATCH 077/244] xen: netback: avoid null-pointer access in netback_uevent
-
-Check if drvdata has been set up yet and return if it hasn't.
-
-Signed-off-by: James Harper <james.harper(a)bendigoit.com.au>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/xenbus.c | 9 +++++++--
- 1 files changed, 7 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index fcd3c34..e30b0c7 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -154,12 +154,17 @@ fail:
- */
- static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
- {
-- struct backend_info *be = dev_get_drvdata(&xdev->dev);
-- struct xen_netif *netif = be->netif;
-+ struct backend_info *be;
-+ struct xen_netif *netif;
- char *val;
-
- DPRINTK("netback_uevent");
-
-+ be = dev_get_drvdata(&xdev->dev);
-+ if (!be)
-+ return 0;
-+ netif = be->netif;
-+
- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
- if (IS_ERR(val)) {
- int err = PTR_ERR(val);
---
-1.7.4
-
-
-From 4a818daa044d9d499412e8f6e2e3086c0521e7b3 Mon Sep 17 00:00:00 2001
-From: Keir Fraser <keir.fraser(a)citrix.com>
-Date: Fri, 11 Jun 2010 11:48:30 +0100
-Subject: [PATCH 078/244] xen: netback: Fixes for delayed copy of tx network packets.
-
- - Should call net_tx_action_dealloc() even when dealloc ring is
- empty, as there may in any case be work to do on the
- pending_inuse list.
- - Should not exit directly from the middle of the tx_action tasklet,
- as the tx_pending_timer should always be checked and updated at the
- end of the tasklet.
-
-Signed-off-by: Keir Fraser <keir.fraser(a)citrix.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-[picked from linux-2.6.18-xen.hg 959:1a97bd686258, ported across a43e2175
"xen/netback: move code around"]
----
- drivers/xen/netback/netback.c | 25 ++++++++++++-------------
- 1 files changed, 12 insertions(+), 13 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 547dcaa..58dfbd2 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1372,16 +1372,6 @@ static void net_tx_submit(struct xen_netbk *netbk)
- netif_rx_ni(skb);
- netif->dev->last_rx = jiffies;
- }
--
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !list_empty(&netbk->pending_inuse_head)) {
-- struct netbk_tx_pending_inuse *oldest;
--
-- oldest = list_entry(netbk->pending_inuse_head.next,
-- struct netbk_tx_pending_inuse, list);
-- mod_timer(&netbk->netbk_tx_pending_timer,
-- oldest->alloc_time + HZ);
-- }
- }
-
- /* Called after netfront has transmitted */
-@@ -1391,19 +1381,28 @@ static void net_tx_action(unsigned long data)
- unsigned nr_mops;
- int ret;
-
-- if (netbk->dealloc_cons != netbk->dealloc_prod)
-- net_tx_action_dealloc(netbk);
-+ net_tx_action_dealloc(netbk);
-
- nr_mops = net_tx_build_mops(netbk);
-
- if (nr_mops == 0)
-- return;
-+ goto out;
-
- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
- netbk->tx_map_ops, nr_mops);
- BUG_ON(ret);
-
- net_tx_submit(netbk);
-+out:
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !list_empty(&netbk->pending_inuse_head)) {
-+ struct netbk_tx_pending_inuse *oldest;
-+
-+ oldest = list_entry(netbk->pending_inuse_head.next,
-+ struct netbk_tx_pending_inuse, list);
-+ mod_timer(&netbk->netbk_tx_pending_timer,
-+ oldest->alloc_time + HZ);
-+ }
- }
-
- static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
---
-1.7.4
-
-
-From 48fa1af97e6c9d304c04f70a75de1340e7d79e18 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 11 Jun 2010 10:51:01 +0100
-Subject: [PATCH 079/244] xen: netback: handle NET_SKBUFF_DATA_USES_OFFSET correctly
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jan Beulich <JBeulich(a)novell.com>
----
- drivers/xen/netback/netback.c | 4 ++++
- 1 files changed, 4 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 58dfbd2..aa094af 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -218,7 +218,11 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
- len -= copy;
- }
-
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+ offset = 0;
-+#else
- offset = nskb->data - skb->data;
-+#endif
-
- nskb->transport_header = skb->transport_header + offset;
- nskb->network_header = skb->network_header + offset;
---
-1.7.4
-
-
-From 7d3e6e42251f179e407fa5236f613e5500b3a3ea Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 11 Jun 2010 10:51:01 +0100
-Subject: [PATCH 080/244] xen: netback: drop frag member from struct netbk_rx_meta
-
-It has been unused since c3219dc "xen/netback: completely drop flip
-support", as has netbk_free_pages().
-
-(Although it now has only a single member struct netbk_rx_meta will
-gain other members in a subsequent patch so there is no point
-reworking to get rid of the struct)
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/common.h | 1 -
- drivers/xen/netback/netback.c | 8 --------
- 2 files changed, 0 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 36cb2b9..be4fe91 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -230,7 +230,6 @@ struct pending_tx_info {
- typedef unsigned int pending_ring_idx_t;
-
- struct netbk_rx_meta {
-- skb_frag_t frag;
- int id;
- };
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index aa094af..9f7e489 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -411,14 +411,6 @@ static void netbk_gop_skb(struct sk_buff *skb,
- netif->rx.req_cons += nr_frags + extra;
- }
-
--static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
--{
-- int i;
--
-- for (i = 0; i < nr_frags; i++)
-- put_page(meta[i].frag.page);
--}
--
- /* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
- used to set up the operations on the top of
- netrx_pending_operations, which have since been done. Check that
---
-1.7.4
-
-
-From 1ced27150d0092c40ebbbbb3896192003d433c0e Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 11 Jun 2010 10:51:01 +0100
-Subject: [PATCH 081/244] xen: netback: linearise SKBs as we copy them into guest memory
on guest-RX.
-
-There's no point in sending lots of little packets to a copying
-receiver if we can instead arrange to copy them all into a single RX
-buffer. We need to copy anyway, so there's no overhead here, and this
-is a little bit easier on the receiving domain's network stack.
-
-Based on a patch by Steven Smith. Fixed to not skip unnecessarily to
-the next buffer which could leave the head fragment of a received
-frame empty if the headlen of an SKB was large (which would crash
-netfront). Instead we only try and pack "small enough" fragments
-together but do not try to coalesce large or whole page fragments.
-
-In previous iterations of this patch we also tried to only include
-2048 bytes per frag because very old netfronts stored other
-information in the second half of the page. It has been determined
-that only frontends which support scatter-gather are going to come
-down this path and that any guest which supports scatter-gather is
-also new enough to allow us to use the full page size for each
-fragment (since this limitation which fixed as part of the SG
-implementation) so we do not need this restriction.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Steven Smith <Steven.Smith(a)eu.citrix.com>
----
- drivers/xen/netback/common.h | 15 ++-
- drivers/xen/netback/netback.c | 282 ++++++++++++++++++++++++++++++-----------
- 2 files changed, 218 insertions(+), 79 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index be4fe91..9c0c048 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -82,7 +82,9 @@ struct xen_netif {
- /* Internal feature information. */
- u8 can_queue:1; /* can queue packets for receiver? */
-
-- /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
-+ /* Allow netif_be_start_xmit() to peek ahead in the rx request
-+ * ring. This is a prediction of what rx_req_cons will be once
-+ * all queued skbs are put on the ring. */
- RING_IDX rx_req_cons_peek;
-
- /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
-@@ -231,6 +233,8 @@ typedef unsigned int pending_ring_idx_t;
-
- struct netbk_rx_meta {
- int id;
-+ int size;
-+ int gso_size;
- };
-
- struct netbk_tx_pending_inuse {
-@@ -240,6 +244,8 @@ struct netbk_tx_pending_inuse {
-
- #define MAX_PENDING_REQS 256
-
-+#define MAX_BUFFER_OFFSET PAGE_SIZE
-+
- /* extra field used in struct page */
- union page_ext {
- struct {
-@@ -301,7 +307,12 @@ struct xen_netbk {
- 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];
-+ /*
-+ * Each head or fragment can be up to 4096 bytes. Given
-+ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
-+ * head/fragment uses 2 copy operation.
-+ */
-+ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
- unsigned char rx_notify[NR_IRQS];
- u16 notify_list[NET_RX_RING_SIZE];
- struct netbk_rx_meta meta[NET_RX_RING_SIZE];
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 9f7e489..d53d88e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -259,6 +259,48 @@ static void tx_queue_callback(unsigned long data)
- netif_wake_queue(netif->dev);
- }
-
-+/* Figure out how many ring slots we're going to need to send @skb to
-+ the guest. */
-+static unsigned count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
-+{
-+ unsigned count;
-+ unsigned copy_off;
-+ unsigned i;
-+
-+ copy_off = 0;
-+ count = 1;
-+
-+ BUG_ON(offset_in_page(skb->data) + skb_headlen(skb) > MAX_BUFFER_OFFSET);
-+
-+ copy_off = skb_headlen(skb);
-+
-+ if (skb_shinfo(skb)->gso_size)
-+ count++;
-+
-+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+ unsigned long size = skb_shinfo(skb)->frags[i].size;
-+ unsigned long bytes;
-+ while (size > 0) {
-+ BUG_ON(copy_off > MAX_BUFFER_OFFSET);
-+
-+ /* These checks are the same as in netbk_gop_frag_copy */
-+ if (copy_off == MAX_BUFFER_OFFSET
-+ || ((copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && copy_off)) {
-+ count++;
-+ copy_off = 0;
-+ }
-+
-+ bytes = size;
-+ if (copy_off + bytes > MAX_BUFFER_OFFSET)
-+ bytes = MAX_BUFFER_OFFSET - copy_off;
-+
-+ copy_off += bytes;
-+ size -= bytes;
-+ }
-+ }
-+ return count;
-+}
-+
- int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct xen_netif *netif = netdev_priv(dev);
-@@ -290,8 +332,9 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- skb = nskb;
- }
-
-- netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
-- !!skb_shinfo(skb)->gso_size;
-+ /* Reserve ring slots for the worst-case number of
-+ * fragments. */
-+ netif->rx_req_cons_peek += count_skb_slots(skb, netif);
- netif_get(netif);
-
- if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
-@@ -335,96 +378,165 @@ struct netrx_pending_operations {
- struct gnttab_copy *copy;
- struct multicall_entry *mcl;
- struct netbk_rx_meta *meta;
-+ int copy_off;
-+ grant_ref_t copy_gref;
- };
-
- /* Set up the grant operations for this fragment. If it's a flipping
- interface, we also set up the unmap request from here. */
--static u16 netbk_gop_frag(struct xen_netif *netif, struct netbk_rx_meta *meta,
-- int i, struct netrx_pending_operations *npo,
-- struct page *page, unsigned long size,
-- unsigned long offset)
-+
-+static void netbk_gop_frag_copy(struct xen_netif *netif,
-+ struct netrx_pending_operations *npo,
-+ struct page *page, unsigned long size,
-+ unsigned long offset, int head)
- {
- struct gnttab_copy *copy_gop;
-- struct xen_netif_rx_request *req;
-- unsigned long old_mfn;
-+ struct netbk_rx_meta *meta;
- int group = netif_page_group(page);
- int idx = netif_page_index(page);
-+ unsigned long bytes;
-+
-+ /* Data must not cross a page boundary. */
-+ BUG_ON(size + offset > PAGE_SIZE);
-
-- old_mfn = virt_to_mfn(page_address(page));
-+ meta = npo->meta + npo->meta_prod - 1;
-
-- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
-+ while (size > 0) {
-+ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
-
-- copy_gop = npo->copy + npo->copy_prod++;
-- copy_gop->flags = GNTCOPY_dest_gref;
-- if (PageForeign(page)) {
-+ /*
-+ * Move to a new receive buffer if:
-+ *
-+ * simple case: we have completely filled the current buffer.
-+ *
-+ * complex case: the current frag would overflow
-+ * the current buffer but only if:
-+ * (i) this frag would fit completely in the next buffer
-+ * and (ii) there is already some data in the current buffer
-+ * and (iii) this is not the head buffer.
-+ *
-+ * Where:
-+ * - (i) stops us splitting a frag into two copies
-+ * unless the frag is too large for a single buffer.
-+ * - (ii) stops us from leaving a buffer pointlessly empty.
-+ * - (iii) stops us leaving the first buffer
-+ * empty. Strictly speaking this is already covered
-+ * by (ii) but is explicitly checked because
-+ * netfront relies on the first buffer being
-+ * non-empty and can crash otherwise.
-+ *
-+ * This means we will effectively linearise small
-+ * frags but do not needlessly split large buffers
-+ * into multiple copies tend to give large frags their
-+ * own buffers as before.
-+ */
-+ if (npo->copy_off == MAX_BUFFER_OFFSET
-+ || ((npo->copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && npo->copy_off && !head)) {
-+ struct xen_netif_rx_request *req;
-+
-+ BUG_ON(head); /* Netfront requires there to be some data in the head buffer. */
-+ /* Overflowed this request, go to the next one */
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->size = 0;
-+ meta->id = req->id;
-+ npo->copy_off = 0;
-+ npo->copy_gref = req->gref;
-+ }
-+
-+ bytes = size;
-+ if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
-+ bytes = MAX_BUFFER_OFFSET - npo->copy_off;
-+
-+ copy_gop = npo->copy + npo->copy_prod++;
-+ copy_gop->flags = GNTCOPY_dest_gref;
-+ if (PageForeign(page)) {
- struct xen_netbk *netbk = &xen_netbk[group];
- struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
- copy_gop->source.domid = src_pend->netif->domid;
- copy_gop->source.u.ref = src_pend->req.gref;
-- copy_gop->flags |= GNTCOPY_source_gref;
-- } else {
-- copy_gop->source.domid = DOMID_SELF;
-- copy_gop->source.u.gmfn = old_mfn;
-- }
-- copy_gop->source.offset = offset;
-- copy_gop->dest.domid = netif->domid;
-- copy_gop->dest.offset = 0;
-- copy_gop->dest.u.ref = req->gref;
-- copy_gop->len = size;
-+ copy_gop->flags |= GNTCOPY_source_gref;
-+ } else {
-+ copy_gop->source.domid = DOMID_SELF;
-+ copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
-+ }
-+ copy_gop->source.offset = offset;
-+ copy_gop->dest.domid = netif->domid;
-
-- return req->id;
-+ copy_gop->dest.offset = npo->copy_off;
-+ copy_gop->dest.u.ref = npo->copy_gref;
-+ copy_gop->len = bytes;
-+
-+ npo->copy_off += bytes;
-+ meta->size += bytes;
-+
-+ offset += bytes;
-+ size -= bytes;
-+ head = 0; /* Must be something in this buffer now */
-+ }
- }
-
--static void netbk_gop_skb(struct sk_buff *skb,
-- struct netrx_pending_operations *npo)
-+/* Prepare an SKB to be transmitted to the frontend. This is
-+ responsible for allocating grant operations, meta structures, etc.
-+ It returns the number of meta structures consumed. The number of
-+ ring slots used is always equal to the number of meta slots used
-+ plus the number of GSO descriptors used. Currently, we use either
-+ zero GSO descriptors (for non-GSO packets) or one descriptor (for
-+ frontend-side LRO). */
-+static int netbk_gop_skb(struct sk_buff *skb,
-+ struct netrx_pending_operations *npo)
- {
- struct xen_netif *netif = netdev_priv(skb->dev);
- int nr_frags = skb_shinfo(skb)->nr_frags;
- int i;
-- int extra;
-- struct netbk_rx_meta *head_meta, *meta;
-+ struct xen_netif_rx_request *req;
-+ struct netbk_rx_meta *meta;
-+ int old_meta_prod;
-+
-+ old_meta_prod = npo->meta_prod;
-
-- head_meta = npo->meta + npo->meta_prod++;
-- head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
-- head_meta->frag.size = skb_shinfo(skb)->gso_size;
-- extra = !!head_meta->frag.size + 1;
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->gso_size = skb_shinfo(skb)->gso_size;
-+ meta->size = 0;
-+ meta->id = req->id;
-+ npo->copy_off = 0;
-+ npo->copy_gref = req->gref;
-+
-+ netbk_gop_frag_copy(netif,
-+ npo, virt_to_page(skb->data),
-+ skb_headlen(skb),
-+ offset_in_page(skb->data), 1);
-+
-+ /* Leave a gap for the GSO descriptor. */
-+ if (skb_shinfo(skb)->gso_size)
-+ netif->rx.req_cons++;
-
- for (i = 0; i < nr_frags; i++) {
-- meta = npo->meta + npo->meta_prod++;
-- meta->frag = skb_shinfo(skb)->frags[i];
-- meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
-- meta->frag.page,
-- meta->frag.size,
-- meta->frag.page_offset);
-+ netbk_gop_frag_copy(netif, npo,
-+ skb_shinfo(skb)->frags[i].page,
-+ skb_shinfo(skb)->frags[i].size,
-+ skb_shinfo(skb)->frags[i].page_offset,
-+ 0);
- }
-
-- /*
-- * This must occur at the end to ensure that we don't trash skb_shinfo
-- * until we're done. We know that the head doesn't cross a page
-- * boundary because such packets get copied in netif_be_start_xmit.
-- */
-- head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
-- virt_to_page(skb->data),
-- skb_headlen(skb),
-- offset_in_page(skb->data));
--
-- netif->rx.req_cons += nr_frags + extra;
-+ return npo->meta_prod - old_meta_prod;
- }
-
- /* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
- used to set up the operations on the top of
- netrx_pending_operations, which have since been done. Check that
- they didn't give any errors and advance over them. */
--static int netbk_check_gop(int nr_frags, domid_t domid,
-+static int netbk_check_gop(int nr_meta_slots, domid_t domid,
- struct netrx_pending_operations *npo)
- {
- struct gnttab_copy *copy_op;
- int status = NETIF_RSP_OKAY;
- int i;
-
-- for (i = 0; i <= nr_frags; i++) {
-- copy_op = npo->copy + npo->copy_cons++;
-- if (copy_op->status != GNTST_okay) {
-+ for (i = 0; i < nr_meta_slots; i++) {
-+ copy_op = npo->copy + npo->copy_cons++;
-+ if (copy_op->status != GNTST_okay) {
- DPRINTK("Bad status %d from copy to DOM%d.\n",
- copy_op->status, domid);
- status = NETIF_RSP_ERROR;
-@@ -435,27 +547,35 @@ static int netbk_check_gop(int nr_frags, domid_t domid,
- }
-
- static void netbk_add_frag_responses(struct xen_netif *netif, int status,
-- struct netbk_rx_meta *meta, int nr_frags)
-+ struct netbk_rx_meta *meta,
-+ int nr_meta_slots)
- {
- int i;
- unsigned long offset;
-
-- for (i = 0; i < nr_frags; i++) {
-- int id = meta[i].id;
-- int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
--
-+ for (i = 0; i < nr_meta_slots; i++) {
-+ int flags;
-+ if (i == nr_meta_slots - 1)
-+ flags = 0;
-+ else
-+ flags = NETRXF_more_data;
-+
- offset = 0;
-- make_rx_response(netif, id, status, offset,
-- meta[i].frag.size, flags);
-+ make_rx_response(netif, meta[i].id, status, offset,
-+ meta[i].size, flags);
- }
- }
-
-+struct skb_cb_overlay {
-+ int meta_slots_used;
-+};
-+
- static void net_rx_action(unsigned long data)
- {
- struct xen_netif *netif = NULL;
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- s8 status;
-- u16 id, irq, flags;
-+ u16 irq, flags;
- struct xen_netif_rx_response *resp;
- struct multicall_entry *mcl;
- struct sk_buff_head rxq;
-@@ -465,6 +585,7 @@ static void net_rx_action(unsigned long data)
- int nr_frags;
- int count;
- unsigned long offset;
-+ struct skb_cb_overlay *sco;
-
- struct netrx_pending_operations npo = {
- .mmu = netbk->rx_mmu,
-@@ -479,10 +600,11 @@ static void net_rx_action(unsigned long data)
- count = 0;
-
- while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
-+ netif = netdev_priv(skb->dev);
- nr_frags = skb_shinfo(skb)->nr_frags;
-- *(int *)skb->cb = nr_frags;
-
-- netbk_gop_skb(skb, &npo);
-+ sco = (struct skb_cb_overlay *)skb->cb;
-+ sco->meta_slots_used = netbk_gop_skb(skb, &npo);
-
- count += nr_frags + 1;
-
-@@ -541,18 +663,20 @@ static void net_rx_action(unsigned long data)
- BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
-
- while ((skb = __skb_dequeue(&rxq)) != NULL) {
-- nr_frags = *(int *)skb->cb;
-+ sco = (struct skb_cb_overlay *)skb->cb;
-
- netif = netdev_priv(skb->dev);
-
- netif->stats.tx_bytes += skb->len;
- netif->stats.tx_packets++;
-
-- status = netbk_check_gop(nr_frags, netif->domid, &npo);
--
-- id = netbk->meta[npo.meta_cons].id;
-- flags = nr_frags ? NETRXF_more_data : 0;
-+ status = netbk_check_gop(sco->meta_slots_used,
-+ netif->domid, &npo);
-
-+ if (sco->meta_slots_used == 1)
-+ flags = 0;
-+ else
-+ flags = NETRXF_more_data;
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
- flags |= NETRXF_csum_blank | NETRXF_data_validated;
- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
-@@ -560,10 +684,12 @@ static void net_rx_action(unsigned long data)
- flags |= NETRXF_data_validated;
-
- offset = 0;
-- resp = make_rx_response(netif, id, status, offset,
-- skb_headlen(skb), flags);
-+ resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
-+ status, offset,
-+ netbk->meta[npo.meta_cons].size,
-+ flags);
-
-- if (netbk->meta[npo.meta_cons].frag.size) {
-+ if (netbk->meta[npo.meta_cons].gso_size) {
- struct xen_netif_extra_info *gso =
- (struct xen_netif_extra_info *)
- RING_GET_RESPONSE(&netif->rx,
-@@ -571,7 +697,7 @@ static void net_rx_action(unsigned long data)
-
- resp->flags |= NETRXF_extra_info;
-
-- gso->u.gso.size = netbk->meta[npo.meta_cons].frag.size;
-+ gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
- gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
- gso->u.gso.pad = 0;
- gso->u.gso.features = 0;
-@@ -580,9 +706,11 @@ static void net_rx_action(unsigned long data)
- gso->flags = 0;
- }
-
-- netbk_add_frag_responses(netif, status,
-- netbk->meta + npo.meta_cons + 1,
-- nr_frags);
-+ if (sco->meta_slots_used > 1) {
-+ netbk_add_frag_responses(netif, status,
-+ netbk->meta + npo.meta_cons + 1,
-+ sco->meta_slots_used - 1);
-+ }
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
- irq = netif->irq;
-@@ -597,8 +725,8 @@ static void net_rx_action(unsigned long data)
- netif_wake_queue(netif->dev);
-
- netif_put(netif);
-+ npo.meta_cons += sco->meta_slots_used;
- dev_kfree_skb(skb);
-- npo.meta_cons += nr_frags + 1;
- }
-
- while (notify_nr != 0) {
---
-1.7.4
-
-
-From 96069b28e612232fb739ef48d9c2c5178b19f562 Mon Sep 17 00:00:00 2001
-From: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Date: Thu, 10 Jun 2010 19:03:15 +0800
-Subject: [PATCH 082/244] xen: netback: Set allocated memory to zero from vmalloc.
-
-This should fix the windows/linux pv driver issue.
-
-Signed-off-by: Dongxiao Xu <dongxiao.xu(a)intel.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index d53d88e..c7024d4 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1724,6 +1724,7 @@ static int __init netback_init(void)
- printk(KERN_ALERT "%s: out of memory\n", __func__);
- return -ENOMEM;
- }
-+ memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
-
- /* We can increase reservation by this much in net_rx_action(). */
- // balloon_update_driver_allowance(NET_RX_RING_SIZE);
---
-1.7.4
-
-
-From 109a748d1c11b7eeaaacedb08c48bc65640b0bb8 Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Mon, 14 Jun 2010 13:23:33 +0100
-Subject: [PATCH 083/244] xen: netback: minor code formatting fixup
-
-Don't include redundant casts from allocation.
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 3 +--
- 1 files changed, 1 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index c7024d4..58e920a 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1718,8 +1718,7 @@ static int __init netback_init(void)
- return -ENODEV;
-
- xen_netbk_group_nr = num_online_cpus();
-- xen_netbk = (struct xen_netbk *)vmalloc(sizeof(struct xen_netbk) *
-- xen_netbk_group_nr);
-+ xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
- if (!xen_netbk) {
- printk(KERN_ALERT "%s: out of memory\n", __func__);
- return -ENOMEM;
---
-1.7.4
-
-
-From 2424b59d68ee6ccdb7e52ab68bdba3a8b742513d Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 30 Jun 2010 10:12:49 +0100
-Subject: [PATCH 084/244] xen: netback: drop more relics of flipping mode
-
-The mmu_update and gnttab_transfer arrays were only used by flipping
-mode. With those gone the multicall now consists of a single call to
-GNTTABOP_copy so drop the multicall as well and just make the one
-hypercall.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Cc: Paul Durrant <paul.durrant(a)citrix.com>
----
- drivers/xen/netback/common.h | 3 --
- drivers/xen/netback/netback.c | 55 +++--------------------------------------
- 2 files changed, 4 insertions(+), 54 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 9c0c048..08e7a0e 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -304,9 +304,6 @@ struct xen_netbk {
- 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];
- /*
- * Each head or fragment can be up to 4096 bytes. Given
- * MAX_BUFFER_OFFSET of 4096 the worst case is that each
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 58e920a..ca65840 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -368,15 +368,9 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- }
-
- struct netrx_pending_operations {
-- unsigned trans_prod, trans_cons;
-- unsigned mmu_prod, mmu_mcl;
-- unsigned mcl_prod, mcl_cons;
- unsigned copy_prod, copy_cons;
- unsigned meta_prod, meta_cons;
-- struct mmu_update *mmu;
-- struct gnttab_transfer *trans;
- struct gnttab_copy *copy;
-- struct multicall_entry *mcl;
- struct netbk_rx_meta *meta;
- int copy_off;
- grant_ref_t copy_gref;
-@@ -577,7 +571,6 @@ static void net_rx_action(unsigned long data)
- s8 status;
- u16 irq, flags;
- struct xen_netif_rx_response *resp;
-- struct multicall_entry *mcl;
- struct sk_buff_head rxq;
- struct sk_buff *skb;
- int notify_nr = 0;
-@@ -588,10 +581,7 @@ static void net_rx_action(unsigned long data)
- struct skb_cb_overlay *sco;
-
- struct netrx_pending_operations npo = {
-- .mmu = netbk->rx_mmu,
-- .trans = netbk->grant_trans_op,
- .copy = netbk->grant_copy_op,
-- .mcl = netbk->rx_mcl,
- .meta = netbk->meta,
- };
-
-@@ -617,50 +607,13 @@ static void net_rx_action(unsigned long data)
-
- 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(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)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(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)netbk->grant_trans_op;
-- mcl->args[2] = npo.trans_prod;
-- }
--
-- if (npo.copy_prod) {
-- 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)netbk->grant_copy_op;
-- mcl->args[2] = npo.copy_prod;
-- }
--
-- /* Nothing to do? */
-- if (!npo.mcl_prod)
-+ if (!npo.copy_prod)
- return;
-
-- BUG_ON(npo.mcl_prod > ARRAY_SIZE(netbk->rx_mcl));
--
-- ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
-+ BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
-+ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
-+ npo.copy_prod);
- BUG_ON(ret != 0);
-- /* The mmu_machphys_update() must not fail. */
-- BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
-
- while ((skb = __skb_dequeue(&rxq)) != NULL) {
- sco = (struct skb_cb_overlay *)skb->cb;
---
-1.7.4
-
-
-From 673a19d9e2d78939c6dc9c49e7e35ee54b54c8c7 Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Fri, 2 Jul 2010 10:28:11 +0100
-Subject: [PATCH 085/244] xen: netback: Fix basic indentation issue
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 11 +++++++----
- 1 files changed, 7 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index ca65840..848503e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -445,10 +445,13 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- copy_gop = npo->copy + npo->copy_prod++;
- copy_gop->flags = GNTCOPY_dest_gref;
- if (PageForeign(page)) {
-- struct xen_netbk *netbk = &xen_netbk[group];
-- struct pending_tx_info *src_pend = &netbk->pending_tx_info[idx];
-- copy_gop->source.domid = src_pend->netif->domid;
-- copy_gop->source.u.ref = src_pend->req.gref;
-+ struct xen_netbk *netbk = &xen_netbk[group];
-+ struct pending_tx_info *src_pend;
-+
-+ src_pend = &netbk->pending_tx_info[idx];
-+
-+ copy_gop->source.domid = src_pend->netif->domid;
-+ copy_gop->source.u.ref = src_pend->req.gref;
- copy_gop->flags |= GNTCOPY_source_gref;
- } else {
- copy_gop->source.domid = DOMID_SELF;
---
-1.7.4
-
-
-From d08b2d1f2ff4723b335d0fb5b91ffd6cb6a005d3 Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Mon, 5 Jul 2010 11:45:29 +0100
-Subject: [PATCH 086/244] xen: netback: Add a new style of passing GSO packets to
frontends.
-
-feature-gso-tcpv4-prefix uses precedes the packet data passed to
-the frontend with a ring entry that contains the necessary
-metadata. This style of GSO passing is required for Citrix
-Windows PV Drivers.
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Cc: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 3 ++-
- drivers/xen/netback/netback.c | 37 ++++++++++++++++++++++++++++++++++---
- drivers/xen/netback/xenbus.c | 15 ++++++++++++---
- include/xen/interface/io/netif.h | 4 ++++
- 4 files changed, 52 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 08e7a0e..78451ab 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -80,7 +80,8 @@ struct xen_netif {
- int features;
-
- /* Internal feature information. */
-- u8 can_queue:1; /* can queue packets for receiver? */
-+ u8 can_queue:1; /* can queue packets for receiver? */
-+ u8 gso_prefix:1; /* use a prefix segment for GSO information */
-
- /* Allow netif_be_start_xmit() to peek ahead in the rx request
- * ring. This is a prediction of what rx_req_cons will be once
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 848503e..e93a62e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -432,6 +432,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- /* Overflowed this request, go to the next one */
- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
- meta = npo->meta + npo->meta_prod++;
-+ meta->gso_size = 0;
- meta->size = 0;
- meta->id = req->id;
- npo->copy_off = 0;
-@@ -492,9 +493,23 @@ static int netbk_gop_skb(struct sk_buff *skb,
-
- old_meta_prod = npo->meta_prod;
-
-+ /* Set up a GSO prefix descriptor, if necessary */
-+ if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->gso_size = skb_shinfo(skb)->gso_size;
-+ meta->size = 0;
-+ meta->id = req->id;
-+ }
-+
- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
- meta = npo->meta + npo->meta_prod++;
-- meta->gso_size = skb_shinfo(skb)->gso_size;
-+
-+ if (!netif->gso_prefix)
-+ meta->gso_size = skb_shinfo(skb)->gso_size;
-+ else
-+ meta->gso_size = 0;
-+
- meta->size = 0;
- meta->id = req->id;
- npo->copy_off = 0;
-@@ -506,7 +521,7 @@ static int netbk_gop_skb(struct sk_buff *skb,
- offset_in_page(skb->data), 1);
-
- /* Leave a gap for the GSO descriptor. */
-- if (skb_shinfo(skb)->gso_size)
-+ if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
- netif->rx.req_cons++;
-
- for (i = 0; i < nr_frags; i++) {
-@@ -623,6 +638,21 @@ static void net_rx_action(unsigned long data)
-
- netif = netdev_priv(skb->dev);
-
-+ if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
-+ resp = RING_GET_RESPONSE(&netif->rx,
-+ netif->rx.rsp_prod_pvt++);
-+
-+ resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
-+
-+ resp->offset = netbk->meta[npo.meta_cons].gso_size;
-+ resp->id = netbk->meta[npo.meta_cons].id;
-+ resp->status = sco->meta_slots_used;
-+
-+ npo.meta_cons++;
-+ sco->meta_slots_used--;
-+ }
-+
-+
- netif->stats.tx_bytes += skb->len;
- netif->stats.tx_packets++;
-
-@@ -633,6 +663,7 @@ static void net_rx_action(unsigned long data)
- flags = 0;
- else
- flags = NETRXF_more_data;
-+
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
- flags |= NETRXF_csum_blank | NETRXF_data_validated;
- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
-@@ -645,7 +676,7 @@ static void net_rx_action(unsigned long data)
- netbk->meta[npo.meta_cons].size,
- flags);
-
-- if (netbk->meta[npo.meta_cons].gso_size) {
-+ if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
- struct xen_netif_extra_info *gso =
- (struct xen_netif_extra_info *)
- RING_GET_RESPONSE(&netif->rx,
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index e30b0c7..cda987f 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -457,16 +457,25 @@ static int connect_rings(struct backend_info *be)
- be->netif->dev->mtu = ETH_DATA_LEN;
- }
-
-- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
"%d",
-- &val) < 0)
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
-+ "%d", &val) < 0)
- val = 0;
- if (val) {
- be->netif->features |= NETIF_F_TSO;
- be->netif->dev->features |= NETIF_F_TSO;
- }
-
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
-+ "%d", &val) < 0)
-+ val = 0;
-+ if (val) {
-+ be->netif->features |= NETIF_F_TSO;
-+ be->netif->dev->features |= NETIF_F_TSO;
-+ be->netif->gso_prefix = 1;
-+ }
-+
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
-- "%d", &val) < 0)
-+ "%d", &val) < 0)
- val = 0;
- if (val) {
- be->netif->features &= ~NETIF_F_IP_CSUM;
-diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
-index 518481c..8309344 100644
---- a/include/xen/interface/io/netif.h
-+++ b/include/xen/interface/io/netif.h
-@@ -131,6 +131,10 @@ struct xen_netif_rx_request {
- #define _NETRXF_extra_info (3)
- #define NETRXF_extra_info (1U<<_NETRXF_extra_info)
-
-+/* GSO Prefix descriptor. */
-+#define _NETRXF_gso_prefix (4)
-+#define NETRXF_gso_prefix (1U<<_NETRXF_gso_prefix)
-+
- struct xen_netif_rx_response {
- uint16_t id;
- uint16_t offset; /* Offset in page of start of received packet */
---
-1.7.4
-
-
-From bd910979612331d60a629c16a49ebeb5efa0f035 Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Fri, 2 Jul 2010 10:28:13 +0100
-Subject: [PATCH 087/244] xen: netback: Make frontend features distinct from netback
feature flags.
-
-Make sure that if a feature flag is disabled by ethtool on netback
-that we do not gratuitously re-enabled it when we check the frontend
-features during ring connection.
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Cc: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 14 ++++++--
- drivers/xen/netback/interface.c | 68 ++++++++++++++++++++++++++++++--------
- drivers/xen/netback/netback.c | 2 +-
- drivers/xen/netback/xenbus.c | 44 ++++++++++---------------
- 4 files changed, 81 insertions(+), 47 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 78451ab..a5f3759 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -76,12 +76,17 @@ struct xen_netif {
- struct vm_struct *tx_comms_area;
- struct vm_struct *rx_comms_area;
-
-- /* Set of features that can be turned on in dev->features. */
-- int features;
-+ /* Flags that must not be set in dev->features */
-+ int features_disabled;
-+
-+ /* Frontend feature information. */
-+ u8 can_sg:1;
-+ u8 gso:1;
-+ u8 gso_prefix:1;
-+ u8 csum:1;
-
- /* Internal feature information. */
- u8 can_queue:1; /* can queue packets for receiver? */
-- u8 gso_prefix:1; /* use a prefix segment for GSO information */
-
- /* Allow netif_be_start_xmit() to peek ahead in the rx request
- * ring. This is a prediction of what rx_req_cons will be once
-@@ -187,6 +192,7 @@ void netif_accel_init(void);
-
- void netif_disconnect(struct xen_netif *netif);
-
-+void netif_set_features(struct xen_netif *netif);
- struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle);
- int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-@@ -223,7 +229,7 @@ static inline int netbk_can_queue(struct net_device *dev)
- static inline int netbk_can_sg(struct net_device *dev)
- {
- struct xen_netif *netif = netdev_priv(dev);
-- return netif->features & NETIF_F_SG;
-+ return netif->can_sg;
- }
-
- struct pending_tx_info {
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 172ef4c..2e8508a 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -121,31 +121,69 @@ static int netbk_change_mtu(struct net_device *dev, int mtu)
- return 0;
- }
-
--static int netbk_set_sg(struct net_device *dev, u32 data)
-+void netif_set_features(struct xen_netif *netif)
- {
-- if (data) {
-- struct xen_netif *netif = netdev_priv(dev);
-+ struct net_device *dev = netif->dev;
-+ int features = dev->features;
-+
-+ if (netif->can_sg)
-+ features |= NETIF_F_SG;
-+ if (netif->gso || netif->gso_prefix)
-+ features |= NETIF_F_TSO;
-+ if (netif->csum)
-+ features |= NETIF_F_IP_CSUM;
-+
-+ features &= ~(netif->features_disabled);
-
-- if (!(netif->features & NETIF_F_SG))
-+ if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
-+ dev->mtu = ETH_DATA_LEN;
-+
-+ dev->features = features;
-+}
-+
-+static int netbk_set_tx_csum(struct net_device *dev, u32 data)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (data) {
-+ if (!netif->csum)
- return -ENOSYS;
-+ netif->features_disabled &= ~NETIF_F_IP_CSUM;
-+ } else {
-+ netif->features_disabled |= NETIF_F_IP_CSUM;
- }
-
-- if (dev->mtu > ETH_DATA_LEN)
-- dev->mtu = ETH_DATA_LEN;
-+ netif_set_features(netif);
-+ return 0;
-+}
-
-- return ethtool_op_set_sg(dev, data);
-+static int netbk_set_sg(struct net_device *dev, u32 data)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (data) {
-+ if (!netif->can_sg)
-+ return -ENOSYS;
-+ netif->features_disabled &= ~NETIF_F_SG;
-+ } else {
-+ netif->features_disabled |= NETIF_F_SG;
-+ }
-+
-+ netif_set_features(netif);
-+ return 0;
- }
-
- static int netbk_set_tso(struct net_device *dev, u32 data)
- {
-+ struct xen_netif *netif = netdev_priv(dev);
- if (data) {
-- struct xen_netif *netif = netdev_priv(dev);
--
-- if (!(netif->features & NETIF_F_TSO))
-+ if (!netif->gso && !netif->gso_prefix)
- return -ENOSYS;
-+ netif->features_disabled &= ~NETIF_F_TSO;
-+ } else {
-+ netif->features_disabled |= NETIF_F_TSO;
- }
-
-- return ethtool_op_set_tso(dev, data);
-+ netif_set_features(netif);
-+ return 0;
- }
-
- static void netbk_get_drvinfo(struct net_device *dev,
-@@ -200,7 +238,7 @@ static struct ethtool_ops network_ethtool_ops =
- .get_drvinfo = netbk_get_drvinfo,
-
- .get_tx_csum = ethtool_op_get_tx_csum,
-- .set_tx_csum = ethtool_op_set_tx_csum,
-+ .set_tx_csum = netbk_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = netbk_set_sg,
- .get_tso = ethtool_op_get_tso,
-@@ -242,7 +280,8 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- netif->domid = domid;
- netif->group = -1;
- netif->handle = handle;
-- netif->features = NETIF_F_SG;
-+ netif->can_sg = 1;
-+ netif->csum = 1;
- atomic_set(&netif->refcnt, 1);
- init_waitqueue_head(&netif->waiting_to_free);
- netif->dev = dev;
-@@ -259,8 +298,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- init_timer(&netif->tx_queue_timeout);
-
- dev->netdev_ops = &netback_ops;
-- dev->features = NETIF_F_IP_CSUM|NETIF_F_SG;
--
-+ netif_set_features(netif);
- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-
- dev->tx_queue_len = netbk_queue_length;
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index e93a62e..63a771e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -238,7 +238,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-
- static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
- {
-- if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
-+ if (netif->can_sg || netif->gso || netif->gso_prefix)
- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
- return 1; /* all in one */
- }
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index cda987f..17ff5cf 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -404,6 +404,7 @@ static void connect(struct backend_info *be)
-
- static int connect_rings(struct backend_info *be)
- {
-+ struct xen_netif *netif = be->netif;
- struct xenbus_device *dev = be->dev;
- unsigned long tx_ring_ref, rx_ring_ref;
- unsigned int evtchn, rx_copy;
-@@ -437,53 +438,42 @@ static int connect_rings(struct backend_info *be)
- if (!rx_copy)
- return -EOPNOTSUPP;
-
-- if (be->netif->dev->tx_queue_len != 0) {
-+ if (netif->dev->tx_queue_len != 0) {
- if (xenbus_scanf(XBT_NIL, dev->otherend,
- "feature-rx-notify", "%d", &val) < 0)
- val = 0;
- if (val)
-- be->netif->can_queue = 1;
-+ netif->can_queue = 1;
- else
- /* Must be non-zero for pfifo_fast to work. */
-- be->netif->dev->tx_queue_len = 1;
-+ netif->dev->tx_queue_len = 1;
- }
-
-- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d",
&val) < 0)
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
-+ "%d", &val) < 0)
- val = 0;
-- if (!val) {
-- be->netif->features &= ~NETIF_F_SG;
-- be->netif->dev->features &= ~NETIF_F_SG;
-- if (be->netif->dev->mtu > ETH_DATA_LEN)
-- be->netif->dev->mtu = ETH_DATA_LEN;
-- }
-+ netif->can_sg = !!val;
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
-- "%d", &val) < 0)
-+ "%d", &val) < 0)
- val = 0;
-- if (val) {
-- be->netif->features |= NETIF_F_TSO;
-- be->netif->dev->features |= NETIF_F_TSO;
-- }
-+ netif->gso = !!val;
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
-- "%d", &val) < 0)
-+ "%d", &val) < 0)
- val = 0;
-- if (val) {
-- be->netif->features |= NETIF_F_TSO;
-- be->netif->dev->features |= NETIF_F_TSO;
-- be->netif->gso_prefix = 1;
-- }
-+ netif->gso_prefix = !!val;
-
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
-- "%d", &val) < 0)
-+ "%d", &val) < 0)
- val = 0;
-- if (val) {
-- be->netif->features &= ~NETIF_F_IP_CSUM;
-- be->netif->dev->features &= ~NETIF_F_IP_CSUM;
-- }
-+ netif->csum = !val;
-+
-+ /* Set dev->features */
-+ netif_set_features(netif);
-
- /* Map the shared frame, irq etc. */
-- err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
-+ err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
- if (err) {
- xenbus_dev_fatal(dev, err,
- "mapping shared-frames %lu/%lu port %u",
---
-1.7.4
-
-
-From cf8c20169427de5829e3ec723712b77de52e64ac Mon Sep 17 00:00:00 2001
-From: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-Date: Thu, 15 Jul 2010 10:46:50 -0700
-Subject: [PATCH 088/244] xen: netback: only initialize for PV domains
-
-HVM domains don't support netback
-
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 63a771e..911c85b 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1701,7 +1701,7 @@ static int __init netback_init(void)
- int rc = 0;
- int group;
-
-- if (!xen_domain())
-+ if (!xen_pv_domain())
- return -ENODEV;
-
- xen_netbk_group_nr = num_online_cpus();
---
-1.7.4
-
-
-From dfa4906cfade8541573814c34be82ba02c348317 Mon Sep 17 00:00:00 2001
-From: Owen Smith <owen.smith(a)citrix.com>
-Date: Wed, 22 Dec 2010 15:05:00 +0000
-Subject: [PATCH 089/244] Union the blkif_request request specific fields
-
-Prepare for extending the block device ring to allow request
-specific fields, by moving the request specific fields for
-reads, writes and barrier requests to a union member
-
-Signed-off-by: Owen Smith <owen.smith(a)citrix.com>
----
- drivers/block/xen-blkfront.c | 8 ++++----
- include/xen/interface/io/blkif.h | 16 +++++++++++-----
- 2 files changed, 15 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
-index d7aa39e..cc4514c 100644
---- a/drivers/block/xen-blkfront.c
-+++ b/drivers/block/xen-blkfront.c
-@@ -281,7 +281,7 @@ static int blkif_queue_request(struct request *req)
- info->shadow[id].request = req;
-
- ring_req->id = id;
-- ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
-+ ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
- ring_req->handle = info->handle;
-
- ring_req->operation = rq_data_dir(req) ?
-@@ -317,7 +317,7 @@ static int blkif_queue_request(struct request *req)
- rq_data_dir(req) );
-
- info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
-- ring_req->seg[i] =
-+ ring_req->u.rw.seg[i] =
- (struct blkif_request_segment) {
- .gref = ref,
- .first_sect = fsect,
-@@ -615,7 +615,7 @@ static void blkif_completion(struct blk_shadow *s)
- {
- int i;
- for (i = 0; i < s->req.nr_segments; i++)
-- gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
-+ gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL);
- }
-
- static irqreturn_t blkif_interrupt(int irq, void *dev_id)
-@@ -932,7 +932,7 @@ static int blkif_recover(struct blkfront_info *info)
- /* Rewrite any grant references invalidated by susp/resume. */
- for (j = 0; j < req->nr_segments; j++)
- gnttab_grant_foreign_access_ref(
-- req->seg[j].gref,
-+ req->u.rw.seg[j].gref,
- info->xbdev->otherend_id,
- pfn_to_mfn(info->shadow[req->id].frame[j]),
- rq_data_dir(info->shadow[req->id].request));
-diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
-index c2d1fa4..e4f743c 100644
---- a/include/xen/interface/io/blkif.h
-+++ b/include/xen/interface/io/blkif.h
-@@ -51,11 +51,7 @@ typedef uint64_t blkif_sector_t;
- */
- #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
-
--struct blkif_request {
-- uint8_t operation; /* BLKIF_OP_??? */
-- uint8_t nr_segments; /* number of segments */
-- blkif_vdev_t handle; /* only for read/write requests */
-- uint64_t id; /* private guest value, echoed in resp */
-+struct blkif_request_rw {
- blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
- struct blkif_request_segment {
- grant_ref_t gref; /* reference to I/O buffer frame */
-@@ -65,6 +61,16 @@ struct blkif_request {
- } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- };
-
-+struct blkif_request {
-+ uint8_t operation; /* BLKIF_OP_??? */
-+ uint8_t nr_segments; /* number of segments */
-+ blkif_vdev_t handle; /* only for read/write requests */
-+ uint64_t id; /* private guest value, echoed in resp */
-+ union {
-+ struct blkif_request_rw rw;
-+ } u;
-+};
-+
- struct blkif_response {
- uint64_t id; /* copied from request */
- uint8_t operation; /* copied from request */
---
-1.7.4
-
-
-From e8bc588ab4c297e3f3d8f61f205b2d2db258907b Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 18 Jan 2011 20:09:41 -0500
-Subject: [PATCH 090/244] xen: Mark all initial reserved pages for the balloon as
INVALID_P2M_ENTRY.
-
-With this patch, we diligently set regions that will be used by the
-balloon driver to be INVALID_P2M_ENTRY and under the ownership
-of the balloon driver. We are OK using the __set_phys_to_machine
-as we do not expect to be allocating any P2M middle or entries pages.
-The set_phys_to_machine has the side-effect of potentially allocating
-new pages and we do not want that at this stage.
-
-We can do this because xen_build_mfn_list_list will have already
-allocated all such pages up to xen_max_p2m_pfn.
-
-We also move the check for auto translated physmap down the
-stack so it is present in __set_phys_to_machine.
-
-[v2: Rebased with mmu->p2m code split]
-Reviewed-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/include/asm/xen/page.h | 1 +
- arch/x86/xen/mmu.c | 2 +-
- arch/x86/xen/p2m.c | 9 ++++-----
- arch/x86/xen/setup.c | 7 ++++++-
- drivers/xen/balloon.c | 2 +-
- 5 files changed, 13 insertions(+), 8 deletions(-)
-
-diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
-index f25bdf2..8ea9772 100644
---- a/arch/x86/include/asm/xen/page.h
-+++ b/arch/x86/include/asm/xen/page.h
-@@ -41,6 +41,7 @@ extern unsigned int machine_to_phys_order;
-
- extern unsigned long get_phys_to_machine(unsigned long pfn);
- extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
-+extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
-
- extern int m2p_add_override(unsigned long mfn, struct page *page);
- extern int m2p_remove_override(struct page *page);
-diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
-index 5e92b61..0180ae8 100644
---- a/arch/x86/xen/mmu.c
-+++ b/arch/x86/xen/mmu.c
-@@ -2074,7 +2074,7 @@ static void xen_zap_pfn_range(unsigned long vaddr, unsigned int
order,
- in_frames[i] = virt_to_mfn(vaddr);
-
- MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
-- set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
-+ __set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
-
- if (out_frames)
- out_frames[i] = virt_to_pfn(vaddr);
-diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
-index ddc81a0..df4e367 100644
---- a/arch/x86/xen/p2m.c
-+++ b/arch/x86/xen/p2m.c
-@@ -365,6 +365,10 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
- {
- unsigned topidx, mididx, idx;
-
-+ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
-+ BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-+ return true;
-+ }
- if (unlikely(pfn >= MAX_P2M_PFN)) {
- BUG_ON(mfn != INVALID_P2M_ENTRY);
- return true;
-@@ -384,11 +388,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
-
- bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
- {
-- if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
-- BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-- return true;
-- }
--
- if (unlikely(!__set_phys_to_machine(pfn, mfn))) {
- if (!alloc_p2m(pfn))
- return false;
-diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
-index b5a7f92..7201800 100644
---- a/arch/x86/xen/setup.c
-+++ b/arch/x86/xen/setup.c
-@@ -52,6 +52,8 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
-
- static __init void xen_add_extra_mem(unsigned long pages)
- {
-+ unsigned long pfn;
-+
- u64 size = (u64)pages * PAGE_SIZE;
- u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
-
-@@ -66,6 +68,9 @@ static __init void xen_add_extra_mem(unsigned long pages)
- xen_extra_mem_size += size;
-
- xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
-+
-+ for (pfn = PFN_DOWN(extra_start); pfn <= xen_max_p2m_pfn; pfn++)
-+ __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
- }
-
- static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
-@@ -104,7 +109,7 @@ static unsigned long __init xen_release_chunk(phys_addr_t
start_addr,
- WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
- start, end, ret);
- if (ret == 1) {
-- set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
-+ __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
- len++;
- }
- }
-diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
-index 43f9f02..b1661cd 100644
---- a/drivers/xen/balloon.c
-+++ b/drivers/xen/balloon.c
-@@ -296,7 +296,7 @@ static int decrease_reservation(unsigned long nr_pages)
- /* No more mappings: invalidate P2M and add to balloon. */
- for (i = 0; i < nr_pages; i++) {
- pfn = mfn_to_pfn(frame_list[i]);
-- set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
-+ __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
- balloon_append(pfn_to_page(pfn));
- }
-
---
-1.7.4
-
-
-From f9820a46dd7888b05a36e81166fb1abcc47dcc3f Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 29 Nov 2010 13:52:18 -0500
-Subject: [PATCH 091/244] ttm: Introduce a placeholder for DMA (bus) addresses.
-
-This is right now limited to only non-pool constructs.
-
-[v2: Fixed indentation issues, add review-by tag]
-
-Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/gpu/drm/ttm/ttm_page_alloc.c | 8 +++++---
- drivers/gpu/drm/ttm/ttm_tt.c | 10 ++++++++--
- include/drm/ttm/ttm_bo_driver.h | 2 ++
- include/drm/ttm/ttm_page_alloc.h | 8 ++++++--
- 4 files changed, 21 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
-index b1e02ff..9d9d929 100644
---- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
-+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
-@@ -38,6 +38,7 @@
- #include <linux/mm.h>
- #include <linux/seq_file.h> /* for seq_printf */
- #include <linux/slab.h>
-+#include <linux/dma-mapping.h>
-
- #include <asm/atomic.h>
-
-@@ -662,7 +663,8 @@ out:
- * cached pages.
- */
- int ttm_get_pages(struct list_head *pages, int flags,
-- enum ttm_caching_state cstate, unsigned count)
-+ enum ttm_caching_state cstate, unsigned count,
-+ dma_addr_t *dma_address)
- {
- struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
- struct page *p = NULL;
-@@ -720,7 +722,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
- printk(KERN_ERR TTM_PFX
- "Failed to allocate extra pages "
- "for large request.");
-- ttm_put_pages(pages, 0, flags, cstate);
-+ ttm_put_pages(pages, 0, flags, cstate, NULL);
- return r;
- }
- }
-@@ -731,7 +733,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
-
- /* Put all pages in pages list to correct pool to wait for reuse */
- void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags,
-- enum ttm_caching_state cstate)
-+ enum ttm_caching_state cstate, dma_addr_t *dma_address)
- {
- unsigned long irq_flags;
- struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
-diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
-index af789dc..0d39001 100644
---- a/drivers/gpu/drm/ttm/ttm_tt.c
-+++ b/drivers/gpu/drm/ttm/ttm_tt.c
-@@ -49,12 +49,16 @@ static int ttm_tt_swapin(struct ttm_tt *ttm);
- static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm)
- {
- ttm->pages = drm_calloc_large(ttm->num_pages, sizeof(*ttm->pages));
-+ ttm->dma_address = drm_calloc_large(ttm->num_pages,
-+ sizeof(*ttm->dma_address));
- }
-
- static void ttm_tt_free_page_directory(struct ttm_tt *ttm)
- {
- drm_free_large(ttm->pages);
- ttm->pages = NULL;
-+ drm_free_large(ttm->dma_address);
-+ ttm->dma_address = NULL;
- }
-
- static void ttm_tt_free_user_pages(struct ttm_tt *ttm)
-@@ -105,7 +109,8 @@ static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index)
-
- INIT_LIST_HEAD(&h);
-
-- ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1);
-+ ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1,
-+ &ttm->dma_address[index]);
-
- if (ret != 0)
- return NULL;
-@@ -298,7 +303,8 @@ static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm)
- count++;
- }
- }
-- ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state);
-+ ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state,
-+ ttm->dma_address);
- ttm->state = tt_unpopulated;
- ttm->first_himem_page = ttm->num_pages;
- ttm->last_lomem_page = -1;
-diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
-index 8e0c848..6dc4fcc 100644
---- a/include/drm/ttm/ttm_bo_driver.h
-+++ b/include/drm/ttm/ttm_bo_driver.h
-@@ -149,6 +149,7 @@ enum ttm_caching_state {
- * @swap_storage: Pointer to shmem struct file for swap storage.
- * @caching_state: The current caching state of the pages.
- * @state: The current binding state of the pages.
-+ * @dma_address: The DMA (bus) addresses of the pages (if TTM_PAGE_FLAG_DMA32)
- *
- * This is a structure holding the pages, caching- and aperture binding
- * status for a buffer object that isn't backed by fixed (VRAM / AGP)
-@@ -173,6 +174,7 @@ struct ttm_tt {
- tt_unbound,
- tt_unpopulated,
- } state;
-+ dma_addr_t *dma_address;
- };
-
- #define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */
-diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h
-index 1168214..8062890 100644
---- a/include/drm/ttm/ttm_page_alloc.h
-+++ b/include/drm/ttm/ttm_page_alloc.h
-@@ -36,11 +36,13 @@
- * @flags: ttm flags for page allocation.
- * @cstate: ttm caching state for the page.
- * @count: number of pages to allocate.
-+ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
- */
- int ttm_get_pages(struct list_head *pages,
- int flags,
- enum ttm_caching_state cstate,
-- unsigned count);
-+ unsigned count,
-+ dma_addr_t *dma_address);
- /**
- * Put linked list of pages to pool.
- *
-@@ -49,11 +51,13 @@ int ttm_get_pages(struct list_head *pages,
- * count.
- * @flags: ttm flags for page allocation.
- * @cstate: ttm caching state.
-+ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
- */
- void ttm_put_pages(struct list_head *pages,
- unsigned page_count,
- int flags,
-- enum ttm_caching_state cstate);
-+ enum ttm_caching_state cstate,
-+ dma_addr_t *dma_address);
- /**
- * Initialize pool allocator.
- */
---
-1.7.4
-
-
-From 69a07f0b117a40fcc1a479358d8e1f41793617f2 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 29 Nov 2010 14:03:30 -0500
-Subject: [PATCH 092/244] ttm: Utilize the DMA API for pages that have TTM_PAGE_FLAG_DMA32
set.
-
-For pages that have the TTM_PAGE_FLAG_DMA32 flag set we
-use the DMA API. We save the bus address in our array which we
-use to program the GART (see "radeon/ttm/PCIe: Use dma_addr if TTM
-has set it." and "nouveau/ttm/PCIe: Use dma_addr if TTM has set it.").
-
-The reason behind using the DMA API is that under Xen we would
-end up programming the GART with the bounce buffer (SWIOTLB)
-DMA address instead of the physical DMA address of the TTM page.
-The reason being that alloc_page with GFP_DMA32 does not allocate
-pages under the the 4GB mark when running under Xen hypervisor.
-
-Under baremetal this means we do the DMA API call earlier instead
-of when we program the GART.
-
-For details please refer to:
-https://lkml.org/lkml/2011/1/7/251
-
-[v2: Fixed indentation, revised desc, added Reviewed-by]
-Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/gpu/drm/ttm/ttm_page_alloc.c | 26 +++++++++++++++++++++++---
- 1 files changed, 23 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
-index 9d9d929..737a2a2 100644
---- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
-+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
-@@ -683,14 +683,22 @@ int ttm_get_pages(struct list_head *pages, int flags,
- gfp_flags |= GFP_HIGHUSER;
-
- for (r = 0; r < count; ++r) {
-- p = alloc_page(gfp_flags);
-+ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
-+ void *addr;
-+ addr = dma_alloc_coherent(NULL, PAGE_SIZE,
-+ &dma_address[r],
-+ gfp_flags);
-+ if (addr == NULL)
-+ return -ENOMEM;
-+ p = virt_to_page(addr);
-+ } else
-+ p = alloc_page(gfp_flags);
- if (!p) {
-
- printk(KERN_ERR TTM_PFX
- "Unable to allocate page.");
- return -ENOMEM;
- }
--
- list_add(&p->lru, pages);
- }
- return 0;
-@@ -738,12 +746,24 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count,
int flags,
- unsigned long irq_flags;
- struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
- struct page *p, *tmp;
-+ unsigned r;
-
- if (pool == NULL) {
- /* No pool for this memory type so free the pages */
-
-+ r = page_count-1;
- list_for_each_entry_safe(p, tmp, pages, lru) {
-- __free_page(p);
-+ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
-+ void *addr = page_address(p);
-+ WARN_ON(!addr || !dma_address[r]);
-+ if (addr)
-+ dma_free_coherent(NULL, PAGE_SIZE,
-+ addr,
-+ dma_address[r]);
-+ dma_address[r] = 0;
-+ } else
-+ __free_page(p);
-+ r--;
- }
- /* Make the pages list empty */
- INIT_LIST_HEAD(pages);
---
-1.7.4
-
-
-From 27e8b237944af967e0a808580278d432cb028455 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 2 Dec 2010 10:24:13 -0500
-Subject: [PATCH 093/244] ttm: Expand (*populate) to support an array of DMA addresses.
-
-We pass in the array of ttm pages to be populated in the GART/MM
-of the card (or AGP). Patch titled: "ttm: Utilize the DMA API for
-pages that have TTM_PAGE_FLAG_DMA32 set." uses the DMA API to make
-those pages have a proper DMA addresses (in the situation where
-page_to_phys or virt_to_phys do not give use the DMA (bus) address).
-
-Since we are using the DMA API on those pages, we should pass in the
-DMA address to this function so it can save it in its proper fields
-(later patches use it).
-
-[v2: Added reviewed-by tag]
-
-Reviewed-by: Thomas Hellstrom <thellstrom(a)shipmail.org>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 3 ++-
- drivers/gpu/drm/radeon/radeon_ttm.c | 3 ++-
- drivers/gpu/drm/ttm/ttm_agp_backend.c | 3 ++-
- drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 3 ++-
- include/drm/ttm/ttm_bo_driver.h | 4 +++-
- 6 files changed, 12 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-index 288baca..edc140a 100644
---- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-@@ -20,7 +20,8 @@ struct nouveau_sgdma_be {
-
- static int
- nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
-- struct page **pages, struct page *dummy_read_page)
-+ struct page **pages, struct page *dummy_read_page,
-+ dma_addr_t *dma_addrs)
- {
- struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
- struct drm_device *dev = nvbe->dev;
-diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
-index 01c2c73..6f156e9 100644
---- a/drivers/gpu/drm/radeon/radeon_ttm.c
-+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
-@@ -655,7 +655,8 @@ struct radeon_ttm_backend {
- static int radeon_ttm_backend_populate(struct ttm_backend *backend,
- unsigned long num_pages,
- struct page **pages,
-- struct page *dummy_read_page)
-+ struct page *dummy_read_page,
-+ dma_addr_t *dma_addrs)
- {
- struct radeon_ttm_backend *gtt;
-
-diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c
b/drivers/gpu/drm/ttm/ttm_agp_backend.c
-index f999e36..1c4a72f 100644
---- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
-+++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
-@@ -47,7 +47,8 @@ struct ttm_agp_backend {
-
- static int ttm_agp_populate(struct ttm_backend *backend,
- unsigned long num_pages, struct page **pages,
-- struct page *dummy_read_page)
-+ struct page *dummy_read_page,
-+ dma_addr_t *dma_addrs)
- {
- struct ttm_agp_backend *agp_be =
- container_of(backend, struct ttm_agp_backend, backend);
-diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
-index 0d39001..86d5b17 100644
---- a/drivers/gpu/drm/ttm/ttm_tt.c
-+++ b/drivers/gpu/drm/ttm/ttm_tt.c
-@@ -169,7 +169,7 @@ int ttm_tt_populate(struct ttm_tt *ttm)
- }
-
- be->func->populate(be, ttm->num_pages, ttm->pages,
-- ttm->dummy_read_page);
-+ ttm->dummy_read_page, ttm->dma_address);
- ttm->state = tt_unbound;
- return 0;
- }
-diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
-index 80bc37b..87e43e0 100644
---- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
-+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
-@@ -102,7 +102,8 @@ struct vmw_ttm_backend {
-
- static int vmw_ttm_populate(struct ttm_backend *backend,
- unsigned long num_pages, struct page **pages,
-- struct page *dummy_read_page)
-+ struct page *dummy_read_page,
-+ dma_addr_t *dma_addrs)
- {
- struct vmw_ttm_backend *vmw_be =
- container_of(backend, struct vmw_ttm_backend, backend);
-diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
-index 6dc4fcc..ebcd3dd 100644
---- a/include/drm/ttm/ttm_bo_driver.h
-+++ b/include/drm/ttm/ttm_bo_driver.h
-@@ -50,13 +50,15 @@ struct ttm_backend_func {
- * @pages: Array of pointers to ttm pages.
- * @dummy_read_page: Page to be used instead of NULL pages in the
- * array @pages.
-+ * @dma_addrs: Array of DMA (bus) address of the ttm pages.
- *
- * Populate the backend with ttm pages. Depending on the backend,
- * it may or may not copy the @pages array.
- */
- int (*populate) (struct ttm_backend *backend,
- unsigned long num_pages, struct page **pages,
-- struct page *dummy_read_page);
-+ struct page *dummy_read_page,
-+ dma_addr_t *dma_addrs);
- /**
- * struct ttm_backend_func member clear
- *
---
-1.7.4
-
-
-From 7b2fc719094440d3eacacd95fa6a1f5ac495396b Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 18 Jan 2011 20:15:21 -0500
-Subject: [PATCH 096/244] xen/mmu: Add the notion of identity (1-1) mapping.
-
-Our P2M tree structure is a three-level. On the leaf nodes
-we set the Machine Frame Number (MFN) of the PFN. What this means
-is that when one does: pfn_to_mfn(pfn), which is used when creating
-PTE entries, you get the real MFN of the hardware. When Xen sets
-up a guest it initially populates a array which has descending
-(or ascending) MFN values, as so:
-
- idx: 0, 1, 2
- [0x290F, 0x290E, 0x290D, ..]
-
-so pfn_to_mfn(2)==0x290D. If you start, restart many guests that list
-starts looking quite random.
-
-We graft this structure on our P2M tree structure and stick in
-those MFN in the leafs. But for all other leaf entries, or for the top
-root, or middle one, for which there is a void entry, we assume it is
-"missing". So
- pfn_to_mfn(0xc0000)=INVALID_P2M_ENTRY.
-
-We add the possibility of setting 1-1 mappings on certain regions, so
-that:
- pfn_to_mfn(0xc0000)=0xc0000
-
-The benefit of this is, that we can assume for non-RAM regions (think
-PCI BARs, or ACPI spaces), we can create mappings easily b/c we
-get the PFN value to match the MFN.
-
-For this to work efficiently we introduce one new page p2m_identity and
-allocate (via reserved_brk) any other pages we need to cover the sides
-(1GB or 4MB boundary violations). All entries in p2m_identity are set to
-INVALID_P2M_ENTRY type (Xen toolstack only recognizes that and MFNs,
-no other fancy value).
-
-On lookup we spot that the entry points to p2m_identity and return the identity
-value instead of dereferencing and returning INVALID_P2M_ENTRY. If the entry
-points to an allocated page, we just proceed as before and return the PFN.
-If the PFN has IDENTITY_FRAME_BIT set we unmask that in appropriate functions
-(pfn_to_mfn).
-
-The reason for having the IDENTITY_FRAME_BIT instead of just returning the
-PFN is that we could find ourselves where pfn_to_mfn(pfn)==pfn for a
-non-identity pfn. To protect ourselves against we elect to set (and get) the
-IDENTITY_FRAME_BIT on all identity mapped PFNs.
-
-This simplistic diagram is used to explain the more subtle piece of code.
-There is also a digram of the P2M at the end that can help.
-Imagine your E820 looking as so:
-
- 1GB 2GB
-/-------------------+---------\/----\ /----------\ /---+-----\
-| System RAM | Sys RAM ||ACPI| | reserved | | Sys RAM |
-\-------------------+---------/\----/ \----------/ \---+-----/
- ^- 1029MB ^- 2001MB
-
-[1029MB = 263424 (0x40500), 2001MB = 512256 (0x7D100), 2048MB = 524288 (0x80000)]
-
-And dom0_mem=max:3GB,1GB is passed in to the guest, meaning memory past 1GB
-is actually not present (would have to kick the balloon driver to put it in).
-
-When we are told to set the PFNs for identity mapping (see patch: "xen/setup:
-Set identity mapping for non-RAM E820 and E820 gaps.") we pass in the start
-of the PFN and the end PFN (263424 and 512256 respectively). The first step is
-to reserve_brk a top leaf page if the p2m[1] is missing. The top leaf page
-covers 512^2 of page estate (1GB) and in case the start or end PFN is not
-aligned on 512^2*PAGE_SIZE (1GB) we loop on aligned 1GB PFNs from start pfn to
-end pfn. We reserve_brk top leaf pages if they are missing (means they point
-to p2m_mid_missing).
-
-With the E820 example above, 263424 is not 1GB aligned so we allocate a
-reserve_brk page which will cover the PFNs estate from 0x40000 to 0x80000.
-Each entry in the allocate page is "missing" (points to p2m_missing).
-
-Next stage is to determine if we need to do a more granular boundary check
-on the 4MB (or 2MB depending on architecture) off the start and end pfn's.
-We check if the start pfn and end pfn violate that boundary check, and if
-so reserve_brk a middle (p2m[x][y]) leaf page. This way we have a much finer
-granularity of setting which PFNs are missing and which ones are identity.
-In our example 263424 and 512256 both fail the check so we reserve_brk two
-pages. Populate them with INVALID_P2M_ENTRY (so they both have "missing"
values)
-and assign them to p2m[1][2] and p2m[1][488] respectively.
-
-At this point we would at minimum reserve_brk one page, but could be up to
-three. Each call to set_phys_range_identity has at maximum a three page
-cost. If we were to query the P2M at this stage, all those entries from
-start PFN through end PFN (so 1029MB -> 2001MB) would return INVALID_P2M_ENTRY
-("missing").
-
-The next step is to walk from the start pfn to the end pfn setting
-the IDENTITY_FRAME_BIT on each PFN. This is done in 'set_phys_range_identity'.
-If we find that the middle leaf is pointing to p2m_missing we can swap it over
-to p2m_identity - this way covering 4MB (or 2MB) PFN space. At this point we
-do not need to worry about boundary aligment (so no need to reserve_brk a middle
-page, figure out which PFNs are "missing" and which ones are identity), as
that
-has been done earlier. If we find that the middle leaf is not occupied by
-p2m_identity or p2m_missing, we dereference that page (which covers
-512 PFNs) and set the appropriate PFN with IDENTITY_FRAME_BIT. In our example
-263424 and 512256 end up there, and we set from p2m[1][2][256->511] and
-p2m[1][488][0->256] with IDENTITY_FRAME_BIT set.
-
-All other regions that are void (or not filled) either point to p2m_missing
-(considered missing) or have the default value of INVALID_P2M_ENTRY (also
-considered missing). In our case, p2m[1][2][0->255] and p2m[1][488][257->511]
-contain the INVALID_P2M_ENTRY value and are considered "missing."
-
-This is what the p2m ends up looking (for the E820 above) with this
-fabulous drawing:
-
- p2m /--------------\
- /-----\ | &mfn_list[0],| /-----------------\
- | 0 |------>| &mfn_list[1],| /---------------\ | ~0, ~0, .. |
- |-----| | ..., ~0, ~0 | | ~0, ~0, [x]---+----->| IDENTITY [@256] |
- | 1 |---\ \--------------/ | [p2m_identity]+\ | IDENTITY [@257] |
- |-----| \ | [p2m_identity]+\\ | .... |
- | 2 |--\ \-------------------->| ... | \\ \----------------/
- |-----| \ \---------------/ \\
- | 3 |\ \ \\ p2m_identity
- |-----| \ \-------------------->/---------------\ /-----------------\
- | .. +->+ | [p2m_identity]+-->| ~0, ~0, ~0, ... |
- \-----/ / | [p2m_identity]+-->| ..., ~0 |
- / /---------------\ | .... | \-----------------/
- / | IDENTITY[@0] | /-+-[x], ~0, ~0.. |
- / | IDENTITY[@256]|<----/ \---------------/
- / | ~0, ~0, .... |
- | \---------------/
- |
- p2m_missing p2m_missing
-/------------------\ /------------\
-| [p2m_mid_missing]+---->| ~0, ~0, ~0 |
-| [p2m_mid_missing]+---->| ..., ~0 |
-\------------------/ \------------/
-
-where ~0 is INVALID_P2M_ENTRY. IDENTITY is (PFN | IDENTITY_BIT)
-
-[v5: Changed code to use ranges, added ASCII art]
-[v6: Rebased on top of xen->p2m code split]
-[v4: Squished patches in just this one]
-[v7: Added RESERVE_BRK for potentially allocated pages]
-[v8: Fixed alignment problem]
-[v9: Changed 1<<3X to 1<<BITS_PER_LONG-X]
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/include/asm/xen/page.h | 8 ++-
- arch/x86/xen/p2m.c | 113 ++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 117 insertions(+), 4 deletions(-)
-
-diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
-index 8ea9772..65fa4f2 100644
---- a/arch/x86/include/asm/xen/page.h
-+++ b/arch/x86/include/asm/xen/page.h
-@@ -29,8 +29,10 @@ typedef struct xpaddr {
-
- /**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
- #define INVALID_P2M_ENTRY (~0UL)
--#define FOREIGN_FRAME_BIT (1UL<<31)
-+#define FOREIGN_FRAME_BIT (1UL<<(BITS_PER_LONG-1))
-+#define IDENTITY_FRAME_BIT (1UL<<(BITS_PER_LONG-2))
- #define FOREIGN_FRAME(m) ((m) | FOREIGN_FRAME_BIT)
-+#define IDENTITY_FRAME(m) ((m) | IDENTITY_FRAME_BIT)
-
- /* Maximum amount of memory we can handle in a domain in pages */
- #define MAX_DOMAIN_PAGES \
-@@ -42,6 +44,8 @@ extern unsigned int machine_to_phys_order;
- extern unsigned long get_phys_to_machine(unsigned long pfn);
- extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
- extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
-+extern unsigned long set_phys_range_identity(unsigned long pfn_s,
-+ unsigned long pfn_e);
-
- extern int m2p_add_override(unsigned long mfn, struct page *page);
- extern int m2p_remove_override(struct page *page);
-@@ -58,7 +62,7 @@ static inline unsigned long pfn_to_mfn(unsigned long pfn)
- mfn = get_phys_to_machine(pfn);
-
- if (mfn != INVALID_P2M_ENTRY)
-- mfn &= ~FOREIGN_FRAME_BIT;
-+ mfn &= ~(FOREIGN_FRAME_BIT | IDENTITY_FRAME_BIT);
-
- return mfn;
- }
-diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
-index df4e367..dd30ec8 100644
---- a/arch/x86/xen/p2m.c
-+++ b/arch/x86/xen/p2m.c
-@@ -59,9 +59,15 @@ static RESERVE_BRK_ARRAY(unsigned long **, p2m_top,
P2M_TOP_PER_PAGE);
- static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
- static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
-
-+static RESERVE_BRK_ARRAY(unsigned long, p2m_identity, P2M_PER_PAGE);
-+
- RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE *
P2M_MID_PER_PAGE)));
- RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE *
P2M_MID_PER_PAGE)));
-
-+/* We might hit two boundary violations at the start and end, at max each
-+ * boundary violation will require three middle nodes. */
-+RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
-+
- static inline unsigned p2m_top_index(unsigned long pfn)
- {
- BUG_ON(pfn >= MAX_P2M_PFN);
-@@ -221,6 +227,9 @@ void __init xen_build_dynamic_phys_to_machine(void)
- p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
- p2m_top_init(p2m_top);
-
-+ p2m_identity = extend_brk(PAGE_SIZE, PAGE_SIZE);
-+ p2m_init(p2m_identity);
-+
- /*
- * The domain builder gives us a pre-constructed p2m array in
- * mfn_list for all the pages initially given to us, so we just
-@@ -272,6 +281,14 @@ unsigned long get_phys_to_machine(unsigned long pfn)
- mididx = p2m_mid_index(pfn);
- idx = p2m_index(pfn);
-
-+ /*
-+ * The INVALID_P2M_ENTRY is filled in both p2m_*identity
-+ * and in p2m_*missing, so returning the INVALID_P2M_ENTRY
-+ * would be wrong.
-+ */
-+ if (p2m_top[topidx][mididx] == p2m_identity)
-+ return IDENTITY_FRAME(pfn);
-+
- return p2m_top[topidx][mididx][idx];
- }
- EXPORT_SYMBOL_GPL(get_phys_to_machine);
-@@ -341,9 +358,11 @@ static bool alloc_p2m(unsigned long pfn)
- p2m_top_mfn_p[topidx] = mid_mfn;
- }
-
-- if (p2m_top[topidx][mididx] == p2m_missing) {
-+ if (p2m_top[topidx][mididx] == p2m_identity ||
-+ p2m_top[topidx][mididx] == p2m_missing) {
- /* p2m leaf page is missing */
- unsigned long *p2m;
-+ unsigned long *p2m_orig = p2m_top[topidx][mididx];
-
- p2m = alloc_p2m_page();
- if (!p2m)
-@@ -351,7 +370,7 @@ static bool alloc_p2m(unsigned long pfn)
-
- p2m_init(p2m);
-
-- if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
-+ if (cmpxchg(&mid[mididx], p2m_orig, p2m) != p2m_orig)
- free_p2m_page(p2m);
- else
- mid_mfn[mididx] = virt_to_mfn(p2m);
-@@ -360,6 +379,82 @@ static bool alloc_p2m(unsigned long pfn)
- return true;
- }
-
-+bool __early_alloc_p2m(unsigned long pfn)
-+{
-+ unsigned topidx, mididx, idx;
-+
-+ topidx = p2m_top_index(pfn);
-+ mididx = p2m_mid_index(pfn);
-+ idx = p2m_index(pfn);
-+
-+ /* Pfff.. No boundary cross-over, lets get out. */
-+ if (!idx)
-+ return false;
-+
-+ WARN(p2m_top[topidx][mididx] == p2m_identity,
-+ "P2M[%d][%d] == IDENTITY, should be MISSING (or alloced)!\n",
-+ topidx, mididx);
-+
-+ /*
-+ * Could be done by xen_build_dynamic_phys_to_machine..
-+ */
-+ if (p2m_top[topidx][mididx] != p2m_missing)
-+ return false;
-+
-+ /* Boundary cross-over for the edges: */
-+ if (idx) {
-+ unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
-+
-+ p2m_init(p2m);
-+
-+ p2m_top[topidx][mididx] = p2m;
-+
-+ }
-+ return idx != 0;
-+}
-+unsigned long set_phys_range_identity(unsigned long pfn_s,
-+ unsigned long pfn_e)
-+{
-+ unsigned long pfn;
-+
-+ if (unlikely(pfn_s >= MAX_P2M_PFN || pfn_e >= MAX_P2M_PFN))
-+ return 0;
-+
-+ if (unlikely(xen_feature(XENFEAT_auto_translated_physmap)))
-+ return pfn_e - pfn_s;
-+
-+ if (pfn_s > pfn_e)
-+ return 0;
-+
-+ for (pfn = (pfn_s & ~(P2M_MID_PER_PAGE * P2M_PER_PAGE - 1));
-+ pfn < ALIGN(pfn_e, (P2M_MID_PER_PAGE * P2M_PER_PAGE));
-+ pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE)
-+ {
-+ unsigned topidx = p2m_top_index(pfn);
-+ if (p2m_top[topidx] == p2m_mid_missing) {
-+ unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
-+
-+ p2m_mid_init(mid);
-+
-+ p2m_top[topidx] = mid;
-+ }
-+ }
-+
-+ __early_alloc_p2m(pfn_s);
-+ __early_alloc_p2m(pfn_e);
-+
-+ for (pfn = pfn_s; pfn < pfn_e; pfn++)
-+ if (!__set_phys_to_machine(pfn, IDENTITY_FRAME(pfn)))
-+ break;
-+
-+ if (!WARN((pfn - pfn_s) != (pfn_e - pfn_s),
-+ "Identity mapping failed. We are %ld short of 1-1 mappings!\n",
-+ (pfn_e - pfn_s) - (pfn - pfn_s)))
-+ printk(KERN_DEBUG "1-1 mapping on %lx->%lx\n", pfn_s, pfn);
-+
-+ return pfn - pfn_s;
-+}
-+
- /* Try to install p2m mapping; fail if intermediate bits missing */
- bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
- {
-@@ -378,6 +473,20 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
- mididx = p2m_mid_index(pfn);
- idx = p2m_index(pfn);
-
-+ /* For sparse holes were the p2m leaf has real PFN along with
-+ * PCI holes, stick in the PFN as the MFN value.
-+ */
-+ if (mfn != INVALID_P2M_ENTRY && (mfn & IDENTITY_FRAME_BIT)) {
-+ if (p2m_top[topidx][mididx] == p2m_identity)
-+ return true;
-+
-+ /* Swap over from MISSING to IDENTITY if needed. */
-+ if (p2m_top[topidx][mididx] == p2m_missing) {
-+ p2m_top[topidx][mididx] = p2m_identity;
-+ return true;
-+ }
-+ }
-+
- if (p2m_top[topidx][mididx] == p2m_missing)
- return mfn == INVALID_P2M_ENTRY;
-
---
-1.7.4
-
-
-From 57fafbb798ffde486606244c3392ed6f63050222 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 5 Jan 2011 15:46:31 -0500
-Subject: [PATCH 097/244] xen/mmu: Set _PAGE_IOMAP if PFN is an identity PFN.
-
-If we find that the PFN is within the P2M as an identity
-PFN make sure to tack on the _PAGE_IOMAP flag.
-
-Reviewed-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/mmu.c | 18 ++++++++++++++++--
- 1 files changed, 16 insertions(+), 2 deletions(-)
-
-diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
-index 0180ae8..9c9e076 100644
---- a/arch/x86/xen/mmu.c
-+++ b/arch/x86/xen/mmu.c
-@@ -416,8 +416,12 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
- if (val & _PAGE_PRESENT) {
- unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
- pteval_t flags = val & PTE_FLAGS_MASK;
-- unsigned long mfn = pfn_to_mfn(pfn);
-+ unsigned long mfn;
-
-+ if (!xen_feature(XENFEAT_auto_translated_physmap))
-+ mfn = get_phys_to_machine(pfn);
-+ else
-+ mfn = pfn;
- /*
- * If there's no mfn for the pfn, then just create an
- * empty non-present pte. Unfortunately this loses
-@@ -427,8 +431,18 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
- if (unlikely(mfn == INVALID_P2M_ENTRY)) {
- mfn = 0;
- flags = 0;
-+ } else {
-+ /*
-+ * Paramount to do this test _after_ the
-+ * INVALID_P2M_ENTRY as INVALID_P2M_ENTRY &
-+ * IDENTITY_FRAME_BIT resolves to true.
-+ */
-+ mfn &= ~FOREIGN_FRAME_BIT;
-+ if (mfn & IDENTITY_FRAME_BIT) {
-+ mfn &= ~IDENTITY_FRAME_BIT;
-+ flags |= _PAGE_IOMAP;
-+ }
- }
--
- val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
- }
-
---
-1.7.4
-
-
-From e6f1e7aabca9f9f99ef4fc1c752497b3efa7896c Mon Sep 17 00:00:00 2001
-From: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Date: Mon, 31 Jan 2011 15:18:10 +0000
-Subject: [PATCH 098/244] x86/mm/init: respect memblock reserved regions when destroying
mappings
-
-x86/mm/init: respect memblock reserved regions when destroying mappings
-
-In init_memory_mapping we are destroying all the mappings between
-_brk_end and _end, no matter if some memory areas in that range have
-been reserved using memblock_x86_reserve_range.
-Besides if _end is not pmd aligned we might destroy the
-mappings for valid memory between _end and the following pmd.
-
-In order to avoid this problem, before clearing any pmds we check if the
-corresponding memory area has been reserved and we only destroy the
-mapping if it hasn't.
-
-We found this problem because under Xen we have a valid mapping at _end,
-and if _end is not pmd aligned the current code destroys the initial
-part of it.
-
-In practice this fix does not have any impact on native.
-
-Signed-off-by: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
----
- arch/x86/mm/init.c | 13 +++++++++++--
- 1 files changed, 11 insertions(+), 2 deletions(-)
-
-diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
-index 947f42a..66637bd 100644
---- a/arch/x86/mm/init.c
-+++ b/arch/x86/mm/init.c
-@@ -283,6 +283,8 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
- if (!after_bootmem && !start) {
- pud_t *pud;
- pmd_t *pmd;
-+ unsigned long addr;
-+ u64 size, memblock_addr;
-
- mmu_cr4_features = read_cr4();
-
-@@ -291,11 +293,18 @@ unsigned long __init_refok init_memory_mapping(unsigned long
start,
- * located on different 2M pages. cleanup_highmap(), however,
- * can only consider _end when it runs, so destroy any
- * mappings beyond _brk_end here.
-+ * Respect memblock reserved regions.
- */
- pud = pud_offset(pgd_offset_k(_brk_end), _brk_end);
- pmd = pmd_offset(pud, _brk_end - 1);
-- while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1))
-- pmd_clear(pmd);
-+ addr = (_brk_end + PMD_SIZE - 1) & PMD_MASK;
-+ while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1)) {
-+ memblock_addr = memblock_x86_find_in_range_size(__pa(addr),
-+ &size, PMD_SIZE);
-+ if (memblock_addr == (u64) __pa(addr) && size >= PMD_SIZE)
-+ pmd_clear(pmd);
-+ addr += PMD_SIZE;
-+ }
- }
- #endif
- __flush_tlb_all();
---
-1.7.4
-
-
-From f653d10acc37ee1b09c849640f8c0214b4f1d483 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Thu, 3 Feb 2011 12:18:59 -0500
-Subject: [PATCH 100/244] xen-gntdev: Change page limit to be global instead of per-open
-
-Because there is no limitation on how many times a user can open a
-given device file, an per-file-description limit on the number of
-pages granted offers little to no benefit. Change to a global limit
-and remove the ioctl() as the parameter can now be changed via sysfs.
-
-Xen tools changeset 22768:f8d801e5573e is needed to eliminate the
-error this change produces in xc_gnttab_set_max_grants.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
----
- drivers/xen/gntdev.c | 50 ++++++++++++++------------------------------------
- 1 files changed, 14 insertions(+), 36 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 1e31cdc..23d208a 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -45,15 +45,15 @@ MODULE_AUTHOR("Derek G. Murray
<Derek.Murray(a)cl.cam.ac.uk>, "
- "Gerd Hoffmann <kraxel(a)redhat.com>");
- MODULE_DESCRIPTION("User-space granted page access driver");
-
--static int limit = 1024;
-+static int limit = 1024*1024;
- module_param(limit, int, 0644);
--MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped at "
-- "once by a gntdev instance");
-+MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by "
-+ "the gntdev device");
-+
-+static atomic_t pages_mapped = ATOMIC_INIT(0);
-
- struct gntdev_priv {
- struct list_head maps;
-- uint32_t used;
-- uint32_t limit;
- /* lock protects maps from concurrent changes */
- spinlock_t lock;
- struct mm_struct *mm;
-@@ -82,9 +82,7 @@ static void gntdev_print_maps(struct gntdev_priv *priv,
- #ifdef DEBUG
- struct grant_map *map;
-
-- pr_debug("maps list (priv %p, usage %d/%d)\n",
-- priv, priv->used, priv->limit);
--
-+ pr_debug("%s: maps list (priv %p)\n", __func__, priv);
- list_for_each_entry(map, &priv->maps, next)
- pr_debug(" index %2d, count %2d %s\n",
- map->index, map->count,
-@@ -121,9 +119,6 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv,
int count)
- add->count = count;
- add->priv = priv;
-
-- if (add->count + priv->used > priv->limit)
-- goto err;
--
- return add;
-
- err:
-@@ -154,7 +149,6 @@ static void gntdev_add_map(struct gntdev_priv *priv, struct grant_map
*add)
- list_add_tail(&add->next, &priv->maps);
-
- done:
-- priv->used += add->count;
- gntdev_print_maps(priv, "[new]", add->index);
- }
-
-@@ -200,7 +194,7 @@ static int gntdev_del_map(struct grant_map *map)
- if (map->unmap_ops[i].handle)
- return -EBUSY;
-
-- map->priv->used -= map->count;
-+ atomic_sub(map->count, &pages_mapped);
- list_del(&map->next);
- return 0;
- }
-@@ -386,7 +380,6 @@ static int gntdev_open(struct inode *inode, struct file *flip)
-
- INIT_LIST_HEAD(&priv->maps);
- spin_lock_init(&priv->lock);
-- priv->limit = limit;
-
- priv->mm = get_task_mm(current);
- if (!priv->mm) {
-@@ -443,19 +436,24 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
- pr_debug("priv %p, add %d\n", priv, op.count);
- if (unlikely(op.count <= 0))
- return -EINVAL;
-- if (unlikely(op.count > priv->limit))
-- return -EINVAL;
-
- err = -ENOMEM;
- map = gntdev_alloc_map(priv, op.count);
- if (!map)
- return err;
-+
- if (copy_from_user(map->grants, &u->refs,
- sizeof(map->grants[0]) * op.count) != 0) {
- gntdev_free_map(map);
- return err;
- }
-
-+ if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
-+ pr_debug("can't map: over limit\n");
-+ gntdev_free_map(map);
-+ return err;
-+ }
-+
- spin_lock(&priv->lock);
- gntdev_add_map(priv, map);
- op.index = map->index << PAGE_SHIFT;
-@@ -518,23 +516,6 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv
*priv,
- return 0;
- }
-
--static long gntdev_ioctl_set_max_grants(struct gntdev_priv *priv,
-- struct ioctl_gntdev_set_max_grants __user *u)
--{
-- struct ioctl_gntdev_set_max_grants op;
--
-- if (copy_from_user(&op, u, sizeof(op)) != 0)
-- return -EFAULT;
-- pr_debug("priv %p, limit %d\n", priv, op.count);
-- if (op.count > limit)
-- return -E2BIG;
--
-- spin_lock(&priv->lock);
-- priv->limit = op.count;
-- spin_unlock(&priv->lock);
-- return 0;
--}
--
- static long gntdev_ioctl(struct file *flip,
- unsigned int cmd, unsigned long arg)
- {
-@@ -551,9 +532,6 @@ static long gntdev_ioctl(struct file *flip,
- case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
- return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
-
-- case IOCTL_GNTDEV_SET_MAX_GRANTS:
-- return gntdev_ioctl_set_max_grants(priv, ptr);
--
- default:
- pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
- return -ENOIOCTLCMD;
---
-1.7.4
-
-
-From 0e32bc443544fd0783a56f29c27e233e226f6e6b Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Thu, 3 Feb 2011 12:19:00 -0500
-Subject: [PATCH 101/244] xen-gntdev: Use find_vma rather than iterating our vma list
manually
-
-This should be faster if many mappings exist, and also removes
-the only user of map->vma not related to PTE modification.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
----
- drivers/xen/gntdev.c | 32 ++++++++------------------------
- 1 files changed, 8 insertions(+), 24 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 23d208a..ce8c37c 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -167,23 +167,6 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv
*priv,
- return NULL;
- }
-
--static struct grant_map *gntdev_find_map_vaddr(struct gntdev_priv *priv,
-- unsigned long vaddr)
--{
-- struct grant_map *map;
--
-- list_for_each_entry(map, &priv->maps, next) {
-- if (!map->vma)
-- continue;
-- if (vaddr < map->vma->vm_start)
-- continue;
-- if (vaddr >= map->vma->vm_end)
-- continue;
-- return map;
-- }
-- return NULL;
--}
--
- static int gntdev_del_map(struct grant_map *map)
- {
- int i;
-@@ -494,22 +477,23 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv
*priv,
- struct ioctl_gntdev_get_offset_for_vaddr __user *u)
- {
- struct ioctl_gntdev_get_offset_for_vaddr op;
-+ struct vm_area_struct *vma;
- struct grant_map *map;
-
- if (copy_from_user(&op, u, sizeof(op)) != 0)
- return -EFAULT;
- pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr);
-
-- spin_lock(&priv->lock);
-- map = gntdev_find_map_vaddr(priv, op.vaddr);
-- if (map == NULL ||
-- map->vma->vm_start != op.vaddr) {
-- spin_unlock(&priv->lock);
-+ vma = find_vma(current->mm, op.vaddr);
-+ if (!vma || vma->vm_ops != &gntdev_vmops)
- return -EINVAL;
-- }
-+
-+ map = vma->vm_private_data;
-+ if (!map)
-+ return -EINVAL;
-+
- op.offset = map->index << PAGE_SHIFT;
- op.count = map->count;
-- spin_unlock(&priv->lock);
-
- if (copy_to_user(u, &op, sizeof(op)) != 0)
- return -EFAULT;
---
-1.7.4
-
-
-From 95cf9d619532475076ef07402ea296f3384ea513 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Thu, 3 Feb 2011 12:19:01 -0500
-Subject: [PATCH 102/244] xen-gntdev: Add reference counting to maps
-
-This allows userspace to perform mmap() on the gntdev device and then
-immediately close the filehandle or remove the mapping using the
-remove ioctl, with the mapped area remaining valid until unmapped.
-This also fixes an infinite loop when a gntdev device is closed
-without first unmapping all areas.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
----
- drivers/xen/gntdev.c | 67 ++++++++++++++++++++-----------------------------
- 1 files changed, 27 insertions(+), 40 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index ce8c37c..256162b 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -62,12 +62,12 @@ struct gntdev_priv {
-
- struct grant_map {
- struct list_head next;
-- struct gntdev_priv *priv;
- struct vm_area_struct *vma;
- int index;
- int count;
- int flags;
- int is_mapped;
-+ atomic_t users;
- struct ioctl_gntdev_grant_ref *grants;
- struct gnttab_map_grant_ref *map_ops;
- struct gnttab_unmap_grant_ref *unmap_ops;
-@@ -117,7 +117,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv,
int count)
-
- add->index = 0;
- add->count = count;
-- add->priv = priv;
-+ atomic_set(&add->users, 1);
-
- return add;
-
-@@ -167,28 +167,18 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv
*priv,
- return NULL;
- }
-
--static int gntdev_del_map(struct grant_map *map)
--{
-- int i;
--
-- if (map->vma)
-- return -EBUSY;
-- for (i = 0; i < map->count; i++)
-- if (map->unmap_ops[i].handle)
-- return -EBUSY;
--
-- atomic_sub(map->count, &pages_mapped);
-- list_del(&map->next);
-- return 0;
--}
--
--static void gntdev_free_map(struct grant_map *map)
-+static void gntdev_put_map(struct grant_map *map)
- {
- int i;
-
- if (!map)
- return;
-
-+ if (!atomic_dec_and_test(&map->users))
-+ return;
-+
-+ atomic_sub(map->count, &pages_mapped);
-+
- if (map->pages)
- for (i = 0; i < map->count; i++) {
- if (map->pages[i])
-@@ -267,6 +257,7 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
- map->is_mapped = 0;
- map->vma = NULL;
- vma->vm_private_data = NULL;
-+ gntdev_put_map(map);
- }
-
- static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-@@ -388,17 +379,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
- {
- struct gntdev_priv *priv = flip->private_data;
- struct grant_map *map;
-- int err;
-
- pr_debug("priv %p\n", priv);
-
- spin_lock(&priv->lock);
- while (!list_empty(&priv->maps)) {
- map = list_entry(priv->maps.next, struct grant_map, next);
-- err = gntdev_del_map(map);
-- if (WARN_ON(err))
-- gntdev_free_map(map);
--
-+ list_del(&map->next);
-+ gntdev_put_map(map);
- }
- spin_unlock(&priv->lock);
-
-@@ -425,15 +413,15 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
- if (!map)
- return err;
-
-- if (copy_from_user(map->grants, &u->refs,
-- sizeof(map->grants[0]) * op.count) != 0) {
-- gntdev_free_map(map);
-+ if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
-+ pr_debug("can't map: over limit\n");
-+ gntdev_put_map(map);
- return err;
- }
-
-- if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
-- pr_debug("can't map: over limit\n");
-- gntdev_free_map(map);
-+ if (copy_from_user(map->grants, &u->refs,
-+ sizeof(map->grants[0]) * op.count) != 0) {
-+ gntdev_put_map(map);
- return err;
- }
-
-@@ -442,13 +430,9 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
- op.index = map->index << PAGE_SHIFT;
- spin_unlock(&priv->lock);
-
-- if (copy_to_user(u, &op, sizeof(op)) != 0) {
-- spin_lock(&priv->lock);
-- gntdev_del_map(map);
-- spin_unlock(&priv->lock);
-- gntdev_free_map(map);
-- return err;
-- }
-+ if (copy_to_user(u, &op, sizeof(op)) != 0)
-+ return -EFAULT;
-+
- return 0;
- }
-
-@@ -465,11 +449,12 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
-
- spin_lock(&priv->lock);
- map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
-- if (map)
-- err = gntdev_del_map(map);
-+ if (map) {
-+ list_del(&map->next);
-+ gntdev_put_map(map);
-+ err = 0;
-+ }
- spin_unlock(&priv->lock);
-- if (!err)
-- gntdev_free_map(map);
- return err;
- }
-
-@@ -549,6 +534,8 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- goto unlock_out;
- }
-
-+ atomic_inc(&map->users);
-+
- vma->vm_ops = &gntdev_vmops;
-
- vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
---
-1.7.4
-
-
-From b6266e99c7947b151bff4b0f2b89d526405caa02 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Thu, 3 Feb 2011 12:19:02 -0500
-Subject: [PATCH 103/244] xen-gntdev: Support mapping in HVM domains
-
-HVM does not allow direct PTE modification, so instead we request
-that Xen change its internal p2m mappings on the allocated pages and
-map the memory into userspace normally.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
----
- drivers/xen/gntdev.c | 117 ++++++++++++++++++++++++++++++++-------------
- drivers/xen/grant-table.c | 6 ++
- 2 files changed, 89 insertions(+), 34 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 256162b..bcaf797 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -32,6 +32,7 @@
- #include <linux/sched.h>
- #include <linux/spinlock.h>
- #include <linux/slab.h>
-+#include <linux/highmem.h>
-
- #include <xen/xen.h>
- #include <xen/grant_table.h>
-@@ -52,6 +53,8 @@ MODULE_PARM_DESC(limit, "Maximum number of grants that may be
mapped by "
-
- static atomic_t pages_mapped = ATOMIC_INIT(0);
-
-+static int use_ptemod;
-+
- struct gntdev_priv {
- struct list_head maps;
- /* lock protects maps from concurrent changes */
-@@ -74,6 +77,8 @@ struct grant_map {
- struct page **pages;
- };
-
-+static int unmap_grant_pages(struct grant_map *map, int offset, int pages);
-+
- /* ------------------------------------------------------------------ */
-
- static void gntdev_print_maps(struct gntdev_priv *priv,
-@@ -179,11 +184,34 @@ static void gntdev_put_map(struct grant_map *map)
-
- atomic_sub(map->count, &pages_mapped);
-
-- if (map->pages)
-+ if (map->pages) {
-+ if (!use_ptemod)
-+ unmap_grant_pages(map, 0, map->count);
-+
- for (i = 0; i < map->count; i++) {
-- if (map->pages[i])
-+ uint32_t check, *tmp;
-+ if (!map->pages[i])
-+ continue;
-+ /* XXX When unmapping in an HVM domain, Xen will
-+ * sometimes end up mapping the GFN to an invalid MFN.
-+ * In this case, writes will be discarded and reads will
-+ * return all 0xFF bytes. Leak these unusable GFNs
-+ * until Xen supports fixing their p2m mapping.
-+ *
-+ * Confirmed present in Xen 4.1-RC3 with HVM source
-+ */
-+ tmp = kmap(map->pages[i]);
-+ *tmp = 0xdeaddead;
-+ mb();
-+ check = *tmp;
-+ kunmap(map->pages[i]);
-+ if (check == 0xdeaddead)
- __free_page(map->pages[i]);
-+ else
-+ pr_debug("Discard page %d=%ld\n", i,
-+ page_to_pfn(map->pages[i]));
- }
-+ }
- kfree(map->pages);
- kfree(map->grants);
- kfree(map->map_ops);
-@@ -198,17 +226,16 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
- {
- struct grant_map *map = data;
- unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT;
-+ int flags = map->flags | GNTMAP_application_map | GNTMAP_contains_pte;
- u64 pte_maddr;
-
- BUG_ON(pgnr >= map->count);
- pte_maddr = arbitrary_virt_to_machine(pte).maddr;
-
-- gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr,
-- GNTMAP_contains_pte | map->flags,
-+ gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, flags,
- map->grants[pgnr].ref,
- map->grants[pgnr].domid);
-- gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr,
-- GNTMAP_contains_pte | map->flags,
-+ gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, flags,
- 0 /* handle */);
- return 0;
- }
-@@ -216,6 +243,19 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
- static int map_grant_pages(struct grant_map *map)
- {
- int i, err = 0;
-+ phys_addr_t addr;
-+
-+ if (!use_ptemod) {
-+ for (i = 0; i < map->count; i++) {
-+ addr = (phys_addr_t)
-+ pfn_to_kaddr(page_to_pfn(map->pages[i]));
-+ gnttab_set_map_op(&map->map_ops[i], addr, map->flags,
-+ map->grants[i].ref,
-+ map->grants[i].domid);
-+ gnttab_set_unmap_op(&map->unmap_ops[i], addr,
-+ map->flags, 0 /* handle */);
-+ }
-+ }
-
- pr_debug("map %d+%d\n", map->index, map->count);
- err = gnttab_map_refs(map->map_ops, map->pages, map->count);
-@@ -260,17 +300,8 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
- gntdev_put_map(map);
- }
-
--static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
--{
-- pr_debug("vaddr %p, pgoff %ld (shouldn't happen)\n",
-- vmf->virtual_address, vmf->pgoff);
-- vmf->flags = VM_FAULT_ERROR;
-- return 0;
--}
--
- static struct vm_operations_struct gntdev_vmops = {
- .close = gntdev_vma_close,
-- .fault = gntdev_vma_fault,
- };
-
- /* ------------------------------------------------------------------ */
-@@ -355,14 +386,16 @@ static int gntdev_open(struct inode *inode, struct file *flip)
- INIT_LIST_HEAD(&priv->maps);
- spin_lock_init(&priv->lock);
-
-- priv->mm = get_task_mm(current);
-- if (!priv->mm) {
-- kfree(priv);
-- return -ENOMEM;
-+ if (use_ptemod) {
-+ priv->mm = get_task_mm(current);
-+ if (!priv->mm) {
-+ kfree(priv);
-+ return -ENOMEM;
-+ }
-+ priv->mn.ops = &gntdev_mmu_ops;
-+ ret = mmu_notifier_register(&priv->mn, priv->mm);
-+ mmput(priv->mm);
- }
-- priv->mn.ops = &gntdev_mmu_ops;
-- ret = mmu_notifier_register(&priv->mn, priv->mm);
-- mmput(priv->mm);
-
- if (ret) {
- kfree(priv);
-@@ -390,7 +423,8 @@ static int gntdev_release(struct inode *inode, struct file *flip)
- }
- spin_unlock(&priv->lock);
-
-- mmu_notifier_unregister(&priv->mn, priv->mm);
-+ if (use_ptemod)
-+ mmu_notifier_unregister(&priv->mn, priv->mm);
- kfree(priv);
- return 0;
- }
-@@ -515,7 +549,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- int index = vma->vm_pgoff;
- int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- struct grant_map *map;
-- int err = -EINVAL;
-+ int i, err = -EINVAL;
-
- if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
- return -EINVAL;
-@@ -527,9 +561,9 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- map = gntdev_find_map_index(priv, index, count);
- if (!map)
- goto unlock_out;
-- if (map->vma)
-+ if (use_ptemod && map->vma)
- goto unlock_out;
-- if (priv->mm != vma->vm_mm) {
-+ if (use_ptemod && priv->mm != vma->vm_mm) {
- printk(KERN_WARNING "Huh? Other mm?\n");
- goto unlock_out;
- }
-@@ -541,20 +575,24 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
-
- vma->vm_private_data = map;
-- map->vma = vma;
-
-- map->flags = GNTMAP_host_map | GNTMAP_application_map;
-+ if (use_ptemod)
-+ map->vma = vma;
-+
-+ map->flags = GNTMAP_host_map;
- if (!(vma->vm_flags & VM_WRITE))
- map->flags |= GNTMAP_readonly;
-
- spin_unlock(&priv->lock);
-
-- err = apply_to_page_range(vma->vm_mm, vma->vm_start,
-- vma->vm_end - vma->vm_start,
-- find_grant_ptes, map);
-- if (err) {
-- printk(KERN_WARNING "find_grant_ptes() failure.\n");
-- return err;
-+ if (use_ptemod) {
-+ err = apply_to_page_range(vma->vm_mm, vma->vm_start,
-+ vma->vm_end - vma->vm_start,
-+ find_grant_ptes, map);
-+ if (err) {
-+ printk(KERN_WARNING "find_grant_ptes() failure.\n");
-+ return err;
-+ }
- }
-
- err = map_grant_pages(map);
-@@ -565,6 +603,15 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
-
- map->is_mapped = 1;
-
-+ if (!use_ptemod) {
-+ for (i = 0; i < count; i++) {
-+ err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
-+ map->pages[i]);
-+ if (err)
-+ return err;
-+ }
-+ }
-+
- return 0;
-
- unlock_out:
-@@ -595,6 +642,8 @@ static int __init gntdev_init(void)
- if (!xen_domain())
- return -ENODEV;
-
-+ use_ptemod = xen_pv_domain();
-+
- err = misc_register(&gntdev_miscdev);
- if (err != 0) {
- printk(KERN_ERR "Could not register gntdev device\n");
-diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
-index 9ef54eb..9428ced 100644
---- a/drivers/xen/grant-table.c
-+++ b/drivers/xen/grant-table.c
-@@ -458,6 +458,9 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
- if (ret)
- return ret;
-
-+ if (xen_feature(XENFEAT_auto_translated_physmap))
-+ return ret;
-+
- for (i = 0; i < count; i++) {
- /* m2p override only supported for GNTMAP_contains_pte mappings */
- if (!(map_ops[i].flags & GNTMAP_contains_pte))
-@@ -483,6 +486,9 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
- if (ret)
- return ret;
-
-+ if (xen_feature(XENFEAT_auto_translated_physmap))
-+ return ret;
-+
- for (i = 0; i < count; i++) {
- ret = m2p_remove_override(pages[i]);
- if (ret)
---
-1.7.4
-
-
-From 67824c47b7137bc306b933c8772b8abfd0c09641 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Mon, 7 Feb 2011 17:23:05 -0500
-Subject: [PATCH 104/244] xen-gntalloc: Userspace grant allocation driver
-
-This allows a userspace application to allocate a shared page for
-implementing inter-domain communication or device drivers. These
-shared pages can be mapped using the gntdev device or by the kernel
-in another domain.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
----
- drivers/xen/Kconfig | 8 +
- drivers/xen/Makefile | 2 +
- drivers/xen/gntalloc.c | 486 ++++++++++++++++++++++++++++++++++++++++++++++++
- include/xen/gntalloc.h | 50 +++++
- 4 files changed, 546 insertions(+), 0 deletions(-)
- create mode 100644 drivers/xen/gntalloc.c
- create mode 100644 include/xen/gntalloc.h
-
-diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
-index 07bec09..a3d7afb 100644
---- a/drivers/xen/Kconfig
-+++ b/drivers/xen/Kconfig
-@@ -80,6 +80,14 @@ config XEN_GNTDEV
- help
- Allows userspace processes to use grants.
-
-+config XEN_GRANT_DEV_ALLOC
-+ tristate "User-space grant reference allocator driver"
-+ depends on XEN
-+ help
-+ Allows userspace processes to create pages with access granted
-+ to other domains. This can be used to implement frontend drivers
-+ or as part of an inter-domain shared memory channel.
-+
- config XEN_PLATFORM_PCI
- tristate "xen platform pci device driver"
- depends on XEN_PVHVM && PCI
-diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
-index 5088cc2..9585a1d 100644
---- a/drivers/xen/Makefile
-+++ b/drivers/xen/Makefile
-@@ -10,6 +10,7 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
- obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
- obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
- obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
-+obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
- obj-$(CONFIG_XENFS) += xenfs/
- obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
- obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o
-@@ -18,5 +19,6 @@ obj-$(CONFIG_XEN_DOM0) += pci.o
-
- xen-evtchn-y := evtchn.o
- xen-gntdev-y := gntdev.o
-+xen-gntalloc-y := gntalloc.o
-
- xen-platform-pci-y := platform-pci.o
-diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
-new file mode 100644
-index 0000000..d06bf2b
---- /dev/null
-+++ b/drivers/xen/gntalloc.c
-@@ -0,0 +1,486 @@
-+/******************************************************************************
-+ * gntalloc.c
-+ *
-+ * Device for creating grant references (in user-space) that may be shared
-+ * with other domains.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+/*
-+ * This driver exists to allow userspace programs in Linux to allocate kernel
-+ * memory that will later be shared with another domain. Without this device,
-+ * Linux userspace programs cannot create grant references.
-+ *
-+ * How this stuff works:
-+ * X -> granting a page to Y
-+ * Y -> mapping the grant from X
-+ *
-+ * 1. X uses the gntalloc device to allocate a page of kernel memory, P.
-+ * 2. X creates an entry in the grant table that says domid(Y) can access P.
-+ * This is done without a hypercall unless the grant table needs expansion.
-+ * 3. X gives the grant reference identifier, GREF, to Y.
-+ * 4. Y maps the page, either directly into kernel memory for use in a backend
-+ * driver, or via a the gntdev device to map into the address space of an
-+ * application running in Y. This is the first point at which Xen does any
-+ * tracking of the page.
-+ * 5. A program in X mmap()s a segment of the gntalloc device that corresponds
-+ * to the shared page, and can now communicate with Y over the shared page.
-+ *
-+ *
-+ * NOTE TO USERSPACE LIBRARIES:
-+ * The grant allocation and mmap()ing are, naturally, two separate operations.
-+ * You set up the sharing by calling the create ioctl() and then the mmap().
-+ * Teardown requires munmap() and either close() or ioctl().
-+ *
-+ * WARNING: Since Xen does not allow a guest to forcibly end the use of a grant
-+ * reference, this device can be used to consume kernel memory by leaving grant
-+ * references mapped by another domain when an application exits. Therefore,
-+ * there is a global limit on the number of pages that can be allocated. When
-+ * all references to the page are unmapped, it will be freed during the next
-+ * grant operation.
-+ */
-+
-+#include <linux/atomic.h>
-+#include <linux/module.h>
-+#include <linux/miscdevice.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/mm.h>
-+#include <linux/uaccess.h>
-+#include <linux/types.h>
-+#include <linux/list.h>
-+
-+#include <xen/xen.h>
-+#include <xen/page.h>
-+#include <xen/grant_table.h>
-+#include <xen/gntalloc.h>
-+
-+static int limit = 1024;
-+module_param(limit, int, 0644);
-+MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by "
-+ "the gntalloc device");
-+
-+static LIST_HEAD(gref_list);
-+static DEFINE_SPINLOCK(gref_lock);
-+static int gref_size;
-+
-+/* Metadata on a grant reference. */
-+struct gntalloc_gref {
-+ struct list_head next_gref; /* list entry gref_list */
-+ struct list_head next_file; /* list entry file->list, if open */
-+ struct page *page; /* The shared page */
-+ uint64_t file_index; /* File offset for mmap() */
-+ unsigned int users; /* Use count - when zero, waiting on Xen */
-+ grant_ref_t gref_id; /* The grant reference number */
-+};
-+
-+struct gntalloc_file_private_data {
-+ struct list_head list;
-+ uint64_t index;
-+};
-+
-+static void __del_gref(struct gntalloc_gref *gref);
-+
-+static void do_cleanup(void)
-+{
-+ struct gntalloc_gref *gref, *n;
-+ list_for_each_entry_safe(gref, n, &gref_list, next_gref) {
-+ if (!gref->users)
-+ __del_gref(gref);
-+ }
-+}
-+
-+static int add_grefs(struct ioctl_gntalloc_alloc_gref *op,
-+ uint32_t *gref_ids, struct gntalloc_file_private_data *priv)
-+{
-+ int i, rc, readonly;
-+ LIST_HEAD(queue_gref);
-+ LIST_HEAD(queue_file);
-+ struct gntalloc_gref *gref;
-+
-+ readonly = !(op->flags & GNTALLOC_FLAG_WRITABLE);
-+ rc = -ENOMEM;
-+ for (i = 0; i < op->count; i++) {
-+ gref = kzalloc(sizeof(*gref), GFP_KERNEL);
-+ if (!gref)
-+ goto undo;
-+ list_add_tail(&gref->next_gref, &queue_gref);
-+ list_add_tail(&gref->next_file, &queue_file);
-+ gref->users = 1;
-+ gref->file_index = op->index + i * PAGE_SIZE;
-+ gref->page = alloc_page(GFP_KERNEL|__GFP_ZERO);
-+ if (!gref->page)
-+ goto undo;
-+
-+ /* Grant foreign access to the page. */
-+ gref->gref_id = gnttab_grant_foreign_access(op->domid,
-+ pfn_to_mfn(page_to_pfn(gref->page)), readonly);
-+ if (gref->gref_id < 0) {
-+ rc = gref->gref_id;
-+ goto undo;
-+ }
-+ gref_ids[i] = gref->gref_id;
-+ }
-+
-+ /* Add to gref lists. */
-+ spin_lock(&gref_lock);
-+ list_splice_tail(&queue_gref, &gref_list);
-+ list_splice_tail(&queue_file, &priv->list);
-+ spin_unlock(&gref_lock);
-+
-+ return 0;
-+
-+undo:
-+ spin_lock(&gref_lock);
-+ gref_size -= (op->count - i);
-+
-+ list_for_each_entry(gref, &queue_file, next_file) {
-+ /* __del_gref does not remove from queue_file */
-+ __del_gref(gref);
-+ }
-+
-+ /* It's possible for the target domain to map the just-allocated grant
-+ * references by blindly guessing their IDs; if this is done, then
-+ * __del_gref will leave them in the queue_gref list. They need to be
-+ * added to the global list so that we can free them when they are no
-+ * longer referenced.
-+ */
-+ if (unlikely(!list_empty(&queue_gref)))
-+ list_splice_tail(&queue_gref, &gref_list);
-+ spin_unlock(&gref_lock);
-+ return rc;
-+}
-+
-+static void __del_gref(struct gntalloc_gref *gref)
-+{
-+ if (gref->gref_id > 0) {
-+ if (gnttab_query_foreign_access(gref->gref_id))
-+ return;
-+
-+ if (!gnttab_end_foreign_access_ref(gref->gref_id, 0))
-+ return;
-+ }
-+
-+ gref_size--;
-+ list_del(&gref->next_gref);
-+
-+ if (gref->page)
-+ __free_page(gref->page);
-+
-+ kfree(gref);
-+}
-+
-+/* finds contiguous grant references in a file, returns the first */
-+static struct gntalloc_gref *find_grefs(struct gntalloc_file_private_data *priv,
-+ uint64_t index, uint32_t count)
-+{
-+ struct gntalloc_gref *rv = NULL, *gref;
-+ list_for_each_entry(gref, &priv->list, next_file) {
-+ if (gref->file_index == index && !rv)
-+ rv = gref;
-+ if (rv) {
-+ if (gref->file_index != index)
-+ return NULL;
-+ index += PAGE_SIZE;
-+ count--;
-+ if (count == 0)
-+ return rv;
-+ }
-+ }
-+ return NULL;
-+}
-+
-+/*
-+ * -------------------------------------
-+ * File operations.
-+ * -------------------------------------
-+ */
-+static int gntalloc_open(struct inode *inode, struct file *filp)
-+{
-+ struct gntalloc_file_private_data *priv;
-+
-+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-+ if (!priv)
-+ goto out_nomem;
-+ INIT_LIST_HEAD(&priv->list);
-+
-+ filp->private_data = priv;
-+
-+ pr_debug("%s: priv %p\n", __func__, priv);
-+
-+ return 0;
-+
-+out_nomem:
-+ return -ENOMEM;
-+}
-+
-+static int gntalloc_release(struct inode *inode, struct file *filp)
-+{
-+ struct gntalloc_file_private_data *priv = filp->private_data;
-+ struct gntalloc_gref *gref;
-+
-+ pr_debug("%s: priv %p\n", __func__, priv);
-+
-+ spin_lock(&gref_lock);
-+ while (!list_empty(&priv->list)) {
-+ gref = list_entry(priv->list.next,
-+ struct gntalloc_gref, next_file);
-+ list_del(&gref->next_file);
-+ gref->users--;
-+ if (gref->users == 0)
-+ __del_gref(gref);
-+ }
-+ kfree(priv);
-+ spin_unlock(&gref_lock);
-+
-+ return 0;
-+}
-+
-+static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
-+ struct ioctl_gntalloc_alloc_gref __user *arg)
-+{
-+ int rc = 0;
-+ struct ioctl_gntalloc_alloc_gref op;
-+ uint32_t *gref_ids;
-+
-+ pr_debug("%s: priv %p\n", __func__, priv);
-+
-+ if (copy_from_user(&op, arg, sizeof(op))) {
-+ rc = -EFAULT;
-+ goto out;
-+ }
-+
-+ gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY);
-+ if (!gref_ids) {
-+ rc = -ENOMEM;
-+ goto out;
-+ }
-+
-+ spin_lock(&gref_lock);
-+ /* Clean up pages that were at zero (local) users but were still mapped
-+ * by remote domains. Since those pages count towards the limit that we
-+ * are about to enforce, removing them here is a good idea.
-+ */
-+ do_cleanup();
-+ if (gref_size + op.count > limit) {
-+ spin_unlock(&gref_lock);
-+ rc = -ENOSPC;
-+ goto out_free;
-+ }
-+ gref_size += op.count;
-+ op.index = priv->index;
-+ priv->index += op.count * PAGE_SIZE;
-+ spin_unlock(&gref_lock);
-+
-+ rc = add_grefs(&op, gref_ids, priv);
-+ if (rc < 0)
-+ goto out_free;
-+
-+ /* Once we finish add_grefs, it is unsafe to touch the new reference,
-+ * since it is possible for a concurrent ioctl to remove it (by guessing
-+ * its index). If the userspace application doesn't provide valid memory
-+ * to write the IDs to, then it will need to close the file in order to
-+ * release - which it will do by segfaulting when it tries to access the
-+ * IDs to close them.
-+ */
-+ if (copy_to_user(arg, &op, sizeof(op))) {
-+ rc = -EFAULT;
-+ goto out_free;
-+ }
-+ if (copy_to_user(arg->gref_ids, gref_ids,
-+ sizeof(gref_ids[0]) * op.count)) {
-+ rc = -EFAULT;
-+ goto out_free;
-+ }
-+
-+out_free:
-+ kfree(gref_ids);
-+out:
-+ return rc;
-+}
-+
-+static long gntalloc_ioctl_dealloc(struct gntalloc_file_private_data *priv,
-+ void __user *arg)
-+{
-+ int i, rc = 0;
-+ struct ioctl_gntalloc_dealloc_gref op;
-+ struct gntalloc_gref *gref, *n;
-+
-+ pr_debug("%s: priv %p\n", __func__, priv);
-+
-+ if (copy_from_user(&op, arg, sizeof(op))) {
-+ rc = -EFAULT;
-+ goto dealloc_grant_out;
-+ }
-+
-+ spin_lock(&gref_lock);
-+ gref = find_grefs(priv, op.index, op.count);
-+ if (gref) {
-+ /* Remove from the file list only, and decrease reference count.
-+ * The later call to do_cleanup() will remove from gref_list and
-+ * free the memory if the pages aren't mapped anywhere.
-+ */
-+ for (i = 0; i < op.count; i++) {
-+ n = list_entry(gref->next_file.next,
-+ struct gntalloc_gref, next_file);
-+ list_del(&gref->next_file);
-+ gref->users--;
-+ gref = n;
-+ }
-+ } else {
-+ rc = -EINVAL;
-+ }
-+
-+ do_cleanup();
-+
-+ spin_unlock(&gref_lock);
-+dealloc_grant_out:
-+ return rc;
-+}
-+
-+static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ struct gntalloc_file_private_data *priv = filp->private_data;
-+
-+ switch (cmd) {
-+ case IOCTL_GNTALLOC_ALLOC_GREF:
-+ return gntalloc_ioctl_alloc(priv, (void __user *)arg);
-+
-+ case IOCTL_GNTALLOC_DEALLOC_GREF:
-+ return gntalloc_ioctl_dealloc(priv, (void __user *)arg);
-+
-+ default:
-+ return -ENOIOCTLCMD;
-+ }
-+
-+ return 0;
-+}
-+
-+static void gntalloc_vma_close(struct vm_area_struct *vma)
-+{
-+ struct gntalloc_gref *gref = vma->vm_private_data;
-+ if (!gref)
-+ return;
-+
-+ spin_lock(&gref_lock);
-+ gref->users--;
-+ if (gref->users == 0)
-+ __del_gref(gref);
-+ spin_unlock(&gref_lock);
-+}
-+
-+static struct vm_operations_struct gntalloc_vmops = {
-+ .close = gntalloc_vma_close,
-+};
-+
-+static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
-+{
-+ struct gntalloc_file_private_data *priv = filp->private_data;
-+ struct gntalloc_gref *gref;
-+ int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-+ int rv, i;
-+
-+ pr_debug("%s: priv %p, page %lu+%d\n", __func__,
-+ priv, vma->vm_pgoff, count);
-+
-+ if (!(vma->vm_flags & VM_SHARED)) {
-+ printk(KERN_ERR "%s: Mapping must be shared.\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ spin_lock(&gref_lock);
-+ gref = find_grefs(priv, vma->vm_pgoff << PAGE_SHIFT, count);
-+ if (gref == NULL) {
-+ rv = -ENOENT;
-+ pr_debug("%s: Could not find grant reference",
-+ __func__);
-+ goto out_unlock;
-+ }
-+
-+ vma->vm_private_data = gref;
-+
-+ vma->vm_flags |= VM_RESERVED;
-+ vma->vm_flags |= VM_DONTCOPY;
-+ vma->vm_flags |= VM_PFNMAP | VM_PFN_AT_MMAP;
-+
-+ vma->vm_ops = &gntalloc_vmops;
-+
-+ for (i = 0; i < count; i++) {
-+ gref->users++;
-+ rv = vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
-+ gref->page);
-+ if (rv)
-+ goto out_unlock;
-+
-+ gref = list_entry(gref->next_file.next,
-+ struct gntalloc_gref, next_file);
-+ }
-+ rv = 0;
-+
-+out_unlock:
-+ spin_unlock(&gref_lock);
-+ return rv;
-+}
-+
-+static const struct file_operations gntalloc_fops = {
-+ .owner = THIS_MODULE,
-+ .open = gntalloc_open,
-+ .release = gntalloc_release,
-+ .unlocked_ioctl = gntalloc_ioctl,
-+ .mmap = gntalloc_mmap
-+};
-+
-+/*
-+ * -------------------------------------
-+ * Module creation/destruction.
-+ * -------------------------------------
-+ */
-+static struct miscdevice gntalloc_miscdev = {
-+ .minor = MISC_DYNAMIC_MINOR,
-+ .name = "xen/gntalloc",
-+ .fops = &gntalloc_fops,
-+};
-+
-+static int __init gntalloc_init(void)
-+{
-+ int err;
-+
-+ if (!xen_domain())
-+ return -ENODEV;
-+
-+ err = misc_register(&gntalloc_miscdev);
-+ if (err != 0) {
-+ printk(KERN_ERR "Could not register misc gntalloc device\n");
-+ return err;
-+ }
-+
-+ pr_debug("Created grant allocation device at %d,%d\n",
-+ MISC_MAJOR, gntalloc_miscdev.minor);
-+
-+ return 0;
-+}
-+
-+static void __exit gntalloc_exit(void)
-+{
-+ misc_deregister(&gntalloc_miscdev);
-+}
-+
-+module_init(gntalloc_init);
-+module_exit(gntalloc_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Carter Weatherly <carter.weatherly(a)jhuapl.edu>, "
-+ "Daniel De Graaf <dgdegra(a)tycho.nsa.gov>");
-+MODULE_DESCRIPTION("User-space grant reference allocator driver");
-diff --git a/include/xen/gntalloc.h b/include/xen/gntalloc.h
-new file mode 100644
-index 0000000..bc3b85e
---- /dev/null
-+++ b/include/xen/gntalloc.h
-@@ -0,0 +1,50 @@
-+/******************************************************************************
-+ * gntalloc.h
-+ *
-+ * Interface to /dev/xen/gntalloc.
-+ *
-+ * Author: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-+ *
-+ * This file is in the public domain.
-+ */
-+
-+#ifndef __LINUX_PUBLIC_GNTALLOC_H__
-+#define __LINUX_PUBLIC_GNTALLOC_H__
-+
-+/*
-+ * Allocates a new page and creates a new grant reference.
-+ */
-+#define IOCTL_GNTALLOC_ALLOC_GREF \
-+_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
-+struct ioctl_gntalloc_alloc_gref {
-+ /* IN parameters */
-+ /* The ID of the domain to be given access to the grants. */
-+ uint16_t domid;
-+ /* Flags for this mapping */
-+ uint16_t flags;
-+ /* Number of pages to map */
-+ uint32_t count;
-+ /* OUT parameters */
-+ /* The offset to be used on a subsequent call to mmap(). */
-+ uint64_t index;
-+ /* The grant references of the newly created grant, one per page */
-+ /* Variable size, depending on count */
-+ uint32_t gref_ids[1];
-+};
-+
-+#define GNTALLOC_FLAG_WRITABLE 1
-+
-+/*
-+ * Deallocates the grant reference, allowing the associated page to be freed if
-+ * no other domains are using it.
-+ */
-+#define IOCTL_GNTALLOC_DEALLOC_GREF \
-+_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
-+struct ioctl_gntalloc_dealloc_gref {
-+ /* IN parameters */
-+ /* The offset returned in the map operation */
-+ uint64_t index;
-+ /* Number of references to unmap */
-+ uint32_t count;
-+};
-+#endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
---
-1.7.4
-
-
-From 10aec564458881d30dc0e3b67083ec4849c3ab3a Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Thu, 3 Feb 2011 14:16:54 -0500
-Subject: [PATCH 106/244] xen-gntdev: Fix memory leak when mmap fails
-
-Fix for a memory leak introduced in patch 3. Doesn't merge cleanly across
-patch 4; I can post a corrected version of both patches if that would be
-preferred.
-
-------------------------------------------------------------->8
-
-The error path did not decrement the reference count of the grant structure.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
----
- drivers/xen/gntdev.c | 14 ++++++++------
- 1 files changed, 8 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 9694a1a..2aa8316 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -650,15 +650,13 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- find_grant_ptes, map);
- if (err) {
- printk(KERN_WARNING "find_grant_ptes() failure.\n");
-- return err;
-+ goto out_put_map;
- }
- }
-
- err = map_grant_pages(map);
-- if (err) {
-- printk(KERN_WARNING "map_grant_pages() failure.\n");
-- return err;
-- }
-+ if (err)
-+ goto out_put_map;
-
- map->is_mapped = 1;
-
-@@ -667,7 +665,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
- map->pages[i]);
- if (err)
-- return err;
-+ goto out_put_map;
- }
- }
-
-@@ -676,6 +674,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- unlock_out:
- spin_unlock(&priv->lock);
- return err;
-+
-+out_put_map:
-+ gntdev_put_map(map);
-+ return err;
- }
-
- static const struct file_operations gntdev_fops = {
---
-1.7.4
-
-
-From 203b40c0915fc78e9ca1524c887623e7dc86422d Mon Sep 17 00:00:00 2001
-From: Bastian Blank <waldi(a)debian.org>
-Date: Thu, 29 Jul 2010 17:30:18 +0200
-Subject: [PATCH 107/244] xen: netback: Fix null-pointer access in netback_uevent
-
-The uevent method of Xen netback does not check if the the network
-device is already setup and tries to dereference a null-pointer if not.
-
-Signed-off-by: Bastian Blank <waldi(a)debian.org>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/xenbus.c | 10 ++--------
- 1 files changed, 2 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index 17ff5cf..1fec65a 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -154,17 +154,11 @@ fail:
- */
- static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
- {
-- struct backend_info *be;
-- struct xen_netif *netif;
-+ struct backend_info *be = dev_get_drvdata(&xdev->dev);
- char *val;
-
- DPRINTK("netback_uevent");
-
-- be = dev_get_drvdata(&xdev->dev);
-- if (!be)
-- return 0;
-- netif = be->netif;
--
- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
- if (IS_ERR(val)) {
- int err = PTR_ERR(val);
-@@ -179,7 +173,7 @@ static int netback_uevent(struct xenbus_device *xdev, struct
kobj_uevent_env *en
- kfree(val);
- }
-
-- if (add_uevent_var(env, "vif=%s", netif->dev->name))
-+ if (be && be->netif && add_uevent_var(env, "vif=%s",
be->netif->dev->name))
- return -ENOMEM;
-
- return 0;
---
-1.7.4
-
-
-From bee16269e5ba79706bdae554013cd14285b4f1ad Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 30 Jul 2010 15:16:47 +0100
-Subject: [PATCH 108/244] xen: netback: check if foreign pages are actually
netback-created foreign pages.
-
-020ba906 "xen/netback: Multiple tasklets support." changed
-netbk_gop_frag_copy to attempt to lookup a pending_tx_info for any
-foreign page, regardless of whether the page was a netback-foreign
-page.
-
-In the case of non-netback pages this can lead to dereferencing a NULL
-src_pend->netif.
-
-Restore the behaviour of netif_page_index prior toa3031942
-"xen/netback: Introduce a new struct type page_ext" by performing
-tests to ensure that page is a netback page and extend the same checks
-to netif_page_group.
-
-Actually combine netif_page_{index,group} in to a single function
-since they are always called together and it saves duplicating all the
-checks.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Cc: Xu, Dongxiao <dongxiao.xu(a)intel.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 56 ++++++++++++++++++++++++++++------------
- 1 files changed, 39 insertions(+), 17 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 911c85b..95df223 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -89,18 +89,37 @@ static inline void netif_set_page_ext(struct page *pg, unsigned int
group,
- pg->mapping = ext.mapping;
- }
-
--static inline unsigned int netif_page_group(const struct page *pg)
-+static inline int netif_get_page_ext(struct page *pg, unsigned int *_group, unsigned int
*_idx)
- {
- union page_ext ext = { .mapping = pg->mapping };
-+ struct xen_netbk *netbk;
-+ unsigned int group, idx;
-
-- return ext.e.group - 1;
--}
-+ if (!PageForeign(pg))
-+ return 0;
-
--static inline unsigned int netif_page_index(const struct page *pg)
--{
-- union page_ext ext = { .mapping = pg->mapping };
-+ group = ext.e.group - 1;
-+
-+ if (group < 0 || group >= xen_netbk_group_nr)
-+ return 0;
-+
-+ netbk = &xen_netbk[group];
-+
-+ if (netbk->mmap_pages == NULL)
-+ return 0;
-
-- return ext.e.idx;
-+ idx = ext.e.idx;
-+
-+ if ((idx < 0) || (idx >= MAX_PENDING_REQS))
-+ return 0;
-+
-+ if (netbk->mmap_pages[idx] != pg)
-+ return 0;
-+
-+ *_group = group;
-+ *_idx = idx;
-+
-+ return 1;
- }
-
- /*
-@@ -386,8 +405,12 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- {
- struct gnttab_copy *copy_gop;
- struct netbk_rx_meta *meta;
-- int group = netif_page_group(page);
-- int idx = netif_page_index(page);
-+ /*
-+ * These variables a used iff netif_get_page_ext returns true,
-+ * in which case they are guaranteed to be initialized.
-+ */
-+ unsigned int uninitialized_var(group), uninitialized_var(idx);
-+ int foreign = netif_get_page_ext(page, &group, &idx);
- unsigned long bytes;
-
- /* Data must not cross a page boundary. */
-@@ -445,7 +468,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
-
- copy_gop = npo->copy + npo->copy_prod++;
- copy_gop->flags = GNTCOPY_dest_gref;
-- if (PageForeign(page)) {
-+ if (foreign) {
- struct xen_netbk *netbk = &xen_netbk[group];
- struct pending_tx_info *src_pend;
-
-@@ -1535,14 +1558,13 @@ static void netif_idx_release(struct xen_netbk *netbk, u16
pending_idx)
-
- static void netif_page_release(struct page *page, unsigned int order)
- {
-- int group = netif_page_group(page);
-- int idx = netif_page_index(page);
-- struct xen_netbk *netbk = &xen_netbk[group];
-+ unsigned int group, idx;
-+ int foreign = netif_get_page_ext(page, &group, &idx);
-+
-+ BUG_ON(!foreign);
- BUG_ON(order);
-- BUG_ON(group < 0 || group >= xen_netbk_group_nr);
-- BUG_ON(idx < 0 || idx >= MAX_PENDING_REQS);
-- BUG_ON(netbk->mmap_pages[idx] != page);
-- netif_idx_release(netbk, idx);
-+
-+ netif_idx_release(&xen_netbk[group], idx);
- }
-
- irqreturn_t netif_be_int(int irq, void *dev_id)
---
-1.7.4
-
-
-From 3f33055e8af9d74e35670c52438e190d54ac5f9e Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 30 Jul 2010 15:16:46 +0100
-Subject: [PATCH 109/244] xen: netback: do not unleash netback threads until
initialisation is complete
-
-Otherwise netbk_action_thread can reference &netbk->net_schedule_list
-(via tx_work_todo) before it is initialised. Until now it was zeroed
-which is probably safe but not exactly robust.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Cc: Xu, Dongxiao <dongxiao.xu(a)intel.com>
-Cc: Paul Durrant <Paul.Durrant(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 4 +++-
- 1 files changed, 3 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 95df223..2646383 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1782,7 +1782,6 @@ static int __init netback_init(void)
-
- if (!IS_ERR(netbk->kthread.task)) {
- kthread_bind(netbk->kthread.task, group);
-- wake_up_process(netbk->kthread.task);
- } else {
- printk(KERN_ALERT
- "kthread_run() fails at netback\n");
-@@ -1808,6 +1807,9 @@ static int __init netback_init(void)
- spin_lock_init(&netbk->net_schedule_list_lock);
-
- atomic_set(&netbk->netfront_count, 0);
-+
-+ if (MODPARM_netback_kthread)
-+ wake_up_process(netbk->kthread.task);
- }
-
- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
---
-1.7.4
-
-
-From 329a17f3dbb9c127d431d09df0ed63ec28b8c702 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ijc(a)hellion.org.uk>
-Date: Thu, 2 Sep 2010 14:36:40 +0100
-Subject: [PATCH 110/244] xen: netback: save interrupt state in
add_to_net_schedule_list_tail
-
-add_to_net_schedule_list_tail is called from both hard interrupt context
-(add_to_net_schedule_list_tail) and soft interrupt/process context
-(netif_schedule_work) so use the interrupt state saving spinlock
-variants.
-
-Fixes:
- ------------[ cut here ]------------
- WARNING: at kernel/lockdep.c:2323 trace_hardirqs_on_caller+0xef/0x1a0()
- Hardware name: PowerEdge 860
- Modules linked in: rtc_cmos rtc_core rtc_lib
- Pid: 16, comm: xenwatch Not tainted 2.6.32.18-x86_32p-xen0-00850-ge6b9b2c #98
- Call Trace:
- [<c103951c>] warn_slowpath_common+0x6c/0xc0
- [<c1039585>] warn_slowpath_null+0x15/0x20
- [<c105f60f>] trace_hardirqs_on_caller+0xef/0x1a0
- [<c105f6cb>] trace_hardirqs_on+0xb/0x10
- [<c136cc72>] _spin_unlock_irq+0x22/0x40
- [<c11ab9ef>] add_to_net_schedule_list_tail+0x5f/0xb0
- [<c11aba6b>] netif_be_int+0x2b/0x120
- [<c106dd8e>] handle_IRQ_event+0x2e/0xe0
- [<c106f98e>] handle_level_irq+0x6e/0xf0
- [<c1197cdf>] __xen_evtchn_do_upcall+0x16f/0x190
- [<c11981b8>] xen_evtchn_do_upcall+0x28/0x40
- [<c100b487>] xen_do_upcall+0x7/0xc
- [<c119bcf9>] xs_talkv+0x59/0x1a0
- [<c119bf6a>] xs_single+0x3a/0x50
- [<c119c6f9>] xenbus_read+0x39/0x60
- [<c11adf77>] frontend_changed+0x3e7/0x6a0
- [<c119d35a>] xenbus_otherend_changed+0x8a/0xa0
- [<c119d572>] frontend_changed+0x12/0x20
- [<c119b9dc>] xenwatch_thread+0x7c/0x140
- [<c104ea74>] kthread+0x74/0x80
- [<c100b433>] kernel_thread_helper+0x7/0x10
- ---[ end trace 48d73949a8e0909a ]---
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/netback.c | 6 ++++--
- 1 files changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 2646383..1d080f6 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -787,17 +787,19 @@ static void remove_from_net_schedule_list(struct xen_netif *netif)
-
- static void add_to_net_schedule_list_tail(struct xen_netif *netif)
- {
-+ unsigned long flags;
-+
- struct xen_netbk *netbk = &xen_netbk[netif->group];
- if (__on_net_schedule_list(netif))
- return;
-
-- spin_lock_irq(&netbk->net_schedule_list_lock);
-+ spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
- if (!__on_net_schedule_list(netif) &&
- likely(netif_schedulable(netif))) {
- list_add_tail(&netif->list, &netbk->net_schedule_list);
- netif_get(netif);
- }
-- spin_unlock_irq(&netbk->net_schedule_list_lock);
-+ spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
- }
-
- void netif_schedule_work(struct xen_netif *netif)
---
-1.7.4
-
-
-From 7edc1ededaaa953877d2a052886db4ea2f69effe Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 8 Oct 2010 17:11:51 +0100
-Subject: [PATCH 111/244] xen: netback: increase size of rx_meta array.
-
-We can end up needing as many of these as we need grant copy operations so
-increase the array size for the same reason.
-
-Crash observed on XenServer:
-kernel: ------------[ cut here ]------------
-kernel: kernel BUG at drivers/xen/netback/netback.c:834!
-kernel: invalid opcode: 0000 [#1] SMP
-kernel: last sysfs file: /sys/devices/xen-backend/vbd-10-768/statistics/rd_usecs
-kernel: Process netback (pid: 1413, ti=ec8a4000 task=ed0a6b70 task.ti=ec8a4000)
-kernel: Stack: 00000000 00000612 00000001 00000000 00020000 00000000 ecfbe000 00000000
-kernel: ec8a5f80 ec8a5f98 ec8a5fac 00000000 c0537220 c0539220 00000000 c0534220
-kernel: cd7afaa0 cd7afaa0 0000000c 00000014 062de396 00000001 00000001 00000014
-kernel: Call Trace:
-kernel: [<c0285f10>] ? netbk_action_thread+0x0/0x1fe0
-kernel: [<c013daf2>] ? kthread+0x42/0x70
-kernel: [<c013dab0>] ? kthread+0x0/0x70
-kernel: [<c010569b>] ? kernel_thread_helper+0x7/0x10
-kernel: =======================
-kernel: Code: 00 00 c7 42 08 20 82 53 c0 8b 85 e4 fe ff ff c7 42 10 00 00 00 00 \
- c7 42 14 f0 7f 00 00 89 42 0c 8b 8d ec fe ff ff e9 3e e9 ff ff <0f>
\
- 0b eb fe 0f 0b eb fe 0f 0b eb fe 0f 0b eb fe 31 c0 e8 bf 31
-kernel: EIP: [<c028790a>] netbk_action_thread+0x19fa/0x1fe0 SS:ESP 0069:ec8a5d98
-
-Corresponding to
- BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
----
- drivers/xen/netback/common.h | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index a5f3759..ce0041a 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -319,7 +319,7 @@ struct xen_netbk {
- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
- unsigned char rx_notify[NR_IRQS];
- u16 notify_list[NET_RX_RING_SIZE];
-- struct netbk_rx_meta meta[NET_RX_RING_SIZE];
-+ struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
- };
-
- extern struct xen_netbk *xen_netbk;
---
-1.7.4
-
-
-From 4fbb266d319fcb3349eff2f9c42cdee51c5fcb5f Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 15 Oct 2010 13:41:44 +0100
-Subject: [PATCH 112/244] xen: netback: take net_schedule_list_lock when removing entry
from net_schedule_list
-
-There is a race in net_tx_build_mops between checking if
-net_schedule_list is empty and actually dequeuing the first entry on
-the list. If another thread dequeues the only entry on the list during
-this window we crash because list_first_entry expects a non-empty
-list, like so:
-
-[ 0.133127] BUG: unable to handle kernel NULL pointer dereference at 00000008
-[ 0.133132] IP: [<c12aae71>] net_tx_build_mops+0x91/0xa70
-[ 0.133142] *pdpt = 0000000000000000 *pde = 000000000000000f
-[ 0.133147] Oops: 0002 1 SMP
-[ 0.133150] last sysfs file:
-[ 0.133152] Modules linked in:
-[ 0.133154]
-[ 0.133156] Pid: 55, comm: netback/1 Not tainted (2.6.32.12-0.7.1 #1) Latitude E4310
-[ 0.133158] EIP: 0061:[<c12aae71>] EFLAGS: 00010202 CPU: 1
-[ 0.133161] EIP is at net_tx_build_mops+0x91/0xa70
-[ 0.133163] EAX: 00000012 EBX: 00000008 ECX: e112b734 EDX: e112b76c
-[ 0.133165] ESI: ffffff30 EDI: 00000000 EBP: e112b734 ESP: dfe85d98
-[ 0.133167] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0069
-[ 0.133169] Process netback/1 (pid: 55, ti=dfe84000 task=dfe83340 task.ti=dfe84000)
-[ 0.133170] Stack:
-[ 0.133172] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
-[ 0.133177] <0> 00000000 e112b734 e112ec08 e112b7f8 e112ec08 ffffff30 00000000
00000000
-[ 0.133186] <0> 00000000 00000000 00000000 e112b76c dfe85df4 00000001 00000000
aaaaaaaa
-[ 0.133193] Call Trace:
-[ 0.133202] [<c12abc7f>] net_tx_action+0x42f/0xac0
-[ 0.133206] [<c12ac37a>] netbk_action_thread+0x6a/0x1b0
-[ 0.133212] [<c1057444>] kthread+0x74/0x80
-[ 0.133218] [<c10049d7>] kernel_thread_helper+0x7/0x10
-[ 0.133220] Code: c4 00 00 00 89 74 24 58 39 74 24 2c 0f 84 c7 06 00 00 8b 74 24 \
- 58 8b 5c 24 58 81 ee d0 00 00 00 83 c3 08 89 74 24 34 8b 7c 24 \
- 58 <f0> ff 47 08 89 f0 e8 b4 f9 ff ff 8b 46 2c 8b 56 34 89 44 24 5c
-[ 0.133261] EIP: [<c12aae71>] net_tx_build_mops+0x91/0xa70 SS:ESP 0069:dfe85d98
-[ 0.133265] CR2: 0000000000000008
-[ 0.133274] --[ end trace e2c5c15f54bd9d93 ]--
-
-Therefore after the initial lock free check for an empty list check
-again with the lock held before dequeueing the entry.
-
-Based on a patch by Tomasz Wroblewski.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Tomasz Wroblewski <tomasz.wroblewski(a)citrix.com>
----
- drivers/xen/netback/netback.c | 35 ++++++++++++++++++++++++++++-------
- 1 files changed, 28 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 1d080f6..3b03435 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -774,15 +774,34 @@ static int __on_net_schedule_list(struct xen_netif *netif)
- return !list_empty(&netif->list);
- }
-
-+/* Must be called with net_schedule_list_lock held */
- static void remove_from_net_schedule_list(struct xen_netif *netif)
- {
-- struct xen_netbk *netbk = &xen_netbk[netif->group];
-- spin_lock_irq(&netbk->net_schedule_list_lock);
- if (likely(__on_net_schedule_list(netif))) {
- list_del_init(&netif->list);
- netif_put(netif);
- }
-+}
-+
-+static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
-+{
-+ struct xen_netif *netif = NULL;
-+
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
-+ if (list_empty(&netbk->net_schedule_list))
-+ goto out;
-+
-+ netif = list_first_entry(&netbk->net_schedule_list,
-+ struct xen_netif, list);
-+ if (!netif)
-+ goto out;
-+
-+ netif_get(netif);
-+
-+ remove_from_net_schedule_list(netif);
-+out:
- spin_unlock_irq(&netbk->net_schedule_list_lock);
-+ return netif;
- }
-
- static void add_to_net_schedule_list_tail(struct xen_netif *netif)
-@@ -817,7 +836,10 @@ void netif_schedule_work(struct xen_netif *netif)
-
- void netif_deschedule_work(struct xen_netif *netif)
- {
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
- remove_from_net_schedule_list(netif);
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
- }
-
-
-@@ -1301,12 +1323,11 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- int work_to_do;
- unsigned int data_len;
- pending_ring_idx_t index;
--
-+
- /* Get a netif from the list with work to do. */
-- netif = list_first_entry(&netbk->net_schedule_list,
-- struct xen_netif, list);
-- netif_get(netif);
-- remove_from_net_schedule_list(netif);
-+ netif = poll_net_schedule_list(netbk);
-+ if (!netif)
-+ continue;
-
- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
- if (!work_to_do) {
---
-1.7.4
-
-
-From d58a964195f593879cc0160ac0c6f31bc95cdc6e Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Wed, 15 Dec 2010 09:48:12 +0000
-Subject: [PATCH 113/244] xen: netback: Re-define PKT_PROT_LEN to be bigger.
-
-Re-define PKT_PROT_LEN to be big enough to handle maximal IPv4 and TCP options and
phrase
-the definition so that it's reasonably obvious that's what it's for.
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 14 +++++++++-----
- 1 files changed, 9 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 3b03435..9bbd230 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -36,9 +36,11 @@
-
- #include "common.h"
-
--#include <linux/tcp.h>
--#include <linux/udp.h>
- #include <linux/kthread.h>
-+#include <linux/if_vlan.h>
-+#include <linux/udp.h>
-+
-+#include <net/tcp.h>
-
- #include <xen/balloon.h>
- #include <xen/events.h>
-@@ -125,10 +127,12 @@ static inline int netif_get_page_ext(struct page *pg, unsigned int
*_group, unsi
- /*
- * This is the amount of packet we copy rather than map, so that the
- * guest can't fiddle with the contents of the headers while we do
-- * packet processing on them (netfilter, routing, etc). 72 is enough
-- * to cover TCP+IP headers including options.
-+ * packet processing on them (netfilter, routing, etc).
- */
--#define PKT_PROT_LEN 72
-+#define PKT_PROT_LEN (ETH_HLEN + \
-+ VLAN_HLEN + \
-+ sizeof(struct iphdr) + MAX_IPOPTLEN + \
-+ sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
-
- static inline pending_ring_idx_t pending_index(unsigned i)
- {
---
-1.7.4
-
-
-From 7120999e00f068383bc16d03cceae8d6d511c43a Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Tue, 14 Dec 2010 20:35:19 +0000
-Subject: [PATCH 114/244] xen: netback: Don't count packets we don't actually
receive.
-
-Make sure we only bump rx_packets when we're definitely going to call netif_rx_ni().
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 6 +++---
- 1 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 9bbd230..78d3509 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1512,9 +1512,6 @@ static void net_tx_submit(struct xen_netbk *netbk)
- skb->dev = netif->dev;
- skb->protocol = eth_type_trans(skb, skb->dev);
-
-- netif->stats.rx_bytes += skb->len;
-- netif->stats.rx_packets++;
--
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (skb_checksum_setup(skb)) {
- DPRINTK("Can't setup checksum in net_tx_action\n");
-@@ -1530,6 +1527,9 @@ static void net_tx_submit(struct xen_netbk *netbk)
- continue;
- }
-
-+ netif->stats.rx_bytes += skb->len;
-+ netif->stats.rx_packets++;
-+
- netif_rx_ni(skb);
- netif->dev->last_rx = jiffies;
- }
---
-1.7.4
-
-
-From 3c1f462cb05ad5eb5bb8e65cf6feb9a4e4363ebf Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Tue, 14 Dec 2010 20:35:20 +0000
-Subject: [PATCH 115/244] xen: netback: Remove the 500ms timeout to restart the netif
queue.
-
-It is generally unhelpful as it results in a massive tail-drop should a guest become
-unresponsive for a relatively short period of time and no back-pressure (other than
-that caused by a higher layer protocol) is applied to the sender.
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 20 +-------------------
- 1 files changed, 1 insertions(+), 19 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 78d3509..2caa5f8 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -275,13 +275,6 @@ static inline int netbk_queue_full(struct xen_netif *netif)
- ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
- }
-
--static void tx_queue_callback(unsigned long data)
--{
-- struct xen_netif *netif = (struct xen_netif *)data;
-- if (netif_schedulable(netif))
-- netif_wake_queue(netif->dev);
--}
--
- /* Figure out how many ring slots we're going to need to send @skb to
- the guest. */
- static unsigned count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
-@@ -364,19 +357,8 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- netif->rx.sring->req_event = netif->rx_req_cons_peek +
- netbk_max_required_rx_slots(netif);
- mb(); /* request notification /then/ check & stop the queue */
-- if (netbk_queue_full(netif)) {
-+ if (netbk_queue_full(netif))
- netif_stop_queue(dev);
-- /*
-- * Schedule 500ms timeout to restart the queue, thus
-- * ensuring that an inactive queue will be drained.
-- * Packets will be immediately be dropped until more
-- * receive buffers become available (see
-- * netbk_queue_full() check above).
-- */
-- netif->tx_queue_timeout.data = (unsigned long)netif;
-- netif->tx_queue_timeout.function = tx_queue_callback;
-- mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
-- }
- }
- skb_queue_tail(&netbk->rx_queue, skb);
-
---
-1.7.4
-
-
-From d70d4906c2736dadc5c287caa36c5880947f8688 Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Tue, 14 Dec 2010 20:35:21 +0000
-Subject: [PATCH 116/244] xen: netback: Add a missing test to tx_work_todo.
-
-Adda test so that, when netback is using worker threads, net_tx_action()
-gets called in a timely manner when the pending_inuse list is populated.
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 4 ++++
- 1 files changed, 4 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 2caa5f8..dd52d01 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1695,6 +1695,10 @@ static inline int tx_work_todo(struct xen_netbk *netbk)
- if (netbk->dealloc_cons != netbk->dealloc_prod)
- return 1;
-
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !list_empty(&netbk->pending_inuse_head))
-+ return 1;
-+
- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list))
- return 1;
---
-1.7.4
-
-
-From 8811a0cf07ccd1b9f40eaae76de3aa2792c9fd28 Mon Sep 17 00:00:00 2001
-From: Paul Durrant <paul.durrant(a)citrix.com>
-Date: Tue, 14 Dec 2010 20:35:22 +0000
-Subject: [PATCH 117/244] xen: netback: Re-factor net_tx_action_dealloc() slightly.
-
-There is no need for processing of the pending_inuse list to be within the
dealloc_prod/cons
-loop.
-
-Signed-off-by: Paul Durrant <paul.durrant(a)citrix.com>
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 26 ++++++++++++++------------
- 1 files changed, 14 insertions(+), 12 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index dd52d01..53b3a0e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -906,11 +906,20 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
- gop++;
- }
-
-- if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
-- list_empty(&netbk->pending_inuse_head))
-- break;
-+ } while (dp != netbk->dealloc_prod);
-+
-+ netbk->dealloc_cons = dc;
-
-- /* Copy any entries that have been pending for too long. */
-+ ret = HYPERVISOR_grant_table_op(
-+ GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
-+ gop - netbk->tx_unmap_ops);
-+ BUG_ON(ret);
-+
-+ /*
-+ * Copy any entries that have been pending for too long
-+ */
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !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;
-@@ -936,14 +945,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
-
- break;
- }
-- } while (dp != netbk->dealloc_prod);
--
-- netbk->dealloc_cons = dc;
--
-- ret = HYPERVISOR_grant_table_op(
-- GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
-- gop - netbk->tx_unmap_ops);
-- BUG_ON(ret);
-+ }
-
- list_for_each_entry_safe(inuse, n, &list, list) {
- struct pending_tx_info *pending_tx_info;
---
-1.7.4
-
-
-From 9481475c92f00d15100d0a5083ef338f1b528506 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 5 Jan 2011 09:57:37 +0000
-Subject: [PATCH 118/244] xen: netback: Drop GSO SKBs which do not have csum_blank.
-
-The Linux network stack expects all GSO SKBs to have ip_summed ==
-CHECKSUM_PARTIAL (which implies that the frame contains a partial
-checksum) and the Xen network ring protocol similarly expects an SKB
-which has GSO set to also have NETRX_csum_blank (which also implies a
-partial checksum). Therefore drop such frames on receive otherwise
-they will trigger the warning in skb_gso_segment.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Cc: xen-devel(a)lists.xensource.com
----
- drivers/xen/netback/netback.c | 4 ++++
- 1 files changed, 4 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 53b3a0e..2766b93 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1502,6 +1502,10 @@ static void net_tx_submit(struct xen_netbk *netbk)
- kfree_skb(skb);
- continue;
- }
-+ } else if (skb_is_gso(skb)) {
-+ DPRINTK("Dropping GSO but not CHECKSUM_PARTIAL skb\n");
-+ kfree_skb(skb);
-+ continue;
- }
-
- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
---
-1.7.4
-
-
-From a45f9a0889210fba5c73994ec2fa1c36f82a435f Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 19 Jan 2011 12:43:38 +0000
-Subject: [PATCH 119/244] xen: netback: completely remove tx_queue_timer
-
-"xen: netback: Remove the 500ms timeout to restart the netif queue." missed
-removing the timer initialisation.
-
-Also remove the related comment which has been obsolete since the default for
-MODPARM_copy_skb was switched to true some time ago.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Paul Durrant <Paul.Durrant(a)citrix.com>
----
- drivers/xen/netback/common.h | 3 ---
- drivers/xen/netback/interface.c | 13 +------------
- 2 files changed, 1 insertions(+), 15 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index ce0041a..7e03a46 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -99,9 +99,6 @@ struct xen_netif {
- unsigned long remaining_credit;
- struct timer_list credit_timeout;
-
-- /* Enforce draining of the transmit queue. */
-- struct timer_list tx_queue_timeout;
--
- /* Statistics */
- int nr_copied_skbs;
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 2e8508a..efdc21c 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -41,15 +41,7 @@
- * Module parameter 'queue_length':
- *
- * Enables queuing in the network stack when a client has run out of receive
-- * descriptors. Although this feature can improve receive bandwidth by avoiding
-- * packet loss, it can also result in packets sitting in the 'tx_queue' for
-- * unbounded time. This is bad if those packets hold onto foreign resources.
-- * For example, consider a packet that holds onto resources belonging to the
-- * guest for which it is queued (e.g., packet received on vif1.0, destined for
-- * vif1.1 which is not activated in the guest): in this situation the guest
-- * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
-- * run a timer (tx_queue_timeout) to drain the queue when the interface is
-- * blocked.
-+ * descriptors.
- */
- static unsigned long netbk_queue_length = 32;
- module_param_named(queue_length, netbk_queue_length, ulong, 0644);
-@@ -295,8 +287,6 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- /* Initialize 'expires' now: it's used to track the credit window. */
- netif->credit_timeout.expires = jiffies;
-
-- init_timer(&netif->tx_queue_timeout);
--
- dev->netdev_ops = &netback_ops;
- netif_set_features(netif);
- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-@@ -458,7 +448,6 @@ void netif_disconnect(struct xen_netif *netif)
- wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
-
- del_timer_sync(&netif->credit_timeout);
-- del_timer_sync(&netif->tx_queue_timeout);
-
- if (netif->irq)
- unbind_from_irqhandler(netif->irq, netif);
---
-1.7.4
-
-
-From 2794a483aeafab1c0765a0478b760978b361bad9 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 28 Jan 2011 13:11:45 +0000
-Subject: [PATCH 120/244] Revert "xen: netback: Drop GSO SKBs which do not have
csum_blank."
-
-This reverts commit 082386b4a581b2ba5a125cc8944a57ceb33ff37c.
-
-Based on discussion surrounding the netfront equivalent fix
-(http://patchwork.ozlabs.org/patch/80389/) this issue will be fixed
-differently.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 4 ----
- 1 files changed, 0 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 2766b93..53b3a0e 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1502,10 +1502,6 @@ static void net_tx_submit(struct xen_netbk *netbk)
- kfree_skb(skb);
- continue;
- }
-- } else if (skb_is_gso(skb)) {
-- DPRINTK("Dropping GSO but not CHECKSUM_PARTIAL skb\n");
-- kfree_skb(skb);
-- continue;
- }
-
- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
---
-1.7.4
-
-
-From 01cd16474ee82db4d958c9cf8e481be897fa4ca6 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 27 Jan 2011 15:43:46 +0000
-Subject: [PATCH 121/244] xen: netback: handle incoming GSO SKBs which are not
CHECKSUM_PARTIAL
-
-The Linux network stack expects all GSO SKBs to have ip_summed ==
-CHECKSUM_PARTIAL (which implies that the frame contains a partial
-checksum) and the Xen network ring protocol similarly expects an SKB
-which has GSO set to also have NETRX_csum_blank (which also implies a
-partial checksum).
-
-However there have been cases of buggy guests which mark a frame as
-GSO but do not set csum_blank. If we detect that we a receiving such a
-frame (which manifests as ip_summed != PARTIAL && skb_is_gso) then
-force the SKB to partial and recalculate the checksum, since we cannot
-rely on the peer having done so if they have not set csum_blank.
-
-Add an ethtool stat to track occurances of this event.
-
-A corresponding fix was made to netfront in e0ce4af920eb028f38bfd680b1d733f4c7a0b7cf.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
-Cc: xen-devel(a)lists.xensource.com
----
- drivers/xen/netback/common.h | 1 +
- drivers/xen/netback/interface.c | 9 +++++++-
- drivers/xen/netback/netback.c | 43 ++++++++++++++++++++++++++++++++------
- 3 files changed, 45 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index 7e03a46..f660eb5 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -101,6 +101,7 @@ struct xen_netif {
-
- /* Statistics */
- int nr_copied_skbs;
-+ int rx_gso_checksum_fixup;
-
- /* Miscellaneous private stuff. */
- struct list_head list; /* scheduling list */
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index efdc21c..d3af68e 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -189,7 +189,14 @@ static const struct netif_stat {
- char name[ETH_GSTRING_LEN];
- u16 offset;
- } netbk_stats[] = {
-- { "copied_skbs", offsetof(struct xen_netif, nr_copied_skbs) },
-+ {
-+ "copied_skbs",
-+ offsetof(struct xen_netif, nr_copied_skbs)
-+ },
-+ {
-+ "rx_gso_checksum_fixup",
-+ offsetof(struct xen_netif, rx_gso_checksum_fixup)
-+ },
- };
-
- static int netbk_get_sset_count(struct net_device *dev, int string_set)
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 53b3a0e..8189199 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1222,11 +1222,28 @@ static int netbk_set_skb_gso(struct sk_buff *skb, struct
xen_netif_extra_info *g
- return 0;
- }
-
--static int skb_checksum_setup(struct sk_buff *skb)
-+static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
- {
- struct iphdr *iph;
- unsigned char *th;
- int err = -EPROTO;
-+ int recalculate_partial_csum = 0;
-+
-+ /*
-+ * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
-+ * peers can fail to set NETRXF_csum_blank when sending a GSO
-+ * frame. In this case force the SKB to CHECKSUM_PARTIAL and
-+ * recalculate the partial checksum.
-+ */
-+ if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
-+ netif->rx_gso_checksum_fixup++;
-+ skb->ip_summed = CHECKSUM_PARTIAL;
-+ recalculate_partial_csum = 1;
-+ }
-+
-+ /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
-+ if (skb->ip_summed != CHECKSUM_PARTIAL)
-+ return 0;
-
- if (skb->protocol != htons(ETH_P_IP))
- goto out;
-@@ -1240,9 +1257,23 @@ static int skb_checksum_setup(struct sk_buff *skb)
- switch (iph->protocol) {
- case IPPROTO_TCP:
- skb->csum_offset = offsetof(struct tcphdr, check);
-+
-+ if (recalculate_partial_csum) {
-+ struct tcphdr *tcph = (struct tcphdr *)th;
-+ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-+ skb->len - iph->ihl*4,
-+ IPPROTO_TCP, 0);
-+ }
- break;
- case IPPROTO_UDP:
- skb->csum_offset = offsetof(struct udphdr, check);
-+
-+ if (recalculate_partial_csum) {
-+ struct udphdr *udph = (struct udphdr *)th;
-+ udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-+ skb->len - iph->ihl*4,
-+ IPPROTO_UDP, 0);
-+ }
- break;
- default:
- if (net_ratelimit())
-@@ -1496,12 +1527,10 @@ static void net_tx_submit(struct xen_netbk *netbk)
- skb->dev = netif->dev;
- skb->protocol = eth_type_trans(skb, skb->dev);
-
-- if (skb->ip_summed == CHECKSUM_PARTIAL) {
-- if (skb_checksum_setup(skb)) {
-- DPRINTK("Can't setup checksum in net_tx_action\n");
-- kfree_skb(skb);
-- continue;
-- }
-+ if (checksum_setup(netif, skb)) {
-+ DPRINTK("Can't setup checksum in net_tx_action\n");
-+ kfree_skb(skb);
-+ continue;
- }
-
- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
---
-1.7.4
-
-
-From 929c2cd7541a48c9ab64af1b25b3e53ed396e0c5 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 18 Jan 2011 11:37:12 +0000
-Subject: [PATCH 122/244] xen: netback: rationalise types used in count_skb_slots
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 10 +++-------
- 1 files changed, 3 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 8189199..22c1fa5 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -277,14 +277,10 @@ static inline int netbk_queue_full(struct xen_netif *netif)
-
- /* Figure out how many ring slots we're going to need to send @skb to
- the guest. */
--static unsigned count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
-+static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
- {
-- unsigned count;
-- unsigned copy_off;
-- unsigned i;
--
-- copy_off = 0;
-- count = 1;
-+ unsigned int count = 1;
-+ int i, copy_off = 0;
-
- BUG_ON(offset_in_page(skb->data) + skb_headlen(skb) > MAX_BUFFER_OFFSET);
-
---
-1.7.4
-
-
-From 0ded854cc2e58205d857df3d96ef6f9a108a4a66 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 18 Jan 2011 11:21:35 +0000
-Subject: [PATCH 123/244] xen: netback: refactor logic for moving to a new receive
buffer.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 80 ++++++++++++++++++++++++-----------------
- 1 files changed, 47 insertions(+), 33 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 22c1fa5..909e0ef 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -275,8 +275,51 @@ static inline int netbk_queue_full(struct xen_netif *netif)
- ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
- }
-
--/* Figure out how many ring slots we're going to need to send @skb to
-- the guest. */
-+/*
-+ * Returns true if we should start a new receive buffer instead of
-+ * adding 'size' bytes to a buffer which currently contains 'offset'
-+ * bytes.
-+ */
-+static bool start_new_rx_buffer(int offset, unsigned long size, int head)
-+{
-+ /* simple case: we have completely filled the current buffer. */
-+ if (offset == MAX_BUFFER_OFFSET)
-+ return true;
-+
-+ /*
-+ * complex case: start a fresh buffer if the current frag
-+ * would overflow the current buffer but only if:
-+ * (i) this frag would fit completely in the next buffer
-+ * and (ii) there is already some data in the current buffer
-+ * and (iii) this is not the head buffer.
-+ *
-+ * Where:
-+ * - (i) stops us splitting a frag into two copies
-+ * unless the frag is too large for a single buffer.
-+ * - (ii) stops us from leaving a buffer pointlessly empty.
-+ * - (iii) stops us leaving the first buffer
-+ * empty. Strictly speaking this is already covered
-+ * by (ii) but is explicitly checked because
-+ * netfront relies on the first buffer being
-+ * non-empty and can crash otherwise.
-+ *
-+ * This means we will effectively linearise small
-+ * frags but do not needlessly split large buffers
-+ * into multiple copies tend to give large frags their
-+ * own buffers as before.
-+ */
-+ if ((offset + size > MAX_BUFFER_OFFSET) &&
-+ (size <= MAX_BUFFER_OFFSET) && offset && !head)
-+ return true;
-+
-+ return false;
-+}
-+
-+/*
-+ * Figure out how many ring slots we're going to need to send @skb to
-+ * the guest. This function is essentially a dry run of
-+ * netbk_gop_frag_copy.
-+ */
- static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
- {
- unsigned int count = 1;
-@@ -295,9 +338,7 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xen_netif *netif
- while (size > 0) {
- BUG_ON(copy_off > MAX_BUFFER_OFFSET);
-
-- /* These checks are the same as in netbk_gop_frag_copy */
-- if (copy_off == MAX_BUFFER_OFFSET
-- || ((copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && copy_off)) {
-+ if (start_new_rx_buffer(copy_off, size, 0)) {
- count++;
- copy_off = 0;
- }
-@@ -403,34 +444,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- while (size > 0) {
- BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
-
-- /*
-- * Move to a new receive buffer if:
-- *
-- * simple case: we have completely filled the current buffer.
-- *
-- * complex case: the current frag would overflow
-- * the current buffer but only if:
-- * (i) this frag would fit completely in the next buffer
-- * and (ii) there is already some data in the current buffer
-- * and (iii) this is not the head buffer.
-- *
-- * Where:
-- * - (i) stops us splitting a frag into two copies
-- * unless the frag is too large for a single buffer.
-- * - (ii) stops us from leaving a buffer pointlessly empty.
-- * - (iii) stops us leaving the first buffer
-- * empty. Strictly speaking this is already covered
-- * by (ii) but is explicitly checked because
-- * netfront relies on the first buffer being
-- * non-empty and can crash otherwise.
-- *
-- * This means we will effectively linearise small
-- * frags but do not needlessly split large buffers
-- * into multiple copies tend to give large frags their
-- * own buffers as before.
-- */
-- if (npo->copy_off == MAX_BUFFER_OFFSET
-- || ((npo->copy_off + size > MAX_BUFFER_OFFSET) && (size <=
MAX_BUFFER_OFFSET) && npo->copy_off && !head)) {
-+ if (start_new_rx_buffer(npo->copy_off, size, head)) {
- struct xen_netif_rx_request *req;
-
- BUG_ON(head); /* Netfront requires there to be some data in the head buffer. */
---
-1.7.4
-
-
-From 9e79b27c9369d25ca86abf66611a700783ce1ef2 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 2 Feb 2011 11:12:39 +0000
-Subject: [PATCH 124/244] xen: netback: refactor code to get next rx buffer into own
function.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 37 ++++++++++++++++++++++++++-----------
- 1 files changed, 26 insertions(+), 11 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index 909e0ef..a8ee1c2 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -418,6 +418,25 @@ struct netrx_pending_operations {
- grant_ref_t copy_gref;
- };
-
-+static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
-+ struct netrx_pending_operations *npo)
-+{
-+ struct netbk_rx_meta *meta;
-+ struct xen_netif_rx_request *req;
-+
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->gso_size = 0;
-+ meta->size = 0;
-+ meta->id = req->id;
-+
-+ npo->copy_off = 0;
-+ npo->copy_gref = req->gref;
-+
-+ return meta;
-+}
-+
- /* Set up the grant operations for this fragment. If it's a flipping
- interface, we also set up the unmap request from here. */
-
-@@ -445,17 +464,13 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
-
- if (start_new_rx_buffer(npo->copy_off, size, head)) {
-- struct xen_netif_rx_request *req;
--
-- BUG_ON(head); /* Netfront requires there to be some data in the head buffer. */
-- /* Overflowed this request, go to the next one */
-- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-- meta = npo->meta + npo->meta_prod++;
-- meta->gso_size = 0;
-- meta->size = 0;
-- meta->id = req->id;
-- npo->copy_off = 0;
-- npo->copy_gref = req->gref;
-+ /*
-+ * Netfront requires there to be some data in the head
-+ * buffer.
-+ */
-+ BUG_ON(head);
-+
-+ meta = get_next_rx_buffer(netif, npo);
- }
-
- bytes = size;
---
-1.7.4
-
-
-From e02c96928e165eb351ded4cc78cce4c615778be3 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 2 Feb 2011 11:14:17 +0000
-Subject: [PATCH 125/244] xen: netback: simplify use of netbk_add_frag_responses
-
-Move all the logic into the function instead of having some in the caller.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/netback.c | 14 +++++++++-----
- 1 files changed, 9 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index a8ee1c2..cfe7931 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -599,6 +599,12 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
- int i;
- unsigned long offset;
-
-+ /* No fragments used */
-+ if (nr_meta_slots <= 1)
-+ return;
-+
-+ nr_meta_slots--;
-+
- for (i = 0; i < nr_meta_slots; i++) {
- int flags;
- if (i == nr_meta_slots - 1)
-@@ -727,11 +733,9 @@ static void net_rx_action(unsigned long data)
- gso->flags = 0;
- }
-
-- if (sco->meta_slots_used > 1) {
-- netbk_add_frag_responses(netif, status,
-- netbk->meta + npo.meta_cons + 1,
-- sco->meta_slots_used - 1);
-- }
-+ netbk_add_frag_responses(netif, status,
-+ netbk->meta + npo.meta_cons + 1,
-+ sco->meta_slots_used);
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
- irq = netif->irq;
---
-1.7.4
-
-
-From 9304651128c7fdc2ffdf36e9fd589a13d5aca35d Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 24 Dec 2010 13:37:04 +0000
-Subject: [PATCH 126/244] xen: netback: cleanup coding style
-
-Fix checkpatch.pl errors plus manual sweep.
-
-Including:
-- remove incorrect and unnecessary filenames from comment headers.
-- do not include <linux/version.h>
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/common.h | 57 ++----------------------
- drivers/xen/netback/interface.c | 18 +++----
- drivers/xen/netback/netback.c | 93 ++++++++++++++++++++-------------------
- drivers/xen/netback/xenbus.c | 65 ++++++++++++---------------
- 4 files changed, 89 insertions(+), 144 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index f660eb5..a2455a0 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -1,6 +1,4 @@
--/******************************************************************************
-- * arch/xen/drivers/netif/backend/common.h
-- *
-+/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
-@@ -29,19 +27,18 @@
- #ifndef __NETIF__BACKEND__COMMON_H__
- #define __NETIF__BACKEND__COMMON_H__
-
--#include <linux/version.h>
- #include <linux/module.h>
- #include <linux/interrupt.h>
- #include <linux/slab.h>
- #include <linux/ip.h>
- #include <linux/in.h>
-+#include <linux/io.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/wait.h>
- #include <linux/sched.h>
-
- #include <xen/interface/io/netif.h>
--#include <asm/io.h>
- #include <asm/pgalloc.h>
- #include <xen/interface/grant_table.h>
- #include <xen/grant_table.h>
-@@ -49,7 +46,7 @@
-
- #define DPRINTK(_f, _a...) \
- pr_debug("(file=%s, line=%d) " _f, \
-- __FILE__ , __LINE__ , ## _a )
-+ __FILE__ , __LINE__ , ## _a)
- #define IPRINTK(fmt, args...) \
- printk(KERN_INFO "xen_net: " fmt, ##args)
- #define WPRINTK(fmt, args...) \
-@@ -132,66 +129,22 @@ enum {
-
- extern int netbk_copy_skb_mode;
-
--/* Function pointers into netback accelerator plugin modules */
--struct netback_accel_hooks {
-- struct module *owner;
-- int (*probe)(struct xenbus_device *dev);
-- int (*remove)(struct xenbus_device *dev);
--};
--
--/* Structure to track the state of a netback accelerator plugin */
--struct netback_accelerator {
-- struct list_head link;
-- int id;
-- char *eth_name;
-- atomic_t use_count;
-- struct netback_accel_hooks *hooks;
--};
--
- struct backend_info {
- struct xenbus_device *dev;
- struct xen_netif *netif;
- enum xenbus_state frontend_state;
- struct xenbus_watch hotplug_status_watch;
- int have_hotplug_status_watch:1;
--
-- /* State relating to the netback accelerator */
-- void *netback_accel_priv;
-- /* The accelerator that this backend is currently using */
-- struct netback_accelerator *accelerator;
- };
-
--#define NETBACK_ACCEL_VERSION 0x00010001
--
--/*
-- * Connect an accelerator plugin module to netback. Returns zero on
-- * success, < 0 on error, > 0 (with highest version number supported)
-- * if version mismatch.
-- */
--extern int netback_connect_accelerator(unsigned version,
-- int id, const char *eth_name,
-- struct netback_accel_hooks *hooks);
--/* Disconnect a previously connected accelerator plugin module */
--extern void netback_disconnect_accelerator(int id, const char *eth_name);
--
--
--extern
--void netback_probe_accelerators(struct backend_info *be,
-- struct xenbus_device *dev);
--extern
--void netback_remove_accelerators(struct backend_info *be,
-- struct xenbus_device *dev);
--extern
--void netif_accel_init(void);
--
--
- #define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
- #define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-
- void netif_disconnect(struct xen_netif *netif);
-
- void netif_set_features(struct xen_netif *netif);
--struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle);
-+struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-+ unsigned int handle);
- int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index d3af68e..4622653 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -1,6 +1,4 @@
--/******************************************************************************
-- * arch/xen/drivers/netif/backend/interface.c
-- *
-+/*
- * Network-device interface management.
- *
- * Copyright (c) 2004-2005, Keir Fraser
-@@ -232,8 +230,7 @@ static void netbk_get_strings(struct net_device *dev, u32 stringset,
u8 * data)
- }
- }
-
--static struct ethtool_ops network_ethtool_ops =
--{
-+static struct ethtool_ops network_ethtool_ops = {
- .get_drvinfo = netbk_get_drvinfo,
-
- .get_tx_csum = ethtool_op_get_tx_csum,
-@@ -249,8 +246,7 @@ static struct ethtool_ops network_ethtool_ops =
- .get_strings = netbk_get_strings,
- };
-
--static struct net_device_ops netback_ops =
--{
-+static struct net_device_ops netback_ops = {
- .ndo_start_xmit = netif_be_start_xmit,
- .ndo_get_stats = netif_be_get_stats,
- .ndo_open = net_open,
-@@ -258,7 +254,8 @@ static struct net_device_ops netback_ops =
- .ndo_change_mtu = netbk_change_mtu,
- };
-
--struct xen_netif *netif_alloc(struct device *parent, domid_t domid, unsigned int
handle)
-+struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-+ unsigned int handle)
- {
- int err = 0;
- struct net_device *dev;
-@@ -323,8 +320,9 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
unsigned int
- return netif;
- }
-
--static int map_frontend_pages(
-- struct xen_netif *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
-+static int map_frontend_pages(struct xen_netif *netif,
-+ grant_ref_t tx_ring_ref,
-+ grant_ref_t rx_ring_ref)
- {
- struct gnttab_map_grant_ref op;
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index cfe7931..d4aa8ac 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -1,11 +1,9 @@
--/******************************************************************************
-- * drivers/xen/netback/netback.c
-- *
-+/*
- * Back-end of the driver for virtual network devices. This portion of the
- * driver exports a 'unified' network-device interface that can be accessed
- * by any operating system that implements a compatible front end. A
- * reference front-end implementation can be found in:
-- * drivers/xen/netfront/netfront.c
-+ * drivers/net/xen-netfront.c
- *
- * Copyright (c) 2002-2005, K A Fraser
- *
-@@ -82,8 +80,8 @@ static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
- }
-
- /* extra field used in struct page */
--static inline void netif_set_page_ext(struct page *pg, unsigned int group,
-- unsigned int idx)
-+static inline void netif_set_page_ext(struct page *pg,
-+ unsigned int group, unsigned int idx)
- {
- union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
-
-@@ -91,7 +89,8 @@ static inline void netif_set_page_ext(struct page *pg, unsigned int
group,
- pg->mapping = ext.mapping;
- }
-
--static inline int netif_get_page_ext(struct page *pg, unsigned int *_group, unsigned int
*_idx)
-+static int netif_get_page_ext(struct page *pg,
-+ unsigned int *_group, unsigned int *_idx)
- {
- union page_ext ext = { .mapping = pg->mapping };
- struct xen_netbk *netbk;
-@@ -325,7 +324,7 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xen_netif *netif
- unsigned int count = 1;
- int i, copy_off = 0;
-
-- BUG_ON(offset_in_page(skb->data) + skb_headlen(skb) > MAX_BUFFER_OFFSET);
-+ BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
-
- copy_off = skb_headlen(skb);
-
-@@ -376,7 +375,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- */
- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
- struct sk_buff *nskb = netbk_copy_skb(skb);
-- if ( unlikely(nskb == NULL) )
-+ if (unlikely(nskb == NULL))
- goto drop;
- /* Copy only the header fields we use in this driver. */
- nskb->dev = skb->dev;
-@@ -385,8 +384,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
- skb = nskb;
- }
-
-- /* Reserve ring slots for the worst-case number of
-- * fragments. */
-+ /* Reserve ring slots for the worst-case number of fragments. */
- netif->rx_req_cons_peek += count_skb_slots(skb, netif);
- netif_get(netif);
-
-@@ -437,9 +435,10 @@ static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif
*netif,
- return meta;
- }
-
--/* Set up the grant operations for this fragment. If it's a flipping
-- interface, we also set up the unmap request from here. */
--
-+/*
-+ * 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 netbk_gop_frag_copy(struct xen_netif *netif,
- struct netrx_pending_operations *npo,
- struct page *page, unsigned long size,
-@@ -450,7 +449,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- /*
- * These variables a used iff netif_get_page_ext returns true,
- * in which case they are guaranteed to be initialized.
-- */
-+ */
- unsigned int uninitialized_var(group), uninitialized_var(idx);
- int foreign = netif_get_page_ext(page, &group, &idx);
- unsigned long bytes;
-@@ -489,8 +488,9 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- copy_gop->source.u.ref = src_pend->req.gref;
- copy_gop->flags |= GNTCOPY_source_gref;
- } else {
-+ void *vaddr = page_address(page);
- copy_gop->source.domid = DOMID_SELF;
-- copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
-+ copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
- }
- copy_gop->source.offset = offset;
- copy_gop->dest.domid = netif->domid;
-@@ -504,17 +504,22 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
-
- offset += bytes;
- size -= bytes;
-- head = 0; /* Must be something in this buffer now */
-+ head = 0; /* There must be something in this buffer now. */
- }
- }
-
--/* Prepare an SKB to be transmitted to the frontend. This is
-- responsible for allocating grant operations, meta structures, etc.
-- It returns the number of meta structures consumed. The number of
-- ring slots used is always equal to the number of meta slots used
-- plus the number of GSO descriptors used. Currently, we use either
-- zero GSO descriptors (for non-GSO packets) or one descriptor (for
-- frontend-side LRO). */
-+/*
-+ * Prepare an SKB to be transmitted to the frontend.
-+ *
-+ * This function is responsible for allocating grant operations, meta
-+ * structures, etc.
-+ *
-+ * It returns the number of meta structures consumed. The number of
-+ * ring slots used is always equal to the number of meta slots used
-+ * plus the number of GSO descriptors used. Currently, we use either
-+ * zero GSO descriptors (for non-GSO packets) or one descriptor (for
-+ * frontend-side LRO).
-+ */
- static int netbk_gop_skb(struct sk_buff *skb,
- struct netrx_pending_operations *npo)
- {
-@@ -569,10 +574,12 @@ static int netbk_gop_skb(struct sk_buff *skb,
- return npo->meta_prod - old_meta_prod;
- }
-
--/* This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
-- used to set up the operations on the top of
-- netrx_pending_operations, which have since been done. Check that
-- they didn't give any errors and advance over them. */
-+/*
-+ * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
-+ * used to set up the operations on the top of
-+ * netrx_pending_operations, which have since been done. Check that
-+ * they didn't give any errors and advance over them.
-+ */
- static int netbk_check_gop(int nr_meta_slots, domid_t domid,
- struct netrx_pending_operations *npo)
- {
-@@ -906,9 +913,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
- dc = netbk->dealloc_cons;
- gop = netbk->tx_unmap_ops;
-
-- /*
-- * Free up any grants we have finished using
-- */
-+ /* Free up any grants we have finished using. */
- do {
- dp = netbk->dealloc_prod;
-
-@@ -1018,7 +1023,8 @@ static void netbk_tx_err(struct xen_netif *netif,
-
- static int netbk_count_requests(struct xen_netif *netif,
- struct xen_netif_tx_request *first,
-- struct xen_netif_tx_request *txp, int work_to_do)
-+ struct xen_netif_tx_request *txp,
-+ int work_to_do)
- {
- RING_IDX cons = netif->tx.req_cons;
- int frags = 0;
-@@ -1058,10 +1064,10 @@ static int netbk_count_requests(struct xen_netif *netif,
- }
-
- static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
-- struct xen_netif *netif,
-- struct sk_buff *skb,
-- struct xen_netif_tx_request *txp,
-- struct gnttab_map_grant_ref *mop)
-+ struct xen_netif *netif,
-+ struct sk_buff *skb,
-+ struct xen_netif_tx_request *txp,
-+ struct gnttab_map_grant_ref *mop)
- {
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- skb_frag_t *frags = shinfo->frags;
-@@ -1200,7 +1206,8 @@ static void netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
- }
- }
-
--int netbk_get_extras(struct xen_netif *netif, struct xen_netif_extra_info *extras,
-+int netbk_get_extras(struct xen_netif *netif,
-+ struct xen_netif_extra_info *extras,
- int work_to_do)
- {
- struct xen_netif_extra_info extra;
-@@ -1228,7 +1235,8 @@ int netbk_get_extras(struct xen_netif *netif, struct
xen_netif_extra_info *extra
- return work_to_do;
- }
-
--static int netbk_set_skb_gso(struct sk_buff *skb, struct xen_netif_extra_info *gso)
-+static int netbk_set_skb_gso(struct sk_buff *skb,
-+ struct xen_netif_extra_info *gso)
- {
- if (!gso->u.gso.size) {
- DPRINTK("GSO size must not be zero.\n");
-@@ -1365,7 +1373,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- struct xen_netif *netif;
- struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
- u16 pending_idx;
- RING_IDX idx;
- int work_to_do;
-@@ -1427,7 +1435,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
- DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
- txreq.offset, txreq.size,
-- (txreq.offset &~PAGE_MASK) + txreq.size);
-+ (txreq.offset&~PAGE_MASK) + txreq.size);
- netbk_tx_err(netif, &txreq, idx);
- continue;
- }
-@@ -1807,9 +1815,6 @@ static int __init netback_init(void)
- }
- memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
-
-- /* We can increase reservation by this much in net_rx_action(). */
--// balloon_update_driver_allowance(NET_RX_RING_SIZE);
--
- for (group = 0; group < xen_netbk_group_nr; group++) {
- struct xen_netbk *netbk = &xen_netbk[group];
- skb_queue_head_init(&netbk->rx_queue);
-@@ -1894,8 +1899,6 @@ static int __init netback_init(void)
- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
- }
-
-- //netif_accel_init();
--
- rc = netif_xenbus_init();
- if (rc)
- goto failed_init;
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index 1fec65a..dd44341 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -1,20 +1,22 @@
--/* Xenbus code for netif backend
-- Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
-- Copyright (C) 2005 XenSource Ltd
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+/*
-+ * Xenbus code for netif backend
-+ *
-+ * Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
-+ * Copyright (C) 2005 XenSource Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- #include <stdarg.h>
-@@ -22,13 +24,6 @@
- #include <xen/xenbus.h>
- #include "common.h"
-
--#if 0
--#undef DPRINTK
--#define DPRINTK(fmt, args...) \
-- printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__,
__LINE__, ##args)
--#endif
--
--
- static int connect_rings(struct backend_info *);
- static void connect(struct backend_info *);
- static void backend_create_netif(struct backend_info *be);
-@@ -36,9 +31,7 @@ static void unregister_hotplug_status_watch(struct backend_info *be);
-
- static int netback_remove(struct xenbus_device *dev)
- {
-- struct backend_info *be = dev_get_drvdata(&dev->dev);
--
-- //netback_remove_accelerators(be, dev);
-+ struct backend_info *be = dev_get_drvdata(&dev->dev);
-
- unregister_hotplug_status_watch(be);
- if (be->netif) {
-@@ -126,8 +119,6 @@ static int netback_probe(struct xenbus_device *dev,
- goto fail;
- }
-
-- //netback_probe_accelerators(be, dev);
--
- err = xenbus_switch_state(dev, XenbusStateInitWait);
- if (err)
- goto fail;
-@@ -147,12 +138,13 @@ fail:
- }
-
-
--/**
-+/*
- * Handle the creation of the hotplug script environment. We add the script
- * and vif variables to the environment, for the benefit of the vif-* hotplug
- * scripts.
- */
--static int netback_uevent(struct xenbus_device *xdev, struct kobj_uevent_env *env)
-+static int netback_uevent(struct xenbus_device *xdev,
-+ struct kobj_uevent_env *env)
- {
- struct backend_info *be = dev_get_drvdata(&xdev->dev);
- char *val;
-@@ -164,8 +156,7 @@ static int netback_uevent(struct xenbus_device *xdev, struct
kobj_uevent_env *en
- int err = PTR_ERR(val);
- xenbus_dev_fatal(xdev, err, "reading script");
- return err;
-- }
-- else {
-+ } else {
- if (add_uevent_var(env, "script=%s", val)) {
- kfree(val);
- return -ENOMEM;
-@@ -173,10 +164,10 @@ static int netback_uevent(struct xenbus_device *xdev, struct
kobj_uevent_env *en
- kfree(val);
- }
-
-- if (be && be->netif && add_uevent_var(env, "vif=%s",
be->netif->dev->name))
-- return -ENOMEM;
-+ if (!be || !be->netif)
-+ return 0;
-
-- return 0;
-+ return add_uevent_var(env, "vif=%s", be->netif->dev->name);
- }
-
-
-@@ -234,7 +225,7 @@ static void frontend_changed(struct xenbus_device *dev,
- case XenbusStateInitialising:
- if (dev->state == XenbusStateClosed) {
- printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-- __FUNCTION__, dev->nodename);
-+ __func__, dev->nodename);
- xenbus_switch_state(dev, XenbusStateInitWait);
- }
- break;
---
-1.7.4
-
-
-From 7ab35b88fd3b452d8b9aec972ab7d3e9de710894 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 19 Jan 2011 10:51:45 +0000
-Subject: [PATCH 127/244] xen: netback: drop private ?PRINTK macros in favour of pr_*
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/xen/netback/common.h | 10 ++--------
- drivers/xen/netback/interface.c | 13 +++++++------
- drivers/xen/netback/netback.c | 38 +++++++++++++++++++-------------------
- drivers/xen/netback/xenbus.c | 13 +++----------
- 4 files changed, 31 insertions(+), 43 deletions(-)
-
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-index a2455a0..49dc4cf 100644
---- a/drivers/xen/netback/common.h
-+++ b/drivers/xen/netback/common.h
-@@ -27,6 +27,8 @@
- #ifndef __NETIF__BACKEND__COMMON_H__
- #define __NETIF__BACKEND__COMMON_H__
-
-+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-+
- #include <linux/module.h>
- #include <linux/interrupt.h>
- #include <linux/slab.h>
-@@ -44,14 +46,6 @@
- #include <xen/grant_table.h>
- #include <xen/xenbus.h>
-
--#define DPRINTK(_f, _a...) \
-- pr_debug("(file=%s, line=%d) " _f, \
-- __FILE__ , __LINE__ , ## _a)
--#define IPRINTK(fmt, args...) \
-- printk(KERN_INFO "xen_net: " fmt, ##args)
--#define WPRINTK(fmt, args...) \
-- printk(KERN_WARNING "xen_net: " fmt, ##args)
--
- struct xen_netif {
- /* Unique identifier for this interface. */
- domid_t domid;
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-index 4622653..b429f8c 100644
---- a/drivers/xen/netback/interface.c
-+++ b/drivers/xen/netback/interface.c
-@@ -29,6 +29,7 @@
- */
-
- #include "common.h"
-+
- #include <linux/ethtool.h>
- #include <linux/rtnetlink.h>
-
-@@ -265,7 +266,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
- snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
- dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
- if (dev == NULL) {
-- DPRINTK("Could not create netif: out of memory\n");
-+ pr_debug("Could not allocate netdev\n");
- return ERR_PTR(-ENOMEM);
- }
-
-@@ -310,13 +311,13 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t
domid,
- err = register_netdevice(dev);
- rtnl_unlock();
- if (err) {
-- DPRINTK("Could not register new net device %s: err=%d\n",
-- dev->name, err);
-+ pr_debug("Could not register new net device %s: err=%d\n",
-+ dev->name, err);
- free_netdev(dev);
- return ERR_PTR(err);
- }
-
-- DPRINTK("Successfully created netif\n");
-+ pr_debug("Successfully created netif\n");
- return netif;
- }
-
-@@ -333,7 +334,7 @@ static int map_frontend_pages(struct xen_netif *netif,
- BUG();
-
- if (op.status) {
-- DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
-+ pr_debug("Gnttab failure mapping tx_ring_ref!\n");
- return op.status;
- }
-
-@@ -353,7 +354,7 @@ static int map_frontend_pages(struct xen_netif *netif,
- (unsigned long)netif->tx_comms_area->addr,
- GNTMAP_host_map, netif->tx_shmem_handle);
- HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
-- DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
-+ pr_debug("Gnttab failure mapping rx_ring_ref!\n");
- return op.status;
- }
-
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-index d4aa8ac..b290525 100644
---- a/drivers/xen/netback/netback.c
-+++ b/drivers/xen/netback/netback.c
-@@ -590,8 +590,8 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
- for (i = 0; i < nr_meta_slots; i++) {
- copy_op = npo->copy + npo->copy_cons++;
- if (copy_op->status != GNTST_okay) {
-- DPRINTK("Bad status %d from copy to DOM%d.\n",
-- copy_op->status, domid);
-+ pr_debug("Bad status %d from copy to DOM%d.\n",
-+ copy_op->status, domid);
- status = NETIF_RSP_ERROR;
- }
- }
-@@ -1034,19 +1034,19 @@ static int netbk_count_requests(struct xen_netif *netif,
-
- do {
- if (frags >= work_to_do) {
-- DPRINTK("Need more frags\n");
-+ pr_debug("Need more frags\n");
- return -frags;
- }
-
- if (unlikely(frags >= MAX_SKB_FRAGS)) {
-- DPRINTK("Too many frags\n");
-+ pr_debug("Too many frags\n");
- return -frags;
- }
-
- memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
- sizeof(*txp));
- if (txp->size > first->size) {
-- DPRINTK("Frags galore\n");
-+ pr_debug("Frags galore\n");
- return -frags;
- }
-
-@@ -1054,8 +1054,8 @@ static int netbk_count_requests(struct xen_netif *netif,
- frags++;
-
- if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-- DPRINTK("txp->offset: %x, size: %u\n",
-- txp->offset, txp->size);
-+ pr_debug("txp->offset: %x, size: %u\n",
-+ txp->offset, txp->size);
- return -frags;
- }
- } while ((txp++)->flags & NETTXF_more_data);
-@@ -1215,7 +1215,7 @@ int netbk_get_extras(struct xen_netif *netif,
-
- do {
- if (unlikely(work_to_do-- <= 0)) {
-- DPRINTK("Missing extra info\n");
-+ pr_debug("Missing extra info\n");
- return -EBADR;
- }
-
-@@ -1224,7 +1224,7 @@ int netbk_get_extras(struct xen_netif *netif,
- if (unlikely(!extra.type ||
- extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
- netif->tx.req_cons = ++cons;
-- DPRINTK("Invalid extra type: %d\n", extra.type);
-+ pr_debug("Invalid extra type: %d\n", extra.type);
- return -EINVAL;
- }
-
-@@ -1239,13 +1239,13 @@ static int netbk_set_skb_gso(struct sk_buff *skb,
- struct xen_netif_extra_info *gso)
- {
- if (!gso->u.gso.size) {
-- DPRINTK("GSO size must not be zero.\n");
-+ pr_debug("GSO size must not be zero.\n");
- return -EINVAL;
- }
-
- /* Currently only TCPv4 S.O. is supported. */
- if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-- DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
-+ pr_debug("Bad GSO type %d.\n", gso->u.gso.type);
- return -EINVAL;
- }
-
-@@ -1426,16 +1426,16 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- idx += ret;
-
- if (unlikely(txreq.size < ETH_HLEN)) {
-- DPRINTK("Bad packet size: %d\n", txreq.size);
-+ pr_debug("Bad packet size: %d\n", txreq.size);
- netbk_tx_err(netif, &txreq, idx);
- continue;
- }
-
- /* No crossing a page as the payload mustn't fragment. */
- if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-- DPRINTK("txreq.offset: %x, size: %u, end: %lu\n",
-- txreq.offset, txreq.size,
-- (txreq.offset&~PAGE_MASK) + txreq.size);
-+ pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
-+ txreq.offset, txreq.size,
-+ (txreq.offset&~PAGE_MASK) + txreq.size);
- netbk_tx_err(netif, &txreq, idx);
- continue;
- }
-@@ -1450,7 +1450,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
- GFP_ATOMIC | __GFP_NOWARN);
- if (unlikely(skb == NULL)) {
-- DPRINTK("Can't allocate a skb in start_xmit.\n");
-+ pr_debug("Can't allocate a skb in start_xmit.\n");
- netbk_tx_err(netif, &txreq, idx);
- break;
- }
-@@ -1525,7 +1525,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
-
- /* Check the remap error code. */
- if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
-- DPRINTK("netback grant failed.\n");
-+ pr_debug("netback grant failed.\n");
- skb_shinfo(skb)->nr_frags = 0;
- kfree_skb(skb);
- continue;
-@@ -1565,14 +1565,14 @@ static void net_tx_submit(struct xen_netbk *netbk)
- skb->protocol = eth_type_trans(skb, skb->dev);
-
- if (checksum_setup(netif, skb)) {
-- DPRINTK("Can't setup checksum in net_tx_action\n");
-+ pr_debug("Can't setup checksum in net_tx_action\n");
- kfree_skb(skb);
- continue;
- }
-
- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
- unlikely(skb_linearize(skb))) {
-- DPRINTK("Can't linearize skb in net_tx_action.\n");
-+ pr_debug("Can't linearize skb in net_tx_action.\n");
- kfree_skb(skb);
- continue;
- }
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-index dd44341..867dc25 100644
---- a/drivers/xen/netback/xenbus.c
-+++ b/drivers/xen/netback/xenbus.c
-@@ -19,9 +19,6 @@
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
--#include <stdarg.h>
--#include <linux/module.h>
--#include <xen/xenbus.h>
- #include "common.h"
-
- static int connect_rings(struct backend_info *);
-@@ -132,7 +129,7 @@ abort_transaction:
- xenbus_transaction_end(xbt, 1);
- xenbus_dev_fatal(dev, err, "%s", message);
- fail:
-- DPRINTK("failed");
-+ pr_debug("failed");
- netback_remove(dev);
- return err;
- }
-@@ -149,8 +146,6 @@ static int netback_uevent(struct xenbus_device *xdev,
- struct backend_info *be = dev_get_drvdata(&xdev->dev);
- char *val;
-
-- DPRINTK("netback_uevent");
--
- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
- if (IS_ERR(val)) {
- int err = PTR_ERR(val);
-@@ -217,7 +212,7 @@ static void frontend_changed(struct xenbus_device *dev,
- {
- struct backend_info *be = dev_get_drvdata(&dev->dev);
-
-- DPRINTK("%s", xenbus_strstate(frontend_state));
-+ pr_debug("frontend state %s", xenbus_strstate(frontend_state));
-
- be->frontend_state = frontend_state;
-
-@@ -297,7 +292,7 @@ static void xen_net_read_rate(struct xenbus_device *dev,
- return;
-
- fail:
-- WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
-+ pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
- kfree(ratestr);
- }
-
-@@ -396,8 +391,6 @@ static int connect_rings(struct backend_info *be)
- int err;
- int val;
-
-- DPRINTK("");
--
- err = xenbus_gather(XBT_NIL, dev->otherend,
- "tx-ring-ref", "%lu", &tx_ring_ref,
- "rx-ring-ref", "%lu", &rx_ring_ref,
---
-1.7.4
-
-
-From 34db20ebe74e4ffacda2d42eb9cd92ae9b770970 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 18 Jan 2011 12:54:12 +0000
-Subject: [PATCH 128/244] xen: netback: move under drivers/net/xen-netback/
-
-From the kernel's PoV netback is just another network device driver.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/Kconfig | 7 +
- drivers/net/Makefile | 1 +
- drivers/net/xen-netback/Makefile | 3 +
- drivers/net/xen-netback/common.h | 273 +++++
- drivers/net/xen-netback/interface.c | 470 +++++++++
- drivers/net/xen-netback/netback.c | 1934 +++++++++++++++++++++++++++++++++++
- drivers/net/xen-netback/xenbus.c | 489 +++++++++
- drivers/xen/Kconfig | 7 -
- drivers/xen/Makefile | 1 -
- drivers/xen/netback/Makefile | 3 -
- drivers/xen/netback/common.h | 273 -----
- drivers/xen/netback/interface.c | 470 ---------
- drivers/xen/netback/netback.c | 1934 -----------------------------------
- drivers/xen/netback/xenbus.c | 489 ---------
- 14 files changed, 3177 insertions(+), 3177 deletions(-)
- create mode 100644 drivers/net/xen-netback/Makefile
- create mode 100644 drivers/net/xen-netback/common.h
- create mode 100644 drivers/net/xen-netback/interface.c
- create mode 100644 drivers/net/xen-netback/netback.c
- create mode 100644 drivers/net/xen-netback/xenbus.c
- delete mode 100644 drivers/xen/netback/Makefile
- delete mode 100644 drivers/xen/netback/common.h
- delete mode 100644 drivers/xen/netback/interface.c
- delete mode 100644 drivers/xen/netback/netback.c
- delete mode 100644 drivers/xen/netback/xenbus.c
-
-diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
-index cbf0635..5b088f5 100644
---- a/drivers/net/Kconfig
-+++ b/drivers/net/Kconfig
-@@ -2970,6 +2970,13 @@ config XEN_NETDEV_FRONTEND
- if you are compiling a kernel for a Xen guest, you almost
- certainly want to enable this.
-
-+config XEN_NETDEV_BACKEND
-+ tristate "Xen backend network device"
-+ depends on XEN_BACKEND
-+ help
-+ Implement the network backend driver, which passes packets
-+ from the guest domain's frontend drivers to the network.
-+
- config ISERIES_VETH
- tristate "iSeries Virtual Ethernet driver support"
- depends on PPC_ISERIES
-diff --git a/drivers/net/Makefile b/drivers/net/Makefile
-index b90738d..145dfd7 100644
---- a/drivers/net/Makefile
-+++ b/drivers/net/Makefile
-@@ -171,6 +171,7 @@ obj-$(CONFIG_SLIP) += slip.o
- obj-$(CONFIG_SLHC) += slhc.o
-
- obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
-+obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
-
- obj-$(CONFIG_DUMMY) += dummy.o
- obj-$(CONFIG_IFB) += ifb.o
-diff --git a/drivers/net/xen-netback/Makefile b/drivers/net/xen-netback/Makefile
-new file mode 100644
-index 0000000..e346e81
---- /dev/null
-+++ b/drivers/net/xen-netback/Makefile
-@@ -0,0 +1,3 @@
-+obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
-+
-+xen-netback-y := netback.o xenbus.o interface.o
-diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-new file mode 100644
-index 0000000..2d727a0
---- /dev/null
-+++ b/drivers/net/xen-netback/common.h
-@@ -0,0 +1,273 @@
-+/*
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#ifndef __XEN_NETBACK__COMMON_H__
-+#define __XEN_NETBACK__COMMON_H__
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-+
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <linux/ip.h>
-+#include <linux/in.h>
-+#include <linux/io.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/wait.h>
-+#include <linux/sched.h>
-+
-+#include <xen/interface/io/netif.h>
-+#include <asm/pgalloc.h>
-+#include <xen/interface/grant_table.h>
-+#include <xen/grant_table.h>
-+#include <xen/xenbus.h>
-+
-+struct xen_netif {
-+ /* Unique identifier for this interface. */
-+ domid_t domid;
-+ int group;
-+ unsigned int handle;
-+
-+ u8 fe_dev_addr[6];
-+
-+ /* Physical parameters of the comms window. */
-+ grant_handle_t tx_shmem_handle;
-+ grant_ref_t tx_shmem_ref;
-+ grant_handle_t rx_shmem_handle;
-+ grant_ref_t rx_shmem_ref;
-+ unsigned int irq;
-+
-+ /* The shared rings and indexes. */
-+ struct xen_netif_tx_back_ring tx;
-+ struct xen_netif_rx_back_ring rx;
-+ struct vm_struct *tx_comms_area;
-+ struct vm_struct *rx_comms_area;
-+
-+ /* Flags that must not be set in dev->features */
-+ int features_disabled;
-+
-+ /* Frontend feature information. */
-+ u8 can_sg:1;
-+ u8 gso:1;
-+ u8 gso_prefix:1;
-+ u8 csum:1;
-+
-+ /* Internal feature information. */
-+ u8 can_queue:1; /* can queue packets for receiver? */
-+
-+ /* Allow netif_be_start_xmit() to peek ahead in the rx request
-+ * ring. This is a prediction of what rx_req_cons will be once
-+ * all queued skbs are put on the ring. */
-+ RING_IDX rx_req_cons_peek;
-+
-+ /* 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;
-+
-+ /* Statistics */
-+ int nr_copied_skbs;
-+ int rx_gso_checksum_fixup;
-+
-+ /* Miscellaneous private stuff. */
-+ struct list_head list; /* scheduling list */
-+ atomic_t refcnt;
-+ struct net_device *dev;
-+ struct net_device_stats stats;
-+
-+ unsigned int carrier;
-+
-+ wait_queue_head_t waiting_to_free;
-+};
-+
-+/*
-+ * Implement our own carrier flag: the network stack's version causes delays
-+ * when the carrier is re-enabled (in particular, dev_activate() may not
-+ * immediately be called, which can cause packet loss; also the etherbridge
-+ * can be rather lazy in activating its port).
-+ */
-+#define netback_carrier_on(netif) ((netif)->carrier = 1)
-+#define netback_carrier_off(netif) ((netif)->carrier = 0)
-+#define netback_carrier_ok(netif) ((netif)->carrier)
-+
-+enum {
-+ NETBK_DONT_COPY_SKB,
-+ NETBK_DELAYED_COPY_SKB,
-+ NETBK_ALWAYS_COPY_SKB,
-+};
-+
-+extern int netbk_copy_skb_mode;
-+
-+struct backend_info {
-+ struct xenbus_device *dev;
-+ struct xen_netif *netif;
-+ enum xenbus_state frontend_state;
-+ struct xenbus_watch hotplug_status_watch;
-+ int have_hotplug_status_watch:1;
-+};
-+
-+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
-+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-+
-+void netif_disconnect(struct xen_netif *netif);
-+
-+void netif_set_features(struct xen_netif *netif);
-+struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-+ unsigned int handle);
-+int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
-+ unsigned long rx_ring_ref, unsigned int evtchn);
-+
-+static inline void netif_get(struct xen_netif *netif)
-+{
-+ atomic_inc(&netif->refcnt);
-+}
-+
-+static inline void netif_put(struct xen_netif *netif)
-+{
-+ if (atomic_dec_and_test(&netif->refcnt))
-+ wake_up(&netif->waiting_to_free);
-+}
-+
-+int netif_xenbus_init(void);
-+
-+#define netif_schedulable(netif) \
-+ (netif_running((netif)->dev) && netback_carrier_ok(netif))
-+
-+void netif_schedule_work(struct xen_netif *netif);
-+void netif_deschedule_work(struct xen_netif *netif);
-+
-+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+struct net_device_stats *netif_be_get_stats(struct net_device *dev);
-+irqreturn_t netif_be_int(int irq, void *dev_id);
-+
-+static inline int netbk_can_queue(struct net_device *dev)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ return netif->can_queue;
-+}
-+
-+static inline int netbk_can_sg(struct net_device *dev)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ return netif->can_sg;
-+}
-+
-+struct pending_tx_info {
-+ struct xen_netif_tx_request req;
-+ struct xen_netif *netif;
-+};
-+typedef unsigned int pending_ring_idx_t;
-+
-+struct netbk_rx_meta {
-+ int id;
-+ int size;
-+ int gso_size;
-+};
-+
-+struct netbk_tx_pending_inuse {
-+ struct list_head list;
-+ unsigned long alloc_time;
-+};
-+
-+#define MAX_PENDING_REQS 256
-+
-+#define MAX_BUFFER_OFFSET PAGE_SIZE
-+
-+/* extra field used in struct page */
-+union page_ext {
-+ struct {
-+#if BITS_PER_LONG < 64
-+#define IDX_WIDTH 8
-+#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
-+ unsigned int group:GROUP_WIDTH;
-+ unsigned int idx:IDX_WIDTH;
-+#else
-+ unsigned int group, idx;
-+#endif
-+ } e;
-+ void *mapping;
-+};
-+
-+struct xen_netbk {
-+ union {
-+ struct {
-+ struct tasklet_struct net_tx_tasklet;
-+ struct tasklet_struct net_rx_tasklet;
-+ } tasklet;
-+
-+ struct {
-+ wait_queue_head_t netbk_action_wq;
-+ struct task_struct *task;
-+ } kthread;
-+ };
-+
-+ struct sk_buff_head rx_queue;
-+ struct sk_buff_head tx_queue;
-+
-+ struct timer_list net_timer;
-+ struct timer_list netbk_tx_pending_timer;
-+
-+ struct page **mmap_pages;
-+
-+ 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 net_schedule_list;
-+
-+ /* Protect the net_schedule_list in netif. */
-+ spinlock_t net_schedule_list_lock;
-+
-+ atomic_t netfront_count;
-+
-+ 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];
-+
-+ /*
-+ * Each head or fragment can be up to 4096 bytes. Given
-+ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
-+ * head/fragment uses 2 copy operation.
-+ */
-+ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
-+ unsigned char rx_notify[NR_IRQS];
-+ u16 notify_list[NET_RX_RING_SIZE];
-+ struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
-+};
-+
-+extern struct xen_netbk *xen_netbk;
-+extern int xen_netbk_group_nr;
-+
-+#endif /* __XEN_NETBACK__COMMON_H__ */
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-new file mode 100644
-index 0000000..b429f8c
---- /dev/null
-+++ b/drivers/net/xen-netback/interface.c
-@@ -0,0 +1,470 @@
-+/*
-+ * Network-device interface management.
-+ *
-+ * Copyright (c) 2004-2005, Keir Fraser
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#include "common.h"
-+
-+#include <linux/ethtool.h>
-+#include <linux/rtnetlink.h>
-+
-+#include <xen/events.h>
-+#include <asm/xen/hypercall.h>
-+
-+/*
-+ * Module parameter 'queue_length':
-+ *
-+ * Enables queuing in the network stack when a client has run out of receive
-+ * descriptors.
-+ */
-+static unsigned long netbk_queue_length = 32;
-+module_param_named(queue_length, netbk_queue_length, ulong, 0644);
-+
-+static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
-+ struct xen_netif *netif)
-+{
-+ int i;
-+ int min_netfront_count;
-+ int min_group = 0;
-+ min_netfront_count = atomic_read(&netbk[0].netfront_count);
-+ for (i = 0; i < group_nr; i++) {
-+ int netfront_count = atomic_read(&netbk[i].netfront_count);
-+ if (netfront_count < min_netfront_count) {
-+ min_group = i;
-+ min_netfront_count = netfront_count;
-+ }
-+ }
-+
-+ netif->group = min_group;
-+ atomic_inc(&netbk[netif->group].netfront_count);
-+}
-+
-+static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
-+{
-+ atomic_dec(&netbk[netif->group].netfront_count);
-+}
-+
-+static void __netif_up(struct xen_netif *netif)
-+{
-+ netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
-+ enable_irq(netif->irq);
-+ netif_schedule_work(netif);
-+}
-+
-+static void __netif_down(struct xen_netif *netif)
-+{
-+ disable_irq(netif->irq);
-+ netif_deschedule_work(netif);
-+ netbk_remove_netif(xen_netbk, netif);
-+}
-+
-+static int net_open(struct net_device *dev)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (netback_carrier_ok(netif)) {
-+ __netif_up(netif);
-+ netif_start_queue(dev);
-+ }
-+ return 0;
-+}
-+
-+static int net_close(struct net_device *dev)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (netback_carrier_ok(netif))
-+ __netif_down(netif);
-+ netif_stop_queue(dev);
-+ return 0;
-+}
-+
-+static int netbk_change_mtu(struct net_device *dev, int mtu)
-+{
-+ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
-+
-+ if (mtu > max)
-+ return -EINVAL;
-+ dev->mtu = mtu;
-+ return 0;
-+}
-+
-+void netif_set_features(struct xen_netif *netif)
-+{
-+ struct net_device *dev = netif->dev;
-+ int features = dev->features;
-+
-+ if (netif->can_sg)
-+ features |= NETIF_F_SG;
-+ if (netif->gso || netif->gso_prefix)
-+ features |= NETIF_F_TSO;
-+ if (netif->csum)
-+ features |= NETIF_F_IP_CSUM;
-+
-+ features &= ~(netif->features_disabled);
-+
-+ if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
-+ dev->mtu = ETH_DATA_LEN;
-+
-+ dev->features = features;
-+}
-+
-+static int netbk_set_tx_csum(struct net_device *dev, u32 data)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (data) {
-+ if (!netif->csum)
-+ return -ENOSYS;
-+ netif->features_disabled &= ~NETIF_F_IP_CSUM;
-+ } else {
-+ netif->features_disabled |= NETIF_F_IP_CSUM;
-+ }
-+
-+ netif_set_features(netif);
-+ return 0;
-+}
-+
-+static int netbk_set_sg(struct net_device *dev, u32 data)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (data) {
-+ if (!netif->can_sg)
-+ return -ENOSYS;
-+ netif->features_disabled &= ~NETIF_F_SG;
-+ } else {
-+ netif->features_disabled |= NETIF_F_SG;
-+ }
-+
-+ netif_set_features(netif);
-+ return 0;
-+}
-+
-+static int netbk_set_tso(struct net_device *dev, u32 data)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ if (data) {
-+ if (!netif->gso && !netif->gso_prefix)
-+ return -ENOSYS;
-+ netif->features_disabled &= ~NETIF_F_TSO;
-+ } else {
-+ netif->features_disabled |= NETIF_F_TSO;
-+ }
-+
-+ netif_set_features(netif);
-+ return 0;
-+}
-+
-+static void netbk_get_drvinfo(struct net_device *dev,
-+ struct ethtool_drvinfo *info)
-+{
-+ strcpy(info->driver, "netbk");
-+ strcpy(info->bus_info, dev_name(dev->dev.parent));
-+}
-+
-+static const struct netif_stat {
-+ char name[ETH_GSTRING_LEN];
-+ u16 offset;
-+} netbk_stats[] = {
-+ {
-+ "copied_skbs",
-+ offsetof(struct xen_netif, nr_copied_skbs)
-+ },
-+ {
-+ "rx_gso_checksum_fixup",
-+ offsetof(struct xen_netif, rx_gso_checksum_fixup)
-+ },
-+};
-+
-+static int netbk_get_sset_count(struct net_device *dev, int string_set)
-+{
-+ switch (string_set) {
-+ case ETH_SS_STATS:
-+ return ARRAY_SIZE(netbk_stats);
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+static void netbk_get_ethtool_stats(struct net_device *dev,
-+ struct ethtool_stats *stats, u64 * data)
-+{
-+ void *netif = netdev_priv(dev);
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-+ data[i] = *(int *)(netif + netbk_stats[i].offset);
-+}
-+
-+static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
-+{
-+ int i;
-+
-+ switch (stringset) {
-+ case ETH_SS_STATS:
-+ for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-+ memcpy(data + i * ETH_GSTRING_LEN,
-+ netbk_stats[i].name, ETH_GSTRING_LEN);
-+ break;
-+ }
-+}
-+
-+static struct ethtool_ops network_ethtool_ops = {
-+ .get_drvinfo = netbk_get_drvinfo,
-+
-+ .get_tx_csum = ethtool_op_get_tx_csum,
-+ .set_tx_csum = netbk_set_tx_csum,
-+ .get_sg = ethtool_op_get_sg,
-+ .set_sg = netbk_set_sg,
-+ .get_tso = ethtool_op_get_tso,
-+ .set_tso = netbk_set_tso,
-+ .get_link = ethtool_op_get_link,
-+
-+ .get_sset_count = netbk_get_sset_count,
-+ .get_ethtool_stats = netbk_get_ethtool_stats,
-+ .get_strings = netbk_get_strings,
-+};
-+
-+static struct net_device_ops netback_ops = {
-+ .ndo_start_xmit = netif_be_start_xmit,
-+ .ndo_get_stats = netif_be_get_stats,
-+ .ndo_open = net_open,
-+ .ndo_stop = net_close,
-+ .ndo_change_mtu = netbk_change_mtu,
-+};
-+
-+struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-+ unsigned int handle)
-+{
-+ int err = 0;
-+ struct net_device *dev;
-+ struct xen_netif *netif;
-+ char name[IFNAMSIZ] = {};
-+
-+ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
-+ dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
-+ if (dev == NULL) {
-+ pr_debug("Could not allocate netdev\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ SET_NETDEV_DEV(dev, parent);
-+
-+ netif = netdev_priv(dev);
-+ memset(netif, 0, sizeof(*netif));
-+ netif->domid = domid;
-+ netif->group = -1;
-+ netif->handle = handle;
-+ netif->can_sg = 1;
-+ netif->csum = 1;
-+ atomic_set(&netif->refcnt, 1);
-+ init_waitqueue_head(&netif->waiting_to_free);
-+ netif->dev = dev;
-+ INIT_LIST_HEAD(&netif->list);
-+
-+ netback_carrier_off(netif);
-+
-+ netif->credit_bytes = netif->remaining_credit = ~0UL;
-+ netif->credit_usec = 0UL;
-+ init_timer(&netif->credit_timeout);
-+ /* Initialize 'expires' now: it's used to track the credit window. */
-+ netif->credit_timeout.expires = jiffies;
-+
-+ dev->netdev_ops = &netback_ops;
-+ netif_set_features(netif);
-+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-+
-+ dev->tx_queue_len = netbk_queue_length;
-+
-+ /*
-+ * Initialise a dummy MAC address. We choose the numerically
-+ * largest non-broadcast address to prevent the address getting
-+ * stolen by an Ethernet bridge for STP purposes.
-+ * (FE:FF:FF:FF:FF:FF)
-+ */
-+ memset(dev->dev_addr, 0xFF, ETH_ALEN);
-+ dev->dev_addr[0] &= ~0x01;
-+
-+ rtnl_lock();
-+ err = register_netdevice(dev);
-+ rtnl_unlock();
-+ if (err) {
-+ pr_debug("Could not register new net device %s: err=%d\n",
-+ dev->name, err);
-+ free_netdev(dev);
-+ return ERR_PTR(err);
-+ }
-+
-+ pr_debug("Successfully created netif\n");
-+ return netif;
-+}
-+
-+static int map_frontend_pages(struct xen_netif *netif,
-+ grant_ref_t tx_ring_ref,
-+ grant_ref_t rx_ring_ref)
-+{
-+ struct gnttab_map_grant_ref op;
-+
-+ gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
-+ GNTMAP_host_map, tx_ring_ref, netif->domid);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+ BUG();
-+
-+ if (op.status) {
-+ pr_debug("Gnttab failure mapping tx_ring_ref!\n");
-+ return op.status;
-+ }
-+
-+ netif->tx_shmem_ref = tx_ring_ref;
-+ netif->tx_shmem_handle = op.handle;
-+
-+ gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
-+ GNTMAP_host_map, rx_ring_ref, netif->domid);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+ BUG();
-+
-+ if (op.status) {
-+ struct gnttab_unmap_grant_ref unop;
-+
-+ gnttab_set_unmap_op(&unop,
-+ (unsigned long)netif->tx_comms_area->addr,
-+ GNTMAP_host_map, netif->tx_shmem_handle);
-+ HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
-+ pr_debug("Gnttab failure mapping rx_ring_ref!\n");
-+ return op.status;
-+ }
-+
-+ netif->rx_shmem_ref = rx_ring_ref;
-+ netif->rx_shmem_handle = op.handle;
-+
-+ return 0;
-+}
-+
-+static void unmap_frontend_pages(struct xen_netif *netif)
-+{
-+ struct gnttab_unmap_grant_ref op;
-+
-+ gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
-+ GNTMAP_host_map, netif->tx_shmem_handle);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+ BUG();
-+
-+ gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
-+ GNTMAP_host_map, netif->rx_shmem_handle);
-+
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+ BUG();
-+}
-+
-+int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
-+ unsigned long rx_ring_ref, unsigned int evtchn)
-+{
-+ int err = -ENOMEM;
-+ struct xen_netif_tx_sring *txs;
-+ struct xen_netif_rx_sring *rxs;
-+
-+ /* Already connected through? */
-+ if (netif->irq)
-+ return 0;
-+
-+ netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
-+ if (netif->tx_comms_area == NULL)
-+ return -ENOMEM;
-+ netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
-+ if (netif->rx_comms_area == NULL)
-+ goto err_rx;
-+
-+ err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
-+ if (err)
-+ goto err_map;
-+
-+ err = bind_interdomain_evtchn_to_irqhandler(
-+ netif->domid, evtchn, netif_be_int, 0,
-+ netif->dev->name, netif);
-+ if (err < 0)
-+ goto err_hypervisor;
-+ netif->irq = err;
-+ disable_irq(netif->irq);
-+
-+ txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
-+ BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
-+
-+ rxs = (struct xen_netif_rx_sring *)
-+ ((char *)netif->rx_comms_area->addr);
-+ BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
-+
-+ netif->rx_req_cons_peek = 0;
-+
-+ netif_get(netif);
-+
-+ rtnl_lock();
-+ netback_carrier_on(netif);
-+ if (netif_running(netif->dev))
-+ __netif_up(netif);
-+ rtnl_unlock();
-+
-+ return 0;
-+err_hypervisor:
-+ unmap_frontend_pages(netif);
-+err_map:
-+ free_vm_area(netif->rx_comms_area);
-+err_rx:
-+ free_vm_area(netif->tx_comms_area);
-+ return err;
-+}
-+
-+void netif_disconnect(struct xen_netif *netif)
-+{
-+ if (netback_carrier_ok(netif)) {
-+ rtnl_lock();
-+ netback_carrier_off(netif);
-+ netif_carrier_off(netif->dev); /* discard queued packets */
-+ if (netif_running(netif->dev))
-+ __netif_down(netif);
-+ rtnl_unlock();
-+ netif_put(netif);
-+ }
-+
-+ atomic_dec(&netif->refcnt);
-+ wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
-+
-+ del_timer_sync(&netif->credit_timeout);
-+
-+ if (netif->irq)
-+ unbind_from_irqhandler(netif->irq, netif);
-+
-+ unregister_netdev(netif->dev);
-+
-+ if (netif->tx.sring) {
-+ unmap_frontend_pages(netif);
-+ free_vm_area(netif->tx_comms_area);
-+ free_vm_area(netif->rx_comms_area);
-+ }
-+
-+ free_netdev(netif->dev);
-+}
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-new file mode 100644
-index 0000000..b290525
---- /dev/null
-+++ b/drivers/net/xen-netback/netback.c
-@@ -0,0 +1,1934 @@
-+/*
-+ * Back-end of the driver for virtual network devices. This portion of the
-+ * driver exports a 'unified' network-device interface that can be accessed
-+ * by any operating system that implements a compatible front end. A
-+ * reference front-end implementation can be found in:
-+ * drivers/net/xen-netfront.c
-+ *
-+ * Copyright (c) 2002-2005, K A Fraser
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#include "common.h"
-+
-+#include <linux/kthread.h>
-+#include <linux/if_vlan.h>
-+#include <linux/udp.h>
-+
-+#include <net/tcp.h>
-+
-+#include <xen/balloon.h>
-+#include <xen/events.h>
-+#include <xen/interface/memory.h>
-+
-+#include <asm/xen/hypercall.h>
-+#include <asm/xen/page.h>
-+
-+/*define NETBE_DEBUG_INTERRUPT*/
-+
-+struct xen_netbk *xen_netbk;
-+int xen_netbk_group_nr;
-+
-+static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
-+static void make_tx_response(struct xen_netif *netif,
-+ struct xen_netif_tx_request *txp,
-+ s8 st);
-+static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
-+ u16 id,
-+ s8 st,
-+ u16 offset,
-+ u16 size,
-+ u16 flags);
-+
-+static void net_tx_action(unsigned long data);
-+
-+static void net_rx_action(unsigned long data);
-+
-+static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
-+ unsigned int idx)
-+{
-+ return page_to_pfn(netbk->mmap_pages[idx]);
-+}
-+
-+static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
-+ unsigned int idx)
-+{
-+ return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
-+}
-+
-+/* extra field used in struct page */
-+static inline void netif_set_page_ext(struct page *pg,
-+ unsigned int group, unsigned int idx)
-+{
-+ union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
-+
-+ BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
-+ pg->mapping = ext.mapping;
-+}
-+
-+static int netif_get_page_ext(struct page *pg,
-+ unsigned int *_group, unsigned int *_idx)
-+{
-+ union page_ext ext = { .mapping = pg->mapping };
-+ struct xen_netbk *netbk;
-+ unsigned int group, idx;
-+
-+ if (!PageForeign(pg))
-+ return 0;
-+
-+ group = ext.e.group - 1;
-+
-+ if (group < 0 || group >= xen_netbk_group_nr)
-+ return 0;
-+
-+ netbk = &xen_netbk[group];
-+
-+ if (netbk->mmap_pages == NULL)
-+ return 0;
-+
-+ idx = ext.e.idx;
-+
-+ if ((idx < 0) || (idx >= MAX_PENDING_REQS))
-+ return 0;
-+
-+ if (netbk->mmap_pages[idx] != pg)
-+ return 0;
-+
-+ *_group = group;
-+ *_idx = idx;
-+
-+ return 1;
-+}
-+
-+/*
-+ * This is the amount of packet we copy rather than map, so that the
-+ * guest can't fiddle with the contents of the headers while we do
-+ * packet processing on them (netfilter, routing, etc).
-+ */
-+#define PKT_PROT_LEN (ETH_HLEN + \
-+ VLAN_HLEN + \
-+ sizeof(struct iphdr) + MAX_IPOPTLEN + \
-+ sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
-+
-+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 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;
-+module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
-+MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
-+
-+int netbk_copy_skb_mode;
-+
-+static int MODPARM_netback_kthread;
-+module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
-+MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
-+
-+/*
-+ * Netback bottom half handler.
-+ * dir indicates the data direction.
-+ * rx: 1, tx: 0.
-+ */
-+static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
-+{
-+ if (MODPARM_netback_kthread)
-+ wake_up(&netbk->kthread.netbk_action_wq);
-+ else if (dir)
-+ tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
-+ else
-+ tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
-+}
-+
-+static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
-+{
-+ smp_mb();
-+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
-+ !list_empty(&netbk->net_schedule_list))
-+ xen_netbk_bh_handler(netbk, 0);
-+}
-+
-+static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-+{
-+ struct skb_shared_info *ninfo;
-+ struct sk_buff *nskb;
-+ unsigned long offset;
-+ int ret;
-+ int len;
-+ int headlen;
-+
-+ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
-+
-+ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-+ if (unlikely(!nskb))
-+ goto err;
-+
-+ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-+ headlen = skb_end_pointer(nskb) - nskb->data;
-+ if (headlen > skb_headlen(skb))
-+ headlen = skb_headlen(skb);
-+ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-+ BUG_ON(ret);
-+
-+ ninfo = skb_shinfo(nskb);
-+ ninfo->gso_size = skb_shinfo(skb)->gso_size;
-+ ninfo->gso_type = skb_shinfo(skb)->gso_type;
-+
-+ offset = headlen;
-+ len = skb->len - headlen;
-+
-+ nskb->len = skb->len;
-+ nskb->data_len = len;
-+ nskb->truesize += len;
-+
-+ while (len) {
-+ struct page *page;
-+ int copy;
-+ int zero;
-+
-+ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-+ dump_stack();
-+ goto err_free;
-+ }
-+
-+ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-+ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
-+
-+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-+ if (unlikely(!page))
-+ goto err_free;
-+
-+ ret = skb_copy_bits(skb, offset, page_address(page), copy);
-+ BUG_ON(ret);
-+
-+ ninfo->frags[ninfo->nr_frags].page = page;
-+ ninfo->frags[ninfo->nr_frags].page_offset = 0;
-+ ninfo->frags[ninfo->nr_frags].size = copy;
-+ ninfo->nr_frags++;
-+
-+ offset += copy;
-+ len -= copy;
-+ }
-+
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+ offset = 0;
-+#else
-+ offset = nskb->data - skb->data;
-+#endif
-+
-+ nskb->transport_header = skb->transport_header + offset;
-+ nskb->network_header = skb->network_header + offset;
-+ nskb->mac_header = skb->mac_header + offset;
-+
-+ return nskb;
-+
-+ err_free:
-+ kfree_skb(nskb);
-+ err:
-+ return NULL;
-+}
-+
-+static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
-+{
-+ if (netif->can_sg || netif->gso || netif->gso_prefix)
-+ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-+ return 1; /* all in one */
-+}
-+
-+static inline int netbk_queue_full(struct xen_netif *netif)
-+{
-+ RING_IDX peek = netif->rx_req_cons_peek;
-+ RING_IDX needed = netbk_max_required_rx_slots(netif);
-+
-+ return ((netif->rx.sring->req_prod - peek) < needed) ||
-+ ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
-+}
-+
-+/*
-+ * Returns true if we should start a new receive buffer instead of
-+ * adding 'size' bytes to a buffer which currently contains 'offset'
-+ * bytes.
-+ */
-+static bool start_new_rx_buffer(int offset, unsigned long size, int head)
-+{
-+ /* simple case: we have completely filled the current buffer. */
-+ if (offset == MAX_BUFFER_OFFSET)
-+ return true;
-+
-+ /*
-+ * complex case: start a fresh buffer if the current frag
-+ * would overflow the current buffer but only if:
-+ * (i) this frag would fit completely in the next buffer
-+ * and (ii) there is already some data in the current buffer
-+ * and (iii) this is not the head buffer.
-+ *
-+ * Where:
-+ * - (i) stops us splitting a frag into two copies
-+ * unless the frag is too large for a single buffer.
-+ * - (ii) stops us from leaving a buffer pointlessly empty.
-+ * - (iii) stops us leaving the first buffer
-+ * empty. Strictly speaking this is already covered
-+ * by (ii) but is explicitly checked because
-+ * netfront relies on the first buffer being
-+ * non-empty and can crash otherwise.
-+ *
-+ * This means we will effectively linearise small
-+ * frags but do not needlessly split large buffers
-+ * into multiple copies tend to give large frags their
-+ * own buffers as before.
-+ */
-+ if ((offset + size > MAX_BUFFER_OFFSET) &&
-+ (size <= MAX_BUFFER_OFFSET) && offset && !head)
-+ return true;
-+
-+ return false;
-+}
-+
-+/*
-+ * Figure out how many ring slots we're going to need to send @skb to
-+ * the guest. This function is essentially a dry run of
-+ * netbk_gop_frag_copy.
-+ */
-+static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
-+{
-+ unsigned int count = 1;
-+ int i, copy_off = 0;
-+
-+ BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
-+
-+ copy_off = skb_headlen(skb);
-+
-+ if (skb_shinfo(skb)->gso_size)
-+ count++;
-+
-+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+ unsigned long size = skb_shinfo(skb)->frags[i].size;
-+ unsigned long bytes;
-+ while (size > 0) {
-+ BUG_ON(copy_off > MAX_BUFFER_OFFSET);
-+
-+ if (start_new_rx_buffer(copy_off, size, 0)) {
-+ count++;
-+ copy_off = 0;
-+ }
-+
-+ bytes = size;
-+ if (copy_off + bytes > MAX_BUFFER_OFFSET)
-+ bytes = MAX_BUFFER_OFFSET - copy_off;
-+
-+ copy_off += bytes;
-+ size -= bytes;
-+ }
-+ }
-+ return count;
-+}
-+
-+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ struct xen_netbk *netbk;
-+
-+ BUG_ON(skb->dev != dev);
-+
-+ if (netif->group == -1)
-+ goto drop;
-+
-+ netbk = &xen_netbk[netif->group];
-+
-+ /* Drop the packet if the target domain has no receive buffers. */
-+ if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
-+ goto drop;
-+
-+ /*
-+ * XXX For now we also copy skbuffs whose head crosses a page
-+ * boundary, because netbk_gop_skb can't handle them.
-+ */
-+ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
-+ struct sk_buff *nskb = netbk_copy_skb(skb);
-+ if (unlikely(nskb == NULL))
-+ goto drop;
-+ /* Copy only the header fields we use in this driver. */
-+ nskb->dev = skb->dev;
-+ nskb->ip_summed = skb->ip_summed;
-+ dev_kfree_skb(skb);
-+ skb = nskb;
-+ }
-+
-+ /* Reserve ring slots for the worst-case number of fragments. */
-+ netif->rx_req_cons_peek += count_skb_slots(skb, netif);
-+ netif_get(netif);
-+
-+ if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
-+ netif->rx.sring->req_event = netif->rx_req_cons_peek +
-+ netbk_max_required_rx_slots(netif);
-+ mb(); /* request notification /then/ check & stop the queue */
-+ if (netbk_queue_full(netif))
-+ netif_stop_queue(dev);
-+ }
-+ skb_queue_tail(&netbk->rx_queue, skb);
-+
-+ xen_netbk_bh_handler(netbk, 1);
-+
-+ return 0;
-+
-+ drop:
-+ netif->stats.tx_dropped++;
-+ dev_kfree_skb(skb);
-+ return 0;
-+}
-+
-+struct netrx_pending_operations {
-+ unsigned copy_prod, copy_cons;
-+ unsigned meta_prod, meta_cons;
-+ struct gnttab_copy *copy;
-+ struct netbk_rx_meta *meta;
-+ int copy_off;
-+ grant_ref_t copy_gref;
-+};
-+
-+static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
-+ struct netrx_pending_operations *npo)
-+{
-+ struct netbk_rx_meta *meta;
-+ struct xen_netif_rx_request *req;
-+
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->gso_size = 0;
-+ meta->size = 0;
-+ meta->id = req->id;
-+
-+ npo->copy_off = 0;
-+ npo->copy_gref = req->gref;
-+
-+ return meta;
-+}
-+
-+/*
-+ * 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 netbk_gop_frag_copy(struct xen_netif *netif,
-+ struct netrx_pending_operations *npo,
-+ struct page *page, unsigned long size,
-+ unsigned long offset, int head)
-+{
-+ struct gnttab_copy *copy_gop;
-+ struct netbk_rx_meta *meta;
-+ /*
-+ * These variables a used iff netif_get_page_ext returns true,
-+ * in which case they are guaranteed to be initialized.
-+ */
-+ unsigned int uninitialized_var(group), uninitialized_var(idx);
-+ int foreign = netif_get_page_ext(page, &group, &idx);
-+ unsigned long bytes;
-+
-+ /* Data must not cross a page boundary. */
-+ BUG_ON(size + offset > PAGE_SIZE);
-+
-+ meta = npo->meta + npo->meta_prod - 1;
-+
-+ while (size > 0) {
-+ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
-+
-+ if (start_new_rx_buffer(npo->copy_off, size, head)) {
-+ /*
-+ * Netfront requires there to be some data in the head
-+ * buffer.
-+ */
-+ BUG_ON(head);
-+
-+ meta = get_next_rx_buffer(netif, npo);
-+ }
-+
-+ bytes = size;
-+ if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
-+ bytes = MAX_BUFFER_OFFSET - npo->copy_off;
-+
-+ copy_gop = npo->copy + npo->copy_prod++;
-+ copy_gop->flags = GNTCOPY_dest_gref;
-+ if (foreign) {
-+ struct xen_netbk *netbk = &xen_netbk[group];
-+ struct pending_tx_info *src_pend;
-+
-+ src_pend = &netbk->pending_tx_info[idx];
-+
-+ copy_gop->source.domid = src_pend->netif->domid;
-+ copy_gop->source.u.ref = src_pend->req.gref;
-+ copy_gop->flags |= GNTCOPY_source_gref;
-+ } else {
-+ void *vaddr = page_address(page);
-+ copy_gop->source.domid = DOMID_SELF;
-+ copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
-+ }
-+ copy_gop->source.offset = offset;
-+ copy_gop->dest.domid = netif->domid;
-+
-+ copy_gop->dest.offset = npo->copy_off;
-+ copy_gop->dest.u.ref = npo->copy_gref;
-+ copy_gop->len = bytes;
-+
-+ npo->copy_off += bytes;
-+ meta->size += bytes;
-+
-+ offset += bytes;
-+ size -= bytes;
-+ head = 0; /* There must be something in this buffer now. */
-+ }
-+}
-+
-+/*
-+ * Prepare an SKB to be transmitted to the frontend.
-+ *
-+ * This function is responsible for allocating grant operations, meta
-+ * structures, etc.
-+ *
-+ * It returns the number of meta structures consumed. The number of
-+ * ring slots used is always equal to the number of meta slots used
-+ * plus the number of GSO descriptors used. Currently, we use either
-+ * zero GSO descriptors (for non-GSO packets) or one descriptor (for
-+ * frontend-side LRO).
-+ */
-+static int netbk_gop_skb(struct sk_buff *skb,
-+ struct netrx_pending_operations *npo)
-+{
-+ struct xen_netif *netif = netdev_priv(skb->dev);
-+ int nr_frags = skb_shinfo(skb)->nr_frags;
-+ int i;
-+ struct xen_netif_rx_request *req;
-+ struct netbk_rx_meta *meta;
-+ int old_meta_prod;
-+
-+ old_meta_prod = npo->meta_prod;
-+
-+ /* Set up a GSO prefix descriptor, if necessary */
-+ if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ meta = npo->meta + npo->meta_prod++;
-+ meta->gso_size = skb_shinfo(skb)->gso_size;
-+ meta->size = 0;
-+ meta->id = req->id;
-+ }
-+
-+ req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ meta = npo->meta + npo->meta_prod++;
-+
-+ if (!netif->gso_prefix)
-+ meta->gso_size = skb_shinfo(skb)->gso_size;
-+ else
-+ meta->gso_size = 0;
-+
-+ meta->size = 0;
-+ meta->id = req->id;
-+ npo->copy_off = 0;
-+ npo->copy_gref = req->gref;
-+
-+ netbk_gop_frag_copy(netif,
-+ npo, virt_to_page(skb->data),
-+ skb_headlen(skb),
-+ offset_in_page(skb->data), 1);
-+
-+ /* Leave a gap for the GSO descriptor. */
-+ if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
-+ netif->rx.req_cons++;
-+
-+ for (i = 0; i < nr_frags; i++) {
-+ netbk_gop_frag_copy(netif, npo,
-+ skb_shinfo(skb)->frags[i].page,
-+ skb_shinfo(skb)->frags[i].size,
-+ skb_shinfo(skb)->frags[i].page_offset,
-+ 0);
-+ }
-+
-+ return npo->meta_prod - old_meta_prod;
-+}
-+
-+/*
-+ * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
-+ * used to set up the operations on the top of
-+ * netrx_pending_operations, which have since been done. Check that
-+ * they didn't give any errors and advance over them.
-+ */
-+static int netbk_check_gop(int nr_meta_slots, domid_t domid,
-+ struct netrx_pending_operations *npo)
-+{
-+ struct gnttab_copy *copy_op;
-+ int status = NETIF_RSP_OKAY;
-+ int i;
-+
-+ for (i = 0; i < nr_meta_slots; i++) {
-+ copy_op = npo->copy + npo->copy_cons++;
-+ if (copy_op->status != GNTST_okay) {
-+ pr_debug("Bad status %d from copy to DOM%d.\n",
-+ copy_op->status, domid);
-+ status = NETIF_RSP_ERROR;
-+ }
-+ }
-+
-+ return status;
-+}
-+
-+static void netbk_add_frag_responses(struct xen_netif *netif, int status,
-+ struct netbk_rx_meta *meta,
-+ int nr_meta_slots)
-+{
-+ int i;
-+ unsigned long offset;
-+
-+ /* No fragments used */
-+ if (nr_meta_slots <= 1)
-+ return;
-+
-+ nr_meta_slots--;
-+
-+ for (i = 0; i < nr_meta_slots; i++) {
-+ int flags;
-+ if (i == nr_meta_slots - 1)
-+ flags = 0;
-+ else
-+ flags = NETRXF_more_data;
-+
-+ offset = 0;
-+ make_rx_response(netif, meta[i].id, status, offset,
-+ meta[i].size, flags);
-+ }
-+}
-+
-+struct skb_cb_overlay {
-+ int meta_slots_used;
-+};
-+
-+static void net_rx_action(unsigned long data)
-+{
-+ struct xen_netif *netif = NULL;
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ s8 status;
-+ u16 irq, flags;
-+ struct xen_netif_rx_response *resp;
-+ struct sk_buff_head rxq;
-+ struct sk_buff *skb;
-+ int notify_nr = 0;
-+ int ret;
-+ int nr_frags;
-+ int count;
-+ unsigned long offset;
-+ struct skb_cb_overlay *sco;
-+
-+ struct netrx_pending_operations npo = {
-+ .copy = netbk->grant_copy_op,
-+ .meta = netbk->meta,
-+ };
-+
-+ skb_queue_head_init(&rxq);
-+
-+ count = 0;
-+
-+ while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
-+ netif = netdev_priv(skb->dev);
-+ nr_frags = skb_shinfo(skb)->nr_frags;
-+
-+ sco = (struct skb_cb_overlay *)skb->cb;
-+ sco->meta_slots_used = netbk_gop_skb(skb, &npo);
-+
-+ count += nr_frags + 1;
-+
-+ __skb_queue_tail(&rxq, skb);
-+
-+ /* Filled the batch queue? */
-+ if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
-+ break;
-+ }
-+
-+ BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
-+
-+ if (!npo.copy_prod)
-+ return;
-+
-+ BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
-+ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
-+ npo.copy_prod);
-+ BUG_ON(ret != 0);
-+
-+ while ((skb = __skb_dequeue(&rxq)) != NULL) {
-+ sco = (struct skb_cb_overlay *)skb->cb;
-+
-+ netif = netdev_priv(skb->dev);
-+
-+ if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
-+ resp = RING_GET_RESPONSE(&netif->rx,
-+ netif->rx.rsp_prod_pvt++);
-+
-+ resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
-+
-+ resp->offset = netbk->meta[npo.meta_cons].gso_size;
-+ resp->id = netbk->meta[npo.meta_cons].id;
-+ resp->status = sco->meta_slots_used;
-+
-+ npo.meta_cons++;
-+ sco->meta_slots_used--;
-+ }
-+
-+
-+ netif->stats.tx_bytes += skb->len;
-+ netif->stats.tx_packets++;
-+
-+ status = netbk_check_gop(sco->meta_slots_used,
-+ netif->domid, &npo);
-+
-+ if (sco->meta_slots_used == 1)
-+ flags = 0;
-+ else
-+ flags = NETRXF_more_data;
-+
-+ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
-+ flags |= NETRXF_csum_blank | NETRXF_data_validated;
-+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
-+ /* remote but checksummed. */
-+ flags |= NETRXF_data_validated;
-+
-+ offset = 0;
-+ resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
-+ status, offset,
-+ netbk->meta[npo.meta_cons].size,
-+ flags);
-+
-+ if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
-+ struct xen_netif_extra_info *gso =
-+ (struct xen_netif_extra_info *)
-+ RING_GET_RESPONSE(&netif->rx,
-+ netif->rx.rsp_prod_pvt++);
-+
-+ resp->flags |= NETRXF_extra_info;
-+
-+ gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
-+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
-+ gso->u.gso.pad = 0;
-+ gso->u.gso.features = 0;
-+
-+ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
-+ gso->flags = 0;
-+ }
-+
-+ netbk_add_frag_responses(netif, status,
-+ netbk->meta + npo.meta_cons + 1,
-+ sco->meta_slots_used);
-+
-+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
-+ irq = netif->irq;
-+ if (ret && !netbk->rx_notify[irq]) {
-+ netbk->rx_notify[irq] = 1;
-+ netbk->notify_list[notify_nr++] = irq;
-+ }
-+
-+ if (netif_queue_stopped(netif->dev) &&
-+ netif_schedulable(netif) &&
-+ !netbk_queue_full(netif))
-+ netif_wake_queue(netif->dev);
-+
-+ netif_put(netif);
-+ npo.meta_cons += sco->meta_slots_used;
-+ dev_kfree_skb(skb);
-+ }
-+
-+ while (notify_nr != 0) {
-+ irq = netbk->notify_list[--notify_nr];
-+ netbk->rx_notify[irq] = 0;
-+ notify_remote_via_irq(irq);
-+ }
-+
-+ /* More work to do? */
-+ if (!skb_queue_empty(&netbk->rx_queue) &&
-+ !timer_pending(&netbk->net_timer))
-+ xen_netbk_bh_handler(netbk, 1);
-+}
-+
-+static void net_alarm(unsigned long data)
-+{
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ xen_netbk_bh_handler(netbk, 1);
-+}
-+
-+static void netbk_tx_pending_timeout(unsigned long data)
-+{
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ xen_netbk_bh_handler(netbk, 0);
-+}
-+
-+struct net_device_stats *netif_be_get_stats(struct net_device *dev)
-+{
-+ struct xen_netif *netif = netdev_priv(dev);
-+ return &netif->stats;
-+}
-+
-+static int __on_net_schedule_list(struct xen_netif *netif)
-+{
-+ return !list_empty(&netif->list);
-+}
-+
-+/* Must be called with net_schedule_list_lock held */
-+static void remove_from_net_schedule_list(struct xen_netif *netif)
-+{
-+ if (likely(__on_net_schedule_list(netif))) {
-+ list_del_init(&netif->list);
-+ netif_put(netif);
-+ }
-+}
-+
-+static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
-+{
-+ struct xen_netif *netif = NULL;
-+
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
-+ if (list_empty(&netbk->net_schedule_list))
-+ goto out;
-+
-+ netif = list_first_entry(&netbk->net_schedule_list,
-+ struct xen_netif, list);
-+ if (!netif)
-+ goto out;
-+
-+ netif_get(netif);
-+
-+ remove_from_net_schedule_list(netif);
-+out:
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
-+ return netif;
-+}
-+
-+static void add_to_net_schedule_list_tail(struct xen_netif *netif)
-+{
-+ unsigned long flags;
-+
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
-+ if (__on_net_schedule_list(netif))
-+ return;
-+
-+ spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
-+ if (!__on_net_schedule_list(netif) &&
-+ likely(netif_schedulable(netif))) {
-+ list_add_tail(&netif->list, &netbk->net_schedule_list);
-+ netif_get(netif);
-+ }
-+ spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
-+}
-+
-+void netif_schedule_work(struct xen_netif *netif)
-+{
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
-+ int more_to_do;
-+
-+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-+
-+ if (more_to_do) {
-+ add_to_net_schedule_list_tail(netif);
-+ maybe_schedule_tx_action(netbk);
-+ }
-+}
-+
-+void netif_deschedule_work(struct xen_netif *netif)
-+{
-+ struct xen_netbk *netbk = &xen_netbk[netif->group];
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
-+ remove_from_net_schedule_list(netif);
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
-+}
-+
-+
-+static void tx_add_credit(struct xen_netif *netif)
-+{
-+ unsigned long max_burst, max_credit;
-+
-+ /*
-+ * 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(&netif->tx, netif->tx.req_cons)->size;
-+ max_burst = min(max_burst, 131072UL);
-+ max_burst = max(max_burst, netif->credit_bytes);
-+
-+ /* Take care that adding a new chunk of credit doesn't wrap to zero. */
-+ max_credit = netif->remaining_credit + netif->credit_bytes;
-+ if (max_credit < netif->remaining_credit)
-+ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
-+
-+ netif->remaining_credit = min(max_credit, max_burst);
-+}
-+
-+static void tx_credit_callback(unsigned long data)
-+{
-+ struct xen_netif *netif = (struct xen_netif *)data;
-+ tx_add_credit(netif);
-+ netif_schedule_work(netif);
-+}
-+
-+static inline int copy_pending_req(struct xen_netbk *netbk,
-+ pending_ring_idx_t pending_idx)
-+{
-+ return gnttab_copy_grant_page(
-+ netbk->grant_tx_handle[pending_idx],
-+ &netbk->mmap_pages[pending_idx]);
-+}
-+
-+static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
-+{
-+ struct netbk_tx_pending_inuse *inuse, *n;
-+ struct gnttab_unmap_grant_ref *gop;
-+ u16 pending_idx;
-+ pending_ring_idx_t dc, dp;
-+ struct xen_netif *netif;
-+ int ret;
-+ LIST_HEAD(list);
-+
-+ dc = netbk->dealloc_cons;
-+ gop = netbk->tx_unmap_ops;
-+
-+ /* Free up any grants we have finished using. */
-+ do {
-+ dp = netbk->dealloc_prod;
-+
-+ /* Ensure we see all indices enqueued by netif_idx_release(). */
-+ smp_rmb();
-+
-+ while (dc != dp) {
-+ unsigned long pfn;
-+ struct netbk_tx_pending_inuse *pending_inuse =
-+ netbk->pending_inuse;
-+
-+ pending_idx = netbk->dealloc_ring[pending_index(dc++)];
-+ list_move_tail(&pending_inuse[pending_idx].list, &list);
-+
-+ 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(netbk, pending_idx),
-+ GNTMAP_host_map,
-+ netbk->grant_tx_handle[pending_idx]);
-+ gop++;
-+ }
-+
-+ } while (dp != netbk->dealloc_prod);
-+
-+ netbk->dealloc_cons = dc;
-+
-+ ret = HYPERVISOR_grant_table_op(
-+ GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
-+ gop - netbk->tx_unmap_ops);
-+ BUG_ON(ret);
-+
-+ /*
-+ * Copy any entries that have been pending for too long
-+ */
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !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;
-+ pending_tx_info = netbk->pending_tx_info;
-+
-+ if (time_after(inuse->alloc_time + HZ / 2, jiffies))
-+ break;
-+
-+ pending_idx = inuse - netbk->pending_inuse;
-+
-+ pending_tx_info[pending_idx].netif->nr_copied_skbs++;
-+
-+ switch (copy_pending_req(netbk, pending_idx)) {
-+ case 0:
-+ list_move_tail(&inuse->list, &list);
-+ continue;
-+ case -EBUSY:
-+ list_del_init(&inuse->list);
-+ continue;
-+ case -ENOENT:
-+ continue;
-+ }
-+
-+ break;
-+ }
-+ }
-+
-+ list_for_each_entry_safe(inuse, n, &list, list) {
-+ struct pending_tx_info *pending_tx_info;
-+ pending_ring_idx_t index;
-+
-+ 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(netbk->mmap_pages[pending_idx]);
-+
-+ index = pending_index(netbk->pending_prod++);
-+ netbk->pending_ring[index] = pending_idx;
-+
-+ netif_put(netif);
-+
-+ list_del_init(&inuse->list);
-+ }
-+}
-+
-+static void netbk_tx_err(struct xen_netif *netif,
-+ struct xen_netif_tx_request *txp, RING_IDX end)
-+{
-+ RING_IDX cons = netif->tx.req_cons;
-+
-+ do {
-+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ if (cons >= end)
-+ break;
-+ txp = RING_GET_REQUEST(&netif->tx, cons++);
-+ } while (1);
-+ netif->tx.req_cons = cons;
-+ netif_schedule_work(netif);
-+ netif_put(netif);
-+}
-+
-+static int netbk_count_requests(struct xen_netif *netif,
-+ struct xen_netif_tx_request *first,
-+ struct xen_netif_tx_request *txp,
-+ int work_to_do)
-+{
-+ RING_IDX cons = netif->tx.req_cons;
-+ int frags = 0;
-+
-+ if (!(first->flags & NETTXF_more_data))
-+ return 0;
-+
-+ do {
-+ if (frags >= work_to_do) {
-+ pr_debug("Need more frags\n");
-+ return -frags;
-+ }
-+
-+ if (unlikely(frags >= MAX_SKB_FRAGS)) {
-+ pr_debug("Too many frags\n");
-+ return -frags;
-+ }
-+
-+ memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
-+ sizeof(*txp));
-+ if (txp->size > first->size) {
-+ pr_debug("Frags galore\n");
-+ return -frags;
-+ }
-+
-+ first->size -= txp->size;
-+ frags++;
-+
-+ if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-+ pr_debug("txp->offset: %x, size: %u\n",
-+ txp->offset, txp->size);
-+ return -frags;
-+ }
-+ } while ((txp++)->flags & NETTXF_more_data);
-+
-+ return frags;
-+}
-+
-+static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
-+ struct xen_netif *netif,
-+ struct sk_buff *skb,
-+ struct xen_netif_tx_request *txp,
-+ struct gnttab_map_grant_ref *mop)
-+{
-+ struct skb_shared_info *shinfo = skb_shinfo(skb);
-+ skb_frag_t *frags = shinfo->frags;
-+ unsigned long pending_idx = *((u16 *)skb->data);
-+ int i, start;
-+
-+ /* Skip first skb fragment if it is on same page as header fragment. */
-+ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
-+
-+ for (i = start; i < shinfo->nr_frags; i++, txp++) {
-+ pending_ring_idx_t index;
-+ struct pending_tx_info *pending_tx_info =
-+ netbk->pending_tx_info;
-+
-+ index = pending_index(netbk->pending_cons++);
-+ 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);
-+
-+ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
-+ netif_get(netif);
-+ pending_tx_info[pending_idx].netif = netif;
-+ frags[i].page = (void *)pending_idx;
-+ }
-+
-+ return mop;
-+}
-+
-+static int netbk_tx_check_mop(struct xen_netbk *netbk,
-+ struct sk_buff *skb,
-+ struct gnttab_map_grant_ref **mopp)
-+{
-+ struct gnttab_map_grant_ref *mop = *mopp;
-+ int pending_idx = *((u16 *)skb->data);
-+ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
-+ struct xen_netif *netif = pending_tx_info[pending_idx].netif;
-+ struct xen_netif_tx_request *txp;
-+ struct skb_shared_info *shinfo = skb_shinfo(skb);
-+ int nr_frags = shinfo->nr_frags;
-+ int i, err, start;
-+
-+ /* Check status of header. */
-+ err = mop->status;
-+ if (unlikely(err)) {
-+ pending_ring_idx_t index;
-+ index = pending_index(netbk->pending_prod++);
-+ txp = &pending_tx_info[pending_idx].req;
-+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ netbk->pending_ring[index] = pending_idx;
-+ netif_put(netif);
-+ } else {
-+ set_phys_to_machine(
-+ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
-+ FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
-+ netbk->grant_tx_handle[pending_idx] = mop->handle;
-+ }
-+
-+ /* Skip first skb fragment if it is on same page as header fragment. */
-+ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
-+
-+ 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)) {
-+ unsigned long addr;
-+ addr = idx_to_kaddr(netbk, pending_idx);
-+ set_phys_to_machine(
-+ __pa(addr)>>PAGE_SHIFT,
-+ FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
-+ netbk->grant_tx_handle[pending_idx] = mop->handle;
-+ /* Had a previous error? Invalidate this fragment. */
-+ if (unlikely(err))
-+ netif_idx_release(netbk, pending_idx);
-+ continue;
-+ }
-+
-+ /* Error on this fragment: respond to client with an error. */
-+ txp = &netbk->pending_tx_info[pending_idx].req;
-+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ index = pending_index(netbk->pending_prod++);
-+ netbk->pending_ring[index] = pending_idx;
-+ netif_put(netif);
-+
-+ /* Not the first error? Preceding frags already invalidated. */
-+ if (err)
-+ continue;
-+
-+ /* First error: invalidate header and preceding fragments. */
-+ pending_idx = *((u16 *)skb->data);
-+ netif_idx_release(netbk, pending_idx);
-+ for (j = start; j < i; j++) {
-+ pending_idx = (unsigned long)shinfo->frags[i].page;
-+ netif_idx_release(netbk, pending_idx);
-+ }
-+
-+ /* Remember the error: invalidate all subsequent fragments. */
-+ err = newerr;
-+ }
-+
-+ *mopp = mop + 1;
-+ return err;
-+}
-+
-+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;
-+ int i;
-+
-+ for (i = 0; i < nr_frags; i++) {
-+ skb_frag_t *frag = shinfo->frags + i;
-+ struct xen_netif_tx_request *txp;
-+ unsigned long pending_idx;
-+
-+ pending_idx = (unsigned long)frag->page;
-+
-+ netbk->pending_inuse[pending_idx].alloc_time = jiffies;
-+ list_add_tail(&netbk->pending_inuse[pending_idx].list,
-+ &netbk->pending_inuse_head);
-+
-+ txp = &netbk->pending_tx_info[pending_idx].req;
-+ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
-+ frag->size = txp->size;
-+ frag->page_offset = txp->offset;
-+
-+ skb->len += txp->size;
-+ skb->data_len += txp->size;
-+ skb->truesize += txp->size;
-+ }
-+}
-+
-+int netbk_get_extras(struct xen_netif *netif,
-+ struct xen_netif_extra_info *extras,
-+ int work_to_do)
-+{
-+ struct xen_netif_extra_info extra;
-+ RING_IDX cons = netif->tx.req_cons;
-+
-+ do {
-+ if (unlikely(work_to_do-- <= 0)) {
-+ pr_debug("Missing extra info\n");
-+ return -EBADR;
-+ }
-+
-+ memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
-+ sizeof(extra));
-+ if (unlikely(!extra.type ||
-+ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-+ netif->tx.req_cons = ++cons;
-+ pr_debug("Invalid extra type: %d\n", extra.type);
-+ return -EINVAL;
-+ }
-+
-+ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-+ netif->tx.req_cons = ++cons;
-+ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
-+
-+ return work_to_do;
-+}
-+
-+static int netbk_set_skb_gso(struct sk_buff *skb,
-+ struct xen_netif_extra_info *gso)
-+{
-+ if (!gso->u.gso.size) {
-+ pr_debug("GSO size must not be zero.\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Currently only TCPv4 S.O. is supported. */
-+ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-+ pr_debug("Bad GSO type %d.\n", gso->u.gso.type);
-+ return -EINVAL;
-+ }
-+
-+ skb_shinfo(skb)->gso_size = gso->u.gso.size;
-+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
-+
-+ /* Header must be checked, and gso_segs computed. */
-+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-+ skb_shinfo(skb)->gso_segs = 0;
-+
-+ return 0;
-+}
-+
-+static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
-+{
-+ struct iphdr *iph;
-+ unsigned char *th;
-+ int err = -EPROTO;
-+ int recalculate_partial_csum = 0;
-+
-+ /*
-+ * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
-+ * peers can fail to set NETRXF_csum_blank when sending a GSO
-+ * frame. In this case force the SKB to CHECKSUM_PARTIAL and
-+ * recalculate the partial checksum.
-+ */
-+ if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
-+ netif->rx_gso_checksum_fixup++;
-+ skb->ip_summed = CHECKSUM_PARTIAL;
-+ recalculate_partial_csum = 1;
-+ }
-+
-+ /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
-+ if (skb->ip_summed != CHECKSUM_PARTIAL)
-+ return 0;
-+
-+ if (skb->protocol != htons(ETH_P_IP))
-+ goto out;
-+
-+ iph = (void *)skb->data;
-+ th = skb->data + 4 * iph->ihl;
-+ if (th >= skb_tail_pointer(skb))
-+ goto out;
-+
-+ skb->csum_start = th - skb->head;
-+ switch (iph->protocol) {
-+ case IPPROTO_TCP:
-+ skb->csum_offset = offsetof(struct tcphdr, check);
-+
-+ if (recalculate_partial_csum) {
-+ struct tcphdr *tcph = (struct tcphdr *)th;
-+ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-+ skb->len - iph->ihl*4,
-+ IPPROTO_TCP, 0);
-+ }
-+ break;
-+ case IPPROTO_UDP:
-+ skb->csum_offset = offsetof(struct udphdr, check);
-+
-+ if (recalculate_partial_csum) {
-+ struct udphdr *udph = (struct udphdr *)th;
-+ udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-+ skb->len - iph->ihl*4,
-+ IPPROTO_UDP, 0);
-+ }
-+ break;
-+ default:
-+ if (net_ratelimit())
-+ printk(KERN_ERR "Attempting to checksum a non-"
-+ "TCP/UDP packet, dropping a protocol"
-+ " %d packet", iph->protocol);
-+ goto out;
-+ }
-+
-+ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
-+ goto out;
-+
-+ err = 0;
-+
-+out:
-+ return err;
-+}
-+
-+static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
-+{
-+ unsigned long now = jiffies;
-+ unsigned long next_credit =
-+ netif->credit_timeout.expires +
-+ msecs_to_jiffies(netif->credit_usec / 1000);
-+
-+ /* Timer could already be pending in rare cases. */
-+ if (timer_pending(&netif->credit_timeout))
-+ return true;
-+
-+ /* Passed the point where we can replenish credit? */
-+ if (time_after_eq(now, next_credit)) {
-+ netif->credit_timeout.expires = now;
-+ tx_add_credit(netif);
-+ }
-+
-+ /* Still too big to send right now? Set a callback. */
-+ if (size > netif->remaining_credit) {
-+ netif->credit_timeout.data =
-+ (unsigned long)netif;
-+ netif->credit_timeout.function =
-+ tx_credit_callback;
-+ mod_timer(&netif->credit_timeout,
-+ next_credit);
-+
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static unsigned net_tx_build_mops(struct xen_netbk *netbk)
-+{
-+ struct gnttab_map_grant_ref *mop;
-+ struct sk_buff *skb;
-+ int ret;
-+
-+ mop = netbk->tx_map_ops;
-+ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+ !list_empty(&netbk->net_schedule_list)) {
-+ struct xen_netif *netif;
-+ struct xen_netif_tx_request txreq;
-+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
-+ u16 pending_idx;
-+ RING_IDX idx;
-+ int work_to_do;
-+ unsigned int data_len;
-+ pending_ring_idx_t index;
-+
-+ /* Get a netif from the list with work to do. */
-+ netif = poll_net_schedule_list(netbk);
-+ if (!netif)
-+ continue;
-+
-+ RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
-+ if (!work_to_do) {
-+ netif_put(netif);
-+ continue;
-+ }
-+
-+ idx = netif->tx.req_cons;
-+ rmb(); /* Ensure that we see the request before we copy it. */
-+ memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
-+
-+ /* Credit-based scheduling. */
-+ if (txreq.size > netif->remaining_credit &&
-+ tx_credit_exceeded(netif, txreq.size)) {
-+ netif_put(netif);
-+ continue;
-+ }
-+
-+ netif->remaining_credit -= txreq.size;
-+
-+ work_to_do--;
-+ netif->tx.req_cons = ++idx;
-+
-+ memset(extras, 0, sizeof(extras));
-+ if (txreq.flags & NETTXF_extra_info) {
-+ work_to_do = netbk_get_extras(netif, extras,
-+ work_to_do);
-+ idx = netif->tx.req_cons;
-+ if (unlikely(work_to_do < 0)) {
-+ netbk_tx_err(netif, &txreq, idx);
-+ continue;
-+ }
-+ }
-+
-+ ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
-+ if (unlikely(ret < 0)) {
-+ netbk_tx_err(netif, &txreq, idx - ret);
-+ continue;
-+ }
-+ idx += ret;
-+
-+ if (unlikely(txreq.size < ETH_HLEN)) {
-+ pr_debug("Bad packet size: %d\n", txreq.size);
-+ netbk_tx_err(netif, &txreq, idx);
-+ continue;
-+ }
-+
-+ /* No crossing a page as the payload mustn't fragment. */
-+ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-+ pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
-+ txreq.offset, txreq.size,
-+ (txreq.offset&~PAGE_MASK) + txreq.size);
-+ netbk_tx_err(netif, &txreq, idx);
-+ continue;
-+ }
-+
-+ index = pending_index(netbk->pending_cons);
-+ pending_idx = netbk->pending_ring[index];
-+
-+ data_len = (txreq.size > PKT_PROT_LEN &&
-+ ret < MAX_SKB_FRAGS) ?
-+ PKT_PROT_LEN : txreq.size;
-+
-+ skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
-+ GFP_ATOMIC | __GFP_NOWARN);
-+ if (unlikely(skb == NULL)) {
-+ pr_debug("Can't allocate a skb in start_xmit.\n");
-+ netbk_tx_err(netif, &txreq, idx);
-+ break;
-+ }
-+
-+ /* Packets passed to netif_rx() must have some headroom. */
-+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
-+
-+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
-+ struct xen_netif_extra_info *gso;
-+ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
-+
-+ if (netbk_set_skb_gso(skb, gso)) {
-+ kfree_skb(skb);
-+ netbk_tx_err(netif, &txreq, idx);
-+ continue;
-+ }
-+ }
-+
-+ gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
-+ GNTMAP_host_map | GNTMAP_readonly,
-+ txreq.gref, netif->domid);
-+ mop++;
-+
-+ memcpy(&netbk->pending_tx_info[pending_idx].req,
-+ &txreq, sizeof(txreq));
-+ netbk->pending_tx_info[pending_idx].netif = netif;
-+ *((u16 *)skb->data) = pending_idx;
-+
-+ __skb_put(skb, data_len);
-+
-+ skb_shinfo(skb)->nr_frags = ret;
-+ if (data_len < txreq.size) {
-+ skb_shinfo(skb)->nr_frags++;
-+ skb_shinfo(skb)->frags[0].page =
-+ (void *)(unsigned long)pending_idx;
-+ } else {
-+ /* Discriminate from any valid pending_idx value. */
-+ skb_shinfo(skb)->frags[0].page = (void *)~0UL;
-+ }
-+
-+ __skb_queue_tail(&netbk->tx_queue, skb);
-+
-+ netbk->pending_cons++;
-+
-+ mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
-+
-+ netif->tx.req_cons = idx;
-+ netif_schedule_work(netif);
-+
-+ if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
-+ break;
-+ }
-+
-+ return mop - netbk->tx_map_ops;
-+}
-+
-+static void net_tx_submit(struct xen_netbk *netbk)
-+{
-+ struct gnttab_map_grant_ref *mop;
-+ struct sk_buff *skb;
-+
-+ mop = netbk->tx_map_ops;
-+ while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
-+ struct xen_netif_tx_request *txp;
-+ struct xen_netif *netif;
-+ u16 pending_idx;
-+ unsigned data_len;
-+
-+ pending_idx = *((u16 *)skb->data);
-+ netif = netbk->pending_tx_info[pending_idx].netif;
-+ txp = &netbk->pending_tx_info[pending_idx].req;
-+
-+ /* Check the remap error code. */
-+ if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
-+ pr_debug("netback grant failed.\n");
-+ skb_shinfo(skb)->nr_frags = 0;
-+ kfree_skb(skb);
-+ continue;
-+ }
-+
-+ data_len = skb->len;
-+ memcpy(skb->data,
-+ (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
-+ data_len);
-+ if (data_len < txp->size) {
-+ /* Append the packet payload as a fragment. */
-+ txp->offset += data_len;
-+ txp->size -= data_len;
-+ } else {
-+ /* Schedule a response immediately. */
-+ netif_idx_release(netbk, pending_idx);
-+ }
-+
-+ if (txp->flags & NETTXF_csum_blank)
-+ skb->ip_summed = CHECKSUM_PARTIAL;
-+ else if (txp->flags & NETTXF_data_validated)
-+ skb->ip_summed = CHECKSUM_UNNECESSARY;
-+
-+ netbk_fill_frags(netbk, skb);
-+
-+ /*
-+ * If the initial fragment was < PKT_PROT_LEN then
-+ * pull through some bytes from the other fragments to
-+ * increase the linear region to PKT_PROT_LEN bytes.
-+ */
-+ if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
-+ int target = min_t(int, skb->len, PKT_PROT_LEN);
-+ __pskb_pull_tail(skb, target - skb_headlen(skb));
-+ }
-+
-+ skb->dev = netif->dev;
-+ skb->protocol = eth_type_trans(skb, skb->dev);
-+
-+ if (checksum_setup(netif, skb)) {
-+ pr_debug("Can't setup checksum in net_tx_action\n");
-+ kfree_skb(skb);
-+ continue;
-+ }
-+
-+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
-+ unlikely(skb_linearize(skb))) {
-+ pr_debug("Can't linearize skb in net_tx_action.\n");
-+ kfree_skb(skb);
-+ continue;
-+ }
-+
-+ netif->stats.rx_bytes += skb->len;
-+ netif->stats.rx_packets++;
-+
-+ netif_rx_ni(skb);
-+ netif->dev->last_rx = jiffies;
-+ }
-+}
-+
-+/* Called after netfront has transmitted */
-+static void net_tx_action(unsigned long data)
-+{
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ unsigned nr_mops;
-+ int ret;
-+
-+ net_tx_action_dealloc(netbk);
-+
-+ nr_mops = net_tx_build_mops(netbk);
-+
-+ if (nr_mops == 0)
-+ goto out;
-+
-+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-+ netbk->tx_map_ops, nr_mops);
-+ BUG_ON(ret);
-+
-+ net_tx_submit(netbk);
-+out:
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !list_empty(&netbk->pending_inuse_head)) {
-+ struct netbk_tx_pending_inuse *oldest;
-+
-+ oldest = list_entry(netbk->pending_inuse_head.next,
-+ struct netbk_tx_pending_inuse, list);
-+ mod_timer(&netbk->netbk_tx_pending_timer,
-+ oldest->alloc_time + HZ);
-+ }
-+}
-+
-+static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
-+{
-+ static DEFINE_SPINLOCK(_lock);
-+ unsigned long flags;
-+ pending_ring_idx_t index;
-+
-+ spin_lock_irqsave(&_lock, flags);
-+ index = pending_index(netbk->dealloc_prod);
-+ netbk->dealloc_ring[index] = pending_idx;
-+ /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
-+ smp_wmb();
-+ netbk->dealloc_prod++;
-+ spin_unlock_irqrestore(&_lock, flags);
-+
-+ xen_netbk_bh_handler(netbk, 0);
-+}
-+
-+static void netif_page_release(struct page *page, unsigned int order)
-+{
-+ unsigned int group, idx;
-+ int foreign = netif_get_page_ext(page, &group, &idx);
-+
-+ BUG_ON(!foreign);
-+ BUG_ON(order);
-+
-+ netif_idx_release(&xen_netbk[group], idx);
-+}
-+
-+irqreturn_t netif_be_int(int irq, void *dev_id)
-+{
-+ struct xen_netif *netif = dev_id;
-+ struct xen_netbk *netbk;
-+
-+ if (netif->group == -1)
-+ return IRQ_NONE;
-+
-+ netbk = &xen_netbk[netif->group];
-+
-+ add_to_net_schedule_list_tail(netif);
-+ maybe_schedule_tx_action(netbk);
-+
-+ if (netif_schedulable(netif) && !netbk_queue_full(netif))
-+ netif_wake_queue(netif->dev);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void make_tx_response(struct xen_netif *netif,
-+ struct xen_netif_tx_request *txp,
-+ s8 st)
-+{
-+ RING_IDX i = netif->tx.rsp_prod_pvt;
-+ struct xen_netif_tx_response *resp;
-+ int notify;
-+
-+ resp = RING_GET_RESPONSE(&netif->tx, i);
-+ resp->id = txp->id;
-+ resp->status = st;
-+
-+ if (txp->flags & NETTXF_extra_info)
-+ RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
-+
-+ netif->tx.rsp_prod_pvt = ++i;
-+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
-+ if (notify)
-+ notify_remote_via_irq(netif->irq);
-+}
-+
-+static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
-+ u16 id,
-+ s8 st,
-+ u16 offset,
-+ u16 size,
-+ u16 flags)
-+{
-+ RING_IDX i = netif->rx.rsp_prod_pvt;
-+ struct xen_netif_rx_response *resp;
-+
-+ resp = RING_GET_RESPONSE(&netif->rx, i);
-+ resp->offset = offset;
-+ resp->flags = flags;
-+ resp->id = id;
-+ resp->status = (s16)size;
-+ if (st < 0)
-+ resp->status = (s16)st;
-+
-+ netif->rx.rsp_prod_pvt = ++i;
-+
-+ return resp;
-+}
-+
-+#ifdef NETBE_DEBUG_INTERRUPT
-+static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+ struct list_head *ent;
-+ struct xen_netif *netif;
-+ int i = 0;
-+ int group = 0;
-+
-+ printk(KERN_ALERT "netif_schedule_list:\n");
-+
-+ for (group = 0; group < xen_netbk_group_nr; group++) {
-+ struct xen_netbk *netbk = &xen_netbk[group];
-+ spin_lock_irq(&netbk->net_schedule_list_lock);
-+ printk(KERN_ALERT "xen_netback group number: %d\n", group);
-+ list_for_each(ent, &netbk->net_schedule_list) {
-+ netif = list_entry(ent, struct xen_netif, list);
-+ printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-+ "rx_resp_prod=%08x\n",
-+ i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-+ printk(KERN_ALERT
-+ " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
-+ netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-+ printk(KERN_ALERT
-+ " shared(rx_req_prod=%08x "
-+ "rx_resp_prod=%08x\n",
-+ netif->rx.sring->req_prod,
-+ netif->rx.sring->rsp_prod);
-+ printk(KERN_ALERT
-+ " rx_event=%08x, tx_req_prod=%08x\n",
-+ netif->rx.sring->rsp_event,
-+ netif->tx.sring->req_prod);
-+ printk(KERN_ALERT
-+ " tx_resp_prod=%08x, tx_event=%08x)\n",
-+ netif->tx.sring->rsp_prod,
-+ netif->tx.sring->rsp_event);
-+ i++;
-+ }
-+ spin_unlock_irq(&netbk->net_schedule_list_lock);
-+ }
-+
-+ printk(KERN_ALERT " ** End of netif_schedule_list **\n");
-+
-+ return IRQ_HANDLED;
-+}
-+#endif
-+
-+static inline int rx_work_todo(struct xen_netbk *netbk)
-+{
-+ return !skb_queue_empty(&netbk->rx_queue);
-+}
-+
-+static inline int tx_work_todo(struct xen_netbk *netbk)
-+{
-+ if (netbk->dealloc_cons != netbk->dealloc_prod)
-+ return 1;
-+
-+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+ !list_empty(&netbk->pending_inuse_head))
-+ return 1;
-+
-+ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+ !list_empty(&netbk->net_schedule_list))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+static int netbk_action_thread(void *data)
-+{
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ while (!kthread_should_stop()) {
-+ wait_event_interruptible(netbk->kthread.netbk_action_wq,
-+ rx_work_todo(netbk)
-+ || tx_work_todo(netbk)
-+ || kthread_should_stop());
-+ cond_resched();
-+
-+ if (kthread_should_stop())
-+ break;
-+
-+ if (rx_work_todo(netbk))
-+ net_rx_action((unsigned long)netbk);
-+
-+ if (tx_work_todo(netbk))
-+ net_tx_action((unsigned long)netbk);
-+ }
-+
-+ return 0;
-+}
-+
-+static int __init netback_init(void)
-+{
-+ int i;
-+ struct page *page;
-+ int rc = 0;
-+ int group;
-+
-+ if (!xen_pv_domain())
-+ return -ENODEV;
-+
-+ xen_netbk_group_nr = num_online_cpus();
-+ xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
-+ if (!xen_netbk) {
-+ printk(KERN_ALERT "%s: out of memory\n", __func__);
-+ return -ENOMEM;
-+ }
-+ memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
-+
-+ for (group = 0; group < xen_netbk_group_nr; group++) {
-+ struct xen_netbk *netbk = &xen_netbk[group];
-+ skb_queue_head_init(&netbk->rx_queue);
-+ skb_queue_head_init(&netbk->tx_queue);
-+
-+ init_timer(&netbk->net_timer);
-+ netbk->net_timer.data = (unsigned long)netbk;
-+ netbk->net_timer.function = net_alarm;
-+
-+ init_timer(&netbk->netbk_tx_pending_timer);
-+ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
-+ netbk->netbk_tx_pending_timer.function =
-+ netbk_tx_pending_timeout;
-+
-+ netbk->mmap_pages =
-+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-+ if (!netbk->mmap_pages) {
-+ printk(KERN_ALERT "%s: out of memory\n", __func__);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ 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);
-+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
-+ }
-+
-+ netbk->pending_cons = 0;
-+ netbk->pending_prod = MAX_PENDING_REQS;
-+ for (i = 0; i < MAX_PENDING_REQS; i++)
-+ netbk->pending_ring[i] = i;
-+
-+ if (MODPARM_netback_kthread) {
-+ init_waitqueue_head(&netbk->kthread.netbk_action_wq);
-+ netbk->kthread.task =
-+ kthread_create(netbk_action_thread,
-+ (void *)netbk,
-+ "netback/%u", group);
-+
-+ if (!IS_ERR(netbk->kthread.task)) {
-+ kthread_bind(netbk->kthread.task, group);
-+ } else {
-+ printk(KERN_ALERT
-+ "kthread_run() fails at netback\n");
-+ free_empty_pages_and_pagevec(netbk->mmap_pages,
-+ MAX_PENDING_REQS);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ rc = PTR_ERR(netbk->kthread.task);
-+ goto failed_init;
-+ }
-+ } else {
-+ tasklet_init(&netbk->tasklet.net_tx_tasklet,
-+ net_tx_action,
-+ (unsigned long)netbk);
-+ tasklet_init(&netbk->tasklet.net_rx_tasklet,
-+ net_rx_action,
-+ (unsigned long)netbk);
-+ }
-+
-+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
-+ INIT_LIST_HEAD(&netbk->net_schedule_list);
-+
-+ spin_lock_init(&netbk->net_schedule_list_lock);
-+
-+ atomic_set(&netbk->netfront_count, 0);
-+
-+ if (MODPARM_netback_kthread)
-+ wake_up_process(netbk->kthread.task);
-+ }
-+
-+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
-+ if (MODPARM_copy_skb) {
-+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-+ NULL, 0))
-+ netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
-+ else
-+ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
-+ }
-+
-+ rc = netif_xenbus_init();
-+ if (rc)
-+ goto failed_init;
-+
-+#ifdef NETBE_DEBUG_INTERRUPT
-+ (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-+ 0,
-+ netif_be_dbg,
-+ IRQF_SHARED,
-+ "net-be-dbg",
-+ &netif_be_dbg);
-+#endif
-+
-+ return 0;
-+
-+failed_init:
-+ for (i = 0; i < group; i++) {
-+ struct xen_netbk *netbk = &xen_netbk[i];
-+ free_empty_pages_and_pagevec(netbk->mmap_pages,
-+ MAX_PENDING_REQS);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ if (MODPARM_netback_kthread)
-+ kthread_stop(netbk->kthread.task);
-+ }
-+ vfree(xen_netbk);
-+ return rc;
-+
-+}
-+
-+module_init(netback_init);
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
-new file mode 100644
-index 0000000..867dc25
---- /dev/null
-+++ b/drivers/net/xen-netback/xenbus.c
-@@ -0,0 +1,489 @@
-+/*
-+ * Xenbus code for netif backend
-+ *
-+ * Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
-+ * Copyright (C) 2005 XenSource Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+*/
-+
-+#include "common.h"
-+
-+static int connect_rings(struct backend_info *);
-+static void connect(struct backend_info *);
-+static void backend_create_netif(struct backend_info *be);
-+static void unregister_hotplug_status_watch(struct backend_info *be);
-+
-+static int netback_remove(struct xenbus_device *dev)
-+{
-+ struct backend_info *be = dev_get_drvdata(&dev->dev);
-+
-+ unregister_hotplug_status_watch(be);
-+ if (be->netif) {
-+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-+ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-+ netif_disconnect(be->netif);
-+ be->netif = NULL;
-+ }
-+ kfree(be);
-+ dev_set_drvdata(&dev->dev, NULL);
-+ return 0;
-+}
-+
-+
-+/**
-+ * Entry point to this code when a new device is created. Allocate the basic
-+ * structures and switch to InitWait.
-+ */
-+static int netback_probe(struct xenbus_device *dev,
-+ const struct xenbus_device_id *id)
-+{
-+ const char *message;
-+ struct xenbus_transaction xbt;
-+ int err;
-+ int sg;
-+ struct backend_info *be = kzalloc(sizeof(struct backend_info),
-+ GFP_KERNEL);
-+ if (!be) {
-+ xenbus_dev_fatal(dev, -ENOMEM,
-+ "allocating backend structure");
-+ return -ENOMEM;
-+ }
-+
-+ be->dev = dev;
-+ dev_set_drvdata(&dev->dev, be);
-+
-+ sg = 1;
-+ if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
-+ sg = 0;
-+
-+ do {
-+ err = xenbus_transaction_start(&xbt);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err, "starting transaction");
-+ goto fail;
-+ }
-+
-+ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
sg);
-+ if (err) {
-+ message = "writing feature-sg";
-+ goto abort_transaction;
-+ }
-+
-+ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
-+ "%d", sg);
-+ if (err) {
-+ message = "writing feature-gso-tcpv4";
-+ goto abort_transaction;
-+ }
-+
-+ /* We support rx-copy path. */
-+ err = xenbus_printf(xbt, dev->nodename,
-+ "feature-rx-copy", "%d", 1);
-+ if (err) {
-+ message = "writing feature-rx-copy";
-+ goto abort_transaction;
-+ }
-+
-+ /*
-+ * We don't support rx-flip path (except old guests who don't
-+ * grok this feature flag).
-+ */
-+ err = xenbus_printf(xbt, dev->nodename,
-+ "feature-rx-flip", "%d", 0);
-+ if (err) {
-+ message = "writing feature-rx-flip";
-+ goto abort_transaction;
-+ }
-+
-+ err = xenbus_transaction_end(xbt, 0);
-+ } while (err == -EAGAIN);
-+
-+ if (err) {
-+ xenbus_dev_fatal(dev, err, "completing transaction");
-+ goto fail;
-+ }
-+
-+ err = xenbus_switch_state(dev, XenbusStateInitWait);
-+ if (err)
-+ goto fail;
-+
-+ /* This kicks hotplug scripts, so do it immediately. */
-+ backend_create_netif(be);
-+
-+ return 0;
-+
-+abort_transaction:
-+ xenbus_transaction_end(xbt, 1);
-+ xenbus_dev_fatal(dev, err, "%s", message);
-+fail:
-+ pr_debug("failed");
-+ netback_remove(dev);
-+ return err;
-+}
-+
-+
-+/*
-+ * Handle the creation of the hotplug script environment. We add the script
-+ * and vif variables to the environment, for the benefit of the vif-* hotplug
-+ * scripts.
-+ */
-+static int netback_uevent(struct xenbus_device *xdev,
-+ struct kobj_uevent_env *env)
-+{
-+ struct backend_info *be = dev_get_drvdata(&xdev->dev);
-+ char *val;
-+
-+ val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
-+ if (IS_ERR(val)) {
-+ int err = PTR_ERR(val);
-+ xenbus_dev_fatal(xdev, err, "reading script");
-+ return err;
-+ } else {
-+ if (add_uevent_var(env, "script=%s", val)) {
-+ kfree(val);
-+ return -ENOMEM;
-+ }
-+ kfree(val);
-+ }
-+
-+ if (!be || !be->netif)
-+ return 0;
-+
-+ return add_uevent_var(env, "vif=%s", be->netif->dev->name);
-+}
-+
-+
-+static void backend_create_netif(struct backend_info *be)
-+{
-+ int err;
-+ long handle;
-+ struct xenbus_device *dev = be->dev;
-+
-+ if (be->netif != NULL)
-+ return;
-+
-+ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
-+ if (err != 1) {
-+ xenbus_dev_fatal(dev, err, "reading handle");
-+ return;
-+ }
-+
-+ be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
-+ if (IS_ERR(be->netif)) {
-+ err = PTR_ERR(be->netif);
-+ be->netif = NULL;
-+ xenbus_dev_fatal(dev, err, "creating interface");
-+ return;
-+ }
-+
-+ kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
-+}
-+
-+
-+static void disconnect_backend(struct xenbus_device *dev)
-+{
-+ struct backend_info *be = dev_get_drvdata(&dev->dev);
-+
-+ if (be->netif) {
-+ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-+ netif_disconnect(be->netif);
-+ be->netif = NULL;
-+ }
-+}
-+
-+/**
-+ * Callback received when the frontend's state changes.
-+ */
-+static void frontend_changed(struct xenbus_device *dev,
-+ enum xenbus_state frontend_state)
-+{
-+ struct backend_info *be = dev_get_drvdata(&dev->dev);
-+
-+ pr_debug("frontend state %s", xenbus_strstate(frontend_state));
-+
-+ be->frontend_state = frontend_state;
-+
-+ switch (frontend_state) {
-+ case XenbusStateInitialising:
-+ if (dev->state == XenbusStateClosed) {
-+ printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-+ __func__, dev->nodename);
-+ xenbus_switch_state(dev, XenbusStateInitWait);
-+ }
-+ break;
-+
-+ case XenbusStateInitialised:
-+ break;
-+
-+ case XenbusStateConnected:
-+ if (dev->state == XenbusStateConnected)
-+ break;
-+ backend_create_netif(be);
-+ if (be->netif)
-+ connect(be);
-+ break;
-+
-+ case XenbusStateClosing:
-+ if (be->netif)
-+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-+ disconnect_backend(dev);
-+ xenbus_switch_state(dev, XenbusStateClosing);
-+ break;
-+
-+ case XenbusStateClosed:
-+ xenbus_switch_state(dev, XenbusStateClosed);
-+ if (xenbus_dev_is_online(dev))
-+ break;
-+ /* fall through if not online */
-+ case XenbusStateUnknown:
-+ device_unregister(&dev->dev);
-+ break;
-+
-+ default:
-+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-+ frontend_state);
-+ break;
-+ }
-+}
-+
-+
-+static void xen_net_read_rate(struct xenbus_device *dev,
-+ unsigned long *bytes, unsigned long *usec)
-+{
-+ char *s, *e;
-+ unsigned long b, u;
-+ char *ratestr;
-+
-+ /* Default to unlimited bandwidth. */
-+ *bytes = ~0UL;
-+ *usec = 0;
-+
-+ ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
-+ if (IS_ERR(ratestr))
-+ return;
-+
-+ s = ratestr;
-+ b = simple_strtoul(s, &e, 10);
-+ if ((s == e) || (*e != ','))
-+ goto fail;
-+
-+ s = e + 1;
-+ u = simple_strtoul(s, &e, 10);
-+ if ((s == e) || (*e != '\0'))
-+ goto fail;
-+
-+ *bytes = b;
-+ *usec = u;
-+
-+ kfree(ratestr);
-+ return;
-+
-+ fail:
-+ pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
-+ kfree(ratestr);
-+}
-+
-+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
-+{
-+ char *s, *e, *macstr;
-+ int i;
-+
-+ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
-+ if (IS_ERR(macstr))
-+ return PTR_ERR(macstr);
-+
-+ for (i = 0; i < ETH_ALEN; i++) {
-+ mac[i] = simple_strtoul(s, &e, 16);
-+ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
-+ kfree(macstr);
-+ return -ENOENT;
-+ }
-+ s = e+1;
-+ }
-+
-+ kfree(macstr);
-+ return 0;
-+}
-+
-+static void unregister_hotplug_status_watch(struct backend_info *be)
-+{
-+ if (be->have_hotplug_status_watch) {
-+ unregister_xenbus_watch(&be->hotplug_status_watch);
-+ kfree(be->hotplug_status_watch.node);
-+ }
-+ be->have_hotplug_status_watch = 0;
-+}
-+
-+static void hotplug_status_changed(struct xenbus_watch *watch,
-+ const char **vec,
-+ unsigned int vec_size)
-+{
-+ struct backend_info *be = container_of(watch,
-+ struct backend_info,
-+ hotplug_status_watch);
-+ char *str;
-+ unsigned int len;
-+
-+ str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status",
&len);
-+ if (IS_ERR(str))
-+ return;
-+ if (len == sizeof("connected")-1 && !memcmp(str,
"connected", len)) {
-+ xenbus_switch_state(be->dev, XenbusStateConnected);
-+ /* Not interested in this watch anymore. */
-+ unregister_hotplug_status_watch(be);
-+ }
-+ kfree(str);
-+}
-+
-+static void connect(struct backend_info *be)
-+{
-+ int err;
-+ struct xenbus_device *dev = be->dev;
-+
-+ err = connect_rings(be);
-+ if (err)
-+ return;
-+
-+ err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
-+ return;
-+ }
-+
-+ xen_net_read_rate(dev, &be->netif->credit_bytes,
-+ &be->netif->credit_usec);
-+ be->netif->remaining_credit = be->netif->credit_bytes;
-+
-+ unregister_hotplug_status_watch(be);
-+ err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
-+ hotplug_status_changed,
-+ "%s/%s", dev->nodename, "hotplug-status");
-+ if (err) {
-+ /* Switch now, since we can't do a watch. */
-+ xenbus_switch_state(dev, XenbusStateConnected);
-+ } else {
-+ be->have_hotplug_status_watch = 1;
-+ }
-+
-+ netif_wake_queue(be->netif->dev);
-+}
-+
-+
-+static int connect_rings(struct backend_info *be)
-+{
-+ struct xen_netif *netif = be->netif;
-+ struct xenbus_device *dev = be->dev;
-+ unsigned long tx_ring_ref, rx_ring_ref;
-+ unsigned int evtchn, rx_copy;
-+ int err;
-+ int val;
-+
-+ err = xenbus_gather(XBT_NIL, dev->otherend,
-+ "tx-ring-ref", "%lu", &tx_ring_ref,
-+ "rx-ring-ref", "%lu", &rx_ring_ref,
-+ "event-channel", "%u", &evtchn, NULL);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err,
-+ "reading %s/ring-ref and event-channel",
-+ dev->otherend);
-+ return err;
-+ }
-+
-+ err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy",
"%u",
-+ &rx_copy);
-+ if (err == -ENOENT) {
-+ err = 0;
-+ rx_copy = 0;
-+ }
-+ if (err < 0) {
-+ xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
-+ dev->otherend);
-+ return err;
-+ }
-+ if (!rx_copy)
-+ return -EOPNOTSUPP;
-+
-+ if (netif->dev->tx_queue_len != 0) {
-+ if (xenbus_scanf(XBT_NIL, dev->otherend,
-+ "feature-rx-notify", "%d", &val) < 0)
-+ val = 0;
-+ if (val)
-+ netif->can_queue = 1;
-+ else
-+ /* Must be non-zero for pfifo_fast to work. */
-+ netif->dev->tx_queue_len = 1;
-+ }
-+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
-+ "%d", &val) < 0)
-+ val = 0;
-+ netif->can_sg = !!val;
-+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
-+ "%d", &val) < 0)
-+ val = 0;
-+ netif->gso = !!val;
-+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
-+ "%d", &val) < 0)
-+ val = 0;
-+ netif->gso_prefix = !!val;
-+
-+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
-+ "%d", &val) < 0)
-+ val = 0;
-+ netif->csum = !val;
-+
-+ /* Set dev->features */
-+ netif_set_features(netif);
-+
-+ /* Map the shared frame, irq etc. */
-+ err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
-+ if (err) {
-+ xenbus_dev_fatal(dev, err,
-+ "mapping shared-frames %lu/%lu port %u",
-+ tx_ring_ref, rx_ring_ref, evtchn);
-+ return err;
-+ }
-+ return 0;
-+}
-+
-+
-+/* ** Driver Registration ** */
-+
-+
-+static const struct xenbus_device_id netback_ids[] = {
-+ { "vif" },
-+ { "" }
-+};
-+
-+
-+static struct xenbus_driver netback = {
-+ .name = "vif",
-+ .owner = THIS_MODULE,
-+ .ids = netback_ids,
-+ .probe = netback_probe,
-+ .remove = netback_remove,
-+ .uevent = netback_uevent,
-+ .otherend_changed = frontend_changed,
-+};
-+
-+
-+int netif_xenbus_init(void)
-+{
-+ printk(KERN_CRIT "registering netback\n");
-+ return xenbus_register_backend(&netback);
-+}
-diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
-index 30290a8..5a48ce9 100644
---- a/drivers/xen/Kconfig
-+++ b/drivers/xen/Kconfig
-@@ -37,13 +37,6 @@ config XEN_BACKEND
- depends on XEN_PCIDEV_BACKEND
-
-
--config XEN_NETDEV_BACKEND
-- tristate "Xen backend network device"
-- depends on XEN_BACKEND && NET
-- help
-- Implement the network backend driver, which passes packets
-- from the guest domain's frontend drivers to the network.
+-extern struct xen_netbk *xen_netbk;
+-extern int xen_netbk_group_nr;
+-
+-#endif /* __NETIF__BACKEND__COMMON_H__ */
+diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
+deleted file mode 100644
+index b429f8c..0000000
+--- a/drivers/xen/netback/interface.c
++++ /dev/null
+@@ -1,470 +0,0 @@
+-/*
+- * Network-device interface management.
+- *
+- * Copyright (c) 2004-2005, Keir Fraser
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License version 2
+- * as published by the Free Software Foundation; or, when distributed
+- * separately from the Linux kernel or incorporated into other
+- * software packages, subject to the following license:
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining a copy
+- * of this source file (the "Software"), to deal in the Software without
+- * restriction, including without limitation the rights to use, copy, modify,
+- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+- * and to permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be included in
+- * all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+- * IN THE SOFTWARE.
+- */
+-
+-#include "common.h"
+-
+-#include <linux/ethtool.h>
+-#include <linux/rtnetlink.h>
+-
+-#include <xen/events.h>
+-#include <asm/xen/hypercall.h>
+-
+-/*
+- * Module parameter 'queue_length':
+- *
+- * Enables queuing in the network stack when a client has run out of receive
+- * descriptors.
+- */
+-static unsigned long netbk_queue_length = 32;
+-module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+-
+-static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
+- struct xen_netif *netif)
+-{
+- int i;
+- int min_netfront_count;
+- int min_group = 0;
+- min_netfront_count = atomic_read(&netbk[0].netfront_count);
+- for (i = 0; i < group_nr; i++) {
+- int netfront_count = atomic_read(&netbk[i].netfront_count);
+- if (netfront_count < min_netfront_count) {
+- min_group = i;
+- min_netfront_count = netfront_count;
+- }
+- }
+-
+- netif->group = min_group;
+- atomic_inc(&netbk[netif->group].netfront_count);
+-}
+-
+-static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
+-{
+- atomic_dec(&netbk[netif->group].netfront_count);
+-}
+-
+-static void __netif_up(struct xen_netif *netif)
+-{
+- netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
+- enable_irq(netif->irq);
+- netif_schedule_work(netif);
+-}
+-
+-static void __netif_down(struct xen_netif *netif)
+-{
+- disable_irq(netif->irq);
+- netif_deschedule_work(netif);
+- netbk_remove_netif(xen_netbk, netif);
+-}
+-
+-static int net_open(struct net_device *dev)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- if (netback_carrier_ok(netif)) {
+- __netif_up(netif);
+- netif_start_queue(dev);
+- }
+- return 0;
+-}
+-
+-static int net_close(struct net_device *dev)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- if (netback_carrier_ok(netif))
+- __netif_down(netif);
+- netif_stop_queue(dev);
+- return 0;
+-}
+-
+-static int netbk_change_mtu(struct net_device *dev, int mtu)
+-{
+- int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+-
+- if (mtu > max)
+- return -EINVAL;
+- dev->mtu = mtu;
+- return 0;
+-}
+-
+-void netif_set_features(struct xen_netif *netif)
+-{
+- struct net_device *dev = netif->dev;
+- int features = dev->features;
+-
+- if (netif->can_sg)
+- features |= NETIF_F_SG;
+- if (netif->gso || netif->gso_prefix)
+- features |= NETIF_F_TSO;
+- if (netif->csum)
+- features |= NETIF_F_IP_CSUM;
+-
+- features &= ~(netif->features_disabled);
+-
+- if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
+- dev->mtu = ETH_DATA_LEN;
+-
+- dev->features = features;
+-}
+-
+-static int netbk_set_tx_csum(struct net_device *dev, u32 data)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- if (data) {
+- if (!netif->csum)
+- return -ENOSYS;
+- netif->features_disabled &= ~NETIF_F_IP_CSUM;
+- } else {
+- netif->features_disabled |= NETIF_F_IP_CSUM;
+- }
+-
+- netif_set_features(netif);
+- return 0;
+-}
+-
+-static int netbk_set_sg(struct net_device *dev, u32 data)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- if (data) {
+- if (!netif->can_sg)
+- return -ENOSYS;
+- netif->features_disabled &= ~NETIF_F_SG;
+- } else {
+- netif->features_disabled |= NETIF_F_SG;
+- }
+-
+- netif_set_features(netif);
+- return 0;
+-}
+-
+-static int netbk_set_tso(struct net_device *dev, u32 data)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- if (data) {
+- if (!netif->gso && !netif->gso_prefix)
+- return -ENOSYS;
+- netif->features_disabled &= ~NETIF_F_TSO;
+- } else {
+- netif->features_disabled |= NETIF_F_TSO;
+- }
+-
+- netif_set_features(netif);
+- return 0;
+-}
+-
+-static void netbk_get_drvinfo(struct net_device *dev,
+- struct ethtool_drvinfo *info)
+-{
+- strcpy(info->driver, "netbk");
+- strcpy(info->bus_info, dev_name(dev->dev.parent));
+-}
+-
+-static const struct netif_stat {
+- char name[ETH_GSTRING_LEN];
+- u16 offset;
+-} netbk_stats[] = {
+- {
+- "copied_skbs",
+- offsetof(struct xen_netif, nr_copied_skbs)
+- },
+- {
+- "rx_gso_checksum_fixup",
+- offsetof(struct xen_netif, rx_gso_checksum_fixup)
+- },
+-};
+-
+-static int netbk_get_sset_count(struct net_device *dev, int string_set)
+-{
+- switch (string_set) {
+- case ETH_SS_STATS:
+- return ARRAY_SIZE(netbk_stats);
+- default:
+- return -EINVAL;
+- }
+-}
+-
+-static void netbk_get_ethtool_stats(struct net_device *dev,
+- struct ethtool_stats *stats, u64 * data)
+-{
+- void *netif = netdev_priv(dev);
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
+- data[i] = *(int *)(netif + netbk_stats[i].offset);
+-}
+-
+-static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+-{
+- int i;
+-
+- switch (stringset) {
+- case ETH_SS_STATS:
+- for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
+- memcpy(data + i * ETH_GSTRING_LEN,
+- netbk_stats[i].name, ETH_GSTRING_LEN);
+- break;
+- }
+-}
+-
+-static struct ethtool_ops network_ethtool_ops = {
+- .get_drvinfo = netbk_get_drvinfo,
+-
+- .get_tx_csum = ethtool_op_get_tx_csum,
+- .set_tx_csum = netbk_set_tx_csum,
+- .get_sg = ethtool_op_get_sg,
+- .set_sg = netbk_set_sg,
+- .get_tso = ethtool_op_get_tso,
+- .set_tso = netbk_set_tso,
+- .get_link = ethtool_op_get_link,
+-
+- .get_sset_count = netbk_get_sset_count,
+- .get_ethtool_stats = netbk_get_ethtool_stats,
+- .get_strings = netbk_get_strings,
+-};
+-
+-static struct net_device_ops netback_ops = {
+- .ndo_start_xmit = netif_be_start_xmit,
+- .ndo_get_stats = netif_be_get_stats,
+- .ndo_open = net_open,
+- .ndo_stop = net_close,
+- .ndo_change_mtu = netbk_change_mtu,
+-};
+-
+-struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
+- unsigned int handle)
+-{
+- int err = 0;
+- struct net_device *dev;
+- struct xen_netif *netif;
+- char name[IFNAMSIZ] = {};
+-
+- snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
+- dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
+- if (dev == NULL) {
+- pr_debug("Could not allocate netdev\n");
+- return ERR_PTR(-ENOMEM);
+- }
+-
+- SET_NETDEV_DEV(dev, parent);
+-
+- netif = netdev_priv(dev);
+- memset(netif, 0, sizeof(*netif));
+- netif->domid = domid;
+- netif->group = -1;
+- netif->handle = handle;
+- netif->can_sg = 1;
+- netif->csum = 1;
+- atomic_set(&netif->refcnt, 1);
+- init_waitqueue_head(&netif->waiting_to_free);
+- netif->dev = dev;
+- INIT_LIST_HEAD(&netif->list);
+-
+- netback_carrier_off(netif);
+-
+- netif->credit_bytes = netif->remaining_credit = ~0UL;
+- netif->credit_usec = 0UL;
+- init_timer(&netif->credit_timeout);
+- /* Initialize 'expires' now: it's used to track the credit window. */
+- netif->credit_timeout.expires = jiffies;
+-
+- dev->netdev_ops = &netback_ops;
+- netif_set_features(netif);
+- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+-
+- dev->tx_queue_len = netbk_queue_length;
+-
+- /*
+- * Initialise a dummy MAC address. We choose the numerically
+- * largest non-broadcast address to prevent the address getting
+- * stolen by an Ethernet bridge for STP purposes.
+- * (FE:FF:FF:FF:FF:FF)
+- */
+- memset(dev->dev_addr, 0xFF, ETH_ALEN);
+- dev->dev_addr[0] &= ~0x01;
+-
+- rtnl_lock();
+- err = register_netdevice(dev);
+- rtnl_unlock();
+- if (err) {
+- pr_debug("Could not register new net device %s: err=%d\n",
+- dev->name, err);
+- free_netdev(dev);
+- return ERR_PTR(err);
+- }
+-
+- pr_debug("Successfully created netif\n");
+- return netif;
+-}
+-
+-static int map_frontend_pages(struct xen_netif *netif,
+- grant_ref_t tx_ring_ref,
+- grant_ref_t rx_ring_ref)
+-{
+- struct gnttab_map_grant_ref op;
+-
+- gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
+- GNTMAP_host_map, tx_ring_ref, netif->domid);
+-
+- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+- BUG();
+-
+- if (op.status) {
+- pr_debug("Gnttab failure mapping tx_ring_ref!\n");
+- return op.status;
+- }
+-
+- netif->tx_shmem_ref = tx_ring_ref;
+- netif->tx_shmem_handle = op.handle;
+-
+- gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
+- GNTMAP_host_map, rx_ring_ref, netif->domid);
+-
+- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+- BUG();
+-
+- if (op.status) {
+- struct gnttab_unmap_grant_ref unop;
+-
+- gnttab_set_unmap_op(&unop,
+- (unsigned long)netif->tx_comms_area->addr,
+- GNTMAP_host_map, netif->tx_shmem_handle);
+- HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
+- pr_debug("Gnttab failure mapping rx_ring_ref!\n");
+- return op.status;
+- }
+-
+- netif->rx_shmem_ref = rx_ring_ref;
+- netif->rx_shmem_handle = op.handle;
+-
+- return 0;
+-}
+-
+-static void unmap_frontend_pages(struct xen_netif *netif)
+-{
+- struct gnttab_unmap_grant_ref op;
+-
+- gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
+- GNTMAP_host_map, netif->tx_shmem_handle);
+-
+- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+- BUG();
+-
+- gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
+- GNTMAP_host_map, netif->rx_shmem_handle);
+-
+- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+- BUG();
+-}
+-
+-int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+- unsigned long rx_ring_ref, unsigned int evtchn)
+-{
+- int err = -ENOMEM;
+- struct xen_netif_tx_sring *txs;
+- struct xen_netif_rx_sring *rxs;
+-
+- /* Already connected through? */
+- if (netif->irq)
+- return 0;
+-
+- netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
+- if (netif->tx_comms_area == NULL)
+- return -ENOMEM;
+- netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
+- if (netif->rx_comms_area == NULL)
+- goto err_rx;
+-
+- err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
+- if (err)
+- goto err_map;
+-
+- err = bind_interdomain_evtchn_to_irqhandler(
+- netif->domid, evtchn, netif_be_int, 0,
+- netif->dev->name, netif);
+- if (err < 0)
+- goto err_hypervisor;
+- netif->irq = err;
+- disable_irq(netif->irq);
+-
+- txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
+- BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
+-
+- rxs = (struct xen_netif_rx_sring *)
+- ((char *)netif->rx_comms_area->addr);
+- BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
+-
+- netif->rx_req_cons_peek = 0;
+-
+- netif_get(netif);
+-
+- rtnl_lock();
+- netback_carrier_on(netif);
+- if (netif_running(netif->dev))
+- __netif_up(netif);
+- rtnl_unlock();
+-
+- return 0;
+-err_hypervisor:
+- unmap_frontend_pages(netif);
+-err_map:
+- free_vm_area(netif->rx_comms_area);
+-err_rx:
+- free_vm_area(netif->tx_comms_area);
+- return err;
+-}
+-
+-void netif_disconnect(struct xen_netif *netif)
+-{
+- if (netback_carrier_ok(netif)) {
+- rtnl_lock();
+- netback_carrier_off(netif);
+- netif_carrier_off(netif->dev); /* discard queued packets */
+- if (netif_running(netif->dev))
+- __netif_down(netif);
+- rtnl_unlock();
+- netif_put(netif);
+- }
+-
+- atomic_dec(&netif->refcnt);
+- wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
+-
+- del_timer_sync(&netif->credit_timeout);
+-
+- if (netif->irq)
+- unbind_from_irqhandler(netif->irq, netif);
+-
+- unregister_netdev(netif->dev);
+-
+- if (netif->tx.sring) {
+- unmap_frontend_pages(netif);
+- free_vm_area(netif->tx_comms_area);
+- free_vm_area(netif->rx_comms_area);
+- }
+-
+- free_netdev(netif->dev);
+-}
+diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
+deleted file mode 100644
+index b290525..0000000
+--- a/drivers/xen/netback/netback.c
++++ /dev/null
+@@ -1,1934 +0,0 @@
+-/*
+- * Back-end of the driver for virtual network devices. This portion of the
+- * driver exports a 'unified' network-device interface that can be accessed
+- * by any operating system that implements a compatible front end. A
+- * reference front-end implementation can be found in:
+- * drivers/net/xen-netfront.c
+- *
+- * Copyright (c) 2002-2005, K A Fraser
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License version 2
+- * as published by the Free Software Foundation; or, when distributed
+- * separately from the Linux kernel or incorporated into other
+- * software packages, subject to the following license:
+- *
+- * Permission is hereby granted, free of charge, to any person obtaining a copy
+- * of this source file (the "Software"), to deal in the Software without
+- * restriction, including without limitation the rights to use, copy, modify,
+- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+- * and to permit persons to whom the Software is furnished to do so, subject to
+- * the following conditions:
+- *
+- * The above copyright notice and this permission notice shall be included in
+- * all copies or substantial portions of the Software.
+- *
+- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+- * IN THE SOFTWARE.
+- */
+-
+-#include "common.h"
+-
+-#include <linux/kthread.h>
+-#include <linux/if_vlan.h>
+-#include <linux/udp.h>
+-
+-#include <net/tcp.h>
+-
+-#include <xen/balloon.h>
+-#include <xen/events.h>
+-#include <xen/interface/memory.h>
+-
+-#include <asm/xen/hypercall.h>
+-#include <asm/xen/page.h>
+-
+-/*define NETBE_DEBUG_INTERRUPT*/
+-
+-struct xen_netbk *xen_netbk;
+-int xen_netbk_group_nr;
+-
+-static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+-static void make_tx_response(struct xen_netif *netif,
+- struct xen_netif_tx_request *txp,
+- s8 st);
+-static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
+- u16 id,
+- s8 st,
+- u16 offset,
+- u16 size,
+- u16 flags);
+-
+-static void net_tx_action(unsigned long data);
+-
+-static void net_rx_action(unsigned long data);
+-
+-static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
+- unsigned int idx)
+-{
+- return page_to_pfn(netbk->mmap_pages[idx]);
+-}
+-
+-static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
+- unsigned int idx)
+-{
+- return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
+-}
+-
+-/* extra field used in struct page */
+-static inline void netif_set_page_ext(struct page *pg,
+- unsigned int group, unsigned int idx)
+-{
+- union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
+-
+- BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
+- pg->mapping = ext.mapping;
+-}
+-
+-static int netif_get_page_ext(struct page *pg,
+- unsigned int *_group, unsigned int *_idx)
+-{
+- union page_ext ext = { .mapping = pg->mapping };
+- struct xen_netbk *netbk;
+- unsigned int group, idx;
+-
+- if (!PageForeign(pg))
+- return 0;
+-
+- group = ext.e.group - 1;
+-
+- if (group < 0 || group >= xen_netbk_group_nr)
+- return 0;
+-
+- netbk = &xen_netbk[group];
+-
+- if (netbk->mmap_pages == NULL)
+- return 0;
+-
+- idx = ext.e.idx;
+-
+- if ((idx < 0) || (idx >= MAX_PENDING_REQS))
+- return 0;
+-
+- if (netbk->mmap_pages[idx] != pg)
+- return 0;
+-
+- *_group = group;
+- *_idx = idx;
+-
+- return 1;
+-}
+-
+-/*
+- * This is the amount of packet we copy rather than map, so that the
+- * guest can't fiddle with the contents of the headers while we do
+- * packet processing on them (netfilter, routing, etc).
+- */
+-#define PKT_PROT_LEN (ETH_HLEN + \
+- VLAN_HLEN + \
+- sizeof(struct iphdr) + MAX_IPOPTLEN + \
+- sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
+-
+-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 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;
+-module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
+-MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
+-
+-int netbk_copy_skb_mode;
+-
+-static int MODPARM_netback_kthread;
+-module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
+-MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
+-
+-/*
+- * Netback bottom half handler.
+- * dir indicates the data direction.
+- * rx: 1, tx: 0.
+- */
+-static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
+-{
+- if (MODPARM_netback_kthread)
+- wake_up(&netbk->kthread.netbk_action_wq);
+- else if (dir)
+- tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
+- else
+- tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
+-}
+-
+-static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
+-{
+- smp_mb();
+- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
+- !list_empty(&netbk->net_schedule_list))
+- xen_netbk_bh_handler(netbk, 0);
+-}
+-
+-static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+-{
+- struct skb_shared_info *ninfo;
+- struct sk_buff *nskb;
+- unsigned long offset;
+- int ret;
+- int len;
+- int headlen;
+-
+- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
+-
+- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
+- if (unlikely(!nskb))
+- goto err;
+-
+- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
+- headlen = skb_end_pointer(nskb) - nskb->data;
+- if (headlen > skb_headlen(skb))
+- headlen = skb_headlen(skb);
+- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
+- BUG_ON(ret);
+-
+- ninfo = skb_shinfo(nskb);
+- ninfo->gso_size = skb_shinfo(skb)->gso_size;
+- ninfo->gso_type = skb_shinfo(skb)->gso_type;
+-
+- offset = headlen;
+- len = skb->len - headlen;
+-
+- nskb->len = skb->len;
+- nskb->data_len = len;
+- nskb->truesize += len;
+-
+- while (len) {
+- struct page *page;
+- int copy;
+- int zero;
+-
+- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
+- dump_stack();
+- goto err_free;
+- }
+-
+- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
+- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
+-
+- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
+- if (unlikely(!page))
+- goto err_free;
+-
+- ret = skb_copy_bits(skb, offset, page_address(page), copy);
+- BUG_ON(ret);
+-
+- ninfo->frags[ninfo->nr_frags].page = page;
+- ninfo->frags[ninfo->nr_frags].page_offset = 0;
+- ninfo->frags[ninfo->nr_frags].size = copy;
+- ninfo->nr_frags++;
+-
+- offset += copy;
+- len -= copy;
+- }
+-
+-#ifdef NET_SKBUFF_DATA_USES_OFFSET
+- offset = 0;
+-#else
+- offset = nskb->data - skb->data;
+-#endif
+-
+- nskb->transport_header = skb->transport_header + offset;
+- nskb->network_header = skb->network_header + offset;
+- nskb->mac_header = skb->mac_header + offset;
+-
+- return nskb;
+-
+- err_free:
+- kfree_skb(nskb);
+- err:
+- return NULL;
+-}
+-
+-static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
+-{
+- if (netif->can_sg || netif->gso || netif->gso_prefix)
+- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
+- return 1; /* all in one */
+-}
+-
+-static inline int netbk_queue_full(struct xen_netif *netif)
+-{
+- RING_IDX peek = netif->rx_req_cons_peek;
+- RING_IDX needed = netbk_max_required_rx_slots(netif);
+-
+- return ((netif->rx.sring->req_prod - peek) < needed) ||
+- ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
+-}
+-
+-/*
+- * Returns true if we should start a new receive buffer instead of
+- * adding 'size' bytes to a buffer which currently contains 'offset'
+- * bytes.
+- */
+-static bool start_new_rx_buffer(int offset, unsigned long size, int head)
+-{
+- /* simple case: we have completely filled the current buffer. */
+- if (offset == MAX_BUFFER_OFFSET)
+- return true;
+-
+- /*
+- * complex case: start a fresh buffer if the current frag
+- * would overflow the current buffer but only if:
+- * (i) this frag would fit completely in the next buffer
+- * and (ii) there is already some data in the current buffer
+- * and (iii) this is not the head buffer.
+- *
+- * Where:
+- * - (i) stops us splitting a frag into two copies
+- * unless the frag is too large for a single buffer.
+- * - (ii) stops us from leaving a buffer pointlessly empty.
+- * - (iii) stops us leaving the first buffer
+- * empty. Strictly speaking this is already covered
+- * by (ii) but is explicitly checked because
+- * netfront relies on the first buffer being
+- * non-empty and can crash otherwise.
+- *
+- * This means we will effectively linearise small
+- * frags but do not needlessly split large buffers
+- * into multiple copies tend to give large frags their
+- * own buffers as before.
+- */
+- if ((offset + size > MAX_BUFFER_OFFSET) &&
+- (size <= MAX_BUFFER_OFFSET) && offset && !head)
+- return true;
+-
+- return false;
+-}
+-
+-/*
+- * Figure out how many ring slots we're going to need to send @skb to
+- * the guest. This function is essentially a dry run of
+- * netbk_gop_frag_copy.
+- */
+-static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
+-{
+- unsigned int count = 1;
+- int i, copy_off = 0;
+-
+- BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
+-
+- copy_off = skb_headlen(skb);
+-
+- if (skb_shinfo(skb)->gso_size)
+- count++;
+-
+- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+- unsigned long size = skb_shinfo(skb)->frags[i].size;
+- unsigned long bytes;
+- while (size > 0) {
+- BUG_ON(copy_off > MAX_BUFFER_OFFSET);
+-
+- if (start_new_rx_buffer(copy_off, size, 0)) {
+- count++;
+- copy_off = 0;
+- }
+-
+- bytes = size;
+- if (copy_off + bytes > MAX_BUFFER_OFFSET)
+- bytes = MAX_BUFFER_OFFSET - copy_off;
+-
+- copy_off += bytes;
+- size -= bytes;
+- }
+- }
+- return count;
+-}
+-
+-int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- struct xen_netbk *netbk;
+-
+- BUG_ON(skb->dev != dev);
+-
+- if (netif->group == -1)
+- goto drop;
+-
+- netbk = &xen_netbk[netif->group];
+-
+- /* Drop the packet if the target domain has no receive buffers. */
+- if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
+- goto drop;
+-
+- /*
+- * XXX For now we also copy skbuffs whose head crosses a page
+- * boundary, because netbk_gop_skb can't handle them.
+- */
+- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
+- struct sk_buff *nskb = netbk_copy_skb(skb);
+- if (unlikely(nskb == NULL))
+- goto drop;
+- /* Copy only the header fields we use in this driver. */
+- nskb->dev = skb->dev;
+- nskb->ip_summed = skb->ip_summed;
+- dev_kfree_skb(skb);
+- skb = nskb;
+- }
+-
+- /* Reserve ring slots for the worst-case number of fragments. */
+- netif->rx_req_cons_peek += count_skb_slots(skb, netif);
+- netif_get(netif);
+-
+- if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
+- netif->rx.sring->req_event = netif->rx_req_cons_peek +
+- netbk_max_required_rx_slots(netif);
+- mb(); /* request notification /then/ check & stop the queue */
+- if (netbk_queue_full(netif))
+- netif_stop_queue(dev);
+- }
+- skb_queue_tail(&netbk->rx_queue, skb);
+-
+- xen_netbk_bh_handler(netbk, 1);
+-
+- return 0;
+-
+- drop:
+- netif->stats.tx_dropped++;
+- dev_kfree_skb(skb);
+- return 0;
+-}
+-
+-struct netrx_pending_operations {
+- unsigned copy_prod, copy_cons;
+- unsigned meta_prod, meta_cons;
+- struct gnttab_copy *copy;
+- struct netbk_rx_meta *meta;
+- int copy_off;
+- grant_ref_t copy_gref;
+-};
+-
+-static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
+- struct netrx_pending_operations *npo)
+-{
+- struct netbk_rx_meta *meta;
+- struct xen_netif_rx_request *req;
+-
+- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+-
+- meta = npo->meta + npo->meta_prod++;
+- meta->gso_size = 0;
+- meta->size = 0;
+- meta->id = req->id;
+-
+- npo->copy_off = 0;
+- npo->copy_gref = req->gref;
+-
+- return meta;
+-}
+-
+-/*
+- * 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 netbk_gop_frag_copy(struct xen_netif *netif,
+- struct netrx_pending_operations *npo,
+- struct page *page, unsigned long size,
+- unsigned long offset, int head)
+-{
+- struct gnttab_copy *copy_gop;
+- struct netbk_rx_meta *meta;
+- /*
+- * These variables a used iff netif_get_page_ext returns true,
+- * in which case they are guaranteed to be initialized.
+- */
+- unsigned int uninitialized_var(group), uninitialized_var(idx);
+- int foreign = netif_get_page_ext(page, &group, &idx);
+- unsigned long bytes;
+-
+- /* Data must not cross a page boundary. */
+- BUG_ON(size + offset > PAGE_SIZE);
+-
+- meta = npo->meta + npo->meta_prod - 1;
+-
+- while (size > 0) {
+- BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
+-
+- if (start_new_rx_buffer(npo->copy_off, size, head)) {
+- /*
+- * Netfront requires there to be some data in the head
+- * buffer.
+- */
+- BUG_ON(head);
+-
+- meta = get_next_rx_buffer(netif, npo);
+- }
+-
+- bytes = size;
+- if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
+- bytes = MAX_BUFFER_OFFSET - npo->copy_off;
+-
+- copy_gop = npo->copy + npo->copy_prod++;
+- copy_gop->flags = GNTCOPY_dest_gref;
+- if (foreign) {
+- struct xen_netbk *netbk = &xen_netbk[group];
+- struct pending_tx_info *src_pend;
+-
+- src_pend = &netbk->pending_tx_info[idx];
+-
+- copy_gop->source.domid = src_pend->netif->domid;
+- copy_gop->source.u.ref = src_pend->req.gref;
+- copy_gop->flags |= GNTCOPY_source_gref;
+- } else {
+- void *vaddr = page_address(page);
+- copy_gop->source.domid = DOMID_SELF;
+- copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
+- }
+- copy_gop->source.offset = offset;
+- copy_gop->dest.domid = netif->domid;
+-
+- copy_gop->dest.offset = npo->copy_off;
+- copy_gop->dest.u.ref = npo->copy_gref;
+- copy_gop->len = bytes;
+-
+- npo->copy_off += bytes;
+- meta->size += bytes;
+-
+- offset += bytes;
+- size -= bytes;
+- head = 0; /* There must be something in this buffer now. */
+- }
+-}
+-
+-/*
+- * Prepare an SKB to be transmitted to the frontend.
+- *
+- * This function is responsible for allocating grant operations, meta
+- * structures, etc.
+- *
+- * It returns the number of meta structures consumed. The number of
+- * ring slots used is always equal to the number of meta slots used
+- * plus the number of GSO descriptors used. Currently, we use either
+- * zero GSO descriptors (for non-GSO packets) or one descriptor (for
+- * frontend-side LRO).
+- */
+-static int netbk_gop_skb(struct sk_buff *skb,
+- struct netrx_pending_operations *npo)
+-{
+- struct xen_netif *netif = netdev_priv(skb->dev);
+- int nr_frags = skb_shinfo(skb)->nr_frags;
+- int i;
+- struct xen_netif_rx_request *req;
+- struct netbk_rx_meta *meta;
+- int old_meta_prod;
+-
+- old_meta_prod = npo->meta_prod;
+-
+- /* Set up a GSO prefix descriptor, if necessary */
+- if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
+- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+- meta = npo->meta + npo->meta_prod++;
+- meta->gso_size = skb_shinfo(skb)->gso_size;
+- meta->size = 0;
+- meta->id = req->id;
+- }
+-
+- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
+- meta = npo->meta + npo->meta_prod++;
+-
+- if (!netif->gso_prefix)
+- meta->gso_size = skb_shinfo(skb)->gso_size;
+- else
+- meta->gso_size = 0;
+-
+- meta->size = 0;
+- meta->id = req->id;
+- npo->copy_off = 0;
+- npo->copy_gref = req->gref;
+-
+- netbk_gop_frag_copy(netif,
+- npo, virt_to_page(skb->data),
+- skb_headlen(skb),
+- offset_in_page(skb->data), 1);
+-
+- /* Leave a gap for the GSO descriptor. */
+- if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
+- netif->rx.req_cons++;
+-
+- for (i = 0; i < nr_frags; i++) {
+- netbk_gop_frag_copy(netif, npo,
+- skb_shinfo(skb)->frags[i].page,
+- skb_shinfo(skb)->frags[i].size,
+- skb_shinfo(skb)->frags[i].page_offset,
+- 0);
+- }
+-
+- return npo->meta_prod - old_meta_prod;
+-}
+-
+-/*
+- * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
+- * used to set up the operations on the top of
+- * netrx_pending_operations, which have since been done. Check that
+- * they didn't give any errors and advance over them.
+- */
+-static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+- struct netrx_pending_operations *npo)
+-{
+- struct gnttab_copy *copy_op;
+- int status = NETIF_RSP_OKAY;
+- int i;
+-
+- for (i = 0; i < nr_meta_slots; i++) {
+- copy_op = npo->copy + npo->copy_cons++;
+- if (copy_op->status != GNTST_okay) {
+- pr_debug("Bad status %d from copy to DOM%d.\n",
+- copy_op->status, domid);
+- status = NETIF_RSP_ERROR;
+- }
+- }
+-
+- return status;
+-}
+-
+-static void netbk_add_frag_responses(struct xen_netif *netif, int status,
+- struct netbk_rx_meta *meta,
+- int nr_meta_slots)
+-{
+- int i;
+- unsigned long offset;
+-
+- /* No fragments used */
+- if (nr_meta_slots <= 1)
+- return;
+-
+- nr_meta_slots--;
+-
+- for (i = 0; i < nr_meta_slots; i++) {
+- int flags;
+- if (i == nr_meta_slots - 1)
+- flags = 0;
+- else
+- flags = NETRXF_more_data;
+-
+- offset = 0;
+- make_rx_response(netif, meta[i].id, status, offset,
+- meta[i].size, flags);
+- }
+-}
+-
+-struct skb_cb_overlay {
+- int meta_slots_used;
+-};
+-
+-static void net_rx_action(unsigned long data)
+-{
+- struct xen_netif *netif = NULL;
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+- s8 status;
+- u16 irq, flags;
+- struct xen_netif_rx_response *resp;
+- struct sk_buff_head rxq;
+- struct sk_buff *skb;
+- int notify_nr = 0;
+- int ret;
+- int nr_frags;
+- int count;
+- unsigned long offset;
+- struct skb_cb_overlay *sco;
+-
+- struct netrx_pending_operations npo = {
+- .copy = netbk->grant_copy_op,
+- .meta = netbk->meta,
+- };
+-
+- skb_queue_head_init(&rxq);
+-
+- count = 0;
+-
+- while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
+- netif = netdev_priv(skb->dev);
+- nr_frags = skb_shinfo(skb)->nr_frags;
+-
+- sco = (struct skb_cb_overlay *)skb->cb;
+- sco->meta_slots_used = netbk_gop_skb(skb, &npo);
+-
+- count += nr_frags + 1;
+-
+- __skb_queue_tail(&rxq, skb);
+-
+- /* Filled the batch queue? */
+- if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
+- break;
+- }
+-
+- BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
+-
+- if (!npo.copy_prod)
+- return;
+-
+- BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
+- ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
+- npo.copy_prod);
+- BUG_ON(ret != 0);
+-
+- while ((skb = __skb_dequeue(&rxq)) != NULL) {
+- sco = (struct skb_cb_overlay *)skb->cb;
+-
+- netif = netdev_priv(skb->dev);
+-
+- if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
+- resp = RING_GET_RESPONSE(&netif->rx,
+- netif->rx.rsp_prod_pvt++);
+-
+- resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
+-
+- resp->offset = netbk->meta[npo.meta_cons].gso_size;
+- resp->id = netbk->meta[npo.meta_cons].id;
+- resp->status = sco->meta_slots_used;
+-
+- npo.meta_cons++;
+- sco->meta_slots_used--;
+- }
+-
+-
+- netif->stats.tx_bytes += skb->len;
+- netif->stats.tx_packets++;
+-
+- status = netbk_check_gop(sco->meta_slots_used,
+- netif->domid, &npo);
+-
+- if (sco->meta_slots_used == 1)
+- flags = 0;
+- else
+- flags = NETRXF_more_data;
+-
+- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+- flags |= NETRXF_csum_blank | NETRXF_data_validated;
+- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+- /* remote but checksummed. */
+- flags |= NETRXF_data_validated;
+-
+- offset = 0;
+- resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
+- status, offset,
+- netbk->meta[npo.meta_cons].size,
+- flags);
+-
+- if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
+- struct xen_netif_extra_info *gso =
+- (struct xen_netif_extra_info *)
+- RING_GET_RESPONSE(&netif->rx,
+- netif->rx.rsp_prod_pvt++);
+-
+- resp->flags |= NETRXF_extra_info;
+-
+- gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
+- gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+- gso->u.gso.pad = 0;
+- gso->u.gso.features = 0;
+-
+- gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+- gso->flags = 0;
+- }
+-
+- netbk_add_frag_responses(netif, status,
+- netbk->meta + npo.meta_cons + 1,
+- sco->meta_slots_used);
+-
+- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
+- irq = netif->irq;
+- if (ret && !netbk->rx_notify[irq]) {
+- netbk->rx_notify[irq] = 1;
+- netbk->notify_list[notify_nr++] = irq;
+- }
+-
+- if (netif_queue_stopped(netif->dev) &&
+- netif_schedulable(netif) &&
+- !netbk_queue_full(netif))
+- netif_wake_queue(netif->dev);
+-
+- netif_put(netif);
+- npo.meta_cons += sco->meta_slots_used;
+- dev_kfree_skb(skb);
+- }
+-
+- while (notify_nr != 0) {
+- irq = netbk->notify_list[--notify_nr];
+- netbk->rx_notify[irq] = 0;
+- notify_remote_via_irq(irq);
+- }
+-
+- /* More work to do? */
+- if (!skb_queue_empty(&netbk->rx_queue) &&
+- !timer_pending(&netbk->net_timer))
+- xen_netbk_bh_handler(netbk, 1);
+-}
+-
+-static void net_alarm(unsigned long data)
+-{
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+- xen_netbk_bh_handler(netbk, 1);
+-}
+-
+-static void netbk_tx_pending_timeout(unsigned long data)
+-{
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+- xen_netbk_bh_handler(netbk, 0);
+-}
+-
+-struct net_device_stats *netif_be_get_stats(struct net_device *dev)
+-{
+- struct xen_netif *netif = netdev_priv(dev);
+- return &netif->stats;
+-}
+-
+-static int __on_net_schedule_list(struct xen_netif *netif)
+-{
+- return !list_empty(&netif->list);
+-}
+-
+-/* Must be called with net_schedule_list_lock held */
+-static void remove_from_net_schedule_list(struct xen_netif *netif)
+-{
+- if (likely(__on_net_schedule_list(netif))) {
+- list_del_init(&netif->list);
+- netif_put(netif);
+- }
+-}
+-
+-static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
+-{
+- struct xen_netif *netif = NULL;
+-
+- spin_lock_irq(&netbk->net_schedule_list_lock);
+- if (list_empty(&netbk->net_schedule_list))
+- goto out;
+-
+- netif = list_first_entry(&netbk->net_schedule_list,
+- struct xen_netif, list);
+- if (!netif)
+- goto out;
+-
+- netif_get(netif);
+-
+- remove_from_net_schedule_list(netif);
+-out:
+- spin_unlock_irq(&netbk->net_schedule_list_lock);
+- return netif;
+-}
+-
+-static void add_to_net_schedule_list_tail(struct xen_netif *netif)
+-{
+- unsigned long flags;
+-
+- struct xen_netbk *netbk = &xen_netbk[netif->group];
+- if (__on_net_schedule_list(netif))
+- return;
+-
+- spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
+- if (!__on_net_schedule_list(netif) &&
+- likely(netif_schedulable(netif))) {
+- list_add_tail(&netif->list, &netbk->net_schedule_list);
+- netif_get(netif);
+- }
+- spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
+-}
+-
+-void netif_schedule_work(struct xen_netif *netif)
+-{
+- struct xen_netbk *netbk = &xen_netbk[netif->group];
+- int more_to_do;
+-
+- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
+-
+- if (more_to_do) {
+- add_to_net_schedule_list_tail(netif);
+- maybe_schedule_tx_action(netbk);
+- }
+-}
+-
+-void netif_deschedule_work(struct xen_netif *netif)
+-{
+- struct xen_netbk *netbk = &xen_netbk[netif->group];
+- spin_lock_irq(&netbk->net_schedule_list_lock);
+- remove_from_net_schedule_list(netif);
+- spin_unlock_irq(&netbk->net_schedule_list_lock);
+-}
+-
+-
+-static void tx_add_credit(struct xen_netif *netif)
+-{
+- unsigned long max_burst, max_credit;
+-
+- /*
+- * 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(&netif->tx, netif->tx.req_cons)->size;
+- max_burst = min(max_burst, 131072UL);
+- max_burst = max(max_burst, netif->credit_bytes);
+-
+- /* Take care that adding a new chunk of credit doesn't wrap to zero. */
+- max_credit = netif->remaining_credit + netif->credit_bytes;
+- if (max_credit < netif->remaining_credit)
+- max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
+-
+- netif->remaining_credit = min(max_credit, max_burst);
+-}
+-
+-static void tx_credit_callback(unsigned long data)
+-{
+- struct xen_netif *netif = (struct xen_netif *)data;
+- tx_add_credit(netif);
+- netif_schedule_work(netif);
+-}
+-
+-static inline int copy_pending_req(struct xen_netbk *netbk,
+- pending_ring_idx_t pending_idx)
+-{
+- return gnttab_copy_grant_page(
+- netbk->grant_tx_handle[pending_idx],
+- &netbk->mmap_pages[pending_idx]);
+-}
+-
+-static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
+-{
+- struct netbk_tx_pending_inuse *inuse, *n;
+- struct gnttab_unmap_grant_ref *gop;
+- u16 pending_idx;
+- pending_ring_idx_t dc, dp;
+- struct xen_netif *netif;
+- int ret;
+- LIST_HEAD(list);
+-
+- dc = netbk->dealloc_cons;
+- gop = netbk->tx_unmap_ops;
+-
+- /* Free up any grants we have finished using. */
+- do {
+- dp = netbk->dealloc_prod;
+-
+- /* Ensure we see all indices enqueued by netif_idx_release(). */
+- smp_rmb();
+-
+- while (dc != dp) {
+- unsigned long pfn;
+- struct netbk_tx_pending_inuse *pending_inuse =
+- netbk->pending_inuse;
+-
+- pending_idx = netbk->dealloc_ring[pending_index(dc++)];
+- list_move_tail(&pending_inuse[pending_idx].list, &list);
+-
+- 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(netbk, pending_idx),
+- GNTMAP_host_map,
+- netbk->grant_tx_handle[pending_idx]);
+- gop++;
+- }
+-
+- } while (dp != netbk->dealloc_prod);
+-
+- netbk->dealloc_cons = dc;
+-
+- ret = HYPERVISOR_grant_table_op(
+- GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
+- gop - netbk->tx_unmap_ops);
+- BUG_ON(ret);
+-
+- /*
+- * Copy any entries that have been pending for too long
+- */
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !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;
+- pending_tx_info = netbk->pending_tx_info;
+-
+- if (time_after(inuse->alloc_time + HZ / 2, jiffies))
+- break;
+-
+- pending_idx = inuse - netbk->pending_inuse;
+-
+- pending_tx_info[pending_idx].netif->nr_copied_skbs++;
+-
+- switch (copy_pending_req(netbk, pending_idx)) {
+- case 0:
+- list_move_tail(&inuse->list, &list);
+- continue;
+- case -EBUSY:
+- list_del_init(&inuse->list);
+- continue;
+- case -ENOENT:
+- continue;
+- }
+-
+- break;
+- }
+- }
+-
+- list_for_each_entry_safe(inuse, n, &list, list) {
+- struct pending_tx_info *pending_tx_info;
+- pending_ring_idx_t index;
+-
+- 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(netbk->mmap_pages[pending_idx]);
+-
+- index = pending_index(netbk->pending_prod++);
+- netbk->pending_ring[index] = pending_idx;
+-
+- netif_put(netif);
+-
+- list_del_init(&inuse->list);
+- }
+-}
+-
+-static void netbk_tx_err(struct xen_netif *netif,
+- struct xen_netif_tx_request *txp, RING_IDX end)
+-{
+- RING_IDX cons = netif->tx.req_cons;
+-
+- do {
+- make_tx_response(netif, txp, NETIF_RSP_ERROR);
+- if (cons >= end)
+- break;
+- txp = RING_GET_REQUEST(&netif->tx, cons++);
+- } while (1);
+- netif->tx.req_cons = cons;
+- netif_schedule_work(netif);
+- netif_put(netif);
+-}
+-
+-static int netbk_count_requests(struct xen_netif *netif,
+- struct xen_netif_tx_request *first,
+- struct xen_netif_tx_request *txp,
+- int work_to_do)
+-{
+- RING_IDX cons = netif->tx.req_cons;
+- int frags = 0;
+-
+- if (!(first->flags & NETTXF_more_data))
+- return 0;
+-
+- do {
+- if (frags >= work_to_do) {
+- pr_debug("Need more frags\n");
+- return -frags;
+- }
+-
+- if (unlikely(frags >= MAX_SKB_FRAGS)) {
+- pr_debug("Too many frags\n");
+- return -frags;
+- }
+-
+- memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
+- sizeof(*txp));
+- if (txp->size > first->size) {
+- pr_debug("Frags galore\n");
+- return -frags;
+- }
+-
+- first->size -= txp->size;
+- frags++;
+-
+- if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
+- pr_debug("txp->offset: %x, size: %u\n",
+- txp->offset, txp->size);
+- return -frags;
+- }
+- } while ((txp++)->flags & NETTXF_more_data);
+-
+- return frags;
+-}
+-
+-static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
+- struct xen_netif *netif,
+- struct sk_buff *skb,
+- struct xen_netif_tx_request *txp,
+- struct gnttab_map_grant_ref *mop)
+-{
+- struct skb_shared_info *shinfo = skb_shinfo(skb);
+- skb_frag_t *frags = shinfo->frags;
+- unsigned long pending_idx = *((u16 *)skb->data);
+- int i, start;
+-
+- /* Skip first skb fragment if it is on same page as header fragment. */
+- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+-
+- for (i = start; i < shinfo->nr_frags; i++, txp++) {
+- pending_ring_idx_t index;
+- struct pending_tx_info *pending_tx_info =
+- netbk->pending_tx_info;
+-
+- index = pending_index(netbk->pending_cons++);
+- 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);
+-
+- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
+- netif_get(netif);
+- pending_tx_info[pending_idx].netif = netif;
+- frags[i].page = (void *)pending_idx;
+- }
+-
+- return mop;
+-}
+-
+-static int netbk_tx_check_mop(struct xen_netbk *netbk,
+- struct sk_buff *skb,
+- struct gnttab_map_grant_ref **mopp)
+-{
+- struct gnttab_map_grant_ref *mop = *mopp;
+- int pending_idx = *((u16 *)skb->data);
+- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
+- struct xen_netif *netif = pending_tx_info[pending_idx].netif;
+- struct xen_netif_tx_request *txp;
+- struct skb_shared_info *shinfo = skb_shinfo(skb);
+- int nr_frags = shinfo->nr_frags;
+- int i, err, start;
+-
+- /* Check status of header. */
+- err = mop->status;
+- if (unlikely(err)) {
+- pending_ring_idx_t index;
+- index = pending_index(netbk->pending_prod++);
+- txp = &pending_tx_info[pending_idx].req;
+- make_tx_response(netif, txp, NETIF_RSP_ERROR);
+- netbk->pending_ring[index] = pending_idx;
+- netif_put(netif);
+- } else {
+- set_phys_to_machine(
+- __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
+- FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
+- netbk->grant_tx_handle[pending_idx] = mop->handle;
+- }
+-
+- /* Skip first skb fragment if it is on same page as header fragment. */
+- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+-
+- 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)) {
+- unsigned long addr;
+- addr = idx_to_kaddr(netbk, pending_idx);
+- set_phys_to_machine(
+- __pa(addr)>>PAGE_SHIFT,
+- FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
+- netbk->grant_tx_handle[pending_idx] = mop->handle;
+- /* Had a previous error? Invalidate this fragment. */
+- if (unlikely(err))
+- netif_idx_release(netbk, pending_idx);
+- continue;
+- }
+-
+- /* Error on this fragment: respond to client with an error. */
+- txp = &netbk->pending_tx_info[pending_idx].req;
+- make_tx_response(netif, txp, NETIF_RSP_ERROR);
+- index = pending_index(netbk->pending_prod++);
+- netbk->pending_ring[index] = pending_idx;
+- netif_put(netif);
+-
+- /* Not the first error? Preceding frags already invalidated. */
+- if (err)
+- continue;
+-
+- /* First error: invalidate header and preceding fragments. */
+- pending_idx = *((u16 *)skb->data);
+- netif_idx_release(netbk, pending_idx);
+- for (j = start; j < i; j++) {
+- pending_idx = (unsigned long)shinfo->frags[i].page;
+- netif_idx_release(netbk, pending_idx);
+- }
+-
+- /* Remember the error: invalidate all subsequent fragments. */
+- err = newerr;
+- }
+-
+- *mopp = mop + 1;
+- return err;
+-}
+-
+-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;
+- int i;
+-
+- for (i = 0; i < nr_frags; i++) {
+- skb_frag_t *frag = shinfo->frags + i;
+- struct xen_netif_tx_request *txp;
+- unsigned long pending_idx;
+-
+- pending_idx = (unsigned long)frag->page;
+-
+- netbk->pending_inuse[pending_idx].alloc_time = jiffies;
+- list_add_tail(&netbk->pending_inuse[pending_idx].list,
+- &netbk->pending_inuse_head);
+-
+- txp = &netbk->pending_tx_info[pending_idx].req;
+- frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
+- frag->size = txp->size;
+- frag->page_offset = txp->offset;
+-
+- skb->len += txp->size;
+- skb->data_len += txp->size;
+- skb->truesize += txp->size;
+- }
+-}
+-
+-int netbk_get_extras(struct xen_netif *netif,
+- struct xen_netif_extra_info *extras,
+- int work_to_do)
+-{
+- struct xen_netif_extra_info extra;
+- RING_IDX cons = netif->tx.req_cons;
+-
+- do {
+- if (unlikely(work_to_do-- <= 0)) {
+- pr_debug("Missing extra info\n");
+- return -EBADR;
+- }
+-
+- memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
+- sizeof(extra));
+- if (unlikely(!extra.type ||
+- extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+- netif->tx.req_cons = ++cons;
+- pr_debug("Invalid extra type: %d\n", extra.type);
+- return -EINVAL;
+- }
+-
+- memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
+- netif->tx.req_cons = ++cons;
+- } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
+-
+- return work_to_do;
+-}
+-
+-static int netbk_set_skb_gso(struct sk_buff *skb,
+- struct xen_netif_extra_info *gso)
+-{
+- if (!gso->u.gso.size) {
+- pr_debug("GSO size must not be zero.\n");
+- return -EINVAL;
+- }
+-
+- /* Currently only TCPv4 S.O. is supported. */
+- if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+- pr_debug("Bad GSO type %d.\n", gso->u.gso.type);
+- return -EINVAL;
+- }
+-
+- skb_shinfo(skb)->gso_size = gso->u.gso.size;
+- skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+-
+- /* Header must be checked, and gso_segs computed. */
+- skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+- skb_shinfo(skb)->gso_segs = 0;
+-
+- return 0;
+-}
+-
+-static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
+-{
+- struct iphdr *iph;
+- unsigned char *th;
+- int err = -EPROTO;
+- int recalculate_partial_csum = 0;
+-
+- /*
+- * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
+- * peers can fail to set NETRXF_csum_blank when sending a GSO
+- * frame. In this case force the SKB to CHECKSUM_PARTIAL and
+- * recalculate the partial checksum.
+- */
+- if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
+- netif->rx_gso_checksum_fixup++;
+- skb->ip_summed = CHECKSUM_PARTIAL;
+- recalculate_partial_csum = 1;
+- }
+-
+- /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
+- if (skb->ip_summed != CHECKSUM_PARTIAL)
+- return 0;
+-
+- if (skb->protocol != htons(ETH_P_IP))
+- goto out;
+-
+- iph = (void *)skb->data;
+- th = skb->data + 4 * iph->ihl;
+- if (th >= skb_tail_pointer(skb))
+- goto out;
+-
+- skb->csum_start = th - skb->head;
+- switch (iph->protocol) {
+- case IPPROTO_TCP:
+- skb->csum_offset = offsetof(struct tcphdr, check);
+-
+- if (recalculate_partial_csum) {
+- struct tcphdr *tcph = (struct tcphdr *)th;
+- tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+- skb->len - iph->ihl*4,
+- IPPROTO_TCP, 0);
+- }
+- break;
+- case IPPROTO_UDP:
+- skb->csum_offset = offsetof(struct udphdr, check);
+-
+- if (recalculate_partial_csum) {
+- struct udphdr *udph = (struct udphdr *)th;
+- udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+- skb->len - iph->ihl*4,
+- IPPROTO_UDP, 0);
+- }
+- break;
+- default:
+- if (net_ratelimit())
+- printk(KERN_ERR "Attempting to checksum a non-"
+- "TCP/UDP packet, dropping a protocol"
+- " %d packet", iph->protocol);
+- goto out;
+- }
+-
+- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+- goto out;
+-
+- err = 0;
+-
+-out:
+- return err;
+-}
+-
+-static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
+-{
+- unsigned long now = jiffies;
+- unsigned long next_credit =
+- netif->credit_timeout.expires +
+- msecs_to_jiffies(netif->credit_usec / 1000);
+-
+- /* Timer could already be pending in rare cases. */
+- if (timer_pending(&netif->credit_timeout))
+- return true;
+-
+- /* Passed the point where we can replenish credit? */
+- if (time_after_eq(now, next_credit)) {
+- netif->credit_timeout.expires = now;
+- tx_add_credit(netif);
+- }
+-
+- /* Still too big to send right now? Set a callback. */
+- if (size > netif->remaining_credit) {
+- netif->credit_timeout.data =
+- (unsigned long)netif;
+- netif->credit_timeout.function =
+- tx_credit_callback;
+- mod_timer(&netif->credit_timeout,
+- next_credit);
+-
+- return true;
+- }
+-
+- return false;
+-}
+-
+-static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+-{
+- struct gnttab_map_grant_ref *mop;
+- struct sk_buff *skb;
+- int ret;
+-
+- mop = netbk->tx_map_ops;
+- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+- !list_empty(&netbk->net_schedule_list)) {
+- struct xen_netif *netif;
+- struct xen_netif_tx_request txreq;
+- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+- u16 pending_idx;
+- RING_IDX idx;
+- int work_to_do;
+- unsigned int data_len;
+- pending_ring_idx_t index;
+-
+- /* Get a netif from the list with work to do. */
+- netif = poll_net_schedule_list(netbk);
+- if (!netif)
+- continue;
+-
+- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
+- if (!work_to_do) {
+- netif_put(netif);
+- continue;
+- }
+-
+- idx = netif->tx.req_cons;
+- rmb(); /* Ensure that we see the request before we copy it. */
+- memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
+-
+- /* Credit-based scheduling. */
+- if (txreq.size > netif->remaining_credit &&
+- tx_credit_exceeded(netif, txreq.size)) {
+- netif_put(netif);
+- continue;
+- }
+-
+- netif->remaining_credit -= txreq.size;
+-
+- work_to_do--;
+- netif->tx.req_cons = ++idx;
+-
+- memset(extras, 0, sizeof(extras));
+- if (txreq.flags & NETTXF_extra_info) {
+- work_to_do = netbk_get_extras(netif, extras,
+- work_to_do);
+- idx = netif->tx.req_cons;
+- if (unlikely(work_to_do < 0)) {
+- netbk_tx_err(netif, &txreq, idx);
+- continue;
+- }
+- }
+-
+- ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
+- if (unlikely(ret < 0)) {
+- netbk_tx_err(netif, &txreq, idx - ret);
+- continue;
+- }
+- idx += ret;
+-
+- if (unlikely(txreq.size < ETH_HLEN)) {
+- pr_debug("Bad packet size: %d\n", txreq.size);
+- netbk_tx_err(netif, &txreq, idx);
+- continue;
+- }
+-
+- /* No crossing a page as the payload mustn't fragment. */
+- if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
+- pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
+- txreq.offset, txreq.size,
+- (txreq.offset&~PAGE_MASK) + txreq.size);
+- netbk_tx_err(netif, &txreq, idx);
+- continue;
+- }
+-
+- index = pending_index(netbk->pending_cons);
+- pending_idx = netbk->pending_ring[index];
+-
+- data_len = (txreq.size > PKT_PROT_LEN &&
+- ret < MAX_SKB_FRAGS) ?
+- PKT_PROT_LEN : txreq.size;
+-
+- skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
+- GFP_ATOMIC | __GFP_NOWARN);
+- if (unlikely(skb == NULL)) {
+- pr_debug("Can't allocate a skb in start_xmit.\n");
+- netbk_tx_err(netif, &txreq, idx);
+- break;
+- }
+-
+- /* Packets passed to netif_rx() must have some headroom. */
+- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+-
+- if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+- struct xen_netif_extra_info *gso;
+- gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+-
+- if (netbk_set_skb_gso(skb, gso)) {
+- kfree_skb(skb);
+- netbk_tx_err(netif, &txreq, idx);
+- continue;
+- }
+- }
+-
+- gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
+- GNTMAP_host_map | GNTMAP_readonly,
+- txreq.gref, netif->domid);
+- mop++;
+-
+- memcpy(&netbk->pending_tx_info[pending_idx].req,
+- &txreq, sizeof(txreq));
+- netbk->pending_tx_info[pending_idx].netif = netif;
+- *((u16 *)skb->data) = pending_idx;
+-
+- __skb_put(skb, data_len);
+-
+- skb_shinfo(skb)->nr_frags = ret;
+- if (data_len < txreq.size) {
+- skb_shinfo(skb)->nr_frags++;
+- skb_shinfo(skb)->frags[0].page =
+- (void *)(unsigned long)pending_idx;
+- } else {
+- /* Discriminate from any valid pending_idx value. */
+- skb_shinfo(skb)->frags[0].page = (void *)~0UL;
+- }
+-
+- __skb_queue_tail(&netbk->tx_queue, skb);
+-
+- netbk->pending_cons++;
+-
+- mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
+-
+- netif->tx.req_cons = idx;
+- netif_schedule_work(netif);
+-
+- if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
+- break;
+- }
+-
+- return mop - netbk->tx_map_ops;
+-}
+-
+-static void net_tx_submit(struct xen_netbk *netbk)
+-{
+- struct gnttab_map_grant_ref *mop;
+- struct sk_buff *skb;
+-
+- mop = netbk->tx_map_ops;
+- while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
+- struct xen_netif_tx_request *txp;
+- struct xen_netif *netif;
+- u16 pending_idx;
+- unsigned data_len;
+-
+- pending_idx = *((u16 *)skb->data);
+- netif = netbk->pending_tx_info[pending_idx].netif;
+- txp = &netbk->pending_tx_info[pending_idx].req;
+-
+- /* Check the remap error code. */
+- if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
+- pr_debug("netback grant failed.\n");
+- skb_shinfo(skb)->nr_frags = 0;
+- kfree_skb(skb);
+- continue;
+- }
+-
+- data_len = skb->len;
+- memcpy(skb->data,
+- (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
+- data_len);
+- if (data_len < txp->size) {
+- /* Append the packet payload as a fragment. */
+- txp->offset += data_len;
+- txp->size -= data_len;
+- } else {
+- /* Schedule a response immediately. */
+- netif_idx_release(netbk, pending_idx);
+- }
+-
+- if (txp->flags & NETTXF_csum_blank)
+- skb->ip_summed = CHECKSUM_PARTIAL;
+- else if (txp->flags & NETTXF_data_validated)
+- skb->ip_summed = CHECKSUM_UNNECESSARY;
+-
+- netbk_fill_frags(netbk, skb);
+-
+- /*
+- * If the initial fragment was < PKT_PROT_LEN then
+- * pull through some bytes from the other fragments to
+- * increase the linear region to PKT_PROT_LEN bytes.
+- */
+- if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
+- int target = min_t(int, skb->len, PKT_PROT_LEN);
+- __pskb_pull_tail(skb, target - skb_headlen(skb));
+- }
+-
+- skb->dev = netif->dev;
+- skb->protocol = eth_type_trans(skb, skb->dev);
+-
+- if (checksum_setup(netif, skb)) {
+- pr_debug("Can't setup checksum in net_tx_action\n");
+- kfree_skb(skb);
+- continue;
+- }
+-
+- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
+- unlikely(skb_linearize(skb))) {
+- pr_debug("Can't linearize skb in net_tx_action.\n");
+- kfree_skb(skb);
+- continue;
+- }
+-
+- netif->stats.rx_bytes += skb->len;
+- netif->stats.rx_packets++;
+-
+- netif_rx_ni(skb);
+- netif->dev->last_rx = jiffies;
+- }
+-}
+-
+-/* Called after netfront has transmitted */
+-static void net_tx_action(unsigned long data)
+-{
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+- unsigned nr_mops;
+- int ret;
+-
+- net_tx_action_dealloc(netbk);
+-
+- nr_mops = net_tx_build_mops(netbk);
+-
+- if (nr_mops == 0)
+- goto out;
+-
+- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+- netbk->tx_map_ops, nr_mops);
+- BUG_ON(ret);
+-
+- net_tx_submit(netbk);
+-out:
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !list_empty(&netbk->pending_inuse_head)) {
+- struct netbk_tx_pending_inuse *oldest;
+-
+- oldest = list_entry(netbk->pending_inuse_head.next,
+- struct netbk_tx_pending_inuse, list);
+- mod_timer(&netbk->netbk_tx_pending_timer,
+- oldest->alloc_time + HZ);
+- }
+-}
+-
+-static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+-{
+- static DEFINE_SPINLOCK(_lock);
+- unsigned long flags;
+- pending_ring_idx_t index;
+-
+- spin_lock_irqsave(&_lock, flags);
+- index = pending_index(netbk->dealloc_prod);
+- netbk->dealloc_ring[index] = pending_idx;
+- /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
+- smp_wmb();
+- netbk->dealloc_prod++;
+- spin_unlock_irqrestore(&_lock, flags);
+-
+- xen_netbk_bh_handler(netbk, 0);
+-}
+-
+-static void netif_page_release(struct page *page, unsigned int order)
+-{
+- unsigned int group, idx;
+- int foreign = netif_get_page_ext(page, &group, &idx);
+-
+- BUG_ON(!foreign);
+- BUG_ON(order);
+-
+- netif_idx_release(&xen_netbk[group], idx);
+-}
-
- config XENFS
- tristate "Xen filesystem"
- default y
-diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
-index c0e0509..533a199 100644
---- a/drivers/xen/Makefile
-+++ b/drivers/xen/Makefile
-@@ -9,7 +9,6 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
- obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
- obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
- obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
--obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
- obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
- obj-$(CONFIG_XENFS) += xenfs/
- obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
-diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile
+-irqreturn_t netif_be_int(int irq, void *dev_id)
+-{
+- struct xen_netif *netif = dev_id;
+- struct xen_netbk *netbk;
+-
+- if (netif->group == -1)
+- return IRQ_NONE;
+-
+- netbk = &xen_netbk[netif->group];
+-
+- add_to_net_schedule_list_tail(netif);
+- maybe_schedule_tx_action(netbk);
+-
+- if (netif_schedulable(netif) && !netbk_queue_full(netif))
+- netif_wake_queue(netif->dev);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static void make_tx_response(struct xen_netif *netif,
+- struct xen_netif_tx_request *txp,
+- s8 st)
+-{
+- RING_IDX i = netif->tx.rsp_prod_pvt;
+- struct xen_netif_tx_response *resp;
+- int notify;
+-
+- resp = RING_GET_RESPONSE(&netif->tx, i);
+- resp->id = txp->id;
+- resp->status = st;
+-
+- if (txp->flags & NETTXF_extra_info)
+- RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
+-
+- netif->tx.rsp_prod_pvt = ++i;
+- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
+- if (notify)
+- notify_remote_via_irq(netif->irq);
+-}
+-
+-static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
+- u16 id,
+- s8 st,
+- u16 offset,
+- u16 size,
+- u16 flags)
+-{
+- RING_IDX i = netif->rx.rsp_prod_pvt;
+- struct xen_netif_rx_response *resp;
+-
+- resp = RING_GET_RESPONSE(&netif->rx, i);
+- resp->offset = offset;
+- resp->flags = flags;
+- resp->id = id;
+- resp->status = (s16)size;
+- if (st < 0)
+- resp->status = (s16)st;
+-
+- netif->rx.rsp_prod_pvt = ++i;
+-
+- return resp;
+-}
+-
+-#ifdef NETBE_DEBUG_INTERRUPT
+-static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct list_head *ent;
+- struct xen_netif *netif;
+- int i = 0;
+- int group = 0;
+-
+- printk(KERN_ALERT "netif_schedule_list:\n");
+-
+- for (group = 0; group < xen_netbk_group_nr; group++) {
+- struct xen_netbk *netbk = &xen_netbk[group];
+- spin_lock_irq(&netbk->net_schedule_list_lock);
+- printk(KERN_ALERT "xen_netback group number: %d\n", group);
+- list_for_each(ent, &netbk->net_schedule_list) {
+- netif = list_entry(ent, struct xen_netif, list);
+- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
+- "rx_resp_prod=%08x\n",
+- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
+- printk(KERN_ALERT
+- " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
+- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
+- printk(KERN_ALERT
+- " shared(rx_req_prod=%08x "
+- "rx_resp_prod=%08x\n",
+- netif->rx.sring->req_prod,
+- netif->rx.sring->rsp_prod);
+- printk(KERN_ALERT
+- " rx_event=%08x, tx_req_prod=%08x\n",
+- netif->rx.sring->rsp_event,
+- netif->tx.sring->req_prod);
+- printk(KERN_ALERT
+- " tx_resp_prod=%08x, tx_event=%08x)\n",
+- netif->tx.sring->rsp_prod,
+- netif->tx.sring->rsp_event);
+- i++;
+- }
+- spin_unlock_irq(&netbk->net_schedule_list_lock);
+- }
+-
+- printk(KERN_ALERT " ** End of netif_schedule_list **\n");
+-
+- return IRQ_HANDLED;
+-}
+-#endif
+-
+-static inline int rx_work_todo(struct xen_netbk *netbk)
+-{
+- return !skb_queue_empty(&netbk->rx_queue);
+-}
+-
+-static inline int tx_work_todo(struct xen_netbk *netbk)
+-{
+- if (netbk->dealloc_cons != netbk->dealloc_prod)
+- return 1;
+-
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !list_empty(&netbk->pending_inuse_head))
+- return 1;
+-
+- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+- !list_empty(&netbk->net_schedule_list))
+- return 1;
+-
+- return 0;
+-}
+-
+-static int netbk_action_thread(void *data)
+-{
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+- while (!kthread_should_stop()) {
+- wait_event_interruptible(netbk->kthread.netbk_action_wq,
+- rx_work_todo(netbk)
+- || tx_work_todo(netbk)
+- || kthread_should_stop());
+- cond_resched();
+-
+- if (kthread_should_stop())
+- break;
+-
+- if (rx_work_todo(netbk))
+- net_rx_action((unsigned long)netbk);
+-
+- if (tx_work_todo(netbk))
+- net_tx_action((unsigned long)netbk);
+- }
+-
+- return 0;
+-}
+-
+-static int __init netback_init(void)
+-{
+- int i;
+- struct page *page;
+- int rc = 0;
+- int group;
+-
+- if (!xen_pv_domain())
+- return -ENODEV;
+-
+- xen_netbk_group_nr = num_online_cpus();
+- xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
+- if (!xen_netbk) {
+- printk(KERN_ALERT "%s: out of memory\n", __func__);
+- return -ENOMEM;
+- }
+- memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
+-
+- for (group = 0; group < xen_netbk_group_nr; group++) {
+- struct xen_netbk *netbk = &xen_netbk[group];
+- skb_queue_head_init(&netbk->rx_queue);
+- skb_queue_head_init(&netbk->tx_queue);
+-
+- init_timer(&netbk->net_timer);
+- netbk->net_timer.data = (unsigned long)netbk;
+- netbk->net_timer.function = net_alarm;
+-
+- init_timer(&netbk->netbk_tx_pending_timer);
+- netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
+- netbk->netbk_tx_pending_timer.function =
+- netbk_tx_pending_timeout;
+-
+- netbk->mmap_pages =
+- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+- if (!netbk->mmap_pages) {
+- printk(KERN_ALERT "%s: out of memory\n", __func__);
+- del_timer(&netbk->netbk_tx_pending_timer);
+- del_timer(&netbk->net_timer);
+- 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);
+- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+- }
+-
+- netbk->pending_cons = 0;
+- netbk->pending_prod = MAX_PENDING_REQS;
+- for (i = 0; i < MAX_PENDING_REQS; i++)
+- netbk->pending_ring[i] = i;
+-
+- if (MODPARM_netback_kthread) {
+- init_waitqueue_head(&netbk->kthread.netbk_action_wq);
+- netbk->kthread.task =
+- kthread_create(netbk_action_thread,
+- (void *)netbk,
+- "netback/%u", group);
+-
+- if (!IS_ERR(netbk->kthread.task)) {
+- kthread_bind(netbk->kthread.task, group);
+- } else {
+- printk(KERN_ALERT
+- "kthread_run() fails at netback\n");
+- free_empty_pages_and_pagevec(netbk->mmap_pages,
+- MAX_PENDING_REQS);
+- del_timer(&netbk->netbk_tx_pending_timer);
+- del_timer(&netbk->net_timer);
+- rc = PTR_ERR(netbk->kthread.task);
+- goto failed_init;
+- }
+- } else {
+- tasklet_init(&netbk->tasklet.net_tx_tasklet,
+- net_tx_action,
+- (unsigned long)netbk);
+- tasklet_init(&netbk->tasklet.net_rx_tasklet,
+- net_rx_action,
+- (unsigned long)netbk);
+- }
+-
+- INIT_LIST_HEAD(&netbk->pending_inuse_head);
+- INIT_LIST_HEAD(&netbk->net_schedule_list);
+-
+- spin_lock_init(&netbk->net_schedule_list_lock);
+-
+- atomic_set(&netbk->netfront_count, 0);
+-
+- if (MODPARM_netback_kthread)
+- wake_up_process(netbk->kthread.task);
+- }
+-
+- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+- if (MODPARM_copy_skb) {
+- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
+- NULL, 0))
+- netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
+- else
+- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+- }
+-
+- rc = netif_xenbus_init();
+- if (rc)
+- goto failed_init;
+-
+-#ifdef NETBE_DEBUG_INTERRUPT
+- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
+- 0,
+- netif_be_dbg,
+- IRQF_SHARED,
+- "net-be-dbg",
+- &netif_be_dbg);
+-#endif
+-
+- return 0;
+-
+-failed_init:
+- for (i = 0; i < group; i++) {
+- struct xen_netbk *netbk = &xen_netbk[i];
+- free_empty_pages_and_pagevec(netbk->mmap_pages,
+- MAX_PENDING_REQS);
+- del_timer(&netbk->netbk_tx_pending_timer);
+- del_timer(&netbk->net_timer);
+- if (MODPARM_netback_kthread)
+- kthread_stop(netbk->kthread.task);
+- }
+- vfree(xen_netbk);
+- return rc;
+-
+-}
+-
+-module_init(netback_init);
+-
+-MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
deleted file mode 100644
-index e346e81..0000000
---- a/drivers/xen/netback/Makefile
+index 867dc25..0000000
+--- a/drivers/xen/netback/xenbus.c
+++ /dev/null
-@@ -1,3 +0,0 @@
--obj-$(CONFIG_XEN_NETDEV_BACKEND) := xen-netback.o
+@@ -1,489 +0,0 @@
+-/*
+- * Xenbus code for netif backend
+- *
+- * Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
+- * Copyright (C) 2005 XenSource Ltd
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-*/
+-
+-#include "common.h"
+-
+-static int connect_rings(struct backend_info *);
+-static void connect(struct backend_info *);
+-static void backend_create_netif(struct backend_info *be);
+-static void unregister_hotplug_status_watch(struct backend_info *be);
+-
+-static int netback_remove(struct xenbus_device *dev)
+-{
+- struct backend_info *be = dev_get_drvdata(&dev->dev);
+-
+- unregister_hotplug_status_watch(be);
+- if (be->netif) {
+- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
+- netif_disconnect(be->netif);
+- be->netif = NULL;
+- }
+- kfree(be);
+- dev_set_drvdata(&dev->dev, NULL);
+- return 0;
+-}
+-
+-
+-/**
+- * Entry point to this code when a new device is created. Allocate the basic
+- * structures and switch to InitWait.
+- */
+-static int netback_probe(struct xenbus_device *dev,
+- const struct xenbus_device_id *id)
+-{
+- const char *message;
+- struct xenbus_transaction xbt;
+- int err;
+- int sg;
+- struct backend_info *be = kzalloc(sizeof(struct backend_info),
+- GFP_KERNEL);
+- if (!be) {
+- xenbus_dev_fatal(dev, -ENOMEM,
+- "allocating backend structure");
+- return -ENOMEM;
+- }
+-
+- be->dev = dev;
+- dev_set_drvdata(&dev->dev, be);
+-
+- sg = 1;
+- if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
+- sg = 0;
+-
+- do {
+- err = xenbus_transaction_start(&xbt);
+- if (err) {
+- xenbus_dev_fatal(dev, err, "starting transaction");
+- goto fail;
+- }
+-
+- err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
sg);
+- if (err) {
+- message = "writing feature-sg";
+- goto abort_transaction;
+- }
+-
+- err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
+- "%d", sg);
+- if (err) {
+- message = "writing feature-gso-tcpv4";
+- goto abort_transaction;
+- }
+-
+- /* We support rx-copy path. */
+- err = xenbus_printf(xbt, dev->nodename,
+- "feature-rx-copy", "%d", 1);
+- if (err) {
+- message = "writing feature-rx-copy";
+- goto abort_transaction;
+- }
+-
+- /*
+- * We don't support rx-flip path (except old guests who don't
+- * grok this feature flag).
+- */
+- err = xenbus_printf(xbt, dev->nodename,
+- "feature-rx-flip", "%d", 0);
+- if (err) {
+- message = "writing feature-rx-flip";
+- goto abort_transaction;
+- }
+-
+- err = xenbus_transaction_end(xbt, 0);
+- } while (err == -EAGAIN);
+-
+- if (err) {
+- xenbus_dev_fatal(dev, err, "completing transaction");
+- goto fail;
+- }
+-
+- err = xenbus_switch_state(dev, XenbusStateInitWait);
+- if (err)
+- goto fail;
+-
+- /* This kicks hotplug scripts, so do it immediately. */
+- backend_create_netif(be);
+-
+- return 0;
+-
+-abort_transaction:
+- xenbus_transaction_end(xbt, 1);
+- xenbus_dev_fatal(dev, err, "%s", message);
+-fail:
+- pr_debug("failed");
+- netback_remove(dev);
+- return err;
+-}
+-
+-
+-/*
+- * Handle the creation of the hotplug script environment. We add the script
+- * and vif variables to the environment, for the benefit of the vif-* hotplug
+- * scripts.
+- */
+-static int netback_uevent(struct xenbus_device *xdev,
+- struct kobj_uevent_env *env)
+-{
+- struct backend_info *be = dev_get_drvdata(&xdev->dev);
+- char *val;
+-
+- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
+- if (IS_ERR(val)) {
+- int err = PTR_ERR(val);
+- xenbus_dev_fatal(xdev, err, "reading script");
+- return err;
+- } else {
+- if (add_uevent_var(env, "script=%s", val)) {
+- kfree(val);
+- return -ENOMEM;
+- }
+- kfree(val);
+- }
+-
+- if (!be || !be->netif)
+- return 0;
+-
+- return add_uevent_var(env, "vif=%s", be->netif->dev->name);
+-}
+-
+-
+-static void backend_create_netif(struct backend_info *be)
+-{
+- int err;
+- long handle;
+- struct xenbus_device *dev = be->dev;
+-
+- if (be->netif != NULL)
+- return;
+-
+- err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
+- if (err != 1) {
+- xenbus_dev_fatal(dev, err, "reading handle");
+- return;
+- }
+-
+- be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
+- if (IS_ERR(be->netif)) {
+- err = PTR_ERR(be->netif);
+- be->netif = NULL;
+- xenbus_dev_fatal(dev, err, "creating interface");
+- return;
+- }
+-
+- kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+-}
+-
+-
+-static void disconnect_backend(struct xenbus_device *dev)
+-{
+- struct backend_info *be = dev_get_drvdata(&dev->dev);
+-
+- if (be->netif) {
+- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
+- netif_disconnect(be->netif);
+- be->netif = NULL;
+- }
+-}
-
--xen-netback-y := netback.o xenbus.o interface.o
-diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h
-deleted file mode 100644
-index 49dc4cf..0000000
---- a/drivers/xen/netback/common.h
-+++ /dev/null
-@@ -1,273 +0,0 @@
--/*
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License version 2
-- * as published by the Free Software Foundation; or, when distributed
-- * separately from the Linux kernel or incorporated into other
-- * software packages, subject to the following license:
-- *
-- * Permission is hereby granted, free of charge, to any person obtaining a copy
-- * of this source file (the "Software"), to deal in the Software without
-- * restriction, including without limitation the rights to use, copy, modify,
-- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-- * and to permit persons to whom the Software is furnished to do so, subject to
-- * the following conditions:
-- *
-- * The above copyright notice and this permission notice shall be included in
-- * all copies or substantial portions of the Software.
-- *
-- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-- * IN THE SOFTWARE.
+-/**
+- * Callback received when the frontend's state changes.
- */
+-static void frontend_changed(struct xenbus_device *dev,
+- enum xenbus_state frontend_state)
+-{
+- struct backend_info *be = dev_get_drvdata(&dev->dev);
-
--#ifndef __NETIF__BACKEND__COMMON_H__
--#define __NETIF__BACKEND__COMMON_H__
+- pr_debug("frontend state %s", xenbus_strstate(frontend_state));
-
--#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+- be->frontend_state = frontend_state;
-
--#include <linux/module.h>
--#include <linux/interrupt.h>
--#include <linux/slab.h>
--#include <linux/ip.h>
--#include <linux/in.h>
--#include <linux/io.h>
--#include <linux/netdevice.h>
--#include <linux/etherdevice.h>
--#include <linux/wait.h>
--#include <linux/sched.h>
+- switch (frontend_state) {
+- case XenbusStateInitialising:
+- if (dev->state == XenbusStateClosed) {
+- printk(KERN_INFO "%s: %s: prepare for reconnect\n",
+- __func__, dev->nodename);
+- xenbus_switch_state(dev, XenbusStateInitWait);
+- }
+- break;
-
--#include <xen/interface/io/netif.h>
--#include <asm/pgalloc.h>
--#include <xen/interface/grant_table.h>
--#include <xen/grant_table.h>
--#include <xen/xenbus.h>
+- case XenbusStateInitialised:
+- break;
-
--struct xen_netif {
-- /* Unique identifier for this interface. */
-- domid_t domid;
-- int group;
-- unsigned int handle;
+- case XenbusStateConnected:
+- if (dev->state == XenbusStateConnected)
+- break;
+- backend_create_netif(be);
+- if (be->netif)
+- connect(be);
+- break;
-
-- u8 fe_dev_addr[6];
+- case XenbusStateClosing:
+- if (be->netif)
+- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+- disconnect_backend(dev);
+- xenbus_switch_state(dev, XenbusStateClosing);
+- break;
-
-- /* Physical parameters of the comms window. */
-- grant_handle_t tx_shmem_handle;
-- grant_ref_t tx_shmem_ref;
-- grant_handle_t rx_shmem_handle;
-- grant_ref_t rx_shmem_ref;
-- unsigned int irq;
+- case XenbusStateClosed:
+- xenbus_switch_state(dev, XenbusStateClosed);
+- if (xenbus_dev_is_online(dev))
+- break;
+- /* fall through if not online */
+- case XenbusStateUnknown:
+- device_unregister(&dev->dev);
+- break;
-
-- /* The shared rings and indexes. */
-- struct xen_netif_tx_back_ring tx;
-- struct xen_netif_rx_back_ring rx;
-- struct vm_struct *tx_comms_area;
-- struct vm_struct *rx_comms_area;
+- default:
+- xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+- frontend_state);
+- break;
+- }
+-}
-
-- /* Flags that must not be set in dev->features */
-- int features_disabled;
-
-- /* Frontend feature information. */
-- u8 can_sg:1;
-- u8 gso:1;
-- u8 gso_prefix:1;
-- u8 csum:1;
+-static void xen_net_read_rate(struct xenbus_device *dev,
+- unsigned long *bytes, unsigned long *usec)
+-{
+- char *s, *e;
+- unsigned long b, u;
+- char *ratestr;
-
-- /* Internal feature information. */
-- u8 can_queue:1; /* can queue packets for receiver? */
+- /* Default to unlimited bandwidth. */
+- *bytes = ~0UL;
+- *usec = 0;
-
-- /* Allow netif_be_start_xmit() to peek ahead in the rx request
-- * ring. This is a prediction of what rx_req_cons will be once
-- * all queued skbs are put on the ring. */
-- RING_IDX rx_req_cons_peek;
+- ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
+- if (IS_ERR(ratestr))
+- return;
-
-- /* 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;
+- s = ratestr;
+- b = simple_strtoul(s, &e, 10);
+- if ((s == e) || (*e != ','))
+- goto fail;
-
-- /* Statistics */
-- int nr_copied_skbs;
-- int rx_gso_checksum_fixup;
+- s = e + 1;
+- u = simple_strtoul(s, &e, 10);
+- if ((s == e) || (*e != '\0'))
+- goto fail;
-
-- /* Miscellaneous private stuff. */
-- struct list_head list; /* scheduling list */
-- atomic_t refcnt;
-- struct net_device *dev;
-- struct net_device_stats stats;
+- *bytes = b;
+- *usec = u;
-
-- unsigned int carrier;
+- kfree(ratestr);
+- return;
-
-- wait_queue_head_t waiting_to_free;
+- fail:
+- pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
+- kfree(ratestr);
+-}
+-
+-static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+-{
+- char *s, *e, *macstr;
+- int i;
+-
+- macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+- if (IS_ERR(macstr))
+- return PTR_ERR(macstr);
+-
+- for (i = 0; i < ETH_ALEN; i++) {
+- mac[i] = simple_strtoul(s, &e, 16);
+- if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+- kfree(macstr);
+- return -ENOENT;
+- }
+- s = e+1;
+- }
+-
+- kfree(macstr);
+- return 0;
+-}
+-
+-static void unregister_hotplug_status_watch(struct backend_info *be)
+-{
+- if (be->have_hotplug_status_watch) {
+- unregister_xenbus_watch(&be->hotplug_status_watch);
+- kfree(be->hotplug_status_watch.node);
+- }
+- be->have_hotplug_status_watch = 0;
+-}
+-
+-static void hotplug_status_changed(struct xenbus_watch *watch,
+- const char **vec,
+- unsigned int vec_size)
+-{
+- struct backend_info *be = container_of(watch,
+- struct backend_info,
+- hotplug_status_watch);
+- char *str;
+- unsigned int len;
+-
+- str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status",
&len);
+- if (IS_ERR(str))
+- return;
+- if (len == sizeof("connected")-1 && !memcmp(str,
"connected", len)) {
+- xenbus_switch_state(be->dev, XenbusStateConnected);
+- /* Not interested in this watch anymore. */
+- unregister_hotplug_status_watch(be);
+- }
+- kfree(str);
+-}
+-
+-static void connect(struct backend_info *be)
+-{
+- int err;
+- struct xenbus_device *dev = be->dev;
+-
+- err = connect_rings(be);
+- if (err)
+- return;
+-
+- err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
+- if (err) {
+- xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+- return;
+- }
+-
+- xen_net_read_rate(dev, &be->netif->credit_bytes,
+- &be->netif->credit_usec);
+- be->netif->remaining_credit = be->netif->credit_bytes;
+-
+- unregister_hotplug_status_watch(be);
+- err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
+- hotplug_status_changed,
+- "%s/%s", dev->nodename, "hotplug-status");
+- if (err) {
+- /* Switch now, since we can't do a watch. */
+- xenbus_switch_state(dev, XenbusStateConnected);
+- } else {
+- be->have_hotplug_status_watch = 1;
+- }
+-
+- netif_wake_queue(be->netif->dev);
+-}
+-
+-
+-static int connect_rings(struct backend_info *be)
+-{
+- struct xen_netif *netif = be->netif;
+- struct xenbus_device *dev = be->dev;
+- unsigned long tx_ring_ref, rx_ring_ref;
+- unsigned int evtchn, rx_copy;
+- int err;
+- int val;
+-
+- err = xenbus_gather(XBT_NIL, dev->otherend,
+- "tx-ring-ref", "%lu", &tx_ring_ref,
+- "rx-ring-ref", "%lu", &rx_ring_ref,
+- "event-channel", "%u", &evtchn, NULL);
+- if (err) {
+- xenbus_dev_fatal(dev, err,
+- "reading %s/ring-ref and event-channel",
+- dev->otherend);
+- return err;
+- }
+-
+- err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy",
"%u",
+- &rx_copy);
+- if (err == -ENOENT) {
+- err = 0;
+- rx_copy = 0;
+- }
+- if (err < 0) {
+- xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
+- dev->otherend);
+- return err;
+- }
+- if (!rx_copy)
+- return -EOPNOTSUPP;
+-
+- if (netif->dev->tx_queue_len != 0) {
+- if (xenbus_scanf(XBT_NIL, dev->otherend,
+- "feature-rx-notify", "%d", &val) < 0)
+- val = 0;
+- if (val)
+- netif->can_queue = 1;
+- else
+- /* Must be non-zero for pfifo_fast to work. */
+- netif->dev->tx_queue_len = 1;
+- }
+-
+- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
+- "%d", &val) < 0)
+- val = 0;
+- netif->can_sg = !!val;
+-
+- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
+- "%d", &val) < 0)
+- val = 0;
+- netif->gso = !!val;
+-
+- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
+- "%d", &val) < 0)
+- val = 0;
+- netif->gso_prefix = !!val;
+-
+- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
+- "%d", &val) < 0)
+- val = 0;
+- netif->csum = !val;
+-
+- /* Set dev->features */
+- netif_set_features(netif);
+-
+- /* Map the shared frame, irq etc. */
+- err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
+- if (err) {
+- xenbus_dev_fatal(dev, err,
+- "mapping shared-frames %lu/%lu port %u",
+- tx_ring_ref, rx_ring_ref, evtchn);
+- return err;
+- }
+- return 0;
+-}
+-
+-
+-/* ** Driver Registration ** */
+-
+-
+-static const struct xenbus_device_id netback_ids[] = {
+- { "vif" },
+- { "" }
-};
-
--/*
-- * Implement our own carrier flag: the network stack's version causes delays
-- * when the carrier is re-enabled (in particular, dev_activate() may not
-- * immediately be called, which can cause packet loss; also the etherbridge
-- * can be rather lazy in activating its port).
-- */
--#define netback_carrier_on(netif) ((netif)->carrier = 1)
--#define netback_carrier_off(netif) ((netif)->carrier = 0)
--#define netback_carrier_ok(netif) ((netif)->carrier)
-
--enum {
-- NETBK_DONT_COPY_SKB,
-- NETBK_DELAYED_COPY_SKB,
-- NETBK_ALWAYS_COPY_SKB,
+-static struct xenbus_driver netback = {
+- .name = "vif",
+- .owner = THIS_MODULE,
+- .ids = netback_ids,
+- .probe = netback_probe,
+- .remove = netback_remove,
+- .uevent = netback_uevent,
+- .otherend_changed = frontend_changed,
-};
-
--extern int netbk_copy_skb_mode;
-
--struct backend_info {
-- struct xenbus_device *dev;
+-int netif_xenbus_init(void)
+-{
+- printk(KERN_CRIT "registering netback\n");
+- return xenbus_register_backend(&netback);
+-}
+--
+1.7.4
+
+
+From 932240f6f2a1ee52e330e281069efd2f728ff7ed Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 13:02:14 +0000
+Subject: [PATCH 085/203] xen: netback: remove queue_length module option
+
+This setting can be controlled via sysfs.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/interface.c | 11 ++---------
+ 1 files changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index b429f8c..249f010 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -36,14 +36,7 @@
+ #include <xen/events.h>
+ #include <asm/xen/hypercall.h>
+
+-/*
+- * Module parameter 'queue_length':
+- *
+- * Enables queuing in the network stack when a client has run out of receive
+- * descriptors.
+- */
+-static unsigned long netbk_queue_length = 32;
+-module_param_named(queue_length, netbk_queue_length, ulong, 0644);
++#define NETBK_QUEUE_LENGTH 32
+
+ static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
+ struct xen_netif *netif)
+@@ -296,7 +289,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
+ netif_set_features(netif);
+ SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+
+- dev->tx_queue_len = netbk_queue_length;
++ dev->tx_queue_len = NETBK_QUEUE_LENGTH;
+
+ /*
+ * Initialise a dummy MAC address. We choose the numerically
+--
+1.7.4
+
+
+From 96568c3f81c7ba4d4fea43be791e4a773331ed7c Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 14:16:52 +0000
+Subject: [PATCH 086/203] xen: netback: correct error return from ethtool hooks.
+
+Should be -EOPNOTSUPP not -ENOSYS.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/interface.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index 249f010..c41d93e 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -130,7 +130,7 @@ static int netbk_set_tx_csum(struct net_device *dev, u32 data)
+ struct xen_netif *netif = netdev_priv(dev);
+ if (data) {
+ if (!netif->csum)
+- return -ENOSYS;
++ return -EOPNOTSUPP;
+ netif->features_disabled &= ~NETIF_F_IP_CSUM;
+ } else {
+ netif->features_disabled |= NETIF_F_IP_CSUM;
+@@ -145,7 +145,7 @@ static int netbk_set_sg(struct net_device *dev, u32 data)
+ struct xen_netif *netif = netdev_priv(dev);
+ if (data) {
+ if (!netif->can_sg)
+- return -ENOSYS;
++ return -EOPNOTSUPP;
+ netif->features_disabled &= ~NETIF_F_SG;
+ } else {
+ netif->features_disabled |= NETIF_F_SG;
+@@ -160,7 +160,7 @@ static int netbk_set_tso(struct net_device *dev, u32 data)
+ struct xen_netif *netif = netdev_priv(dev);
+ if (data) {
+ if (!netif->gso && !netif->gso_prefix)
+- return -ENOSYS;
++ return -EOPNOTSUPP;
+ netif->features_disabled &= ~NETIF_F_TSO;
+ } else {
+ netif->features_disabled |= NETIF_F_TSO;
+--
+1.7.4
+
+
+From 12a5b4f364888f291bcd8e38a146f30fcceb9588 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 14:20:04 +0000
+Subject: [PATCH 087/203] xen: netback: avoid leading _ in function parameter names.
+
+It is usually used to distinguish lower-level functions or to avoid naming
+conflicts in macros.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/netback.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index b290525..cd2af15 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -90,7 +90,7 @@ static inline void netif_set_page_ext(struct page *pg,
+ }
+
+ static int netif_get_page_ext(struct page *pg,
+- unsigned int *_group, unsigned int *_idx)
++ unsigned int *pgroup, unsigned int *pidx)
+ {
+ union page_ext ext = { .mapping = pg->mapping };
+ struct xen_netbk *netbk;
+@@ -117,8 +117,8 @@ static int netif_get_page_ext(struct page *pg,
+ if (netbk->mmap_pages[idx] != pg)
+ return 0;
+
+- *_group = group;
+- *_idx = idx;
++ *pgroup = group;
++ *pidx = idx;
+
+ return 1;
+ }
+--
+1.7.4
+
+
+From a789731f0ed97fc762835a568f2fefbf0d490ccf Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 14:21:24 +0000
+Subject: [PATCH 088/203] xen: netback: drop unused debug interrupt handler.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/netback.c | 57 -------------------------------------
+ 1 files changed, 0 insertions(+), 57 deletions(-)
+
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index cd2af15..a7646f3 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -47,8 +47,6 @@
+ #include <asm/xen/hypercall.h>
+ #include <asm/xen/page.h>
+
+-/*define NETBE_DEBUG_INTERRUPT*/
+-
+ struct xen_netbk *xen_netbk;
+ int xen_netbk_group_nr;
+
+@@ -1707,52 +1705,6 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
+ return resp;
+ }
+
+-#ifdef NETBE_DEBUG_INTERRUPT
+-static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
+-{
+- struct list_head *ent;
- struct xen_netif *netif;
-- enum xenbus_state frontend_state;
-- struct xenbus_watch hotplug_status_watch;
-- int have_hotplug_status_watch:1;
--};
--
--#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
--#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+- int i = 0;
+- int group = 0;
-
--void netif_disconnect(struct xen_netif *netif);
+- printk(KERN_ALERT "netif_schedule_list:\n");
-
--void netif_set_features(struct xen_netif *netif);
--struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-- unsigned int handle);
--int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
-- unsigned long rx_ring_ref, unsigned int evtchn);
+- for (group = 0; group < xen_netbk_group_nr; group++) {
+- struct xen_netbk *netbk = &xen_netbk[group];
+- spin_lock_irq(&netbk->net_schedule_list_lock);
+- printk(KERN_ALERT "xen_netback group number: %d\n", group);
+- list_for_each(ent, &netbk->net_schedule_list) {
+- netif = list_entry(ent, struct xen_netif, list);
+- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
+- "rx_resp_prod=%08x\n",
+- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
+- printk(KERN_ALERT
+- " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
+- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
+- printk(KERN_ALERT
+- " shared(rx_req_prod=%08x "
+- "rx_resp_prod=%08x\n",
+- netif->rx.sring->req_prod,
+- netif->rx.sring->rsp_prod);
+- printk(KERN_ALERT
+- " rx_event=%08x, tx_req_prod=%08x\n",
+- netif->rx.sring->rsp_event,
+- netif->tx.sring->req_prod);
+- printk(KERN_ALERT
+- " tx_resp_prod=%08x, tx_event=%08x)\n",
+- netif->tx.sring->rsp_prod,
+- netif->tx.sring->rsp_event);
+- i++;
+- }
+- spin_unlock_irq(&netbk->net_schedule_list_lock);
+- }
-
--static inline void netif_get(struct xen_netif *netif)
--{
-- atomic_inc(&netif->refcnt);
--}
+- printk(KERN_ALERT " ** End of netif_schedule_list **\n");
-
--static inline void netif_put(struct xen_netif *netif)
--{
-- if (atomic_dec_and_test(&netif->refcnt))
-- wake_up(&netif->waiting_to_free);
+- return IRQ_HANDLED;
-}
+-#endif
-
--int netif_xenbus_init(void);
--
--#define netif_schedulable(netif) \
-- (netif_running((netif)->dev) && netback_carrier_ok(netif))
--
--void netif_schedule_work(struct xen_netif *netif);
--void netif_deschedule_work(struct xen_netif *netif);
--
--int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
--struct net_device_stats *netif_be_get_stats(struct net_device *dev);
--irqreturn_t netif_be_int(int irq, void *dev_id);
+ static inline int rx_work_todo(struct xen_netbk *netbk)
+ {
+ return !skb_queue_empty(&netbk->rx_queue);
+@@ -1903,15 +1855,6 @@ static int __init netback_init(void)
+ if (rc)
+ goto failed_init;
+
+-#ifdef NETBE_DEBUG_INTERRUPT
+- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
+- 0,
+- netif_be_dbg,
+- IRQF_SHARED,
+- "net-be-dbg",
+- &netif_be_dbg);
+-#endif
-
--static inline int netbk_can_queue(struct net_device *dev)
+ return 0;
+
+ failed_init:
+--
+1.7.4
+
+
+From 056508bc941b3715c72a5fa00a6b38a006979dd9 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 16:42:27 +0000
+Subject: [PATCH 089/203] xen: netif: properly namespace the Xen netif protocol header.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/netback.c | 38 +++++++++---------
+ drivers/net/xen-netfront.c | 20 +++++-----
+ include/xen/interface/io/netif.h | 80 ++++++++++++++++++------------------
+ 3 files changed, 69 insertions(+), 69 deletions(-)
+
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index a7646f3..69b4535 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -582,7 +582,7 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+ struct netrx_pending_operations *npo)
+ {
+ struct gnttab_copy *copy_op;
+- int status = NETIF_RSP_OKAY;
++ int status = XEN_NETIF_RSP_OKAY;
+ int i;
+
+ for (i = 0; i < nr_meta_slots; i++) {
+@@ -590,7 +590,7 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+ if (copy_op->status != GNTST_okay) {
+ pr_debug("Bad status %d from copy to DOM%d.\n",
+ copy_op->status, domid);
+- status = NETIF_RSP_ERROR;
++ status = XEN_NETIF_RSP_ERROR;
+ }
+ }
+
+@@ -615,7 +615,7 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
+ if (i == nr_meta_slots - 1)
+ flags = 0;
+ else
+- flags = NETRXF_more_data;
++ flags = XEN_NETRXF_more_data;
+
+ offset = 0;
+ make_rx_response(netif, meta[i].id, status, offset,
+@@ -687,7 +687,7 @@ static void net_rx_action(unsigned long data)
+ resp = RING_GET_RESPONSE(&netif->rx,
+ netif->rx.rsp_prod_pvt++);
+
+- resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
++ resp->flags = XEN_NETRXF_gso_prefix | XEN_NETRXF_more_data;
+
+ resp->offset = netbk->meta[npo.meta_cons].gso_size;
+ resp->id = netbk->meta[npo.meta_cons].id;
+@@ -707,13 +707,13 @@ static void net_rx_action(unsigned long data)
+ if (sco->meta_slots_used == 1)
+ flags = 0;
+ else
+- flags = NETRXF_more_data;
++ flags = XEN_NETRXF_more_data;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
+- flags |= NETRXF_csum_blank | NETRXF_data_validated;
++ flags |= XEN_NETRXF_csum_blank | XEN_NETRXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed. */
+- flags |= NETRXF_data_validated;
++ flags |= XEN_NETRXF_data_validated;
+
+ offset = 0;
+ resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
+@@ -727,7 +727,7 @@ static void net_rx_action(unsigned long data)
+ RING_GET_RESPONSE(&netif->rx,
+ netif->rx.rsp_prod_pvt++);
+
+- resp->flags |= NETRXF_extra_info;
++ resp->flags |= XEN_NETRXF_extra_info;
+
+ gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+@@ -989,7 +989,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
+ netif = pending_tx_info[pending_idx].netif;
+
+ make_tx_response(netif, &pending_tx_info[pending_idx].req,
+- NETIF_RSP_OKAY);
++ XEN_NETIF_RSP_OKAY);
+
+ /* Ready for next use. */
+ gnttab_reset_grant_page(netbk->mmap_pages[pending_idx]);
+@@ -1009,7 +1009,7 @@ static void netbk_tx_err(struct xen_netif *netif,
+ RING_IDX cons = netif->tx.req_cons;
+
+ do {
+- make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
+ if (cons >= end)
+ break;
+ txp = RING_GET_REQUEST(&netif->tx, cons++);
+@@ -1027,7 +1027,7 @@ static int netbk_count_requests(struct xen_netif *netif,
+ RING_IDX cons = netif->tx.req_cons;
+ int frags = 0;
+
+- if (!(first->flags & NETTXF_more_data))
++ if (!(first->flags & XEN_NETTXF_more_data))
+ return 0;
+
+ do {
+@@ -1056,7 +1056,7 @@ static int netbk_count_requests(struct xen_netif *netif,
+ txp->offset, txp->size);
+ return -frags;
+ }
+- } while ((txp++)->flags & NETTXF_more_data);
++ } while ((txp++)->flags & XEN_NETTXF_more_data);
+
+ return frags;
+ }
+@@ -1115,7 +1115,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+ pending_ring_idx_t index;
+ index = pending_index(netbk->pending_prod++);
+ txp = &pending_tx_info[pending_idx].req;
+- make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
+ netbk->pending_ring[index] = pending_idx;
+ netif_put(netif);
+ } else {
+@@ -1151,7 +1151,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+
+ /* Error on this fragment: respond to client with an error. */
+ txp = &netbk->pending_tx_info[pending_idx].req;
+- make_tx_response(netif, txp, NETIF_RSP_ERROR);
++ make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
+ index = pending_index(netbk->pending_prod++);
+ netbk->pending_ring[index] = pending_idx;
+ netif_put(netif);
+@@ -1406,7 +1406,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ netif->tx.req_cons = ++idx;
+
+ memset(extras, 0, sizeof(extras));
+- if (txreq.flags & NETTXF_extra_info) {
++ if (txreq.flags & XEN_NETTXF_extra_info) {
+ work_to_do = netbk_get_extras(netif, extras,
+ work_to_do);
+ idx = netif->tx.req_cons;
+@@ -1542,9 +1542,9 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ netif_idx_release(netbk, pending_idx);
+ }
+
+- if (txp->flags & NETTXF_csum_blank)
++ if (txp->flags & XEN_NETTXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+- else if (txp->flags & NETTXF_data_validated)
++ else if (txp->flags & XEN_NETTXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netbk_fill_frags(netbk, skb);
+@@ -1673,8 +1673,8 @@ static void make_tx_response(struct xen_netif *netif,
+ resp->id = txp->id;
+ resp->status = st;
+
+- if (txp->flags & NETTXF_extra_info)
+- RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
++ if (txp->flags & XEN_NETTXF_extra_info)
++ RING_GET_RESPONSE(&netif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+
+ netif->tx.rsp_prod_pvt = ++i;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
+diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
+index 458bb57..cc23d42 100644
+--- a/drivers/net/xen-netfront.c
++++ b/drivers/net/xen-netfront.c
+@@ -356,7 +356,7 @@ static void xennet_tx_buf_gc(struct net_device *dev)
+ struct xen_netif_tx_response *txrsp;
+
+ txrsp = RING_GET_RESPONSE(&np->tx, cons);
+- if (txrsp->status == NETIF_RSP_NULL)
++ if (txrsp->status == XEN_NETIF_RSP_NULL)
+ continue;
+
+ id = txrsp->id;
+@@ -413,7 +413,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device
*dev,
+ larger than a page), split it it into page-sized chunks. */
+ while (len > PAGE_SIZE - offset) {
+ tx->size = PAGE_SIZE - offset;
+- tx->flags |= NETTXF_more_data;
++ tx->flags |= XEN_NETTXF_more_data;
+ len -= tx->size;
+ data += tx->size;
+ offset = 0;
+@@ -439,7 +439,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device
*dev,
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+- tx->flags |= NETTXF_more_data;
++ tx->flags |= XEN_NETTXF_more_data;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+@@ -514,10 +514,10 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ tx->flags = 0;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ /* local packet? */
+- tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
++ tx->flags |= XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed. */
+- tx->flags |= NETTXF_data_validated;
++ tx->flags |= XEN_NETTXF_data_validated;
+
+ if (skb_shinfo(skb)->gso_size) {
+ struct xen_netif_extra_info *gso;
+@@ -528,7 +528,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ if (extra)
+ extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+ else
+- tx->flags |= NETTXF_extra_info;
++ tx->flags |= XEN_NETTXF_extra_info;
+
+ gso->u.gso.size = skb_shinfo(skb)->gso_size;
+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+@@ -648,7 +648,7 @@ static int xennet_get_responses(struct netfront_info *np,
+ int err = 0;
+ unsigned long ret;
+
+- if (rx->flags & NETRXF_extra_info) {
++ if (rx->flags & XEN_NETRXF_extra_info) {
+ err = xennet_get_extras(np, extras, rp);
+ cons = np->rx.rsp_cons;
+ }
+@@ -685,7 +685,7 @@ static int xennet_get_responses(struct netfront_info *np,
+ __skb_queue_tail(list, skb);
+
+ next:
+- if (!(rx->flags & NETRXF_more_data))
++ if (!(rx->flags & XEN_NETRXF_more_data))
+ break;
+
+ if (cons + frags == rp) {
+@@ -950,9 +950,9 @@ err:
+ skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+ skb->len += skb->data_len;
+
+- if (rx->flags & NETRXF_csum_blank)
++ if (rx->flags & XEN_NETRXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+- else if (rx->flags & NETRXF_data_validated)
++ else if (rx->flags & XEN_NETRXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ __skb_queue_tail(&rxq, skb);
+diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
+index 8309344..cb94668 100644
+--- a/include/xen/interface/io/netif.h
++++ b/include/xen/interface/io/netif.h
+@@ -22,50 +22,50 @@
+
+ /*
+ * This is the 'wire' format for packets:
+- * Request 1: netif_tx_request -- NETTXF_* (any flags)
+- * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info)
+- * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE)
+- * Request 4: netif_tx_request -- NETTXF_more_data
+- * Request 5: netif_tx_request -- NETTXF_more_data
++ * Request 1: xen_netif_tx_request -- XEN_NETTXF_* (any flags)
++ * [Request 2: xen_netif_extra_info] (only if request 1 has XEN_NETTXF_extra_info)
++ * [Request 3: xen_netif_extra_info] (only if request 2 has XEN_NETIF_EXTRA_MORE)
++ * Request 4: xen_netif_tx_request -- XEN_NETTXF_more_data
++ * Request 5: xen_netif_tx_request -- XEN_NETTXF_more_data
+ * ...
+- * Request N: netif_tx_request -- 0
++ * Request N: xen_netif_tx_request -- 0
+ */
+
+ /* Protocol checksum field is blank in the packet (hardware offload)? */
+-#define _NETTXF_csum_blank (0)
+-#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank)
++#define _XEN_NETTXF_csum_blank (0)
++#define XEN_NETTXF_csum_blank (1U<<_XEN_NETTXF_csum_blank)
+
+ /* Packet data has been validated against protocol checksum. */
+-#define _NETTXF_data_validated (1)
+-#define NETTXF_data_validated (1U<<_NETTXF_data_validated)
++#define _XEN_NETTXF_data_validated (1)
++#define XEN_NETTXF_data_validated (1U<<_XEN_NETTXF_data_validated)
+
+ /* Packet continues in the next request descriptor. */
+-#define _NETTXF_more_data (2)
+-#define NETTXF_more_data (1U<<_NETTXF_more_data)
++#define _XEN_NETTXF_more_data (2)
++#define XEN_NETTXF_more_data (1U<<_XEN_NETTXF_more_data)
+
+ /* Packet to be followed by extra descriptor(s). */
+-#define _NETTXF_extra_info (3)
+-#define NETTXF_extra_info (1U<<_NETTXF_extra_info)
++#define _XEN_NETTXF_extra_info (3)
++#define XEN_NETTXF_extra_info (1U<<_XEN_NETTXF_extra_info)
+
+ struct xen_netif_tx_request {
+ grant_ref_t gref; /* Reference to buffer page */
+ uint16_t offset; /* Offset within buffer page */
+- uint16_t flags; /* NETTXF_* */
++ uint16_t flags; /* XEN_NETTXF_* */
+ uint16_t id; /* Echoed in response message. */
+ uint16_t size; /* Packet size in bytes. */
+ };
+
+-/* Types of netif_extra_info descriptors. */
+-#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
+-#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
+-#define XEN_NETIF_EXTRA_TYPE_MAX (2)
++/* Types of xen_netif_extra_info descriptors. */
++#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
++#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
++#define XEN_NETIF_EXTRA_TYPE_MAX (2)
+
+-/* netif_extra_info flags. */
+-#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
+-#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
++/* xen_netif_extra_info flags. */
++#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
++#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+
+ /* GSO types - only TCPv4 currently supported. */
+-#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
++#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
+
+ /*
+ * This structure needs to fit within both netif_tx_request and
+@@ -107,7 +107,7 @@ struct xen_netif_extra_info {
+
+ struct xen_netif_tx_response {
+ uint16_t id;
+- int16_t status; /* NETIF_RSP_* */
++ int16_t status; /* XEN_NETIF_RSP_* */
+ };
+
+ struct xen_netif_rx_request {
+@@ -116,29 +116,29 @@ struct xen_netif_rx_request {
+ };
+
+ /* Packet data has been validated against protocol checksum. */
+-#define _NETRXF_data_validated (0)
+-#define NETRXF_data_validated (1U<<_NETRXF_data_validated)
++#define _XEN_NETRXF_data_validated (0)
++#define XEN_NETRXF_data_validated (1U<<_XEN_NETRXF_data_validated)
+
+ /* Protocol checksum field is blank in the packet (hardware offload)? */
+-#define _NETRXF_csum_blank (1)
+-#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank)
++#define _XEN_NETRXF_csum_blank (1)
++#define XEN_NETRXF_csum_blank (1U<<_XEN_NETRXF_csum_blank)
+
+ /* Packet continues in the next request descriptor. */
+-#define _NETRXF_more_data (2)
+-#define NETRXF_more_data (1U<<_NETRXF_more_data)
++#define _XEN_NETRXF_more_data (2)
++#define XEN_NETRXF_more_data (1U<<_XEN_NETRXF_more_data)
+
+ /* Packet to be followed by extra descriptor(s). */
+-#define _NETRXF_extra_info (3)
+-#define NETRXF_extra_info (1U<<_NETRXF_extra_info)
++#define _XEN_NETRXF_extra_info (3)
++#define XEN_NETRXF_extra_info (1U<<_XEN_NETRXF_extra_info)
+
+ /* GSO Prefix descriptor. */
+-#define _NETRXF_gso_prefix (4)
+-#define NETRXF_gso_prefix (1U<<_NETRXF_gso_prefix)
++#define _XEN_NETRXF_gso_prefix (4)
++#define XEN_NETRXF_gso_prefix (1U<<_XEN_NETRXF_gso_prefix)
+
+ struct xen_netif_rx_response {
+ uint16_t id;
+ uint16_t offset; /* Offset in page of start of received packet */
+- uint16_t flags; /* NETRXF_* */
++ uint16_t flags; /* XEN_NETRXF_* */
+ int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
+ };
+
+@@ -153,10 +153,10 @@ DEFINE_RING_TYPES(xen_netif_rx,
+ struct xen_netif_rx_request,
+ struct xen_netif_rx_response);
+
+-#define NETIF_RSP_DROPPED -2
+-#define NETIF_RSP_ERROR -1
+-#define NETIF_RSP_OKAY 0
+-/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
+-#define NETIF_RSP_NULL 1
++#define XEN_NETIF_RSP_DROPPED -2
++#define XEN_NETIF_RSP_ERROR -1
++#define XEN_NETIF_RSP_OKAY 0
++/* No response: used for auxiliary requests (e.g., xen_netif_extra_info). */
++#define XEN_NETIF_RSP_NULL 1
+
+ #endif
+--
+1.7.4
+
+
+From 16d8ace0b7af72fb9e355eee165251e1f9b511e1 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 1 Feb 2011 16:50:24 +0000
+Subject: [PATCH 090/203] xen: netif: improve Kconfig help text for front- and backend
drivers.
+
+Signed-off-by: Ian Campell <ian.campbell(a)citrix.com>
+---
+ drivers/net/Kconfig | 35 +++++++++++++++++++++++++++--------
+ 1 files changed, 27 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 5b088f5..1c77e183 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -2963,19 +2963,38 @@ config XEN_NETDEV_FRONTEND
+ select XEN_XENBUS_FRONTEND
+ default y
+ help
+- The network device frontend driver allows the kernel to
+- access network devices exported exported by a virtual
+- machine containing a physical network device driver. The
+- frontend driver is intended for unprivileged guest domains;
+- if you are compiling a kernel for a Xen guest, you almost
+- certainly want to enable this.
++ This driver provides support for Xen paravirtual network
++ devices exported by a Xen network driver domain (often
++ domain 0).
++
++ The corresponding Linux backend driver is enabled by the
++ CONFIG_XEN_NETDEV_BACKEND option.
++
++ If you are compiling a kernel for use as Xen guest, you
++ should say Y here. To compile this driver as a module, chose
++ M here: the module will be called xen-netfront.
+
+ config XEN_NETDEV_BACKEND
+ tristate "Xen backend network device"
+ depends on XEN_BACKEND
+ help
+- Implement the network backend driver, which passes packets
+- from the guest domain's frontend drivers to the network.
++ This driver allows the kernel to act as a Xen network driver
++ domain which exports paravirtual network devices to other
++ Xen domains. These devices can be accessed by any operating
++ system that implements a compatible front end.
++
++ The corresponding Linux frontend driver is enabled by the
++ CONFIG_XEN_NETDEV_FRONTEND configuration option.
++
++ The backend driver presents a standard network device
++ endpoint for each paravirtual network device to the driver
++ domain network stack. These can then be bridged or routed
++ etc in order to provide full network connectivity.
++
++ If you are compiling a kernel to run in a Xen network driver
++ domain (often this is domain 0) you should say Y here. To
++ compile this driver as a module, chose M here: the module
++ will be called xen-netback.
+
+ config ISERIES_VETH
+ tristate "iSeries Virtual Ethernet driver support"
+--
+1.7.4
+
+
+From 54f3edcf01cab556198efc7d576d9feb4b836569 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Wed, 19 Jan 2011 14:41:55 +0000
+Subject: [PATCH 091/203] xen: netback: drop ethtool drvinfo callback
+
+The default provided by the network core is sufficient for our needs.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/interface.c | 9 ---------
+ 1 files changed, 0 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index c41d93e..28b0832 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -170,13 +170,6 @@ static int netbk_set_tso(struct net_device *dev, u32 data)
+ return 0;
+ }
+
+-static void netbk_get_drvinfo(struct net_device *dev,
+- struct ethtool_drvinfo *info)
-{
-- struct xen_netif *netif = netdev_priv(dev);
-- return netif->can_queue;
+- strcpy(info->driver, "netbk");
+- strcpy(info->bus_info, dev_name(dev->dev.parent));
-}
-
--static inline int netbk_can_sg(struct net_device *dev)
--{
-- struct xen_netif *netif = netdev_priv(dev);
-- return netif->can_sg;
--}
+ static const struct netif_stat {
+ char name[ETH_GSTRING_LEN];
+ u16 offset;
+@@ -225,8 +218,6 @@ static void netbk_get_strings(struct net_device *dev, u32 stringset,
u8 * data)
+ }
+
+ static struct ethtool_ops network_ethtool_ops = {
+- .get_drvinfo = netbk_get_drvinfo,
-
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = netbk_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+--
+1.7.4
+
+
+From 02f5acfcf4ad6c982c7eb0c6fd361749ad9140cd Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 16:24:28 +0000
+Subject: [PATCH 092/203] xen: netback: use xen_netbk prefix where appropriate
+
+Do not use net_ of netif_ since these belong to the network core.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/netback.c | 84 ++++++++++++++++++------------------
+ 1 files changed, 42 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index 69b4535..6ed4459 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -50,7 +50,7 @@
+ struct xen_netbk *xen_netbk;
+ int xen_netbk_group_nr;
+
+-static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
++static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+ static void make_tx_response(struct xen_netif *netif,
+ struct xen_netif_tx_request *txp,
+ s8 st);
+@@ -61,9 +61,9 @@ static struct xen_netif_rx_response *make_rx_response(struct xen_netif
*netif,
+ u16 size,
+ u16 flags);
+
+-static void net_tx_action(unsigned long data);
++static void xen_netbk_tx_action(unsigned long data);
+
+-static void net_rx_action(unsigned long data);
++static void xen_netbk_rx_action(unsigned long data);
+
+ static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
+ unsigned int idx)
+@@ -78,8 +78,8 @@ static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
+ }
+
+ /* extra field used in struct page */
+-static inline void netif_set_page_ext(struct page *pg,
+- unsigned int group, unsigned int idx)
++static inline void set_page_ext(struct page *pg,
++ unsigned int group, unsigned int idx)
+ {
+ union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
+
+@@ -87,8 +87,8 @@ static inline void netif_set_page_ext(struct page *pg,
+ pg->mapping = ext.mapping;
+ }
+
+-static int netif_get_page_ext(struct page *pg,
+- unsigned int *pgroup, unsigned int *pidx)
++static int get_page_ext(struct page *pg,
++ unsigned int *pgroup, unsigned int *pidx)
+ {
+ union page_ext ext = { .mapping = pg->mapping };
+ struct xen_netbk *netbk;
+@@ -445,11 +445,11 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ struct gnttab_copy *copy_gop;
+ struct netbk_rx_meta *meta;
+ /*
+- * These variables a used iff netif_get_page_ext returns true,
++ * These variables a used iff get_page_ext returns true,
+ * in which case they are guaranteed to be initialized.
+ */
+ unsigned int uninitialized_var(group), uninitialized_var(idx);
+- int foreign = netif_get_page_ext(page, &group, &idx);
++ int foreign = get_page_ext(page, &group, &idx);
+ unsigned long bytes;
+
+ /* Data must not cross a page boundary. */
+@@ -627,7 +627,7 @@ struct skb_cb_overlay {
+ int meta_slots_used;
+ };
+
+-static void net_rx_action(unsigned long data)
++static void xen_netbk_rx_action(unsigned long data)
+ {
+ struct xen_netif *netif = NULL;
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+@@ -915,7 +915,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
+ do {
+ dp = netbk->dealloc_prod;
+
+- /* Ensure we see all indices enqueued by netif_idx_release(). */
++ /* Ensure we see all indices enqueued by xen_netbk_idx_release(). */
+ smp_rmb();
+
+ while (dc != dp) {
+@@ -1061,11 +1061,11 @@ static int netbk_count_requests(struct xen_netif *netif,
+ return frags;
+ }
+
+-static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
+- struct xen_netif *netif,
+- struct sk_buff *skb,
+- struct xen_netif_tx_request *txp,
+- struct gnttab_map_grant_ref *mop)
++static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
++ struct xen_netif *netif,
++ struct sk_buff *skb,
++ struct xen_netif_tx_request *txp,
++ struct gnttab_map_grant_ref *mop)
+ {
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ skb_frag_t *frags = shinfo->frags;
+@@ -1096,9 +1096,9 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netbk *netbk,
+ return mop;
+ }
+
+-static int netbk_tx_check_mop(struct xen_netbk *netbk,
+- struct sk_buff *skb,
+- struct gnttab_map_grant_ref **mopp)
++static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
++ struct sk_buff *skb,
++ struct gnttab_map_grant_ref **mopp)
+ {
+ struct gnttab_map_grant_ref *mop = *mopp;
+ int pending_idx = *((u16 *)skb->data);
+@@ -1145,7 +1145,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+ netbk->grant_tx_handle[pending_idx] = mop->handle;
+ /* Had a previous error? Invalidate this fragment. */
+ if (unlikely(err))
+- netif_idx_release(netbk, pending_idx);
++ xen_netbk_idx_release(netbk, pending_idx);
+ continue;
+ }
+
+@@ -1162,10 +1162,10 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+
+ /* First error: invalidate header and preceding fragments. */
+ pending_idx = *((u16 *)skb->data);
+- netif_idx_release(netbk, pending_idx);
++ xen_netbk_idx_release(netbk, pending_idx);
+ for (j = start; j < i; j++) {
+ pending_idx = (unsigned long)shinfo->frags[i].page;
+- netif_idx_release(netbk, pending_idx);
++ xen_netbk_idx_release(netbk, pending_idx);
+ }
+
+ /* Remember the error: invalidate all subsequent fragments. */
+@@ -1176,7 +1176,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+ return err;
+ }
+
+-static void netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
++static void xen_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;
+@@ -1359,7 +1359,7 @@ static bool tx_credit_exceeded(struct xen_netif *netif, unsigned
size)
+ return false;
+ }
+
+-static unsigned net_tx_build_mops(struct xen_netbk *netbk)
++static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ {
+ struct gnttab_map_grant_ref *mop;
+ struct sk_buff *skb;
+@@ -1493,7 +1493,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+
+ netbk->pending_cons++;
+
+- mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
++ mop = xen_netbk_get_requests(netbk, netif, skb, txfrags, mop);
+
+ netif->tx.req_cons = idx;
+ netif_schedule_work(netif);
+@@ -1505,7 +1505,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ return mop - netbk->tx_map_ops;
+ }
+
+-static void net_tx_submit(struct xen_netbk *netbk)
++static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ {
+ struct gnttab_map_grant_ref *mop;
+ struct sk_buff *skb;
+@@ -1522,7 +1522,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ txp = &netbk->pending_tx_info[pending_idx].req;
+
+ /* Check the remap error code. */
+- if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
++ if (unlikely(xen_netbk_tx_check_mop(netbk, skb, &mop))) {
+ pr_debug("netback grant failed.\n");
+ skb_shinfo(skb)->nr_frags = 0;
+ kfree_skb(skb);
+@@ -1539,7 +1539,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ txp->size -= data_len;
+ } else {
+ /* Schedule a response immediately. */
+- netif_idx_release(netbk, pending_idx);
++ xen_netbk_idx_release(netbk, pending_idx);
+ }
+
+ if (txp->flags & XEN_NETTXF_csum_blank)
+@@ -1547,7 +1547,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ else if (txp->flags & XEN_NETTXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+- netbk_fill_frags(netbk, skb);
++ xen_netbk_fill_frags(netbk, skb);
+
+ /*
+ * If the initial fragment was < PKT_PROT_LEN then
+@@ -1584,7 +1584,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+ }
+
+ /* Called after netfront has transmitted */
+-static void net_tx_action(unsigned long data)
++static void xen_netbk_tx_action(unsigned long data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ unsigned nr_mops;
+@@ -1592,7 +1592,7 @@ static void net_tx_action(unsigned long data)
+
+ net_tx_action_dealloc(netbk);
+
+- nr_mops = net_tx_build_mops(netbk);
++ nr_mops = xen_netbk_tx_build_mops(netbk);
+
+ if (nr_mops == 0)
+ goto out;
+@@ -1601,7 +1601,7 @@ static void net_tx_action(unsigned long data)
+ netbk->tx_map_ops, nr_mops);
+ BUG_ON(ret);
+
+- net_tx_submit(netbk);
++ xen_netbk_tx_submit(netbk);
+ out:
+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+ !list_empty(&netbk->pending_inuse_head)) {
+@@ -1614,7 +1614,7 @@ out:
+ }
+ }
+
+-static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
++static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+ {
+ static DEFINE_SPINLOCK(_lock);
+ unsigned long flags;
+@@ -1634,12 +1634,12 @@ static void netif_idx_release(struct xen_netbk *netbk, u16
pending_idx)
+ static void netif_page_release(struct page *page, unsigned int order)
+ {
+ unsigned int group, idx;
+- int foreign = netif_get_page_ext(page, &group, &idx);
++ int foreign = get_page_ext(page, &group, &idx);
+
+ BUG_ON(!foreign);
+ BUG_ON(order);
+
+- netif_idx_release(&xen_netbk[group], idx);
++ xen_netbk_idx_release(&xen_netbk[group], idx);
+ }
+
+ irqreturn_t netif_be_int(int irq, void *dev_id)
+@@ -1726,7 +1726,7 @@ static inline int tx_work_todo(struct xen_netbk *netbk)
+ return 0;
+ }
+
+-static int netbk_action_thread(void *data)
++static int xen_netbk_action_thread(void *data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ while (!kthread_should_stop()) {
+@@ -1740,10 +1740,10 @@ static int netbk_action_thread(void *data)
+ break;
+
+ if (rx_work_todo(netbk))
+- net_rx_action((unsigned long)netbk);
++ xen_netbk_rx_action((unsigned long)netbk);
+
+ if (tx_work_todo(netbk))
+- net_tx_action((unsigned long)netbk);
++ xen_netbk_tx_action((unsigned long)netbk);
+ }
+
+ return 0;
+@@ -1794,7 +1794,7 @@ static int __init netback_init(void)
+ 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);
++ set_page_ext(page, group, i);
+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
+
+@@ -1806,7 +1806,7 @@ static int __init netback_init(void)
+ if (MODPARM_netback_kthread) {
+ init_waitqueue_head(&netbk->kthread.netbk_action_wq);
+ netbk->kthread.task =
+- kthread_create(netbk_action_thread,
++ kthread_create(xen_netbk_action_thread,
+ (void *)netbk,
+ "netback/%u", group);
+
+@@ -1824,10 +1824,10 @@ static int __init netback_init(void)
+ }
+ } else {
+ tasklet_init(&netbk->tasklet.net_tx_tasklet,
+- net_tx_action,
++ xen_netbk_tx_action,
+ (unsigned long)netbk);
+ tasklet_init(&netbk->tasklet.net_rx_tasklet,
+- net_rx_action,
++ xen_netbk_rx_action,
+ (unsigned long)netbk);
+ }
+
+--
+1.7.4
+
+
+From 0feb757d74b864a7d8d00fb57a8c523bd3081d42 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 17:00:54 +0000
+Subject: [PATCH 093/203] xen: netback: refactor to make all xen_netbk knowledge internal
to netback.c
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/common.h | 95 +---------------------------
+ drivers/net/xen-netback/interface.c | 28 +--------
+ drivers/net/xen-netback/netback.c | 117 ++++++++++++++++++++++++++++++++++-
+ 3 files changed, 120 insertions(+), 120 deletions(-)
+
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index 2d727a0..32a9e4f 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -177,97 +177,8 @@ static inline int netbk_can_sg(struct net_device *dev)
+ return netif->can_sg;
+ }
+
-struct pending_tx_info {
- struct xen_netif_tx_request req;
- struct xen_netif *netif;
@@ -26852,96 +20055,54 @@ index 49dc4cf..0000000
-
- struct page **mmap_pages;
-
-- 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 net_schedule_list;
--
-- /* Protect the net_schedule_list in netif. */
-- spinlock_t net_schedule_list_lock;
--
-- atomic_t netfront_count;
--
-- 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];
--
-- /*
-- * Each head or fragment can be up to 4096 bytes. Given
-- * MAX_BUFFER_OFFSET of 4096 the worst case is that each
-- * head/fragment uses 2 copy operation.
-- */
-- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
-- unsigned char rx_notify[NR_IRQS];
-- u16 notify_list[NET_RX_RING_SIZE];
-- struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
--};
--
--extern struct xen_netbk *xen_netbk;
--extern int xen_netbk_group_nr;
--
--#endif /* __NETIF__BACKEND__COMMON_H__ */
-diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c
-deleted file mode 100644
-index b429f8c..0000000
---- a/drivers/xen/netback/interface.c
-+++ /dev/null
-@@ -1,470 +0,0 @@
--/*
-- * Network-device interface management.
-- *
-- * Copyright (c) 2004-2005, Keir Fraser
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License version 2
-- * as published by the Free Software Foundation; or, when distributed
-- * separately from the Linux kernel or incorporated into other
-- * software packages, subject to the following license:
-- *
-- * Permission is hereby granted, free of charge, to any person obtaining a copy
-- * of this source file (the "Software"), to deal in the Software without
-- * restriction, including without limitation the rights to use, copy, modify,
-- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-- * and to permit persons to whom the Software is furnished to do so, subject to
-- * the following conditions:
-- *
-- * The above copyright notice and this permission notice shall be included in
-- * all copies or substantial portions of the Software.
-- *
-- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-- * IN THE SOFTWARE.
-- */
+- pending_ring_idx_t pending_prod;
+- pending_ring_idx_t pending_cons;
+- pending_ring_idx_t dealloc_prod;
+- pending_ring_idx_t dealloc_cons;
-
--#include "common.h"
+- struct list_head pending_inuse_head;
+- struct list_head net_schedule_list;
-
--#include <linux/ethtool.h>
--#include <linux/rtnetlink.h>
+- /* Protect the net_schedule_list in netif. */
+- spinlock_t net_schedule_list_lock;
-
--#include <xen/events.h>
--#include <asm/xen/hypercall.h>
+- atomic_t netfront_count;
-
--/*
-- * Module parameter 'queue_length':
-- *
-- * Enables queuing in the network stack when a client has run out of receive
-- * descriptors.
-- */
--static unsigned long netbk_queue_length = 32;
--module_param_named(queue_length, netbk_queue_length, ulong, 0644);
+- 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];
+-
+- /*
+- * Each head or fragment can be up to 4096 bytes. Given
+- * MAX_BUFFER_OFFSET of 4096 the worst case is that each
+- * head/fragment uses 2 copy operation.
+- */
+- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
+- unsigned char rx_notify[NR_IRQS];
+- u16 notify_list[NET_RX_RING_SIZE];
+- struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
+-};
-
+-extern struct xen_netbk *xen_netbk;
+-extern int xen_netbk_group_nr;
++/* (De)Register a netif with the netback backend. */
++void xen_netbk_add_netif(struct xen_netif *netif);
++void xen_netbk_remove_netif(struct xen_netif *netif);
+
+ #endif /* __XEN_NETBACK__COMMON_H__ */
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index 28b0832..54ae275 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -38,33 +38,9 @@
+
+ #define NETBK_QUEUE_LENGTH 32
+
-static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
- struct xen_netif *netif)
-{
@@ -26966,171 +20127,509 @@ index b429f8c..0000000
- atomic_dec(&netbk[netif->group].netfront_count);
-}
-
--static void __netif_up(struct xen_netif *netif)
--{
+ static void __netif_up(struct xen_netif *netif)
+ {
- netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
++ xen_netbk_add_netif(netif);
+ enable_irq(netif->irq);
+ netif_schedule_work(netif);
+ }
+@@ -73,7 +49,7 @@ static void __netif_down(struct xen_netif *netif)
+ {
+ disable_irq(netif->irq);
+ netif_deschedule_work(netif);
+- netbk_remove_netif(xen_netbk, netif);
++ xen_netbk_remove_netif(netif);
+ }
+
+ static int net_open(struct net_device *dev)
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index 6ed4459..d10ddbc 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -47,8 +47,121 @@
+ #include <asm/xen/hypercall.h>
+ #include <asm/xen/page.h>
+
+-struct xen_netbk *xen_netbk;
+-int xen_netbk_group_nr;
++struct pending_tx_info {
++ struct xen_netif_tx_request req;
++ struct xen_netif *netif;
++};
++typedef unsigned int pending_ring_idx_t;
++
++struct netbk_rx_meta {
++ int id;
++ int size;
++ int gso_size;
++};
++
++struct netbk_tx_pending_inuse {
++ struct list_head list;
++ unsigned long alloc_time;
++};
++
++#define MAX_PENDING_REQS 256
++
++#define MAX_BUFFER_OFFSET PAGE_SIZE
++
++/* extra field used in struct page */
++union page_ext {
++ struct {
++#if BITS_PER_LONG < 64
++#define IDX_WIDTH 8
++#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
++ unsigned int group:GROUP_WIDTH;
++ unsigned int idx:IDX_WIDTH;
++#else
++ unsigned int group, idx;
++#endif
++ } e;
++ void *mapping;
++};
++
++struct xen_netbk {
++ union {
++ struct {
++ struct tasklet_struct net_tx_tasklet;
++ struct tasklet_struct net_rx_tasklet;
++ } tasklet;
++
++ struct {
++ wait_queue_head_t netbk_action_wq;
++ struct task_struct *task;
++ } kthread;
++ };
++
++ struct sk_buff_head rx_queue;
++ struct sk_buff_head tx_queue;
++
++ struct timer_list net_timer;
++ struct timer_list netbk_tx_pending_timer;
++
++ struct page **mmap_pages;
++
++ 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 net_schedule_list;
++
++ /* Protect the net_schedule_list in netif. */
++ spinlock_t net_schedule_list_lock;
++
++ atomic_t netfront_count;
++
++ 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];
++
++ /*
++ * Each head or fragment can be up to 4096 bytes. Given
++ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
++ * head/fragment uses 2 copy operation.
++ */
++ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
++ unsigned char rx_notify[NR_IRQS];
++ u16 notify_list[NET_RX_RING_SIZE];
++ struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
++};
++
++static struct xen_netbk *xen_netbk;
++static int xen_netbk_group_nr;
++
++void xen_netbk_add_netif(struct xen_netif *netif)
++{
++ int i;
++ int min_netfront_count;
++ int min_group = 0;
++ min_netfront_count = atomic_read(&xen_netbk[0].netfront_count);
++ for (i = 0; i < xen_netbk_group_nr; i++) {
++ int netfront_count = atomic_read(&xen_netbk[i].netfront_count);
++ if (netfront_count < min_netfront_count) {
++ min_group = i;
++ min_netfront_count = netfront_count;
++ }
++ }
++
++ netif->group = min_group;
++ atomic_inc(&xen_netbk[netif->group].netfront_count);
++}
++
++void xen_netbk_remove_netif(struct xen_netif *netif)
++{
++ atomic_dec(&xen_netbk[netif->group].netfront_count);
++}
+
+ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+ static void make_tx_response(struct xen_netif *netif,
+--
+1.7.4
+
+
+From 651ae17d2aaedb2adca37c7b7c9eda195c3cad6b Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Thu, 20 Jan 2011 17:08:23 +0000
+Subject: [PATCH 094/203] xen: netback: use xenvif_ prefix where appropriate
+
+Avoids use of netif_ prefix which belongs to the networking core.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/common.h | 65 +++---
+ drivers/net/xen-netback/interface.c | 316 ++++++++++++++--------------
+ drivers/net/xen-netback/netback.c | 394 +++++++++++++++++------------------
+ drivers/net/xen-netback/xenbus.c | 72 +++----
+ 4 files changed, 422 insertions(+), 425 deletions(-)
+
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index 32a9e4f..f6da94b 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -46,7 +46,7 @@
+ #include <xen/grant_table.h>
+ #include <xen/xenbus.h>
+
+-struct xen_netif {
++struct xenvif {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ int group;
+@@ -79,7 +79,7 @@ struct xen_netif {
+ /* Internal feature information. */
+ u8 can_queue:1; /* can queue packets for receiver? */
+
+- /* Allow netif_be_start_xmit() to peek ahead in the rx request
++ /* Allow xenvif_start_xmit() to peek ahead in the rx request
+ * ring. This is a prediction of what rx_req_cons will be once
+ * all queued skbs are put on the ring. */
+ RING_IDX rx_req_cons_peek;
+@@ -111,9 +111,9 @@ struct xen_netif {
+ * immediately be called, which can cause packet loss; also the etherbridge
+ * can be rather lazy in activating its port).
+ */
+-#define netback_carrier_on(netif) ((netif)->carrier = 1)
+-#define netback_carrier_off(netif) ((netif)->carrier = 0)
+-#define netback_carrier_ok(netif) ((netif)->carrier)
++#define xenvif_carrier_on(xenvif) ((xenvif)->carrier = 1)
++#define xenvif_carrier_off(xenvif) ((xenvif)->carrier = 0)
++#define xenvif_carrier_ok(xenvif) ((xenvif)->carrier)
+
+ enum {
+ NETBK_DONT_COPY_SKB,
+@@ -125,7 +125,7 @@ extern int netbk_copy_skb_mode;
+
+ struct backend_info {
+ struct xenbus_device *dev;
+- struct xen_netif *netif;
++ struct xenvif *vif;
+ enum xenbus_state frontend_state;
+ struct xenbus_watch hotplug_status_watch;
+ int have_hotplug_status_watch:1;
+@@ -134,51 +134,52 @@ struct backend_info {
+ #define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+ #define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+
+-void netif_disconnect(struct xen_netif *netif);
++void xenvif_disconnect(struct xenvif *vif);
+
+-void netif_set_features(struct xen_netif *netif);
+-struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
+- unsigned int handle);
+-int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
+- unsigned long rx_ring_ref, unsigned int evtchn);
++void xenvif_set_features(struct xenvif *vif);
++struct xenvif *xenvif_alloc(struct device *parent,
++ domid_t domid,
++ unsigned int handle);
++int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn);
+
+-static inline void netif_get(struct xen_netif *netif)
++static inline void xenvif_get(struct xenvif *vif)
+ {
+- atomic_inc(&netif->refcnt);
++ atomic_inc(&vif->refcnt);
+ }
+
+-static inline void netif_put(struct xen_netif *netif)
++static inline void xenvif_put(struct xenvif *vif)
+ {
+- if (atomic_dec_and_test(&netif->refcnt))
+- wake_up(&netif->waiting_to_free);
++ if (atomic_dec_and_test(&vif->refcnt))
++ wake_up(&vif->waiting_to_free);
+ }
+
+-int netif_xenbus_init(void);
++int xenvif_xenbus_init(void);
+
+-#define netif_schedulable(netif) \
+- (netif_running((netif)->dev) && netback_carrier_ok(netif))
++#define xenvif_schedulable(vif) \
++ (netif_running((vif)->dev) && xenvif_carrier_ok(vif))
+
+-void netif_schedule_work(struct xen_netif *netif);
+-void netif_deschedule_work(struct xen_netif *netif);
++void xenvif_schedule_work(struct xenvif *vif);
++void xenvif_deschedule_work(struct xenvif *vif);
+
+-int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-struct net_device_stats *netif_be_get_stats(struct net_device *dev);
+-irqreturn_t netif_be_int(int irq, void *dev_id);
++int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev);
++struct net_device_stats *xenvif_get_stats(struct net_device *dev);
++irqreturn_t xenvif_interrupt(int irq, void *dev_id);
+
+ static inline int netbk_can_queue(struct net_device *dev)
+ {
+- struct xen_netif *netif = netdev_priv(dev);
+- return netif->can_queue;
++ struct xenvif *vif = netdev_priv(dev);
++ return vif->can_queue;
+ }
+
+ static inline int netbk_can_sg(struct net_device *dev)
+ {
+- struct xen_netif *netif = netdev_priv(dev);
+- return netif->can_sg;
++ struct xenvif *vif = netdev_priv(dev);
++ return vif->can_sg;
+ }
+
+-/* (De)Register a netif with the netback backend. */
+-void xen_netbk_add_netif(struct xen_netif *netif);
+-void xen_netbk_remove_netif(struct xen_netif *netif);
++/* (De)Register a xenvif with the netback backend. */
++void xen_netbk_add_xenvif(struct xenvif *vif);
++void xen_netbk_remove_xenvif(struct xenvif *vif);
+
+ #endif /* __XEN_NETBACK__COMMON_H__ */
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index 54ae275..a065173 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -38,40 +38,40 @@
+
+ #define NETBK_QUEUE_LENGTH 32
+
+-static void __netif_up(struct xen_netif *netif)
++static void xenvif_up(struct xenvif *vif)
+ {
+- xen_netbk_add_netif(netif);
- enable_irq(netif->irq);
- netif_schedule_work(netif);
--}
--
++ xen_netbk_add_xenvif(vif);
++ enable_irq(vif->irq);
++ xenvif_schedule_work(vif);
+ }
+
-static void __netif_down(struct xen_netif *netif)
--{
++static void xenvif_down(struct xenvif *vif)
+ {
- disable_irq(netif->irq);
- netif_deschedule_work(netif);
-- netbk_remove_netif(xen_netbk, netif);
--}
--
+- xen_netbk_remove_netif(netif);
++ disable_irq(vif->irq);
++ xenvif_deschedule_work(vif);
++ xen_netbk_remove_xenvif(vif);
+ }
+
-static int net_open(struct net_device *dev)
--{
++static int xenvif_open(struct net_device *dev)
+ {
- struct xen_netif *netif = netdev_priv(dev);
- if (netback_carrier_ok(netif)) {
- __netif_up(netif);
-- netif_start_queue(dev);
-- }
-- return 0;
--}
--
++ struct xenvif *vif = netdev_priv(dev);
++ if (xenvif_carrier_ok(vif)) {
++ xenvif_up(vif);
+ netif_start_queue(dev);
+ }
+ return 0;
+ }
+
-static int net_close(struct net_device *dev)
--{
++static int xenvif_close(struct net_device *dev)
+ {
- struct xen_netif *netif = netdev_priv(dev);
- if (netback_carrier_ok(netif))
- __netif_down(netif);
-- netif_stop_queue(dev);
-- return 0;
--}
--
++ struct xenvif *vif = netdev_priv(dev);
++ if (xenvif_carrier_ok(vif))
++ xenvif_down(vif);
+ netif_stop_queue(dev);
+ return 0;
+ }
+
-static int netbk_change_mtu(struct net_device *dev, int mtu)
--{
-- int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
--
-- if (mtu > max)
-- return -EINVAL;
-- dev->mtu = mtu;
-- return 0;
--}
--
++static int xenvif_change_mtu(struct net_device *dev, int mtu)
+ {
+ int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+@@ -81,19 +81,19 @@ static int netbk_change_mtu(struct net_device *dev, int mtu)
+ return 0;
+ }
+
-void netif_set_features(struct xen_netif *netif)
--{
++void xenvif_set_features(struct xenvif *vif)
+ {
- struct net_device *dev = netif->dev;
-- int features = dev->features;
--
++ struct net_device *dev = vif->dev;
+ int features = dev->features;
+
- if (netif->can_sg)
-- features |= NETIF_F_SG;
++ if (vif->can_sg)
+ features |= NETIF_F_SG;
- if (netif->gso || netif->gso_prefix)
-- features |= NETIF_F_TSO;
++ if (vif->gso || vif->gso_prefix)
+ features |= NETIF_F_TSO;
- if (netif->csum)
-- features |= NETIF_F_IP_CSUM;
--
++ if (vif->csum)
+ features |= NETIF_F_IP_CSUM;
+
- features &= ~(netif->features_disabled);
--
-- if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
-- dev->mtu = ETH_DATA_LEN;
--
-- dev->features = features;
--}
--
++ features &= ~(vif->features_disabled);
+
+ if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
+ dev->mtu = ETH_DATA_LEN;
+@@ -101,130 +101,130 @@ void netif_set_features(struct xen_netif *netif)
+ dev->features = features;
+ }
+
-static int netbk_set_tx_csum(struct net_device *dev, u32 data)
--{
++static int xenvif_set_tx_csum(struct net_device *dev, u32 data)
+ {
- struct xen_netif *netif = netdev_priv(dev);
-- if (data) {
++ struct xenvif *vif = netdev_priv(dev);
+ if (data) {
- if (!netif->csum)
-- return -ENOSYS;
++ if (!vif->csum)
+ return -EOPNOTSUPP;
- netif->features_disabled &= ~NETIF_F_IP_CSUM;
-- } else {
++ vif->features_disabled &= ~NETIF_F_IP_CSUM;
+ } else {
- netif->features_disabled |= NETIF_F_IP_CSUM;
-- }
--
++ vif->features_disabled |= NETIF_F_IP_CSUM;
+ }
+
- netif_set_features(netif);
-- return 0;
--}
--
++ xenvif_set_features(vif);
+ return 0;
+ }
+
-static int netbk_set_sg(struct net_device *dev, u32 data)
--{
++static int xenvif_set_sg(struct net_device *dev, u32 data)
+ {
- struct xen_netif *netif = netdev_priv(dev);
-- if (data) {
++ struct xenvif *vif = netdev_priv(dev);
+ if (data) {
- if (!netif->can_sg)
-- return -ENOSYS;
++ if (!vif->can_sg)
+ return -EOPNOTSUPP;
- netif->features_disabled &= ~NETIF_F_SG;
-- } else {
++ vif->features_disabled &= ~NETIF_F_SG;
+ } else {
- netif->features_disabled |= NETIF_F_SG;
-- }
--
++ vif->features_disabled |= NETIF_F_SG;
+ }
+
- netif_set_features(netif);
-- return 0;
--}
--
++ xenvif_set_features(vif);
+ return 0;
+ }
+
-static int netbk_set_tso(struct net_device *dev, u32 data)
--{
++static int xenvif_set_tso(struct net_device *dev, u32 data)
+ {
- struct xen_netif *netif = netdev_priv(dev);
-- if (data) {
++ struct xenvif *vif = netdev_priv(dev);
+ if (data) {
- if (!netif->gso && !netif->gso_prefix)
-- return -ENOSYS;
++ if (!vif->gso && !vif->gso_prefix)
+ return -EOPNOTSUPP;
- netif->features_disabled &= ~NETIF_F_TSO;
-- } else {
++ vif->features_disabled &= ~NETIF_F_TSO;
+ } else {
- netif->features_disabled |= NETIF_F_TSO;
-- }
--
++ vif->features_disabled |= NETIF_F_TSO;
+ }
+
- netif_set_features(netif);
-- return 0;
--}
--
--static void netbk_get_drvinfo(struct net_device *dev,
-- struct ethtool_drvinfo *info)
--{
-- strcpy(info->driver, "netbk");
-- strcpy(info->bus_info, dev_name(dev->dev.parent));
--}
--
++ xenvif_set_features(vif);
+ return 0;
+ }
+
-static const struct netif_stat {
-- char name[ETH_GSTRING_LEN];
-- u16 offset;
++static const struct xenvif_stat {
+ char name[ETH_GSTRING_LEN];
+ u16 offset;
-} netbk_stats[] = {
-- {
-- "copied_skbs",
++} xenvif_stats[] = {
+ {
+ "copied_skbs",
- offsetof(struct xen_netif, nr_copied_skbs)
-- },
-- {
-- "rx_gso_checksum_fixup",
++ offsetof(struct xenvif, nr_copied_skbs)
+ },
+ {
+ "rx_gso_checksum_fixup",
- offsetof(struct xen_netif, rx_gso_checksum_fixup)
-- },
--};
--
++ offsetof(struct xenvif, rx_gso_checksum_fixup)
+ },
+ };
+
-static int netbk_get_sset_count(struct net_device *dev, int string_set)
--{
-- switch (string_set) {
-- case ETH_SS_STATS:
++static int xenvif_get_sset_count(struct net_device *dev, int string_set)
+ {
+ switch (string_set) {
+ case ETH_SS_STATS:
- return ARRAY_SIZE(netbk_stats);
-- default:
-- return -EINVAL;
-- }
--}
--
++ return ARRAY_SIZE(xenvif_stats);
+ default:
+ return -EINVAL;
+ }
+ }
+
-static void netbk_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats, u64 * data)
--{
++static void xenvif_get_ethtool_stats(struct net_device *dev,
++ struct ethtool_stats *stats, u64 * data)
+ {
- void *netif = netdev_priv(dev);
-- int i;
--
++ void *vif = netdev_priv(dev);
+ int i;
+
- for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
- data[i] = *(int *)(netif + netbk_stats[i].offset);
--}
--
++ for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
++ data[i] = *(int *)(vif + xenvif_stats[i].offset);
+ }
+
-static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
--{
-- int i;
--
-- switch (stringset) {
-- case ETH_SS_STATS:
++static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+ {
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
- for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-- memcpy(data + i * ETH_GSTRING_LEN,
++ for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
+ memcpy(data + i * ETH_GSTRING_LEN,
- netbk_stats[i].name, ETH_GSTRING_LEN);
-- break;
-- }
--}
--
++ xenvif_stats[i].name, ETH_GSTRING_LEN);
+ break;
+ }
+ }
+
-static struct ethtool_ops network_ethtool_ops = {
-- .get_drvinfo = netbk_get_drvinfo,
--
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = netbk_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
@@ -27142,33 +20641,55 @@ index b429f8c..0000000
- .get_sset_count = netbk_get_sset_count,
- .get_ethtool_stats = netbk_get_ethtool_stats,
- .get_strings = netbk_get_strings,
--};
--
++static struct ethtool_ops xenvif_ethtool_ops = {
++ .get_tx_csum = ethtool_op_get_tx_csum,
++ .set_tx_csum = xenvif_set_tx_csum,
++ .get_sg = ethtool_op_get_sg,
++ .set_sg = xenvif_set_sg,
++ .get_tso = ethtool_op_get_tso,
++ .set_tso = xenvif_set_tso,
++ .get_link = ethtool_op_get_link,
++
++ .get_sset_count = xenvif_get_sset_count,
++ .get_ethtool_stats = xenvif_get_ethtool_stats,
++ .get_strings = xenvif_get_strings,
+ };
+
-static struct net_device_ops netback_ops = {
- .ndo_start_xmit = netif_be_start_xmit,
- .ndo_get_stats = netif_be_get_stats,
- .ndo_open = net_open,
- .ndo_stop = net_close,
- .ndo_change_mtu = netbk_change_mtu,
--};
--
++static struct net_device_ops xenvif_netdev_ops = {
++ .ndo_start_xmit = xenvif_start_xmit,
++ .ndo_get_stats = xenvif_get_stats,
++ .ndo_open = xenvif_open,
++ .ndo_stop = xenvif_close,
++ .ndo_change_mtu = xenvif_change_mtu,
+ };
+
-struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
- unsigned int handle)
--{
-- int err = 0;
-- struct net_device *dev;
++struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
++ unsigned int handle)
+ {
+ int err = 0;
+ struct net_device *dev;
- struct xen_netif *netif;
-- char name[IFNAMSIZ] = {};
--
-- snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
++ struct xenvif *vif;
+ char name[IFNAMSIZ] = {};
+
+ snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
- dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
-- if (dev == NULL) {
-- pr_debug("Could not allocate netdev\n");
-- return ERR_PTR(-ENOMEM);
-- }
--
-- SET_NETDEV_DEV(dev, parent);
--
++ dev = alloc_netdev(sizeof(struct xenvif), name, ether_setup);
+ if (dev == NULL) {
+ pr_debug("Could not allocate netdev\n");
+ return ERR_PTR(-ENOMEM);
+@@ -232,29 +232,29 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t
domid,
+
+ SET_NETDEV_DEV(dev, parent);
+
- netif = netdev_priv(dev);
- memset(netif, 0, sizeof(*netif));
- netif->domid = domid;
@@ -27186,13658 +20707,20317 @@ index b429f8c..0000000
- netif->credit_bytes = netif->remaining_credit = ~0UL;
- netif->credit_usec = 0UL;
- init_timer(&netif->credit_timeout);
-- /* Initialize 'expires' now: it's used to track the credit window. */
++ vif = netdev_priv(dev);
++ memset(vif, 0, sizeof(*vif));
++ vif->domid = domid;
++ vif->group = -1;
++ vif->handle = handle;
++ vif->can_sg = 1;
++ vif->csum = 1;
++ atomic_set(&vif->refcnt, 1);
++ init_waitqueue_head(&vif->waiting_to_free);
++ vif->dev = dev;
++ INIT_LIST_HEAD(&vif->list);
++
++ xenvif_carrier_off(vif);
++
++ vif->credit_bytes = vif->remaining_credit = ~0UL;
++ vif->credit_usec = 0UL;
++ init_timer(&vif->credit_timeout);
+ /* Initialize 'expires' now: it's used to track the credit window. */
- netif->credit_timeout.expires = jiffies;
--
++ vif->credit_timeout.expires = jiffies;
+
- dev->netdev_ops = &netback_ops;
- netif_set_features(netif);
- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
--
-- dev->tx_queue_len = netbk_queue_length;
--
-- /*
-- * Initialise a dummy MAC address. We choose the numerically
-- * largest non-broadcast address to prevent the address getting
-- * stolen by an Ethernet bridge for STP purposes.
-- * (FE:FF:FF:FF:FF:FF)
-- */
-- memset(dev->dev_addr, 0xFF, ETH_ALEN);
-- dev->dev_addr[0] &= ~0x01;
--
-- rtnl_lock();
-- err = register_netdevice(dev);
-- rtnl_unlock();
-- if (err) {
-- pr_debug("Could not register new net device %s: err=%d\n",
-- dev->name, err);
-- free_netdev(dev);
-- return ERR_PTR(err);
-- }
--
++ dev->netdev_ops = &xenvif_netdev_ops;
++ xenvif_set_features(vif);
++ SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
+
+ dev->tx_queue_len = NETBK_QUEUE_LENGTH;
+
+@@ -277,18 +277,18 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t
domid,
+ return ERR_PTR(err);
+ }
+
- pr_debug("Successfully created netif\n");
- return netif;
--}
--
++ pr_debug("Successfully created xenvif\n");
++ return vif;
+ }
+
-static int map_frontend_pages(struct xen_netif *netif,
-- grant_ref_t tx_ring_ref,
-- grant_ref_t rx_ring_ref)
--{
-- struct gnttab_map_grant_ref op;
--
++static int map_frontend_pages(struct xenvif *vif,
+ grant_ref_t tx_ring_ref,
+ grant_ref_t rx_ring_ref)
+ {
+ struct gnttab_map_grant_ref op;
+
- gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
- GNTMAP_host_map, tx_ring_ref, netif->domid);
--
-- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-- BUG();
--
-- if (op.status) {
-- pr_debug("Gnttab failure mapping tx_ring_ref!\n");
-- return op.status;
-- }
--
++ gnttab_set_map_op(&op, (unsigned long)vif->tx_comms_area->addr,
++ GNTMAP_host_map, tx_ring_ref, vif->domid);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+@@ -298,11 +298,11 @@ static int map_frontend_pages(struct xen_netif *netif,
+ return op.status;
+ }
+
- netif->tx_shmem_ref = tx_ring_ref;
- netif->tx_shmem_handle = op.handle;
--
++ vif->tx_shmem_ref = tx_ring_ref;
++ vif->tx_shmem_handle = op.handle;
+
- gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
- GNTMAP_host_map, rx_ring_ref, netif->domid);
--
-- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-- BUG();
--
-- if (op.status) {
-- struct gnttab_unmap_grant_ref unop;
--
-- gnttab_set_unmap_op(&unop,
++ gnttab_set_map_op(&op, (unsigned long)vif->rx_comms_area->addr,
++ GNTMAP_host_map, rx_ring_ref, vif->domid);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+@@ -311,120 +311,120 @@ static int map_frontend_pages(struct xen_netif *netif,
+ struct gnttab_unmap_grant_ref unop;
+
+ gnttab_set_unmap_op(&unop,
- (unsigned long)netif->tx_comms_area->addr,
- GNTMAP_host_map, netif->tx_shmem_handle);
-- HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
-- pr_debug("Gnttab failure mapping rx_ring_ref!\n");
-- return op.status;
-- }
--
++ (unsigned long)vif->tx_comms_area->addr,
++ GNTMAP_host_map, vif->tx_shmem_handle);
+ HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
+ pr_debug("Gnttab failure mapping rx_ring_ref!\n");
+ return op.status;
+ }
+
- netif->rx_shmem_ref = rx_ring_ref;
- netif->rx_shmem_handle = op.handle;
--
-- return 0;
--}
--
++ vif->rx_shmem_ref = rx_ring_ref;
++ vif->rx_shmem_handle = op.handle;
+
+ return 0;
+ }
+
-static void unmap_frontend_pages(struct xen_netif *netif)
--{
-- struct gnttab_unmap_grant_ref op;
--
++static void unmap_frontend_pages(struct xenvif *vif)
+ {
+ struct gnttab_unmap_grant_ref op;
+
- gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
- GNTMAP_host_map, netif->tx_shmem_handle);
--
-- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-- BUG();
--
++ gnttab_set_unmap_op(&op, (unsigned long)vif->tx_comms_area->addr,
++ GNTMAP_host_map, vif->tx_shmem_handle);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
- gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
- GNTMAP_host_map, netif->rx_shmem_handle);
--
-- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-- BUG();
--}
--
++ gnttab_set_unmap_op(&op, (unsigned long)vif->rx_comms_area->addr,
++ GNTMAP_host_map, vif->rx_shmem_handle);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+ }
+
-int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn)
--{
-- int err = -ENOMEM;
-- struct xen_netif_tx_sring *txs;
-- struct xen_netif_rx_sring *rxs;
--
-- /* Already connected through? */
++int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
++ unsigned long rx_ring_ref, unsigned int evtchn)
+ {
+ int err = -ENOMEM;
+ struct xen_netif_tx_sring *txs;
+ struct xen_netif_rx_sring *rxs;
+
+ /* Already connected through? */
- if (netif->irq)
-- return 0;
--
++ if (vif->irq)
+ return 0;
+
- netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
- if (netif->tx_comms_area == NULL)
-- return -ENOMEM;
++ vif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (vif->tx_comms_area == NULL)
+ return -ENOMEM;
- netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
- if (netif->rx_comms_area == NULL)
-- goto err_rx;
--
++ vif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
++ if (vif->rx_comms_area == NULL)
+ goto err_rx;
+
- err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
-- if (err)
-- goto err_map;
--
-- err = bind_interdomain_evtchn_to_irqhandler(
++ err = map_frontend_pages(vif, tx_ring_ref, rx_ring_ref);
+ if (err)
+ goto err_map;
+
+ err = bind_interdomain_evtchn_to_irqhandler(
- netif->domid, evtchn, netif_be_int, 0,
- netif->dev->name, netif);
-- if (err < 0)
-- goto err_hypervisor;
++ vif->domid, evtchn, xenvif_interrupt, 0,
++ vif->dev->name, vif);
+ if (err < 0)
+ goto err_hypervisor;
- netif->irq = err;
- disable_irq(netif->irq);
--
++ vif->irq = err;
++ disable_irq(vif->irq);
+
- txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
- BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
--
-- rxs = (struct xen_netif_rx_sring *)
++ txs = (struct xen_netif_tx_sring *)vif->tx_comms_area->addr;
++ BACK_RING_INIT(&vif->tx, txs, PAGE_SIZE);
+
+ rxs = (struct xen_netif_rx_sring *)
- ((char *)netif->rx_comms_area->addr);
- BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
--
++ ((char *)vif->rx_comms_area->addr);
++ BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE);
+
- netif->rx_req_cons_peek = 0;
--
++ vif->rx_req_cons_peek = 0;
+
- netif_get(netif);
--
-- rtnl_lock();
++ xenvif_get(vif);
+
+ rtnl_lock();
- netback_carrier_on(netif);
- if (netif_running(netif->dev))
- __netif_up(netif);
-- rtnl_unlock();
--
-- return 0;
--err_hypervisor:
++ xenvif_carrier_on(vif);
++ if (netif_running(vif->dev))
++ xenvif_up(vif);
+ rtnl_unlock();
+
+ return 0;
+ err_hypervisor:
- unmap_frontend_pages(netif);
--err_map:
++ unmap_frontend_pages(vif);
+ err_map:
- free_vm_area(netif->rx_comms_area);
--err_rx:
++ free_vm_area(vif->rx_comms_area);
+ err_rx:
- free_vm_area(netif->tx_comms_area);
-- return err;
--}
--
++ free_vm_area(vif->tx_comms_area);
+ return err;
+ }
+
-void netif_disconnect(struct xen_netif *netif)
--{
++void xenvif_disconnect(struct xenvif *vif)
+ {
- if (netback_carrier_ok(netif)) {
-- rtnl_lock();
++ if (xenvif_carrier_ok(vif)) {
+ rtnl_lock();
- netback_carrier_off(netif);
- netif_carrier_off(netif->dev); /* discard queued packets */
- if (netif_running(netif->dev))
- __netif_down(netif);
-- rtnl_unlock();
++ xenvif_carrier_off(vif);
++ netif_carrier_off(vif->dev); /* discard queued packets */
++ if (netif_running(vif->dev))
++ xenvif_down(vif);
+ rtnl_unlock();
- netif_put(netif);
-- }
--
++ xenvif_put(vif);
+ }
+
- atomic_dec(&netif->refcnt);
- wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
--
++ atomic_dec(&vif->refcnt);
++ wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
+
- del_timer_sync(&netif->credit_timeout);
--
++ del_timer_sync(&vif->credit_timeout);
+
- if (netif->irq)
- unbind_from_irqhandler(netif->irq, netif);
--
++ if (vif->irq)
++ unbind_from_irqhandler(vif->irq, vif);
+
- unregister_netdev(netif->dev);
--
++ unregister_netdev(vif->dev);
+
- if (netif->tx.sring) {
- unmap_frontend_pages(netif);
- free_vm_area(netif->tx_comms_area);
- free_vm_area(netif->rx_comms_area);
-- }
--
++ if (vif->tx.sring) {
++ unmap_frontend_pages(vif);
++ free_vm_area(vif->tx_comms_area);
++ free_vm_area(vif->rx_comms_area);
+ }
+
- free_netdev(netif->dev);
--}
-diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c
-deleted file mode 100644
-index b290525..0000000
---- a/drivers/xen/netback/netback.c
-+++ /dev/null
-@@ -1,1934 +0,0 @@
--/*
-- * Back-end of the driver for virtual network devices. This portion of the
-- * driver exports a 'unified' network-device interface that can be accessed
-- * by any operating system that implements a compatible front end. A
-- * reference front-end implementation can be found in:
-- * drivers/net/xen-netfront.c
-- *
-- * Copyright (c) 2002-2005, K A Fraser
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License version 2
-- * as published by the Free Software Foundation; or, when distributed
-- * separately from the Linux kernel or incorporated into other
-- * software packages, subject to the following license:
-- *
-- * Permission is hereby granted, free of charge, to any person obtaining a copy
-- * of this source file (the "Software"), to deal in the Software without
-- * restriction, including without limitation the rights to use, copy, modify,
-- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-- * and to permit persons to whom the Software is furnished to do so, subject to
-- * the following conditions:
-- *
-- * The above copyright notice and this permission notice shall be included in
-- * all copies or substantial portions of the Software.
-- *
-- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-- * IN THE SOFTWARE.
-- */
--
--#include "common.h"
--
--#include <linux/kthread.h>
--#include <linux/if_vlan.h>
--#include <linux/udp.h>
--
--#include <net/tcp.h>
--
--#include <xen/balloon.h>
--#include <xen/events.h>
--#include <xen/interface/memory.h>
--
--#include <asm/xen/hypercall.h>
--#include <asm/xen/page.h>
--
--/*define NETBE_DEBUG_INTERRUPT*/
--
--struct xen_netbk *xen_netbk;
--int xen_netbk_group_nr;
--
--static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
++ free_netdev(vif->dev);
+ }
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index d10ddbc..f2f9c6f 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -49,7 +49,7 @@
+
+ struct pending_tx_info {
+ struct xen_netif_tx_request req;
+- struct xen_netif *netif;
++ struct xenvif *vif;
+ };
+ typedef unsigned int pending_ring_idx_t;
+
+@@ -140,7 +140,7 @@ struct xen_netbk {
+ static struct xen_netbk *xen_netbk;
+ static int xen_netbk_group_nr;
+
+-void xen_netbk_add_netif(struct xen_netif *netif)
++void xen_netbk_add_xenvif(struct xenvif *vif)
+ {
+ int i;
+ int min_netfront_count;
+@@ -154,20 +154,20 @@ void xen_netbk_add_netif(struct xen_netif *netif)
+ }
+ }
+
+- netif->group = min_group;
+- atomic_inc(&xen_netbk[netif->group].netfront_count);
++ vif->group = min_group;
++ atomic_inc(&xen_netbk[vif->group].netfront_count);
+ }
+
+-void xen_netbk_remove_netif(struct xen_netif *netif)
++void xen_netbk_remove_xenvif(struct xenvif *vif)
+ {
+- atomic_dec(&xen_netbk[netif->group].netfront_count);
++ atomic_dec(&xen_netbk[vif->group].netfront_count);
+ }
+
+ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
-static void make_tx_response(struct xen_netif *netif,
-- struct xen_netif_tx_request *txp,
-- s8 st);
++static void make_tx_response(struct xenvif *vif,
+ struct xen_netif_tx_request *txp,
+ s8 st);
-static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
-- u16 id,
-- s8 st,
-- u16 offset,
-- u16 size,
-- u16 flags);
--
--static void net_tx_action(unsigned long data);
--
--static void net_rx_action(unsigned long data);
--
--static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
-- unsigned int idx)
--{
-- return page_to_pfn(netbk->mmap_pages[idx]);
--}
--
--static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
-- unsigned int idx)
--{
-- return (unsigned long)pfn_to_kaddr(idx_to_pfn(netbk, idx));
--}
--
--/* extra field used in struct page */
--static inline void netif_set_page_ext(struct page *pg,
-- unsigned int group, unsigned int idx)
--{
-- union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
--
-- BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
-- pg->mapping = ext.mapping;
--}
--
--static int netif_get_page_ext(struct page *pg,
-- unsigned int *_group, unsigned int *_idx)
--{
-- union page_ext ext = { .mapping = pg->mapping };
-- struct xen_netbk *netbk;
-- unsigned int group, idx;
--
-- if (!PageForeign(pg))
-- return 0;
--
-- group = ext.e.group - 1;
--
-- if (group < 0 || group >= xen_netbk_group_nr)
-- return 0;
--
-- netbk = &xen_netbk[group];
--
-- if (netbk->mmap_pages == NULL)
-- return 0;
--
-- idx = ext.e.idx;
--
-- if ((idx < 0) || (idx >= MAX_PENDING_REQS))
-- return 0;
--
-- if (netbk->mmap_pages[idx] != pg)
-- return 0;
--
-- *_group = group;
-- *_idx = idx;
--
-- return 1;
--}
--
--/*
-- * This is the amount of packet we copy rather than map, so that the
-- * guest can't fiddle with the contents of the headers while we do
-- * packet processing on them (netfilter, routing, etc).
-- */
--#define PKT_PROT_LEN (ETH_HLEN + \
-- VLAN_HLEN + \
-- sizeof(struct iphdr) + MAX_IPOPTLEN + \
-- sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE)
--
--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 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;
--module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
--MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
--
--int netbk_copy_skb_mode;
--
--static int MODPARM_netback_kthread;
--module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
--MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
--
--/*
-- * Netback bottom half handler.
-- * dir indicates the data direction.
-- * rx: 1, tx: 0.
-- */
--static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
--{
-- if (MODPARM_netback_kthread)
-- wake_up(&netbk->kthread.netbk_action_wq);
-- else if (dir)
-- tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
-- else
-- tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
--}
--
--static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
--{
-- smp_mb();
-- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
-- !list_empty(&netbk->net_schedule_list))
-- xen_netbk_bh_handler(netbk, 0);
--}
--
--static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
--{
-- struct skb_shared_info *ninfo;
-- struct sk_buff *nskb;
-- unsigned long offset;
-- int ret;
-- int len;
-- int headlen;
--
-- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
--
-- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-- if (unlikely(!nskb))
-- goto err;
--
-- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-- headlen = skb_end_pointer(nskb) - nskb->data;
-- if (headlen > skb_headlen(skb))
-- headlen = skb_headlen(skb);
-- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-- BUG_ON(ret);
--
-- ninfo = skb_shinfo(nskb);
-- ninfo->gso_size = skb_shinfo(skb)->gso_size;
-- ninfo->gso_type = skb_shinfo(skb)->gso_type;
--
-- offset = headlen;
-- len = skb->len - headlen;
--
-- nskb->len = skb->len;
-- nskb->data_len = len;
-- nskb->truesize += len;
--
-- while (len) {
-- struct page *page;
-- int copy;
-- int zero;
--
-- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-- dump_stack();
-- goto err_free;
-- }
--
-- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
--
-- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-- if (unlikely(!page))
-- goto err_free;
--
-- ret = skb_copy_bits(skb, offset, page_address(page), copy);
-- BUG_ON(ret);
--
-- ninfo->frags[ninfo->nr_frags].page = page;
-- ninfo->frags[ninfo->nr_frags].page_offset = 0;
-- ninfo->frags[ninfo->nr_frags].size = copy;
-- ninfo->nr_frags++;
--
-- offset += copy;
-- len -= copy;
-- }
--
--#ifdef NET_SKBUFF_DATA_USES_OFFSET
-- offset = 0;
--#else
-- offset = nskb->data - skb->data;
--#endif
--
-- nskb->transport_header = skb->transport_header + offset;
-- nskb->network_header = skb->network_header + offset;
-- nskb->mac_header = skb->mac_header + offset;
--
-- return nskb;
--
-- err_free:
-- kfree_skb(nskb);
-- err:
-- return NULL;
--}
--
++static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
+ u16 id,
+ s8 st,
+ u16 offset,
+@@ -369,20 +369,20 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+ return NULL;
+ }
+
-static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
--{
++static inline int xenvif_max_required_rx_slots(struct xenvif *vif)
+ {
- if (netif->can_sg || netif->gso || netif->gso_prefix)
-- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-- return 1; /* all in one */
--}
--
++ if (vif->can_sg || vif->gso || vif->gso_prefix)
+ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
+ return 1; /* all in one */
+ }
+
-static inline int netbk_queue_full(struct xen_netif *netif)
--{
++static inline int xenvif_queue_full(struct xenvif *vif)
+ {
- RING_IDX peek = netif->rx_req_cons_peek;
- RING_IDX needed = netbk_max_required_rx_slots(netif);
--
++ RING_IDX peek = vif->rx_req_cons_peek;
++ RING_IDX needed = xenvif_max_required_rx_slots(vif);
+
- return ((netif->rx.sring->req_prod - peek) < needed) ||
- ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
--}
--
--/*
-- * Returns true if we should start a new receive buffer instead of
-- * adding 'size' bytes to a buffer which currently contains 'offset'
-- * bytes.
-- */
--static bool start_new_rx_buffer(int offset, unsigned long size, int head)
--{
-- /* simple case: we have completely filled the current buffer. */
-- if (offset == MAX_BUFFER_OFFSET)
-- return true;
--
-- /*
-- * complex case: start a fresh buffer if the current frag
-- * would overflow the current buffer but only if:
-- * (i) this frag would fit completely in the next buffer
-- * and (ii) there is already some data in the current buffer
-- * and (iii) this is not the head buffer.
-- *
-- * Where:
-- * - (i) stops us splitting a frag into two copies
-- * unless the frag is too large for a single buffer.
-- * - (ii) stops us from leaving a buffer pointlessly empty.
-- * - (iii) stops us leaving the first buffer
-- * empty. Strictly speaking this is already covered
-- * by (ii) but is explicitly checked because
-- * netfront relies on the first buffer being
-- * non-empty and can crash otherwise.
-- *
-- * This means we will effectively linearise small
-- * frags but do not needlessly split large buffers
-- * into multiple copies tend to give large frags their
-- * own buffers as before.
-- */
-- if ((offset + size > MAX_BUFFER_OFFSET) &&
-- (size <= MAX_BUFFER_OFFSET) && offset && !head)
-- return true;
--
-- return false;
--}
--
--/*
-- * Figure out how many ring slots we're going to need to send @skb to
-- * the guest. This function is essentially a dry run of
-- * netbk_gop_frag_copy.
-- */
++ return ((vif->rx.sring->req_prod - peek) < needed) ||
++ ((vif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
+ }
+
+ /*
+@@ -430,7 +430,7 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int
head)
+ * the guest. This function is essentially a dry run of
+ * netbk_gop_frag_copy.
+ */
-static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
--{
-- unsigned int count = 1;
-- int i, copy_off = 0;
--
-- BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
--
-- copy_off = skb_headlen(skb);
--
-- if (skb_shinfo(skb)->gso_size)
-- count++;
--
-- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-- unsigned long size = skb_shinfo(skb)->frags[i].size;
-- unsigned long bytes;
-- while (size > 0) {
-- BUG_ON(copy_off > MAX_BUFFER_OFFSET);
--
-- if (start_new_rx_buffer(copy_off, size, 0)) {
-- count++;
-- copy_off = 0;
-- }
--
-- bytes = size;
-- if (copy_off + bytes > MAX_BUFFER_OFFSET)
-- bytes = MAX_BUFFER_OFFSET - copy_off;
--
-- copy_off += bytes;
-- size -= bytes;
-- }
-- }
-- return count;
--}
--
++static unsigned int count_skb_slots(struct sk_buff *skb, struct xenvif *vif)
+ {
+ unsigned int count = 1;
+ int i, copy_off = 0;
+@@ -464,20 +464,20 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xen_netif *netif
+ return count;
+ }
+
-int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
--{
++int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
- struct xen_netif *netif = netdev_priv(dev);
-- struct xen_netbk *netbk;
--
-- BUG_ON(skb->dev != dev);
--
++ struct xenvif *vif = netdev_priv(dev);
+ struct xen_netbk *netbk;
+
+ BUG_ON(skb->dev != dev);
+
- if (netif->group == -1)
-- goto drop;
--
++ if (vif->group == -1)
+ goto drop;
+
- netbk = &xen_netbk[netif->group];
--
-- /* Drop the packet if the target domain has no receive buffers. */
++ netbk = &xen_netbk[vif->group];
+
+ /* Drop the packet if the target domain has no receive buffers. */
- if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
-- goto drop;
--
-- /*
-- * XXX For now we also copy skbuffs whose head crosses a page
-- * boundary, because netbk_gop_skb can't handle them.
-- */
-- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
-- struct sk_buff *nskb = netbk_copy_skb(skb);
-- if (unlikely(nskb == NULL))
-- goto drop;
-- /* Copy only the header fields we use in this driver. */
-- nskb->dev = skb->dev;
-- nskb->ip_summed = skb->ip_summed;
-- dev_kfree_skb(skb);
-- skb = nskb;
-- }
--
-- /* Reserve ring slots for the worst-case number of fragments. */
++ if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
+ goto drop;
+
+ /*
+@@ -496,14 +496,14 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ }
+
+ /* Reserve ring slots for the worst-case number of fragments. */
- netif->rx_req_cons_peek += count_skb_slots(skb, netif);
- netif_get(netif);
--
++ vif->rx_req_cons_peek += count_skb_slots(skb, vif);
++ xenvif_get(vif);
+
- if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
- netif->rx.sring->req_event = netif->rx_req_cons_peek +
- netbk_max_required_rx_slots(netif);
-- mb(); /* request notification /then/ check & stop the queue */
++ if (netbk_can_queue(dev) && xenvif_queue_full(vif)) {
++ vif->rx.sring->req_event = vif->rx_req_cons_peek +
++ xenvif_max_required_rx_slots(vif);
+ mb(); /* request notification /then/ check & stop the queue */
- if (netbk_queue_full(netif))
-- netif_stop_queue(dev);
-- }
-- skb_queue_tail(&netbk->rx_queue, skb);
--
-- xen_netbk_bh_handler(netbk, 1);
--
-- return 0;
--
-- drop:
++ if (xenvif_queue_full(vif))
+ netif_stop_queue(dev);
+ }
+ skb_queue_tail(&netbk->rx_queue, skb);
+@@ -513,7 +513,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ return 0;
+
+ drop:
- netif->stats.tx_dropped++;
-- dev_kfree_skb(skb);
-- return 0;
--}
--
--struct netrx_pending_operations {
-- unsigned copy_prod, copy_cons;
-- unsigned meta_prod, meta_cons;
-- struct gnttab_copy *copy;
-- struct netbk_rx_meta *meta;
-- int copy_off;
-- grant_ref_t copy_gref;
--};
--
--static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
-- struct netrx_pending_operations *npo)
--{
-- struct netbk_rx_meta *meta;
-- struct xen_netif_rx_request *req;
--
-- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
--
-- meta = npo->meta + npo->meta_prod++;
-- meta->gso_size = 0;
-- meta->size = 0;
-- meta->id = req->id;
--
-- npo->copy_off = 0;
-- npo->copy_gref = req->gref;
--
-- return meta;
--}
--
--/*
-- * 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 netbk_gop_frag_copy(struct xen_netif *netif,
-- struct netrx_pending_operations *npo,
-- struct page *page, unsigned long size,
-- unsigned long offset, int head)
--{
-- struct gnttab_copy *copy_gop;
-- struct netbk_rx_meta *meta;
-- /*
-- * These variables a used iff netif_get_page_ext returns true,
-- * in which case they are guaranteed to be initialized.
-- */
-- unsigned int uninitialized_var(group), uninitialized_var(idx);
-- int foreign = netif_get_page_ext(page, &group, &idx);
-- unsigned long bytes;
--
-- /* Data must not cross a page boundary. */
-- BUG_ON(size + offset > PAGE_SIZE);
--
-- meta = npo->meta + npo->meta_prod - 1;
--
-- while (size > 0) {
-- BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
--
-- if (start_new_rx_buffer(npo->copy_off, size, head)) {
-- /*
-- * Netfront requires there to be some data in the head
-- * buffer.
-- */
-- BUG_ON(head);
--
++ vif->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+@@ -527,13 +527,13 @@ struct netrx_pending_operations {
+ grant_ref_t copy_gref;
+ };
+
+-static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
++static struct netbk_rx_meta *get_next_rx_buffer(struct xenvif *vif,
+ struct netrx_pending_operations *npo)
+ {
+ struct netbk_rx_meta *meta;
+ struct xen_netif_rx_request *req;
+
+- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
++ req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
+
+ meta = npo->meta + npo->meta_prod++;
+ meta->gso_size = 0;
+@@ -550,7 +550,7 @@ static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif
*netif,
+ * 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 netbk_gop_frag_copy(struct xen_netif *netif,
++static void netbk_gop_frag_copy(struct xenvif *vif,
+ struct netrx_pending_operations *npo,
+ struct page *page, unsigned long size,
+ unsigned long offset, int head)
+@@ -580,7 +580,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ */
+ BUG_ON(head);
+
- meta = get_next_rx_buffer(netif, npo);
-- }
--
-- bytes = size;
-- if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
-- bytes = MAX_BUFFER_OFFSET - npo->copy_off;
--
-- copy_gop = npo->copy + npo->copy_prod++;
-- copy_gop->flags = GNTCOPY_dest_gref;
-- if (foreign) {
-- struct xen_netbk *netbk = &xen_netbk[group];
-- struct pending_tx_info *src_pend;
--
-- src_pend = &netbk->pending_tx_info[idx];
--
++ meta = get_next_rx_buffer(vif, npo);
+ }
+
+ bytes = size;
+@@ -595,7 +595,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+
+ src_pend = &netbk->pending_tx_info[idx];
+
- copy_gop->source.domid = src_pend->netif->domid;
-- copy_gop->source.u.ref = src_pend->req.gref;
-- copy_gop->flags |= GNTCOPY_source_gref;
-- } else {
-- void *vaddr = page_address(page);
-- copy_gop->source.domid = DOMID_SELF;
-- copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
-- }
-- copy_gop->source.offset = offset;
++ copy_gop->source.domid = src_pend->vif->domid;
+ copy_gop->source.u.ref = src_pend->req.gref;
+ copy_gop->flags |= GNTCOPY_source_gref;
+ } else {
+@@ -604,7 +604,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
+ }
+ copy_gop->source.offset = offset;
- copy_gop->dest.domid = netif->domid;
--
-- copy_gop->dest.offset = npo->copy_off;
-- copy_gop->dest.u.ref = npo->copy_gref;
-- copy_gop->len = bytes;
--
-- npo->copy_off += bytes;
-- meta->size += bytes;
--
-- offset += bytes;
-- size -= bytes;
-- head = 0; /* There must be something in this buffer now. */
-- }
--}
--
--/*
-- * Prepare an SKB to be transmitted to the frontend.
-- *
-- * This function is responsible for allocating grant operations, meta
-- * structures, etc.
-- *
-- * It returns the number of meta structures consumed. The number of
-- * ring slots used is always equal to the number of meta slots used
-- * plus the number of GSO descriptors used. Currently, we use either
-- * zero GSO descriptors (for non-GSO packets) or one descriptor (for
-- * frontend-side LRO).
-- */
--static int netbk_gop_skb(struct sk_buff *skb,
-- struct netrx_pending_operations *npo)
--{
++ copy_gop->dest.domid = vif->domid;
+
+ copy_gop->dest.offset = npo->copy_off;
+ copy_gop->dest.u.ref = npo->copy_gref;
+@@ -634,7 +634,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
+ static int netbk_gop_skb(struct sk_buff *skb,
+ struct netrx_pending_operations *npo)
+ {
- struct xen_netif *netif = netdev_priv(skb->dev);
-- int nr_frags = skb_shinfo(skb)->nr_frags;
-- int i;
-- struct xen_netif_rx_request *req;
-- struct netbk_rx_meta *meta;
-- int old_meta_prod;
--
-- old_meta_prod = npo->meta_prod;
--
-- /* Set up a GSO prefix descriptor, if necessary */
++ struct xenvif *vif = netdev_priv(skb->dev);
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
+ struct xen_netif_rx_request *req;
+@@ -644,18 +644,18 @@ static int netbk_gop_skb(struct sk_buff *skb,
+ old_meta_prod = npo->meta_prod;
+
+ /* Set up a GSO prefix descriptor, if necessary */
- if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-- meta = npo->meta + npo->meta_prod++;
-- meta->gso_size = skb_shinfo(skb)->gso_size;
-- meta->size = 0;
-- meta->id = req->id;
-- }
--
++ if (skb_shinfo(skb)->gso_size && vif->gso_prefix) {
++ req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
+ meta = npo->meta + npo->meta_prod++;
+ meta->gso_size = skb_shinfo(skb)->gso_size;
+ meta->size = 0;
+ meta->id = req->id;
+ }
+
- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-- meta = npo->meta + npo->meta_prod++;
--
++ req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
+ meta = npo->meta + npo->meta_prod++;
+
- if (!netif->gso_prefix)
-- meta->gso_size = skb_shinfo(skb)->gso_size;
-- else
-- meta->gso_size = 0;
--
-- meta->size = 0;
-- meta->id = req->id;
-- npo->copy_off = 0;
-- npo->copy_gref = req->gref;
--
++ if (!vif->gso_prefix)
+ meta->gso_size = skb_shinfo(skb)->gso_size;
+ else
+ meta->gso_size = 0;
+@@ -665,17 +665,16 @@ static int netbk_gop_skb(struct sk_buff *skb,
+ npo->copy_off = 0;
+ npo->copy_gref = req->gref;
+
- netbk_gop_frag_copy(netif,
- npo, virt_to_page(skb->data),
-- skb_headlen(skb),
-- offset_in_page(skb->data), 1);
--
-- /* Leave a gap for the GSO descriptor. */
++ netbk_gop_frag_copy(vif, npo, virt_to_page(skb->data),
+ skb_headlen(skb),
+ offset_in_page(skb->data), 1);
+
+ /* Leave a gap for the GSO descriptor. */
- if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
- netif->rx.req_cons++;
--
-- for (i = 0; i < nr_frags; i++) {
++ if (skb_shinfo(skb)->gso_size && !vif->gso_prefix)
++ vif->rx.req_cons++;
+
+ for (i = 0; i < nr_frags; i++) {
- netbk_gop_frag_copy(netif, npo,
-- skb_shinfo(skb)->frags[i].page,
-- skb_shinfo(skb)->frags[i].size,
-- skb_shinfo(skb)->frags[i].page_offset,
-- 0);
-- }
--
-- return npo->meta_prod - old_meta_prod;
--}
--
--/*
-- * This is a twin to netbk_gop_skb. Assume that netbk_gop_skb was
-- * used to set up the operations on the top of
-- * netrx_pending_operations, which have since been done. Check that
-- * they didn't give any errors and advance over them.
-- */
--static int netbk_check_gop(int nr_meta_slots, domid_t domid,
-- struct netrx_pending_operations *npo)
--{
-- struct gnttab_copy *copy_op;
-- int status = NETIF_RSP_OKAY;
-- int i;
--
-- for (i = 0; i < nr_meta_slots; i++) {
-- copy_op = npo->copy + npo->copy_cons++;
-- if (copy_op->status != GNTST_okay) {
-- pr_debug("Bad status %d from copy to DOM%d.\n",
-- copy_op->status, domid);
-- status = NETIF_RSP_ERROR;
-- }
-- }
--
-- return status;
--}
--
++ netbk_gop_frag_copy(vif, npo,
+ skb_shinfo(skb)->frags[i].page,
+ skb_shinfo(skb)->frags[i].size,
+ skb_shinfo(skb)->frags[i].page_offset,
+@@ -710,7 +709,7 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
+ return status;
+ }
+
-static void netbk_add_frag_responses(struct xen_netif *netif, int status,
-- struct netbk_rx_meta *meta,
-- int nr_meta_slots)
--{
-- int i;
-- unsigned long offset;
--
-- /* No fragments used */
-- if (nr_meta_slots <= 1)
-- return;
--
-- nr_meta_slots--;
--
-- for (i = 0; i < nr_meta_slots; i++) {
-- int flags;
-- if (i == nr_meta_slots - 1)
-- flags = 0;
-- else
-- flags = NETRXF_more_data;
--
-- offset = 0;
++static void netbk_add_frag_responses(struct xenvif *vif, int status,
+ struct netbk_rx_meta *meta,
+ int nr_meta_slots)
+ {
+@@ -731,7 +730,7 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
+ flags = XEN_NETRXF_more_data;
+
+ offset = 0;
- make_rx_response(netif, meta[i].id, status, offset,
-- meta[i].size, flags);
-- }
--}
--
--struct skb_cb_overlay {
-- int meta_slots_used;
--};
--
--static void net_rx_action(unsigned long data)
--{
++ make_rx_response(vif, meta[i].id, status, offset,
+ meta[i].size, flags);
+ }
+ }
+@@ -742,7 +741,7 @@ struct skb_cb_overlay {
+
+ static void xen_netbk_rx_action(unsigned long data)
+ {
- struct xen_netif *netif = NULL;
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- s8 status;
-- u16 irq, flags;
-- struct xen_netif_rx_response *resp;
-- struct sk_buff_head rxq;
-- struct sk_buff *skb;
-- int notify_nr = 0;
-- int ret;
-- int nr_frags;
-- int count;
-- unsigned long offset;
-- struct skb_cb_overlay *sco;
--
-- struct netrx_pending_operations npo = {
-- .copy = netbk->grant_copy_op,
-- .meta = netbk->meta,
-- };
--
-- skb_queue_head_init(&rxq);
--
-- count = 0;
--
-- while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
++ struct xenvif *vif = NULL;
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ s8 status;
+ u16 irq, flags;
+@@ -766,7 +765,7 @@ static void xen_netbk_rx_action(unsigned long data)
+ count = 0;
+
+ while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
- netif = netdev_priv(skb->dev);
-- nr_frags = skb_shinfo(skb)->nr_frags;
--
-- sco = (struct skb_cb_overlay *)skb->cb;
-- sco->meta_slots_used = netbk_gop_skb(skb, &npo);
--
-- count += nr_frags + 1;
--
-- __skb_queue_tail(&rxq, skb);
--
-- /* Filled the batch queue? */
-- if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
-- break;
-- }
--
-- BUG_ON(npo.meta_prod > ARRAY_SIZE(netbk->meta));
--
-- if (!npo.copy_prod)
-- return;
--
-- BUG_ON(npo.copy_prod > ARRAY_SIZE(netbk->grant_copy_op));
-- ret = HYPERVISOR_grant_table_op(GNTTABOP_copy, &netbk->grant_copy_op,
-- npo.copy_prod);
-- BUG_ON(ret != 0);
--
-- while ((skb = __skb_dequeue(&rxq)) != NULL) {
-- sco = (struct skb_cb_overlay *)skb->cb;
--
++ vif = netdev_priv(skb->dev);
+ nr_frags = skb_shinfo(skb)->nr_frags;
+
+ sco = (struct skb_cb_overlay *)skb->cb;
+@@ -794,11 +793,11 @@ static void xen_netbk_rx_action(unsigned long data)
+ while ((skb = __skb_dequeue(&rxq)) != NULL) {
+ sco = (struct skb_cb_overlay *)skb->cb;
+
- netif = netdev_priv(skb->dev);
--
++ vif = netdev_priv(skb->dev);
+
- if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
- resp = RING_GET_RESPONSE(&netif->rx,
- netif->rx.rsp_prod_pvt++);
--
-- resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
--
-- resp->offset = netbk->meta[npo.meta_cons].gso_size;
-- resp->id = netbk->meta[npo.meta_cons].id;
-- resp->status = sco->meta_slots_used;
--
-- npo.meta_cons++;
-- sco->meta_slots_used--;
-- }
--
--
++ if (netbk->meta[npo.meta_cons].gso_size && vif->gso_prefix) {
++ resp = RING_GET_RESPONSE(&vif->rx,
++ vif->rx.rsp_prod_pvt++);
+
+ resp->flags = XEN_NETRXF_gso_prefix | XEN_NETRXF_more_data;
+
+@@ -811,11 +810,11 @@ static void xen_netbk_rx_action(unsigned long data)
+ }
+
+
- netif->stats.tx_bytes += skb->len;
- netif->stats.tx_packets++;
--
-- status = netbk_check_gop(sco->meta_slots_used,
++ vif->stats.tx_bytes += skb->len;
++ vif->stats.tx_packets++;
+
+ status = netbk_check_gop(sco->meta_slots_used,
- netif->domid, &npo);
--
-- if (sco->meta_slots_used == 1)
-- flags = 0;
-- else
-- flags = NETRXF_more_data;
--
-- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
-- flags |= NETRXF_csum_blank | NETRXF_data_validated;
-- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
-- /* remote but checksummed. */
-- flags |= NETRXF_data_validated;
--
-- offset = 0;
++ vif->domid, &npo);
+
+ if (sco->meta_slots_used == 1)
+ flags = 0;
+@@ -829,16 +828,16 @@ static void xen_netbk_rx_action(unsigned long data)
+ flags |= XEN_NETRXF_data_validated;
+
+ offset = 0;
- resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
-- status, offset,
-- netbk->meta[npo.meta_cons].size,
-- flags);
--
++ resp = make_rx_response(vif, netbk->meta[npo.meta_cons].id,
+ status, offset,
+ netbk->meta[npo.meta_cons].size,
+ flags);
+
- if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
-- struct xen_netif_extra_info *gso =
-- (struct xen_netif_extra_info *)
++ if (netbk->meta[npo.meta_cons].gso_size && !vif->gso_prefix) {
+ struct xen_netif_extra_info *gso =
+ (struct xen_netif_extra_info *)
- RING_GET_RESPONSE(&netif->rx,
- netif->rx.rsp_prod_pvt++);
--
-- resp->flags |= NETRXF_extra_info;
--
-- gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
-- gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
-- gso->u.gso.pad = 0;
-- gso->u.gso.features = 0;
--
-- gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
-- gso->flags = 0;
-- }
--
++ RING_GET_RESPONSE(&vif->rx,
++ vif->rx.rsp_prod_pvt++);
+
+ resp->flags |= XEN_NETRXF_extra_info;
+
+@@ -851,23 +850,23 @@ static void xen_netbk_rx_action(unsigned long data)
+ gso->flags = 0;
+ }
+
- netbk_add_frag_responses(netif, status,
-- netbk->meta + npo.meta_cons + 1,
-- sco->meta_slots_used);
--
++ netbk_add_frag_responses(vif, status,
+ netbk->meta + npo.meta_cons + 1,
+ sco->meta_slots_used);
+
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
- irq = netif->irq;
-- if (ret && !netbk->rx_notify[irq]) {
-- netbk->rx_notify[irq] = 1;
-- netbk->notify_list[notify_nr++] = irq;
-- }
--
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
++ irq = vif->irq;
+ if (ret && !netbk->rx_notify[irq]) {
+ netbk->rx_notify[irq] = 1;
+ netbk->notify_list[notify_nr++] = irq;
+ }
+
- if (netif_queue_stopped(netif->dev) &&
- netif_schedulable(netif) &&
- !netbk_queue_full(netif))
- netif_wake_queue(netif->dev);
--
++ if (netif_queue_stopped(vif->dev) &&
++ xenvif_schedulable(vif) &&
++ !xenvif_queue_full(vif))
++ netif_wake_queue(vif->dev);
+
- netif_put(netif);
-- npo.meta_cons += sco->meta_slots_used;
-- dev_kfree_skb(skb);
-- }
--
-- while (notify_nr != 0) {
-- irq = netbk->notify_list[--notify_nr];
-- netbk->rx_notify[irq] = 0;
-- notify_remote_via_irq(irq);
-- }
--
-- /* More work to do? */
-- if (!skb_queue_empty(&netbk->rx_queue) &&
-- !timer_pending(&netbk->net_timer))
-- xen_netbk_bh_handler(netbk, 1);
--}
--
--static void net_alarm(unsigned long data)
--{
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- xen_netbk_bh_handler(netbk, 1);
--}
--
++ xenvif_put(vif);
+ npo.meta_cons += sco->meta_slots_used;
+ dev_kfree_skb(skb);
+ }
+@@ -890,93 +889,92 @@ static void net_alarm(unsigned long data)
+ xen_netbk_bh_handler(netbk, 1);
+ }
+
-static void netbk_tx_pending_timeout(unsigned long data)
--{
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- xen_netbk_bh_handler(netbk, 0);
--}
--
++static void xen_netbk_tx_pending_timeout(unsigned long data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ xen_netbk_bh_handler(netbk, 0);
+ }
+
-struct net_device_stats *netif_be_get_stats(struct net_device *dev)
--{
++struct net_device_stats *xenvif_get_stats(struct net_device *dev)
+ {
- struct xen_netif *netif = netdev_priv(dev);
- return &netif->stats;
--}
--
++ struct xenvif *vif = netdev_priv(dev);
++ return &vif->stats;
+ }
+
-static int __on_net_schedule_list(struct xen_netif *netif)
--{
++static int __on_net_schedule_list(struct xenvif *vif)
+ {
- return !list_empty(&netif->list);
--}
--
--/* Must be called with net_schedule_list_lock held */
++ return !list_empty(&vif->list);
+ }
+
+ /* Must be called with net_schedule_list_lock held */
-static void remove_from_net_schedule_list(struct xen_netif *netif)
--{
++static void remove_from_net_schedule_list(struct xenvif *vif)
+ {
- if (likely(__on_net_schedule_list(netif))) {
- list_del_init(&netif->list);
- netif_put(netif);
-- }
--}
--
++ if (likely(__on_net_schedule_list(vif))) {
++ list_del_init(&vif->list);
++ xenvif_put(vif);
+ }
+ }
+
-static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
--{
++static struct xenvif *poll_net_schedule_list(struct xen_netbk *netbk)
+ {
- struct xen_netif *netif = NULL;
--
-- spin_lock_irq(&netbk->net_schedule_list_lock);
-- if (list_empty(&netbk->net_schedule_list))
-- goto out;
--
++ struct xenvif *vif = NULL;
+
+ spin_lock_irq(&netbk->net_schedule_list_lock);
+ if (list_empty(&netbk->net_schedule_list))
+ goto out;
+
- netif = list_first_entry(&netbk->net_schedule_list,
- struct xen_netif, list);
- if (!netif)
-- goto out;
--
++ vif = list_first_entry(&netbk->net_schedule_list,
++ struct xenvif, list);
++ if (!vif)
+ goto out;
+
- netif_get(netif);
--
++ xenvif_get(vif);
+
- remove_from_net_schedule_list(netif);
--out:
-- spin_unlock_irq(&netbk->net_schedule_list_lock);
++ remove_from_net_schedule_list(vif);
+ out:
+ spin_unlock_irq(&netbk->net_schedule_list_lock);
- return netif;
--}
--
++ return vif;
+ }
+
-static void add_to_net_schedule_list_tail(struct xen_netif *netif)
--{
-- unsigned long flags;
--
++static void add_to_net_schedule_list_tail(struct xenvif *vif)
+ {
+ unsigned long flags;
+
- struct xen_netbk *netbk = &xen_netbk[netif->group];
- if (__on_net_schedule_list(netif))
-- return;
--
-- spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
++ struct xen_netbk *netbk = &xen_netbk[vif->group];
++ if (__on_net_schedule_list(vif))
+ return;
+
+ spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
- if (!__on_net_schedule_list(netif) &&
- likely(netif_schedulable(netif))) {
- list_add_tail(&netif->list, &netbk->net_schedule_list);
- netif_get(netif);
-- }
-- spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
--}
--
++ if (!__on_net_schedule_list(vif) &&
++ likely(xenvif_schedulable(vif))) {
++ list_add_tail(&vif->list, &netbk->net_schedule_list);
++ xenvif_get(vif);
+ }
+ spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
+ }
+
-void netif_schedule_work(struct xen_netif *netif)
--{
++void xenvif_schedule_work(struct xenvif *vif)
+ {
- struct xen_netbk *netbk = &xen_netbk[netif->group];
-- int more_to_do;
--
++ struct xen_netbk *netbk = &xen_netbk[vif->group];
+ int more_to_do;
+
- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
--
-- if (more_to_do) {
++ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
+
+ if (more_to_do) {
- add_to_net_schedule_list_tail(netif);
-- maybe_schedule_tx_action(netbk);
-- }
--}
--
++ add_to_net_schedule_list_tail(vif);
+ maybe_schedule_tx_action(netbk);
+ }
+ }
+
-void netif_deschedule_work(struct xen_netif *netif)
--{
++void xenvif_deschedule_work(struct xenvif *vif)
+ {
- struct xen_netbk *netbk = &xen_netbk[netif->group];
-- spin_lock_irq(&netbk->net_schedule_list_lock);
++ struct xen_netbk *netbk = &xen_netbk[vif->group];
+ spin_lock_irq(&netbk->net_schedule_list_lock);
- remove_from_net_schedule_list(netif);
-- spin_unlock_irq(&netbk->net_schedule_list_lock);
--}
--
++ remove_from_net_schedule_list(vif);
+ spin_unlock_irq(&netbk->net_schedule_list_lock);
+ }
+
-
-static void tx_add_credit(struct xen_netif *netif)
--{
-- unsigned long max_burst, max_credit;
--
-- /*
-- * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
-- * Otherwise the interface can seize up due to insufficient credit.
-- */
++static void tx_add_credit(struct xenvif *vif)
+ {
+ unsigned long max_burst, max_credit;
+
+@@ -984,23 +982,23 @@ static void tx_add_credit(struct xen_netif *netif)
+ * 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(&netif->tx, netif->tx.req_cons)->size;
-- max_burst = min(max_burst, 131072UL);
++ max_burst = RING_GET_REQUEST(&vif->tx, vif->tx.req_cons)->size;
+ max_burst = min(max_burst, 131072UL);
- max_burst = max(max_burst, netif->credit_bytes);
--
-- /* Take care that adding a new chunk of credit doesn't wrap to zero. */
++ max_burst = max(max_burst, vif->credit_bytes);
+
+ /* Take care that adding a new chunk of credit doesn't wrap to zero. */
- max_credit = netif->remaining_credit + netif->credit_bytes;
- if (max_credit < netif->remaining_credit)
-- max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
--
++ max_credit = vif->remaining_credit + vif->credit_bytes;
++ if (max_credit < vif->remaining_credit)
+ max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
+
- netif->remaining_credit = min(max_credit, max_burst);
--}
--
--static void tx_credit_callback(unsigned long data)
--{
++ vif->remaining_credit = min(max_credit, max_burst);
+ }
+
+ static void tx_credit_callback(unsigned long data)
+ {
- struct xen_netif *netif = (struct xen_netif *)data;
- tx_add_credit(netif);
- netif_schedule_work(netif);
--}
--
--static inline int copy_pending_req(struct xen_netbk *netbk,
-- pending_ring_idx_t pending_idx)
--{
-- return gnttab_copy_grant_page(
-- netbk->grant_tx_handle[pending_idx],
-- &netbk->mmap_pages[pending_idx]);
--}
--
++ struct xenvif *vif = (struct xenvif *)data;
++ tx_add_credit(vif);
++ xenvif_schedule_work(vif);
+ }
+
+ static inline int copy_pending_req(struct xen_netbk *netbk,
+@@ -1011,7 +1009,7 @@ static inline int copy_pending_req(struct xen_netbk *netbk,
+ &netbk->mmap_pages[pending_idx]);
+ }
+
-static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
--{
-- struct netbk_tx_pending_inuse *inuse, *n;
-- struct gnttab_unmap_grant_ref *gop;
-- u16 pending_idx;
-- pending_ring_idx_t dc, dp;
-- struct xen_netif *netif;
-- int ret;
-- LIST_HEAD(list);
--
-- dc = netbk->dealloc_cons;
-- gop = netbk->tx_unmap_ops;
--
-- /* Free up any grants we have finished using. */
-- do {
-- dp = netbk->dealloc_prod;
--
-- /* Ensure we see all indices enqueued by netif_idx_release(). */
-- smp_rmb();
--
-- while (dc != dp) {
-- unsigned long pfn;
-- struct netbk_tx_pending_inuse *pending_inuse =
-- netbk->pending_inuse;
--
-- pending_idx = netbk->dealloc_ring[pending_index(dc++)];
-- list_move_tail(&pending_inuse[pending_idx].list, &list);
--
-- 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(netbk, pending_idx),
-- GNTMAP_host_map,
-- netbk->grant_tx_handle[pending_idx]);
-- gop++;
-- }
--
-- } while (dp != netbk->dealloc_prod);
--
-- netbk->dealloc_cons = dc;
--
-- ret = HYPERVISOR_grant_table_op(
-- GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
-- gop - netbk->tx_unmap_ops);
-- BUG_ON(ret);
--
-- /*
-- * Copy any entries that have been pending for too long
-- */
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !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;
-- pending_tx_info = netbk->pending_tx_info;
--
-- if (time_after(inuse->alloc_time + HZ / 2, jiffies))
-- break;
--
-- pending_idx = inuse - netbk->pending_inuse;
--
-- pending_tx_info[pending_idx].netif->nr_copied_skbs++;
--
-- switch (copy_pending_req(netbk, pending_idx)) {
-- case 0:
-- list_move_tail(&inuse->list, &list);
-- continue;
-- case -EBUSY:
-- list_del_init(&inuse->list);
-- continue;
-- case -ENOENT:
-- continue;
-- }
--
-- break;
-- }
-- }
--
-- list_for_each_entry_safe(inuse, n, &list, list) {
-- struct pending_tx_info *pending_tx_info;
-- pending_ring_idx_t index;
--
-- 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(netbk->mmap_pages[pending_idx]);
--
-- index = pending_index(netbk->pending_prod++);
-- netbk->pending_ring[index] = pending_idx;
--
++static inline void xen_netbk_tx_action_dealloc(struct xen_netbk *netbk)
+ {
+ struct netbk_tx_pending_inuse *inuse, *n;
+ struct gnttab_unmap_grant_ref *gop;
+@@ -1110,34 +1108,34 @@ static inline void net_tx_action_dealloc(struct xen_netbk
*netbk)
+ index = pending_index(netbk->pending_prod++);
+ netbk->pending_ring[index] = pending_idx;
+
- netif_put(netif);
--
-- list_del_init(&inuse->list);
-- }
--}
--
++ xenvif_put(vif);
+
+ list_del_init(&inuse->list);
+ }
+ }
+
-static void netbk_tx_err(struct xen_netif *netif,
- struct xen_netif_tx_request *txp, RING_IDX end)
--{
++static void netbk_tx_err(struct xenvif *vif,
++ struct xen_netif_tx_request *txp, RING_IDX end)
+ {
- RING_IDX cons = netif->tx.req_cons;
--
-- do {
-- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-- if (cons >= end)
-- break;
++ RING_IDX cons = vif->tx.req_cons;
+
+ do {
+- make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
++ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+ if (cons >= end)
+ break;
- txp = RING_GET_REQUEST(&netif->tx, cons++);
-- } while (1);
++ txp = RING_GET_REQUEST(&vif->tx, cons++);
+ } while (1);
- netif->tx.req_cons = cons;
- netif_schedule_work(netif);
- netif_put(netif);
--}
--
++ vif->tx.req_cons = cons;
++ xenvif_schedule_work(vif);
++ xenvif_put(vif);
+ }
+
-static int netbk_count_requests(struct xen_netif *netif,
-- struct xen_netif_tx_request *first,
-- struct xen_netif_tx_request *txp,
-- int work_to_do)
--{
++static int netbk_count_requests(struct xenvif *vif,
+ struct xen_netif_tx_request *first,
+ struct xen_netif_tx_request *txp,
+ int work_to_do)
+ {
- RING_IDX cons = netif->tx.req_cons;
-- int frags = 0;
--
-- if (!(first->flags & NETTXF_more_data))
-- return 0;
--
-- do {
-- if (frags >= work_to_do) {
-- pr_debug("Need more frags\n");
-- return -frags;
-- }
--
-- if (unlikely(frags >= MAX_SKB_FRAGS)) {
-- pr_debug("Too many frags\n");
-- return -frags;
-- }
--
++ RING_IDX cons = vif->tx.req_cons;
+ int frags = 0;
+
+ if (!(first->flags & XEN_NETTXF_more_data))
+@@ -1154,7 +1152,7 @@ static int netbk_count_requests(struct xen_netif *netif,
+ return -frags;
+ }
+
- memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
-- sizeof(*txp));
-- if (txp->size > first->size) {
-- pr_debug("Frags galore\n");
-- return -frags;
-- }
--
-- first->size -= txp->size;
-- frags++;
--
-- if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-- pr_debug("txp->offset: %x, size: %u\n",
-- txp->offset, txp->size);
-- return -frags;
-- }
-- } while ((txp++)->flags & NETTXF_more_data);
--
-- return frags;
--}
--
--static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
-- struct xen_netif *netif,
-- struct sk_buff *skb,
-- struct xen_netif_tx_request *txp,
-- struct gnttab_map_grant_ref *mop)
--{
-- struct skb_shared_info *shinfo = skb_shinfo(skb);
-- skb_frag_t *frags = shinfo->frags;
-- unsigned long pending_idx = *((u16 *)skb->data);
-- int i, start;
--
-- /* Skip first skb fragment if it is on same page as header fragment. */
-- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
--
-- for (i = start; i < shinfo->nr_frags; i++, txp++) {
-- pending_ring_idx_t index;
-- struct pending_tx_info *pending_tx_info =
-- netbk->pending_tx_info;
--
-- index = pending_index(netbk->pending_cons++);
-- 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);
--
-- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
++ memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
+ sizeof(*txp));
+ if (txp->size > first->size) {
+ pr_debug("Frags galore\n");
+@@ -1175,7 +1173,7 @@ static int netbk_count_requests(struct xen_netif *netif,
+ }
+
+ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
+- struct xen_netif *netif,
++ struct xenvif *vif,
+ struct sk_buff *skb,
+ struct xen_netif_tx_request *txp,
+ struct gnttab_map_grant_ref *mop)
+@@ -1201,8 +1199,8 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
+ txp->gref, netif->domid);
+
+ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
- netif_get(netif);
- pending_tx_info[pending_idx].netif = netif;
-- frags[i].page = (void *)pending_idx;
-- }
--
-- return mop;
--}
--
--static int netbk_tx_check_mop(struct xen_netbk *netbk,
-- struct sk_buff *skb,
-- struct gnttab_map_grant_ref **mopp)
--{
-- struct gnttab_map_grant_ref *mop = *mopp;
-- int pending_idx = *((u16 *)skb->data);
-- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
-- struct xen_netif *netif = pending_tx_info[pending_idx].netif;
-- struct xen_netif_tx_request *txp;
-- struct skb_shared_info *shinfo = skb_shinfo(skb);
-- int nr_frags = shinfo->nr_frags;
-- int i, err, start;
--
-- /* Check status of header. */
-- err = mop->status;
-- if (unlikely(err)) {
-- pending_ring_idx_t index;
-- index = pending_index(netbk->pending_prod++);
-- txp = &pending_tx_info[pending_idx].req;
-- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-- netbk->pending_ring[index] = pending_idx;
-- netif_put(netif);
-- } else {
-- set_phys_to_machine(
-- __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
-- FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
-- netbk->grant_tx_handle[pending_idx] = mop->handle;
-- }
--
-- /* Skip first skb fragment if it is on same page as header fragment. */
-- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
--
-- 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)) {
-- unsigned long addr;
-- addr = idx_to_kaddr(netbk, pending_idx);
-- set_phys_to_machine(
-- __pa(addr)>>PAGE_SHIFT,
-- FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
-- netbk->grant_tx_handle[pending_idx] = mop->handle;
-- /* Had a previous error? Invalidate this fragment. */
-- if (unlikely(err))
-- netif_idx_release(netbk, pending_idx);
-- continue;
-- }
--
-- /* Error on this fragment: respond to client with an error. */
-- txp = &netbk->pending_tx_info[pending_idx].req;
-- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-- index = pending_index(netbk->pending_prod++);
-- netbk->pending_ring[index] = pending_idx;
-- netif_put(netif);
--
-- /* Not the first error? Preceding frags already invalidated. */
-- if (err)
-- continue;
--
-- /* First error: invalidate header and preceding fragments. */
-- pending_idx = *((u16 *)skb->data);
-- netif_idx_release(netbk, pending_idx);
-- for (j = start; j < i; j++) {
-- pending_idx = (unsigned long)shinfo->frags[i].page;
-- netif_idx_release(netbk, pending_idx);
-- }
--
-- /* Remember the error: invalidate all subsequent fragments. */
-- err = newerr;
-- }
--
-- *mopp = mop + 1;
-- return err;
--}
--
--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;
-- int i;
--
-- for (i = 0; i < nr_frags; i++) {
-- skb_frag_t *frag = shinfo->frags + i;
-- struct xen_netif_tx_request *txp;
-- unsigned long pending_idx;
--
-- pending_idx = (unsigned long)frag->page;
--
-- netbk->pending_inuse[pending_idx].alloc_time = jiffies;
-- list_add_tail(&netbk->pending_inuse[pending_idx].list,
-- &netbk->pending_inuse_head);
--
-- txp = &netbk->pending_tx_info[pending_idx].req;
-- frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
-- frag->size = txp->size;
-- frag->page_offset = txp->offset;
--
-- skb->len += txp->size;
-- skb->data_len += txp->size;
-- skb->truesize += txp->size;
-- }
--}
--
++ xenvif_get(vif);
++ pending_tx_info[pending_idx].vif = vif;
+ frags[i].page = (void *)pending_idx;
+ }
+
+@@ -1216,7 +1214,7 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+ struct gnttab_map_grant_ref *mop = *mopp;
+ int pending_idx = *((u16 *)skb->data);
+ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
+- struct xen_netif *netif = pending_tx_info[pending_idx].netif;
++ struct xenvif *vif = pending_tx_info[pending_idx].vif;
+ struct xen_netif_tx_request *txp;
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ int nr_frags = shinfo->nr_frags;
+@@ -1228,9 +1226,9 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+ pending_ring_idx_t index;
+ index = pending_index(netbk->pending_prod++);
+ txp = &pending_tx_info[pending_idx].req;
+- make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
++ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+ netbk->pending_ring[index] = pending_idx;
+- netif_put(netif);
++ xenvif_put(vif);
+ } else {
+ set_phys_to_machine(
+ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
+@@ -1264,10 +1262,10 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+
+ /* Error on this fragment: respond to client with an error. */
+ txp = &netbk->pending_tx_info[pending_idx].req;
+- make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
++ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+ index = pending_index(netbk->pending_prod++);
+ netbk->pending_ring[index] = pending_idx;
+- netif_put(netif);
++ xenvif_put(vif);
+
+ /* Not the first error? Preceding frags already invalidated. */
+ if (err)
+@@ -1317,12 +1315,12 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
+ }
+ }
+
-int netbk_get_extras(struct xen_netif *netif,
-- struct xen_netif_extra_info *extras,
-- int work_to_do)
--{
-- struct xen_netif_extra_info extra;
++int netbk_get_extras(struct xenvif *vif,
+ struct xen_netif_extra_info *extras,
+ int work_to_do)
+ {
+ struct xen_netif_extra_info extra;
- RING_IDX cons = netif->tx.req_cons;
--
-- do {
-- if (unlikely(work_to_do-- <= 0)) {
-- pr_debug("Missing extra info\n");
-- return -EBADR;
-- }
--
++ RING_IDX cons = vif->tx.req_cons;
+
+ do {
+ if (unlikely(work_to_do-- <= 0)) {
+@@ -1330,17 +1328,17 @@ int netbk_get_extras(struct xen_netif *netif,
+ return -EBADR;
+ }
+
- memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
-- sizeof(extra));
-- if (unlikely(!extra.type ||
-- extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++ memcpy(&extra, RING_GET_REQUEST(&vif->tx, cons),
+ sizeof(extra));
+ if (unlikely(!extra.type ||
+ extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
- netif->tx.req_cons = ++cons;
-- pr_debug("Invalid extra type: %d\n", extra.type);
-- return -EINVAL;
-- }
--
-- memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
++ vif->tx.req_cons = ++cons;
+ pr_debug("Invalid extra type: %d\n", extra.type);
+ return -EINVAL;
+ }
+
+ memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
- netif->tx.req_cons = ++cons;
-- } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
--
-- return work_to_do;
--}
--
--static int netbk_set_skb_gso(struct sk_buff *skb,
-- struct xen_netif_extra_info *gso)
--{
-- if (!gso->u.gso.size) {
-- pr_debug("GSO size must not be zero.\n");
-- return -EINVAL;
-- }
--
-- /* Currently only TCPv4 S.O. is supported. */
-- if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-- pr_debug("Bad GSO type %d.\n", gso->u.gso.type);
-- return -EINVAL;
-- }
--
-- skb_shinfo(skb)->gso_size = gso->u.gso.size;
-- skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
--
-- /* Header must be checked, and gso_segs computed. */
-- skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-- skb_shinfo(skb)->gso_segs = 0;
--
-- return 0;
--}
--
++ vif->tx.req_cons = ++cons;
+ } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+ return work_to_do;
+@@ -1370,7 +1368,7 @@ static int netbk_set_skb_gso(struct sk_buff *skb,
+ return 0;
+ }
+
-static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
--{
-- struct iphdr *iph;
-- unsigned char *th;
-- int err = -EPROTO;
-- int recalculate_partial_csum = 0;
--
-- /*
-- * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
-- * peers can fail to set NETRXF_csum_blank when sending a GSO
-- * frame. In this case force the SKB to CHECKSUM_PARTIAL and
-- * recalculate the partial checksum.
-- */
-- if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
++static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
+ {
+ struct iphdr *iph;
+ unsigned char *th;
+@@ -1384,7 +1382,7 @@ static int checksum_setup(struct xen_netif *netif, struct sk_buff
*skb)
+ * recalculate the partial checksum.
+ */
+ if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
- netif->rx_gso_checksum_fixup++;
-- skb->ip_summed = CHECKSUM_PARTIAL;
-- recalculate_partial_csum = 1;
-- }
--
-- /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
-- if (skb->ip_summed != CHECKSUM_PARTIAL)
-- return 0;
--
-- if (skb->protocol != htons(ETH_P_IP))
-- goto out;
--
-- iph = (void *)skb->data;
-- th = skb->data + 4 * iph->ihl;
-- if (th >= skb_tail_pointer(skb))
-- goto out;
--
-- skb->csum_start = th - skb->head;
-- switch (iph->protocol) {
-- case IPPROTO_TCP:
-- skb->csum_offset = offsetof(struct tcphdr, check);
--
-- if (recalculate_partial_csum) {
-- struct tcphdr *tcph = (struct tcphdr *)th;
-- tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-- skb->len - iph->ihl*4,
-- IPPROTO_TCP, 0);
-- }
-- break;
-- case IPPROTO_UDP:
-- skb->csum_offset = offsetof(struct udphdr, check);
--
-- if (recalculate_partial_csum) {
-- struct udphdr *udph = (struct udphdr *)th;
-- udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-- skb->len - iph->ihl*4,
-- IPPROTO_UDP, 0);
-- }
-- break;
-- default:
-- if (net_ratelimit())
-- printk(KERN_ERR "Attempting to checksum a non-"
-- "TCP/UDP packet, dropping a protocol"
-- " %d packet", iph->protocol);
-- goto out;
-- }
--
-- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
-- goto out;
--
-- err = 0;
--
--out:
-- return err;
--}
--
++ vif->rx_gso_checksum_fixup++;
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ recalculate_partial_csum = 1;
+ }
+@@ -1440,30 +1438,30 @@ out:
+ return err;
+ }
+
-static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
--{
-- unsigned long now = jiffies;
-- unsigned long next_credit =
++static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
+ {
+ unsigned long now = jiffies;
+ unsigned long next_credit =
- netif->credit_timeout.expires +
- msecs_to_jiffies(netif->credit_usec / 1000);
--
-- /* Timer could already be pending in rare cases. */
++ vif->credit_timeout.expires +
++ msecs_to_jiffies(vif->credit_usec / 1000);
+
+ /* Timer could already be pending in rare cases. */
- if (timer_pending(&netif->credit_timeout))
-- return true;
--
-- /* Passed the point where we can replenish credit? */
-- if (time_after_eq(now, next_credit)) {
++ if (timer_pending(&vif->credit_timeout))
+ return true;
+
+ /* Passed the point where we can replenish credit? */
+ if (time_after_eq(now, next_credit)) {
- netif->credit_timeout.expires = now;
- tx_add_credit(netif);
-- }
--
-- /* Still too big to send right now? Set a callback. */
++ vif->credit_timeout.expires = now;
++ tx_add_credit(vif);
+ }
+
+ /* Still too big to send right now? Set a callback. */
- if (size > netif->remaining_credit) {
- netif->credit_timeout.data =
- (unsigned long)netif;
- netif->credit_timeout.function =
-- tx_credit_callback;
++ if (size > vif->remaining_credit) {
++ vif->credit_timeout.data =
++ (unsigned long)vif;
++ vif->credit_timeout.function =
+ tx_credit_callback;
- mod_timer(&netif->credit_timeout,
-- next_credit);
--
-- return true;
-- }
--
-- return false;
--}
--
--static unsigned net_tx_build_mops(struct xen_netbk *netbk)
--{
-- struct gnttab_map_grant_ref *mop;
-- struct sk_buff *skb;
-- int ret;
--
-- mop = netbk->tx_map_ops;
-- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-- !list_empty(&netbk->net_schedule_list)) {
++ mod_timer(&vif->credit_timeout,
+ next_credit);
+
+ return true;
+@@ -1481,7 +1479,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ mop = netbk->tx_map_ops;
+ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list)) {
- struct xen_netif *netif;
-- struct xen_netif_tx_request txreq;
-- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
-- u16 pending_idx;
-- RING_IDX idx;
-- int work_to_do;
-- unsigned int data_len;
-- pending_ring_idx_t index;
--
-- /* Get a netif from the list with work to do. */
++ struct xenvif *vif;
+ struct xen_netif_tx_request txreq;
+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+@@ -1492,53 +1490,53 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ pending_ring_idx_t index;
+
+ /* Get a netif from the list with work to do. */
- netif = poll_net_schedule_list(netbk);
- if (!netif)
-- continue;
--
++ vif = poll_net_schedule_list(netbk);
++ if (!vif)
+ continue;
+
- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
-- if (!work_to_do) {
++ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do);
+ if (!work_to_do) {
- netif_put(netif);
-- continue;
-- }
--
++ xenvif_put(vif);
+ continue;
+ }
+
- idx = netif->tx.req_cons;
-- rmb(); /* Ensure that we see the request before we copy it. */
++ idx = vif->tx.req_cons;
+ rmb(); /* Ensure that we see the request before we copy it. */
- memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
--
-- /* Credit-based scheduling. */
++ memcpy(&txreq, RING_GET_REQUEST(&vif->tx, idx), sizeof(txreq));
+
+ /* Credit-based scheduling. */
- if (txreq.size > netif->remaining_credit &&
- tx_credit_exceeded(netif, txreq.size)) {
- netif_put(netif);
-- continue;
-- }
--
++ if (txreq.size > vif->remaining_credit &&
++ tx_credit_exceeded(vif, txreq.size)) {
++ xenvif_put(vif);
+ continue;
+ }
+
- netif->remaining_credit -= txreq.size;
--
-- work_to_do--;
++ vif->remaining_credit -= txreq.size;
+
+ work_to_do--;
- netif->tx.req_cons = ++idx;
--
-- memset(extras, 0, sizeof(extras));
-- if (txreq.flags & NETTXF_extra_info) {
++ vif->tx.req_cons = ++idx;
+
+ memset(extras, 0, sizeof(extras));
+ if (txreq.flags & XEN_NETTXF_extra_info) {
- work_to_do = netbk_get_extras(netif, extras,
-- work_to_do);
++ work_to_do = netbk_get_extras(vif, extras,
+ work_to_do);
- idx = netif->tx.req_cons;
-- if (unlikely(work_to_do < 0)) {
++ idx = vif->tx.req_cons;
+ if (unlikely(work_to_do < 0)) {
- netbk_tx_err(netif, &txreq, idx);
-- continue;
-- }
-- }
--
++ netbk_tx_err(vif, &txreq, idx);
+ continue;
+ }
+ }
+
- ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
-- if (unlikely(ret < 0)) {
++ ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
+ if (unlikely(ret < 0)) {
- netbk_tx_err(netif, &txreq, idx - ret);
-- continue;
-- }
-- idx += ret;
--
-- if (unlikely(txreq.size < ETH_HLEN)) {
-- pr_debug("Bad packet size: %d\n", txreq.size);
++ netbk_tx_err(vif, &txreq, idx - ret);
+ continue;
+ }
+ idx += ret;
+
+ if (unlikely(txreq.size < ETH_HLEN)) {
+ pr_debug("Bad packet size: %d\n", txreq.size);
- netbk_tx_err(netif, &txreq, idx);
-- continue;
-- }
--
-- /* No crossing a page as the payload mustn't fragment. */
-- if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-- pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
-- txreq.offset, txreq.size,
-- (txreq.offset&~PAGE_MASK) + txreq.size);
++ netbk_tx_err(vif, &txreq, idx);
+ continue;
+ }
+
+@@ -1547,7 +1545,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
+ txreq.offset, txreq.size,
+ (txreq.offset&~PAGE_MASK) + txreq.size);
- netbk_tx_err(netif, &txreq, idx);
-- continue;
-- }
--
-- index = pending_index(netbk->pending_cons);
-- pending_idx = netbk->pending_ring[index];
--
-- data_len = (txreq.size > PKT_PROT_LEN &&
-- ret < MAX_SKB_FRAGS) ?
-- PKT_PROT_LEN : txreq.size;
--
-- skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
-- GFP_ATOMIC | __GFP_NOWARN);
-- if (unlikely(skb == NULL)) {
-- pr_debug("Can't allocate a skb in start_xmit.\n");
++ netbk_tx_err(vif, &txreq, idx);
+ continue;
+ }
+
+@@ -1562,7 +1560,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(skb == NULL)) {
+ pr_debug("Can't allocate a skb in start_xmit.\n");
- netbk_tx_err(netif, &txreq, idx);
-- break;
-- }
--
-- /* Packets passed to netif_rx() must have some headroom. */
-- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
--
-- if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
-- struct xen_netif_extra_info *gso;
-- gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
--
-- if (netbk_set_skb_gso(skb, gso)) {
-- kfree_skb(skb);
++ netbk_tx_err(vif, &txreq, idx);
+ break;
+ }
+
+@@ -1575,7 +1573,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+
+ if (netbk_set_skb_gso(skb, gso)) {
+ kfree_skb(skb);
- netbk_tx_err(netif, &txreq, idx);
-- continue;
-- }
-- }
--
-- gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
-- GNTMAP_host_map | GNTMAP_readonly,
-- txreq.gref, netif->domid);
-- mop++;
--
-- memcpy(&netbk->pending_tx_info[pending_idx].req,
-- &txreq, sizeof(txreq));
-- netbk->pending_tx_info[pending_idx].netif = netif;
-- *((u16 *)skb->data) = pending_idx;
--
-- __skb_put(skb, data_len);
--
-- skb_shinfo(skb)->nr_frags = ret;
-- if (data_len < txreq.size) {
-- skb_shinfo(skb)->nr_frags++;
-- skb_shinfo(skb)->frags[0].page =
-- (void *)(unsigned long)pending_idx;
-- } else {
-- /* Discriminate from any valid pending_idx value. */
-- skb_shinfo(skb)->frags[0].page = (void *)~0UL;
-- }
--
-- __skb_queue_tail(&netbk->tx_queue, skb);
--
-- netbk->pending_cons++;
--
-- mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
--
-- netif->tx.req_cons = idx;
-- netif_schedule_work(netif);
--
-- if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
-- break;
-- }
--
-- return mop - netbk->tx_map_ops;
--}
--
--static void net_tx_submit(struct xen_netbk *netbk)
--{
-- struct gnttab_map_grant_ref *mop;
-- struct sk_buff *skb;
--
-- mop = netbk->tx_map_ops;
-- while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
-- struct xen_netif_tx_request *txp;
-- struct xen_netif *netif;
-- u16 pending_idx;
-- unsigned data_len;
--
-- pending_idx = *((u16 *)skb->data);
-- netif = netbk->pending_tx_info[pending_idx].netif;
-- txp = &netbk->pending_tx_info[pending_idx].req;
--
-- /* Check the remap error code. */
-- if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
-- pr_debug("netback grant failed.\n");
-- skb_shinfo(skb)->nr_frags = 0;
-- kfree_skb(skb);
-- continue;
-- }
--
-- data_len = skb->len;
-- memcpy(skb->data,
-- (void *)(idx_to_kaddr(netbk, pending_idx)|txp->offset),
-- data_len);
-- if (data_len < txp->size) {
-- /* Append the packet payload as a fragment. */
-- txp->offset += data_len;
-- txp->size -= data_len;
-- } else {
-- /* Schedule a response immediately. */
-- netif_idx_release(netbk, pending_idx);
-- }
--
-- if (txp->flags & NETTXF_csum_blank)
-- skb->ip_summed = CHECKSUM_PARTIAL;
-- else if (txp->flags & NETTXF_data_validated)
-- skb->ip_summed = CHECKSUM_UNNECESSARY;
--
-- netbk_fill_frags(netbk, skb);
--
-- /*
-- * If the initial fragment was < PKT_PROT_LEN then
-- * pull through some bytes from the other fragments to
-- * increase the linear region to PKT_PROT_LEN bytes.
-- */
-- if (skb_headlen(skb) < PKT_PROT_LEN && skb_is_nonlinear(skb)) {
-- int target = min_t(int, skb->len, PKT_PROT_LEN);
-- __pskb_pull_tail(skb, target - skb_headlen(skb));
-- }
--
++ netbk_tx_err(vif, &txreq, idx);
+ continue;
+ }
+ }
+@@ -1587,7 +1585,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+
+ memcpy(&netbk->pending_tx_info[pending_idx].req,
+ &txreq, sizeof(txreq));
+- netbk->pending_tx_info[pending_idx].netif = netif;
++ netbk->pending_tx_info[pending_idx].vif = vif;
+ *((u16 *)skb->data) = pending_idx;
+
+ __skb_put(skb, data_len);
+@@ -1608,8 +1606,8 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+
+ mop = xen_netbk_get_requests(netbk, netif, skb, txfrags, mop);
+
+- netif->tx.req_cons = idx;
+- netif_schedule_work(netif);
++ vif->tx.req_cons = idx;
++ xenvif_schedule_work(vif);
+
+ if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
+ break;
+@@ -1626,12 +1624,12 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ mop = netbk->tx_map_ops;
+ while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
+ struct xen_netif_tx_request *txp;
+- struct xen_netif *netif;
++ struct xenvif *vif;
+ u16 pending_idx;
+ unsigned data_len;
+
+ pending_idx = *((u16 *)skb->data);
+- netif = netbk->pending_tx_info[pending_idx].netif;
++ vif = netbk->pending_tx_info[pending_idx].vif;
+ txp = &netbk->pending_tx_info[pending_idx].req;
+
+ /* Check the remap error code. */
+@@ -1672,10 +1670,10 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ __pskb_pull_tail(skb, target - skb_headlen(skb));
+ }
+
- skb->dev = netif->dev;
-- skb->protocol = eth_type_trans(skb, skb->dev);
--
++ skb->dev = vif->dev;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
- if (checksum_setup(netif, skb)) {
-- pr_debug("Can't setup checksum in net_tx_action\n");
-- kfree_skb(skb);
-- continue;
-- }
--
-- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
-- unlikely(skb_linearize(skb))) {
-- pr_debug("Can't linearize skb in net_tx_action.\n");
-- kfree_skb(skb);
-- continue;
-- }
--
++ if (checksum_setup(vif, skb)) {
+ pr_debug("Can't setup checksum in net_tx_action\n");
+ kfree_skb(skb);
+ continue;
+@@ -1688,11 +1686,11 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ continue;
+ }
+
- netif->stats.rx_bytes += skb->len;
- netif->stats.rx_packets++;
--
-- netif_rx_ni(skb);
++ vif->stats.rx_bytes += skb->len;
++ vif->stats.rx_packets++;
+
+ netif_rx_ni(skb);
- netif->dev->last_rx = jiffies;
-- }
--}
--
--/* Called after netfront has transmitted */
--static void net_tx_action(unsigned long data)
--{
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- unsigned nr_mops;
-- int ret;
--
-- net_tx_action_dealloc(netbk);
--
-- nr_mops = net_tx_build_mops(netbk);
--
-- if (nr_mops == 0)
-- goto out;
--
-- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-- netbk->tx_map_ops, nr_mops);
-- BUG_ON(ret);
--
-- net_tx_submit(netbk);
--out:
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !list_empty(&netbk->pending_inuse_head)) {
-- struct netbk_tx_pending_inuse *oldest;
--
-- oldest = list_entry(netbk->pending_inuse_head.next,
-- struct netbk_tx_pending_inuse, list);
-- mod_timer(&netbk->netbk_tx_pending_timer,
-- oldest->alloc_time + HZ);
-- }
--}
--
--static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
--{
-- static DEFINE_SPINLOCK(_lock);
-- unsigned long flags;
-- pending_ring_idx_t index;
--
-- spin_lock_irqsave(&_lock, flags);
-- index = pending_index(netbk->dealloc_prod);
-- netbk->dealloc_ring[index] = pending_idx;
-- /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
-- smp_wmb();
-- netbk->dealloc_prod++;
-- spin_unlock_irqrestore(&_lock, flags);
--
-- xen_netbk_bh_handler(netbk, 0);
--}
--
--static void netif_page_release(struct page *page, unsigned int order)
--{
-- unsigned int group, idx;
-- int foreign = netif_get_page_ext(page, &group, &idx);
--
-- BUG_ON(!foreign);
-- BUG_ON(order);
--
-- netif_idx_release(&xen_netbk[group], idx);
--}
--
++ vif->dev->last_rx = jiffies;
+ }
+ }
+
+@@ -1755,57 +1753,57 @@ static void netif_page_release(struct page *page, unsigned int
order)
+ xen_netbk_idx_release(&xen_netbk[group], idx);
+ }
+
-irqreturn_t netif_be_int(int irq, void *dev_id)
--{
++irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+ {
- struct xen_netif *netif = dev_id;
-- struct xen_netbk *netbk;
--
++ struct xenvif *vif = dev_id;
+ struct xen_netbk *netbk;
+
- if (netif->group == -1)
-- return IRQ_NONE;
--
++ if (vif->group == -1)
+ return IRQ_NONE;
+
- netbk = &xen_netbk[netif->group];
--
++ netbk = &xen_netbk[vif->group];
+
- add_to_net_schedule_list_tail(netif);
-- maybe_schedule_tx_action(netbk);
--
++ add_to_net_schedule_list_tail(vif);
+ maybe_schedule_tx_action(netbk);
+
- if (netif_schedulable(netif) && !netbk_queue_full(netif))
- netif_wake_queue(netif->dev);
--
-- return IRQ_HANDLED;
--}
--
++ if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))
++ netif_wake_queue(vif->dev);
+
+ return IRQ_HANDLED;
+ }
+
-static void make_tx_response(struct xen_netif *netif,
-- struct xen_netif_tx_request *txp,
-- s8 st)
--{
++static void make_tx_response(struct xenvif *vif,
+ struct xen_netif_tx_request *txp,
+ s8 st)
+ {
- RING_IDX i = netif->tx.rsp_prod_pvt;
-- struct xen_netif_tx_response *resp;
-- int notify;
--
++ RING_IDX i = vif->tx.rsp_prod_pvt;
+ struct xen_netif_tx_response *resp;
+ int notify;
+
- resp = RING_GET_RESPONSE(&netif->tx, i);
-- resp->id = txp->id;
-- resp->status = st;
--
-- if (txp->flags & NETTXF_extra_info)
-- RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
--
++ resp = RING_GET_RESPONSE(&vif->tx, i);
+ resp->id = txp->id;
+ resp->status = st;
+
+ if (txp->flags & XEN_NETTXF_extra_info)
+- RING_GET_RESPONSE(&netif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
++ RING_GET_RESPONSE(&vif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+
- netif->tx.rsp_prod_pvt = ++i;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
-- if (notify)
++ vif->tx.rsp_prod_pvt = ++i;
++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify);
+ if (notify)
- notify_remote_via_irq(netif->irq);
--}
--
++ notify_remote_via_irq(vif->irq);
+ }
+
-static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
-- u16 id,
-- s8 st,
-- u16 offset,
-- u16 size,
-- u16 flags)
--{
++static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
+ u16 id,
+ s8 st,
+ u16 offset,
+ u16 size,
+ u16 flags)
+ {
- RING_IDX i = netif->rx.rsp_prod_pvt;
-- struct xen_netif_rx_response *resp;
--
++ RING_IDX i = vif->rx.rsp_prod_pvt;
+ struct xen_netif_rx_response *resp;
+
- resp = RING_GET_RESPONSE(&netif->rx, i);
-- resp->offset = offset;
-- resp->flags = flags;
-- resp->id = id;
-- resp->status = (s16)size;
-- if (st < 0)
-- resp->status = (s16)st;
--
++ resp = RING_GET_RESPONSE(&vif->rx, i);
+ resp->offset = offset;
+ resp->flags = flags;
+ resp->id = id;
+@@ -1813,7 +1811,7 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
+ if (st < 0)
+ resp->status = (s16)st;
+
- netif->rx.rsp_prod_pvt = ++i;
--
-- return resp;
--}
--
--#ifdef NETBE_DEBUG_INTERRUPT
--static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
--{
-- struct list_head *ent;
-- struct xen_netif *netif;
-- int i = 0;
-- int group = 0;
--
-- printk(KERN_ALERT "netif_schedule_list:\n");
--
-- for (group = 0; group < xen_netbk_group_nr; group++) {
-- struct xen_netbk *netbk = &xen_netbk[group];
-- spin_lock_irq(&netbk->net_schedule_list_lock);
-- printk(KERN_ALERT "xen_netback group number: %d\n", group);
-- list_for_each(ent, &netbk->net_schedule_list) {
-- netif = list_entry(ent, struct xen_netif, list);
-- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-- "rx_resp_prod=%08x\n",
-- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-- printk(KERN_ALERT
-- " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
-- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-- printk(KERN_ALERT
-- " shared(rx_req_prod=%08x "
-- "rx_resp_prod=%08x\n",
-- netif->rx.sring->req_prod,
-- netif->rx.sring->rsp_prod);
-- printk(KERN_ALERT
-- " rx_event=%08x, tx_req_prod=%08x\n",
-- netif->rx.sring->rsp_event,
-- netif->tx.sring->req_prod);
-- printk(KERN_ALERT
-- " tx_resp_prod=%08x, tx_event=%08x)\n",
-- netif->tx.sring->rsp_prod,
-- netif->tx.sring->rsp_event);
-- i++;
-- }
-- spin_unlock_irq(&netbk->net_schedule_list_lock);
-- }
--
-- printk(KERN_ALERT " ** End of netif_schedule_list **\n");
--
-- return IRQ_HANDLED;
--}
--#endif
--
--static inline int rx_work_todo(struct xen_netbk *netbk)
--{
-- return !skb_queue_empty(&netbk->rx_queue);
--}
--
--static inline int tx_work_todo(struct xen_netbk *netbk)
--{
-- if (netbk->dealloc_cons != netbk->dealloc_prod)
-- return 1;
--
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !list_empty(&netbk->pending_inuse_head))
-- return 1;
--
-- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-- !list_empty(&netbk->net_schedule_list))
-- return 1;
--
-- return 0;
--}
--
--static int netbk_action_thread(void *data)
--{
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- while (!kthread_should_stop()) {
-- wait_event_interruptible(netbk->kthread.netbk_action_wq,
-- rx_work_todo(netbk)
-- || tx_work_todo(netbk)
-- || kthread_should_stop());
-- cond_resched();
--
-- if (kthread_should_stop())
-- break;
--
-- if (rx_work_todo(netbk))
-- net_rx_action((unsigned long)netbk);
--
-- if (tx_work_todo(netbk))
-- net_tx_action((unsigned long)netbk);
-- }
--
-- return 0;
--}
--
--static int __init netback_init(void)
--{
-- int i;
-- struct page *page;
-- int rc = 0;
-- int group;
--
-- if (!xen_pv_domain())
-- return -ENODEV;
--
-- xen_netbk_group_nr = num_online_cpus();
-- xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
-- if (!xen_netbk) {
-- printk(KERN_ALERT "%s: out of memory\n", __func__);
-- return -ENOMEM;
-- }
-- memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);
--
-- for (group = 0; group < xen_netbk_group_nr; group++) {
-- struct xen_netbk *netbk = &xen_netbk[group];
-- skb_queue_head_init(&netbk->rx_queue);
-- skb_queue_head_init(&netbk->tx_queue);
--
-- init_timer(&netbk->net_timer);
-- netbk->net_timer.data = (unsigned long)netbk;
-- netbk->net_timer.function = net_alarm;
--
-- init_timer(&netbk->netbk_tx_pending_timer);
-- netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
-- netbk->netbk_tx_pending_timer.function =
-- netbk_tx_pending_timeout;
--
-- netbk->mmap_pages =
-- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-- if (!netbk->mmap_pages) {
-- printk(KERN_ALERT "%s: out of memory\n", __func__);
-- del_timer(&netbk->netbk_tx_pending_timer);
-- del_timer(&netbk->net_timer);
-- 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);
-- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
-- }
--
-- netbk->pending_cons = 0;
-- netbk->pending_prod = MAX_PENDING_REQS;
-- for (i = 0; i < MAX_PENDING_REQS; i++)
-- netbk->pending_ring[i] = i;
--
-- if (MODPARM_netback_kthread) {
-- init_waitqueue_head(&netbk->kthread.netbk_action_wq);
-- netbk->kthread.task =
-- kthread_create(netbk_action_thread,
-- (void *)netbk,
-- "netback/%u", group);
--
-- if (!IS_ERR(netbk->kthread.task)) {
-- kthread_bind(netbk->kthread.task, group);
-- } else {
-- printk(KERN_ALERT
-- "kthread_run() fails at netback\n");
-- free_empty_pages_and_pagevec(netbk->mmap_pages,
-- MAX_PENDING_REQS);
-- del_timer(&netbk->netbk_tx_pending_timer);
-- del_timer(&netbk->net_timer);
-- rc = PTR_ERR(netbk->kthread.task);
-- goto failed_init;
-- }
-- } else {
-- tasklet_init(&netbk->tasklet.net_tx_tasklet,
-- net_tx_action,
-- (unsigned long)netbk);
-- tasklet_init(&netbk->tasklet.net_rx_tasklet,
-- net_rx_action,
-- (unsigned long)netbk);
-- }
--
-- INIT_LIST_HEAD(&netbk->pending_inuse_head);
-- INIT_LIST_HEAD(&netbk->net_schedule_list);
--
-- spin_lock_init(&netbk->net_schedule_list_lock);
--
-- atomic_set(&netbk->netfront_count, 0);
--
-- if (MODPARM_netback_kthread)
-- wake_up_process(netbk->kthread.task);
-- }
--
-- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
-- if (MODPARM_copy_skb) {
-- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-- NULL, 0))
-- netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
-- else
-- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
-- }
--
-- rc = netif_xenbus_init();
-- if (rc)
-- goto failed_init;
--
--#ifdef NETBE_DEBUG_INTERRUPT
-- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-- 0,
-- netif_be_dbg,
-- IRQF_SHARED,
-- "net-be-dbg",
-- &netif_be_dbg);
--#endif
--
-- return 0;
--
--failed_init:
-- for (i = 0; i < group; i++) {
-- struct xen_netbk *netbk = &xen_netbk[i];
-- free_empty_pages_and_pagevec(netbk->mmap_pages,
-- MAX_PENDING_REQS);
-- del_timer(&netbk->netbk_tx_pending_timer);
-- del_timer(&netbk->net_timer);
-- if (MODPARM_netback_kthread)
-- kthread_stop(netbk->kthread.task);
-- }
-- vfree(xen_netbk);
-- return rc;
--
--}
--
--module_init(netback_init);
--
--MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/xen/netback/xenbus.c b/drivers/xen/netback/xenbus.c
-deleted file mode 100644
-index 867dc25..0000000
---- a/drivers/xen/netback/xenbus.c
-+++ /dev/null
-@@ -1,489 +0,0 @@
--/*
-- * Xenbus code for netif backend
-- *
-- * Copyright (C) 2005 Rusty Russell <rusty(a)rustcorp.com.au>
-- * Copyright (C) 2005 XenSource Ltd
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, write to the Free Software
-- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--*/
--
--#include "common.h"
--
--static int connect_rings(struct backend_info *);
--static void connect(struct backend_info *);
++ vif->rx.rsp_prod_pvt = ++i;
+
+ return resp;
+ }
+@@ -1964,7 +1962,7 @@ static int __init netback_init(void)
+ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ }
+
+- rc = netif_xenbus_init();
++ rc = xenvif_xenbus_init();
+ if (rc)
+ goto failed_init;
+
+diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
+index 867dc25..a6ad259 100644
+--- a/drivers/net/xen-netback/xenbus.c
++++ b/drivers/net/xen-netback/xenbus.c
+@@ -23,7 +23,7 @@
+
+ static int connect_rings(struct backend_info *);
+ static void connect(struct backend_info *);
-static void backend_create_netif(struct backend_info *be);
--static void unregister_hotplug_status_watch(struct backend_info *be);
--
--static int netback_remove(struct xenbus_device *dev)
--{
-- struct backend_info *be = dev_get_drvdata(&dev->dev);
--
-- unregister_hotplug_status_watch(be);
++static void backend_create_xenvif(struct backend_info *be);
+ static void unregister_hotplug_status_watch(struct backend_info *be);
+
+ static int netback_remove(struct xenbus_device *dev)
+@@ -31,11 +31,11 @@ static int netback_remove(struct xenbus_device *dev)
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ unregister_hotplug_status_watch(be);
- if (be->netif) {
-- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
++ if (be->vif) {
+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
- netif_disconnect(be->netif);
- be->netif = NULL;
-- }
-- kfree(be);
-- dev_set_drvdata(&dev->dev, NULL);
-- return 0;
--}
--
--
--/**
-- * Entry point to this code when a new device is created. Allocate the basic
-- * structures and switch to InitWait.
-- */
--static int netback_probe(struct xenbus_device *dev,
-- const struct xenbus_device_id *id)
--{
-- const char *message;
-- struct xenbus_transaction xbt;
-- int err;
-- int sg;
-- struct backend_info *be = kzalloc(sizeof(struct backend_info),
-- GFP_KERNEL);
-- if (!be) {
-- xenbus_dev_fatal(dev, -ENOMEM,
-- "allocating backend structure");
-- return -ENOMEM;
-- }
--
-- be->dev = dev;
-- dev_set_drvdata(&dev->dev, be);
--
-- sg = 1;
-- if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
-- sg = 0;
--
-- do {
-- err = xenbus_transaction_start(&xbt);
-- if (err) {
-- xenbus_dev_fatal(dev, err, "starting transaction");
-- goto fail;
-- }
--
-- err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
sg);
-- if (err) {
-- message = "writing feature-sg";
-- goto abort_transaction;
-- }
--
-- err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
-- "%d", sg);
-- if (err) {
-- message = "writing feature-gso-tcpv4";
-- goto abort_transaction;
-- }
--
-- /* We support rx-copy path. */
-- err = xenbus_printf(xbt, dev->nodename,
-- "feature-rx-copy", "%d", 1);
-- if (err) {
-- message = "writing feature-rx-copy";
-- goto abort_transaction;
-- }
--
-- /*
-- * We don't support rx-flip path (except old guests who don't
-- * grok this feature flag).
-- */
-- err = xenbus_printf(xbt, dev->nodename,
-- "feature-rx-flip", "%d", 0);
-- if (err) {
-- message = "writing feature-rx-flip";
-- goto abort_transaction;
-- }
--
-- err = xenbus_transaction_end(xbt, 0);
-- } while (err == -EAGAIN);
--
-- if (err) {
-- xenbus_dev_fatal(dev, err, "completing transaction");
-- goto fail;
-- }
--
-- err = xenbus_switch_state(dev, XenbusStateInitWait);
-- if (err)
-- goto fail;
--
-- /* This kicks hotplug scripts, so do it immediately. */
++ xenvif_disconnect(be->vif);
++ be->vif = NULL;
+ }
+ kfree(be);
+ dev_set_drvdata(&dev->dev, NULL);
+@@ -121,7 +121,7 @@ static int netback_probe(struct xenbus_device *dev,
+ goto fail;
+
+ /* This kicks hotplug scripts, so do it immediately. */
- backend_create_netif(be);
++ backend_create_xenvif(be);
+
+ return 0;
+
+@@ -159,20 +159,20 @@ static int netback_uevent(struct xenbus_device *xdev,
+ kfree(val);
+ }
+
+- if (!be || !be->netif)
++ if (!be || !be->vif)
+ return 0;
+
+- return add_uevent_var(env, "vif=%s", be->netif->dev->name);
++ return add_uevent_var(env, "vif=%s", be->vif->dev->name);
+ }
+
+
+-static void backend_create_netif(struct backend_info *be)
++static void backend_create_xenvif(struct backend_info *be)
+ {
+ int err;
+ long handle;
+ struct xenbus_device *dev = be->dev;
+
+- if (be->netif != NULL)
++ if (be->vif != NULL)
+ return;
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
+@@ -181,10 +181,10 @@ static void backend_create_netif(struct backend_info *be)
+ return;
+ }
+
+- be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
+- if (IS_ERR(be->netif)) {
+- err = PTR_ERR(be->netif);
+- be->netif = NULL;
++ be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
++ if (IS_ERR(be->vif)) {
++ err = PTR_ERR(be->vif);
++ be->vif = NULL;
+ xenbus_dev_fatal(dev, err, "creating interface");
+ return;
+ }
+@@ -197,10 +197,10 @@ static void disconnect_backend(struct xenbus_device *dev)
+ {
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+- if (be->netif) {
++ if (be->vif) {
+ xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
+- netif_disconnect(be->netif);
+- be->netif = NULL;
++ xenvif_disconnect(be->vif);
++ be->vif = NULL;
+ }
+ }
+
+@@ -231,13 +231,13 @@ static void frontend_changed(struct xenbus_device *dev,
+ case XenbusStateConnected:
+ if (dev->state == XenbusStateConnected)
+ break;
+- backend_create_netif(be);
+- if (be->netif)
++ backend_create_xenvif(be);
++ if (be->vif)
+ connect(be);
+ break;
+
+ case XenbusStateClosing:
+- if (be->netif)
++ if (be->vif)
+ kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+ disconnect_backend(dev);
+ xenbus_switch_state(dev, XenbusStateClosing);
+@@ -357,15 +357,15 @@ static void connect(struct backend_info *be)
+ if (err)
+ return;
+
+- err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
++ err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+ return;
+ }
+
+- xen_net_read_rate(dev, &be->netif->credit_bytes,
+- &be->netif->credit_usec);
+- be->netif->remaining_credit = be->netif->credit_bytes;
++ xen_net_read_rate(dev, &be->vif->credit_bytes,
++ &be->vif->credit_usec);
++ be->vif->remaining_credit = be->vif->credit_bytes;
+
+ unregister_hotplug_status_watch(be);
+ err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
+@@ -378,13 +378,13 @@ static void connect(struct backend_info *be)
+ be->have_hotplug_status_watch = 1;
+ }
+
+- netif_wake_queue(be->netif->dev);
++ netif_wake_queue(be->vif->dev);
+ }
+
+
+ static int connect_rings(struct backend_info *be)
+ {
+- struct xen_netif *netif = be->netif;
++ struct xenvif *vif = be->vif;
+ struct xenbus_device *dev = be->dev;
+ unsigned long tx_ring_ref, rx_ring_ref;
+ unsigned int evtchn, rx_copy;
+@@ -416,42 +416,42 @@ static int connect_rings(struct backend_info *be)
+ if (!rx_copy)
+ return -EOPNOTSUPP;
+
+- if (netif->dev->tx_queue_len != 0) {
++ if (vif->dev->tx_queue_len != 0) {
+ if (xenbus_scanf(XBT_NIL, dev->otherend,
+ "feature-rx-notify", "%d", &val) < 0)
+ val = 0;
+ if (val)
+- netif->can_queue = 1;
++ vif->can_queue = 1;
+ else
+ /* Must be non-zero for pfifo_fast to work. */
+- netif->dev->tx_queue_len = 1;
++ vif->dev->tx_queue_len = 1;
+ }
+
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
+ "%d", &val) < 0)
+ val = 0;
+- netif->can_sg = !!val;
++ vif->can_sg = !!val;
+
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
+ "%d", &val) < 0)
+ val = 0;
+- netif->gso = !!val;
++ vif->gso = !!val;
+
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
+ "%d", &val) < 0)
+ val = 0;
+- netif->gso_prefix = !!val;
++ vif->gso_prefix = !!val;
+
+ if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
+ "%d", &val) < 0)
+ val = 0;
+- netif->csum = !val;
++ vif->csum = !val;
+
+ /* Set dev->features */
+- netif_set_features(netif);
++ xenvif_set_features(vif);
+
+ /* Map the shared frame, irq etc. */
+- err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
++ err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
+ if (err) {
+ xenbus_dev_fatal(dev, err,
+ "mapping shared-frames %lu/%lu port %u",
+@@ -481,9 +481,7 @@ static struct xenbus_driver netback = {
+ .otherend_changed = frontend_changed,
+ };
+
-
-- return 0;
--
--abort_transaction:
-- xenbus_transaction_end(xbt, 1);
-- xenbus_dev_fatal(dev, err, "%s", message);
--fail:
-- pr_debug("failed");
-- netback_remove(dev);
-- return err;
--}
--
+-int netif_xenbus_init(void)
++int xenvif_xenbus_init(void)
+ {
+- printk(KERN_CRIT "registering netback\n");
+ return xenbus_register_backend(&netback);
+ }
+--
+1.7.4
+
+
+From ffb0eb7c4e5115ac17621cb83cf614ba026975df Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 21 Jan 2011 09:42:35 +0000
+Subject: [PATCH 095/203] xen: netback: add reference from xenvif to xen_netbk
+
+Rather than storing the group id simply store a pointer (opaque to xenvif).
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/common.h | 6 +++++-
+ drivers/net/xen-netback/interface.c | 2 +-
+ drivers/net/xen-netback/netback.c | 26 ++++++++++++++------------
+ 3 files changed, 20 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index f6da94b..ebe93fb 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -46,12 +46,16 @@
+ #include <xen/grant_table.h>
+ #include <xen/xenbus.h>
+
++struct xen_netbk;
++
+ struct xenvif {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+- int group;
+ unsigned int handle;
+
++ /* */
++ struct xen_netbk *netbk;
++
+ u8 fe_dev_addr[6];
+
+ /* Physical parameters of the comms window. */
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index a065173..cfbb3cc 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -235,8 +235,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
+ vif = netdev_priv(dev);
+ memset(vif, 0, sizeof(*vif));
+ vif->domid = domid;
+- vif->group = -1;
+ vif->handle = handle;
++ vif->netbk = NULL;
+ vif->can_sg = 1;
+ vif->csum = 1;
+ atomic_set(&vif->refcnt, 1);
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index f2f9c6f..4f04d2d 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -145,6 +145,8 @@ void xen_netbk_add_xenvif(struct xenvif *vif)
+ int i;
+ int min_netfront_count;
+ int min_group = 0;
++ struct xen_netbk *netbk;
++
+ min_netfront_count = atomic_read(&xen_netbk[0].netfront_count);
+ for (i = 0; i < xen_netbk_group_nr; i++) {
+ int netfront_count = atomic_read(&xen_netbk[i].netfront_count);
+@@ -154,13 +156,15 @@ void xen_netbk_add_xenvif(struct xenvif *vif)
+ }
+ }
+
+- vif->group = min_group;
+- atomic_inc(&xen_netbk[vif->group].netfront_count);
++ netbk = &xen_netbk[min_group];
++
++ vif->netbk = netbk;
++ atomic_inc(&netbk->netfront_count);
+ }
+
+ void xen_netbk_remove_xenvif(struct xenvif *vif)
+ {
+- atomic_dec(&xen_netbk[vif->group].netfront_count);
++ atomic_dec(&vif->netbk->netfront_count);
+ }
+
+ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+@@ -471,10 +475,10 @@ int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+ BUG_ON(skb->dev != dev);
+
+- if (vif->group == -1)
++ if (vif->netbk == NULL)
+ goto drop;
+
+- netbk = &xen_netbk[vif->group];
++ netbk = vif->netbk;
+
+ /* Drop the packet if the target domain has no receive buffers. */
+ if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
+@@ -940,7 +944,7 @@ static void add_to_net_schedule_list_tail(struct xenvif *vif)
+ {
+ unsigned long flags;
+
+- struct xen_netbk *netbk = &xen_netbk[vif->group];
++ struct xen_netbk *netbk = vif->netbk;
+ if (__on_net_schedule_list(vif))
+ return;
+
+@@ -955,7 +959,7 @@ static void add_to_net_schedule_list_tail(struct xenvif *vif)
+
+ void xenvif_schedule_work(struct xenvif *vif)
+ {
+- struct xen_netbk *netbk = &xen_netbk[vif->group];
++ struct xen_netbk *netbk = vif->netbk;
+ int more_to_do;
+
+ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
+@@ -968,7 +972,7 @@ void xenvif_schedule_work(struct xenvif *vif)
+
+ void xenvif_deschedule_work(struct xenvif *vif)
+ {
+- struct xen_netbk *netbk = &xen_netbk[vif->group];
++ struct xen_netbk *netbk = vif->netbk;
+ spin_lock_irq(&netbk->net_schedule_list_lock);
+ remove_from_net_schedule_list(vif);
+ spin_unlock_irq(&netbk->net_schedule_list_lock);
+@@ -1756,13 +1760,11 @@ static void netif_page_release(struct page *page, unsigned int
order)
+ irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+ {
+ struct xenvif *vif = dev_id;
+- struct xen_netbk *netbk;
++ struct xen_netbk *netbk = vif->netbk;
+
+- if (vif->group == -1)
++ if (netbk == NULL)
+ return IRQ_NONE;
+
+- netbk = &xen_netbk[vif->group];
-
+ add_to_net_schedule_list_tail(vif);
+ maybe_schedule_tx_action(netbk);
+
+--
+1.7.4
+
+
+From 0cf3cc23560821e8e0b95a1400374a7ff1248e52 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 21 Jan 2011 10:45:25 +0000
+Subject: [PATCH 096/203] xen: netback: refactor to separate network device from worker
pools
+
+The netback worker pool code is in netback.c and uses "struct xen_netbk" and
+xen_netbk_*.
+
+The network dfeivce interface is in interface.c and uses "struct xen_vif" and
+xenvif_*.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/common.h | 69 +++-------
+ drivers/net/xen-netback/interface.c | 227 ++++++++++++++++++++++++++++++-
+ drivers/net/xen-netback/netback.c | 259 ++++++-----------------------------
+ drivers/net/xen-netback/xenbus.c | 11 +-
+ 4 files changed, 289 insertions(+), 277 deletions(-)
+
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index ebe93fb..b998a27 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -109,16 +109,6 @@ struct xenvif {
+ wait_queue_head_t waiting_to_free;
+ };
+
-/*
-- * Handle the creation of the hotplug script environment. We add the script
-- * and vif variables to the environment, for the benefit of the vif-* hotplug
-- * scripts.
+- * Implement our own carrier flag: the network stack's version causes delays
+- * when the carrier is re-enabled (in particular, dev_activate() may not
+- * immediately be called, which can cause packet loss; also the etherbridge
+- * can be rather lazy in activating its port).
- */
--static int netback_uevent(struct xenbus_device *xdev,
-- struct kobj_uevent_env *env)
--{
-- struct backend_info *be = dev_get_drvdata(&xdev->dev);
-- char *val;
+-#define xenvif_carrier_on(xenvif) ((xenvif)->carrier = 1)
+-#define xenvif_carrier_off(xenvif) ((xenvif)->carrier = 0)
+-#define xenvif_carrier_ok(xenvif) ((xenvif)->carrier)
-
-- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
-- if (IS_ERR(val)) {
-- int err = PTR_ERR(val);
-- xenbus_dev_fatal(xdev, err, "reading script");
-- return err;
-- } else {
-- if (add_uevent_var(env, "script=%s", val)) {
-- kfree(val);
-- return -ENOMEM;
-- }
-- kfree(val);
-- }
+ enum {
+ NETBK_DONT_COPY_SKB,
+ NETBK_DELAYED_COPY_SKB,
+@@ -127,63 +117,40 @@ enum {
+
+ extern int netbk_copy_skb_mode;
+
+-struct backend_info {
+- struct xenbus_device *dev;
+- struct xenvif *vif;
+- enum xenbus_state frontend_state;
+- struct xenbus_watch hotplug_status_watch;
+- int have_hotplug_status_watch:1;
+-};
-
-- if (!be || !be->netif)
-- return 0;
+-#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+-#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-
-- return add_uevent_var(env, "vif=%s", be->netif->dev->name);
+-void xenvif_disconnect(struct xenvif *vif);
++#define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
++#define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+
+-void xenvif_set_features(struct xenvif *vif);
+ struct xenvif *xenvif_alloc(struct device *parent,
+ domid_t domid,
+ unsigned int handle);
++
+ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
+ unsigned long rx_ring_ref, unsigned int evtchn);
++void xenvif_disconnect(struct xenvif *vif);
+
+-static inline void xenvif_get(struct xenvif *vif)
+-{
+- atomic_inc(&vif->refcnt);
-}
-
--
--static void backend_create_netif(struct backend_info *be)
+-static inline void xenvif_put(struct xenvif *vif)
-{
-- int err;
-- long handle;
-- struct xenbus_device *dev = be->dev;
--
-- if (be->netif != NULL)
-- return;
--
-- err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
-- if (err != 1) {
-- xenbus_dev_fatal(dev, err, "reading handle");
-- return;
-- }
--
-- be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
-- if (IS_ERR(be->netif)) {
-- err = PTR_ERR(be->netif);
-- be->netif = NULL;
-- xenbus_dev_fatal(dev, err, "creating interface");
-- return;
-- }
--
-- kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
+- if (atomic_dec_and_test(&vif->refcnt))
+- wake_up(&vif->waiting_to_free);
-}
++void xenvif_get(struct xenvif *vif);
++void xenvif_put(struct xenvif *vif);
+
+ int xenvif_xenbus_init(void);
+
+-#define xenvif_schedulable(vif) \
+- (netif_running((vif)->dev) && xenvif_carrier_ok(vif))
++int xenvif_schedulable(struct xenvif *vif);
+
+ void xenvif_schedule_work(struct xenvif *vif);
+-void xenvif_deschedule_work(struct xenvif *vif);
-
+-int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-struct net_device_stats *xenvif_get_stats(struct net_device *dev);
+-irqreturn_t xenvif_interrupt(int irq, void *dev_id);
-
--static void disconnect_backend(struct xenbus_device *dev)
+-static inline int netbk_can_queue(struct net_device *dev)
-{
-- struct backend_info *be = dev_get_drvdata(&dev->dev);
--
-- if (be->netif) {
-- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-- netif_disconnect(be->netif);
-- be->netif = NULL;
-- }
+- struct xenvif *vif = netdev_priv(dev);
+- return vif->can_queue;
-}
--
--/**
-- * Callback received when the frontend's state changes.
-- */
--static void frontend_changed(struct xenbus_device *dev,
-- enum xenbus_state frontend_state)
+
+-static inline int netbk_can_sg(struct net_device *dev)
-{
-- struct backend_info *be = dev_get_drvdata(&dev->dev);
--
-- pr_debug("frontend state %s", xenbus_strstate(frontend_state));
--
-- be->frontend_state = frontend_state;
--
-- switch (frontend_state) {
-- case XenbusStateInitialising:
-- if (dev->state == XenbusStateClosed) {
-- printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-- __func__, dev->nodename);
-- xenbus_switch_state(dev, XenbusStateInitWait);
-- }
-- break;
+- struct xenvif *vif = netdev_priv(dev);
+- return vif->can_sg;
+-}
++int xenvif_queue_full(struct xenvif *vif);
+
+ /* (De)Register a xenvif with the netback backend. */
+ void xen_netbk_add_xenvif(struct xenvif *vif);
+ void xen_netbk_remove_xenvif(struct xenvif *vif);
+
++/* */
++void xen_netbk_schedule_xenvif(struct xenvif *vif);
++void xen_netbk_deschedule_xenfif(struct xenvif *vif);
++
++/* */
++unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb);
++
++/* */
++void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb);
++
+ #endif /* __XEN_NETBACK__COMMON_H__ */
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index cfbb3cc..c906c79 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -36,7 +36,221 @@
+ #include <xen/events.h>
+ #include <asm/xen/hypercall.h>
+
+-#define NETBK_QUEUE_LENGTH 32
++#define XENVIF_QUEUE_LENGTH 32
++
++void xenvif_get(struct xenvif *vif)
++{
++ atomic_inc(&vif->refcnt);
++}
++
++void xenvif_put(struct xenvif *vif)
++{
++ if (atomic_dec_and_test(&vif->refcnt))
++ wake_up(&vif->waiting_to_free);
++}
++
++static int xenvif_max_required_rx_slots(struct xenvif *vif)
++{
++ if (vif->can_sg || vif->gso || vif->gso_prefix)
++ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
++ return 1; /* all in one */
++}
++
++int xenvif_queue_full(struct xenvif *vif)
++{
++ RING_IDX peek = vif->rx_req_cons_peek;
++ RING_IDX needed = xenvif_max_required_rx_slots(vif);
++
++ return ((vif->rx.sring->req_prod - peek) < needed) ||
++ ((vif->rx.rsp_prod_pvt + XEN_NETIF_RX_RING_SIZE - peek) < needed);
++}
++
++/*
++ * Implement our own carrier flag: the network stack's version causes delays
++ * when the carrier is re-enabled (in particular, dev_activate() may not
++ * immediately be called, which can cause packet loss; also the etherbridge
++ * can be rather lazy in activating its port).
++ */
++static void xenvif_carrier_on(struct xenvif *vif)
++{
++ vif->carrier = 1;
++}
++static void xenvif_carrier_off(struct xenvif *vif)
++{
++ vif->carrier = 0;
++}
++static int xenvif_carrier_ok(struct xenvif *vif)
++{
++ return vif->carrier;
++}
++
++int xenvif_schedulable(struct xenvif *vif)
++{
++ return netif_running(vif->dev) && xenvif_carrier_ok(vif);
++}
++
++static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
++{
++ struct xenvif *vif = dev_id;
++
++ if (vif->netbk == NULL)
++ return IRQ_NONE;
++
++ xen_netbk_schedule_xenvif(vif);
++
++ if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))
++ netif_wake_queue(vif->dev);
++
++ return IRQ_HANDLED;
++}
++
++/* TODO: move to networking core */
++static struct sk_buff *xenvif_copy_skb(struct sk_buff *skb)
++{
++ struct skb_shared_info *ninfo;
++ struct sk_buff *nskb;
++ unsigned long offset;
++ int ret;
++ int len;
++ int headlen;
++
++ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++
++ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
++ if (unlikely(!nskb))
++ goto err;
++
++ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
++ headlen = skb_end_pointer(nskb) - nskb->data;
++ if (headlen > skb_headlen(skb))
++ headlen = skb_headlen(skb);
++ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
++ BUG_ON(ret);
++
++ ninfo = skb_shinfo(nskb);
++ ninfo->gso_size = skb_shinfo(skb)->gso_size;
++ ninfo->gso_type = skb_shinfo(skb)->gso_type;
++
++ offset = headlen;
++ len = skb->len - headlen;
++
++ nskb->len = skb->len;
++ nskb->data_len = len;
++ nskb->truesize += len;
++
++ while (len) {
++ struct page *page;
++ int copy;
++ int zero;
++
++ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
++ dump_stack();
++ goto err_free;
++ }
++
++ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
++ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++
++ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
++ if (unlikely(!page))
++ goto err_free;
++
++ ret = skb_copy_bits(skb, offset, page_address(page), copy);
++ BUG_ON(ret);
++
++ ninfo->frags[ninfo->nr_frags].page = page;
++ ninfo->frags[ninfo->nr_frags].page_offset = 0;
++ ninfo->frags[ninfo->nr_frags].size = copy;
++ ninfo->nr_frags++;
++
++ offset += copy;
++ len -= copy;
++ }
++
++#ifdef NET_SKBUFF_DATA_USES_OFFSET
++ offset = 0;
++#else
++ offset = nskb->data - skb->data;
++#endif
++
++ nskb->transport_header = skb->transport_header + offset;
++ nskb->network_header = skb->network_header + offset;
++ nskb->mac_header = skb->mac_header + offset;
++
++ return nskb;
++
++ err_free:
++ kfree_skb(nskb);
++ err:
++ return NULL;
++}
++
++static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct xenvif *vif = netdev_priv(dev);
++
++ BUG_ON(skb->dev != dev);
++
++ if (vif->netbk == NULL)
++ goto drop;
++
++ /* Drop the packet if the target domain has no receive buffers. */
++ if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
++ goto drop;
++
++ /*
++ * XXX For now we also copy skbuffs whose head crosses a page
++ * boundary, because netbk_gop_skb can't handle them.
++ */
++ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
++ struct sk_buff *nskb = xenvif_copy_skb(skb);
++ if (unlikely(nskb == NULL))
++ goto drop;
++ /* Copy only the header fields we use in this driver. */
++ nskb->dev = skb->dev;
++ nskb->ip_summed = skb->ip_summed;
++ dev_kfree_skb(skb);
++ skb = nskb;
++ }
++
++ /* Reserve ring slots for the worst-case number of fragments. */
++ vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
++ xenvif_get(vif);
++
++ if (vif->can_queue && xenvif_queue_full(vif)) {
++ vif->rx.sring->req_event = vif->rx_req_cons_peek +
++ xenvif_max_required_rx_slots(vif);
++ mb(); /* request notification /then/ check & stop the queue */
++ if (xenvif_queue_full(vif))
++ netif_stop_queue(dev);
++ }
++
++ xen_netbk_queue_tx_skb(vif, skb);
++
++ return 0;
++
++ drop:
++ vif->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++ return 0;
++}
++
++static struct net_device_stats *xenvif_get_stats(struct net_device *dev)
++{
++ struct xenvif *vif = netdev_priv(dev);
++ return &vif->stats;
++}
++
++void xenvif_schedule_work(struct xenvif *vif)
++{
++ int more_to_do;
++
++ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
++
++ if (more_to_do)
++ xen_netbk_schedule_xenvif(vif);
++}
++
+
+ static void xenvif_up(struct xenvif *vif)
+ {
+@@ -48,7 +262,7 @@ static void xenvif_up(struct xenvif *vif)
+ static void xenvif_down(struct xenvif *vif)
+ {
+ disable_irq(vif->irq);
+- xenvif_deschedule_work(vif);
++ xen_netbk_deschedule_xenfif(vif);
+ xen_netbk_remove_xenvif(vif);
+ }
+
+@@ -73,7 +287,8 @@ static int xenvif_close(struct net_device *dev)
+
+ static int xenvif_change_mtu(struct net_device *dev, int mtu)
+ {
+- int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++ struct xenvif *vif = netdev_priv(dev);
++ int max = vif->can_sg ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+ if (mtu > max)
+ return -EINVAL;
+@@ -81,7 +296,7 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu)
+ return 0;
+ }
+
+-void xenvif_set_features(struct xenvif *vif)
++static void xenvif_set_features(struct xenvif *vif)
+ {
+ struct net_device *dev = vif->dev;
+ int features = dev->features;
+@@ -256,7 +471,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
+ xenvif_set_features(vif);
+ SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
+
+- dev->tx_queue_len = NETBK_QUEUE_LENGTH;
++ dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
+
+ /*
+ * Initialise a dummy MAC address. We choose the numerically
+@@ -352,6 +567,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
+ if (vif->irq)
+ return 0;
+
++ xenvif_set_features(vif);
++
+ vif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
+ if (vif->tx_comms_area == NULL)
+ return -ENOMEM;
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index 4f04d2d..1b7005c 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -131,10 +131,10 @@ struct xen_netbk {
+ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
+ * head/fragment uses 2 copy operation.
+ */
+- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
++ struct gnttab_copy grant_copy_op[2*XEN_NETIF_RX_RING_SIZE];
+ unsigned char rx_notify[NR_IRQS];
+- u16 notify_list[NET_RX_RING_SIZE];
+- struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
++ u16 notify_list[XEN_NETIF_RX_RING_SIZE];
++ struct netbk_rx_meta meta[2*XEN_NETIF_RX_RING_SIZE];
+ };
+
+ static struct xen_netbk *xen_netbk;
+@@ -164,7 +164,9 @@ void xen_netbk_add_xenvif(struct xenvif *vif)
+
+ void xen_netbk_remove_xenvif(struct xenvif *vif)
+ {
+- atomic_dec(&vif->netbk->netfront_count);
++ struct xen_netbk *netbk = vif->netbk;
++ vif->netbk = NULL;
++ atomic_dec(&netbk->netfront_count);
+ }
+
+ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+@@ -275,7 +277,7 @@ MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace
tasklet");
+ * dir indicates the data direction.
+ * rx: 1, tx: 0.
+ */
+-static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
++void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
+ {
+ if (MODPARM_netback_kthread)
+ wake_up(&netbk->kthread.netbk_action_wq);
+@@ -285,110 +287,6 @@ static inline void xen_netbk_bh_handler(struct xen_netbk *netbk,
int dir)
+ tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
+ }
+
+-static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
+-{
+- smp_mb();
+- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
+- !list_empty(&netbk->net_schedule_list))
+- xen_netbk_bh_handler(netbk, 0);
+-}
-
-- case XenbusStateInitialised:
-- break;
+-static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
+-{
+- struct skb_shared_info *ninfo;
+- struct sk_buff *nskb;
+- unsigned long offset;
+- int ret;
+- int len;
+- int headlen;
-
-- case XenbusStateConnected:
-- if (dev->state == XenbusStateConnected)
-- break;
-- backend_create_netif(be);
-- if (be->netif)
-- connect(be);
-- break;
+- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
-
-- case XenbusStateClosing:
-- if (be->netif)
-- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-- disconnect_backend(dev);
-- xenbus_switch_state(dev, XenbusStateClosing);
-- break;
+- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
+- if (unlikely(!nskb))
+- goto err;
-
-- case XenbusStateClosed:
-- xenbus_switch_state(dev, XenbusStateClosed);
-- if (xenbus_dev_is_online(dev))
-- break;
-- /* fall through if not online */
-- case XenbusStateUnknown:
-- device_unregister(&dev->dev);
-- break;
+- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
+- headlen = skb_end_pointer(nskb) - nskb->data;
+- if (headlen > skb_headlen(skb))
+- headlen = skb_headlen(skb);
+- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
+- BUG_ON(ret);
-
-- default:
-- xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-- frontend_state);
-- break;
-- }
--}
+- ninfo = skb_shinfo(nskb);
+- ninfo->gso_size = skb_shinfo(skb)->gso_size;
+- ninfo->gso_type = skb_shinfo(skb)->gso_type;
-
+- offset = headlen;
+- len = skb->len - headlen;
-
--static void xen_net_read_rate(struct xenbus_device *dev,
-- unsigned long *bytes, unsigned long *usec)
--{
-- char *s, *e;
-- unsigned long b, u;
-- char *ratestr;
+- nskb->len = skb->len;
+- nskb->data_len = len;
+- nskb->truesize += len;
-
-- /* Default to unlimited bandwidth. */
-- *bytes = ~0UL;
-- *usec = 0;
+- while (len) {
+- struct page *page;
+- int copy;
+- int zero;
-
-- ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
-- if (IS_ERR(ratestr))
-- return;
+- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
+- dump_stack();
+- goto err_free;
+- }
-
-- s = ratestr;
-- b = simple_strtoul(s, &e, 10);
-- if ((s == e) || (*e != ','))
-- goto fail;
+- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
+- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
-
-- s = e + 1;
-- u = simple_strtoul(s, &e, 10);
-- if ((s == e) || (*e != '\0'))
-- goto fail;
+- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
+- if (unlikely(!page))
+- goto err_free;
-
-- *bytes = b;
-- *usec = u;
+- ret = skb_copy_bits(skb, offset, page_address(page), copy);
+- BUG_ON(ret);
-
-- kfree(ratestr);
-- return;
+- ninfo->frags[ninfo->nr_frags].page = page;
+- ninfo->frags[ninfo->nr_frags].page_offset = 0;
+- ninfo->frags[ninfo->nr_frags].size = copy;
+- ninfo->nr_frags++;
-
-- fail:
-- pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
-- kfree(ratestr);
--}
+- offset += copy;
+- len -= copy;
+- }
-
--static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
--{
-- char *s, *e, *macstr;
-- int i;
+-#ifdef NET_SKBUFF_DATA_USES_OFFSET
+- offset = 0;
+-#else
+- offset = nskb->data - skb->data;
+-#endif
-
-- macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
-- if (IS_ERR(macstr))
-- return PTR_ERR(macstr);
+- nskb->transport_header = skb->transport_header + offset;
+- nskb->network_header = skb->network_header + offset;
+- nskb->mac_header = skb->mac_header + offset;
-
-- for (i = 0; i < ETH_ALEN; i++) {
-- mac[i] = simple_strtoul(s, &e, 16);
-- if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
-- kfree(macstr);
-- return -ENOENT;
-- }
-- s = e+1;
-- }
+- return nskb;
-
-- kfree(macstr);
-- return 0;
+- err_free:
+- kfree_skb(nskb);
+- err:
+- return NULL;
-}
-
--static void unregister_hotplug_status_watch(struct backend_info *be)
+-static inline int xenvif_max_required_rx_slots(struct xenvif *vif)
-{
-- if (be->have_hotplug_status_watch) {
-- unregister_xenbus_watch(&be->hotplug_status_watch);
-- kfree(be->hotplug_status_watch.node);
-- }
-- be->have_hotplug_status_watch = 0;
+- if (vif->can_sg || vif->gso || vif->gso_prefix)
+- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
+- return 1; /* all in one */
-}
-
--static void hotplug_status_changed(struct xenbus_watch *watch,
-- const char **vec,
-- unsigned int vec_size)
+-static inline int xenvif_queue_full(struct xenvif *vif)
-{
-- struct backend_info *be = container_of(watch,
-- struct backend_info,
-- hotplug_status_watch);
-- char *str;
-- unsigned int len;
+- RING_IDX peek = vif->rx_req_cons_peek;
+- RING_IDX needed = xenvif_max_required_rx_slots(vif);
-
-- str = xenbus_read(XBT_NIL, be->dev->nodename, "hotplug-status",
&len);
-- if (IS_ERR(str))
-- return;
-- if (len == sizeof("connected")-1 && !memcmp(str,
"connected", len)) {
-- xenbus_switch_state(be->dev, XenbusStateConnected);
-- /* Not interested in this watch anymore. */
-- unregister_hotplug_status_watch(be);
-- }
-- kfree(str);
+- return ((vif->rx.sring->req_prod - peek) < needed) ||
+- ((vif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
-}
-
--static void connect(struct backend_info *be)
+ /*
+ * Returns true if we should start a new receive buffer instead of
+ * adding 'size' bytes to a buffer which currently contains 'offset'
+@@ -434,7 +332,7 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int
head)
+ * the guest. This function is essentially a dry run of
+ * netbk_gop_frag_copy.
+ */
+-static unsigned int count_skb_slots(struct sk_buff *skb, struct xenvif *vif)
++unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
+ {
+ unsigned int count = 1;
+ int i, copy_off = 0;
+@@ -468,60 +366,6 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xenvif *vif)
+ return count;
+ }
+
+-int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-- int err;
-- struct xenbus_device *dev = be->dev;
--
-- err = connect_rings(be);
-- if (err)
-- return;
--
-- err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
-- if (err) {
-- xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
-- return;
-- }
--
-- xen_net_read_rate(dev, &be->netif->credit_bytes,
-- &be->netif->credit_usec);
-- be->netif->remaining_credit = be->netif->credit_bytes;
+- struct xenvif *vif = netdev_priv(dev);
+- struct xen_netbk *netbk;
-
-- unregister_hotplug_status_watch(be);
-- err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
-- hotplug_status_changed,
-- "%s/%s", dev->nodename, "hotplug-status");
-- if (err) {
-- /* Switch now, since we can't do a watch. */
-- xenbus_switch_state(dev, XenbusStateConnected);
-- } else {
-- be->have_hotplug_status_watch = 1;
-- }
+- BUG_ON(skb->dev != dev);
-
-- netif_wake_queue(be->netif->dev);
--}
+- if (vif->netbk == NULL)
+- goto drop;
-
+- netbk = vif->netbk;
-
--static int connect_rings(struct backend_info *be)
--{
-- struct xen_netif *netif = be->netif;
-- struct xenbus_device *dev = be->dev;
-- unsigned long tx_ring_ref, rx_ring_ref;
-- unsigned int evtchn, rx_copy;
-- int err;
-- int val;
+- /* Drop the packet if the target domain has no receive buffers. */
+- if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
+- goto drop;
-
-- err = xenbus_gather(XBT_NIL, dev->otherend,
-- "tx-ring-ref", "%lu", &tx_ring_ref,
-- "rx-ring-ref", "%lu", &rx_ring_ref,
-- "event-channel", "%u", &evtchn, NULL);
-- if (err) {
-- xenbus_dev_fatal(dev, err,
-- "reading %s/ring-ref and event-channel",
-- dev->otherend);
-- return err;
+- /*
+- * XXX For now we also copy skbuffs whose head crosses a page
+- * boundary, because netbk_gop_skb can't handle them.
+- */
+- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
+- struct sk_buff *nskb = netbk_copy_skb(skb);
+- if (unlikely(nskb == NULL))
+- goto drop;
+- /* Copy only the header fields we use in this driver. */
+- nskb->dev = skb->dev;
+- nskb->ip_summed = skb->ip_summed;
+- dev_kfree_skb(skb);
+- skb = nskb;
- }
-
-- err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy",
"%u",
-- &rx_copy);
-- if (err == -ENOENT) {
-- err = 0;
-- rx_copy = 0;
-- }
-- if (err < 0) {
-- xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
-- dev->otherend);
-- return err;
-- }
-- if (!rx_copy)
-- return -EOPNOTSUPP;
+- /* Reserve ring slots for the worst-case number of fragments. */
+- vif->rx_req_cons_peek += count_skb_slots(skb, vif);
+- xenvif_get(vif);
-
-- if (netif->dev->tx_queue_len != 0) {
-- if (xenbus_scanf(XBT_NIL, dev->otherend,
-- "feature-rx-notify", "%d", &val) < 0)
-- val = 0;
-- if (val)
-- netif->can_queue = 1;
-- else
-- /* Must be non-zero for pfifo_fast to work. */
-- netif->dev->tx_queue_len = 1;
+- if (netbk_can_queue(dev) && xenvif_queue_full(vif)) {
+- vif->rx.sring->req_event = vif->rx_req_cons_peek +
+- xenvif_max_required_rx_slots(vif);
+- mb(); /* request notification /then/ check & stop the queue */
+- if (xenvif_queue_full(vif))
+- netif_stop_queue(dev);
- }
+- skb_queue_tail(&netbk->rx_queue, skb);
-
-- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
-- "%d", &val) < 0)
-- val = 0;
-- netif->can_sg = !!val;
--
-- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
-- "%d", &val) < 0)
-- val = 0;
-- netif->gso = !!val;
--
-- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
-- "%d", &val) < 0)
-- val = 0;
-- netif->gso_prefix = !!val;
--
-- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
-- "%d", &val) < 0)
-- val = 0;
-- netif->csum = !val;
+- xen_netbk_bh_handler(netbk, 1);
-
-- /* Set dev->features */
-- netif_set_features(netif);
+- return 0;
-
-- /* Map the shared frame, irq etc. */
-- err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
-- if (err) {
-- xenbus_dev_fatal(dev, err,
-- "mapping shared-frames %lu/%lu port %u",
-- tx_ring_ref, rx_ring_ref, evtchn);
-- return err;
-- }
+- drop:
+- vif->stats.tx_dropped++;
+- dev_kfree_skb(skb);
- return 0;
-}
-
--
--/* ** Driver Registration ** */
--
--
--static const struct xenbus_device_id netback_ids[] = {
-- { "vif" },
-- { "" }
--};
--
--
--static struct xenbus_driver netback = {
-- .name = "vif",
-- .owner = THIS_MODULE,
-- .ids = netback_ids,
-- .probe = netback_probe,
-- .remove = netback_remove,
-- .uevent = netback_uevent,
-- .otherend_changed = frontend_changed,
--};
--
--
--int netif_xenbus_init(void)
--{
-- printk(KERN_CRIT "registering netback\n");
-- return xenbus_register_backend(&netback);
--}
---
-1.7.4
-
-
-From 932240f6f2a1ee52e330e281069efd2f728ff7ed Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 13:02:14 +0000
-Subject: [PATCH 129/244] xen: netback: remove queue_length module option
-
-This setting can be controlled via sysfs.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/interface.c | 11 ++---------
- 1 files changed, 2 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index b429f8c..249f010 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -36,14 +36,7 @@
- #include <xen/events.h>
- #include <asm/xen/hypercall.h>
-
--/*
-- * Module parameter 'queue_length':
-- *
-- * Enables queuing in the network stack when a client has run out of receive
-- * descriptors.
-- */
--static unsigned long netbk_queue_length = 32;
--module_param_named(queue_length, netbk_queue_length, ulong, 0644);
-+#define NETBK_QUEUE_LENGTH 32
-
- static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
- struct xen_netif *netif)
-@@ -296,7 +289,7 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
- netif_set_features(netif);
- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
+ struct netrx_pending_operations {
+ unsigned copy_prod, copy_cons;
+ unsigned meta_prod, meta_cons;
+@@ -780,7 +624,7 @@ static void xen_netbk_rx_action(unsigned long data)
+ __skb_queue_tail(&rxq, skb);
-- dev->tx_queue_len = netbk_queue_length;
-+ dev->tx_queue_len = NETBK_QUEUE_LENGTH;
+ /* Filled the batch queue? */
+- if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
++ if (count + MAX_SKB_FRAGS >= XEN_NETIF_RX_RING_SIZE)
+ break;
+ }
- /*
- * Initialise a dummy MAC address. We choose the numerically
---
-1.7.4
-
-
-From 96568c3f81c7ba4d4fea43be791e4a773331ed7c Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 14:16:52 +0000
-Subject: [PATCH 130/244] xen: netback: correct error return from ethtool hooks.
-
-Should be -EOPNOTSUPP not -ENOSYS.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/interface.c | 6 +++---
- 1 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index 249f010..c41d93e 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -130,7 +130,7 @@ static int netbk_set_tx_csum(struct net_device *dev, u32 data)
- struct xen_netif *netif = netdev_priv(dev);
- if (data) {
- if (!netif->csum)
-- return -ENOSYS;
-+ return -EOPNOTSUPP;
- netif->features_disabled &= ~NETIF_F_IP_CSUM;
- } else {
- netif->features_disabled |= NETIF_F_IP_CSUM;
-@@ -145,7 +145,7 @@ static int netbk_set_sg(struct net_device *dev, u32 data)
- struct xen_netif *netif = netdev_priv(dev);
- if (data) {
- if (!netif->can_sg)
-- return -ENOSYS;
-+ return -EOPNOTSUPP;
- netif->features_disabled &= ~NETIF_F_SG;
- } else {
- netif->features_disabled |= NETIF_F_SG;
-@@ -160,7 +160,7 @@ static int netbk_set_tso(struct net_device *dev, u32 data)
- struct xen_netif *netif = netdev_priv(dev);
- if (data) {
- if (!netif->gso && !netif->gso_prefix)
-- return -ENOSYS;
-+ return -EOPNOTSUPP;
- netif->features_disabled &= ~NETIF_F_TSO;
- } else {
- netif->features_disabled |= NETIF_F_TSO;
---
-1.7.4
-
-
-From 12a5b4f364888f291bcd8e38a146f30fcceb9588 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 14:20:04 +0000
-Subject: [PATCH 131/244] xen: netback: avoid leading _ in function parameter names.
-
-It is usually used to distinguish lower-level functions or to avoid naming
-conflicts in macros.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/netback.c | 6 +++---
- 1 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index b290525..cd2af15 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -90,7 +90,7 @@ static inline void netif_set_page_ext(struct page *pg,
+@@ -887,9 +731,12 @@ static void xen_netbk_rx_action(unsigned long data)
+ xen_netbk_bh_handler(netbk, 1);
}
- static int netif_get_page_ext(struct page *pg,
-- unsigned int *_group, unsigned int *_idx)
-+ unsigned int *pgroup, unsigned int *pidx)
+-static void net_alarm(unsigned long data)
++void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb)
{
- union page_ext ext = { .mapping = pg->mapping };
- struct xen_netbk *netbk;
-@@ -117,8 +117,8 @@ static int netif_get_page_ext(struct page *pg,
- if (netbk->mmap_pages[idx] != pg)
- return 0;
-
-- *_group = group;
-- *_idx = idx;
-+ *pgroup = group;
-+ *pidx = idx;
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
++ struct xen_netbk *netbk = vif->netbk;
++
++ skb_queue_tail(&netbk->rx_queue, skb);
++
+ xen_netbk_bh_handler(netbk, 1);
+ }
- return 1;
+@@ -899,10 +746,10 @@ static void xen_netbk_tx_pending_timeout(unsigned long data)
+ xen_netbk_bh_handler(netbk, 0);
}
---
-1.7.4
-
-
-From a789731f0ed97fc762835a568f2fefbf0d490ccf Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 14:21:24 +0000
-Subject: [PATCH 132/244] xen: netback: drop unused debug interrupt handler.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/netback.c | 57 -------------------------------------
- 1 files changed, 0 insertions(+), 57 deletions(-)
-
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index cd2af15..a7646f3 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -47,8 +47,6 @@
- #include <asm/xen/hypercall.h>
- #include <asm/xen/page.h>
--/*define NETBE_DEBUG_INTERRUPT*/
--
- struct xen_netbk *xen_netbk;
- int xen_netbk_group_nr;
+-struct net_device_stats *xenvif_get_stats(struct net_device *dev)
++static void xen_netbk_alarm(unsigned long data)
+ {
+- struct xenvif *vif = netdev_priv(dev);
+- return &vif->stats;
++ struct xen_netbk *netbk = (struct xen_netbk *)data;
++ xen_netbk_bh_handler(netbk, 1);
+ }
-@@ -1707,52 +1705,6 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
- return resp;
+ static int __on_net_schedule_list(struct xenvif *vif)
+@@ -940,13 +787,13 @@ out:
+ return vif;
}
--#ifdef NETBE_DEBUG_INTERRUPT
--static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
--{
-- struct list_head *ent;
-- struct xen_netif *netif;
-- int i = 0;
-- int group = 0;
--
-- printk(KERN_ALERT "netif_schedule_list:\n");
--
-- for (group = 0; group < xen_netbk_group_nr; group++) {
-- struct xen_netbk *netbk = &xen_netbk[group];
-- spin_lock_irq(&netbk->net_schedule_list_lock);
-- printk(KERN_ALERT "xen_netback group number: %d\n", group);
-- list_for_each(ent, &netbk->net_schedule_list) {
-- netif = list_entry(ent, struct xen_netif, list);
-- printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-- "rx_resp_prod=%08x\n",
-- i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-- printk(KERN_ALERT
-- " tx_req_cons=%08x, tx_resp_prod=%08x)\n",
-- netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-- printk(KERN_ALERT
-- " shared(rx_req_prod=%08x "
-- "rx_resp_prod=%08x\n",
-- netif->rx.sring->req_prod,
-- netif->rx.sring->rsp_prod);
-- printk(KERN_ALERT
-- " rx_event=%08x, tx_req_prod=%08x\n",
-- netif->rx.sring->rsp_event,
-- netif->tx.sring->req_prod);
-- printk(KERN_ALERT
-- " tx_resp_prod=%08x, tx_event=%08x)\n",
-- netif->tx.sring->rsp_prod,
-- netif->tx.sring->rsp_event);
-- i++;
-- }
-- spin_unlock_irq(&netbk->net_schedule_list_lock);
-- }
--
-- printk(KERN_ALERT " ** End of netif_schedule_list **\n");
--
-- return IRQ_HANDLED;
+-static void add_to_net_schedule_list_tail(struct xenvif *vif)
++void xen_netbk_schedule_xenvif(struct xenvif *vif)
+ {
+ unsigned long flags;
+
+ struct xen_netbk *netbk = vif->netbk;
+ if (__on_net_schedule_list(vif))
+- return;
++ goto kick;
+
+ spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
+ if (!__on_net_schedule_list(vif) &&
+@@ -955,22 +802,15 @@ static void add_to_net_schedule_list_tail(struct xenvif *vif)
+ xenvif_get(vif);
+ }
+ spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
-}
--#endif
-
- static inline int rx_work_todo(struct xen_netbk *netbk)
- {
- return !skb_queue_empty(&netbk->rx_queue);
-@@ -1903,15 +1855,6 @@ static int __init netback_init(void)
- if (rc)
- goto failed_init;
-
--#ifdef NETBE_DEBUG_INTERRUPT
-- (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-- 0,
-- netif_be_dbg,
-- IRQF_SHARED,
-- "net-be-dbg",
-- &netif_be_dbg);
--#endif
+-void xenvif_schedule_work(struct xenvif *vif)
+-{
+- struct xen_netbk *netbk = vif->netbk;
+- int more_to_do;
-
- return 0;
+- RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
- failed_init:
---
-1.7.4
-
-
-From 056508bc941b3715c72a5fa00a6b38a006979dd9 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 16:42:27 +0000
-Subject: [PATCH 133/244] xen: netif: properly namespace the Xen netif protocol header.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/netback.c | 38 +++++++++---------
- drivers/net/xen-netfront.c | 20 +++++-----
- include/xen/interface/io/netif.h | 80 ++++++++++++++++++------------------
- 3 files changed, 69 insertions(+), 69 deletions(-)
-
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index a7646f3..69b4535 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -582,7 +582,7 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
- struct netrx_pending_operations *npo)
- {
- struct gnttab_copy *copy_op;
-- int status = NETIF_RSP_OKAY;
-+ int status = XEN_NETIF_RSP_OKAY;
- int i;
+- if (more_to_do) {
+- add_to_net_schedule_list_tail(vif);
+- maybe_schedule_tx_action(netbk);
+- }
++kick:
++ smp_mb();
++ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
++ !list_empty(&netbk->net_schedule_list))
++ xen_netbk_bh_handler(netbk, 0);
+ }
- for (i = 0; i < nr_meta_slots; i++) {
-@@ -590,7 +590,7 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
- if (copy_op->status != GNTST_okay) {
- pr_debug("Bad status %d from copy to DOM%d.\n",
- copy_op->status, domid);
-- status = NETIF_RSP_ERROR;
-+ status = XEN_NETIF_RSP_ERROR;
- }
- }
+-void xenvif_deschedule_work(struct xenvif *vif)
++void xen_netbk_deschedule_xenfif(struct xenvif *vif)
+ {
+ struct xen_netbk *netbk = vif->netbk;
+ spin_lock_irq(&netbk->net_schedule_list_lock);
+@@ -1019,7 +859,7 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
+ struct gnttab_unmap_grant_ref *gop;
+ u16 pending_idx;
+ pending_ring_idx_t dc, dp;
+- struct xen_netif *netif;
++ struct xenvif *vif;
+ int ret;
+ LIST_HEAD(list);
-@@ -615,7 +615,7 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
- if (i == nr_meta_slots - 1)
- flags = 0;
- else
-- flags = NETRXF_more_data;
-+ flags = XEN_NETRXF_more_data;
+@@ -1077,7 +917,7 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
- offset = 0;
- make_rx_response(netif, meta[i].id, status, offset,
-@@ -687,7 +687,7 @@ static void net_rx_action(unsigned long data)
- resp = RING_GET_RESPONSE(&netif->rx,
- netif->rx.rsp_prod_pvt++);
+ pending_idx = inuse - netbk->pending_inuse;
-- resp->flags = NETRXF_gso_prefix | NETRXF_more_data;
-+ resp->flags = XEN_NETRXF_gso_prefix | XEN_NETRXF_more_data;
+- pending_tx_info[pending_idx].netif->nr_copied_skbs++;
++ pending_tx_info[pending_idx].vif->nr_copied_skbs++;
- resp->offset = netbk->meta[npo.meta_cons].gso_size;
- resp->id = netbk->meta[npo.meta_cons].id;
-@@ -707,13 +707,13 @@ static void net_rx_action(unsigned long data)
- if (sco->meta_slots_used == 1)
- flags = 0;
- else
-- flags = NETRXF_more_data;
-+ flags = XEN_NETRXF_more_data;
+ switch (copy_pending_req(netbk, pending_idx)) {
+ case 0:
+@@ -1101,9 +941,9 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
+ pending_tx_info = netbk->pending_tx_info;
+ pending_idx = inuse - netbk->pending_inuse;
- if (skb->ip_summed == CHECKSUM_PARTIAL) /* local packet? */
-- flags |= NETRXF_csum_blank | NETRXF_data_validated;
-+ flags |= XEN_NETRXF_csum_blank | XEN_NETRXF_data_validated;
- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
- /* remote but checksummed. */
-- flags |= NETRXF_data_validated;
-+ flags |= XEN_NETRXF_data_validated;
+- netif = pending_tx_info[pending_idx].netif;
++ vif = pending_tx_info[pending_idx].vif;
- offset = 0;
- resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
-@@ -727,7 +727,7 @@ static void net_rx_action(unsigned long data)
- RING_GET_RESPONSE(&netif->rx,
- netif->rx.rsp_prod_pvt++);
+- make_tx_response(netif, &pending_tx_info[pending_idx].req,
++ make_tx_response(vif, &pending_tx_info[pending_idx].req,
+ XEN_NETIF_RSP_OKAY);
-- resp->flags |= NETRXF_extra_info;
-+ resp->flags |= XEN_NETRXF_extra_info;
+ /* Ready for next use. */
+@@ -1200,7 +1040,7 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
- gso->u.gso.size = netbk->meta[npo.meta_cons].gso_size;
- gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
-@@ -989,7 +989,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
- netif = pending_tx_info[pending_idx].netif;
+ gnttab_set_map_op(mop++, idx_to_kaddr(netbk, pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+- txp->gref, netif->domid);
++ txp->gref, vif->domid);
- make_tx_response(netif, &pending_tx_info[pending_idx].req,
-- NETIF_RSP_OKAY);
-+ XEN_NETIF_RSP_OKAY);
+ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
+ xenvif_get(vif);
+@@ -1319,9 +1159,9 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
+ }
+ }
- /* Ready for next use. */
- gnttab_reset_grant_page(netbk->mmap_pages[pending_idx]);
-@@ -1009,7 +1009,7 @@ static void netbk_tx_err(struct xen_netif *netif,
- RING_IDX cons = netif->tx.req_cons;
+-int netbk_get_extras(struct xenvif *vif,
+- struct xen_netif_extra_info *extras,
+- int work_to_do)
++static int xen_netbk_get_extras(struct xenvif *vif,
++ struct xen_netif_extra_info *extras,
++ int work_to_do)
+ {
+ struct xen_netif_extra_info extra;
+ RING_IDX cons = vif->tx.req_cons;
+@@ -1522,8 +1362,8 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- do {
-- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
- if (cons >= end)
- break;
- txp = RING_GET_REQUEST(&netif->tx, cons++);
-@@ -1027,7 +1027,7 @@ static int netbk_count_requests(struct xen_netif *netif,
- RING_IDX cons = netif->tx.req_cons;
- int frags = 0;
+ memset(extras, 0, sizeof(extras));
+ if (txreq.flags & XEN_NETTXF_extra_info) {
+- work_to_do = netbk_get_extras(vif, extras,
+- work_to_do);
++ work_to_do = xen_netbk_get_extras(vif, extras,
++ work_to_do);
+ idx = vif->tx.req_cons;
+ if (unlikely(work_to_do < 0)) {
+ netbk_tx_err(vif, &txreq, idx);
+@@ -1584,7 +1424,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
-- if (!(first->flags & NETTXF_more_data))
-+ if (!(first->flags & XEN_NETTXF_more_data))
- return 0;
+ gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+- txreq.gref, netif->domid);
++ txreq.gref, vif->domid);
+ mop++;
- do {
-@@ -1056,7 +1056,7 @@ static int netbk_count_requests(struct xen_netif *netif,
- txp->offset, txp->size);
- return -frags;
- }
-- } while ((txp++)->flags & NETTXF_more_data);
-+ } while ((txp++)->flags & XEN_NETTXF_more_data);
+ memcpy(&netbk->pending_tx_info[pending_idx].req,
+@@ -1608,7 +1448,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- return frags;
- }
-@@ -1115,7 +1115,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
- pending_ring_idx_t index;
- index = pending_index(netbk->pending_prod++);
- txp = &pending_tx_info[pending_idx].req;
-- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
- netbk->pending_ring[index] = pending_idx;
- netif_put(netif);
- } else {
-@@ -1151,7 +1151,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+ netbk->pending_cons++;
- /* Error on this fragment: respond to client with an error. */
- txp = &netbk->pending_tx_info[pending_idx].req;
-- make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+ make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
- netif_put(netif);
-@@ -1406,7 +1406,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- netif->tx.req_cons = ++idx;
+- mop = xen_netbk_get_requests(netbk, netif, skb, txfrags, mop);
++ mop = xen_netbk_get_requests(netbk, vif, skb, txfrags, mop);
- memset(extras, 0, sizeof(extras));
-- if (txreq.flags & NETTXF_extra_info) {
-+ if (txreq.flags & XEN_NETTXF_extra_info) {
- work_to_do = netbk_get_extras(netif, extras,
- work_to_do);
- idx = netif->tx.req_cons;
-@@ -1542,9 +1542,9 @@ static void net_tx_submit(struct xen_netbk *netbk)
- netif_idx_release(netbk, pending_idx);
- }
+ vif->tx.req_cons = idx;
+ xenvif_schedule_work(vif);
+@@ -1705,7 +1545,7 @@ static void xen_netbk_tx_action(unsigned long data)
+ unsigned nr_mops;
+ int ret;
-- if (txp->flags & NETTXF_csum_blank)
-+ if (txp->flags & XEN_NETTXF_csum_blank)
- skb->ip_summed = CHECKSUM_PARTIAL;
-- else if (txp->flags & NETTXF_data_validated)
-+ else if (txp->flags & XEN_NETTXF_data_validated)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+- net_tx_action_dealloc(netbk);
++ xen_netbk_tx_action_dealloc(netbk);
- netbk_fill_frags(netbk, skb);
-@@ -1673,8 +1673,8 @@ static void make_tx_response(struct xen_netif *netif,
- resp->id = txp->id;
- resp->status = st;
+ nr_mops = xen_netbk_tx_build_mops(netbk);
-- if (txp->flags & NETTXF_extra_info)
-- RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
-+ if (txp->flags & XEN_NETTXF_extra_info)
-+ RING_GET_RESPONSE(&netif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+@@ -1738,7 +1578,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16
pending_idx)
+ spin_lock_irqsave(&_lock, flags);
+ index = pending_index(netbk->dealloc_prod);
+ netbk->dealloc_ring[index] = pending_idx;
+- /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
++ /* Sync with xen_netbk_tx_action_dealloc: insert idx /then/ incr producer. */
+ smp_wmb();
+ netbk->dealloc_prod++;
+ spin_unlock_irqrestore(&_lock, flags);
+@@ -1757,23 +1597,6 @@ static void netif_page_release(struct page *page, unsigned int
order)
+ xen_netbk_idx_release(&xen_netbk[group], idx);
+ }
- netif->tx.rsp_prod_pvt = ++i;
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
-diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
-index 458bb57..cc23d42 100644
---- a/drivers/net/xen-netfront.c
-+++ b/drivers/net/xen-netfront.c
-@@ -356,7 +356,7 @@ static void xennet_tx_buf_gc(struct net_device *dev)
- struct xen_netif_tx_response *txrsp;
+-irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+-{
+- struct xenvif *vif = dev_id;
+- struct xen_netbk *netbk = vif->netbk;
+-
+- if (netbk == NULL)
+- return IRQ_NONE;
+-
+- add_to_net_schedule_list_tail(vif);
+- maybe_schedule_tx_action(netbk);
+-
+- if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))
+- netif_wake_queue(vif->dev);
+-
+- return IRQ_HANDLED;
+-}
+-
+ static void make_tx_response(struct xenvif *vif,
+ struct xen_netif_tx_request *txp,
+ s8 st)
+@@ -1887,12 +1710,12 @@ static int __init netback_init(void)
- txrsp = RING_GET_RESPONSE(&np->tx, cons);
-- if (txrsp->status == NETIF_RSP_NULL)
-+ if (txrsp->status == XEN_NETIF_RSP_NULL)
- continue;
+ init_timer(&netbk->net_timer);
+ netbk->net_timer.data = (unsigned long)netbk;
+- netbk->net_timer.function = net_alarm;
++ netbk->net_timer.function = xen_netbk_alarm;
- id = txrsp->id;
-@@ -413,7 +413,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device
*dev,
- larger than a page), split it it into page-sized chunks. */
- while (len > PAGE_SIZE - offset) {
- tx->size = PAGE_SIZE - offset;
-- tx->flags |= NETTXF_more_data;
-+ tx->flags |= XEN_NETTXF_more_data;
- len -= tx->size;
- data += tx->size;
- offset = 0;
-@@ -439,7 +439,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device
*dev,
- for (i = 0; i < frags; i++) {
- skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+ init_timer(&netbk->netbk_tx_pending_timer);
+ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
+ netbk->netbk_tx_pending_timer.function =
+- netbk_tx_pending_timeout;
++ xen_netbk_tx_pending_timeout;
-- tx->flags |= NETTXF_more_data;
-+ tx->flags |= XEN_NETTXF_more_data;
+ netbk->mmap_pages =
+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
+index a6ad259..e854420 100644
+--- a/drivers/net/xen-netback/xenbus.c
++++ b/drivers/net/xen-netback/xenbus.c
+@@ -21,6 +21,14 @@
- id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
- np->tx_skbs[id].skb = skb_get(skb);
-@@ -514,10 +514,10 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- tx->flags = 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- /* local packet? */
-- tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
-+ tx->flags |= XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated;
- else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
- /* remote but checksummed. */
-- tx->flags |= NETTXF_data_validated;
-+ tx->flags |= XEN_NETTXF_data_validated;
+ #include "common.h"
- if (skb_shinfo(skb)->gso_size) {
- struct xen_netif_extra_info *gso;
-@@ -528,7 +528,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- if (extra)
- extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
- else
-- tx->flags |= NETTXF_extra_info;
-+ tx->flags |= XEN_NETTXF_extra_info;
++struct backend_info {
++ struct xenbus_device *dev;
++ struct xenvif *vif;
++ enum xenbus_state frontend_state;
++ struct xenbus_watch hotplug_status_watch;
++ int have_hotplug_status_watch:1;
++};
++
+ static int connect_rings(struct backend_info *);
+ static void connect(struct backend_info *);
+ static void backend_create_xenvif(struct backend_info *be);
+@@ -447,9 +455,6 @@ static int connect_rings(struct backend_info *be)
+ val = 0;
+ vif->csum = !val;
- gso->u.gso.size = skb_shinfo(skb)->gso_size;
- gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
-@@ -648,7 +648,7 @@ static int xennet_get_responses(struct netfront_info *np,
- int err = 0;
- unsigned long ret;
+- /* Set dev->features */
+- xenvif_set_features(vif);
+-
+ /* Map the shared frame, irq etc. */
+ err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
+ if (err) {
+--
+1.7.4
+
+
+From f1c011ec476d1ee2c36afb9df40024ffca087b08 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 21 Jan 2011 11:10:22 +0000
+Subject: [PATCH 097/203] xen: netback: switch to kthread mode and drop tasklet mode
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/net/xen-netback/netback.c | 108 +++++++++++-------------------------
+ 1 files changed, 33 insertions(+), 75 deletions(-)
+
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index 1b7005c..73e35fd 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -84,17 +84,8 @@ union page_ext {
+ };
-- if (rx->flags & NETRXF_extra_info) {
-+ if (rx->flags & XEN_NETRXF_extra_info) {
- err = xennet_get_extras(np, extras, rp);
- cons = np->rx.rsp_cons;
- }
-@@ -685,7 +685,7 @@ static int xennet_get_responses(struct netfront_info *np,
- __skb_queue_tail(list, skb);
+ struct xen_netbk {
+- union {
+- struct {
+- struct tasklet_struct net_tx_tasklet;
+- struct tasklet_struct net_rx_tasklet;
+- } tasklet;
+-
+- struct {
+- wait_queue_head_t netbk_action_wq;
+- struct task_struct *task;
+- } kthread;
+- };
++ wait_queue_head_t wq;
++ struct task_struct *task;
- next:
-- if (!(rx->flags & NETRXF_more_data))
-+ if (!(rx->flags & XEN_NETRXF_more_data))
- break;
+ struct sk_buff_head rx_queue;
+ struct sk_buff_head tx_queue;
+@@ -180,10 +171,6 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif
*vif,
+ u16 size,
+ u16 flags);
- if (cons + frags == rp) {
-@@ -950,9 +950,9 @@ err:
- skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
- skb->len += skb->data_len;
+-static void xen_netbk_tx_action(unsigned long data);
+-
+-static void xen_netbk_rx_action(unsigned long data);
+-
+ static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
+ unsigned int idx)
+ {
+@@ -268,23 +255,9 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
-- if (rx->flags & NETRXF_csum_blank)
-+ if (rx->flags & XEN_NETRXF_csum_blank)
- skb->ip_summed = CHECKSUM_PARTIAL;
-- else if (rx->flags & NETRXF_data_validated)
-+ else if (rx->flags & XEN_NETRXF_data_validated)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ int netbk_copy_skb_mode;
- __skb_queue_tail(&rxq, skb);
-diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
-index 8309344..cb94668 100644
---- a/include/xen/interface/io/netif.h
-+++ b/include/xen/interface/io/netif.h
-@@ -22,50 +22,50 @@
+-static int MODPARM_netback_kthread;
+-module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
+-MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
+-
+-/*
+- * Netback bottom half handler.
+- * dir indicates the data direction.
+- * rx: 1, tx: 0.
+- */
+-void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
++static void xen_netbk_kick_thread(struct xen_netbk *netbk)
+ {
+- if (MODPARM_netback_kthread)
+- wake_up(&netbk->kthread.netbk_action_wq);
+- else if (dir)
+- tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
+- else
+- tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
++ wake_up(&netbk->wq);
+ }
/*
- * This is the 'wire' format for packets:
-- * Request 1: netif_tx_request -- NETTXF_* (any flags)
-- * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info)
-- * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE)
-- * Request 4: netif_tx_request -- NETTXF_more_data
-- * Request 5: netif_tx_request -- NETTXF_more_data
-+ * Request 1: xen_netif_tx_request -- XEN_NETTXF_* (any flags)
-+ * [Request 2: xen_netif_extra_info] (only if request 1 has XEN_NETTXF_extra_info)
-+ * [Request 3: xen_netif_extra_info] (only if request 2 has XEN_NETIF_EXTRA_MORE)
-+ * Request 4: xen_netif_tx_request -- XEN_NETTXF_more_data
-+ * Request 5: xen_netif_tx_request -- XEN_NETTXF_more_data
- * ...
-- * Request N: netif_tx_request -- 0
-+ * Request N: xen_netif_tx_request -- 0
- */
+@@ -587,10 +560,9 @@ struct skb_cb_overlay {
+ int meta_slots_used;
+ };
+
+-static void xen_netbk_rx_action(unsigned long data)
++static void xen_netbk_rx_action(struct xen_netbk *netbk)
+ {
+ struct xenvif *vif = NULL;
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+ s8 status;
+ u16 irq, flags;
+ struct xen_netif_rx_response *resp;
+@@ -728,7 +700,7 @@ static void xen_netbk_rx_action(unsigned long data)
+ /* More work to do? */
+ if (!skb_queue_empty(&netbk->rx_queue) &&
+ !timer_pending(&netbk->net_timer))
+- xen_netbk_bh_handler(netbk, 1);
++ xen_netbk_kick_thread(netbk);
+ }
- /* Protocol checksum field is blank in the packet (hardware offload)? */
--#define _NETTXF_csum_blank (0)
--#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank)
-+#define _XEN_NETTXF_csum_blank (0)
-+#define XEN_NETTXF_csum_blank (1U<<_XEN_NETTXF_csum_blank)
+ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb)
+@@ -737,19 +709,19 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff
*skb)
- /* Packet data has been validated against protocol checksum. */
--#define _NETTXF_data_validated (1)
--#define NETTXF_data_validated (1U<<_NETTXF_data_validated)
-+#define _XEN_NETTXF_data_validated (1)
-+#define XEN_NETTXF_data_validated (1U<<_XEN_NETTXF_data_validated)
+ skb_queue_tail(&netbk->rx_queue, skb);
- /* Packet continues in the next request descriptor. */
--#define _NETTXF_more_data (2)
--#define NETTXF_more_data (1U<<_NETTXF_more_data)
-+#define _XEN_NETTXF_more_data (2)
-+#define XEN_NETTXF_more_data (1U<<_XEN_NETTXF_more_data)
+- xen_netbk_bh_handler(netbk, 1);
++ xen_netbk_kick_thread(netbk);
+ }
- /* Packet to be followed by extra descriptor(s). */
--#define _NETTXF_extra_info (3)
--#define NETTXF_extra_info (1U<<_NETTXF_extra_info)
-+#define _XEN_NETTXF_extra_info (3)
-+#define XEN_NETTXF_extra_info (1U<<_XEN_NETTXF_extra_info)
+ static void xen_netbk_tx_pending_timeout(unsigned long data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+- xen_netbk_bh_handler(netbk, 0);
++ xen_netbk_kick_thread(netbk);
+ }
- struct xen_netif_tx_request {
- grant_ref_t gref; /* Reference to buffer page */
- uint16_t offset; /* Offset within buffer page */
-- uint16_t flags; /* NETTXF_* */
-+ uint16_t flags; /* XEN_NETTXF_* */
- uint16_t id; /* Echoed in response message. */
- uint16_t size; /* Packet size in bytes. */
- };
+ static void xen_netbk_alarm(unsigned long data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+- xen_netbk_bh_handler(netbk, 1);
++ xen_netbk_kick_thread(netbk);
+ }
--/* Types of netif_extra_info descriptors. */
--#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
--#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
--#define XEN_NETIF_EXTRA_TYPE_MAX (2)
-+/* Types of xen_netif_extra_info descriptors. */
-+#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
-+#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
-+#define XEN_NETIF_EXTRA_TYPE_MAX (2)
+ static int __on_net_schedule_list(struct xenvif *vif)
+@@ -807,7 +779,7 @@ kick:
+ smp_mb();
+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
+ !list_empty(&netbk->net_schedule_list))
+- xen_netbk_bh_handler(netbk, 0);
++ xen_netbk_kick_thread(netbk);
+ }
--/* netif_extra_info flags. */
--#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
--#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
-+/* xen_netif_extra_info flags. */
-+#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
-+#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+ void xen_netbk_deschedule_xenfif(struct xenvif *vif)
+@@ -1539,9 +1511,8 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ }
- /* GSO types - only TCPv4 currently supported. */
--#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
-+#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
+ /* Called after netfront has transmitted */
+-static void xen_netbk_tx_action(unsigned long data)
++static void xen_netbk_tx_action(struct xen_netbk *netbk)
+ {
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+ unsigned nr_mops;
+ int ret;
- /*
- * This structure needs to fit within both netif_tx_request and
-@@ -107,7 +107,7 @@ struct xen_netif_extra_info {
+@@ -1583,7 +1554,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16
pending_idx)
+ netbk->dealloc_prod++;
+ spin_unlock_irqrestore(&_lock, flags);
- struct xen_netif_tx_response {
- uint16_t id;
-- int16_t status; /* NETIF_RSP_* */
-+ int16_t status; /* XEN_NETIF_RSP_* */
- };
+- xen_netbk_bh_handler(netbk, 0);
++ xen_netbk_kick_thread(netbk);
+ }
- struct xen_netif_rx_request {
-@@ -116,29 +116,29 @@ struct xen_netif_rx_request {
- };
+ static void netif_page_release(struct page *page, unsigned int order)
+@@ -1662,11 +1633,11 @@ static inline int tx_work_todo(struct xen_netbk *netbk)
+ return 0;
+ }
- /* Packet data has been validated against protocol checksum. */
--#define _NETRXF_data_validated (0)
--#define NETRXF_data_validated (1U<<_NETRXF_data_validated)
-+#define _XEN_NETRXF_data_validated (0)
-+#define XEN_NETRXF_data_validated (1U<<_XEN_NETRXF_data_validated)
+-static int xen_netbk_action_thread(void *data)
++static int xen_netbk_kthread(void *data)
+ {
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+ while (!kthread_should_stop()) {
+- wait_event_interruptible(netbk->kthread.netbk_action_wq,
++ wait_event_interruptible(netbk->wq,
+ rx_work_todo(netbk)
+ || tx_work_todo(netbk)
+ || kthread_should_stop());
+@@ -1676,10 +1647,10 @@ static int xen_netbk_action_thread(void *data)
+ break;
- /* Protocol checksum field is blank in the packet (hardware offload)? */
--#define _NETRXF_csum_blank (1)
--#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank)
-+#define _XEN_NETRXF_csum_blank (1)
-+#define XEN_NETRXF_csum_blank (1U<<_XEN_NETRXF_csum_blank)
+ if (rx_work_todo(netbk))
+- xen_netbk_rx_action((unsigned long)netbk);
++ xen_netbk_rx_action(netbk);
- /* Packet continues in the next request descriptor. */
--#define _NETRXF_more_data (2)
--#define NETRXF_more_data (1U<<_NETRXF_more_data)
-+#define _XEN_NETRXF_more_data (2)
-+#define XEN_NETRXF_more_data (1U<<_XEN_NETRXF_more_data)
+ if (tx_work_todo(netbk))
+- xen_netbk_tx_action((unsigned long)netbk);
++ xen_netbk_tx_action(netbk);
+ }
- /* Packet to be followed by extra descriptor(s). */
--#define _NETRXF_extra_info (3)
--#define NETRXF_extra_info (1U<<_NETRXF_extra_info)
-+#define _XEN_NETRXF_extra_info (3)
-+#define XEN_NETRXF_extra_info (1U<<_XEN_NETRXF_extra_info)
+ return 0;
+@@ -1739,34 +1710,23 @@ static int __init netback_init(void)
+ for (i = 0; i < MAX_PENDING_REQS; i++)
+ netbk->pending_ring[i] = i;
- /* GSO Prefix descriptor. */
--#define _NETRXF_gso_prefix (4)
--#define NETRXF_gso_prefix (1U<<_NETRXF_gso_prefix)
-+#define _XEN_NETRXF_gso_prefix (4)
-+#define XEN_NETRXF_gso_prefix (1U<<_XEN_NETRXF_gso_prefix)
+- if (MODPARM_netback_kthread) {
+- init_waitqueue_head(&netbk->kthread.netbk_action_wq);
+- netbk->kthread.task =
+- kthread_create(xen_netbk_action_thread,
+- (void *)netbk,
+- "netback/%u", group);
+-
+- if (!IS_ERR(netbk->kthread.task)) {
+- kthread_bind(netbk->kthread.task, group);
+- } else {
+- printk(KERN_ALERT
+- "kthread_run() fails at netback\n");
+- free_empty_pages_and_pagevec(netbk->mmap_pages,
+- MAX_PENDING_REQS);
+- del_timer(&netbk->netbk_tx_pending_timer);
+- del_timer(&netbk->net_timer);
+- rc = PTR_ERR(netbk->kthread.task);
+- goto failed_init;
+- }
+- } else {
+- tasklet_init(&netbk->tasklet.net_tx_tasklet,
+- xen_netbk_tx_action,
+- (unsigned long)netbk);
+- tasklet_init(&netbk->tasklet.net_rx_tasklet,
+- xen_netbk_rx_action,
+- (unsigned long)netbk);
++ init_waitqueue_head(&netbk->wq);
++ netbk->task = kthread_create(xen_netbk_kthread,
++ (void *)netbk,
++ "netback/%u", group);
++
++ if (IS_ERR(netbk->task)) {
++ printk(KERN_ALERT "kthread_run() fails at netback\n");
++ free_empty_pages_and_pagevec(netbk->mmap_pages,
++ MAX_PENDING_REQS);
++ del_timer(&netbk->netbk_tx_pending_timer);
++ del_timer(&netbk->net_timer);
++ rc = PTR_ERR(netbk->task);
++ goto failed_init;
+ }
- struct xen_netif_rx_response {
- uint16_t id;
- uint16_t offset; /* Offset in page of start of received packet */
-- uint16_t flags; /* NETRXF_* */
-+ uint16_t flags; /* XEN_NETRXF_* */
- int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
- };
++ kthread_bind(netbk->task, group);
++
+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
+ INIT_LIST_HEAD(&netbk->net_schedule_list);
-@@ -153,10 +153,10 @@ DEFINE_RING_TYPES(xen_netif_rx,
- struct xen_netif_rx_request,
- struct xen_netif_rx_response);
+@@ -1774,8 +1734,7 @@ static int __init netback_init(void)
--#define NETIF_RSP_DROPPED -2
--#define NETIF_RSP_ERROR -1
--#define NETIF_RSP_OKAY 0
--/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
--#define NETIF_RSP_NULL 1
-+#define XEN_NETIF_RSP_DROPPED -2
-+#define XEN_NETIF_RSP_ERROR -1
-+#define XEN_NETIF_RSP_OKAY 0
-+/* No response: used for auxiliary requests (e.g., xen_netif_extra_info). */
-+#define XEN_NETIF_RSP_NULL 1
+ atomic_set(&netbk->netfront_count, 0);
- #endif
+- if (MODPARM_netback_kthread)
+- wake_up_process(netbk->kthread.task);
++ wake_up_process(netbk->task);
+ }
+
+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+@@ -1800,8 +1759,7 @@ failed_init:
+ MAX_PENDING_REQS);
+ del_timer(&netbk->netbk_tx_pending_timer);
+ del_timer(&netbk->net_timer);
+- if (MODPARM_netback_kthread)
+- kthread_stop(netbk->kthread.task);
++ kthread_stop(netbk->task);
+ }
+ vfree(xen_netbk);
+ return rc;
--
1.7.4
-From 16d8ace0b7af72fb9e355eee165251e1f9b511e1 Mon Sep 17 00:00:00 2001
+From e564d36cd3368e17218052148932322f7fe324bf Mon Sep 17 00:00:00 2001
From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 1 Feb 2011 16:50:24 +0000
-Subject: [PATCH 134/244] xen: netif: improve Kconfig help text for front- and backend
drivers.
+Date: Wed, 2 Feb 2011 17:25:26 +0000
+Subject: [PATCH 098/203] xen: netback: handle frames whose head crosses a page boundary
-Signed-off-by: Ian Campell <ian.campbell(a)citrix.com>
+Previoulsy we copied any skb whose head crossed a page boundary before
+forwarding to the guest. However dealing with these skbs is relatively straight
+forward.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/net/Kconfig | 35 +++++++++++++++++++++++++++--------
- 1 files changed, 27 insertions(+), 8 deletions(-)
+ drivers/net/xen-netback/interface.c | 103 ++---------------------------------
+ drivers/net/xen-netback/netback.c | 48 +++++++++++------
+ 2 files changed, 36 insertions(+), 115 deletions(-)
-diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
-index 5b088f5..1c77e183 100644
---- a/drivers/net/Kconfig
-+++ b/drivers/net/Kconfig
-@@ -2963,19 +2963,38 @@ config XEN_NETDEV_FRONTEND
- select XEN_XENBUS_FRONTEND
- default y
- help
-- The network device frontend driver allows the kernel to
-- access network devices exported exported by a virtual
-- machine containing a physical network device driver. The
-- frontend driver is intended for unprivileged guest domains;
-- if you are compiling a kernel for a Xen guest, you almost
-- certainly want to enable this.
-+ This driver provides support for Xen paravirtual network
-+ devices exported by a Xen network driver domain (often
-+ domain 0).
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index c906c79..1bd2eeb 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -51,9 +51,12 @@ void xenvif_put(struct xenvif *vif)
+
+ static int xenvif_max_required_rx_slots(struct xenvif *vif)
+ {
++ int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE);
+
-+ The corresponding Linux backend driver is enabled by the
-+ CONFIG_XEN_NETDEV_BACKEND option.
+ if (vif->can_sg || vif->gso || vif->gso_prefix)
+- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
+- return 1; /* all in one */
++ max += MAX_SKB_FRAGS + 1; /* extra_info + frags */
+
-+ If you are compiling a kernel for use as Xen guest, you
-+ should say Y here. To compile this driver as a module, chose
-+ M here: the module will be called xen-netfront.
++ return max;
+ }
- config XEN_NETDEV_BACKEND
- tristate "Xen backend network device"
- depends on XEN_BACKEND
- help
-- Implement the network backend driver, which passes packets
-- from the guest domain's frontend drivers to the network.
-+ This driver allows the kernel to act as a Xen network driver
-+ domain which exports paravirtual network devices to other
-+ Xen domains. These devices can be accessed by any operating
-+ system that implements a compatible front end.
+ int xenvif_queue_full(struct xenvif *vif)
+@@ -104,87 +107,6 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+ return IRQ_HANDLED;
+ }
+
+-/* TODO: move to networking core */
+-static struct sk_buff *xenvif_copy_skb(struct sk_buff *skb)
+-{
+- struct skb_shared_info *ninfo;
+- struct sk_buff *nskb;
+- unsigned long offset;
+- int ret;
+- int len;
+- int headlen;
+-
+- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
+-
+- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
+- if (unlikely(!nskb))
+- goto err;
+-
+- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
+- headlen = skb_end_pointer(nskb) - nskb->data;
+- if (headlen > skb_headlen(skb))
+- headlen = skb_headlen(skb);
+- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
+- BUG_ON(ret);
+-
+- ninfo = skb_shinfo(nskb);
+- ninfo->gso_size = skb_shinfo(skb)->gso_size;
+- ninfo->gso_type = skb_shinfo(skb)->gso_type;
+-
+- offset = headlen;
+- len = skb->len - headlen;
+-
+- nskb->len = skb->len;
+- nskb->data_len = len;
+- nskb->truesize += len;
+-
+- while (len) {
+- struct page *page;
+- int copy;
+- int zero;
+-
+- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
+- dump_stack();
+- goto err_free;
+- }
+-
+- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
+- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
+-
+- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
+- if (unlikely(!page))
+- goto err_free;
+-
+- ret = skb_copy_bits(skb, offset, page_address(page), copy);
+- BUG_ON(ret);
+-
+- ninfo->frags[ninfo->nr_frags].page = page;
+- ninfo->frags[ninfo->nr_frags].page_offset = 0;
+- ninfo->frags[ninfo->nr_frags].size = copy;
+- ninfo->nr_frags++;
+-
+- offset += copy;
+- len -= copy;
+- }
+-
+-#ifdef NET_SKBUFF_DATA_USES_OFFSET
+- offset = 0;
+-#else
+- offset = nskb->data - skb->data;
+-#endif
+-
+- nskb->transport_header = skb->transport_header + offset;
+- nskb->network_header = skb->network_header + offset;
+- nskb->mac_header = skb->mac_header + offset;
+-
+- return nskb;
+-
+- err_free:
+- kfree_skb(nskb);
+- err:
+- return NULL;
+-}
+-
+ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct xenvif *vif = netdev_priv(dev);
+@@ -198,21 +120,6 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device
*dev)
+ if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
+ goto drop;
+
+- /*
+- * XXX For now we also copy skbuffs whose head crosses a page
+- * boundary, because netbk_gop_skb can't handle them.
+- */
+- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
+- struct sk_buff *nskb = xenvif_copy_skb(skb);
+- if (unlikely(nskb == NULL))
+- goto drop;
+- /* Copy only the header fields we use in this driver. */
+- nskb->dev = skb->dev;
+- nskb->ip_summed = skb->ip_summed;
+- dev_kfree_skb(skb);
+- skb = nskb;
+- }
+-
+ /* Reserve ring slots for the worst-case number of fragments. */
+ vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
+ xenvif_get(vif);
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index 73e35fd..79b8c30 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -307,12 +307,13 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int
head)
+ */
+ unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
+ {
+- unsigned int count = 1;
+- int i, copy_off = 0;
++ unsigned int count;
++ int i, copy_off;
+
+- BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
++ count = DIV_ROUND_UP(
++ offset_in_page(skb->data)+skb_headlen(skb), PAGE_SIZE);
+
+- copy_off = skb_headlen(skb);
++ copy_off = skb_headlen(skb) % PAGE_SIZE;
+
+ if (skb_shinfo(skb)->gso_size)
+ count++;
+@@ -371,10 +372,10 @@ static struct netbk_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 netbk_gop_frag_copy(struct xenvif *vif,
++static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
+ struct netrx_pending_operations *npo,
+ struct page *page, unsigned long size,
+- unsigned long offset, int head)
++ unsigned long offset, int *head)
+ {
+ struct gnttab_copy *copy_gop;
+ struct netbk_rx_meta *meta;
+@@ -394,12 +395,12 @@ static void netbk_gop_frag_copy(struct xenvif *vif,
+ while (size > 0) {
+ BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
+
+- if (start_new_rx_buffer(npo->copy_off, size, head)) {
++ if (start_new_rx_buffer(npo->copy_off, size, *head)) {
+ /*
+ * Netfront requires there to be some data in the head
+ * buffer.
+ */
+- BUG_ON(head);
++ BUG_ON(*head);
+
+ meta = get_next_rx_buffer(vif, npo);
+ }
+@@ -436,7 +437,13 @@ static void netbk_gop_frag_copy(struct xenvif *vif,
+
+ offset += bytes;
+ size -= bytes;
+- head = 0; /* There must be something in this buffer now. */
+
-+ The corresponding Linux frontend driver is enabled by the
-+ CONFIG_XEN_NETDEV_FRONTEND configuration option.
++ /* Leave a gap for the GSO descriptor. */
++ if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix)
++ vif->rx.req_cons++;
+
-+ The backend driver presents a standard network device
-+ endpoint for each paravirtual network device to the driver
-+ domain network stack. These can then be bridged or routed
-+ etc in order to provide full network connectivity.
++ *head = 0; /* There must be something in this buffer now. */
+
-+ If you are compiling a kernel to run in a Xen network driver
-+ domain (often this is domain 0) you should say Y here. To
-+ compile this driver as a module, chose M here: the module
-+ will be called xen-netback.
+ }
+ }
+
+@@ -460,6 +467,8 @@ static int netbk_gop_skb(struct sk_buff *skb,
+ int i;
+ struct xen_netif_rx_request *req;
+ struct netbk_rx_meta *meta;
++ unsigned char *data;
++ int head = 1;
+ int old_meta_prod;
+
+ old_meta_prod = npo->meta_prod;
+@@ -486,20 +495,25 @@ static int netbk_gop_skb(struct sk_buff *skb,
+ npo->copy_off = 0;
+ npo->copy_gref = req->gref;
+
+- netbk_gop_frag_copy(vif, npo, virt_to_page(skb->data),
+- skb_headlen(skb),
+- offset_in_page(skb->data), 1);
++ data = skb->data;
++ while (data < skb_tail_pointer(skb)) {
++ unsigned int offset = offset_in_page(data);
++ unsigned int len = PAGE_SIZE - offset;
+
+- /* Leave a gap for the GSO descriptor. */
+- if (skb_shinfo(skb)->gso_size && !vif->gso_prefix)
+- vif->rx.req_cons++;
++ if (data + len > skb_tail_pointer(skb))
++ len = skb_tail_pointer(skb) - data;
++
++ netbk_gop_frag_copy(vif, skb, npo,
++ virt_to_page(data), len, offset, &head);
++ data += len;
++ }
+
+ for (i = 0; i < nr_frags; i++) {
+- netbk_gop_frag_copy(vif, npo,
++ netbk_gop_frag_copy(vif, skb, npo,
+ skb_shinfo(skb)->frags[i].page,
+ skb_shinfo(skb)->frags[i].size,
+ skb_shinfo(skb)->frags[i].page_offset,
+- 0);
++ &head);
+ }
- config ISERIES_VETH
- tristate "iSeries Virtual Ethernet driver support"
+ return npo->meta_prod - old_meta_prod;
--
1.7.4
-From 54f3edcf01cab556198efc7d576d9feb4b836569 Mon Sep 17 00:00:00 2001
+From 64702558e140c916ac2aca9bf0ec50521de105ca Mon Sep 17 00:00:00 2001
From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 19 Jan 2011 14:41:55 +0000
-Subject: [PATCH 135/244] xen: netback: drop ethtool drvinfo callback
+Date: Sat, 11 Dec 2010 10:15:50 +0000
+Subject: [PATCH 099/203] xen: netback: Make dependency on PageForeign conditional
-The default provided by the network core is sufficient for our needs.
+When PageForeign is not available we fallback to a copying TX mode.
+
+All uses of PageForeign are now gated with HAVE_XEN_PAGE_FOREIGN, this should
+allow for easier removal of the dependency for upstream, e.g. using unifdef.
Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/net/xen-netback/interface.c | 9 ---------
- 1 files changed, 0 insertions(+), 9 deletions(-)
+ drivers/net/xen-netback/common.h | 4 +
+ drivers/net/xen-netback/interface.c | 2 +
+ drivers/net/xen-netback/netback.c | 279 ++++++++++++++++++++++++++++++-----
+ drivers/net/xen-netback/xenbus.c | 2 +
+ 4 files changed, 252 insertions(+), 35 deletions(-)
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index b998a27..8890825 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -95,7 +95,9 @@ struct xenvif {
+ struct timer_list credit_timeout;
+
+ /* Statistics */
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ int nr_copied_skbs;
++#endif
+ int rx_gso_checksum_fixup;
+
+ /* Miscellaneous private stuff. */
+@@ -109,6 +111,7 @@ struct xenvif {
+ wait_queue_head_t waiting_to_free;
+ };
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ enum {
+ NETBK_DONT_COPY_SKB,
+ NETBK_DELAYED_COPY_SKB,
+@@ -116,6 +119,7 @@ enum {
+ };
+
+ extern int netbk_copy_skb_mode;
++#endif
+
+ #define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+ #define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index c41d93e..28b0832 100644
+index 1bd2eeb..6e11878 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
-@@ -170,13 +170,6 @@ static int netbk_set_tso(struct net_device *dev, u32 data)
- return 0;
- }
-
--static void netbk_get_drvinfo(struct net_device *dev,
-- struct ethtool_drvinfo *info)
--{
-- strcpy(info->driver, "netbk");
-- strcpy(info->bus_info, dev_name(dev->dev.parent));
--}
--
- static const struct netif_stat {
+@@ -272,10 +272,12 @@ static const struct xenvif_stat {
char name[ETH_GSTRING_LEN];
u16 offset;
-@@ -225,8 +218,6 @@ static void netbk_get_strings(struct net_device *dev, u32 stringset,
u8 * data)
- }
-
- static struct ethtool_ops network_ethtool_ops = {
-- .get_drvinfo = netbk_get_drvinfo,
--
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = netbk_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
---
-1.7.4
-
-
-From 02f5acfcf4ad6c982c7eb0c6fd361749ad9140cd Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 16:24:28 +0000
-Subject: [PATCH 136/244] xen: netback: use xen_netbk prefix where appropriate
-
-Do not use net_ of netif_ since these belong to the network core.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/netback.c | 84 ++++++++++++++++++------------------
- 1 files changed, 42 insertions(+), 42 deletions(-)
-
+ } xenvif_stats[] = {
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ {
+ "copied_skbs",
+ offsetof(struct xenvif, nr_copied_skbs)
+ },
++#endif
+ {
+ "rx_gso_checksum_fixup",
+ offsetof(struct xenvif, rx_gso_checksum_fixup)
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 69b4535..6ed4459 100644
+index 79b8c30..265fbdd 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
-@@ -50,7 +50,7 @@
- struct xen_netbk *xen_netbk;
- int xen_netbk_group_nr;
+@@ -40,7 +40,9 @@
--static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx);
-+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
- static void make_tx_response(struct xen_netif *netif,
- struct xen_netif_tx_request *txp,
- s8 st);
-@@ -61,9 +61,9 @@ static struct xen_netif_rx_response *make_rx_response(struct xen_netif
*netif,
- u16 size,
- u16 flags);
+ #include <net/tcp.h>
--static void net_tx_action(unsigned long data);
-+static void xen_netbk_tx_action(unsigned long data);
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ #include <xen/balloon.h>
++#endif
+ #include <xen/events.h>
+ #include <xen/interface/memory.h>
--static void net_rx_action(unsigned long data);
-+static void xen_netbk_rx_action(unsigned long data);
+@@ -59,10 +61,12 @@ struct netbk_rx_meta {
+ int gso_size;
+ };
- static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
- unsigned int idx)
-@@ -78,8 +78,8 @@ static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ struct netbk_tx_pending_inuse {
+ struct list_head list;
+ unsigned long alloc_time;
+ };
++#endif
+
+ #define MAX_PENDING_REQS 256
+
+@@ -91,16 +95,24 @@ struct xen_netbk {
+ struct sk_buff_head tx_queue;
+
+ struct timer_list net_timer;
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ struct timer_list netbk_tx_pending_timer;
++#endif
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ struct page **mmap_pages;
++#else
++ struct page *mmap_pages[MAX_PENDING_REQS];
++#endif
+
+ pending_ring_idx_t pending_prod;
+ pending_ring_idx_t pending_cons;
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ pending_ring_idx_t dealloc_prod;
+ pending_ring_idx_t dealloc_cons;
+
+ struct list_head pending_inuse_head;
++#endif
+ struct list_head net_schedule_list;
+
+ /* Protect the net_schedule_list in netif. */
+@@ -109,13 +121,20 @@ struct xen_netbk {
+ atomic_t netfront_count;
+
+ struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ 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];
++#else
++ struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
++#endif
++
+ u16 pending_ring[MAX_PENDING_REQS];
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ u16 dealloc_ring[MAX_PENDING_REQS];
++#endif
+
+ /*
+ * Each head or fragment can be up to 4096 bytes. Given
+@@ -184,9 +203,10 @@ static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
}
/* extra field used in struct page */
--static inline void netif_set_page_ext(struct page *pg,
-- unsigned int group, unsigned int idx)
-+static inline void set_page_ext(struct page *pg,
-+ unsigned int group, unsigned int idx)
+-static inline void set_page_ext(struct page *pg,
+- unsigned int group, unsigned int idx)
++static inline void set_page_ext(struct page *pg, struct xen_netbk *netbk,
++ unsigned int idx)
{
++ unsigned int group = netbk - xen_netbk;
union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
-@@ -87,8 +87,8 @@ static inline void netif_set_page_ext(struct page *pg,
- pg->mapping = ext.mapping;
+ BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
+@@ -200,8 +220,10 @@ static int get_page_ext(struct page *pg,
+ struct xen_netbk *netbk;
+ unsigned int group, idx;
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ if (!PageForeign(pg))
+ return 0;
++#endif
+
+ group = ext.e.group - 1;
+
+@@ -210,8 +232,10 @@ static int get_page_ext(struct page *pg,
+
+ netbk = &xen_netbk[group];
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ if (netbk->mmap_pages == NULL)
+ return 0;
++#endif
+
+ idx = ext.e.idx;
+
+@@ -248,12 +272,14 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk
*netbk)
+ netbk->pending_prod + netbk->pending_cons;
}
--static int netif_get_page_ext(struct page *pg,
-- unsigned int *pgroup, unsigned int *pidx)
-+static int get_page_ext(struct page *pg,
-+ unsigned int *pgroup, unsigned int *pidx)
- {
- union page_ext ext = { .mapping = pg->mapping };
- struct xen_netbk *netbk;
-@@ -445,11 +445,11 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- struct gnttab_copy *copy_gop;
- struct netbk_rx_meta *meta;
- /*
-- * These variables a used iff netif_get_page_ext returns true,
-+ * These variables a used iff get_page_ext returns true,
- * in which case they are guaranteed to be initialized.
- */
- unsigned int uninitialized_var(group), uninitialized_var(idx);
-- int foreign = netif_get_page_ext(page, &group, &idx);
-+ int foreign = get_page_ext(page, &group, &idx);
- unsigned long bytes;
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ /* Setting this allows the safe use of this driver without netloop. */
+ static int MODPARM_copy_skb = 1;
+ module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
+ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
- /* Data must not cross a page boundary. */
-@@ -627,7 +627,7 @@ struct skb_cb_overlay {
- int meta_slots_used;
- };
+ int netbk_copy_skb_mode;
++#endif
--static void net_rx_action(unsigned long data)
-+static void xen_netbk_rx_action(unsigned long data)
+ static void xen_netbk_kick_thread(struct xen_netbk *netbk)
+ {
+@@ -726,11 +752,13 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff
*skb)
+ xen_netbk_kick_thread(netbk);
+ }
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ static void xen_netbk_tx_pending_timeout(unsigned long data)
{
- struct xen_netif *netif = NULL;
struct xen_netbk *netbk = (struct xen_netbk *)data;
-@@ -915,7 +915,7 @@ static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
- do {
- dp = netbk->dealloc_prod;
+ xen_netbk_kick_thread(netbk);
+ }
++#endif
-- /* Ensure we see all indices enqueued by netif_idx_release(). */
-+ /* Ensure we see all indices enqueued by xen_netbk_idx_release(). */
- smp_rmb();
+ static void xen_netbk_alarm(unsigned long data)
+ {
+@@ -831,6 +859,7 @@ static void tx_credit_callback(unsigned long data)
+ xenvif_schedule_work(vif);
+ }
- while (dc != dp) {
-@@ -1061,11 +1061,11 @@ static int netbk_count_requests(struct xen_netif *netif,
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ static inline int copy_pending_req(struct xen_netbk *netbk,
+ pending_ring_idx_t pending_idx)
+ {
+@@ -838,7 +867,9 @@ static inline int copy_pending_req(struct xen_netbk *netbk,
+ netbk->grant_tx_handle[pending_idx],
+ &netbk->mmap_pages[pending_idx]);
+ }
++#endif
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk *netbk)
+ {
+ struct netbk_tx_pending_inuse *inuse, *n;
+@@ -943,6 +974,7 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
+ list_del_init(&inuse->list);
+ }
+ }
++#endif
+
+ static void netbk_tx_err(struct xenvif *vif,
+ struct xen_netif_tx_request *txp, RING_IDX end)
+@@ -998,15 +1030,37 @@ static int netbk_count_requests(struct xenvif *vif,
+ return -frags;
+ }
+ } while ((txp++)->flags & XEN_NETTXF_more_data);
+-
return frags;
}
--static struct gnttab_map_grant_ref *netbk_get_requests(struct xen_netbk *netbk,
-- struct xen_netif *netif,
-- struct sk_buff *skb,
-- struct xen_netif_tx_request *txp,
-- struct gnttab_map_grant_ref *mop)
-+static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
-+ struct xen_netif *netif,
-+ struct sk_buff *skb,
-+ struct xen_netif_tx_request *txp,
-+ struct gnttab_map_grant_ref *mop)
++#ifndef HAVE_XEN_PAGE_FOREIGN
++static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
++ struct sk_buff *skb,
++ unsigned long pending_idx)
++{
++ struct page *page;
++ page = alloc_page(GFP_KERNEL|__GFP_COLD);
++ if (!page)
++ return NULL;
++ set_page_ext(page, netbk, pending_idx);
++ netbk->mmap_pages[pending_idx] = page;
++ return page;
++}
++#endif
++
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
+ struct xenvif *vif,
+ struct sk_buff *skb,
+ struct xen_netif_tx_request *txp,
+- struct gnttab_map_grant_ref *mop)
++ struct gnttab_map_grant_ref *gop)
++#else
++static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
++ struct xenvif *vif,
++ struct sk_buff *skb,
++ struct xen_netif_tx_request *txp,
++ struct gnttab_copy *gop)
++#endif
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
-@@ -1096,9 +1096,9 @@ static struct gnttab_map_grant_ref *netbk_get_requests(struct
xen_netbk *netbk,
- return mop;
+@@ -1017,16 +1071,39 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
+ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+
+ for (i = start; i < shinfo->nr_frags; i++, txp++) {
++#ifndef HAVE_XEN_PAGE_FOREIGN
++ struct page *page;
++#endif
+ pending_ring_idx_t index;
+ struct pending_tx_info *pending_tx_info =
+ netbk->pending_tx_info;
+
+ index = pending_index(netbk->pending_cons++);
+ pending_idx = netbk->pending_ring[index];
+-
+- gnttab_set_map_op(mop++, idx_to_kaddr(netbk, pending_idx),
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ gnttab_set_map_op(gop++, idx_to_kaddr(netbk, pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+ txp->gref, vif->domid);
++#else
++ page = xen_netbk_alloc_page(netbk, skb, pending_idx);
++ if (!page)
++ return NULL;
++
++ netbk->mmap_pages[pending_idx] = page;
++
++ gop->source.u.ref = txp->gref;
++ gop->source.domid = vif->domid;
++ gop->source.offset = txp->offset;
++
++ gop->dest.u.gmfn = virt_to_mfn(page_address(page));
++ gop->dest.domid = DOMID_SELF;
++ gop->dest.offset = txp->offset;
++
++ gop->len = txp->size;
++ gop->flags = GNTCOPY_source_gref;
++
++ gop++;
++#endif
+
+ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
+ xenvif_get(vif);
+@@ -1034,14 +1111,24 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
+ frags[i].page = (void *)pending_idx;
+ }
+
+- return mop;
++ return gop;
}
--static int netbk_tx_check_mop(struct xen_netbk *netbk,
-- struct sk_buff *skb,
-- struct gnttab_map_grant_ref **mopp)
-+static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+-static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
++#ifdef HAVE_XEN_PAGE_FOREIGN
++static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
+ struct sk_buff *skb,
+- struct gnttab_map_grant_ref **mopp)
++ struct gnttab_map_grant_ref **gopp)
++#else
++static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
+ struct sk_buff *skb,
-+ struct gnttab_map_grant_ref **mopp)
++ struct gnttab_copy **gopp)
++#endif
{
- struct gnttab_map_grant_ref *mop = *mopp;
+- struct gnttab_map_grant_ref *mop = *mopp;
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ struct gnttab_map_grant_ref *gop = *gopp;
++#else
++ struct gnttab_copy *gop = *gopp;
++#endif
int pending_idx = *((u16 *)skb->data);
-@@ -1145,7 +1145,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
- netbk->grant_tx_handle[pending_idx] = mop->handle;
+ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
+ struct xenvif *vif = pending_tx_info[pending_idx].vif;
+@@ -1051,7 +1138,7 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+ int i, err, start;
+
+ /* Check status of header. */
+- err = mop->status;
++ err = gop->status;
+ if (unlikely(err)) {
+ pending_ring_idx_t index;
+ index = pending_index(netbk->pending_prod++);
+@@ -1059,11 +1146,13 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+ netbk->pending_ring[index] = pending_idx;
+ xenvif_put(vif);
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ } else {
+ set_phys_to_machine(
+ __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
+- FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
+- netbk->grant_tx_handle[pending_idx] = mop->handle;
++ FOREIGN_FRAME(gop->dev_bus_addr >> PAGE_SHIFT));
++ netbk->grant_tx_handle[pending_idx] = gop->handle;
++#endif
+ }
+
+ /* Skip first skb fragment if it is on same page as header fragment. */
+@@ -1076,14 +1165,16 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+ pending_idx = (unsigned long)shinfo->frags[i].page;
+
+ /* Check error status: if okay then remember grant handle. */
+- newerr = (++mop)->status;
++ newerr = (++gop)->status;
+ if (likely(!newerr)) {
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ unsigned long addr;
+ addr = idx_to_kaddr(netbk, pending_idx);
+ set_phys_to_machine(
+ __pa(addr)>>PAGE_SHIFT,
+- FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
+- netbk->grant_tx_handle[pending_idx] = mop->handle;
++ FOREIGN_FRAME(gop->dev_bus_addr>>PAGE_SHIFT));
++ netbk->grant_tx_handle[pending_idx] = gop->handle;
++#endif
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
-- netif_idx_release(netbk, pending_idx);
-+ xen_netbk_idx_release(netbk, pending_idx);
- continue;
- }
+ xen_netbk_idx_release(netbk, pending_idx);
+@@ -1113,7 +1204,7 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+ err = newerr;
+ }
-@@ -1162,10 +1162,10 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
+- *mopp = mop + 1;
++ *gopp = gop + 1;
+ return err;
+ }
- /* First error: invalidate header and preceding fragments. */
- pending_idx = *((u16 *)skb->data);
-- netif_idx_release(netbk, pending_idx);
-+ xen_netbk_idx_release(netbk, pending_idx);
- for (j = start; j < i; j++) {
- pending_idx = (unsigned long)shinfo->frags[i].page;
-- netif_idx_release(netbk, pending_idx);
-+ xen_netbk_idx_release(netbk, pending_idx);
- }
+@@ -1129,10 +1220,11 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
+ unsigned long pending_idx;
- /* Remember the error: invalidate all subsequent fragments. */
-@@ -1176,7 +1176,7 @@ static int netbk_tx_check_mop(struct xen_netbk *netbk,
- return err;
+ pending_idx = (unsigned long)frag->page;
+-
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ netbk->pending_inuse[pending_idx].alloc_time = jiffies;
+ list_add_tail(&netbk->pending_inuse[pending_idx].list,
+ &netbk->pending_inuse_head);
++#endif
+
+ txp = &netbk->pending_tx_info[pending_idx].req;
+ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
+@@ -1142,6 +1234,10 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
+ skb->len += txp->size;
+ skb->data_len += txp->size;
+ skb->truesize += txp->size;
++
++ /* Take an extra reference to offset xen_netbk_idx_release */
++ get_page(netbk->mmap_pages[pending_idx]);
++ xen_netbk_idx_release(netbk, pending_idx);
+ }
}
--static void netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
-+static void xen_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;
-@@ -1359,7 +1359,7 @@ static bool tx_credit_exceeded(struct xen_netif *netif, unsigned
size)
+@@ -1300,18 +1396,24 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned
size)
return false;
}
--static unsigned net_tx_build_mops(struct xen_netbk *netbk)
-+static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+-static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
++static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
{
- struct gnttab_map_grant_ref *mop;
+- struct gnttab_map_grant_ref *mop;
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ struct gnttab_map_grant_ref *gop = netbk->tx_map_ops, *request_gop;
++#else
++ struct gnttab_copy *gop = netbk->tx_copy_ops, *request_gop;
++#endif
struct sk_buff *skb;
-@@ -1493,7 +1493,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
+ int ret;
+
+- mop = netbk->tx_map_ops;
+ while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list)) {
+ struct xenvif *vif;
+ struct xen_netif_tx_request txreq;
+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
++#ifndef HAVE_XEN_PAGE_FOREIGN
++ struct page *page;
++#endif
+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+ u16 pending_idx;
+ RING_IDX idx;
+@@ -1408,10 +1510,35 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ }
+ }
+
+- gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ gnttab_set_map_op(gop, idx_to_kaddr(netbk, pending_idx),
+ GNTMAP_host_map | GNTMAP_readonly,
+ txreq.gref, vif->domid);
+- mop++;
++ gop++;
++#else
++ /* XXX could copy straight to head */
++ page = xen_netbk_alloc_page(netbk, skb, pending_idx);
++ if (!page) {
++ kfree_skb(skb);
++ netbk_tx_err(vif, &txreq, idx);
++ continue;
++ }
++
++ netbk->mmap_pages[pending_idx] = page;
++
++ gop->source.u.ref = txreq.gref;
++ gop->source.domid = vif->domid;
++ gop->source.offset = txreq.offset;
++
++ gop->dest.u.gmfn = virt_to_mfn(page_address(page));
++ gop->dest.domid = DOMID_SELF;
++ gop->dest.offset = txreq.offset;
++
++ gop->len = txreq.size;
++ gop->flags = GNTCOPY_source_gref;
++
++ gop++;
++#endif
+
+ memcpy(&netbk->pending_tx_info[pending_idx].req,
+ &txreq, sizeof(txreq));
+@@ -1434,24 +1561,43 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
netbk->pending_cons++;
-- mop = netbk_get_requests(netbk, netif, skb, txfrags, mop);
-+ mop = xen_netbk_get_requests(netbk, netif, skb, txfrags, mop);
+- mop = xen_netbk_get_requests(netbk, vif, skb, txfrags, mop);
++ request_gop = xen_netbk_get_requests(netbk, vif,
++ skb, txfrags, gop);
++ if (request_gop == NULL) {
++ kfree_skb(skb);
++ netbk_tx_err(vif, &txreq, idx);
++ continue;
++ }
++ gop = request_gop;
- netif->tx.req_cons = idx;
- netif_schedule_work(netif);
-@@ -1505,7 +1505,7 @@ static unsigned net_tx_build_mops(struct xen_netbk *netbk)
- return mop - netbk->tx_map_ops;
+ vif->tx.req_cons = idx;
+ xenvif_schedule_work(vif);
+
+- if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ if ((gop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
+ break;
++#else
++ if ((gop-netbk->tx_copy_ops) >= ARRAY_SIZE(netbk->tx_copy_ops))
++ break;
++#endif
+ }
+
+- return mop - netbk->tx_map_ops;
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ return gop - netbk->tx_map_ops;
++#else
++ return gop - netbk->tx_copy_ops;
++#endif
}
--static void net_tx_submit(struct xen_netbk *netbk)
-+static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
{
- struct gnttab_map_grant_ref *mop;
+- struct gnttab_map_grant_ref *mop;
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ struct gnttab_map_grant_ref *gop = netbk->tx_map_ops;
++#else
++ struct gnttab_copy *gop = netbk->tx_copy_ops;
++#endif
struct sk_buff *skb;
-@@ -1522,7 +1522,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
+
+- mop = netbk->tx_map_ops;
+ while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
+ struct xen_netif_tx_request *txp;
+ struct xenvif *vif;
+@@ -1463,7 +1609,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
txp = &netbk->pending_tx_info[pending_idx].req;
/* Check the remap error code. */
-- if (unlikely(netbk_tx_check_mop(netbk, skb, &mop))) {
-+ if (unlikely(xen_netbk_tx_check_mop(netbk, skb, &mop))) {
+- if (unlikely(xen_netbk_tx_check_mop(netbk, skb, &mop))) {
++ if (unlikely(xen_netbk_tx_check_gop(netbk, skb, &gop))) {
pr_debug("netback grant failed.\n");
skb_shinfo(skb)->nr_frags = 0;
kfree_skb(skb);
-@@ -1539,7 +1539,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
- txp->size -= data_len;
- } else {
- /* Schedule a response immediately. */
-- netif_idx_release(netbk, pending_idx);
-+ xen_netbk_idx_release(netbk, pending_idx);
+@@ -1509,12 +1655,14 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ continue;
}
- if (txp->flags & XEN_NETTXF_csum_blank)
-@@ -1547,7 +1547,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
- else if (txp->flags & XEN_NETTXF_data_validated)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-- netbk_fill_frags(netbk, skb);
-+ xen_netbk_fill_frags(netbk, skb);
-
- /*
- * If the initial fragment was < PKT_PROT_LEN then
-@@ -1584,7 +1584,7 @@ static void net_tx_submit(struct xen_netbk *netbk)
- }
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
+ unlikely(skb_linearize(skb))) {
+ pr_debug("Can't linearize skb in net_tx_action.\n");
+ kfree_skb(skb);
+ continue;
+ }
++#endif
+ vif->stats.rx_bytes += skb->len;
+ vif->stats.rx_packets++;
+@@ -1527,21 +1675,31 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
/* Called after netfront has transmitted */
--static void net_tx_action(unsigned long data)
-+static void xen_netbk_tx_action(unsigned long data)
+ static void xen_netbk_tx_action(struct xen_netbk *netbk)
{
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- unsigned nr_mops;
-@@ -1592,7 +1592,7 @@ static void net_tx_action(unsigned long data)
+- unsigned nr_mops;
++ unsigned nr_gops;
+ int ret;
- net_tx_action_dealloc(netbk);
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ xen_netbk_tx_action_dealloc(netbk);
++#endif
-- nr_mops = net_tx_build_mops(netbk);
-+ nr_mops = xen_netbk_tx_build_mops(netbk);
+- nr_mops = xen_netbk_tx_build_mops(netbk);
++ nr_gops = xen_netbk_tx_build_gops(netbk);
- if (nr_mops == 0)
+- if (nr_mops == 0)
++#ifdef HAVE_XEN_PAGE_FOREIGN
++ if (nr_gops == 0)
goto out;
-@@ -1601,7 +1601,7 @@ static void net_tx_action(unsigned long data)
- netbk->tx_map_ops, nr_mops);
- BUG_ON(ret);
-
-- net_tx_submit(netbk);
-+ xen_netbk_tx_submit(netbk);
- out:
- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
- !list_empty(&netbk->pending_inuse_head)) {
-@@ -1614,7 +1614,7 @@ out:
- }
- }
-
--static void netif_idx_release(struct xen_netbk *netbk, u16 pending_idx)
-+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
- {
- static DEFINE_SPINLOCK(_lock);
- unsigned long flags;
-@@ -1634,12 +1634,12 @@ static void netif_idx_release(struct xen_netbk *netbk, u16
pending_idx)
- static void netif_page_release(struct page *page, unsigned int order)
- {
- unsigned int group, idx;
-- int foreign = netif_get_page_ext(page, &group, &idx);
-+ int foreign = get_page_ext(page, &group, &idx);
-
- BUG_ON(!foreign);
- BUG_ON(order);
-
-- netif_idx_release(&xen_netbk[group], idx);
-+ xen_netbk_idx_release(&xen_netbk[group], idx);
- }
-
- irqreturn_t netif_be_int(int irq, void *dev_id)
-@@ -1726,7 +1726,7 @@ static inline int tx_work_todo(struct xen_netbk *netbk)
- return 0;
- }
-
--static int netbk_action_thread(void *data)
-+static int xen_netbk_action_thread(void *data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- while (!kthread_should_stop()) {
-@@ -1740,10 +1740,10 @@ static int netbk_action_thread(void *data)
- break;
-
- if (rx_work_todo(netbk))
-- net_rx_action((unsigned long)netbk);
-+ xen_netbk_rx_action((unsigned long)netbk);
-
- if (tx_work_todo(netbk))
-- net_tx_action((unsigned long)netbk);
-+ xen_netbk_tx_action((unsigned long)netbk);
- }
-
- return 0;
-@@ -1794,7 +1794,7 @@ static int __init netback_init(void)
- 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);
-+ set_page_ext(page, group, i);
- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
- }
-
-@@ -1806,7 +1806,7 @@ static int __init netback_init(void)
- if (MODPARM_netback_kthread) {
- init_waitqueue_head(&netbk->kthread.netbk_action_wq);
- netbk->kthread.task =
-- kthread_create(netbk_action_thread,
-+ kthread_create(xen_netbk_action_thread,
- (void *)netbk,
- "netback/%u", group);
-
-@@ -1824,10 +1824,10 @@ static int __init netback_init(void)
- }
- } else {
- tasklet_init(&netbk->tasklet.net_tx_tasklet,
-- net_tx_action,
-+ xen_netbk_tx_action,
- (unsigned long)netbk);
- tasklet_init(&netbk->tasklet.net_rx_tasklet,
-- net_rx_action,
-+ xen_netbk_rx_action,
- (unsigned long)netbk);
- }
-
---
-1.7.4
-
-
-From 0feb757d74b864a7d8d00fb57a8c523bd3081d42 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 17:00:54 +0000
-Subject: [PATCH 137/244] xen: netback: refactor to make all xen_netbk knowledge internal
to netback.c
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/common.h | 95 +---------------------------
- drivers/net/xen-netback/interface.c | 28 +--------
- drivers/net/xen-netback/netback.c | 117 ++++++++++++++++++++++++++++++++++-
- 3 files changed, 120 insertions(+), 120 deletions(-)
-
-diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-index 2d727a0..32a9e4f 100644
---- a/drivers/net/xen-netback/common.h
-+++ b/drivers/net/xen-netback/common.h
-@@ -177,97 +177,8 @@ static inline int netbk_can_sg(struct net_device *dev)
- return netif->can_sg;
- }
-
--struct pending_tx_info {
-- struct xen_netif_tx_request req;
-- struct xen_netif *netif;
--};
--typedef unsigned int pending_ring_idx_t;
--
--struct netbk_rx_meta {
-- int id;
-- int size;
-- int gso_size;
--};
--
--struct netbk_tx_pending_inuse {
-- struct list_head list;
-- unsigned long alloc_time;
--};
--
--#define MAX_PENDING_REQS 256
--
--#define MAX_BUFFER_OFFSET PAGE_SIZE
--
--/* extra field used in struct page */
--union page_ext {
-- struct {
--#if BITS_PER_LONG < 64
--#define IDX_WIDTH 8
--#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
-- unsigned int group:GROUP_WIDTH;
-- unsigned int idx:IDX_WIDTH;
--#else
-- unsigned int group, idx;
--#endif
-- } e;
-- void *mapping;
--};
--
--struct xen_netbk {
-- union {
-- struct {
-- struct tasklet_struct net_tx_tasklet;
-- struct tasklet_struct net_rx_tasklet;
-- } tasklet;
--
-- struct {
-- wait_queue_head_t netbk_action_wq;
-- struct task_struct *task;
-- } kthread;
-- };
--
-- struct sk_buff_head rx_queue;
-- struct sk_buff_head tx_queue;
--
-- struct timer_list net_timer;
-- struct timer_list netbk_tx_pending_timer;
--
-- struct page **mmap_pages;
--
-- 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 net_schedule_list;
--
-- /* Protect the net_schedule_list in netif. */
-- spinlock_t net_schedule_list_lock;
--
-- atomic_t netfront_count;
--
-- 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];
--
-- /*
-- * Each head or fragment can be up to 4096 bytes. Given
-- * MAX_BUFFER_OFFSET of 4096 the worst case is that each
-- * head/fragment uses 2 copy operation.
-- */
-- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
-- unsigned char rx_notify[NR_IRQS];
-- u16 notify_list[NET_RX_RING_SIZE];
-- struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
--};
--
--extern struct xen_netbk *xen_netbk;
--extern int xen_netbk_group_nr;
-+/* (De)Register a netif with the netback backend. */
-+void xen_netbk_add_netif(struct xen_netif *netif);
-+void xen_netbk_remove_netif(struct xen_netif *netif);
-
- #endif /* __XEN_NETBACK__COMMON_H__ */
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index 28b0832..54ae275 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -38,33 +38,9 @@
-
- #define NETBK_QUEUE_LENGTH 32
-
--static void netbk_add_netif(struct xen_netbk *netbk, int group_nr,
-- struct xen_netif *netif)
--{
-- int i;
-- int min_netfront_count;
-- int min_group = 0;
-- min_netfront_count = atomic_read(&netbk[0].netfront_count);
-- for (i = 0; i < group_nr; i++) {
-- int netfront_count = atomic_read(&netbk[i].netfront_count);
-- if (netfront_count < min_netfront_count) {
-- min_group = i;
-- min_netfront_count = netfront_count;
-- }
-- }
--
-- netif->group = min_group;
-- atomic_inc(&netbk[netif->group].netfront_count);
--}
--
--static void netbk_remove_netif(struct xen_netbk *netbk, struct xen_netif *netif)
--{
-- atomic_dec(&netbk[netif->group].netfront_count);
--}
-
- static void __netif_up(struct xen_netif *netif)
- {
-- netbk_add_netif(xen_netbk, xen_netbk_group_nr, netif);
-+ xen_netbk_add_netif(netif);
- enable_irq(netif->irq);
- netif_schedule_work(netif);
- }
-@@ -73,7 +49,7 @@ static void __netif_down(struct xen_netif *netif)
- {
- disable_irq(netif->irq);
- netif_deschedule_work(netif);
-- netbk_remove_netif(xen_netbk, netif);
-+ xen_netbk_remove_netif(netif);
- }
-
- static int net_open(struct net_device *dev)
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 6ed4459..d10ddbc 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -47,8 +47,121 @@
- #include <asm/xen/hypercall.h>
- #include <asm/xen/page.h>
-
--struct xen_netbk *xen_netbk;
--int xen_netbk_group_nr;
-+struct pending_tx_info {
-+ struct xen_netif_tx_request req;
-+ struct xen_netif *netif;
-+};
-+typedef unsigned int pending_ring_idx_t;
-+
-+struct netbk_rx_meta {
-+ int id;
-+ int size;
-+ int gso_size;
-+};
-+
-+struct netbk_tx_pending_inuse {
-+ struct list_head list;
-+ unsigned long alloc_time;
-+};
-+
-+#define MAX_PENDING_REQS 256
-+
-+#define MAX_BUFFER_OFFSET PAGE_SIZE
-+
-+/* extra field used in struct page */
-+union page_ext {
-+ struct {
-+#if BITS_PER_LONG < 64
-+#define IDX_WIDTH 8
-+#define GROUP_WIDTH (BITS_PER_LONG - IDX_WIDTH)
-+ unsigned int group:GROUP_WIDTH;
-+ unsigned int idx:IDX_WIDTH;
-+#else
-+ unsigned int group, idx;
-+#endif
-+ } e;
-+ void *mapping;
-+};
-+
-+struct xen_netbk {
-+ union {
-+ struct {
-+ struct tasklet_struct net_tx_tasklet;
-+ struct tasklet_struct net_rx_tasklet;
-+ } tasklet;
-+
-+ struct {
-+ wait_queue_head_t netbk_action_wq;
-+ struct task_struct *task;
-+ } kthread;
-+ };
-+
-+ struct sk_buff_head rx_queue;
-+ struct sk_buff_head tx_queue;
-+
-+ struct timer_list net_timer;
-+ struct timer_list netbk_tx_pending_timer;
-+
-+ struct page **mmap_pages;
-+
-+ 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 net_schedule_list;
-+
-+ /* Protect the net_schedule_list in netif. */
-+ spinlock_t net_schedule_list_lock;
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+- netbk->tx_map_ops, nr_mops);
++ netbk->tx_map_ops, nr_gops);
++#else
++ if (nr_gops == 0)
++ return;
++ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy,
++ netbk->tx_copy_ops, nr_gops);
++#endif
+ BUG_ON(ret);
+
+ xen_netbk_tx_submit(netbk);
+
-+ atomic_t netfront_count;
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ out:
+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+ !list_empty(&netbk->pending_inuse_head)) {
+@@ -1552,8 +1710,10 @@ out:
+ mod_timer(&netbk->netbk_tx_pending_timer,
+ oldest->alloc_time + HZ);
+ }
++#endif
+ }
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+ {
+ static DEFINE_SPINLOCK(_lock);
+@@ -1581,6 +1741,33 @@ static void netif_page_release(struct page *page, unsigned int
order)
+
+ xen_netbk_idx_release(&xen_netbk[group], idx);
+ }
++#else
++static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
++{
++ struct xenvif *vif;
++ struct pending_tx_info *pending_tx_info;
++ pending_ring_idx_t 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];
++ /* Already complete? */
++ if (netbk->mmap_pages[pending_idx] == NULL)
++ return;
+
-+ grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
-+ u16 pending_ring[MAX_PENDING_REQS];
-+ u16 dealloc_ring[MAX_PENDING_REQS];
++ pending_tx_info = &netbk->pending_tx_info[pending_idx];
+
-+ /*
-+ * Each head or fragment can be up to 4096 bytes. Given
-+ * MAX_BUFFER_OFFSET of 4096 the worst case is that each
-+ * head/fragment uses 2 copy operation.
-+ */
-+ struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
-+ unsigned char rx_notify[NR_IRQS];
-+ u16 notify_list[NET_RX_RING_SIZE];
-+ struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
-+};
++ vif = pending_tx_info->vif;
+
-+static struct xen_netbk *xen_netbk;
-+static int xen_netbk_group_nr;
++ make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY);
+
-+void xen_netbk_add_netif(struct xen_netif *netif)
-+{
-+ int i;
-+ int min_netfront_count;
-+ int min_group = 0;
-+ min_netfront_count = atomic_read(&xen_netbk[0].netfront_count);
-+ for (i = 0; i < xen_netbk_group_nr; i++) {
-+ int netfront_count = atomic_read(&xen_netbk[i].netfront_count);
-+ if (netfront_count < min_netfront_count) {
-+ min_group = i;
-+ min_netfront_count = netfront_count;
-+ }
-+ }
++ index = pending_index(netbk->pending_prod++);
++ netbk->pending_ring[index] = pending_idx;
+
-+ netif->group = min_group;
-+ atomic_inc(&xen_netbk[netif->group].netfront_count);
-+}
++ xenvif_put(vif);
+
-+void xen_netbk_remove_netif(struct xen_netif *netif)
-+{
-+ atomic_dec(&xen_netbk[netif->group].netfront_count);
++ netbk->mmap_pages[pending_idx]->mapping = 0;
++ put_page(netbk->mmap_pages[pending_idx]);
++ netbk->mmap_pages[pending_idx] = NULL;
+}
++#endif
- static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
- static void make_tx_response(struct xen_netif *netif,
+ static void make_tx_response(struct xenvif *vif,
+ struct xen_netif_tx_request *txp,
+@@ -1633,12 +1820,14 @@ static inline int rx_work_todo(struct xen_netbk *netbk)
+
+ static inline int tx_work_todo(struct xen_netbk *netbk)
+ {
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ if (netbk->dealloc_cons != netbk->dealloc_prod)
+ return 1;
+
+ if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+ !list_empty(&netbk->pending_inuse_head))
+ return 1;
++#endif
+
+ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list))
+@@ -1673,7 +1862,9 @@ static int xen_netbk_kthread(void *data)
+ static int __init netback_init(void)
+ {
+ int i;
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ struct page *page;
++#endif
+ int rc = 0;
+ int group;
+
+@@ -1697,11 +1888,14 @@ static int __init netback_init(void)
+ netbk->net_timer.data = (unsigned long)netbk;
+ netbk->net_timer.function = xen_netbk_alarm;
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ init_timer(&netbk->netbk_tx_pending_timer);
+ netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
+ netbk->netbk_tx_pending_timer.function =
+ xen_netbk_tx_pending_timeout;
++#endif
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ netbk->mmap_pages =
+ alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+ if (!netbk->mmap_pages) {
+@@ -1715,9 +1909,10 @@ static int __init netback_init(void)
+ for (i = 0; i < MAX_PENDING_REQS; i++) {
+ page = netbk->mmap_pages[i];
+ SetPageForeign(page, netif_page_release);
+- set_page_ext(page, group, i);
++ set_page_ext(page, netbk, i);
+ INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ }
++#endif
+
+ netbk->pending_cons = 0;
+ netbk->pending_prod = MAX_PENDING_REQS;
+@@ -1731,9 +1926,11 @@ static int __init netback_init(void)
+
+ if (IS_ERR(netbk->task)) {
+ printk(KERN_ALERT "kthread_run() fails at netback\n");
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ free_empty_pages_and_pagevec(netbk->mmap_pages,
+ MAX_PENDING_REQS);
+ del_timer(&netbk->netbk_tx_pending_timer);
++#endif
+ del_timer(&netbk->net_timer);
+ rc = PTR_ERR(netbk->task);
+ goto failed_init;
+@@ -1741,7 +1938,9 @@ static int __init netback_init(void)
+
+ kthread_bind(netbk->task, group);
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ INIT_LIST_HEAD(&netbk->pending_inuse_head);
++#endif
+ INIT_LIST_HEAD(&netbk->net_schedule_list);
+
+ spin_lock_init(&netbk->net_schedule_list_lock);
+@@ -1751,6 +1950,7 @@ static int __init netback_init(void)
+ wake_up_process(netbk->task);
+ }
+
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+ if (MODPARM_copy_skb) {
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
+@@ -1759,6 +1959,7 @@ static int __init netback_init(void)
+ else
+ netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ }
++#endif
+
+ rc = xenvif_xenbus_init();
+ if (rc)
+@@ -1769,9 +1970,17 @@ static int __init netback_init(void)
+ failed_init:
+ for (i = 0; i < group; i++) {
+ struct xen_netbk *netbk = &xen_netbk[i];
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ free_empty_pages_and_pagevec(netbk->mmap_pages,
+ MAX_PENDING_REQS);
+ del_timer(&netbk->netbk_tx_pending_timer);
++#else
++ int j;
++ for (j = 0; j < MAX_PENDING_REQS; j++) {
++ if (netbk->mmap_pages[i])
++ __free_page(netbk->mmap_pages[i]);
++ }
++#endif
+ del_timer(&netbk->net_timer);
+ kthread_stop(netbk->task);
+ }
+diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
+index e854420..d56b1ee 100644
+--- a/drivers/net/xen-netback/xenbus.c
++++ b/drivers/net/xen-netback/xenbus.c
+@@ -74,8 +74,10 @@ static int netback_probe(struct xenbus_device *dev,
+ dev_set_drvdata(&dev->dev, be);
+
+ sg = 1;
++#ifdef HAVE_XEN_PAGE_FOREIGN
+ if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
+ sg = 0;
++#endif
+
+ do {
+ err = xenbus_transaction_start(&xbt);
--
1.7.4
-From 651ae17d2aaedb2adca37c7b7c9eda195c3cad6b Mon Sep 17 00:00:00 2001
+From 33bf93e7541633b7667bf9390107cf8b2b67968a Mon Sep 17 00:00:00 2001
From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Thu, 20 Jan 2011 17:08:23 +0000
-Subject: [PATCH 138/244] xen: netback: use xenvif_ prefix where appropriate
+Date: Wed, 19 Jan 2011 09:43:44 +0000
+Subject: [PATCH 100/203] xen: netback: completely drop foreign page support
-Avoids use of netif_ prefix which belongs to the networking core.
+for i in drivers/net/xen-netback/*.[ch] ; do
+ echo $i
+ ./scripts/unifdef -B -UHAVE_XEN_PAGE_FOREIGN $i > $i.unifdef
+ mv $i.unifdef $i
+done
Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/net/xen-netback/common.h | 65 +++---
- drivers/net/xen-netback/interface.c | 316 ++++++++++++++--------------
- drivers/net/xen-netback/netback.c | 394 +++++++++++++++++------------------
- drivers/net/xen-netback/xenbus.c | 72 +++----
- 4 files changed, 422 insertions(+), 425 deletions(-)
+ drivers/net/xen-netback/common.h | 13 --
+ drivers/net/xen-netback/interface.c | 6 -
+ drivers/net/xen-netback/netback.c | 376 -----------------------------------
+ drivers/net/xen-netback/xenbus.c | 4 -
+ 4 files changed, 0 insertions(+), 399 deletions(-)
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-index 32a9e4f..f6da94b 100644
+index 8890825..03196ab 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
-@@ -46,7 +46,7 @@
- #include <xen/grant_table.h>
- #include <xen/xenbus.h>
-
--struct xen_netif {
-+struct xenvif {
- /* Unique identifier for this interface. */
- domid_t domid;
- int group;
-@@ -79,7 +79,7 @@ struct xen_netif {
- /* Internal feature information. */
- u8 can_queue:1; /* can queue packets for receiver? */
-
-- /* Allow netif_be_start_xmit() to peek ahead in the rx request
-+ /* Allow xenvif_start_xmit() to peek ahead in the rx request
- * ring. This is a prediction of what rx_req_cons will be once
- * all queued skbs are put on the ring. */
- RING_IDX rx_req_cons_peek;
-@@ -111,9 +111,9 @@ struct xen_netif {
- * immediately be called, which can cause packet loss; also the etherbridge
- * can be rather lazy in activating its port).
- */
--#define netback_carrier_on(netif) ((netif)->carrier = 1)
--#define netback_carrier_off(netif) ((netif)->carrier = 0)
--#define netback_carrier_ok(netif) ((netif)->carrier)
-+#define xenvif_carrier_on(xenvif) ((xenvif)->carrier = 1)
-+#define xenvif_carrier_off(xenvif) ((xenvif)->carrier = 0)
-+#define xenvif_carrier_ok(xenvif) ((xenvif)->carrier)
-
- enum {
- NETBK_DONT_COPY_SKB,
-@@ -125,7 +125,7 @@ extern int netbk_copy_skb_mode;
-
- struct backend_info {
- struct xenbus_device *dev;
-- struct xen_netif *netif;
-+ struct xenvif *vif;
- enum xenbus_state frontend_state;
- struct xenbus_watch hotplug_status_watch;
- int have_hotplug_status_watch:1;
-@@ -134,51 +134,52 @@ struct backend_info {
- #define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
- #define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-
--void netif_disconnect(struct xen_netif *netif);
-+void xenvif_disconnect(struct xenvif *vif);
-
--void netif_set_features(struct xen_netif *netif);
--struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-- unsigned int handle);
--int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
-- unsigned long rx_ring_ref, unsigned int evtchn);
-+void xenvif_set_features(struct xenvif *vif);
-+struct xenvif *xenvif_alloc(struct device *parent,
-+ domid_t domid,
-+ unsigned int handle);
-+int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
-+ unsigned long rx_ring_ref, unsigned int evtchn);
+@@ -95,9 +95,6 @@ struct xenvif {
+ struct timer_list credit_timeout;
--static inline void netif_get(struct xen_netif *netif)
-+static inline void xenvif_get(struct xenvif *vif)
- {
-- atomic_inc(&netif->refcnt);
-+ atomic_inc(&vif->refcnt);
- }
+ /* Statistics */
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- int nr_copied_skbs;
+-#endif
+ int rx_gso_checksum_fixup;
--static inline void netif_put(struct xen_netif *netif)
-+static inline void xenvif_put(struct xenvif *vif)
- {
-- if (atomic_dec_and_test(&netif->refcnt))
-- wake_up(&netif->waiting_to_free);
-+ if (atomic_dec_and_test(&vif->refcnt))
-+ wake_up(&vif->waiting_to_free);
- }
+ /* Miscellaneous private stuff. */
+@@ -111,16 +108,6 @@ struct xenvif {
+ wait_queue_head_t waiting_to_free;
+ };
--int netif_xenbus_init(void);
-+int xenvif_xenbus_init(void);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-enum {
+- NETBK_DONT_COPY_SKB,
+- NETBK_DELAYED_COPY_SKB,
+- NETBK_ALWAYS_COPY_SKB,
+-};
+-
+-extern int netbk_copy_skb_mode;
+-#endif
+-
+ #define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+ #define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
--#define netif_schedulable(netif) \
-- (netif_running((netif)->dev) && netback_carrier_ok(netif))
-+#define xenvif_schedulable(vif) \
-+ (netif_running((vif)->dev) && xenvif_carrier_ok(vif))
+diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
+index 6e11878..98a992d 100644
+--- a/drivers/net/xen-netback/interface.c
++++ b/drivers/net/xen-netback/interface.c
+@@ -272,12 +272,6 @@ static const struct xenvif_stat {
+ char name[ETH_GSTRING_LEN];
+ u16 offset;
+ } xenvif_stats[] = {
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- {
+- "copied_skbs",
+- offsetof(struct xenvif, nr_copied_skbs)
+- },
+-#endif
+ {
+ "rx_gso_checksum_fixup",
+ offsetof(struct xenvif, rx_gso_checksum_fixup)
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index 265fbdd..fbddf3d 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -40,9 +40,6 @@
--void netif_schedule_work(struct xen_netif *netif);
--void netif_deschedule_work(struct xen_netif *netif);
-+void xenvif_schedule_work(struct xenvif *vif);
-+void xenvif_deschedule_work(struct xenvif *vif);
+ #include <net/tcp.h>
--int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
--struct net_device_stats *netif_be_get_stats(struct net_device *dev);
--irqreturn_t netif_be_int(int irq, void *dev_id);
-+int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+struct net_device_stats *xenvif_get_stats(struct net_device *dev);
-+irqreturn_t xenvif_interrupt(int irq, void *dev_id);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-#include <xen/balloon.h>
+-#endif
+ #include <xen/events.h>
+ #include <xen/interface/memory.h>
- static inline int netbk_can_queue(struct net_device *dev)
- {
-- struct xen_netif *netif = netdev_priv(dev);
-- return netif->can_queue;
-+ struct xenvif *vif = netdev_priv(dev);
-+ return vif->can_queue;
- }
+@@ -61,13 +58,6 @@ struct netbk_rx_meta {
+ int gso_size;
+ };
- static inline int netbk_can_sg(struct net_device *dev)
- {
-- struct xen_netif *netif = netdev_priv(dev);
-- return netif->can_sg;
-+ struct xenvif *vif = netdev_priv(dev);
-+ return vif->can_sg;
- }
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-struct netbk_tx_pending_inuse {
+- struct list_head list;
+- unsigned long alloc_time;
+-};
+-#endif
+-
+ #define MAX_PENDING_REQS 256
--/* (De)Register a netif with the netback backend. */
--void xen_netbk_add_netif(struct xen_netif *netif);
--void xen_netbk_remove_netif(struct xen_netif *netif);
-+/* (De)Register a xenvif with the netback backend. */
-+void xen_netbk_add_xenvif(struct xenvif *vif);
-+void xen_netbk_remove_xenvif(struct xenvif *vif);
+ #define MAX_BUFFER_OFFSET PAGE_SIZE
+@@ -95,24 +85,11 @@ struct xen_netbk {
+ struct sk_buff_head tx_queue;
- #endif /* __XEN_NETBACK__COMMON_H__ */
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index 54ae275..a065173 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -38,40 +38,40 @@
+ struct timer_list net_timer;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- struct timer_list netbk_tx_pending_timer;
+-#endif
- #define NETBK_QUEUE_LENGTH 32
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- struct page **mmap_pages;
+-#else
+ struct page *mmap_pages[MAX_PENDING_REQS];
+-#endif
--static void __netif_up(struct xen_netif *netif)
-+static void xenvif_up(struct xenvif *vif)
- {
-- xen_netbk_add_netif(netif);
-- enable_irq(netif->irq);
-- netif_schedule_work(netif);
-+ xen_netbk_add_xenvif(vif);
-+ enable_irq(vif->irq);
-+ xenvif_schedule_work(vif);
- }
+ pending_ring_idx_t pending_prod;
+ pending_ring_idx_t pending_cons;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- pending_ring_idx_t dealloc_prod;
+- pending_ring_idx_t dealloc_cons;
+-
+- struct list_head pending_inuse_head;
+-#endif
+ struct list_head net_schedule_list;
--static void __netif_down(struct xen_netif *netif)
-+static void xenvif_down(struct xenvif *vif)
- {
-- disable_irq(netif->irq);
-- netif_deschedule_work(netif);
-- xen_netbk_remove_netif(netif);
-+ disable_irq(vif->irq);
-+ xenvif_deschedule_work(vif);
-+ xen_netbk_remove_xenvif(vif);
- }
+ /* Protect the net_schedule_list in netif. */
+@@ -121,20 +98,9 @@ struct xen_netbk {
+ atomic_t netfront_count;
--static int net_open(struct net_device *dev)
-+static int xenvif_open(struct net_device *dev)
- {
-- struct xen_netif *netif = netdev_priv(dev);
-- if (netback_carrier_ok(netif)) {
-- __netif_up(netif);
-+ struct xenvif *vif = netdev_priv(dev);
-+ if (xenvif_carrier_ok(vif)) {
-+ xenvif_up(vif);
- netif_start_queue(dev);
- }
- return 0;
- }
+ struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- 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];
+-#else
+ struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
+-#endif
--static int net_close(struct net_device *dev)
-+static int xenvif_close(struct net_device *dev)
- {
-- struct xen_netif *netif = netdev_priv(dev);
-- if (netback_carrier_ok(netif))
-- __netif_down(netif);
-+ struct xenvif *vif = netdev_priv(dev);
-+ if (xenvif_carrier_ok(vif))
-+ xenvif_down(vif);
- netif_stop_queue(dev);
- return 0;
- }
+ u16 pending_ring[MAX_PENDING_REQS];
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- u16 dealloc_ring[MAX_PENDING_REQS];
+-#endif
--static int netbk_change_mtu(struct net_device *dev, int mtu)
-+static int xenvif_change_mtu(struct net_device *dev, int mtu)
- {
- int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+ /*
+ * Each head or fragment can be up to 4096 bytes. Given
+@@ -220,11 +186,6 @@ static int get_page_ext(struct page *pg,
+ struct xen_netbk *netbk;
+ unsigned int group, idx;
-@@ -81,19 +81,19 @@ static int netbk_change_mtu(struct net_device *dev, int mtu)
- return 0;
- }
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if (!PageForeign(pg))
+- return 0;
+-#endif
+-
+ group = ext.e.group - 1;
--void netif_set_features(struct xen_netif *netif)
-+void xenvif_set_features(struct xenvif *vif)
- {
-- struct net_device *dev = netif->dev;
-+ struct net_device *dev = vif->dev;
- int features = dev->features;
+ if (group < 0 || group >= xen_netbk_group_nr)
+@@ -232,11 +193,6 @@ static int get_page_ext(struct page *pg,
-- if (netif->can_sg)
-+ if (vif->can_sg)
- features |= NETIF_F_SG;
-- if (netif->gso || netif->gso_prefix)
-+ if (vif->gso || vif->gso_prefix)
- features |= NETIF_F_TSO;
-- if (netif->csum)
-+ if (vif->csum)
- features |= NETIF_F_IP_CSUM;
+ netbk = &xen_netbk[group];
-- features &= ~(netif->features_disabled);
-+ features &= ~(vif->features_disabled);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if (netbk->mmap_pages == NULL)
+- return 0;
+-#endif
+-
+ idx = ext.e.idx;
- if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
- dev->mtu = ETH_DATA_LEN;
-@@ -101,130 +101,130 @@ void netif_set_features(struct xen_netif *netif)
- dev->features = features;
+ if ((idx < 0) || (idx >= MAX_PENDING_REQS))
+@@ -272,15 +228,6 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk
*netbk)
+ netbk->pending_prod + netbk->pending_cons;
}
--static int netbk_set_tx_csum(struct net_device *dev, u32 data)
-+static int xenvif_set_tx_csum(struct net_device *dev, u32 data)
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-/* Setting this allows the safe use of this driver without netloop. */
+-static int MODPARM_copy_skb = 1;
+-module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
+-MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
+-
+-int netbk_copy_skb_mode;
+-#endif
+-
+ static void xen_netbk_kick_thread(struct xen_netbk *netbk)
{
-- struct xen_netif *netif = netdev_priv(dev);
-+ struct xenvif *vif = netdev_priv(dev);
- if (data) {
-- if (!netif->csum)
-+ if (!vif->csum)
- return -EOPNOTSUPP;
-- netif->features_disabled &= ~NETIF_F_IP_CSUM;
-+ vif->features_disabled &= ~NETIF_F_IP_CSUM;
- } else {
-- netif->features_disabled |= NETIF_F_IP_CSUM;
-+ vif->features_disabled |= NETIF_F_IP_CSUM;
- }
-
-- netif_set_features(netif);
-+ xenvif_set_features(vif);
- return 0;
+ wake_up(&netbk->wq);
+@@ -752,14 +699,6 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff
*skb)
+ xen_netbk_kick_thread(netbk);
}
--static int netbk_set_sg(struct net_device *dev, u32 data)
-+static int xenvif_set_sg(struct net_device *dev, u32 data)
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-static void xen_netbk_tx_pending_timeout(unsigned long data)
+-{
+- struct xen_netbk *netbk = (struct xen_netbk *)data;
+- xen_netbk_kick_thread(netbk);
+-}
+-#endif
+-
+ static void xen_netbk_alarm(unsigned long data)
{
-- struct xen_netif *netif = netdev_priv(dev);
-+ struct xenvif *vif = netdev_priv(dev);
- if (data) {
-- if (!netif->can_sg)
-+ if (!vif->can_sg)
- return -EOPNOTSUPP;
-- netif->features_disabled &= ~NETIF_F_SG;
-+ vif->features_disabled &= ~NETIF_F_SG;
- } else {
-- netif->features_disabled |= NETIF_F_SG;
-+ vif->features_disabled |= NETIF_F_SG;
- }
-
-- netif_set_features(netif);
-+ xenvif_set_features(vif);
- return 0;
+ struct xen_netbk *netbk = (struct xen_netbk *)data;
+@@ -859,123 +798,6 @@ static void tx_credit_callback(unsigned long data)
+ xenvif_schedule_work(vif);
}
--static int netbk_set_tso(struct net_device *dev, u32 data)
-+static int xenvif_set_tso(struct net_device *dev, u32 data)
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-static inline int copy_pending_req(struct xen_netbk *netbk,
+- pending_ring_idx_t pending_idx)
+-{
+- return gnttab_copy_grant_page(
+- netbk->grant_tx_handle[pending_idx],
+- &netbk->mmap_pages[pending_idx]);
+-}
+-#endif
+-
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-static inline void xen_netbk_tx_action_dealloc(struct xen_netbk *netbk)
+-{
+- struct netbk_tx_pending_inuse *inuse, *n;
+- struct gnttab_unmap_grant_ref *gop;
+- u16 pending_idx;
+- pending_ring_idx_t dc, dp;
+- struct xenvif *vif;
+- int ret;
+- LIST_HEAD(list);
+-
+- dc = netbk->dealloc_cons;
+- gop = netbk->tx_unmap_ops;
+-
+- /* Free up any grants we have finished using. */
+- do {
+- dp = netbk->dealloc_prod;
+-
+- /* Ensure we see all indices enqueued by xen_netbk_idx_release(). */
+- smp_rmb();
+-
+- while (dc != dp) {
+- unsigned long pfn;
+- struct netbk_tx_pending_inuse *pending_inuse =
+- netbk->pending_inuse;
+-
+- pending_idx = netbk->dealloc_ring[pending_index(dc++)];
+- list_move_tail(&pending_inuse[pending_idx].list, &list);
+-
+- 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(netbk, pending_idx),
+- GNTMAP_host_map,
+- netbk->grant_tx_handle[pending_idx]);
+- gop++;
+- }
+-
+- } while (dp != netbk->dealloc_prod);
+-
+- netbk->dealloc_cons = dc;
+-
+- ret = HYPERVISOR_grant_table_op(
+- GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
+- gop - netbk->tx_unmap_ops);
+- BUG_ON(ret);
+-
+- /*
+- * Copy any entries that have been pending for too long
+- */
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !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;
+- pending_tx_info = netbk->pending_tx_info;
+-
+- if (time_after(inuse->alloc_time + HZ / 2, jiffies))
+- break;
+-
+- pending_idx = inuse - netbk->pending_inuse;
+-
+- pending_tx_info[pending_idx].vif->nr_copied_skbs++;
+-
+- switch (copy_pending_req(netbk, pending_idx)) {
+- case 0:
+- list_move_tail(&inuse->list, &list);
+- continue;
+- case -EBUSY:
+- list_del_init(&inuse->list);
+- continue;
+- case -ENOENT:
+- continue;
+- }
+-
+- break;
+- }
+- }
+-
+- list_for_each_entry_safe(inuse, n, &list, list) {
+- struct pending_tx_info *pending_tx_info;
+- pending_ring_idx_t index;
+-
+- pending_tx_info = netbk->pending_tx_info;
+- pending_idx = inuse - netbk->pending_inuse;
+-
+- vif = pending_tx_info[pending_idx].vif;
+-
+- make_tx_response(vif, &pending_tx_info[pending_idx].req,
+- XEN_NETIF_RSP_OKAY);
+-
+- /* Ready for next use. */
+- gnttab_reset_grant_page(netbk->mmap_pages[pending_idx]);
+-
+- index = pending_index(netbk->pending_prod++);
+- netbk->pending_ring[index] = pending_idx;
+-
+- xenvif_put(vif);
+-
+- list_del_init(&inuse->list);
+- }
+-}
+-#endif
+-
+ static void netbk_tx_err(struct xenvif *vif,
+ struct xen_netif_tx_request *txp, RING_IDX end)
{
-- struct xen_netif *netif = netdev_priv(dev);
-+ struct xenvif *vif = netdev_priv(dev);
- if (data) {
-- if (!netif->gso && !netif->gso_prefix)
-+ if (!vif->gso && !vif->gso_prefix)
- return -EOPNOTSUPP;
-- netif->features_disabled &= ~NETIF_F_TSO;
-+ vif->features_disabled &= ~NETIF_F_TSO;
- } else {
-- netif->features_disabled |= NETIF_F_TSO;
-+ vif->features_disabled |= NETIF_F_TSO;
- }
-
-- netif_set_features(netif);
-+ xenvif_set_features(vif);
- return 0;
+@@ -1033,7 +855,6 @@ static int netbk_count_requests(struct xenvif *vif,
+ return frags;
}
--static const struct netif_stat {
-+static const struct xenvif_stat {
- char name[ETH_GSTRING_LEN];
- u16 offset;
--} netbk_stats[] = {
-+} xenvif_stats[] = {
- {
- "copied_skbs",
-- offsetof(struct xen_netif, nr_copied_skbs)
-+ offsetof(struct xenvif, nr_copied_skbs)
- },
- {
- "rx_gso_checksum_fixup",
-- offsetof(struct xen_netif, rx_gso_checksum_fixup)
-+ offsetof(struct xenvif, rx_gso_checksum_fixup)
- },
- };
-
--static int netbk_get_sset_count(struct net_device *dev, int string_set)
-+static int xenvif_get_sset_count(struct net_device *dev, int string_set)
- {
- switch (string_set) {
- case ETH_SS_STATS:
-- return ARRAY_SIZE(netbk_stats);
-+ return ARRAY_SIZE(xenvif_stats);
- default:
- return -EINVAL;
- }
+-#ifndef HAVE_XEN_PAGE_FOREIGN
+ static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
+ struct sk_buff *skb,
+ unsigned long pending_idx)
+@@ -1046,21 +867,12 @@ static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
+ netbk->mmap_pages[pending_idx] = page;
+ return page;
}
+-#endif
--static void netbk_get_ethtool_stats(struct net_device *dev,
-- struct ethtool_stats *stats, u64 * data)
-+static void xenvif_get_ethtool_stats(struct net_device *dev,
-+ struct ethtool_stats *stats, u64 * data)
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
+- struct xenvif *vif,
+- struct sk_buff *skb,
+- struct xen_netif_tx_request *txp,
+- struct gnttab_map_grant_ref *gop)
+-#else
+ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
+ struct xenvif *vif,
+ struct sk_buff *skb,
+ struct xen_netif_tx_request *txp,
+ struct gnttab_copy *gop)
+-#endif
{
-- void *netif = netdev_priv(dev);
-+ void *vif = netdev_priv(dev);
- int i;
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ skb_frag_t *frags = shinfo->frags;
+@@ -1071,20 +883,13 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk
*netbk,
+ start = ((unsigned long)shinfo->frags[0].page == pending_idx);
-- for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-- data[i] = *(int *)(netif + netbk_stats[i].offset);
-+ for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
-+ data[i] = *(int *)(vif + xenvif_stats[i].offset);
+ for (i = start; i < shinfo->nr_frags; i++, txp++) {
+-#ifndef HAVE_XEN_PAGE_FOREIGN
+ struct page *page;
+-#endif
+ pending_ring_idx_t index;
+ struct pending_tx_info *pending_tx_info =
+ netbk->pending_tx_info;
+
+ index = pending_index(netbk->pending_cons++);
+ pending_idx = netbk->pending_ring[index];
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- gnttab_set_map_op(gop++, idx_to_kaddr(netbk, pending_idx),
+- GNTMAP_host_map | GNTMAP_readonly,
+- txp->gref, vif->domid);
+-#else
+ page = xen_netbk_alloc_page(netbk, skb, pending_idx);
+ if (!page)
+ return NULL;
+@@ -1103,7 +908,6 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk
*netbk,
+ gop->flags = GNTCOPY_source_gref;
+
+ gop++;
+-#endif
+
+ memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
+ xenvif_get(vif);
+@@ -1114,21 +918,11 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk
*netbk,
+ return gop;
}
--static void netbk_get_strings(struct net_device *dev, u32 stringset, u8 * data)
-+static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
+- struct sk_buff *skb,
+- struct gnttab_map_grant_ref **gopp)
+-#else
+ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
+ struct sk_buff *skb,
+ struct gnttab_copy **gopp)
+-#endif
{
- int i;
-
- switch (stringset) {
- case ETH_SS_STATS:
-- for (i = 0; i < ARRAY_SIZE(netbk_stats); i++)
-+ for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++)
- memcpy(data + i * ETH_GSTRING_LEN,
-- netbk_stats[i].name, ETH_GSTRING_LEN);
-+ xenvif_stats[i].name, ETH_GSTRING_LEN);
- break;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- struct gnttab_map_grant_ref *gop = *gopp;
+-#else
+ struct gnttab_copy *gop = *gopp;
+-#endif
+ int pending_idx = *((u16 *)skb->data);
+ struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
+ struct xenvif *vif = pending_tx_info[pending_idx].vif;
+@@ -1146,13 +940,6 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
+ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+ netbk->pending_ring[index] = pending_idx;
+ xenvif_put(vif);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- } else {
+- set_phys_to_machine(
+- __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
+- FOREIGN_FRAME(gop->dev_bus_addr >> PAGE_SHIFT));
+- netbk->grant_tx_handle[pending_idx] = gop->handle;
+-#endif
}
- }
--static struct ethtool_ops network_ethtool_ops = {
-- .get_tx_csum = ethtool_op_get_tx_csum,
-- .set_tx_csum = netbk_set_tx_csum,
-- .get_sg = ethtool_op_get_sg,
-- .set_sg = netbk_set_sg,
-- .get_tso = ethtool_op_get_tso,
-- .set_tso = netbk_set_tso,
-- .get_link = ethtool_op_get_link,
--
-- .get_sset_count = netbk_get_sset_count,
-- .get_ethtool_stats = netbk_get_ethtool_stats,
-- .get_strings = netbk_get_strings,
-+static struct ethtool_ops xenvif_ethtool_ops = {
-+ .get_tx_csum = ethtool_op_get_tx_csum,
-+ .set_tx_csum = xenvif_set_tx_csum,
-+ .get_sg = ethtool_op_get_sg,
-+ .set_sg = xenvif_set_sg,
-+ .get_tso = ethtool_op_get_tso,
-+ .set_tso = xenvif_set_tso,
-+ .get_link = ethtool_op_get_link,
-+
-+ .get_sset_count = xenvif_get_sset_count,
-+ .get_ethtool_stats = xenvif_get_ethtool_stats,
-+ .get_strings = xenvif_get_strings,
- };
+ /* Skip first skb fragment if it is on same page as header fragment. */
+@@ -1167,14 +954,6 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
+ /* Check error status: if okay then remember grant handle. */
+ newerr = (++gop)->status;
+ if (likely(!newerr)) {
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- unsigned long addr;
+- addr = idx_to_kaddr(netbk, pending_idx);
+- set_phys_to_machine(
+- __pa(addr)>>PAGE_SHIFT,
+- FOREIGN_FRAME(gop->dev_bus_addr>>PAGE_SHIFT));
+- netbk->grant_tx_handle[pending_idx] = gop->handle;
+-#endif
+ /* Had a previous error? Invalidate this fragment. */
+ if (unlikely(err))
+ xen_netbk_idx_release(netbk, pending_idx);
+@@ -1220,11 +999,6 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
+ unsigned long pending_idx;
--static struct net_device_ops netback_ops = {
-- .ndo_start_xmit = netif_be_start_xmit,
-- .ndo_get_stats = netif_be_get_stats,
-- .ndo_open = net_open,
-- .ndo_stop = net_close,
-- .ndo_change_mtu = netbk_change_mtu,
-+static struct net_device_ops xenvif_netdev_ops = {
-+ .ndo_start_xmit = xenvif_start_xmit,
-+ .ndo_get_stats = xenvif_get_stats,
-+ .ndo_open = xenvif_open,
-+ .ndo_stop = xenvif_close,
-+ .ndo_change_mtu = xenvif_change_mtu,
- };
+ pending_idx = (unsigned long)frag->page;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- netbk->pending_inuse[pending_idx].alloc_time = jiffies;
+- list_add_tail(&netbk->pending_inuse[pending_idx].list,
+- &netbk->pending_inuse_head);
+-#endif
--struct xen_netif *netif_alloc(struct device *parent, domid_t domid,
-- unsigned int handle)
-+struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
-+ unsigned int handle)
- {
- int err = 0;
- struct net_device *dev;
-- struct xen_netif *netif;
-+ struct xenvif *vif;
- char name[IFNAMSIZ] = {};
+ txp = &netbk->pending_tx_info[pending_idx].req;
+ frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
+@@ -1398,11 +1172,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
- snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
-- dev = alloc_netdev(sizeof(struct xen_netif), name, ether_setup);
-+ dev = alloc_netdev(sizeof(struct xenvif), name, ether_setup);
- if (dev == NULL) {
- pr_debug("Could not allocate netdev\n");
- return ERR_PTR(-ENOMEM);
-@@ -232,29 +232,29 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t
domid,
+ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+ {
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- struct gnttab_map_grant_ref *gop = netbk->tx_map_ops, *request_gop;
+-#else
+ struct gnttab_copy *gop = netbk->tx_copy_ops, *request_gop;
+-#endif
+ struct sk_buff *skb;
+ int ret;
- SET_NETDEV_DEV(dev, parent);
+@@ -1411,9 +1181,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+ struct xenvif *vif;
+ struct xen_netif_tx_request txreq;
+ struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+-#ifndef HAVE_XEN_PAGE_FOREIGN
+ struct page *page;
+-#endif
+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+ u16 pending_idx;
+ RING_IDX idx;
+@@ -1510,12 +1278,6 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+ }
+ }
-- netif = netdev_priv(dev);
-- memset(netif, 0, sizeof(*netif));
-- netif->domid = domid;
-- netif->group = -1;
-- netif->handle = handle;
-- netif->can_sg = 1;
-- netif->csum = 1;
-- atomic_set(&netif->refcnt, 1);
-- init_waitqueue_head(&netif->waiting_to_free);
-- netif->dev = dev;
-- INIT_LIST_HEAD(&netif->list);
--
-- netback_carrier_off(netif);
--
-- netif->credit_bytes = netif->remaining_credit = ~0UL;
-- netif->credit_usec = 0UL;
-- init_timer(&netif->credit_timeout);
-+ vif = netdev_priv(dev);
-+ memset(vif, 0, sizeof(*vif));
-+ vif->domid = domid;
-+ vif->group = -1;
-+ vif->handle = handle;
-+ vif->can_sg = 1;
-+ vif->csum = 1;
-+ atomic_set(&vif->refcnt, 1);
-+ init_waitqueue_head(&vif->waiting_to_free);
-+ vif->dev = dev;
-+ INIT_LIST_HEAD(&vif->list);
-+
-+ xenvif_carrier_off(vif);
-+
-+ vif->credit_bytes = vif->remaining_credit = ~0UL;
-+ vif->credit_usec = 0UL;
-+ init_timer(&vif->credit_timeout);
- /* Initialize 'expires' now: it's used to track the credit window. */
-- netif->credit_timeout.expires = jiffies;
-+ vif->credit_timeout.expires = jiffies;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- gnttab_set_map_op(gop, idx_to_kaddr(netbk, pending_idx),
+- GNTMAP_host_map | GNTMAP_readonly,
+- txreq.gref, vif->domid);
+- gop++;
+-#else
+ /* XXX could copy straight to head */
+ page = xen_netbk_alloc_page(netbk, skb, pending_idx);
+ if (!page) {
+@@ -1538,7 +1300,6 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+ gop->flags = GNTCOPY_source_gref;
-- dev->netdev_ops = &netback_ops;
-- netif_set_features(netif);
-- SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
-+ dev->netdev_ops = &xenvif_netdev_ops;
-+ xenvif_set_features(vif);
-+ SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
+ gop++;
+-#endif
- dev->tx_queue_len = NETBK_QUEUE_LENGTH;
+ memcpy(&netbk->pending_tx_info[pending_idx].req,
+ &txreq, sizeof(txreq));
+@@ -1573,29 +1334,16 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+ vif->tx.req_cons = idx;
+ xenvif_schedule_work(vif);
-@@ -277,18 +277,18 @@ struct xen_netif *netif_alloc(struct device *parent, domid_t
domid,
- return ERR_PTR(err);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if ((gop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
+- break;
+-#else
+ if ((gop-netbk->tx_copy_ops) >= ARRAY_SIZE(netbk->tx_copy_ops))
+ break;
+-#endif
}
-- pr_debug("Successfully created netif\n");
-- return netif;
-+ pr_debug("Successfully created xenvif\n");
-+ return vif;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- return gop - netbk->tx_map_ops;
+-#else
+ return gop - netbk->tx_copy_ops;
+-#endif
}
--static int map_frontend_pages(struct xen_netif *netif,
-+static int map_frontend_pages(struct xenvif *vif,
- grant_ref_t tx_ring_ref,
- grant_ref_t rx_ring_ref)
+ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
{
- struct gnttab_map_grant_ref op;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- struct gnttab_map_grant_ref *gop = netbk->tx_map_ops;
+-#else
+ struct gnttab_copy *gop = netbk->tx_copy_ops;
+-#endif
+ struct sk_buff *skb;
-- gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
-- GNTMAP_host_map, tx_ring_ref, netif->domid);
-+ gnttab_set_map_op(&op, (unsigned long)vif->tx_comms_area->addr,
-+ GNTMAP_host_map, tx_ring_ref, vif->domid);
+ while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
+@@ -1655,15 +1403,6 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
+ continue;
+ }
- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
- BUG();
-@@ -298,11 +298,11 @@ static int map_frontend_pages(struct xen_netif *netif,
- return op.status;
- }
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
+- unlikely(skb_linearize(skb))) {
+- pr_debug("Can't linearize skb in net_tx_action.\n");
+- kfree_skb(skb);
+- continue;
+- }
+-#endif
+-
+ vif->stats.rx_bytes += skb->len;
+ vif->stats.rx_packets++;
-- netif->tx_shmem_ref = tx_ring_ref;
-- netif->tx_shmem_handle = op.handle;
-+ vif->tx_shmem_ref = tx_ring_ref;
-+ vif->tx_shmem_handle = op.handle;
+@@ -1678,70 +1417,18 @@ static void xen_netbk_tx_action(struct xen_netbk *netbk)
+ unsigned nr_gops;
+ int ret;
-- gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
-- GNTMAP_host_map, rx_ring_ref, netif->domid);
-+ gnttab_set_map_op(&op, (unsigned long)vif->rx_comms_area->addr,
-+ GNTMAP_host_map, rx_ring_ref, vif->domid);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- xen_netbk_tx_action_dealloc(netbk);
+-#endif
+-
+ nr_gops = xen_netbk_tx_build_gops(netbk);
- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
- BUG();
-@@ -311,120 +311,120 @@ static int map_frontend_pages(struct xen_netif *netif,
- struct gnttab_unmap_grant_ref unop;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if (nr_gops == 0)
+- goto out;
+- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+- netbk->tx_map_ops, nr_gops);
+-#else
+ if (nr_gops == 0)
+ return;
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy,
+ netbk->tx_copy_ops, nr_gops);
+-#endif
+ BUG_ON(ret);
- gnttab_set_unmap_op(&unop,
-- (unsigned long)netif->tx_comms_area->addr,
-- GNTMAP_host_map, netif->tx_shmem_handle);
-+ (unsigned long)vif->tx_comms_area->addr,
-+ GNTMAP_host_map, vif->tx_shmem_handle);
- HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop, 1);
- pr_debug("Gnttab failure mapping rx_ring_ref!\n");
- return op.status;
- }
+ xen_netbk_tx_submit(netbk);
-- netif->rx_shmem_ref = rx_ring_ref;
-- netif->rx_shmem_handle = op.handle;
-+ vif->rx_shmem_ref = rx_ring_ref;
-+ vif->rx_shmem_handle = op.handle;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-out:
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !list_empty(&netbk->pending_inuse_head)) {
+- struct netbk_tx_pending_inuse *oldest;
+-
+- oldest = list_entry(netbk->pending_inuse_head.next,
+- struct netbk_tx_pending_inuse, list);
+- mod_timer(&netbk->netbk_tx_pending_timer,
+- oldest->alloc_time + HZ);
+- }
+-#endif
+ }
- return 0;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+-{
+- static DEFINE_SPINLOCK(_lock);
+- unsigned long flags;
+- pending_ring_idx_t index;
+-
+- spin_lock_irqsave(&_lock, flags);
+- index = pending_index(netbk->dealloc_prod);
+- netbk->dealloc_ring[index] = pending_idx;
+- /* Sync with xen_netbk_tx_action_dealloc: insert idx /then/ incr producer. */
+- smp_wmb();
+- netbk->dealloc_prod++;
+- spin_unlock_irqrestore(&_lock, flags);
+-
+- xen_netbk_kick_thread(netbk);
+-}
+-
+-static void netif_page_release(struct page *page, unsigned int order)
+-{
+- unsigned int group, idx;
+- int foreign = get_page_ext(page, &group, &idx);
+-
+- BUG_ON(!foreign);
+- BUG_ON(order);
+-
+- xen_netbk_idx_release(&xen_netbk[group], idx);
+-}
+-#else
+ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+ {
+ struct xenvif *vif;
+@@ -1767,7 +1454,6 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16
pending_idx)
+ put_page(netbk->mmap_pages[pending_idx]);
+ netbk->mmap_pages[pending_idx] = NULL;
}
+-#endif
--static void unmap_frontend_pages(struct xen_netif *netif)
-+static void unmap_frontend_pages(struct xenvif *vif)
+ static void make_tx_response(struct xenvif *vif,
+ struct xen_netif_tx_request *txp,
+@@ -1820,14 +1506,6 @@ static inline int rx_work_todo(struct xen_netbk *netbk)
+
+ static inline int tx_work_todo(struct xen_netbk *netbk)
{
- struct gnttab_unmap_grant_ref op;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if (netbk->dealloc_cons != netbk->dealloc_prod)
+- return 1;
+-
+- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
+- !list_empty(&netbk->pending_inuse_head))
+- return 1;
+-#endif
-- gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
-- GNTMAP_host_map, netif->tx_shmem_handle);
-+ gnttab_set_unmap_op(&op, (unsigned long)vif->tx_comms_area->addr,
-+ GNTMAP_host_map, vif->tx_shmem_handle);
+ if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list))
+@@ -1862,9 +1540,6 @@ static int xen_netbk_kthread(void *data)
+ static int __init netback_init(void)
+ {
+ int i;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- struct page *page;
+-#endif
+ int rc = 0;
+ int group;
- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
- BUG();
+@@ -1888,32 +1563,6 @@ static int __init netback_init(void)
+ netbk->net_timer.data = (unsigned long)netbk;
+ netbk->net_timer.function = xen_netbk_alarm;
-- gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
-- GNTMAP_host_map, netif->rx_shmem_handle);
-+ gnttab_set_unmap_op(&op, (unsigned long)vif->rx_comms_area->addr,
-+ GNTMAP_host_map, vif->rx_shmem_handle);
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- init_timer(&netbk->netbk_tx_pending_timer);
+- netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
+- netbk->netbk_tx_pending_timer.function =
+- xen_netbk_tx_pending_timeout;
+-#endif
+-
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- netbk->mmap_pages =
+- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
+- if (!netbk->mmap_pages) {
+- printk(KERN_ALERT "%s: out of memory\n", __func__);
+- del_timer(&netbk->netbk_tx_pending_timer);
+- del_timer(&netbk->net_timer);
+- rc = -ENOMEM;
+- goto failed_init;
+- }
+-
+- for (i = 0; i < MAX_PENDING_REQS; i++) {
+- page = netbk->mmap_pages[i];
+- SetPageForeign(page, netif_page_release);
+- set_page_ext(page, netbk, i);
+- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+- }
+-#endif
+-
+ netbk->pending_cons = 0;
+ netbk->pending_prod = MAX_PENDING_REQS;
+ for (i = 0; i < MAX_PENDING_REQS; i++)
+@@ -1926,11 +1575,6 @@ static int __init netback_init(void)
- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
- BUG();
- }
+ if (IS_ERR(netbk->task)) {
+ printk(KERN_ALERT "kthread_run() fails at netback\n");
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- free_empty_pages_and_pagevec(netbk->mmap_pages,
+- MAX_PENDING_REQS);
+- del_timer(&netbk->netbk_tx_pending_timer);
+-#endif
+ del_timer(&netbk->net_timer);
+ rc = PTR_ERR(netbk->task);
+ goto failed_init;
+@@ -1938,9 +1582,6 @@ static int __init netback_init(void)
--int netif_map(struct xen_netif *netif, unsigned long tx_ring_ref,
-- unsigned long rx_ring_ref, unsigned int evtchn)
-+int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
-+ unsigned long rx_ring_ref, unsigned int evtchn)
- {
- int err = -ENOMEM;
- struct xen_netif_tx_sring *txs;
- struct xen_netif_rx_sring *rxs;
+ kthread_bind(netbk->task, group);
- /* Already connected through? */
-- if (netif->irq)
-+ if (vif->irq)
- return 0;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- INIT_LIST_HEAD(&netbk->pending_inuse_head);
+-#endif
+ INIT_LIST_HEAD(&netbk->net_schedule_list);
-- netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
-- if (netif->tx_comms_area == NULL)
-+ vif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
-+ if (vif->tx_comms_area == NULL)
- return -ENOMEM;
-- netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
-- if (netif->rx_comms_area == NULL)
-+ vif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
-+ if (vif->rx_comms_area == NULL)
- goto err_rx;
+ spin_lock_init(&netbk->net_schedule_list_lock);
+@@ -1950,17 +1591,6 @@ static int __init netback_init(void)
+ wake_up_process(netbk->task);
+ }
-- err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
-+ err = map_frontend_pages(vif, tx_ring_ref, rx_ring_ref);
- if (err)
- goto err_map;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
+- if (MODPARM_copy_skb) {
+- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
+- NULL, 0))
+- netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
+- else
+- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+- }
+-#endif
+-
+ rc = xenvif_xenbus_init();
+ if (rc)
+ goto failed_init;
+@@ -1970,17 +1600,11 @@ static int __init netback_init(void)
+ failed_init:
+ for (i = 0; i < group; i++) {
+ struct xen_netbk *netbk = &xen_netbk[i];
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- free_empty_pages_and_pagevec(netbk->mmap_pages,
+- MAX_PENDING_REQS);
+- del_timer(&netbk->netbk_tx_pending_timer);
+-#else
+ int j;
+ for (j = 0; j < MAX_PENDING_REQS; j++) {
+ if (netbk->mmap_pages[i])
+ __free_page(netbk->mmap_pages[i]);
+ }
+-#endif
+ del_timer(&netbk->net_timer);
+ kthread_stop(netbk->task);
+ }
+diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
+index d56b1ee..22b8c35 100644
+--- a/drivers/net/xen-netback/xenbus.c
++++ b/drivers/net/xen-netback/xenbus.c
+@@ -74,10 +74,6 @@ static int netback_probe(struct xenbus_device *dev,
+ dev_set_drvdata(&dev->dev, be);
- err = bind_interdomain_evtchn_to_irqhandler(
-- netif->domid, evtchn, netif_be_int, 0,
-- netif->dev->name, netif);
-+ vif->domid, evtchn, xenvif_interrupt, 0,
-+ vif->dev->name, vif);
- if (err < 0)
- goto err_hypervisor;
-- netif->irq = err;
-- disable_irq(netif->irq);
-+ vif->irq = err;
-+ disable_irq(vif->irq);
+ sg = 1;
+-#ifdef HAVE_XEN_PAGE_FOREIGN
+- if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
+- sg = 0;
+-#endif
-- txs = (struct xen_netif_tx_sring *)netif->tx_comms_area->addr;
-- BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
-+ txs = (struct xen_netif_tx_sring *)vif->tx_comms_area->addr;
-+ BACK_RING_INIT(&vif->tx, txs, PAGE_SIZE);
+ do {
+ err = xenbus_transaction_start(&xbt);
+--
+1.7.4
+
+
+From dc5f219e88294b93009eef946251251ffffb6d60 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx(a)linutronix.de>
+Date: Fri, 4 Feb 2011 13:19:20 +0100
+Subject: [PATCH 101/203] genirq: Add IRQF_FORCE_RESUME
+
+Xen needs to reenable interrupts which are marked IRQF_NO_SUSPEND in the
+resume path. Add a flag to force the reenabling in the resume code.
+
+Tested-and-acked-by: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
+Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
+---
+ include/linux/interrupt.h | 3 ++-
+ kernel/irq/manage.c | 11 ++++++++++-
+ kernel/irq/pm.c | 3 ---
+ 3 files changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
+index 55e0d42..d746da1 100644
+--- a/include/linux/interrupt.h
++++ b/include/linux/interrupt.h
+@@ -55,7 +55,7 @@
+ * Used by threaded interrupts which need to keep the
+ * irq line disabled until the threaded handler has been run.
+ * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
+- *
++ * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
+ */
+ #define IRQF_DISABLED 0x00000020
+ #define IRQF_SAMPLE_RANDOM 0x00000040
+@@ -67,6 +67,7 @@
+ #define IRQF_IRQPOLL 0x00001000
+ #define IRQF_ONESHOT 0x00002000
+ #define IRQF_NO_SUSPEND 0x00004000
++#define IRQF_FORCE_RESUME 0x00008000
- rxs = (struct xen_netif_rx_sring *)
-- ((char *)netif->rx_comms_area->addr);
-- BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
-+ ((char *)vif->rx_comms_area->addr);
-+ BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE);
+ #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND)
-- netif->rx_req_cons_peek = 0;
-+ vif->rx_req_cons_peek = 0;
+diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
+index 0caa59f..b4198ee 100644
+--- a/kernel/irq/manage.c
++++ b/kernel/irq/manage.c
+@@ -282,8 +282,17 @@ EXPORT_SYMBOL(disable_irq);
-- netif_get(netif);
-+ xenvif_get(vif);
+ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
+ {
+- if (resume)
++ if (resume) {
++ if (!(desc->status & IRQ_SUSPENDED)) {
++ if (!desc->action)
++ return;
++ if (!(desc->action->flags & IRQF_FORCE_RESUME))
++ return;
++ /* Pretend that it got disabled ! */
++ desc->depth++;
++ }
+ desc->status &= ~IRQ_SUSPENDED;
++ }
- rtnl_lock();
-- netback_carrier_on(netif);
-- if (netif_running(netif->dev))
-- __netif_up(netif);
-+ xenvif_carrier_on(vif);
-+ if (netif_running(vif->dev))
-+ xenvif_up(vif);
- rtnl_unlock();
+ switch (desc->depth) {
+ case 0:
+diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
+index 0d4005d8..d6bfb89 100644
+--- a/kernel/irq/pm.c
++++ b/kernel/irq/pm.c
+@@ -53,9 +53,6 @@ void resume_device_irqs(void)
+ for_each_irq_desc(irq, desc) {
+ unsigned long flags;
- return 0;
- err_hypervisor:
-- unmap_frontend_pages(netif);
-+ unmap_frontend_pages(vif);
- err_map:
-- free_vm_area(netif->rx_comms_area);
-+ free_vm_area(vif->rx_comms_area);
- err_rx:
-- free_vm_area(netif->tx_comms_area);
-+ free_vm_area(vif->tx_comms_area);
- return err;
+- if (!(desc->status & IRQ_SUSPENDED))
+- continue;
+-
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ __enable_irq(desc, irq, true);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+--
+1.7.4
+
+
+From bb70b10fcebc2a02591a1da53e8d6873582b421e Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 18 Jan 2011 20:17:10 -0500
+Subject: [PATCH 102/203] xen/mmu: WARN_ON when racing to swap middle leaf.
+
+The initial bootup code uses set_phys_to_machine quite a lot, and after
+bootup it would be used by the balloon driver. The balloon driver does have
+mutex lock so this should not be necessary - but just in case, add
+a WARN_ON if we do hit this scenario. If we do fail this, it is OK
+to continue as there is a backup mechanism (VM_IO) that can bypass
+the P2M and still set the _PAGE_IOMAP flags.
+
+[v2: Change from WARN to BUG_ON]
+[v3: Rebased on top of xen->p2m code split]
+[v4: Change from BUG_ON to WARN]
+Reviewed-by: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/p2m.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
+index dd30ec8..851da14 100644
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -482,7 +482,8 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+
+ /* Swap over from MISSING to IDENTITY if needed. */
+ if (p2m_top[topidx][mididx] == p2m_missing) {
+- p2m_top[topidx][mididx] = p2m_identity;
++ WARN_ON(cmpxchg(&p2m_top[topidx][mididx], p2m_missing,
++ p2m_identity) != p2m_missing);
+ return true;
+ }
+ }
+--
+1.7.4
+
+
+From da60f4ccf61268444fd83d5e266ffe26d5ce366d Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 1 Feb 2011 17:15:30 -0500
+Subject: [PATCH 103/203] xen/setup: Set identity mapping for non-RAM E820 and E820 gaps.
+
+We walk the E820 region and start at 0 (for PV guests we start
+at ISA_END_ADDRESS) and skip any E820 RAM regions. For all other
+regions and as well the gaps we set them to be identity mappings.
+
+The reasons we do not want to set the identity mapping from 0->
+ISA_END_ADDRESS when running as PV is b/c that the kernel would
+try to read DMI information and fail (no permissions to read that).
+There is a lot of gnarly code to deal with that weird region so
+we won't try to do a cleanup in this patch.
+
+This code ends up calling 'set_phys_to_identity' with the start
+and end PFN of the the E820 that are non-RAM or have gaps.
+On 99% of machines that means one big region right underneath the
+4GB mark. Usually starts at 0xc0000 (or 0x80000) and goes to
+0x100000.
+
+[v2: Fix for E820 crossing 1MB region and clamp the start]
+[v3: Squshed in code that does this over ranges]
+[v4: Moved the comment to the correct spot]
+[v5: Use the "raw" E820 from the hypervisor]
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/setup.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 52 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
+index 7201800..54d9379 100644
+--- a/arch/x86/xen/setup.c
++++ b/arch/x86/xen/setup.c
+@@ -143,12 +143,55 @@ static unsigned long __init xen_return_unused_memory(unsigned long
max_pfn,
+ return released;
}
--void netif_disconnect(struct xen_netif *netif)
-+void xenvif_disconnect(struct xenvif *vif)
++static unsigned long __init xen_set_identity(const struct e820entry *list,
++ ssize_t map_size)
++{
++ phys_addr_t last = xen_initial_domain() ? 0 : ISA_END_ADDRESS;
++ phys_addr_t start_pci = last;
++ const struct e820entry *entry;
++ unsigned long identity = 0;
++ int i;
++
++ for (i = 0, entry = list; i < map_size; i++, entry++) {
++ phys_addr_t start = entry->addr;
++ phys_addr_t end = start + entry->size;
++
++ if (start < last)
++ start = last;
++
++ if (end <= start)
++ continue;
++
++ /* Skip over the 1MB region. */
++ if (last > end)
++ continue;
++
++ if (entry->type == E820_RAM) {
++ if (start > start_pci)
++ identity += set_phys_range_identity(
++ PFN_UP(start_pci), PFN_DOWN(start));
++
++ /* Without saving 'last' we would gooble RAM too
++ * at the end of the loop. */
++ last = end;
++ start_pci = end;
++ continue;
++ }
++ start_pci = min(start, start_pci);
++ last = end;
++ }
++ if (last > start_pci)
++ identity += set_phys_range_identity(
++ PFN_UP(start_pci), PFN_DOWN(last));
++ return identity;
++}
+ /**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ **/
+ char * __init xen_memory_setup(void)
{
-- if (netback_carrier_ok(netif)) {
-+ if (xenvif_carrier_ok(vif)) {
- rtnl_lock();
-- netback_carrier_off(netif);
-- netif_carrier_off(netif->dev); /* discard queued packets */
-- if (netif_running(netif->dev))
-- __netif_down(netif);
-+ xenvif_carrier_off(vif);
-+ netif_carrier_off(vif->dev); /* discard queued packets */
-+ if (netif_running(vif->dev))
-+ xenvif_down(vif);
- rtnl_unlock();
-- netif_put(netif);
-+ xenvif_put(vif);
+ static struct e820entry map[E820MAX] __initdata;
++ static struct e820entry map_raw[E820MAX] __initdata;
+
+ unsigned long max_pfn = xen_start_info->nr_pages;
+ unsigned long long mem_end;
+@@ -156,6 +199,7 @@ char * __init xen_memory_setup(void)
+ struct xen_memory_map memmap;
+ unsigned long extra_pages = 0;
+ unsigned long extra_limit;
++ unsigned long identity_pages = 0;
+ int i;
+ int op;
+
+@@ -181,6 +225,7 @@ char * __init xen_memory_setup(void)
}
+ BUG_ON(rc);
-- atomic_dec(&netif->refcnt);
-- wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
-+ atomic_dec(&vif->refcnt);
-+ wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
++ memcpy(map_raw, map, sizeof(map));
+ e820.nr_map = 0;
+ xen_extra_mem_start = mem_end;
+ for (i = 0; i < memmap.nr_entries; i++) {
+@@ -251,6 +296,13 @@ char * __init xen_memory_setup(void)
-- del_timer_sync(&netif->credit_timeout);
-+ del_timer_sync(&vif->credit_timeout);
+ xen_add_extra_mem(extra_pages);
-- if (netif->irq)
-- unbind_from_irqhandler(netif->irq, netif);
-+ if (vif->irq)
-+ unbind_from_irqhandler(vif->irq, vif);
++ /*
++ * Set P2M for all non-RAM pages and E820 gaps to be identity
++ * type PFNs. We supply it with the non-sanitized version
++ * of the E820.
++ */
++ identity_pages = xen_set_identity(map_raw, memmap.nr_entries);
++ printk(KERN_INFO "Set %ld page(s) to 1-1 mapping.\n", identity_pages);
+ return "Xen";
+ }
-- unregister_netdev(netif->dev);
-+ unregister_netdev(vif->dev);
+--
+1.7.4
+
+
+From 4f5d3a046949c958338ca780145dae21647c8d58 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 22 Dec 2010 08:57:30 -0500
+Subject: [PATCH 104/203] xen/debugfs: Add 'p2m' file for printing out the P2M
layout.
+
+We walk over the whole P2M tree and construct a simplified view of
+which PFN regions belong to what level and what type they are.
+
+Only enabled if CONFIG_XEN_DEBUG_FS is set.
+
+[v2: UNKN->UNKNOWN, use uninitialized_var]
+[v3: Rebased on top of mmu->p2m code split]
+[v4: Fixed the else if]
+Reviewed-by: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/include/asm/xen/page.h | 3 +
+ arch/x86/xen/mmu.c | 14 +++++++
+ arch/x86/xen/p2m.c | 78 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 95 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
+index 65fa4f2..78ebbeb 100644
+--- a/arch/x86/include/asm/xen/page.h
++++ b/arch/x86/include/asm/xen/page.h
+@@ -52,6 +52,9 @@ extern int m2p_remove_override(struct page *page);
+ extern struct page *m2p_find_override(unsigned long mfn);
+ extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
-- if (netif->tx.sring) {
-- unmap_frontend_pages(netif);
-- free_vm_area(netif->tx_comms_area);
-- free_vm_area(netif->rx_comms_area);
-+ if (vif->tx.sring) {
-+ unmap_frontend_pages(vif);
-+ free_vm_area(vif->tx_comms_area);
-+ free_vm_area(vif->rx_comms_area);
- }
++#ifdef CONFIG_XEN_DEBUG_FS
++extern int p2m_dump_show(struct seq_file *m, void *v);
++#endif
+ static inline unsigned long pfn_to_mfn(unsigned long pfn)
+ {
+ unsigned long mfn;
+diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
+index 9c9e076..b13b6ca 100644
+--- a/arch/x86/xen/mmu.c
++++ b/arch/x86/xen/mmu.c
+@@ -46,6 +46,7 @@
+ #include <linux/module.h>
+ #include <linux/gfp.h>
+ #include <linux/memblock.h>
++#include <linux/seq_file.h>
-- free_netdev(netif->dev);
-+ free_netdev(vif->dev);
- }
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index d10ddbc..f2f9c6f 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -49,7 +49,7 @@
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
+@@ -2367,6 +2368,18 @@ EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
- struct pending_tx_info {
- struct xen_netif_tx_request req;
-- struct xen_netif *netif;
-+ struct xenvif *vif;
- };
- typedef unsigned int pending_ring_idx_t;
+ #ifdef CONFIG_XEN_DEBUG_FS
-@@ -140,7 +140,7 @@ struct xen_netbk {
- static struct xen_netbk *xen_netbk;
- static int xen_netbk_group_nr;
++static int p2m_dump_open(struct inode *inode, struct file *filp)
++{
++ return single_open(filp, p2m_dump_show, NULL);
++}
++
++static const struct file_operations p2m_dump_fops = {
++ .open = p2m_dump_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = single_release,
++};
++
+ static struct dentry *d_mmu_debug;
--void xen_netbk_add_netif(struct xen_netif *netif)
-+void xen_netbk_add_xenvif(struct xenvif *vif)
- {
- int i;
- int min_netfront_count;
-@@ -154,20 +154,20 @@ void xen_netbk_add_netif(struct xen_netif *netif)
- }
- }
+ static int __init xen_mmu_debugfs(void)
+@@ -2422,6 +2435,7 @@ static int __init xen_mmu_debugfs(void)
+ debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
+ &mmu_stats.prot_commit_batched);
-- netif->group = min_group;
-- atomic_inc(&xen_netbk[netif->group].netfront_count);
-+ vif->group = min_group;
-+ atomic_inc(&xen_netbk[vif->group].netfront_count);
++ debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
+ return 0;
}
+ fs_initcall(xen_mmu_debugfs);
+diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
+index 851da14..ea613d0 100644
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -30,6 +30,7 @@
+ #include <linux/list.h>
+ #include <linux/hash.h>
+ #include <linux/sched.h>
++#include <linux/seq_file.h>
--void xen_netbk_remove_netif(struct xen_netif *netif)
-+void xen_netbk_remove_xenvif(struct xenvif *vif)
- {
-- atomic_dec(&xen_netbk[netif->group].netfront_count);
-+ atomic_dec(&xen_netbk[vif->group].netfront_count);
+ #include <asm/cache.h>
+ #include <asm/setup.h>
+@@ -635,3 +636,80 @@ unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long
pfn)
+ return ret;
}
-
- static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
--static void make_tx_response(struct xen_netif *netif,
-+static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
- s8 st);
--static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
-+static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
- u16 id,
- s8 st,
- u16 offset,
-@@ -369,20 +369,20 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
- return NULL;
+ EXPORT_SYMBOL_GPL(m2p_find_override_pfn);
++
++#ifdef CONFIG_XEN_DEBUG_FS
++
++int p2m_dump_show(struct seq_file *m, void *v)
++{
++ static const char * const level_name[] = { "top", "middle",
++ "entry", "abnormal" };
++ static const char * const type_name[] = { "identity", "missing",
++ "pfn", "abnormal"};
++#define TYPE_IDENTITY 0
++#define TYPE_MISSING 1
++#define TYPE_PFN 2
++#define TYPE_UNKNOWN 3
++ unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0;
++ unsigned int uninitialized_var(prev_level);
++ unsigned int uninitialized_var(prev_type);
++
++ if (!p2m_top)
++ return 0;
++
++ for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn++) {
++ unsigned topidx = p2m_top_index(pfn);
++ unsigned mididx = p2m_mid_index(pfn);
++ unsigned idx = p2m_index(pfn);
++ unsigned lvl, type;
++
++ lvl = 4;
++ type = TYPE_UNKNOWN;
++ if (p2m_top[topidx] == p2m_mid_missing) {
++ lvl = 0; type = TYPE_MISSING;
++ } else if (p2m_top[topidx] == NULL) {
++ lvl = 0; type = TYPE_UNKNOWN;
++ } else if (p2m_top[topidx][mididx] == NULL) {
++ lvl = 1; type = TYPE_UNKNOWN;
++ } else if (p2m_top[topidx][mididx] == p2m_identity) {
++ lvl = 1; type = TYPE_IDENTITY;
++ } else if (p2m_top[topidx][mididx] == p2m_missing) {
++ lvl = 1; type = TYPE_MISSING;
++ } else if (p2m_top[topidx][mididx][idx] == 0) {
++ lvl = 2; type = TYPE_UNKNOWN;
++ } else if (p2m_top[topidx][mididx][idx] == IDENTITY_FRAME(pfn)) {
++ lvl = 2; type = TYPE_IDENTITY;
++ } else if (p2m_top[topidx][mididx][idx] == INVALID_P2M_ENTRY) {
++ lvl = 2; type = TYPE_MISSING;
++ } else if (p2m_top[topidx][mididx][idx] == pfn) {
++ lvl = 2; type = TYPE_PFN;
++ } else if (p2m_top[topidx][mididx][idx] != pfn) {
++ lvl = 2; type = TYPE_PFN;
++ }
++ if (pfn == 0) {
++ prev_level = lvl;
++ prev_type = type;
++ }
++ if (pfn == MAX_DOMAIN_PAGES-1) {
++ lvl = 3;
++ type = TYPE_UNKNOWN;
++ }
++ if (prev_type != type) {
++ seq_printf(m, " [0x%lx->0x%lx] %s\n",
++ prev_pfn_type, pfn, type_name[prev_type]);
++ prev_pfn_type = pfn;
++ prev_type = type;
++ }
++ if (prev_level != lvl) {
++ seq_printf(m, " [0x%lx->0x%lx] level %s\n",
++ prev_pfn_level, pfn, level_name[prev_level]);
++ prev_pfn_level = pfn;
++ prev_level = lvl;
++ }
++ }
++ return 0;
++#undef TYPE_IDENTITY
++#undef TYPE_MISSING
++#undef TYPE_PFN
++#undef TYPE_UNKNOWN
++}
++#endif
+--
+1.7.4
+
+
+From 84f847d2e878b4d15e7552e86f20251a2d0d4522 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 23 Dec 2010 16:25:29 -0500
+Subject: [PATCH 105/203] xen/debug: WARN_ON when identity PFN has no _PAGE_IOMAP flag
set.
+
+Only enabled if XEN_DEBUG is enabled. We print a warning
+when:
+
+ pfn_to_mfn(pfn) == pfn, but no VM_IO (_PAGE_IOMAP) flag set
+ (and pfn is an identity mapped pfn)
+ pfn_to_mfn(pfn) != pfn, and VM_IO flag is set.
+ (ditto, pfn is an identity mapped pfn)
+
+[v2: Make it dependent on CONFIG_XEN_DEBUG instead of ..DEBUG_FS]
+[v3: Fix compiler warning]
+
+Reviewed-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/Kconfig | 8 ++++++++
+ arch/x86/xen/mmu.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 46 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
+index 5b54892..e4343fe 100644
+--- a/arch/x86/xen/Kconfig
++++ b/arch/x86/xen/Kconfig
+@@ -48,3 +48,11 @@ config XEN_DEBUG_FS
+ help
+ Enable statistics output and various tuning options in debugfs.
+ Enabling this option may incur a significant performance overhead.
++
++config XEN_DEBUG
++ bool "Enable Xen debug checks"
++ depends on XEN
++ default n
++ help
++ Enable various WARN_ON checks in the Xen MMU code.
++ Enabling this option WILL incur a significant performance overhead.
+diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
+index b13b6ca..0c376a2 100644
+--- a/arch/x86/xen/mmu.c
++++ b/arch/x86/xen/mmu.c
+@@ -547,6 +547,41 @@ pte_t xen_make_pte(pteval_t pte)
}
+ PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
--static inline int netbk_max_required_rx_slots(struct xen_netif *netif)
-+static inline int xenvif_max_required_rx_slots(struct xenvif *vif)
++#ifdef CONFIG_XEN_DEBUG
++pte_t xen_make_pte_debug(pteval_t pte)
++{
++ phys_addr_t addr = (pte & PTE_PFN_MASK);
++ phys_addr_t other_addr;
++ bool io_page = false;
++ pte_t _pte;
++
++ if (pte & _PAGE_IOMAP)
++ io_page = true;
++
++ _pte = xen_make_pte(pte);
++
++ if (!addr)
++ return _pte;
++
++ if (io_page &&
++ (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
++ other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
++ WARN(addr != other_addr,
++ "0x%lx is using VM_IO, but it is 0x%lx!\n",
++ (unsigned long)addr, (unsigned long)other_addr);
++ } else {
++ pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
++ other_addr = (_pte.pte & PTE_PFN_MASK);
++ WARN((addr == other_addr) && (!io_page) && (!iomap_set),
++ "0x%lx is missing VM_IO (and wasn't fixed)!\n",
++ (unsigned long)addr);
++ }
++
++ return _pte;
++}
++PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
++#endif
++
+ pgd_t xen_make_pgd(pgdval_t pgd)
{
-- if (netif->can_sg || netif->gso || netif->gso_prefix)
-+ if (vif->can_sg || vif->gso || vif->gso_prefix)
- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
- return 1; /* all in one */
- }
+ pgd = pte_pfn_to_mfn(pgd);
+@@ -1957,6 +1992,9 @@ __init void xen_ident_map_ISA(void)
--static inline int netbk_queue_full(struct xen_netif *netif)
-+static inline int xenvif_queue_full(struct xenvif *vif)
+ static __init void xen_post_allocator_init(void)
+ {
++#ifdef CONFIG_XEN_DEBUG
++ pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
++#endif
+ pv_mmu_ops.set_pte = xen_set_pte;
+ pv_mmu_ops.set_pmd = xen_set_pmd;
+ pv_mmu_ops.set_pud = xen_set_pud;
+--
+1.7.4
+
+
+From 5c560d90ed68b399d5020692d38e6cc77db4f6d0 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Fri, 14 Jan 2011 17:55:44 -0500
+Subject: [PATCH 106/203] xen/m2p: No need to catch exceptions when we know that there is
no RAM
+
+.. beyound what we think is the end of memory. However there might
+be more System RAM - but assigned to a guest. Hence jump to the
+M2P override check and consult.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/include/asm/xen/page.h | 6 +++++-
+ 1 files changed, 5 insertions(+), 1 deletions(-)
+
+diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
+index 78ebbeb..1957070 100644
+--- a/arch/x86/include/asm/xen/page.h
++++ b/arch/x86/include/asm/xen/page.h
+@@ -85,6 +85,10 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return mfn;
+
++ if (unlikely((mfn >> machine_to_phys_order) != 0)) {
++ pfn = ~0;
++ goto try_override;
++ }
+ pfn = 0;
+ /*
+ * The array access can fail (e.g., device space beyond end of RAM).
+@@ -92,7 +96,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
+ * but we must handle the fault without crashing!
+ */
+ __get_user(pfn, &machine_to_phys_mapping[mfn]);
+-
++try_override:
+ /*
+ * If this appears to be a foreign mfn (because the pfn
+ * doesn't map back to the mfn), then check the local override
+--
+1.7.4
+
+
+From ba114b8b8112f1fa4b14c929a85ebf51c9c1a749 Mon Sep 17 00:00:00 2001
+From: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Date: Wed, 2 Feb 2011 18:32:59 +0000
+Subject: [PATCH 107/203] xen/m2p: Check whether the MFN has IDENTITY_FRAME bit set..
+
+If there is no proper PFN value in the M2P for the MFN
+(so we get 0xFFFFF.. or 0x55555, or 0x0), we should
+consult the M2P override to see if there is an entry for this.
+[Note: we also consult the M2P override if the MFN
+is past our machine_to_phys size].
+
+We consult the P2M with the PFN. In case the returned
+MFN is one of the special values: 0xFFF.., 0x5555
+(which signify that the MFN can be either "missing" or it
+belongs to DOMID_IO) or the p2m(m2p(mfn)) != mfn, we check
+the M2P override. If we fail the M2P override check, we reset
+the PFN value to INVALID_P2M_ENTRY.
+
+Next we try to find the MFN in the P2M using the MFN
+value (not the PFN value) and if found, we know
+that this MFN is an identity value and return it as so.
+
+Otherwise we have exhausted all the posibilities and we
+return the PFN, which at this stage can either be a real
+PFN value found in the machine_to_phys.. array, or
+INVALID_P2M_ENTRY value.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/include/asm/xen/page.h | 29 ++++++++++++++++++++++-------
+ 1 files changed, 22 insertions(+), 7 deletions(-)
+
+diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
+index 1957070..c61934f 100644
+--- a/arch/x86/include/asm/xen/page.h
++++ b/arch/x86/include/asm/xen/page.h
+@@ -81,6 +81,7 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn)
+ static inline unsigned long mfn_to_pfn(unsigned long mfn)
{
-- RING_IDX peek = netif->rx_req_cons_peek;
-- RING_IDX needed = netbk_max_required_rx_slots(netif);
-+ RING_IDX peek = vif->rx_req_cons_peek;
-+ RING_IDX needed = xenvif_max_required_rx_slots(vif);
+ unsigned long pfn;
++ int ret = 0;
-- return ((netif->rx.sring->req_prod - peek) < needed) ||
-- ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
-+ return ((vif->rx.sring->req_prod - peek) < needed) ||
-+ ((vif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
- }
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return mfn;
+@@ -95,15 +96,29 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
+ * In such cases it doesn't matter what we return (we return garbage),
+ * but we must handle the fault without crashing!
+ */
+- __get_user(pfn, &machine_to_phys_mapping[mfn]);
++ ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
+ try_override:
+- /*
+- * If this appears to be a foreign mfn (because the pfn
+- * doesn't map back to the mfn), then check the local override
+- * table to see if there's a better pfn to use.
++ /* ret might be < 0 if there are no entries in the m2p for mfn */
++ if (ret < 0)
++ pfn = ~0;
++ else if (get_phys_to_machine(pfn) != mfn)
++ /*
++ * If this appears to be a foreign mfn (because the pfn
++ * doesn't map back to the mfn), then check the local override
++ * table to see if there's a better pfn to use.
++ *
++ * m2p_find_override_pfn returns ~0 if it doesn't find anything.
++ */
++ pfn = m2p_find_override_pfn(mfn, ~0);
++
++ /*
++ * pfn is ~0 if there are no entries in the m2p for mfn or if the
++ * entry doesn't map back to the mfn and m2p_override doesn't have a
++ * valid entry for it.
+ */
+- if (get_phys_to_machine(pfn) != mfn)
+- pfn = m2p_find_override_pfn(mfn, pfn);
++ if (pfn == ~0 &&
++ get_phys_to_machine(mfn) == IDENTITY_FRAME(mfn))
++ pfn = mfn;
- /*
-@@ -430,7 +430,7 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int
head)
- * the guest. This function is essentially a dry run of
- * netbk_gop_frag_copy.
- */
--static unsigned int count_skb_slots(struct sk_buff *skb, struct xen_netif *netif)
-+static unsigned int count_skb_slots(struct sk_buff *skb, struct xenvif *vif)
- {
- unsigned int count = 1;
- int i, copy_off = 0;
-@@ -464,20 +464,20 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xen_netif *netif
- return count;
+ return pfn;
}
+--
+1.7.4
+
+
+From d0783a02ef1bf28650f789b5b37ec1df42b53821 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 9 Dec 2010 15:01:11 -0500
+Subject: [PATCH 108/203] xen/irq: Don't fall over when nr_irqs_gsi > nr_irqs.
+
+This scenario where the nr_irq_gsi is greater than nr_irqs
+is rather strange but lets still try to survive. Make sure
+to print a warning so the user wouldn't be surprised in case
+things don't work.
+
+Solves a bootup-crash when booting Xen and Linux under QEMU.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 7468147..6de2d76 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -414,6 +414,7 @@ static int find_unbound_irq(void)
+ if (bottom == nr_irqs)
+ goto no_irqs;
--int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
-- struct xen_netif *netif = netdev_priv(dev);
-+ struct xenvif *vif = netdev_priv(dev);
- struct xen_netbk *netbk;
-
- BUG_ON(skb->dev != dev);
-
-- if (netif->group == -1)
-+ if (vif->group == -1)
- goto drop;
++retry:
+ /* This loop starts from the top of IRQ space and goes down.
+ * We need this b/c if we have a PCI device in a Xen PV guest
+ * we do not have an IO-APIC (though the backend might have them)
+@@ -437,6 +438,14 @@ static int find_unbound_irq(void)
+ goto no_irqs;
-- netbk = &xen_netbk[netif->group];
-+ netbk = &xen_netbk[vif->group];
+ res = irq_alloc_desc_at(irq, -1);
++ if (res == -EEXIST) {
++ top--;
++ if (bottom > top)
++ printk(KERN_ERR "Eating in GSI/MSI space (%d)!" \
++ " Your PCI device might not work!\n", top);
++ if (top > NR_IRQS_LEGACY)
++ goto retry;
++ }
- /* Drop the packet if the target domain has no receive buffers. */
-- if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
-+ if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
- goto drop;
+ if (WARN_ON(res != irq))
+ return -1;
+--
+1.7.4
+
+
+From 4ab08528537b78a1b9696e9b2757d0e818d157a0 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 11 Jan 2011 17:20:13 +0000
+Subject: [PATCH 109/203] xen: handled remapped IRQs when enabling a pcifront PCI device.
+
+This happens to not be an issue currently because we take pains to try
+to ensure that the GSI-IRQ mapping is 1-1 in a PV guest and that
+regular event channels do not clash. However a subsequent patch is
+going to break this 1-1 mapping.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+---
+ arch/x86/pci/xen.c | 22 ++++++++++++++--------
+ 1 files changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 25cd4a0..2a12f3d 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -226,21 +226,27 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
+ {
+ int rc;
+ int share = 1;
++ u8 gsi;
- /*
-@@ -496,14 +496,14 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- }
+- dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
+-
+- if (dev->irq < 0)
+- return -EINVAL;
++ rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi);
++ if (rc < 0) {
++ dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n",
++ rc);
++ return rc;
++ }
- /* Reserve ring slots for the worst-case number of fragments. */
-- netif->rx_req_cons_peek += count_skb_slots(skb, netif);
-- netif_get(netif);
-+ vif->rx_req_cons_peek += count_skb_slots(skb, vif);
-+ xenvif_get(vif);
+- if (dev->irq < NR_IRQS_LEGACY)
++ if (gsi < NR_IRQS_LEGACY)
+ share = 0;
-- if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
-- netif->rx.sring->req_event = netif->rx_req_cons_peek +
-- netbk_max_required_rx_slots(netif);
-+ if (netbk_can_queue(dev) && xenvif_queue_full(vif)) {
-+ vif->rx.sring->req_event = vif->rx_req_cons_peek +
-+ xenvif_max_required_rx_slots(vif);
- mb(); /* request notification /then/ check & stop the queue */
-- if (netbk_queue_full(netif))
-+ if (xenvif_queue_full(vif))
- netif_stop_queue(dev);
+- rc = xen_allocate_pirq(dev->irq, share, "pcifront");
++ rc = xen_allocate_pirq(gsi, share, "pcifront");
+ if (rc < 0) {
+- dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
+- dev->irq, rc);
++ dev_warn(&dev->dev, "Xen PCI: failed to register GSI%d: %d\n",
++ gsi, rc);
+ return rc;
}
- skb_queue_tail(&netbk->rx_queue, skb);
-@@ -513,7 +513,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
++
++ dev->irq = rc;
++ dev_info(&dev->dev, "Xen PCI mapped GSI%d to IRQ%d\n", gsi,
dev->irq);
return 0;
+ }
- drop:
-- netif->stats.tx_dropped++;
-+ vif->stats.tx_dropped++;
- dev_kfree_skb(skb);
- return 0;
+--
+1.7.4
+
+
+From 449913e7b40a40602cdc080ef3958736077d2914 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 11 Jan 2011 17:20:14 +0000
+Subject: [PATCH 110/203] xen:events: move find_unbound_irq inside CONFIG_PCI_MSI
+
+The only caller is xen_allocate_pirq_msi which is also under this
+ifdef so this fixes:
+ drivers/xen/events.c:377: warning: 'find_unbound_pirq' defined but not used
+when CONFIG_PCI_MSI=n
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+---
+ drivers/xen/events.c | 34 +++++++++++++++++-----------------
+ 1 files changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 6de2d76..8e28c01 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -387,23 +387,6 @@ static int get_nr_hw_irqs(void)
+ return ret;
}
-@@ -527,13 +527,13 @@ struct netrx_pending_operations {
- grant_ref_t copy_gref;
- };
--static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif *netif,
-+static struct netbk_rx_meta *get_next_rx_buffer(struct xenvif *vif,
- struct netrx_pending_operations *npo)
+-static int find_unbound_pirq(int type)
+-{
+- int rc, i;
+- struct physdev_get_free_pirq op_get_free_pirq;
+- op_get_free_pirq.type = type;
+-
+- rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
+- if (!rc)
+- return op_get_free_pirq.pirq;
+-
+- for (i = 0; i < nr_irqs; i++) {
+- if (pirq_to_irq[i] < 0)
+- return i;
+- }
+- return -1;
+-}
+-
+ static int find_unbound_irq(void)
{
- struct netbk_rx_meta *meta;
- struct xen_netif_rx_request *req;
-
-- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
-
- meta = npo->meta + npo->meta_prod++;
- meta->gso_size = 0;
-@@ -550,7 +550,7 @@ static struct netbk_rx_meta *get_next_rx_buffer(struct xen_netif
*netif,
- * 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 netbk_gop_frag_copy(struct xen_netif *netif,
-+static void netbk_gop_frag_copy(struct xenvif *vif,
- struct netrx_pending_operations *npo,
- struct page *page, unsigned long size,
- unsigned long offset, int head)
-@@ -580,7 +580,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- */
- BUG_ON(head);
-
-- meta = get_next_rx_buffer(netif, npo);
-+ meta = get_next_rx_buffer(vif, npo);
- }
-
- bytes = size;
-@@ -595,7 +595,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
-
- src_pend = &netbk->pending_tx_info[idx];
-
-- copy_gop->source.domid = src_pend->netif->domid;
-+ copy_gop->source.domid = src_pend->vif->domid;
- copy_gop->source.u.ref = src_pend->req.gref;
- copy_gop->flags |= GNTCOPY_source_gref;
- } else {
-@@ -604,7 +604,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- copy_gop->source.u.gmfn = virt_to_mfn(vaddr);
- }
- copy_gop->source.offset = offset;
-- copy_gop->dest.domid = netif->domid;
-+ copy_gop->dest.domid = vif->domid;
+ struct irq_data *data;
+@@ -686,6 +669,23 @@ out:
+ #include <linux/msi.h>
+ #include "../pci/msi.h"
- copy_gop->dest.offset = npo->copy_off;
- copy_gop->dest.u.ref = npo->copy_gref;
-@@ -634,7 +634,7 @@ static void netbk_gop_frag_copy(struct xen_netif *netif,
- static int netbk_gop_skb(struct sk_buff *skb,
- struct netrx_pending_operations *npo)
++static int find_unbound_pirq(int type)
++{
++ int rc, i;
++ struct physdev_get_free_pirq op_get_free_pirq;
++ op_get_free_pirq.type = type;
++
++ rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
++ if (!rc)
++ return op_get_free_pirq.pirq;
++
++ for (i = 0; i < nr_irqs; i++) {
++ if (pirq_to_irq[i] < 0)
++ return i;
++ }
++ return -1;
++}
++
+ void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
{
-- struct xen_netif *netif = netdev_priv(skb->dev);
-+ struct xenvif *vif = netdev_priv(skb->dev);
- int nr_frags = skb_shinfo(skb)->nr_frags;
- int i;
- struct xen_netif_rx_request *req;
-@@ -644,18 +644,18 @@ static int netbk_gop_skb(struct sk_buff *skb,
- old_meta_prod = npo->meta_prod;
-
- /* Set up a GSO prefix descriptor, if necessary */
-- if (skb_shinfo(skb)->gso_size && netif->gso_prefix) {
-- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ if (skb_shinfo(skb)->gso_size && vif->gso_prefix) {
-+ req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
- meta = npo->meta + npo->meta_prod++;
- meta->gso_size = skb_shinfo(skb)->gso_size;
- meta->size = 0;
- meta->id = req->id;
- }
-
-- req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons++);
-+ req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
- meta = npo->meta + npo->meta_prod++;
-
-- if (!netif->gso_prefix)
-+ if (!vif->gso_prefix)
- meta->gso_size = skb_shinfo(skb)->gso_size;
- else
- meta->gso_size = 0;
-@@ -665,17 +665,16 @@ static int netbk_gop_skb(struct sk_buff *skb,
- npo->copy_off = 0;
- npo->copy_gref = req->gref;
-
-- netbk_gop_frag_copy(netif,
-- npo, virt_to_page(skb->data),
-+ netbk_gop_frag_copy(vif, npo, virt_to_page(skb->data),
- skb_headlen(skb),
- offset_in_page(skb->data), 1);
-
- /* Leave a gap for the GSO descriptor. */
-- if (skb_shinfo(skb)->gso_size && !netif->gso_prefix)
-- netif->rx.req_cons++;
-+ if (skb_shinfo(skb)->gso_size && !vif->gso_prefix)
-+ vif->rx.req_cons++;
-
- for (i = 0; i < nr_frags; i++) {
-- netbk_gop_frag_copy(netif, npo,
-+ netbk_gop_frag_copy(vif, npo,
- skb_shinfo(skb)->frags[i].page,
- skb_shinfo(skb)->frags[i].size,
- skb_shinfo(skb)->frags[i].page_offset,
-@@ -710,7 +709,7 @@ static int netbk_check_gop(int nr_meta_slots, domid_t domid,
- return status;
+ spin_lock(&irq_mapping_update_lock);
+--
+1.7.4
+
+
+From 5a61eb864cdd63b8db29da707aa8e33b8dd54578 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 11 Jan 2011 17:20:15 +0000
+Subject: [PATCH 111/203] xen: events: add xen_allocate_irq_{dynamic, gsi} and
xen_free_irq
+
+This is neater than open-coded calls to irq_alloc_desc_at and
+irq_free_desc.
+
+No intended behavioural change.
+
+Note that we previously were not checking the return value of
+irq_alloc_desc_at which would be failing for GSI<NR_IRQS_LEGACY
+because the core architecture code has already allocated those for
+us. Hence the additional check against NR_IRQS_LEGACY in
+xen_allocate_irq_gsi.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+---
+ drivers/xen/events.c | 53 +++++++++++++++++++++++++++++++++-----------------
+ 1 files changed, 35 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 8e28c01..e74bdcf 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -387,7 +387,7 @@ static int get_nr_hw_irqs(void)
+ return ret;
}
--static void netbk_add_frag_responses(struct xen_netif *netif, int status,
-+static void netbk_add_frag_responses(struct xenvif *vif, int status,
- struct netbk_rx_meta *meta,
- int nr_meta_slots)
+-static int find_unbound_irq(void)
++static int xen_allocate_irq_dynamic(void)
{
-@@ -731,7 +730,7 @@ static void netbk_add_frag_responses(struct xen_netif *netif, int
status,
- flags = XEN_NETRXF_more_data;
-
- offset = 0;
-- make_rx_response(netif, meta[i].id, status, offset,
-+ make_rx_response(vif, meta[i].id, status, offset,
- meta[i].size, flags);
- }
+ struct irq_data *data;
+ int irq, res;
+@@ -445,6 +445,30 @@ static bool identity_mapped_irq(unsigned irq)
+ return irq < get_nr_hw_irqs();
}
-@@ -742,7 +741,7 @@ struct skb_cb_overlay {
- static void xen_netbk_rx_action(unsigned long data)
++static int xen_allocate_irq_gsi(unsigned gsi)
++{
++ int irq;
++
++ if (!identity_mapped_irq(gsi) &&
++ (xen_initial_domain() || !xen_pv_domain()))
++ return xen_allocate_irq_dynamic();
++
++ /* Legacy IRQ descriptors are already allocated by the arch. */
++ if (gsi < NR_IRQS_LEGACY)
++ return gsi;
++
++ irq = irq_alloc_desc_at(gsi, -1);
++ if (irq < 0)
++ panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq);
++
++ return irq;
++}
++
++static void xen_free_irq(unsigned irq)
++{
++ irq_free_desc(irq);
++}
++
+ static void pirq_unmask_notify(int irq)
{
-- struct xen_netif *netif = NULL;
-+ struct xenvif *vif = NULL;
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- s8 status;
- u16 irq, flags;
-@@ -766,7 +765,7 @@ static void xen_netbk_rx_action(unsigned long data)
- count = 0;
-
- while ((skb = skb_dequeue(&netbk->rx_queue)) != NULL) {
-- netif = netdev_priv(skb->dev);
-+ vif = netdev_priv(skb->dev);
- nr_frags = skb_shinfo(skb)->nr_frags;
-
- sco = (struct skb_cb_overlay *)skb->cb;
-@@ -794,11 +793,11 @@ static void xen_netbk_rx_action(unsigned long data)
- while ((skb = __skb_dequeue(&rxq)) != NULL) {
- sco = (struct skb_cb_overlay *)skb->cb;
-
-- netif = netdev_priv(skb->dev);
-+ vif = netdev_priv(skb->dev);
+ struct physdev_eoi eoi = { .irq = pirq_from_irq(irq) };
+@@ -630,14 +654,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable,
char *name)
+ goto out; /* XXX need refcount? */
+ }
-- if (netbk->meta[npo.meta_cons].gso_size && netif->gso_prefix) {
-- resp = RING_GET_RESPONSE(&netif->rx,
-- netif->rx.rsp_prod_pvt++);
-+ if (netbk->meta[npo.meta_cons].gso_size && vif->gso_prefix) {
-+ resp = RING_GET_RESPONSE(&vif->rx,
-+ vif->rx.rsp_prod_pvt++);
+- /* If we are a PV guest, we don't have GSIs (no ACPI passed). Therefore
+- * we are using the !xen_initial_domain() to drop in the function.*/
+- if (identity_mapped_irq(gsi) || (!xen_initial_domain() &&
+- xen_pv_domain())) {
+- irq = gsi;
+- irq_alloc_desc_at(irq, -1);
+- } else
+- irq = find_unbound_irq();
++ irq = xen_allocate_irq_gsi(gsi);
- resp->flags = XEN_NETRXF_gso_prefix | XEN_NETRXF_more_data;
+ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+ handle_level_irq, name);
+@@ -650,7 +667,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char
*name)
+ * this in the priv domain. */
+ if (xen_initial_domain() &&
+ HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) {
+- irq_free_desc(irq);
++ xen_free_irq(irq);
+ irq = -ENOSPC;
+ goto out;
+ }
+@@ -691,7 +708,7 @@ void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int
alloc)
+ spin_lock(&irq_mapping_update_lock);
-@@ -811,11 +810,11 @@ static void xen_netbk_rx_action(unsigned long data)
- }
+ if (alloc & XEN_ALLOC_IRQ) {
+- *irq = find_unbound_irq();
++ *irq = xen_allocate_irq_dynamic();
+ if (*irq == -1)
+ goto out;
+ }
+@@ -741,7 +758,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
+ spin_lock(&irq_mapping_update_lock);
-- netif->stats.tx_bytes += skb->len;
-- netif->stats.tx_packets++;
-+ vif->stats.tx_bytes += skb->len;
-+ vif->stats.tx_packets++;
+- irq = find_unbound_irq();
++ irq = xen_allocate_irq_dynamic();
- status = netbk_check_gop(sco->meta_slots_used,
-- netif->domid, &npo);
-+ vif->domid, &npo);
+ if (irq == -1)
+ goto out;
+@@ -750,7 +767,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
+ if (rc) {
+ printk(KERN_WARNING "xen map irq failed %d\n", rc);
- if (sco->meta_slots_used == 1)
- flags = 0;
-@@ -829,16 +828,16 @@ static void xen_netbk_rx_action(unsigned long data)
- flags |= XEN_NETRXF_data_validated;
+- irq_free_desc(irq);
++ xen_free_irq(irq);
- offset = 0;
-- resp = make_rx_response(netif, netbk->meta[npo.meta_cons].id,
-+ resp = make_rx_response(vif, netbk->meta[npo.meta_cons].id,
- status, offset,
- netbk->meta[npo.meta_cons].size,
- flags);
+ irq = -1;
+ goto out;
+@@ -792,7 +809,7 @@ int xen_destroy_irq(int irq)
+ }
+ irq_info[irq] = mk_unbound_info();
-- if (netbk->meta[npo.meta_cons].gso_size && !netif->gso_prefix) {
-+ if (netbk->meta[npo.meta_cons].gso_size && !vif->gso_prefix) {
- struct xen_netif_extra_info *gso =
- (struct xen_netif_extra_info *)
-- RING_GET_RESPONSE(&netif->rx,
-- netif->rx.rsp_prod_pvt++);
-+ RING_GET_RESPONSE(&vif->rx,
-+ vif->rx.rsp_prod_pvt++);
+- irq_free_desc(irq);
++ xen_free_irq(irq);
- resp->flags |= XEN_NETRXF_extra_info;
+ out:
+ spin_unlock(&irq_mapping_update_lock);
+@@ -823,7 +840,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
+ irq = evtchn_to_irq[evtchn];
-@@ -851,23 +850,23 @@ static void xen_netbk_rx_action(unsigned long data)
- gso->flags = 0;
- }
+ if (irq == -1) {
+- irq = find_unbound_irq();
++ irq = xen_allocate_irq_dynamic();
-- netbk_add_frag_responses(netif, status,
-+ netbk_add_frag_responses(vif, status,
- netbk->meta + npo.meta_cons + 1,
- sco->meta_slots_used);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_fasteoi_irq, "event");
+@@ -848,7 +865,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+ irq = per_cpu(ipi_to_irq, cpu)[ipi];
-- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
-- irq = netif->irq;
-+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
-+ irq = vif->irq;
- if (ret && !netbk->rx_notify[irq]) {
- netbk->rx_notify[irq] = 1;
- netbk->notify_list[notify_nr++] = irq;
- }
+ if (irq == -1) {
+- irq = find_unbound_irq();
++ irq = xen_allocate_irq_dynamic();
+ if (irq < 0)
+ goto out;
-- if (netif_queue_stopped(netif->dev) &&
-- netif_schedulable(netif) &&
-- !netbk_queue_full(netif))
-- netif_wake_queue(netif->dev);
-+ if (netif_queue_stopped(vif->dev) &&
-+ xenvif_schedulable(vif) &&
-+ !xenvif_queue_full(vif))
-+ netif_wake_queue(vif->dev);
+@@ -884,7 +901,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+ irq = per_cpu(virq_to_irq, cpu)[virq];
-- netif_put(netif);
-+ xenvif_put(vif);
- npo.meta_cons += sco->meta_slots_used;
- dev_kfree_skb(skb);
- }
-@@ -890,93 +889,92 @@ static void net_alarm(unsigned long data)
- xen_netbk_bh_handler(netbk, 1);
- }
+ if (irq == -1) {
+- irq = find_unbound_irq();
++ irq = xen_allocate_irq_dynamic();
--static void netbk_tx_pending_timeout(unsigned long data)
-+static void xen_netbk_tx_pending_timeout(unsigned long data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- xen_netbk_bh_handler(netbk, 0);
- }
+ set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
+ handle_percpu_irq, "virq");
+@@ -943,7 +960,7 @@ static void unbind_from_irq(unsigned int irq)
+ if (irq_info[irq].type != IRQT_UNBOUND) {
+ irq_info[irq] = mk_unbound_info();
--struct net_device_stats *netif_be_get_stats(struct net_device *dev)
-+struct net_device_stats *xenvif_get_stats(struct net_device *dev)
- {
-- struct xen_netif *netif = netdev_priv(dev);
-- return &netif->stats;
-+ struct xenvif *vif = netdev_priv(dev);
-+ return &vif->stats;
- }
+- irq_free_desc(irq);
++ xen_free_irq(irq);
+ }
--static int __on_net_schedule_list(struct xen_netif *netif)
-+static int __on_net_schedule_list(struct xenvif *vif)
- {
-- return !list_empty(&netif->list);
-+ return !list_empty(&vif->list);
+ spin_unlock(&irq_mapping_update_lock);
+--
+1.7.4
+
+
+From 026c9d2d0d75ec51b251aac4ca8855f4fae6af23 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Tue, 11 Jan 2011 17:20:16 +0000
+Subject: [PATCH 112/203] xen: events: allocate GSIs and dynamic IRQs from separate IRQ
ranges.
+
+There are three cases which we need to care about, PV guest, PV domain
+0 and HVM guest.
+
+The PV guest case is simple since it has no access to ACPI or real
+APICs and therefore has no GSIs therefore we simply dynamically
+allocate all IRQs. The potentially interesting case here is PIRQ type
+event channels associated with passed through PCI devices. However
+even in this case the guest has no direct interaction with the
+physical GSI since that happens in the PCI backend.
+
+The PV domain 0 and HVM guest cases are actually the same. In domain 0
+case the kernel sees the host ACPI and GSIs (although it only sees the
+APIC indirectly via the hypervisor) and in the HVM guest case it sees
+the virtualised ACPI and emulated APICs. In these cases we start
+allocating dynamic IRQs at nr_irqs_gsi so that they cannot clash with
+any GSI.
+
+Currently xen_allocate_irq_dynamic starts at nr_irqs and works
+backwards looking for a free IRQ in order to (try and) avoid clashing
+with GSIs used in domain 0 and in HVM guests. This change avoids that
+although we retain the behaviour of allowing dynamic IRQs to encroach
+on the GSI range if no suitable IRQs are available since a future IRQ
+clash is deemed preferable to failure right now.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+---
+ drivers/xen/events.c | 84 +++++++++++++++----------------------------------
+ 1 files changed, 26 insertions(+), 58 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index e74bdcf..06f2e61 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -376,81 +376,49 @@ static void unmask_evtchn(int port)
+ put_cpu();
}
- /* Must be called with net_schedule_list_lock held */
--static void remove_from_net_schedule_list(struct xen_netif *netif)
-+static void remove_from_net_schedule_list(struct xenvif *vif)
+-static int get_nr_hw_irqs(void)
++static int xen_allocate_irq_dynamic(void)
{
-- if (likely(__on_net_schedule_list(netif))) {
-- list_del_init(&netif->list);
-- netif_put(netif);
-+ if (likely(__on_net_schedule_list(vif))) {
-+ list_del_init(&vif->list);
-+ xenvif_put(vif);
- }
- }
+- int ret = 1;
++ int first = 0;
++ int irq;
--static struct xen_netif *poll_net_schedule_list(struct xen_netbk *netbk)
-+static struct xenvif *poll_net_schedule_list(struct xen_netbk *netbk)
- {
-- struct xen_netif *netif = NULL;
-+ struct xenvif *vif = NULL;
+ #ifdef CONFIG_X86_IO_APIC
+- ret = get_nr_irqs_gsi();
++ /*
++ * For an HVM guest or domain 0 which see "real" (emulated or
++ * actual repectively) GSIs we allocate dynamic IRQs
++ * e.g. those corresponding to event channels or MSIs
++ * etc. from the range above those "real" GSIs to avoid
++ * collisions.
++ */
++ if (xen_initial_domain() || xen_hvm_domain())
++ first = get_nr_irqs_gsi();
+ #endif
- spin_lock_irq(&netbk->net_schedule_list_lock);
- if (list_empty(&netbk->net_schedule_list))
- goto out;
+- return ret;
+-}
+-
+-static int xen_allocate_irq_dynamic(void)
+-{
+- struct irq_data *data;
+- int irq, res;
+- int bottom = get_nr_hw_irqs();
+- int top = nr_irqs-1;
+-
+- if (bottom == nr_irqs)
+- goto no_irqs;
+-
+ retry:
+- /* This loop starts from the top of IRQ space and goes down.
+- * We need this b/c if we have a PCI device in a Xen PV guest
+- * we do not have an IO-APIC (though the backend might have them)
+- * mapped in. To not have a collision of physical IRQs with the Xen
+- * event channels start at the top of the IRQ space for virtual IRQs.
+- */
+- for (irq = top; irq > bottom; irq--) {
+- data = irq_get_irq_data(irq);
+- /* only 15->0 have init'd desc; handle irq > 16 */
+- if (!data)
+- break;
+- if (data->chip == &no_irq_chip)
+- break;
+- if (data->chip != &xen_dynamic_chip)
+- continue;
+- if (irq_info[irq].type == IRQT_UNBOUND)
+- return irq;
+- }
++ irq = irq_alloc_desc_from(first, -1);
-- netif = list_first_entry(&netbk->net_schedule_list,
-- struct xen_netif, list);
-- if (!netif)
-+ vif = list_first_entry(&netbk->net_schedule_list,
-+ struct xenvif, list);
-+ if (!vif)
- goto out;
+- if (irq == bottom)
+- goto no_irqs;
+-
+- res = irq_alloc_desc_at(irq, -1);
+- if (res == -EEXIST) {
+- top--;
+- if (bottom > top)
+- printk(KERN_ERR "Eating in GSI/MSI space (%d)!" \
+- " Your PCI device might not work!\n", top);
+- if (top > NR_IRQS_LEGACY)
+- goto retry;
++ if (irq == -ENOMEM && first > NR_IRQS_LEGACY) {
++ printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should
increase nr_irqs\n");
++ first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY);
++ goto retry;
+ }
-- netif_get(netif);
-+ xenvif_get(vif);
+- if (WARN_ON(res != irq))
+- return -1;
++ if (irq < 0)
++ panic("No available IRQ to bind to: increase nr_irqs!\n");
-- remove_from_net_schedule_list(netif);
-+ remove_from_net_schedule_list(vif);
- out:
- spin_unlock_irq(&netbk->net_schedule_list_lock);
-- return netif;
-+ return vif;
+ return irq;
+-
+-no_irqs:
+- panic("No available IRQ to bind to: increase nr_irqs!\n");
+-}
+-
+-static bool identity_mapped_irq(unsigned irq)
+-{
+- /* identity map all the hardware irqs */
+- return irq < get_nr_hw_irqs();
}
--static void add_to_net_schedule_list_tail(struct xen_netif *netif)
-+static void add_to_net_schedule_list_tail(struct xenvif *vif)
+ static int xen_allocate_irq_gsi(unsigned gsi)
{
- unsigned long flags;
+ int irq;
-- struct xen_netbk *netbk = &xen_netbk[netif->group];
-- if (__on_net_schedule_list(netif))
-+ struct xen_netbk *netbk = &xen_netbk[vif->group];
-+ if (__on_net_schedule_list(vif))
- return;
+- if (!identity_mapped_irq(gsi) &&
+- (xen_initial_domain() || !xen_pv_domain()))
++ /*
++ * A PV guest has no concept of a GSI (since it has no ACPI
++ * nor access to/knowledge of the physical APICs). Therefore
++ * all IRQs are dynamically allocated from the entire IRQ
++ * space.
++ */
++ if (xen_pv_domain() && !xen_initial_domain())
+ return xen_allocate_irq_dynamic();
- spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
-- if (!__on_net_schedule_list(netif) &&
-- likely(netif_schedulable(netif))) {
-- list_add_tail(&netif->list, &netbk->net_schedule_list);
-- netif_get(netif);
-+ if (!__on_net_schedule_list(vif) &&
-+ likely(xenvif_schedulable(vif))) {
-+ list_add_tail(&vif->list, &netbk->net_schedule_list);
-+ xenvif_get(vif);
- }
- spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
- }
+ /* Legacy IRQ descriptors are already allocated by the arch. */
+--
+1.7.4
+
+
+From d042c4b63ab93fb3089f2cc9f6628ab91b7b4073 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
+Date: Thu, 3 Feb 2011 09:49:35 +0000
+Subject: [PATCH 113/203] xen: events: do not free legacy IRQs
+
+c514d00c8057 "xen: events: add xen_allocate_irq_{dynamic, gsi} and
+xen_free_irq" correctly avoids reallocating legacy IRQs (which are
+managed by the arch core) but erroneously did not prevent them being
+freed.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 06f2e61..accb37a 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -434,6 +434,10 @@ static int xen_allocate_irq_gsi(unsigned gsi)
--void netif_schedule_work(struct xen_netif *netif)
-+void xenvif_schedule_work(struct xenvif *vif)
+ static void xen_free_irq(unsigned irq)
{
-- struct xen_netbk *netbk = &xen_netbk[netif->group];
-+ struct xen_netbk *netbk = &xen_netbk[vif->group];
- int more_to_do;
-
-- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-+ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
-
- if (more_to_do) {
-- add_to_net_schedule_list_tail(netif);
-+ add_to_net_schedule_list_tail(vif);
- maybe_schedule_tx_action(netbk);
- }
++ /* Legacy IRQ descriptors are managed by the arch. */
++ if (irq < NR_IRQS_LEGACY)
++ return;
++
+ irq_free_desc(irq);
}
--void netif_deschedule_work(struct xen_netif *netif)
-+void xenvif_deschedule_work(struct xenvif *vif)
- {
-- struct xen_netbk *netbk = &xen_netbk[netif->group];
-+ struct xen_netbk *netbk = &xen_netbk[vif->group];
- spin_lock_irq(&netbk->net_schedule_list_lock);
-- remove_from_net_schedule_list(netif);
-+ remove_from_net_schedule_list(vif);
- spin_unlock_irq(&netbk->net_schedule_list_lock);
+--
+1.7.4
+
+
+From 6e435118ec43bbd781df48ceef101d8f1a48e699 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx(a)linutronix.de>
+Date: Sat, 5 Feb 2011 20:08:52 +0000
+Subject: [PATCH 114/203] xen: Remove stale irq_chip.end
+
+irq_chip.end got obsolete with the removal of __do_IRQ()
+
+Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
+Acked-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 18 ------------------
+ 1 files changed, 0 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index accb37a..c8826b5 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -555,23 +555,6 @@ static void ack_pirq(unsigned int irq)
+ }
}
+-static void end_pirq(unsigned int irq)
+-{
+- int evtchn = evtchn_from_irq(irq);
+- struct irq_desc *desc = irq_to_desc(irq);
-
--static void tx_add_credit(struct xen_netif *netif)
-+static void tx_add_credit(struct xenvif *vif)
+- if (WARN_ON(!desc))
+- return;
+-
+- if ((desc->status & (IRQ_DISABLED|IRQ_PENDING)) ==
+- (IRQ_DISABLED|IRQ_PENDING)) {
+- shutdown_pirq(irq);
+- } else if (VALID_EVTCHN(evtchn)) {
+- unmask_evtchn(evtchn);
+- pirq_unmask_notify(irq);
+- }
+-}
+-
+ static int find_irq_by_gsi(unsigned gsi)
{
- unsigned long max_burst, max_credit;
-
-@@ -984,23 +982,23 @@ static void tx_add_credit(struct xen_netif *netif)
- * 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(&netif->tx, netif->tx.req_cons)->size;
-+ max_burst = RING_GET_REQUEST(&vif->tx, vif->tx.req_cons)->size;
- max_burst = min(max_burst, 131072UL);
-- max_burst = max(max_burst, netif->credit_bytes);
-+ max_burst = max(max_burst, vif->credit_bytes);
-
- /* Take care that adding a new chunk of credit doesn't wrap to zero. */
-- max_credit = netif->remaining_credit + netif->credit_bytes;
-- if (max_credit < netif->remaining_credit)
-+ max_credit = vif->remaining_credit + vif->credit_bytes;
-+ if (max_credit < vif->remaining_credit)
- max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
+ int irq;
+@@ -1508,7 +1491,6 @@ static struct irq_chip xen_pirq_chip __read_mostly = {
+ .mask = disable_pirq,
-- netif->remaining_credit = min(max_credit, max_burst);
-+ vif->remaining_credit = min(max_credit, max_burst);
- }
+ .ack = ack_pirq,
+- .end = end_pirq,
- static void tx_credit_callback(unsigned long data)
- {
-- struct xen_netif *netif = (struct xen_netif *)data;
-- tx_add_credit(netif);
-- netif_schedule_work(netif);
-+ struct xenvif *vif = (struct xenvif *)data;
-+ tx_add_credit(vif);
-+ xenvif_schedule_work(vif);
- }
+ .set_affinity = set_affinity_irq,
- static inline int copy_pending_req(struct xen_netbk *netbk,
-@@ -1011,7 +1009,7 @@ static inline int copy_pending_req(struct xen_netbk *netbk,
- &netbk->mmap_pages[pending_idx]);
- }
+--
+1.7.4
+
+
+From ab1d37664458dd36cbf7e8a81cc4199b25937142 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx(a)linutronix.de>
+Date: Sat, 5 Feb 2011 20:08:54 +0000
+Subject: [PATCH 115/203] xen: Switch to new irq_chip functions
+
+Convert Xen to the new irq_chip functions. Brings us closer to enable
+CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
+
+Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
+Acked-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 95 +++++++++++++++++++++++++++-----------------------
+ 1 files changed, 51 insertions(+), 44 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index c8826b5..cf1712f 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -277,7 +277,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
--static inline void net_tx_action_dealloc(struct xen_netbk *netbk)
-+static inline void xen_netbk_tx_action_dealloc(struct xen_netbk *netbk)
- {
- struct netbk_tx_pending_inuse *inuse, *n;
- struct gnttab_unmap_grant_ref *gop;
-@@ -1110,34 +1108,34 @@ static inline void net_tx_action_dealloc(struct xen_netbk
*netbk)
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
+ BUG_ON(irq == -1);
+ #ifdef CONFIG_SMP
+- cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
++ cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
+ #endif
-- netif_put(netif);
-+ xenvif_put(vif);
+ clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
+@@ -294,7 +294,7 @@ static void init_evtchn_cpu_bindings(void)
- list_del_init(&inuse->list);
+ /* By default all event channels notify CPU#0. */
+ for_each_irq_desc(i, desc) {
+- cpumask_copy(desc->affinity, cpumask_of(0));
++ cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
}
+ #endif
+
+@@ -474,7 +474,7 @@ static bool probing_irq(int irq)
+ return desc && desc->action == NULL;
}
--static void netbk_tx_err(struct xen_netif *netif,
-- struct xen_netif_tx_request *txp, RING_IDX end)
-+static void netbk_tx_err(struct xenvif *vif,
-+ struct xen_netif_tx_request *txp, RING_IDX end)
+-static unsigned int startup_pirq(unsigned int irq)
++static unsigned int __startup_pirq(unsigned int irq)
{
-- RING_IDX cons = netif->tx.req_cons;
-+ RING_IDX cons = vif->tx.req_cons;
-
- do {
-- make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
-+ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- if (cons >= end)
- break;
-- txp = RING_GET_REQUEST(&netif->tx, cons++);
-+ txp = RING_GET_REQUEST(&vif->tx, cons++);
- } while (1);
-- netif->tx.req_cons = cons;
-- netif_schedule_work(netif);
-- netif_put(netif);
-+ vif->tx.req_cons = cons;
-+ xenvif_schedule_work(vif);
-+ xenvif_put(vif);
+ struct evtchn_bind_pirq bind_pirq;
+ struct irq_info *info = info_for_irq(irq);
+@@ -512,9 +512,15 @@ out:
+ return 0;
}
--static int netbk_count_requests(struct xen_netif *netif,
-+static int netbk_count_requests(struct xenvif *vif,
- struct xen_netif_tx_request *first,
- struct xen_netif_tx_request *txp,
- int work_to_do)
+-static void shutdown_pirq(unsigned int irq)
++static unsigned int startup_pirq(struct irq_data *data)
++{
++ return __startup_pirq(data->irq);
++}
++
++static void shutdown_pirq(struct irq_data *data)
{
-- RING_IDX cons = netif->tx.req_cons;
-+ RING_IDX cons = vif->tx.req_cons;
- int frags = 0;
-
- if (!(first->flags & XEN_NETTXF_more_data))
-@@ -1154,7 +1152,7 @@ static int netbk_count_requests(struct xen_netif *netif,
- return -frags;
- }
+ struct evtchn_close close;
++ unsigned int irq = data->irq;
+ struct irq_info *info = info_for_irq(irq);
+ int evtchn = evtchn_from_irq(irq);
-- memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
-+ memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
- sizeof(*txp));
- if (txp->size > first->size) {
- pr_debug("Frags galore\n");
-@@ -1175,7 +1173,7 @@ static int netbk_count_requests(struct xen_netif *netif,
+@@ -534,20 +540,20 @@ static void shutdown_pirq(unsigned int irq)
+ info->evtchn = 0;
}
- static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
-- struct xen_netif *netif,
-+ struct xenvif *vif,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
- struct gnttab_map_grant_ref *mop)
-@@ -1201,8 +1199,8 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
- txp->gref, netif->domid);
+-static void enable_pirq(unsigned int irq)
++static void enable_pirq(struct irq_data *data)
+ {
+- startup_pirq(irq);
++ startup_pirq(data);
+ }
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
-- netif_get(netif);
-- pending_tx_info[pending_idx].netif = netif;
-+ xenvif_get(vif);
-+ pending_tx_info[pending_idx].vif = vif;
- frags[i].page = (void *)pending_idx;
- }
+-static void disable_pirq(unsigned int irq)
++static void disable_pirq(struct irq_data *data)
+ {
+ }
-@@ -1216,7 +1214,7 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
- struct gnttab_map_grant_ref *mop = *mopp;
- int pending_idx = *((u16 *)skb->data);
- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
-- struct xen_netif *netif = pending_tx_info[pending_idx].netif;
-+ struct xenvif *vif = pending_tx_info[pending_idx].vif;
- struct xen_netif_tx_request *txp;
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- int nr_frags = shinfo->nr_frags;
-@@ -1228,9 +1226,9 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
- pending_ring_idx_t index;
- index = pending_index(netbk->pending_prod++);
- txp = &pending_tx_info[pending_idx].req;
-- make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
-+ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- netbk->pending_ring[index] = pending_idx;
-- netif_put(netif);
-+ xenvif_put(vif);
- } else {
- set_phys_to_machine(
- __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
-@@ -1264,10 +1262,10 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
+-static void ack_pirq(unsigned int irq)
++static void ack_pirq(struct irq_data *data)
+ {
+- int evtchn = evtchn_from_irq(irq);
++ int evtchn = evtchn_from_irq(data->irq);
- /* Error on this fragment: respond to client with an error. */
- txp = &netbk->pending_tx_info[pending_idx].req;
-- make_tx_response(netif, txp, XEN_NETIF_RSP_ERROR);
-+ make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
-- netif_put(netif);
-+ xenvif_put(vif);
+- move_native_irq(irq);
++ irq_move_irq(data);
- /* Not the first error? Preceding frags already invalidated. */
- if (err)
-@@ -1317,12 +1315,12 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
- }
+ if (VALID_EVTCHN(evtchn)) {
+ mask_evtchn(evtchn);
+@@ -1215,11 +1221,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+ return 0;
}
--int netbk_get_extras(struct xen_netif *netif,
-+int netbk_get_extras(struct xenvif *vif,
- struct xen_netif_extra_info *extras,
- int work_to_do)
+-static int set_affinity_irq(unsigned irq, const struct cpumask *dest)
++static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
++ bool force)
{
- struct xen_netif_extra_info extra;
-- RING_IDX cons = netif->tx.req_cons;
-+ RING_IDX cons = vif->tx.req_cons;
+ unsigned tcpu = cpumask_first(dest);
- do {
- if (unlikely(work_to_do-- <= 0)) {
-@@ -1330,17 +1328,17 @@ int netbk_get_extras(struct xen_netif *netif,
- return -EBADR;
- }
+- return rebind_irq_to_cpu(irq, tcpu);
++ return rebind_irq_to_cpu(data->irq, tcpu);
+ }
-- memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
-+ memcpy(&extra, RING_GET_REQUEST(&vif->tx, cons),
- sizeof(extra));
- if (unlikely(!extra.type ||
- extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-- netif->tx.req_cons = ++cons;
-+ vif->tx.req_cons = ++cons;
- pr_debug("Invalid extra type: %d\n", extra.type);
- return -EINVAL;
- }
+ int resend_irq_on_evtchn(unsigned int irq)
+@@ -1238,35 +1245,35 @@ int resend_irq_on_evtchn(unsigned int irq)
+ return 1;
+ }
- memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-- netif->tx.req_cons = ++cons;
-+ vif->tx.req_cons = ++cons;
- } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
+-static void enable_dynirq(unsigned int irq)
++static void enable_dynirq(struct irq_data *data)
+ {
+- int evtchn = evtchn_from_irq(irq);
++ int evtchn = evtchn_from_irq(data->irq);
- return work_to_do;
-@@ -1370,7 +1368,7 @@ static int netbk_set_skb_gso(struct sk_buff *skb,
- return 0;
+ if (VALID_EVTCHN(evtchn))
+ unmask_evtchn(evtchn);
}
--static int checksum_setup(struct xen_netif *netif, struct sk_buff *skb)
-+static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
+-static void disable_dynirq(unsigned int irq)
++static void disable_dynirq(struct irq_data *data)
{
- struct iphdr *iph;
- unsigned char *th;
-@@ -1384,7 +1382,7 @@ static int checksum_setup(struct xen_netif *netif, struct sk_buff
*skb)
- * recalculate the partial checksum.
- */
- if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
-- netif->rx_gso_checksum_fixup++;
-+ vif->rx_gso_checksum_fixup++;
- skb->ip_summed = CHECKSUM_PARTIAL;
- recalculate_partial_csum = 1;
- }
-@@ -1440,30 +1438,30 @@ out:
- return err;
+- int evtchn = evtchn_from_irq(irq);
++ int evtchn = evtchn_from_irq(data->irq);
+
+ if (VALID_EVTCHN(evtchn))
+ mask_evtchn(evtchn);
}
--static bool tx_credit_exceeded(struct xen_netif *netif, unsigned size)
-+static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
+-static void ack_dynirq(unsigned int irq)
++static void ack_dynirq(struct irq_data *data)
{
- unsigned long now = jiffies;
- unsigned long next_credit =
-- netif->credit_timeout.expires +
-- msecs_to_jiffies(netif->credit_usec / 1000);
-+ vif->credit_timeout.expires +
-+ msecs_to_jiffies(vif->credit_usec / 1000);
-
- /* Timer could already be pending in rare cases. */
-- if (timer_pending(&netif->credit_timeout))
-+ if (timer_pending(&vif->credit_timeout))
- return true;
+- int evtchn = evtchn_from_irq(irq);
++ int evtchn = evtchn_from_irq(data->irq);
- /* Passed the point where we can replenish credit? */
- if (time_after_eq(now, next_credit)) {
-- netif->credit_timeout.expires = now;
-- tx_add_credit(netif);
-+ vif->credit_timeout.expires = now;
-+ tx_add_credit(vif);
- }
+- move_masked_irq(irq);
++ move_masked_irq(data->irq);
- /* Still too big to send right now? Set a callback. */
-- if (size > netif->remaining_credit) {
-- netif->credit_timeout.data =
-- (unsigned long)netif;
-- netif->credit_timeout.function =
-+ if (size > vif->remaining_credit) {
-+ vif->credit_timeout.data =
-+ (unsigned long)vif;
-+ vif->credit_timeout.function =
- tx_credit_callback;
-- mod_timer(&netif->credit_timeout,
-+ mod_timer(&vif->credit_timeout,
- next_credit);
+ if (VALID_EVTCHN(evtchn))
+ unmask_evtchn(evtchn);
+ }
- return true;
-@@ -1481,7 +1479,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- mop = netbk->tx_map_ops;
- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list)) {
-- struct xen_netif *netif;
-+ struct xenvif *vif;
- struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
-@@ -1492,53 +1490,53 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- pending_ring_idx_t index;
+-static int retrigger_dynirq(unsigned int irq)
++static int retrigger_dynirq(struct irq_data *data)
+ {
+- int evtchn = evtchn_from_irq(irq);
++ int evtchn = evtchn_from_irq(data->irq);
+ struct shared_info *sh = HYPERVISOR_shared_info;
+ int ret = 0;
- /* Get a netif from the list with work to do. */
-- netif = poll_net_schedule_list(netbk);
-- if (!netif)
-+ vif = poll_net_schedule_list(netbk);
-+ if (!vif)
- continue;
+@@ -1315,7 +1322,7 @@ static void restore_cpu_pirqs(void)
-- RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
-+ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do);
- if (!work_to_do) {
-- netif_put(netif);
-+ xenvif_put(vif);
- continue;
- }
+ printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
-- idx = netif->tx.req_cons;
-+ idx = vif->tx.req_cons;
- rmb(); /* Ensure that we see the request before we copy it. */
-- memcpy(&txreq, RING_GET_REQUEST(&netif->tx, idx), sizeof(txreq));
-+ memcpy(&txreq, RING_GET_REQUEST(&vif->tx, idx), sizeof(txreq));
+- startup_pirq(irq);
++ __startup_pirq(irq);
+ }
+ }
- /* Credit-based scheduling. */
-- if (txreq.size > netif->remaining_credit &&
-- tx_credit_exceeded(netif, txreq.size)) {
-- netif_put(netif);
-+ if (txreq.size > vif->remaining_credit &&
-+ tx_credit_exceeded(vif, txreq.size)) {
-+ xenvif_put(vif);
- continue;
- }
+@@ -1467,44 +1474,44 @@ void xen_irq_resume(void)
+ }
-- netif->remaining_credit -= txreq.size;
-+ vif->remaining_credit -= txreq.size;
+ static struct irq_chip xen_dynamic_chip __read_mostly = {
+- .name = "xen-dyn",
++ .name = "xen-dyn",
- work_to_do--;
-- netif->tx.req_cons = ++idx;
-+ vif->tx.req_cons = ++idx;
+- .disable = disable_dynirq,
+- .mask = disable_dynirq,
+- .unmask = enable_dynirq,
++ .irq_disable = disable_dynirq,
++ .irq_mask = disable_dynirq,
++ .irq_unmask = enable_dynirq,
- memset(extras, 0, sizeof(extras));
- if (txreq.flags & XEN_NETTXF_extra_info) {
-- work_to_do = netbk_get_extras(netif, extras,
-+ work_to_do = netbk_get_extras(vif, extras,
- work_to_do);
-- idx = netif->tx.req_cons;
-+ idx = vif->tx.req_cons;
- if (unlikely(work_to_do < 0)) {
-- netbk_tx_err(netif, &txreq, idx);
-+ netbk_tx_err(vif, &txreq, idx);
- continue;
- }
- }
+- .eoi = ack_dynirq,
+- .set_affinity = set_affinity_irq,
+- .retrigger = retrigger_dynirq,
++ .irq_eoi = ack_dynirq,
++ .irq_set_affinity = set_affinity_irq,
++ .irq_retrigger = retrigger_dynirq,
+ };
-- ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
-+ ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
- if (unlikely(ret < 0)) {
-- netbk_tx_err(netif, &txreq, idx - ret);
-+ netbk_tx_err(vif, &txreq, idx - ret);
- continue;
- }
- idx += ret;
+ static struct irq_chip xen_pirq_chip __read_mostly = {
+- .name = "xen-pirq",
++ .name = "xen-pirq",
- if (unlikely(txreq.size < ETH_HLEN)) {
- pr_debug("Bad packet size: %d\n", txreq.size);
-- netbk_tx_err(netif, &txreq, idx);
-+ netbk_tx_err(vif, &txreq, idx);
- continue;
- }
+- .startup = startup_pirq,
+- .shutdown = shutdown_pirq,
++ .irq_startup = startup_pirq,
++ .irq_shutdown = shutdown_pirq,
-@@ -1547,7 +1545,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- pr_debug("txreq.offset: %x, size: %u, end: %lu\n",
- txreq.offset, txreq.size,
- (txreq.offset&~PAGE_MASK) + txreq.size);
-- netbk_tx_err(netif, &txreq, idx);
-+ netbk_tx_err(vif, &txreq, idx);
- continue;
- }
+- .enable = enable_pirq,
+- .unmask = enable_pirq,
++ .irq_enable = enable_pirq,
++ .irq_unmask = enable_pirq,
-@@ -1562,7 +1560,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- GFP_ATOMIC | __GFP_NOWARN);
- if (unlikely(skb == NULL)) {
- pr_debug("Can't allocate a skb in start_xmit.\n");
-- netbk_tx_err(netif, &txreq, idx);
-+ netbk_tx_err(vif, &txreq, idx);
- break;
- }
+- .disable = disable_pirq,
+- .mask = disable_pirq,
++ .irq_disable = disable_pirq,
++ .irq_mask = disable_pirq,
-@@ -1575,7 +1573,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+- .ack = ack_pirq,
++ .irq_ack = ack_pirq,
- if (netbk_set_skb_gso(skb, gso)) {
- kfree_skb(skb);
-- netbk_tx_err(netif, &txreq, idx);
-+ netbk_tx_err(vif, &txreq, idx);
- continue;
- }
- }
-@@ -1587,7 +1585,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+- .set_affinity = set_affinity_irq,
++ .irq_set_affinity = set_affinity_irq,
- memcpy(&netbk->pending_tx_info[pending_idx].req,
- &txreq, sizeof(txreq));
-- netbk->pending_tx_info[pending_idx].netif = netif;
-+ netbk->pending_tx_info[pending_idx].vif = vif;
- *((u16 *)skb->data) = pending_idx;
+- .retrigger = retrigger_dynirq,
++ .irq_retrigger = retrigger_dynirq,
+ };
- __skb_put(skb, data_len);
-@@ -1608,8 +1606,8 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
+ static struct irq_chip xen_percpu_chip __read_mostly = {
+- .name = "xen-percpu",
++ .name = "xen-percpu",
- mop = xen_netbk_get_requests(netbk, netif, skb, txfrags, mop);
+- .disable = disable_dynirq,
+- .mask = disable_dynirq,
+- .unmask = enable_dynirq,
++ .irq_disable = disable_dynirq,
++ .irq_mask = disable_dynirq,
++ .irq_unmask = enable_dynirq,
-- netif->tx.req_cons = idx;
-- netif_schedule_work(netif);
-+ vif->tx.req_cons = idx;
-+ xenvif_schedule_work(vif);
+- .ack = ack_dynirq,
++ .irq_ack = ack_dynirq,
+ };
- if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
- break;
-@@ -1626,12 +1624,12 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- mop = netbk->tx_map_ops;
- while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
- struct xen_netif_tx_request *txp;
-- struct xen_netif *netif;
-+ struct xenvif *vif;
- u16 pending_idx;
- unsigned data_len;
+ int xen_set_callback_via(uint64_t via)
+--
+1.7.4
+
+
+From ce9a77f4c22a658f4348683c932bb804af263f67 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)citrix.com>
+Date: Mon, 7 Feb 2011 11:08:39 +0000
+Subject: [PATCH 116/203] xen: Fix compile error introduced by "switch to new
irq_chip functions"
+
+drivers/xen/events.c: In function 'ack_pirq':
+drivers/xen/events.c:568: error: implicit declaration of function 'irq_move_irq'
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index cf1712f..5aa422a 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -553,7 +553,7 @@ static void ack_pirq(struct irq_data *data)
+ {
+ int evtchn = evtchn_from_irq(data->irq);
- pending_idx = *((u16 *)skb->data);
-- netif = netbk->pending_tx_info[pending_idx].netif;
-+ vif = netbk->pending_tx_info[pending_idx].vif;
- txp = &netbk->pending_tx_info[pending_idx].req;
+- irq_move_irq(data);
++ move_native_irq(data->irq);
- /* Check the remap error code. */
-@@ -1672,10 +1670,10 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- __pskb_pull_tail(skb, target - skb_headlen(skb));
- }
+ if (VALID_EVTCHN(evtchn)) {
+ mask_evtchn(evtchn);
+--
+1.7.4
+
+
+From 708b47a4eb3c6db91f9e04443cfd753e86e38b56 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)citrix.com>
+Date: Tue, 8 Feb 2011 14:03:31 +0000
+Subject: [PATCH 117/203] xen/timer: Missing IRQF_NO_SUSPEND in timer code broke suspend.
+
+The patches missed an indirect use of IRQF_NO_SUSPEND pulled in via
+IRQF_TIMER. The following patch fixes the issue.
+
+With this fixlet PV guest migration works just fine. I also booted the
+entire series as a dom0 kernel and it appeared fine.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/time.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
+index 067759e..2e2d370 100644
+--- a/arch/x86/xen/time.c
++++ b/arch/x86/xen/time.c
+@@ -397,7 +397,9 @@ void xen_setup_timer(int cpu)
+ name = "<timer kasprintf failed>";
-- skb->dev = netif->dev;
-+ skb->dev = vif->dev;
- skb->protocol = eth_type_trans(skb, skb->dev);
+ irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
+- IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER,
++ IRQF_DISABLED|IRQF_PERCPU|
++ IRQF_NOBALANCING|IRQF_TIMER|
++ IRQF_FORCE_RESUME,
+ name, NULL);
-- if (checksum_setup(netif, skb)) {
-+ if (checksum_setup(vif, skb)) {
- pr_debug("Can't setup checksum in net_tx_action\n");
- kfree_skb(skb);
- continue;
-@@ -1688,11 +1686,11 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- continue;
- }
+ evt = &per_cpu(xen_clock_events, cpu);
+--
+1.7.4
+
+
+From b052181a985592f81767f631f9f42accb4b436cd Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 11 Feb 2011 15:23:56 +0000
+Subject: [PATCH 118/203] xen: events: mark cpu_evtchn_mask_p as __refdata
+
+This variable starts out pointing at init_evtchn_mask which is marked
+__initdata but is set to point to a non-init data region in xen_init_IRQ
+which is itself an __init function so this is safe.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Tested-and-acked-by: Andrew Jones <drjones(a)redhat.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 7468147..a313890 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -114,7 +114,7 @@ struct cpu_evtchn_s {
+ static __initdata struct cpu_evtchn_s init_evtchn_mask = {
+ .bits[0 ... (NR_EVENT_CHANNELS/BITS_PER_LONG)-1] = ~0ul,
+ };
+-static struct cpu_evtchn_s *cpu_evtchn_mask_p = &init_evtchn_mask;
++static struct cpu_evtchn_s __refdata *cpu_evtchn_mask_p = &init_evtchn_mask;
-- netif->stats.rx_bytes += skb->len;
-- netif->stats.rx_packets++;
-+ vif->stats.rx_bytes += skb->len;
-+ vif->stats.rx_packets++;
+ static inline unsigned long *cpu_evtchn_mask(int cpu)
+ {
+--
+1.7.4
+
+
+From 6b08cfebd3bd346d8a2fd68a2265fc7736849802 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 11 Feb 2011 15:23:58 +0000
+Subject: [PATCH 119/203] xen p2m: annotate variable which appears unused
+
+ CC arch/x86/xen/p2m.o
+arch/x86/xen/p2m.c: In function 'm2p_remove_override':
+arch/x86/xen/p2m.c:460: warning: 'address' may be used uninitialized in this
function
+arch/x86/xen/p2m.c: In function 'm2p_add_override':
+arch/x86/xen/p2m.c:426: warning: 'address' may be used uninitialized in this
function
+
+In actual fact address is inialised in one "if (!PageHighMem(page))"
+statement and used in a second and so is always initialised before
+use.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/p2m.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
+index fd12d7c..89342e5 100644
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -421,7 +421,7 @@ int m2p_add_override(unsigned long mfn, struct page *page)
+ {
+ unsigned long flags;
+ unsigned long pfn;
+- unsigned long address;
++ unsigned long uninitialized_var(address);
+ unsigned level;
+ pte_t *ptep = NULL;
- netif_rx_ni(skb);
-- netif->dev->last_rx = jiffies;
-+ vif->dev->last_rx = jiffies;
- }
- }
+@@ -455,7 +455,7 @@ int m2p_remove_override(struct page *page)
+ unsigned long flags;
+ unsigned long mfn;
+ unsigned long pfn;
+- unsigned long address;
++ unsigned long uninitialized_var(address);
+ unsigned level;
+ pte_t *ptep = NULL;
-@@ -1755,57 +1753,57 @@ static void netif_page_release(struct page *page, unsigned int
order)
- xen_netbk_idx_release(&xen_netbk[group], idx);
+--
+1.7.4
+
+
+From 44b46c3ef805793ab3a7730dc71c72d0f258ea8e Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
+Date: Fri, 11 Feb 2011 16:37:41 +0000
+Subject: [PATCH 120/203] xen: annotate functions which only call into __init at start of
day
+
+Both xen_hvm_init_shared_info and xen_build_mfn_list_list can be
+called at resume time as well as at start of day but only reference
+__init functions (extend_brk) at start of day. Hence annotate with
+__ref.
+
+ WARNING: arch/x86/built-in.o(.text+0x4f1): Section mismatch in reference
+ from the function xen_hvm_init_shared_info() to the function
+ .init.text:extend_brk()
+ The function xen_hvm_init_shared_info() references
+ the function __init extend_brk().
+ This is often because xen_hvm_init_shared_info lacks a __init
+ annotation or the annotation of extend_brk is wrong.
+
+xen_hvm_init_shared_info calls extend_brk() iff !shared_info_page and
+initialises shared_info_page with the result. This happens at start of
+day only.
+
+ WARNING: arch/x86/built-in.o(.text+0x599b): Section mismatch in reference
+ from the function xen_build_mfn_list_list() to the function
+ .init.text:extend_brk()
+ The function xen_build_mfn_list_list() references
+ the function __init extend_brk().
+ This is often because xen_build_mfn_list_list lacks a __init
+ annotation or the annotation of extend_brk is wrong.
+
+(this warning occurs multiple times)
+
+xen_build_mfn_list_list only calls extend_brk() at boot time, while
+building the initial mfn list list
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/enlighten.c | 2 +-
+ arch/x86/xen/p2m.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
+index 50542ef..28e6d42 100644
+--- a/arch/x86/xen/enlighten.c
++++ b/arch/x86/xen/enlighten.c
+@@ -1292,7 +1292,7 @@ static int init_hvm_pv_info(int *major, int *minor)
+ return 0;
}
--irqreturn_t netif_be_int(int irq, void *dev_id)
-+irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+-void xen_hvm_init_shared_info(void)
++void __ref xen_hvm_init_shared_info(void)
{
-- struct xen_netif *netif = dev_id;
-+ struct xenvif *vif = dev_id;
- struct xen_netbk *netbk;
+ int cpu;
+ struct xen_add_to_physmap xatp;
+diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
+index 89342e5..05cfc6a 100644
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -136,7 +136,7 @@ static void p2m_init(unsigned long *p2m)
+ * - After resume we're called from within stop_machine, but the mfn
+ * tree should alreay be completely allocated.
+ */
+-void xen_build_mfn_list_list(void)
++void __ref xen_build_mfn_list_list(void)
+ {
+ unsigned long pfn;
-- if (netif->group == -1)
-+ if (vif->group == -1)
- return IRQ_NONE;
+--
+1.7.4
+
+
+From ef91082e90491ac99343a13f9aeff4669835c6cc Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Thu, 3 Feb 2011 12:18:59 -0500
+Subject: [PATCH 121/203] xen-gntdev: Change page limit to be global instead of per-open
+
+Because there is no limitation on how many times a user can open a
+given device file, an per-file-description limit on the number of
+pages granted offers little to no benefit. Change to a global limit
+and remove the ioctl() as the parameter can now be changed via sysfs.
+
+Xen tools changeset 22768:f8d801e5573e is needed to eliminate the
+error this change produces in xc_gnttab_set_max_grants.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 50 ++++++++++++++------------------------------------
+ 1 files changed, 14 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 1e31cdc..23d208a 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -45,15 +45,15 @@ MODULE_AUTHOR("Derek G. Murray
<Derek.Murray(a)cl.cam.ac.uk>, "
+ "Gerd Hoffmann <kraxel(a)redhat.com>");
+ MODULE_DESCRIPTION("User-space granted page access driver");
-- netbk = &xen_netbk[netif->group];
-+ netbk = &xen_netbk[vif->group];
+-static int limit = 1024;
++static int limit = 1024*1024;
+ module_param(limit, int, 0644);
+-MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped at "
+- "once by a gntdev instance");
++MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by "
++ "the gntdev device");
++
++static atomic_t pages_mapped = ATOMIC_INIT(0);
-- add_to_net_schedule_list_tail(netif);
-+ add_to_net_schedule_list_tail(vif);
- maybe_schedule_tx_action(netbk);
+ struct gntdev_priv {
+ struct list_head maps;
+- uint32_t used;
+- uint32_t limit;
+ /* lock protects maps from concurrent changes */
+ spinlock_t lock;
+ struct mm_struct *mm;
+@@ -82,9 +82,7 @@ static void gntdev_print_maps(struct gntdev_priv *priv,
+ #ifdef DEBUG
+ struct grant_map *map;
-- if (netif_schedulable(netif) && !netbk_queue_full(netif))
-- netif_wake_queue(netif->dev);
-+ if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))
-+ netif_wake_queue(vif->dev);
+- pr_debug("maps list (priv %p, usage %d/%d)\n",
+- priv, priv->used, priv->limit);
+-
++ pr_debug("%s: maps list (priv %p)\n", __func__, priv);
+ list_for_each_entry(map, &priv->maps, next)
+ pr_debug(" index %2d, count %2d %s\n",
+ map->index, map->count,
+@@ -121,9 +119,6 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv,
int count)
+ add->count = count;
+ add->priv = priv;
- return IRQ_HANDLED;
- }
+- if (add->count + priv->used > priv->limit)
+- goto err;
+-
+ return add;
--static void make_tx_response(struct xen_netif *netif,
-+static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
- s8 st)
- {
-- RING_IDX i = netif->tx.rsp_prod_pvt;
-+ RING_IDX i = vif->tx.rsp_prod_pvt;
- struct xen_netif_tx_response *resp;
- int notify;
+ err:
+@@ -154,7 +149,6 @@ static void gntdev_add_map(struct gntdev_priv *priv, struct grant_map
*add)
+ list_add_tail(&add->next, &priv->maps);
-- resp = RING_GET_RESPONSE(&netif->tx, i);
-+ resp = RING_GET_RESPONSE(&vif->tx, i);
- resp->id = txp->id;
- resp->status = st;
+ done:
+- priv->used += add->count;
+ gntdev_print_maps(priv, "[new]", add->index);
+ }
- if (txp->flags & XEN_NETTXF_extra_info)
-- RING_GET_RESPONSE(&netif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
-+ RING_GET_RESPONSE(&vif->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+@@ -200,7 +194,7 @@ static int gntdev_del_map(struct grant_map *map)
+ if (map->unmap_ops[i].handle)
+ return -EBUSY;
-- netif->tx.rsp_prod_pvt = ++i;
-- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
-+ vif->tx.rsp_prod_pvt = ++i;
-+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify);
- if (notify)
-- notify_remote_via_irq(netif->irq);
-+ notify_remote_via_irq(vif->irq);
+- map->priv->used -= map->count;
++ atomic_sub(map->count, &pages_mapped);
+ list_del(&map->next);
+ return 0;
}
+@@ -386,7 +380,6 @@ static int gntdev_open(struct inode *inode, struct file *flip)
--static struct xen_netif_rx_response *make_rx_response(struct xen_netif *netif,
-+static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
- u16 id,
- s8 st,
- u16 offset,
- u16 size,
- u16 flags)
- {
-- RING_IDX i = netif->rx.rsp_prod_pvt;
-+ RING_IDX i = vif->rx.rsp_prod_pvt;
- struct xen_netif_rx_response *resp;
-
-- resp = RING_GET_RESPONSE(&netif->rx, i);
-+ resp = RING_GET_RESPONSE(&vif->rx, i);
- resp->offset = offset;
- resp->flags = flags;
- resp->id = id;
-@@ -1813,7 +1811,7 @@ static struct xen_netif_rx_response *make_rx_response(struct
xen_netif *netif,
- if (st < 0)
- resp->status = (s16)st;
+ INIT_LIST_HEAD(&priv->maps);
+ spin_lock_init(&priv->lock);
+- priv->limit = limit;
-- netif->rx.rsp_prod_pvt = ++i;
-+ vif->rx.rsp_prod_pvt = ++i;
+ priv->mm = get_task_mm(current);
+ if (!priv->mm) {
+@@ -443,19 +436,24 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
+ pr_debug("priv %p, add %d\n", priv, op.count);
+ if (unlikely(op.count <= 0))
+ return -EINVAL;
+- if (unlikely(op.count > priv->limit))
+- return -EINVAL;
- return resp;
- }
-@@ -1964,7 +1962,7 @@ static int __init netback_init(void)
- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
+ err = -ENOMEM;
+ map = gntdev_alloc_map(priv, op.count);
+ if (!map)
+ return err;
++
+ if (copy_from_user(map->grants, &u->refs,
+ sizeof(map->grants[0]) * op.count) != 0) {
+ gntdev_free_map(map);
+ return err;
}
-- rc = netif_xenbus_init();
-+ rc = xenvif_xenbus_init();
- if (rc)
- goto failed_init;
-
-diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
-index 867dc25..a6ad259 100644
---- a/drivers/net/xen-netback/xenbus.c
-+++ b/drivers/net/xen-netback/xenbus.c
-@@ -23,7 +23,7 @@
-
- static int connect_rings(struct backend_info *);
- static void connect(struct backend_info *);
--static void backend_create_netif(struct backend_info *be);
-+static void backend_create_xenvif(struct backend_info *be);
- static void unregister_hotplug_status_watch(struct backend_info *be);
++ if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
++ pr_debug("can't map: over limit\n");
++ gntdev_free_map(map);
++ return err;
++ }
++
+ spin_lock(&priv->lock);
+ gntdev_add_map(priv, map);
+ op.index = map->index << PAGE_SHIFT;
+@@ -518,23 +516,6 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv
*priv,
+ return 0;
+ }
- static int netback_remove(struct xenbus_device *dev)
-@@ -31,11 +31,11 @@ static int netback_remove(struct xenbus_device *dev)
- struct backend_info *be = dev_get_drvdata(&dev->dev);
+-static long gntdev_ioctl_set_max_grants(struct gntdev_priv *priv,
+- struct ioctl_gntdev_set_max_grants __user *u)
+-{
+- struct ioctl_gntdev_set_max_grants op;
+-
+- if (copy_from_user(&op, u, sizeof(op)) != 0)
+- return -EFAULT;
+- pr_debug("priv %p, limit %d\n", priv, op.count);
+- if (op.count > limit)
+- return -E2BIG;
+-
+- spin_lock(&priv->lock);
+- priv->limit = op.count;
+- spin_unlock(&priv->lock);
+- return 0;
+-}
+-
+ static long gntdev_ioctl(struct file *flip,
+ unsigned int cmd, unsigned long arg)
+ {
+@@ -551,9 +532,6 @@ static long gntdev_ioctl(struct file *flip,
+ case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
+ return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
- unregister_hotplug_status_watch(be);
-- if (be->netif) {
-+ if (be->vif) {
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-- netif_disconnect(be->netif);
-- be->netif = NULL;
-+ xenvif_disconnect(be->vif);
-+ be->vif = NULL;
- }
- kfree(be);
- dev_set_drvdata(&dev->dev, NULL);
-@@ -121,7 +121,7 @@ static int netback_probe(struct xenbus_device *dev,
- goto fail;
+- case IOCTL_GNTDEV_SET_MAX_GRANTS:
+- return gntdev_ioctl_set_max_grants(priv, ptr);
+-
+ default:
+ pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
+ return -ENOIOCTLCMD;
+--
+1.7.4
+
+
+From a879211bf1d70339e429603805c014450c275f2a Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Thu, 3 Feb 2011 12:19:00 -0500
+Subject: [PATCH 122/203] xen-gntdev: Use find_vma rather than iterating our vma list
manually
+
+This should be faster if many mappings exist, and also removes
+the only user of map->vma not related to PTE modification.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 32 ++++++++------------------------
+ 1 files changed, 8 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 23d208a..ce8c37c 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -167,23 +167,6 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv
*priv,
+ return NULL;
+ }
- /* This kicks hotplug scripts, so do it immediately. */
-- backend_create_netif(be);
-+ backend_create_xenvif(be);
+-static struct grant_map *gntdev_find_map_vaddr(struct gntdev_priv *priv,
+- unsigned long vaddr)
+-{
+- struct grant_map *map;
+-
+- list_for_each_entry(map, &priv->maps, next) {
+- if (!map->vma)
+- continue;
+- if (vaddr < map->vma->vm_start)
+- continue;
+- if (vaddr >= map->vma->vm_end)
+- continue;
+- return map;
+- }
+- return NULL;
+-}
+-
+ static int gntdev_del_map(struct grant_map *map)
+ {
+ int i;
+@@ -494,22 +477,23 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv
*priv,
+ struct ioctl_gntdev_get_offset_for_vaddr __user *u)
+ {
+ struct ioctl_gntdev_get_offset_for_vaddr op;
++ struct vm_area_struct *vma;
+ struct grant_map *map;
- return 0;
+ if (copy_from_user(&op, u, sizeof(op)) != 0)
+ return -EFAULT;
+ pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr);
-@@ -159,20 +159,20 @@ static int netback_uevent(struct xenbus_device *xdev,
- kfree(val);
- }
+- spin_lock(&priv->lock);
+- map = gntdev_find_map_vaddr(priv, op.vaddr);
+- if (map == NULL ||
+- map->vma->vm_start != op.vaddr) {
+- spin_unlock(&priv->lock);
++ vma = find_vma(current->mm, op.vaddr);
++ if (!vma || vma->vm_ops != &gntdev_vmops)
+ return -EINVAL;
+- }
++
++ map = vma->vm_private_data;
++ if (!map)
++ return -EINVAL;
++
+ op.offset = map->index << PAGE_SHIFT;
+ op.count = map->count;
+- spin_unlock(&priv->lock);
-- if (!be || !be->netif)
-+ if (!be || !be->vif)
- return 0;
+ if (copy_to_user(u, &op, sizeof(op)) != 0)
+ return -EFAULT;
+--
+1.7.4
+
+
+From 68b025c813c2eb41ff25628e3d4952d5185eb1a4 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Thu, 3 Feb 2011 12:19:01 -0500
+Subject: [PATCH 123/203] xen-gntdev: Add reference counting to maps
+
+This allows userspace to perform mmap() on the gntdev device and then
+immediately close the filehandle or remove the mapping using the
+remove ioctl, with the mapped area remaining valid until unmapped.
+This also fixes an infinite loop when a gntdev device is closed
+without first unmapping all areas.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 67 ++++++++++++++++++++-----------------------------
+ 1 files changed, 27 insertions(+), 40 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index ce8c37c..256162b 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -62,12 +62,12 @@ struct gntdev_priv {
-- return add_uevent_var(env, "vif=%s", be->netif->dev->name);
-+ return add_uevent_var(env, "vif=%s", be->vif->dev->name);
- }
+ struct grant_map {
+ struct list_head next;
+- struct gntdev_priv *priv;
+ struct vm_area_struct *vma;
+ int index;
+ int count;
+ int flags;
+ int is_mapped;
++ atomic_t users;
+ struct ioctl_gntdev_grant_ref *grants;
+ struct gnttab_map_grant_ref *map_ops;
+ struct gnttab_unmap_grant_ref *unmap_ops;
+@@ -117,7 +117,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv,
int count)
+ add->index = 0;
+ add->count = count;
+- add->priv = priv;
++ atomic_set(&add->users, 1);
--static void backend_create_netif(struct backend_info *be)
-+static void backend_create_xenvif(struct backend_info *be)
- {
- int err;
- long handle;
- struct xenbus_device *dev = be->dev;
+ return add;
-- if (be->netif != NULL)
-+ if (be->vif != NULL)
- return;
+@@ -167,28 +167,18 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv
*priv,
+ return NULL;
+ }
- err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li",
&handle);
-@@ -181,10 +181,10 @@ static void backend_create_netif(struct backend_info *be)
- return;
- }
+-static int gntdev_del_map(struct grant_map *map)
+-{
+- int i;
+-
+- if (map->vma)
+- return -EBUSY;
+- for (i = 0; i < map->count; i++)
+- if (map->unmap_ops[i].handle)
+- return -EBUSY;
+-
+- atomic_sub(map->count, &pages_mapped);
+- list_del(&map->next);
+- return 0;
+-}
+-
+-static void gntdev_free_map(struct grant_map *map)
++static void gntdev_put_map(struct grant_map *map)
+ {
+ int i;
-- be->netif = netif_alloc(&dev->dev, dev->otherend_id, handle);
-- if (IS_ERR(be->netif)) {
-- err = PTR_ERR(be->netif);
-- be->netif = NULL;
-+ be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle);
-+ if (IS_ERR(be->vif)) {
-+ err = PTR_ERR(be->vif);
-+ be->vif = NULL;
- xenbus_dev_fatal(dev, err, "creating interface");
+ if (!map)
return;
- }
-@@ -197,10 +197,10 @@ static void disconnect_backend(struct xenbus_device *dev)
- {
- struct backend_info *be = dev_get_drvdata(&dev->dev);
-- if (be->netif) {
-+ if (be->vif) {
- xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-- netif_disconnect(be->netif);
-- be->netif = NULL;
-+ xenvif_disconnect(be->vif);
-+ be->vif = NULL;
- }
++ if (!atomic_dec_and_test(&map->users))
++ return;
++
++ atomic_sub(map->count, &pages_mapped);
++
+ if (map->pages)
+ for (i = 0; i < map->count; i++) {
+ if (map->pages[i])
+@@ -267,6 +257,7 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
+ map->is_mapped = 0;
+ map->vma = NULL;
+ vma->vm_private_data = NULL;
++ gntdev_put_map(map);
}
-@@ -231,13 +231,13 @@ static void frontend_changed(struct xenbus_device *dev,
- case XenbusStateConnected:
- if (dev->state == XenbusStateConnected)
- break;
-- backend_create_netif(be);
-- if (be->netif)
-+ backend_create_xenvif(be);
-+ if (be->vif)
- connect(be);
- break;
+ static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+@@ -388,17 +379,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
+ {
+ struct gntdev_priv *priv = flip->private_data;
+ struct grant_map *map;
+- int err;
- case XenbusStateClosing:
-- if (be->netif)
-+ if (be->vif)
- kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
- disconnect_backend(dev);
- xenbus_switch_state(dev, XenbusStateClosing);
-@@ -357,15 +357,15 @@ static void connect(struct backend_info *be)
- if (err)
- return;
+ pr_debug("priv %p\n", priv);
-- err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
-+ err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
- if (err) {
- xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
- return;
+ spin_lock(&priv->lock);
+ while (!list_empty(&priv->maps)) {
+ map = list_entry(priv->maps.next, struct grant_map, next);
+- err = gntdev_del_map(map);
+- if (WARN_ON(err))
+- gntdev_free_map(map);
+-
++ list_del(&map->next);
++ gntdev_put_map(map);
}
+ spin_unlock(&priv->lock);
-- xen_net_read_rate(dev, &be->netif->credit_bytes,
-- &be->netif->credit_usec);
-- be->netif->remaining_credit = be->netif->credit_bytes;
-+ xen_net_read_rate(dev, &be->vif->credit_bytes,
-+ &be->vif->credit_usec);
-+ be->vif->remaining_credit = be->vif->credit_bytes;
+@@ -425,15 +413,15 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
+ if (!map)
+ return err;
- unregister_hotplug_status_watch(be);
- err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
-@@ -378,13 +378,13 @@ static void connect(struct backend_info *be)
- be->have_hotplug_status_watch = 1;
+- if (copy_from_user(map->grants, &u->refs,
+- sizeof(map->grants[0]) * op.count) != 0) {
+- gntdev_free_map(map);
++ if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
++ pr_debug("can't map: over limit\n");
++ gntdev_put_map(map);
+ return err;
}
-- netif_wake_queue(be->netif->dev);
-+ netif_wake_queue(be->vif->dev);
- }
-
-
- static int connect_rings(struct backend_info *be)
- {
-- struct xen_netif *netif = be->netif;
-+ struct xenvif *vif = be->vif;
- struct xenbus_device *dev = be->dev;
- unsigned long tx_ring_ref, rx_ring_ref;
- unsigned int evtchn, rx_copy;
-@@ -416,42 +416,42 @@ static int connect_rings(struct backend_info *be)
- if (!rx_copy)
- return -EOPNOTSUPP;
-
-- if (netif->dev->tx_queue_len != 0) {
-+ if (vif->dev->tx_queue_len != 0) {
- if (xenbus_scanf(XBT_NIL, dev->otherend,
- "feature-rx-notify", "%d", &val) < 0)
- val = 0;
- if (val)
-- netif->can_queue = 1;
-+ vif->can_queue = 1;
- else
- /* Must be non-zero for pfifo_fast to work. */
-- netif->dev->tx_queue_len = 1;
-+ vif->dev->tx_queue_len = 1;
+- if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
+- pr_debug("can't map: over limit\n");
+- gntdev_free_map(map);
++ if (copy_from_user(map->grants, &u->refs,
++ sizeof(map->grants[0]) * op.count) != 0) {
++ gntdev_put_map(map);
+ return err;
}
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg",
- "%d", &val) < 0)
- val = 0;
-- netif->can_sg = !!val;
-+ vif->can_sg = !!val;
+@@ -442,13 +430,9 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
+ op.index = map->index << PAGE_SHIFT;
+ spin_unlock(&priv->lock);
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4",
- "%d", &val) < 0)
- val = 0;
-- netif->gso = !!val;
-+ vif->gso = !!val;
+- if (copy_to_user(u, &op, sizeof(op)) != 0) {
+- spin_lock(&priv->lock);
+- gntdev_del_map(map);
+- spin_unlock(&priv->lock);
+- gntdev_free_map(map);
+- return err;
+- }
++ if (copy_to_user(u, &op, sizeof(op)) != 0)
++ return -EFAULT;
++
+ return 0;
+ }
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4-prefix",
- "%d", &val) < 0)
- val = 0;
-- netif->gso_prefix = !!val;
-+ vif->gso_prefix = !!val;
+@@ -465,11 +449,12 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
- "%d", &val) < 0)
- val = 0;
-- netif->csum = !val;
-+ vif->csum = !val;
+ spin_lock(&priv->lock);
+ map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
+- if (map)
+- err = gntdev_del_map(map);
++ if (map) {
++ list_del(&map->next);
++ gntdev_put_map(map);
++ err = 0;
++ }
+ spin_unlock(&priv->lock);
+- if (!err)
+- gntdev_free_map(map);
+ return err;
+ }
- /* Set dev->features */
-- netif_set_features(netif);
-+ xenvif_set_features(vif);
+@@ -549,6 +534,8 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ goto unlock_out;
+ }
- /* Map the shared frame, irq etc. */
-- err = netif_map(netif, tx_ring_ref, rx_ring_ref, evtchn);
-+ err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
- if (err) {
- xenbus_dev_fatal(dev, err,
- "mapping shared-frames %lu/%lu port %u",
-@@ -481,9 +481,7 @@ static struct xenbus_driver netback = {
- .otherend_changed = frontend_changed,
- };
++ atomic_inc(&map->users);
++
+ vma->vm_ops = &gntdev_vmops;
--
--int netif_xenbus_init(void)
-+int xenvif_xenbus_init(void)
- {
-- printk(KERN_CRIT "registering netback\n");
- return xenbus_register_backend(&netback);
- }
+ vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
--
1.7.4
-From ffb0eb7c4e5115ac17621cb83cf614ba026975df Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 21 Jan 2011 09:42:35 +0000
-Subject: [PATCH 139/244] xen: netback: add reference from xenvif to xen_netbk
+From aab8f11a6b4641fcb8c139420f2eae879b5d1698 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Thu, 3 Feb 2011 12:19:02 -0500
+Subject: [PATCH 124/203] xen-gntdev: Support mapping in HVM domains
-Rather than storing the group id simply store a pointer (opaque to xenvif).
+HVM does not allow direct PTE modification, so instead we request
+that Xen change its internal p2m mappings on the allocated pages and
+map the memory into userspace normally.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Note:
+The HVM path for map and unmap is slightly different: HVM keeps the pages
+mapped until the area is deleted, while the PV case (use_ptemod being true)
+must unmap them when userspace unmaps the range. In the normal use case,
+this makes no difference to users since unmap time is deletion time.
+
+[v2: Expanded commit descr.]
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/net/xen-netback/common.h | 6 +++++-
- drivers/net/xen-netback/interface.c | 2 +-
- drivers/net/xen-netback/netback.c | 26 ++++++++++++++------------
- 3 files changed, 20 insertions(+), 14 deletions(-)
+ drivers/xen/gntdev.c | 117 ++++++++++++++++++++++++++++++++-------------
+ drivers/xen/grant-table.c | 6 ++
+ 2 files changed, 89 insertions(+), 34 deletions(-)
-diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-index f6da94b..ebe93fb 100644
---- a/drivers/net/xen-netback/common.h
-+++ b/drivers/net/xen-netback/common.h
-@@ -46,12 +46,16 @@
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 256162b..bcaf797 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -32,6 +32,7 @@
+ #include <linux/sched.h>
+ #include <linux/spinlock.h>
+ #include <linux/slab.h>
++#include <linux/highmem.h>
+
+ #include <xen/xen.h>
#include <xen/grant_table.h>
- #include <xen/xenbus.h>
+@@ -52,6 +53,8 @@ MODULE_PARM_DESC(limit, "Maximum number of grants that may be
mapped by "
-+struct xen_netbk;
+ static atomic_t pages_mapped = ATOMIC_INIT(0);
+
++static int use_ptemod;
+
- struct xenvif {
- /* Unique identifier for this interface. */
- domid_t domid;
-- int group;
- unsigned int handle;
+ struct gntdev_priv {
+ struct list_head maps;
+ /* lock protects maps from concurrent changes */
+@@ -74,6 +77,8 @@ struct grant_map {
+ struct page **pages;
+ };
-+ /* */
-+ struct xen_netbk *netbk;
++static int unmap_grant_pages(struct grant_map *map, int offset, int pages);
+
- u8 fe_dev_addr[6];
+ /* ------------------------------------------------------------------ */
- /* Physical parameters of the comms window. */
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index a065173..cfbb3cc 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -235,8 +235,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
- vif = netdev_priv(dev);
- memset(vif, 0, sizeof(*vif));
- vif->domid = domid;
-- vif->group = -1;
- vif->handle = handle;
-+ vif->netbk = NULL;
- vif->can_sg = 1;
- vif->csum = 1;
- atomic_set(&vif->refcnt, 1);
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index f2f9c6f..4f04d2d 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -145,6 +145,8 @@ void xen_netbk_add_xenvif(struct xenvif *vif)
- int i;
- int min_netfront_count;
- int min_group = 0;
-+ struct xen_netbk *netbk;
+ static void gntdev_print_maps(struct gntdev_priv *priv,
+@@ -179,11 +184,34 @@ static void gntdev_put_map(struct grant_map *map)
+
+ atomic_sub(map->count, &pages_mapped);
+
+- if (map->pages)
++ if (map->pages) {
++ if (!use_ptemod)
++ unmap_grant_pages(map, 0, map->count);
+
- min_netfront_count = atomic_read(&xen_netbk[0].netfront_count);
- for (i = 0; i < xen_netbk_group_nr; i++) {
- int netfront_count = atomic_read(&xen_netbk[i].netfront_count);
-@@ -154,13 +156,15 @@ void xen_netbk_add_xenvif(struct xenvif *vif)
+ for (i = 0; i < map->count; i++) {
+- if (map->pages[i])
++ uint32_t check, *tmp;
++ if (!map->pages[i])
++ continue;
++ /* XXX When unmapping in an HVM domain, Xen will
++ * sometimes end up mapping the GFN to an invalid MFN.
++ * In this case, writes will be discarded and reads will
++ * return all 0xFF bytes. Leak these unusable GFNs
++ * until Xen supports fixing their p2m mapping.
++ *
++ * Confirmed present in Xen 4.1-RC3 with HVM source
++ */
++ tmp = kmap(map->pages[i]);
++ *tmp = 0xdeaddead;
++ mb();
++ check = *tmp;
++ kunmap(map->pages[i]);
++ if (check == 0xdeaddead)
+ __free_page(map->pages[i]);
++ else
++ pr_debug("Discard page %d=%ld\n", i,
++ page_to_pfn(map->pages[i]));
}
- }
++ }
+ kfree(map->pages);
+ kfree(map->grants);
+ kfree(map->map_ops);
+@@ -198,17 +226,16 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
+ {
+ struct grant_map *map = data;
+ unsigned int pgnr = (addr - map->vma->vm_start) >> PAGE_SHIFT;
++ int flags = map->flags | GNTMAP_application_map | GNTMAP_contains_pte;
+ u64 pte_maddr;
-- vif->group = min_group;
-- atomic_inc(&xen_netbk[vif->group].netfront_count);
-+ netbk = &xen_netbk[min_group];
-+
-+ vif->netbk = netbk;
-+ atomic_inc(&netbk->netfront_count);
- }
+ BUG_ON(pgnr >= map->count);
+ pte_maddr = arbitrary_virt_to_machine(pte).maddr;
- void xen_netbk_remove_xenvif(struct xenvif *vif)
+- gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr,
+- GNTMAP_contains_pte | map->flags,
++ gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, flags,
+ map->grants[pgnr].ref,
+ map->grants[pgnr].domid);
+- gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr,
+- GNTMAP_contains_pte | map->flags,
++ gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, flags,
+ 0 /* handle */);
+ return 0;
+ }
+@@ -216,6 +243,19 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
+ static int map_grant_pages(struct grant_map *map)
{
-- atomic_dec(&xen_netbk[vif->group].netfront_count);
-+ atomic_dec(&vif->netbk->netfront_count);
+ int i, err = 0;
++ phys_addr_t addr;
++
++ if (!use_ptemod) {
++ for (i = 0; i < map->count; i++) {
++ addr = (phys_addr_t)
++ pfn_to_kaddr(page_to_pfn(map->pages[i]));
++ gnttab_set_map_op(&map->map_ops[i], addr, map->flags,
++ map->grants[i].ref,
++ map->grants[i].domid);
++ gnttab_set_unmap_op(&map->unmap_ops[i], addr,
++ map->flags, 0 /* handle */);
++ }
++ }
+
+ pr_debug("map %d+%d\n", map->index, map->count);
+ err = gnttab_map_refs(map->map_ops, map->pages, map->count);
+@@ -260,17 +300,8 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
+ gntdev_put_map(map);
}
- static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
-@@ -471,10 +475,10 @@ int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+-static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+-{
+- pr_debug("vaddr %p, pgoff %ld (shouldn't happen)\n",
+- vmf->virtual_address, vmf->pgoff);
+- vmf->flags = VM_FAULT_ERROR;
+- return 0;
+-}
+-
+ static struct vm_operations_struct gntdev_vmops = {
+ .close = gntdev_vma_close,
+- .fault = gntdev_vma_fault,
+ };
- BUG_ON(skb->dev != dev);
+ /* ------------------------------------------------------------------ */
+@@ -355,14 +386,16 @@ static int gntdev_open(struct inode *inode, struct file *flip)
+ INIT_LIST_HEAD(&priv->maps);
+ spin_lock_init(&priv->lock);
-- if (vif->group == -1)
-+ if (vif->netbk == NULL)
- goto drop;
+- priv->mm = get_task_mm(current);
+- if (!priv->mm) {
+- kfree(priv);
+- return -ENOMEM;
++ if (use_ptemod) {
++ priv->mm = get_task_mm(current);
++ if (!priv->mm) {
++ kfree(priv);
++ return -ENOMEM;
++ }
++ priv->mn.ops = &gntdev_mmu_ops;
++ ret = mmu_notifier_register(&priv->mn, priv->mm);
++ mmput(priv->mm);
+ }
+- priv->mn.ops = &gntdev_mmu_ops;
+- ret = mmu_notifier_register(&priv->mn, priv->mm);
+- mmput(priv->mm);
-- netbk = &xen_netbk[vif->group];
-+ netbk = vif->netbk;
+ if (ret) {
+ kfree(priv);
+@@ -390,7 +423,8 @@ static int gntdev_release(struct inode *inode, struct file *flip)
+ }
+ spin_unlock(&priv->lock);
- /* Drop the packet if the target domain has no receive buffers. */
- if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
-@@ -940,7 +944,7 @@ static void add_to_net_schedule_list_tail(struct xenvif *vif)
- {
- unsigned long flags;
+- mmu_notifier_unregister(&priv->mn, priv->mm);
++ if (use_ptemod)
++ mmu_notifier_unregister(&priv->mn, priv->mm);
+ kfree(priv);
+ return 0;
+ }
+@@ -515,7 +549,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ int index = vma->vm_pgoff;
+ int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ struct grant_map *map;
+- int err = -EINVAL;
++ int i, err = -EINVAL;
-- struct xen_netbk *netbk = &xen_netbk[vif->group];
-+ struct xen_netbk *netbk = vif->netbk;
- if (__on_net_schedule_list(vif))
- return;
+ if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+@@ -527,9 +561,9 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ map = gntdev_find_map_index(priv, index, count);
+ if (!map)
+ goto unlock_out;
+- if (map->vma)
++ if (use_ptemod && map->vma)
+ goto unlock_out;
+- if (priv->mm != vma->vm_mm) {
++ if (use_ptemod && priv->mm != vma->vm_mm) {
+ printk(KERN_WARNING "Huh? Other mm?\n");
+ goto unlock_out;
+ }
+@@ -541,20 +575,24 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;
+
+ vma->vm_private_data = map;
+- map->vma = vma;
+
+- map->flags = GNTMAP_host_map | GNTMAP_application_map;
++ if (use_ptemod)
++ map->vma = vma;
++
++ map->flags = GNTMAP_host_map;
+ if (!(vma->vm_flags & VM_WRITE))
+ map->flags |= GNTMAP_readonly;
+
+ spin_unlock(&priv->lock);
+
+- err = apply_to_page_range(vma->vm_mm, vma->vm_start,
+- vma->vm_end - vma->vm_start,
+- find_grant_ptes, map);
+- if (err) {
+- printk(KERN_WARNING "find_grant_ptes() failure.\n");
+- return err;
++ if (use_ptemod) {
++ err = apply_to_page_range(vma->vm_mm, vma->vm_start,
++ vma->vm_end - vma->vm_start,
++ find_grant_ptes, map);
++ if (err) {
++ printk(KERN_WARNING "find_grant_ptes() failure.\n");
++ return err;
++ }
+ }
-@@ -955,7 +959,7 @@ static void add_to_net_schedule_list_tail(struct xenvif *vif)
+ err = map_grant_pages(map);
+@@ -565,6 +603,15 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- void xenvif_schedule_work(struct xenvif *vif)
- {
-- struct xen_netbk *netbk = &xen_netbk[vif->group];
-+ struct xen_netbk *netbk = vif->netbk;
- int more_to_do;
+ map->is_mapped = 1;
- RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
-@@ -968,7 +972,7 @@ void xenvif_schedule_work(struct xenvif *vif)
++ if (!use_ptemod) {
++ for (i = 0; i < count; i++) {
++ err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
++ map->pages[i]);
++ if (err)
++ return err;
++ }
++ }
++
+ return 0;
- void xenvif_deschedule_work(struct xenvif *vif)
- {
-- struct xen_netbk *netbk = &xen_netbk[vif->group];
-+ struct xen_netbk *netbk = vif->netbk;
- spin_lock_irq(&netbk->net_schedule_list_lock);
- remove_from_net_schedule_list(vif);
- spin_unlock_irq(&netbk->net_schedule_list_lock);
-@@ -1756,13 +1760,11 @@ static void netif_page_release(struct page *page, unsigned int
order)
- irqreturn_t xenvif_interrupt(int irq, void *dev_id)
- {
- struct xenvif *vif = dev_id;
-- struct xen_netbk *netbk;
-+ struct xen_netbk *netbk = vif->netbk;
+ unlock_out:
+@@ -595,6 +642,8 @@ static int __init gntdev_init(void)
+ if (!xen_domain())
+ return -ENODEV;
-- if (vif->group == -1)
-+ if (netbk == NULL)
- return IRQ_NONE;
++ use_ptemod = xen_pv_domain();
++
+ err = misc_register(&gntdev_miscdev);
+ if (err != 0) {
+ printk(KERN_ERR "Could not register gntdev device\n");
+diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
+index 9ef54eb..9428ced 100644
+--- a/drivers/xen/grant-table.c
++++ b/drivers/xen/grant-table.c
+@@ -458,6 +458,9 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
+ if (ret)
+ return ret;
-- netbk = &xen_netbk[vif->group];
--
- add_to_net_schedule_list_tail(vif);
- maybe_schedule_tx_action(netbk);
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return ret;
++
+ for (i = 0; i < count; i++) {
+ /* m2p override only supported for GNTMAP_contains_pte mappings */
+ if (!(map_ops[i].flags & GNTMAP_contains_pte))
+@@ -483,6 +486,9 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
+ if (ret)
+ return ret;
++ if (xen_feature(XENFEAT_auto_translated_physmap))
++ return ret;
++
+ for (i = 0; i < count; i++) {
+ ret = m2p_remove_override(pages[i]);
+ if (ret)
--
1.7.4
-From 0cf3cc23560821e8e0b95a1400374a7ff1248e52 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 21 Jan 2011 10:45:25 +0000
-Subject: [PATCH 140/244] xen: netback: refactor to separate network device from worker
pools
-
-The netback worker pool code is in netback.c and uses "struct xen_netbk" and
-xen_netbk_*.
+From dd3140588d9551235ebc2a0dacdca098e7677573 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Mon, 7 Feb 2011 17:23:05 -0500
+Subject: [PATCH 125/203] xen-gntalloc: Userspace grant allocation driver
-The network dfeivce interface is in interface.c and uses "struct xen_vif" and
-xenvif_*.
+This allows a userspace application to allocate a shared page for
+implementing inter-domain communication or device drivers. These
+shared pages can be mapped using the gntdev device or by the kernel
+in another domain.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/net/xen-netback/common.h | 69 +++-------
- drivers/net/xen-netback/interface.c | 227 ++++++++++++++++++++++++++++++-
- drivers/net/xen-netback/netback.c | 259 ++++++-----------------------------
- drivers/net/xen-netback/xenbus.c | 11 +-
- 4 files changed, 289 insertions(+), 277 deletions(-)
+ drivers/xen/Kconfig | 8 +
+ drivers/xen/Makefile | 2 +
+ drivers/xen/gntalloc.c | 486 ++++++++++++++++++++++++++++++++++++++++++++++++
+ include/xen/gntalloc.h | 50 +++++
+ 4 files changed, 546 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/xen/gntalloc.c
+ create mode 100644 include/xen/gntalloc.h
-diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-index ebe93fb..b998a27 100644
---- a/drivers/net/xen-netback/common.h
-+++ b/drivers/net/xen-netback/common.h
-@@ -109,16 +109,6 @@ struct xenvif {
- wait_queue_head_t waiting_to_free;
- };
-
--/*
-- * Implement our own carrier flag: the network stack's version causes delays
-- * when the carrier is re-enabled (in particular, dev_activate() may not
-- * immediately be called, which can cause packet loss; also the etherbridge
-- * can be rather lazy in activating its port).
-- */
--#define xenvif_carrier_on(xenvif) ((xenvif)->carrier = 1)
--#define xenvif_carrier_off(xenvif) ((xenvif)->carrier = 0)
--#define xenvif_carrier_ok(xenvif) ((xenvif)->carrier)
--
- enum {
- NETBK_DONT_COPY_SKB,
- NETBK_DELAYED_COPY_SKB,
-@@ -127,63 +117,40 @@ enum {
-
- extern int netbk_copy_skb_mode;
-
--struct backend_info {
-- struct xenbus_device *dev;
-- struct xenvif *vif;
-- enum xenbus_state frontend_state;
-- struct xenbus_watch hotplug_status_watch;
-- int have_hotplug_status_watch:1;
--};
--
--#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
--#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
--
--void xenvif_disconnect(struct xenvif *vif);
-+#define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
-+#define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
+index 07bec09..a3d7afb 100644
+--- a/drivers/xen/Kconfig
++++ b/drivers/xen/Kconfig
+@@ -80,6 +80,14 @@ config XEN_GNTDEV
+ help
+ Allows userspace processes to use grants.
--void xenvif_set_features(struct xenvif *vif);
- struct xenvif *xenvif_alloc(struct device *parent,
- domid_t domid,
- unsigned int handle);
++config XEN_GRANT_DEV_ALLOC
++ tristate "User-space grant reference allocator driver"
++ depends on XEN
++ help
++ Allows userspace processes to create pages with access granted
++ to other domains. This can be used to implement frontend drivers
++ or as part of an inter-domain shared memory channel.
+
- int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
-+void xenvif_disconnect(struct xenvif *vif);
-
--static inline void xenvif_get(struct xenvif *vif)
--{
-- atomic_inc(&vif->refcnt);
--}
--
--static inline void xenvif_put(struct xenvif *vif)
--{
-- if (atomic_dec_and_test(&vif->refcnt))
-- wake_up(&vif->waiting_to_free);
--}
-+void xenvif_get(struct xenvif *vif);
-+void xenvif_put(struct xenvif *vif);
-
- int xenvif_xenbus_init(void);
-
--#define xenvif_schedulable(vif) \
-- (netif_running((vif)->dev) && xenvif_carrier_ok(vif))
-+int xenvif_schedulable(struct xenvif *vif);
-
- void xenvif_schedule_work(struct xenvif *vif);
--void xenvif_deschedule_work(struct xenvif *vif);
--
--int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev);
--struct net_device_stats *xenvif_get_stats(struct net_device *dev);
--irqreturn_t xenvif_interrupt(int irq, void *dev_id);
--
--static inline int netbk_can_queue(struct net_device *dev)
--{
-- struct xenvif *vif = netdev_priv(dev);
-- return vif->can_queue;
--}
-
--static inline int netbk_can_sg(struct net_device *dev)
--{
-- struct xenvif *vif = netdev_priv(dev);
-- return vif->can_sg;
--}
-+int xenvif_queue_full(struct xenvif *vif);
+ config XEN_PLATFORM_PCI
+ tristate "xen platform pci device driver"
+ depends on XEN_PVHVM && PCI
+diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
+index 5088cc2..9585a1d 100644
+--- a/drivers/xen/Makefile
++++ b/drivers/xen/Makefile
+@@ -10,6 +10,7 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
+ obj-$(CONFIG_XEN_BALLOON) += balloon.o
+ obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
+ obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
++obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
+ obj-$(CONFIG_XENFS) += xenfs/
+ obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
+ obj-$(CONFIG_XEN_PLATFORM_PCI) += xen-platform-pci.o
+@@ -18,5 +19,6 @@ obj-$(CONFIG_XEN_DOM0) += pci.o
- /* (De)Register a xenvif with the netback backend. */
- void xen_netbk_add_xenvif(struct xenvif *vif);
- void xen_netbk_remove_xenvif(struct xenvif *vif);
+ xen-evtchn-y := evtchn.o
+ xen-gntdev-y := gntdev.o
++xen-gntalloc-y := gntalloc.o
-+/* */
-+void xen_netbk_schedule_xenvif(struct xenvif *vif);
-+void xen_netbk_deschedule_xenfif(struct xenvif *vif);
-+
-+/* */
-+unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb);
+ xen-platform-pci-y := platform-pci.o
+diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
+new file mode 100644
+index 0000000..d06bf2b
+--- /dev/null
++++ b/drivers/xen/gntalloc.c
+@@ -0,0 +1,486 @@
++/******************************************************************************
++ * gntalloc.c
++ *
++ * Device for creating grant references (in user-space) that may be shared
++ * with other domains.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
+
-+/* */
-+void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb);
++/*
++ * This driver exists to allow userspace programs in Linux to allocate kernel
++ * memory that will later be shared with another domain. Without this device,
++ * Linux userspace programs cannot create grant references.
++ *
++ * How this stuff works:
++ * X -> granting a page to Y
++ * Y -> mapping the grant from X
++ *
++ * 1. X uses the gntalloc device to allocate a page of kernel memory, P.
++ * 2. X creates an entry in the grant table that says domid(Y) can access P.
++ * This is done without a hypercall unless the grant table needs expansion.
++ * 3. X gives the grant reference identifier, GREF, to Y.
++ * 4. Y maps the page, either directly into kernel memory for use in a backend
++ * driver, or via a the gntdev device to map into the address space of an
++ * application running in Y. This is the first point at which Xen does any
++ * tracking of the page.
++ * 5. A program in X mmap()s a segment of the gntalloc device that corresponds
++ * to the shared page, and can now communicate with Y over the shared page.
++ *
++ *
++ * NOTE TO USERSPACE LIBRARIES:
++ * The grant allocation and mmap()ing are, naturally, two separate operations.
++ * You set up the sharing by calling the create ioctl() and then the mmap().
++ * Teardown requires munmap() and either close() or ioctl().
++ *
++ * WARNING: Since Xen does not allow a guest to forcibly end the use of a grant
++ * reference, this device can be used to consume kernel memory by leaving grant
++ * references mapped by another domain when an application exits. Therefore,
++ * there is a global limit on the number of pages that can be allocated. When
++ * all references to the page are unmapped, it will be freed during the next
++ * grant operation.
++ */
+
- #endif /* __XEN_NETBACK__COMMON_H__ */
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index cfbb3cc..c906c79 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -36,7 +36,221 @@
- #include <xen/events.h>
- #include <asm/xen/hypercall.h>
-
--#define NETBK_QUEUE_LENGTH 32
-+#define XENVIF_QUEUE_LENGTH 32
++#include <linux/atomic.h>
++#include <linux/module.h>
++#include <linux/miscdevice.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/mm.h>
++#include <linux/uaccess.h>
++#include <linux/types.h>
++#include <linux/list.h>
+
-+void xenvif_get(struct xenvif *vif)
-+{
-+ atomic_inc(&vif->refcnt);
-+}
++#include <xen/xen.h>
++#include <xen/page.h>
++#include <xen/grant_table.h>
++#include <xen/gntalloc.h>
+
-+void xenvif_put(struct xenvif *vif)
-+{
-+ if (atomic_dec_and_test(&vif->refcnt))
-+ wake_up(&vif->waiting_to_free);
-+}
++static int limit = 1024;
++module_param(limit, int, 0644);
++MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by "
++ "the gntalloc device");
+
-+static int xenvif_max_required_rx_slots(struct xenvif *vif)
-+{
-+ if (vif->can_sg || vif->gso || vif->gso_prefix)
-+ return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-+ return 1; /* all in one */
-+}
++static LIST_HEAD(gref_list);
++static DEFINE_SPINLOCK(gref_lock);
++static int gref_size;
+
-+int xenvif_queue_full(struct xenvif *vif)
-+{
-+ RING_IDX peek = vif->rx_req_cons_peek;
-+ RING_IDX needed = xenvif_max_required_rx_slots(vif);
++/* Metadata on a grant reference. */
++struct gntalloc_gref {
++ struct list_head next_gref; /* list entry gref_list */
++ struct list_head next_file; /* list entry file->list, if open */
++ struct page *page; /* The shared page */
++ uint64_t file_index; /* File offset for mmap() */
++ unsigned int users; /* Use count - when zero, waiting on Xen */
++ grant_ref_t gref_id; /* The grant reference number */
++};
+
-+ return ((vif->rx.sring->req_prod - peek) < needed) ||
-+ ((vif->rx.rsp_prod_pvt + XEN_NETIF_RX_RING_SIZE - peek) < needed);
-+}
++struct gntalloc_file_private_data {
++ struct list_head list;
++ uint64_t index;
++};
+
-+/*
-+ * Implement our own carrier flag: the network stack's version causes delays
-+ * when the carrier is re-enabled (in particular, dev_activate() may not
-+ * immediately be called, which can cause packet loss; also the etherbridge
-+ * can be rather lazy in activating its port).
-+ */
-+static void xenvif_carrier_on(struct xenvif *vif)
-+{
-+ vif->carrier = 1;
-+}
-+static void xenvif_carrier_off(struct xenvif *vif)
-+{
-+ vif->carrier = 0;
-+}
-+static int xenvif_carrier_ok(struct xenvif *vif)
-+{
-+ return vif->carrier;
-+}
++static void __del_gref(struct gntalloc_gref *gref);
+
-+int xenvif_schedulable(struct xenvif *vif)
++static void do_cleanup(void)
+{
-+ return netif_running(vif->dev) && xenvif_carrier_ok(vif);
++ struct gntalloc_gref *gref, *n;
++ list_for_each_entry_safe(gref, n, &gref_list, next_gref) {
++ if (!gref->users)
++ __del_gref(gref);
++ }
+}
+
-+static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
++static int add_grefs(struct ioctl_gntalloc_alloc_gref *op,
++ uint32_t *gref_ids, struct gntalloc_file_private_data *priv)
+{
-+ struct xenvif *vif = dev_id;
++ int i, rc, readonly;
++ LIST_HEAD(queue_gref);
++ LIST_HEAD(queue_file);
++ struct gntalloc_gref *gref;
+
-+ if (vif->netbk == NULL)
-+ return IRQ_NONE;
++ readonly = !(op->flags & GNTALLOC_FLAG_WRITABLE);
++ rc = -ENOMEM;
++ for (i = 0; i < op->count; i++) {
++ gref = kzalloc(sizeof(*gref), GFP_KERNEL);
++ if (!gref)
++ goto undo;
++ list_add_tail(&gref->next_gref, &queue_gref);
++ list_add_tail(&gref->next_file, &queue_file);
++ gref->users = 1;
++ gref->file_index = op->index + i * PAGE_SIZE;
++ gref->page = alloc_page(GFP_KERNEL|__GFP_ZERO);
++ if (!gref->page)
++ goto undo;
+
-+ xen_netbk_schedule_xenvif(vif);
++ /* Grant foreign access to the page. */
++ gref->gref_id = gnttab_grant_foreign_access(op->domid,
++ pfn_to_mfn(page_to_pfn(gref->page)), readonly);
++ if (gref->gref_id < 0) {
++ rc = gref->gref_id;
++ goto undo;
++ }
++ gref_ids[i] = gref->gref_id;
++ }
+
-+ if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))
-+ netif_wake_queue(vif->dev);
++ /* Add to gref lists. */
++ spin_lock(&gref_lock);
++ list_splice_tail(&queue_gref, &gref_list);
++ list_splice_tail(&queue_file, &priv->list);
++ spin_unlock(&gref_lock);
+
-+ return IRQ_HANDLED;
-+}
++ return 0;
+
-+/* TODO: move to networking core */
-+static struct sk_buff *xenvif_copy_skb(struct sk_buff *skb)
-+{
-+ struct skb_shared_info *ninfo;
-+ struct sk_buff *nskb;
-+ unsigned long offset;
-+ int ret;
-+ int len;
-+ int headlen;
++undo:
++ spin_lock(&gref_lock);
++ gref_size -= (op->count - i);
+
-+ BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++ list_for_each_entry(gref, &queue_file, next_file) {
++ /* __del_gref does not remove from queue_file */
++ __del_gref(gref);
++ }
+
-+ nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-+ if (unlikely(!nskb))
-+ goto err;
++ /* It's possible for the target domain to map the just-allocated grant
++ * references by blindly guessing their IDs; if this is done, then
++ * __del_gref will leave them in the queue_gref list. They need to be
++ * added to the global list so that we can free them when they are no
++ * longer referenced.
++ */
++ if (unlikely(!list_empty(&queue_gref)))
++ list_splice_tail(&queue_gref, &gref_list);
++ spin_unlock(&gref_lock);
++ return rc;
++}
+
-+ skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-+ headlen = skb_end_pointer(nskb) - nskb->data;
-+ if (headlen > skb_headlen(skb))
-+ headlen = skb_headlen(skb);
-+ ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-+ BUG_ON(ret);
++static void __del_gref(struct gntalloc_gref *gref)
++{
++ if (gref->gref_id > 0) {
++ if (gnttab_query_foreign_access(gref->gref_id))
++ return;
+
-+ ninfo = skb_shinfo(nskb);
-+ ninfo->gso_size = skb_shinfo(skb)->gso_size;
-+ ninfo->gso_type = skb_shinfo(skb)->gso_type;
++ if (!gnttab_end_foreign_access_ref(gref->gref_id, 0))
++ return;
++ }
+
-+ offset = headlen;
-+ len = skb->len - headlen;
++ gref_size--;
++ list_del(&gref->next_gref);
+
-+ nskb->len = skb->len;
-+ nskb->data_len = len;
-+ nskb->truesize += len;
++ if (gref->page)
++ __free_page(gref->page);
+
-+ while (len) {
-+ struct page *page;
-+ int copy;
-+ int zero;
++ kfree(gref);
++}
+
-+ if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-+ dump_stack();
-+ goto err_free;
++/* finds contiguous grant references in a file, returns the first */
++static struct gntalloc_gref *find_grefs(struct gntalloc_file_private_data *priv,
++ uint64_t index, uint32_t count)
++{
++ struct gntalloc_gref *rv = NULL, *gref;
++ list_for_each_entry(gref, &priv->list, next_file) {
++ if (gref->file_index == index && !rv)
++ rv = gref;
++ if (rv) {
++ if (gref->file_index != index)
++ return NULL;
++ index += PAGE_SIZE;
++ count--;
++ if (count == 0)
++ return rv;
+ }
++ }
++ return NULL;
++}
+
-+ copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-+ zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++/*
++ * -------------------------------------
++ * File operations.
++ * -------------------------------------
++ */
++static int gntalloc_open(struct inode *inode, struct file *filp)
++{
++ struct gntalloc_file_private_data *priv;
+
-+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-+ if (unlikely(!page))
-+ goto err_free;
++ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ goto out_nomem;
++ INIT_LIST_HEAD(&priv->list);
+
-+ ret = skb_copy_bits(skb, offset, page_address(page), copy);
-+ BUG_ON(ret);
++ filp->private_data = priv;
+
-+ ninfo->frags[ninfo->nr_frags].page = page;
-+ ninfo->frags[ninfo->nr_frags].page_offset = 0;
-+ ninfo->frags[ninfo->nr_frags].size = copy;
-+ ninfo->nr_frags++;
++ pr_debug("%s: priv %p\n", __func__, priv);
+
-+ offset += copy;
-+ len -= copy;
-+ }
++ return 0;
+
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+ offset = 0;
-+#else
-+ offset = nskb->data - skb->data;
-+#endif
++out_nomem:
++ return -ENOMEM;
++}
+
-+ nskb->transport_header = skb->transport_header + offset;
-+ nskb->network_header = skb->network_header + offset;
-+ nskb->mac_header = skb->mac_header + offset;
++static int gntalloc_release(struct inode *inode, struct file *filp)
++{
++ struct gntalloc_file_private_data *priv = filp->private_data;
++ struct gntalloc_gref *gref;
+
-+ return nskb;
++ pr_debug("%s: priv %p\n", __func__, priv);
+
-+ err_free:
-+ kfree_skb(nskb);
-+ err:
-+ return NULL;
++ spin_lock(&gref_lock);
++ while (!list_empty(&priv->list)) {
++ gref = list_entry(priv->list.next,
++ struct gntalloc_gref, next_file);
++ list_del(&gref->next_file);
++ gref->users--;
++ if (gref->users == 0)
++ __del_gref(gref);
++ }
++ kfree(priv);
++ spin_unlock(&gref_lock);
++
++ return 0;
+}
+
-+static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
++static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv,
++ struct ioctl_gntalloc_alloc_gref __user *arg)
+{
-+ struct xenvif *vif = netdev_priv(dev);
++ int rc = 0;
++ struct ioctl_gntalloc_alloc_gref op;
++ uint32_t *gref_ids;
+
-+ BUG_ON(skb->dev != dev);
++ pr_debug("%s: priv %p\n", __func__, priv);
+
-+ if (vif->netbk == NULL)
-+ goto drop;
++ if (copy_from_user(&op, arg, sizeof(op))) {
++ rc = -EFAULT;
++ goto out;
++ }
+
-+ /* Drop the packet if the target domain has no receive buffers. */
-+ if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
-+ goto drop;
++ gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY);
++ if (!gref_ids) {
++ rc = -ENOMEM;
++ goto out;
++ }
+
-+ /*
-+ * XXX For now we also copy skbuffs whose head crosses a page
-+ * boundary, because netbk_gop_skb can't handle them.
++ spin_lock(&gref_lock);
++ /* Clean up pages that were at zero (local) users but were still mapped
++ * by remote domains. Since those pages count towards the limit that we
++ * are about to enforce, removing them here is a good idea.
+ */
-+ if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
-+ struct sk_buff *nskb = xenvif_copy_skb(skb);
-+ if (unlikely(nskb == NULL))
-+ goto drop;
-+ /* Copy only the header fields we use in this driver. */
-+ nskb->dev = skb->dev;
-+ nskb->ip_summed = skb->ip_summed;
-+ dev_kfree_skb(skb);
-+ skb = nskb;
++ do_cleanup();
++ if (gref_size + op.count > limit) {
++ spin_unlock(&gref_lock);
++ rc = -ENOSPC;
++ goto out_free;
+ }
++ gref_size += op.count;
++ op.index = priv->index;
++ priv->index += op.count * PAGE_SIZE;
++ spin_unlock(&gref_lock);
+
-+ /* Reserve ring slots for the worst-case number of fragments. */
-+ vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
-+ xenvif_get(vif);
++ rc = add_grefs(&op, gref_ids, priv);
++ if (rc < 0)
++ goto out_free;
+
-+ if (vif->can_queue && xenvif_queue_full(vif)) {
-+ vif->rx.sring->req_event = vif->rx_req_cons_peek +
-+ xenvif_max_required_rx_slots(vif);
-+ mb(); /* request notification /then/ check & stop the queue */
-+ if (xenvif_queue_full(vif))
-+ netif_stop_queue(dev);
++ /* Once we finish add_grefs, it is unsafe to touch the new reference,
++ * since it is possible for a concurrent ioctl to remove it (by guessing
++ * its index). If the userspace application doesn't provide valid memory
++ * to write the IDs to, then it will need to close the file in order to
++ * release - which it will do by segfaulting when it tries to access the
++ * IDs to close them.
++ */
++ if (copy_to_user(arg, &op, sizeof(op))) {
++ rc = -EFAULT;
++ goto out_free;
++ }
++ if (copy_to_user(arg->gref_ids, gref_ids,
++ sizeof(gref_ids[0]) * op.count)) {
++ rc = -EFAULT;
++ goto out_free;
+ }
+
-+ xen_netbk_queue_tx_skb(vif, skb);
-+
-+ return 0;
-+
-+ drop:
-+ vif->stats.tx_dropped++;
-+ dev_kfree_skb(skb);
-+ return 0;
++out_free:
++ kfree(gref_ids);
++out:
++ return rc;
+}
+
-+static struct net_device_stats *xenvif_get_stats(struct net_device *dev)
++static long gntalloc_ioctl_dealloc(struct gntalloc_file_private_data *priv,
++ void __user *arg)
+{
-+ struct xenvif *vif = netdev_priv(dev);
-+ return &vif->stats;
++ int i, rc = 0;
++ struct ioctl_gntalloc_dealloc_gref op;
++ struct gntalloc_gref *gref, *n;
++
++ pr_debug("%s: priv %p\n", __func__, priv);
++
++ if (copy_from_user(&op, arg, sizeof(op))) {
++ rc = -EFAULT;
++ goto dealloc_grant_out;
++ }
++
++ spin_lock(&gref_lock);
++ gref = find_grefs(priv, op.index, op.count);
++ if (gref) {
++ /* Remove from the file list only, and decrease reference count.
++ * The later call to do_cleanup() will remove from gref_list and
++ * free the memory if the pages aren't mapped anywhere.
++ */
++ for (i = 0; i < op.count; i++) {
++ n = list_entry(gref->next_file.next,
++ struct gntalloc_gref, next_file);
++ list_del(&gref->next_file);
++ gref->users--;
++ gref = n;
++ }
++ } else {
++ rc = -EINVAL;
++ }
++
++ do_cleanup();
++
++ spin_unlock(&gref_lock);
++dealloc_grant_out:
++ return rc;
+}
+
-+void xenvif_schedule_work(struct xenvif *vif)
++static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
++ unsigned long arg)
+{
-+ int more_to_do;
++ struct gntalloc_file_private_data *priv = filp->private_data;
+
-+ RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
++ switch (cmd) {
++ case IOCTL_GNTALLOC_ALLOC_GREF:
++ return gntalloc_ioctl_alloc(priv, (void __user *)arg);
+
-+ if (more_to_do)
-+ xen_netbk_schedule_xenvif(vif);
++ case IOCTL_GNTALLOC_DEALLOC_GREF:
++ return gntalloc_ioctl_dealloc(priv, (void __user *)arg);
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++
++ return 0;
+}
+
-
- static void xenvif_up(struct xenvif *vif)
- {
-@@ -48,7 +262,7 @@ static void xenvif_up(struct xenvif *vif)
- static void xenvif_down(struct xenvif *vif)
- {
- disable_irq(vif->irq);
-- xenvif_deschedule_work(vif);
-+ xen_netbk_deschedule_xenfif(vif);
- xen_netbk_remove_xenvif(vif);
- }
-
-@@ -73,7 +287,8 @@ static int xenvif_close(struct net_device *dev)
-
- static int xenvif_change_mtu(struct net_device *dev, int mtu)
- {
-- int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
-+ struct xenvif *vif = netdev_priv(dev);
-+ int max = vif->can_sg ? 65535 - ETH_HLEN : ETH_DATA_LEN;
-
- if (mtu > max)
- return -EINVAL;
-@@ -81,7 +296,7 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu)
- return 0;
- }
-
--void xenvif_set_features(struct xenvif *vif)
-+static void xenvif_set_features(struct xenvif *vif)
- {
- struct net_device *dev = vif->dev;
- int features = dev->features;
-@@ -256,7 +471,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
- xenvif_set_features(vif);
- SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
-
-- dev->tx_queue_len = NETBK_QUEUE_LENGTH;
-+ dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
-
- /*
- * Initialise a dummy MAC address. We choose the numerically
-@@ -352,6 +567,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
- if (vif->irq)
- return 0;
-
-+ xenvif_set_features(vif);
++static void gntalloc_vma_close(struct vm_area_struct *vma)
++{
++ struct gntalloc_gref *gref = vma->vm_private_data;
++ if (!gref)
++ return;
+
- vif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
- if (vif->tx_comms_area == NULL)
- return -ENOMEM;
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 4f04d2d..1b7005c 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -131,10 +131,10 @@ struct xen_netbk {
- * MAX_BUFFER_OFFSET of 4096 the worst case is that each
- * head/fragment uses 2 copy operation.
- */
-- struct gnttab_copy grant_copy_op[2*NET_RX_RING_SIZE];
-+ struct gnttab_copy grant_copy_op[2*XEN_NETIF_RX_RING_SIZE];
- unsigned char rx_notify[NR_IRQS];
-- u16 notify_list[NET_RX_RING_SIZE];
-- struct netbk_rx_meta meta[2*NET_RX_RING_SIZE];
-+ u16 notify_list[XEN_NETIF_RX_RING_SIZE];
-+ struct netbk_rx_meta meta[2*XEN_NETIF_RX_RING_SIZE];
- };
-
- static struct xen_netbk *xen_netbk;
-@@ -164,7 +164,9 @@ void xen_netbk_add_xenvif(struct xenvif *vif)
-
- void xen_netbk_remove_xenvif(struct xenvif *vif)
- {
-- atomic_dec(&vif->netbk->netfront_count);
-+ struct xen_netbk *netbk = vif->netbk;
-+ vif->netbk = NULL;
-+ atomic_dec(&netbk->netfront_count);
- }
-
- static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
-@@ -275,7 +277,7 @@ MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace
tasklet");
- * dir indicates the data direction.
- * rx: 1, tx: 0.
- */
--static inline void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
-+void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
- {
- if (MODPARM_netback_kthread)
- wake_up(&netbk->kthread.netbk_action_wq);
-@@ -285,110 +287,6 @@ static inline void xen_netbk_bh_handler(struct xen_netbk *netbk,
int dir)
- tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
- }
-
--static inline void maybe_schedule_tx_action(struct xen_netbk *netbk)
--{
-- smp_mb();
-- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
-- !list_empty(&netbk->net_schedule_list))
-- xen_netbk_bh_handler(netbk, 0);
--}
--
--static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
--{
-- struct skb_shared_info *ninfo;
-- struct sk_buff *nskb;
-- unsigned long offset;
-- int ret;
-- int len;
-- int headlen;
--
-- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
--
-- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-- if (unlikely(!nskb))
-- goto err;
--
-- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-- headlen = skb_end_pointer(nskb) - nskb->data;
-- if (headlen > skb_headlen(skb))
-- headlen = skb_headlen(skb);
-- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-- BUG_ON(ret);
--
-- ninfo = skb_shinfo(nskb);
-- ninfo->gso_size = skb_shinfo(skb)->gso_size;
-- ninfo->gso_type = skb_shinfo(skb)->gso_type;
--
-- offset = headlen;
-- len = skb->len - headlen;
--
-- nskb->len = skb->len;
-- nskb->data_len = len;
-- nskb->truesize += len;
--
-- while (len) {
-- struct page *page;
-- int copy;
-- int zero;
--
-- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-- dump_stack();
-- goto err_free;
-- }
--
-- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
--
-- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-- if (unlikely(!page))
-- goto err_free;
--
-- ret = skb_copy_bits(skb, offset, page_address(page), copy);
-- BUG_ON(ret);
--
-- ninfo->frags[ninfo->nr_frags].page = page;
-- ninfo->frags[ninfo->nr_frags].page_offset = 0;
-- ninfo->frags[ninfo->nr_frags].size = copy;
-- ninfo->nr_frags++;
--
-- offset += copy;
-- len -= copy;
-- }
--
--#ifdef NET_SKBUFF_DATA_USES_OFFSET
-- offset = 0;
--#else
-- offset = nskb->data - skb->data;
--#endif
--
-- nskb->transport_header = skb->transport_header + offset;
-- nskb->network_header = skb->network_header + offset;
-- nskb->mac_header = skb->mac_header + offset;
--
-- return nskb;
--
-- err_free:
-- kfree_skb(nskb);
-- err:
-- return NULL;
--}
--
--static inline int xenvif_max_required_rx_slots(struct xenvif *vif)
--{
-- if (vif->can_sg || vif->gso || vif->gso_prefix)
-- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-- return 1; /* all in one */
--}
--
--static inline int xenvif_queue_full(struct xenvif *vif)
--{
-- RING_IDX peek = vif->rx_req_cons_peek;
-- RING_IDX needed = xenvif_max_required_rx_slots(vif);
--
-- return ((vif->rx.sring->req_prod - peek) < needed) ||
-- ((vif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
--}
--
- /*
- * Returns true if we should start a new receive buffer instead of
- * adding 'size' bytes to a buffer which currently contains 'offset'
-@@ -434,7 +332,7 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int
head)
- * the guest. This function is essentially a dry run of
- * netbk_gop_frag_copy.
- */
--static unsigned int count_skb_slots(struct sk_buff *skb, struct xenvif *vif)
-+unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
- {
- unsigned int count = 1;
- int i, copy_off = 0;
-@@ -468,60 +366,6 @@ static unsigned int count_skb_slots(struct sk_buff *skb, struct
xenvif *vif)
- return count;
- }
-
--int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
--{
-- struct xenvif *vif = netdev_priv(dev);
-- struct xen_netbk *netbk;
--
-- BUG_ON(skb->dev != dev);
--
-- if (vif->netbk == NULL)
-- goto drop;
--
-- netbk = vif->netbk;
--
-- /* Drop the packet if the target domain has no receive buffers. */
-- if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
-- goto drop;
--
-- /*
-- * XXX For now we also copy skbuffs whose head crosses a page
-- * boundary, because netbk_gop_skb can't handle them.
-- */
-- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
-- struct sk_buff *nskb = netbk_copy_skb(skb);
-- if (unlikely(nskb == NULL))
-- goto drop;
-- /* Copy only the header fields we use in this driver. */
-- nskb->dev = skb->dev;
-- nskb->ip_summed = skb->ip_summed;
-- dev_kfree_skb(skb);
-- skb = nskb;
-- }
--
-- /* Reserve ring slots for the worst-case number of fragments. */
-- vif->rx_req_cons_peek += count_skb_slots(skb, vif);
-- xenvif_get(vif);
--
-- if (netbk_can_queue(dev) && xenvif_queue_full(vif)) {
-- vif->rx.sring->req_event = vif->rx_req_cons_peek +
-- xenvif_max_required_rx_slots(vif);
-- mb(); /* request notification /then/ check & stop the queue */
-- if (xenvif_queue_full(vif))
-- netif_stop_queue(dev);
-- }
-- skb_queue_tail(&netbk->rx_queue, skb);
--
-- xen_netbk_bh_handler(netbk, 1);
--
-- return 0;
--
-- drop:
-- vif->stats.tx_dropped++;
-- dev_kfree_skb(skb);
-- return 0;
--}
--
- struct netrx_pending_operations {
- unsigned copy_prod, copy_cons;
- unsigned meta_prod, meta_cons;
-@@ -780,7 +624,7 @@ static void xen_netbk_rx_action(unsigned long data)
- __skb_queue_tail(&rxq, skb);
-
- /* Filled the batch queue? */
-- if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
-+ if (count + MAX_SKB_FRAGS >= XEN_NETIF_RX_RING_SIZE)
- break;
- }
-
-@@ -887,9 +731,12 @@ static void xen_netbk_rx_action(unsigned long data)
- xen_netbk_bh_handler(netbk, 1);
- }
-
--static void net_alarm(unsigned long data)
-+void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb)
- {
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ struct xen_netbk *netbk = vif->netbk;
++ spin_lock(&gref_lock);
++ gref->users--;
++ if (gref->users == 0)
++ __del_gref(gref);
++ spin_unlock(&gref_lock);
++}
++
++static struct vm_operations_struct gntalloc_vmops = {
++ .close = gntalloc_vma_close,
++};
+
-+ skb_queue_tail(&netbk->rx_queue, skb);
++static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct gntalloc_file_private_data *priv = filp->private_data;
++ struct gntalloc_gref *gref;
++ int count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++ int rv, i;
+
- xen_netbk_bh_handler(netbk, 1);
- }
-
-@@ -899,10 +746,10 @@ static void xen_netbk_tx_pending_timeout(unsigned long data)
- xen_netbk_bh_handler(netbk, 0);
- }
-
--struct net_device_stats *xenvif_get_stats(struct net_device *dev)
-+static void xen_netbk_alarm(unsigned long data)
- {
-- struct xenvif *vif = netdev_priv(dev);
-- return &vif->stats;
-+ struct xen_netbk *netbk = (struct xen_netbk *)data;
-+ xen_netbk_bh_handler(netbk, 1);
- }
-
- static int __on_net_schedule_list(struct xenvif *vif)
-@@ -940,13 +787,13 @@ out:
- return vif;
- }
-
--static void add_to_net_schedule_list_tail(struct xenvif *vif)
-+void xen_netbk_schedule_xenvif(struct xenvif *vif)
- {
- unsigned long flags;
-
- struct xen_netbk *netbk = vif->netbk;
- if (__on_net_schedule_list(vif))
-- return;
-+ goto kick;
-
- spin_lock_irqsave(&netbk->net_schedule_list_lock, flags);
- if (!__on_net_schedule_list(vif) &&
-@@ -955,22 +802,15 @@ static void add_to_net_schedule_list_tail(struct xenvif *vif)
- xenvif_get(vif);
- }
- spin_unlock_irqrestore(&netbk->net_schedule_list_lock, flags);
--}
--
--void xenvif_schedule_work(struct xenvif *vif)
--{
-- struct xen_netbk *netbk = vif->netbk;
-- int more_to_do;
--
-- RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do);
-
-- if (more_to_do) {
-- add_to_net_schedule_list_tail(vif);
-- maybe_schedule_tx_action(netbk);
-- }
-+kick:
-+ smp_mb();
-+ if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
-+ !list_empty(&netbk->net_schedule_list))
-+ xen_netbk_bh_handler(netbk, 0);
- }
-
--void xenvif_deschedule_work(struct xenvif *vif)
-+void xen_netbk_deschedule_xenfif(struct xenvif *vif)
- {
- struct xen_netbk *netbk = vif->netbk;
- spin_lock_irq(&netbk->net_schedule_list_lock);
-@@ -1019,7 +859,7 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
- struct gnttab_unmap_grant_ref *gop;
- u16 pending_idx;
- pending_ring_idx_t dc, dp;
-- struct xen_netif *netif;
-+ struct xenvif *vif;
- int ret;
- LIST_HEAD(list);
-
-@@ -1077,7 +917,7 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
-
- pending_idx = inuse - netbk->pending_inuse;
-
-- pending_tx_info[pending_idx].netif->nr_copied_skbs++;
-+ pending_tx_info[pending_idx].vif->nr_copied_skbs++;
-
- switch (copy_pending_req(netbk, pending_idx)) {
- case 0:
-@@ -1101,9 +941,9 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
- pending_tx_info = netbk->pending_tx_info;
- pending_idx = inuse - netbk->pending_inuse;
-
-- netif = pending_tx_info[pending_idx].netif;
-+ vif = pending_tx_info[pending_idx].vif;
-
-- make_tx_response(netif, &pending_tx_info[pending_idx].req,
-+ make_tx_response(vif, &pending_tx_info[pending_idx].req,
- XEN_NETIF_RSP_OKAY);
-
- /* Ready for next use. */
-@@ -1200,7 +1040,7 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
-
- gnttab_set_map_op(mop++, idx_to_kaddr(netbk, pending_idx),
- GNTMAP_host_map | GNTMAP_readonly,
-- txp->gref, netif->domid);
-+ txp->gref, vif->domid);
-
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
- xenvif_get(vif);
-@@ -1319,9 +1159,9 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
- }
- }
-
--int netbk_get_extras(struct xenvif *vif,
-- struct xen_netif_extra_info *extras,
-- int work_to_do)
-+static int xen_netbk_get_extras(struct xenvif *vif,
-+ struct xen_netif_extra_info *extras,
-+ int work_to_do)
- {
- struct xen_netif_extra_info extra;
- RING_IDX cons = vif->tx.req_cons;
-@@ -1522,8 +1362,8 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
-
- memset(extras, 0, sizeof(extras));
- if (txreq.flags & XEN_NETTXF_extra_info) {
-- work_to_do = netbk_get_extras(vif, extras,
-- work_to_do);
-+ work_to_do = xen_netbk_get_extras(vif, extras,
-+ work_to_do);
- idx = vif->tx.req_cons;
- if (unlikely(work_to_do < 0)) {
- netbk_tx_err(vif, &txreq, idx);
-@@ -1584,7 +1424,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
-
- gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
- GNTMAP_host_map | GNTMAP_readonly,
-- txreq.gref, netif->domid);
-+ txreq.gref, vif->domid);
- mop++;
-
- memcpy(&netbk->pending_tx_info[pending_idx].req,
-@@ -1608,7 +1448,7 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
-
- netbk->pending_cons++;
-
-- mop = xen_netbk_get_requests(netbk, netif, skb, txfrags, mop);
-+ mop = xen_netbk_get_requests(netbk, vif, skb, txfrags, mop);
-
- vif->tx.req_cons = idx;
- xenvif_schedule_work(vif);
-@@ -1705,7 +1545,7 @@ static void xen_netbk_tx_action(unsigned long data)
- unsigned nr_mops;
- int ret;
-
-- net_tx_action_dealloc(netbk);
-+ xen_netbk_tx_action_dealloc(netbk);
-
- nr_mops = xen_netbk_tx_build_mops(netbk);
-
-@@ -1738,7 +1578,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16
pending_idx)
- spin_lock_irqsave(&_lock, flags);
- index = pending_index(netbk->dealloc_prod);
- netbk->dealloc_ring[index] = pending_idx;
-- /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
-+ /* Sync with xen_netbk_tx_action_dealloc: insert idx /then/ incr producer. */
- smp_wmb();
- netbk->dealloc_prod++;
- spin_unlock_irqrestore(&_lock, flags);
-@@ -1757,23 +1597,6 @@ static void netif_page_release(struct page *page, unsigned int
order)
- xen_netbk_idx_release(&xen_netbk[group], idx);
- }
-
--irqreturn_t xenvif_interrupt(int irq, void *dev_id)
--{
-- struct xenvif *vif = dev_id;
-- struct xen_netbk *netbk = vif->netbk;
--
-- if (netbk == NULL)
-- return IRQ_NONE;
--
-- add_to_net_schedule_list_tail(vif);
-- maybe_schedule_tx_action(netbk);
--
-- if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))
-- netif_wake_queue(vif->dev);
--
-- return IRQ_HANDLED;
--}
--
- static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
- s8 st)
-@@ -1887,12 +1710,12 @@ static int __init netback_init(void)
-
- init_timer(&netbk->net_timer);
- netbk->net_timer.data = (unsigned long)netbk;
-- netbk->net_timer.function = net_alarm;
-+ netbk->net_timer.function = xen_netbk_alarm;
-
- init_timer(&netbk->netbk_tx_pending_timer);
- netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
- netbk->netbk_tx_pending_timer.function =
-- netbk_tx_pending_timeout;
-+ xen_netbk_tx_pending_timeout;
-
- netbk->mmap_pages =
- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
-index a6ad259..e854420 100644
---- a/drivers/net/xen-netback/xenbus.c
-+++ b/drivers/net/xen-netback/xenbus.c
-@@ -21,6 +21,14 @@
-
- #include "common.h"
-
-+struct backend_info {
-+ struct xenbus_device *dev;
-+ struct xenvif *vif;
-+ enum xenbus_state frontend_state;
-+ struct xenbus_watch hotplug_status_watch;
-+ int have_hotplug_status_watch:1;
++ pr_debug("%s: priv %p, page %lu+%d\n", __func__,
++ priv, vma->vm_pgoff, count);
++
++ if (!(vma->vm_flags & VM_SHARED)) {
++ printk(KERN_ERR "%s: Mapping must be shared.\n", __func__);
++ return -EINVAL;
++ }
++
++ spin_lock(&gref_lock);
++ gref = find_grefs(priv, vma->vm_pgoff << PAGE_SHIFT, count);
++ if (gref == NULL) {
++ rv = -ENOENT;
++ pr_debug("%s: Could not find grant reference",
++ __func__);
++ goto out_unlock;
++ }
++
++ vma->vm_private_data = gref;
++
++ vma->vm_flags |= VM_RESERVED;
++ vma->vm_flags |= VM_DONTCOPY;
++ vma->vm_flags |= VM_PFNMAP | VM_PFN_AT_MMAP;
++
++ vma->vm_ops = &gntalloc_vmops;
++
++ for (i = 0; i < count; i++) {
++ gref->users++;
++ rv = vm_insert_page(vma, vma->vm_start + i * PAGE_SIZE,
++ gref->page);
++ if (rv)
++ goto out_unlock;
++
++ gref = list_entry(gref->next_file.next,
++ struct gntalloc_gref, next_file);
++ }
++ rv = 0;
++
++out_unlock:
++ spin_unlock(&gref_lock);
++ return rv;
++}
++
++static const struct file_operations gntalloc_fops = {
++ .owner = THIS_MODULE,
++ .open = gntalloc_open,
++ .release = gntalloc_release,
++ .unlocked_ioctl = gntalloc_ioctl,
++ .mmap = gntalloc_mmap
+};
+
- static int connect_rings(struct backend_info *);
- static void connect(struct backend_info *);
- static void backend_create_xenvif(struct backend_info *be);
-@@ -447,9 +455,6 @@ static int connect_rings(struct backend_info *be)
- val = 0;
- vif->csum = !val;
-
-- /* Set dev->features */
-- xenvif_set_features(vif);
--
- /* Map the shared frame, irq etc. */
- err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
- if (err) {
---
-1.7.4
-
-
-From f1c011ec476d1ee2c36afb9df40024ffca087b08 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 21 Jan 2011 11:10:22 +0000
-Subject: [PATCH 141/244] xen: netback: switch to kthread mode and drop tasklet mode
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
----
- drivers/net/xen-netback/netback.c | 108 +++++++++++-------------------------
- 1 files changed, 33 insertions(+), 75 deletions(-)
-
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 1b7005c..73e35fd 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -84,17 +84,8 @@ union page_ext {
- };
-
- struct xen_netbk {
-- union {
-- struct {
-- struct tasklet_struct net_tx_tasklet;
-- struct tasklet_struct net_rx_tasklet;
-- } tasklet;
--
-- struct {
-- wait_queue_head_t netbk_action_wq;
-- struct task_struct *task;
-- } kthread;
-- };
-+ wait_queue_head_t wq;
-+ struct task_struct *task;
-
- struct sk_buff_head rx_queue;
- struct sk_buff_head tx_queue;
-@@ -180,10 +171,6 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif
*vif,
- u16 size,
- u16 flags);
-
--static void xen_netbk_tx_action(unsigned long data);
--
--static void xen_netbk_rx_action(unsigned long data);
--
- static inline unsigned long idx_to_pfn(struct xen_netbk *netbk,
- unsigned int idx)
- {
-@@ -268,23 +255,9 @@ MODULE_PARM_DESC(copy_skb, "Copy data received from netfront
without netloop");
-
- int netbk_copy_skb_mode;
-
--static int MODPARM_netback_kthread;
--module_param_named(netback_kthread, MODPARM_netback_kthread, bool, 0);
--MODULE_PARM_DESC(netback_kthread, "Use kernel thread to replace tasklet");
--
--/*
-- * Netback bottom half handler.
-- * dir indicates the data direction.
-- * rx: 1, tx: 0.
-- */
--void xen_netbk_bh_handler(struct xen_netbk *netbk, int dir)
-+static void xen_netbk_kick_thread(struct xen_netbk *netbk)
- {
-- if (MODPARM_netback_kthread)
-- wake_up(&netbk->kthread.netbk_action_wq);
-- else if (dir)
-- tasklet_schedule(&netbk->tasklet.net_rx_tasklet);
-- else
-- tasklet_schedule(&netbk->tasklet.net_tx_tasklet);
-+ wake_up(&netbk->wq);
- }
-
- /*
-@@ -587,10 +560,9 @@ struct skb_cb_overlay {
- int meta_slots_used;
- };
-
--static void xen_netbk_rx_action(unsigned long data)
-+static void xen_netbk_rx_action(struct xen_netbk *netbk)
- {
- struct xenvif *vif = NULL;
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
- s8 status;
- u16 irq, flags;
- struct xen_netif_rx_response *resp;
-@@ -728,7 +700,7 @@ static void xen_netbk_rx_action(unsigned long data)
- /* More work to do? */
- if (!skb_queue_empty(&netbk->rx_queue) &&
- !timer_pending(&netbk->net_timer))
-- xen_netbk_bh_handler(netbk, 1);
-+ xen_netbk_kick_thread(netbk);
- }
-
- void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb)
-@@ -737,19 +709,19 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff
*skb)
-
- skb_queue_tail(&netbk->rx_queue, skb);
-
-- xen_netbk_bh_handler(netbk, 1);
-+ xen_netbk_kick_thread(netbk);
- }
-
- static void xen_netbk_tx_pending_timeout(unsigned long data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- xen_netbk_bh_handler(netbk, 0);
-+ xen_netbk_kick_thread(netbk);
- }
-
- static void xen_netbk_alarm(unsigned long data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- xen_netbk_bh_handler(netbk, 1);
-+ xen_netbk_kick_thread(netbk);
- }
-
- static int __on_net_schedule_list(struct xenvif *vif)
-@@ -807,7 +779,7 @@ kick:
- smp_mb();
- if ((nr_pending_reqs(netbk) < (MAX_PENDING_REQS/2)) &&
- !list_empty(&netbk->net_schedule_list))
-- xen_netbk_bh_handler(netbk, 0);
-+ xen_netbk_kick_thread(netbk);
- }
-
- void xen_netbk_deschedule_xenfif(struct xenvif *vif)
-@@ -1539,9 +1511,8 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- }
-
- /* Called after netfront has transmitted */
--static void xen_netbk_tx_action(unsigned long data)
-+static void xen_netbk_tx_action(struct xen_netbk *netbk)
- {
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
- unsigned nr_mops;
- int ret;
-
-@@ -1583,7 +1554,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16
pending_idx)
- netbk->dealloc_prod++;
- spin_unlock_irqrestore(&_lock, flags);
-
-- xen_netbk_bh_handler(netbk, 0);
-+ xen_netbk_kick_thread(netbk);
- }
-
- static void netif_page_release(struct page *page, unsigned int order)
-@@ -1662,11 +1633,11 @@ static inline int tx_work_todo(struct xen_netbk *netbk)
- return 0;
- }
-
--static int xen_netbk_action_thread(void *data)
-+static int xen_netbk_kthread(void *data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- while (!kthread_should_stop()) {
-- wait_event_interruptible(netbk->kthread.netbk_action_wq,
-+ wait_event_interruptible(netbk->wq,
- rx_work_todo(netbk)
- || tx_work_todo(netbk)
- || kthread_should_stop());
-@@ -1676,10 +1647,10 @@ static int xen_netbk_action_thread(void *data)
- break;
-
- if (rx_work_todo(netbk))
-- xen_netbk_rx_action((unsigned long)netbk);
-+ xen_netbk_rx_action(netbk);
-
- if (tx_work_todo(netbk))
-- xen_netbk_tx_action((unsigned long)netbk);
-+ xen_netbk_tx_action(netbk);
- }
-
- return 0;
-@@ -1739,34 +1710,23 @@ static int __init netback_init(void)
- for (i = 0; i < MAX_PENDING_REQS; i++)
- netbk->pending_ring[i] = i;
-
-- if (MODPARM_netback_kthread) {
-- init_waitqueue_head(&netbk->kthread.netbk_action_wq);
-- netbk->kthread.task =
-- kthread_create(xen_netbk_action_thread,
-- (void *)netbk,
-- "netback/%u", group);
--
-- if (!IS_ERR(netbk->kthread.task)) {
-- kthread_bind(netbk->kthread.task, group);
-- } else {
-- printk(KERN_ALERT
-- "kthread_run() fails at netback\n");
-- free_empty_pages_and_pagevec(netbk->mmap_pages,
-- MAX_PENDING_REQS);
-- del_timer(&netbk->netbk_tx_pending_timer);
-- del_timer(&netbk->net_timer);
-- rc = PTR_ERR(netbk->kthread.task);
-- goto failed_init;
-- }
-- } else {
-- tasklet_init(&netbk->tasklet.net_tx_tasklet,
-- xen_netbk_tx_action,
-- (unsigned long)netbk);
-- tasklet_init(&netbk->tasklet.net_rx_tasklet,
-- xen_netbk_rx_action,
-- (unsigned long)netbk);
-+ init_waitqueue_head(&netbk->wq);
-+ netbk->task = kthread_create(xen_netbk_kthread,
-+ (void *)netbk,
-+ "netback/%u", group);
++/*
++ * -------------------------------------
++ * Module creation/destruction.
++ * -------------------------------------
++ */
++static struct miscdevice gntalloc_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "xen/gntalloc",
++ .fops = &gntalloc_fops,
++};
++
++static int __init gntalloc_init(void)
++{
++ int err;
++
++ if (!xen_domain())
++ return -ENODEV;
++
++ err = misc_register(&gntalloc_miscdev);
++ if (err != 0) {
++ printk(KERN_ERR "Could not register misc gntalloc device\n");
++ return err;
++ }
+
-+ if (IS_ERR(netbk->task)) {
-+ printk(KERN_ALERT "kthread_run() fails at netback\n");
-+ free_empty_pages_and_pagevec(netbk->mmap_pages,
-+ MAX_PENDING_REQS);
-+ del_timer(&netbk->netbk_tx_pending_timer);
-+ del_timer(&netbk->net_timer);
-+ rc = PTR_ERR(netbk->task);
-+ goto failed_init;
- }
-
-+ kthread_bind(netbk->task, group);
++ pr_debug("Created grant allocation device at %d,%d\n",
++ MISC_MAJOR, gntalloc_miscdev.minor);
+
- INIT_LIST_HEAD(&netbk->pending_inuse_head);
- INIT_LIST_HEAD(&netbk->net_schedule_list);
-
-@@ -1774,8 +1734,7 @@ static int __init netback_init(void)
-
- atomic_set(&netbk->netfront_count, 0);
-
-- if (MODPARM_netback_kthread)
-- wake_up_process(netbk->kthread.task);
-+ wake_up_process(netbk->task);
- }
-
- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
-@@ -1800,8 +1759,7 @@ failed_init:
- MAX_PENDING_REQS);
- del_timer(&netbk->netbk_tx_pending_timer);
- del_timer(&netbk->net_timer);
-- if (MODPARM_netback_kthread)
-- kthread_stop(netbk->kthread.task);
-+ kthread_stop(netbk->task);
- }
- vfree(xen_netbk);
- return rc;
++ return 0;
++}
++
++static void __exit gntalloc_exit(void)
++{
++ misc_deregister(&gntalloc_miscdev);
++}
++
++module_init(gntalloc_init);
++module_exit(gntalloc_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Carter Weatherly <carter.weatherly(a)jhuapl.edu>, "
++ "Daniel De Graaf <dgdegra(a)tycho.nsa.gov>");
++MODULE_DESCRIPTION("User-space grant reference allocator driver");
+diff --git a/include/xen/gntalloc.h b/include/xen/gntalloc.h
+new file mode 100644
+index 0000000..bc3b85e
+--- /dev/null
++++ b/include/xen/gntalloc.h
+@@ -0,0 +1,50 @@
++/******************************************************************************
++ * gntalloc.h
++ *
++ * Interface to /dev/xen/gntalloc.
++ *
++ * Author: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
++ *
++ * This file is in the public domain.
++ */
++
++#ifndef __LINUX_PUBLIC_GNTALLOC_H__
++#define __LINUX_PUBLIC_GNTALLOC_H__
++
++/*
++ * Allocates a new page and creates a new grant reference.
++ */
++#define IOCTL_GNTALLOC_ALLOC_GREF \
++_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
++struct ioctl_gntalloc_alloc_gref {
++ /* IN parameters */
++ /* The ID of the domain to be given access to the grants. */
++ uint16_t domid;
++ /* Flags for this mapping */
++ uint16_t flags;
++ /* Number of pages to map */
++ uint32_t count;
++ /* OUT parameters */
++ /* The offset to be used on a subsequent call to mmap(). */
++ uint64_t index;
++ /* The grant references of the newly created grant, one per page */
++ /* Variable size, depending on count */
++ uint32_t gref_ids[1];
++};
++
++#define GNTALLOC_FLAG_WRITABLE 1
++
++/*
++ * Deallocates the grant reference, allowing the associated page to be freed if
++ * no other domains are using it.
++ */
++#define IOCTL_GNTALLOC_DEALLOC_GREF \
++_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
++struct ioctl_gntalloc_dealloc_gref {
++ /* IN parameters */
++ /* The offset returned in the map operation */
++ uint64_t index;
++ /* Number of references to unmap */
++ uint32_t count;
++};
++#endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
--
1.7.4
-From e564d36cd3368e17218052148932322f7fe324bf Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 2 Feb 2011 17:25:26 +0000
-Subject: [PATCH 142/244] xen: netback: handle frames whose head crosses a page boundary
+From bdc612dc6903c4ea06e40d02f84ad5e25d93459d Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Thu, 3 Feb 2011 12:19:04 -0500
+Subject: [PATCH 126/203] xen/gntalloc,gntdev: Add unmap notify ioctl
-Previoulsy we copied any skb whose head crossed a page boundary before
-forwarding to the guest. However dealing with these skbs is relatively straight
-forward.
+This ioctl allows the users of a shared page to be notified when
+the other end exits abnormally.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+[v2: updated description in structs]
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/net/xen-netback/interface.c | 103 ++---------------------------------
- drivers/net/xen-netback/netback.c | 48 +++++++++++------
- 2 files changed, 36 insertions(+), 115 deletions(-)
+ drivers/xen/gntalloc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/xen/gntdev.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-
+ include/xen/gntalloc.h | 32 +++++++++++++++++++++++++
+ include/xen/gntdev.h | 31 ++++++++++++++++++++++++
+ 4 files changed, 182 insertions(+), 1 deletions(-)
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index c906c79..1bd2eeb 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -51,9 +51,12 @@ void xenvif_put(struct xenvif *vif)
+diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
+index d06bf2b..a7ffdfe 100644
+--- a/drivers/xen/gntalloc.c
++++ b/drivers/xen/gntalloc.c
+@@ -60,11 +60,13 @@
+ #include <linux/uaccess.h>
+ #include <linux/types.h>
+ #include <linux/list.h>
++#include <linux/highmem.h>
- static int xenvif_max_required_rx_slots(struct xenvif *vif)
+ #include <xen/xen.h>
+ #include <xen/page.h>
+ #include <xen/grant_table.h>
+ #include <xen/gntalloc.h>
++#include <xen/events.h>
+
+ static int limit = 1024;
+ module_param(limit, int, 0644);
+@@ -75,6 +77,12 @@ static LIST_HEAD(gref_list);
+ static DEFINE_SPINLOCK(gref_lock);
+ static int gref_size;
+
++struct notify_info {
++ uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
++ uint16_t flags:2; /* Bits 12-13: Unmap notification flags */
++ int event; /* Port (event channel) to notify */
++};
++
+ /* Metadata on a grant reference. */
+ struct gntalloc_gref {
+ struct list_head next_gref; /* list entry gref_list */
+@@ -83,6 +91,7 @@ struct gntalloc_gref {
+ uint64_t file_index; /* File offset for mmap() */
+ unsigned int users; /* Use count - when zero, waiting on Xen */
+ grant_ref_t gref_id; /* The grant reference number */
++ struct notify_info notify; /* Unmap notification */
+ };
+
+ struct gntalloc_file_private_data {
+@@ -164,6 +173,16 @@ undo:
+
+ static void __del_gref(struct gntalloc_gref *gref)
{
-+ int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE);
++ if (gref->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
++ uint8_t *tmp = kmap(gref->page);
++ tmp[gref->notify.pgoff] = 0;
++ kunmap(gref->page);
++ }
++ if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
++ notify_remote_via_evtchn(gref->notify.event);
+
- if (vif->can_sg || vif->gso || vif->gso_prefix)
-- return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-- return 1; /* all in one */
-+ max += MAX_SKB_FRAGS + 1; /* extra_info + frags */
++ gref->notify.flags = 0;
+
-+ return max;
- }
-
- int xenvif_queue_full(struct xenvif *vif)
-@@ -104,87 +107,6 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
- return IRQ_HANDLED;
+ if (gref->gref_id > 0) {
+ if (gnttab_query_foreign_access(gref->gref_id))
+ return;
+@@ -349,6 +368,43 @@ dealloc_grant_out:
+ return rc;
}
--/* TODO: move to networking core */
--static struct sk_buff *xenvif_copy_skb(struct sk_buff *skb)
--{
-- struct skb_shared_info *ninfo;
-- struct sk_buff *nskb;
-- unsigned long offset;
-- int ret;
-- int len;
-- int headlen;
--
-- BUG_ON(skb_shinfo(skb)->frag_list != NULL);
--
-- nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-- if (unlikely(!nskb))
-- goto err;
--
-- skb_reserve(nskb, NET_SKB_PAD + NET_IP_ALIGN);
-- headlen = skb_end_pointer(nskb) - nskb->data;
-- if (headlen > skb_headlen(skb))
-- headlen = skb_headlen(skb);
-- ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-- BUG_ON(ret);
--
-- ninfo = skb_shinfo(nskb);
-- ninfo->gso_size = skb_shinfo(skb)->gso_size;
-- ninfo->gso_type = skb_shinfo(skb)->gso_type;
--
-- offset = headlen;
-- len = skb->len - headlen;
--
-- nskb->len = skb->len;
-- nskb->data_len = len;
-- nskb->truesize += len;
--
-- while (len) {
-- struct page *page;
-- int copy;
-- int zero;
--
-- if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-- dump_stack();
-- goto err_free;
-- }
--
-- copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-- zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
--
-- page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-- if (unlikely(!page))
-- goto err_free;
--
-- ret = skb_copy_bits(skb, offset, page_address(page), copy);
-- BUG_ON(ret);
--
-- ninfo->frags[ninfo->nr_frags].page = page;
-- ninfo->frags[ninfo->nr_frags].page_offset = 0;
-- ninfo->frags[ninfo->nr_frags].size = copy;
-- ninfo->nr_frags++;
--
-- offset += copy;
-- len -= copy;
-- }
--
--#ifdef NET_SKBUFF_DATA_USES_OFFSET
-- offset = 0;
--#else
-- offset = nskb->data - skb->data;
--#endif
--
-- nskb->transport_header = skb->transport_header + offset;
-- nskb->network_header = skb->network_header + offset;
-- nskb->mac_header = skb->mac_header + offset;
--
-- return nskb;
--
-- err_free:
-- kfree_skb(nskb);
-- err:
-- return NULL;
--}
--
- static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
++static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
++ void __user *arg)
++{
++ struct ioctl_gntalloc_unmap_notify op;
++ struct gntalloc_gref *gref;
++ uint64_t index;
++ int pgoff;
++ int rc;
++
++ if (copy_from_user(&op, arg, sizeof(op)))
++ return -EFAULT;
++
++ index = op.index & ~(PAGE_SIZE - 1);
++ pgoff = op.index & (PAGE_SIZE - 1);
++
++ spin_lock(&gref_lock);
++
++ gref = find_grefs(priv, index, 1);
++ if (!gref) {
++ rc = -ENOENT;
++ goto unlock_out;
++ }
++
++ if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT)) {
++ rc = -EINVAL;
++ goto unlock_out;
++ }
++
++ gref->notify.flags = op.action;
++ gref->notify.pgoff = pgoff;
++ gref->notify.event = op.event_channel_port;
++ rc = 0;
++ unlock_out:
++ spin_unlock(&gref_lock);
++ return rc;
++}
++
+ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
- struct xenvif *vif = netdev_priv(dev);
-@@ -198,21 +120,6 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device
*dev)
- if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
- goto drop;
+@@ -361,6 +417,9 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
+ case IOCTL_GNTALLOC_DEALLOC_GREF:
+ return gntalloc_ioctl_dealloc(priv, (void __user *)arg);
-- /*
-- * XXX For now we also copy skbuffs whose head crosses a page
-- * boundary, because netbk_gop_skb can't handle them.
-- */
-- if ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE) {
-- struct sk_buff *nskb = xenvif_copy_skb(skb);
-- if (unlikely(nskb == NULL))
-- goto drop;
-- /* Copy only the header fields we use in this driver. */
-- nskb->dev = skb->dev;
-- nskb->ip_summed = skb->ip_summed;
-- dev_kfree_skb(skb);
-- skb = nskb;
-- }
--
- /* Reserve ring slots for the worst-case number of fragments. */
- vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
- xenvif_get(vif);
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 73e35fd..79b8c30 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -307,12 +307,13 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int
head)
- */
- unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
- {
-- unsigned int count = 1;
-- int i, copy_off = 0;
-+ unsigned int count;
-+ int i, copy_off;
++ case IOCTL_GNTALLOC_SET_UNMAP_NOTIFY:
++ return gntalloc_ioctl_unmap_notify(priv, (void __user *)arg);
++
+ default:
+ return -ENOIOCTLCMD;
+ }
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index bcaf797..9694a1a 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -37,6 +37,7 @@
+ #include <xen/xen.h>
+ #include <xen/grant_table.h>
+ #include <xen/gntdev.h>
++#include <xen/events.h>
+ #include <asm/xen/hypervisor.h>
+ #include <asm/xen/hypercall.h>
+ #include <asm/xen/page.h>
+@@ -63,6 +64,13 @@ struct gntdev_priv {
+ struct mmu_notifier mn;
+ };
-- BUG_ON(offset_in_page(skb->data)+skb_headlen(skb) > MAX_BUFFER_OFFSET);
-+ count = DIV_ROUND_UP(
-+ offset_in_page(skb->data)+skb_headlen(skb), PAGE_SIZE);
++struct unmap_notify {
++ int flags;
++ /* Address relative to the start of the grant_map */
++ int addr;
++ int event;
++};
++
+ struct grant_map {
+ struct list_head next;
+ struct vm_area_struct *vma;
+@@ -71,6 +79,7 @@ struct grant_map {
+ int flags;
+ int is_mapped;
+ atomic_t users;
++ struct unmap_notify notify;
+ struct ioctl_gntdev_grant_ref *grants;
+ struct gnttab_map_grant_ref *map_ops;
+ struct gnttab_unmap_grant_ref *unmap_ops;
+@@ -165,7 +174,7 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv
*priv,
+ list_for_each_entry(map, &priv->maps, next) {
+ if (map->index != index)
+ continue;
+- if (map->count != count)
++ if (count && map->count != count)
+ continue;
+ return map;
+ }
+@@ -184,6 +193,10 @@ static void gntdev_put_map(struct grant_map *map)
-- copy_off = skb_headlen(skb);
-+ copy_off = skb_headlen(skb) % PAGE_SIZE;
+ atomic_sub(map->count, &pages_mapped);
- if (skb_shinfo(skb)->gso_size)
- count++;
-@@ -371,10 +372,10 @@ static struct netbk_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 netbk_gop_frag_copy(struct xenvif *vif,
-+static void netbk_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
- struct netrx_pending_operations *npo,
- struct page *page, unsigned long size,
-- unsigned long offset, int head)
-+ unsigned long offset, int *head)
++ if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
++ notify_remote_via_evtchn(map->notify.event);
++ }
++
+ if (map->pages) {
+ if (!use_ptemod)
+ unmap_grant_pages(map, 0, map->count);
+@@ -274,6 +287,16 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
{
- struct gnttab_copy *copy_gop;
- struct netbk_rx_meta *meta;
-@@ -394,12 +395,12 @@ static void netbk_gop_frag_copy(struct xenvif *vif,
- while (size > 0) {
- BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
+ int i, err = 0;
-- if (start_new_rx_buffer(npo->copy_off, size, head)) {
-+ if (start_new_rx_buffer(npo->copy_off, size, *head)) {
- /*
- * Netfront requires there to be some data in the head
- * buffer.
- */
-- BUG_ON(head);
-+ BUG_ON(*head);
++ if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
++ int pgno = (map->notify.addr >> PAGE_SHIFT);
++ if (pgno >= offset && pgno < offset + pages) {
++ uint8_t *tmp = kmap(map->pages[pgno]);
++ tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
++ kunmap(map->pages[pgno]);
++ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
++ }
++ }
++
+ pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
+ err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
+ if (err)
+@@ -519,6 +542,39 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv
*priv,
+ return 0;
+ }
- meta = get_next_rx_buffer(vif, npo);
- }
-@@ -436,7 +437,13 @@ static void netbk_gop_frag_copy(struct xenvif *vif,
++static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
++{
++ struct ioctl_gntdev_unmap_notify op;
++ struct grant_map *map;
++ int rc;
++
++ if (copy_from_user(&op, u, sizeof(op)))
++ return -EFAULT;
++
++ if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
++ return -EINVAL;
++
++ spin_lock(&priv->lock);
++
++ list_for_each_entry(map, &priv->maps, next) {
++ uint64_t begin = map->index << PAGE_SHIFT;
++ uint64_t end = (map->index + map->count) << PAGE_SHIFT;
++ if (op.index >= begin && op.index < end)
++ goto found;
++ }
++ rc = -ENOENT;
++ goto unlock_out;
++
++ found:
++ map->notify.flags = op.action;
++ map->notify.addr = op.index - (map->index << PAGE_SHIFT);
++ map->notify.event = op.event_channel_port;
++ rc = 0;
++ unlock_out:
++ spin_unlock(&priv->lock);
++ return rc;
++}
++
+ static long gntdev_ioctl(struct file *flip,
+ unsigned int cmd, unsigned long arg)
+ {
+@@ -535,6 +591,9 @@ static long gntdev_ioctl(struct file *flip,
+ case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
+ return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
- offset += bytes;
- size -= bytes;
-- head = 0; /* There must be something in this buffer now. */
++ case IOCTL_GNTDEV_SET_UNMAP_NOTIFY:
++ return gntdev_ioctl_notify(priv, ptr);
+
-+ /* Leave a gap for the GSO descriptor. */
-+ if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix)
-+ vif->rx.req_cons++;
+ default:
+ pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
+ return -ENOIOCTLCMD;
+diff --git a/include/xen/gntalloc.h b/include/xen/gntalloc.h
+index bc3b85e..76bd580 100644
+--- a/include/xen/gntalloc.h
++++ b/include/xen/gntalloc.h
+@@ -47,4 +47,36 @@ struct ioctl_gntalloc_dealloc_gref {
+ /* Number of references to unmap */
+ uint32_t count;
+ };
+
-+ *head = 0; /* There must be something in this buffer now. */
++/*
++ * Sets up an unmap notification within the page, so that the other side can do
++ * cleanup if this side crashes. Required to implement cross-domain robust
++ * mutexes or close notification on communication channels.
++ *
++ * Each mapped page only supports one notification; multiple calls referring to
++ * the same page overwrite the previous notification. You must clear the
++ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
++ * to occur.
++ */
++#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
++_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
++struct ioctl_gntalloc_unmap_notify {
++ /* IN parameters */
++ /* Offset in the file descriptor for a byte within the page (same as
++ * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
++ * be cleared. Otherwise, it can be any byte in the page whose
++ * notification we are adjusting.
++ */
++ uint64_t index;
++ /* Action(s) to take on unmap */
++ uint32_t action;
++ /* Event channel to notify */
++ uint32_t event_channel_port;
++};
+
- }
- }
-
-@@ -460,6 +467,8 @@ static int netbk_gop_skb(struct sk_buff *skb,
- int i;
- struct xen_netif_rx_request *req;
- struct netbk_rx_meta *meta;
-+ unsigned char *data;
-+ int head = 1;
- int old_meta_prod;
-
- old_meta_prod = npo->meta_prod;
-@@ -486,20 +495,25 @@ static int netbk_gop_skb(struct sk_buff *skb,
- npo->copy_off = 0;
- npo->copy_gref = req->gref;
-
-- netbk_gop_frag_copy(vif, npo, virt_to_page(skb->data),
-- skb_headlen(skb),
-- offset_in_page(skb->data), 1);
-+ data = skb->data;
-+ while (data < skb_tail_pointer(skb)) {
-+ unsigned int offset = offset_in_page(data);
-+ unsigned int len = PAGE_SIZE - offset;
-
-- /* Leave a gap for the GSO descriptor. */
-- if (skb_shinfo(skb)->gso_size && !vif->gso_prefix)
-- vif->rx.req_cons++;
-+ if (data + len > skb_tail_pointer(skb))
-+ len = skb_tail_pointer(skb) - data;
++/* Clear (set to zero) the byte specified by index */
++#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
++/* Send an interrupt on the indicated event channel */
++#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
-+ netbk_gop_frag_copy(vif, skb, npo,
-+ virt_to_page(data), len, offset, &head);
-+ data += len;
-+ }
-
- for (i = 0; i < nr_frags; i++) {
-- netbk_gop_frag_copy(vif, npo,
-+ netbk_gop_frag_copy(vif, skb, npo,
- skb_shinfo(skb)->frags[i].page,
- skb_shinfo(skb)->frags[i].size,
- skb_shinfo(skb)->frags[i].page_offset,
-- 0);
-+ &head);
- }
+ #endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
+diff --git a/include/xen/gntdev.h b/include/xen/gntdev.h
+index eb23f41..5304bd3 100644
+--- a/include/xen/gntdev.h
++++ b/include/xen/gntdev.h
+@@ -116,4 +116,35 @@ struct ioctl_gntdev_set_max_grants {
+ uint32_t count;
+ };
- return npo->meta_prod - old_meta_prod;
++/*
++ * Sets up an unmap notification within the page, so that the other side can do
++ * cleanup if this side crashes. Required to implement cross-domain robust
++ * mutexes or close notification on communication channels.
++ *
++ * Each mapped page only supports one notification; multiple calls referring to
++ * the same page overwrite the previous notification. You must clear the
++ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
++ * to occur.
++ */
++#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
++_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
++struct ioctl_gntdev_unmap_notify {
++ /* IN parameters */
++ /* Offset in the file descriptor for a byte within the page (same as
++ * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
++ * be cleared. Otherwise, it can be any byte in the page whose
++ * notification we are adjusting.
++ */
++ uint64_t index;
++ /* Action(s) to take on unmap */
++ uint32_t action;
++ /* Event channel to notify */
++ uint32_t event_channel_port;
++};
++
++/* Clear (set to zero) the byte specified by index */
++#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
++/* Send an interrupt on the indicated event channel */
++#define UNMAP_NOTIFY_SEND_EVENT 0x2
++
+ #endif /* __LINUX_PUBLIC_GNTDEV_H__ */
--
1.7.4
-From 64702558e140c916ac2aca9bf0ec50521de105ca Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Sat, 11 Dec 2010 10:15:50 +0000
-Subject: [PATCH 143/244] xen: netback: Make dependency on PageForeign conditional
-
-When PageForeign is not available we fallback to a copying TX mode.
+From 90b6f30548a52f3a59cda5c7db0b9c2a99ebb156 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Thu, 3 Feb 2011 14:16:54 -0500
+Subject: [PATCH 127/203] xen-gntdev: Fix memory leak when mmap fails
-All uses of PageForeign are now gated with HAVE_XEN_PAGE_FOREIGN, this should
-allow for easier removal of the dependency for upstream, e.g. using unifdef.
+The error path did not decrement the reference count of the grant structure.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/net/xen-netback/common.h | 4 +
- drivers/net/xen-netback/interface.c | 2 +
- drivers/net/xen-netback/netback.c | 279 ++++++++++++++++++++++++++++++-----
- drivers/net/xen-netback/xenbus.c | 2 +
- 4 files changed, 252 insertions(+), 35 deletions(-)
+ drivers/xen/gntdev.c | 14 ++++++++------
+ 1 files changed, 8 insertions(+), 6 deletions(-)
-diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-index b998a27..8890825 100644
---- a/drivers/net/xen-netback/common.h
-+++ b/drivers/net/xen-netback/common.h
-@@ -95,7 +95,9 @@ struct xenvif {
- struct timer_list credit_timeout;
-
- /* Statistics */
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- int nr_copied_skbs;
-+#endif
- int rx_gso_checksum_fixup;
-
- /* Miscellaneous private stuff. */
-@@ -109,6 +111,7 @@ struct xenvif {
- wait_queue_head_t waiting_to_free;
- };
-
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- enum {
- NETBK_DONT_COPY_SKB,
- NETBK_DELAYED_COPY_SKB,
-@@ -116,6 +119,7 @@ enum {
- };
-
- extern int netbk_copy_skb_mode;
-+#endif
-
- #define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
- #define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index 1bd2eeb..6e11878 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -272,10 +272,12 @@ static const struct xenvif_stat {
- char name[ETH_GSTRING_LEN];
- u16 offset;
- } xenvif_stats[] = {
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- {
- "copied_skbs",
- offsetof(struct xenvif, nr_copied_skbs)
- },
-+#endif
- {
- "rx_gso_checksum_fixup",
- offsetof(struct xenvif, rx_gso_checksum_fixup)
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 79b8c30..265fbdd 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -40,7 +40,9 @@
-
- #include <net/tcp.h>
-
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- #include <xen/balloon.h>
-+#endif
- #include <xen/events.h>
- #include <xen/interface/memory.h>
-
-@@ -59,10 +61,12 @@ struct netbk_rx_meta {
- int gso_size;
- };
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 9694a1a..2aa8316 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -650,15 +650,13 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ find_grant_ptes, map);
+ if (err) {
+ printk(KERN_WARNING "find_grant_ptes() failure.\n");
+- return err;
++ goto out_put_map;
+ }
+ }
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- struct netbk_tx_pending_inuse {
- struct list_head list;
- unsigned long alloc_time;
- };
-+#endif
+ err = map_grant_pages(map);
+- if (err) {
+- printk(KERN_WARNING "map_grant_pages() failure.\n");
+- return err;
+- }
++ if (err)
++ goto out_put_map;
- #define MAX_PENDING_REQS 256
+ map->is_mapped = 1;
-@@ -91,16 +95,24 @@ struct xen_netbk {
- struct sk_buff_head tx_queue;
+@@ -667,7 +665,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
+ map->pages[i]);
+ if (err)
+- return err;
++ goto out_put_map;
+ }
+ }
- struct timer_list net_timer;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- struct timer_list netbk_tx_pending_timer;
-+#endif
+@@ -676,6 +674,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ unlock_out:
+ spin_unlock(&priv->lock);
+ return err;
++
++out_put_map:
++ gntdev_put_map(map);
++ return err;
+ }
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- struct page **mmap_pages;
-+#else
-+ struct page *mmap_pages[MAX_PENDING_REQS];
-+#endif
+ static const struct file_operations gntdev_fops = {
+--
+1.7.4
+
+
+From 0ea22f072fb1b3da4307573c280ce904f0bf1589 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Tue, 8 Feb 2011 09:14:06 -0500
+Subject: [PATCH 128/203] xen-gntdev: Fix unmap notify on PV domains
+
+In paravirtualized guests, the struct page* for mappings is only a
+placeholder, and cannot be used to access the granted memory. Use the
+userspace mapping that we have set up in order to implement
+UNMAP_NOTIFY_CLEAR_BYTE.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 9 +++++++--
+ 1 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 2aa8316..75f8037 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -289,7 +289,12 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
- pending_ring_idx_t pending_prod;
- pending_ring_idx_t pending_cons;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- pending_ring_idx_t dealloc_prod;
- pending_ring_idx_t dealloc_cons;
+ if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
+ int pgno = (map->notify.addr >> PAGE_SHIFT);
+- if (pgno >= offset && pgno < offset + pages) {
++ if (pgno >= offset && pgno < offset + pages && use_ptemod) {
++ void __user *tmp;
++ tmp = map->vma->vm_start + map->notify.addr;
++ copy_to_user(tmp, &err, 1);
++ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
++ } else if (pgno >= offset && pgno < offset + pages) {
+ uint8_t *tmp = kmap(map->pages[pgno]);
+ tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
+ kunmap(map->pages[pgno]);
+@@ -298,7 +303,7 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+ }
- struct list_head pending_inuse_head;
-+#endif
- struct list_head net_schedule_list;
+ pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
+- err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
++ err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages);
+ if (err)
+ return err;
- /* Protect the net_schedule_list in netif. */
-@@ -109,13 +121,20 @@ struct xen_netbk {
- atomic_t netfront_count;
+--
+1.7.4
+
+
+From 84e4075d60fc8f1c0b937765620bc784dd0c3d39 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Wed, 9 Feb 2011 15:11:59 -0500
+Subject: [PATCH 129/203] xen-gntdev: Use map->vma for checking map validity
+
+The is_mapped flag used to be set at the completion of the map operation,
+but was not checked in all error paths. Use map->vma instead, which will
+now be cleared if the initial grant mapping fails.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 8 ++------
+ 1 files changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 75f8037..4ca4262 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -77,7 +77,6 @@ struct grant_map {
+ int index;
+ int count;
+ int flags;
+- int is_mapped;
+ atomic_t users;
+ struct unmap_notify notify;
+ struct ioctl_gntdev_grant_ref *grants;
+@@ -322,7 +321,6 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
+ struct grant_map *map = vma->vm_private_data;
- struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- 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];
+ pr_debug("close %p\n", vma);
+- map->is_mapped = 0;
+ map->vma = NULL;
+ vma->vm_private_data = NULL;
+ gntdev_put_map(map);
+@@ -347,8 +345,6 @@ static void mn_invl_range_start(struct mmu_notifier *mn,
+ list_for_each_entry(map, &priv->maps, next) {
+ if (!map->vma)
+ continue;
+- if (!map->is_mapped)
+- continue;
+ if (map->vma->vm_start >= end)
+ continue;
+ if (map->vma->vm_end <= start)
+@@ -663,8 +659,6 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ if (err)
+ goto out_put_map;
- grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
-+#else
-+ struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
-+#endif
-+
- u16 pending_ring[MAX_PENDING_REQS];
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- u16 dealloc_ring[MAX_PENDING_REQS];
-+#endif
+- map->is_mapped = 1;
+-
+ if (!use_ptemod) {
+ for (i = 0; i < count; i++) {
+ err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
+@@ -681,6 +675,8 @@ unlock_out:
+ return err;
- /*
- * Each head or fragment can be up to 4096 bytes. Given
-@@ -184,9 +203,10 @@ static inline unsigned long idx_to_kaddr(struct xen_netbk *netbk,
+ out_put_map:
++ if (use_ptemod)
++ map->vma = NULL;
+ gntdev_put_map(map);
+ return err;
+ }
+--
+1.7.4
+
+
+From b57c18694ea1641b691fa05ed8af0ce339fa430b Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Wed, 9 Feb 2011 15:12:00 -0500
+Subject: [PATCH 130/203] xen-gntdev: Avoid unmapping ranges twice
+
+In paravirtualized domains, mn_invl_page or mn_invl_range_start can
+unmap a segment of a mapped region without unmapping all pages. When
+the region is later released, the pages will be unmapped twice, leading
+to an incorrect -EINVAL return.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 33 +++++++++++++++++++++++++++++++--
+ 1 files changed, 31 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 4ca4262..4687cd5 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -282,7 +282,7 @@ static int map_grant_pages(struct grant_map *map)
+ return err;
}
- /* extra field used in struct page */
--static inline void set_page_ext(struct page *pg,
-- unsigned int group, unsigned int idx)
-+static inline void set_page_ext(struct page *pg, struct xen_netbk *netbk,
-+ unsigned int idx)
+-static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
++static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
{
-+ unsigned int group = netbk - xen_netbk;
- union page_ext ext = { .e = { .group = group + 1, .idx = idx } };
-
- BUILD_BUG_ON(sizeof(ext) > sizeof(ext.mapping));
-@@ -200,8 +220,10 @@ static int get_page_ext(struct page *pg,
- struct xen_netbk *netbk;
- unsigned int group, idx;
-
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- if (!PageForeign(pg))
- return 0;
-+#endif
-
- group = ext.e.group - 1;
+ int i, err = 0;
-@@ -210,8 +232,10 @@ static int get_page_ext(struct page *pg,
+@@ -301,7 +301,6 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+ }
+ }
- netbk = &xen_netbk[group];
+- pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
+ err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages);
+ if (err)
+ return err;
+@@ -314,6 +313,36 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+ return err;
+ }
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- if (netbk->mmap_pages == NULL)
- return 0;
-+#endif
++static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
++{
++ int range, err = 0;
++
++ pr_debug("unmap %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
++
++ /* It is possible the requested range will have a "hole" where we
++ * already unmapped some of the grants. Only unmap valid ranges.
++ */
++ while (pages && !err) {
++ while (pages && !map->unmap_ops[offset].handle) {
++ offset++;
++ pages--;
++ }
++ range = 0;
++ while (range < pages) {
++ if (!map->unmap_ops[offset+range].handle) {
++ range--;
++ break;
++ }
++ range++;
++ }
++ err = __unmap_grant_pages(map, offset, range);
++ offset += range;
++ pages -= range;
++ }
++
++ return err;
++}
++
+ /* ------------------------------------------------------------------ */
- idx = ext.e.idx;
+ static void gntdev_vma_close(struct vm_area_struct *vma)
+--
+1.7.4
+
+
+From 12996fc38a2d760f3b30c9ceae26d0eeb92fe52d Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Wed, 9 Feb 2011 16:11:32 -0500
+Subject: [PATCH 131/203] xen-gntdev: Avoid double-mapping memory
+
+If an already-mapped area of the device was mapped into userspace a
+second time, a hypercall was incorrectly made to remap the memory
+again. Avoid the hypercall on later mmap calls, and fail the mmap call
+if a writable mapping is attempted on a read-only range.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 15 ++++++++++++---
+ 1 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 4687cd5..2c4cc94 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -258,6 +258,9 @@ static int map_grant_pages(struct grant_map *map)
+ phys_addr_t addr;
-@@ -248,12 +272,14 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk
*netbk)
- netbk->pending_prod + netbk->pending_cons;
- }
+ if (!use_ptemod) {
++ /* Note: it could already be mapped */
++ if (map->map_ops[0].handle)
++ return 0;
+ for (i = 0; i < map->count; i++) {
+ addr = (phys_addr_t)
+ pfn_to_kaddr(page_to_pfn(map->pages[i]));
+@@ -668,9 +671,15 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
+ if (use_ptemod)
+ map->vma = vma;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- /* Setting this allows the safe use of this driver without netloop. */
- static int MODPARM_copy_skb = 1;
- module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
- MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
+- map->flags = GNTMAP_host_map;
+- if (!(vma->vm_flags & VM_WRITE))
+- map->flags |= GNTMAP_readonly;
++ if (map->flags) {
++ if ((vma->vm_flags & VM_WRITE) &&
++ (map->flags & GNTMAP_readonly))
++ return -EINVAL;
++ } else {
++ map->flags = GNTMAP_host_map;
++ if (!(vma->vm_flags & VM_WRITE))
++ map->flags |= GNTMAP_readonly;
++ }
- int netbk_copy_skb_mode;
-+#endif
+ spin_unlock(&priv->lock);
- static void xen_netbk_kick_thread(struct xen_netbk *netbk)
- {
-@@ -726,11 +752,13 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff
*skb)
- xen_netbk_kick_thread(netbk);
- }
+--
+1.7.4
+
+
+From 9960be970cea52c1cb7d7c747ff6da367e1c01b5 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Wed, 9 Feb 2011 18:15:50 -0500
+Subject: [PATCH 132/203] xen-gntdev: prevent using UNMAP_NOTIFY_CLEAR_BYTE on read-only
mappings
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 10 +++++++++-
+ 1 files changed, 9 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 2c4cc94..2a4733c 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -294,7 +294,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+ if (pgno >= offset && pgno < offset + pages && use_ptemod) {
+ void __user *tmp;
+ tmp = map->vma->vm_start + map->notify.addr;
+- copy_to_user(tmp, &err, 1);
++ err = copy_to_user(tmp, &err, 1);
++ if (err)
++ return err;
+ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
+ } else if (pgno >= offset && pgno < offset + pages) {
+ uint8_t *tmp = kmap(map->pages[pgno]);
+@@ -599,6 +601,12 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void
__user *u)
+ goto unlock_out;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- static void xen_netbk_tx_pending_timeout(unsigned long data)
- {
- struct xen_netbk *netbk = (struct xen_netbk *)data;
- xen_netbk_kick_thread(netbk);
- }
-+#endif
+ found:
++ if ((op.action & UNMAP_NOTIFY_CLEAR_BYTE) &&
++ (map->flags & GNTMAP_readonly)) {
++ rc = -EINVAL;
++ goto unlock_out;
++ }
++
+ map->notify.flags = op.action;
+ map->notify.addr = op.index - (map->index << PAGE_SHIFT);
+ map->notify.event = op.event_channel_port;
+--
+1.7.4
+
+
+From aa95762050b578ea143d674c228f8d5afd33e9ab Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx(a)linutronix.de>
+Date: Sat, 5 Feb 2011 20:08:59 +0000
+Subject: [PATCH 133/203] xen: Use IRQF_FORCE_RESUME
+
+Mark the IRQF_NO_SUSPEND interrupts IRQF_FORCE_RESUME and remove the extra
+walk through the interrupt descriptors.
+
+Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 20 +-------------------
+ 1 files changed, 1 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 5aa422a..975e90f 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -977,7 +977,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ if (irq < 0)
+ return irq;
- static void xen_netbk_alarm(unsigned long data)
+- irqflags |= IRQF_NO_SUSPEND;
++ irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME;
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+@@ -1433,7 +1433,6 @@ void xen_poll_irq(int irq)
+ void xen_irq_resume(void)
{
-@@ -831,6 +859,7 @@ static void tx_credit_callback(unsigned long data)
- xenvif_schedule_work(vif);
- }
+ unsigned int cpu, irq, evtchn;
+- struct irq_desc *desc;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- static inline int copy_pending_req(struct xen_netbk *netbk,
- pending_ring_idx_t pending_idx)
- {
-@@ -838,7 +867,9 @@ static inline int copy_pending_req(struct xen_netbk *netbk,
- netbk->grant_tx_handle[pending_idx],
- &netbk->mmap_pages[pending_idx]);
- }
-+#endif
+ init_evtchn_cpu_bindings();
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- static inline void xen_netbk_tx_action_dealloc(struct xen_netbk *netbk)
- {
- struct netbk_tx_pending_inuse *inuse, *n;
-@@ -943,6 +974,7 @@ static inline void xen_netbk_tx_action_dealloc(struct xen_netbk
*netbk)
- list_del_init(&inuse->list);
+@@ -1453,23 +1452,6 @@ void xen_irq_resume(void)
+ restore_cpu_ipis(cpu);
}
- }
-+#endif
- static void netbk_tx_err(struct xenvif *vif,
- struct xen_netif_tx_request *txp, RING_IDX end)
-@@ -998,15 +1030,37 @@ static int netbk_count_requests(struct xenvif *vif,
- return -frags;
- }
- } while ((txp++)->flags & XEN_NETTXF_more_data);
+- /*
+- * Unmask any IRQF_NO_SUSPEND IRQs which are enabled. These
+- * are not handled by the IRQ core.
+- */
+- for_each_irq_desc(irq, desc) {
+- if (!desc->action || !(desc->action->flags & IRQF_NO_SUSPEND))
+- continue;
+- if (desc->status & IRQ_DISABLED)
+- continue;
-
- return frags;
+- evtchn = evtchn_from_irq(irq);
+- if (evtchn == -1)
+- continue;
+-
+- unmask_evtchn(evtchn);
+- }
+-
+ restore_cpu_pirqs();
}
-+#ifndef HAVE_XEN_PAGE_FOREIGN
-+static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
-+ struct sk_buff *skb,
-+ unsigned long pending_idx)
-+{
-+ struct page *page;
-+ page = alloc_page(GFP_KERNEL|__GFP_COLD);
-+ if (!page)
-+ return NULL;
-+ set_page_ext(page, netbk, pending_idx);
-+ netbk->mmap_pages[pending_idx] = page;
-+ return page;
-+}
-+#endif
-+
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
- struct xenvif *vif,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
-- struct gnttab_map_grant_ref *mop)
-+ struct gnttab_map_grant_ref *gop)
-+#else
-+static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
-+ struct xenvif *vif,
-+ struct sk_buff *skb,
-+ struct xen_netif_tx_request *txp,
-+ struct gnttab_copy *gop)
-+#endif
- {
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- skb_frag_t *frags = shinfo->frags;
-@@ -1017,16 +1071,39 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
+--
+1.7.4
+
+
+From 1f169f66ddcc3b4614f840bef367de1ca20e16fe Mon Sep 17 00:00:00 2001
+From: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Date: Thu, 10 Feb 2011 12:08:21 +0000
+Subject: [PATCH 134/203] xen: change xen/[gntdev/gntalloc] to default m
+
+When CONFIG_XEN is enabled the gntdev and gntalloc driver will be
+compiled as a module by default.
+
+[v2: Added the fix for the gntalloc driver as well]
+
+Signed-off-by: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/Kconfig | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
+index a3d7afb..a59638b 100644
+--- a/drivers/xen/Kconfig
++++ b/drivers/xen/Kconfig
+@@ -76,6 +76,7 @@ config XEN_XENBUS_FRONTEND
+ config XEN_GNTDEV
+ tristate "userspace grant access device driver"
+ depends on XEN
++ default m
+ select MMU_NOTIFIER
+ help
+ Allows userspace processes to use grants.
+@@ -83,6 +84,7 @@ config XEN_GNTDEV
+ config XEN_GRANT_DEV_ALLOC
+ tristate "User-space grant reference allocator driver"
+ depends on XEN
++ default m
+ help
+ Allows userspace processes to create pages with access granted
+ to other domains. This can be used to implement frontend drivers
+--
+1.7.4
+
+
+From db2e2e6ee9ee9ce93b04c6975fdfef304771d6ad Mon Sep 17 00:00:00 2001
+From: Tejun Heo <tj(a)kernel.org>
+Date: Mon, 24 Jan 2011 15:43:03 +0100
+Subject: [PATCH 135/203] xen-pcifront: don't use flush_scheduled_work()
+
+flush_scheduled_work() is scheduled for deprecation. Cancel ->op_work
+directly instead.
+
+Signed-off-by: Tejun Heo <tj(a)kernel.org>
+Cc: Ryan Wilson <hap9(a)epoch.ncsc.mil>
+Cc: Jan Beulich <JBeulich(a)novell.com>
+Cc: Jesse Barnes <jbarnes(a)virtuousgeek.org>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/pci/xen-pcifront.c | 3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
+index 3a5a6fc..030ce37 100644
+--- a/drivers/pci/xen-pcifront.c
++++ b/drivers/pci/xen-pcifront.c
+@@ -733,8 +733,7 @@ static void free_pdev(struct pcifront_device *pdev)
- for (i = start; i < shinfo->nr_frags; i++, txp++) {
-+#ifndef HAVE_XEN_PAGE_FOREIGN
-+ struct page *page;
-+#endif
- pending_ring_idx_t index;
- struct pending_tx_info *pending_tx_info =
- netbk->pending_tx_info;
+ pcifront_free_roots(pdev);
- index = pending_index(netbk->pending_cons++);
- pending_idx = netbk->pending_ring[index];
--
-- gnttab_set_map_op(mop++, idx_to_kaddr(netbk, pending_idx),
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ gnttab_set_map_op(gop++, idx_to_kaddr(netbk, pending_idx),
- GNTMAP_host_map | GNTMAP_readonly,
- txp->gref, vif->domid);
-+#else
-+ page = xen_netbk_alloc_page(netbk, skb, pending_idx);
-+ if (!page)
-+ return NULL;
-+
-+ netbk->mmap_pages[pending_idx] = page;
-+
-+ gop->source.u.ref = txp->gref;
-+ gop->source.domid = vif->domid;
-+ gop->source.offset = txp->offset;
-+
-+ gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-+ gop->dest.domid = DOMID_SELF;
-+ gop->dest.offset = txp->offset;
-+
-+ gop->len = txp->size;
-+ gop->flags = GNTCOPY_source_gref;
-+
-+ gop++;
-+#endif
+- /*For PCIE_AER error handling job*/
+- flush_scheduled_work();
++ cancel_work_sync(&pdev->op_work);
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
- xenvif_get(vif);
-@@ -1034,14 +1111,24 @@ static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct
xen_netbk *net
- frags[i].page = (void *)pending_idx;
+ if (pdev->irq >= 0)
+ unbind_from_irqhandler(pdev->irq, pdev);
+--
+1.7.4
+
+
+From 1fb6c1f210d13d7099ece8aee5f351b7e5ecb3bd Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 17 Feb 2011 11:23:58 -0500
+Subject: [PATCH 136/203] xen/irq: Cleanup up the pirq_to_irq for DomU PV PCI passthrough
guests as well.
+
+We only did this for PV guests that are xen_initial_domain() but
+there is not reason not to do this for other cases. The other
+case is only exercised when you pass in a PCI device to a PV guest
+_and_ the device in question.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 3 ++-
+ 1 files changed, 2 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 975e90f..89987a7 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -766,8 +766,9 @@ int xen_destroy_irq(int irq)
+ printk(KERN_WARNING "unmap irq failed %d\n", rc);
+ goto out;
+ }
+- pirq_to_irq[info->u.pirq.pirq] = -1;
}
++ pirq_to_irq[info->u.pirq.pirq] = -1;
++
+ irq_info[irq] = mk_unbound_info();
-- return mop;
-+ return gop;
- }
-
--static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
- struct sk_buff *skb,
-- struct gnttab_map_grant_ref **mopp)
-+ struct gnttab_map_grant_ref **gopp)
-+#else
-+static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
-+ struct sk_buff *skb,
-+ struct gnttab_copy **gopp)
-+#endif
- {
-- struct gnttab_map_grant_ref *mop = *mopp;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ struct gnttab_map_grant_ref *gop = *gopp;
-+#else
-+ struct gnttab_copy *gop = *gopp;
-+#endif
- int pending_idx = *((u16 *)skb->data);
- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
- struct xenvif *vif = pending_tx_info[pending_idx].vif;
-@@ -1051,7 +1138,7 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
- int i, err, start;
-
- /* Check status of header. */
-- err = mop->status;
-+ err = gop->status;
- if (unlikely(err)) {
- pending_ring_idx_t index;
- index = pending_index(netbk->pending_prod++);
-@@ -1059,11 +1146,13 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- netbk->pending_ring[index] = pending_idx;
- xenvif_put(vif);
-+#ifdef HAVE_XEN_PAGE_FOREIGN
+ xen_free_irq(irq);
+--
+1.7.4
+
+
+From 1d4610527bc71d3f9eea520fc51a02d54f79dcd0 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 16 Feb 2011 13:43:22 -0500
+Subject: [PATCH 137/203] xen-pcifront: Sanity check the MSI/MSI-X values
+
+Check the returned vector values for any values that are
+odd or plain incorrect (say vector value zero), and if so
+print a warning. Also fixup the return values.
+
+This patch was precipiated by the Xen PCIBack returning the
+incorrect values due to how it was retrieving PIRQ values.
+This has been fixed in the xen-pciback by
+"xen/pciback: Utilize 'xen_pirq_from_irq' to get PIRQ value"
+patch.
+
+Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/pci/xen-pcifront.c | 20 ++++++++++++++++----
+ 1 files changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
+index 030ce37..5c7b6ad 100644
+--- a/drivers/pci/xen-pcifront.c
++++ b/drivers/pci/xen-pcifront.c
+@@ -277,18 +277,24 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
+ if (likely(!err)) {
+ if (likely(!op.value)) {
+ /* we get the result */
+- for (i = 0; i < nvec; i++)
++ for (i = 0; i < nvec; i++) {
++ if (op.msix_entries[i].vector <= 0) {
++ dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n",
++ i, op.msix_entries[i].vector);
++ err = -EINVAL;
++ *(*vector+i) = -1;
++ continue;
++ }
+ *(*vector+i) = op.msix_entries[i].vector;
+- return 0;
++ }
+ } else {
+ printk(KERN_DEBUG "enable msix get value %x\n",
+ op.value);
+- return op.value;
+ }
} else {
- set_phys_to_machine(
- __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
-- FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
-- netbk->grant_tx_handle[pending_idx] = mop->handle;
-+ FOREIGN_FRAME(gop->dev_bus_addr >> PAGE_SHIFT));
-+ netbk->grant_tx_handle[pending_idx] = gop->handle;
-+#endif
+ dev_err(&dev->dev, "enable msix get err %x\n", err);
+- return err;
}
++ return err;
+ }
- /* Skip first skb fragment if it is on same page as header fragment. */
-@@ -1076,14 +1165,16 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
- pending_idx = (unsigned long)shinfo->frags[i].page;
+ static void pci_frontend_disable_msix(struct pci_dev *dev)
+@@ -325,6 +331,12 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int
**vector)
+ err = do_pci_op(pdev, &op);
+ if (likely(!err)) {
+ *(*vector) = op.value;
++ if (op.value <= 0) {
++ dev_warn(&dev->dev, "MSI entry is invalid: %d!\n",
++ op.value);
++ err = -EINVAL;
++ *(*vector) = -1;
++ }
+ } else {
+ dev_err(&dev->dev, "pci frontend enable msi failed for dev "
+ "%x:%x\n", op.bus, op.devfn);
+--
+1.7.4
+
+
+From 55cb8cd45e0600df1473489518d7f12ce1bbe973 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 16 Feb 2011 13:43:04 -0500
+Subject: [PATCH 138/203] pci/xen: Use xen_allocate_pirq_msi instead of xen_allocate_pirq
+
+xen_allocate_pirq -> xen_map_pirq_gsi -> PHYSDEVOP_alloc_irq_vector IFF
+xen_initial_domain() in addition to the kernel side book-keeping side of
+things (set chip and handler, update irq_info etc) whereas
+xen_allocate_pirq_msi just does the kernel book keeping.
+
+Also xen_allocate_pirq allocates an IRQ in the 1-1 GSI space whereas
+xen_allocate_pirq_msi allocates a dynamic one in the >GSI IRQ space.
+
+All of this is uneccessary as this code path is only executed
+when we run as a domU PV guest with an MSI/MSI-X PCI card passed in.
+Hence we can jump straight to allocating an dynamic IRQ (and
+binding it to the proper PIRQ) and skip the rest.
+
+In short: this change is a cosmetic one.
+
+Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
+Reviewed-by: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 25cd4a0..6432f75 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -157,14 +157,14 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ goto error;
+ i = 0;
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+- irq = xen_allocate_pirq(v[i], 0, /* not sharable */
++ xen_allocate_pirq_msi(
+ (type == PCI_CAP_ID_MSIX) ?
+- "pcifront-msi-x" : "pcifront-msi");
++ "pcifront-msi-x" : "pcifront-msi",
++ &irq, &v[i], XEN_ALLOC_IRQ);
+ if (irq < 0) {
+ ret = -1;
+ goto free;
+ }
+-
+ ret = set_irq_msi(irq, msidesc);
+ if (ret)
+ goto error_while;
+--
+1.7.4
+
+
+From cc0f89c4a426fcd6400a89e9e34e4a8851abef76 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 17 Feb 2011 12:02:23 -0500
+Subject: [PATCH 139/203] pci/xen: Cleanup: convert int** to int[]
+
+Cleanup code. Cosmetic change to make the code look easier
+to read.
+
+Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/include/asm/xen/pci.h | 8 ++++----
+ arch/x86/pci/xen.c | 4 ++--
+ drivers/pci/xen-pcifront.c | 12 ++++++------
+ 3 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
+index 2329b3e..aa86209 100644
+--- a/arch/x86/include/asm/xen/pci.h
++++ b/arch/x86/include/asm/xen/pci.h
+@@ -27,16 +27,16 @@ static inline void __init xen_setup_pirqs(void)
+ * its own functions.
+ */
+ struct xen_pci_frontend_ops {
+- int (*enable_msi)(struct pci_dev *dev, int **vectors);
++ int (*enable_msi)(struct pci_dev *dev, int vectors[]);
+ void (*disable_msi)(struct pci_dev *dev);
+- int (*enable_msix)(struct pci_dev *dev, int **vectors, int nvec);
++ int (*enable_msix)(struct pci_dev *dev, int vectors[], int nvec);
+ void (*disable_msix)(struct pci_dev *dev);
+ };
- /* Check error status: if okay then remember grant handle. */
-- newerr = (++mop)->status;
-+ newerr = (++gop)->status;
- if (likely(!newerr)) {
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- unsigned long addr;
- addr = idx_to_kaddr(netbk, pending_idx);
- set_phys_to_machine(
- __pa(addr)>>PAGE_SHIFT,
-- FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
-- netbk->grant_tx_handle[pending_idx] = mop->handle;
-+ FOREIGN_FRAME(gop->dev_bus_addr>>PAGE_SHIFT));
-+ netbk->grant_tx_handle[pending_idx] = gop->handle;
-+#endif
- /* Had a previous error? Invalidate this fragment. */
- if (unlikely(err))
- xen_netbk_idx_release(netbk, pending_idx);
-@@ -1113,7 +1204,7 @@ static int xen_netbk_tx_check_mop(struct xen_netbk *netbk,
- err = newerr;
- }
+ extern struct xen_pci_frontend_ops *xen_pci_frontend;
-- *mopp = mop + 1;
-+ *gopp = gop + 1;
- return err;
+ static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev,
+- int **vectors)
++ int vectors[])
+ {
+ if (xen_pci_frontend && xen_pci_frontend->enable_msi)
+ return xen_pci_frontend->enable_msi(dev, vectors);
+@@ -48,7 +48,7 @@ static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev)
+ xen_pci_frontend->disable_msi(dev);
}
+ static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev,
+- int **vectors, int nvec)
++ int vectors[], int nvec)
+ {
+ if (xen_pci_frontend && xen_pci_frontend->enable_msix)
+ return xen_pci_frontend->enable_msix(dev, vectors, nvec);
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 6432f75..30fdd09 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -150,9 +150,9 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ return -ENOMEM;
-@@ -1129,10 +1220,11 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
- unsigned long pending_idx;
-
- pending_idx = (unsigned long)frag->page;
--
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- netbk->pending_inuse[pending_idx].alloc_time = jiffies;
- list_add_tail(&netbk->pending_inuse[pending_idx].list,
- &netbk->pending_inuse_head);
-+#endif
-
- txp = &netbk->pending_tx_info[pending_idx].req;
- frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
-@@ -1142,6 +1234,10 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
- skb->len += txp->size;
- skb->data_len += txp->size;
- skb->truesize += txp->size;
-+
-+ /* Take an extra reference to offset xen_netbk_idx_release */
-+ get_page(netbk->mmap_pages[pending_idx]);
-+ xen_netbk_idx_release(netbk, pending_idx);
- }
- }
+ if (type == PCI_CAP_ID_MSIX)
+- ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
++ ret = xen_pci_frontend_enable_msix(dev, v, nvec);
+ else
+- ret = xen_pci_frontend_enable_msi(dev, &v);
++ ret = xen_pci_frontend_enable_msi(dev, v);
+ if (ret)
+ goto error;
+ i = 0;
+diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
+index 5c7b6ad..492b7d8 100644
+--- a/drivers/pci/xen-pcifront.c
++++ b/drivers/pci/xen-pcifront.c
+@@ -243,7 +243,7 @@ struct pci_ops pcifront_bus_ops = {
-@@ -1300,18 +1396,24 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned
size)
- return false;
+ #ifdef CONFIG_PCI_MSI
+ static int pci_frontend_enable_msix(struct pci_dev *dev,
+- int **vector, int nvec)
++ int vector[], int nvec)
+ {
+ int err;
+ int i;
+@@ -282,10 +282,10 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
+ dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n",
+ i, op.msix_entries[i].vector);
+ err = -EINVAL;
+- *(*vector+i) = -1;
++ vector[i] = -1;
+ continue;
+ }
+- *(*vector+i) = op.msix_entries[i].vector;
++ vector[i] = op.msix_entries[i].vector;
+ }
+ } else {
+ printk(KERN_DEBUG "enable msix get value %x\n",
+@@ -316,7 +316,7 @@ static void pci_frontend_disable_msix(struct pci_dev *dev)
+ dev_err(&dev->dev, "pci_disable_msix get err %x\n", err);
}
--static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
-+static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+-static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
++static int pci_frontend_enable_msi(struct pci_dev *dev, int vector[])
{
-- struct gnttab_map_grant_ref *mop;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ struct gnttab_map_grant_ref *gop = netbk->tx_map_ops, *request_gop;
-+#else
-+ struct gnttab_copy *gop = netbk->tx_copy_ops, *request_gop;
-+#endif
- struct sk_buff *skb;
- int ret;
+ int err;
+ struct xen_pci_op op = {
+@@ -330,12 +330,12 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int
**vector)
-- mop = netbk->tx_map_ops;
- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list)) {
- struct xenvif *vif;
- struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
-+#ifndef HAVE_XEN_PAGE_FOREIGN
-+ struct page *page;
-+#endif
- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
- u16 pending_idx;
- RING_IDX idx;
-@@ -1408,10 +1510,35 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
- }
+ err = do_pci_op(pdev, &op);
+ if (likely(!err)) {
+- *(*vector) = op.value;
++ vector[0] = op.value;
+ if (op.value <= 0) {
+ dev_warn(&dev->dev, "MSI entry is invalid: %d!\n",
+ op.value);
+ err = -EINVAL;
+- *(*vector) = -1;
++ vector[0] = -1;
}
-
-- gnttab_set_map_op(mop, idx_to_kaddr(netbk, pending_idx),
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ gnttab_set_map_op(gop, idx_to_kaddr(netbk, pending_idx),
- GNTMAP_host_map | GNTMAP_readonly,
- txreq.gref, vif->domid);
-- mop++;
-+ gop++;
-+#else
-+ /* XXX could copy straight to head */
-+ page = xen_netbk_alloc_page(netbk, skb, pending_idx);
-+ if (!page) {
-+ kfree_skb(skb);
-+ netbk_tx_err(vif, &txreq, idx);
-+ continue;
-+ }
-+
-+ netbk->mmap_pages[pending_idx] = page;
-+
-+ gop->source.u.ref = txreq.gref;
-+ gop->source.domid = vif->domid;
-+ gop->source.offset = txreq.offset;
-+
-+ gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-+ gop->dest.domid = DOMID_SELF;
-+ gop->dest.offset = txreq.offset;
-+
-+ gop->len = txreq.size;
-+ gop->flags = GNTCOPY_source_gref;
+ } else {
+ dev_err(&dev->dev, "pci frontend enable msi failed for dev "
+--
+1.7.4
+
+
+From 3d74a539ae07a8f3c061332e426fc07b2310cf05 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 17 Feb 2011 16:12:51 -0500
+Subject: [PATCH 140/203] pci/xen: When free-ing MSI-X/MSI irq->desc also use generic
code.
+
+This code path is only run when an MSI/MSI-X PCI device is passed
+in to PV DomU.
+
+In 2.6.37 time-frame we over-wrote the default cleanup handler for
+MSI/MSI-X irq->desc to be "xen_teardown_msi_irqs". That function
+calls the the xen-pcifront driver which can tell the backend to
+cleanup/take back the MSI/MSI-X device.
+
+However, we forgot to continue the process of free-ing the MSI/MSI-X
+device resources (irq->desc) in the PV domU side. Which is what
+the default cleanup handler: default_teardown_msi_irqs did.
+
+Hence we would leak IRQ descriptors.
+
+Without this patch, doing "rmmod igbvf;modprobe igbvf" multiple
+times ends with abandoned IRQ descriptors:
+
+ 28: 5 xen-pirq-pcifront-msi-x
+ 29: 8 xen-pirq-pcifront-msi-x
+...
+130: 10 xen-pirq-pcifront-msi-x
+
+with the end result of running out of IRQ descriptors.
+
+Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 30fdd09..57afd1d 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -193,6 +193,9 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
+ xen_pci_frontend_disable_msix(dev);
+ else
+ xen_pci_frontend_disable_msi(dev);
+
-+ gop++;
-+#endif
-
- memcpy(&netbk->pending_tx_info[pending_idx].req,
- &txreq, sizeof(txreq));
-@@ -1434,24 +1561,43 @@ static unsigned xen_netbk_tx_build_mops(struct xen_netbk *netbk)
-
- netbk->pending_cons++;
-
-- mop = xen_netbk_get_requests(netbk, vif, skb, txfrags, mop);
-+ request_gop = xen_netbk_get_requests(netbk, vif,
-+ skb, txfrags, gop);
-+ if (request_gop == NULL) {
-+ kfree_skb(skb);
-+ netbk_tx_err(vif, &txreq, idx);
-+ continue;
-+ }
-+ gop = request_gop;
-
- vif->tx.req_cons = idx;
- xenvif_schedule_work(vif);
-
-- if ((mop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ if ((gop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
- break;
-+#else
-+ if ((gop-netbk->tx_copy_ops) >= ARRAY_SIZE(netbk->tx_copy_ops))
-+ break;
-+#endif
- }
-
-- return mop - netbk->tx_map_ops;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ return gop - netbk->tx_map_ops;
-+#else
-+ return gop - netbk->tx_copy_ops;
-+#endif
++ /* Free the IRQ's and the msidesc using the generic code. */
++ default_teardown_msi_irqs(dev);
}
- static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- {
-- struct gnttab_map_grant_ref *mop;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ struct gnttab_map_grant_ref *gop = netbk->tx_map_ops;
-+#else
-+ struct gnttab_copy *gop = netbk->tx_copy_ops;
-+#endif
- struct sk_buff *skb;
-
-- mop = netbk->tx_map_ops;
- while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
- struct xen_netif_tx_request *txp;
- struct xenvif *vif;
-@@ -1463,7 +1609,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- txp = &netbk->pending_tx_info[pending_idx].req;
+ static void xen_teardown_msi_irq(unsigned int irq)
+--
+1.7.4
+
+
+From 2f14ddc3a7146ea4cd5a3d1ecd993f85f2e4f948 Mon Sep 17 00:00:00 2001
+From: Zhang, Fengzhe <fengzhe.zhang(a)intel.com>
+Date: Wed, 16 Feb 2011 22:26:20 +0800
+Subject: [PATCH 141/203] xen/setup: Inhibit resource API from using System RAM E820 gaps
as PCI mem gaps.
+
+With the hypervisor argument of dom0_mem=X we iterate over the physical
+(only for the initial domain) E820 and subtract the the size from each
+E820_RAM region the delta so that the cumulative size of all E820_RAM regions
+is equal to 'X'. This sometimes ends up with E820_RAM regions with zero size
+(which are removed by e820_sanitize) and E820_RAM that are smaller
+than physically.
+
+Later on the PCI API looks at the E820 and attempts to set up an
+resource region for the "PCI mem". The E820 (assume dom0_mem=1GB is
+set) compared to the physical looks as so:
+
+ [ 0.000000] BIOS-provided physical RAM map:
+ [ 0.000000] Xen: 0000000000000000 - 0000000000097c00 (usable)
+ [ 0.000000] Xen: 0000000000097c00 - 0000000000100000 (reserved)
+-[ 0.000000] Xen: 0000000000100000 - 00000000defafe00 (usable)
++[ 0.000000] Xen: 0000000000100000 - 0000000040000000 (usable)
+ [ 0.000000] Xen: 00000000defafe00 - 00000000defb1ea0 (ACPI NVS)
+ [ 0.000000] Xen: 00000000defb1ea0 - 00000000e0000000 (reserved)
+ [ 0.000000] Xen: 00000000f4000000 - 00000000f8000000 (reserved)
+..
+And we get
+[ 0.000000] Allocating PCI resources starting at 40000000 (gap: 40000000:9efafe00)
+
+while it should have started at e0000000 (a nice big gap up to
+f4000000 exists). The "Allocating PCI" is part of the resource API.
+
+The users that end up using those PCI I/O regions usually supply their
+own BARs when calling the resource API (request_resource, or allocate_resource),
+but there are exceptions which provide an empty 'struct resource' and
+expect the API to provide the 'struct resource' to be populated with valid
values.
+The one that triggered this bug was the intel AGP driver that requested
+a region for the flush page (intel_i9xx_setup_flush).
+
+Before this patch, when running under Xen hypervisor, the 'struct resource'
+returned could have (depending on the dom0_mem size) physical ranges of a 'System
RAM'
+instead of 'I/O' regions. This ended up with the Hypervisor failing a request
+to populate PTE's with those PFNs as the domain did not have access to those
+'System RAM' regions (rightly so).
+
+After this patch, the left-over E820_RAM region from the truncation, will be
+labeled as E820_UNUSABLE. The E820 will look as so:
+
+ [ 0.000000] BIOS-provided physical RAM map:
+ [ 0.000000] Xen: 0000000000000000 - 0000000000097c00 (usable)
+ [ 0.000000] Xen: 0000000000097c00 - 0000000000100000 (reserved)
+-[ 0.000000] Xen: 0000000000100000 - 00000000defafe00 (usable)
++[ 0.000000] Xen: 0000000000100000 - 0000000040000000 (usable)
++[ 0.000000] Xen: 0000000040000000 - 00000000defafe00 (unusable)
+ [ 0.000000] Xen: 00000000defafe00 - 00000000defb1ea0 (ACPI NVS)
+ [ 0.000000] Xen: 00000000defb1ea0 - 00000000e0000000 (reserved)
+ [ 0.000000] Xen: 00000000f4000000 - 00000000f8000000 (reserved)
+
+For more information:
+http://mid.gmane.org/1A42CE6F5F474C41B63392A5F80372B2335E978C@shsmsx501.ccr.corp.intel.com
+
+BugLink:
http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1726
+
+Signed-off-by: Fengzhe Zhang <fengzhe.zhang(a)intel.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/xen/setup.c | 8 ++++++++
+ 1 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
+index a8a66a5..2a4add9 100644
+--- a/arch/x86/xen/setup.c
++++ b/arch/x86/xen/setup.c
+@@ -194,6 +194,14 @@ char * __init xen_memory_setup(void)
+ end -= delta;
- /* Check the remap error code. */
-- if (unlikely(xen_netbk_tx_check_mop(netbk, skb, &mop))) {
-+ if (unlikely(xen_netbk_tx_check_gop(netbk, skb, &gop))) {
- pr_debug("netback grant failed.\n");
- skb_shinfo(skb)->nr_frags = 0;
- kfree_skb(skb);
-@@ -1509,12 +1655,14 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- continue;
+ extra_pages += PFN_DOWN(delta);
++ /*
++ * Set RAM below 4GB that is not for us to be unusable.
++ * This prevents "System RAM" address space from being
++ * used as potential resource for I/O address (happens
++ * when 'allocate_resource' is called).
++ */
++ if (delta && end < 0x100000000UL)
++ e820_add_region(end, delta, E820_UNUSABLE);
}
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
- unlikely(skb_linearize(skb))) {
- pr_debug("Can't linearize skb in net_tx_action.\n");
- kfree_skb(skb);
- continue;
- }
-+#endif
+ if (map[i].size > 0 && end > xen_extra_mem_start)
+--
+1.7.4
+
+
+From 458059da8969d8b70a1d0e6600b3f11f91887728 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:26 +0000
+Subject: [PATCH 142/203] xen: pci: only define xen_initdom_setup_msi_irqs if
CONFIG_XEN_DOM0
+
+Fixes:
+ CC arch/x86/pci/xen.o
+arch/x86/pci/xen.c:183: warning: 'xen_initdom_setup_msi_irqs' defined but not
used
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 8634e1b..47c4688 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -203,6 +203,7 @@ static void xen_teardown_msi_irq(unsigned int irq)
+ xen_destroy_irq(irq);
+ }
- vif->stats.rx_bytes += skb->len;
- vif->stats.rx_packets++;
-@@ -1527,21 +1675,31 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- /* Called after netfront has transmitted */
- static void xen_netbk_tx_action(struct xen_netbk *netbk)
++#ifdef CONFIG_XEN_DOM0
+ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
-- unsigned nr_mops;
-+ unsigned nr_gops;
- int ret;
-
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- xen_netbk_tx_action_dealloc(netbk);
-+#endif
-
-- nr_mops = xen_netbk_tx_build_mops(netbk);
-+ nr_gops = xen_netbk_tx_build_gops(netbk);
-
-- if (nr_mops == 0)
-+#ifdef HAVE_XEN_PAGE_FOREIGN
-+ if (nr_gops == 0)
- goto out;
--
- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-- netbk->tx_map_ops, nr_mops);
-+ netbk->tx_map_ops, nr_gops);
-+#else
-+ if (nr_gops == 0)
-+ return;
-+ ret = HYPERVISOR_grant_table_op(GNTTABOP_copy,
-+ netbk->tx_copy_ops, nr_gops);
+ int irq, ret;
+@@ -224,6 +225,7 @@ error:
+ return ret;
+ }
+ #endif
+#endif
- BUG_ON(ret);
- xen_netbk_tx_submit(netbk);
-+
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- out:
- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
- !list_empty(&netbk->pending_inuse_head)) {
-@@ -1552,8 +1710,10 @@ out:
- mod_timer(&netbk->netbk_tx_pending_timer,
- oldest->alloc_time + HZ);
+ static int xen_pcifront_enable_irq(struct pci_dev *dev)
+ {
+--
+1.7.4
+
+
+From 290d9163997c4c460f1e6cb666f0e44712bb7087 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:27 +0000
+Subject: [PATCH 143/203] xen: events: do not leak IRQ from xen_allocate_pirq_msi when no
pirq available.
+
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: xen-devel(a)lists.xensource.com
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 5 ++++-
+ 1 files changed, 4 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 89987a7..bce3035 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -676,8 +676,11 @@ void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int
alloc)
+
+ if (alloc & XEN_ALLOC_PIRQ) {
+ *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
+- if (*pirq == -1)
++ if (*pirq == -1) {
++ xen_free_irq(*irq);
++ *irq = -1;
+ goto out;
++ }
}
-+#endif
+
+ set_irq_chip_and_handler_name(*irq, &xen_pirq_chip,
+--
+1.7.4
+
+
+From b0a311e11032c5ac23183906b0d2baa5d0252446 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:28 +0000
+Subject: [PATCH 144/203] xen: events: drop XEN_ALLOC_IRQ flag to xen_allocate_pirq_msi
+
+All callers pass this flag so it is pointless.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 6 +++---
+ drivers/xen/events.c | 12 +++++-------
+ include/xen/events.h | 5 +----
+ 3 files changed, 9 insertions(+), 14 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 47c4688..ca5fa09 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -101,7 +101,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+ if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
+ xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ);
++ "msi-x" : "msi", &irq, &pirq, 0);
+ if (irq < 0)
+ goto error;
+ ret = set_irq_msi(irq, msidesc);
+@@ -112,7 +112,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ return 0;
+ }
+ xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ |
XEN_ALLOC_PIRQ));
++ "msi-x" : "msi", &irq, &pirq, 1);
+ if (irq < 0 || pirq < 0)
+ goto error;
+ printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
+@@ -160,7 +160,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ xen_allocate_pirq_msi(
+ (type == PCI_CAP_ID_MSIX) ?
+ "pcifront-msi-x" : "pcifront-msi",
+- &irq, &v[i], XEN_ALLOC_IRQ);
++ &irq, &v[i], 0);
+ if (irq < 0) {
+ ret = -1;
+ goto free;
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index bce3035..36e9adc 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -664,17 +664,15 @@ static int find_unbound_pirq(int type)
+ return -1;
}
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
++void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_pirq)
{
- static DEFINE_SPINLOCK(_lock);
-@@ -1581,6 +1741,33 @@ static void netif_page_release(struct page *page, unsigned int
order)
+ spin_lock(&irq_mapping_update_lock);
- xen_netbk_idx_release(&xen_netbk[group], idx);
- }
-+#else
-+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
-+{
-+ struct xenvif *vif;
-+ struct pending_tx_info *pending_tx_info;
-+ pending_ring_idx_t index;
-+
-+ /* Already complete? */
-+ if (netbk->mmap_pages[pending_idx] == NULL)
-+ return;
-+
-+ pending_tx_info = &netbk->pending_tx_info[pending_idx];
-+
-+ vif = pending_tx_info->vif;
-+
-+ make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY);
-+
-+ index = pending_index(netbk->pending_prod++);
-+ netbk->pending_ring[index] = pending_idx;
-+
-+ xenvif_put(vif);
-+
-+ netbk->mmap_pages[pending_idx]->mapping = 0;
-+ put_page(netbk->mmap_pages[pending_idx]);
-+ netbk->mmap_pages[pending_idx] = NULL;
-+}
-+#endif
+- if (alloc & XEN_ALLOC_IRQ) {
+- *irq = xen_allocate_irq_dynamic();
+- if (*irq == -1)
+- goto out;
+- }
++ *irq = xen_allocate_irq_dynamic();
++ if (*irq == -1)
++ goto out;
- static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
-@@ -1633,12 +1820,14 @@ static inline int rx_work_todo(struct xen_netbk *netbk)
+- if (alloc & XEN_ALLOC_PIRQ) {
++ if (alloc_pirq) {
+ *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
+ if (*pirq == -1) {
+ xen_free_irq(*irq);
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 00f53dd..8d98861 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -75,10 +75,7 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
+ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
- static inline int tx_work_todo(struct xen_netbk *netbk)
- {
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- if (netbk->dealloc_cons != netbk->dealloc_prod)
- return 1;
+ #ifdef CONFIG_PCI_MSI
+-/* Allocate an irq and a pirq to be used with MSIs. */
+-#define XEN_ALLOC_PIRQ (1 << 0)
+-#define XEN_ALLOC_IRQ (1 << 1)
+-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask);
++void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_pirq);
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
+ #endif
- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
- !list_empty(&netbk->pending_inuse_head))
- return 1;
-+#endif
+--
+1.7.4
+
+
+From d71552da237c3f5fd88422ea19b4e64706e4f813 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:29 +0000
+Subject: [PATCH 145/203] xen: events: return irq from xen_allocate_pirq_msi
+
+consistent with other similar functions.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 12 ++++++------
+ drivers/xen/events.c | 19 +++++++++++--------
+ include/xen/events.h | 2 +-
+ 3 files changed, 18 insertions(+), 15 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index ca5fa09..6fd695b 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -100,8 +100,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
+ ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+ if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
+- xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi", &irq, &pirq, 0);
++ irq = xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
++ "msi-x" : "msi", &pirq, 0);
+ if (irq < 0)
+ goto error;
+ ret = set_irq_msi(irq, msidesc);
+@@ -111,8 +111,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ " pirq=%d\n", irq, pirq);
+ return 0;
+ }
+- xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi", &irq, &pirq, 1);
++ irq = xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
++ "msi-x" : "msi", &pirq, 1);
+ if (irq < 0 || pirq < 0)
+ goto error;
+ printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
+@@ -157,10 +157,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ goto error;
+ i = 0;
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+- xen_allocate_pirq_msi(
++ irq = xen_allocate_pirq_msi(
+ (type == PCI_CAP_ID_MSIX) ?
+ "pcifront-msi-x" : "pcifront-msi",
+- &irq, &v[i], 0);
++ &v[i], 0);
+ if (irq < 0) {
+ ret = -1;
+ goto free;
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 36e9adc..ed3420d 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -664,31 +664,34 @@ static int find_unbound_pirq(int type)
+ return -1;
+ }
- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list))
-@@ -1673,7 +1862,9 @@ static int xen_netbk_kthread(void *data)
- static int __init netback_init(void)
+-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_pirq)
++int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq)
{
- int i;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- struct page *page;
-+#endif
- int rc = 0;
- int group;
-
-@@ -1697,11 +1888,14 @@ static int __init netback_init(void)
- netbk->net_timer.data = (unsigned long)netbk;
- netbk->net_timer.function = xen_netbk_alarm;
++ int irq;
++
+ spin_lock(&irq_mapping_update_lock);
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- init_timer(&netbk->netbk_tx_pending_timer);
- netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
- netbk->netbk_tx_pending_timer.function =
- xen_netbk_tx_pending_timeout;
-+#endif
+- *irq = xen_allocate_irq_dynamic();
+- if (*irq == -1)
++ irq = xen_allocate_irq_dynamic();
++ if (irq == -1)
+ goto out;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- netbk->mmap_pages =
- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
- if (!netbk->mmap_pages) {
-@@ -1715,9 +1909,10 @@ static int __init netback_init(void)
- for (i = 0; i < MAX_PENDING_REQS; i++) {
- page = netbk->mmap_pages[i];
- SetPageForeign(page, netif_page_release);
-- set_page_ext(page, group, i);
-+ set_page_ext(page, netbk, i);
- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
+ if (alloc_pirq) {
+ *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
+ if (*pirq == -1) {
+- xen_free_irq(*irq);
+- *irq = -1;
++ xen_free_irq(irq);
++ irq = -1;
+ goto out;
}
-+#endif
+ }
- netbk->pending_cons = 0;
- netbk->pending_prod = MAX_PENDING_REQS;
-@@ -1731,9 +1926,11 @@ static int __init netback_init(void)
+- set_irq_chip_and_handler_name(*irq, &xen_pirq_chip,
++ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+ handle_level_irq, name);
- if (IS_ERR(netbk->task)) {
- printk(KERN_ALERT "kthread_run() fails at netback\n");
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- free_empty_pages_and_pagevec(netbk->mmap_pages,
- MAX_PENDING_REQS);
- del_timer(&netbk->netbk_tx_pending_timer);
-+#endif
- del_timer(&netbk->net_timer);
- rc = PTR_ERR(netbk->task);
- goto failed_init;
-@@ -1741,7 +1938,9 @@ static int __init netback_init(void)
+- irq_info[*irq] = mk_pirq_info(0, *pirq, 0, 0);
+- pirq_to_irq[*pirq] = *irq;
++ irq_info[irq] = mk_pirq_info(0, *pirq, 0, 0);
++ pirq_to_irq[*pirq] = irq;
- kthread_bind(netbk->task, group);
+ out:
+ spin_unlock(&irq_mapping_update_lock);
++ return irq;
+ }
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- INIT_LIST_HEAD(&netbk->pending_inuse_head);
-+#endif
- INIT_LIST_HEAD(&netbk->net_schedule_list);
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 8d98861..f70536a 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -75,7 +75,7 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
+ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
- spin_lock_init(&netbk->net_schedule_list_lock);
-@@ -1751,6 +1950,7 @@ static int __init netback_init(void)
- wake_up_process(netbk->task);
- }
+ #ifdef CONFIG_PCI_MSI
+-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_pirq);
++int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq);
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
+ #endif
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
- if (MODPARM_copy_skb) {
- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-@@ -1759,6 +1959,7 @@ static int __init netback_init(void)
- else
- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
- }
-+#endif
+--
+1.7.4
+
+
+From e70c689053946cf87902c06f98941db5ed5ef6b7 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:30 +0000
+Subject: [PATCH 146/203] xen: pci: collapse apic_register_gsi_xen_hvm and
xen_hvm_register_pirq
+
+apic_register_gsi_xen_hvm is a tiny wrapper around
+xen_hvm_register_pirq.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 11 +++--------
+ 1 files changed, 3 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 6fd695b..0d5087e 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -20,7 +20,8 @@
+ #include <asm/xen/pci.h>
- rc = xenvif_xenbus_init();
- if (rc)
-@@ -1769,9 +1970,17 @@ static int __init netback_init(void)
- failed_init:
- for (i = 0; i < group; i++) {
- struct xen_netbk *netbk = &xen_netbk[i];
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- free_empty_pages_and_pagevec(netbk->mmap_pages,
- MAX_PENDING_REQS);
- del_timer(&netbk->netbk_tx_pending_timer);
-+#else
-+ int j;
-+ for (j = 0; j < MAX_PENDING_REQS; j++) {
-+ if (netbk->mmap_pages[i])
-+ __free_page(netbk->mmap_pages[i]);
-+ }
-+#endif
- del_timer(&netbk->net_timer);
- kthread_stop(netbk->task);
+ #ifdef CONFIG_ACPI
+-static int xen_hvm_register_pirq(u32 gsi, int triggering)
++static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
++ int trigger, int polarity)
+ {
+ int rc, irq;
+ struct physdev_map_pirq map_irq;
+@@ -41,7 +42,7 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering)
+ return -1;
}
-diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
-index e854420..d56b1ee 100644
---- a/drivers/net/xen-netback/xenbus.c
-+++ b/drivers/net/xen-netback/xenbus.c
-@@ -74,8 +74,10 @@ static int netback_probe(struct xenbus_device *dev,
- dev_set_drvdata(&dev->dev, be);
- sg = 1;
-+#ifdef HAVE_XEN_PAGE_FOREIGN
- if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
- sg = 0;
-+#endif
+- if (triggering == ACPI_EDGE_SENSITIVE) {
++ if (trigger == ACPI_EDGE_SENSITIVE) {
+ shareable = 0;
+ name = "ioapic-edge";
+ } else {
+@@ -55,12 +56,6 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering)
- do {
- err = xenbus_transaction_start(&xbt);
+ return irq;
+ }
+-
+-static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
+- int trigger, int polarity)
+-{
+- return xen_hvm_register_pirq(gsi, trigger);
+-}
+ #endif
+
+ #if defined(CONFIG_PCI_MSI)
--
1.7.4
-From 33bf93e7541633b7667bf9390107cf8b2b67968a Mon Sep 17 00:00:00 2001
+From a3b7bc8f4a9c12df1d71d5f9b7eb5c1a85119729 Mon Sep 17 00:00:00 2001
From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Wed, 19 Jan 2011 09:43:44 +0000
-Subject: [PATCH 144/244] xen: netback: completely drop foreign page support
-
-for i in drivers/net/xen-netback/*.[ch] ; do
- echo $i
- ./scripts/unifdef -B -UHAVE_XEN_PAGE_FOREIGN $i > $i.unifdef
- mv $i.unifdef $i
-done
+Date: Fri, 18 Feb 2011 16:43:31 +0000
+Subject: [PATCH 147/203] xen: events: assume PHYSDEVOP_get_free_pirq exists
+
+The find_unbound_pirq is called only from xen_allocate_pirq_msi and
+only if alloc_pirq is true. The only caller which does this is
+xen_hvm_setup_msi_irqs. The use of this function is gated, in
+pci_xen_hvm_init, on XENFEAT_hvm_pirqs.
+
+The PHYSDEVOP_get_free_pirq interfaces was added to the hypervisor in
+22410:be96f6058c05 while XENFEAT_hvm_pirqs was added a couple of
+minutes prior in 22409:6663214f06ac. Therefore we do not need to
+concern ourselves with hypervisors which support XENFEAT_hvm_pirqs but
+not PHYSDEVOP_get_free_pirq.
+
+This eliminates the fallback path in find_unbound_pirq which walks to
+pirq_to_irq array looking for a free pirq. Unlike the
+PHYSDEVOP_get_free_pirq interface this fallback only looks up a free
+pirq but does not reserve it. Removing this fallback will simplify
+locking in the future.
Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/net/xen-netback/common.h | 13 --
- drivers/net/xen-netback/interface.c | 6 -
- drivers/net/xen-netback/netback.c | 376 -----------------------------------
- drivers/net/xen-netback/xenbus.c | 4 -
- 4 files changed, 0 insertions(+), 399 deletions(-)
+ drivers/xen/events.c | 15 ++++++---------
+ 1 files changed, 6 insertions(+), 9 deletions(-)
-diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
-index 8890825..03196ab 100644
---- a/drivers/net/xen-netback/common.h
-+++ b/drivers/net/xen-netback/common.h
-@@ -95,9 +95,6 @@ struct xenvif {
- struct timer_list credit_timeout;
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index ed3420d..c21066f 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -649,19 +649,16 @@ out:
- /* Statistics */
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- int nr_copied_skbs;
--#endif
- int rx_gso_checksum_fixup;
+ static int find_unbound_pirq(int type)
+ {
+- int rc, i;
++ int rc;
+ struct physdev_get_free_pirq op_get_free_pirq;
+- op_get_free_pirq.type = type;
- /* Miscellaneous private stuff. */
-@@ -111,16 +108,6 @@ struct xenvif {
- wait_queue_head_t waiting_to_free;
- };
++ op_get_free_pirq.type = type;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
+- if (!rc)
+- return op_get_free_pirq.pirq;
--#ifdef HAVE_XEN_PAGE_FOREIGN
--enum {
-- NETBK_DONT_COPY_SKB,
-- NETBK_DELAYED_COPY_SKB,
-- NETBK_ALWAYS_COPY_SKB,
--};
--
--extern int netbk_copy_skb_mode;
--#endif
+- for (i = 0; i < nr_irqs; i++) {
+- if (pirq_to_irq[i] < 0)
+- return i;
+- }
+- return -1;
++ WARN_ONCE(rc == -ENOSYS,
++ "hypervisor does not support the PHYSDEVOP_get_free_pirq interface\n");
++
++ return rc ? -1 : op_get_free_pirq.pirq;
+ }
+
+ int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq)
+--
+1.7.4
+
+
+From 3d621208a9221fda2148317b486195e3f7e9d068 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:32 +0000
+Subject: [PATCH 148/203] xen: events: separate MSI PIRQ allocation from PIRQ binding to
IRQ
+
+Split the binding aspect of xen_allocate_pirq_msi out into a new
+xen_bind_pirq_to_irq function.
+
+In xen_hvm_setup_msi_irq when allocating a pirq write the MSI message
+to signal the PIRQ as soon as the pirq is obtained. There is no way to
+free the pirq back so if the subsequent binding to an IRQ fails we
+want to ensure that we will reuse the PIRQ next time rather than leak
+it.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 68 +++++++++++++++++++------------------------------
+ drivers/xen/events.c | 30 ++++++++++-----------
+ include/xen/events.h | 4 ++-
+ 3 files changed, 43 insertions(+), 59 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 0d5087e..93e4215 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -86,7 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int
pirq,
+
+ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+ {
+- int irq, pirq, ret = 0;
++ int irq, pirq;
+ struct msi_desc *msidesc;
+ struct msi_msg msg;
+
+@@ -94,39 +94,32 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ __read_msi_msg(msidesc, &msg);
+ pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
+ ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+- if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
+- irq = xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi", &pirq, 0);
+- if (irq < 0)
++ if (msg.data != XEN_PIRQ_MSI_DATA ||
++ xen_irq_from_pirq(pirq) < 0) {
++ pirq = xen_allocate_pirq_msi(dev, msidesc);
++ if (pirq < 0)
+ goto error;
+- ret = set_irq_msi(irq, msidesc);
+- if (ret < 0)
+- goto error_while;
+- printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d"
+- " pirq=%d\n", irq, pirq);
+- return 0;
++ xen_msi_compose_msg(dev, pirq, &msg);
++ __write_msi_msg(msidesc, &msg);
++ dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
++ } else {
++ dev_dbg(&dev->dev,
++ "xen: msi already bound to pirq=%d\n", pirq);
+ }
+- irq = xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi", &pirq, 1);
+- if (irq < 0 || pirq < 0)
++ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
++ (type == PCI_CAP_ID_MSIX) ?
++ "msi-x" : "msi");
++ if (irq < 0)
+ goto error;
+- printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
+- xen_msi_compose_msg(dev, pirq, &msg);
+- ret = set_irq_msi(irq, msidesc);
+- if (ret < 0)
+- goto error_while;
+- write_msi_msg(irq, &msg);
++ dev_dbg(&dev->dev,
++ "xen: msi --> pirq=%d --> irq=%d\n", pirq, irq);
+ }
+ return 0;
+
+-error_while:
+- unbind_from_irqhandler(irq, NULL);
+ error:
+- if (ret == -ENODEV)
+- dev_err(&dev->dev, "Xen PCI frontend has not registered" \
+- " MSI/MSI-X support!\n");
-
- #define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
- #define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+- return ret;
++ dev_err(&dev->dev,
++ "Xen PCI frontend has not registered MSI/MSI-X support!\n");
++ return -ENODEV;
+ }
-diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
-index 6e11878..98a992d 100644
---- a/drivers/net/xen-netback/interface.c
-+++ b/drivers/net/xen-netback/interface.c
-@@ -272,12 +272,6 @@ static const struct xenvif_stat {
- char name[ETH_GSTRING_LEN];
- u16 offset;
- } xenvif_stats[] = {
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- {
-- "copied_skbs",
-- offsetof(struct xenvif, nr_copied_skbs)
-- },
--#endif
- {
- "rx_gso_checksum_fixup",
- offsetof(struct xenvif, rx_gso_checksum_fixup)
-diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
-index 265fbdd..fbddf3d 100644
---- a/drivers/net/xen-netback/netback.c
-+++ b/drivers/net/xen-netback/netback.c
-@@ -40,9 +40,6 @@
+ /*
+@@ -152,28 +145,19 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ goto error;
+ i = 0;
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+- irq = xen_allocate_pirq_msi(
+- (type == PCI_CAP_ID_MSIX) ?
+- "pcifront-msi-x" : "pcifront-msi",
+- &v[i], 0);
+- if (irq < 0) {
+- ret = -1;
++ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
++ (type == PCI_CAP_ID_MSIX) ?
++ "pcifront-msi-x" :
++ "pcifront-msi");
++ if (irq < 0)
+ goto free;
+- }
+- ret = set_irq_msi(irq, msidesc);
+- if (ret)
+- goto error_while;
+ i++;
+ }
+ kfree(v);
+ return 0;
- #include <net/tcp.h>
+-error_while:
+- unbind_from_irqhandler(irq, NULL);
+ error:
+- if (ret == -ENODEV)
+- dev_err(&dev->dev, "Xen PCI frontend has not registered" \
+- " MSI/MSI-X support!\n");
++ dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X
support!\n");
+ free:
+ kfree(v);
+ return ret;
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index c21066f..1033f62 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -647,12 +647,12 @@ out:
+ #include <linux/msi.h>
+ #include "../pci/msi.h"
--#ifdef HAVE_XEN_PAGE_FOREIGN
--#include <xen/balloon.h>
--#endif
- #include <xen/events.h>
- #include <xen/interface/memory.h>
+-static int find_unbound_pirq(int type)
++int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
+ {
+ int rc;
+ struct physdev_get_free_pirq op_get_free_pirq;
-@@ -61,13 +58,6 @@ struct netbk_rx_meta {
- int gso_size;
- };
+- op_get_free_pirq.type = type;
++ op_get_free_pirq.type = MAP_PIRQ_TYPE_MSI;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
--#ifdef HAVE_XEN_PAGE_FOREIGN
--struct netbk_tx_pending_inuse {
-- struct list_head list;
-- unsigned long alloc_time;
--};
--#endif
--
- #define MAX_PENDING_REQS 256
+ WARN_ONCE(rc == -ENOSYS,
+@@ -661,9 +661,10 @@ static int find_unbound_pirq(int type)
+ return rc ? -1 : op_get_free_pirq.pirq;
+ }
- #define MAX_BUFFER_OFFSET PAGE_SIZE
-@@ -95,24 +85,11 @@ struct xen_netbk {
- struct sk_buff_head tx_queue;
+-int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq)
++int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
++ int pirq, const char *name)
+ {
+- int irq;
++ int irq, ret;
- struct timer_list net_timer;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- struct timer_list netbk_tx_pending_timer;
--#endif
+ spin_lock(&irq_mapping_update_lock);
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- struct page **mmap_pages;
--#else
- struct page *mmap_pages[MAX_PENDING_REQS];
--#endif
+@@ -671,24 +672,21 @@ int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq)
+ if (irq == -1)
+ goto out;
- pending_ring_idx_t pending_prod;
- pending_ring_idx_t pending_cons;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- pending_ring_idx_t dealloc_prod;
-- pending_ring_idx_t dealloc_cons;
+- if (alloc_pirq) {
+- *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
+- if (*pirq == -1) {
+- xen_free_irq(irq);
+- irq = -1;
+- goto out;
+- }
+- }
-
-- struct list_head pending_inuse_head;
--#endif
- struct list_head net_schedule_list;
+ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+ handle_level_irq, name);
- /* Protect the net_schedule_list in netif. */
-@@ -121,20 +98,9 @@ struct xen_netbk {
- atomic_t netfront_count;
+- irq_info[irq] = mk_pirq_info(0, *pirq, 0, 0);
+- pirq_to_irq[*pirq] = irq;
+-
++ irq_info[irq] = mk_pirq_info(0, pirq, 0, 0);
++ pirq_to_irq[pirq] = irq;
++ ret = set_irq_msi(irq, msidesc);
++ if (ret < 0)
++ goto error_irq;
+ out:
+ spin_unlock(&irq_mapping_update_lock);
+ return irq;
++error_irq:
++ spin_unlock(&irq_mapping_update_lock);
++ xen_free_irq(irq);
++ return -1;
+ }
- struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- 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];
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
+diff --git a/include/xen/events.h b/include/xen/events.h
+index f70536a..18bf825 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -75,7 +75,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
+ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
+
+ #ifdef CONFIG_PCI_MSI
+-int xen_allocate_pirq_msi(char *name, int *pirq, int alloc_pirq);
++int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
++int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
++ int pirq, const char *name);
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
+ #endif
+
+--
+1.7.4
+
+
+From 83ca2344daef90649dac5ff1f22392c2e048d2fb Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:33 +0000
+Subject: [PATCH 149/203] xen: events: refactor xen_create_msi_irq slightly
+
+Calling PHYSDEVOP_map_pirq earlier simplifies error handling and
+starts to make the tail end of this function look like
+xen_bind_pirq_msi_to_irq.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 15 ++++++---------
+ 1 files changed, 6 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 1033f62..b54285e 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -716,6 +716,12 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc
*msidesc, int type)
+ map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
+ }
+
++ rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
++ if (rc) {
++ dev_warn(&dev->dev, "xen map irq failed %d\n", rc);
++ goto out;
++ }
++
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = xen_allocate_irq_dynamic();
+@@ -723,15 +729,6 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc
*msidesc, int type)
+ if (irq == -1)
+ goto out;
+
+- rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+- if (rc) {
+- printk(KERN_WARNING "xen map irq failed %d\n", rc);
-
-- grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
--#else
- struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
--#endif
+- xen_free_irq(irq);
+-
+- irq = -1;
+- goto out;
+- }
+ irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index);
- u16 pending_ring[MAX_PENDING_REQS];
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- u16 dealloc_ring[MAX_PENDING_REQS];
--#endif
+ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+--
+1.7.4
+
+
+From 3c8728dbc7942997ea91bc9dbf6416a3070c6721 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:34 +0000
+Subject: [PATCH 150/203] xen: events: update pirq_to_irq in xen_create_msi_irq
+
+I don't think this was a deliberate ommision.
+
+Makes the tail end of this function look even more like
+xen_bind_pirq_msi_to_irq.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index b54285e..721b393 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -730,6 +730,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
+ goto out;
- /*
- * Each head or fragment can be up to 4096 bytes. Given
-@@ -220,11 +186,6 @@ static int get_page_ext(struct page *pg,
- struct xen_netbk *netbk;
- unsigned int group, idx;
+ irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index);
++ pirq_to_irq[map_irq.pirq] = irq;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if (!PageForeign(pg))
-- return 0;
--#endif
+ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+ handle_level_irq,
+--
+1.7.4
+
+
+From a3805cf7bd00c259d46b43aa79b12002db3a2921 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:35 +0000
+Subject: [PATCH 151/203] xen: events: push set_irq_msi down into xen_create_msi_irq
+
+Makes the tail end of this function look even more like
+xen_bind_pirq_msi_to_irq.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 10 +---------
+ drivers/xen/events.c | 10 +++++++++-
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 93e4215..15fd981 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -185,23 +185,15 @@ static void xen_teardown_msi_irq(unsigned int irq)
+ #ifdef CONFIG_XEN_DOM0
+ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+ {
+- int irq, ret;
++ int irq;
+ struct msi_desc *msidesc;
+
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+ irq = xen_create_msi_irq(dev, msidesc, type);
+ if (irq < 0)
+ return -1;
+-
+- ret = set_irq_msi(irq, msidesc);
+- if (ret)
+- goto error;
+ }
+ return 0;
-
- group = ext.e.group - 1;
-
- if (group < 0 || group >= xen_netbk_group_nr)
-@@ -232,11 +193,6 @@ static int get_page_ext(struct page *pg,
+-error:
+- xen_destroy_irq(irq);
+- return ret;
+ }
+ #endif
+ #endif
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 721b393..77ede77 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -691,7 +691,7 @@ error_irq:
- netbk = &xen_netbk[group];
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
+ {
+- int irq = -1;
++ int ret, irq = -1;
+ struct physdev_map_pirq map_irq;
+ int rc;
+ int pos;
+@@ -736,9 +736,17 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc
*msidesc, int type)
+ handle_level_irq,
+ (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi");
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if (netbk->mmap_pages == NULL)
-- return 0;
--#endif
--
- idx = ext.e.idx;
++ ret = set_irq_msi(irq, msidesc);
++ if (ret)
++ goto out_irq;
++
+ out:
+ spin_unlock(&irq_mapping_update_lock);
+ return irq;
++out_irq:
++ spin_unlock(&irq_mapping_update_lock);
++ xen_free_irq(irq);
++ return -1;
+ }
+ #endif
- if ((idx < 0) || (idx >= MAX_PENDING_REQS))
-@@ -272,15 +228,6 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xen_netbk
*netbk)
- netbk->pending_prod + netbk->pending_cons;
+--
+1.7.4
+
+
+From 84798bd20f98d01fbd4b479cc35dc878d6eb6165 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 16:43:36 +0000
+Subject: [PATCH 152/203] xen: events: use xen_bind_pirq_msi_to_irq from
xen_create_msi_irq
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 4 ++--
+ drivers/xen/events.c | 36 +++++++-----------------------------
+ include/xen/events.h | 2 +-
+ 3 files changed, 10 insertions(+), 32 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 15fd981..ffd8c7a 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -106,7 +106,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ dev_dbg(&dev->dev,
+ "xen: msi already bound to pirq=%d\n", pirq);
+ }
+- irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
++ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
+ (type == PCI_CAP_ID_MSIX) ?
+ "msi-x" : "msi");
+ if (irq < 0)
+@@ -145,7 +145,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ goto error;
+ i = 0;
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+- irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
++ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
+ (type == PCI_CAP_ID_MSIX) ?
+ "pcifront-msi-x" :
+ "pcifront-msi");
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 77ede77..3446948 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -662,7 +662,7 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc
*msidesc)
}
--#ifdef HAVE_XEN_PAGE_FOREIGN
--/* Setting this allows the safe use of this driver without netloop. */
--static int MODPARM_copy_skb = 1;
--module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
--MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without
netloop");
--
--int netbk_copy_skb_mode;
--#endif
--
- static void xen_netbk_kick_thread(struct xen_netbk *netbk)
+ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+- int pirq, const char *name)
++ int pirq, int vector, const char *name)
{
- wake_up(&netbk->wq);
-@@ -752,14 +699,6 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff
*skb)
- xen_netbk_kick_thread(netbk);
- }
+ int irq, ret;
--#ifdef HAVE_XEN_PAGE_FOREIGN
--static void xen_netbk_tx_pending_timeout(unsigned long data)
--{
-- struct xen_netbk *netbk = (struct xen_netbk *)data;
-- xen_netbk_kick_thread(netbk);
--}
--#endif
--
- static void xen_netbk_alarm(unsigned long data)
+@@ -675,7 +675,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc
*msidesc,
+ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+ handle_level_irq, name);
+
+- irq_info[irq] = mk_pirq_info(0, pirq, 0, 0);
++ irq_info[irq] = mk_pirq_info(0, pirq, 0, vector);
+ pirq_to_irq[pirq] = irq;
+ ret = set_irq_msi(irq, msidesc);
+ if (ret < 0)
+@@ -691,7 +691,6 @@ error_irq:
+
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
{
- struct xen_netbk *netbk = (struct xen_netbk *)data;
-@@ -859,123 +798,6 @@ static void tx_credit_callback(unsigned long data)
- xenvif_schedule_work(vif);
- }
+- int ret, irq = -1;
+ struct physdev_map_pirq map_irq;
+ int rc;
+ int pos;
+@@ -719,34 +718,13 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc
*msidesc, int type)
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+ if (rc) {
+ dev_warn(&dev->dev, "xen map irq failed %d\n", rc);
+- goto out;
++ return -1;
+ }
--#ifdef HAVE_XEN_PAGE_FOREIGN
--static inline int copy_pending_req(struct xen_netbk *netbk,
-- pending_ring_idx_t pending_idx)
--{
-- return gnttab_copy_grant_page(
-- netbk->grant_tx_handle[pending_idx],
-- &netbk->mmap_pages[pending_idx]);
--}
--#endif
--
--#ifdef HAVE_XEN_PAGE_FOREIGN
--static inline void xen_netbk_tx_action_dealloc(struct xen_netbk *netbk)
--{
-- struct netbk_tx_pending_inuse *inuse, *n;
-- struct gnttab_unmap_grant_ref *gop;
-- u16 pending_idx;
-- pending_ring_idx_t dc, dp;
-- struct xenvif *vif;
-- int ret;
-- LIST_HEAD(list);
--
-- dc = netbk->dealloc_cons;
-- gop = netbk->tx_unmap_ops;
--
-- /* Free up any grants we have finished using. */
-- do {
-- dp = netbk->dealloc_prod;
--
-- /* Ensure we see all indices enqueued by xen_netbk_idx_release(). */
-- smp_rmb();
--
-- while (dc != dp) {
-- unsigned long pfn;
-- struct netbk_tx_pending_inuse *pending_inuse =
-- netbk->pending_inuse;
+- spin_lock(&irq_mapping_update_lock);
-
-- pending_idx = netbk->dealloc_ring[pending_index(dc++)];
-- list_move_tail(&pending_inuse[pending_idx].list, &list);
+- irq = xen_allocate_irq_dynamic();
-
-- pfn = idx_to_pfn(netbk, pending_idx);
-- /* Already unmapped? */
-- if (!phys_to_machine_mapping_valid(pfn))
-- continue;
+- if (irq == -1)
+- goto out;
-
-- gnttab_set_unmap_op(gop,
-- idx_to_kaddr(netbk, pending_idx),
-- GNTMAP_host_map,
-- netbk->grant_tx_handle[pending_idx]);
-- gop++;
-- }
+- irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index);
+- pirq_to_irq[map_irq.pirq] = irq;
-
-- } while (dp != netbk->dealloc_prod);
+- set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+- handle_level_irq,
+- (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi");
-
-- netbk->dealloc_cons = dc;
+- ret = set_irq_msi(irq, msidesc);
+- if (ret)
+- goto out_irq;
-
-- ret = HYPERVISOR_grant_table_op(
-- GNTTABOP_unmap_grant_ref, netbk->tx_unmap_ops,
-- gop - netbk->tx_unmap_ops);
-- BUG_ON(ret);
+-out:
+- spin_unlock(&irq_mapping_update_lock);
+- return irq;
+-out_irq:
+- spin_unlock(&irq_mapping_update_lock);
+- xen_free_irq(irq);
+- return -1;
++ return xen_bind_pirq_msi_to_irq(dev, msidesc,
++ map_irq.pirq, map_irq.index,
++ (type == PCI_CAP_ID_MSIX) ?
++ "msi-x" : "msi");
+ }
+ #endif
+
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 18bf825..45c08a0 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -77,7 +77,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char
*name);
+ #ifdef CONFIG_PCI_MSI
+ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
+ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+- int pirq, const char *name);
++ int pirq, int vector, const char *name);
+ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
+ #endif
+
+--
+1.7.4
+
+
+From c5ae07bb307b658c8458f29ca77d237aec0f9327 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <Ian.Campbell(a)citrix.com>
+Date: Fri, 18 Feb 2011 17:06:55 +0000
+Subject: [PATCH 153/203] xen: events: remove dom0 specific xen_create_msi_irq
+
+The function name does not distinguish it from xen_allocate_pirq_msi
+(which operates on domU and pvhvm domains rather than dom0).
+
+Hoist domain 0 specific functionality up into the only caller leaving
+functionality common to all guest types in xen_bind_pirq_msi_to_irq.
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/pci/xen.c | 45 ++++++++++++++++++++++++++++++++++++++++-----
+ drivers/xen/events.c | 41 -----------------------------------------
+ include/xen/events.h | 1 -
+ 3 files changed, 40 insertions(+), 47 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index ffd8c7a..8c4085a 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -185,15 +185,50 @@ static void xen_teardown_msi_irq(unsigned int irq)
+ #ifdef CONFIG_XEN_DOM0
+ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+ {
+- int irq;
++ int ret = 0;
+ struct msi_desc *msidesc;
+
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+- irq = xen_create_msi_irq(dev, msidesc, type);
+- if (irq < 0)
+- return -1;
++ struct physdev_map_pirq map_irq;
++
++ memset(&map_irq, 0, sizeof(map_irq));
++ map_irq.domid = DOMID_SELF;
++ map_irq.type = MAP_PIRQ_TYPE_MSI;
++ map_irq.index = -1;
++ map_irq.pirq = -1;
++ map_irq.bus = dev->bus->number;
++ map_irq.devfn = dev->devfn;
++
++ if (type == PCI_CAP_ID_MSIX) {
++ int pos;
++ u32 table_offset, bir;
++
++ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++
++ pci_read_config_dword(dev, pos + PCI_MSIX_TABLE,
++ &table_offset);
++ bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
++
++ map_irq.table_base = pci_resource_start(dev, bir);
++ map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
++ }
++
++ ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
++ if (ret) {
++ dev_warn(&dev->dev, "xen map irq failed %d\n", ret);
++ goto out;
++ }
++
++ ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
++ map_irq.pirq, map_irq.index,
++ (type == PCI_CAP_ID_MSIX) ?
++ "msi-x" : "msi");
++ if (ret < 0)
++ goto out;
+ }
+- return 0;
++ ret = 0;
++out:
++ return ret;
+ }
+ #endif
+ #endif
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 3446948..6befe62 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -644,9 +644,6 @@ out:
+ }
+
+ #ifdef CONFIG_PCI_MSI
+-#include <linux/msi.h>
+-#include "../pci/msi.h"
-
-- /*
-- * Copy any entries that have been pending for too long
-- */
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !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;
-- pending_tx_info = netbk->pending_tx_info;
+ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
+ {
+ int rc;
+@@ -688,44 +685,6 @@ error_irq:
+ xen_free_irq(irq);
+ return -1;
+ }
-
-- if (time_after(inuse->alloc_time + HZ / 2, jiffies))
-- break;
+-int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
+-{
+- struct physdev_map_pirq map_irq;
+- int rc;
+- int pos;
+- u32 table_offset, bir;
-
-- pending_idx = inuse - netbk->pending_inuse;
+- memset(&map_irq, 0, sizeof(map_irq));
+- map_irq.domid = DOMID_SELF;
+- map_irq.type = MAP_PIRQ_TYPE_MSI;
+- map_irq.index = -1;
+- map_irq.pirq = -1;
+- map_irq.bus = dev->bus->number;
+- map_irq.devfn = dev->devfn;
-
-- pending_tx_info[pending_idx].vif->nr_copied_skbs++;
+- if (type == PCI_CAP_ID_MSIX) {
+- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-
-- switch (copy_pending_req(netbk, pending_idx)) {
-- case 0:
-- list_move_tail(&inuse->list, &list);
-- continue;
-- case -EBUSY:
-- list_del_init(&inuse->list);
-- continue;
-- case -ENOENT:
-- continue;
-- }
+- pci_read_config_dword(dev, msix_table_offset_reg(pos),
+- &table_offset);
+- bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
-
-- break;
-- }
+- map_irq.table_base = pci_resource_start(dev, bir);
+- map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
- }
-
-- list_for_each_entry_safe(inuse, n, &list, list) {
-- struct pending_tx_info *pending_tx_info;
-- pending_ring_idx_t index;
--
-- pending_tx_info = netbk->pending_tx_info;
-- pending_idx = inuse - netbk->pending_inuse;
--
-- vif = pending_tx_info[pending_idx].vif;
--
-- make_tx_response(vif, &pending_tx_info[pending_idx].req,
-- XEN_NETIF_RSP_OKAY);
--
-- /* Ready for next use. */
-- gnttab_reset_grant_page(netbk->mmap_pages[pending_idx]);
--
-- index = pending_index(netbk->pending_prod++);
-- netbk->pending_ring[index] = pending_idx;
--
-- xenvif_put(vif);
--
-- list_del_init(&inuse->list);
+- rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+- if (rc) {
+- dev_warn(&dev->dev, "xen map irq failed %d\n", rc);
+- return -1;
- }
+-
+- return xen_bind_pirq_msi_to_irq(dev, msidesc,
+- map_irq.pirq, map_irq.index,
+- (type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi");
-}
--#endif
+ #endif
+
+ int xen_destroy_irq(int irq)
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 45c08a0..962da2c 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -78,7 +78,6 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char
*name);
+ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
+ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+ int pirq, int vector, const char *name);
+-int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
+ #endif
+
+ /* De-allocates the above mentioned physical interrupt. */
+--
+1.7.4
+
+
+From 77c35acb7c81cd94c6b30a3bef488dd2d8145131 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Wed, 23 Feb 2011 08:11:35 -0500
+Subject: [PATCH 154/203] xen-gntdev: Fix incorrect use of zero handle
+
+The handle with numeric value 0 is a valid map handle, so it cannot
+be used to indicate that a page has not been mapped. Use -1 instead.
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 23 ++++++++++++++++-------
+ 1 files changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index 2a4733c..cdc28dc 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -126,6 +126,8 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv,
int count)
+ add->pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ if (add->pages[i] == NULL)
+ goto err;
++ add->map_ops[i].handle = -1;
++ add->unmap_ops[i].handle = -1;
+ }
+
+ add->index = 0;
+@@ -248,7 +250,7 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
+ map->grants[pgnr].ref,
+ map->grants[pgnr].domid);
+ gnttab_set_unmap_op(&map->unmap_ops[pgnr], pte_maddr, flags,
+- 0 /* handle */);
++ -1 /* handle */);
+ return 0;
+ }
+
+@@ -259,7 +261,7 @@ static int map_grant_pages(struct grant_map *map)
+
+ if (!use_ptemod) {
+ /* Note: it could already be mapped */
+- if (map->map_ops[0].handle)
++ if (map->map_ops[0].handle != -1)
+ return 0;
+ for (i = 0; i < map->count; i++) {
+ addr = (phys_addr_t)
+@@ -268,7 +270,7 @@ static int map_grant_pages(struct grant_map *map)
+ map->grants[i].ref,
+ map->grants[i].domid);
+ gnttab_set_unmap_op(&map->unmap_ops[i], addr,
+- map->flags, 0 /* handle */);
++ map->flags, -1 /* handle */);
+ }
+ }
+
+@@ -280,7 +282,11 @@ static int map_grant_pages(struct grant_map *map)
+ for (i = 0; i < map->count; i++) {
+ if (map->map_ops[i].status)
+ err = -EINVAL;
+- map->unmap_ops[i].handle = map->map_ops[i].handle;
++ else {
++ BUG_ON(map->map_ops[i].handle == -1);
++ map->unmap_ops[i].handle = map->map_ops[i].handle;
++ pr_debug("map handle=%d\n", map->map_ops[i].handle);
++ }
+ }
+ return err;
+ }
+@@ -313,7 +319,10 @@ static int __unmap_grant_pages(struct grant_map *map, int offset,
int pages)
+ for (i = 0; i < pages; i++) {
+ if (map->unmap_ops[offset+i].status)
+ err = -EINVAL;
+- map->unmap_ops[offset+i].handle = 0;
++ pr_debug("unmap handle=%d st=%d\n",
++ map->unmap_ops[offset+i].handle,
++ map->unmap_ops[offset+i].status);
++ map->unmap_ops[offset+i].handle = -1;
+ }
+ return err;
+ }
+@@ -328,13 +337,13 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+ * already unmapped some of the grants. Only unmap valid ranges.
+ */
+ while (pages && !err) {
+- while (pages && !map->unmap_ops[offset].handle) {
++ while (pages && map->unmap_ops[offset].handle == -1) {
+ offset++;
+ pages--;
+ }
+ range = 0;
+ while (range < pages) {
+- if (!map->unmap_ops[offset+range].handle) {
++ if (map->unmap_ops[offset+range].handle == -1) {
+ range--;
+ break;
+ }
+--
+1.7.4
+
+
+From f4ee4af447b67135de7eb8a6615811c13ce938e2 Mon Sep 17 00:00:00 2001
+From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Date: Wed, 23 Feb 2011 08:11:36 -0500
+Subject: [PATCH 155/203] xen-gntdev: Add cast to pointer
+
+Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/gntdev.c | 4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
+index cdc28dc..d43ff30 100644
+--- a/drivers/xen/gntdev.c
++++ b/drivers/xen/gntdev.c
+@@ -298,8 +298,8 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+ if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
+ int pgno = (map->notify.addr >> PAGE_SHIFT);
+ if (pgno >= offset && pgno < offset + pages && use_ptemod) {
+- void __user *tmp;
+- tmp = map->vma->vm_start + map->notify.addr;
++ void __user *tmp = (void __user *)
++ map->vma->vm_start + map->notify.addr;
+ err = copy_to_user(tmp, &err, 1);
+ if (err)
+ return err;
+--
+1.7.4
+
+
+From 2bd3f2608788e776ff0524ce77cca995094191a1 Mon Sep 17 00:00:00 2001
+From: Alex Deucher <alexdeucher(a)gmail.com>
+Date: Thu, 24 Feb 2011 03:16:21 -0500
+Subject: [PATCH 156/203] drm/radeon/kms: clean up gart dummy page handling
+
+As per Konrad's original patch, the dummy page used
+by the gart code and allocated in radeon_gart_init()
+was not freed properly in radeon_gart_fini().
+
+At the same time r6xx and newer allocated and freed the
+dummy page on their own. So to do Konrad's patch one
+better, just remove the allocation and freeing of the
+dummy page in the r6xx, 7xx, evergreen, and ni code and
+allocate and free in the gart_init/fini() functions for
+all asics.
+
+Cc: Jerome Glisse <jglisse(a)redhat.com>
+Signed-off-by: Alex Deucher <alexdeucher(a)gmail.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/gpu/drm/radeon/evergreen.c | 4 ----
+ drivers/gpu/drm/radeon/r600.c | 4 ----
+ drivers/gpu/drm/radeon/radeon_gart.c | 2 ++
+ drivers/gpu/drm/radeon/rv770.c | 4 ----
+ 4 files changed, 2 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
+index d270b3f..f643133 100644
+--- a/drivers/gpu/drm/radeon/evergreen.c
++++ b/drivers/gpu/drm/radeon/evergreen.c
+@@ -3048,9 +3048,6 @@ int evergreen_init(struct radeon_device *rdev)
+ {
+ int r;
+
+- r = radeon_dummy_page_init(rdev);
+- if (r)
+- return r;
+ /* This don't do much */
+ r = radeon_gem_init(rdev);
+ if (r)
+@@ -3162,7 +3159,6 @@ void evergreen_fini(struct radeon_device *rdev)
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+- radeon_dummy_page_fini(rdev);
+ }
+
+ static void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
+diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
+index de88624..36efc45 100644
+--- a/drivers/gpu/drm/radeon/r600.c
++++ b/drivers/gpu/drm/radeon/r600.c
+@@ -2509,9 +2509,6 @@ int r600_init(struct radeon_device *rdev)
+ {
+ int r;
+
+- r = radeon_dummy_page_init(rdev);
+- if (r)
+- return r;
+ if (r600_debugfs_mc_info_init(rdev)) {
+ DRM_ERROR("Failed to register debugfs file for mc !\n");
+ }
+@@ -2625,7 +2622,6 @@ void r600_fini(struct radeon_device *rdev)
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+- radeon_dummy_page_fini(rdev);
+ }
+
+
+diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
+index 6501611..dc04c7b 100644
+--- a/drivers/gpu/drm/radeon/radeon_gart.c
++++ b/drivers/gpu/drm/radeon/radeon_gart.c
+@@ -269,4 +269,6 @@ void radeon_gart_fini(struct radeon_device *rdev)
+ kfree(rdev->gart.pages_addr);
+ rdev->gart.pages = NULL;
+ rdev->gart.pages_addr = NULL;
++
++ radeon_dummy_page_fini(rdev);
+ }
+diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
+index d8ba676..6a312e6 100644
+--- a/drivers/gpu/drm/radeon/rv770.c
++++ b/drivers/gpu/drm/radeon/rv770.c
+@@ -1256,9 +1256,6 @@ int rv770_init(struct radeon_device *rdev)
+ {
+ int r;
+
+- r = radeon_dummy_page_init(rdev);
+- if (r)
+- return r;
+ /* This don't do much */
+ r = radeon_gem_init(rdev);
+ if (r)
+@@ -1373,7 +1370,6 @@ void rv770_fini(struct radeon_device *rdev)
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+- radeon_dummy_page_fini(rdev);
+ }
+
+ static void rv770_pcie_gen2_enable(struct radeon_device *rdev)
+--
+1.7.4
+
+
+From 36ff9d246ac231fe6bce55121ddd6f799c9b0c3b Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 29 Nov 2010 13:52:18 -0500
+Subject: [PATCH 157/203] ttm: Introduce a placeholder for DMA (bus) addresses.
+
+This is right now limited to only non-pool constructs.
+
+[v2: Fixed indentation issues, add review-by tag]
+
+Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/gpu/drm/ttm/ttm_page_alloc.c | 8 +++++---
+ drivers/gpu/drm/ttm/ttm_tt.c | 10 ++++++++--
+ include/drm/ttm/ttm_bo_driver.h | 2 ++
+ include/drm/ttm/ttm_page_alloc.h | 8 ++++++--
+ 4 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
+index b1e02ff..9d9d929 100644
+--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
++++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
+@@ -38,6 +38,7 @@
+ #include <linux/mm.h>
+ #include <linux/seq_file.h> /* for seq_printf */
+ #include <linux/slab.h>
++#include <linux/dma-mapping.h>
+
+ #include <asm/atomic.h>
+
+@@ -662,7 +663,8 @@ out:
+ * cached pages.
+ */
+ int ttm_get_pages(struct list_head *pages, int flags,
+- enum ttm_caching_state cstate, unsigned count)
++ enum ttm_caching_state cstate, unsigned count,
++ dma_addr_t *dma_address)
+ {
+ struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
+ struct page *p = NULL;
+@@ -720,7 +722,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
+ printk(KERN_ERR TTM_PFX
+ "Failed to allocate extra pages "
+ "for large request.");
+- ttm_put_pages(pages, 0, flags, cstate);
++ ttm_put_pages(pages, 0, flags, cstate, NULL);
+ return r;
+ }
+ }
+@@ -731,7 +733,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
+
+ /* Put all pages in pages list to correct pool to wait for reuse */
+ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags,
+- enum ttm_caching_state cstate)
++ enum ttm_caching_state cstate, dma_addr_t *dma_address)
+ {
+ unsigned long irq_flags;
+ struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
+diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
+index af789dc..0d39001 100644
+--- a/drivers/gpu/drm/ttm/ttm_tt.c
++++ b/drivers/gpu/drm/ttm/ttm_tt.c
+@@ -49,12 +49,16 @@ static int ttm_tt_swapin(struct ttm_tt *ttm);
+ static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm)
+ {
+ ttm->pages = drm_calloc_large(ttm->num_pages, sizeof(*ttm->pages));
++ ttm->dma_address = drm_calloc_large(ttm->num_pages,
++ sizeof(*ttm->dma_address));
+ }
+
+ static void ttm_tt_free_page_directory(struct ttm_tt *ttm)
+ {
+ drm_free_large(ttm->pages);
+ ttm->pages = NULL;
++ drm_free_large(ttm->dma_address);
++ ttm->dma_address = NULL;
+ }
+
+ static void ttm_tt_free_user_pages(struct ttm_tt *ttm)
+@@ -105,7 +109,8 @@ static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index)
+
+ INIT_LIST_HEAD(&h);
+
+- ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1);
++ ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1,
++ &ttm->dma_address[index]);
+
+ if (ret != 0)
+ return NULL;
+@@ -298,7 +303,8 @@ static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm)
+ count++;
+ }
+ }
+- ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state);
++ ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state,
++ ttm->dma_address);
+ ttm->state = tt_unpopulated;
+ ttm->first_himem_page = ttm->num_pages;
+ ttm->last_lomem_page = -1;
+diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
+index 1da8af6..1cff8b8 100644
+--- a/include/drm/ttm/ttm_bo_driver.h
++++ b/include/drm/ttm/ttm_bo_driver.h
+@@ -149,6 +149,7 @@ enum ttm_caching_state {
+ * @swap_storage: Pointer to shmem struct file for swap storage.
+ * @caching_state: The current caching state of the pages.
+ * @state: The current binding state of the pages.
++ * @dma_address: The DMA (bus) addresses of the pages (if TTM_PAGE_FLAG_DMA32)
+ *
+ * This is a structure holding the pages, caching- and aperture binding
+ * status for a buffer object that isn't backed by fixed (VRAM / AGP)
+@@ -173,6 +174,7 @@ struct ttm_tt {
+ tt_unbound,
+ tt_unpopulated,
+ } state;
++ dma_addr_t *dma_address;
+ };
+
+ #define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */
+diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h
+index 1168214..8062890 100644
+--- a/include/drm/ttm/ttm_page_alloc.h
++++ b/include/drm/ttm/ttm_page_alloc.h
+@@ -36,11 +36,13 @@
+ * @flags: ttm flags for page allocation.
+ * @cstate: ttm caching state for the page.
+ * @count: number of pages to allocate.
++ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
+ */
+ int ttm_get_pages(struct list_head *pages,
+ int flags,
+ enum ttm_caching_state cstate,
+- unsigned count);
++ unsigned count,
++ dma_addr_t *dma_address);
+ /**
+ * Put linked list of pages to pool.
+ *
+@@ -49,11 +51,13 @@ int ttm_get_pages(struct list_head *pages,
+ * count.
+ * @flags: ttm flags for page allocation.
+ * @cstate: ttm caching state.
++ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
+ */
+ void ttm_put_pages(struct list_head *pages,
+ unsigned page_count,
+ int flags,
+- enum ttm_caching_state cstate);
++ enum ttm_caching_state cstate,
++ dma_addr_t *dma_address);
+ /**
+ * Initialize pool allocator.
+ */
+--
+1.7.4
+
+
+From 0438748313f46e887aca12ef0cfc4178f2dfe920 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 29 Nov 2010 14:03:30 -0500
+Subject: [PATCH 158/203] ttm: Utilize the DMA API for pages that have TTM_PAGE_FLAG_DMA32
set.
+
+For pages that have the TTM_PAGE_FLAG_DMA32 flag set we
+use the DMA API. We save the bus address in our array which we
+use to program the GART (see "radeon/ttm/PCIe: Use dma_addr if TTM
+has set it." and "nouveau/ttm/PCIe: Use dma_addr if TTM has set it.").
+
+The reason behind using the DMA API is that under Xen we would
+end up programming the GART with the bounce buffer (SWIOTLB)
+DMA address instead of the physical DMA address of the TTM page.
+The reason being that alloc_page with GFP_DMA32 does not allocate
+pages under the the 4GB mark when running under Xen hypervisor.
+
+Under baremetal this means we do the DMA API call earlier instead
+of when we program the GART.
+
+For details please refer to:
+https://lkml.org/lkml/2011/1/7/251
+
+[v2: Fixed indentation, revised desc, added Reviewed-by]
+Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/gpu/drm/ttm/ttm_page_alloc.c | 26 +++++++++++++++++++++++---
+ 1 files changed, 23 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
+index 9d9d929..737a2a2 100644
+--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
++++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
+@@ -683,14 +683,22 @@ int ttm_get_pages(struct list_head *pages, int flags,
+ gfp_flags |= GFP_HIGHUSER;
+
+ for (r = 0; r < count; ++r) {
+- p = alloc_page(gfp_flags);
++ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
++ void *addr;
++ addr = dma_alloc_coherent(NULL, PAGE_SIZE,
++ &dma_address[r],
++ gfp_flags);
++ if (addr == NULL)
++ return -ENOMEM;
++ p = virt_to_page(addr);
++ } else
++ p = alloc_page(gfp_flags);
+ if (!p) {
+
+ printk(KERN_ERR TTM_PFX
+ "Unable to allocate page.");
+ return -ENOMEM;
+ }
-
- static void netbk_tx_err(struct xenvif *vif,
- struct xen_netif_tx_request *txp, RING_IDX end)
- {
-@@ -1033,7 +855,6 @@ static int netbk_count_requests(struct xenvif *vif,
- return frags;
- }
+ list_add(&p->lru, pages);
+ }
+ return 0;
+@@ -738,12 +746,24 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count,
int flags,
+ unsigned long irq_flags;
+ struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
+ struct page *p, *tmp;
++ unsigned r;
--#ifndef HAVE_XEN_PAGE_FOREIGN
- static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
- struct sk_buff *skb,
- unsigned long pending_idx)
-@@ -1046,21 +867,12 @@ static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
- netbk->mmap_pages[pending_idx] = page;
- return page;
- }
--#endif
+ if (pool == NULL) {
+ /* No pool for this memory type so free the pages */
--#ifdef HAVE_XEN_PAGE_FOREIGN
--static struct gnttab_map_grant_ref *xen_netbk_get_requests(struct xen_netbk *netbk,
-- struct xenvif *vif,
-- struct sk_buff *skb,
-- struct xen_netif_tx_request *txp,
-- struct gnttab_map_grant_ref *gop)
--#else
- static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
- struct xenvif *vif,
- struct sk_buff *skb,
- struct xen_netif_tx_request *txp,
- struct gnttab_copy *gop)
--#endif
- {
- struct skb_shared_info *shinfo = skb_shinfo(skb);
- skb_frag_t *frags = shinfo->frags;
-@@ -1071,20 +883,13 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk
*netbk,
- start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++ r = page_count-1;
+ list_for_each_entry_safe(p, tmp, pages, lru) {
+- __free_page(p);
++ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
++ void *addr = page_address(p);
++ WARN_ON(!addr || !dma_address[r]);
++ if (addr)
++ dma_free_coherent(NULL, PAGE_SIZE,
++ addr,
++ dma_address[r]);
++ dma_address[r] = 0;
++ } else
++ __free_page(p);
++ r--;
+ }
+ /* Make the pages list empty */
+ INIT_LIST_HEAD(pages);
+--
+1.7.4
+
+
+From 6b1f175951de66ac07e765a07d4f22004c0d7ce2 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 2 Dec 2010 10:24:13 -0500
+Subject: [PATCH 159/203] ttm: Expand (*populate) to support an array of DMA addresses.
+
+We pass in the array of ttm pages to be populated in the GART/MM
+of the card (or AGP). Patch titled: "ttm: Utilize the DMA API for
+pages that have TTM_PAGE_FLAG_DMA32 set." uses the DMA API to make
+those pages have a proper DMA addresses (in the situation where
+page_to_phys or virt_to_phys do not give use the DMA (bus) address).
+
+Since we are using the DMA API on those pages, we should pass in the
+DMA address to this function so it can save it in its proper fields
+(later patches use it).
+
+[v2: Added reviewed-by tag]
+
+Reviewed-by: Thomas Hellstrom <thellstrom(a)shipmail.org>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/gpu/drm/nouveau/nouveau_sgdma.c | 3 ++-
+ drivers/gpu/drm/radeon/radeon_ttm.c | 3 ++-
+ drivers/gpu/drm/ttm/ttm_agp_backend.c | 3 ++-
+ drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
+ drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 3 ++-
+ include/drm/ttm/ttm_bo_driver.h | 4 +++-
+ 6 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+index 9a250eb..c3c0674 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+@@ -20,7 +20,8 @@ struct nouveau_sgdma_be {
- for (i = start; i < shinfo->nr_frags; i++, txp++) {
--#ifndef HAVE_XEN_PAGE_FOREIGN
- struct page *page;
--#endif
- pending_ring_idx_t index;
- struct pending_tx_info *pending_tx_info =
- netbk->pending_tx_info;
+ static int
+ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages,
+- struct page **pages, struct page *dummy_read_page)
++ struct page **pages, struct page *dummy_read_page,
++ dma_addr_t *dma_addrs)
+ {
+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be;
+ struct drm_device *dev = nvbe->dev;
+diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
+index e5b2cf1..81f422d 100644
+--- a/drivers/gpu/drm/radeon/radeon_ttm.c
++++ b/drivers/gpu/drm/radeon/radeon_ttm.c
+@@ -655,7 +655,8 @@ struct radeon_ttm_backend {
+ static int radeon_ttm_backend_populate(struct ttm_backend *backend,
+ unsigned long num_pages,
+ struct page **pages,
+- struct page *dummy_read_page)
++ struct page *dummy_read_page,
++ dma_addr_t *dma_addrs)
+ {
+ struct radeon_ttm_backend *gtt;
- index = pending_index(netbk->pending_cons++);
- pending_idx = netbk->pending_ring[index];
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- gnttab_set_map_op(gop++, idx_to_kaddr(netbk, pending_idx),
-- GNTMAP_host_map | GNTMAP_readonly,
-- txp->gref, vif->domid);
--#else
- page = xen_netbk_alloc_page(netbk, skb, pending_idx);
- if (!page)
- return NULL;
-@@ -1103,7 +908,6 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk
*netbk,
- gop->flags = GNTCOPY_source_gref;
+diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c
b/drivers/gpu/drm/ttm/ttm_agp_backend.c
+index f999e36..1c4a72f 100644
+--- a/drivers/gpu/drm/ttm/ttm_agp_backend.c
++++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c
+@@ -47,7 +47,8 @@ struct ttm_agp_backend {
- gop++;
--#endif
+ static int ttm_agp_populate(struct ttm_backend *backend,
+ unsigned long num_pages, struct page **pages,
+- struct page *dummy_read_page)
++ struct page *dummy_read_page,
++ dma_addr_t *dma_addrs)
+ {
+ struct ttm_agp_backend *agp_be =
+ container_of(backend, struct ttm_agp_backend, backend);
+diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
+index 0d39001..86d5b17 100644
+--- a/drivers/gpu/drm/ttm/ttm_tt.c
++++ b/drivers/gpu/drm/ttm/ttm_tt.c
+@@ -169,7 +169,7 @@ int ttm_tt_populate(struct ttm_tt *ttm)
+ }
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
- xenvif_get(vif);
-@@ -1114,21 +918,11 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk
*netbk,
- return gop;
+ be->func->populate(be, ttm->num_pages, ttm->pages,
+- ttm->dummy_read_page);
++ ttm->dummy_read_page, ttm->dma_address);
+ ttm->state = tt_unbound;
+ return 0;
}
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+index 80bc37b..87e43e0 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+@@ -102,7 +102,8 @@ struct vmw_ttm_backend {
--#ifdef HAVE_XEN_PAGE_FOREIGN
--static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
-- struct sk_buff *skb,
-- struct gnttab_map_grant_ref **gopp)
--#else
- static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
- struct sk_buff *skb,
- struct gnttab_copy **gopp)
--#endif
+ static int vmw_ttm_populate(struct ttm_backend *backend,
+ unsigned long num_pages, struct page **pages,
+- struct page *dummy_read_page)
++ struct page *dummy_read_page,
++ dma_addr_t *dma_addrs)
{
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- struct gnttab_map_grant_ref *gop = *gopp;
--#else
- struct gnttab_copy *gop = *gopp;
--#endif
- int pending_idx = *((u16 *)skb->data);
- struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
- struct xenvif *vif = pending_tx_info[pending_idx].vif;
-@@ -1146,13 +940,6 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
- make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
- netbk->pending_ring[index] = pending_idx;
- xenvif_put(vif);
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- } else {
-- set_phys_to_machine(
-- __pa(idx_to_kaddr(netbk, pending_idx)) >> PAGE_SHIFT,
-- FOREIGN_FRAME(gop->dev_bus_addr >> PAGE_SHIFT));
-- netbk->grant_tx_handle[pending_idx] = gop->handle;
--#endif
- }
+ struct vmw_ttm_backend *vmw_be =
+ container_of(backend, struct vmw_ttm_backend, backend);
+diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
+index 1cff8b8..efed082 100644
+--- a/include/drm/ttm/ttm_bo_driver.h
++++ b/include/drm/ttm/ttm_bo_driver.h
+@@ -50,13 +50,15 @@ struct ttm_backend_func {
+ * @pages: Array of pointers to ttm pages.
+ * @dummy_read_page: Page to be used instead of NULL pages in the
+ * array @pages.
++ * @dma_addrs: Array of DMA (bus) address of the ttm pages.
+ *
+ * Populate the backend with ttm pages. Depending on the backend,
+ * it may or may not copy the @pages array.
+ */
+ int (*populate) (struct ttm_backend *backend,
+ unsigned long num_pages, struct page **pages,
+- struct page *dummy_read_page);
++ struct page *dummy_read_page,
++ dma_addr_t *dma_addrs);
+ /**
+ * struct ttm_backend_func member clear
+ *
+--
+1.7.4
+
+
+From eadf243146fbcd88ead082be5341996e52c13b73 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 24 Feb 2011 11:23:49 -0500
+Subject: [PATCH 160/203] radeon/ttm/PCIe: Use dma_addr if TTM has set it.
+
+If the TTM layer has used the DMA API to setup pages that are
+TTM_PAGE_FLAG_DMA32 (look at patch titled: "ttm: Utilize the dma_addr_t
+array for pages that are to in DMA32 pool."), lets use it
+when programming the GART in the PCIe type cards.
+
+This patch skips doing the pci_map_page (and pci_unmap_page) if
+there is a DMA addresses passed in for that page. If the dma_address
+is zero (or DMA_ERROR_CODE), then we continue on with our old
+behaviour.
+
+[v2: Fixed an indentation problem, added reviewed-by tag]
+[v3: Added Acked-by Jerome]
+
+Acked-by: Jerome Glisse <j.glisse(a)gmail.com>
+Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/gpu/drm/radeon/radeon.h | 4 ++-
+ drivers/gpu/drm/radeon/radeon_gart.c | 37 +++++++++++++++++++++++----------
+ drivers/gpu/drm/radeon/radeon_ttm.c | 5 +++-
+ 3 files changed, 33 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
+index 56c48b6..c5955d3 100644
+--- a/drivers/gpu/drm/radeon/radeon.h
++++ b/drivers/gpu/drm/radeon/radeon.h
+@@ -319,6 +319,7 @@ struct radeon_gart {
+ union radeon_gart_table table;
+ struct page **pages;
+ dma_addr_t *pages_addr;
++ bool *ttm_alloced;
+ bool ready;
+ };
- /* Skip first skb fragment if it is on same page as header fragment. */
-@@ -1167,14 +954,6 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
- /* Check error status: if okay then remember grant handle. */
- newerr = (++gop)->status;
- if (likely(!newerr)) {
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- unsigned long addr;
-- addr = idx_to_kaddr(netbk, pending_idx);
-- set_phys_to_machine(
-- __pa(addr)>>PAGE_SHIFT,
-- FOREIGN_FRAME(gop->dev_bus_addr>>PAGE_SHIFT));
-- netbk->grant_tx_handle[pending_idx] = gop->handle;
--#endif
- /* Had a previous error? Invalidate this fragment. */
- if (unlikely(err))
- xen_netbk_idx_release(netbk, pending_idx);
-@@ -1220,11 +999,6 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct
sk_buff *skb)
- unsigned long pending_idx;
+@@ -331,7 +332,8 @@ void radeon_gart_fini(struct radeon_device *rdev);
+ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
+ int pages);
+ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
+- int pages, struct page **pagelist);
++ int pages, struct page **pagelist,
++ dma_addr_t *dma_addr);
- pending_idx = (unsigned long)frag->page;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- netbk->pending_inuse[pending_idx].alloc_time = jiffies;
-- list_add_tail(&netbk->pending_inuse[pending_idx].list,
-- &netbk->pending_inuse_head);
--#endif
- txp = &netbk->pending_tx_info[pending_idx].req;
- frag->page = virt_to_page(idx_to_kaddr(netbk, pending_idx));
-@@ -1398,11 +1172,7 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
+ /*
+diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
+index dc04c7b..de4a86f 100644
+--- a/drivers/gpu/drm/radeon/radeon_gart.c
++++ b/drivers/gpu/drm/radeon/radeon_gart.c
+@@ -149,8 +149,9 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
+ p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
+ for (i = 0; i < pages; i++, p++) {
+ if (rdev->gart.pages[p]) {
+- pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
+- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
++ if (!rdev->gart.ttm_alloced[p])
++ pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
++ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ rdev->gart.pages[p] = NULL;
+ rdev->gart.pages_addr[p] = rdev->dummy_page.addr;
+ page_base = rdev->gart.pages_addr[p];
+@@ -165,7 +166,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
+ }
- static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
+ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
+- int pages, struct page **pagelist)
++ int pages, struct page **pagelist, dma_addr_t *dma_addr)
{
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- struct gnttab_map_grant_ref *gop = netbk->tx_map_ops, *request_gop;
--#else
- struct gnttab_copy *gop = netbk->tx_copy_ops, *request_gop;
--#endif
- struct sk_buff *skb;
- int ret;
+ unsigned t;
+ unsigned p;
+@@ -180,15 +181,22 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
+ p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
-@@ -1411,9 +1181,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
- struct xenvif *vif;
- struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
--#ifndef HAVE_XEN_PAGE_FOREIGN
- struct page *page;
--#endif
- struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
- u16 pending_idx;
- RING_IDX idx;
-@@ -1510,12 +1278,6 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
- }
+ for (i = 0; i < pages; i++, p++) {
+- /* we need to support large memory configurations */
+- /* assume that unbind have already been call on the range */
+- rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i],
++ /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32
++ * is requested. */
++ if (dma_addr[i] != DMA_ERROR_CODE) {
++ rdev->gart.ttm_alloced[p] = true;
++ rdev->gart.pages_addr[p] = dma_addr[i];
++ } else {
++ /* we need to support large memory configurations */
++ /* assume that unbind have already been call on the range */
++ rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i],
+ 0, PAGE_SIZE,
+ PCI_DMA_BIDIRECTIONAL);
+- if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) {
+- /* FIXME: failed to map page (return -ENOMEM?) */
+- radeon_gart_unbind(rdev, offset, pages);
+- return -ENOMEM;
++ if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) {
++ /* FIXME: failed to map page (return -ENOMEM?) */
++ radeon_gart_unbind(rdev, offset, pages);
++ return -ENOMEM;
++ }
}
+ rdev->gart.pages[p] = pagelist[i];
+ page_base = rdev->gart.pages_addr[p];
+@@ -251,6 +259,12 @@ int radeon_gart_init(struct radeon_device *rdev)
+ radeon_gart_fini(rdev);
+ return -ENOMEM;
+ }
++ rdev->gart.ttm_alloced = kzalloc(sizeof(bool) *
++ rdev->gart.num_cpu_pages, GFP_KERNEL);
++ if (rdev->gart.ttm_alloced == NULL) {
++ radeon_gart_fini(rdev);
++ return -ENOMEM;
++ }
+ /* set GART entry to point to the dummy page by default */
+ for (i = 0; i < rdev->gart.num_cpu_pages; i++) {
+ rdev->gart.pages_addr[i] = rdev->dummy_page.addr;
+@@ -267,8 +281,9 @@ void radeon_gart_fini(struct radeon_device *rdev)
+ rdev->gart.ready = false;
+ kfree(rdev->gart.pages);
+ kfree(rdev->gart.pages_addr);
++ kfree(rdev->gart.ttm_alloced);
+ rdev->gart.pages = NULL;
+ rdev->gart.pages_addr = NULL;
+-
++ rdev->gart.ttm_alloced = NULL;
+ radeon_dummy_page_fini(rdev);
+ }
+diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
+index 81f422d..9ead11f 100644
+--- a/drivers/gpu/drm/radeon/radeon_ttm.c
++++ b/drivers/gpu/drm/radeon/radeon_ttm.c
+@@ -647,6 +647,7 @@ struct radeon_ttm_backend {
+ unsigned long num_pages;
+ struct page **pages;
+ struct page *dummy_read_page;
++ dma_addr_t *dma_addrs;
+ bool populated;
+ bool bound;
+ unsigned offset;
+@@ -662,6 +663,7 @@ static int radeon_ttm_backend_populate(struct ttm_backend *backend,
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- gnttab_set_map_op(gop, idx_to_kaddr(netbk, pending_idx),
-- GNTMAP_host_map | GNTMAP_readonly,
-- txreq.gref, vif->domid);
-- gop++;
--#else
- /* XXX could copy straight to head */
- page = xen_netbk_alloc_page(netbk, skb, pending_idx);
- if (!page) {
-@@ -1538,7 +1300,6 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
- gop->flags = GNTCOPY_source_gref;
+ gtt = container_of(backend, struct radeon_ttm_backend, backend);
+ gtt->pages = pages;
++ gtt->dma_addrs = dma_addrs;
+ gtt->num_pages = num_pages;
+ gtt->dummy_read_page = dummy_read_page;
+ gtt->populated = true;
+@@ -674,6 +676,7 @@ static void radeon_ttm_backend_clear(struct ttm_backend *backend)
+
+ gtt = container_of(backend, struct radeon_ttm_backend, backend);
+ gtt->pages = NULL;
++ gtt->dma_addrs = NULL;
+ gtt->num_pages = 0;
+ gtt->dummy_read_page = NULL;
+ gtt->populated = false;
+@@ -694,7 +697,7 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend,
+ gtt->num_pages, bo_mem, backend);
+ }
+ r = radeon_gart_bind(gtt->rdev, gtt->offset,
+- gtt->num_pages, gtt->pages);
++ gtt->num_pages, gtt->pages, gtt->dma_addrs);
+ if (r) {
+ DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
+ gtt->num_pages, gtt->offset);
+--
+1.7.4
+
+
+From 7c20cf7644dc632b61a6f7ee52fa4ae2f8abc1b2 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 2 Dec 2010 11:36:24 -0500
+Subject: [PATCH 161/203] nouveau/ttm/PCIe: Use dma_addr if TTM has set it.
+
+If the TTM layer has used the DMA API to setup pages that are
+TTM_PAGE_FLAG_DMA32 (look at patch titled: "ttm: Utilize the
+DMA API for pages that have TTM_PAGE_FLAG_DMA32 set"), lets
+use it when programming the GART in the PCIe type cards.
+
+This patch skips doing the pci_map_page (and pci_unmap_page) if
+there is a DMA addresses passed in for that page. If the dma_address
+is zero (or DMA_ERROR_CODE), then we continue on with our old
+behaviour.
+
+[v2: Added a review-by tag]
+
+Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
+---
+ drivers/gpu/drm/nouveau/nouveau_sgdma.c | 28 +++++++++++++++++++++-------
+ 1 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+index c3c0674..07b1151 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
++++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+@@ -12,6 +12,7 @@ struct nouveau_sgdma_be {
+ struct drm_device *dev;
+
+ dma_addr_t *pages;
++ bool *ttm_alloced;
+ unsigned nr_pages;
- gop++;
--#endif
+ u64 offset;
+@@ -35,15 +36,25 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long
num_pages,
+ if (!nvbe->pages)
+ return -ENOMEM;
- memcpy(&netbk->pending_tx_info[pending_idx].req,
- &txreq, sizeof(txreq));
-@@ -1573,29 +1334,16 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
- vif->tx.req_cons = idx;
- xenvif_schedule_work(vif);
++ nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
++ if (!nvbe->ttm_alloced)
++ return -ENOMEM;
++
+ nvbe->nr_pages = 0;
+ while (num_pages--) {
+- nvbe->pages[nvbe->nr_pages] =
+- pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0,
++ if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) {
++ nvbe->pages[nvbe->nr_pages] =
++ dma_addrs[nvbe->nr_pages];
++ nvbe->ttm_alloced[nvbe->nr_pages] = true;
++ } else {
++ nvbe->pages[nvbe->nr_pages] =
++ pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0,
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+- if (pci_dma_mapping_error(dev->pdev,
+- nvbe->pages[nvbe->nr_pages])) {
+- be->func->clear(be);
+- return -EFAULT;
++ if (pci_dma_mapping_error(dev->pdev,
++ nvbe->pages[nvbe->nr_pages])) {
++ be->func->clear(be);
++ return -EFAULT;
++ }
+ }
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if ((gop - netbk->tx_map_ops) >= ARRAY_SIZE(netbk->tx_map_ops))
-- break;
--#else
- if ((gop-netbk->tx_copy_ops) >= ARRAY_SIZE(netbk->tx_copy_ops))
- break;
--#endif
- }
+ nvbe->nr_pages++;
+@@ -66,11 +77,14 @@ nouveau_sgdma_clear(struct ttm_backend *be)
+ be->func->unbind(be);
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- return gop - netbk->tx_map_ops;
--#else
- return gop - netbk->tx_copy_ops;
--#endif
+ while (nvbe->nr_pages--) {
+- pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
++ if (!nvbe->ttm_alloced[nvbe->nr_pages])
++ pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+ }
+ kfree(nvbe->pages);
++ kfree(nvbe->ttm_alloced);
+ nvbe->pages = NULL;
++ nvbe->ttm_alloced = NULL;
+ nvbe->nr_pages = 0;
+ }
}
+--
+1.7.4
+
+
+From 02bbfbab7dd6a107ea2f5d6e882631cd31c72eda Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 22 Feb 2011 13:24:32 -0500
+Subject: [PATCH 162/203] ttm: Include the 'struct dev' when using the DMA API.
+
+This makes the accounting when using 'debug_dma_dump_mappings()'
+and CONFIG_DMA_API_DEBUG=y be assigned to the correct device
+instead of 'fallback'.
+
+No functional change - just cosmetic.
+
+At first it seems that we just need to keep a copy of
+'struct device' in the struct ttm_bo_device and use that. However,
+when 'ttm_tt_destroy' is called it sets ttm->be (which contains
+the 'struct ttm_bo_device') to NULL so we cannot use it. Hence
+we copy the 'struct device' pointer to the 'struct ttm_tm' and keep
+it there.
+
+[v2: Added 'struct device' in 'struct ttm_tm']
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/gpu/drm/nouveau/nouveau_mem.c | 1 +
+ drivers/gpu/drm/radeon/radeon_ttm.c | 1 +
+ drivers/gpu/drm/ttm/ttm_page_alloc.c | 11 ++++++-----
+ drivers/gpu/drm/ttm/ttm_tt.c | 5 +++--
+ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +-
+ include/drm/ttm/ttm_bo_driver.h | 2 ++
+ include/drm/ttm/ttm_page_alloc.h | 8 ++++++--
+ 7 files changed, 20 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c
b/drivers/gpu/drm/nouveau/nouveau_mem.c
+index 26347b7..7b57067 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
+@@ -409,6 +409,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
+ if (ret)
+ return ret;
- static void xen_netbk_tx_submit(struct xen_netbk *netbk)
++ dev_priv->ttm.bdev.dev = dev->dev;
+ ret = ttm_bo_device_init(&dev_priv->ttm.bdev,
+ dev_priv->ttm.bo_global_ref.ref.object,
+ &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
+diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
+index 9ead11f..d19bfcf 100644
+--- a/drivers/gpu/drm/radeon/radeon_ttm.c
++++ b/drivers/gpu/drm/radeon/radeon_ttm.c
+@@ -513,6 +513,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
+ if (r) {
+ return r;
+ }
++ rdev->mman.bdev.dev = rdev->dev;
+ /* No others user of address space so set it to 0 */
+ r = ttm_bo_device_init(&rdev->mman.bdev,
+ rdev->mman.bo_global_ref.ref.object,
+diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
+index 737a2a2..35849db 100644
+--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
++++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
+@@ -664,7 +664,7 @@ out:
+ */
+ int ttm_get_pages(struct list_head *pages, int flags,
+ enum ttm_caching_state cstate, unsigned count,
+- dma_addr_t *dma_address)
++ dma_addr_t *dma_address, struct device *dev)
{
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- struct gnttab_map_grant_ref *gop = netbk->tx_map_ops;
--#else
- struct gnttab_copy *gop = netbk->tx_copy_ops;
--#endif
- struct sk_buff *skb;
+ struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
+ struct page *p = NULL;
+@@ -685,7 +685,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
+ for (r = 0; r < count; ++r) {
+ if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
+ void *addr;
+- addr = dma_alloc_coherent(NULL, PAGE_SIZE,
++ addr = dma_alloc_coherent(dev, PAGE_SIZE,
+ &dma_address[r],
+ gfp_flags);
+ if (addr == NULL)
+@@ -730,7 +730,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
+ printk(KERN_ERR TTM_PFX
+ "Failed to allocate extra pages "
+ "for large request.");
+- ttm_put_pages(pages, 0, flags, cstate, NULL);
++ ttm_put_pages(pages, 0, flags, cstate, NULL, NULL);
+ return r;
+ }
+ }
+@@ -741,7 +741,8 @@ int ttm_get_pages(struct list_head *pages, int flags,
- while ((skb = __skb_dequeue(&netbk->tx_queue)) != NULL) {
-@@ -1655,15 +1403,6 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
- continue;
+ /* Put all pages in pages list to correct pool to wait for reuse */
+ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags,
+- enum ttm_caching_state cstate, dma_addr_t *dma_address)
++ enum ttm_caching_state cstate, dma_addr_t *dma_address,
++ struct device *dev)
+ {
+ unsigned long irq_flags;
+ struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
+@@ -757,7 +758,7 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int
flags,
+ void *addr = page_address(p);
+ WARN_ON(!addr || !dma_address[r]);
+ if (addr)
+- dma_free_coherent(NULL, PAGE_SIZE,
++ dma_free_coherent(dev, PAGE_SIZE,
+ addr,
+ dma_address[r]);
+ dma_address[r] = 0;
+diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
+index 86d5b17..354f9d9 100644
+--- a/drivers/gpu/drm/ttm/ttm_tt.c
++++ b/drivers/gpu/drm/ttm/ttm_tt.c
+@@ -110,7 +110,7 @@ static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index)
+ INIT_LIST_HEAD(&h);
+
+ ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1,
+- &ttm->dma_address[index]);
++ &ttm->dma_address[index], ttm->dev);
+
+ if (ret != 0)
+ return NULL;
+@@ -304,7 +304,7 @@ static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm)
}
+ }
+ ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state,
+- ttm->dma_address);
++ ttm->dma_address, ttm->dev);
+ ttm->state = tt_unpopulated;
+ ttm->first_himem_page = ttm->num_pages;
+ ttm->last_lomem_page = -1;
+@@ -397,6 +397,7 @@ struct ttm_tt *ttm_tt_create(struct ttm_bo_device *bdev, unsigned
long size,
+ ttm->last_lomem_page = -1;
+ ttm->caching_state = tt_cached;
+ ttm->page_flags = page_flags;
++ ttm->dev = bdev->dev;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
-- unlikely(skb_linearize(skb))) {
-- pr_debug("Can't linearize skb in net_tx_action.\n");
-- kfree_skb(skb);
-- continue;
-- }
--#endif
--
- vif->stats.rx_bytes += skb->len;
- vif->stats.rx_packets++;
+ ttm->dummy_read_page = dummy_read_page;
-@@ -1678,70 +1417,18 @@ static void xen_netbk_tx_action(struct xen_netbk *netbk)
- unsigned nr_gops;
- int ret;
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+index 10ca97e..4a8c789 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+@@ -322,7 +322,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long
chipset)
+ ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
+ dev_priv->active_master = &dev_priv->fbdev_master;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- xen_netbk_tx_action_dealloc(netbk);
--#endif
-
- nr_gops = xen_netbk_tx_build_gops(netbk);
++ dev_priv->bdev.dev = dev->dev;
+ ret = ttm_bo_device_init(&dev_priv->bdev,
+ dev_priv->bo_global_ref.ref.object,
+ &vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET,
+diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
+index efed082..7589c0a 100644
+--- a/include/drm/ttm/ttm_bo_driver.h
++++ b/include/drm/ttm/ttm_bo_driver.h
+@@ -177,6 +177,7 @@ struct ttm_tt {
+ tt_unpopulated,
+ } state;
+ dma_addr_t *dma_address;
++ struct device *dev;
+ };
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if (nr_gops == 0)
-- goto out;
-- ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-- netbk->tx_map_ops, nr_gops);
--#else
- if (nr_gops == 0)
- return;
- ret = HYPERVISOR_grant_table_op(GNTTABOP_copy,
- netbk->tx_copy_ops, nr_gops);
--#endif
- BUG_ON(ret);
+ #define TTM_MEMTYPE_FLAG_FIXED (1 << 0) /* Fixed (on-card) PCI memory */
+@@ -551,6 +552,7 @@ struct ttm_bo_device {
+ struct list_head device_list;
+ struct ttm_bo_global *glob;
+ struct ttm_bo_driver *driver;
++ struct device *dev;
+ rwlock_t vm_lock;
+ struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
+ spinlock_t fence_lock;
+diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h
+index 8062890..ccb6b7a 100644
+--- a/include/drm/ttm/ttm_page_alloc.h
++++ b/include/drm/ttm/ttm_page_alloc.h
+@@ -37,12 +37,14 @@
+ * @cstate: ttm caching state for the page.
+ * @count: number of pages to allocate.
+ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
++ * @dev: struct device for appropiate DMA accounting.
+ */
+ int ttm_get_pages(struct list_head *pages,
+ int flags,
+ enum ttm_caching_state cstate,
+ unsigned count,
+- dma_addr_t *dma_address);
++ dma_addr_t *dma_address,
++ struct device *dev);
+ /**
+ * Put linked list of pages to pool.
+ *
+@@ -52,12 +54,14 @@ int ttm_get_pages(struct list_head *pages,
+ * @flags: ttm flags for page allocation.
+ * @cstate: ttm caching state.
+ * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
++ * @dev: struct device for appropiate DMA accounting.
+ */
+ void ttm_put_pages(struct list_head *pages,
+ unsigned page_count,
+ int flags,
+ enum ttm_caching_state cstate,
+- dma_addr_t *dma_address);
++ dma_addr_t *dma_address,
++ struct device *dev);
+ /**
+ * Initialize pool allocator.
+ */
+--
+1.7.4
+
+
+From 733301920082553b52ce4453493fe6abf6aa7d1a Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 23 Feb 2011 22:42:38 -0500
+Subject: [PATCH 163/203] ttm: Pass in 'struct device' to TTM so it can do DMA API
on behalf of device.
+
+We want to pass in the 'struct device' to the TTM layer in a nice way.
+This is not strictly required, but it does make accounting of
+pages and their DMA addresses correct when using CONFIG_DMA_API_DEBUG=y.
+
+This patch builds on top of "ttm: Include the 'struct dev' when using the
DMA API."
+and moves the mechanism of passing in 'struct device' to the TTM API.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/gpu/drm/nouveau/nouveau_mem.c | 4 ++--
+ drivers/gpu/drm/radeon/radeon_ttm.c | 4 ++--
+ drivers/gpu/drm/ttm/ttm_bo.c | 4 +++-
+ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 ++--
+ include/drm/ttm/ttm_bo_driver.h | 5 ++++-
+ 5 files changed, 13 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c
b/drivers/gpu/drm/nouveau/nouveau_mem.c
+index 7b57067..3706156 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
++++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
+@@ -409,11 +409,11 @@ nouveau_mem_vram_init(struct drm_device *dev)
+ if (ret)
+ return ret;
- xen_netbk_tx_submit(netbk);
+- dev_priv->ttm.bdev.dev = dev->dev;
+ ret = ttm_bo_device_init(&dev_priv->ttm.bdev,
+ dev_priv->ttm.bo_global_ref.ref.object,
+ &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
+- dma_bits <= 32 ? true : false);
++ dma_bits <= 32 ? true : false,
++ dev->dev);
+ if (ret) {
+ NV_ERROR(dev, "Error initialising bo driver: %d\n", ret);
+ return ret;
+diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
+index d19bfcf..371890c 100644
+--- a/drivers/gpu/drm/radeon/radeon_ttm.c
++++ b/drivers/gpu/drm/radeon/radeon_ttm.c
+@@ -513,12 +513,12 @@ int radeon_ttm_init(struct radeon_device *rdev)
+ if (r) {
+ return r;
+ }
+- rdev->mman.bdev.dev = rdev->dev;
+ /* No others user of address space so set it to 0 */
+ r = ttm_bo_device_init(&rdev->mman.bdev,
+ rdev->mman.bo_global_ref.ref.object,
+ &radeon_bo_driver, DRM_FILE_PAGE_OFFSET,
+- rdev->need_dma32);
++ rdev->need_dma32,
++ rdev->dev);
+ if (r) {
+ DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
+ return r;
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index af61fc2..278a2d3 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -1526,12 +1526,14 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
+ struct ttm_bo_global *glob,
+ struct ttm_bo_driver *driver,
+ uint64_t file_page_offset,
+- bool need_dma32)
++ bool need_dma32,
++ struct device *dev)
+ {
+ int ret = -EINVAL;
+
+ rwlock_init(&bdev->vm_lock);
+ bdev->driver = driver;
++ bdev->dev = dev;
+
+ memset(bdev->man, 0, sizeof(bdev->man));
--#ifdef HAVE_XEN_PAGE_FOREIGN
--out:
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !list_empty(&netbk->pending_inuse_head)) {
-- struct netbk_tx_pending_inuse *oldest;
--
-- oldest = list_entry(netbk->pending_inuse_head.next,
-- struct netbk_tx_pending_inuse, list);
-- mod_timer(&netbk->netbk_tx_pending_timer,
-- oldest->alloc_time + HZ);
-- }
--#endif
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+index 4a8c789..803d979 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+@@ -322,11 +322,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long
chipset)
+ ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
+ dev_priv->active_master = &dev_priv->fbdev_master;
+
+- dev_priv->bdev.dev = dev->dev;
+ ret = ttm_bo_device_init(&dev_priv->bdev,
+ dev_priv->bo_global_ref.ref.object,
+ &vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET,
+- false);
++ false,
++ dev->dev);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed initializing TTM buffer object driver.\n");
+ goto out_err1;
+diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
+index 7589c0a..2024a74 100644
+--- a/include/drm/ttm/ttm_bo_driver.h
++++ b/include/drm/ttm/ttm_bo_driver.h
+@@ -793,6 +793,8 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
+ * @file_page_offset: Offset into the device address space that is available
+ * for buffer data. This ensures compatibility with other users of the
+ * address space.
++ * @need_dma32: Allocate pages under 4GB
++ * @dev: 'struct device' of the PCI device.
+ *
+ * Initializes a struct ttm_bo_device:
+ * Returns:
+@@ -801,7 +803,8 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
+ extern int ttm_bo_device_init(struct ttm_bo_device *bdev,
+ struct ttm_bo_global *glob,
+ struct ttm_bo_driver *driver,
+- uint64_t file_page_offset, bool need_dma32);
++ uint64_t file_page_offset, bool need_dma32,
++ struct device *dev);
+
+ /**
+ * ttm_bo_unmap_virtual
+--
+1.7.4
+
+
+From 92ecb86a77e143a9b9b4491158d063a0b319709f Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 8 Nov 2010 14:13:35 -0500
+Subject: [PATCH 164/203] xen/pci: Add xen_[find|register|unregister]_device_domain_owner
functions.
+
+When the Xen PCI backend is told to enable or disable MSI/MSI-X functions,
+the initial domain performs these operations. The initial domain needs
+to know which domain (guest) is going to use the PCI device so when it
+makes the appropiate hypercall to retrieve the MSI/MSI-X vector it will
+also assign the PCI device to the appropiate domain (guest).
+
+This boils down to us needing a mechanism to find, set and unset the domain
+id that will be using the device.
+
+[v2: EXPORT_SYMBOL -> EXPORT_SYMBOL_GPL.]
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ arch/x86/include/asm/xen/pci.h | 16 +++++++++
+ arch/x86/pci/xen.c | 73 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 89 insertions(+), 0 deletions(-)
+
+diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
+index aa86209..4fbda9a 100644
+--- a/arch/x86/include/asm/xen/pci.h
++++ b/arch/x86/include/asm/xen/pci.h
+@@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void)
+ #endif
+ #if defined(CONFIG_XEN_DOM0)
+ void __init xen_setup_pirqs(void);
++int xen_find_device_domain_owner(struct pci_dev *dev);
++int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
++int xen_unregister_device_domain_owner(struct pci_dev *dev);
+ #else
+ static inline void __init xen_setup_pirqs(void)
+ {
}
++static inline int xen_find_device_domain_owner(struct pci_dev *dev)
++{
++ return -1;
++}
++static inline int xen_register_device_domain_owner(struct pci_dev *dev,
++ uint16_t domain)
++{
++ return -1;
++}
++static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
++{
++ return -1;
++}
+ #endif
--#ifdef HAVE_XEN_PAGE_FOREIGN
--static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
--{
-- static DEFINE_SPINLOCK(_lock);
-- unsigned long flags;
-- pending_ring_idx_t index;
--
-- spin_lock_irqsave(&_lock, flags);
-- index = pending_index(netbk->dealloc_prod);
-- netbk->dealloc_ring[index] = pending_idx;
-- /* Sync with xen_netbk_tx_action_dealloc: insert idx /then/ incr producer. */
-- smp_wmb();
-- netbk->dealloc_prod++;
-- spin_unlock_irqrestore(&_lock, flags);
--
-- xen_netbk_kick_thread(netbk);
--}
--
--static void netif_page_release(struct page *page, unsigned int order)
--{
-- unsigned int group, idx;
-- int foreign = get_page_ext(page, &group, &idx);
--
-- BUG_ON(!foreign);
-- BUG_ON(order);
--
-- xen_netbk_idx_release(&xen_netbk[group], idx);
--}
--#else
- static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+ #if defined(CONFIG_PCI_MSI)
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 8c4085a..2d04454 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -444,3 +444,76 @@ void __init xen_setup_pirqs(void)
+ }
+ }
+ #endif
++
++struct xen_device_domain_owner {
++ domid_t domain;
++ struct pci_dev *dev;
++ struct list_head list;
++};
++
++static DEFINE_SPINLOCK(dev_domain_list_spinlock);
++static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
++
++static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
++{
++ struct xen_device_domain_owner *owner;
++
++ list_for_each_entry(owner, &dev_domain_list, list) {
++ if (owner->dev == dev)
++ return owner;
++ }
++ return NULL;
++}
++
++int xen_find_device_domain_owner(struct pci_dev *dev)
++{
++ struct xen_device_domain_owner *owner;
++ int domain = -ENODEV;
++
++ spin_lock(&dev_domain_list_spinlock);
++ owner = find_device(dev);
++ if (owner)
++ domain = owner->domain;
++ spin_unlock(&dev_domain_list_spinlock);
++ return domain;
++}
++EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
++
++int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
++{
++ struct xen_device_domain_owner *owner;
++
++ owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
++ if (!owner)
++ return -ENODEV;
++
++ spin_lock(&dev_domain_list_spinlock);
++ if (find_device(dev)) {
++ spin_unlock(&dev_domain_list_spinlock);
++ kfree(owner);
++ return -EEXIST;
++ }
++ owner->domain = domain;
++ owner->dev = dev;
++ list_add_tail(&owner->list, &dev_domain_list);
++ spin_unlock(&dev_domain_list_spinlock);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
++
++int xen_unregister_device_domain_owner(struct pci_dev *dev)
++{
++ struct xen_device_domain_owner *owner;
++
++ spin_lock(&dev_domain_list_spinlock);
++ owner = find_device(dev);
++ if (!owner) {
++ spin_unlock(&dev_domain_list_spinlock);
++ return -ENODEV;
++ }
++ list_del(&owner->list);
++ spin_unlock(&dev_domain_list_spinlock);
++ kfree(owner);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
+--
+1.7.4
+
+
+From 338415cd3c45f2519ea87858ee9e7abec0fa9ba1 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 24 Feb 2011 13:35:52 -0500
+Subject: [PATCH 165/203] xen/irq: Check if the PCI device is owned by a domain different
than DOMID_SELF.
+
+We check if there is a domain owner for the PCI device. In case of failure
+(meaning no domain has registered for this device) we make DOMID_SELF the owner.
+
+[v2: deal with rebasing on v2.6.37-1]
+[v3: deal with rebasing on stable/irq.cleanup]
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Acked-by: Xiantao Zhang <xiantao.zhang(a)intel.com>
+---
+ arch/x86/pci/xen.c | 21 ++++++++++++++++-----
+ drivers/xen/events.c | 16 ++++++++++------
+ include/xen/events.h | 3 ++-
+ 3 files changed, 28 insertions(+), 12 deletions(-)
+
+diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
+index 2d04454..309c0a0 100644
+--- a/arch/x86/pci/xen.c
++++ b/arch/x86/pci/xen.c
+@@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ }
+ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
+ (type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi");
++ "msi-x" : "msi",
++ DOMID_SELF);
+ if (irq < 0)
+ goto error;
+ dev_dbg(&dev->dev,
+@@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
+ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
+ (type == PCI_CAP_ID_MSIX) ?
+ "pcifront-msi-x" :
+- "pcifront-msi");
++ "pcifront-msi",
++ DOMID_SELF);
+ if (irq < 0)
+ goto free;
+ i++;
+@@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec,
int type)
+
+ list_for_each_entry(msidesc, &dev->msi_list, list) {
+ struct physdev_map_pirq map_irq;
++ domid_t domid;
++
++ domid = ret = xen_find_device_domain_owner(dev);
++ /* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED,
++ * hence check ret value for < 0. */
++ if (ret < 0)
++ domid = DOMID_SELF;
+
+ memset(&map_irq, 0, sizeof(map_irq));
+- map_irq.domid = DOMID_SELF;
++ map_irq.domid = domid;
+ map_irq.type = MAP_PIRQ_TYPE_MSI;
+ map_irq.index = -1;
+ map_irq.pirq = -1;
+@@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int
nvec, int type)
+
+ ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+ if (ret) {
+- dev_warn(&dev->dev, "xen map irq failed %d\n", ret);
++ dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n",
++ ret, domid);
+ goto out;
+ }
+
+ ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
+ map_irq.pirq, map_irq.index,
+ (type == PCI_CAP_ID_MSIX) ?
+- "msi-x" : "msi");
++ "msi-x" : "msi",
++ domid);
+ if (ret < 0)
+ goto out;
+ }
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 6befe62..3ccba7d 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -97,6 +97,7 @@ struct irq_info
+ unsigned short gsi;
+ unsigned char vector;
+ unsigned char flags;
++ uint16_t domid;
+ } pirq;
+ } u;
+ };
+@@ -153,11 +154,13 @@ static struct irq_info mk_virq_info(unsigned short evtchn, unsigned
short virq)
+ }
+
+ static struct irq_info mk_pirq_info(unsigned short evtchn, unsigned short pirq,
+- unsigned short gsi, unsigned short vector)
++ unsigned short gsi, unsigned short vector,
++ domid_t domid)
{
- struct xenvif *vif;
-@@ -1767,7 +1454,6 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16
pending_idx)
- put_page(netbk->mmap_pages[pending_idx]);
- netbk->mmap_pages[pending_idx] = NULL;
+ return (struct irq_info) { .type = IRQT_PIRQ, .evtchn = evtchn,
+ .cpu = 0,
+- .u.pirq = { .pirq = pirq, .gsi = gsi, .vector = vector } };
++ .u.pirq = { .pirq = pirq, .gsi = gsi,
++ .vector = vector, .domid = domid } };
}
--#endif
- static void make_tx_response(struct xenvif *vif,
- struct xen_netif_tx_request *txp,
-@@ -1820,14 +1506,6 @@ static inline int rx_work_todo(struct xen_netbk *netbk)
+ /*
+@@ -633,7 +636,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char
*name)
+ goto out;
+ }
- static inline int tx_work_todo(struct xen_netbk *netbk)
- {
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if (netbk->dealloc_cons != netbk->dealloc_prod)
-- return 1;
--
-- if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-- !list_empty(&netbk->pending_inuse_head))
-- return 1;
--#endif
+- irq_info[irq] = mk_pirq_info(0, pirq, gsi, irq_op.vector);
++ irq_info[irq] = mk_pirq_info(0, pirq, gsi, irq_op.vector, DOMID_SELF);
+ irq_info[irq].u.pirq.flags |= shareable ? PIRQ_SHAREABLE : 0;
+ pirq_to_irq[pirq] = irq;
- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list))
-@@ -1862,9 +1540,6 @@ static int xen_netbk_kthread(void *data)
- static int __init netback_init(void)
+@@ -659,7 +662,8 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc
*msidesc)
+ }
+
+ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+- int pirq, int vector, const char *name)
++ int pirq, int vector, const char *name,
++ domid_t domid)
{
- int i;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- struct page *page;
--#endif
- int rc = 0;
- int group;
+ int irq, ret;
-@@ -1888,32 +1563,6 @@ static int __init netback_init(void)
- netbk->net_timer.data = (unsigned long)netbk;
- netbk->net_timer.function = xen_netbk_alarm;
+@@ -672,7 +676,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc
*msidesc,
+ set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
+ handle_level_irq, name);
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- init_timer(&netbk->netbk_tx_pending_timer);
-- netbk->netbk_tx_pending_timer.data = (unsigned long)netbk;
-- netbk->netbk_tx_pending_timer.function =
-- xen_netbk_tx_pending_timeout;
--#endif
--
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- netbk->mmap_pages =
-- alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-- if (!netbk->mmap_pages) {
-- printk(KERN_ALERT "%s: out of memory\n", __func__);
-- del_timer(&netbk->netbk_tx_pending_timer);
-- del_timer(&netbk->net_timer);
-- rc = -ENOMEM;
-- goto failed_init;
-- }
--
-- for (i = 0; i < MAX_PENDING_REQS; i++) {
-- page = netbk->mmap_pages[i];
-- SetPageForeign(page, netif_page_release);
-- set_page_ext(page, netbk, i);
-- INIT_LIST_HEAD(&netbk->pending_inuse[i].list);
-- }
--#endif
--
- netbk->pending_cons = 0;
- netbk->pending_prod = MAX_PENDING_REQS;
- for (i = 0; i < MAX_PENDING_REQS; i++)
-@@ -1926,11 +1575,6 @@ static int __init netback_init(void)
+- irq_info[irq] = mk_pirq_info(0, pirq, 0, vector);
++ irq_info[irq] = mk_pirq_info(0, pirq, 0, vector, domid);
+ pirq_to_irq[pirq] = irq;
+ ret = set_irq_msi(irq, msidesc);
+ if (ret < 0)
+@@ -702,7 +706,7 @@ int xen_destroy_irq(int irq)
- if (IS_ERR(netbk->task)) {
- printk(KERN_ALERT "kthread_run() fails at netback\n");
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- free_empty_pages_and_pagevec(netbk->mmap_pages,
-- MAX_PENDING_REQS);
-- del_timer(&netbk->netbk_tx_pending_timer);
--#endif
- del_timer(&netbk->net_timer);
- rc = PTR_ERR(netbk->task);
- goto failed_init;
-@@ -1938,9 +1582,6 @@ static int __init netback_init(void)
+ if (xen_initial_domain()) {
+ unmap_irq.pirq = info->u.pirq.pirq;
+- unmap_irq.domid = DOMID_SELF;
++ unmap_irq.domid = info->u.pirq.domid;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
+ if (rc) {
+ printk(KERN_WARNING "unmap irq failed %d\n", rc);
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 962da2c..d146200 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -77,7 +77,8 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char
*name);
+ #ifdef CONFIG_PCI_MSI
+ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
+ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+- int pirq, int vector, const char *name);
++ int pirq, int vector, const char *name,
++ domid_t domid);
+ #endif
- kthread_bind(netbk->task, group);
+ /* De-allocates the above mentioned physical interrupt. */
+--
+1.7.4
+
+
+From 256b7b7ebebfe53468564466d9302dbaf26ebcbe Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 8 Nov 2010 14:26:36 -0500
+Subject: [PATCH 166/203] xen/irq: Add support to check if IRQ line is shared with other
domains.
+
+We do this via the PHYSDEVOP_irq_status_query support hypervisor call.
+We will get a positive value if another domain has binded its
+PIRQ to the specified GSI (IRQ line).
+
+[v2: Deal with v2.6.37-rc1 rebase fallout]
+[v3: Deal with stable/irq.cleanup fallout]
+[v4: xen_ignore_irq->xen_test_irq_shared]
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 12 ++++++++++++
+ include/xen/events.h | 3 +++
+ 2 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 3ccba7d..3afd1f4 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -1377,6 +1377,18 @@ void xen_poll_irq(int irq)
+ xen_poll_irq_timeout(irq, 0 /* no timeout */);
+ }
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- INIT_LIST_HEAD(&netbk->pending_inuse_head);
--#endif
- INIT_LIST_HEAD(&netbk->net_schedule_list);
++/* Check whether the IRQ line is shared with other guests. */
++int xen_test_irq_shared(int irq)
++{
++ struct irq_info *info = info_for_irq(irq);
++ struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq };
++
++ if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
++ return 0;
++ return !(irq_status.flags & XENIRQSTAT_shared);
++}
++EXPORT_SYMBOL_GPL(xen_test_irq_shared);
++
+ void xen_irq_resume(void)
+ {
+ unsigned int cpu, irq, evtchn;
+diff --git a/include/xen/events.h b/include/xen/events.h
+index d146200..71fad28 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -93,4 +93,7 @@ int xen_gsi_from_irq(unsigned pirq);
+ /* Return irq from pirq */
+ int xen_irq_from_pirq(unsigned pirq);
- spin_lock_init(&netbk->net_schedule_list_lock);
-@@ -1950,17 +1591,6 @@ static int __init netback_init(void)
- wake_up_process(netbk->task);
- }
++/* Determine whether to ignore this IRQ if it is passed to a guest. */
++int xen_test_irq_shared(int irq);
++
+ #endif /* _XEN_EVENTS_H */
+--
+1.7.4
+
+
+From 507762e78160d66c3381aae1dc8cbd595f73f73c Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ian.campbell(a)citrix.com>
+Date: Mon, 9 Feb 2009 12:05:50 -0800
+Subject: [PATCH 167/203] xen/irq: implement bind_interdomain_evtchn_to_irqhandler for
backend drivers
+
+Impact: new Xen-internal API
+
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 38 ++++++++++++++++++++++++++++++++++++++
+ include/xen/events.h | 6 ++++++
+ 2 files changed, 44 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index 3afd1f4..f300265 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -798,6 +798,21 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+ return irq;
+ }
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
-- if (MODPARM_copy_skb) {
-- if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-- NULL, 0))
-- netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
-- else
-- netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
-- }
--#endif
--
- rc = xenvif_xenbus_init();
- if (rc)
- goto failed_init;
-@@ -1970,17 +1600,11 @@ static int __init netback_init(void)
- failed_init:
- for (i = 0; i < group; i++) {
- struct xen_netbk *netbk = &xen_netbk[i];
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- free_empty_pages_and_pagevec(netbk->mmap_pages,
-- MAX_PENDING_REQS);
-- del_timer(&netbk->netbk_tx_pending_timer);
--#else
- int j;
- for (j = 0; j < MAX_PENDING_REQS; j++) {
- if (netbk->mmap_pages[i])
- __free_page(netbk->mmap_pages[i]);
- }
--#endif
- del_timer(&netbk->net_timer);
- kthread_stop(netbk->task);
- }
-diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
-index d56b1ee..22b8c35 100644
---- a/drivers/net/xen-netback/xenbus.c
-+++ b/drivers/net/xen-netback/xenbus.c
-@@ -74,10 +74,6 @@ static int netback_probe(struct xenbus_device *dev,
- dev_set_drvdata(&dev->dev, be);
++static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
++ unsigned int remote_port)
++{
++ struct evtchn_bind_interdomain bind_interdomain;
++ int err;
++
++ bind_interdomain.remote_dom = remote_domain;
++ bind_interdomain.remote_port = remote_port;
++
++ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++ &bind_interdomain);
++
++ return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
++}
++
- sg = 1;
--#ifdef HAVE_XEN_PAGE_FOREIGN
-- if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
-- sg = 0;
--#endif
+ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+ {
+@@ -893,6 +908,29 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn,
+ }
+ EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
- do {
- err = xenbus_transaction_start(&xbt);
++int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
++ unsigned int remote_port,
++ irq_handler_t handler,
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id)
++{
++ int irq, retval;
++
++ irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
++ if (irq < 0)
++ return irq;
++
++ retval = request_irq(irq, handler, irqflags, devname, dev_id);
++ if (retval != 0) {
++ unbind_from_irq(irq);
++ return retval;
++ }
++
++ return irq;
++}
++EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
++
+ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname, void *dev_id)
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 71fad28..23de713 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -23,6 +23,12 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id);
++int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
++ unsigned int remote_port,
++ irq_handler_t handler,
++ unsigned long irqflags,
++ const char *devname,
++ void *dev_id);
+
+ /*
+ * Common unbind function for all event sources. Takes IRQ to unbind from.
--
1.7.4
-From dc5f219e88294b93009eef946251251ffffb6d60 Mon Sep 17 00:00:00 2001
-From: Thomas Gleixner <tglx(a)linutronix.de>
-Date: Fri, 4 Feb 2011 13:19:20 +0100
-Subject: [PATCH 146/244] genirq: Add IRQF_FORCE_RESUME
+From faf6ced2cde784ff515274f89278f222fefdb24a Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 24 Feb 2011 14:20:12 -0500
+Subject: [PATCH 168/203] xen/irq: Export 'xen_pirq_from_irq' function.
-Xen needs to reenable interrupts which are marked IRQF_NO_SUSPEND in the
-resume path. Add a flag to force the reenabling in the resume code.
+We need this to find the real Xen PIRQ value for a device
+that requests an MSI or MSI-X. In the past we used
+'xen_gsi_from_irq' since that function would return
+an Xen PIRQ or GSI depending on the provided IRQ. Now that
+we have seperated that we need to use the correct
+function.
-Tested-and-acked-by: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
-Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
+[v2: Deal with rebase on stable/irq.cleanup]
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- include/linux/interrupt.h | 3 ++-
- kernel/irq/manage.c | 11 ++++++++++-
- kernel/irq/pm.c | 3 ---
- 3 files changed, 12 insertions(+), 5 deletions(-)
+ drivers/xen/events.c | 6 ++++++
+ include/xen/events.h | 3 +++
+ 2 files changed, 9 insertions(+), 0 deletions(-)
-diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
-index 55e0d42..d746da1 100644
---- a/include/linux/interrupt.h
-+++ b/include/linux/interrupt.h
-@@ -55,7 +55,7 @@
- * Used by threaded interrupts which need to keep the
- * irq line disabled until the threaded handler has been run.
- * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
-- *
-+ * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
- */
- #define IRQF_DISABLED 0x00000020
- #define IRQF_SAMPLE_RANDOM 0x00000040
-@@ -67,6 +67,7 @@
- #define IRQF_IRQPOLL 0x00001000
- #define IRQF_ONESHOT 0x00002000
- #define IRQF_NO_SUSPEND 0x00004000
-+#define IRQF_FORCE_RESUME 0x00008000
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index f300265..e285c11 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -739,6 +739,12 @@ int xen_irq_from_pirq(unsigned pirq)
+ return pirq_to_irq[pirq];
+ }
- #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND)
++
++int xen_pirq_from_irq(unsigned irq)
++{
++ return pirq_from_irq(irq);
++}
++EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
+ int bind_evtchn_to_irq(unsigned int evtchn)
+ {
+ int irq;
+diff --git a/include/xen/events.h b/include/xen/events.h
+index 23de713..a0c8185 100644
+--- a/include/xen/events.h
++++ b/include/xen/events.h
+@@ -99,6 +99,9 @@ int xen_gsi_from_irq(unsigned pirq);
+ /* Return irq from pirq */
+ int xen_irq_from_pirq(unsigned pirq);
-diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
-index 0caa59f..b4198ee 100644
---- a/kernel/irq/manage.c
-+++ b/kernel/irq/manage.c
-@@ -282,8 +282,17 @@ EXPORT_SYMBOL(disable_irq);
++/* Return the pirq allocated to the irq. */
++int xen_pirq_from_irq(unsigned irq);
++
+ /* Determine whether to ignore this IRQ if it is passed to a guest. */
+ int xen_test_irq_shared(int irq);
- void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
- {
-- if (resume)
-+ if (resume) {
-+ if (!(desc->status & IRQ_SUSPENDED)) {
-+ if (!desc->action)
-+ return;
-+ if (!(desc->action->flags & IRQF_FORCE_RESUME))
-+ return;
-+ /* Pretend that it got disabled ! */
-+ desc->depth++;
+--
+1.7.4
+
+
+From 57d64e41477079960a5e2b5f5923121bd9118d47 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 16 Feb 2011 16:26:44 -0500
+Subject: [PATCH 169/203] xen/irq: The Xen hypervisor cleans up the PIRQs if the other
domain forgot.
+
+And if the other domain forgot to clean up its PIRQs we don't need
+to fail the operation. Just take a note of it and continue on.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/events.c | 9 ++++++++-
+ 1 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/events.c b/drivers/xen/events.c
+index e285c11..803c71a 100644
+--- a/drivers/xen/events.c
++++ b/drivers/xen/events.c
+@@ -708,7 +708,14 @@ int xen_destroy_irq(int irq)
+ unmap_irq.pirq = info->u.pirq.pirq;
+ unmap_irq.domid = info->u.pirq.domid;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
+- if (rc) {
++ /* If another domain quits without making the pci_disable_msix
++ * call, the Xen hypervisor takes care of freeing the PIRQs
++ * (free_domain_pirqs).
++ */
++ if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF))
++ printk(KERN_INFO "domain %d does not have %d anymore\n",
++ info->u.pirq.domid, info->u.pirq.pirq);
++ else if (rc) {
+ printk(KERN_WARNING "unmap irq failed %d\n", rc);
+ goto out;
+ }
+--
+1.7.4
+
+
+From 6d3057d191cd8cedae334c5182c06d2ceec7966e Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 13 Oct 2009 17:22:20 -0400
+Subject: [PATCH 170/203] xen-pciback: Initial copy from linux-2.6.18.hg off pciback
driver.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/pciback/Makefile | 17 +
+ drivers/xen/pciback/conf_space.c | 435 ++++++++
+ drivers/xen/pciback/conf_space.h | 126 +++
+ drivers/xen/pciback/conf_space_capability.c | 69 ++
+ drivers/xen/pciback/conf_space_capability.h | 23 +
+ drivers/xen/pciback/conf_space_capability_msi.c | 79 ++
+ drivers/xen/pciback/conf_space_capability_pm.c | 126 +++
+ drivers/xen/pciback/conf_space_capability_vpd.c | 40 +
+ drivers/xen/pciback/conf_space_header.c | 317 ++++++
+ drivers/xen/pciback/conf_space_quirks.c | 138 +++
+ drivers/xen/pciback/conf_space_quirks.h | 35 +
+ drivers/xen/pciback/controller.c | 443 ++++++++
+ drivers/xen/pciback/passthrough.c | 176 +++
+ drivers/xen/pciback/pci_stub.c | 1316 +++++++++++++++++++++++
+ drivers/xen/pciback/pciback.h | 126 +++
+ drivers/xen/pciback/pciback_ops.c | 134 +++
+ drivers/xen/pciback/slot.c | 187 ++++
+ drivers/xen/pciback/vpci.c | 242 +++++
+ drivers/xen/pciback/xenbus.c | 710 ++++++++++++
+ 19 files changed, 4739 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/xen/pciback/Makefile
+ create mode 100644 drivers/xen/pciback/conf_space.c
+ create mode 100644 drivers/xen/pciback/conf_space.h
+ create mode 100644 drivers/xen/pciback/conf_space_capability.c
+ create mode 100644 drivers/xen/pciback/conf_space_capability.h
+ create mode 100644 drivers/xen/pciback/conf_space_capability_msi.c
+ create mode 100644 drivers/xen/pciback/conf_space_capability_pm.c
+ create mode 100644 drivers/xen/pciback/conf_space_capability_vpd.c
+ create mode 100644 drivers/xen/pciback/conf_space_header.c
+ create mode 100644 drivers/xen/pciback/conf_space_quirks.c
+ create mode 100644 drivers/xen/pciback/conf_space_quirks.h
+ create mode 100644 drivers/xen/pciback/controller.c
+ create mode 100644 drivers/xen/pciback/passthrough.c
+ create mode 100644 drivers/xen/pciback/pci_stub.c
+ create mode 100644 drivers/xen/pciback/pciback.h
+ create mode 100644 drivers/xen/pciback/pciback_ops.c
+ create mode 100644 drivers/xen/pciback/slot.c
+ create mode 100644 drivers/xen/pciback/vpci.c
+ create mode 100644 drivers/xen/pciback/xenbus.c
+
+diff --git a/drivers/xen/pciback/Makefile b/drivers/xen/pciback/Makefile
+new file mode 100644
+index 0000000..106dae7
+--- /dev/null
++++ b/drivers/xen/pciback/Makefile
+@@ -0,0 +1,17 @@
++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
++
++pciback-y := pci_stub.o pciback_ops.o xenbus.o
++pciback-y += conf_space.o conf_space_header.o \
++ conf_space_capability.o \
++ conf_space_capability_vpd.o \
++ conf_space_capability_pm.o \
++ conf_space_quirks.o
++pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
++
++ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+diff --git a/drivers/xen/pciback/conf_space.c b/drivers/xen/pciback/conf_space.c
+new file mode 100644
+index 0000000..0c76db1
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space.c
+@@ -0,0 +1,435 @@
++/*
++ * PCI Backend - Functions for creating a virtual configuration space for
++ * exported PCI Devices.
++ * It's dangerous to allow PCI Driver Domains to change their
++ * device's resources (memory, i/o ports, interrupts). We need to
++ * restrict changes to certain PCI Configuration registers:
++ * BARs, INTERRUPT_PIN, most registers in the header...
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++static int permissive;
++module_param(permissive, bool, 0644);
++
++#define DEFINE_PCI_CONFIG(op,size,type) \
++int pciback_##op##_config_##size \
++(struct pci_dev *dev, int offset, type value, void *data) \
++{ \
++ return pci_##op##_config_##size (dev, offset, value); \
++}
++
++DEFINE_PCI_CONFIG(read, byte, u8 *)
++DEFINE_PCI_CONFIG(read, word, u16 *)
++DEFINE_PCI_CONFIG(read, dword, u32 *)
++
++DEFINE_PCI_CONFIG(write, byte, u8)
++DEFINE_PCI_CONFIG(write, word, u16)
++DEFINE_PCI_CONFIG(write, dword, u32)
++
++static int conf_space_read(struct pci_dev *dev,
++ const struct config_field_entry *entry,
++ int offset, u32 *value)
++{
++ int ret = 0;
++ const struct config_field *field = entry->field;
++
++ *value = 0;
++
++ switch (field->size) {
++ case 1:
++ if (field->u.b.read)
++ ret = field->u.b.read(dev, offset, (u8 *) value,
++ entry->data);
++ break;
++ case 2:
++ if (field->u.w.read)
++ ret = field->u.w.read(dev, offset, (u16 *) value,
++ entry->data);
++ break;
++ case 4:
++ if (field->u.dw.read)
++ ret = field->u.dw.read(dev, offset, value, entry->data);
++ break;
++ }
++ return ret;
++}
++
++static int conf_space_write(struct pci_dev *dev,
++ const struct config_field_entry *entry,
++ int offset, u32 value)
++{
++ int ret = 0;
++ const struct config_field *field = entry->field;
++
++ switch (field->size) {
++ case 1:
++ if (field->u.b.write)
++ ret = field->u.b.write(dev, offset, (u8) value,
++ entry->data);
++ break;
++ case 2:
++ if (field->u.w.write)
++ ret = field->u.w.write(dev, offset, (u16) value,
++ entry->data);
++ break;
++ case 4:
++ if (field->u.dw.write)
++ ret = field->u.dw.write(dev, offset, value,
++ entry->data);
++ break;
++ }
++ return ret;
++}
++
++static inline u32 get_mask(int size)
++{
++ if (size == 1)
++ return 0xff;
++ else if (size == 2)
++ return 0xffff;
++ else
++ return 0xffffffff;
++}
++
++static inline int valid_request(int offset, int size)
++{
++ /* Validate request (no un-aligned requests) */
++ if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
++ return 1;
++ return 0;
++}
++
++static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
++ int offset)
++{
++ if (offset >= 0) {
++ new_val_mask <<= (offset * 8);
++ new_val <<= (offset * 8);
++ } else {
++ new_val_mask >>= (offset * -8);
++ new_val >>= (offset * -8);
++ }
++ val = (val & ~new_val_mask) | (new_val & new_val_mask);
++
++ return val;
++}
++
++static int pcibios_err_to_errno(int err)
++{
++ switch (err) {
++ case PCIBIOS_SUCCESSFUL:
++ return XEN_PCI_ERR_success;
++ case PCIBIOS_DEVICE_NOT_FOUND:
++ return XEN_PCI_ERR_dev_not_found;
++ case PCIBIOS_BAD_REGISTER_NUMBER:
++ return XEN_PCI_ERR_invalid_offset;
++ case PCIBIOS_FUNC_NOT_SUPPORTED:
++ return XEN_PCI_ERR_not_implemented;
++ case PCIBIOS_SET_FAILED:
++ return XEN_PCI_ERR_access_denied;
++ }
++ return err;
++}
++
++int pciback_config_read(struct pci_dev *dev, int offset, int size,
++ u32 * ret_val)
++{
++ int err = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ const struct config_field_entry *cfg_entry;
++ const struct config_field *field;
++ int req_start, req_end, field_start, field_end;
++ /* if read fails for any reason, return 0 (as if device didn't respond) */
++ u32 value = 0, tmp_val;
++
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
++ pci_name(dev), size, offset);
++
++ if (!valid_request(offset, size)) {
++ err = XEN_PCI_ERR_invalid_offset;
++ goto out;
++ }
++
++ /* Get the real value first, then modify as appropriate */
++ switch (size) {
++ case 1:
++ err = pci_read_config_byte(dev, offset, (u8 *) & value);
++ break;
++ case 2:
++ err = pci_read_config_word(dev, offset, (u16 *) & value);
++ break;
++ case 4:
++ err = pci_read_config_dword(dev, offset, &value);
++ break;
++ }
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ req_start = offset;
++ req_end = offset + size;
++ field_start = OFFSET(cfg_entry);
++ field_end = OFFSET(cfg_entry) + field->size;
++
++ if ((req_start >= field_start && req_start < field_end)
++ || (req_end > field_start && req_end <= field_end)) {
++ err = conf_space_read(dev, cfg_entry, field_start,
++ &tmp_val);
++ if (err)
++ goto out;
++
++ value = merge_value(value, tmp_val,
++ get_mask(field->size),
++ field_start - req_start);
++ }
++ }
++
++ out:
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
++ pci_name(dev), size, offset, value);
++
++ *ret_val = value;
++ return pcibios_err_to_errno(err);
++}
++
++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
++{
++ int err = 0, handled = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ const struct config_field_entry *cfg_entry;
++ const struct config_field *field;
++ u32 tmp_val;
++ int req_start, req_end, field_start, field_end;
++
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG
++ "pciback: %s: write request %d bytes at 0x%x = %x\n",
++ pci_name(dev), size, offset, value);
++
++ if (!valid_request(offset, size))
++ return XEN_PCI_ERR_invalid_offset;
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ req_start = offset;
++ req_end = offset + size;
++ field_start = OFFSET(cfg_entry);
++ field_end = OFFSET(cfg_entry) + field->size;
++
++ if ((req_start >= field_start && req_start < field_end)
++ || (req_end > field_start && req_end <= field_end)) {
++ tmp_val = 0;
++
++ err = pciback_config_read(dev, field_start,
++ field->size, &tmp_val);
++ if (err)
++ break;
++
++ tmp_val = merge_value(tmp_val, value, get_mask(size),
++ req_start - field_start);
++
++ err = conf_space_write(dev, cfg_entry, field_start,
++ tmp_val);
++
++ /* handled is set true here, but not every byte
++ * may have been written! Properly detecting if
++ * every byte is handled is unnecessary as the
++ * flag is used to detect devices that need
++ * special helpers to work correctly.
++ */
++ handled = 1;
++ }
++ }
++
++ if (!handled && !err) {
++ /* By default, anything not specificially handled above is
++ * read-only. The permissive flag changes this behavior so
++ * that anything not specifically handled above is writable.
++ * This means that some fields may still be read-only because
++ * they have entries in the config_field list that intercept
++ * the write and do nothing. */
++ if (dev_data->permissive || permissive) {
++ switch (size) {
++ case 1:
++ err = pci_write_config_byte(dev, offset,
++ (u8) value);
++ break;
++ case 2:
++ err = pci_write_config_word(dev, offset,
++ (u16) value);
++ break;
++ case 4:
++ err = pci_write_config_dword(dev, offset,
++ (u32) value);
++ break;
++ }
++ } else if (!dev_data->warned_on_write) {
++ dev_data->warned_on_write = 1;
++ dev_warn(&dev->dev, "Driver tried to write to a "
++ "read-only configuration space field at offset "
++ "0x%x, size %d. This may be harmless, but if "
++ "you have problems with your device:\n"
++ "1) see permissive attribute in sysfs\n"
++ "2) report problems to the xen-devel "
++ "mailing list along with details of your "
++ "device obtained from lspci.\n", offset, size);
++ }
++ }
++
++ return pcibios_err_to_errno(err);
++}
++
++void pciback_config_free_dyn_fields(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry, *t;
++ const struct config_field *field;
++
++ dev_dbg(&dev->dev,
++ "free-ing dynamically allocated virtual configuration space fields\n");
++ if (!dev_data)
++ return;
++
++ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ if (field->clean) {
++ field->clean((struct config_field *)field);
++
++ if (cfg_entry->data)
++ kfree(cfg_entry->data);
++
++ list_del(&cfg_entry->list);
++ kfree(cfg_entry);
++ }
++
++ }
++}
++
++void pciback_config_reset_dev(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ const struct config_field_entry *cfg_entry;
++ const struct config_field *field;
++
++ dev_dbg(&dev->dev, "resetting virtual configuration space\n");
++ if (!dev_data)
++ return;
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++
++ if (field->reset)
++ field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
++ }
++}
++
++void pciback_config_free_dev(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry, *t;
++ const struct config_field *field;
++
++ dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
++ if (!dev_data)
++ return;
++
++ list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
++ list_del(&cfg_entry->list);
++
++ field = cfg_entry->field;
++
++ if (field->release)
++ field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
++
++ kfree(cfg_entry);
++ }
++}
++
++int pciback_config_add_field_offset(struct pci_dev *dev,
++ const struct config_field *field,
++ unsigned int base_offset)
++{
++ int err = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry;
++ void *tmp;
++
++ cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
++ if (!cfg_entry) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ cfg_entry->data = NULL;
++ cfg_entry->field = field;
++ cfg_entry->base_offset = base_offset;
++
++ /* silently ignore duplicate fields */
++ err = pciback_field_is_dup(dev,OFFSET(cfg_entry));
++ if (err)
++ goto out;
++
++ if (field->init) {
++ tmp = field->init(dev, OFFSET(cfg_entry));
++
++ if (IS_ERR(tmp)) {
++ err = PTR_ERR(tmp);
++ goto out;
++ }
++
++ cfg_entry->data = tmp;
++ }
++
++ dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
++ OFFSET(cfg_entry));
++ list_add_tail(&cfg_entry->list, &dev_data->config_fields);
++
++ out:
++ if (err)
++ kfree(cfg_entry);
++
++ return err;
++}
++
++/* This sets up the device's virtual configuration space to keep track of
++ * certain registers (like the base address registers (BARs) so that we can
++ * keep the client from manipulating them directly.
++ */
++int pciback_config_init_dev(struct pci_dev *dev)
++{
++ int err = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++
++ dev_dbg(&dev->dev, "initializing virtual configuration space\n");
++
++ INIT_LIST_HEAD(&dev_data->config_fields);
++
++ err = pciback_config_header_add_fields(dev);
++ if (err)
++ goto out;
++
++ err = pciback_config_capability_add_fields(dev);
++ if (err)
++ goto out;
++
++ err = pciback_config_quirks_init(dev);
++
++ out:
++ return err;
++}
++
++int pciback_config_init(void)
++{
++ return pciback_config_capability_init();
++}
+diff --git a/drivers/xen/pciback/conf_space.h b/drivers/xen/pciback/conf_space.h
+new file mode 100644
+index 0000000..fe746ef
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space.h
+@@ -0,0 +1,126 @@
++/*
++ * PCI Backend - Common data structures for overriding the configuration space
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#ifndef __XEN_PCIBACK_CONF_SPACE_H__
++#define __XEN_PCIBACK_CONF_SPACE_H__
++
++#include <linux/list.h>
++#include <linux/err.h>
++
++/* conf_field_init can return an errno in a ptr with ERR_PTR() */
++typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
++typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
++typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
++
++typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
++ void *data);
++typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
++ void *data);
++typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
++ void *data);
++typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
++ void *data);
++typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
++ void *data);
++typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
++ void *data);
++
++/* These are the fields within the configuration space which we
++ * are interested in intercepting reads/writes to and changing their
++ * values.
++ */
++struct config_field {
++ unsigned int offset;
++ unsigned int size;
++ unsigned int mask;
++ conf_field_init init;
++ conf_field_reset reset;
++ conf_field_free release;
++ void (*clean) (struct config_field * field);
++ union {
++ struct {
++ conf_dword_write write;
++ conf_dword_read read;
++ } dw;
++ struct {
++ conf_word_write write;
++ conf_word_read read;
++ } w;
++ struct {
++ conf_byte_write write;
++ conf_byte_read read;
++ } b;
++ } u;
++ struct list_head list;
++};
++
++struct config_field_entry {
++ struct list_head list;
++ const struct config_field *field;
++ unsigned int base_offset;
++ void *data;
++};
++
++#define OFFSET(cfg_entry)
((cfg_entry)->base_offset+(cfg_entry)->field->offset)
++
++/* Add fields to a device - the add_fields macro expects to get a pointer to
++ * the first entry in an array (of which the ending is marked by size==0)
++ */
++int pciback_config_add_field_offset(struct pci_dev *dev,
++ const struct config_field *field,
++ unsigned int offset);
++
++static inline int pciback_config_add_field(struct pci_dev *dev,
++ const struct config_field *field)
++{
++ return pciback_config_add_field_offset(dev, field, 0);
++}
++
++static inline int pciback_config_add_fields(struct pci_dev *dev,
++ const struct config_field *field)
++{
++ int i, err = 0;
++ for (i = 0; field[i].size != 0; i++) {
++ err = pciback_config_add_field(dev, &field[i]);
++ if (err)
++ break;
++ }
++ return err;
++}
++
++static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
++ const struct config_field *field,
++ unsigned int offset)
++{
++ int i, err = 0;
++ for (i = 0; field[i].size != 0; i++) {
++ err = pciback_config_add_field_offset(dev, &field[i], offset);
++ if (err)
++ break;
++ }
++ return err;
++}
++
++/* Read/Write the real configuration space */
++int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
++ void *data);
++int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
++ void *data);
++int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
++ void *data);
++int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
++ void *data);
++int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
++ void *data);
++int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
++ void *data);
++
++int pciback_config_capability_init(void);
++
++int pciback_config_header_add_fields(struct pci_dev *dev);
++int pciback_config_capability_add_fields(struct pci_dev *dev);
++
++#endif /* __XEN_PCIBACK_CONF_SPACE_H__ */
+diff --git a/drivers/xen/pciback/conf_space_capability.c
b/drivers/xen/pciback/conf_space_capability.c
+new file mode 100644
+index 0000000..50efca4
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_capability.c
+@@ -0,0 +1,69 @@
++/*
++ * PCI Backend - Handles the virtual fields found on the capability lists
++ * in the configuration space.
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static LIST_HEAD(capabilities);
++
++static const struct config_field caplist_header[] = {
++ {
++ .offset = PCI_CAP_LIST_ID,
++ .size = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = NULL,
++ },
++ {}
++};
++
++static inline void register_capability(struct pciback_config_capability *cap)
++{
++ list_add_tail(&cap->cap_list, &capabilities);
++}
++
++int pciback_config_capability_add_fields(struct pci_dev *dev)
++{
++ int err = 0;
++ struct pciback_config_capability *cap;
++ int cap_offset;
++
++ list_for_each_entry(cap, &capabilities, cap_list) {
++ cap_offset = pci_find_capability(dev, cap->capability);
++ if (cap_offset) {
++ dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n",
++ cap->capability, cap_offset);
++
++ err = pciback_config_add_fields_offset(dev,
++ caplist_header,
++ cap_offset);
++ if (err)
++ goto out;
++ err = pciback_config_add_fields_offset(dev,
++ cap->fields,
++ cap_offset);
++ if (err)
++ goto out;
++ }
++ }
++
++ out:
++ return err;
++}
++
++extern struct pciback_config_capability pciback_config_capability_vpd;
++extern struct pciback_config_capability pciback_config_capability_pm;
++
++int pciback_config_capability_init(void)
++{
++ register_capability(&pciback_config_capability_vpd);
++ register_capability(&pciback_config_capability_pm);
++
++ return 0;
++}
+diff --git a/drivers/xen/pciback/conf_space_capability.h
b/drivers/xen/pciback/conf_space_capability.h
+new file mode 100644
+index 0000000..823392e
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_capability.h
+@@ -0,0 +1,23 @@
++/*
++ * PCI Backend - Data structures for special overlays for structures on
++ * the capability list.
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#ifndef __PCIBACK_CONFIG_CAPABILITY_H__
++#define __PCIBACK_CONFIG_CAPABILITY_H__
++
++#include <linux/pci.h>
++#include <linux/list.h>
++
++struct pciback_config_capability {
++ struct list_head cap_list;
++
++ int capability;
++
++ /* If the device has the capability found above, add these fields */
++ const struct config_field *fields;
++};
++
++#endif
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+new file mode 100644
+index 0000000..762e396
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -0,0 +1,79 @@
++/*
++ * PCI Backend -- Configuration overlay for MSI capability
++ */
++#include <linux/pci.h>
++#include <linux/slab.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++#include <xen/interface/io/pciif.h>
++#include "pciback.h"
++
++int pciback_enable_msi(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op)
++{
++ int otherend = pdev->xdev->otherend_id;
++ int status;
++
++ status = pci_enable_msi(dev);
++
++ if (status) {
++ printk("error enable msi for guest %x status %x\n", otherend, status);
++ op->value = 0;
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ op->value = dev->irq;
++ return 0;
++}
++
++int pciback_disable_msi(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op)
++{
++ pci_disable_msi(dev);
++
++ op->value = dev->irq;
++ return 0;
++}
++
++int pciback_enable_msix(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op)
++{
++ int i, result;
++ struct msix_entry *entries;
++
++ if (op->value > SH_INFO_MAX_VEC)
++ return -EINVAL;
++
++ entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
++ if (entries == NULL)
++ return -ENOMEM;
++
++ for (i = 0; i < op->value; i++) {
++ entries[i].entry = op->msix_entries[i].entry;
++ entries[i].vector = op->msix_entries[i].vector;
++ }
++
++ result = pci_enable_msix(dev, entries, op->value);
++
++ for (i = 0; i < op->value; i++) {
++ op->msix_entries[i].entry = entries[i].entry;
++ op->msix_entries[i].vector = entries[i].vector;
++ }
++
++ kfree(entries);
++
++ op->value = result;
++
++ return result;
++}
++
++int pciback_disable_msix(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op)
++{
++
++ pci_disable_msix(dev);
++
++ op->value = dev->irq;
++ return 0;
++}
++
+diff --git a/drivers/xen/pciback/conf_space_capability_pm.c
b/drivers/xen/pciback/conf_space_capability_pm.c
+new file mode 100644
+index 0000000..e2f99c7
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_capability_pm.c
+@@ -0,0 +1,126 @@
++/*
++ * PCI Backend - Configuration space overlay for power management
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
++ void *data)
++{
++ int err;
++ u16 real_value;
++
++ err = pci_read_config_word(dev, offset, &real_value);
++ if (err)
++ goto out;
++
++ *value = real_value & ~PCI_PM_CAP_PME_MASK;
++
++ out:
++ return err;
++}
++
++/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
++ * Can't allow driver domain to enable PMEs - they're shared */
++#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
++
++static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
++ void *data)
++{
++ int err;
++ u16 old_value;
++ pci_power_t new_state, old_state;
++
++ err = pci_read_config_word(dev, offset, &old_value);
++ if (err)
++ goto out;
++
++ old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
++ new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
++
++ new_value &= PM_OK_BITS;
++ if ((old_value & PM_OK_BITS) != new_value) {
++ new_value = (old_value & ~PM_OK_BITS) | new_value;
++ err = pci_write_config_word(dev, offset, new_value);
++ if (err)
++ goto out;
++ }
++
++ /* Let pci core handle the power management change */
++ dev_dbg(&dev->dev, "set power state to %x\n", new_state);
++ err = pci_set_power_state(dev, new_state);
++ if (err) {
++ err = PCIBIOS_SET_FAILED;
++ goto out;
++ }
++
++ /*
++ * Device may lose PCI config info on D3->D0 transition. This
++ * is a problem for some guests which will not reset BARs. Even
++ * those that have a go will be foiled by our BAR-write handler
++ * which will discard the write! Since Linux won't re-init
++ * the config space automatically in all cases, we do it here.
++ * Future: Should we re-initialise all first 64 bytes of config space?
++ */
++ if (new_state == PCI_D0 &&
++ (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
++ !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
++ pci_restore_bars(dev);
++
++ out:
++ return err;
++}
++
++/* Ensure PMEs are disabled */
++static void *pm_ctrl_init(struct pci_dev *dev, int offset)
++{
++ int err;
++ u16 value;
++
++ err = pci_read_config_word(dev, offset, &value);
++ if (err)
++ goto out;
++
++ if (value & PCI_PM_CTRL_PME_ENABLE) {
++ value &= ~PCI_PM_CTRL_PME_ENABLE;
++ err = pci_write_config_word(dev, offset, value);
++ }
++
++ out:
++ return ERR_PTR(err);
++}
++
++static const struct config_field caplist_pm[] = {
++ {
++ .offset = PCI_PM_PMC,
++ .size = 2,
++ .u.w.read = pm_caps_read,
++ },
++ {
++ .offset = PCI_PM_CTRL,
++ .size = 2,
++ .init = pm_ctrl_init,
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = pm_ctrl_write,
++ },
++ {
++ .offset = PCI_PM_PPB_EXTENSIONS,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ .offset = PCI_PM_DATA_REGISTER,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {}
++};
++
++struct pciback_config_capability pciback_config_capability_pm = {
++ .capability = PCI_CAP_ID_PM,
++ .fields = caplist_pm,
++};
+diff --git a/drivers/xen/pciback/conf_space_capability_vpd.c
b/drivers/xen/pciback/conf_space_capability_vpd.c
+new file mode 100644
+index 0000000..920cb4a
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_capability_vpd.c
+@@ -0,0 +1,40 @@
++/*
++ * PCI Backend - Configuration space overlay for Vital Product Data
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static int vpd_address_write(struct pci_dev *dev, int offset, u16 value,
++ void *data)
++{
++ /* Disallow writes to the vital product data */
++ if (value & PCI_VPD_ADDR_F)
++ return PCIBIOS_SET_FAILED;
++ else
++ return pci_write_config_word(dev, offset, value);
++}
++
++static const struct config_field caplist_vpd[] = {
++ {
++ .offset = PCI_VPD_ADDR,
++ .size = 2,
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = vpd_address_write,
++ },
++ {
++ .offset = PCI_VPD_DATA,
++ .size = 4,
++ .u.dw.read = pciback_read_config_dword,
++ .u.dw.write = NULL,
++ },
++ {}
++};
++
++struct pciback_config_capability pciback_config_capability_vpd = {
++ .capability = PCI_CAP_ID_VPD,
++ .fields = caplist_vpd,
++};
+diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
+new file mode 100644
+index 0000000..f794e12
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_header.c
+@@ -0,0 +1,317 @@
++/*
++ * PCI Backend - Handles the virtual fields in the configuration space headers.
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++
++struct pci_bar_info {
++ u32 val;
++ u32 len_val;
++ int which;
++};
++
++#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
++#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
++
++static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
++{
++ int err;
++
++ if (!dev->is_enabled && is_enable_cmd(value)) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: enable\n",
++ pci_name(dev));
++ err = pci_enable_device(dev);
++ if (err)
++ return err;
++ } else if (dev->is_enabled && !is_enable_cmd(value)) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: disable\n",
++ pci_name(dev));
++ pci_disable_device(dev);
++ }
++
++ if (!dev->is_busmaster && is_master_cmd(value)) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: set bus master\n",
++ pci_name(dev));
++ pci_set_master(dev);
++ }
++
++ if (value & PCI_COMMAND_INVALIDATE) {
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG
++ "pciback: %s: enable memory-write-invalidate\n",
++ pci_name(dev));
++ err = pci_set_mwi(dev);
++ if (err) {
++ printk(KERN_WARNING
++ "pciback: %s: cannot enable memory-write-invalidate (%d)\n",
++ pci_name(dev), err);
++ value &= ~PCI_COMMAND_INVALIDATE;
++ }
++ }
++
++ return pci_write_config_word(dev, offset, value);
++}
++
++static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ if (unlikely(!bar)) {
++ printk(KERN_WARNING "pciback: driver data not found for %s\n",
++ pci_name(dev));
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ /* A write to obtain the length must happen as a 32-bit write.
++ * This does not (yet) support writing individual bytes
++ */
++ if (value == ~PCI_ROM_ADDRESS_ENABLE)
++ bar->which = 1;
++ else {
++ u32 tmpval;
++ pci_read_config_dword(dev, offset, &tmpval);
++ if (tmpval != bar->val && value == bar->val) {
++ /* Allow restoration of bar value. */
++ pci_write_config_dword(dev, offset, bar->val);
++ }
++ bar->which = 0;
++ }
++
++ /* Do we need to support enabling/disabling the rom address here? */
++
++ return 0;
++}
++
++/* For the BARs, only allow writes which write ~0 or
++ * the correct resource information
++ * (Needed for when the driver probes the resource usage)
++ */
++static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ if (unlikely(!bar)) {
++ printk(KERN_WARNING "pciback: driver data not found for %s\n",
++ pci_name(dev));
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ /* A write to obtain the length must happen as a 32-bit write.
++ * This does not (yet) support writing individual bytes
++ */
++ if (value == ~0)
++ bar->which = 1;
++ else {
++ u32 tmpval;
++ pci_read_config_dword(dev, offset, &tmpval);
++ if (tmpval != bar->val && value == bar->val) {
++ /* Allow restoration of bar value. */
++ pci_write_config_dword(dev, offset, bar->val);
++ }
++ bar->which = 0;
++ }
++
++ return 0;
++}
++
++static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ if (unlikely(!bar)) {
++ printk(KERN_WARNING "pciback: driver data not found for %s\n",
++ pci_name(dev));
++ return XEN_PCI_ERR_op_failed;
++ }
++
++ *value = bar->which ? bar->len_val : bar->val;
++
++ return 0;
++}
++
++static inline void read_dev_bar(struct pci_dev *dev,
++ struct pci_bar_info *bar_info, int offset,
++ u32 len_mask)
++{
++ pci_read_config_dword(dev, offset, &bar_info->val);
++ pci_write_config_dword(dev, offset, len_mask);
++ pci_read_config_dword(dev, offset, &bar_info->len_val);
++ pci_write_config_dword(dev, offset, bar_info->val);
++}
++
++static void *bar_init(struct pci_dev *dev, int offset)
++{
++ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++
++ if (!bar)
++ return ERR_PTR(-ENOMEM);
++
++ read_dev_bar(dev, bar, offset, ~0);
++ bar->which = 0;
++
++ return bar;
++}
++
++static void *rom_init(struct pci_dev *dev, int offset)
++{
++ struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++
++ if (!bar)
++ return ERR_PTR(-ENOMEM);
++
++ read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
++ bar->which = 0;
++
++ return bar;
++}
++
++static void bar_reset(struct pci_dev *dev, int offset, void *data)
++{
++ struct pci_bar_info *bar = data;
++
++ bar->which = 0;
++}
++
++static void bar_release(struct pci_dev *dev, int offset, void *data)
++{
++ kfree(data);
++}
++
++static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
++ void *data)
++{
++ *value = (u8) dev->irq;
++
++ return 0;
++}
++
++static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
++{
++ u8 cur_value;
++ int err;
++
++ err = pci_read_config_byte(dev, offset, &cur_value);
++ if (err)
++ goto out;
++
++ if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
++ || value == PCI_BIST_START)
++ err = pci_write_config_byte(dev, offset, value);
++
++ out:
++ return err;
++}
++
++static const struct config_field header_common[] = {
++ {
++ .offset = PCI_COMMAND,
++ .size = 2,
++ .u.w.read = pciback_read_config_word,
++ .u.w.write = command_write,
++ },
++ {
++ .offset = PCI_INTERRUPT_LINE,
++ .size = 1,
++ .u.b.read = interrupt_read,
++ },
++ {
++ .offset = PCI_INTERRUPT_PIN,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ /* Any side effects of letting driver domain control cache line? */
++ .offset = PCI_CACHE_LINE_SIZE,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ .u.b.write = pciback_write_config_byte,
++ },
++ {
++ .offset = PCI_LATENCY_TIMER,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ },
++ {
++ .offset = PCI_BIST,
++ .size = 1,
++ .u.b.read = pciback_read_config_byte,
++ .u.b.write = bist_write,
++ },
++ {}
++};
++
++#define CFG_FIELD_BAR(reg_offset) \
++ { \
++ .offset = reg_offset, \
++ .size = 4, \
++ .init = bar_init, \
++ .reset = bar_reset, \
++ .release = bar_release, \
++ .u.dw.read = bar_read, \
++ .u.dw.write = bar_write, \
++ }
++
++#define CFG_FIELD_ROM(reg_offset) \
++ { \
++ .offset = reg_offset, \
++ .size = 4, \
++ .init = rom_init, \
++ .reset = bar_reset, \
++ .release = bar_release, \
++ .u.dw.read = bar_read, \
++ .u.dw.write = rom_write, \
++ }
++
++static const struct config_field header_0[] = {
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
++ CFG_FIELD_ROM(PCI_ROM_ADDRESS),
++ {}
++};
++
++static const struct config_field header_1[] = {
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
++ CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
++ CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
++ {}
++};
++
++int pciback_config_header_add_fields(struct pci_dev *dev)
++{
++ int err;
++
++ err = pciback_config_add_fields(dev, header_common);
++ if (err)
++ goto out;
++
++ switch (dev->hdr_type) {
++ case PCI_HEADER_TYPE_NORMAL:
++ err = pciback_config_add_fields(dev, header_0);
++ break;
++
++ case PCI_HEADER_TYPE_BRIDGE:
++ err = pciback_config_add_fields(dev, header_1);
++ break;
++
++ default:
++ err = -EINVAL;
++ printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
++ pci_name(dev), dev->hdr_type);
++ break;
++ }
++
++ out:
++ return err;
++}
+diff --git a/drivers/xen/pciback/conf_space_quirks.c
b/drivers/xen/pciback/conf_space_quirks.c
+new file mode 100644
+index 0000000..244a438
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_quirks.c
+@@ -0,0 +1,138 @@
++/*
++ * PCI Backend - Handle special overlays for broken devices.
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ * Author: Chris Bookholt <hap10(a)epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++LIST_HEAD(pciback_quirks);
++
++static inline const struct pci_device_id *
++match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
++{
++ if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
++ (id->device == PCI_ANY_ID || id->device == dev->device) &&
++ (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor)
&&
++ (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device)
&&
++ !((id->class ^ dev->class) & id->class_mask))
++ return id;
++ return NULL;
++}
++
++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
++{
++ struct pciback_config_quirk *tmp_quirk;
++
++ list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list)
++ if (match_one_device(&tmp_quirk->devid, dev) != NULL)
++ goto out;
++ tmp_quirk = NULL;
++ printk(KERN_DEBUG
++ "quirk didn't match any device pciback knows about\n");
++ out:
++ return tmp_quirk;
++}
++
++static inline void register_quirk(struct pciback_config_quirk *quirk)
++{
++ list_add_tail(&quirk->quirks_list, &pciback_quirks);
++}
++
++int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg)
++{
++ int ret = 0;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++ struct config_field_entry *cfg_entry;
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ if ( OFFSET(cfg_entry) == reg) {
++ ret = 1;
++ break;
++ }
++ }
++ return ret;
++}
++
++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
++ *field)
++{
++ int err = 0;
++
++ switch (field->size) {
++ case 1:
++ field->u.b.read = pciback_read_config_byte;
++ field->u.b.write = pciback_write_config_byte;
++ break;
++ case 2:
++ field->u.w.read = pciback_read_config_word;
++ field->u.w.write = pciback_write_config_word;
++ break;
++ case 4:
++ field->u.dw.read = pciback_read_config_dword;
++ field->u.dw.write = pciback_write_config_dword;
++ break;
++ default:
++ err = -EINVAL;
++ goto out;
++ }
++
++ pciback_config_add_field(dev, field);
++
++ out:
++ return err;
++}
++
++int pciback_config_quirks_init(struct pci_dev *dev)
++{
++ struct pciback_config_quirk *quirk;
++ int ret = 0;
++
++ quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC);
++ if (!quirk) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ quirk->devid.vendor = dev->vendor;
++ quirk->devid.device = dev->device;
++ quirk->devid.subvendor = dev->subsystem_vendor;
++ quirk->devid.subdevice = dev->subsystem_device;
++ quirk->devid.class = 0;
++ quirk->devid.class_mask = 0;
++ quirk->devid.driver_data = 0UL;
++
++ quirk->pdev = dev;
++
++ register_quirk(quirk);
++ out:
++ return ret;
++}
++
++void pciback_config_field_free(struct config_field *field)
++{
++ kfree(field);
++}
++
++int pciback_config_quirk_release(struct pci_dev *dev)
++{
++ struct pciback_config_quirk *quirk;
++ int ret = 0;
++
++ quirk = pciback_find_quirk(dev);
++ if (!quirk) {
++ ret = -ENXIO;
++ goto out;
++ }
++
++ list_del(&quirk->quirks_list);
++ kfree(quirk);
++
++ out:
++ return ret;
++}
+diff --git a/drivers/xen/pciback/conf_space_quirks.h
b/drivers/xen/pciback/conf_space_quirks.h
+new file mode 100644
+index 0000000..acd0e1a
+--- /dev/null
++++ b/drivers/xen/pciback/conf_space_quirks.h
+@@ -0,0 +1,35 @@
++/*
++ * PCI Backend - Data structures for special overlays for broken devices.
++ *
++ * Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ * Chris Bookholt <hap10(a)epoch.ncsc.mil>
++ */
++
++#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++
++#include <linux/pci.h>
++#include <linux/list.h>
++
++struct pciback_config_quirk {
++ struct list_head quirks_list;
++ struct pci_device_id devid;
++ struct pci_dev *pdev;
++};
++
++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev);
++
++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
++ *field);
++
++int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg);
++
++int pciback_config_quirks_init(struct pci_dev *dev);
++
++void pciback_config_field_free(struct config_field *field);
++
++int pciback_config_quirk_release(struct pci_dev *dev);
++
++int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg);
++
++#endif
+diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
+new file mode 100644
+index 0000000..294e48f
+--- /dev/null
++++ b/drivers/xen/pciback/controller.c
+@@ -0,0 +1,443 @@
++/*
++ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
++ * Alex Williamson <alex.williamson(a)hp.com>
++ *
++ * PCI "Controller" Backend - virtualize PCI bus topology based on PCI
++ * controllers. Devices under the same PCI controller are exposed on the
++ * same virtual domain:bus. Within a bus, device slots are virtualized
++ * to compact the bus.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++
++#include <linux/acpi.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++#define PCI_MAX_BUSSES 255
++#define PCI_MAX_SLOTS 32
++
++struct controller_dev_entry {
++ struct list_head list;
++ struct pci_dev *dev;
++ unsigned int devfn;
++};
++
++struct controller_list_entry {
++ struct list_head list;
++ struct pci_controller *controller;
++ unsigned int domain;
++ unsigned int bus;
++ unsigned int next_devfn;
++ struct list_head dev_list;
++};
++
++struct controller_dev_data {
++ struct list_head list;
++ unsigned int next_domain;
++ unsigned int next_bus;
++ spinlock_t lock;
++};
++
++struct walk_info {
++ struct pciback_device *pdev;
++ int resource_count;
++ int root_num;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct controller_dev_data *dev_data = pdev->pci_dev_data;
++ struct controller_dev_entry *dev_entry;
++ struct controller_list_entry *cntrl_entry;
++ struct pci_dev *dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++ if (cntrl_entry->domain != domain ||
++ cntrl_entry->bus != bus)
++ continue;
++
++ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
++ if (devfn == dev_entry->devfn) {
++ dev = dev_entry->dev;
++ goto found;
++ }
++ }
++ }
++found:
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++ int devid, publish_pci_dev_cb publish_cb)
++{
++ struct controller_dev_data *dev_data = pdev->pci_dev_data;
++ struct controller_dev_entry *dev_entry;
++ struct controller_list_entry *cntrl_entry;
++ struct pci_controller *dev_controller = PCI_CONTROLLER(dev);
++ unsigned long flags;
++ int ret = 0, found = 0;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ /* Look to see if we already have a domain:bus for this controller */
++ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++ if (cntrl_entry->controller == dev_controller) {
++ found = 1;
++ break;
++ }
++ }
++
++ if (!found) {
++ cntrl_entry = kmalloc(sizeof(*cntrl_entry), GFP_ATOMIC);
++ if (!cntrl_entry) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ cntrl_entry->controller = dev_controller;
++ cntrl_entry->next_devfn = PCI_DEVFN(0, 0);
++
++ cntrl_entry->domain = dev_data->next_domain;
++ cntrl_entry->bus = dev_data->next_bus++;
++ if (dev_data->next_bus > PCI_MAX_BUSSES) {
++ dev_data->next_domain++;
++ dev_data->next_bus = 0;
++ }
++
++ INIT_LIST_HEAD(&cntrl_entry->dev_list);
++
++ list_add_tail(&cntrl_entry->list, &dev_data->list);
++ }
++
++ if (PCI_SLOT(cntrl_entry->next_devfn) > PCI_MAX_SLOTS) {
++ /*
++ * While it seems unlikely, this can actually happen if
++ * a controller has P2P bridges under it.
++ */
++ xenbus_dev_fatal(pdev->xdev, -ENOSPC, "Virtual bus %04x:%02x "
++ "is full, no room to export %04x:%02x:%02x.%x",
++ cntrl_entry->domain, cntrl_entry->bus,
++ pci_domain_nr(dev->bus), dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++ ret = -ENOSPC;
++ goto out;
++ }
++
++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_ATOMIC);
++ if (!dev_entry) {
++ if (list_empty(&cntrl_entry->dev_list)) {
++ list_del(&cntrl_entry->list);
++ kfree(cntrl_entry);
++ }
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ dev_entry->dev = dev;
++ dev_entry->devfn = cntrl_entry->next_devfn;
++
++ list_add_tail(&dev_entry->list, &cntrl_entry->dev_list);
++
++ cntrl_entry->next_devfn += PCI_DEVFN(1, 0);
++
++out:
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ /* TODO: Publish virtual domain:bus:slot.func here. */
++
++ return ret;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ struct controller_dev_data *dev_data = pdev->pci_dev_data;
++ struct controller_list_entry *cntrl_entry;
++ struct controller_dev_entry *dev_entry = NULL;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++ if (cntrl_entry->controller != PCI_CONTROLLER(dev))
++ continue;
++
++ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
++ if (dev_entry->dev == dev) {
++ found_dev = dev_entry->dev;
++ break;
++ }
++ }
++ }
++
++ if (!found_dev) {
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++ return;
++ }
++
++ list_del(&dev_entry->list);
++ kfree(dev_entry);
++
++ if (list_empty(&cntrl_entry->dev_list)) {
++ list_del(&cntrl_entry->list);
++ kfree(cntrl_entry);
++ }
++
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ struct controller_dev_data *dev_data;
++
++ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
++ if (!dev_data)
++ return -ENOMEM;
++
++ spin_lock_init(&dev_data->lock);
++
++ INIT_LIST_HEAD(&dev_data->list);
++
++ /* Starting domain:bus numbers */
++ dev_data->next_domain = 0;
++ dev_data->next_bus = 0;
++
++ pdev->pci_dev_data = dev_data;
++
++ return 0;
++}
++
++static acpi_status write_xenbus_resource(struct acpi_resource *res, void *data)
++{
++ struct walk_info *info = data;
++ struct acpi_resource_address64 addr;
++ acpi_status status;
++ int i, len, err;
++ char str[32], tmp[3];
++ unsigned char *ptr, *buf;
++
++ status = acpi_resource_to_address64(res, &addr);
++
++ /* Do we care about this range? Let's check. */
++ if (!ACPI_SUCCESS(status) ||
++ !(addr.resource_type == ACPI_MEMORY_RANGE ||
++ addr.resource_type == ACPI_IO_RANGE) ||
++ !addr.address_length || addr.producer_consumer != ACPI_PRODUCER)
++ return AE_OK;
++
++ /*
++ * Furthermore, we really only care to tell the guest about
++ * address ranges that require address translation of some sort.
++ */
++ if (!(addr.resource_type == ACPI_MEMORY_RANGE &&
++ addr.info.mem.translation) &&
++ !(addr.resource_type == ACPI_IO_RANGE &&
++ addr.info.io.translation))
++ return AE_OK;
++
++ /* Store the resource in xenbus for the guest */
++ len = snprintf(str, sizeof(str), "root-%d-resource-%d",
++ info->root_num, info->resource_count);
++ if (unlikely(len >= (sizeof(str) - 1)))
++ return AE_OK;
++
++ buf = kzalloc((sizeof(*res) * 2) + 1, GFP_KERNEL);
++ if (!buf)
++ return AE_OK;
++
++ /* Clean out resource_source */
++ res->data.address64.resource_source.index = 0xFF;
++ res->data.address64.resource_source.string_length = 0;
++ res->data.address64.resource_source.string_ptr = NULL;
++
++ ptr = (unsigned char *)res;
++
++ /* Turn the acpi_resource into an ASCII byte stream */
++ for (i = 0; i < sizeof(*res); i++) {
++ snprintf(tmp, sizeof(tmp), "%02x", ptr[i]);
++ strncat(buf, tmp, 2);
++ }
++
++ err = xenbus_printf(XBT_NIL, info->pdev->xdev->nodename,
++ str, "%s", buf);
++
++ if (!err)
++ info->resource_count++;
++
++ kfree(buf);
++
++ return AE_OK;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_root_cb)
++{
++ struct controller_dev_data *dev_data = pdev->pci_dev_data;
++ struct controller_list_entry *cntrl_entry;
++ int i, root_num, len, err = 0;
++ unsigned int domain, bus;
++ char str[64];
++ struct walk_info info;
++
++ spin_lock(&dev_data->lock);
++
++ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++ /* First publish all the domain:bus info */
++ err = publish_root_cb(pdev, cntrl_entry->domain,
++ cntrl_entry->bus);
++ if (err)
++ goto out;
++
++ /*
++ * Now figure out which root-%d this belongs to
++ * so we can associate resources with it.
++ */
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ "root_num", "%d", &root_num);
++
++ if (err != 1)
++ goto out;
++
++ for (i = 0; i < root_num; i++) {
++ len = snprintf(str, sizeof(str), "root-%d", i);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ str, "%x:%x", &domain, &bus);
++ if (err != 2)
++ goto out;
++
++ /* Is this the one we just published? */
++ if (domain == cntrl_entry->domain &&
++ bus == cntrl_entry->bus)
++ break;
++ }
++
++ if (i == root_num)
++ goto out;
++
++ info.pdev = pdev;
++ info.resource_count = 0;
++ info.root_num = i;
++
++ /* Let ACPI do the heavy lifting on decoding resources */
++ acpi_walk_resources(cntrl_entry->controller->acpi_handle,
++ METHOD_NAME__CRS, write_xenbus_resource,
++ &info);
++
++ /* No resouces. OK. On to the next one */
++ if (!info.resource_count)
++ continue;
++
++ /* Store the number of resources we wrote for this root-%d */
++ len = snprintf(str, sizeof(str), "root-%d-resources", i);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++ "%d", info.resource_count);
++ if (err)
++ goto out;
++ }
++
++ /* Finally, write some magic to synchronize with the guest. */
++ len = snprintf(str, sizeof(str), "root-resource-magic");
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++ "%lx", (sizeof(struct acpi_resource) * 2) + 1);
++
++out:
++ spin_unlock(&dev_data->lock);
++
++ return err;
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ struct controller_dev_data *dev_data = pdev->pci_dev_data;
++ struct controller_list_entry *cntrl_entry, *c;
++ struct controller_dev_entry *dev_entry, *d;
++
++ list_for_each_entry_safe(cntrl_entry, c, &dev_data->list, list) {
++ list_for_each_entry_safe(dev_entry, d,
++ &cntrl_entry->dev_list, list) {
++ list_del(&dev_entry->list);
++ pcistub_put_pci_dev(dev_entry->dev);
++ kfree(dev_entry);
++ }
++ list_del(&cntrl_entry->list);
++ kfree(cntrl_entry);
++ }
++
++ kfree(dev_data);
++ pdev->pci_dev_data = NULL;
++}
++
++int pciback_get_pcifront_dev(struct pci_dev *pcidev,
++ struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++{
++ struct controller_dev_data *dev_data = pdev->pci_dev_data;
++ struct controller_dev_entry *dev_entry;
++ struct controller_list_entry *cntrl_entry;
++ unsigned long flags;
++ int found = 0;
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
++ if ( (dev_entry->dev->bus->number ==
++ pcidev->bus->number) &&
++ (dev_entry->dev->devfn ==
++ pcidev->devfn) &&
++ (pci_domain_nr(dev_entry->dev->bus) ==
++ pci_domain_nr(pcidev->bus)))
++ {
++ found = 1;
++ *domain = cntrl_entry->domain;
++ *bus = cntrl_entry->bus;
++ *devfn = dev_entry->devfn;
++ goto out;
++ }
++ }
++ }
++out:
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++ return found;
++
++}
++
+diff --git a/drivers/xen/pciback/passthrough.c b/drivers/xen/pciback/passthrough.c
+new file mode 100644
+index 0000000..9e7a0c4
+--- /dev/null
++++ b/drivers/xen/pciback/passthrough.c
+@@ -0,0 +1,176 @@
++/*
++ * PCI Backend - Provides restricted access to the real PCI bus topology
++ * to the frontend
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++struct passthrough_dev_data {
++ /* Access to dev_list must be protected by lock */
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry;
++ struct pci_dev *dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
++ if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
++ && bus == (unsigned int)dev_entry->dev->bus->number
++ && devfn == dev_entry->dev->devfn) {
++ dev = dev_entry->dev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++ int devid, publish_pci_dev_cb publish_cb)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry;
++ unsigned long flags;
++ unsigned int domain, bus, devfn;
++ int err;
++
++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
++ if (!dev_entry)
++ return -ENOMEM;
++ dev_entry->dev = dev;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++ list_add_tail(&dev_entry->list, &dev_data->dev_list);
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ /* Publish this device. */
++ domain = (unsigned int)pci_domain_nr(dev->bus);
++ bus = (unsigned int)dev->bus->number;
++ devfn = dev->devfn;
++ err = publish_cb(pdev, domain, bus, devfn, devid);
++
++ return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry, *t;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&dev_data->lock, flags);
++
++ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
++ if (dev_entry->dev == dev) {
++ list_del(&dev_entry->list);
++ found_dev = dev_entry->dev;
++ kfree(dev_entry);
++ }
++ }
++
++ spin_unlock_irqrestore(&dev_data->lock, flags);
++
++ if (found_dev)
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ struct passthrough_dev_data *dev_data;
++
++ dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
++ if (!dev_data)
++ return -ENOMEM;
++
++ spin_lock_init(&dev_data->lock);
++
++ INIT_LIST_HEAD(&dev_data->dev_list);
++
++ pdev->pci_dev_data = dev_data;
++
++ return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_root_cb)
++{
++ int err = 0;
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry, *e;
++ struct pci_dev *dev;
++ int found;
++ unsigned int domain, bus;
++
++ spin_lock(&dev_data->lock);
++
++ list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
++ /* Only publish this device as a root if none of its
++ * parent bridges are exported
++ */
++ found = 0;
++ dev = dev_entry->dev->bus->self;
++ for (; !found && dev != NULL; dev = dev->bus->self) {
++ list_for_each_entry(e, &dev_data->dev_list, list) {
++ if (dev == e->dev) {
++ found = 1;
++ break;
++ }
++ }
++ }
++
++ domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
++ bus = (unsigned int)dev_entry->dev->bus->number;
++
++ if (!found) {
++ err = publish_root_cb(pdev, domain, bus);
++ if (err)
++ break;
++ }
++ }
++
++ spin_unlock(&dev_data->lock);
++
++ return err;
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++ struct pci_dev_entry *dev_entry, *t;
++
++ list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
++ list_del(&dev_entry->list);
++ pcistub_put_pci_dev(dev_entry->dev);
++ kfree(dev_entry);
++ }
++
++ kfree(dev_data);
++ pdev->pci_dev_data = NULL;
++}
++
++int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++
++{
++ *domain = pci_domain_nr(pcidev->bus);
++ *bus = pcidev->bus->number;
++ *devfn = pcidev->devfn;
++ return 1;
++}
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+new file mode 100644
+index 0000000..c481a73
+--- /dev/null
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -0,0 +1,1316 @@
++/*
++ * PCI Stub Driver - Grabs devices in backend to be exported later
++ *
++ * Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ * Chris Bookholt <hap10(a)epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/rwsem.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/kref.h>
++#include <linux/pci.h>
++#include <linux/wait.h>
++#include <asm/atomic.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++static char *pci_devs_to_hide = NULL;
++wait_queue_head_t aer_wait_queue;
++/*Add sem for sync AER handling and pciback remove/reconfigue ops,
++* We want to avoid in middle of AER ops, pciback devices is being removed
++*/
++static DECLARE_RWSEM(pcistub_sem);
++module_param_named(hide, pci_devs_to_hide, charp, 0444);
++
++struct pcistub_device_id {
++ struct list_head slot_list;
++ int domain;
++ unsigned char bus;
++ unsigned int devfn;
++};
++static LIST_HEAD(pcistub_device_ids);
++static DEFINE_SPINLOCK(device_ids_lock);
++
++struct pcistub_device {
++ struct kref kref;
++ struct list_head dev_list;
++ spinlock_t lock;
++
++ struct pci_dev *dev;
++ struct pciback_device *pdev; /* non-NULL if struct pci_dev is in use */
++};
++
++/* Access to pcistub_devices & seized_devices lists and the initialize_devices
++ * flag must be locked with pcistub_devices_lock
++ */
++static DEFINE_SPINLOCK(pcistub_devices_lock);
++static LIST_HEAD(pcistub_devices);
++
++/* wait for device_initcall before initializing our devices
++ * (see pcistub_init_devices_late)
++ */
++static int initialize_devices = 0;
++static LIST_HEAD(seized_devices);
++
++static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++
++ dev_dbg(&dev->dev, "pcistub_device_alloc\n");
++
++ psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC);
++ if (!psdev)
++ return NULL;
++
++ psdev->dev = pci_dev_get(dev);
++ if (!psdev->dev) {
++ kfree(psdev);
++ return NULL;
++ }
++
++ kref_init(&psdev->kref);
++ spin_lock_init(&psdev->lock);
++
++ return psdev;
++}
++
++/* Don't call this directly as it's called by pcistub_device_put */
++static void pcistub_device_release(struct kref *kref)
++{
++ struct pcistub_device *psdev;
++
++ psdev = container_of(kref, struct pcistub_device, kref);
++
++ dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
++
++ /* Clean-up the device */
++ pciback_reset_device(psdev->dev);
++ pciback_config_free_dyn_fields(psdev->dev);
++ pciback_config_free_dev(psdev->dev);
++ kfree(pci_get_drvdata(psdev->dev));
++ pci_set_drvdata(psdev->dev, NULL);
++
++ pci_dev_put(psdev->dev);
++
++ kfree(psdev);
++}
++
++static inline void pcistub_device_get(struct pcistub_device *psdev)
++{
++ kref_get(&psdev->kref);
++}
++
++static inline void pcistub_device_put(struct pcistub_device *psdev)
++{
++ kref_put(&psdev->kref, pcistub_device_release);
++}
++
++static struct pcistub_device *pcistub_device_find(int domain, int bus,
++ int slot, int func)
++{
++ struct pcistub_device *psdev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev != NULL
++ && domain == pci_domain_nr(psdev->dev->bus)
++ && bus == psdev->dev->bus->number
++ && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
++ pcistub_device_get(psdev);
++ goto out;
++ }
++ }
++
++ /* didn't find it */
++ psdev = NULL;
++
++ out:
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return psdev;
++}
++
++static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
++ struct pcistub_device *psdev)
++{
++ struct pci_dev *pci_dev = NULL;
++ unsigned long flags;
++
++ pcistub_device_get(psdev);
++
++ spin_lock_irqsave(&psdev->lock, flags);
++ if (!psdev->pdev) {
++ psdev->pdev = pdev;
++ pci_dev = psdev->dev;
++ }
++ spin_unlock_irqrestore(&psdev->lock, flags);
++
++ if (!pci_dev)
++ pcistub_device_put(psdev);
++
++ return pci_dev;
++}
++
++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
++ int domain, int bus,
++ int slot, int func)
++{
++ struct pcistub_device *psdev;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev != NULL
++ && domain == pci_domain_nr(psdev->dev->bus)
++ && bus == psdev->dev->bus->number
++ && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
++ found_dev = pcistub_device_get_pci_dev(pdev, psdev);
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return found_dev;
++}
++
++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
++ struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev == dev) {
++ found_dev = pcistub_device_get_pci_dev(pdev, psdev);
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return found_dev;
++}
++
++void pcistub_put_pci_dev(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev, *found_psdev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev == dev) {
++ found_psdev = psdev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ /*hold this lock for avoiding breaking link between
++ * pcistub and pciback when AER is in processing
++ */
++ down_write(&pcistub_sem);
++ /* Cleanup our device
++ * (so it's ready for the next domain)
++ */
++ pciback_reset_device(found_psdev->dev);
++ pciback_config_free_dyn_fields(found_psdev->dev);
++ pciback_config_reset_dev(found_psdev->dev);
++
++ spin_lock_irqsave(&found_psdev->lock, flags);
++ found_psdev->pdev = NULL;
++ spin_unlock_irqrestore(&found_psdev->lock, flags);
++
++ pcistub_device_put(found_psdev);
++ up_write(&pcistub_sem);
++}
++
++static int __devinit pcistub_match_one(struct pci_dev *dev,
++ struct pcistub_device_id *pdev_id)
++{
++ /* Match the specified device by domain, bus, slot, func and also if
++ * any of the device's parent bridges match.
++ */
++ for (; dev != NULL; dev = dev->bus->self) {
++ if (pci_domain_nr(dev->bus) == pdev_id->domain
++ && dev->bus->number == pdev_id->bus
++ && dev->devfn == pdev_id->devfn)
++ return 1;
++
++ /* Sometimes topmost bridge links to itself. */
++ if (dev == dev->bus->self)
++ break;
++ }
++
++ return 0;
++}
++
++static int __devinit pcistub_match(struct pci_dev *dev)
++{
++ struct pcistub_device_id *pdev_id;
++ unsigned long flags;
++ int found = 0;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
++ if (pcistub_match_one(dev, pdev_id)) {
++ found = 1;
++ break;
++ }
++ }
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return found;
++}
++
++static int __devinit pcistub_init_device(struct pci_dev *dev)
++{
++ struct pciback_dev_data *dev_data;
++ int err = 0;
++
++ dev_dbg(&dev->dev, "initializing...\n");
++
++ /* The PCI backend is not intended to be a module (or to work with
++ * removable PCI devices (yet). If it were, pciback_config_free()
++ * would need to be called somewhere to free the memory allocated
++ * here and then to call kfree(pci_get_drvdata(psdev->dev)).
++ */
++ dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
++ if (!dev_data) {
++ err = -ENOMEM;
++ goto out;
++ }
++ pci_set_drvdata(dev, dev_data);
++
++ dev_dbg(&dev->dev, "initializing config\n");
++
++ init_waitqueue_head(&aer_wait_queue);
++ err = pciback_config_init_dev(dev);
++ if (err)
++ goto out;
++
++ /* HACK: Force device (& ACPI) to determine what IRQ it's on - we
++ * must do this here because pcibios_enable_device may specify
++ * the pci device's true irq (and possibly its other resources)
++ * if they differ from what's in the configuration space.
++ * This makes the assumption that the device's resources won't
++ * change after this point (otherwise this code may break!)
++ */
++ dev_dbg(&dev->dev, "enabling device\n");
++ err = pci_enable_device(dev);
++ if (err)
++ goto config_release;
++
++ /* Now disable the device (this also ensures some private device
++ * data is setup before we export)
++ */
++ dev_dbg(&dev->dev, "reset device\n");
++ pciback_reset_device(dev);
++
++ return 0;
++
++ config_release:
++ pciback_config_free_dev(dev);
++
++ out:
++ pci_set_drvdata(dev, NULL);
++ kfree(dev_data);
++ return err;
++}
++
++/*
++ * Because some initialization still happens on
++ * devices during fs_initcall, we need to defer
++ * full initialization of our devices until
++ * device_initcall.
++ */
++static int __init pcistub_init_devices_late(void)
++{
++ struct pcistub_device *psdev;
++ unsigned long flags;
++ int err = 0;
++
++ pr_debug("pciback: pcistub_init_devices_late\n");
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ while (!list_empty(&seized_devices)) {
++ psdev = container_of(seized_devices.next,
++ struct pcistub_device, dev_list);
++ list_del(&psdev->dev_list);
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ err = pcistub_init_device(psdev->dev);
++ if (err) {
++ dev_err(&psdev->dev->dev,
++ "error %d initializing device\n", err);
++ kfree(psdev);
++ psdev = NULL;
++ }
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ if (psdev)
++ list_add_tail(&psdev->dev_list, &pcistub_devices);
++ }
++
++ initialize_devices = 1;
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ return 0;
++}
++
++static int __devinit pcistub_seize(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++ unsigned long flags;
++ int err = 0;
++
++ psdev = pcistub_device_alloc(dev);
++ if (!psdev)
++ return -ENOMEM;
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ if (initialize_devices) {
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ /* don't want irqs disabled when calling pcistub_init_device */
++ err = pcistub_init_device(psdev->dev);
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ if (!err)
++ list_add(&psdev->dev_list, &pcistub_devices);
++ } else {
++ dev_dbg(&dev->dev, "deferring initialization\n");
++ list_add(&psdev->dev_list, &seized_devices);
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ if (err)
++ pcistub_device_put(psdev);
++
++ return err;
++}
++
++static int __devinit pcistub_probe(struct pci_dev *dev,
++ const struct pci_device_id *id)
++{
++ int err = 0;
++
++ dev_dbg(&dev->dev, "probing...\n");
++
++ if (pcistub_match(dev)) {
++
++ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
++ && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
++ dev_err(&dev->dev, "can't export pci devices that "
++ "don't have a normal (0) or bridge (1) "
++ "header type!\n");
++ err = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&dev->dev, "seizing device\n");
++ err = pcistub_seize(dev);
++#ifdef CONFIG_PCI_GUESTDEV
++ } else if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
++ if (!pci_is_guestdev(dev)) {
++ err = -ENODEV;
++ goto out;
++ }
++
++ dev_info(&dev->dev, "seizing device\n");
++ err = pcistub_seize(dev);
++#endif /* CONFIG_PCI_GUESTDEV */
++ } else
++ /* Didn't find the device */
++ err = -ENODEV;
++
++ out:
++ return err;
++}
++
++static void pcistub_remove(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev, *found_psdev = NULL;
++ unsigned long flags;
++
++ dev_dbg(&dev->dev, "removing\n");
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++ pciback_config_quirk_release(dev);
++
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (psdev->dev == dev) {
++ found_psdev = psdev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ if (found_psdev) {
++ dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
++ found_psdev->pdev);
++
++ if (found_psdev->pdev) {
++ printk(KERN_WARNING "pciback: ****** removing device "
++ "%s while still in-use! ******\n",
++ pci_name(found_psdev->dev));
++ printk(KERN_WARNING "pciback: ****** driver domain may "
++ "still access this device's i/o resources!\n");
++ printk(KERN_WARNING "pciback: ****** shutdown driver "
++ "domain before binding device\n");
++ printk(KERN_WARNING "pciback: ****** to other drivers "
++ "or domains\n");
++
++ pciback_release_pci_dev(found_psdev->pdev,
++ found_psdev->dev);
++ }
++
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ list_del(&found_psdev->dev_list);
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++ /* the final put for releasing from the list */
++ pcistub_device_put(found_psdev);
++ }
++}
++
++static const struct pci_device_id pcistub_ids[] = {
++ {
++ .vendor = PCI_ANY_ID,
++ .device = PCI_ANY_ID,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ },
++ {0,},
++};
++
++static void kill_domain_by_device(struct pcistub_device *psdev)
++{
++ struct xenbus_transaction xbt;
++ int err;
++ char nodename[1024];
++
++ if (!psdev)
++ dev_err(&psdev->dev->dev,
++ "device is NULL when do AER recovery/kill_domain\n");
++ sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
++ psdev->pdev->xdev->otherend_id);
++ nodename[strlen(nodename)] = '\0';
++
++again:
++ err = xenbus_transaction_start(&xbt);
++ if (err)
++ {
++ dev_err(&psdev->dev->dev,
++ "error %d when start xenbus transaction\n", err);
++ return;
++ }
++ /*PV AER handlers will set this flag*/
++ xenbus_printf(xbt, nodename, "aerState" , "aerfail" );
++ err = xenbus_transaction_end(xbt, 0);
++ if (err)
++ {
++ if (err == -EAGAIN)
++ goto again;
++ dev_err(&psdev->dev->dev,
++ "error %d when end xenbus transaction\n", err);
++ return;
++ }
++}
++
++/* For each aer recovery step error_detected, mmio_enabled, etc, front_end and
++ * backend need to have cooperation. In pciback, those steps will do similar
++ * jobs: send service request and waiting for front_end response.
++*/
++static pci_ers_result_t common_process(struct pcistub_device *psdev,
++ pci_channel_state_t state, int aer_cmd, pci_ers_result_t result)
++{
++ pci_ers_result_t res = result;
++ struct xen_pcie_aer_op *aer_op;
++ int ret;
++
++ /*with PV AER drivers*/
++ aer_op = &(psdev->pdev->sh_info->aer_op);
++ aer_op->cmd = aer_cmd ;
++ /*useful for error_detected callback*/
++ aer_op->err = state;
++ /*pcifront_end BDF*/
++ ret = pciback_get_pcifront_dev(psdev->dev, psdev->pdev,
++ &aer_op->domain, &aer_op->bus, &aer_op->devfn);
++ if (!ret) {
++ dev_err(&psdev->dev->dev,
++ "pciback: failed to get pcifront device\n");
++ return PCI_ERS_RESULT_NONE;
++ }
++ wmb();
++
++ dev_dbg(&psdev->dev->dev,
++ "pciback: aer_op %x dom %x bus %x devfn %x\n",
++ aer_cmd, aer_op->domain, aer_op->bus, aer_op->devfn);
++ /*local flag to mark there's aer request, pciback callback will use this
++ * flag to judge whether we need to check pci-front give aer service
++ * ack signal
++ */
++ set_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
++
++ /*It is possible that a pcifront conf_read_write ops request invokes
++ * the callback which cause the spurious execution of wake_up.
++ * Yet it is harmless and better than a spinlock here
++ */
++ set_bit(_XEN_PCIB_active,
++ (unsigned long *)&psdev->pdev->sh_info->flags);
++ wmb();
++ notify_remote_via_irq(psdev->pdev->evtchn_irq);
++
++ ret = wait_event_timeout(aer_wait_queue, !(test_bit(_XEN_PCIB_active,
++ (unsigned long *)&psdev->pdev->sh_info->flags)), 300*HZ);
++
++ if (!ret) {
++ if (test_bit(_XEN_PCIB_active,
++ (unsigned long *)&psdev->pdev->sh_info->flags)) {
++ dev_err(&psdev->dev->dev,
++ "pcifront aer process not responding!\n");
++ clear_bit(_XEN_PCIB_active,
++ (unsigned long *)&psdev->pdev->sh_info->flags);
++ aer_op->err = PCI_ERS_RESULT_NONE;
++ return res;
++ }
++ }
++ clear_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
++
++ if ( test_bit( _XEN_PCIF_active,
++ (unsigned long*)&psdev->pdev->sh_info->flags)) {
++ dev_dbg(&psdev->dev->dev,
++ "schedule pci_conf service in pciback \n");
++ test_and_schedule_op(psdev->pdev);
++ }
++
++ res = (pci_ers_result_t)aer_op->err;
++ return res;
++}
++
++/*
++* pciback_slot_reset: it will send the slot_reset request to pcifront in case
++* of the device driver could provide this service, and then wait for pcifront
++* ack.
++* @dev: pointer to PCI devices
++* return value is used by aer_core do_recovery policy
++*/
++static pci_ers_result_t pciback_slot_reset(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++ pci_ers_result_t result;
++
++ result = PCI_ERS_RESULT_RECOVERED;
++ dev_dbg(&dev->dev, "pciback_slot_reset(bus:%x,devfn:%x)\n",
++ dev->bus->number, dev->devfn);
++
++ down_write(&pcistub_sem);
++ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
++ dev->bus->number,
++ PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn));
++
++ if ( !psdev || !psdev->pdev )
++ {
++ dev_err(&dev->dev,
++ "pciback device is not found/assigned\n");
++ goto end;
++ }
++
++ if ( !psdev->pdev->sh_info )
++ {
++ dev_err(&dev->dev, "pciback device is not connected or owned"
++ " by HVM, kill it\n");
++ kill_domain_by_device(psdev);
++ goto release;
++ }
++
++ if ( !test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
++ dev_err(&dev->dev,
++ "guest with no AER driver should have been killed\n");
++ goto release;
++ }
++ result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result);
++
++ if (result == PCI_ERS_RESULT_NONE ||
++ result == PCI_ERS_RESULT_DISCONNECT) {
++ dev_dbg(&dev->dev,
++ "No AER slot_reset service or disconnected!\n");
++ kill_domain_by_device(psdev);
++ }
++release:
++ pcistub_device_put(psdev);
++end:
++ up_write(&pcistub_sem);
++ return result;
++
++}
++
++
++/*pciback_mmio_enabled: it will send the mmio_enabled request to pcifront
++* in case of the device driver could provide this service, and then wait
++* for pcifront ack.
++* @dev: pointer to PCI devices
++* return value is used by aer_core do_recovery policy
++*/
++
++static pci_ers_result_t pciback_mmio_enabled(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++ pci_ers_result_t result;
++
++ result = PCI_ERS_RESULT_RECOVERED;
++ dev_dbg(&dev->dev, "pciback_mmio_enabled(bus:%x,devfn:%x)\n",
++ dev->bus->number, dev->devfn);
++
++ down_write(&pcistub_sem);
++ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
++ dev->bus->number,
++ PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn));
++
++ if ( !psdev || !psdev->pdev )
++ {
++ dev_err(&dev->dev,
++ "pciback device is not found/assigned\n");
++ goto end;
++ }
++
++ if ( !psdev->pdev->sh_info )
++ {
++ dev_err(&dev->dev, "pciback device is not connected or owned"
++ " by HVM, kill it\n");
++ kill_domain_by_device(psdev);
++ goto release;
++ }
++
++ if ( !test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
++ dev_err(&dev->dev,
++ "guest with no AER driver should have been killed\n");
++ goto release;
++ }
++ result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result);
++
++ if (result == PCI_ERS_RESULT_NONE ||
++ result == PCI_ERS_RESULT_DISCONNECT) {
++ dev_dbg(&dev->dev,
++ "No AER mmio_enabled service or disconnected!\n");
++ kill_domain_by_device(psdev);
++ }
++release:
++ pcistub_device_put(psdev);
++end:
++ up_write(&pcistub_sem);
++ return result;
++}
++
++/*pciback_error_detected: it will send the error_detected request to pcifront
++* in case of the device driver could provide this service, and then wait
++* for pcifront ack.
++* @dev: pointer to PCI devices
++* @error: the current PCI connection state
++* return value is used by aer_core do_recovery policy
++*/
++
++static pci_ers_result_t pciback_error_detected(struct pci_dev *dev,
++ pci_channel_state_t error)
++{
++ struct pcistub_device *psdev;
++ pci_ers_result_t result;
++
++ result = PCI_ERS_RESULT_CAN_RECOVER;
++ dev_dbg(&dev->dev, "pciback_error_detected(bus:%x,devfn:%x)\n",
++ dev->bus->number, dev->devfn);
++
++ down_write(&pcistub_sem);
++ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
++ dev->bus->number,
++ PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn));
++
++ if ( !psdev || !psdev->pdev )
++ {
++ dev_err(&dev->dev,
++ "pciback device is not found/assigned\n");
++ goto end;
++ }
++
++ if ( !psdev->pdev->sh_info )
++ {
++ dev_err(&dev->dev, "pciback device is not connected or owned"
++ " by HVM, kill it\n");
++ kill_domain_by_device(psdev);
++ goto release;
++ }
++
++ /*Guest owns the device yet no aer handler regiested, kill guest*/
++ if ( !test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
++ dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n");
++ kill_domain_by_device(psdev);
++ goto release;
++ }
++ result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result);
++
++ if (result == PCI_ERS_RESULT_NONE ||
++ result == PCI_ERS_RESULT_DISCONNECT) {
++ dev_dbg(&dev->dev,
++ "No AER error_detected service or disconnected!\n");
++ kill_domain_by_device(psdev);
++ }
++release:
++ pcistub_device_put(psdev);
++end:
++ up_write(&pcistub_sem);
++ return result;
++}
++
++/*pciback_error_resume: it will send the error_resume request to pcifront
++* in case of the device driver could provide this service, and then wait
++* for pcifront ack.
++* @dev: pointer to PCI devices
++*/
++
++static void pciback_error_resume(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++
++ dev_dbg(&dev->dev, "pciback_error_resume(bus:%x,devfn:%x)\n",
++ dev->bus->number, dev->devfn);
++
++ down_write(&pcistub_sem);
++ psdev = pcistub_device_find(pci_domain_nr(dev->bus),
++ dev->bus->number,
++ PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn));
++
++ if ( !psdev || !psdev->pdev )
++ {
++ dev_err(&dev->dev,
++ "pciback device is not found/assigned\n");
++ goto end;
++ }
++
++ if ( !psdev->pdev->sh_info )
++ {
++ dev_err(&dev->dev, "pciback device is not connected or owned"
++ " by HVM, kill it\n");
++ kill_domain_by_device(psdev);
++ goto release;
++ }
++
++ if ( !test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags) ) {
++ dev_err(&dev->dev,
++ "guest with no AER driver should have been killed\n");
++ kill_domain_by_device(psdev);
++ goto release;
++ }
++ common_process(psdev, 1, XEN_PCI_OP_aer_resume, PCI_ERS_RESULT_RECOVERED);
++release:
++ pcistub_device_put(psdev);
++end:
++ up_write(&pcistub_sem);
++ return;
++}
++
++/*add pciback AER handling*/
++static struct pci_error_handlers pciback_error_handler = {
++ .error_detected = pciback_error_detected,
++ .mmio_enabled = pciback_mmio_enabled,
++ .slot_reset = pciback_slot_reset,
++ .resume = pciback_error_resume,
++};
++
++/*
++ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
++ * for a normal device. I don't want it to be loaded automatically.
++ */
++
++static struct pci_driver pciback_pci_driver = {
++ .name = "pciback",
++ .id_table = pcistub_ids,
++ .probe = pcistub_probe,
++ .remove = pcistub_remove,
++ .err_handler = &pciback_error_handler,
++};
++
++static inline int str_to_slot(const char *buf, int *domain, int *bus,
++ int *slot, int *func)
++{
++ int err;
++
++ err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
++ if (err == 4)
++ return 0;
++ else if (err < 0)
++ return -EINVAL;
++
++ /* try again without domain */
++ *domain = 0;
++ err = sscanf(buf, " %x:%x.%x", bus, slot, func);
++ if (err == 3)
++ return 0;
++
++ return -EINVAL;
++}
++
++static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
++ *slot, int *func, int *reg, int *size, int *mask)
++{
++ int err;
++
++ err =
++ sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot,
++ func, reg, size, mask);
++ if (err == 7)
++ return 0;
++ return -EINVAL;
++}
++
++static int pcistub_device_id_add(int domain, int bus, int slot, int func)
++{
++ struct pcistub_device_id *pci_dev_id;
++ unsigned long flags;
++
++ pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
++ if (!pci_dev_id)
++ return -ENOMEM;
++
++ pci_dev_id->domain = domain;
++ pci_dev_id->bus = bus;
++ pci_dev_id->devfn = PCI_DEVFN(slot, func);
++
++ pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
++ domain, bus, slot, func);
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return 0;
++}
++
++static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
++{
++ struct pcistub_device_id *pci_dev_id, *t;
++ int devfn = PCI_DEVFN(slot, func);
++ int err = -ENOENT;
++ unsigned long flags;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
++
++ if (pci_dev_id->domain == domain
++ && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
++ /* Don't break; here because it's possible the same
++ * slot could be in the list more than once
++ */
++ list_del(&pci_dev_id->slot_list);
++ kfree(pci_dev_id);
++
++ err = 0;
++
++ pr_debug("pciback: removed %04x:%02x:%02x.%01x from "
++ "seize list\n", domain, bus, slot, func);
++ }
++ }
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return err;
++}
++
++static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
++ int size, int mask)
++{
++ int err = 0;
++ struct pcistub_device *psdev;
++ struct pci_dev *dev;
++ struct config_field *field;
++
++ psdev = pcistub_device_find(domain, bus, slot, func);
++ if (!psdev || !psdev->dev) {
++ err = -ENODEV;
++ goto out;
++ }
++ dev = psdev->dev;
++
++ field = kzalloc(sizeof(*field), GFP_ATOMIC);
++ if (!field) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ field->offset = reg;
++ field->size = size;
++ field->mask = mask;
++ field->init = NULL;
++ field->reset = NULL;
++ field->release = NULL;
++ field->clean = pciback_config_field_free;
++
++ err = pciback_config_quirks_add_field(dev, field);
++ if (err)
++ kfree(field);
++ out:
++ return err;
++}
++
++static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func;
++ int err;
++
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++
++ err = pcistub_device_id_add(domain, bus, slot, func);
++
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
++
++static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func;
++ int err;
++
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++
++ err = pcistub_device_id_remove(domain, bus, slot, func);
++
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
++
++static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
++{
++ struct pcistub_device_id *pci_dev_id;
++ size_t count = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
++ if (count >= PAGE_SIZE)
++ break;
++
++ count += scnprintf(buf + count, PAGE_SIZE - count,
++ "%04x:%02x:%02x.%01x\n",
++ pci_dev_id->domain, pci_dev_id->bus,
++ PCI_SLOT(pci_dev_id->devfn),
++ PCI_FUNC(pci_dev_id->devfn));
++ }
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return count;
++}
++
++DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
++
++static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func, reg, size, mask;
++ int err;
++
++ err = str_to_quirk(buf, &domain, &bus, &slot, &func, ®,
&size,
++ &mask);
++ if (err)
++ goto out;
++
++ err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
++
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
++{
++ int count = 0;
++ unsigned long flags;
++ extern struct list_head pciback_quirks;
++ struct pciback_config_quirk *quirk;
++ struct pciback_dev_data *dev_data;
++ const struct config_field *field;
++ const struct config_field_entry *cfg_entry;
++
++ spin_lock_irqsave(&device_ids_lock, flags);
++ list_for_each_entry(quirk, &pciback_quirks, quirks_list) {
++ if (count >= PAGE_SIZE)
++ goto out;
++
++ count += scnprintf(buf + count, PAGE_SIZE - count,
++ "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n",
++ quirk->pdev->bus->number,
++ PCI_SLOT(quirk->pdev->devfn),
++ PCI_FUNC(quirk->pdev->devfn),
++ quirk->devid.vendor, quirk->devid.device,
++ quirk->devid.subvendor,
++ quirk->devid.subdevice);
++
++ dev_data = pci_get_drvdata(quirk->pdev);
++
++ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++ field = cfg_entry->field;
++ if (count >= PAGE_SIZE)
++ goto out;
++
++ count += scnprintf(buf + count, PAGE_SIZE - count,
++ "\t\t%08x:%01x:%08x\n",
++ cfg_entry->base_offset + field->offset,
++ field->size, field->mask);
++ }
++ }
++
++ out:
++ spin_unlock_irqrestore(&device_ids_lock, flags);
++
++ return count;
++}
++
++DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
++
++static ssize_t permissive_add(struct device_driver *drv, const char *buf,
++ size_t count)
++{
++ int domain, bus, slot, func;
++ int err;
++ struct pcistub_device *psdev;
++ struct pciback_dev_data *dev_data;
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++ psdev = pcistub_device_find(domain, bus, slot, func);
++ if (!psdev) {
++ err = -ENODEV;
++ goto out;
++ }
++ if (!psdev->dev) {
++ err = -ENODEV;
++ goto release;
++ }
++ dev_data = pci_get_drvdata(psdev->dev);
++ /* the driver data for a device should never be null at this point */
++ if (!dev_data) {
++ err = -ENXIO;
++ goto release;
++ }
++ if (!dev_data->permissive) {
++ dev_data->permissive = 1;
++ /* Let user know that what they're doing could be unsafe */
++ dev_warn(&psdev->dev->dev,
++ "enabling permissive mode configuration space accesses!\n");
++ dev_warn(&psdev->dev->dev,
++ "permissive mode is potentially unsafe!\n");
++ }
++ release:
++ pcistub_device_put(psdev);
++ out:
++ if (!err)
++ err = count;
++ return err;
++}
++
++static ssize_t permissive_show(struct device_driver *drv, char *buf)
++{
++ struct pcistub_device *psdev;
++ struct pciback_dev_data *dev_data;
++ size_t count = 0;
++ unsigned long flags;
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (count >= PAGE_SIZE)
++ break;
++ if (!psdev->dev)
++ continue;
++ dev_data = pci_get_drvdata(psdev->dev);
++ if (!dev_data || !dev_data->permissive)
++ continue;
++ count +=
++ scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
++ pci_name(psdev->dev));
++ }
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return count;
++}
++
++DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
++
++#ifdef CONFIG_PCI_MSI
++
++int pciback_get_owner(struct pci_dev *dev)
++{
++ struct pcistub_device *psdev;
++
++ psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number,
++ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++
++ if (!psdev || !psdev->pdev)
++ return -1;
++
++ return psdev->pdev->xdev->otherend_id;
++}
++#endif
++
++static void pcistub_exit(void)
++{
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
++ driver_remove_file(&pciback_pci_driver.driver,
++ &driver_attr_remove_slot);
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
++ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
++
++ pci_unregister_driver(&pciback_pci_driver);
++ WARN_ON(unregister_msi_get_owner(pciback_get_owner));
++}
++
++static int __init pcistub_init(void)
++{
++ int pos = 0;
++ int err = 0;
++ int domain, bus, slot, func;
++ int parsed;
++
++ if (pci_devs_to_hide && *pci_devs_to_hide) {
++ do {
++ parsed = 0;
++
++ err = sscanf(pci_devs_to_hide + pos,
++ " (%x:%x:%x.%x) %n",
++ &domain, &bus, &slot, &func, &parsed);
++ if (err != 4) {
++ domain = 0;
++ err = sscanf(pci_devs_to_hide + pos,
++ " (%x:%x.%x) %n",
++ &bus, &slot, &func, &parsed);
++ if (err != 3)
++ goto parse_error;
++ }
++
++ err = pcistub_device_id_add(domain, bus, slot, func);
++ if (err)
++ goto out;
++
++ /* if parsed<=0, we've reached the end of the string */
++ pos += parsed;
++ } while (parsed > 0 && pci_devs_to_hide[pos]);
++ }
++
++ /* If we're the first PCI Device Driver to register, we're the
++ * first one to get offered PCI devices as they become
++ * available (and thus we can be the first to grab them)
++ */
++ err = pci_register_driver(&pciback_pci_driver);
++ if (err < 0)
++ goto out;
++
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_new_slot);
++ if (!err)
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_remove_slot);
++ if (!err)
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_slots);
++ if (!err)
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_quirks);
++ if (!err)
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_permissive);
++
++ if (!err)
++ err = register_msi_get_owner(pciback_get_owner);
++ if (err)
++ pcistub_exit();
++
++ out:
++ return err;
++
++ parse_error:
++ printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at
\"%s\"\n",
++ pci_devs_to_hide + pos);
++ return -EINVAL;
++}
++
++#ifndef MODULE
++/*
++ * fs_initcall happens before device_initcall
++ * so pciback *should* get called first (b/c we
++ * want to suck up any device before other drivers
++ * get a chance by being the first pci device
++ * driver to register)
++ */
++fs_initcall(pcistub_init);
++#endif
++
++static int __init pciback_init(void)
++{
++ int err;
++
++ err = pciback_config_init();
++ if (err)
++ return err;
++
++#ifdef MODULE
++ err = pcistub_init();
++ if (err < 0)
++ return err;
++#endif
++
++ pcistub_init_devices_late();
++ err = pciback_xenbus_register();
++ if (err)
++ pcistub_exit();
++
++ return err;
++}
++
++static void __exit pciback_cleanup(void)
++{
++ pciback_xenbus_unregister();
++ pcistub_exit();
++}
++
++module_init(pciback_init);
++module_exit(pciback_cleanup);
++
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+new file mode 100644
+index 0000000..6744f45
+--- /dev/null
++++ b/drivers/xen/pciback/pciback.h
+@@ -0,0 +1,126 @@
++/*
++ * PCI Backend Common Data Structures & Function Declarations
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++#ifndef __XEN_PCIBACK_H__
++#define __XEN_PCIBACK_H__
++
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <xen/xenbus.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <asm/atomic.h>
++#include <xen/interface/io/pciif.h>
++
++struct pci_dev_entry {
++ struct list_head list;
++ struct pci_dev *dev;
++};
++
++#define _PDEVF_op_active (0)
++#define PDEVF_op_active (1<<(_PDEVF_op_active))
++#define _PCIB_op_pending (1)
++#define PCIB_op_pending (1<<(_PCIB_op_pending))
++
++struct pciback_device {
++ void *pci_dev_data;
++ spinlock_t dev_lock;
++
++ struct xenbus_device *xdev;
++
++ struct xenbus_watch be_watch;
++ u8 be_watching;
++
++ int evtchn_irq;
++
++ struct vm_struct *sh_area;
++ struct xen_pci_sharedinfo *sh_info;
++
++ unsigned long flags;
++
++ struct work_struct op_work;
++};
++
++struct pciback_dev_data {
++ struct list_head config_fields;
++ int permissive;
++ int warned_on_write;
++};
++
++/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
++ int domain, int bus,
++ int slot, int func);
++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
++ struct pci_dev *dev);
++void pcistub_put_pci_dev(struct pci_dev *dev);
++
++/* Ensure a device is turned off or reset */
++void pciback_reset_device(struct pci_dev *pdev);
++
++/* Access a virtual configuration space for a PCI device */
++int pciback_config_init(void);
++int pciback_config_init_dev(struct pci_dev *dev);
++void pciback_config_free_dyn_fields(struct pci_dev *dev);
++void pciback_config_reset_dev(struct pci_dev *dev);
++void pciback_config_free_dev(struct pci_dev *dev);
++int pciback_config_read(struct pci_dev *dev, int offset, int size,
++ u32 * ret_val);
++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
++
++/* Handle requests for specific devices from the frontend */
++typedef int (*publish_pci_dev_cb) (struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn, unsigned int devid);
++typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
++ unsigned int domain, unsigned int bus);
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++ int devid, publish_pci_dev_cb publish_cb);
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn);
++
++/**
++* Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in pciback
++* before sending aer request to pcifront, so that guest could identify
++* device, coopearte with pciback to finish aer recovery job if device driver
++* has the capability
++*/
++
++int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus, unsigned int *devfn);
++int pciback_init_devices(struct pciback_device *pdev);
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb cb);
++void pciback_release_devices(struct pciback_device *pdev);
++
++/* Handles events from front-end */
++irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
++void pciback_do_op(void *data);
++
++int pciback_xenbus_register(void);
++void pciback_xenbus_unregister(void);
++
++#ifdef CONFIG_PCI_MSI
++int pciback_enable_msi(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op);
++
++int pciback_disable_msi(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op);
++
++
++int pciback_enable_msix(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op);
++
++int pciback_disable_msix(struct pciback_device *pdev,
++ struct pci_dev *dev, struct xen_pci_op *op);
++#endif
++extern int verbose_request;
++
++void test_and_schedule_op(struct pciback_device *pdev);
++#endif
++
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+new file mode 100644
+index 0000000..b85b2db
+--- /dev/null
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -0,0 +1,134 @@
++/*
++ * PCI Backend Operations - respond to PCI requests from Frontend
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/wait.h>
++#include <asm/bitops.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++
++int verbose_request = 0;
++module_param(verbose_request, int, 0644);
++
++/* Ensure a device is "turned off" and ready to be exported.
++ * (Also see pciback_config_reset to ensure virtual configuration space is
++ * ready to be re-exported)
++ */
++void pciback_reset_device(struct pci_dev *dev)
++{
++ u16 cmd;
++
++ /* Disable devices (but not bridges) */
++ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
++ pci_disable_device(dev);
++
++ pci_write_config_word(dev, PCI_COMMAND, 0);
++
++ dev->is_enabled = 0;
++ dev->is_busmaster = 0;
++ } else {
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ if (cmd & (PCI_COMMAND_INVALIDATE)) {
++ cmd &= ~(PCI_COMMAND_INVALIDATE);
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++ dev->is_busmaster = 0;
++ }
++ }
++}
++extern wait_queue_head_t aer_wait_queue;
++extern struct workqueue_struct *pciback_wq;
++/*
++* Now the same evtchn is used for both pcifront conf_read_write request
++* as well as pcie aer front end ack. We use a new work_queue to schedule
++* pciback conf_read_write service for avoiding confict with aer_core
++* do_recovery job which also use the system default work_queue
++*/
++void test_and_schedule_op(struct pciback_device *pdev)
++{
++ /* Check that frontend is requesting an operation and that we are not
++ * already processing a request */
++ if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
++ && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
++ {
++ queue_work(pciback_wq, &pdev->op_work);
++ }
++ /*_XEN_PCIB_active should have been cleared by pcifront. And also make
++ sure pciback is waiting for ack by checking _PCIB_op_pending*/
++ if (!test_bit(_XEN_PCIB_active,(unsigned long *)&pdev->sh_info->flags)
++ &&test_bit(_PCIB_op_pending, &pdev->flags)) {
++ wake_up(&aer_wait_queue);
++ }
++}
++
++/* Performing the configuration space reads/writes must not be done in atomic
++ * context because some of the pci_* functions can sleep (mostly due to ACPI
++ * use of semaphores). This function is intended to be called from a work
++ * queue in process context taking a struct pciback_device as a parameter */
++void pciback_do_op(void *data)
++{
++ struct pciback_device *pdev = data;
++ struct pci_dev *dev;
++ struct xen_pci_op *op = &pdev->sh_info->op;
++
++ dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
++
++ if (dev == NULL)
++ op->err = XEN_PCI_ERR_dev_not_found;
++ else
++ {
++ switch (op->cmd)
++ {
++ case XEN_PCI_OP_conf_read:
++ op->err = pciback_config_read(dev,
++ op->offset, op->size, &op->value);
++ break;
++ case XEN_PCI_OP_conf_write:
++ op->err = pciback_config_write(dev,
++ op->offset, op->size, op->value);
++ break;
++#ifdef CONFIG_PCI_MSI
++ case XEN_PCI_OP_enable_msi:
++ op->err = pciback_enable_msi(pdev, dev, op);
++ break;
++ case XEN_PCI_OP_disable_msi:
++ op->err = pciback_disable_msi(pdev, dev, op);
++ break;
++ case XEN_PCI_OP_enable_msix:
++ op->err = pciback_enable_msix(pdev, dev, op);
++ break;
++ case XEN_PCI_OP_disable_msix:
++ op->err = pciback_disable_msix(pdev, dev, op);
++ break;
++#endif
++ default:
++ op->err = XEN_PCI_ERR_not_implemented;
++ break;
++ }
++ }
++ /* Tell the driver domain that we're done. */
++ wmb();
++ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
++ notify_remote_via_irq(pdev->evtchn_irq);
++
++ /* Mark that we're done. */
++ smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */
++ clear_bit(_PDEVF_op_active, &pdev->flags);
++ smp_mb__after_clear_bit(); /* /before/ final check for work */
++
++ /* Check to see if the driver domain tried to start another request in
++ * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
++ */
++ test_and_schedule_op(pdev);
++}
++
++irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct pciback_device *pdev = dev_id;
++
++ test_and_schedule_op(pdev);
++
++ return IRQ_HANDLED;
++}
+diff --git a/drivers/xen/pciback/slot.c b/drivers/xen/pciback/slot.c
+new file mode 100644
+index 0000000..105a8b6
+--- /dev/null
++++ b/drivers/xen/pciback/slot.c
+@@ -0,0 +1,187 @@
++/*
++ * PCI Backend - Provides a Virtual PCI bus (with real devices)
++ * to the frontend
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil> (vpci.c)
++ * Author: Tristan Gingold <tristan.gingold(a)bull.net>, from vpci.c
++ */
++
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++/* There are at most 32 slots in a pci bus. */
++#define PCI_SLOT_MAX 32
++
++#define PCI_BUS_NBR 2
++
++struct slot_dev_data {
++ /* Access to dev_list must be protected by lock */
++ struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
++ spinlock_t lock;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct pci_dev *dev = NULL;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if (domain != 0 || PCI_FUNC(devfn) != 0)
++ return NULL;
++
++ if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
++ return NULL;
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++ dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++ return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++ int devid, publish_pci_dev_cb publish_cb)
++{
++ int err = 0, slot, bus;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
++ err = -EFAULT;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Can't export bridges on the virtual PCI bus");
++ goto out;
++ }
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++
++ /* Assign to a new slot on the virtual PCI bus */
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (slot_dev->slots[bus][slot] == NULL) {
++ printk(KERN_INFO
++ "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
++ pci_name(dev), slot, bus);
++ slot_dev->slots[bus][slot] = dev;
++ goto unlock;
++ }
++ }
++
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "No more space on root virtual PCI bus");
++
++ unlock:
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++ /* Publish this device. */
++ if(!err)
++ err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid);
++
++ out:
++ return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ int slot, bus;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (slot_dev->slots[bus][slot] == dev) {
++ slot_dev->slots[bus][slot] = NULL;
++ found_dev = dev;
++ goto out;
++ }
++ }
++
++ out:
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++ if (found_dev)
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ int slot, bus;
++ struct slot_dev_data *slot_dev;
++
++ slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
++ if (!slot_dev)
++ return -ENOMEM;
++
++ spin_lock_init(&slot_dev->lock);
++
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++)
++ slot_dev->slots[bus][slot] = NULL;
++
++ pdev->pci_dev_data = slot_dev;
++
++ return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_cb)
++{
++ /* The Virtual PCI bus has only one root */
++ return publish_cb(pdev, 0, 0);
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ int slot, bus;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ struct pci_dev *dev;
++
++ for (bus = 0; bus < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ dev = slot_dev->slots[bus][slot];
++ if (dev != NULL)
++ pcistub_put_pci_dev(dev);
++ }
++
++ kfree(slot_dev);
++ pdev->pci_dev_data = NULL;
++}
++
++int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++{
++ int slot, busnr;
++ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++ struct pci_dev *dev;
++ int found = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&slot_dev->lock, flags);
++
++ for (busnr = 0; busnr < PCI_BUS_NBR; bus++)
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ dev = slot_dev->slots[busnr][slot];
++ if (dev && dev->bus->number == pcidev->bus->number
++ && dev->devfn == pcidev->devfn
++ && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)) {
++ found = 1;
++ *domain = 0;
++ *bus = busnr;
++ *devfn = PCI_DEVFN(slot,0);
++ goto out;
++ }
++ }
++out:
++ spin_unlock_irqrestore(&slot_dev->lock, flags);
++ return found;
++
++}
+diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
+new file mode 100644
+index 0000000..a5b7ece
+--- /dev/null
++++ b/drivers/xen/pciback/vpci.c
+@@ -0,0 +1,242 @@
++/*
++ * PCI Backend - Provides a Virtual PCI bus (with real devices)
++ * to the frontend
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++#define PCI_SLOT_MAX 32
++
++struct vpci_dev_data {
++ /* Access to dev_list must be protected by lock */
++ struct list_head dev_list[PCI_SLOT_MAX];
++ spinlock_t lock;
++};
++
++static inline struct list_head *list_first(struct list_head *head)
++{
++ return head->next;
++}
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn)
++{
++ struct pci_dev_entry *entry;
++ struct pci_dev *dev = NULL;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if (domain != 0 || bus != 0)
++ return NULL;
++
++ if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++
++ list_for_each_entry(entry,
++ &vpci_dev->dev_list[PCI_SLOT(devfn)],
++ list) {
++ if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
++ dev = entry->dev;
++ break;
++ }
++ }
++
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++ }
++ return dev;
++}
++
++static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
++{
++ if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
++ && l->bus == r->bus && PCI_SLOT(l->devfn) ==
PCI_SLOT(r->devfn))
++ return 1;
++
++ return 0;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++ int devid, publish_pci_dev_cb publish_cb)
++{
++ int err = 0, slot, func;
++ struct pci_dev_entry *t, *dev_entry;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ unsigned long flags;
++
++ if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
++ err = -EFAULT;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Can't export bridges on the virtual PCI bus");
++ goto out;
++ }
++
++ dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
++ if (!dev_entry) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error adding entry to virtual PCI bus");
++ goto out;
++ }
++
++ dev_entry->dev = dev;
++
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++
++ /* Keep multi-function devices together on the virtual PCI bus */
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (!list_empty(&vpci_dev->dev_list[slot])) {
++ t = list_entry(list_first(&vpci_dev->dev_list[slot]),
++ struct pci_dev_entry, list);
++
++ if (match_slot(dev, t->dev)) {
++ pr_info("pciback: vpci: %s: "
++ "assign to virtual slot %d func %d\n",
++ pci_name(dev), slot,
++ PCI_FUNC(dev->devfn));
++ list_add_tail(&dev_entry->list,
++ &vpci_dev->dev_list[slot]);
++ func = PCI_FUNC(dev->devfn);
++ goto unlock;
++ }
++ }
++ }
++
++ /* Assign to a new slot on the virtual PCI bus */
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ if (list_empty(&vpci_dev->dev_list[slot])) {
++ printk(KERN_INFO
++ "pciback: vpci: %s: assign to virtual slot %d\n",
++ pci_name(dev), slot);
++ list_add_tail(&dev_entry->list,
++ &vpci_dev->dev_list[slot]);
++ func = PCI_FUNC(dev->devfn);
++ goto unlock;
++ }
++ }
++
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "No more space on root virtual PCI bus");
++
++ unlock:
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++
++ /* Publish this device. */
++ if(!err)
++ err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
++
++ out:
++ return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++ int slot;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ struct pci_dev *found_dev = NULL;
++ unsigned long flags;
++
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ struct pci_dev_entry *e, *tmp;
++ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
++ list) {
++ if (e->dev == dev) {
++ list_del(&e->list);
++ found_dev = e->dev;
++ kfree(e);
++ goto out;
++ }
++ }
++ }
++
++ out:
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++
++ if (found_dev)
++ pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++ int slot;
++ struct vpci_dev_data *vpci_dev;
++
++ vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
++ if (!vpci_dev)
++ return -ENOMEM;
++
++ spin_lock_init(&vpci_dev->lock);
++
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
++ }
++
++ pdev->pci_dev_data = vpci_dev;
++
++ return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++ publish_pci_root_cb publish_cb)
++{
++ /* The Virtual PCI bus has only one root */
++ return publish_cb(pdev, 0, 0);
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++ int slot;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ struct pci_dev_entry *e, *tmp;
++ list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
++ list) {
++ list_del(&e->list);
++ pcistub_put_pci_dev(e->dev);
++ kfree(e);
++ }
++ }
++
++ kfree(vpci_dev);
++ pdev->pci_dev_data = NULL;
++}
++
++int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++{
++ struct pci_dev_entry *entry;
++ struct pci_dev *dev = NULL;
++ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++ unsigned long flags;
++ int found = 0, slot;
++
++ spin_lock_irqsave(&vpci_dev->lock, flags);
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ list_for_each_entry(entry,
++ &vpci_dev->dev_list[slot],
++ list) {
++ dev = entry->dev;
++ if (dev && dev->bus->number == pcidev->bus->number
++ && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)
++ && dev->devfn == pcidev->devfn)
++ {
++ found = 1;
++ *domain = 0;
++ *bus = 0;
++ *devfn = PCI_DEVFN(slot, PCI_FUNC(pcidev->devfn));
++ }
++ }
++ }
++ spin_unlock_irqrestore(&vpci_dev->lock, flags);
++ return found;
++}
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+new file mode 100644
+index 0000000..4d56c45
+--- /dev/null
++++ b/drivers/xen/pciback/xenbus.c
+@@ -0,0 +1,710 @@
++/*
++ * PCI Backend Xenbus Setup - handles setup with frontend and xend
++ *
++ * Author: Ryan Wilson <hap9(a)epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/vmalloc.h>
++#include <xen/xenbus.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++
++#define INVALID_EVTCHN_IRQ (-1)
++struct workqueue_struct *pciback_wq;
++
++static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
++{
++ struct pciback_device *pdev;
++
++ pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL);
++ if (pdev == NULL)
++ goto out;
++ dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
++
++ pdev->xdev = xdev;
++ xdev->dev.driver_data = pdev;
++
++ spin_lock_init(&pdev->dev_lock);
++
++ pdev->sh_area = NULL;
++ pdev->sh_info = NULL;
++ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
++ pdev->be_watching = 0;
++
++ INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
++
++ if (pciback_init_devices(pdev)) {
++ kfree(pdev);
++ pdev = NULL;
++ }
++ out:
++ return pdev;
++}
++
++static void pciback_disconnect(struct pciback_device *pdev)
++{
++ spin_lock(&pdev->dev_lock);
++
++ /* Ensure the guest can't trigger our handler before removing devices */
++ if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) {
++ unbind_from_irqhandler(pdev->evtchn_irq, pdev);
++ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
++ }
++
++ /* If the driver domain started an op, make sure we complete it
++ * before releasing the shared memory */
++ flush_workqueue(pciback_wq);
++
++ if (pdev->sh_info != NULL) {
++ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
++ pdev->sh_info = NULL;
++ }
++
++ spin_unlock(&pdev->dev_lock);
++}
++
++static void free_pdev(struct pciback_device *pdev)
++{
++ if (pdev->be_watching)
++ unregister_xenbus_watch(&pdev->be_watch);
++
++ pciback_disconnect(pdev);
++
++ pciback_release_devices(pdev);
++
++ pdev->xdev->dev.driver_data = NULL;
++ pdev->xdev = NULL;
++
++ kfree(pdev);
++}
++
++static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
++ int remote_evtchn)
++{
++ int err = 0;
++ struct vm_struct *area;
++
++ dev_dbg(&pdev->xdev->dev,
++ "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
++ gnt_ref, remote_evtchn);
++
++ area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
++ if (IS_ERR(area)) {
++ err = PTR_ERR(area);
++ goto out;
++ }
++ pdev->sh_area = area;
++ pdev->sh_info = area->addr;
++
++ err = bind_interdomain_evtchn_to_irqhandler(
++ pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
++ SA_SAMPLE_RANDOM, "pciback", pdev);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error binding event channel to IRQ");
++ goto out;
++ }
++ pdev->evtchn_irq = err;
++ err = 0;
++
++ dev_dbg(&pdev->xdev->dev, "Attached!\n");
++ out:
++ return err;
++}
++
++static int pciback_attach(struct pciback_device *pdev)
++{
++ int err = 0;
++ int gnt_ref, remote_evtchn;
++ char *magic = NULL;
++
++ spin_lock(&pdev->dev_lock);
++
++ /* Make sure we only do this setup once */
++ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++ XenbusStateInitialised)
++ goto out;
++
++ /* Wait for frontend to state that it has published the configuration */
++ if (xenbus_read_driver_state(pdev->xdev->otherend) !=
++ XenbusStateInitialised)
++ goto out;
++
++ dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
++
++ err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
++ "pci-op-ref", "%u", &gnt_ref,
++ "event-channel", "%u", &remote_evtchn,
++ "magic", NULL, &magic, NULL);
++ if (err) {
++ /* If configuration didn't get read correctly, wait longer */
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading configuration from frontend");
++ goto out;
++ }
++
++ if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
++ xenbus_dev_fatal(pdev->xdev, -EFAULT,
++ "version mismatch (%s/%s) with pcifront - "
++ "halting pciback",
++ magic, XEN_PCI_MAGIC);
++ goto out;
++ }
++
++ err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
++ if (err)
++ goto out;
++
++ dev_dbg(&pdev->xdev->dev, "Connecting...\n");
++
++ err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
++ if (err)
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error switching to connected state!");
++
++ dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
++ out:
++ spin_unlock(&pdev->dev_lock);
++
++ if (magic)
++ kfree(magic);
++
++ return err;
++}
++
++static int pciback_publish_pci_dev(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus,
++ unsigned int devfn, unsigned int devid)
++{
++ int err;
++ int len;
++ char str[64];
++
++ len = snprintf(str, sizeof(str), "vdev-%d", devid);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++ "%04x:%02x:%02x.%02x", domain, bus,
++ PCI_SLOT(devfn), PCI_FUNC(devfn));
++
++ out:
++ return err;
++}
++
++static int pciback_export_device(struct pciback_device *pdev,
++ int domain, int bus, int slot, int func,
++ int devid)
++{
++ struct pci_dev *dev;
++ int err = 0;
++
++ dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func
%x\n",
++ domain, bus, slot, func);
++
++ dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
++ if (!dev) {
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Couldn't locate PCI device "
++ "(%04x:%02x:%02x.%01x)! "
++ "perhaps already in-use?",
++ domain, bus, slot, func);
++ goto out;
++ }
++
++ err = pciback_add_pci_dev(pdev, dev, devid, pciback_publish_pci_dev);
++ if (err)
++ goto out;
++
++ /* TODO: It'd be nice to export a bridge and have all of its children
++ * get exported with it. This may be best done in xend (which will
++ * have to calculate resource usage anyway) but we probably want to
++ * put something in here to ensure that if a bridge gets given to a
++ * driver domain, that all devices under that bridge are not given
++ * to other driver domains (as he who controls the bridge can disable
++ * it and stop the other devices from working).
++ */
++ out:
++ return err;
++}
++
++static int pciback_remove_device(struct pciback_device *pdev,
++ int domain, int bus, int slot, int func)
++{
++ int err = 0;
++ struct pci_dev *dev;
++
++ dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func
%x\n",
++ domain, bus, slot, func);
++
++ dev = pciback_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
++ if (!dev) {
++ err = -EINVAL;
++ dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
++ "(%04x:%02x:%02x.%01x)! not owned by this domain\n",
++ domain, bus, slot, func);
++ goto out;
++ }
++
++ pciback_release_pci_dev(pdev, dev);
++
++ out:
++ return err;
++}
++
++static int pciback_publish_pci_root(struct pciback_device *pdev,
++ unsigned int domain, unsigned int bus)
++{
++ unsigned int d, b;
++ int i, root_num, len, err;
++ char str[64];
++
++ dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ "root_num", "%d", &root_num);
++ if (err == 0 || err == -ENOENT)
++ root_num = 0;
++ else if (err < 0)
++ goto out;
++
++ /* Verify that we haven't already published this pci root */
++ for (i = 0; i < root_num; i++) {
++ len = snprintf(str, sizeof(str), "root-%d", i);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ str, "%x:%x", &d, &b);
++ if (err < 0)
++ goto out;
++ if (err != 2) {
++ err = -EINVAL;
++ goto out;
++ }
++
++ if (d == domain && b == bus) {
++ err = 0;
++ goto out;
+ }
- desc->status &= ~IRQ_SUSPENDED;
+ }
-
- switch (desc->depth) {
- case 0:
-diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
-index 0d4005d8..d6bfb89 100644
---- a/kernel/irq/pm.c
-+++ b/kernel/irq/pm.c
-@@ -53,9 +53,6 @@ void resume_device_irqs(void)
- for_each_irq_desc(irq, desc) {
- unsigned long flags;
-
-- if (!(desc->status & IRQ_SUSPENDED))
-- continue;
--
- raw_spin_lock_irqsave(&desc->lock, flags);
- __enable_irq(desc, irq, true);
- raw_spin_unlock_irqrestore(&desc->lock, flags);
---
-1.7.4
-
-
-From bb70b10fcebc2a02591a1da53e8d6873582b421e Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 18 Jan 2011 20:17:10 -0500
-Subject: [PATCH 147/244] xen/mmu: WARN_ON when racing to swap middle leaf.
-
-The initial bootup code uses set_phys_to_machine quite a lot, and after
-bootup it would be used by the balloon driver. The balloon driver does have
-mutex lock so this should not be necessary - but just in case, add
-a WARN_ON if we do hit this scenario. If we do fail this, it is OK
-to continue as there is a backup mechanism (VM_IO) that can bypass
-the P2M and still set the _PAGE_IOMAP flags.
-
-[v2: Change from WARN to BUG_ON]
-[v3: Rebased on top of xen->p2m code split]
-[v4: Change from BUG_ON to WARN]
-Reviewed-by: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/p2m.c | 3 ++-
- 1 files changed, 2 insertions(+), 1 deletions(-)
-
-diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
-index dd30ec8..851da14 100644
---- a/arch/x86/xen/p2m.c
-+++ b/arch/x86/xen/p2m.c
-@@ -482,7 +482,8 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
-
- /* Swap over from MISSING to IDENTITY if needed. */
- if (p2m_top[topidx][mididx] == p2m_missing) {
-- p2m_top[topidx][mididx] = p2m_identity;
-+ WARN_ON(cmpxchg(&p2m_top[topidx][mididx], p2m_missing,
-+ p2m_identity) != p2m_missing);
- return true;
- }
- }
---
-1.7.4
-
-
-From da60f4ccf61268444fd83d5e266ffe26d5ce366d Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 1 Feb 2011 17:15:30 -0500
-Subject: [PATCH 148/244] xen/setup: Set identity mapping for non-RAM E820 and E820 gaps.
-
-We walk the E820 region and start at 0 (for PV guests we start
-at ISA_END_ADDRESS) and skip any E820 RAM regions. For all other
-regions and as well the gaps we set them to be identity mappings.
-
-The reasons we do not want to set the identity mapping from 0->
-ISA_END_ADDRESS when running as PV is b/c that the kernel would
-try to read DMI information and fail (no permissions to read that).
-There is a lot of gnarly code to deal with that weird region so
-we won't try to do a cleanup in this patch.
-
-This code ends up calling 'set_phys_to_identity' with the start
-and end PFN of the the E820 that are non-RAM or have gaps.
-On 99% of machines that means one big region right underneath the
-4GB mark. Usually starts at 0xc0000 (or 0x80000) and goes to
-0x100000.
-
-[v2: Fix for E820 crossing 1MB region and clamp the start]
-[v3: Squshed in code that does this over ranges]
-[v4: Moved the comment to the correct spot]
-[v5: Use the "raw" E820 from the hypervisor]
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/setup.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 52 insertions(+), 0 deletions(-)
-
-diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
-index 7201800..54d9379 100644
---- a/arch/x86/xen/setup.c
-+++ b/arch/x86/xen/setup.c
-@@ -143,12 +143,55 @@ static unsigned long __init xen_return_unused_memory(unsigned long
max_pfn,
- return released;
- }
-
-+static unsigned long __init xen_set_identity(const struct e820entry *list,
-+ ssize_t map_size)
++
++ len = snprintf(str, sizeof(str), "root-%d", root_num);
++ if (unlikely(len >= (sizeof(str) - 1))) {
++ err = -ENOMEM;
++ goto out;
++ }
++
++ dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
++ root_num, domain, bus);
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++ "%04x:%02x", domain, bus);
++ if (err)
++ goto out;
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
++ "root_num", "%d", (root_num + 1));
++
++ out:
++ return err;
++}
++
++static int pciback_reconfigure(struct pciback_device *pdev)
+{
-+ phys_addr_t last = xen_initial_domain() ? 0 : ISA_END_ADDRESS;
-+ phys_addr_t start_pci = last;
-+ const struct e820entry *entry;
-+ unsigned long identity = 0;
-+ int i;
++ int err = 0;
++ int num_devs;
++ int domain, bus, slot, func;
++ int substate;
++ int i, len;
++ char state_str[64];
++ char dev_str[64];
+
-+ for (i = 0, entry = list; i < map_size; i++, entry++) {
-+ phys_addr_t start = entry->addr;
-+ phys_addr_t end = start + entry->size;
++ spin_lock(&pdev->dev_lock);
+
-+ if (start < last)
-+ start = last;
++ dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
++
++ /* Make sure we only reconfigure once */
++ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++ XenbusStateReconfiguring)
++ goto out;
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs",
"%d",
++ &num_devs);
++ if (err != 1) {
++ if (err >= 0)
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading number of devices");
++ goto out;
++ }
++
++ for (i = 0; i < num_devs; i++) {
++ len = snprintf(state_str, sizeof(state_str), "state-%d", i);
++ if (unlikely(len >= (sizeof(state_str) - 1))) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "String overflow while reading "
++ "configuration");
++ goto out;
++ }
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
++ "%d", &substate);
++ if (err != 1)
++ substate = XenbusStateUnknown;
++
++ switch (substate) {
++ case XenbusStateInitialising:
++ dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
++
++ len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
++ if (unlikely(len >= (sizeof(dev_str) - 1))) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "String overflow while "
++ "reading configuration");
++ goto out;
++ }
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ dev_str, "%x:%x:%x.%x",
++ &domain, &bus, &slot, &func);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading device "
++ "configuration");
++ goto out;
++ }
++ if (err != 4) {
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error parsing pci device "
++ "configuration");
++ goto out;
++ }
++
++ err = pciback_export_device(pdev, domain, bus, slot,
++ func, i);
++ if (err)
++ goto out;
++
++ /* Publish pci roots. */
++ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error while publish PCI root"
++ "buses for frontend");
++ goto out;
++ }
++
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
++ state_str, "%d",
++ XenbusStateInitialised);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error switching substate of "
++ "dev-%d\n", i);
++ goto out;
++ }
++ break;
++
++ case XenbusStateClosing:
++ dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
++
++ len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
++ if (unlikely(len >= (sizeof(dev_str) - 1))) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "String overflow while "
++ "reading configuration");
++ goto out;
++ }
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++ dev_str, "%x:%x:%x.%x",
++ &domain, &bus, &slot, &func);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading device "
++ "configuration");
++ goto out;
++ }
++ if (err != 4) {
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error parsing pci device "
++ "configuration");
++ goto out;
++ }
+
-+ if (end <= start)
-+ continue;
++ err = pciback_remove_device(pdev, domain, bus, slot,
++ func);
++ if(err)
++ goto out;
+
-+ /* Skip over the 1MB region. */
-+ if (last > end)
-+ continue;
++ /* TODO: If at some point we implement support for pci
++ * root hot-remove on pcifront side, we'll need to
++ * remove unnecessary xenstore nodes of pci roots here.
++ */
+
-+ if (entry->type == E820_RAM) {
-+ if (start > start_pci)
-+ identity += set_phys_range_identity(
-+ PFN_UP(start_pci), PFN_DOWN(start));
++ break;
+
-+ /* Without saving 'last' we would gooble RAM too
-+ * at the end of the loop. */
-+ last = end;
-+ start_pci = end;
-+ continue;
++ default:
++ break;
+ }
-+ start_pci = min(start, start_pci);
-+ last = end;
+ }
-+ if (last > start_pci)
-+ identity += set_phys_range_identity(
-+ PFN_UP(start_pci), PFN_DOWN(last));
-+ return identity;
++
++ err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error switching to reconfigured state!");
++ goto out;
++ }
++
++ out:
++ spin_unlock(&pdev->dev_lock);
++
++ return 0;
+}
- /**
- * machine_specific_memory_setup - Hook for machine specific memory setup.
- **/
- char * __init xen_memory_setup(void)
- {
- static struct e820entry map[E820MAX] __initdata;
-+ static struct e820entry map_raw[E820MAX] __initdata;
-
- unsigned long max_pfn = xen_start_info->nr_pages;
- unsigned long long mem_end;
-@@ -156,6 +199,7 @@ char * __init xen_memory_setup(void)
- struct xen_memory_map memmap;
- unsigned long extra_pages = 0;
- unsigned long extra_limit;
-+ unsigned long identity_pages = 0;
- int i;
- int op;
-
-@@ -181,6 +225,7 @@ char * __init xen_memory_setup(void)
- }
- BUG_ON(rc);
-
-+ memcpy(map_raw, map, sizeof(map));
- e820.nr_map = 0;
- xen_extra_mem_start = mem_end;
- for (i = 0; i < memmap.nr_entries; i++) {
-@@ -251,6 +296,13 @@ char * __init xen_memory_setup(void)
-
- xen_add_extra_mem(extra_pages);
-
-+ /*
-+ * Set P2M for all non-RAM pages and E820 gaps to be identity
-+ * type PFNs. We supply it with the non-sanitized version
-+ * of the E820.
-+ */
-+ identity_pages = xen_set_identity(map_raw, memmap.nr_entries);
-+ printk(KERN_INFO "Set %ld page(s) to 1-1 mapping.\n", identity_pages);
- return "Xen";
- }
-
---
-1.7.4
-
-
-From 4f5d3a046949c958338ca780145dae21647c8d58 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 22 Dec 2010 08:57:30 -0500
-Subject: [PATCH 149/244] xen/debugfs: Add 'p2m' file for printing out the P2M
layout.
-
-We walk over the whole P2M tree and construct a simplified view of
-which PFN regions belong to what level and what type they are.
-
-Only enabled if CONFIG_XEN_DEBUG_FS is set.
-
-[v2: UNKN->UNKNOWN, use uninitialized_var]
-[v3: Rebased on top of mmu->p2m code split]
-[v4: Fixed the else if]
-Reviewed-by: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/include/asm/xen/page.h | 3 +
- arch/x86/xen/mmu.c | 14 +++++++
- arch/x86/xen/p2m.c | 78 +++++++++++++++++++++++++++++++++++++++
- 3 files changed, 95 insertions(+), 0 deletions(-)
-
-diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
-index 65fa4f2..78ebbeb 100644
---- a/arch/x86/include/asm/xen/page.h
-+++ b/arch/x86/include/asm/xen/page.h
-@@ -52,6 +52,9 @@ extern int m2p_remove_override(struct page *page);
- extern struct page *m2p_find_override(unsigned long mfn);
- extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
-
-+#ifdef CONFIG_XEN_DEBUG_FS
-+extern int p2m_dump_show(struct seq_file *m, void *v);
-+#endif
- static inline unsigned long pfn_to_mfn(unsigned long pfn)
- {
- unsigned long mfn;
-diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
-index 9c9e076..b13b6ca 100644
---- a/arch/x86/xen/mmu.c
-+++ b/arch/x86/xen/mmu.c
-@@ -46,6 +46,7 @@
- #include <linux/module.h>
- #include <linux/gfp.h>
- #include <linux/memblock.h>
-+#include <linux/seq_file.h>
-
- #include <asm/pgtable.h>
- #include <asm/tlbflush.h>
-@@ -2367,6 +2368,18 @@ EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
-
- #ifdef CONFIG_XEN_DEBUG_FS
-
-+static int p2m_dump_open(struct inode *inode, struct file *filp)
++
++static void pciback_frontend_changed(struct xenbus_device *xdev,
++ enum xenbus_state fe_state)
+{
-+ return single_open(filp, p2m_dump_show, NULL);
-+}
++ struct pciback_device *pdev = xdev->dev.driver_data;
+
-+static const struct file_operations p2m_dump_fops = {
-+ .open = p2m_dump_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
++ dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
- static struct dentry *d_mmu_debug;
-
- static int __init xen_mmu_debugfs(void)
-@@ -2422,6 +2435,7 @@ static int __init xen_mmu_debugfs(void)
- debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
- &mmu_stats.prot_commit_batched);
-
-+ debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
- return 0;
- }
- fs_initcall(xen_mmu_debugfs);
-diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
-index 851da14..ea613d0 100644
---- a/arch/x86/xen/p2m.c
-+++ b/arch/x86/xen/p2m.c
-@@ -30,6 +30,7 @@
- #include <linux/list.h>
- #include <linux/hash.h>
- #include <linux/sched.h>
-+#include <linux/seq_file.h>
-
- #include <asm/cache.h>
- #include <asm/setup.h>
-@@ -635,3 +636,80 @@ unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long
pfn)
- return ret;
- }
- EXPORT_SYMBOL_GPL(m2p_find_override_pfn);
++ switch (fe_state) {
++ case XenbusStateInitialised:
++ pciback_attach(pdev);
++ break;
+
-+#ifdef CONFIG_XEN_DEBUG_FS
++ case XenbusStateReconfiguring:
++ pciback_reconfigure(pdev);
++ break;
+
-+int p2m_dump_show(struct seq_file *m, void *v)
++ case XenbusStateConnected:
++ /* pcifront switched its state from reconfiguring to connected.
++ * Then switch to connected state.
++ */
++ xenbus_switch_state(xdev, XenbusStateConnected);
++ break;
++
++ case XenbusStateClosing:
++ pciback_disconnect(pdev);
++ xenbus_switch_state(xdev, XenbusStateClosing);
++ break;
++
++ case XenbusStateClosed:
++ pciback_disconnect(pdev);
++ xenbus_switch_state(xdev, XenbusStateClosed);
++ if (xenbus_dev_is_online(xdev))
++ break;
++ /* fall through if not online */
++ case XenbusStateUnknown:
++ dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
++ device_unregister(&xdev->dev);
++ break;
++
++ default:
++ break;
++ }
++}
++
++static int pciback_setup_backend(struct pciback_device *pdev)
+{
-+ static const char * const level_name[] = { "top", "middle",
-+ "entry", "abnormal" };
-+ static const char * const type_name[] = { "identity", "missing",
-+ "pfn", "abnormal"};
-+#define TYPE_IDENTITY 0
-+#define TYPE_MISSING 1
-+#define TYPE_PFN 2
-+#define TYPE_UNKNOWN 3
-+ unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0;
-+ unsigned int uninitialized_var(prev_level);
-+ unsigned int uninitialized_var(prev_type);
++ /* Get configuration from xend (if available now) */
++ int domain, bus, slot, func;
++ int err = 0;
++ int i, num_devs;
++ char dev_str[64];
++ char state_str[64];
+
-+ if (!p2m_top)
-+ return 0;
++ spin_lock(&pdev->dev_lock);
+
-+ for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn++) {
-+ unsigned topidx = p2m_top_index(pfn);
-+ unsigned mididx = p2m_mid_index(pfn);
-+ unsigned idx = p2m_index(pfn);
-+ unsigned lvl, type;
++ /* It's possible we could get the call to setup twice, so make sure
++ * we're not already connected.
++ */
++ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++ XenbusStateInitWait)
++ goto out;
+
-+ lvl = 4;
-+ type = TYPE_UNKNOWN;
-+ if (p2m_top[topidx] == p2m_mid_missing) {
-+ lvl = 0; type = TYPE_MISSING;
-+ } else if (p2m_top[topidx] == NULL) {
-+ lvl = 0; type = TYPE_UNKNOWN;
-+ } else if (p2m_top[topidx][mididx] == NULL) {
-+ lvl = 1; type = TYPE_UNKNOWN;
-+ } else if (p2m_top[topidx][mididx] == p2m_identity) {
-+ lvl = 1; type = TYPE_IDENTITY;
-+ } else if (p2m_top[topidx][mididx] == p2m_missing) {
-+ lvl = 1; type = TYPE_MISSING;
-+ } else if (p2m_top[topidx][mididx][idx] == 0) {
-+ lvl = 2; type = TYPE_UNKNOWN;
-+ } else if (p2m_top[topidx][mididx][idx] == IDENTITY_FRAME(pfn)) {
-+ lvl = 2; type = TYPE_IDENTITY;
-+ } else if (p2m_top[topidx][mididx][idx] == INVALID_P2M_ENTRY) {
-+ lvl = 2; type = TYPE_MISSING;
-+ } else if (p2m_top[topidx][mididx][idx] == pfn) {
-+ lvl = 2; type = TYPE_PFN;
-+ } else if (p2m_top[topidx][mididx][idx] != pfn) {
-+ lvl = 2; type = TYPE_PFN;
-+ }
-+ if (pfn == 0) {
-+ prev_level = lvl;
-+ prev_type = type;
++ dev_dbg(&pdev->xdev->dev, "getting be setup\n");
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs",
"%d",
++ &num_devs);
++ if (err != 1) {
++ if (err >= 0)
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading number of devices");
++ goto out;
++ }
++
++ for (i = 0; i < num_devs; i++) {
++ int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
++ if (unlikely(l >= (sizeof(dev_str) - 1))) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "String overflow while reading "
++ "configuration");
++ goto out;
+ }
-+ if (pfn == MAX_DOMAIN_PAGES-1) {
-+ lvl = 3;
-+ type = TYPE_UNKNOWN;
++
++ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
++ "%x:%x:%x.%x", &domain, &bus, &slot, &func);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error reading device configuration");
++ goto out;
+ }
-+ if (prev_type != type) {
-+ seq_printf(m, " [0x%lx->0x%lx] %s\n",
-+ prev_pfn_type, pfn, type_name[prev_type]);
-+ prev_pfn_type = pfn;
-+ prev_type = type;
++ if (err != 4) {
++ err = -EINVAL;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error parsing pci device "
++ "configuration");
++ goto out;
+ }
-+ if (prev_level != lvl) {
-+ seq_printf(m, " [0x%lx->0x%lx] level %s\n",
-+ prev_pfn_level, pfn, level_name[prev_level]);
-+ prev_pfn_level = pfn;
-+ prev_level = lvl;
++
++ err = pciback_export_device(pdev, domain, bus, slot, func, i);
++ if (err)
++ goto out;
++
++ /* Switch substate of this device. */
++ l = snprintf(state_str, sizeof(state_str), "state-%d", i);
++ if (unlikely(l >= (sizeof(state_str) - 1))) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(pdev->xdev, err,
++ "String overflow while reading "
++ "configuration");
++ goto out;
+ }
++ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
++ "%d", XenbusStateInitialised);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err, "Error switching "
++ "substate of dev-%d\n", i);
++ goto out;
++ }
+ }
-+ return 0;
-+#undef TYPE_IDENTITY
-+#undef TYPE_MISSING
-+#undef TYPE_PFN
-+#undef TYPE_UNKNOWN
++
++ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
++ if (err) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error while publish PCI root buses "
++ "for frontend");
++ goto out;
++ }
++
++ err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
++ if (err)
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error switching to initialised state!");
++
++ out:
++ spin_unlock(&pdev->dev_lock);
++
++ if (!err)
++ /* see if pcifront is already configured (if not, we'll wait) */
++ pciback_attach(pdev);
++
++ return err;
+}
-+#endif
---
-1.7.4
-
-
-From 84f847d2e878b4d15e7552e86f20251a2d0d4522 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 23 Dec 2010 16:25:29 -0500
-Subject: [PATCH 150/244] xen/debug: WARN_ON when identity PFN has no _PAGE_IOMAP flag
set.
-
-Only enabled if XEN_DEBUG is enabled. We print a warning
-when:
-
- pfn_to_mfn(pfn) == pfn, but no VM_IO (_PAGE_IOMAP) flag set
- (and pfn is an identity mapped pfn)
- pfn_to_mfn(pfn) != pfn, and VM_IO flag is set.
- (ditto, pfn is an identity mapped pfn)
-
-[v2: Make it dependent on CONFIG_XEN_DEBUG instead of ..DEBUG_FS]
-[v3: Fix compiler warning]
-
-Reviewed-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/Kconfig | 8 ++++++++
- arch/x86/xen/mmu.c | 38 ++++++++++++++++++++++++++++++++++++++
- 2 files changed, 46 insertions(+), 0 deletions(-)
-
-diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
-index 5b54892..e4343fe 100644
---- a/arch/x86/xen/Kconfig
-+++ b/arch/x86/xen/Kconfig
-@@ -48,3 +48,11 @@ config XEN_DEBUG_FS
- help
- Enable statistics output and various tuning options in debugfs.
- Enabling this option may incur a significant performance overhead.
+
-+config XEN_DEBUG
-+ bool "Enable Xen debug checks"
-+ depends on XEN
-+ default n
-+ help
-+ Enable various WARN_ON checks in the Xen MMU code.
-+ Enabling this option WILL incur a significant performance overhead.
-diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
-index b13b6ca..0c376a2 100644
---- a/arch/x86/xen/mmu.c
-+++ b/arch/x86/xen/mmu.c
-@@ -547,6 +547,41 @@ pte_t xen_make_pte(pteval_t pte)
- }
- PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
-
-+#ifdef CONFIG_XEN_DEBUG
-+pte_t xen_make_pte_debug(pteval_t pte)
++static void pciback_be_watch(struct xenbus_watch *watch,
++ const char **vec, unsigned int len)
+{
-+ phys_addr_t addr = (pte & PTE_PFN_MASK);
-+ phys_addr_t other_addr;
-+ bool io_page = false;
-+ pte_t _pte;
++ struct pciback_device *pdev =
++ container_of(watch, struct pciback_device, be_watch);
+
-+ if (pte & _PAGE_IOMAP)
-+ io_page = true;
++ switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
++ case XenbusStateInitWait:
++ pciback_setup_backend(pdev);
++ break;
+
-+ _pte = xen_make_pte(pte);
++ default:
++ break;
++ }
++}
+
-+ if (!addr)
-+ return _pte;
++static int pciback_xenbus_probe(struct xenbus_device *dev,
++ const struct xenbus_device_id *id)
++{
++ int err = 0;
++ struct pciback_device *pdev = alloc_pdev(dev);
+
-+ if (io_page &&
-+ (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
-+ other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
-+ WARN(addr != other_addr,
-+ "0x%lx is using VM_IO, but it is 0x%lx!\n",
-+ (unsigned long)addr, (unsigned long)other_addr);
-+ } else {
-+ pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
-+ other_addr = (_pte.pte & PTE_PFN_MASK);
-+ WARN((addr == other_addr) && (!io_page) && (!iomap_set),
-+ "0x%lx is missing VM_IO (and wasn't fixed)!\n",
-+ (unsigned long)addr);
++ if (pdev == NULL) {
++ err = -ENOMEM;
++ xenbus_dev_fatal(dev, err,
++ "Error allocating pciback_device struct");
++ goto out;
+ }
+
-+ return _pte;
++ /* wait for xend to configure us */
++ err = xenbus_switch_state(dev, XenbusStateInitWait);
++ if (err)
++ goto out;
++
++ /* watch the backend node for backend configuration information */
++ err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
++ pciback_be_watch);
++ if (err)
++ goto out;
++ pdev->be_watching = 1;
++
++ /* We need to force a call to our callback here in case
++ * xend already configured us!
++ */
++ pciback_be_watch(&pdev->be_watch, NULL, 0);
++
++ out:
++ return err;
++}
++
++static int pciback_xenbus_remove(struct xenbus_device *dev)
++{
++ struct pciback_device *pdev = dev->dev.driver_data;
++
++ if (pdev != NULL)
++ free_pdev(pdev);
++
++ return 0;
++}
++
++static const struct xenbus_device_id xenpci_ids[] = {
++ {"pci"},
++ {{0}},
++};
++
++static struct xenbus_driver xenbus_pciback_driver = {
++ .name = "pciback",
++ .owner = THIS_MODULE,
++ .ids = xenpci_ids,
++ .probe = pciback_xenbus_probe,
++ .remove = pciback_xenbus_remove,
++ .otherend_changed = pciback_frontend_changed,
++};
++
++int __init pciback_xenbus_register(void)
++{
++ if (!is_running_on_xen())
++ return -ENODEV;
++ pciback_wq = create_workqueue("pciback_workqueue");
++ if (!pciback_wq) {
++ printk(KERN_ERR "pciback_xenbus_register: create"
++ "pciback_workqueue failed\n");
++ return -EFAULT;
++ }
++ return xenbus_register_backend(&xenbus_pciback_driver);
+}
-+PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
-+#endif
+
- pgd_t xen_make_pgd(pgdval_t pgd)
- {
- pgd = pte_pfn_to_mfn(pgd);
-@@ -1957,6 +1992,9 @@ __init void xen_ident_map_ISA(void)
-
- static __init void xen_post_allocator_init(void)
- {
-+#ifdef CONFIG_XEN_DEBUG
-+ pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
-+#endif
- pv_mmu_ops.set_pte = xen_set_pte;
- pv_mmu_ops.set_pmd = xen_set_pmd;
- pv_mmu_ops.set_pud = xen_set_pud;
++void __exit pciback_xenbus_unregister(void)
++{
++ destroy_workqueue(pciback_wq);
++ xenbus_unregister_driver(&xenbus_pciback_driver);
++}
--
1.7.4
-From 5c560d90ed68b399d5020692d38e6cc77db4f6d0 Mon Sep 17 00:00:00 2001
+From a4c91b92b09f5b0b7fcb2c6ccd2bc3347eaa2db9 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Fri, 14 Jan 2011 17:55:44 -0500
-Subject: [PATCH 151/244] xen/m2p: No need to catch exceptions when we know that there is
no RAM
-
-.. beyound what we think is the end of memory. However there might
-be more System RAM - but assigned to a guest. Hence jump to the
-M2P override check and consult.
+Date: Tue, 13 Oct 2009 17:22:22 -0400
+Subject: [PATCH 171/203] xen-pciback: Fix include header name change (evtchn.h is now
events.h)
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- arch/x86/include/asm/xen/page.h | 6 +++++-
- 1 files changed, 5 insertions(+), 1 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 2 +-
+ drivers/xen/pciback/pciback_ops.c | 2 +-
+ drivers/xen/pciback/xenbus.c | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
-diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
-index 78ebbeb..1957070 100644
---- a/arch/x86/include/asm/xen/page.h
-+++ b/arch/x86/include/asm/xen/page.h
-@@ -85,6 +85,10 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
- if (xen_feature(XENFEAT_auto_translated_physmap))
- return mfn;
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index c481a73..c02f21f 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -13,7 +13,7 @@
+ #include <linux/pci.h>
+ #include <linux/wait.h>
+ #include <asm/atomic.h>
+-#include <xen/evtchn.h>
++#include <xen/events.h>
+ #include "pciback.h"
+ #include "conf_space.h"
+ #include "conf_space_quirks.h"
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index b85b2db..58d09eb 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -6,7 +6,7 @@
+ #include <linux/module.h>
+ #include <linux/wait.h>
+ #include <asm/bitops.h>
+-#include <xen/evtchn.h>
++#include <xen/events.h>
+ #include "pciback.h"
-+ if (unlikely((mfn >> machine_to_phys_order) != 0)) {
-+ pfn = ~0;
-+ goto try_override;
-+ }
- pfn = 0;
- /*
- * The array access can fail (e.g., device space beyond end of RAM).
-@@ -92,7 +96,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
- * but we must handle the fault without crashing!
- */
- __get_user(pfn, &machine_to_phys_mapping[mfn]);
--
-+try_override:
- /*
- * If this appears to be a foreign mfn (because the pfn
- * doesn't map back to the mfn), then check the local override
+ int verbose_request = 0;
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index 4d56c45..bbca3fe 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -8,7 +8,7 @@
+ #include <linux/list.h>
+ #include <linux/vmalloc.h>
+ #include <xen/xenbus.h>
+-#include <xen/evtchn.h>
++#include <xen/events.h>
+ #include "pciback.h"
+
+ #define INVALID_EVTCHN_IRQ (-1)
--
1.7.4
-From ba114b8b8112f1fa4b14c929a85ebf51c9c1a749 Mon Sep 17 00:00:00 2001
-From: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Date: Wed, 2 Feb 2011 18:32:59 +0000
-Subject: [PATCH 152/244] xen/m2p: Check whether the MFN has IDENTITY_FRAME bit set..
+From f9645fb1e1dc8fc0596469aa47b661a4f5070a1c Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 13 Oct 2009 17:22:24 -0400
+Subject: [PATCH 172/203] xen-pciback: Use pci_is_enabled() instead of is_enabled.
-If there is no proper PFN value in the M2P for the MFN
-(so we get 0xFFFFF.. or 0x55555, or 0x0), we should
-consult the M2P override to see if there is an entry for this.
-[Note: we also consult the M2P override if the MFN
-is past our machine_to_phys size].
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/pciback/conf_space_header.c | 4 ++--
+ drivers/xen/pciback/pciback_ops.c | 1 -
+ 2 files changed, 2 insertions(+), 3 deletions(-)
-We consult the P2M with the PFN. In case the returned
-MFN is one of the special values: 0xFFF.., 0x5555
-(which signify that the MFN can be either "missing" or it
-belongs to DOMID_IO) or the p2m(m2p(mfn)) != mfn, we check
-the M2P override. If we fail the M2P override check, we reset
-the PFN value to INVALID_P2M_ENTRY.
+diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
+index f794e12..5a9e028 100644
+--- a/drivers/xen/pciback/conf_space_header.c
++++ b/drivers/xen/pciback/conf_space_header.c
+@@ -22,14 +22,14 @@ static int command_write(struct pci_dev *dev, int offset, u16 value,
void *data)
+ {
+ int err;
+
+- if (!dev->is_enabled && is_enable_cmd(value)) {
++ if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
+ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: enable\n",
+ pci_name(dev));
+ err = pci_enable_device(dev);
+ if (err)
+ return err;
+- } else if (dev->is_enabled && !is_enable_cmd(value)) {
++ } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
+ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: disable\n",
+ pci_name(dev));
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 58d09eb..2d570e7 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -26,7 +26,6 @@ void pciback_reset_device(struct pci_dev *dev)
+
+ pci_write_config_word(dev, PCI_COMMAND, 0);
+
+- dev->is_enabled = 0;
+ dev->is_busmaster = 0;
+ } else {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+--
+1.7.4
-Next we try to find the MFN in the P2M using the MFN
-value (not the PFN value) and if found, we know
-that this MFN is an identity value and return it as so.
-Otherwise we have exhausted all the posibilities and we
-return the PFN, which at this stage can either be a real
-PFN value found in the machine_to_phys.. array, or
-INVALID_P2M_ENTRY value.
+From a16f8410e3eb0e9db51aa1c90c95715893395a8a Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 13 Oct 2009 17:22:25 -0400
+Subject: [PATCH 173/203] xen-pciback: Fix usage of INIT_WORK.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- arch/x86/include/asm/xen/page.h | 29 ++++++++++++++++++++++-------
- 1 files changed, 22 insertions(+), 7 deletions(-)
+ drivers/xen/pciback/pciback.h | 4 ++--
+ drivers/xen/pciback/pciback_ops.c | 7 ++++---
+ drivers/xen/pciback/xenbus.c | 3 ++-
+ 3 files changed, 8 insertions(+), 6 deletions(-)
-diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
-index 1957070..c61934f 100644
---- a/arch/x86/include/asm/xen/page.h
-+++ b/arch/x86/include/asm/xen/page.h
-@@ -81,6 +81,7 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn)
- static inline unsigned long mfn_to_pfn(unsigned long mfn)
- {
- unsigned long pfn;
-+ int ret = 0;
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index 6744f45..4fb8c05 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -99,8 +99,8 @@ int pciback_publish_pci_roots(struct pciback_device *pdev,
+ void pciback_release_devices(struct pciback_device *pdev);
- if (xen_feature(XENFEAT_auto_translated_physmap))
- return mfn;
-@@ -95,15 +96,29 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
- * In such cases it doesn't matter what we return (we return garbage),
- * but we must handle the fault without crashing!
- */
-- __get_user(pfn, &machine_to_phys_mapping[mfn]);
-+ ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
- try_override:
-- /*
-- * If this appears to be a foreign mfn (because the pfn
-- * doesn't map back to the mfn), then check the local override
-- * table to see if there's a better pfn to use.
-+ /* ret might be < 0 if there are no entries in the m2p for mfn */
-+ if (ret < 0)
-+ pfn = ~0;
-+ else if (get_phys_to_machine(pfn) != mfn)
-+ /*
-+ * If this appears to be a foreign mfn (because the pfn
-+ * doesn't map back to the mfn), then check the local override
-+ * table to see if there's a better pfn to use.
-+ *
-+ * m2p_find_override_pfn returns ~0 if it doesn't find anything.
-+ */
-+ pfn = m2p_find_override_pfn(mfn, ~0);
+ /* Handles events from front-end */
+-irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
+-void pciback_do_op(void *data);
++irqreturn_t pciback_handle_event(int irq, void *dev_id);
++void pciback_do_op(struct work_struct *data);
+
+ int pciback_xenbus_register(void);
+ void pciback_xenbus_unregister(void);
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 2d570e7..6624faf 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -66,9 +66,10 @@ void test_and_schedule_op(struct pciback_device *pdev)
+ * context because some of the pci_* functions can sleep (mostly due to ACPI
+ * use of semaphores). This function is intended to be called from a work
+ * queue in process context taking a struct pciback_device as a parameter */
+-void pciback_do_op(void *data)
+
-+ /*
-+ * pfn is ~0 if there are no entries in the m2p for mfn or if the
-+ * entry doesn't map back to the mfn and m2p_override doesn't have a
-+ * valid entry for it.
- */
-- if (get_phys_to_machine(pfn) != mfn)
-- pfn = m2p_find_override_pfn(mfn, pfn);
-+ if (pfn == ~0 &&
-+ get_phys_to_machine(mfn) == IDENTITY_FRAME(mfn))
-+ pfn = mfn;
++void pciback_do_op(struct work_struct *data)
+ {
+- struct pciback_device *pdev = data;
++ struct pciback_device *pdev = container_of(data, struct pciback_device, op_work);
+ struct pci_dev *dev;
+ struct xen_pci_op *op = &pdev->sh_info->op;
- return pfn;
+@@ -123,7 +124,7 @@ void pciback_do_op(void *data)
+ test_and_schedule_op(pdev);
}
+
+-irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t pciback_handle_event(int irq, void *dev_id)
+ {
+ struct pciback_device *pdev = dev_id;
+
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index bbca3fe..bd52289 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -9,6 +9,7 @@
+ #include <linux/vmalloc.h>
+ #include <xen/xenbus.h>
+ #include <xen/events.h>
++#include <linux/workqueue.h>
+ #include "pciback.h"
+
+ #define INVALID_EVTCHN_IRQ (-1)
+@@ -33,7 +34,7 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+ pdev->be_watching = 0;
+
+- INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
++ INIT_WORK(&pdev->op_work, pciback_do_op);
+
+ if (pciback_init_devices(pdev)) {
+ kfree(pdev);
--
1.7.4
-From d0783a02ef1bf28650f789b5b37ec1df42b53821 Mon Sep 17 00:00:00 2001
+From e0e72f5f5b3eff68c649c193d937fad54c7e956e Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 9 Dec 2010 15:01:11 -0500
-Subject: [PATCH 154/244] xen/irq: Don't fall over when nr_irqs_gsi > nr_irqs.
-
-This scenario where the nr_irq_gsi is greater than nr_irqs
-is rather strange but lets still try to survive. Make sure
-to print a warning so the user wouldn't be surprised in case
-things don't work.
-
-Solves a bootup-crash when booting Xen and Linux under QEMU.
+Date: Tue, 13 Oct 2009 17:22:26 -0400
+Subject: [PATCH 174/203] xen-pciback: Update the calling mechanism for
xenbus_[map|unmap]_ring_valloc functions.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/events.c | 9 +++++++++
- 1 files changed, 9 insertions(+), 0 deletions(-)
+ drivers/xen/pciback/pciback.h | 1 -
+ drivers/xen/pciback/xenbus.c | 18 +++++++++---------
+ 2 files changed, 9 insertions(+), 10 deletions(-)
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 7468147..6de2d76 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -414,6 +414,7 @@ static int find_unbound_irq(void)
- if (bottom == nr_irqs)
- goto no_irqs;
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index 4fb8c05..5e8e14e 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -36,7 +36,6 @@ struct pciback_device {
-+retry:
- /* This loop starts from the top of IRQ space and goes down.
- * We need this b/c if we have a PCI device in a Xen PV guest
- * we do not have an IO-APIC (though the backend might have them)
-@@ -437,6 +438,14 @@ static int find_unbound_irq(void)
- goto no_irqs;
+ int evtchn_irq;
- res = irq_alloc_desc_at(irq, -1);
-+ if (res == -EEXIST) {
-+ top--;
-+ if (bottom > top)
-+ printk(KERN_ERR "Eating in GSI/MSI space (%d)!" \
-+ " Your PCI device might not work!\n", top);
-+ if (top > NR_IRQS_LEGACY)
-+ goto retry;
-+ }
+- struct vm_struct *sh_area;
+ struct xen_pci_sharedinfo *sh_info;
- if (WARN_ON(res != irq))
- return -1;
+ unsigned long flags;
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index bd52289..5be1350 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -7,6 +7,7 @@
+ #include <linux/init.h>
+ #include <linux/list.h>
+ #include <linux/vmalloc.h>
++#include <linux/workqueue.h>
+ #include <xen/xenbus.h>
+ #include <xen/events.h>
+ #include <linux/workqueue.h>
+@@ -29,7 +30,6 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+
+ spin_lock_init(&pdev->dev_lock);
+
+- pdev->sh_area = NULL;
+ pdev->sh_info = NULL;
+ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+ pdev->be_watching = 0;
+@@ -59,7 +59,7 @@ static void pciback_disconnect(struct pciback_device *pdev)
+ flush_workqueue(pciback_wq);
+
+ if (pdev->sh_info != NULL) {
+- xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
++ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+ pdev->sh_info = NULL;
+ }
+
+@@ -85,23 +85,23 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
+ int remote_evtchn)
+ {
+ int err = 0;
+- struct vm_struct *area;
++ void *vaddr;
+
+ dev_dbg(&pdev->xdev->dev,
+ "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
+ gnt_ref, remote_evtchn);
+
+- area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
+- if (IS_ERR(area)) {
+- err = PTR_ERR(area);
++ err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr);
++ if (err < 0) {
++ xenbus_dev_fatal(pdev->xdev, err,
++ "Error mapping other domain page in ours.");
+ goto out;
+ }
+- pdev->sh_area = area;
+- pdev->sh_info = area->addr;
++ pdev->sh_info = vaddr;
+
+ err = bind_interdomain_evtchn_to_irqhandler(
+ pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
+- SA_SAMPLE_RANDOM, "pciback", pdev);
++ 0, "pciback", pdev);
+ if (err < 0) {
+ xenbus_dev_fatal(pdev->xdev, err,
+ "Error binding event channel to IRQ");
--
1.7.4
-From 4ab08528537b78a1b9696e9b2757d0e818d157a0 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 11 Jan 2011 17:20:13 +0000
-Subject: [PATCH 155/244] xen: handled remapped IRQs when enabling a pcifront PCI device.
-
-This happens to not be an issue currently because we take pains to try
-to ensure that the GSI-IRQ mapping is 1-1 in a PV guest and that
-regular event channels do not clash. However a subsequent patch is
-going to break this 1-1 mapping.
+From 2e44d1116767a69ce24b4909a074e38c97da7aeb Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 13 Oct 2009 17:22:30 -0400
+Subject: [PATCH 175/203] xen-pciback: Add check to load only under priviliged domain.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- arch/x86/pci/xen.c | 22 ++++++++++++++--------
- 1 files changed, 14 insertions(+), 8 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 5 +++++
+ drivers/xen/pciback/xenbus.c | 2 --
+ 2 files changed, 5 insertions(+), 2 deletions(-)
-diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
-index 25cd4a0..2a12f3d 100644
---- a/arch/x86/pci/xen.c
-+++ b/arch/x86/pci/xen.c
-@@ -226,21 +226,27 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index c02f21f..d97dac5 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -14,6 +14,8 @@
+ #include <linux/wait.h>
+ #include <asm/atomic.h>
+ #include <xen/events.h>
++#include <asm/xen/pci.h>
++#include <asm/xen/hypervisor.h>
+ #include "pciback.h"
+ #include "conf_space.h"
+ #include "conf_space_quirks.h"
+@@ -1286,6 +1288,9 @@ static int __init pciback_init(void)
{
- int rc;
- int share = 1;
-+ u8 gsi;
-
-- dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
--
-- if (dev->irq < 0)
-- return -EINVAL;
-+ rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi);
-+ if (rc < 0) {
-+ dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n",
-+ rc);
-+ return rc;
-+ }
-
-- if (dev->irq < NR_IRQS_LEGACY)
-+ if (gsi < NR_IRQS_LEGACY)
- share = 0;
+ int err;
-- rc = xen_allocate_pirq(dev->irq, share, "pcifront");
-+ rc = xen_allocate_pirq(gsi, share, "pcifront");
- if (rc < 0) {
-- dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
-- dev->irq, rc);
-+ dev_warn(&dev->dev, "Xen PCI: failed to register GSI%d: %d\n",
-+ gsi, rc);
- return rc;
- }
++ if (!xen_initial_domain())
++ return -ENODEV;
+
-+ dev->irq = rc;
-+ dev_info(&dev->dev, "Xen PCI mapped GSI%d to IRQ%d\n", gsi,
dev->irq);
- return 0;
- }
+ err = pciback_config_init();
+ if (err)
+ return err;
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index 5be1350..a85c413 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -693,8 +693,6 @@ static struct xenbus_driver xenbus_pciback_driver = {
+
+ int __init pciback_xenbus_register(void)
+ {
+- if (!is_running_on_xen())
+- return -ENODEV;
+ pciback_wq = create_workqueue("pciback_workqueue");
+ if (!pciback_wq) {
+ printk(KERN_ERR "pciback_xenbus_register: create"
+--
+1.7.4
+
+
+From e52f6bc512613c2a447b4e26ff66cf3810e4da33 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 13 Oct 2009 17:22:31 -0400
+Subject: [PATCH 176/203] xen-pciback: Remove usage of pci_restore_bars() as Linux handles
the power-up states correctly now.
+
+Originally this code was pulled from the upstream kernel, and stuck
+in the linux-2.6-sparse tree. At that point of time, the Linux tree (2.6.16?)
+did not know how to handle this. Nowadays the pci_set_power_state routine
+handles this case so we do not need this anymore.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/pciback/conf_space_capability_pm.c | 13 -------------
+ 1 files changed, 0 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/xen/pciback/conf_space_capability_pm.c
b/drivers/xen/pciback/conf_space_capability_pm.c
+index e2f99c7..e1d3af4 100644
+--- a/drivers/xen/pciback/conf_space_capability_pm.c
++++ b/drivers/xen/pciback/conf_space_capability_pm.c
+@@ -58,19 +58,6 @@ static int pm_ctrl_write(struct pci_dev *dev, int offset, u16
new_value,
+ goto out;
+ }
+- /*
+- * Device may lose PCI config info on D3->D0 transition. This
+- * is a problem for some guests which will not reset BARs. Even
+- * those that have a go will be foiled by our BAR-write handler
+- * which will discard the write! Since Linux won't re-init
+- * the config space automatically in all cases, we do it here.
+- * Future: Should we re-initialise all first 64 bytes of config space?
+- */
+- if (new_state == PCI_D0 &&
+- (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
+- !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
+- pci_restore_bars(dev);
+-
+ out:
+ return err;
+ }
--
1.7.4
-From 449913e7b40a40602cdc080ef3958736077d2914 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 11 Jan 2011 17:20:14 +0000
-Subject: [PATCH 156/244] xen:events: move find_unbound_irq inside CONFIG_PCI_MSI
+From 9c663bc577e3052cb0fdd2dfc7a7550be3897ce5 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 5 Nov 2009 15:25:43 -0500
+Subject: [PATCH 177/203] xen-pciback: Return the physical IRQ number instead of the
allocated IRQ number to pcifront.
-The only caller is xen_allocate_pirq_msi which is also under this
-ifdef so this fixes:
- drivers/xen/events.c:377: warning: 'find_unbound_pirq' defined but not used
-when CONFIG_PCI_MSI=n
+The allocation of IRQ numbers in Linux privileged domains is based
+on finding the first unbound IRQ number. After the allocation is done
+a HYPERCALL to Xen is done, which allocates a PIRQ globally.
+That PIRQ->IRQ binding is saved in data structures that are used
+during ISR executions.
+
+Before this patch, for non-privileged domains we would return the local
+IRQ number instead of the PIRQ. The non-privileged domains require the
+PIRQ so that they can attach the their own interrupt handler to it.
+Fortunatly there is a function, 'xen_gsi_from_irq' that returns
+that global IRQ number.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/events.c | 34 +++++++++++++++++-----------------
- 1 files changed, 17 insertions(+), 17 deletions(-)
+ drivers/xen/pciback/conf_space_capability_msi.c | 12 ++++++++----
+ 1 files changed, 8 insertions(+), 4 deletions(-)
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 6de2d76..8e28c01 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -387,23 +387,6 @@ static int get_nr_hw_irqs(void)
- return ret;
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+index 762e396..7fb5371 100644
+--- a/drivers/xen/pciback/conf_space_capability_msi.c
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -6,6 +6,7 @@
+ #include "conf_space.h"
+ #include "conf_space_capability.h"
+ #include <xen/interface/io/pciif.h>
++#include <xen/events.h>
+ #include "pciback.h"
+
+ int pciback_enable_msi(struct pciback_device *pdev,
+@@ -22,7 +23,9 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ return XEN_PCI_ERR_op_failed;
+ }
+
+- op->value = dev->irq;
++ /* The value the guest needs is actually the IDT vector, not the
++ * the local domain's IRQ number. */
++ op->value = xen_gsi_from_irq(dev->irq);
+ return 0;
}
--static int find_unbound_pirq(int type)
--{
-- int rc, i;
-- struct physdev_get_free_pirq op_get_free_pirq;
-- op_get_free_pirq.type = type;
--
-- rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
-- if (!rc)
-- return op_get_free_pirq.pirq;
--
-- for (i = 0; i < nr_irqs; i++) {
-- if (pirq_to_irq[i] < 0)
-- return i;
-- }
-- return -1;
--}
--
- static int find_unbound_irq(void)
+@@ -31,7 +34,7 @@ int pciback_disable_msi(struct pciback_device *pdev,
{
- struct irq_data *data;
-@@ -686,6 +669,23 @@ out:
- #include <linux/msi.h>
- #include "../pci/msi.h"
+ pci_disable_msi(dev);
+
+- op->value = dev->irq;
++ op->value = xen_gsi_from_irq(dev->irq);
+ return 0;
+ }
+
+@@ -57,7 +60,8 @@ int pciback_enable_msix(struct pciback_device *pdev,
+
+ for (i = 0; i < op->value; i++) {
+ op->msix_entries[i].entry = entries[i].entry;
+- op->msix_entries[i].vector = entries[i].vector;
++ op->msix_entries[i].vector =
++ xen_gsi_from_irq(entries[i].vector);
+ }
+
+ kfree(entries);
+@@ -73,7 +77,7 @@ int pciback_disable_msix(struct pciback_device *pdev,
+
+ pci_disable_msix(dev);
+
+- op->value = dev->irq;
++ op->value = xen_gsi_from_irq(dev->irq);
+ return 0;
+ }
-+static int find_unbound_pirq(int type)
-+{
-+ int rc, i;
-+ struct physdev_get_free_pirq op_get_free_pirq;
-+ op_get_free_pirq.type = type;
-+
-+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
-+ if (!rc)
-+ return op_get_free_pirq.pirq;
-+
-+ for (i = 0; i < nr_irqs; i++) {
-+ if (pirq_to_irq[i] < 0)
-+ return i;
-+ }
-+ return -1;
-+}
-+
- void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
- {
- spin_lock(&irq_mapping_update_lock);
--
1.7.4
-From 5a61eb864cdd63b8db29da707aa8e33b8dd54578 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 11 Jan 2011 17:20:15 +0000
-Subject: [PATCH 157/244] xen: events: add xen_allocate_irq_{dynamic, gsi} and
xen_free_irq
-
-This is neater than open-coded calls to irq_alloc_desc_at and
-irq_free_desc.
-
-No intended behavioural change.
-
-Note that we previously were not checking the return value of
-irq_alloc_desc_at which would be failing for GSI<NR_IRQS_LEGACY
-because the core architecture code has already allocated those for
-us. Hence the additional check against NR_IRQS_LEGACY in
-xen_allocate_irq_gsi.
+From f88da5c0e001b475b139501b10b9c6ef4b0d8f59 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 5 Nov 2009 15:25:44 -0500
+Subject: [PATCH 178/203] xen-pciback: Fix checkpatch warnings and errors for pciback/
directory.
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/events.c | 53 +++++++++++++++++++++++++++++++++-----------------
- 1 files changed, 35 insertions(+), 18 deletions(-)
+ drivers/xen/pciback/conf_space.c | 34 +++---
+ drivers/xen/pciback/conf_space.h | 30 ++--
+ drivers/xen/pciback/conf_space_capability.c | 5 +-
+ drivers/xen/pciback/conf_space_capability.h | 3 +
+ drivers/xen/pciback/conf_space_capability_msi.c | 3 +-
+ drivers/xen/pciback/conf_space_capability_pm.c | 4 +-
+ drivers/xen/pciback/conf_space_capability_vpd.c | 2 +-
+ drivers/xen/pciback/conf_space_header.c | 7 +-
+ drivers/xen/pciback/conf_space_quirks.c | 16 ++-
+ drivers/xen/pciback/controller.c | 15 +-
+ drivers/xen/pciback/passthrough.c | 6 +-
+ drivers/xen/pciback/pci_stub.c | 165 +++++++++++------------
+ drivers/xen/pciback/pciback.h | 28 +++--
+ drivers/xen/pciback/pciback_ops.c | 74 +++++------
+ drivers/xen/pciback/slot.c | 22 ++--
+ drivers/xen/pciback/vpci.c | 28 ++--
+ drivers/xen/pciback/xenbus.c | 42 +++---
+ 17 files changed, 245 insertions(+), 239 deletions(-)
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 8e28c01..e74bdcf 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -387,7 +387,7 @@ static int get_nr_hw_irqs(void)
- return ret;
+diff --git a/drivers/xen/pciback/conf_space.c b/drivers/xen/pciback/conf_space.c
+index 0c76db1..370c18e 100644
+--- a/drivers/xen/pciback/conf_space.c
++++ b/drivers/xen/pciback/conf_space.c
+@@ -18,11 +18,11 @@
+ static int permissive;
+ module_param(permissive, bool, 0644);
+
+-#define DEFINE_PCI_CONFIG(op,size,type) \
++#define DEFINE_PCI_CONFIG(op, size, type) \
+ int pciback_##op##_config_##size \
+ (struct pci_dev *dev, int offset, type value, void *data) \
+ { \
+- return pci_##op##_config_##size (dev, offset, value); \
++ return pci_##op##_config_##size(dev, offset, value); \
}
--static int find_unbound_irq(void)
-+static int xen_allocate_irq_dynamic(void)
+ DEFINE_PCI_CONFIG(read, byte, u8 *)
+@@ -139,14 +139,15 @@ static int pcibios_err_to_errno(int err)
+ }
+
+ int pciback_config_read(struct pci_dev *dev, int offset, int size,
+- u32 * ret_val)
++ u32 *ret_val)
{
- struct irq_data *data;
- int irq, res;
-@@ -445,6 +445,30 @@ static bool identity_mapped_irq(unsigned irq)
- return irq < get_nr_hw_irqs();
+ int err = 0;
+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
+ const struct config_field_entry *cfg_entry;
+ const struct config_field *field;
+ int req_start, req_end, field_start, field_end;
+- /* if read fails for any reason, return 0 (as if device didn't respond) */
++ /* if read fails for any reason, return 0
++ * (as if device didn't respond) */
+ u32 value = 0, tmp_val;
+
+ if (unlikely(verbose_request))
+@@ -161,10 +162,10 @@ int pciback_config_read(struct pci_dev *dev, int offset, int size,
+ /* Get the real value first, then modify as appropriate */
+ switch (size) {
+ case 1:
+- err = pci_read_config_byte(dev, offset, (u8 *) & value);
++ err = pci_read_config_byte(dev, offset, (u8 *) &value);
+ break;
+ case 2:
+- err = pci_read_config_word(dev, offset, (u16 *) & value);
++ err = pci_read_config_word(dev, offset, (u16 *) &value);
+ break;
+ case 4:
+ err = pci_read_config_dword(dev, offset, &value);
+@@ -192,7 +193,7 @@ int pciback_config_read(struct pci_dev *dev, int offset, int size,
+ }
+ }
+
+- out:
++out:
+ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
+ pci_name(dev), size, offset, value);
+@@ -276,8 +277,8 @@ int pciback_config_write(struct pci_dev *dev, int offset, int size,
u32 value)
+ } else if (!dev_data->warned_on_write) {
+ dev_data->warned_on_write = 1;
+ dev_warn(&dev->dev, "Driver tried to write to a "
+- "read-only configuration space field at offset "
+- "0x%x, size %d. This may be harmless, but if "
++ "read-only configuration space field at offset"
++ " 0x%x, size %d. This may be harmless, but if "
+ "you have problems with your device:\n"
+ "1) see permissive attribute in sysfs\n"
+ "2) report problems to the xen-devel "
+@@ -295,8 +296,8 @@ void pciback_config_free_dyn_fields(struct pci_dev *dev)
+ struct config_field_entry *cfg_entry, *t;
+ const struct config_field *field;
+
+- dev_dbg(&dev->dev,
+- "free-ing dynamically allocated virtual configuration space fields\n");
++ dev_dbg(&dev->dev, "free-ing dynamically allocated virtual "
++ "configuration space fields\n");
+ if (!dev_data)
+ return;
+
+@@ -306,8 +307,7 @@ void pciback_config_free_dyn_fields(struct pci_dev *dev)
+ if (field->clean) {
+ field->clean((struct config_field *)field);
+
+- if (cfg_entry->data)
+- kfree(cfg_entry->data);
++ kfree(cfg_entry->data);
+
+ list_del(&cfg_entry->list);
+ kfree(cfg_entry);
+@@ -376,7 +376,7 @@ int pciback_config_add_field_offset(struct pci_dev *dev,
+ cfg_entry->base_offset = base_offset;
+
+ /* silently ignore duplicate fields */
+- err = pciback_field_is_dup(dev,OFFSET(cfg_entry));
++ err = pciback_field_is_dup(dev, OFFSET(cfg_entry));
+ if (err)
+ goto out;
+
+@@ -395,14 +395,14 @@ int pciback_config_add_field_offset(struct pci_dev *dev,
+ OFFSET(cfg_entry));
+ list_add_tail(&cfg_entry->list, &dev_data->config_fields);
+
+- out:
++out:
+ if (err)
+ kfree(cfg_entry);
+
+ return err;
}
-+static int xen_allocate_irq_gsi(unsigned gsi)
-+{
-+ int irq;
-+
-+ if (!identity_mapped_irq(gsi) &&
-+ (xen_initial_domain() || !xen_pv_domain()))
-+ return xen_allocate_irq_dynamic();
-+
-+ /* Legacy IRQ descriptors are already allocated by the arch. */
-+ if (gsi < NR_IRQS_LEGACY)
-+ return gsi;
-+
-+ irq = irq_alloc_desc_at(gsi, -1);
-+ if (irq < 0)
-+ panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq);
-+
-+ return irq;
-+}
-+
-+static void xen_free_irq(unsigned irq)
-+{
-+ irq_free_desc(irq);
-+}
-+
- static void pirq_unmask_notify(int irq)
+-/* This sets up the device's virtual configuration space to keep track of
++/* This sets up the device's virtual configuration space to keep track of
+ * certain registers (like the base address registers (BARs) so that we can
+ * keep the client from manipulating them directly.
+ */
+@@ -425,7 +425,7 @@ int pciback_config_init_dev(struct pci_dev *dev)
+
+ err = pciback_config_quirks_init(dev);
+
+- out:
++out:
+ return err;
+ }
+
+diff --git a/drivers/xen/pciback/conf_space.h b/drivers/xen/pciback/conf_space.h
+index fe746ef..50ebef2 100644
+--- a/drivers/xen/pciback/conf_space.h
++++ b/drivers/xen/pciback/conf_space.h
+@@ -11,21 +11,21 @@
+ #include <linux/err.h>
+
+ /* conf_field_init can return an errno in a ptr with ERR_PTR() */
+-typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
+-typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
+-typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
++typedef void *(*conf_field_init) (struct pci_dev *dev, int offset);
++typedef void (*conf_field_reset) (struct pci_dev *dev, int offset, void *data);
++typedef void (*conf_field_free) (struct pci_dev *dev, int offset, void *data);
+
+-typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
++typedef int (*conf_dword_write) (struct pci_dev *dev, int offset, u32 value,
+ void *data);
+-typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
++typedef int (*conf_word_write) (struct pci_dev *dev, int offset, u16 value,
+ void *data);
+-typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
++typedef int (*conf_byte_write) (struct pci_dev *dev, int offset, u8 value,
+ void *data);
+-typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
++typedef int (*conf_dword_read) (struct pci_dev *dev, int offset, u32 *value,
+ void *data);
+-typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
++typedef int (*conf_word_read) (struct pci_dev *dev, int offset, u16 *value,
+ void *data);
+-typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
++typedef int (*conf_byte_read) (struct pci_dev *dev, int offset, u8 *value,
+ void *data);
+
+ /* These are the fields within the configuration space which we
+@@ -39,7 +39,7 @@ struct config_field {
+ conf_field_init init;
+ conf_field_reset reset;
+ conf_field_free release;
+- void (*clean) (struct config_field * field);
++ void (*clean) (struct config_field *field);
+ union {
+ struct {
+ conf_dword_write write;
+@@ -92,8 +92,8 @@ static inline int pciback_config_add_fields(struct pci_dev *dev,
+ }
+
+ static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
+- const struct config_field *field,
+- unsigned int offset)
++ const struct config_field *field,
++ unsigned int offset)
{
- struct physdev_eoi eoi = { .irq = pirq_from_irq(irq) };
-@@ -630,14 +654,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable,
char *name)
- goto out; /* XXX need refcount? */
+ int i, err = 0;
+ for (i = 0; field[i].size != 0; i++) {
+@@ -105,11 +105,11 @@ static inline int pciback_config_add_fields_offset(struct pci_dev
*dev,
+ }
+
+ /* Read/Write the real configuration space */
+-int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
++int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 *value,
+ void *data);
+-int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
++int pciback_read_config_word(struct pci_dev *dev, int offset, u16 *value,
+ void *data);
+-int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
++int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 *value,
+ void *data);
+ int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
+ void *data);
+diff --git a/drivers/xen/pciback/conf_space_capability.c
b/drivers/xen/pciback/conf_space_capability.c
+index 50efca4..0ea84d6 100644
+--- a/drivers/xen/pciback/conf_space_capability.c
++++ b/drivers/xen/pciback/conf_space_capability.c
+@@ -53,13 +53,10 @@ int pciback_config_capability_add_fields(struct pci_dev *dev)
+ }
}
-- /* If we are a PV guest, we don't have GSIs (no ACPI passed). Therefore
-- * we are using the !xen_initial_domain() to drop in the function.*/
-- if (identity_mapped_irq(gsi) || (!xen_initial_domain() &&
-- xen_pv_domain())) {
-- irq = gsi;
-- irq_alloc_desc_at(irq, -1);
-- } else
-- irq = find_unbound_irq();
-+ irq = xen_allocate_irq_gsi(gsi);
+- out:
++out:
+ return err;
+ }
+
+-extern struct pciback_config_capability pciback_config_capability_vpd;
+-extern struct pciback_config_capability pciback_config_capability_pm;
+-
+ int pciback_config_capability_init(void)
+ {
+ register_capability(&pciback_config_capability_vpd);
+diff --git a/drivers/xen/pciback/conf_space_capability.h
b/drivers/xen/pciback/conf_space_capability.h
+index 823392e..8da3ac4 100644
+--- a/drivers/xen/pciback/conf_space_capability.h
++++ b/drivers/xen/pciback/conf_space_capability.h
+@@ -20,4 +20,7 @@ struct pciback_config_capability {
+ const struct config_field *fields;
+ };
+
++extern struct pciback_config_capability pciback_config_capability_vpd;
++extern struct pciback_config_capability pciback_config_capability_pm;
++
+ #endif
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+index 7fb5371..b70ea8b 100644
+--- a/drivers/xen/pciback/conf_space_capability_msi.c
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -18,7 +18,8 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ status = pci_enable_msi(dev);
+
+ if (status) {
+- printk("error enable msi for guest %x status %x\n", otherend, status);
++ printk(KERN_ERR "error enable msi for guest %x status %x\n",
++ otherend, status);
+ op->value = 0;
+ return XEN_PCI_ERR_op_failed;
+ }
+diff --git a/drivers/xen/pciback/conf_space_capability_pm.c
b/drivers/xen/pciback/conf_space_capability_pm.c
+index e1d3af4..0442616 100644
+--- a/drivers/xen/pciback/conf_space_capability_pm.c
++++ b/drivers/xen/pciback/conf_space_capability_pm.c
+@@ -20,7 +20,7 @@ static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
+
+ *value = real_value & ~PCI_PM_CAP_PME_MASK;
+
+- out:
++out:
+ return err;
+ }
+
+@@ -77,7 +77,7 @@ static void *pm_ctrl_init(struct pci_dev *dev, int offset)
+ err = pci_write_config_word(dev, offset, value);
+ }
+
+- out:
++out:
+ return ERR_PTR(err);
+ }
+
+diff --git a/drivers/xen/pciback/conf_space_capability_vpd.c
b/drivers/xen/pciback/conf_space_capability_vpd.c
+index 920cb4a..e7b4d66 100644
+--- a/drivers/xen/pciback/conf_space_capability_vpd.c
++++ b/drivers/xen/pciback/conf_space_capability_vpd.c
+@@ -33,7 +33,7 @@ static const struct config_field caplist_vpd[] = {
+ },
+ {}
+ };
+-
++
+ struct pciback_config_capability pciback_config_capability_vpd = {
+ .capability = PCI_CAP_ID_VPD,
+ .fields = caplist_vpd,
+diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
+index 5a9e028..3ae7da1 100644
+--- a/drivers/xen/pciback/conf_space_header.c
++++ b/drivers/xen/pciback/conf_space_header.c
+@@ -51,7 +51,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value,
void *data)
+ err = pci_set_mwi(dev);
+ if (err) {
+ printk(KERN_WARNING
+- "pciback: %s: cannot enable memory-write-invalidate (%d)\n",
++ "pciback: %s: cannot enable "
++ "memory-write-invalidate (%d)\n",
+ pci_name(dev), err);
+ value &= ~PCI_COMMAND_INVALIDATE;
+ }
+@@ -206,7 +207,7 @@ static int bist_write(struct pci_dev *dev, int offset, u8 value, void
*data)
+ || value == PCI_BIST_START)
+ err = pci_write_config_byte(dev, offset, value);
- set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
- handle_level_irq, name);
-@@ -650,7 +667,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char
*name)
- * this in the priv domain. */
- if (xen_initial_domain() &&
- HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) {
-- irq_free_desc(irq);
-+ xen_free_irq(irq);
- irq = -ENOSPC;
- goto out;
- }
-@@ -691,7 +708,7 @@ void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int
alloc)
- spin_lock(&irq_mapping_update_lock);
+- out:
++out:
+ return err;
+ }
- if (alloc & XEN_ALLOC_IRQ) {
-- *irq = find_unbound_irq();
-+ *irq = xen_allocate_irq_dynamic();
- if (*irq == -1)
- goto out;
+@@ -312,6 +313,6 @@ int pciback_config_header_add_fields(struct pci_dev *dev)
+ break;
}
-@@ -741,7 +758,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
-
- spin_lock(&irq_mapping_update_lock);
-- irq = find_unbound_irq();
-+ irq = xen_allocate_irq_dynamic();
+- out:
++out:
+ return err;
+ }
+diff --git a/drivers/xen/pciback/conf_space_quirks.c
b/drivers/xen/pciback/conf_space_quirks.c
+index 244a438..45c31fb 100644
+--- a/drivers/xen/pciback/conf_space_quirks.c
++++ b/drivers/xen/pciback/conf_space_quirks.c
+@@ -18,8 +18,10 @@ match_one_device(const struct pci_device_id *id, const struct pci_dev
*dev)
+ {
+ if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
+ (id->device == PCI_ANY_ID || id->device == dev->device) &&
+- (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor)
&&
+- (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device)
&&
++ (id->subvendor == PCI_ANY_ID ||
++ id->subvendor == dev->subsystem_vendor) &&
++ (id->subdevice == PCI_ANY_ID ||
++ id->subdevice == dev->subsystem_device) &&
+ !((id->class ^ dev->class) & id->class_mask))
+ return id;
+ return NULL;
+@@ -35,7 +37,7 @@ struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
+ tmp_quirk = NULL;
+ printk(KERN_DEBUG
+ "quirk didn't match any device pciback knows about\n");
+- out:
++out:
+ return tmp_quirk;
+ }
- if (irq == -1)
- goto out;
-@@ -750,7 +767,7 @@ int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int type)
- if (rc) {
- printk(KERN_WARNING "xen map irq failed %d\n", rc);
+@@ -51,7 +53,7 @@ int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg)
+ struct config_field_entry *cfg_entry;
-- irq_free_desc(irq);
-+ xen_free_irq(irq);
+ list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
+- if ( OFFSET(cfg_entry) == reg) {
++ if (OFFSET(cfg_entry) == reg) {
+ ret = 1;
+ break;
+ }
+@@ -84,7 +86,7 @@ int pciback_config_quirks_add_field(struct pci_dev *dev, struct
config_field
- irq = -1;
- goto out;
-@@ -792,7 +809,7 @@ int xen_destroy_irq(int irq)
- }
- irq_info[irq] = mk_unbound_info();
+ pciback_config_add_field(dev, field);
-- irq_free_desc(irq);
-+ xen_free_irq(irq);
+- out:
++out:
+ return err;
+ }
- out:
- spin_unlock(&irq_mapping_update_lock);
-@@ -823,7 +840,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
- irq = evtchn_to_irq[evtchn];
+@@ -110,7 +112,7 @@ int pciback_config_quirks_init(struct pci_dev *dev)
+ quirk->pdev = dev;
- if (irq == -1) {
-- irq = find_unbound_irq();
-+ irq = xen_allocate_irq_dynamic();
+ register_quirk(quirk);
+- out:
++out:
+ return ret;
+ }
- set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
- handle_fasteoi_irq, "event");
-@@ -848,7 +865,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
- irq = per_cpu(ipi_to_irq, cpu)[ipi];
+@@ -133,6 +135,6 @@ int pciback_config_quirk_release(struct pci_dev *dev)
+ list_del(&quirk->quirks_list);
+ kfree(quirk);
- if (irq == -1) {
-- irq = find_unbound_irq();
-+ irq = xen_allocate_irq_dynamic();
- if (irq < 0)
+- out:
++out:
+ return ret;
+ }
+diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
+index 294e48f..7f04f11 100644
+--- a/drivers/xen/pciback/controller.c
++++ b/drivers/xen/pciback/controller.c
+@@ -259,7 +259,7 @@ static acpi_status write_xenbus_resource(struct acpi_resource *res,
void *data)
+ !(addr.resource_type == ACPI_IO_RANGE &&
+ addr.info.io.translation))
+ return AE_OK;
+-
++
+ /* Store the resource in xenbus for the guest */
+ len = snprintf(str, sizeof(str), "root-%d-resource-%d",
+ info->root_num, info->resource_count);
+@@ -314,7 +314,7 @@ int pciback_publish_pci_roots(struct pciback_device *pdev,
goto out;
-@@ -884,7 +901,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
- irq = per_cpu(virq_to_irq, cpu)[virq];
-
- if (irq == -1) {
-- irq = find_unbound_irq();
-+ irq = xen_allocate_irq_dynamic();
-
- set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
- handle_percpu_irq, "virq");
-@@ -943,7 +960,7 @@ static void unbind_from_irq(unsigned int irq)
- if (irq_info[irq].type != IRQT_UNBOUND) {
- irq_info[irq] = mk_unbound_info();
+ /*
+- * Now figure out which root-%d this belongs to
++ * Now figure out which root-%d this belongs to
+ * so we can associate resources with it.
+ */
+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
+@@ -407,8 +407,8 @@ void pciback_release_devices(struct pciback_device *pdev)
+ pdev->pci_dev_data = NULL;
+ }
-- irq_free_desc(irq);
-+ xen_free_irq(irq);
- }
+-int pciback_get_pcifront_dev(struct pci_dev *pcidev,
+- struct pciback_device *pdev,
++int pciback_get_pcifront_dev(struct pci_dev *pcidev,
++ struct pciback_device *pdev,
+ unsigned int *domain, unsigned int *bus, unsigned int *devfn)
+ {
+ struct controller_dev_data *dev_data = pdev->pci_dev_data;
+@@ -420,13 +420,12 @@ int pciback_get_pcifront_dev(struct pci_dev *pcidev,
- spin_unlock(&irq_mapping_update_lock);
---
-1.7.4
-
-
-From 026c9d2d0d75ec51b251aac4ca8855f4fae6af23 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Tue, 11 Jan 2011 17:20:16 +0000
-Subject: [PATCH 158/244] xen: events: allocate GSIs and dynamic IRQs from separate IRQ
ranges.
-
-There are three cases which we need to care about, PV guest, PV domain
-0 and HVM guest.
-
-The PV guest case is simple since it has no access to ACPI or real
-APICs and therefore has no GSIs therefore we simply dynamically
-allocate all IRQs. The potentially interesting case here is PIRQ type
-event channels associated with passed through PCI devices. However
-even in this case the guest has no direct interaction with the
-physical GSI since that happens in the PCI backend.
-
-The PV domain 0 and HVM guest cases are actually the same. In domain 0
-case the kernel sees the host ACPI and GSIs (although it only sees the
-APIC indirectly via the hypervisor) and in the HVM guest case it sees
-the virtualised ACPI and emulated APICs. In these cases we start
-allocating dynamic IRQs at nr_irqs_gsi so that they cannot clash with
-any GSI.
-
-Currently xen_allocate_irq_dynamic starts at nr_irqs and works
-backwards looking for a free IRQ in order to (try and) avoid clashing
-with GSIs used in domain 0 and in HVM guests. This change avoids that
-although we retain the behaviour of allowing dynamic IRQs to encroach
-on the GSI range if no suitable IRQs are available since a future IRQ
-clash is deemed preferable to failure right now.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Cc: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
----
- drivers/xen/events.c | 84 +++++++++++++++----------------------------------
- 1 files changed, 26 insertions(+), 58 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index e74bdcf..06f2e61 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -376,81 +376,49 @@ static void unmask_evtchn(int port)
- put_cpu();
+ list_for_each_entry(cntrl_entry, &dev_data->list, list) {
+ list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
+- if ( (dev_entry->dev->bus->number ==
++ if ((dev_entry->dev->bus->number ==
+ pcidev->bus->number) &&
+- (dev_entry->dev->devfn ==
++ (dev_entry->dev->devfn ==
+ pcidev->devfn) &&
+ (pci_domain_nr(dev_entry->dev->bus) ==
+- pci_domain_nr(pcidev->bus)))
+- {
++ pci_domain_nr(pcidev->bus))) {
+ found = 1;
+ *domain = cntrl_entry->domain;
+ *bus = cntrl_entry->bus;
+diff --git a/drivers/xen/pciback/passthrough.c b/drivers/xen/pciback/passthrough.c
+index 9e7a0c4..5386bebf 100644
+--- a/drivers/xen/pciback/passthrough.c
++++ b/drivers/xen/pciback/passthrough.c
+@@ -165,8 +165,10 @@ void pciback_release_devices(struct pciback_device *pdev)
+ pdev->pci_dev_data = NULL;
}
--static int get_nr_hw_irqs(void)
-+static int xen_allocate_irq_dynamic(void)
+-int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
+- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++int pciback_get_pcifront_dev(struct pci_dev *pcidev,
++ struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus,
++ unsigned int *devfn)
+
{
-- int ret = 1;
-+ int first = 0;
-+ int irq;
+ *domain = pci_domain_nr(pcidev->bus);
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index d97dac5..28222ee 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -20,7 +20,7 @@
+ #include "conf_space.h"
+ #include "conf_space_quirks.h"
- #ifdef CONFIG_X86_IO_APIC
-- ret = get_nr_irqs_gsi();
-+ /*
-+ * For an HVM guest or domain 0 which see "real" (emulated or
-+ * actual repectively) GSIs we allocate dynamic IRQs
-+ * e.g. those corresponding to event channels or MSIs
-+ * etc. from the range above those "real" GSIs to avoid
-+ * collisions.
-+ */
-+ if (xen_initial_domain() || xen_hvm_domain())
-+ first = get_nr_irqs_gsi();
- #endif
+-static char *pci_devs_to_hide = NULL;
++static char *pci_devs_to_hide;
+ wait_queue_head_t aer_wait_queue;
+ /*Add sem for sync AER handling and pciback remove/reconfigue ops,
+ * We want to avoid in middle of AER ops, pciback devices is being removed
+@@ -43,7 +43,7 @@ struct pcistub_device {
+ spinlock_t lock;
-- return ret;
--}
--
--static int xen_allocate_irq_dynamic(void)
--{
-- struct irq_data *data;
-- int irq, res;
-- int bottom = get_nr_hw_irqs();
-- int top = nr_irqs-1;
--
-- if (bottom == nr_irqs)
-- goto no_irqs;
--
- retry:
-- /* This loop starts from the top of IRQ space and goes down.
-- * We need this b/c if we have a PCI device in a Xen PV guest
-- * we do not have an IO-APIC (though the backend might have them)
-- * mapped in. To not have a collision of physical IRQs with the Xen
-- * event channels start at the top of the IRQ space for virtual IRQs.
-- */
-- for (irq = top; irq > bottom; irq--) {
-- data = irq_get_irq_data(irq);
-- /* only 15->0 have init'd desc; handle irq > 16 */
-- if (!data)
-- break;
-- if (data->chip == &no_irq_chip)
-- break;
-- if (data->chip != &xen_dynamic_chip)
-- continue;
-- if (irq_info[irq].type == IRQT_UNBOUND)
-- return irq;
-- }
-+ irq = irq_alloc_desc_from(first, -1);
+ struct pci_dev *dev;
+- struct pciback_device *pdev; /* non-NULL if struct pci_dev is in use */
++ struct pciback_device *pdev;/* non-NULL if struct pci_dev is in use */
+ };
-- if (irq == bottom)
-- goto no_irqs;
--
-- res = irq_alloc_desc_at(irq, -1);
-- if (res == -EEXIST) {
-- top--;
-- if (bottom > top)
-- printk(KERN_ERR "Eating in GSI/MSI space (%d)!" \
-- " Your PCI device might not work!\n", top);
-- if (top > NR_IRQS_LEGACY)
-- goto retry;
-+ if (irq == -ENOMEM && first > NR_IRQS_LEGACY) {
-+ printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should
increase nr_irqs\n");
-+ first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY);
-+ goto retry;
- }
+ /* Access to pcistub_devices & seized_devices lists and the initialize_devices
+@@ -55,7 +55,7 @@ static LIST_HEAD(pcistub_devices);
+ /* wait for device_initcall before initializing our devices
+ * (see pcistub_init_devices_late)
+ */
+-static int initialize_devices = 0;
++static int initialize_devices;
+ static LIST_HEAD(seized_devices);
-- if (WARN_ON(res != irq))
-- return -1;
-+ if (irq < 0)
-+ panic("No available IRQ to bind to: increase nr_irqs!\n");
+ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
+@@ -132,7 +132,7 @@ static struct pcistub_device *pcistub_device_find(int domain, int
bus,
+ /* didn't find it */
+ psdev = NULL;
- return irq;
--
--no_irqs:
-- panic("No available IRQ to bind to: increase nr_irqs!\n");
--}
--
--static bool identity_mapped_irq(unsigned irq)
--{
-- /* identity map all the hardware irqs */
-- return irq < get_nr_hw_irqs();
+- out:
++out:
+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
+ return psdev;
}
+@@ -321,10 +321,10 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
- static int xen_allocate_irq_gsi(unsigned gsi)
- {
- int irq;
+ return 0;
-- if (!identity_mapped_irq(gsi) &&
-- (xen_initial_domain() || !xen_pv_domain()))
-+ /*
-+ * A PV guest has no concept of a GSI (since it has no ACPI
-+ * nor access to/knowledge of the physical APICs). Therefore
-+ * all IRQs are dynamically allocated from the entire IRQ
-+ * space.
-+ */
-+ if (xen_pv_domain() && !xen_initial_domain())
- return xen_allocate_irq_dynamic();
+- config_release:
++config_release:
+ pciback_config_free_dev(dev);
- /* Legacy IRQ descriptors are already allocated by the arch. */
---
-1.7.4
-
-
-From d042c4b63ab93fb3089f2cc9f6628ab91b7b4073 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
-Date: Thu, 3 Feb 2011 09:49:35 +0000
-Subject: [PATCH 159/244] xen: events: do not free legacy IRQs
-
-c514d00c8057 "xen: events: add xen_allocate_irq_{dynamic, gsi} and
-xen_free_irq" correctly avoids reallocating legacy IRQs (which are
-managed by the arch core) but erroneously did not prevent them being
-freed.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 4 ++++
- 1 files changed, 4 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 06f2e61..accb37a 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -434,6 +434,10 @@ static int xen_allocate_irq_gsi(unsigned gsi)
+- out:
++out:
+ pci_set_drvdata(dev, NULL);
+ kfree(dev_data);
+ return err;
+@@ -443,7 +443,7 @@ static int __devinit pcistub_probe(struct pci_dev *dev,
+ /* Didn't find the device */
+ err = -ENODEV;
- static void xen_free_irq(unsigned irq)
- {
-+ /* Legacy IRQ descriptors are managed by the arch. */
-+ if (irq < NR_IRQS_LEGACY)
-+ return;
-+
- irq_free_desc(irq);
+- out:
++out:
+ return err;
}
---
-1.7.4
-
-
-From 6e435118ec43bbd781df48ceef101d8f1a48e699 Mon Sep 17 00:00:00 2001
-From: Thomas Gleixner <tglx(a)linutronix.de>
-Date: Sat, 5 Feb 2011 20:08:52 +0000
-Subject: [PATCH 160/244] xen: Remove stale irq_chip.end
-
-irq_chip.end got obsolete with the removal of __do_IRQ()
-
-Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
-Acked-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 18 ------------------
- 1 files changed, 0 insertions(+), 18 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index accb37a..c8826b5 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -555,23 +555,6 @@ static void ack_pirq(unsigned int irq)
+@@ -511,26 +511,24 @@ static void kill_domain_by_device(struct pcistub_device *psdev)
+ int err;
+ char nodename[1024];
+
+- if (!psdev)
++ if (!psdev)
+ dev_err(&psdev->dev->dev,
+ "device is NULL when do AER recovery/kill_domain\n");
+- sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
++ sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
+ psdev->pdev->xdev->otherend_id);
+ nodename[strlen(nodename)] = '\0';
+
+ again:
+ err = xenbus_transaction_start(&xbt);
+- if (err)
+- {
++ if (err) {
+ dev_err(&psdev->dev->dev,
+ "error %d when start xenbus transaction\n", err);
+ return;
}
- }
+ /*PV AER handlers will set this flag*/
+- xenbus_printf(xbt, nodename, "aerState" , "aerfail" );
++ xenbus_printf(xbt, nodename, "aerState" , "aerfail");
+ err = xenbus_transaction_end(xbt, 0);
+- if (err)
+- {
++ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ dev_err(&psdev->dev->dev,
+@@ -541,9 +539,9 @@ again:
+
+ /* For each aer recovery step error_detected, mmio_enabled, etc, front_end and
+ * backend need to have cooperation. In pciback, those steps will do similar
+- * jobs: send service request and waiting for front_end response.
++ * jobs: send service request and waiting for front_end response.
+ */
+-static pci_ers_result_t common_process(struct pcistub_device *psdev,
++static pci_ers_result_t common_process(struct pcistub_device *psdev,
+ pci_channel_state_t state, int aer_cmd, pci_ers_result_t result)
+ {
+ pci_ers_result_t res = result;
+@@ -561,12 +559,12 @@ static pci_ers_result_t common_process(struct pcistub_device
*psdev,
+ if (!ret) {
+ dev_err(&psdev->dev->dev,
+ "pciback: failed to get pcifront device\n");
+- return PCI_ERS_RESULT_NONE;
++ return PCI_ERS_RESULT_NONE;
+ }
+ wmb();
+
+- dev_dbg(&psdev->dev->dev,
+- "pciback: aer_op %x dom %x bus %x devfn %x\n",
++ dev_dbg(&psdev->dev->dev,
++ "pciback: aer_op %x dom %x bus %x devfn %x\n",
+ aer_cmd, aer_op->domain, aer_op->bus, aer_op->devfn);
+ /*local flag to mark there's aer request, pciback callback will use this
+ * flag to judge whether we need to check pci-front give aer service
+@@ -575,21 +573,21 @@ static pci_ers_result_t common_process(struct pcistub_device
*psdev,
+ set_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
+
+ /*It is possible that a pcifront conf_read_write ops request invokes
+- * the callback which cause the spurious execution of wake_up.
++ * the callback which cause the spurious execution of wake_up.
+ * Yet it is harmless and better than a spinlock here
+ */
+- set_bit(_XEN_PCIB_active,
++ set_bit(_XEN_PCIB_active,
+ (unsigned long *)&psdev->pdev->sh_info->flags);
+ wmb();
+ notify_remote_via_irq(psdev->pdev->evtchn_irq);
+
+ ret = wait_event_timeout(aer_wait_queue, !(test_bit(_XEN_PCIB_active,
+- (unsigned long *)&psdev->pdev->sh_info->flags)), 300*HZ);
++ (unsigned long *)&psdev->pdev->sh_info->flags)), 300*HZ);
--static void end_pirq(unsigned int irq)
--{
-- int evtchn = evtchn_from_irq(irq);
-- struct irq_desc *desc = irq_to_desc(irq);
--
-- if (WARN_ON(!desc))
-- return;
--
-- if ((desc->status & (IRQ_DISABLED|IRQ_PENDING)) ==
-- (IRQ_DISABLED|IRQ_PENDING)) {
-- shutdown_pirq(irq);
-- } else if (VALID_EVTCHN(evtchn)) {
-- unmask_evtchn(evtchn);
-- pirq_unmask_notify(irq);
-- }
--}
--
- static int find_irq_by_gsi(unsigned gsi)
- {
- int irq;
-@@ -1508,7 +1491,6 @@ static struct irq_chip xen_pirq_chip __read_mostly = {
- .mask = disable_pirq,
+ if (!ret) {
+- if (test_bit(_XEN_PCIB_active,
++ if (test_bit(_XEN_PCIB_active,
+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
+- dev_err(&psdev->dev->dev,
++ dev_err(&psdev->dev->dev,
+ "pcifront aer process not responding!\n");
+ clear_bit(_XEN_PCIB_active,
+ (unsigned long *)&psdev->pdev->sh_info->flags);
+@@ -599,16 +597,16 @@ static pci_ers_result_t common_process(struct pcistub_device
*psdev,
+ }
+ clear_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
- .ack = ack_pirq,
-- .end = end_pirq,
+- if ( test_bit( _XEN_PCIF_active,
+- (unsigned long*)&psdev->pdev->sh_info->flags)) {
+- dev_dbg(&psdev->dev->dev,
++ if (test_bit(_XEN_PCIF_active,
++ (unsigned long *)&psdev->pdev->sh_info->flags)) {
++ dev_dbg(&psdev->dev->dev,
+ "schedule pci_conf service in pciback \n");
+ test_and_schedule_op(psdev->pdev);
+ }
- .set_affinity = set_affinity_irq,
+ res = (pci_ers_result_t)aer_op->err;
+ return res;
+-}
++}
---
-1.7.4
-
-
-From ab1d37664458dd36cbf7e8a81cc4199b25937142 Mon Sep 17 00:00:00 2001
-From: Thomas Gleixner <tglx(a)linutronix.de>
-Date: Sat, 5 Feb 2011 20:08:54 +0000
-Subject: [PATCH 161/244] xen: Switch to new irq_chip functions
-
-Convert Xen to the new irq_chip functions. Brings us closer to enable
-CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
-
-Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
-Acked-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 95 +++++++++++++++++++++++++++-----------------------
- 1 files changed, 51 insertions(+), 44 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index c8826b5..cf1712f 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -277,7 +277,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+ /*
+ * pciback_slot_reset: it will send the slot_reset request to pcifront in case
+@@ -632,24 +630,22 @@ static pci_ers_result_t pciback_slot_reset(struct pci_dev *dev)
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
- BUG_ON(irq == -1);
- #ifdef CONFIG_SMP
-- cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
-+ cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
- #endif
+- if ( !psdev || !psdev->pdev )
+- {
+- dev_err(&dev->dev,
++ if (!psdev || !psdev->pdev) {
++ dev_err(&dev->dev,
+ "pciback device is not found/assigned\n");
+ goto end;
+ }
- clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
-@@ -294,7 +294,7 @@ static void init_evtchn_cpu_bindings(void)
+- if ( !psdev->pdev->sh_info )
+- {
++ if (!psdev->pdev->sh_info) {
+ dev_err(&dev->dev, "pciback device is not connected or owned"
+ " by HVM, kill it\n");
+ kill_domain_by_device(psdev);
+ goto release;
+ }
- /* By default all event channels notify CPU#0. */
- for_each_irq_desc(i, desc) {
-- cpumask_copy(desc->affinity, cpumask_of(0));
-+ cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
+- if ( !test_bit(_XEN_PCIB_AERHANDLER,
+- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
+- dev_err(&dev->dev,
++ if (!test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags)) {
++ dev_err(&dev->dev,
+ "guest with no AER driver should have been killed\n");
+ goto release;
}
- #endif
+@@ -657,7 +653,7 @@ static pci_ers_result_t pciback_slot_reset(struct pci_dev *dev)
-@@ -474,7 +474,7 @@ static bool probing_irq(int irq)
- return desc && desc->action == NULL;
+ if (result == PCI_ERS_RESULT_NONE ||
+ result == PCI_ERS_RESULT_DISCONNECT) {
+- dev_dbg(&dev->dev,
++ dev_dbg(&dev->dev,
+ "No AER slot_reset service or disconnected!\n");
+ kill_domain_by_device(psdev);
+ }
+@@ -670,9 +666,9 @@ end:
}
--static unsigned int startup_pirq(unsigned int irq)
-+static unsigned int __startup_pirq(unsigned int irq)
- {
- struct evtchn_bind_pirq bind_pirq;
- struct irq_info *info = info_for_irq(irq);
-@@ -512,9 +512,15 @@ out:
- return 0;
- }
--static void shutdown_pirq(unsigned int irq)
-+static unsigned int startup_pirq(struct irq_data *data)
-+{
-+ return __startup_pirq(data->irq);
-+}
-+
-+static void shutdown_pirq(struct irq_data *data)
- {
- struct evtchn_close close;
-+ unsigned int irq = data->irq;
- struct irq_info *info = info_for_irq(irq);
- int evtchn = evtchn_from_irq(irq);
+-/*pciback_mmio_enabled: it will send the mmio_enabled request to pcifront
+-* in case of the device driver could provide this service, and then wait
+-* for pcifront ack.
++/*pciback_mmio_enabled: it will send the mmio_enabled request to pcifront
++* in case of the device driver could provide this service, and then wait
++* for pcifront ack
+ * @dev: pointer to PCI devices
+ * return value is used by aer_core do_recovery policy
+ */
+@@ -692,24 +688,22 @@ static pci_ers_result_t pciback_mmio_enabled(struct pci_dev *dev)
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
-@@ -534,20 +540,20 @@ static void shutdown_pirq(unsigned int irq)
- info->evtchn = 0;
- }
+- if ( !psdev || !psdev->pdev )
+- {
+- dev_err(&dev->dev,
++ if (!psdev || !psdev->pdev) {
++ dev_err(&dev->dev,
+ "pciback device is not found/assigned\n");
+ goto end;
+ }
--static void enable_pirq(unsigned int irq)
-+static void enable_pirq(struct irq_data *data)
- {
-- startup_pirq(irq);
-+ startup_pirq(data);
- }
+- if ( !psdev->pdev->sh_info )
+- {
++ if (!psdev->pdev->sh_info) {
+ dev_err(&dev->dev, "pciback device is not connected or owned"
+ " by HVM, kill it\n");
+ kill_domain_by_device(psdev);
+ goto release;
+ }
--static void disable_pirq(unsigned int irq)
-+static void disable_pirq(struct irq_data *data)
- {
+- if ( !test_bit(_XEN_PCIB_AERHANDLER,
+- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
+- dev_err(&dev->dev,
++ if (!test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags)) {
++ dev_err(&dev->dev,
+ "guest with no AER driver should have been killed\n");
+ goto release;
+ }
+@@ -717,7 +711,7 @@ static pci_ers_result_t pciback_mmio_enabled(struct pci_dev *dev)
+
+ if (result == PCI_ERS_RESULT_NONE ||
+ result == PCI_ERS_RESULT_DISCONNECT) {
+- dev_dbg(&dev->dev,
++ dev_dbg(&dev->dev,
+ "No AER mmio_enabled service or disconnected!\n");
+ kill_domain_by_device(psdev);
+ }
+@@ -728,8 +722,8 @@ end:
+ return result;
}
--static void ack_pirq(unsigned int irq)
-+static void ack_pirq(struct irq_data *data)
- {
-- int evtchn = evtchn_from_irq(irq);
-+ int evtchn = evtchn_from_irq(data->irq);
+-/*pciback_error_detected: it will send the error_detected request to pcifront
+-* in case of the device driver could provide this service, and then wait
++/*pciback_error_detected: it will send the error_detected request to pcifront
++* in case of the device driver could provide this service, and then wait
+ * for pcifront ack.
+ * @dev: pointer to PCI devices
+ * @error: the current PCI connection state
+@@ -752,15 +746,13 @@ static pci_ers_result_t pciback_error_detected(struct pci_dev
*dev,
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
-- move_native_irq(irq);
-+ irq_move_irq(data);
+- if ( !psdev || !psdev->pdev )
+- {
+- dev_err(&dev->dev,
++ if (!psdev || !psdev->pdev) {
++ dev_err(&dev->dev,
+ "pciback device is not found/assigned\n");
+ goto end;
+ }
- if (VALID_EVTCHN(evtchn)) {
- mask_evtchn(evtchn);
-@@ -1215,11 +1221,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
- return 0;
- }
+- if ( !psdev->pdev->sh_info )
+- {
++ if (!psdev->pdev->sh_info) {
+ dev_err(&dev->dev, "pciback device is not connected or owned"
+ " by HVM, kill it\n");
+ kill_domain_by_device(psdev);
+@@ -768,8 +760,8 @@ static pci_ers_result_t pciback_error_detected(struct pci_dev *dev,
+ }
--static int set_affinity_irq(unsigned irq, const struct cpumask *dest)
-+static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
-+ bool force)
- {
- unsigned tcpu = cpumask_first(dest);
+ /*Guest owns the device yet no aer handler regiested, kill guest*/
+- if ( !test_bit(_XEN_PCIB_AERHANDLER,
+- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
++ if (!test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags)) {
+ dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n");
+ kill_domain_by_device(psdev);
+ goto release;
+@@ -778,7 +770,7 @@ static pci_ers_result_t pciback_error_detected(struct pci_dev *dev,
-- return rebind_irq_to_cpu(irq, tcpu);
-+ return rebind_irq_to_cpu(data->irq, tcpu);
+ if (result == PCI_ERS_RESULT_NONE ||
+ result == PCI_ERS_RESULT_DISCONNECT) {
+- dev_dbg(&dev->dev,
++ dev_dbg(&dev->dev,
+ "No AER error_detected service or disconnected!\n");
+ kill_domain_by_device(psdev);
+ }
+@@ -789,8 +781,8 @@ end:
+ return result;
}
- int resend_irq_on_evtchn(unsigned int irq)
-@@ -1238,35 +1245,35 @@ int resend_irq_on_evtchn(unsigned int irq)
- return 1;
- }
+-/*pciback_error_resume: it will send the error_resume request to pcifront
+-* in case of the device driver could provide this service, and then wait
++/*pciback_error_resume: it will send the error_resume request to pcifront
++* in case of the device driver could provide this service, and then wait
+ * for pcifront ack.
+ * @dev: pointer to PCI devices
+ */
+@@ -808,29 +800,28 @@ static void pciback_error_resume(struct pci_dev *dev)
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
--static void enable_dynirq(unsigned int irq)
-+static void enable_dynirq(struct irq_data *data)
- {
-- int evtchn = evtchn_from_irq(irq);
-+ int evtchn = evtchn_from_irq(data->irq);
+- if ( !psdev || !psdev->pdev )
+- {
+- dev_err(&dev->dev,
++ if (!psdev || !psdev->pdev) {
++ dev_err(&dev->dev,
+ "pciback device is not found/assigned\n");
+ goto end;
+ }
- if (VALID_EVTCHN(evtchn))
- unmask_evtchn(evtchn);
- }
+- if ( !psdev->pdev->sh_info )
+- {
++ if (!psdev->pdev->sh_info) {
+ dev_err(&dev->dev, "pciback device is not connected or owned"
+ " by HVM, kill it\n");
+ kill_domain_by_device(psdev);
+ goto release;
+ }
--static void disable_dynirq(unsigned int irq)
-+static void disable_dynirq(struct irq_data *data)
- {
-- int evtchn = evtchn_from_irq(irq);
-+ int evtchn = evtchn_from_irq(data->irq);
+- if ( !test_bit(_XEN_PCIB_AERHANDLER,
+- (unsigned long *)&psdev->pdev->sh_info->flags) ) {
+- dev_err(&dev->dev,
++ if (!test_bit(_XEN_PCIB_AERHANDLER,
++ (unsigned long *)&psdev->pdev->sh_info->flags)) {
++ dev_err(&dev->dev,
+ "guest with no AER driver should have been killed\n");
+ kill_domain_by_device(psdev);
+ goto release;
+ }
+- common_process(psdev, 1, XEN_PCI_OP_aer_resume, PCI_ERS_RESULT_RECOVERED);
++ common_process(psdev, 1, XEN_PCI_OP_aer_resume,
++ PCI_ERS_RESULT_RECOVERED);
+ release:
+ pcistub_device_put(psdev);
+ end:
+@@ -923,8 +914,8 @@ static int pcistub_device_id_remove(int domain, int bus, int slot,
int func)
+ unsigned long flags;
- if (VALID_EVTCHN(evtchn))
- mask_evtchn(evtchn);
+ spin_lock_irqsave(&device_ids_lock, flags);
+- list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
+-
++ list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids,
++ slot_list) {
+ if (pci_dev_id->domain == domain
+ && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
+ /* Don't break; here because it's possible the same
+@@ -976,7 +967,7 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func,
int reg,
+ err = pciback_config_quirks_add_field(dev, field);
+ if (err)
+ kfree(field);
+- out:
++out:
+ return err;
}
--static void ack_dynirq(unsigned int irq)
-+static void ack_dynirq(struct irq_data *data)
- {
-- int evtchn = evtchn_from_irq(irq);
-+ int evtchn = evtchn_from_irq(data->irq);
+@@ -992,7 +983,7 @@ static ssize_t pcistub_slot_add(struct device_driver *drv, const char
*buf,
-- move_masked_irq(irq);
-+ move_masked_irq(data->irq);
+ err = pcistub_device_id_add(domain, bus, slot, func);
- if (VALID_EVTCHN(evtchn))
- unmask_evtchn(evtchn);
- }
+- out:
++out:
+ if (!err)
+ err = count;
+ return err;
+@@ -1012,7 +1003,7 @@ static ssize_t pcistub_slot_remove(struct device_driver *drv, const
char *buf,
--static int retrigger_dynirq(unsigned int irq)
-+static int retrigger_dynirq(struct irq_data *data)
- {
-- int evtchn = evtchn_from_irq(irq);
-+ int evtchn = evtchn_from_irq(data->irq);
- struct shared_info *sh = HYPERVISOR_shared_info;
- int ret = 0;
+ err = pcistub_device_id_remove(domain, bus, slot, func);
-@@ -1315,7 +1322,7 @@ static void restore_cpu_pirqs(void)
+- out:
++out:
+ if (!err)
+ err = count;
+ return err;
+@@ -1057,7 +1048,7 @@ static ssize_t pcistub_quirk_add(struct device_driver *drv, const
char *buf,
- printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
+ err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
-- startup_pirq(irq);
-+ __startup_pirq(irq);
+- out:
++out:
+ if (!err)
+ err = count;
+ return err;
+@@ -1067,7 +1058,6 @@ static ssize_t pcistub_quirk_show(struct device_driver *drv, char
*buf)
+ {
+ int count = 0;
+ unsigned long flags;
+- extern struct list_head pciback_quirks;
+ struct pciback_config_quirk *quirk;
+ struct pciback_dev_data *dev_data;
+ const struct config_field *field;
+@@ -1096,12 +1086,13 @@ static ssize_t pcistub_quirk_show(struct device_driver *drv, char
*buf)
+
+ count += scnprintf(buf + count, PAGE_SIZE - count,
+ "\t\t%08x:%01x:%08x\n",
+- cfg_entry->base_offset + field->offset,
+- field->size, field->mask);
++ cfg_entry->base_offset +
++ field->offset, field->size,
++ field->mask);
+ }
}
- }
-@@ -1467,44 +1474,44 @@ void xen_irq_resume(void)
- }
+- out:
++out:
+ spin_unlock_irqrestore(&device_ids_lock, flags);
- static struct irq_chip xen_dynamic_chip __read_mostly = {
-- .name = "xen-dyn",
-+ .name = "xen-dyn",
+ return count;
+@@ -1137,14 +1128,14 @@ static ssize_t permissive_add(struct device_driver *drv, const
char *buf,
+ if (!dev_data->permissive) {
+ dev_data->permissive = 1;
+ /* Let user know that what they're doing could be unsafe */
+- dev_warn(&psdev->dev->dev,
+- "enabling permissive mode configuration space accesses!\n");
++ dev_warn(&psdev->dev->dev, "enabling permissive mode "
++ "configuration space accesses!\n");
+ dev_warn(&psdev->dev->dev,
+ "permissive mode is potentially unsafe!\n");
+ }
+- release:
++release:
+ pcistub_device_put(psdev);
+- out:
++out:
+ if (!err)
+ err = count;
+ return err;
+@@ -1264,10 +1255,10 @@ static int __init pcistub_init(void)
+ if (err)
+ pcistub_exit();
-- .disable = disable_dynirq,
-- .mask = disable_dynirq,
-- .unmask = enable_dynirq,
-+ .irq_disable = disable_dynirq,
-+ .irq_mask = disable_dynirq,
-+ .irq_unmask = enable_dynirq,
+- out:
++out:
+ return err;
-- .eoi = ack_dynirq,
-- .set_affinity = set_affinity_irq,
-- .retrigger = retrigger_dynirq,
-+ .irq_eoi = ack_dynirq,
-+ .irq_set_affinity = set_affinity_irq,
-+ .irq_retrigger = retrigger_dynirq,
+- parse_error:
++parse_error:
+ printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at
\"%s\"\n",
+ pci_devs_to_hide + pos);
+ return -EINVAL;
+@@ -1276,7 +1267,7 @@ static int __init pcistub_init(void)
+ #ifndef MODULE
+ /*
+ * fs_initcall happens before device_initcall
+- * so pciback *should* get called first (b/c we
++ * so pciback *should* get called first (b/c we
+ * want to suck up any device before other drivers
+ * get a chance by being the first pci device
+ * driver to register)
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index 5e8e14e..98e2912 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -49,6 +49,12 @@ struct pciback_dev_data {
+ int warned_on_write;
};
- static struct irq_chip xen_pirq_chip __read_mostly = {
-- .name = "xen-pirq",
-+ .name = "xen-pirq",
++/* Used by XenBus and pciback_ops.c */
++extern wait_queue_head_t aer_wait_queue;
++extern struct workqueue_struct *pciback_wq;
++/* Used by pcistub.c and conf_space_quirks.c */
++extern struct list_head pciback_quirks;
++
+ /* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
+ struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
+ int domain, int bus,
+@@ -67,14 +73,14 @@ void pciback_config_free_dyn_fields(struct pci_dev *dev);
+ void pciback_config_reset_dev(struct pci_dev *dev);
+ void pciback_config_free_dev(struct pci_dev *dev);
+ int pciback_config_read(struct pci_dev *dev, int offset, int size,
+- u32 * ret_val);
++ u32 *ret_val);
+ int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
+
+ /* Handle requests for specific devices from the frontend */
+ typedef int (*publish_pci_dev_cb) (struct pciback_device *pdev,
+ unsigned int domain, unsigned int bus,
+ unsigned int devfn, unsigned int devid);
+-typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
++typedef int (*publish_pci_root_cb) (struct pciback_device *pdev,
+ unsigned int domain, unsigned int bus);
+ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
+ int devid, publish_pci_dev_cb publish_cb);
+@@ -83,15 +89,17 @@ struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+ unsigned int domain, unsigned int bus,
+ unsigned int devfn);
+
+-/**
++/**
+ * Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in pciback
+-* before sending aer request to pcifront, so that guest could identify
++* before sending aer request to pcifront, so that guest could identify
+ * device, coopearte with pciback to finish aer recovery job if device driver
+ * has the capability
+ */
-- .startup = startup_pirq,
-- .shutdown = shutdown_pirq,
-+ .irq_startup = startup_pirq,
-+ .irq_shutdown = shutdown_pirq,
+-int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
+- unsigned int *domain, unsigned int *bus, unsigned int *devfn);
++int pciback_get_pcifront_dev(struct pci_dev *pcidev,
++ struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus,
++ unsigned int *devfn);
+ int pciback_init_devices(struct pciback_device *pdev);
+ int pciback_publish_pci_roots(struct pciback_device *pdev,
+ publish_pci_root_cb cb);
+@@ -106,17 +114,17 @@ void pciback_xenbus_unregister(void);
-- .enable = enable_pirq,
-- .unmask = enable_pirq,
-+ .irq_enable = enable_pirq,
-+ .irq_unmask = enable_pirq,
+ #ifdef CONFIG_PCI_MSI
+ int pciback_enable_msi(struct pciback_device *pdev,
+- struct pci_dev *dev, struct xen_pci_op *op);
++ struct pci_dev *dev, struct xen_pci_op *op);
-- .disable = disable_pirq,
-- .mask = disable_pirq,
-+ .irq_disable = disable_pirq,
-+ .irq_mask = disable_pirq,
+ int pciback_disable_msi(struct pciback_device *pdev,
+- struct pci_dev *dev, struct xen_pci_op *op);
++ struct pci_dev *dev, struct xen_pci_op *op);
-- .ack = ack_pirq,
-+ .irq_ack = ack_pirq,
-- .set_affinity = set_affinity_irq,
-+ .irq_set_affinity = set_affinity_irq,
+ int pciback_enable_msix(struct pciback_device *pdev,
+- struct pci_dev *dev, struct xen_pci_op *op);
++ struct pci_dev *dev, struct xen_pci_op *op);
-- .retrigger = retrigger_dynirq,
-+ .irq_retrigger = retrigger_dynirq,
- };
+ int pciback_disable_msix(struct pciback_device *pdev,
+- struct pci_dev *dev, struct xen_pci_op *op);
++ struct pci_dev *dev, struct xen_pci_op *op);
+ #endif
+ extern int verbose_request;
- static struct irq_chip xen_percpu_chip __read_mostly = {
-- .name = "xen-percpu",
-+ .name = "xen-percpu",
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 6624faf..bf83dca 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -5,11 +5,11 @@
+ */
+ #include <linux/module.h>
+ #include <linux/wait.h>
+-#include <asm/bitops.h>
++#include <linux/bitops.h>
+ #include <xen/events.h>
+ #include "pciback.h"
-- .disable = disable_dynirq,
-- .mask = disable_dynirq,
-- .unmask = enable_dynirq,
-+ .irq_disable = disable_dynirq,
-+ .irq_mask = disable_dynirq,
-+ .irq_unmask = enable_dynirq,
+-int verbose_request = 0;
++int verbose_request;
+ module_param(verbose_request, int, 0644);
-- .ack = ack_dynirq,
-+ .irq_ack = ack_dynirq,
- };
+ /* Ensure a device is "turned off" and ready to be exported.
+@@ -37,12 +37,10 @@ void pciback_reset_device(struct pci_dev *dev)
+ }
+ }
+ }
+-extern wait_queue_head_t aer_wait_queue;
+-extern struct workqueue_struct *pciback_wq;
+ /*
+ * Now the same evtchn is used for both pcifront conf_read_write request
+ * as well as pcie aer front end ack. We use a new work_queue to schedule
+-* pciback conf_read_write service for avoiding confict with aer_core
++* pciback conf_read_write service for avoiding confict with aer_core
+ * do_recovery job which also use the system default work_queue
+ */
+ void test_and_schedule_op(struct pciback_device *pdev)
+@@ -50,14 +48,13 @@ void test_and_schedule_op(struct pciback_device *pdev)
+ /* Check that frontend is requesting an operation and that we are not
+ * already processing a request */
+ if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
+- && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
+- {
++ && !test_and_set_bit(_PDEVF_op_active, &pdev->flags)) {
+ queue_work(pciback_wq, &pdev->op_work);
+ }
+ /*_XEN_PCIB_active should have been cleared by pcifront. And also make
+ sure pciback is waiting for ack by checking _PCIB_op_pending*/
+- if (!test_bit(_XEN_PCIB_active,(unsigned long *)&pdev->sh_info->flags)
+- &&test_bit(_PCIB_op_pending, &pdev->flags)) {
++ if (!test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags)
++ && test_bit(_PCIB_op_pending, &pdev->flags)) {
+ wake_up(&aer_wait_queue);
+ }
+ }
+@@ -69,7 +66,8 @@ void test_and_schedule_op(struct pciback_device *pdev)
- int xen_set_callback_via(uint64_t via)
---
-1.7.4
-
-
-From ce9a77f4c22a658f4348683c932bb804af263f67 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)citrix.com>
-Date: Mon, 7 Feb 2011 11:08:39 +0000
-Subject: [PATCH 162/244] xen: Fix compile error introduced by "switch to new
irq_chip functions"
-
-drivers/xen/events.c: In function 'ack_pirq':
-drivers/xen/events.c:568: error: implicit declaration of function 'irq_move_irq'
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index cf1712f..5aa422a 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -553,7 +553,7 @@ static void ack_pirq(struct irq_data *data)
+ void pciback_do_op(struct work_struct *data)
{
- int evtchn = evtchn_from_irq(data->irq);
+- struct pciback_device *pdev = container_of(data, struct pciback_device, op_work);
++ struct pciback_device *pdev =
++ container_of(data, struct pciback_device, op_work);
+ struct pci_dev *dev;
+ struct xen_pci_op *op = &pdev->sh_info->op;
-- irq_move_irq(data);
-+ move_native_irq(data->irq);
+@@ -77,38 +75,36 @@ void pciback_do_op(struct work_struct *data)
- if (VALID_EVTCHN(evtchn)) {
- mask_evtchn(evtchn);
---
-1.7.4
-
-
-From bacc3572cf3cceb464a61f71301d6733059d733a Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)citrix.com>
-Date: Tue, 8 Feb 2011 14:03:31 +0000
-Subject: [PATCH 163/244] xen/timer: Missing IRQF_NO_SUSPEND in timer code broke suspend.
-
-The patches missed an indirect use of IRQF_NO_SUSPEND pulled in via
-IRQF_TIMER. The following patch fixes the issue.
-
-With this fixlet PV guest migration works just fine. I also booted the
-entire series as a dom0 kernel and it appeared fine.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/time.c | 4 +++-
- 1 files changed, 3 insertions(+), 1 deletions(-)
-
-diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
-index 067759e..2e2d370 100644
---- a/arch/x86/xen/time.c
-+++ b/arch/x86/xen/time.c
-@@ -397,7 +397,9 @@ void xen_setup_timer(int cpu)
- name = "<timer kasprintf failed>";
+ if (dev == NULL)
+ op->err = XEN_PCI_ERR_dev_not_found;
+- else
+- {
+- switch (op->cmd)
+- {
+- case XEN_PCI_OP_conf_read:
+- op->err = pciback_config_read(dev,
+- op->offset, op->size, &op->value);
+- break;
+- case XEN_PCI_OP_conf_write:
+- op->err = pciback_config_write(dev,
+- op->offset, op->size, op->value);
+- break;
++ else {
++ switch (op->cmd) {
++ case XEN_PCI_OP_conf_read:
++ op->err = pciback_config_read(dev,
++ op->offset, op->size, &op->value);
++ break;
++ case XEN_PCI_OP_conf_write:
++ op->err = pciback_config_write(dev,
++ op->offset, op->size, op->value);
++ break;
+ #ifdef CONFIG_PCI_MSI
+- case XEN_PCI_OP_enable_msi:
+- op->err = pciback_enable_msi(pdev, dev, op);
+- break;
+- case XEN_PCI_OP_disable_msi:
+- op->err = pciback_disable_msi(pdev, dev, op);
+- break;
+- case XEN_PCI_OP_enable_msix:
+- op->err = pciback_enable_msix(pdev, dev, op);
+- break;
+- case XEN_PCI_OP_disable_msix:
+- op->err = pciback_disable_msix(pdev, dev, op);
+- break;
++ case XEN_PCI_OP_enable_msi:
++ op->err = pciback_enable_msi(pdev, dev, op);
++ break;
++ case XEN_PCI_OP_disable_msi:
++ op->err = pciback_disable_msi(pdev, dev, op);
++ break;
++ case XEN_PCI_OP_enable_msix:
++ op->err = pciback_enable_msix(pdev, dev, op);
++ break;
++ case XEN_PCI_OP_disable_msix:
++ op->err = pciback_disable_msix(pdev, dev, op);
++ break;
+ #endif
+- default:
+- op->err = XEN_PCI_ERR_not_implemented;
+- break;
++ default:
++ op->err = XEN_PCI_ERR_not_implemented;
++ break;
+ }
+ }
+- /* Tell the driver domain that we're done. */
++ /* Tell the driver domain that we're done. */
+ wmb();
+ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+ notify_remote_via_irq(pdev->evtchn_irq);
+@@ -119,7 +115,7 @@ void pciback_do_op(struct work_struct *data)
+ smp_mb__after_clear_bit(); /* /before/ final check for work */
- irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
-- IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER,
-+ IRQF_DISABLED|IRQF_PERCPU|
-+ IRQF_NOBALANCING|IRQF_TIMER|
-+ IRQF_FORCE_RESUME,
- name, NULL);
+ /* Check to see if the driver domain tried to start another request in
+- * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
++ * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active.
+ */
+ test_and_schedule_op(pdev);
+ }
+diff --git a/drivers/xen/pciback/slot.c b/drivers/xen/pciback/slot.c
+index 105a8b6..efb922d 100644
+--- a/drivers/xen/pciback/slot.c
++++ b/drivers/xen/pciback/slot.c
+@@ -65,7 +65,8 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev
*dev,
+ for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+ if (slot_dev->slots[bus][slot] == NULL) {
+ printk(KERN_INFO
+- "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
++ "pciback: slot: %s: assign to virtual "
++ "slot %d, bus %d\n",
+ pci_name(dev), slot, bus);
+ slot_dev->slots[bus][slot] = dev;
+ goto unlock;
+@@ -76,14 +77,14 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev
*dev,
+ xenbus_dev_fatal(pdev->xdev, err,
+ "No more space on root virtual PCI bus");
- evt = &per_cpu(xen_clock_events, cpu);
---
-1.7.4
-
-
-From e22ff7614860bc282ba1eb25440d8fc56975e357 Mon Sep 17 00:00:00 2001
-From: Thomas Gleixner <tglx(a)linutronix.de>
-Date: Wed, 9 Feb 2011 10:48:48 +0100
-Subject: [PATCH 165/244] xen: Interrupt cleanups
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/Kconfig | 1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
-
-diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
-index d5ed94d..739f8a5 100644
---- a/arch/x86/Kconfig
-+++ b/arch/x86/Kconfig
-@@ -63,6 +63,7 @@ config X86
- select HAVE_ARCH_JUMP_LABEL
- select HAVE_TEXT_POKE_SMP
- select HAVE_GENERIC_HARDIRQS
-+ select GENERIC_HARDIRQS_NO_DEPRECATED
- select HAVE_SPARSE_IRQ
- select GENERIC_IRQ_PROBE
- select GENERIC_PENDING_IRQ if SMP
---
-1.7.4
-
-
-From 4ed563fef5bbdca310f75136f770576d97dfe78b Mon Sep 17 00:00:00 2001
-From: Thomas Gleixner <tglx(a)linutronix.de>
-Date: Sat, 5 Feb 2011 20:08:59 +0000
-Subject: [PATCH 166/244] xen: Use IRQF_FORCE_RESUME
-
-Mark the IRQF_NO_SUSPEND interrupts IRQF_FORCE_RESUME and remove the extra
-walk through the interrupt descriptors.
-
-Signed-off-by: Thomas Gleixner <tglx(a)linutronix.de>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 20 +-------------------
- 1 files changed, 1 insertions(+), 19 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 5aa422a..975e90f 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -977,7 +977,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
- if (irq < 0)
- return irq;
+- unlock:
++unlock:
+ spin_unlock_irqrestore(&slot_dev->lock, flags);
-- irqflags |= IRQF_NO_SUSPEND;
-+ irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME;
- retval = request_irq(irq, handler, irqflags, devname, dev_id);
- if (retval != 0) {
- unbind_from_irq(irq);
-@@ -1433,7 +1433,6 @@ void xen_poll_irq(int irq)
- void xen_irq_resume(void)
- {
- unsigned int cpu, irq, evtchn;
-- struct irq_desc *desc;
+ /* Publish this device. */
+- if(!err)
++ if (!err)
+ err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid);
- init_evtchn_cpu_bindings();
+- out:
++out:
+ return err;
+ }
-@@ -1453,23 +1452,6 @@ void xen_irq_resume(void)
- restore_cpu_ipis(cpu);
- }
+@@ -105,7 +106,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct
pci_dev *dev)
+ }
+ }
-- /*
-- * Unmask any IRQF_NO_SUSPEND IRQs which are enabled. These
-- * are not handled by the IRQ core.
-- */
-- for_each_irq_desc(irq, desc) {
-- if (!desc->action || !(desc->action->flags & IRQF_NO_SUSPEND))
-- continue;
-- if (desc->status & IRQ_DISABLED)
-- continue;
--
-- evtchn = evtchn_from_irq(irq);
-- if (evtchn == -1)
-- continue;
--
-- unmask_evtchn(evtchn);
-- }
--
- restore_cpu_pirqs();
- }
+- out:
++out:
+ spin_unlock_irqrestore(&slot_dev->lock, flags);
---
-1.7.4
-
-
-From e61e3fbbbc209d5b6a10752beb6b67860f8694c4 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Wed, 9 Feb 2011 16:11:32 -0500
-Subject: [PATCH 178/244] xen-gntdev: Avoid double-mapping memory
-
-If an already-mapped area of the device was mapped into userspace a
-second time, a hypercall was incorrectly made to remap the memory
-again. Avoid the hypercall on later mmap calls, and fail the mmap call
-if a writable mapping is attempted on a read-only range.
-
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/gntdev.c | 15 ++++++++++++---
- 1 files changed, 12 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 3fde99d..ad544a5 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -258,6 +258,9 @@ static int map_grant_pages(struct grant_map *map)
- phys_addr_t addr;
+ if (found_dev)
+@@ -156,8 +157,10 @@ void pciback_release_devices(struct pciback_device *pdev)
+ pdev->pci_dev_data = NULL;
+ }
- if (!use_ptemod) {
-+ /* Note: it could already be mapped */
-+ if (map->map_ops[0].handle)
-+ return 0;
- for (i = 0; i < map->count; i++) {
- addr = (phys_addr_t)
- pfn_to_kaddr(page_to_pfn(map->pages[i]));
-@@ -674,9 +677,15 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- if (use_ptemod)
- map->vma = vma;
+-int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
+- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++int pciback_get_pcifront_dev(struct pci_dev *pcidev,
++ struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus,
++ unsigned int *devfn)
+ {
+ int slot, busnr;
+ struct slot_dev_data *slot_dev = pdev->pci_dev_data;
+@@ -172,11 +175,12 @@ int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct
pciback_device *pdev
+ dev = slot_dev->slots[busnr][slot];
+ if (dev && dev->bus->number == pcidev->bus->number
+ && dev->devfn == pcidev->devfn
+- && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)) {
++ && pci_domain_nr(dev->bus) ==
++ pci_domain_nr(pcidev->bus)) {
+ found = 1;
+ *domain = 0;
+ *bus = busnr;
+- *devfn = PCI_DEVFN(slot,0);
++ *devfn = PCI_DEVFN(slot, 0);
+ goto out;
+ }
+ }
+diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
+index a5b7ece..721b81b 100644
+--- a/drivers/xen/pciback/vpci.c
++++ b/drivers/xen/pciback/vpci.c
+@@ -125,14 +125,14 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev
*dev,
+ xenbus_dev_fatal(pdev->xdev, err,
+ "No more space on root virtual PCI bus");
-- map->flags = GNTMAP_host_map;
-- if (!(vma->vm_flags & VM_WRITE))
-- map->flags |= GNTMAP_readonly;
-+ if (map->flags) {
-+ if ((vma->vm_flags & VM_WRITE) &&
-+ (map->flags & GNTMAP_readonly))
-+ return -EINVAL;
-+ } else {
-+ map->flags = GNTMAP_host_map;
-+ if (!(vma->vm_flags & VM_WRITE))
-+ map->flags |= GNTMAP_readonly;
-+ }
+- unlock:
++unlock:
+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
- spin_unlock(&priv->lock);
+ /* Publish this device. */
+- if(!err)
++ if (!err)
+ err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
---
-1.7.4
-
-
-From 5602b1a8adabd58ef2d1545380591bee238da313 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 10 Feb 2011 10:30:14 -0500
-Subject: [PATCH 180/244] Revert "xen: Interrupt cleanups"
-
-This reverts commit e22ff7614860bc282ba1eb25440d8fc56975e357.
----
- arch/x86/Kconfig | 1 -
- 1 files changed, 0 insertions(+), 1 deletions(-)
-
-diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
-index 739f8a5..d5ed94d 100644
---- a/arch/x86/Kconfig
-+++ b/arch/x86/Kconfig
-@@ -63,7 +63,6 @@ config X86
- select HAVE_ARCH_JUMP_LABEL
- select HAVE_TEXT_POKE_SMP
- select HAVE_GENERIC_HARDIRQS
-- select GENERIC_HARDIRQS_NO_DEPRECATED
- select HAVE_SPARSE_IRQ
- select GENERIC_IRQ_PROBE
- select GENERIC_PENDING_IRQ if SMP
---
-1.7.4
-
-
-From 4c283ce67281d06df373880ed260d87c7e2538ef Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 11 Feb 2011 15:23:56 +0000
-Subject: [PATCH 182/244] xen: events: mark cpu_evtchn_mask_p as __refdata
-
-This variable starts out pointing at init_evtchn_mask which is marked
-__initdata but is set to point to a non-init data region in xen_init_IRQ
-which is itself an __init function so this is safe.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Tested-and-acked-by: Andrew Jones <drjones(a)redhat.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 7468147..a313890 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -114,7 +114,7 @@ struct cpu_evtchn_s {
- static __initdata struct cpu_evtchn_s init_evtchn_mask = {
- .bits[0 ... (NR_EVENT_CHANNELS/BITS_PER_LONG)-1] = ~0ul,
- };
--static struct cpu_evtchn_s *cpu_evtchn_mask_p = &init_evtchn_mask;
-+static struct cpu_evtchn_s __refdata *cpu_evtchn_mask_p = &init_evtchn_mask;
+- out:
++out:
+ return err;
+ }
- static inline unsigned long *cpu_evtchn_mask(int cpu)
- {
---
-1.7.4
-
-
-From 49cbdb55f69f602a8e3f4049c37886d2325375b5 Mon Sep 17 00:00:00 2001
-From: Ian Campbell <ian.campbell(a)citrix.com>
-Date: Fri, 11 Feb 2011 15:23:58 +0000
-Subject: [PATCH 184/244] xen p2m: annotate variable which appears unused
-
- CC arch/x86/xen/p2m.o
-arch/x86/xen/p2m.c: In function 'm2p_remove_override':
-arch/x86/xen/p2m.c:460: warning: 'address' may be used uninitialized in this
function
-arch/x86/xen/p2m.c: In function 'm2p_add_override':
-arch/x86/xen/p2m.c:426: warning: 'address' may be used uninitialized in this
function
-
-In actual fact address is inialised in one "if (!PageHighMem(page))"
-statement and used in a second and so is always initialised before
-use.
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/p2m.c | 4 ++--
- 1 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
-index 53fe9fc..3720efa 100644
---- a/arch/x86/xen/p2m.c
-+++ b/arch/x86/xen/p2m.c
-@@ -421,7 +421,7 @@ int m2p_add_override(unsigned long mfn, struct page *page)
- {
- unsigned long flags;
- unsigned long pfn;
-- unsigned long address;
-+ unsigned long uninitialized_var(address);
- unsigned level;
- pte_t *ptep = NULL;
+@@ -158,7 +158,7 @@ void pciback_release_pci_dev(struct pciback_device *pdev, struct
pci_dev *dev)
+ }
+ }
-@@ -455,7 +455,7 @@ int m2p_remove_override(struct page *page)
- unsigned long flags;
- unsigned long mfn;
- unsigned long pfn;
-- unsigned long address;
-+ unsigned long uninitialized_var(address);
- unsigned level;
- pte_t *ptep = NULL;
+- out:
++out:
+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
---
-1.7.4
-
-
-From 44b46c3ef805793ab3a7730dc71c72d0f258ea8e Mon Sep 17 00:00:00 2001
-From: Ian Campbell <Ian.Campbell(a)eu.citrix.com>
-Date: Fri, 11 Feb 2011 16:37:41 +0000
-Subject: [PATCH 187/244] xen: annotate functions which only call into __init at start of
day
-
-Both xen_hvm_init_shared_info and xen_build_mfn_list_list can be
-called at resume time as well as at start of day but only reference
-__init functions (extend_brk) at start of day. Hence annotate with
-__ref.
-
- WARNING: arch/x86/built-in.o(.text+0x4f1): Section mismatch in reference
- from the function xen_hvm_init_shared_info() to the function
- .init.text:extend_brk()
- The function xen_hvm_init_shared_info() references
- the function __init extend_brk().
- This is often because xen_hvm_init_shared_info lacks a __init
- annotation or the annotation of extend_brk is wrong.
-
-xen_hvm_init_shared_info calls extend_brk() iff !shared_info_page and
-initialises shared_info_page with the result. This happens at start of
-day only.
-
- WARNING: arch/x86/built-in.o(.text+0x599b): Section mismatch in reference
- from the function xen_build_mfn_list_list() to the function
- .init.text:extend_brk()
- The function xen_build_mfn_list_list() references
- the function __init extend_brk().
- This is often because xen_build_mfn_list_list lacks a __init
- annotation or the annotation of extend_brk is wrong.
-
-(this warning occurs multiple times)
-
-xen_build_mfn_list_list only calls extend_brk() at boot time, while
-building the initial mfn list list
-
-Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/xen/enlighten.c | 2 +-
- arch/x86/xen/p2m.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
-index 50542ef..28e6d42 100644
---- a/arch/x86/xen/enlighten.c
-+++ b/arch/x86/xen/enlighten.c
-@@ -1292,7 +1292,7 @@ static int init_hvm_pv_info(int *major, int *minor)
- return 0;
+ if (found_dev)
+@@ -176,9 +176,8 @@ int pciback_init_devices(struct pciback_device *pdev)
+
+ spin_lock_init(&vpci_dev->lock);
+
+- for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++ for (slot = 0; slot < PCI_SLOT_MAX; slot++)
+ INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
+- }
+
+ pdev->pci_dev_data = vpci_dev;
+
+@@ -211,8 +210,10 @@ void pciback_release_devices(struct pciback_device *pdev)
+ pdev->pci_dev_data = NULL;
}
--void xen_hvm_init_shared_info(void)
-+void __ref xen_hvm_init_shared_info(void)
- {
- int cpu;
- struct xen_add_to_physmap xatp;
-diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
-index 89342e5..05cfc6a 100644
---- a/arch/x86/xen/p2m.c
-+++ b/arch/x86/xen/p2m.c
-@@ -136,7 +136,7 @@ static void p2m_init(unsigned long *p2m)
- * - After resume we're called from within stop_machine, but the mfn
- * tree should alreay be completely allocated.
- */
--void xen_build_mfn_list_list(void)
-+void __ref xen_build_mfn_list_list(void)
+-int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct pciback_device *pdev,
+- unsigned int *domain, unsigned int *bus, unsigned int *devfn)
++int pciback_get_pcifront_dev(struct pci_dev *pcidev,
++ struct pciback_device *pdev,
++ unsigned int *domain, unsigned int *bus,
++ unsigned int *devfn)
{
- unsigned long pfn;
+ struct pci_dev_entry *entry;
+ struct pci_dev *dev = NULL;
+@@ -227,15 +228,16 @@ int pciback_get_pcifront_dev(struct pci_dev *pcidev, struct
pciback_device *pdev
+ list) {
+ dev = entry->dev;
+ if (dev && dev->bus->number == pcidev->bus->number
+- && pci_domain_nr(dev->bus) == pci_domain_nr(pcidev->bus)
+- && dev->devfn == pcidev->devfn)
+- {
++ && pci_domain_nr(dev->bus) ==
++ pci_domain_nr(pcidev->bus)
++ && dev->devfn == pcidev->devfn) {
+ found = 1;
+ *domain = 0;
+ *bus = 0;
+- *devfn = PCI_DEVFN(slot, PCI_FUNC(pcidev->devfn));
++ *devfn = PCI_DEVFN(slot,
++ PCI_FUNC(pcidev->devfn));
+ }
+- }
++ }
+ }
+ spin_unlock_irqrestore(&vpci_dev->lock, flags);
+ return found;
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index a85c413..efec585 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -40,7 +40,7 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+ kfree(pdev);
+ pdev = NULL;
+ }
+- out:
++out:
+ return pdev;
+ }
---
-1.7.4
-
-
-From bdc612dc6903c4ea06e40d02f84ad5e25d93459d Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Thu, 3 Feb 2011 12:19:04 -0500
-Subject: [PATCH 193/244] xen/gntalloc,gntdev: Add unmap notify ioctl
-
-This ioctl allows the users of a shared page to be notified when
-the other end exits abnormally.
-
-[v2: updated description in structs]
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/gntalloc.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
- drivers/xen/gntdev.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-
- include/xen/gntalloc.h | 32 +++++++++++++++++++++++++
- include/xen/gntdev.h | 31 ++++++++++++++++++++++++
- 4 files changed, 182 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c
-index d06bf2b..a7ffdfe 100644
---- a/drivers/xen/gntalloc.c
-+++ b/drivers/xen/gntalloc.c
-@@ -60,11 +60,13 @@
- #include <linux/uaccess.h>
- #include <linux/types.h>
- #include <linux/list.h>
-+#include <linux/highmem.h>
+@@ -111,7 +111,7 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
+ err = 0;
- #include <xen/xen.h>
- #include <xen/page.h>
- #include <xen/grant_table.h>
- #include <xen/gntalloc.h>
-+#include <xen/events.h>
+ dev_dbg(&pdev->xdev->dev, "Attached!\n");
+- out:
++out:
+ return err;
+ }
- static int limit = 1024;
- module_param(limit, int, 0644);
-@@ -75,6 +77,12 @@ static LIST_HEAD(gref_list);
- static DEFINE_SPINLOCK(gref_lock);
- static int gref_size;
+@@ -166,11 +166,10 @@ static int pciback_attach(struct pciback_device *pdev)
+ "Error switching to connected state!");
-+struct notify_info {
-+ uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
-+ uint16_t flags:2; /* Bits 12-13: Unmap notification flags */
-+ int event; /* Port (event channel) to notify */
-+};
-+
- /* Metadata on a grant reference. */
- struct gntalloc_gref {
- struct list_head next_gref; /* list entry gref_list */
-@@ -83,6 +91,7 @@ struct gntalloc_gref {
- uint64_t file_index; /* File offset for mmap() */
- unsigned int users; /* Use count - when zero, waiting on Xen */
- grant_ref_t gref_id; /* The grant reference number */
-+ struct notify_info notify; /* Unmap notification */
- };
+ dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+- out:
++out:
+ spin_unlock(&pdev->dev_lock);
- struct gntalloc_file_private_data {
-@@ -164,6 +173,16 @@ undo:
+- if (magic)
+- kfree(magic);
++ kfree(magic);
- static void __del_gref(struct gntalloc_gref *gref)
- {
-+ if (gref->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
-+ uint8_t *tmp = kmap(gref->page);
-+ tmp[gref->notify.pgoff] = 0;
-+ kunmap(gref->page);
-+ }
-+ if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
-+ notify_remote_via_evtchn(gref->notify.event);
-+
-+ gref->notify.flags = 0;
-+
- if (gref->gref_id > 0) {
- if (gnttab_query_foreign_access(gref->gref_id))
- return;
-@@ -349,6 +368,43 @@ dealloc_grant_out:
- return rc;
+ return err;
}
+@@ -193,7 +192,7 @@ static int pciback_publish_pci_dev(struct pciback_device *pdev,
+ "%04x:%02x:%02x.%02x", domain, bus,
+ PCI_SLOT(devfn), PCI_FUNC(devfn));
-+static long gntalloc_ioctl_unmap_notify(struct gntalloc_file_private_data *priv,
-+ void __user *arg)
-+{
-+ struct ioctl_gntalloc_unmap_notify op;
-+ struct gntalloc_gref *gref;
-+ uint64_t index;
-+ int pgoff;
-+ int rc;
-+
-+ if (copy_from_user(&op, arg, sizeof(op)))
-+ return -EFAULT;
-+
-+ index = op.index & ~(PAGE_SIZE - 1);
-+ pgoff = op.index & (PAGE_SIZE - 1);
-+
-+ spin_lock(&gref_lock);
-+
-+ gref = find_grefs(priv, index, 1);
-+ if (!gref) {
-+ rc = -ENOENT;
-+ goto unlock_out;
-+ }
-+
-+ if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT)) {
-+ rc = -EINVAL;
-+ goto unlock_out;
-+ }
-+
-+ gref->notify.flags = op.action;
-+ gref->notify.pgoff = pgoff;
-+ gref->notify.event = op.event_channel_port;
-+ rc = 0;
-+ unlock_out:
-+ spin_unlock(&gref_lock);
-+ return rc;
-+}
-+
- static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
- {
-@@ -361,6 +417,9 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
- case IOCTL_GNTALLOC_DEALLOC_GREF:
- return gntalloc_ioctl_dealloc(priv, (void __user *)arg);
+- out:
++out:
+ return err;
+ }
-+ case IOCTL_GNTALLOC_SET_UNMAP_NOTIFY:
-+ return gntalloc_ioctl_unmap_notify(priv, (void __user *)arg);
-+
- default:
- return -ENOIOCTLCMD;
- }
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index bcaf797..9694a1a 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -37,6 +37,7 @@
- #include <xen/xen.h>
- #include <xen/grant_table.h>
- #include <xen/gntdev.h>
-+#include <xen/events.h>
- #include <asm/xen/hypervisor.h>
- #include <asm/xen/hypercall.h>
- #include <asm/xen/page.h>
-@@ -63,6 +64,13 @@ struct gntdev_priv {
- struct mmu_notifier mn;
- };
+@@ -230,7 +229,7 @@ static int pciback_export_device(struct pciback_device *pdev,
+ * to other driver domains (as he who controls the bridge can disable
+ * it and stop the other devices from working).
+ */
+- out:
++out:
+ return err;
+ }
-+struct unmap_notify {
-+ int flags;
-+ /* Address relative to the start of the grant_map */
-+ int addr;
-+ int event;
-+};
-+
- struct grant_map {
- struct list_head next;
- struct vm_area_struct *vma;
-@@ -71,6 +79,7 @@ struct grant_map {
- int flags;
- int is_mapped;
- atomic_t users;
-+ struct unmap_notify notify;
- struct ioctl_gntdev_grant_ref *grants;
- struct gnttab_map_grant_ref *map_ops;
- struct gnttab_unmap_grant_ref *unmap_ops;
-@@ -165,7 +174,7 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv
*priv,
- list_for_each_entry(map, &priv->maps, next) {
- if (map->index != index)
- continue;
-- if (map->count != count)
-+ if (count && map->count != count)
- continue;
- return map;
+@@ -253,8 +252,8 @@ static int pciback_remove_device(struct pciback_device *pdev,
}
-@@ -184,6 +193,10 @@ static void gntdev_put_map(struct grant_map *map)
-
- atomic_sub(map->count, &pages_mapped);
-+ if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) {
-+ notify_remote_via_evtchn(map->notify.event);
-+ }
+ pciback_release_pci_dev(pdev, dev);
+-
+- out:
+
- if (map->pages) {
- if (!use_ptemod)
- unmap_grant_pages(map, 0, map->count);
-@@ -274,6 +287,16 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
- {
- int i, err = 0;
++out:
+ return err;
+ }
-+ if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
-+ int pgno = (map->notify.addr >> PAGE_SHIFT);
-+ if (pgno >= offset && pgno < offset + pages) {
-+ uint8_t *tmp = kmap(map->pages[pgno]);
-+ tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
-+ kunmap(map->pages[pgno]);
-+ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
-+ }
-+ }
-+
- pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
- err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
- if (err)
-@@ -519,6 +542,39 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv
*priv,
- return 0;
+@@ -314,7 +313,7 @@ static int pciback_publish_pci_root(struct pciback_device *pdev,
+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
+ "root_num", "%d", (root_num + 1));
+
+- out:
++out:
+ return err;
}
-+static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
-+{
-+ struct ioctl_gntdev_unmap_notify op;
-+ struct grant_map *map;
-+ int rc;
-+
-+ if (copy_from_user(&op, u, sizeof(op)))
-+ return -EFAULT;
-+
-+ if (op.action & ~(UNMAP_NOTIFY_CLEAR_BYTE|UNMAP_NOTIFY_SEND_EVENT))
-+ return -EINVAL;
-+
-+ spin_lock(&priv->lock);
-+
-+ list_for_each_entry(map, &priv->maps, next) {
-+ uint64_t begin = map->index << PAGE_SHIFT;
-+ uint64_t end = (map->index + map->count) << PAGE_SHIFT;
-+ if (op.index >= begin && op.index < end)
-+ goto found;
-+ }
-+ rc = -ENOENT;
-+ goto unlock_out;
-+
-+ found:
-+ map->notify.flags = op.action;
-+ map->notify.addr = op.index - (map->index << PAGE_SHIFT);
-+ map->notify.event = op.event_channel_port;
-+ rc = 0;
-+ unlock_out:
-+ spin_unlock(&priv->lock);
-+ return rc;
-+}
-+
- static long gntdev_ioctl(struct file *flip,
- unsigned int cmd, unsigned long arg)
- {
-@@ -535,6 +591,9 @@ static long gntdev_ioctl(struct file *flip,
- case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
- return gntdev_ioctl_get_offset_for_vaddr(priv, ptr);
+@@ -358,7 +357,7 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+ }
+ err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
+ "%d", &substate);
+- if (err != 1)
++ if (err != 1)
+ substate = XenbusStateUnknown;
-+ case IOCTL_GNTDEV_SET_UNMAP_NOTIFY:
-+ return gntdev_ioctl_notify(priv, ptr);
-+
- default:
- pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
- return -ENOIOCTLCMD;
-diff --git a/include/xen/gntalloc.h b/include/xen/gntalloc.h
-index bc3b85e..76bd580 100644
---- a/include/xen/gntalloc.h
-+++ b/include/xen/gntalloc.h
-@@ -47,4 +47,36 @@ struct ioctl_gntalloc_dealloc_gref {
- /* Number of references to unmap */
- uint32_t count;
- };
-+
-+/*
-+ * Sets up an unmap notification within the page, so that the other side can do
-+ * cleanup if this side crashes. Required to implement cross-domain robust
-+ * mutexes or close notification on communication channels.
-+ *
-+ * Each mapped page only supports one notification; multiple calls referring to
-+ * the same page overwrite the previous notification. You must clear the
-+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
-+ * to occur.
-+ */
-+#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
-+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
-+struct ioctl_gntalloc_unmap_notify {
-+ /* IN parameters */
-+ /* Offset in the file descriptor for a byte within the page (same as
-+ * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
-+ * be cleared. Otherwise, it can be any byte in the page whose
-+ * notification we are adjusting.
-+ */
-+ uint64_t index;
-+ /* Action(s) to take on unmap */
-+ uint32_t action;
-+ /* Event channel to notify */
-+ uint32_t event_channel_port;
-+};
-+
-+/* Clear (set to zero) the byte specified by index */
-+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
-+/* Send an interrupt on the indicated event channel */
-+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+ switch (substate) {
+@@ -389,14 +388,15 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+ "configuration");
+ goto out;
+ }
+-
+
- #endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
-diff --git a/include/xen/gntdev.h b/include/xen/gntdev.h
-index eb23f41..5304bd3 100644
---- a/include/xen/gntdev.h
-+++ b/include/xen/gntdev.h
-@@ -116,4 +116,35 @@ struct ioctl_gntdev_set_max_grants {
- uint32_t count;
+ err = pciback_export_device(pdev, domain, bus, slot,
+ func, i);
+ if (err)
+ goto out;
+
+ /* Publish pci roots. */
+- err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
++ err = pciback_publish_pci_roots(pdev,
++ pciback_publish_pci_root);
+ if (err) {
+ xenbus_dev_fatal(pdev->xdev, err,
+ "Error while publish PCI root"
+@@ -412,7 +412,7 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+ "Error switching substate of "
+ "dev-%d\n", i);
+ goto out;
+- }
++ }
+ break;
+
+ case XenbusStateClosing:
+@@ -445,7 +445,7 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+
+ err = pciback_remove_device(pdev, domain, bus, slot,
+ func);
+- if(err)
++ if (err)
+ goto out;
+
+ /* TODO: If at some point we implement support for pci
+@@ -466,8 +466,8 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+ "Error switching to reconfigured state!");
+ goto out;
+ }
+-
+- out:
++
++out:
+ spin_unlock(&pdev->dev_lock);
+
+ return 0;
+@@ -591,7 +591,7 @@ static int pciback_setup_backend(struct pciback_device *pdev)
+ xenbus_dev_fatal(pdev->xdev, err, "Error switching "
+ "substate of dev-%d\n", i);
+ goto out;
+- }
++ }
+ }
+
+ err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
+@@ -607,7 +607,7 @@ static int pciback_setup_backend(struct pciback_device *pdev)
+ xenbus_dev_fatal(pdev->xdev, err,
+ "Error switching to initialised state!");
+
+- out:
++out:
+ spin_unlock(&pdev->dev_lock);
+
+ if (!err)
+@@ -663,7 +663,7 @@ static int pciback_xenbus_probe(struct xenbus_device *dev,
+ */
+ pciback_be_watch(&pdev->be_watch, NULL, 0);
+
+- out:
++out:
+ return err;
+ }
+
+@@ -679,7 +679,7 @@ static int pciback_xenbus_remove(struct xenbus_device *dev)
+
+ static const struct xenbus_device_id xenpci_ids[] = {
+ {"pci"},
+- {{0}},
++ {""},
};
-+/*
-+ * Sets up an unmap notification within the page, so that the other side can do
-+ * cleanup if this side crashes. Required to implement cross-domain robust
-+ * mutexes or close notification on communication channels.
-+ *
-+ * Each mapped page only supports one notification; multiple calls referring to
-+ * the same page overwrite the previous notification. You must clear the
-+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
-+ * to occur.
-+ */
-+#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
-+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
-+struct ioctl_gntdev_unmap_notify {
-+ /* IN parameters */
-+ /* Offset in the file descriptor for a byte within the page (same as
-+ * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
-+ * be cleared. Otherwise, it can be any byte in the page whose
-+ * notification we are adjusting.
-+ */
-+ uint64_t index;
-+ /* Action(s) to take on unmap */
-+ uint32_t action;
-+ /* Event channel to notify */
-+ uint32_t event_channel_port;
-+};
-+
-+/* Clear (set to zero) the byte specified by index */
-+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
-+/* Send an interrupt on the indicated event channel */
-+#define UNMAP_NOTIFY_SEND_EVENT 0x2
-+
- #endif /* __LINUX_PUBLIC_GNTDEV_H__ */
+ static struct xenbus_driver xenbus_pciback_driver = {
--
1.7.4
-From 0ea22f072fb1b3da4307573c280ce904f0bf1589 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Tue, 8 Feb 2011 09:14:06 -0500
-Subject: [PATCH 195/244] xen-gntdev: Fix unmap notify on PV domains
+From dbcfc1c122172cae29736c95cb87979b654965cb Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 8 Mar 2010 18:39:15 -0500
+Subject: [PATCH 179/203] xen-pciback: remove driver_data direct access to struct device
-In paravirtualized guests, the struct page* for mappings is only a
-placeholder, and cannot be used to access the granted memory. Use the
-userspace mapping that we have set up in order to implement
-UNMAP_NOTIFY_CLEAR_BYTE.
+The driver core is going to not allow direct access to the
+driver_data pointer in struct device. Instead, the functions
+dev_get_drvdata() and dev_set_drvdata() should be used.
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/gntdev.c | 9 +++++++--
- 1 files changed, 7 insertions(+), 2 deletions(-)
+ drivers/xen/pciback/xenbus.c | 8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 2aa8316..75f8037 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -289,7 +289,12 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index efec585..af6c25a 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -26,7 +26,7 @@ static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
+ dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
- if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
- int pgno = (map->notify.addr >> PAGE_SHIFT);
-- if (pgno >= offset && pgno < offset + pages) {
-+ if (pgno >= offset && pgno < offset + pages && use_ptemod) {
-+ void __user *tmp;
-+ tmp = map->vma->vm_start + map->notify.addr;
-+ copy_to_user(tmp, &err, 1);
-+ map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
-+ } else if (pgno >= offset && pgno < offset + pages) {
- uint8_t *tmp = kmap(map->pages[pgno]);
- tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
- kunmap(map->pages[pgno]);
-@@ -298,7 +303,7 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
- }
+ pdev->xdev = xdev;
+- xdev->dev.driver_data = pdev;
++ dev_set_drvdata(&xdev->dev, pdev);
- pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
-- err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages, pages);
-+ err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages);
- if (err)
- return err;
+ spin_lock_init(&pdev->dev_lock);
+
+@@ -75,7 +75,7 @@ static void free_pdev(struct pciback_device *pdev)
+
+ pciback_release_devices(pdev);
+- pdev->xdev->dev.driver_data = NULL;
++ dev_set_drvdata(&pdev->xdev->dev, NULL);
+ pdev->xdev = NULL;
+
+ kfree(pdev);
+@@ -476,7 +476,7 @@ out:
+ static void pciback_frontend_changed(struct xenbus_device *xdev,
+ enum xenbus_state fe_state)
+ {
+- struct pciback_device *pdev = xdev->dev.driver_data;
++ struct pciback_device *pdev = dev_get_drvdata(&xdev->dev);
+
+ dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
+
+@@ -669,7 +669,7 @@ out:
+
+ static int pciback_xenbus_remove(struct xenbus_device *dev)
+ {
+- struct pciback_device *pdev = dev->dev.driver_data;
++ struct pciback_device *pdev = dev_get_drvdata(&dev->dev);
+
+ if (pdev != NULL)
+ free_pdev(pdev);
--
1.7.4
-From 84e4075d60fc8f1c0b937765620bc784dd0c3d39 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Wed, 9 Feb 2011 15:11:59 -0500
-Subject: [PATCH 196/244] xen-gntdev: Use map->vma for checking map validity
+From 47ec0e3343f9a7cc8944effc293960add935e196 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 8 Mar 2010 18:47:55 -0500
+Subject: [PATCH 180/203] xen-pciback: Fix compile error: 'TASK_NORMAL'
undeclared.
-The is_mapped flag used to be set at the completion of the map operation,
-but was not checked in all error paths. Use map->vma instead, which will
-now be cleared if the initial grant mapping fails.
+Both files were missing the #include <linux/sched.h>
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/gntdev.c | 8 ++------
- 1 files changed, 2 insertions(+), 6 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 1 +
+ drivers/xen/pciback/pciback_ops.c | 1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 75f8037..4ca4262 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -77,7 +77,6 @@ struct grant_map {
- int index;
- int count;
- int flags;
-- int is_mapped;
- atomic_t users;
- struct unmap_notify notify;
- struct ioctl_gntdev_grant_ref *grants;
-@@ -322,7 +321,6 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
- struct grant_map *map = vma->vm_private_data;
-
- pr_debug("close %p\n", vma);
-- map->is_mapped = 0;
- map->vma = NULL;
- vma->vm_private_data = NULL;
- gntdev_put_map(map);
-@@ -347,8 +345,6 @@ static void mn_invl_range_start(struct mmu_notifier *mn,
- list_for_each_entry(map, &priv->maps, next) {
- if (!map->vma)
- continue;
-- if (!map->is_mapped)
-- continue;
- if (map->vma->vm_start >= end)
- continue;
- if (map->vma->vm_end <= start)
-@@ -663,8 +659,6 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct
*vma)
- if (err)
- goto out_put_map;
-
-- map->is_mapped = 1;
--
- if (!use_ptemod) {
- for (i = 0; i < count; i++) {
- err = vm_insert_page(vma, vma->vm_start + i*PAGE_SIZE,
-@@ -681,6 +675,8 @@ unlock_out:
- return err;
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 28222ee..6fc0b6e 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -12,6 +12,7 @@
+ #include <linux/kref.h>
+ #include <linux/pci.h>
+ #include <linux/wait.h>
++#include <linux/sched.h>
+ #include <asm/atomic.h>
+ #include <xen/events.h>
+ #include <asm/xen/pci.h>
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index bf83dca..2b9a93e 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -7,6 +7,7 @@
+ #include <linux/wait.h>
+ #include <linux/bitops.h>
+ #include <xen/events.h>
++#include <linux/sched.h>
+ #include "pciback.h"
- out_put_map:
-+ if (use_ptemod)
-+ map->vma = NULL;
- gntdev_put_map(map);
- return err;
- }
+ int verbose_request;
--
1.7.4
-From b57c18694ea1641b691fa05ed8af0ce339fa430b Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Wed, 9 Feb 2011 15:12:00 -0500
-Subject: [PATCH 197/244] xen-gntdev: Avoid unmapping ranges twice
+From 139a71e1ede3d7ac69f05bec42965d5b00aed03b Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 9 Dec 2009 17:43:16 -0500
+Subject: [PATCH 181/203] xen-pciback: Remove the vestiges of CONFIG_PCI_GUESTDEV.
-In paravirtualized domains, mn_invl_page or mn_invl_range_start can
-unmap a segment of a mapped region without unmapping all pages. When
-the region is later released, the pages will be unmapped twice, leading
-to an incorrect -EINVAL return.
+The same functionality for this (that used to be called
+pci_is_guestdev) is now via: "pci=resource_alignment="
+command line argument.
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/gntdev.c | 33 +++++++++++++++++++++++++++++++--
- 1 files changed, 31 insertions(+), 2 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 10 ----------
+ 1 files changed, 0 insertions(+), 10 deletions(-)
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 4ca4262..4687cd5 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -282,7 +282,7 @@ static int map_grant_pages(struct grant_map *map)
- return err;
- }
-
--static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
-+static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
- {
- int i, err = 0;
-
-@@ -301,7 +301,6 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
- }
- }
-
-- pr_debug("map %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
- err = gnttab_unmap_refs(map->unmap_ops + offset, map->pages + offset, pages);
- if (err)
- return err;
-@@ -314,6 +313,36 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int
pages)
- return err;
- }
-
-+static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
-+{
-+ int range, err = 0;
-+
-+ pr_debug("unmap %d+%d [%d+%d]\n", map->index, map->count, offset,
pages);
-+
-+ /* It is possible the requested range will have a "hole" where we
-+ * already unmapped some of the grants. Only unmap valid ranges.
-+ */
-+ while (pages && !err) {
-+ while (pages && !map->unmap_ops[offset].handle) {
-+ offset++;
-+ pages--;
-+ }
-+ range = 0;
-+ while (range < pages) {
-+ if (!map->unmap_ops[offset+range].handle) {
-+ range--;
-+ break;
-+ }
-+ range++;
-+ }
-+ err = __unmap_grant_pages(map, offset, range);
-+ offset += range;
-+ pages -= range;
-+ }
-+
-+ return err;
-+}
-+
- /* ------------------------------------------------------------------ */
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 6fc0b6e..d30aa7c 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -430,16 +430,6 @@ static int __devinit pcistub_probe(struct pci_dev *dev,
- static void gntdev_vma_close(struct vm_area_struct *vma)
+ dev_info(&dev->dev, "seizing device\n");
+ err = pcistub_seize(dev);
+-#ifdef CONFIG_PCI_GUESTDEV
+- } else if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+- if (!pci_is_guestdev(dev)) {
+- err = -ENODEV;
+- goto out;
+- }
+-
+- dev_info(&dev->dev, "seizing device\n");
+- err = pcistub_seize(dev);
+-#endif /* CONFIG_PCI_GUESTDEV */
+ } else
+ /* Didn't find the device */
+ err = -ENODEV;
--
1.7.4
-From 9960be970cea52c1cb7d7c747ff6da367e1c01b5 Mon Sep 17 00:00:00 2001
-From: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
-Date: Wed, 9 Feb 2011 18:15:50 -0500
-Subject: [PATCH 199/244] xen-gntdev: prevent using UNMAP_NOTIFY_CLEAR_BYTE on read-only
mappings
+From 4cc738bdf28898d008f6a34dcbcdbb8b05ee4247 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 9 Dec 2009 17:43:17 -0500
+Subject: [PATCH 182/203] xen-pciback: Remove deprecated routine to find domain owner of
PCI device.
+
+In linux-2.6.18.hg tree the mechanism to find the domain owner was
+for the MSI driver (msi-xen.c) to call in this function to retrieve
+the domain number. This is not the way anymore.
-Signed-off-by: Daniel De Graaf <dgdegra(a)tycho.nsa.gov>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- drivers/xen/gntdev.c | 10 +++++++++-
- 1 files changed, 9 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
-index 2c4cc94..2a4733c 100644
---- a/drivers/xen/gntdev.c
-+++ b/drivers/xen/gntdev.c
-@@ -294,7 +294,9 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int
pages)
- if (pgno >= offset && pgno < offset + pages && use_ptemod) {
- void __user *tmp;
- tmp = map->vma->vm_start + map->notify.addr;
-- copy_to_user(tmp, &err, 1);
-+ err = copy_to_user(tmp, &err, 1);
-+ if (err)
-+ return err;
- map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
- } else if (pgno >= offset && pgno < offset + pages) {
- uint8_t *tmp = kmap(map->pages[pgno]);
-@@ -599,6 +601,12 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void
__user *u)
- goto unlock_out;
-
- found:
-+ if ((op.action & UNMAP_NOTIFY_CLEAR_BYTE) &&
-+ (map->flags & GNTMAP_readonly)) {
-+ rc = -EINVAL;
-+ goto unlock_out;
-+ }
-+
- map->notify.flags = op.action;
- map->notify.addr = op.index - (map->index << PAGE_SHIFT);
- map->notify.event = op.event_channel_port;
---
-1.7.4
-
+ drivers/xen/pciback/pci_stub.c | 19 -------------------
+ 1 files changed, 0 insertions(+), 19 deletions(-)
-From 56fc689ba6765e1f26e85bf2522011a2f8a56451 Mon Sep 17 00:00:00 2001
-From: John Stultz <johnstul(a)us.ibm.com>
-Date: Mon, 26 Apr 2010 19:03:05 -0700
-Subject: [PATCH 201/244] x86: Convert untested clocksources to
clocksource_register_hz/khz
-
-This converts the remaining x86 clocksources to use
-clocksource_register_hz/khz. I was not able to test them, so
-any extra assistance to make sure time functions properly with
-the clocksources changeed here would be appreciated!
-
-CC: jacob.jun.pan(a)intel.com
-CC: Glauber Costa <glommer(a)redhat.com>
-CC: Dimitri Sivanich <sivanich(a)sgi.com>
-CC: Rusty Russell <rusty(a)rustcorp.com.au>
-CC: Jeremy Fitzhardinge <jeremy(a)xensource.com>
-CC: Chris McDermott <lcm(a)us.ibm.com>
-CC: Thomas Gleixner <tglx(a)linutronix.de>
-Signed-off-by: John Stultz <johnstul(a)us.ibm.com>
----
- arch/x86/kernel/apb_timer.c | 10 +---------
- arch/x86/kernel/i8253.c | 6 +-----
- arch/x86/kernel/kvmclock.c | 6 +-----
- arch/x86/lguest/boot.c | 4 +---
- arch/x86/platform/uv/uv_time.c | 6 +-----
- arch/x86/xen/time.c | 6 +-----
- drivers/clocksource/cyclone.c | 10 ++--------
- 7 files changed, 8 insertions(+), 40 deletions(-)
-
-diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
-index 51ef31a..29ebf5a 100644
---- a/arch/x86/kernel/apb_timer.c
-+++ b/arch/x86/kernel/apb_timer.c
-@@ -177,7 +177,6 @@ static struct clocksource clocksource_apbt = {
- .rating = APBT_CLOCKSOURCE_RATING,
- .read = apbt_read_clocksource,
- .mask = APBT_MASK,
-- .shift = APBT_SHIFT,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .resume = apbt_restart_clocksource,
- };
-@@ -595,14 +594,7 @@ static int apbt_clocksource_register(void)
- if (t1 == apbt_read_clocksource(&clocksource_apbt))
- panic("APBT counter not counting. APBT disabled\n");
-
-- /*
-- * initialize and register APBT clocksource
-- * convert that to ns/clock cycle
-- * mult = (ns/c) * 2^APBT_SHIFT
-- */
-- clocksource_apbt.mult = div_sc(MSEC_PER_SEC,
-- (unsigned long) apbt_freq, APBT_SHIFT);
-- clocksource_register(&clocksource_apbt);
-+ clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000);
-
- return 0;
- }
-diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c
-index 2dfd315..212fe65 100644
---- a/arch/x86/kernel/i8253.c
-+++ b/arch/x86/kernel/i8253.c
-@@ -188,8 +188,6 @@ static struct clocksource pit_cs = {
- .rating = 110,
- .read = pit_read,
- .mask = CLOCKSOURCE_MASK(32),
-- .mult = 0,
-- .shift = 20,
- };
-
- static int __init init_pit_clocksource(void)
-@@ -205,9 +203,7 @@ static int __init init_pit_clocksource(void)
- pit_ce.mode != CLOCK_EVT_MODE_PERIODIC)
- return 0;
-
-- pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift);
--
-- return clocksource_register(&pit_cs);
-+ return clocksource_register_hz(&pit_cs, CLOCK_TICK_RATE);
- }
- arch_initcall(init_pit_clocksource);
-
-diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
-index f98d3ea..6389a6b 100644
---- a/arch/x86/kernel/kvmclock.c
-+++ b/arch/x86/kernel/kvmclock.c
-@@ -26,8 +26,6 @@
- #include <asm/x86_init.h>
- #include <asm/reboot.h>
-
--#define KVM_SCALE 22
--
- static int kvmclock = 1;
- static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
- static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
-@@ -120,8 +118,6 @@ static struct clocksource kvm_clock = {
- .read = kvm_clock_get_cycles,
- .rating = 400,
- .mask = CLOCKSOURCE_MASK(64),
-- .mult = 1 << KVM_SCALE,
-- .shift = KVM_SCALE,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
-
-@@ -203,7 +199,7 @@ void __init kvmclock_init(void)
- machine_ops.crash_shutdown = kvm_crash_shutdown;
- #endif
- kvm_get_preset_lpj();
-- clocksource_register(&kvm_clock);
-+ clocksource_register_hz(&kvm_clock, NSEC_PER_SEC);
- pv_info.paravirt_enabled = 1;
- pv_info.name = "KVM";
-
-diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
-index eba687f0..5b96fd9 100644
---- a/arch/x86/lguest/boot.c
-+++ b/arch/x86/lguest/boot.c
-@@ -913,8 +913,6 @@ static struct clocksource lguest_clock = {
- .rating = 200,
- .read = lguest_clock_read,
- .mask = CLOCKSOURCE_MASK(64),
-- .mult = 1 << 22,
-- .shift = 22,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
-
-@@ -997,7 +995,7 @@ static void lguest_time_init(void)
- /* Set up the timer interrupt (0) to go to our simple timer routine */
- set_irq_handler(0, lguest_time_irq);
-
-- clocksource_register(&lguest_clock);
-+ clocksource_register_hz(&lguest_clock, NSEC_PER_SEC);
-
- /* We can't set cpumask in the initializer: damn C limitations! Set it
- * here and register our timer device. */
-diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c
-index 9daf5d1..0eb9018 100644
---- a/arch/x86/platform/uv/uv_time.c
-+++ b/arch/x86/platform/uv/uv_time.c
-@@ -40,7 +40,6 @@ static struct clocksource clocksource_uv = {
- .rating = 400,
- .read = uv_read_rtc,
- .mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
-- .shift = 10,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index d30aa7c..30e7b59 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -1157,22 +1157,6 @@ static ssize_t permissive_show(struct device_driver *drv, char
*buf)
-@@ -372,14 +371,11 @@ static __init int uv_rtc_setup_clock(void)
- if (!is_uv_system())
- return -ENODEV;
+ DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
-- clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
-- clocksource_uv.shift);
+-#ifdef CONFIG_PCI_MSI
-
- /* If single blade, prefer tsc */
- if (uv_num_possible_blades() == 1)
- clocksource_uv.rating = 250;
-
-- rc = clocksource_register(&clocksource_uv);
-+ rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second);
- if (rc)
- printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
- else
-diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
-index 067759e..04e1159 100644
---- a/arch/x86/xen/time.c
-+++ b/arch/x86/xen/time.c
-@@ -26,8 +26,6 @@
-
- #include "xen-ops.h"
-
--#define XEN_SHIFT 22
--
- /* Xen may fire a timer up to this many ns early */
- #define TIMER_SLOP 100000
- #define NS_PER_TICK (1000000000LL / HZ)
-@@ -211,8 +209,6 @@ static struct clocksource xen_clocksource __read_mostly = {
- .rating = 400,
- .read = xen_clocksource_get_cycles,
- .mask = ~0,
-- .mult = 1<<XEN_SHIFT, /* time directly in nanoseconds */
-- .shift = XEN_SHIFT,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
+-int pciback_get_owner(struct pci_dev *dev)
+-{
+- struct pcistub_device *psdev;
+-
+- psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number,
+- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+-
+- if (!psdev || !psdev->pdev)
+- return -1;
+-
+- return psdev->pdev->xdev->otherend_id;
+-}
+-#endif
+-
+ static void pcistub_exit(void)
+ {
+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
+@@ -1183,7 +1167,6 @@ static void pcistub_exit(void)
+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
-@@ -446,7 +442,7 @@ static __init void xen_time_init(void)
- int cpu = smp_processor_id();
- struct timespec tp;
-
-- clocksource_register(&xen_clocksource);
-+ clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC);
-
- if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
- /* Successfully turned off 100Hz tick, so we have the
-diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
-index 64e528e..72f811f 100644
---- a/drivers/clocksource/cyclone.c
-+++ b/drivers/clocksource/cyclone.c
-@@ -29,8 +29,6 @@ static struct clocksource clocksource_cyclone = {
- .rating = 250,
- .read = read_cyclone,
- .mask = CYCLONE_TIMER_MASK,
-- .mult = 10,
-- .shift = 0,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
+ pci_unregister_driver(&pciback_pci_driver);
+- WARN_ON(unregister_msi_get_owner(pciback_get_owner));
+ }
-@@ -108,12 +106,8 @@ static int __init init_cyclone_clocksource(void)
- }
- cyclone_ptr = cyclone_timer;
+ static int __init pcistub_init(void)
+@@ -1241,8 +1224,6 @@ static int __init pcistub_init(void)
+ err = driver_create_file(&pciback_pci_driver.driver,
+ &driver_attr_permissive);
-- /* sort out mult/shift values: */
-- clocksource_cyclone.shift = 22;
-- clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
-- clocksource_cyclone.shift);
--
-- return clocksource_register(&clocksource_cyclone);
-+ return clocksource_register_hz(&clocksource_cyclone,
-+ CYCLONE_TIMER_FREQ);
- }
+- if (!err)
+- err = register_msi_get_owner(pciback_get_owner);
+ if (err)
+ pcistub_exit();
- arch_initcall(init_cyclone_clocksource);
--
1.7.4
-From 146ad55c02a3afc46ad0dca147a7ac909d39f123 Mon Sep 17 00:00:00 2001
-From: John Stultz <johnstul(a)us.ibm.com>
-Date: Mon, 26 Apr 2010 20:20:47 -0700
-Subject: [PATCH 202/244] ia64: convert to clocksource_register_hz/khz
-
-This converts the ia64 clocksources to use clocksource_register_hz/khz
+From 0617b5c7a8378042b65fa112819e9e12b44c5223 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 22 Dec 2009 13:53:41 -0500
+Subject: [PATCH 183/203] xen-pciback: Fix compiler warning in pci_stub.c.
-This is untested, so any assistance in testing would be appreciated!
+warning: the frame size of 1036 bytes is larger than 1024 bytes
-CC: Tony Luck <tony.luck(a)intel.com>
-CC: Thomas Gleixner <tglx(a)linutronix.de>
-Signed-off-by: John Stultz <johnstul(a)us.ibm.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- arch/ia64/kernel/cyclone.c | 6 +-----
- arch/ia64/kernel/time.c | 9 ++-------
- arch/ia64/sn/kernel/sn2/timer.c | 6 +-----
- drivers/char/hpet.c | 6 +-----
- 4 files changed, 5 insertions(+), 22 deletions(-)
-
-diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c
-index d52f1f7..f64097b 100644
---- a/arch/ia64/kernel/cyclone.c
-+++ b/arch/ia64/kernel/cyclone.c
-@@ -31,8 +31,6 @@ static struct clocksource clocksource_cyclone = {
- .rating = 300,
- .read = read_cyclone,
- .mask = (1LL << 40) - 1,
-- .mult = 0, /*to be caluclated*/
-- .shift = 16,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ drivers/xen/pciback/pci_stub.c | 5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 30e7b59..0b5a16b 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -496,16 +496,17 @@ static const struct pci_device_id pcistub_ids[] = {
+ {0,},
};
-@@ -118,9 +116,7 @@ int __init init_cyclone_clock(void)
- /* initialize last tick */
- cyclone_mc = cyclone_timer;
- clocksource_cyclone.fsys_mmio = cyclone_timer;
-- clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
-- clocksource_cyclone.shift);
-- clocksource_register(&clocksource_cyclone);
-+ clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ);
++#define PCI_NODENAME_MAX 40
+ static void kill_domain_by_device(struct pcistub_device *psdev)
+ {
+ struct xenbus_transaction xbt;
+ int err;
+- char nodename[1024];
++ char nodename[PCI_NODENAME_MAX];
- return 0;
- }
-diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
-index 9702fa9..41c40f0 100644
---- a/arch/ia64/kernel/time.c
-+++ b/arch/ia64/kernel/time.c
-@@ -73,8 +73,6 @@ static struct clocksource clocksource_itc = {
- .rating = 350,
- .read = itc_get_cycles,
- .mask = CLOCKSOURCE_MASK(64),
-- .mult = 0, /*to be calculated*/
-- .shift = 16,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- #ifdef CONFIG_PARAVIRT
- .resume = paravirt_clocksource_resume,
-@@ -374,11 +372,8 @@ ia64_init_itm (void)
- ia64_cpu_local_tick();
-
- if (!itc_clocksource) {
-- /* Sort out mult/shift values: */
-- clocksource_itc.mult =
-- clocksource_hz2mult(local_cpu_data->itc_freq,
-- clocksource_itc.shift);
-- clocksource_register(&clocksource_itc);
-+ clocksource_register_hz(&clocksource_itc,
-+ local_cpu_data->itc_freq);
- itc_clocksource = &clocksource_itc;
- }
- }
-diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
-index 21d6f09..c34efda 100644
---- a/arch/ia64/sn/kernel/sn2/timer.c
-+++ b/arch/ia64/sn/kernel/sn2/timer.c
-@@ -33,8 +33,6 @@ static struct clocksource clocksource_sn2 = {
- .rating = 450,
- .read = read_sn2,
- .mask = (1LL << 55) - 1,
-- .mult = 0,
-- .shift = 10,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
+ if (!psdev)
+ dev_err(&psdev->dev->dev,
+ "device is NULL when do AER recovery/kill_domain\n");
+- sprintf(nodename, "/local/domain/0/backend/pci/%d/0",
++ snprintf(nodename, PCI_NODENAME_MAX, "/local/domain/0/backend/pci/%d/0",
+ psdev->pdev->xdev->otherend_id);
+ nodename[strlen(nodename)] = '\0';
-@@ -57,9 +55,7 @@ ia64_sn_udelay (unsigned long usecs)
- void __init sn_timer_init(void)
- {
- clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
-- clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
-- clocksource_sn2.shift);
-- clocksource_register(&clocksource_sn2);
-+ clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second);
-
- ia64_udelay = &ia64_sn_udelay;
- }
-diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
-index 7066e80..051474c 100644
---- a/drivers/char/hpet.c
-+++ b/drivers/char/hpet.c
-@@ -84,8 +84,6 @@ static struct clocksource clocksource_hpet = {
- .rating = 250,
- .read = read_hpet,
- .mask = CLOCKSOURCE_MASK(64),
-- .mult = 0, /* to be calculated */
-- .shift = 10,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
- static struct clocksource *hpet_clocksource;
-@@ -934,9 +932,7 @@ int hpet_alloc(struct hpet_data *hdp)
- if (!hpet_clocksource) {
- hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
- CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
-- clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
-- clocksource_hpet.shift);
-- clocksource_register(&clocksource_hpet);
-+ clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq);
- hpetp->hp_clocksource = &clocksource_hpet;
- hpet_clocksource = &clocksource_hpet;
- }
--
1.7.4
-From 0ee7bd91c8ecf0372ea34dcc27042bd6b0b5c74f Mon Sep 17 00:00:00 2001
-From: John Stultz <johnstul(a)us.ibm.com>
-Date: Tue, 19 Oct 2010 17:49:07 -0700
-Subject: [PATCH 203/244] alpha: convert to clocksource_register_hz
+From 33b0a6e48e5f8fb218908648991fcc7377db7519 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Tue, 22 Dec 2009 13:53:42 -0500
+Subject: [PATCH 184/203] xen-pciback: Fix compile warning in vpci.c
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+warning: ‘func’ may be used uninitialized in this function
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
+---
+ drivers/xen/pciback/vpci.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/xen/pciback/vpci.c b/drivers/xen/pciback/vpci.c
+index 721b81b..2857ab8 100644
+--- a/drivers/xen/pciback/vpci.c
++++ b/drivers/xen/pciback/vpci.c
+@@ -65,7 +65,7 @@ static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
+ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
+ int devid, publish_pci_dev_cb publish_cb)
+ {
+- int err = 0, slot, func;
++ int err = 0, slot, func = -1;
+ struct pci_dev_entry *t, *dev_entry;
+ struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
+ unsigned long flags;
+--
+1.7.4
+
-Converts alpha to use clocksource_register_hz.
+From ea765da03054c02c4847489086aaf3d2dd914cf4 Mon Sep 17 00:00:00 2001
+From: Ian Campbell <ijc(a)hellion.org.uk>
+Date: Thu, 3 Dec 2009 21:56:20 +0000
+Subject: [PATCH 185/203] xen: rename pciback module to xen-pciback.
-Patch is untested, so help from maintainers would be appreciated.
+pciback is rather generic for a modular distro style kernel.
-Signed-off-by: John Stultz <johnstul(a)us.ibm.com>
-CC: Richard Henderson <rth(a)twiddle.net>
-CC: Ivan Kokshaysky <ink(a)jurassic.park.msu.ru>
-CC: Matt Turner <mattst88(a)gmail.com>
-CC: Thomas Gleixner <tglx(a)linutronix.de>
+Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
+Cc: Jeremy Fitzhardinge <jeremy(a)goop.org>
+Cc: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- arch/alpha/kernel/time.c | 3 +--
- 1 files changed, 1 insertions(+), 2 deletions(-)
+ drivers/xen/pciback/Makefile | 24 ++++++++++++------------
+ 1 files changed, 12 insertions(+), 12 deletions(-)
-diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
-index c1f3e7c..33b8110 100644
---- a/arch/alpha/kernel/time.c
-+++ b/arch/alpha/kernel/time.c
-@@ -378,8 +378,7 @@ static struct clocksource clocksource_rpcc = {
+diff --git a/drivers/xen/pciback/Makefile b/drivers/xen/pciback/Makefile
+index 106dae7..38bc123 100644
+--- a/drivers/xen/pciback/Makefile
++++ b/drivers/xen/pciback/Makefile
+@@ -1,16 +1,16 @@
+-obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o
- static inline void register_rpcc_clocksource(long cycle_freq)
- {
-- clocksource_calc_mult_shift(&clocksource_rpcc, cycle_freq, 4);
-- clocksource_register(&clocksource_rpcc);
-+ clocksource_register_hz(&clocksource_rpcc, cycle_freq);
- }
- #else /* !CONFIG_SMP */
- static inline void register_rpcc_clocksource(long cycle_freq)
+-pciback-y := pci_stub.o pciback_ops.o xenbus.o
+-pciback-y += conf_space.o conf_space_header.o \
+- conf_space_capability.o \
+- conf_space_capability_vpd.o \
+- conf_space_capability_pm.o \
+- conf_space_quirks.o
+-pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
+-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
+-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
+-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
+-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
++xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o
++xen-pciback-y += conf_space.o conf_space_header.o \
++ conf_space_capability.o \
++ conf_space_capability_vpd.o \
++ conf_space_capability_pm.o \
++ conf_space_quirks.o
++xen-pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
++xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
++xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
++xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
++xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
+
+ ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
--
1.7.4
-From 18438061418b7217258db996508a41df43cf59ee Mon Sep 17 00:00:00 2001
-From: John Stultz <johnstul(a)us.ibm.com>
-Date: Mon, 26 Apr 2010 20:24:37 -0700
-Subject: [PATCH 204/244] sparc: convert to clocksource_register_hz/khz
-
-This converts the sparc clocksources to use clocksource_register_hz/khz
+From cb524fe17d83d64d91f8ed52532c9dca49ba7778 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 9 Dec 2009 17:43:15 -0500
+Subject: [PATCH 186/203] xen-pciback: Register the owner (domain) of the PCI device.
-This is untested, so any assistance in testing would be appreciated!
+When the front-end and back-end start negotiating we register
+the domain that will use the PCI device. Furthermore during shutdown
+of guest or unbinding of the PCI device (and unloading of module)
+from pciback we unregister the domain owner.
-CC: "David S. Miller" <davem(a)davemloft.net>
-CC: Thomas Gleixner <tglx(a)linutronix.de>
-Signed-off-by: John Stultz <johnstul(a)us.ibm.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
---
- arch/sparc/kernel/time_64.c | 4 +---
- 1 files changed, 1 insertions(+), 3 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 2 ++
+ drivers/xen/pciback/xenbus.c | 13 +++++++++++++
+ 2 files changed, 15 insertions(+), 0 deletions(-)
-diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c
-index 3bc9c99..58aa27b 100644
---- a/arch/sparc/kernel/time_64.c
-+++ b/arch/sparc/kernel/time_64.c
-@@ -816,14 +816,12 @@ void __init time_init(void)
- clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT);
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 0b5a16b..02178e2 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -90,6 +90,8 @@ static void pcistub_device_release(struct kref *kref)
+
+ dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
+
++ xen_unregister_device_domain_owner(psdev->dev);
++
+ /* Clean-up the device */
+ pciback_reset_device(psdev->dev);
+ pciback_config_free_dyn_fields(psdev->dev);
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index af6c25a..d448bf5 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -10,6 +10,7 @@
+ #include <linux/workqueue.h>
+ #include <xen/xenbus.h>
+ #include <xen/events.h>
++#include <asm/xen/pci.h>
+ #include <linux/workqueue.h>
+ #include "pciback.h"
- clocksource_tick.name = tick_ops->name;
-- clocksource_calc_mult_shift(&clocksource_tick, freq, 4);
- clocksource_tick.read = clocksource_tick_read;
+@@ -221,6 +222,15 @@ static int pciback_export_device(struct pciback_device *pdev,
+ if (err)
+ goto out;
-+ clocksource_register_hz(&clocksource_tick, freq);
- printk("clocksource: mult[%x] shift[%d]\n",
- clocksource_tick.mult, clocksource_tick.shift);
++ dev_dbg(&dev->dev, "registering for %d\n",
pdev->xdev->otherend_id);
++ if (xen_register_device_domain_owner(dev,
++ pdev->xdev->otherend_id) != 0) {
++ dev_err(&dev->dev, "device has been assigned to another " \
++ "domain! Over-writting the ownership, but beware.\n");
++ xen_unregister_device_domain_owner(dev);
++ xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
++ }
++
+ /* TODO: It'd be nice to export a bridge and have all of its children
+ * get exported with it. This may be best done in xend (which will
+ * have to calculate resource usage anyway) but we probably want to
+@@ -251,6 +261,9 @@ static int pciback_remove_device(struct pciback_device *pdev,
+ goto out;
+ }
-- clocksource_register(&clocksource_tick);
--
- sparc64_clockevent.name = tick_ops->name;
- clockevents_calc_mult_shift(&sparc64_clockevent, freq, 4);
++ dev_dbg(&dev->dev, "unregistering for %d\n",
pdev->xdev->otherend_id);
++ xen_unregister_device_domain_owner(dev);
++
+ pciback_release_pci_dev(pdev, dev);
+ out:
--
1.7.4
-From 8b96e146d09d3b9743f5e9c590893bc4770a2923 Mon Sep 17 00:00:00 2001
-From: John Stultz <johnstul(a)us.ibm.com>
-Date: Mon, 26 Apr 2010 20:23:11 -0700
-Subject: [PATCH 205/244] mips: convert to clocksource_register_hz/khz
+From b9d20e9c2627385fc0b39fa8bc45655a656bb71e Mon Sep 17 00:00:00 2001
+From: Zhao, Yu <yu.zhao(a)intel.com>
+Date: Wed, 3 Mar 2010 13:27:55 -0500
+Subject: [PATCH 187/203] xen-pciback: guest SR-IOV support for PV guest
+
+These changes are for PV guest to use Virtual Function. Because the VF's
+vendor, device registers in cfg space are 0xffff, which are invalid and
+ignored by PCI device scan. Values in 'struct pci_dev' are fixed up by
+SR-IOV code, and using these values will present correct VID and DID to
+PV guest kernel.
-This converts the mips clocksources to use clocksource_register_hz/khz
+And command registers in the cfg space are read only 0, which means we
+have to emulate MMIO enable bit (VF only uses MMIO resource) so PV
+kernel can work properly.
-This is untested, so any assistance in testing would be appreciated!
+Acked-by: jbeulich(a)novell.com
-Signed-off-by: John Stultz <johnstul(a)us.ibm.com>
-CC: Ralf Baechle <ralf(a)linux-mips.org>
-CC: Thomas Gleixner <tglx(a)linutronix.de>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- arch/mips/alchemy/common/time.c | 3 +-
- arch/mips/cavium-octeon/csrc-octeon.c | 3 +-
- arch/mips/include/asm/time.h | 6 ----
- arch/mips/jz4740/time.c | 3 +-
- arch/mips/kernel/cevt-txx9.c | 3 +-
- arch/mips/kernel/csrc-bcm1480.c | 3 +-
- arch/mips/kernel/csrc-ioasic.c | 4 +--
- arch/mips/kernel/csrc-powertv.c | 35 ++---------------------
- arch/mips/kernel/csrc-r4k.c | 4 +--
- arch/mips/kernel/csrc-sb1250.c | 3 +-
- arch/mips/kernel/i8253.c | 5 +--
- arch/mips/loongson/common/cs5536/cs5536_mfgpt.c | 5 +--
- arch/mips/sgi-ip27/ip27-timer.c | 3 +-
- 13 files changed, 14 insertions(+), 66 deletions(-)
-
-diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
-index 2aecb2f..d5da6ad 100644
---- a/arch/mips/alchemy/common/time.c
-+++ b/arch/mips/alchemy/common/time.c
-@@ -141,8 +141,7 @@ static int __init alchemy_time_init(unsigned int m2int)
- goto cntr_err;
-
- /* register counter1 clocksource and event device */
-- clocksource_set_clock(&au1x_counter1_clocksource, 32768);
-- clocksource_register(&au1x_counter1_clocksource);
-+ clocksource_register_hz(&au1x_counter1_clocksource, 32768);
-
- cd->shift = 32;
- cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
-diff --git a/arch/mips/cavium-octeon/csrc-octeon.c
b/arch/mips/cavium-octeon/csrc-octeon.c
-index 26bf711..29d56af 100644
---- a/arch/mips/cavium-octeon/csrc-octeon.c
-+++ b/arch/mips/cavium-octeon/csrc-octeon.c
-@@ -105,8 +105,7 @@ unsigned long long notrace sched_clock(void)
- void __init plat_time_init(void)
- {
- clocksource_mips.rating = 300;
-- clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate());
-- clocksource_register(&clocksource_mips);
-+ clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());
- }
-
- static u64 octeon_udelay_factor;
-diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h
-index c7f1bfe..bc14447 100644
---- a/arch/mips/include/asm/time.h
-+++ b/arch/mips/include/asm/time.h
-@@ -84,12 +84,6 @@ static inline int init_mips_clocksource(void)
- #endif
- }
-
--static inline void clocksource_set_clock(struct clocksource *cs,
-- unsigned int clock)
--{
-- clocksource_calc_mult_shift(cs, clock, 4);
--}
--
- static inline void clockevent_set_clock(struct clock_event_device *cd,
- unsigned int clock)
- {
-diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
-index fe01678..03dfd4e 100644
---- a/arch/mips/jz4740/time.c
-+++ b/arch/mips/jz4740/time.c
-@@ -121,8 +121,7 @@ void __init plat_time_init(void)
-
- clockevents_register_device(&jz4740_clockevent);
-
-- clocksource_set_clock(&jz4740_clocksource, clk_rate);
-- ret = clocksource_register(&jz4740_clocksource);
-+ ret = clocksource_register_hz(&jz4740_clocksource, clk_rate);
+ drivers/xen/pciback/conf_space_header.c | 71 ++++++++++++++++++++++++++++--
+ 1 files changed, 66 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
+index 3ae7da1..1f4f86e 100644
+--- a/drivers/xen/pciback/conf_space_header.c
++++ b/drivers/xen/pciback/conf_space_header.c
+@@ -18,6 +18,25 @@ struct pci_bar_info {
+ #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
+ #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
- if (ret)
- printk(KERN_ERR "Failed to register clocksource: %d\n", ret);
-diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c
-index 0b73773..f0ab92a 100644
---- a/arch/mips/kernel/cevt-txx9.c
-+++ b/arch/mips/kernel/cevt-txx9.c
-@@ -51,8 +51,7 @@ void __init txx9_clocksource_init(unsigned long baseaddr,
++static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
++{
++ int i;
++ int ret;
++
++ ret = pciback_read_config_word(dev, offset, value, data);
++ if (!atomic_read(&dev->enable_cnt))
++ return ret;
++
++ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
++ if (dev->resource[i].flags & IORESOURCE_IO)
++ *value |= PCI_COMMAND_IO;
++ if (dev->resource[i].flags & IORESOURCE_MEM)
++ *value |= PCI_COMMAND_MEMORY;
++ }
++
++ return ret;
++}
++
+ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
{
- struct txx9_tmr_reg __iomem *tmrptr;
-
-- clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
-- clocksource_register(&txx9_clocksource.cs);
-+ clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
-
- tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
- __raw_writel(TCR_BASE, &tmrptr->tcr);
-diff --git a/arch/mips/kernel/csrc-bcm1480.c b/arch/mips/kernel/csrc-bcm1480.c
-index 51489f8..f96f99c 100644
---- a/arch/mips/kernel/csrc-bcm1480.c
-+++ b/arch/mips/kernel/csrc-bcm1480.c
-@@ -49,6 +49,5 @@ void __init sb1480_clocksource_init(void)
-
- plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
- zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
-- clocksource_set_clock(cs, zbbus);
-- clocksource_register(cs);
-+ clocksource_register_hz(cs, zbbus);
- }
-diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c
-index 23da108..46bd7fa 100644
---- a/arch/mips/kernel/csrc-ioasic.c
-+++ b/arch/mips/kernel/csrc-ioasic.c
-@@ -59,7 +59,5 @@ void __init dec_ioasic_clocksource_init(void)
- printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
-
- clocksource_dec.rating = 200 + freq / 10000000;
-- clocksource_set_clock(&clocksource_dec, freq);
--
-- clocksource_register(&clocksource_dec);
-+ clocksource_register_hz(&clocksource_dec, freq);
- }
-diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c
-index a27c16c..2e7c523 100644
---- a/arch/mips/kernel/csrc-powertv.c
-+++ b/arch/mips/kernel/csrc-powertv.c
-@@ -78,9 +78,7 @@ static void __init powertv_c0_hpt_clocksource_init(void)
-
- clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
-
-- clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
--
-- clocksource_register(&clocksource_mips);
-+ clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
- }
-
- /**
-@@ -130,43 +128,16 @@ static struct clocksource clocksource_tim_c = {
- /**
- * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock
- *
-- * The hard part here is coming up with a constant k and shift s such that
-- * the 48-bit TIM_C value multiplied by k doesn't overflow and that value,
-- * when shifted right by s, yields the corresponding number of nanoseconds.
- * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to
-- * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the
-- * number of nanoseconds. Since the TIM_C value has 48 bits and the math is
-- * done in 64 bits, avoiding an overflow means that k must be less than
-- * 64 - 48 = 16 bits.
-+ * 1 / (27,000,000/8) seconds.
- */
- static void __init powertv_tim_c_clocksource_init(void)
+ int err;
+@@ -142,10 +161,26 @@ static inline void read_dev_bar(struct pci_dev *dev,
+ struct pci_bar_info *bar_info, int offset,
+ u32 len_mask)
{
-- int prescale;
-- unsigned long dividend;
-- unsigned long k;
-- int s;
-- const int max_k_bits = (64 - 48) - 1;
-- const unsigned long billion = 1000000000;
- const unsigned long counts_per_second = 27000000 / 8;
-
-- prescale = BITS_PER_LONG - ilog2(billion) - 1;
-- dividend = billion << prescale;
-- k = dividend / counts_per_second;
-- s = ilog2(k) - max_k_bits;
--
-- if (s < 0)
-- s = prescale;
--
-- else {
-- k >>= s;
-- s += prescale;
-- }
--
-- clocksource_tim_c.mult = k;
-- clocksource_tim_c.shift = s;
- clocksource_tim_c.rating = 200;
-
-- clocksource_register(&clocksource_tim_c);
-+ clocksource_register_hz(&clocksource_tim_c, counts_per_second);
- tim_c = (struct tim_c *) asic_reg_addr(tim_ch);
- }
-
-diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
-index e95a3cd..decd1fa 100644
---- a/arch/mips/kernel/csrc-r4k.c
-+++ b/arch/mips/kernel/csrc-r4k.c
-@@ -30,9 +30,7 @@ int __init init_r4k_clocksource(void)
- /* Calculate a somewhat reasonable rating value */
- clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
-
-- clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
--
-- clocksource_register(&clocksource_mips);
-+ clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
-
- return 0;
+- pci_read_config_dword(dev, offset, &bar_info->val);
+- pci_write_config_dword(dev, offset, len_mask);
+- pci_read_config_dword(dev, offset, &bar_info->len_val);
+- pci_write_config_dword(dev, offset, bar_info->val);
++ int pos;
++ struct resource *res = dev->resource;
++
++ if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
++ pos = PCI_ROM_RESOURCE;
++ else {
++ pos = (offset - PCI_BASE_ADDRESS_0) / 4;
++ if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
++ PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
++ (PCI_BASE_ADDRESS_SPACE_MEMORY |
++ PCI_BASE_ADDRESS_MEM_TYPE_64))) {
++ bar_info->val = res[pos - 1].start >> 32;
++ bar_info->len_val = res[pos - 1].end >> 32;
++ return;
++ }
++ }
++
++ bar_info->val = res[pos].start |
++ (res[pos].flags & PCI_REGION_FLAG_MASK);
++ bar_info->len_val = res[pos].end - res[pos].start + 1;
}
-diff --git a/arch/mips/kernel/csrc-sb1250.c b/arch/mips/kernel/csrc-sb1250.c
-index d14d3d1..e9606d9 100644
---- a/arch/mips/kernel/csrc-sb1250.c
-+++ b/arch/mips/kernel/csrc-sb1250.c
-@@ -65,6 +65,5 @@ void __init sb1250_clocksource_init(void)
- IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
- R_SCD_TIMER_CFG)));
-
-- clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
-- clocksource_register(cs);
-+ clocksource_register_hz(cs, V_SCD_TIMER_FREQ);
- }
-diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c
-index 2392a7a2..9fadd17 100644
---- a/arch/mips/kernel/i8253.c
-+++ b/arch/mips/kernel/i8253.c
-@@ -196,8 +196,6 @@ static struct clocksource clocksource_pit = {
- .rating = 110,
- .read = pit_read,
- .mask = CLOCKSOURCE_MASK(32),
-- .mult = 0,
-- .shift = 20,
- };
-
- static int __init init_pit_clocksource(void)
-@@ -205,7 +203,6 @@ static int __init init_pit_clocksource(void)
- if (num_possible_cpus() > 1) /* PIT does not scale! */
- return 0;
-
-- clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
-- return clocksource_register(&clocksource_pit);
-+ return clocksource_register_hz(&clocksource_pit, CLOCK_TICK_RATE);
- }
- arch_initcall(init_pit_clocksource);
-diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
-index 8c807c9..0cb1b97 100644
---- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
-+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
-@@ -201,8 +201,6 @@ static struct clocksource clocksource_mfgpt = {
- .rating = 120, /* Functional for real use, but not desired */
- .read = mfgpt_read,
- .mask = CLOCKSOURCE_MASK(32),
-- .mult = 0,
-- .shift = 22,
- };
-
- int __init init_mfgpt_clocksource(void)
-@@ -210,8 +208,7 @@ int __init init_mfgpt_clocksource(void)
- if (num_possible_cpus() > 1) /* MFGPT does not scale! */
- return 0;
-- clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22);
-- return clocksource_register(&clocksource_mfgpt);
-+ return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
+ static void *bar_init(struct pci_dev *dev, int offset)
+@@ -186,6 +221,22 @@ static void bar_release(struct pci_dev *dev, int offset, void
*data)
+ kfree(data);
}
- arch_initcall(init_mfgpt_clocksource);
-diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
-index d6802d6..3cac883 100644
---- a/arch/mips/sgi-ip27/ip27-timer.c
-+++ b/arch/mips/sgi-ip27/ip27-timer.c
-@@ -177,8 +177,7 @@ static void __init hub_rt_clocksource_init(void)
++static int pciback_read_vendor(struct pci_dev *dev, int offset,
++ u16 *value, void *data)
++{
++ *value = dev->vendor;
++
++ return 0;
++}
++
++static int pciback_read_device(struct pci_dev *dev, int offset,
++ u16 *value, void *data)
++{
++ *value = dev->device;
++
++ return 0;
++}
++
+ static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
+ void *data)
{
- struct clocksource *cs = &hub_rt_clocksource;
-
-- clocksource_set_clock(cs, CYCLES_PER_SEC);
-- clocksource_register(cs);
-+ clocksource_register_hz(cs, CYCLES_PER_SEC);
- }
+@@ -213,9 +264,19 @@ out:
- void __init plat_time_init(void)
+ static const struct config_field header_common[] = {
+ {
++ .offset = PCI_VENDOR_ID,
++ .size = 2,
++ .u.w.read = pciback_read_vendor,
++ },
++ {
++ .offset = PCI_DEVICE_ID,
++ .size = 2,
++ .u.w.read = pciback_read_device,
++ },
++ {
+ .offset = PCI_COMMAND,
+ .size = 2,
+- .u.w.read = pciback_read_config_word,
++ .u.w.read = command_read,
+ .u.w.write = command_write,
+ },
+ {
--
1.7.4
-From d4927a73fd75afe5a220d02fca106a6437021c3f Mon Sep 17 00:00:00 2001
-From: John Stultz <johnstul(a)us.ibm.com>
-Date: Mon, 26 Apr 2010 20:20:07 -0700
-Subject: [PATCH 206/244] blackfin: convert to clocksource_register_hz
+From 93c8ff641cc167d2f7a73645b79a8e193e4d1f8c Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 3 Mar 2010 13:38:43 -0500
+Subject: [PATCH 188/203] xen-pciback: Disable MSI/MSI-X when reseting device
-This converts the blackfin clocksource to use clocksource_register_hz.
+In cases where the guest is abruptly killed and has not disabled
+MSI/MSI-X interrupts we want to do that.
-This is untested, so any assistance in testing would be appreciated!
+Otherwise when the guest is started up and enables MSI, we would
+get a WARN() that the device already had been enabled.
-CC: Mike Frysinger <vapier(a)gentoo.org>
-CC: Thomas Gleixner <tglx(a)linutronix.de>
-Signed-off-by: John Stultz <johnstul(a)us.ibm.com>
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- arch/blackfin/kernel/time-ts.c | 35 ++---------------------------------
- 1 files changed, 2 insertions(+), 33 deletions(-)
-
-diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
-index 8c9a43d..4a01371 100644
---- a/arch/blackfin/kernel/time-ts.c
-+++ b/arch/blackfin/kernel/time-ts.c
-@@ -23,29 +23,6 @@
- #include <asm/gptimers.h>
- #include <asm/nmi.h>
-
--/* Accelerators for sched_clock()
-- * convert from cycles(64bits) => nanoseconds (64bits)
-- * basic equation:
-- * ns = cycles / (freq / ns_per_sec)
-- * ns = cycles * (ns_per_sec / freq)
-- * ns = cycles * (10^9 / (cpu_khz * 10^3))
-- * ns = cycles * (10^6 / cpu_khz)
-- *
-- * Then we use scaling math (suggested by george(a)mvista.com) to get:
-- * ns = cycles * (10^6 * SC / cpu_khz) / SC
-- * ns = cycles * cyc2ns_scale / SC
-- *
-- * And since SC is a constant power of two, we can convert the div
-- * into a shift.
-- *
-- * We can use khz divisor instead of mhz to keep a better precision, since
-- * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
-- * (mathieu.desnoyers(a)polymtl.ca)
-- *
-- * -johnstul(a)us.ibm.com "math is hard, lets go shopping!"
-- */
--
--#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
-
- #if defined(CONFIG_CYCLES_CLOCKSOURCE)
-
-@@ -63,7 +40,6 @@ static struct clocksource bfin_cs_cycles = {
- .rating = 400,
- .read = bfin_read_cycles,
- .mask = CLOCKSOURCE_MASK(64),
-- .shift = CYC2NS_SCALE_FACTOR,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
-
-@@ -75,10 +51,7 @@ static inline unsigned long long bfin_cs_cycles_sched_clock(void)
-
- static int __init bfin_cs_cycles_init(void)
- {
-- bfin_cs_cycles.mult = \
-- clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
--
-- if (clocksource_register(&bfin_cs_cycles))
-+ if (clocksource_register_hz(&bfin_cs_cycles, get_cclk()))
- panic("failed to register clocksource");
-
- return 0;
-@@ -111,7 +84,6 @@ static struct clocksource bfin_cs_gptimer0 = {
- .rating = 350,
- .read = bfin_read_gptimer0,
- .mask = CLOCKSOURCE_MASK(32),
-- .shift = CYC2NS_SCALE_FACTOR,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- };
-
-@@ -125,10 +97,7 @@ static int __init bfin_cs_gptimer0_init(void)
- {
- setup_gptimer0();
+ drivers/xen/pciback/pciback_ops.c | 8 ++++++++
+ 1 files changed, 8 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 2b9a93e..011db67 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -23,6 +23,14 @@ void pciback_reset_device(struct pci_dev *dev)
-- bfin_cs_gptimer0.mult = \
-- clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift);
--
-- if (clocksource_register(&bfin_cs_gptimer0))
-+ if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk()))
- panic("failed to register clocksource");
+ /* Disable devices (but not bridges) */
+ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
++#ifdef CONFIG_PCI_MSI
++ /* The guest could have been abruptly killed without
++ * disabling MSI/MSI-X interrupts.*/
++ if (dev->msix_enabled)
++ pci_disable_msix(dev);
++ if (dev->msi_enabled)
++ pci_disable_msi(dev);
++#endif
+ pci_disable_device(dev);
- return 0;
+ pci_write_config_word(dev, PCI_COMMAND, 0);
--
1.7.4
-From 1f169f66ddcc3b4614f840bef367de1ca20e16fe Mon Sep 17 00:00:00 2001
-From: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
-Date: Thu, 10 Feb 2011 12:08:21 +0000
-Subject: [PATCH 207/244] xen: change xen/[gntdev/gntalloc] to default m
+From 2a42c52bfca255f6754ad5bd53bb3f893fd6992f Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 12 Apr 2010 11:46:00 -0400
+Subject: [PATCH 189/203] xen-pciback: Allocate IRQ handler for device that is shared with
guest.
-When CONFIG_XEN is enabled the gntdev and gntalloc driver will be
-compiled as a module by default.
+If the pciback module is loaded with fake_irq_handler=1 we install
+for all devices that are to be passed to the guest domain a IRQ handler.
+The IRQ handler will return IRQ_HANDLED or IRQ_NONE depending on
+on the ack_intr flag.
-[v2: Added the fix for the gntalloc driver as well]
+The trigger to install this IRQ handler is when the enable_isr flag
+is set.
-Signed-off-by: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/Kconfig | 2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
-index a3d7afb..a59638b 100644
---- a/drivers/xen/Kconfig
-+++ b/drivers/xen/Kconfig
-@@ -76,6 +76,7 @@ config XEN_XENBUS_FRONTEND
- config XEN_GNTDEV
- tristate "userspace grant access device driver"
- depends on XEN
-+ default m
- select MMU_NOTIFIER
- help
- Allows userspace processes to use grants.
-@@ -83,6 +84,7 @@ config XEN_GNTDEV
- config XEN_GRANT_DEV_ALLOC
- tristate "User-space grant reference allocator driver"
- depends on XEN
-+ default m
- help
- Allows userspace processes to create pages with access granted
- to other domains. This can be used to implement frontend drivers
---
-1.7.4
-
+ drivers/xen/pciback/pci_stub.c | 13 ++++-
+ drivers/xen/pciback/pciback.h | 12 ++++-
+ drivers/xen/pciback/pciback_ops.c | 95 ++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 115 insertions(+), 5 deletions(-)
-From 2b38de9460a0c6560c865afa536b15919dd0f658 Mon Sep 17 00:00:00 2001
-From: Andrea Arcangeli <aarcange(a)redhat.com>
-Date: Wed, 16 Feb 2011 19:33:04 +0100
-Subject: [PATCH 208/244] fix pgd_lock deadlock
-
-On Tue, Feb 15, 2011 at 09:05:20PM +0100, Thomas Gleixner wrote:
-> Did you try with DEBUG_PAGEALLOC, which is calling into cpa quite a
-> lot?
-
-I tried DEBUG_PAGEALLOC and it seems to work fine (in addition to
-lockdep), it doesn't spwan any debug check.
-
-In addition to testing it (both prev patch and below one) I looked
-into the code and the free_pages calling into
-pageattr->split_large_page apparently happens all at boot time.
-
-Now one doubt remains if we need change_page_attr to run from irqs
-(not from DEBUG_PAGEALLOC though). Now is change_page_attr really sane
-to run from irqs? I thought __flush_tlb_all was delivering IPI (in
-that case it also wouldn't have been safe in the first place to run
-with irq disabled) but of course the "__" version is local, so after
-all maybe it's safe to run with interrupts too (I'd be amazed if
-somebody is calling it from irq, if not even DEBUG_PAGEALLOC does) but
-with the below patch it will remain safe from irq as far as the
-pgd_lock is concerned.
-
-I think the previous patch was safe too though, avoiding VM
-manipulations from interrupts makes everything simpler. Normally only
-gart drivers should call it at init time to avoid prefetching of
-cachelines in the next 2m page with different (writeback) cache
-attributes of the pages physically aliased in the gart and mapped with
-different cache attribute, that init stuff happening from interrupt
-sounds weird. Anyway I post the below patch too as an alternative to
-still allow pageattr from irq.
-
-With both patches the big dependency remains on __mmdrop not to run
-from irq. The alternative approach is to remove the page_table_lock
-from vmalloc_sync_all (which is only needed by Xen paravirt guest
-AFIK) and solve that problem in a different way, but I don't even know
-why they need it exactly, I tried not to impact that.
-
-===
-Subject: fix pgd_lock deadlock
-
-From: Andrea Arcangeli <aarcange(a)redhat.com>
-
-It's forbidden to take the page_table_lock with the irq disabled or if there's
-contention the IPIs (for tlb flushes) sent with the page_table_lock held will
-never run leading to a deadlock.
-
-pageattr also seems to take advantage the pgd_lock to serialize
-split_large_page which isn't necessary so split it off to a separate spinlock
-(as a read_lock wouldn't enough to serialize split_large_page). Then we can use
-a read-write lock to allow pageattr to keep taking it from interrupts, but
-without having to always clear interrupts for readers. Writers are only safe
-from regular kernel context and they must clear irqs before taking it.
-
-Signed-off-by: Andrea Arcangeli <aarcange(a)redhat.com>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- arch/x86/include/asm/pgtable.h | 2 +-
- arch/x86/mm/fault.c | 23 ++++++++++++++++++-----
- arch/x86/mm/init_64.c | 6 +++---
- arch/x86/mm/pageattr.c | 17 ++++++++++-------
- arch/x86/mm/pgtable.c | 10 +++++-----
- arch/x86/xen/mmu.c | 10 ++++------
- 6 files changed, 41 insertions(+), 27 deletions(-)
-
-diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
-index 18601c8..9fa5a2b 100644
---- a/arch/x86/include/asm/pgtable.h
-+++ b/arch/x86/include/asm/pgtable.h
-@@ -25,7 +25,7 @@
- extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
- #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
-
--extern spinlock_t pgd_lock;
-+extern rwlock_t pgd_lock;
- extern struct list_head pgd_list;
-
- extern struct mm_struct *pgd_page_get_mm(struct page *page);
-diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
-index 7d90ceb..336f220 100644
---- a/arch/x86/mm/fault.c
-+++ b/arch/x86/mm/fault.c
-@@ -179,7 +179,21 @@ force_sig_info_fault(int si_signo, int si_code, unsigned long
address,
- force_sig_info(si_signo, &info, tsk);
- }
-
--DEFINE_SPINLOCK(pgd_lock);
-+/*
-+ * The pgd_lock only protects the pgd_list. It can be taken from
-+ * interrupt context but only in read mode (there's no need to clear
-+ * interrupts before taking it in read mode). Write mode can only be
-+ * taken from regular kernel context (not from irqs) and it must
-+ * disable irqs before taking it. This way it can still be taken in
-+ * read mode from interrupt context (in case
-+ * pageattr->split_large_page is ever called from interrupt context),
-+ * but without forcing the pgd_list readers to clear interrupts before
-+ * taking it (like vmalloc_sync_all() that then wants to take the
-+ * page_table_lock while holding the pgd_lock, which can only be taken
-+ * while irqs are left enabled to avoid deadlocking against the IPI
-+ * delivery of an SMP TLB flush run with the page_table_lock hold).
-+ */
-+DEFINE_RWLOCK(pgd_lock);
- LIST_HEAD(pgd_list);
-
- #ifdef CONFIG_X86_32
-@@ -229,15 +243,14 @@ void vmalloc_sync_all(void)
- for (address = VMALLOC_START & PMD_MASK;
- address >= TASK_SIZE && address < FIXADDR_TOP;
- address += PMD_SIZE) {
--
-- unsigned long flags;
- struct page *page;
-
-- spin_lock_irqsave(&pgd_lock, flags);
-+ read_lock(&pgd_lock);
- list_for_each_entry(page, &pgd_list, lru) {
- spinlock_t *pgt_lock;
- pmd_t *ret;
-
-+ /* the pgt_lock only for Xen */
- pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 02178e2..45bbe99 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -21,6 +21,8 @@
+ #include "conf_space.h"
+ #include "conf_space_quirks.h"
- spin_lock(pgt_lock);
-@@ -247,7 +260,7 @@ void vmalloc_sync_all(void)
- if (!ret)
- break;
- }
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ read_unlock(&pgd_lock);
++#define DRV_NAME "pciback"
++
+ static char *pci_devs_to_hide;
+ wait_queue_head_t aer_wait_queue;
+ /*Add sem for sync AER handling and pciback remove/reconfigue ops,
+@@ -290,13 +292,20 @@ static int __devinit pcistub_init_device(struct pci_dev *dev)
+ * would need to be called somewhere to free the memory allocated
+ * here and then to call kfree(pci_get_drvdata(psdev->dev)).
+ */
+- dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
++ dev_data = kzalloc(sizeof(*dev_data) + strlen(DRV_NAME "[]")
++ + strlen(pci_name(dev)) + 1, GFP_ATOMIC);
+ if (!dev_data) {
+ err = -ENOMEM;
+ goto out;
}
- }
-
-diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
-index 71a5929..043fa4f 100644
---- a/arch/x86/mm/init_64.c
-+++ b/arch/x86/mm/init_64.c
-@@ -105,18 +105,18 @@ void sync_global_pgds(unsigned long start, unsigned long end)
-
- for (address = start; address <= end; address += PGDIR_SIZE) {
- const pgd_t *pgd_ref = pgd_offset_k(address);
-- unsigned long flags;
- struct page *page;
-
- if (pgd_none(*pgd_ref))
- continue;
-
-- spin_lock_irqsave(&pgd_lock, flags);
-+ read_lock(&pgd_lock);
- list_for_each_entry(page, &pgd_list, lru) {
- pgd_t *pgd;
- spinlock_t *pgt_lock;
-
- pgd = (pgd_t *)page_address(page) + pgd_index(address);
-+ /* the pgt_lock only for Xen */
- pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
- spin_lock(pgt_lock);
-
-@@ -128,7 +128,7 @@ void sync_global_pgds(unsigned long start, unsigned long end)
+ pci_set_drvdata(dev, dev_data);
- spin_unlock(pgt_lock);
- }
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ read_unlock(&pgd_lock);
- }
- }
++ /*
++ * Setup name for fake IRQ handler. It will only be enabled
++ * once the device is turned on by the guest.
++ */
++ sprintf(dev_data->irq_name, DRV_NAME "[%s]", pci_name(dev));
++
+ dev_dbg(&dev->dev, "initializing config\n");
-diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
-index d343b3c..6f30dc9 100644
---- a/arch/x86/mm/pageattr.c
-+++ b/arch/x86/mm/pageattr.c
-@@ -47,6 +47,7 @@ struct cpa_data {
- * splitting a large page entry along with changing the attribute.
+ init_waitqueue_head(&aer_wait_queue);
+@@ -837,7 +846,7 @@ static struct pci_error_handlers pciback_error_handler = {
*/
- static DEFINE_SPINLOCK(cpa_lock);
-+static DEFINE_SPINLOCK(pgattr_lock);
-
- #define CPA_FLUSHTLB 1
- #define CPA_ARRAY 2
-@@ -60,9 +61,9 @@ void update_page_count(int level, unsigned long pages)
- unsigned long flags;
- /* Protect against CPA */
-- spin_lock_irqsave(&pgd_lock, flags);
-+ spin_lock_irqsave(&pgattr_lock, flags);
- direct_pages_count[level] += pages;
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ spin_unlock_irqrestore(&pgattr_lock, flags);
- }
+ static struct pci_driver pciback_pci_driver = {
+- .name = "pciback",
++ .name = DRV_NAME,
+ .id_table = pcistub_ids,
+ .probe = pcistub_probe,
+ .remove = pcistub_remove,
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index 98e2912..9d1b0a6 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -45,8 +45,13 @@ struct pciback_device {
- static void split_page_count(int level)
-@@ -376,6 +377,7 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t
pte)
- if (!SHARED_KERNEL_PMD) {
- struct page *page;
+ struct pciback_dev_data {
+ struct list_head config_fields;
+- int permissive;
+- int warned_on_write;
++ unsigned int permissive : 1;
++ unsigned int warned_on_write : 1;
++ unsigned int enable_intx : 1;
++ unsigned int isr_on : 1; /* Whether the IRQ handler is installed. */
++ unsigned int ack_intr : 1; /* .. and ACK-ing */
++ unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
++ char irq_name[0]; /* pciback[000:04:00.0] */
+ };
-+ read_lock(&pgd_lock);
- list_for_each_entry(page, &pgd_list, lru) {
- pgd_t *pgd;
- pud_t *pud;
-@@ -386,6 +388,7 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t
pte)
- pmd = pmd_offset(pud, address);
- set_pte_atomic((pte_t *)pmd, pte);
- }
-+ read_unlock(&pgd_lock);
- }
+ /* Used by XenBus and pciback_ops.c */
+@@ -131,3 +136,6 @@ extern int verbose_request;
+ void test_and_schedule_op(struct pciback_device *pdev);
#endif
- }
-@@ -403,7 +406,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
- if (cpa->force_split)
- return 1;
-
-- spin_lock_irqsave(&pgd_lock, flags);
-+ spin_lock_irqsave(&pgattr_lock, flags);
- /*
- * Check for races, another CPU might have split this page
- * up already:
-@@ -498,7 +501,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
- }
-
- out_unlock:
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ spin_unlock_irqrestore(&pgattr_lock, flags);
-
- return do_split;
- }
-@@ -519,7 +522,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
- if (!base)
- return -ENOMEM;
-- spin_lock_irqsave(&pgd_lock, flags);
-+ spin_lock_irqsave(&pgattr_lock, flags);
- /*
- * Check for races, another CPU might have split this page
- * up for us already:
-@@ -587,11 +590,11 @@ static int split_large_page(pte_t *kpte, unsigned long address)
- out_unlock:
- /*
- * If we dropped out via the lookup_address check under
-- * pgd_lock then stick the page back into the pool:
-+ * pgattr_lock then stick the page back into the pool:
- */
- if (base)
- __free_page(base);
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ spin_unlock_irqrestore(&pgattr_lock, flags);
-
- return 0;
- }
-diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
-index 500242d..86ecfa8 100644
---- a/arch/x86/mm/pgtable.c
-+++ b/arch/x86/mm/pgtable.c
-@@ -121,14 +121,14 @@ static void pgd_ctor(struct mm_struct *mm, pgd_t *pgd)
-
- static void pgd_dtor(pgd_t *pgd)
- {
-- unsigned long flags; /* can be called from interrupt context */
-+ unsigned long flags;
-
- if (SHARED_KERNEL_PMD)
- return;
-
-- spin_lock_irqsave(&pgd_lock, flags);
-+ write_lock_irqsave(&pgd_lock, flags);
- pgd_list_del(pgd);
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ write_unlock_irqrestore(&pgd_lock, flags);
- }
-
- /*
-@@ -280,12 +280,12 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
- * respect to anything walking the pgd_list, so that they
- * never see a partially populated pgd.
- */
-- spin_lock_irqsave(&pgd_lock, flags);
-+ write_lock_irqsave(&pgd_lock, flags);
-
- pgd_ctor(mm, pgd);
- pgd_prepopulate_pmd(mm, pgd, pmds);
-
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ write_unlock_irqrestore(&pgd_lock, flags);
-
- return pgd;
++/* Handles shared IRQs that can to device domain and control domain. */
++void pciback_irq_handler(struct pci_dev *dev, int reset);
++irqreturn_t pciback_guest_interrupt(int irq, void *dev_id);
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 011db67..cb54893 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -13,6 +13,78 @@
+ int verbose_request;
+ module_param(verbose_request, int, 0644);
-diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
-index 0c376a2..85c4342 100644
---- a/arch/x86/xen/mmu.c
-+++ b/arch/x86/xen/mmu.c
-@@ -1036,10 +1036,9 @@ static void xen_pgd_pin(struct mm_struct *mm)
- */
- void xen_mm_pin_all(void)
++/* Ensure a device is has the fake IRQ handler "turned on/off" and is
++ * ready to be exported. This MUST be run after pciback_reset_device
++ * which does the actual PCI device enable/disable.
++ */
++void pciback_control_isr(struct pci_dev *dev, int reset)
++{
++ struct pciback_dev_data *dev_data;
++ int rc;
++ int enable = 0;
++
++ dev_data = pci_get_drvdata(dev);
++ if (!dev_data)
++ return;
++
++ /* We don't deal with bridges */
++ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL)
++ return;
++
++ if (reset) {
++ dev_data->enable_intx = 0;
++ dev_data->ack_intr = 0;
++ }
++ enable = dev_data->enable_intx;
++
++ /* Asked to disable, but ISR isn't runnig */
++ if (!enable && !dev_data->isr_on)
++ return;
++
++ /* Squirrel away the IRQs in the dev_data. We need this
++ * b/c when device transitions to MSI, the dev->irq is
++ * overwritten with the MSI vector.
++ */
++ if (enable)
++ dev_data->irq = dev->irq;
++
++ dev_dbg(&dev->dev, "%s: #%d %s %s%s %s-> %s\n",
++ dev_data->irq_name,
++ dev_data->irq,
++ pci_is_enabled(dev) ? "on" : "off",
++ dev->msi_enabled ? "MSI" : "",
++ dev->msix_enabled ? "MSI/X" : "",
++ dev_data->isr_on ? "enable" : "disable",
++ enable ? "enable" : "disable");
++
++ if (enable) {
++ rc = request_irq(dev_data->irq,
++ pciback_guest_interrupt, IRQF_SHARED,
++ dev_data->irq_name, dev);
++ if (rc) {
++ dev_err(&dev->dev, "%s: failed to install fake IRQ " \
++ "handler for IRQ %d! (rc:%d)\n", dev_data->irq_name,
++ dev_data->irq, rc);
++ goto out;
++ }
++ }
++ else {
++ free_irq(dev_data->irq, dev);
++ dev_data->irq = 0;
++ }
++ dev_data->isr_on = enable;
++ dev_data->ack_intr = enable;
++out:
++ dev_dbg(&dev->dev, "%s: #%d %s %s%s %s\n",
++ dev_data->irq_name,
++ dev_data->irq,
++ pci_is_enabled(dev) ? "on" : "off",
++ dev->msi_enabled ? "MSI" : "",
++ dev->msix_enabled ? "MSI/X" : "",
++ enable ? (dev_data->isr_on ? "enabled" : "failed to enable") :
++ (dev_data->isr_on ? "failed to disable" : "disabled"));
++}
++
+ /* Ensure a device is "turned off" and ready to be exported.
+ * (Also see pciback_config_reset to ensure virtual configuration space is
+ * ready to be re-exported)
+@@ -21,6 +93,8 @@ void pciback_reset_device(struct pci_dev *dev)
{
-- unsigned long flags;
- struct page *page;
-
-- spin_lock_irqsave(&pgd_lock, flags);
-+ read_lock(&pgd_lock);
-
- list_for_each_entry(page, &pgd_list, lru) {
- if (!PagePinned(page)) {
-@@ -1048,7 +1047,7 @@ void xen_mm_pin_all(void)
- }
- }
-
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ read_unlock(&pgd_lock);
- }
+ u16 cmd;
- /*
-@@ -1149,10 +1148,9 @@ static void xen_pgd_unpin(struct mm_struct *mm)
- */
- void xen_mm_unpin_all(void)
- {
-- unsigned long flags;
- struct page *page;
++ pciback_control_isr(dev, 1 /* reset device */);
++
+ /* Disable devices (but not bridges) */
+ if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
+ #ifdef CONFIG_PCI_MSI
+@@ -78,13 +152,18 @@ void pciback_do_op(struct work_struct *data)
+ struct pciback_device *pdev =
+ container_of(data, struct pciback_device, op_work);
+ struct pci_dev *dev;
++ struct pciback_dev_data *dev_data = NULL;
+ struct xen_pci_op *op = &pdev->sh_info->op;
++ int test_intx = 0;
-- spin_lock_irqsave(&pgd_lock, flags);
-+ read_lock(&pgd_lock);
+ dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
- list_for_each_entry(page, &pgd_list, lru) {
- if (PageSavePinned(page)) {
-@@ -1162,7 +1160,7 @@ void xen_mm_unpin_all(void)
+ if (dev == NULL)
+ op->err = XEN_PCI_ERR_dev_not_found;
+ else {
++ dev_data = pci_get_drvdata(dev);
++ if (dev_data)
++ test_intx = dev_data->enable_intx;
+ switch (op->cmd) {
+ case XEN_PCI_OP_conf_read:
+ op->err = pciback_config_read(dev,
+@@ -109,10 +188,15 @@ void pciback_do_op(struct work_struct *data)
+ break;
+ #endif
+ default:
+- op->err = XEN_PCI_ERR_not_implemented;
++ op->err = XEN_PCI_ERR_not_implemented;
+ break;
}
}
++ if (!op->err && dev && dev_data) {
++ /* Transition detected */
++ if ((dev_data->enable_intx != test_intx))
++ pciback_control_isr(dev, 0 /* no reset */);
++ }
+ /* Tell the driver domain that we're done. */
+ wmb();
+ clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
+@@ -137,3 +221,12 @@ irqreturn_t pciback_handle_event(int irq, void *dev_id)
-- spin_unlock_irqrestore(&pgd_lock, flags);
-+ read_unlock(&pgd_lock);
+ return IRQ_HANDLED;
}
-
- void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
---
-1.7.4
-
-
-From a5c2467c12bdbac588e272c66f985d25b5a6ae21 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 14:41:16 -0500
-Subject: [PATCH 212/244] xen/irq: Use the Xen PIRQ value instead of GSI value to check.
-
-In reality it does not matter as we save the PIRQ value
-as GSI for legacy interrupts (INT). So for those PIRQ==GSI.
-
-But in case in the future we seperate the PIRQ==GSI
-for legacy interrupts, we won't hit this bug.
----
- drivers/xen/events.c | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 3929c20..6cad295 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -1441,7 +1441,7 @@ int xen_ignore_irq(int irq)
- {
- struct irq_info *info = info_for_irq(irq);
- struct physdev_irq_status_query irq_status = { .irq =
-- info->u.pirq.gsi };
-+ info->u.pirq.pirq };
-
- if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
- return 0;
++irqreturn_t pciback_guest_interrupt(int irq, void *dev_id)
++{
++ struct pci_dev *dev = (struct pci_dev *)dev_id;
++ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++
++ if (dev_data->isr_on && dev_data->ack_intr)
++ return IRQ_HANDLED;
++ return IRQ_NONE;
++}
--
1.7.4
-From bd9b08c4150f4ed9ca3481244d38e7964cd62c25 Mon Sep 17 00:00:00 2001
+From ff798d2af7f9f02521295a073d38d86f00771739 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 13:47:16 -0500
-Subject: [PATCH 213/244] xen/irq: Export 'xen_pirq_from_irq' function.
-
-We need this to find the real Xen PIRQ value for either
-an device that requests an MSI, MSI-X.
+Date: Mon, 12 Apr 2010 11:47:15 -0400
+Subject: [PATCH 190/203] xen-pciback: Add SysFS instrumentation for the fake IRQ
handler.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/events.c | 6 ++++++
- include/xen/events.h | 3 +++
- 2 files changed, 9 insertions(+), 0 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 75 +++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 74 insertions(+), 1 deletions(-)
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 6cad295..6fae78a 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -790,6 +790,12 @@ int xen_gsi_from_irq(unsigned irq)
- return pirq_to_irq[pirq];
- }
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 45bbe99..ee2cd68 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -1038,6 +1038,70 @@ static ssize_t pcistub_slot_show(struct device_driver *drv, char
*buf)
+
+ DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
++static ssize_t pcistub_irq_handler_show(struct device_driver *drv, char *buf)
++{
++ struct pcistub_device *psdev;
++ struct pciback_dev_data *dev_data;
++ size_t count = 0;
++ unsigned long flags;
+
-+int xen_pirq_from_irq(unsigned irq)
++ spin_lock_irqsave(&pcistub_devices_lock, flags);
++ list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++ if (count >= PAGE_SIZE)
++ break;
++ if (!psdev->dev)
++ continue;
++ dev_data = pci_get_drvdata(psdev->dev);
++ if (!dev_data)
++ continue;
++ count +=
++ scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing\n",
++ pci_name(psdev->dev),
++ dev_data->isr_on ? "on" : "off",
++ dev_data->ack_intr ? "ack" : "not ack");
++ }
++ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++ return count;
++}
++
++DRIVER_ATTR(irq_handlers, S_IRUSR, pcistub_irq_handler_show, NULL);
++
++static ssize_t pcistub_irq_handler_switch(struct device_driver *drv,
++ const char *buf,
++ size_t count)
+{
-+ return pirq_from_irq(irq);
++ struct pcistub_device *psdev;
++ struct pciback_dev_data *dev_data;
++ int domain, bus, slot, func;
++ int err = -ENOENT;
++
++ err = str_to_slot(buf, &domain, &bus, &slot, &func);
++ if (err)
++ goto out;
++
++ psdev = pcistub_device_find(domain, bus, slot, func);
++
++ if (!psdev)
++ goto out;
++
++ dev_data = pci_get_drvdata(psdev->dev);
++ if (!dev_data)
++ goto out;
++
++ dev_dbg(&psdev->dev->dev, "%s fake irq handler: %d->%d\n",
++ dev_data->irq_name, dev_data->isr_on,
++ !dev_data->isr_on);
++
++ dev_data->isr_on = !(dev_data->isr_on);
++ if (dev_data->isr_on)
++ dev_data->ack_intr = 1;
++out:
++ if (!err)
++ err = count;
++ return err;
+}
-+EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
- int bind_evtchn_to_irq(unsigned int evtchn)
++DRIVER_ATTR(irq_handler_state, S_IWUSR, NULL, pcistub_irq_handler_switch);
++
+ static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
+ size_t count)
{
- int irq;
-diff --git a/include/xen/events.h b/include/xen/events.h
-index 2fe1644..baf5c0d 100644
---- a/include/xen/events.h
-+++ b/include/xen/events.h
-@@ -95,6 +95,9 @@ int xen_vector_from_irq(unsigned pirq);
- /* Return irq from pirq */
- int xen_irq_from_pirq(unsigned pirq);
+@@ -1177,7 +1241,10 @@ static void pcistub_exit(void)
+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
+ driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
+-
++ driver_remove_file(&pciback_pci_driver.driver,
++ &driver_attr_irq_handlers);
++ driver_remove_file(&pciback_pci_driver.driver,
++ &driver_attr_irq_handler_state);
+ pci_unregister_driver(&pciback_pci_driver);
+ }
-+/* Return the pirq allocated to the irq. */
-+int xen_pirq_from_irq(unsigned irq);
-+
- /* Determine whether to ignore this IRQ if passed to a guest. */
- int xen_ignore_irq(int irq);
+@@ -1236,6 +1303,12 @@ static int __init pcistub_init(void)
+ err = driver_create_file(&pciback_pci_driver.driver,
+ &driver_attr_permissive);
+
++ if (!err)
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_irq_handlers);
++ if (!err)
++ err = driver_create_file(&pciback_pci_driver.driver,
++ &driver_attr_irq_handler_state);
+ if (err)
+ pcistub_exit();
--
1.7.4
-From 575c8f289a97f3800f1442e13795d93fef87ca2b Mon Sep 17 00:00:00 2001
+From 446e7d199298a891003b36a2cd29d8db46640443 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 13:44:38 -0500
-Subject: [PATCH 215/244] xen/pciback: Utilize 'xen_pirq_from_irq' to get PIRQ
value.
+Date: Mon, 19 Apr 2010 14:39:10 -0400
+Subject: [PATCH 191/203] xen-pciback: When device transitions to MSI/MSI-X stop ACK-ing
on the
+ legacy interrupt.
-In the past the Xen IRQ code had overloaded the irq->gsi with
-ton of uses. The 'gsi' would be a real GSI, an vector value, or
-a Xen PIRQ value. We were quite dilligient in having the correct
-value there for the guest, but with the IRQ rework code this
-overloading is gone. As so, use the correct function to retrieve
-the PIRQ value.
+But don't remove the irq handler from the legacy interrupt. The device
+might still transition back to the legacy interrupts.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/pciback/conf_space_capability_msi.c | 26 +++++++++++++++-------
- 1 files changed, 18 insertions(+), 8 deletions(-)
+ drivers/xen/pciback/conf_space_capability_msi.c | 17 ++++++++++++++++-
+ 1 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index 3acda69..c9b0aba 100644
+index b70ea8b..a236e2d 100644
--- a/drivers/xen/pciback/conf_space_capability_msi.c
+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -30,7 +30,8 @@ int pciback_enable_msi(struct pciback_device *pdev,
+@@ -12,6 +12,7 @@
+ int pciback_enable_msi(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
++ struct pciback_dev_data *dev_data;
+ int otherend = pdev->xdev->otherend_id;
+ int status;
+@@ -27,21 +28,29 @@ int pciback_enable_msi(struct pciback_device *pdev,
/* The value the guest needs is actually the IDT vector, not the
* the local domain's IRQ number. */
-- op->value = xen_gsi_from_irq(dev->irq);
-+
-+ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 0;
-@@ -47,7 +48,7 @@ int pciback_disable_msi(struct pciback_device *pdev,
- printk(KERN_DEBUG "pciback: %s: disable MSI\n", pci_name(dev));
+ op->value = xen_gsi_from_irq(dev->irq);
++ dev_data = pci_get_drvdata(dev);
++ if (dev_data)
++ dev_data->ack_intr = 0;
+ return 0;
+ }
+
+ int pciback_disable_msi(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
++ struct pciback_dev_data *dev_data;
pci_disable_msi(dev);
-- op->value = xen_gsi_from_irq(dev->irq);
-+ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 1;
-@@ -77,12 +78,17 @@ int pciback_enable_msix(struct pciback_device *pdev,
+ op->value = xen_gsi_from_irq(dev->irq);
++ dev_data = pci_get_drvdata(dev);
++ if (dev_data)
++ dev_data->ack_intr = 1;
+ return 0;
+ }
- result = pci_enable_msix(dev, entries, op->value);
+ int pciback_enable_msix(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
++ struct pciback_dev_data *dev_data;
+ int i, result;
+ struct msix_entry *entries;
-- for (i = 0; i < op->value; i++) {
-- op->msix_entries[i].entry = entries[i].entry;
-- op->msix_entries[i].vector =
-- xen_gsi_from_irq(entries[i].vector);
-+ if (result == 0) {
-+ for (i = 0; i < op->value; i++) {
-+ op->msix_entries[i].entry = entries[i].entry;
-+ if (entries[i].vector)
-+ op->msix_entries[i].vector =
-+ xen_pirq_from_irq(entries[i].vector);
-+ }
-+ } else {
-+ printk(KERN_WARNING "pciback: %s: failed to enable MSI-X: err %d!\n",
-+ pci_name(dev), result);
- }
--
+@@ -68,6 +77,9 @@ int pciback_enable_msix(struct pciback_device *pdev,
kfree(entries);
op->value = result;
-@@ -102,7 +108,11 @@ int pciback_disable_msix(struct pciback_device *pdev,
- pci_name(dev));
- pci_disable_msix(dev);
-
-- op->value = xen_gsi_from_irq(dev->irq);
-+ /*
-+ * SR-IOV devices (which don't have any legacy IRQ) have
-+ * an undefined IRQ value of zero.
-+ */
-+ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 1;
---
-1.7.4
-
-
-From 4e9fecd2ff61c6de8935899d22f4d885ea1e86d0 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 16:26:44 -0500
-Subject: [PATCH 217/244] xen/irq: The Xen hypervisor cleans up the PIRQs if the other
domain forgot.
-
-And if the other domain forgot to clean up its PIRQs we don't need
-to fail the operation. Just take a note of it and continue on.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/events.c | 9 ++++++++-
- 1 files changed, 8 insertions(+), 1 deletions(-)
-
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 6fae78a..ae75de9 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -765,7 +765,14 @@ int xen_destroy_irq(int irq)
- unmap_irq.pirq = info->u.pirq.gsi;
- unmap_irq.domid = info->u.pirq.domid;
- rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
-- if (rc) {
-+ /* If another domain quits without making the pci_disable_msix
-+ * call, the Xen hypervisor takes care of freeing the PIRQs
-+ * (free_domain_pirqs).
-+ */
-+ if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF))
-+ printk(KERN_INFO "domain %d does not have %d anymore\n",
-+ info->u.pirq.domid, info->u.pirq.pirq);
-+ else if (rc) {
- printk(KERN_WARNING "unmap irq failed %d\n", rc);
- goto out;
- }
---
-1.7.4
-
-
-From 749e3b1fb00ad9537bbf866b8ad81fa2eff29ce5 Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 15:43:25 -0500
-Subject: [PATCH 224/244] xen/pciback: Don't setup an fake IRQ handler for SR-IOV
devices.
-
-If we try to setup an fake IRQ handler for legacy interrupts
-for devices that only have MSI-X (most if not all SR-IOV cards),
-we will fail with this:
-
-pciback[0000:01:10.0]: failed to install fake IRQ handler for IRQ 0! (rc:-38)
-
-Since those cards don't have anything in dev->irq.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/pciback/pciback_ops.c | 7 +++++++
- 1 files changed, 7 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
-index 9a465e9..68980d8 100644
---- a/drivers/xen/pciback/pciback_ops.c
-+++ b/drivers/xen/pciback/pciback_ops.c
-@@ -48,6 +48,13 @@ void pciback_control_isr(struct pci_dev *dev, int reset)
- if (enable)
- dev_data->irq = dev->irq;
-
-+ /*
-+ * SR-IOV devices in all use MSI-X and have no legacy
-+ * interrupts, so inhibit creating a fake IRQ handler for them.
-+ */
-+ if (dev_data->irq == 0)
-+ goto out;
-+
- dev_dbg(&dev->dev, "%s: #%d %s %s%s %s-> %s\n",
- dev_data->irq_name,
- dev_data->irq,
---
-1.7.4
-
-
-From 647388a2bb3a993644a0f05189d83c7fe56a7f0c Mon Sep 17 00:00:00 2001
-From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 17 Feb 2011 11:18:00 -0500
-Subject: [PATCH 227/244] xen/pciback: Print out the MSI/MSI-X (PIRQ) values when
allocating
-
-If the verbose_request is set (and loglevel high enought), print out
-the MSI/MSI-X values sent to the guest. This should aid in debugging
-issues.
-
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/xen/pciback/conf_space_capability_msi.c | 15 +++++++++++++++
- 1 files changed, 15 insertions(+), 0 deletions(-)
-
-diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
-index c9b0aba..041e4aa 100644
---- a/drivers/xen/pciback/conf_space_capability_msi.c
-+++ b/drivers/xen/pciback/conf_space_capability_msi.c
-@@ -32,6 +32,10 @@ int pciback_enable_msi(struct pciback_device *pdev,
- * the local domain's IRQ number. */
-
- op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: MSI: %d\n", pci_name(dev),
-+ op->value);
-+
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 0;
-@@ -49,6 +53,9 @@ int pciback_disable_msi(struct pciback_device *pdev,
- pci_disable_msi(dev);
-
- op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: MSI: %d\n", pci_name(dev),
-+ op->value);
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 1;
-@@ -84,6 +91,11 @@ int pciback_enable_msix(struct pciback_device *pdev,
- if (entries[i].vector)
- op->msix_entries[i].vector =
- xen_pirq_from_irq(entries[i].vector);
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: " \
-+ "MSI-X[%d]: %d\n",
-+ pci_name(dev), i,
-+ op->msix_entries[i].vector);
- }
- } else {
- printk(KERN_WARNING "pciback: %s: failed to enable MSI-X: err %d!\n",
-@@ -113,6 +125,9 @@ int pciback_disable_msix(struct pciback_device *pdev,
- * an undefined IRQ value of zero.
- */
- op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
-+ if (unlikely(verbose_request))
-+ printk(KERN_DEBUG "pciback: %s: MSI-X: %d\n", pci_name(dev),
-+ op->value);
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 1;
---
-1.7.4
-
-
-From db2e2e6ee9ee9ce93b04c6975fdfef304771d6ad Mon Sep 17 00:00:00 2001
-From: Tejun Heo <tj(a)kernel.org>
-Date: Mon, 24 Jan 2011 15:43:03 +0100
-Subject: [PATCH 228/244] xen-pcifront: don't use flush_scheduled_work()
-
-flush_scheduled_work() is scheduled for deprecation. Cancel ->op_work
-directly instead.
-
-Signed-off-by: Tejun Heo <tj(a)kernel.org>
-Cc: Ryan Wilson <hap9(a)epoch.ncsc.mil>
-Cc: Jan Beulich <JBeulich(a)novell.com>
-Cc: Jesse Barnes <jbarnes(a)virtuousgeek.org>
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
----
- drivers/pci/xen-pcifront.c | 3 +--
- 1 files changed, 1 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
-index 3a5a6fc..030ce37 100644
---- a/drivers/pci/xen-pcifront.c
-+++ b/drivers/pci/xen-pcifront.c
-@@ -733,8 +733,7 @@ static void free_pdev(struct pcifront_device *pdev)
++ dev_data = pci_get_drvdata(dev);
++ if (dev_data)
++ dev_data->ack_intr = 0;
- pcifront_free_roots(pdev);
+ return result;
+ }
+@@ -75,10 +87,13 @@ int pciback_enable_msix(struct pciback_device *pdev,
+ int pciback_disable_msix(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
+-
++ struct pciback_dev_data *dev_data;
+ pci_disable_msix(dev);
-- /*For PCIE_AER error handling job*/
-- flush_scheduled_work();
-+ cancel_work_sync(&pdev->op_work);
+ op->value = xen_gsi_from_irq(dev->irq);
++ dev_data = pci_get_drvdata(dev);
++ if (dev_data)
++ dev_data->ack_intr = 1;
+ return 0;
+ }
- if (pdev->irq >= 0)
- unbind_from_irqhandler(pdev->irq, pdev);
--
1.7.4
-From 1fb6c1f210d13d7099ece8aee5f351b7e5ecb3bd Mon Sep 17 00:00:00 2001
+From 21c175503ade61702706a1db311a00d054bbdb2f Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 17 Feb 2011 11:23:58 -0500
-Subject: [PATCH 233/244] xen/irq: Cleanup up the pirq_to_irq for DomU PV PCI passthrough
guests as well.
+Date: Mon, 19 Apr 2010 14:40:38 -0400
+Subject: [PATCH 192/203] xen-pciback: Enable interrupt handler when device is enabled.
-We only did this for PV guests that are xen_initial_domain() but
-there is not reason not to do this for other cases. The other
-case is only exercised when you pass in a PCI device to a PV guest
-_and_ the device in question.
+And also request it to be disabled when the device has been
+disabled.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/xen/events.c | 3 ++-
- 1 files changed, 2 insertions(+), 1 deletions(-)
+ drivers/xen/pciback/conf_space_header.c | 6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
-diff --git a/drivers/xen/events.c b/drivers/xen/events.c
-index 975e90f..89987a7 100644
---- a/drivers/xen/events.c
-+++ b/drivers/xen/events.c
-@@ -766,8 +766,9 @@ int xen_destroy_irq(int irq)
- printk(KERN_WARNING "unmap irq failed %d\n", rc);
- goto out;
- }
-- pirq_to_irq[info->u.pirq.pirq] = -1;
+diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
+index 1f4f86e..cb450f4 100644
+--- a/drivers/xen/pciback/conf_space_header.c
++++ b/drivers/xen/pciback/conf_space_header.c
+@@ -39,8 +39,10 @@ static int command_read(struct pci_dev *dev, int offset, u16 *value,
void *data)
+
+ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
+ {
++ struct pciback_dev_data *dev_data;
+ int err;
+
++ dev_data = pci_get_drvdata(dev);
+ if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
+ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: enable\n",
+@@ -48,11 +50,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value,
void *data)
+ err = pci_enable_device(dev);
+ if (err)
+ return err;
++ if (dev_data)
++ dev_data->enable_intx = 1;
+ } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
+ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: disable\n",
+ pci_name(dev));
+ pci_disable_device(dev);
++ if (dev_data)
++ dev_data->enable_intx = 0;
}
-+ pirq_to_irq[info->u.pirq.pirq] = -1;
-+
- irq_info[irq] = mk_unbound_info();
- xen_free_irq(irq);
+ if (!dev->is_busmaster && is_master_cmd(value)) {
--
1.7.4
-From 1d4610527bc71d3f9eea520fc51a02d54f79dcd0 Mon Sep 17 00:00:00 2001
+From 25a782a051af48a60bd92fe93375eb38a7aa5206 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 13:43:22 -0500
-Subject: [PATCH 237/244] xen-pcifront: Sanity check the MSI/MSI-X values
+Date: Mon, 19 Apr 2010 16:23:06 -0400
+Subject: [PATCH 193/203] xen-pciback: Probe the IRQ line to check if it is not shared.
-Check the returned vector values for any values that are
-odd or plain incorrect (say vector value zero), and if so
-print a warning. Also fixup the return values.
+If it is not shared, we stop ACK-ing the IRQ line as there is
+no need for this irq handler to return IRQ_HANDLED.
-This patch was precipiated by the Xen PCIBack returning the
-incorrect values due to how it was retrieving PIRQ values.
-This has been fixed in the xen-pciback by
-"xen/pciback: Utilize 'xen_pirq_from_irq' to get PIRQ value"
-patch.
+We have to this check once much much later than the pciback
+and pcifront have started talking as guests doing the hypercall
+that would notify the other guest that the IRQ line is shared
+is done asynchronously.
-Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
+[v2: xen_ignore_irq->xen_test_irq_shared]
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- drivers/pci/xen-pcifront.c | 20 ++++++++++++++++----
- 1 files changed, 16 insertions(+), 4 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 5 +++--
+ drivers/xen/pciback/pciback.h | 1 +
+ drivers/xen/pciback/pciback_ops.c | 12 +++++++++++-
+ 3 files changed, 15 insertions(+), 3 deletions(-)
-diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
-index 030ce37..5c7b6ad 100644
---- a/drivers/pci/xen-pcifront.c
-+++ b/drivers/pci/xen-pcifront.c
-@@ -277,18 +277,24 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
- if (likely(!err)) {
- if (likely(!op.value)) {
- /* we get the result */
-- for (i = 0; i < nvec; i++)
-+ for (i = 0; i < nvec; i++) {
-+ if (op.msix_entries[i].vector <= 0) {
-+ dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n",
-+ i, op.msix_entries[i].vector);
-+ err = -EINVAL;
-+ *(*vector+i) = -1;
-+ continue;
-+ }
- *(*vector+i) = op.msix_entries[i].vector;
-- return 0;
-+ }
- } else {
- printk(KERN_DEBUG "enable msix get value %x\n",
- op.value);
-- return op.value;
- }
- } else {
- dev_err(&dev->dev, "enable msix get err %x\n", err);
-- return err;
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index ee2cd68..88c7ca1 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -1055,10 +1055,11 @@ static ssize_t pcistub_irq_handler_show(struct device_driver
*drv, char *buf)
+ if (!dev_data)
+ continue;
+ count +=
+- scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing\n",
++ scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing:%ld\n",
+ pci_name(psdev->dev),
+ dev_data->isr_on ? "on" : "off",
+- dev_data->ack_intr ? "ack" : "not ack");
++ dev_data->ack_intr ? "ack" : "not ack",
++ dev_data->handled);
}
-+ return err;
- }
+ spin_unlock_irqrestore(&pcistub_devices_lock, flags);
+ return count;
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index 9d1b0a6..fc31052 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -50,6 +50,7 @@ struct pciback_dev_data {
+ unsigned int enable_intx : 1;
+ unsigned int isr_on : 1; /* Whether the IRQ handler is installed. */
+ unsigned int ack_intr : 1; /* .. and ACK-ing */
++ unsigned long handled;
+ unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
+ char irq_name[0]; /* pciback[000:04:00.0] */
+ };
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index cb54893..2c5a90d 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -226,7 +226,17 @@ irqreturn_t pciback_guest_interrupt(int irq, void *dev_id)
+ struct pci_dev *dev = (struct pci_dev *)dev_id;
+ struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
- static void pci_frontend_disable_msix(struct pci_dev *dev)
-@@ -325,6 +331,12 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int
**vector)
- err = do_pci_op(pdev, &op);
- if (likely(!err)) {
- *(*vector) = op.value;
-+ if (op.value <= 0) {
-+ dev_warn(&dev->dev, "MSI entry is invalid: %d!\n",
-+ op.value);
-+ err = -EINVAL;
-+ *(*vector) = -1;
+- if (dev_data->isr_on && dev_data->ack_intr)
++ if (dev_data->isr_on && dev_data->ack_intr) {
++ dev_data->handled++;
++ if ((dev_data->handled % 1000) == 0) {
++ if (xen_test_irq_shared(irq)) {
++ printk(KERN_INFO "%s IRQ line is not shared "
++ "with other domains. Turning ISR off\n",
++ dev_data->irq_name);
++ dev_data->ack_intr = 0;
++ }
+ }
- } else {
- dev_err(&dev->dev, "pci frontend enable msi failed for dev "
- "%x:%x\n", op.bus, op.devfn);
+ return IRQ_HANDLED;
++ }
+ return IRQ_NONE;
+ }
--
1.7.4
-From 55cb8cd45e0600df1473489518d7f12ce1bbe973 Mon Sep 17 00:00:00 2001
+From 6191b41a7f3b63c4d762a2d0534f64d388ab2cf2 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Wed, 16 Feb 2011 13:43:04 -0500
-Subject: [PATCH 238/244] pci/xen: Use xen_allocate_pirq_msi instead of xen_allocate_pirq
-
-xen_allocate_pirq -> xen_map_pirq_gsi -> PHYSDEVOP_alloc_irq_vector IFF
-xen_initial_domain() in addition to the kernel side book-keeping side of
-things (set chip and handler, update irq_info etc) whereas
-xen_allocate_pirq_msi just does the kernel book keeping.
-
-Also xen_allocate_pirq allocates an IRQ in the 1-1 GSI space whereas
-xen_allocate_pirq_msi allocates a dynamic one in the >GSI IRQ space.
-
-All of this is uneccessary as this code path is only executed
-when we run as a domU PV guest with an MSI/MSI-X PCI card passed in.
-Hence we can jump straight to allocating an dynamic IRQ (and
-binding it to the proper PIRQ) and skip the rest.
-
-In short: this change is a cosmetic one.
+Date: Tue, 20 Apr 2010 20:22:40 -0400
+Subject: [PATCH 194/203] xen-pciback: Add debug statements for the MSI/MSI-X
configuration module.
-Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
-Reviewed-by: Stefano Stabellini <stefano.stabellini(a)eu.citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- arch/x86/pci/xen.c | 6 +++---
- 1 files changed, 3 insertions(+), 3 deletions(-)
+ drivers/xen/pciback/conf_space_capability_msi.c | 11 +++++++++++
+ 1 files changed, 11 insertions(+), 0 deletions(-)
-diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
-index 25cd4a0..6432f75 100644
---- a/arch/x86/pci/xen.c
-+++ b/arch/x86/pci/xen.c
-@@ -157,14 +157,14 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
- goto error;
- i = 0;
- list_for_each_entry(msidesc, &dev->msi_list, list) {
-- irq = xen_allocate_pirq(v[i], 0, /* not sharable */
-+ xen_allocate_pirq_msi(
- (type == PCI_CAP_ID_MSIX) ?
-- "pcifront-msi-x" : "pcifront-msi");
-+ "pcifront-msi-x" : "pcifront-msi",
-+ &irq, &v[i], XEN_ALLOC_IRQ);
- if (irq < 0) {
- ret = -1;
- goto free;
- }
--
- ret = set_irq_msi(irq, msidesc);
- if (ret)
- goto error_while;
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+index a236e2d..b15131e 100644
+--- a/drivers/xen/pciback/conf_space_capability_msi.c
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -16,6 +16,9 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ int otherend = pdev->xdev->otherend_id;
+ int status;
+
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: enable MSI\n", pci_name(dev));
++
+ status = pci_enable_msi(dev);
+
+ if (status) {
+@@ -31,6 +34,7 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 0;
++
+ return 0;
+ }
+
+@@ -38,6 +42,9 @@ int pciback_disable_msi(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
+ struct pciback_dev_data *dev_data;
++
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: disable MSI\n", pci_name(dev));
+ pci_disable_msi(dev);
+
+ op->value = xen_gsi_from_irq(dev->irq);
+@@ -54,6 +61,8 @@ int pciback_enable_msix(struct pciback_device *pdev,
+ int i, result;
+ struct msix_entry *entries;
+
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: enable MSI-X\n", pci_name(dev));
+ if (op->value > SH_INFO_MAX_VEC)
+ return -EINVAL;
+
+@@ -88,6 +97,8 @@ int pciback_disable_msix(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
+ struct pciback_dev_data *dev_data;
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: disable MSI-X\n", pci_name(dev));
+ pci_disable_msix(dev);
+
+ op->value = xen_gsi_from_irq(dev->irq);
--
1.7.4
-From cc0f89c4a426fcd6400a89e9e34e4a8851abef76 Mon Sep 17 00:00:00 2001
+From 72b558f033e163ac371afa880ff7036859f6f0b0 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 17 Feb 2011 12:02:23 -0500
-Subject: [PATCH 239/244] pci/xen: Cleanup: convert int** to int[]
+Date: Fri, 23 Jul 2010 14:35:47 -0400
+Subject: [PATCH 195/203] xen-pciback: Redo spinlock usage.
-Cleanup code. Cosmetic change to make the code look easier
-to read.
+We were using coarse spinlocks that could end up with a deadlock.
+This patch fixes that and makes the spinlocks much more fine-grained.
-Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- arch/x86/include/asm/xen/pci.h | 8 ++++----
- arch/x86/pci/xen.c | 4 ++--
- drivers/pci/xen-pcifront.c | 12 ++++++------
- 3 files changed, 12 insertions(+), 12 deletions(-)
+ drivers/xen/pciback/xenbus.c | 34 +++++++++++++++++++++-------------
+ 1 files changed, 21 insertions(+), 13 deletions(-)
-diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
-index 2329b3e..aa86209 100644
---- a/arch/x86/include/asm/xen/pci.h
-+++ b/arch/x86/include/asm/xen/pci.h
-@@ -27,16 +27,16 @@ static inline void __init xen_setup_pirqs(void)
- * its own functions.
- */
- struct xen_pci_frontend_ops {
-- int (*enable_msi)(struct pci_dev *dev, int **vectors);
-+ int (*enable_msi)(struct pci_dev *dev, int vectors[]);
- void (*disable_msi)(struct pci_dev *dev);
-- int (*enable_msix)(struct pci_dev *dev, int **vectors, int nvec);
-+ int (*enable_msix)(struct pci_dev *dev, int vectors[], int nvec);
- void (*disable_msix)(struct pci_dev *dev);
- };
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index d448bf5..f0d5426 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -54,23 +54,31 @@ static void pciback_disconnect(struct pciback_device *pdev)
+ unbind_from_irqhandler(pdev->evtchn_irq, pdev);
+ pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
+ }
++ spin_unlock(&pdev->dev_lock);
- extern struct xen_pci_frontend_ops *xen_pci_frontend;
+ /* If the driver domain started an op, make sure we complete it
+ * before releasing the shared memory */
++
++ /* Note, the workqueue does not use spinlocks at all.*/
+ flush_workqueue(pciback_wq);
- static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev,
-- int **vectors)
-+ int vectors[])
- {
- if (xen_pci_frontend && xen_pci_frontend->enable_msi)
- return xen_pci_frontend->enable_msi(dev, vectors);
-@@ -48,7 +48,7 @@ static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev)
- xen_pci_frontend->disable_msi(dev);
++ spin_lock(&pdev->dev_lock);
+ if (pdev->sh_info != NULL) {
+ xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info);
+ pdev->sh_info = NULL;
+ }
+-
+ spin_unlock(&pdev->dev_lock);
++
}
- static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev,
-- int **vectors, int nvec)
-+ int vectors[], int nvec)
+
+ static void free_pdev(struct pciback_device *pdev)
{
- if (xen_pci_frontend && xen_pci_frontend->enable_msix)
- return xen_pci_frontend->enable_msix(dev, vectors, nvec);
-diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
-index 6432f75..30fdd09 100644
---- a/arch/x86/pci/xen.c
-+++ b/arch/x86/pci/xen.c
-@@ -150,9 +150,9 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int
type)
- return -ENOMEM;
+- if (pdev->be_watching)
++ spin_lock(&pdev->dev_lock);
++ if (pdev->be_watching) {
+ unregister_xenbus_watch(&pdev->be_watch);
++ pdev->be_watching = 0;
++ }
++ spin_unlock(&pdev->dev_lock);
- if (type == PCI_CAP_ID_MSIX)
-- ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
-+ ret = xen_pci_frontend_enable_msix(dev, v, nvec);
- else
-- ret = xen_pci_frontend_enable_msi(dev, &v);
-+ ret = xen_pci_frontend_enable_msi(dev, v);
- if (ret)
- goto error;
- i = 0;
-diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
-index 5c7b6ad..492b7d8 100644
---- a/drivers/pci/xen-pcifront.c
-+++ b/drivers/pci/xen-pcifront.c
-@@ -243,7 +243,7 @@ struct pci_ops pcifront_bus_ops = {
+ pciback_disconnect(pdev);
- #ifdef CONFIG_PCI_MSI
- static int pci_frontend_enable_msix(struct pci_dev *dev,
-- int **vector, int nvec)
-+ int vector[], int nvec)
- {
- int err;
- int i;
-@@ -282,10 +282,10 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
- dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n",
- i, op.msix_entries[i].vector);
- err = -EINVAL;
-- *(*vector+i) = -1;
-+ vector[i] = -1;
- continue;
- }
-- *(*vector+i) = op.msix_entries[i].vector;
-+ vector[i] = op.msix_entries[i].vector;
- }
- } else {
- printk(KERN_DEBUG "enable msix get value %x\n",
-@@ -316,7 +316,7 @@ static void pci_frontend_disable_msix(struct pci_dev *dev)
- dev_err(&dev->dev, "pci_disable_msix get err %x\n", err);
+@@ -98,7 +106,10 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
+ "Error mapping other domain page in ours.");
+ goto out;
+ }
++
++ spin_lock(&pdev->dev_lock);
+ pdev->sh_info = vaddr;
++ spin_unlock(&pdev->dev_lock);
+
+ err = bind_interdomain_evtchn_to_irqhandler(
+ pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
+@@ -108,7 +119,10 @@ static int pciback_do_attach(struct pciback_device *pdev, int
gnt_ref,
+ "Error binding event channel to IRQ");
+ goto out;
+ }
++
++ spin_lock(&pdev->dev_lock);
+ pdev->evtchn_irq = err;
++ spin_unlock(&pdev->dev_lock);
+ err = 0;
+
+ dev_dbg(&pdev->xdev->dev, "Attached!\n");
+@@ -122,7 +136,6 @@ static int pciback_attach(struct pciback_device *pdev)
+ int gnt_ref, remote_evtchn;
+ char *magic = NULL;
+
+- spin_lock(&pdev->dev_lock);
+
+ /* Make sure we only do this setup once */
+ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+@@ -168,7 +181,6 @@ static int pciback_attach(struct pciback_device *pdev)
+
+ dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
+ out:
+- spin_unlock(&pdev->dev_lock);
+
+ kfree(magic);
+
+@@ -340,7 +352,6 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+ char state_str[64];
+ char dev_str[64];
+
+- spin_lock(&pdev->dev_lock);
+
+ dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
+
+@@ -481,8 +492,6 @@ static int pciback_reconfigure(struct pciback_device *pdev)
+ }
+
+ out:
+- spin_unlock(&pdev->dev_lock);
+-
+ return 0;
}
--static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
-+static int pci_frontend_enable_msi(struct pci_dev *dev, int vector[])
- {
- int err;
- struct xen_pci_op op = {
-@@ -330,12 +330,12 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int
**vector)
+@@ -539,8 +548,6 @@ static int pciback_setup_backend(struct pciback_device *pdev)
+ char dev_str[64];
+ char state_str[64];
+
+- spin_lock(&pdev->dev_lock);
+-
+ /* It's possible we could get the call to setup twice, so make sure
+ * we're not already connected.
+ */
+@@ -621,8 +628,6 @@ static int pciback_setup_backend(struct pciback_device *pdev)
+ "Error switching to initialised state!");
+
+ out:
+- spin_unlock(&pdev->dev_lock);
+-
+ if (!err)
+ /* see if pcifront is already configured (if not, we'll wait) */
+ pciback_attach(pdev);
+@@ -669,7 +674,10 @@ static int pciback_xenbus_probe(struct xenbus_device *dev,
+ pciback_be_watch);
+ if (err)
+ goto out;
++
++ spin_lock(&pdev->dev_lock);
+ pdev->be_watching = 1;
++ spin_unlock(&pdev->dev_lock);
+
+ /* We need to force a call to our callback here in case
+ * xend already configured us!
+@@ -708,8 +716,8 @@ int __init pciback_xenbus_register(void)
+ {
+ pciback_wq = create_workqueue("pciback_workqueue");
+ if (!pciback_wq) {
+- printk(KERN_ERR "pciback_xenbus_register: create"
+- "pciback_workqueue failed\n");
++ printk(KERN_ERR "%s: create"
++ "pciback_workqueue failed\n",__FUNCTION__);
+ return -EFAULT;
+ }
+ return xenbus_register_backend(&xenbus_pciback_driver);
+--
+1.7.4
+
+
+From 0db69b61a6240cb1a5e96c9352cdc4ff435a6449 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Wed, 28 Jul 2010 13:28:34 -0400
+Subject: [PATCH 196/203] xen-pciback: Remove spinlock for be->watching state.
+
+There is no need to guard this with a spinlock. It
+is already guarded by the xenwatch_thread against multiple
+customers.
+
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+---
+ drivers/xen/pciback/xenbus.c | 4 ----
+ 1 files changed, 0 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index f0d5426..993b659 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -73,12 +73,10 @@ static void pciback_disconnect(struct pciback_device *pdev)
+
+ static void free_pdev(struct pciback_device *pdev)
+ {
+- spin_lock(&pdev->dev_lock);
+ if (pdev->be_watching) {
+ unregister_xenbus_watch(&pdev->be_watch);
+ pdev->be_watching = 0;
+ }
+- spin_unlock(&pdev->dev_lock);
+
+ pciback_disconnect(pdev);
- err = do_pci_op(pdev, &op);
- if (likely(!err)) {
-- *(*vector) = op.value;
-+ vector[0] = op.value;
- if (op.value <= 0) {
- dev_warn(&dev->dev, "MSI entry is invalid: %d!\n",
- op.value);
- err = -EINVAL;
-- *(*vector) = -1;
-+ vector[0] = -1;
- }
- } else {
- dev_err(&dev->dev, "pci frontend enable msi failed for dev "
+@@ -675,9 +673,7 @@ static int pciback_xenbus_probe(struct xenbus_device *dev,
+ if (err)
+ goto out;
+
+- spin_lock(&pdev->dev_lock);
+ pdev->be_watching = 1;
+- spin_unlock(&pdev->dev_lock);
+
+ /* We need to force a call to our callback here in case
+ * xend already configured us!
--
1.7.4
-From 3d74a539ae07a8f3c061332e426fc07b2310cf05 Mon Sep 17 00:00:00 2001
+From 4c824ee73ed5a83bf289b565b5dc4a99c7999bc5 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 17 Feb 2011 16:12:51 -0500
-Subject: [PATCH 240/244] pci/xen: When free-ing MSI-X/MSI irq->desc also use generic
code.
+Date: Thu, 24 Feb 2011 14:40:39 -0500
+Subject: [PATCH 197/203] xen/pciback: Fix checkpatch warnings and errors.
-This code path is only run when an MSI/MSI-X PCI device is passed
-in to PV DomU.
+Checkpatch found some extra warnings and errors. This mega
+patch fixes all of them in one swoop.
-In 2.6.37 time-frame we over-wrote the default cleanup handler for
-MSI/MSI-X irq->desc to be "xen_teardown_msi_irqs". That function
-calls the the xen-pcifront driver which can tell the backend to
-cleanup/take back the MSI/MSI-X device.
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-However, we forgot to continue the process of free-ing the MSI/MSI-X
-device resources (irq->desc) in the PV domU side. Which is what
-the default cleanup handler: default_teardown_msi_irqs did.
+Conflicts:
-Hence we would leak IRQ descriptors.
+ drivers/xen/events.c
+---
+ drivers/xen/pciback/conf_space.c | 4 +-
+ drivers/xen/pciback/conf_space_capability_msi.c | 11 +++---
+ drivers/xen/pciback/conf_space_header.c | 42 +++++++++++-----------
+ drivers/xen/pciback/controller.c | 2 +-
+ drivers/xen/pciback/pci_stub.c | 7 ++--
+ drivers/xen/pciback/pciback.h | 16 ++++----
+ drivers/xen/pciback/pciback_ops.c | 9 ++---
+ drivers/xen/pciback/xenbus.c | 14 ++++----
+ 8 files changed, 53 insertions(+), 52 deletions(-)
-Without this patch, doing "rmmod igbvf;modprobe igbvf" multiple
-times ends with abandoned IRQ descriptors:
+diff --git a/drivers/xen/pciback/conf_space.c b/drivers/xen/pciback/conf_space.c
+index 370c18e..eb6bba0 100644
+--- a/drivers/xen/pciback/conf_space.c
++++ b/drivers/xen/pciback/conf_space.c
+@@ -18,8 +18,8 @@
+ static int permissive;
+ module_param(permissive, bool, 0644);
+
+-#define DEFINE_PCI_CONFIG(op, size, type) \
+-int pciback_##op##_config_##size \
++#define DEFINE_PCI_CONFIG(op, size, type) \
++int pciback_##op##_config_##size \
+ (struct pci_dev *dev, int offset, type value, void *data) \
+ { \
+ return pci_##op##_config_##size(dev, offset, value); \
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+index b15131e..3acda69 100644
+--- a/drivers/xen/pciback/conf_space_capability_msi.c
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -16,7 +16,7 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ int otherend = pdev->xdev->otherend_id;
+ int status;
+
+- if (unlikely(verbose_request))
++ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: enable MSI\n", pci_name(dev));
+
+ status = pci_enable_msi(dev);
+@@ -43,7 +43,7 @@ int pciback_disable_msi(struct pciback_device *pdev,
+ {
+ struct pciback_dev_data *dev_data;
+
+- if (unlikely(verbose_request))
++ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: disable MSI\n", pci_name(dev));
+ pci_disable_msi(dev);
+
+@@ -61,7 +61,7 @@ int pciback_enable_msix(struct pciback_device *pdev,
+ int i, result;
+ struct msix_entry *entries;
+
+- if (unlikely(verbose_request))
++ if (unlikely(verbose_request))
+ printk(KERN_DEBUG "pciback: %s: enable MSI-X\n", pci_name(dev));
+ if (op->value > SH_INFO_MAX_VEC)
+ return -EINVAL;
+@@ -97,8 +97,9 @@ int pciback_disable_msix(struct pciback_device *pdev,
+ struct pci_dev *dev, struct xen_pci_op *op)
+ {
+ struct pciback_dev_data *dev_data;
+- if (unlikely(verbose_request))
+- printk(KERN_DEBUG "pciback: %s: disable MSI-X\n", pci_name(dev));
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: disable MSI-X\n",
++ pci_name(dev));
+ pci_disable_msix(dev);
+
+ op->value = xen_gsi_from_irq(dev->irq);
+diff --git a/drivers/xen/pciback/conf_space_header.c
b/drivers/xen/pciback/conf_space_header.c
+index cb450f4..22ad0f5 100644
+--- a/drivers/xen/pciback/conf_space_header.c
++++ b/drivers/xen/pciback/conf_space_header.c
+@@ -316,27 +316,27 @@ static const struct config_field header_common[] = {
+ {}
+ };
+
+-#define CFG_FIELD_BAR(reg_offset) \
+- { \
+- .offset = reg_offset, \
+- .size = 4, \
+- .init = bar_init, \
+- .reset = bar_reset, \
+- .release = bar_release, \
+- .u.dw.read = bar_read, \
+- .u.dw.write = bar_write, \
+- }
+-
+-#define CFG_FIELD_ROM(reg_offset) \
+- { \
+- .offset = reg_offset, \
+- .size = 4, \
+- .init = rom_init, \
+- .reset = bar_reset, \
+- .release = bar_release, \
+- .u.dw.read = bar_read, \
+- .u.dw.write = rom_write, \
+- }
++#define CFG_FIELD_BAR(reg_offset) \
++ { \
++ .offset = reg_offset, \
++ .size = 4, \
++ .init = bar_init, \
++ .reset = bar_reset, \
++ .release = bar_release, \
++ .u.dw.read = bar_read, \
++ .u.dw.write = bar_write, \
++ }
++
++#define CFG_FIELD_ROM(reg_offset) \
++ { \
++ .offset = reg_offset, \
++ .size = 4, \
++ .init = rom_init, \
++ .reset = bar_reset, \
++ .release = bar_release, \
++ .u.dw.read = bar_read, \
++ .u.dw.write = rom_write, \
++ }
+
+ static const struct config_field header_0[] = {
+ CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
+diff --git a/drivers/xen/pciback/controller.c b/drivers/xen/pciback/controller.c
+index 7f04f11..5a7e4cc 100644
+--- a/drivers/xen/pciback/controller.c
++++ b/drivers/xen/pciback/controller.c
+@@ -378,7 +378,7 @@ int pciback_publish_pci_roots(struct pciback_device *pdev,
+ }
+
+ err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
+- "%lx", (sizeof(struct acpi_resource) * 2) + 1);
++ "%lx", (sizeof(struct acpi_resource) *2) + 1);
+
+ out:
+ spin_unlock(&dev_data->lock);
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index 88c7ca1..c8f6f29 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -13,7 +13,7 @@
+ #include <linux/pci.h>
+ #include <linux/wait.h>
+ #include <linux/sched.h>
+-#include <asm/atomic.h>
++#include <linux/atomic.h>
+ #include <xen/events.h>
+ #include <asm/xen/pci.h>
+ #include <asm/xen/hypervisor.h>
+@@ -603,7 +603,7 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev,
+ if (test_bit(_XEN_PCIF_active,
+ (unsigned long *)&psdev->pdev->sh_info->flags)) {
+ dev_dbg(&psdev->dev->dev,
+- "schedule pci_conf service in pciback \n");
++ "schedule pci_conf service in pciback\n");
+ test_and_schedule_op(psdev->pdev);
+ }
+
+@@ -1055,7 +1055,8 @@ static ssize_t pcistub_irq_handler_show(struct device_driver *drv,
char *buf)
+ if (!dev_data)
+ continue;
+ count +=
+- scnprintf(buf + count, PAGE_SIZE - count, "%s:%s:%sing:%ld\n",
++ scnprintf(buf + count, PAGE_SIZE - count,
++ "%s:%s:%sing:%ld\n",
+ pci_name(psdev->dev),
+ dev_data->isr_on ? "on" : "off",
+ dev_data->ack_intr ? "ack" : "not ack",
+diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h
+index fc31052..5c14020 100644
+--- a/drivers/xen/pciback/pciback.h
++++ b/drivers/xen/pciback/pciback.h
+@@ -12,7 +12,7 @@
+ #include <linux/list.h>
+ #include <linux/spinlock.h>
+ #include <linux/workqueue.h>
+-#include <asm/atomic.h>
++#include <linux/atomic.h>
+ #include <xen/interface/io/pciif.h>
+
+ struct pci_dev_entry {
+@@ -20,8 +20,8 @@ struct pci_dev_entry {
+ struct pci_dev *dev;
+ };
+
+-#define _PDEVF_op_active (0)
+-#define PDEVF_op_active (1<<(_PDEVF_op_active))
++#define _PDEVF_op_active (0)
++#define PDEVF_op_active (1<<(_PDEVF_op_active))
+ #define _PCIB_op_pending (1)
+ #define PCIB_op_pending (1<<(_PCIB_op_pending))
+
+@@ -45,11 +45,11 @@ struct pciback_device {
+
+ struct pciback_dev_data {
+ struct list_head config_fields;
+- unsigned int permissive : 1;
+- unsigned int warned_on_write : 1;
+- unsigned int enable_intx : 1;
+- unsigned int isr_on : 1; /* Whether the IRQ handler is installed. */
+- unsigned int ack_intr : 1; /* .. and ACK-ing */
++ unsigned int permissive:1;
++ unsigned int warned_on_write:1;
++ unsigned int enable_intx:1;
++ unsigned int isr_on:1; /* Whether the IRQ handler is installed. */
++ unsigned int ack_intr:1; /* .. and ACK-ing */
+ unsigned long handled;
+ unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
+ char irq_name[0]; /* pciback[000:04:00.0] */
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 2c5a90d..6c398fd 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -63,12 +63,11 @@ void pciback_control_isr(struct pci_dev *dev, int reset)
+ dev_data->irq_name, dev);
+ if (rc) {
+ dev_err(&dev->dev, "%s: failed to install fake IRQ " \
+- "handler for IRQ %d! (rc:%d)\n", dev_data->irq_name,
+- dev_data->irq, rc);
++ "handler for IRQ %d! (rc:%d)\n",
++ dev_data->irq_name, dev_data->irq, rc);
+ goto out;
+ }
+- }
+- else {
++ } else {
+ free_irq(dev_data->irq, dev);
+ dev_data->irq = 0;
+ }
+@@ -188,7 +187,7 @@ void pciback_do_op(struct work_struct *data)
+ break;
+ #endif
+ default:
+- op->err = XEN_PCI_ERR_not_implemented;
++ op->err = XEN_PCI_ERR_not_implemented;
+ break;
+ }
+ }
+diff --git a/drivers/xen/pciback/xenbus.c b/drivers/xen/pciback/xenbus.c
+index 993b659..70030c4 100644
+--- a/drivers/xen/pciback/xenbus.c
++++ b/drivers/xen/pciback/xenbus.c
+@@ -700,12 +700,12 @@ static const struct xenbus_device_id xenpci_ids[] = {
+ };
+
+ static struct xenbus_driver xenbus_pciback_driver = {
+- .name = "pciback",
+- .owner = THIS_MODULE,
+- .ids = xenpci_ids,
+- .probe = pciback_xenbus_probe,
+- .remove = pciback_xenbus_remove,
+- .otherend_changed = pciback_frontend_changed,
++ .name = "pciback",
++ .owner = THIS_MODULE,
++ .ids = xenpci_ids,
++ .probe = pciback_xenbus_probe,
++ .remove = pciback_xenbus_remove,
++ .otherend_changed = pciback_frontend_changed,
+ };
+
+ int __init pciback_xenbus_register(void)
+@@ -713,7 +713,7 @@ int __init pciback_xenbus_register(void)
+ pciback_wq = create_workqueue("pciback_workqueue");
+ if (!pciback_wq) {
+ printk(KERN_ERR "%s: create"
+- "pciback_workqueue failed\n",__FUNCTION__);
++ "pciback_workqueue failed\n", __func__);
+ return -EFAULT;
+ }
+ return xenbus_register_backend(&xenbus_pciback_driver);
+--
+1.7.4
- 28: 5 xen-pirq-pcifront-msi-x
- 29: 8 xen-pirq-pcifront-msi-x
-...
-130: 10 xen-pirq-pcifront-msi-x
-with the end result of running out of IRQ descriptors.
+From 32bc28c28fa60442d2d1fff6be11344a22db95a3 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Mon, 13 Dec 2010 11:30:29 -0500
+Subject: [PATCH 198/203] xen/xen-pciback: Swap over to DEFINE_PCI_DEVICE_TABLE
-Reviewed-by: Ian Campbell <Ian.Campbell(a)citrix.com>
+[v2: Jan Beulich recommendation to not drop 'static']
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- arch/x86/pci/xen.c | 3 +++
- 1 files changed, 3 insertions(+), 0 deletions(-)
+ drivers/xen/pciback/pci_stub.c | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
-diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
-index 30fdd09..57afd1d 100644
---- a/arch/x86/pci/xen.c
-+++ b/arch/x86/pci/xen.c
-@@ -193,6 +193,9 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
- xen_pci_frontend_disable_msix(dev);
- else
- xen_pci_frontend_disable_msi(dev);
-+
-+ /* Free the IRQ's and the msidesc using the generic code. */
-+ default_teardown_msi_irqs(dev);
+diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c
+index c8f6f29..c4d1071 100644
+--- a/drivers/xen/pciback/pci_stub.c
++++ b/drivers/xen/pciback/pci_stub.c
+@@ -497,7 +497,7 @@ static void pcistub_remove(struct pci_dev *dev)
+ }
}
- static void xen_teardown_msi_irq(unsigned int irq)
+-static const struct pci_device_id pcistub_ids[] = {
++static DEFINE_PCI_DEVICE_TABLE(pcistub_ids) = {
+ {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
--
1.7.4
-From c39d35161e87f1d7c0628af6907ac66a8c77f63f Mon Sep 17 00:00:00 2001
+From 81436578eb9dad88e83f88412f3aed916e8bb89e Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 2 Dec 2010 11:04:29 -0500
-Subject: [PATCH 241/244] radeon/ttm/PCIe: Use dma_addr if TTM has set it.
-
-If the TTM layer has used the DMA API to setup pages that are
-TTM_PAGE_FLAG_DMA32 (look at patch titled: "ttm: Utilize the dma_addr_t
-array for pages that are to in DMA32 pool."), lets use it
-when programming the GART in the PCIe type cards.
+Date: Wed, 16 Feb 2011 13:44:38 -0500
+Subject: [PATCH 199/203] xen/pciback: Utilize 'xen_pirq_from_irq' to get PIRQ
value.
-This patch skips doing the pci_map_page (and pci_unmap_page) if
-there is a DMA addresses passed in for that page. If the dma_address
-is zero (or DMA_ERROR_CODE), then we continue on with our old
-behaviour.
+In the past the Xen IRQ code had overloaded the irq->gsi with
+ton of uses. The 'gsi' would be a real GSI, an vector value, or
+a Xen PIRQ value. We were quite dilligient in having the correct
+value there for the guest, but with the IRQ rework code this
+overloading is gone. As so, use the correct function to retrieve
+the PIRQ value.
-[v2: Fixed an indentation problem, added reviewed-by tag]
-[v3: Added Acked-by Jerome]
+Handling of invalid values is fixed in the front-end with patch:
+"xen-pcifront: Sanity check the MSI/MSI-X values"
-Acked-by: Jerome Glisse <j.glisse(a)gmail.com>
-Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/gpu/drm/radeon/radeon.h | 4 ++-
- drivers/gpu/drm/radeon/radeon_gart.c | 36 ++++++++++++++++++++++++---------
- drivers/gpu/drm/radeon/radeon_ttm.c | 5 +++-
- 3 files changed, 33 insertions(+), 12 deletions(-)
+ drivers/xen/pciback/conf_space_capability_msi.c | 26 +++++++++++++++-------
+ 1 files changed, 18 insertions(+), 8 deletions(-)
-diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
-index 73f600d..c9bbab9 100644
---- a/drivers/gpu/drm/radeon/radeon.h
-+++ b/drivers/gpu/drm/radeon/radeon.h
-@@ -317,6 +317,7 @@ struct radeon_gart {
- union radeon_gart_table table;
- struct page **pages;
- dma_addr_t *pages_addr;
-+ bool *ttm_alloced;
- bool ready;
- };
-
-@@ -329,7 +330,8 @@ void radeon_gart_fini(struct radeon_device *rdev);
- void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
- int pages);
- int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
-- int pages, struct page **pagelist);
-+ int pages, struct page **pagelist,
-+ dma_addr_t *dma_addr);
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+index 3acda69..c9b0aba 100644
+--- a/drivers/xen/pciback/conf_space_capability_msi.c
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -30,7 +30,8 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ /* The value the guest needs is actually the IDT vector, not the
+ * the local domain's IRQ number. */
+- op->value = xen_gsi_from_irq(dev->irq);
++
++ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 0;
+@@ -47,7 +48,7 @@ int pciback_disable_msi(struct pciback_device *pdev,
+ printk(KERN_DEBUG "pciback: %s: disable MSI\n", pci_name(dev));
+ pci_disable_msi(dev);
- /*
-diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
-index e65b903..5214bc2 100644
---- a/drivers/gpu/drm/radeon/radeon_gart.c
-+++ b/drivers/gpu/drm/radeon/radeon_gart.c
-@@ -149,8 +149,9 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
- p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
- for (i = 0; i < pages; i++, p++) {
- if (rdev->gart.pages[p]) {
-- pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
-- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-+ if (!rdev->gart.ttm_alloced[p])
-+ pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
-+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- rdev->gart.pages[p] = NULL;
- rdev->gart.pages_addr[p] = rdev->dummy_page.addr;
- page_base = rdev->gart.pages_addr[p];
-@@ -165,7 +166,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
- }
+- op->value = xen_gsi_from_irq(dev->irq);
++ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 1;
+@@ -77,12 +78,17 @@ int pciback_enable_msix(struct pciback_device *pdev,
- int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
-- int pages, struct page **pagelist)
-+ int pages, struct page **pagelist, dma_addr_t *dma_addr)
- {
- unsigned t;
- unsigned p;
-@@ -180,15 +181,22 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
- p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
+ result = pci_enable_msix(dev, entries, op->value);
- for (i = 0; i < pages; i++, p++) {
-- /* we need to support large memory configurations */
-- /* assume that unbind have already been call on the range */
-- rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i],
-+ /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32
-+ * is requested. */
-+ if (dma_addr[i] != DMA_ERROR_CODE) {
-+ rdev->gart.ttm_alloced[p] = true;
-+ rdev->gart.pages_addr[p] = dma_addr[i];
-+ } else {
-+ /* we need to support large memory configurations */
-+ /* assume that unbind have already been call on the range */
-+ rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i],
- 0, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
-- if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) {
-- /* FIXME: failed to map page (return -ENOMEM?) */
-- radeon_gart_unbind(rdev, offset, pages);
-- return -ENOMEM;
-+ if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) {
-+ /* FIXME: failed to map page (return -ENOMEM?) */
-+ radeon_gart_unbind(rdev, offset, pages);
-+ return -ENOMEM;
-+ }
- }
- rdev->gart.pages[p] = pagelist[i];
- page_base = rdev->gart.pages_addr[p];
-@@ -251,6 +259,12 @@ int radeon_gart_init(struct radeon_device *rdev)
- radeon_gart_fini(rdev);
- return -ENOMEM;
- }
-+ rdev->gart.ttm_alloced = kzalloc(sizeof(bool) *
-+ rdev->gart.num_cpu_pages, GFP_KERNEL);
-+ if (rdev->gart.ttm_alloced == NULL) {
-+ radeon_gart_fini(rdev);
-+ return -ENOMEM;
-+ }
- /* set GART entry to point to the dummy page by default */
- for (i = 0; i < rdev->gart.num_cpu_pages; i++) {
- rdev->gart.pages_addr[i] = rdev->dummy_page.addr;
-@@ -267,6 +281,8 @@ void radeon_gart_fini(struct radeon_device *rdev)
- rdev->gart.ready = false;
- kfree(rdev->gart.pages);
- kfree(rdev->gart.pages_addr);
-+ kfree(rdev->gart.ttm_alloced);
- rdev->gart.pages = NULL;
- rdev->gart.pages_addr = NULL;
-+ rdev->gart.ttm_alloced = NULL;
- }
-diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
-index 6f156e9..ca04505 100644
---- a/drivers/gpu/drm/radeon/radeon_ttm.c
-+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
-@@ -647,6 +647,7 @@ struct radeon_ttm_backend {
- unsigned long num_pages;
- struct page **pages;
- struct page *dummy_read_page;
-+ dma_addr_t *dma_addrs;
- bool populated;
- bool bound;
- unsigned offset;
-@@ -662,6 +663,7 @@ static int radeon_ttm_backend_populate(struct ttm_backend *backend,
+- for (i = 0; i < op->value; i++) {
+- op->msix_entries[i].entry = entries[i].entry;
+- op->msix_entries[i].vector =
+- xen_gsi_from_irq(entries[i].vector);
++ if (result == 0) {
++ for (i = 0; i < op->value; i++) {
++ op->msix_entries[i].entry = entries[i].entry;
++ if (entries[i].vector)
++ op->msix_entries[i].vector =
++ xen_pirq_from_irq(entries[i].vector);
++ }
++ } else {
++ printk(KERN_WARNING "pciback: %s: failed to enable MSI-X: err %d!\n",
++ pci_name(dev), result);
+ }
+-
+ kfree(entries);
- gtt = container_of(backend, struct radeon_ttm_backend, backend);
- gtt->pages = pages;
-+ gtt->dma_addrs = dma_addrs;
- gtt->num_pages = num_pages;
- gtt->dummy_read_page = dummy_read_page;
- gtt->populated = true;
-@@ -674,6 +676,7 @@ static void radeon_ttm_backend_clear(struct ttm_backend *backend)
+ op->value = result;
+@@ -102,7 +108,11 @@ int pciback_disable_msix(struct pciback_device *pdev,
+ pci_name(dev));
+ pci_disable_msix(dev);
- gtt = container_of(backend, struct radeon_ttm_backend, backend);
- gtt->pages = NULL;
-+ gtt->dma_addrs = NULL;
- gtt->num_pages = 0;
- gtt->dummy_read_page = NULL;
- gtt->populated = false;
-@@ -694,7 +697,7 @@ static int radeon_ttm_backend_bind(struct ttm_backend *backend,
- gtt->num_pages, bo_mem, backend);
- }
- r = radeon_gart_bind(gtt->rdev, gtt->offset,
-- gtt->num_pages, gtt->pages);
-+ gtt->num_pages, gtt->pages, gtt->dma_addrs);
- if (r) {
- DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
- gtt->num_pages, gtt->offset);
+- op->value = xen_gsi_from_irq(dev->irq);
++ /*
++ * SR-IOV devices (which don't have any legacy IRQ) have
++ * an undefined IRQ value of zero.
++ */
++ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 1;
--
1.7.4
-From e0138c26cdeee8c033256ccd9e07d66db3c998be Mon Sep 17 00:00:00 2001
+From 2e7c6959832ac7aa7551a18ee919ce522444bac1 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Thu, 2 Dec 2010 11:36:24 -0500
-Subject: [PATCH 242/244] nouveau/ttm/PCIe: Use dma_addr if TTM has set it.
+Date: Wed, 16 Feb 2011 15:43:25 -0500
+Subject: [PATCH 200/203] xen/pciback: Don't setup an fake IRQ handler for SR-IOV
devices.
-If the TTM layer has used the DMA API to setup pages that are
-TTM_PAGE_FLAG_DMA32 (look at patch titled: "ttm: Utilize the
-DMA API for pages that have TTM_PAGE_FLAG_DMA32 set"), lets
-use it when programming the GART in the PCIe type cards.
+If we try to setup an fake IRQ handler for legacy interrupts
+for devices that only have MSI-X (most if not all SR-IOV cards),
+we will fail with this:
-This patch skips doing the pci_map_page (and pci_unmap_page) if
-there is a DMA addresses passed in for that page. If the dma_address
-is zero (or DMA_ERROR_CODE), then we continue on with our old
-behaviour.
+pciback[0000:01:10.0]: failed to install fake IRQ handler for IRQ 0! (rc:-38)
-[v2: Added a review-by tag]
+Since those cards don't have anything in dev->irq.
-Reviewed-by: Thomas Hellstrom <thomas(a)shipmail.org>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Tested-by: Ian Campbell <ian.campbell(a)citrix.com>
---
- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 28 +++++++++++++++++++++-------
- 1 files changed, 21 insertions(+), 7 deletions(-)
+ drivers/xen/pciback/pciback_ops.c | 7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
-diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-index edc140a..bbdd982 100644
---- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
-@@ -12,6 +12,7 @@ struct nouveau_sgdma_be {
- struct drm_device *dev;
-
- dma_addr_t *pages;
-+ bool *ttm_alloced;
- unsigned nr_pages;
-
- unsigned pte_start;
-@@ -35,15 +36,25 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long
num_pages,
- if (!nvbe->pages)
- return -ENOMEM;
+diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c
+index 6c398fd..28a2a55 100644
+--- a/drivers/xen/pciback/pciback_ops.c
++++ b/drivers/xen/pciback/pciback_ops.c
+@@ -48,6 +48,13 @@ void pciback_control_isr(struct pci_dev *dev, int reset)
+ if (enable)
+ dev_data->irq = dev->irq;
-+ nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
-+ if (!nvbe->ttm_alloced)
-+ return -ENOMEM;
++ /*
++ * SR-IOV devices in all use MSI-X and have no legacy
++ * interrupts, so inhibit creating a fake IRQ handler for them.
++ */
++ if (dev_data->irq == 0)
++ goto out;
+
- nvbe->nr_pages = 0;
- while (num_pages--) {
-- nvbe->pages[nvbe->nr_pages] =
-- pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0,
-+ if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) {
-+ nvbe->pages[nvbe->nr_pages] =
-+ dma_addrs[nvbe->nr_pages];
-+ nvbe->ttm_alloced[nvbe->nr_pages] = true;
-+ } else {
-+ nvbe->pages[nvbe->nr_pages] =
-+ pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0,
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-- if (pci_dma_mapping_error(dev->pdev,
-- nvbe->pages[nvbe->nr_pages])) {
-- be->func->clear(be);
-- return -EFAULT;
-+ if (pci_dma_mapping_error(dev->pdev,
-+ nvbe->pages[nvbe->nr_pages])) {
-+ be->func->clear(be);
-+ return -EFAULT;
-+ }
- }
-
- nvbe->nr_pages++;
-@@ -66,11 +77,14 @@ nouveau_sgdma_clear(struct ttm_backend *be)
- be->func->unbind(be);
-
- while (nvbe->nr_pages--) {
-- pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
-+ if (!nvbe->ttm_alloced[nvbe->nr_pages])
-+ pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages],
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- }
- kfree(nvbe->pages);
-+ kfree(nvbe->ttm_alloced);
- nvbe->pages = NULL;
-+ nvbe->ttm_alloced = NULL;
- nvbe->nr_pages = 0;
- }
- }
+ dev_dbg(&dev->dev, "%s: #%d %s %s%s %s-> %s\n",
+ dev_data->irq_name,
+ dev_data->irq,
--
1.7.4
-From 2f14ddc3a7146ea4cd5a3d1ecd993f85f2e4f948 Mon Sep 17 00:00:00 2001
-From: Zhang, Fengzhe <fengzhe.zhang(a)intel.com>
-Date: Wed, 16 Feb 2011 22:26:20 +0800
-Subject: [PATCH 243/244] xen/setup: Inhibit resource API from using System RAM E820 gaps
as PCI mem gaps.
-
-With the hypervisor argument of dom0_mem=X we iterate over the physical
-(only for the initial domain) E820 and subtract the the size from each
-E820_RAM region the delta so that the cumulative size of all E820_RAM regions
-is equal to 'X'. This sometimes ends up with E820_RAM regions with zero size
-(which are removed by e820_sanitize) and E820_RAM that are smaller
-than physically.
-
-Later on the PCI API looks at the E820 and attempts to set up an
-resource region for the "PCI mem". The E820 (assume dom0_mem=1GB is
-set) compared to the physical looks as so:
-
- [ 0.000000] BIOS-provided physical RAM map:
- [ 0.000000] Xen: 0000000000000000 - 0000000000097c00 (usable)
- [ 0.000000] Xen: 0000000000097c00 - 0000000000100000 (reserved)
--[ 0.000000] Xen: 0000000000100000 - 00000000defafe00 (usable)
-+[ 0.000000] Xen: 0000000000100000 - 0000000040000000 (usable)
- [ 0.000000] Xen: 00000000defafe00 - 00000000defb1ea0 (ACPI NVS)
- [ 0.000000] Xen: 00000000defb1ea0 - 00000000e0000000 (reserved)
- [ 0.000000] Xen: 00000000f4000000 - 00000000f8000000 (reserved)
-..
-And we get
-[ 0.000000] Allocating PCI resources starting at 40000000 (gap: 40000000:9efafe00)
-
-while it should have started at e0000000 (a nice big gap up to
-f4000000 exists). The "Allocating PCI" is part of the resource API.
-
-The users that end up using those PCI I/O regions usually supply their
-own BARs when calling the resource API (request_resource, or allocate_resource),
-but there are exceptions which provide an empty 'struct resource' and
-expect the API to provide the 'struct resource' to be populated with valid
values.
-The one that triggered this bug was the intel AGP driver that requested
-a region for the flush page (intel_i9xx_setup_flush).
-
-Before this patch, when running under Xen hypervisor, the 'struct resource'
-returned could have (depending on the dom0_mem size) physical ranges of a 'System
RAM'
-instead of 'I/O' regions. This ended up with the Hypervisor failing a request
-to populate PTE's with those PFNs as the domain did not have access to those
-'System RAM' regions (rightly so).
-
-After this patch, the left-over E820_RAM region from the truncation, will be
-labeled as E820_UNUSABLE. The E820 will look as so:
-
- [ 0.000000] BIOS-provided physical RAM map:
- [ 0.000000] Xen: 0000000000000000 - 0000000000097c00 (usable)
- [ 0.000000] Xen: 0000000000097c00 - 0000000000100000 (reserved)
--[ 0.000000] Xen: 0000000000100000 - 00000000defafe00 (usable)
-+[ 0.000000] Xen: 0000000000100000 - 0000000040000000 (usable)
-+[ 0.000000] Xen: 0000000040000000 - 00000000defafe00 (unusable)
- [ 0.000000] Xen: 00000000defafe00 - 00000000defb1ea0 (ACPI NVS)
- [ 0.000000] Xen: 00000000defb1ea0 - 00000000e0000000 (reserved)
- [ 0.000000] Xen: 00000000f4000000 - 00000000f8000000 (reserved)
-
-For more information:
-http://mid.gmane.org/1A42CE6F5F474C41B63392A5F80372B2335E978C@shsmsx501.ccr.corp.intel.com
+From e0c91c10d4a258c83e1cc593d53338099a49a5c6 Mon Sep 17 00:00:00 2001
+From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Date: Thu, 17 Feb 2011 11:18:00 -0500
+Subject: [PATCH 201/203] xen/pciback: Print out the MSI/MSI-X (PIRQ) values when
allocating
-BugLink:
http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1726
+If the verbose_request is set (and loglevel high enought), print out
+the MSI/MSI-X values sent to the guest. This should aid in debugging
+issues.
-Signed-off-by: Fengzhe Zhang <fengzhe.zhang(a)intel.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
---
- arch/x86/xen/setup.c | 8 ++++++++
- 1 files changed, 8 insertions(+), 0 deletions(-)
+ drivers/xen/pciback/conf_space_capability_msi.c | 15 +++++++++++++++
+ 1 files changed, 15 insertions(+), 0 deletions(-)
-diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
-index a8a66a5..2a4add9 100644
---- a/arch/x86/xen/setup.c
-+++ b/arch/x86/xen/setup.c
-@@ -194,6 +194,14 @@ char * __init xen_memory_setup(void)
- end -= delta;
+diff --git a/drivers/xen/pciback/conf_space_capability_msi.c
b/drivers/xen/pciback/conf_space_capability_msi.c
+index c9b0aba..041e4aa 100644
+--- a/drivers/xen/pciback/conf_space_capability_msi.c
++++ b/drivers/xen/pciback/conf_space_capability_msi.c
+@@ -32,6 +32,10 @@ int pciback_enable_msi(struct pciback_device *pdev,
+ * the local domain's IRQ number. */
- extra_pages += PFN_DOWN(delta);
-+ /*
-+ * Set RAM below 4GB that is not for us to be unusable.
-+ * This prevents "System RAM" address space from being
-+ * used as potential resource for I/O address (happens
-+ * when 'allocate_resource' is called).
-+ */
-+ if (delta && end < 0x100000000UL)
-+ e820_add_region(end, delta, E820_UNUSABLE);
- }
+ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: MSI: %d\n", pci_name(dev),
++ op->value);
++
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 0;
+@@ -49,6 +53,9 @@ int pciback_disable_msi(struct pciback_device *pdev,
+ pci_disable_msi(dev);
- if (map[i].size > 0 && end > xen_extra_mem_start)
+ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: MSI: %d\n", pci_name(dev),
++ op->value);
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 1;
+@@ -84,6 +91,11 @@ int pciback_enable_msix(struct pciback_device *pdev,
+ if (entries[i].vector)
+ op->msix_entries[i].vector =
+ xen_pirq_from_irq(entries[i].vector);
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: " \
++ "MSI-X[%d]: %d\n",
++ pci_name(dev), i,
++ op->msix_entries[i].vector);
+ }
+ } else {
+ printk(KERN_WARNING "pciback: %s: failed to enable MSI-X: err %d!\n",
+@@ -113,6 +125,9 @@ int pciback_disable_msix(struct pciback_device *pdev,
+ * an undefined IRQ value of zero.
+ */
+ op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
++ if (unlikely(verbose_request))
++ printk(KERN_DEBUG "pciback: %s: MSI-X: %d\n", pci_name(dev),
++ op->value);
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 1;
--
1.7.4
-From 5a893fc28f0393adb7c885a871b8c59e623fd528 Mon Sep 17 00:00:00 2001
+From eca446355aca91790d71a53a23ff10533b895f02 Mon Sep 17 00:00:00 2001
From: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
-Date: Tue, 22 Feb 2011 13:24:32 -0500
-Subject: [PATCH 244/244] ttm: Include the 'struct dev' when using the DMA API.
+Date: Thu, 24 Feb 2011 14:34:31 -0500
+Subject: [PATCH 202/203] xen-pciback: Enable Xen-PCI-back to be compiled.
-This makes the accounting when using 'debug_dma_dump_mappings()'
-and CONFIG_DMA_API_DEBUG=y be assigned to the correct device
-instead of 'fallback'.
+Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge(a)citrix.com>
-No functional change - just cosmetic.
+Conflicts:
-Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk(a)oracle.com>
+ drivers/xen/Kconfig
+ drivers/xen/Makefile
---
- drivers/gpu/drm/nouveau/nouveau_mem.c | 1 +
- drivers/gpu/drm/radeon/radeon_ttm.c | 1 +
- drivers/gpu/drm/ttm/ttm_page_alloc.c | 11 ++++++-----
- drivers/gpu/drm/ttm/ttm_tt.c | 4 ++--
- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +-
- include/drm/ttm/ttm_bo_driver.h | 1 +
- include/drm/ttm/ttm_page_alloc.h | 8 ++++++--
- 7 files changed, 18 insertions(+), 10 deletions(-)
+ drivers/xen/Kconfig | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/xen/Makefile | 1 +
+ 2 files changed, 66 insertions(+), 0 deletions(-)
-diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c
b/drivers/gpu/drm/nouveau/nouveau_mem.c
-index a163c7c..931b221 100644
---- a/drivers/gpu/drm/nouveau/nouveau_mem.c
-+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
-@@ -559,6 +559,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
- if (ret)
- return ret;
-
-+ dev_priv->ttm.bdev.dev = dev->dev;
- ret = ttm_bo_device_init(&dev_priv->ttm.bdev,
- dev_priv->ttm.bo_global_ref.ref.object,
- &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
-diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
-index ca04505..cfe223f 100644
---- a/drivers/gpu/drm/radeon/radeon_ttm.c
-+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
-@@ -513,6 +513,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
- if (r) {
- return r;
- }
-+ rdev->mman.bdev.dev = rdev->dev;
- /* No others user of address space so set it to 0 */
- r = ttm_bo_device_init(&rdev->mman.bdev,
- rdev->mman.bo_global_ref.ref.object,
-diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
-index 737a2a2..35849db 100644
---- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
-+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
-@@ -664,7 +664,7 @@ out:
- */
- int ttm_get_pages(struct list_head *pages, int flags,
- enum ttm_caching_state cstate, unsigned count,
-- dma_addr_t *dma_address)
-+ dma_addr_t *dma_address, struct device *dev)
- {
- struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
- struct page *p = NULL;
-@@ -685,7 +685,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
- for (r = 0; r < count; ++r) {
- if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) {
- void *addr;
-- addr = dma_alloc_coherent(NULL, PAGE_SIZE,
-+ addr = dma_alloc_coherent(dev, PAGE_SIZE,
- &dma_address[r],
- gfp_flags);
- if (addr == NULL)
-@@ -730,7 +730,7 @@ int ttm_get_pages(struct list_head *pages, int flags,
- printk(KERN_ERR TTM_PFX
- "Failed to allocate extra pages "
- "for large request.");
-- ttm_put_pages(pages, 0, flags, cstate, NULL);
-+ ttm_put_pages(pages, 0, flags, cstate, NULL, NULL);
- return r;
- }
- }
-@@ -741,7 +741,8 @@ int ttm_get_pages(struct list_head *pages, int flags,
-
- /* Put all pages in pages list to correct pool to wait for reuse */
- void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags,
-- enum ttm_caching_state cstate, dma_addr_t *dma_address)
-+ enum ttm_caching_state cstate, dma_addr_t *dma_address,
-+ struct device *dev)
- {
- unsigned long irq_flags;
- struct ttm_page_pool *pool = ttm_get_pool(flags, cstate);
-@@ -757,7 +758,7 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int
flags,
- void *addr = page_address(p);
- WARN_ON(!addr || !dma_address[r]);
- if (addr)
-- dma_free_coherent(NULL, PAGE_SIZE,
-+ dma_free_coherent(dev, PAGE_SIZE,
- addr,
- dma_address[r]);
- dma_address[r] = 0;
-diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
-index 86d5b17..0f8fc9f 100644
---- a/drivers/gpu/drm/ttm/ttm_tt.c
-+++ b/drivers/gpu/drm/ttm/ttm_tt.c
-@@ -110,7 +110,7 @@ static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index)
- INIT_LIST_HEAD(&h);
-
- ret = ttm_get_pages(&h, ttm->page_flags, ttm->caching_state, 1,
-- &ttm->dma_address[index]);
-+ &ttm->dma_address[index], ttm->be->bdev->dev);
-
- if (ret != 0)
- return NULL;
-@@ -304,7 +304,7 @@ static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm)
- }
- }
- ttm_put_pages(&h, count, ttm->page_flags, ttm->caching_state,
-- ttm->dma_address);
-+ ttm->dma_address, ttm->be->bdev->dev);
- ttm->state = tt_unpopulated;
- ttm->first_himem_page = ttm->num_pages;
- ttm->last_lomem_page = -1;
-diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
-index 10ca97e..4a8c789 100644
---- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
-+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
-@@ -322,7 +322,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long
chipset)
- ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
- dev_priv->active_master = &dev_priv->fbdev_master;
+diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
+index 07bec09..ff57e97 100644
+--- a/drivers/xen/Kconfig
++++ b/drivers/xen/Kconfig
+@@ -37,6 +37,71 @@ config XEN_BACKEND
+ Support for backend device drivers that provide I/O services
+ to other virtual machines.
--
-+ dev_priv->bdev.dev = dev->dev;
- ret = ttm_bo_device_init(&dev_priv->bdev,
- dev_priv->bo_global_ref.ref.object,
- &vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET,
-diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
-index ebcd3dd..4d97014 100644
---- a/include/drm/ttm/ttm_bo_driver.h
-+++ b/include/drm/ttm/ttm_bo_driver.h
-@@ -533,6 +533,7 @@ struct ttm_bo_device {
- struct list_head device_list;
- struct ttm_bo_global *glob;
- struct ttm_bo_driver *driver;
-+ struct device *dev;
- rwlock_t vm_lock;
- struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
- /*
-diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h
-index 8062890..ccb6b7a 100644
---- a/include/drm/ttm/ttm_page_alloc.h
-+++ b/include/drm/ttm/ttm_page_alloc.h
-@@ -37,12 +37,14 @@
- * @cstate: ttm caching state for the page.
- * @count: number of pages to allocate.
- * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
-+ * @dev: struct device for appropiate DMA accounting.
- */
- int ttm_get_pages(struct list_head *pages,
- int flags,
- enum ttm_caching_state cstate,
- unsigned count,
-- dma_addr_t *dma_address);
-+ dma_addr_t *dma_address,
-+ struct device *dev);
- /**
- * Put linked list of pages to pool.
- *
-@@ -52,12 +54,14 @@ int ttm_get_pages(struct list_head *pages,
- * @flags: ttm flags for page allocation.
- * @cstate: ttm caching state.
- * @dma_address: The DMA (bus) address of pages (if TTM_PAGE_FLAG_DMA32 set).
-+ * @dev: struct device for appropiate DMA accounting.
- */
- void ttm_put_pages(struct list_head *pages,
- unsigned page_count,
- int flags,
- enum ttm_caching_state cstate,
-- dma_addr_t *dma_address);
-+ dma_addr_t *dma_address,
-+ struct device *dev);
- /**
- * Initialize pool allocator.
- */
++config XEN_PCIDEV_BACKEND
++ tristate "PCI-device backend driver"
++ depends on PCI
++ depends on XEN_BACKEND
++ help
++ The PCI device backend driver allows the kernel to export arbitrary
++ PCI devices to other guests. If you select this to be a module, you
++ will need to make sure no other driver has bound to the device(s)
++ you want to make visible to other guests.
++
++choice
++ prompt "PCI Backend Mode"
++ depends on XEN_PCIDEV_BACKEND
++ default XEN_PCIDEV_BACKEND_VPCI if !IA64
++ default XEN_PCIDEV_BACKEND_CONTROLLER if IA64
++
++config XEN_PCIDEV_BACKEND_VPCI
++ bool "Virtual PCI"
++ ---help---
++ This PCI Backend hides the true PCI topology and makes the frontend
++ think there is a single PCI bus with only the exported devices on it.
++ For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
++ second device at 02:1a.1 will be re-assigned to 00:01.1.
++
++config XEN_PCIDEV_BACKEND_PASS
++ bool "Passthrough"
++ ---help---
++ This PCI Backend provides a real view of the PCI topology to the
++ frontend (for example, a device at 06:01.b will still appear at
++ 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
++ PCI devices to its driver domains. This may be required for drivers
++ which depend on finding their hardward in certain bus/slot
++ locations.
++
++config XEN_PCIDEV_BACKEND_SLOT
++ bool "Slot"
++ ---help---
++ This PCI Backend hides the true PCI topology and makes the frontend
++ think there is a single PCI bus with only the exported devices on it.
++ Contrary to the virtual PCI backend, a function becomes a new slot.
++ For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
++ second device at 02:1a.1 will be re-assigned to 00:01.0.
++
++config XEN_PCIDEV_BACKEND_CONTROLLER
++ bool "Controller"
++ depends on IA64
++ ---help---
++ This PCI backend virtualizes the PCI bus topology by providing a
++ virtual bus per PCI root device. Devices which are physically under
++ the same root bus will appear on the same virtual bus. For systems
++ with complex I/O addressing, this is the only backend which supports
++ extended I/O port spaces and MMIO translation offsets. This backend
++ also supports slot virtualization. For example, a device at
++ 0000:01:02.1 will be re-assigned to 0000:00:00.0. A second device
++ at 0000:02:05.0 (behind a P2P bridge on bus 0000:01) will be
++ re-assigned to 0000:00:01.0. A third device at 0000:16:05.0 (under
++ a different PCI root bus) will be re-assigned to 0000:01:00.0.
++
++endchoice
++
++config XEN_PCIDEV_BE_DEBUG
++ bool "PCI Backend Debugging"
++ depends on XEN_PCIDEV_BACKEND
++
++
+ config XENFS
+ tristate "Xen filesystem"
+ default y
+diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
+index 5088cc2..b8b93c6 100644
+--- a/drivers/xen/Makefile
++++ b/drivers/xen/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
+ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
+ obj-$(CONFIG_XEN_BALLOON) += balloon.o
+ obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o
++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/
+ obj-$(CONFIG_XEN_GNTDEV) += xen-gntdev.o
+ obj-$(CONFIG_XEN_GRANT_DEV_ALLOC) += xen-gntalloc.o
+ obj-$(CONFIG_XENFS) += xenfs/
--
1.7.4
+