WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [linux-2.6.18-xen] Solarflare: PV netback accelerator.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] Solarflare: PV netback accelerator.
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 18 Feb 2008 06:00:40 -0800
Delivery-date: Mon, 18 Feb 2008 06:02:35 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1203330664 0
# Node ID af0d925ba938861fe202a91b4d9da952027b0672
# Parent  651fc2abdd5d32bed0bc88bcf3684e8126238fe4
Solarflare: PV netback accelerator.
Signed-off-by: Kieran Mansley <kmansley@xxxxxxxxxxxxxx>
---
 drivers/xen/Kconfig                                      |    6 
 drivers/xen/Makefile                                     |    1 
 drivers/xen/sfc_netback/Makefile                         |   12 
 drivers/xen/sfc_netback/accel.c                          |  129 +
 drivers/xen/sfc_netback/accel.h                          |  393 ++++
 drivers/xen/sfc_netback/accel_debugfs.c                  |  170 ++
 drivers/xen/sfc_netback/accel_fwd.c                      |  415 ++++
 drivers/xen/sfc_netback/accel_msg.c                      |  392 ++++
 drivers/xen/sfc_netback/accel_solarflare.c               | 1253 +++++++++++++++
 drivers/xen/sfc_netback/accel_solarflare.h               |   88 +
 drivers/xen/sfc_netback/accel_xenbus.c                   |  831 +++++++++
 drivers/xen/sfc_netback/ci/compat.h                      |   53 
 drivers/xen/sfc_netback/ci/compat/gcc.h                  |  158 +
 drivers/xen/sfc_netback/ci/compat/gcc_x86.h              |  115 +
 drivers/xen/sfc_netback/ci/compat/primitive.h            |   77 
 drivers/xen/sfc_netback/ci/compat/sysdep.h               |  166 +
 drivers/xen/sfc_netback/ci/compat/utils.h                |  269 +++
 drivers/xen/sfc_netback/ci/compat/x86.h                  |   48 
 drivers/xen/sfc_netback/ci/compat/x86_64.h               |   54 
 drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h      |  276 +++
 drivers/xen/sfc_netback/ci/efhw/common.h                 |  102 +
 drivers/xen/sfc_netback/ci/efhw/common_sysdep.h          |   67 
 drivers/xen/sfc_netback/ci/efhw/debug.h                  |   84 +
 drivers/xen/sfc_netback/ci/efhw/efhw_config.h            |   43 
 drivers/xen/sfc_netback/ci/efhw/efhw_types.h             |  342 ++++
 drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h        |   84 +
 drivers/xen/sfc_netback/ci/efhw/iopage_types.h           |  188 ++
 drivers/xen/sfc_netback/ci/efhw/public.h                 |   83 
 drivers/xen/sfc_netback/ci/efhw/sysdep.h                 |   72 
 drivers/xen/sfc_netback/ci/efrm/nic_table.h              |   98 +
 drivers/xen/sfc_netback/ci/efrm/sysdep.h                 |   54 
 drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h           |  248 ++
 drivers/xen/sfc_netback/ci/tools/config.h                |   49 
 drivers/xen/sfc_netback/ci/tools/debug.h                 |  336 ++++
 drivers/xen/sfc_netback/ci/tools/log.h                   |  262 +++
 drivers/xen/sfc_netback/ci/tools/platform/gcc_x86.h      |  361 ++++
 drivers/xen/sfc_netback/ci/tools/platform/linux_kernel.h |  362 ++++
 drivers/xen/sfc_netback/ci/tools/sysdep.h                |  132 +
 38 files changed, 7873 insertions(+)

diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/Kconfig
--- a/drivers/xen/Kconfig       Mon Feb 18 10:30:33 2008 +0000
+++ b/drivers/xen/Kconfig       Mon Feb 18 10:31:04 2008 +0000
@@ -82,6 +82,12 @@ config XEN_NETDEV_ACCEL_SFC_UTIL
 config XEN_NETDEV_ACCEL_SFC_UTIL
         tristate
         default n
+
+config XEN_NETDEV_ACCEL_SFC_BACKEND
+       tristate "Network-device backend driver acceleration for Solarflare 
NICs"
+        depends on XEN_NETDEV_BACKEND
+        select XEN_NETDEV_ACCEL_SFC_UTIL
+        default m
 
 config XEN_NETDEV_LOOPBACK
        tristate "Network-device loopback driver"
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/Makefile
--- a/drivers/xen/Makefile      Mon Feb 18 10:30:33 2008 +0000
+++ b/drivers/xen/Makefile      Mon Feb 18 10:31:04 2008 +0000
@@ -20,3 +20,4 @@ obj-$(CONFIG_XEN_GRANT_DEV)   += gntdev/
 obj-$(CONFIG_XEN_GRANT_DEV)    += gntdev/
 obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL)                += sfc_netutil/
 obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND)    += sfc_netfront/
+obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND)     += sfc_netback/
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/Makefile  Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,12 @@
+EXTRA_CFLAGS += -Idrivers/xen/sfc_netutil -Idrivers/xen/netback 
-Idrivers/net/sfc
+EXTRA_CFLAGS += -D__ci_driver__ 
+EXTRA_CFLAGS += -DEFX_USE_KCOMPAT
+EXTRA_CFLAGS += -Werror
+
+ifdef GCOV
+EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage -DEFX_GCOV
+endif
+
+obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND) := sfc_netback.o
+
+sfc_netback-objs   := accel.o accel_fwd.o accel_msg.o accel_solarflare.o 
accel_xenbus.o accel_debugfs.o
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel.c   Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,129 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include "accel.h"
+#include "accel_msg_iface.h"
+#include "accel_solarflare.h"
+
+#include <linux/notifier.h>
+
+#ifdef EFX_GCOV
+#include "gcov.h"
+#endif
+
+static int netback_accel_netdev_event(struct notifier_block *nb,
+                                     unsigned long event, void *ptr)
+{
+       struct net_device *net_dev = (struct net_device *)ptr;
+       struct netback_accel *bend;
+
+       if ((event == NETDEV_UP) || (event == NETDEV_DOWN)) {
+               mutex_lock(&bend_list_mutex);
+               bend = bend_list;
+               while (bend != NULL) {
+                       mutex_lock(&bend->bend_mutex);
+                       /*
+                        * This happens when the shared pages have
+                        * been unmapped, but the bend not yet removed
+                        * from list
+                        */
+                       if (bend->shared_page == NULL)
+                               goto next;
+
+                       if (bend->net_dev->ifindex == net_dev->ifindex)
+                               netback_accel_set_interface_state
+                                       (bend, event == NETDEV_UP);
+
+               next:
+                       mutex_unlock(&bend->bend_mutex);
+                       bend = bend->next_bend;
+               }
+               mutex_unlock(&bend_list_mutex);
+       }
+
+       return NOTIFY_DONE;
+}
+
+
+static struct notifier_block netback_accel_netdev_notifier = {
+       .notifier_call = netback_accel_netdev_event,
+};
+
+
+unsigned max_pages = NETBACK_ACCEL_DEFAULT_MAX_BUF_PAGES;
+module_param(max_pages, int, 0666);
+MODULE_PARM_DESC(max_pages, 
+                "The number of buffer pages to enforce on each guest");
+
+/* Initialise subsystems need for the accelerated fast path */
+static int __init netback_accel_init(void)
+{
+       int rc = 0;
+
+#ifdef EFX_GCOV
+       gcov_provider_init(THIS_MODULE);
+#endif
+
+       rc = netback_accel_init_fwd();
+
+       if (rc == 0)
+               netback_accel_debugfs_init();
+
+       if (rc == 0)
+               rc = netback_accel_sf_init();
+
+       if (rc == 0)
+               rc = register_netdevice_notifier
+                       (&netback_accel_netdev_notifier);
+
+       /*
+        * What if no device was found, shouldn't we clean up stuff
+        * we've allocated for acceleration subsystem?
+        */
+
+       return rc;
+}
+
+module_init(netback_accel_init);
+
+static void __exit netback_accel_exit(void)
+{
+       unregister_netdevice_notifier(&netback_accel_netdev_notifier);
+
+       netback_accel_sf_shutdown();
+
+       netback_accel_shutdown_bends();
+
+       netback_accel_debugfs_fini();
+
+       netback_accel_shutdown_fwd();
+
+#ifdef EFX_GCOV
+       gcov_provider_fini(THIS_MODULE);
+#endif
+}
+
+module_exit(netback_accel_exit);
+
+MODULE_LICENSE("GPL");
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel.h   Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,393 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef NETBACK_ACCEL_H
+#define NETBACK_ACCEL_H
+
+#include <linux/slab.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+
+#include <xen/xenbus.h>
+
+#include "accel_shared_fifo.h"
+#include "accel_msg_iface.h"
+#include "accel_util.h"
+
+/**************************************************************************
+ * Datatypes
+ **************************************************************************/
+
+#define NETBACK_ACCEL_DEFAULT_MAX_FILTERS (8)
+#define NETBACK_ACCEL_DEFAULT_MAX_MCASTS (8)
+#define NETBACK_ACCEL_DEFAULT_MAX_BUF_PAGES (384)
+/* Variable to store module parameter for max_buf_pages */
+extern unsigned max_pages;
+
+#define NETBACK_ACCEL_STATS 1
+
+#if NETBACK_ACCEL_STATS
+#define NETBACK_ACCEL_STATS_OP(x) x
+#else
+#define NETBACK_ACCEL_STATS_OP(x)
+#endif
+
+/*! Statistics for a given backend */
+struct netback_accel_stats {
+       /*! Number of eventq wakeup events */
+       u64 evq_wakeups;
+       /*! Number of eventq timeout events */
+       u64 evq_timeouts;
+       /*! Number of filters used */
+       u32 num_filters;
+       /*! Number of buffer pages registered */
+       u32 num_buffer_pages;
+};
+
+
+/* Debug fs nodes for each of the above stats */
+struct netback_accel_dbfs {
+       struct dentry *evq_wakeups;
+       struct dentry *evq_timeouts;
+       struct dentry *num_filters;
+       struct dentry *num_buffer_pages;
+};
+
+
+/*! Resource limits for a given NIC */
+struct netback_accel_limits {
+       int max_filters;            /*!< Max. number of filters to use. */
+       int max_mcasts;      /*!< Max. number  of mcast subscriptions */
+       int max_buf_pages;        /*!< Max. number of pages of NIC buffers */
+};
+
+
+/*! The state for an instance of the back end driver. */
+struct netback_accel {
+       /*! mutex to protect this state */
+       struct mutex bend_mutex;
+
+       /*! Watches on xenstore */
+       struct xenbus_watch domu_accel_watch;
+       struct xenbus_watch config_accel_watch;
+
+       /*! Pointer to whatever device cookie ties us in to the hypervisor */
+       void *hdev_data;
+
+       /*! FIFO indices. Next page is msg FIFOs */
+       struct net_accel_shared_page *shared_page;
+
+       /*! Defer control message processing */
+       struct work_struct handle_msg;
+
+       /*! Identifies other end VM and interface.*/
+       int far_end;
+       int vif_num;
+
+       /*!< To unmap the shared pages */
+       void *sh_pages_unmap;
+
+       /* Resource tracking */
+       /*! Limits on H/W & Dom0 resources */
+       struct netback_accel_limits quotas;
+
+       /* Hardware resources */
+       /*! The H/W type of associated NIC */
+       enum net_accel_hw_type hw_type;
+       /*! State of allocation */             
+       int hw_state;
+       /*! Index into ci_driver.nics[] for this interface */
+       int nic_index;
+       /*! How to set up the acceleration for this hardware */
+       int (*accel_setup)(struct netback_accel *); 
+       /*! And how to stop it. */
+       void (*accel_shutdown)(struct netback_accel *);
+
+       /*! The physical/real net_dev for this interface */
+       struct net_device *net_dev;
+
+       /*! Magic pointer to locate state in fowarding table */
+       void *fwd_priv;
+
+       /*! Message FIFO */
+       sh_msg_fifo2 to_domU;
+       /*! Message FIFO */
+       sh_msg_fifo2 from_domU;
+
+       /*! General notification channel id */
+       int msg_channel;
+       /*! General notification channel irq */
+       int msg_channel_irq;
+
+       /*! Event channel id dedicated to network packet interrupts. */
+       int net_channel; 
+       /*! Event channel irq dedicated to network packets interrupts */
+       int net_channel_irq; 
+
+       /*! The MAC address the frontend goes by. */
+       u8 mac[ETH_ALEN];
+       /*! Driver name of associated NIC */
+       char *nicname;    
+
+       /*! Array of pointers to buffer pages mapped */
+       grant_handle_t *buffer_maps; 
+       u64 *buffer_addrs;
+       /*! Index into buffer_maps */
+       int buffer_maps_index; 
+       /*! Max number of pages that domU is allowed/will request to map */
+       int max_pages; 
+
+       /*! Pointer to hardware specific private area */
+       void *accel_hw_priv; 
+
+       /*! Wait queue for changes in accelstate. */
+       wait_queue_head_t state_wait_queue;
+
+       /*! Current state of the frontend according to the xenbus
+        *  watch. */
+       XenbusState frontend_state;
+
+       /*! Current state of this backend. */
+       XenbusState backend_state;
+
+       /*! Non-zero if the backend is being removed. */
+       int removing;
+
+       /*! Non-zero if the setup_vnic has been called. */
+       int vnic_is_setup;
+
+#if NETBACK_ACCEL_STATS
+       struct netback_accel_stats stats;
+#endif 
+#if defined(CONFIG_DEBUG_FS)
+       char *dbfs_dir_name;
+       struct dentry *dbfs_dir;
+       struct netback_accel_dbfs dbfs;
+#endif
+
+       /*! List */
+       struct netback_accel *next_bend;
+};
+
+
+/*
+ * Values for netback_accel.hw_state.  States of resource allocation
+ * we can go through
+ */
+/*! No hardware has yet been allocated. */
+#define NETBACK_ACCEL_RES_NONE  (0)
+/*! Hardware has been allocated. */
+#define NETBACK_ACCEL_RES_ALLOC (1)
+#define NETBACK_ACCEL_RES_FILTER (2)
+#define NETBACK_ACCEL_RES_HWINFO (3)
+
+/*! Filtering specification. This assumes that for VNIC support we
+ *  will always want wildcard entries, so only specifies the
+ *  destination IP/port
+ */
+struct netback_accel_filter_spec {
+       /*! Internal, used to access efx_vi API */
+       void *filter_handle; 
+
+       /*! Destination IP in network order */
+       u32 destip_be;
+       /*! Destination port in network order */
+       u16 destport_be;
+       /*! Mac address */
+       u8  mac[ETH_ALEN];
+       /*! TCP or UDP */
+       u8  proto;      
+};
+
+
+/**************************************************************************
+ * From accel.c
+ **************************************************************************/
+
+/*! \brief Start up all the acceleration plugins 
+ *
+ * \return 0 on success, an errno on failure
+ */
+extern int netback_accel_init_accel(void);
+
+/*! \brief Shut down all the acceleration plugins 
+ */
+extern void netback_accel_shutdown_accel(void);
+
+
+/**************************************************************************
+ * From accel_fwd.c
+ **************************************************************************/
+
+/*! \brief Init the forwarding infrastructure
+ * \return 0 on success, or -ENOMEM if it couldn't get memory for the
+ * forward table 
+ */
+extern int netback_accel_init_fwd(void);
+
+/*! \brief Shut down the forwarding and free memory. */
+extern void netback_accel_shutdown_fwd(void);
+
+/*! Initialise each nic port's fowarding table */
+extern void *netback_accel_init_fwd_port(void);
+extern void netback_accel_shutdown_fwd_port(void *fwd_priv);
+
+/*! \brief Add an entry to the forwarding table. 
+ * \param mac : MAC address, used as hash key
+ * \param ctxt : value to associate with key (can be NULL, see
+ * netback_accel_fwd_set_context)
+ * \return 0 on success, -ENOMEM if table was full and could no grow it
+ */
+extern int netback_accel_fwd_add(const __u8 *mac, void *context,
+                                void *fwd_priv);
+
+/*! \brief Remove an entry from the forwarding table. 
+ * \param mac : the MAC address to remove
+ * \return nothing: it is not an error if the mac was not in the table
+ */
+extern void netback_accel_fwd_remove(const __u8 *mac, void *fwd_priv);
+
+/*! \brief Set the context pointer for an existing fwd table entry.
+ * \param mac : key that is already present in the table
+ * \param context : new value to associate with key
+ * \return 0 on success, -ENOENT if mac not present in table.
+ */
+extern int netback_accel_fwd_set_context(const __u8 *mac, void *context,
+                                        void *fwd_priv);
+
+/**************************************************************************
+ * From accel_msg.c
+ **************************************************************************/
+
+
+/*! \brief Send the start-of-day message that handshakes with the VNIC
+ *  and tells it its MAC address.
+ *
+ * \param bend The back end driver data structure
+ * \param version The version of communication to use, e.g. 
NET_ACCEL_MSG_VERSION
+ */
+extern void netback_accel_msg_tx_hello(struct netback_accel *bend,
+                                      unsigned version);
+
+/*! \brief Send a "there's a new local mac address" message 
+ *
+ * \param bend The back end driver data structure for the vnic to send
+ * the message to 
+ * \param mac Pointer to the new mac address
+ */
+extern void netback_accel_msg_tx_new_localmac(struct netback_accel *bend,
+                                             const void *mac);
+
+/*! \brief Send a "a mac address that was local has gone away" message 
+ *
+ * \param bend The back end driver data structure for the vnic to send
+ * the message to 
+ * \param mac Pointer to the old mac address
+ */
+extern void netback_accel_msg_tx_old_localmac(struct netback_accel *bend,
+                                             const void *mac);
+
+extern void netback_accel_set_interface_state(struct netback_accel *bend,
+                                             int up);
+
+/*! \brief Process the message queue for a bend that has just
+ * interrupted.
+ * 
+ * Demultiplexs an interrupt from the front end driver, taking
+ * messages from the fifo and taking appropriate action.
+ * 
+ * \param bend The back end driver data structure
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+extern void netback_accel_msg_rx_handler(struct work_struct *arg);
+#else
+extern void netback_accel_msg_rx_handler(void *bend_void);
+#endif
+
+/**************************************************************************
+ * From accel_xenbus.c
+ **************************************************************************/
+/*! List of all the bends currently in existence. */
+extern struct netback_accel *bend_list;
+extern struct mutex bend_list_mutex;
+
+/*! \brief Probe a new network interface. */
+extern int netback_accel_probe(struct xenbus_device *dev);
+
+/*! \brief Remove a network interface. */
+extern int netback_accel_remove(struct xenbus_device *dev);
+
+/*! \brief Shutdown all accelerator backends */
+extern void netback_accel_shutdown_bends(void);
+
+/*! \brief Initiate the xenbus state teardown handshake */
+extern void netback_accel_set_closing(struct netback_accel *bend);
+
+/**************************************************************************
+ * From accel_debugfs.c
+ **************************************************************************/
+/*! Global statistics */
+struct netback_accel_global_stats {
+       /*! Number of TX packets seen through driverlink */
+       u64 dl_tx_packets;
+       /*! Number of TX packets seen through driverlink we didn't like */
+       u64 dl_tx_bad_packets;
+       /*! Number of RX packets seen through driverlink */
+       u64 dl_rx_packets;
+       /*! Number of mac addresses we are forwarding to */
+       u32 num_fwds;
+};
+
+/*! Debug fs entries for each of the above stats */
+struct netback_accel_global_dbfs {
+       struct dentry *dl_tx_packets;
+       struct dentry *dl_tx_bad_packets;
+       struct dentry *dl_rx_packets;
+       struct dentry *num_fwds;
+};
+
+#if NETBACK_ACCEL_STATS
+extern struct netback_accel_global_stats global_stats;
+#endif
+
+/*! \brief Initialise the debugfs root and populate with global stats */
+extern void netback_accel_debugfs_init(void);
+
+/*! \brief Remove our debugfs root directory */
+extern void netback_accel_debugfs_fini(void);
+
+/*! \brief Add per-bend statistics to debug fs */
+extern int netback_accel_debugfs_create(struct netback_accel *bend);
+/*! \brief Remove per-bend statistics from debug fs */
+extern int netback_accel_debugfs_remove(struct netback_accel *bend);
+
+#endif /* NETBACK_ACCEL_H */
+
+
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel_debugfs.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel_debugfs.c   Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,170 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+
+#include "accel.h"
+
+#if defined(CONFIG_DEBUG_FS)
+static struct dentry *sfc_debugfs_root = NULL;
+#endif
+
+#if NETBACK_ACCEL_STATS
+struct netback_accel_global_stats global_stats;
+#if defined(CONFIG_DEBUG_FS)
+static struct netback_accel_global_dbfs  global_dbfs;
+#endif
+#endif
+
+/*
+ * Extend debugfs helper functions to have a u64 version
+ */ 
+static void debugfs_u64_set(void *data, u64 val)
+{
+  *(u64 *)data = val;
+}
+
+static u64 debugfs_u64_get(void *data)
+{
+  return *(u64 *)data;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+
+struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+                                  struct dentry *parent, u64 *value)
+{
+  return debugfs_create_file(name, mode, parent, value, &fops_u64);
+}
+
+
+void netback_accel_debugfs_init(void) 
+{
+#if defined(CONFIG_DEBUG_FS)
+       sfc_debugfs_root = debugfs_create_dir("sfc_netback", NULL);
+       if (sfc_debugfs_root == NULL)
+               return;
+
+       global_dbfs.num_fwds = debugfs_create_u32
+               ("num_fwds", S_IRUSR | S_IRGRP | S_IROTH,
+                sfc_debugfs_root, &global_stats.num_fwds);
+       global_dbfs.dl_tx_packets = debugfs_create_u64
+               ("dl_tx_packets", S_IRUSR | S_IRGRP | S_IROTH,
+                sfc_debugfs_root, &global_stats.dl_tx_packets);
+       global_dbfs.dl_rx_packets = debugfs_create_u64
+               ("dl_rx_packets", S_IRUSR | S_IRGRP | S_IROTH,
+                sfc_debugfs_root, &global_stats.dl_rx_packets);
+       global_dbfs.dl_tx_bad_packets = debugfs_create_u64
+               ("dl_tx_bad_packets", S_IRUSR | S_IRGRP | S_IROTH,
+                sfc_debugfs_root, &global_stats.dl_tx_bad_packets);
+#endif
+}
+
+
+void netback_accel_debugfs_fini(void)
+{
+#if defined(CONFIG_DEBUG_FS)
+       debugfs_remove(global_dbfs.num_fwds);
+       debugfs_remove(global_dbfs.dl_tx_packets);
+       debugfs_remove(global_dbfs.dl_rx_packets);
+       debugfs_remove(global_dbfs.dl_tx_bad_packets);
+
+       debugfs_remove(sfc_debugfs_root);
+#endif
+}
+
+
+int netback_accel_debugfs_create(struct netback_accel *bend)
+{
+#if defined(CONFIG_DEBUG_FS)
+       /* Smallest length is 7 (vif0.0\n) */
+       int length = 7, temp;
+
+       if (sfc_debugfs_root == NULL)
+               return -ENOENT;
+
+       /* Work out length of string representation of far_end and vif_num */
+       temp = bend->far_end;
+       while (temp > 9) {
+               length++;
+               temp = temp / 10;
+       }
+       temp = bend->vif_num;
+       while (temp > 9) {
+               length++;
+               temp = temp / 10;
+       }
+
+       bend->dbfs_dir_name = kmalloc(length, GFP_KERNEL);
+       if (bend->dbfs_dir_name == NULL)
+               return -ENOMEM;
+       sprintf(bend->dbfs_dir_name, "vif%d.%d", bend->far_end, bend->vif_num);
+
+       bend->dbfs_dir = debugfs_create_dir(bend->dbfs_dir_name, 
+                                           sfc_debugfs_root);
+       if (bend->dbfs_dir == NULL) {
+               kfree(bend->dbfs_dir_name);
+               return -ENOMEM;
+       }
+
+#if NETBACK_ACCEL_STATS
+       bend->dbfs.evq_wakeups = debugfs_create_u64
+               ("evq_wakeups", S_IRUSR | S_IRGRP | S_IROTH,
+                bend->dbfs_dir, &bend->stats.evq_wakeups);
+       bend->dbfs.evq_timeouts = debugfs_create_u64
+               ("evq_timeouts", S_IRUSR | S_IRGRP | S_IROTH,
+                bend->dbfs_dir, &bend->stats.evq_timeouts);
+       bend->dbfs.num_filters = debugfs_create_u32
+               ("num_filters", S_IRUSR | S_IRGRP | S_IROTH,
+                bend->dbfs_dir, &bend->stats.num_filters);
+       bend->dbfs.num_buffer_pages = debugfs_create_u32
+               ("num_buffer_pages", S_IRUSR | S_IRGRP | S_IROTH,
+                bend->dbfs_dir, &bend->stats.num_buffer_pages);
+#endif
+#endif
+        return 0;
+}
+
+
+int netback_accel_debugfs_remove(struct netback_accel *bend)
+{
+#if defined(CONFIG_DEBUG_FS)
+       if (bend->dbfs_dir != NULL) {
+#if NETBACK_ACCEL_STATS
+               debugfs_remove(bend->dbfs.evq_wakeups);
+               debugfs_remove(bend->dbfs.evq_timeouts);
+               debugfs_remove(bend->dbfs.num_filters);
+               debugfs_remove(bend->dbfs.num_buffer_pages);
+#endif
+               debugfs_remove(bend->dbfs_dir);
+       }
+
+       if (bend->dbfs_dir_name)
+               kfree(bend->dbfs_dir_name);
+#endif
+        return 0;
+}
+
+
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel_fwd.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel_fwd.c       Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,415 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include "accel.h"
+#include "accel_cuckoo_hash.h"
+#include "accel_util.h"
+#include "accel_solarflare.h"
+
+#include "driverlink_api.h"
+
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+
+/* State stored in the forward table */
+struct fwd_struct {
+       struct list_head link; /* Forms list */
+       void * context;
+       __u8 valid;
+       __u8 mac[ETH_ALEN];
+};
+
+/* Max value we support */
+#define NUM_FWDS_BITS 8
+#define NUM_FWDS (1 << NUM_FWDS_BITS)
+#define FWD_MASK (NUM_FWDS - 1)
+
+struct port_fwd {
+       /* Make a list */
+       struct list_head link;
+       /* Hash table to store the fwd_structs */
+       cuckoo_hash_table fwd_hash_table;
+       /* The array of fwd_structs */
+       struct fwd_struct *fwd_array;
+       /* Linked list of entries in use. */
+       struct list_head fwd_list;
+       /* Could do something clever with a reader/writer lock. */
+       spinlock_t fwd_lock;
+       /* Make find_free_entry() a bit faster by caching this */
+       int last_free_index;
+};
+
+/*
+ * This is unlocked as it's only called from dl probe and remove,
+ * which are themselves synchronised.  Could get rid of it entirely as
+ * it's never iterated, but useful for debug
+ */
+static struct list_head port_fwds;
+
+
+/* Search the fwd_array for an unused entry */
+static int fwd_find_free_entry(struct port_fwd *fwd_set)
+{
+       int index = fwd_set->last_free_index;
+
+       do {
+               if (!fwd_set->fwd_array[index].valid) {
+                       fwd_set->last_free_index = index;
+                       return index;
+               }
+               index++;
+               if (index >= NUM_FWDS)
+                       index = 0;
+       } while (index != fwd_set->last_free_index);
+
+       return -ENOMEM;
+}
+
+
+/* Look up a MAC in the hash table. Caller should hold table lock. */
+static inline struct fwd_struct *fwd_find_entry(const __u8 *mac,
+                                               struct port_fwd *fwd_set)
+{
+       cuckoo_hash_value value;
+       cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac);
+
+       if (cuckoo_hash_lookup(&fwd_set->fwd_hash_table,
+                              (cuckoo_hash_key *)(&key),
+                              &value)) {
+               struct fwd_struct *fwd = &fwd_set->fwd_array[value];
+               DPRINTK_ON(memcmp(fwd->mac, mac, ETH_ALEN) != 0);
+               return fwd;
+       }
+
+       return NULL;
+}
+
+
+/* Initialise each nic port's fowarding table */
+void *netback_accel_init_fwd_port(void) 
+{      
+       struct port_fwd *fwd_set;
+
+       fwd_set = kzalloc(sizeof(struct port_fwd), GFP_KERNEL);
+       if (fwd_set == NULL) {
+               return NULL;
+       }
+
+       spin_lock_init(&fwd_set->fwd_lock);
+       
+       fwd_set->fwd_array = kzalloc(sizeof (struct fwd_struct) * NUM_FWDS,
+                                    GFP_KERNEL);
+       if (fwd_set->fwd_array == NULL) {
+               kfree(fwd_set);
+               return NULL;
+       }
+       
+       if (cuckoo_hash_init(&fwd_set->fwd_hash_table, NUM_FWDS_BITS, 8) != 0) {
+               kfree(fwd_set->fwd_array);
+               kfree(fwd_set);
+               return NULL;
+       }
+       
+       INIT_LIST_HEAD(&fwd_set->fwd_list);
+       
+       list_add(&fwd_set->link, &port_fwds);
+
+       return fwd_set;
+}
+
+
+void netback_accel_shutdown_fwd_port(void *fwd_priv)
+{
+       struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
+
+       BUG_ON(fwd_priv == NULL);
+       
+       BUG_ON(list_empty(&port_fwds));
+       list_del(&fwd_set->link);
+
+       BUG_ON(!list_empty(&fwd_set->fwd_list));
+
+       cuckoo_hash_destroy(&fwd_set->fwd_hash_table);
+       kfree(fwd_set->fwd_array);
+       kfree(fwd_set);
+}
+
+
+int netback_accel_init_fwd()
+{
+       INIT_LIST_HEAD(&port_fwds);
+       return 0;
+}
+
+
+void netback_accel_shutdown_fwd()
+{
+       BUG_ON(!list_empty(&port_fwds));
+}
+
+
+/*
+ * Add an entry to the forwarding table.  Returns -ENOMEM if no
+ * space.
+ */
+int netback_accel_fwd_add(const __u8 *mac, void *context, void *fwd_priv)
+{
+       struct fwd_struct *fwd;
+       int rc = 0, index;
+       unsigned long flags;
+       cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac);
+       struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
+
+       BUG_ON(fwd_priv == NULL);
+
+       DPRINTK("Adding mac " MAC_FMT "\n", MAC_ARG(mac));
+       
+       spin_lock_irqsave(&fwd_set->fwd_lock, flags);
+       
+       if ((rc = fwd_find_free_entry(fwd_set)) < 0 ) {
+               spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
+               return rc;
+       }
+
+       index = rc;
+
+       /* Shouldn't already be in the table */
+       BUG_ON(cuckoo_hash_lookup(&fwd_set->fwd_hash_table,
+                                 (cuckoo_hash_key *)(&key), &rc) != 0);
+
+       if ((rc = cuckoo_hash_add(&fwd_set->fwd_hash_table,
+                                 (cuckoo_hash_key *)(&key), index, 1)) == 0) {
+               fwd = &fwd_set->fwd_array[index];
+               fwd->valid = 1;
+               fwd->context = context;
+               memcpy(fwd->mac, mac, ETH_ALEN);
+               list_add(&fwd->link, &fwd_set->fwd_list);
+               NETBACK_ACCEL_STATS_OP(global_stats.num_fwds++);
+       }
+
+       spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
+
+       /*
+        * No need to tell frontend that this mac address is local -
+        * it should auto-discover through packets on fastpath what is
+        * local and what is not, and just being on same server
+        * doesn't make it local (it could be on a different
+        * bridge)
+        */
+
+       return rc;
+}
+
+
+/* remove an entry from the forwarding tables. */
+void netback_accel_fwd_remove(const __u8 *mac, void *fwd_priv)
+{
+       struct fwd_struct *fwd;
+       unsigned long flags;
+       cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac);
+       struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
+
+       DPRINTK("Removing mac " MAC_FMT "\n", MAC_ARG(mac));
+
+       BUG_ON(fwd_priv == NULL);
+
+       spin_lock_irqsave(&fwd_set->fwd_lock, flags);
+
+       fwd = fwd_find_entry(mac, fwd_set);
+       if (fwd != NULL) {
+               BUG_ON(list_empty(&fwd_set->fwd_list));
+               list_del(&fwd->link);
+
+               fwd->valid = 0;
+               cuckoo_hash_remove(&fwd_set->fwd_hash_table, 
+                                  (cuckoo_hash_key *)(&key));
+               NETBACK_ACCEL_STATS_OP(global_stats.num_fwds--);
+       }
+       spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
+
+       /*
+        * No need to tell frontend that this is no longer present -
+        * the frontend is currently only interested in remote
+        * addresses and it works these out (mostly) by itself
+        */
+}
+
+
+/* Set the context pointer for a hash table entry. */
+int netback_accel_fwd_set_context(const __u8 *mac, void *context, 
+                                 void *fwd_priv)
+{
+       struct fwd_struct *fwd;
+       unsigned long flags;
+       int rc = -ENOENT;
+       struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
+
+       BUG_ON(fwd_priv == NULL);
+
+       spin_lock_irqsave(&fwd_set->fwd_lock, flags);
+       fwd = fwd_find_entry(mac, fwd_set);
+       if (fwd != NULL) {
+               fwd->context = context;
+               rc = 0;
+       }
+       spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
+       return rc;
+}
+
+
+/**************************************************************************
+ * Process a received packet
+ **************************************************************************/
+
+/*
+ * Returns whether or not we have a match in our forward table for the
+ * this skb. Must be called with appropriate fwd_lock already held
+ */
+static struct netback_accel *for_a_vnic(struct netback_pkt_buf *skb, 
+                                       struct port_fwd *fwd_set)
+{
+       struct fwd_struct *fwd;
+       struct netback_accel *retval = NULL;
+
+       fwd = fwd_find_entry(skb->mac.raw, fwd_set);
+       if (fwd != NULL)
+               retval = fwd->context;
+       return retval;
+}
+
+
+static inline int packet_is_arp_reply(struct sk_buff *skb)
+{
+       return skb->protocol == ntohs(ETH_P_ARP) 
+               && skb->nh.arph->ar_op == ntohs(ARPOP_REPLY);
+}
+
+
+static inline void hdr_to_filt(struct ethhdr *ethhdr, struct iphdr *ip,
+                              struct netback_accel_filter_spec *spec)
+{
+       spec->proto = ip->protocol;
+       spec->destip_be = ip->daddr;
+       memcpy(spec->mac, ethhdr->h_source, ETH_ALEN);
+
+       if (ip->protocol == IPPROTO_TCP) {
+               struct tcphdr *tcp = (struct tcphdr *)((char *)ip + 4 * 
ip->ihl);
+               spec->destport_be = tcp->dest;
+       } else {
+               struct udphdr *udp = (struct udphdr *)((char *)ip + 4 * 
ip->ihl);
+               EPRINTK_ON(ip->protocol != IPPROTO_UDP);
+               spec->destport_be = udp->dest;
+       }
+}
+
+
+static inline int netback_accel_can_filter(struct netback_pkt_buf *skb) 
+{
+       return (skb->protocol == htons(ETH_P_IP) && 
+               ((skb->nh.iph->protocol == IPPROTO_TCP) ||
+                (skb->nh.iph->protocol == IPPROTO_UDP)));
+}
+
+
+static inline void netback_accel_filter_packet(struct netback_accel *bend,
+                                              struct netback_pkt_buf *skb)
+{
+       struct netback_accel_filter_spec fs;
+       struct ethhdr *eh = (struct ethhdr *)(skb->mac.raw);
+
+       hdr_to_filt(eh, skb->nh.iph, &fs);
+       
+       netback_accel_filter_check_add(bend, &fs);
+}
+
+
+/*
+ * Receive a packet and do something appropriate with it. Return true
+ * to take exclusive ownership of the packet.  This is verging on
+ * solarflare specific
+ */
+void netback_accel_rx_packet(struct netback_pkt_buf *skb, void *fwd_priv)
+{
+       struct netback_accel *bend;
+       struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
+       unsigned long flags;
+
+       BUG_ON(fwd_priv == NULL);
+
+       /* Checking for bcast is cheaper so do that first */
+       if (is_broadcast_ether_addr(skb->mac.raw)) {
+               /* pass through the slow path by not claiming ownership */
+               return;
+       } else if (is_multicast_ether_addr(skb->mac.raw)) {
+               /* pass through the slow path by not claiming ownership */
+               return;
+       } else {
+               /* It is unicast */
+               spin_lock_irqsave(&fwd_set->fwd_lock, flags);
+               /* We insert filter to pass it off to a VNIC */
+               if ((bend = for_a_vnic(skb, fwd_set)) != NULL)
+                       if (netback_accel_can_filter(skb))
+                               netback_accel_filter_packet(bend, skb);
+               spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
+       }
+       return;
+}
+
+
+void netback_accel_tx_packet(struct sk_buff *skb, void *fwd_priv) 
+{
+       __u8 *mac;
+       unsigned long flags;
+       struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
+       struct fwd_struct *fwd;
+
+       BUG_ON(fwd_priv == NULL);
+
+       if (is_broadcast_ether_addr(skb->mac.raw) && packet_is_arp_reply(skb)) {
+               /*
+                * update our fast path forwarding to reflect this
+                * gratuitous ARP
+                */ 
+               mac = skb->mac.raw+ETH_ALEN;
+
+               DPRINTK("%s: found gratuitous ARP for " MAC_FMT "\n",
+                       __FUNCTION__, MAC_ARG(mac));
+
+               spin_lock_irqsave(&fwd_set->fwd_lock, flags);
+               /*
+                * Might not be local, but let's tell them all it is,
+                * and they can restore the fastpath if they continue
+                * to get packets that way
+                */
+               list_for_each_entry(fwd, &fwd_set->fwd_list, link) {
+                       struct netback_accel *bend = fwd->context;
+                       if (bend != NULL)
+                               netback_accel_msg_tx_new_localmac(bend, mac);
+               }
+
+               spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
+       }
+       return;
+}
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel_msg.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel_msg.c       Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,392 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include <xen/evtchn.h>
+
+#include "accel.h"
+#include "accel_msg_iface.h"
+#include "accel_util.h"
+#include "accel_solarflare.h"
+
+/* Send a HELLO to front end to start things off */
+void netback_accel_msg_tx_hello(struct netback_accel *bend, unsigned version)
+{
+       unsigned long lock_state;
+       struct net_accel_msg *msg = 
+               net_accel_msg_start_send(bend->shared_page,
+                                        &bend->to_domU, &lock_state);
+       /* The queue _cannot_ be full, we're the first users. */
+       EPRINTK_ON(msg == NULL);
+
+       if (msg != NULL) {
+               net_accel_msg_init(msg, NET_ACCEL_MSG_HELLO);
+               msg->u.hello.version = version;
+               msg->u.hello.max_pages = bend->quotas.max_buf_pages; 
+               VPRINTK("Sending hello to channel %d\n", bend->msg_channel);
+               net_accel_msg_complete_send_notify(bend->shared_page, 
+                                                  &bend->to_domU,
+                                                  &lock_state, 
+                                                  bend->msg_channel_irq);
+       }
+}
+
+/* Send a local mac message to vnic */
+static void netback_accel_msg_tx_localmac(struct netback_accel *bend, 
+                                         int type, const void *mac)
+{
+       unsigned long lock_state;
+       struct net_accel_msg *msg;
+
+       BUG_ON(bend == NULL || mac == NULL);
+
+       VPRINTK("Sending local mac message: " MAC_FMT "\n", 
+               MAC_ARG((const char *)mac));  
+       
+       msg = net_accel_msg_start_send(bend->shared_page, &bend->to_domU,
+                                      &lock_state);
+       
+       if (msg != NULL) {
+               net_accel_msg_init(msg, NET_ACCEL_MSG_LOCALMAC);
+               msg->u.localmac.flags = type;
+               memcpy(msg->u.localmac.mac, mac, ETH_ALEN);
+               net_accel_msg_complete_send_notify(bend->shared_page, 
+                                                  &bend->to_domU,
+                                                  &lock_state, 
+                                                  bend->msg_channel_irq);
+       } else {
+               /*
+                * TODO if this happens we may leave a domU
+                * fastpathing packets when they should be delivered
+                * locally.  Solution is get domU to timeout entries
+                * in its fastpath lookup table when it receives no RX
+                * traffic
+                */
+               EPRINTK("%s: saw full queue, may need ARP timer to recover\n",
+                       __FUNCTION__);
+       }
+}
+
+/* Send an add local mac message to vnic */
+void netback_accel_msg_tx_new_localmac(struct netback_accel *bend,
+                                      const void *mac)
+{
+       netback_accel_msg_tx_localmac(bend, NET_ACCEL_MSG_ADD, mac);
+}
+
+
+static int netback_accel_msg_rx_buffer_map(struct netback_accel *bend, 
+                                          struct net_accel_msg *msg)
+{
+       int log2_pages, rc;
+
+       /* Can only allocate in power of two */
+       log2_pages = log2_ge(msg->u.mapbufs.pages, 0);
+       if (msg->u.mapbufs.pages != pow2(log2_pages)) {
+               EPRINTK("%s: Can only alloc bufs in power of 2 sizes (%d)\n",
+                       __FUNCTION__, msg->u.mapbufs.pages);
+               rc = -EINVAL;
+               goto err_out;
+       }
+  
+       /*
+        * Sanity.  Assumes NET_ACCEL_MSG_MAX_PAGE_REQ is same for
+        * both directions/domains
+        */
+       if (msg->u.mapbufs.pages > NET_ACCEL_MSG_MAX_PAGE_REQ) {
+               EPRINTK("%s: too many pages in a single message: %d %d\n", 
+                       __FUNCTION__, msg->u.mapbufs.pages,
+                       NET_ACCEL_MSG_MAX_PAGE_REQ);
+               rc = -EINVAL;
+               goto err_out;
+       }
+  
+       if ((rc = netback_accel_add_buffers(bend, msg->u.mapbufs.pages, 
+                                           log2_pages, msg->u.mapbufs.grants, 
+                                           &msg->u.mapbufs.buf)) < 0) {
+               goto err_out;
+       }
+
+       msg->id |= NET_ACCEL_MSG_REPLY;
+  
+       return 0;
+
+ err_out:
+       EPRINTK("%s: err_out\n", __FUNCTION__);
+       msg->id |= NET_ACCEL_MSG_ERROR | NET_ACCEL_MSG_REPLY;
+       return rc;
+}
+
+
+/* Hint from frontend that one of our filters is out of date */
+static int netback_accel_process_fastpath(struct netback_accel *bend, 
+                                         struct net_accel_msg *msg)
+{
+       struct netback_accel_filter_spec spec;
+
+       if (msg->u.fastpath.flags & NET_ACCEL_MSG_REMOVE) {
+               /* 
+                * Would be nice to BUG() this but would leave us
+                * vulnerable to naughty frontend
+                */
+               EPRINTK_ON(msg->u.fastpath.flags & NET_ACCEL_MSG_ADD);
+               
+               memcpy(spec.mac, msg->u.fastpath.mac, ETH_ALEN);
+               spec.destport_be = msg->u.fastpath.port;
+               spec.destip_be = msg->u.fastpath.ip;
+               spec.proto = msg->u.fastpath.proto;
+
+               netback_accel_filter_remove_spec(bend, &spec);
+       }
+
+       return 0;
+}
+
+
+/* Flow control for message queues */
+inline void set_queue_not_full(struct netback_accel *bend)
+{
+       if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL_B, 
+                             (unsigned long *)&bend->shared_page->aflags))
+               notify_remote_via_irq(bend->msg_channel_irq);
+       else
+               VPRINTK("queue not full bit already set, not signalling\n");
+}
+
+
+/* Flow control for message queues */
+inline void set_queue_full(struct netback_accel *bend)
+{
+       if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0FULL_B,
+                             (unsigned long *)&bend->shared_page->aflags))
+               notify_remote_via_irq(bend->msg_channel_irq);
+       else
+               VPRINTK("queue full bit already set, not signalling\n");
+}
+
+
+void netback_accel_set_interface_state(struct netback_accel *bend, int up)
+{
+       bend->shared_page->net_dev_up = up;
+       if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_NETUPDOWN_B, 
+                            (unsigned long *)&bend->shared_page->aflags))
+               notify_remote_via_irq(bend->msg_channel_irq);
+       else
+               VPRINTK("interface up/down bit already set, not signalling\n");
+}
+
+
+static int check_rx_hello_version(unsigned version) 
+{
+       /* Should only happen if there's been a version mismatch */
+       BUG_ON(version == NET_ACCEL_MSG_VERSION);
+
+       if (version > NET_ACCEL_MSG_VERSION) {
+               /* Newer protocol, we must refuse */
+               return -EPROTO;
+       }
+
+       if (version < NET_ACCEL_MSG_VERSION) {
+               /*
+                * We are newer, so have discretion to accept if we
+                * wish.  For now however, just reject
+                */
+               return -EPROTO;
+       }
+
+       return -EINVAL;
+}
+
+
+static int process_rx_msg(struct netback_accel *bend,
+                         struct net_accel_msg *msg)
+{
+       int err = 0;
+                     
+       switch (msg->id) {
+       case NET_ACCEL_MSG_REPLY | NET_ACCEL_MSG_HELLO:
+               /* Reply to a HELLO; mark ourselves as connected */
+               DPRINTK("got Hello reply, version %.8x\n",
+                       msg->u.hello.version);
+               
+               /*
+                * Check that we've not successfully done this
+                * already.  NB no check at the moment that this reply
+                * comes after we've actually sent a HELLO as that's
+                * not possible with the current code structure
+                */
+               if (bend->hw_state != NETBACK_ACCEL_RES_NONE)
+                       return -EPROTO;
+
+               /* Store max_pages for accel_setup */
+               if (msg->u.hello.max_pages > bend->quotas.max_buf_pages) {
+                       EPRINTK("More pages than quota allows (%d > %d)\n",
+                               msg->u.hello.max_pages, 
+                               bend->quotas.max_buf_pages);
+                       /* Force it down to the quota */
+                       msg->u.hello.max_pages = bend->quotas.max_buf_pages;
+               }
+               bend->max_pages = msg->u.hello.max_pages;
+               
+               /* Set up the hardware visible to the other end */
+               err = bend->accel_setup(bend);
+               if (err) {
+                       /* This is fatal */
+                       DPRINTK("Hello gave accel_setup error %d\n", err);
+                       netback_accel_set_closing(bend);
+               } else {
+                       /*
+                        * Now add the context so that packet
+                        * forwarding will commence
+                        */
+                       netback_accel_fwd_set_context(bend->mac, bend, 
+                                                     bend->fwd_priv);
+               }
+               break;
+       case NET_ACCEL_MSG_REPLY | NET_ACCEL_MSG_HELLO | NET_ACCEL_MSG_ERROR:
+               EPRINTK("got Hello error, versions us:%.8x them:%.8x\n",
+                       NET_ACCEL_MSG_VERSION, msg->u.hello.version);
+
+               if (bend->hw_state != NETBACK_ACCEL_RES_NONE)
+                       return -EPROTO;
+
+               if (msg->u.hello.version != NET_ACCEL_MSG_VERSION) {
+                       /* Error is due to version mismatch */
+                       err = check_rx_hello_version(msg->u.hello.version);
+                       if (err == 0) {
+                               /*
+                                * It's OK to be compatible, send
+                                * another hello with compatible version
+                                */
+                               netback_accel_msg_tx_hello
+                                       (bend, msg->u.hello.version);
+                       } else {
+                               /*
+                                * Tell frontend that we're not going to
+                                * send another HELLO by going to Closing.
+                                */
+                               netback_accel_set_closing(bend);
+                       }
+               } 
+               break;
+       case NET_ACCEL_MSG_MAPBUF:
+               VPRINTK("Got mapped buffers request %d\n",
+                       msg->u.mapbufs.reqid);
+
+               if (bend->hw_state == NETBACK_ACCEL_RES_NONE)
+                       return -EPROTO;
+
+               /*
+                * Frontend wants a buffer table entry for the
+                * supplied pages
+                */
+               err = netback_accel_msg_rx_buffer_map(bend, msg);
+               if (net_accel_msg_reply_notify(bend->shared_page,
+                                              bend->msg_channel_irq, 
+                                              &bend->to_domU, msg)) {
+                       /*
+                        * This is fatal as we can't tell the frontend
+                        * about the problem through the message
+                        * queue, and so would otherwise stalemate
+                        */
+                       netback_accel_set_closing(bend);
+               }
+               break;
+       case NET_ACCEL_MSG_FASTPATH:
+               DPRINTK("Got fastpath request\n");
+
+               if (bend->hw_state == NETBACK_ACCEL_RES_NONE)
+                       return -EPROTO;
+
+               err = netback_accel_process_fastpath(bend, msg);
+               break;
+       default:
+               EPRINTK("Huh? Message code is %x\n", msg->id);
+               err = -EPROTO;
+               break;
+       }
+       return err;
+}
+
+
+/*  Demultiplex an IRQ from the frontend driver.  */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+void netback_accel_msg_rx_handler(struct work_struct *arg)
+#else
+void netback_accel_msg_rx_handler(void *bend_void)
+#endif
+{
+       struct net_accel_msg msg;
+       int err, queue_was_full = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+       struct netback_accel *bend = 
+               container_of(arg, struct netback_accel, handle_msg);
+#else
+       struct netback_accel *bend = (struct netback_accel *)bend_void;
+#endif
+
+       mutex_lock(&bend->bend_mutex);
+
+       /*
+        * This happens when the shared pages have been unmapped, but
+        * the workqueue not flushed yet
+        */
+       if (bend->shared_page == NULL)
+               goto done;
+
+       if ((bend->shared_page->aflags &
+            NET_ACCEL_MSG_AFLAGS_TO_DOM0_MASK) != 0) {
+               if (bend->shared_page->aflags &
+                   NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL) {
+                       /* We've been told there may now be space. */
+                       clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL_B, 
+                                 (unsigned long *)&bend->shared_page->aflags);
+               }
+
+               if (bend->shared_page->aflags &
+                   NET_ACCEL_MSG_AFLAGS_QUEUEUFULL) {
+                       clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUFULL_B, 
+                                 (unsigned long *)&bend->shared_page->aflags);
+                       queue_was_full = 1;
+               }
+       }
+
+       while ((err = net_accel_msg_recv(bend->shared_page, &bend->from_domU,
+                                        &msg)) == 0) {
+               err = process_rx_msg(bend, &msg);
+               
+               if (err != 0) {
+                       EPRINTK("%s: Error %d\n", __FUNCTION__, err);
+                       goto err;
+               }
+       }
+
+ err:
+       /* There will be space now if we can make any. */
+       if (queue_was_full) 
+               set_queue_not_full(bend);
+ done:
+       mutex_unlock(&bend->bend_mutex);
+
+       return;
+}
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel_solarflare.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel_solarflare.c        Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,1253 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include "common.h"
+
+#include "accel.h"
+#include "accel_solarflare.h"
+#include "accel_msg_iface.h"
+#include "accel_util.h"
+
+#include "accel_cuckoo_hash.h"
+
+#include "ci/driver/resource/efx_vi.h"
+
+#include "ci/efrm/nic_table.h" 
+#include "ci/efhw/public.h"
+
+#include <xen/evtchn.h>
+#include <xen/driver_util.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include "driverlink_api.h"
+
+#define SF_XEN_RX_USR_BUF_SIZE 2048
+
+struct falcon_bend_accel_priv {
+       struct efx_vi_state *efx_vih;
+
+       /*! Array of pointers to dma_map state, used so VNIC can
+        *  request their removal in a single message
+        */
+       struct efx_vi_dma_map_state **dma_maps;
+       /*! Index into dma_maps */
+       int dma_maps_index; 
+
+       /*! Serialises access to filters */
+       spinlock_t filter_lock;      
+       /*! Bitmap of which filters are free */
+       unsigned long free_filters;      
+       /*! Used for index normalisation */
+       u32 filter_idx_mask;            
+       struct netback_accel_filter_spec *fspecs; 
+       cuckoo_hash_table filter_hash_table;
+
+       u32 txdmaq_gnt;
+       u32 rxdmaq_gnt;
+       u32 doorbell_gnt;
+       u32 evq_rptr_gnt;
+       u32 evq_mem_gnts[EF_HW_FALCON_EVQ_PAGES];
+       u32 evq_npages;
+};
+
+/* Forward declaration */
+static int netback_accel_filter_init(struct netback_accel *);
+static void netback_accel_filter_shutdown(struct netback_accel *);
+
+/**************************************************************************
+ * 
+ * Driverlink stuff
+ *
+ **************************************************************************/
+
+struct driverlink_port {
+       struct list_head link;
+       enum net_accel_hw_type type;
+       struct net_device *net_dev;
+       struct efx_dl_device *efx_dl_dev;
+       int nic_index;
+       void *fwd_priv;
+};
+
+static struct list_head dl_ports;
+
+/* This mutex protects global state, such as the dl_ports list */
+DEFINE_MUTEX(accel_mutex);
+
+static int init_done = 0;
+
+/* The DL callbacks */
+
+
+#if defined(EFX_USE_FASTCALL)
+static enum efx_veto fastcall
+#else
+static enum efx_veto
+#endif
+bend_dl_tx_packet(struct efx_dl_device *efx_dl_dev,
+                 struct sk_buff *skb)
+{
+       struct driverlink_port *port = efx_dl_dev->priv;
+
+       BUG_ON(port == NULL);
+
+       NETBACK_ACCEL_STATS_OP(global_stats.dl_tx_packets++);
+       if (skb->mac.raw != NULL)
+               netback_accel_tx_packet(skb, port->fwd_priv);
+       else {
+               DPRINTK("Ignoring packet with missing mac address\n");
+               NETBACK_ACCEL_STATS_OP(global_stats.dl_tx_bad_packets++);
+       }
+       return EFX_ALLOW_PACKET;
+}
+
+/* EFX_USE_FASTCALL */
+#if defined(EFX_USE_FASTCALL)
+static enum efx_veto fastcall
+#else
+static enum efx_veto
+#endif
+bend_dl_rx_packet(struct efx_dl_device *efx_dl_dev,
+                 const char *pkt_buf, int pkt_len)
+{
+       struct driverlink_port *port = efx_dl_dev->priv;
+       struct netback_pkt_buf pkt;
+       struct ethhdr *eh;
+
+       BUG_ON(port == NULL);
+
+       pkt.mac.raw = (char *)pkt_buf;
+       pkt.nh.raw = (char *)pkt_buf + ETH_HLEN;
+       eh = (struct ethhdr *)pkt_buf;
+       pkt.protocol = eh->h_proto;
+
+       NETBACK_ACCEL_STATS_OP(global_stats.dl_rx_packets++);
+       netback_accel_rx_packet(&pkt, port->fwd_priv);
+       return EFX_ALLOW_PACKET;
+}
+
+
+/* Callbacks we'd like to get from the netdriver through driverlink */
+struct efx_dl_callbacks bend_dl_callbacks =
+       {
+               .tx_packet = bend_dl_tx_packet,
+               .rx_packet = bend_dl_rx_packet,
+       };
+
+
+static struct netback_accel_hooks accel_hooks = {
+       THIS_MODULE,
+       &netback_accel_probe,
+       &netback_accel_remove
+};
+
+
+/*
+ * Handy helper which given an efx_dl_device works out which
+ * efab_nic_t index into efrm_nic_table.nics[] it corresponds to 
+ */
+static int efx_device_to_efab_nic_index(struct efx_dl_device *efx_dl_dev) 
+{
+       int i;
+
+       for (i = 0; i < EFHW_MAX_NR_DEVS; i++) {
+               struct efhw_nic *nic = efrm_nic_table.nic[i];
+
+               /*
+                * It's possible for the nic structure to have not
+                * been initialised if the resource driver failed its
+                * driverlink probe
+                */ 
+               if (nic == NULL || nic->net_driver_dev == NULL)
+                       continue;
+
+               /* Work out if these are talking about the same NIC */
+               if (nic->net_driver_dev->pci_dev == efx_dl_dev->pci_dev)
+                       return i;
+       }
+
+       return -1;
+}
+
+
+/* Driver link probe - register our callbacks */
+static int bend_dl_probe(struct efx_dl_device *efx_dl_dev,
+                        const struct net_device *net_dev,
+                        const struct efx_dl_device_info *dev_info,
+                        const char* silicon_rev)
+{
+       int rc;
+       enum net_accel_hw_type type;
+       struct driverlink_port *port;
+
+       DPRINTK("%s: %s\n", __FUNCTION__, silicon_rev);
+
+       if (strcmp(silicon_rev, "falcon/a1") == 0)
+               type = NET_ACCEL_MSG_HWTYPE_FALCON_A;
+       else if (strcmp(silicon_rev, "falcon/b0") == 0)
+               type = NET_ACCEL_MSG_HWTYPE_FALCON_B;
+       else {
+               EPRINTK("%s: unsupported silicon %s\n", __FUNCTION__,
+                       silicon_rev);
+               rc = -EINVAL;
+               goto fail1;
+       }
+       
+       port = kmalloc(sizeof(struct driverlink_port), GFP_KERNEL);
+       if (port == NULL) {
+               EPRINTK("%s: no memory for dl probe\n", __FUNCTION__);
+               rc = -ENOMEM;
+               goto fail1;
+       }
+
+       port->efx_dl_dev = efx_dl_dev;
+       efx_dl_dev->priv = port;
+
+       port->nic_index = efx_device_to_efab_nic_index(efx_dl_dev);
+       if (port->nic_index < 0) {
+               /*
+                * This can happen in theory if the resource driver
+                * failed to initialise properly
+                */
+               EPRINTK("%s: nic structure not found\n", __FUNCTION__);
+               rc = -EINVAL;
+               goto fail2;
+       }
+
+       port->fwd_priv = netback_accel_init_fwd_port();
+       if (port->fwd_priv == NULL) {
+               EPRINTK("%s: failed to set up forwarding for port\n",
+                       __FUNCTION__);
+               rc = -ENOMEM;
+               goto fail2;
+       }
+
+       rc = efx_dl_register_callbacks(efx_dl_dev, &bend_dl_callbacks);
+       if (rc != 0) {
+               EPRINTK("%s: register_callbacks failed\n", __FUNCTION__);
+               goto fail3;
+       }
+
+       port->type = type;
+       port->net_dev = (struct net_device *)net_dev;
+
+       mutex_lock(&accel_mutex);
+       list_add(&port->link, &dl_ports);
+       mutex_unlock(&accel_mutex);
+
+       rc = netback_connect_accelerator(NETBACK_ACCEL_VERSION, 0,
+                                        port->net_dev->name, &accel_hooks);
+
+       if (rc < 0) {
+               EPRINTK("Xen netback accelerator version mismatch\n");
+               goto fail4;
+       } else if (rc > 0) {
+               /*
+                * In future may want to add backwards compatibility
+                * and accept certain subsets of previous versions
+                */
+               EPRINTK("Xen netback accelerator version mismatch\n");
+               goto fail4;
+       } 
+
+       return 0;
+
+ fail4:
+       mutex_lock(&accel_mutex);
+       list_del(&port->link);
+       mutex_unlock(&accel_mutex);
+
+       efx_dl_unregister_callbacks(efx_dl_dev, &bend_dl_callbacks);
+ fail3: 
+       netback_accel_shutdown_fwd_port(port->fwd_priv);
+ fail2:
+       efx_dl_dev->priv = NULL;
+       kfree(port);
+ fail1:
+       return rc;
+}
+
+
+static void bend_dl_remove(struct efx_dl_device *efx_dl_dev)
+{
+       struct driverlink_port *port;
+
+       DPRINTK("Unregistering driverlink callbacks.\n");
+
+       mutex_lock(&accel_mutex);
+
+       port = (struct driverlink_port *)efx_dl_dev->priv;
+
+       BUG_ON(list_empty(&dl_ports));
+       BUG_ON(port == NULL);
+       BUG_ON(port->efx_dl_dev != efx_dl_dev);
+
+       netback_disconnect_accelerator(0, port->net_dev->name);
+
+       list_del(&port->link);
+
+       mutex_unlock(&accel_mutex);
+
+       efx_dl_unregister_callbacks(efx_dl_dev, &bend_dl_callbacks);
+       netback_accel_shutdown_fwd_port(port->fwd_priv);
+
+       efx_dl_dev->priv = NULL;
+       kfree(port);
+
+       return;
+}
+
+
+static struct efx_dl_driver bend_dl_driver = 
+       {
+               .name = "SFC Xen backend",
+               .probe = bend_dl_probe,
+               .remove = bend_dl_remove,
+       };
+
+
+int netback_accel_sf_init(void)
+{
+       int rc, nic_i;
+       struct efhw_nic *nic;
+
+       INIT_LIST_HEAD(&dl_ports);
+
+       rc = efx_dl_register_driver(&bend_dl_driver);
+       /* If we couldn't find the NET driver, give up */
+       if (rc == -ENOENT)
+               return rc;
+       
+       if (rc == 0) {
+               EFRM_FOR_EACH_NIC(nic_i, nic)
+                       falcon_nic_set_rx_usr_buf_size(nic, 
+                                                      SF_XEN_RX_USR_BUF_SIZE);
+       }
+
+       init_done = (rc == 0);
+       return rc;
+}
+
+
+void netback_accel_sf_shutdown(void)
+{
+       if (!init_done)
+               return;
+       DPRINTK("Unregistering driverlink driver\n");
+
+       /*
+        * This will trigger removal callbacks for all the devices, which
+        * will unregister their callbacks, disconnect from netfront, etc.
+        */
+       efx_dl_unregister_driver(&bend_dl_driver);
+}
+
+
+int netback_accel_sf_hwtype(struct netback_accel *bend)
+{
+       struct driverlink_port *port;
+
+       mutex_lock(&accel_mutex);
+
+       list_for_each_entry(port, &dl_ports, link) {
+               if (strcmp(bend->nicname, port->net_dev->name) == 0) {
+                       bend->hw_type = port->type;
+                       bend->accel_setup = netback_accel_setup_vnic_hw;
+                       bend->accel_shutdown = netback_accel_shutdown_vnic_hw;
+                       bend->fwd_priv = port->fwd_priv;
+                       /* This is just needed to pass to efx_vi_alloc */
+                       bend->nic_index = port->nic_index;
+                       bend->net_dev = port->net_dev;
+                       mutex_unlock(&accel_mutex);
+                       return 0;
+               }
+       }
+
+       mutex_unlock(&accel_mutex);
+
+       EPRINTK("Failed to identify backend device '%s' with a NIC\n",
+               bend->nicname);
+
+       return -ENOENT;
+}
+
+
+/****************************************************************************
+ * Resource management code
+ ***************************************************************************/
+
+static int alloc_page_state(struct netback_accel *bend, int max_pages)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv;
+
+       if (max_pages < 0 || max_pages > bend->quotas.max_buf_pages) {
+               EPRINTK("%s: invalid max_pages: %d\n", __FUNCTION__, max_pages);
+               return -EINVAL;
+       }
+
+       accel_hw_priv = kzalloc(sizeof(struct falcon_bend_accel_priv),
+                               GFP_KERNEL);
+       if (accel_hw_priv == NULL) {
+               EPRINTK("%s: no memory for accel_hw_priv\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       accel_hw_priv->dma_maps = kzalloc
+               (sizeof(struct efx_vi_dma_map_state **) * 
+                (max_pages / NET_ACCEL_MSG_MAX_PAGE_REQ), GFP_KERNEL);
+       if (accel_hw_priv->dma_maps == NULL) {
+               EPRINTK("%s: no memory for dma_maps\n", __FUNCTION__);
+               kfree(accel_hw_priv);
+               return -ENOMEM;
+       }
+
+       bend->buffer_maps = kzalloc(sizeof(struct vm_struct *) * max_pages, 
+                                   GFP_KERNEL);
+       if (bend->buffer_maps == NULL) {
+               EPRINTK("%s: no memory for buffer_maps\n", __FUNCTION__);
+               kfree(accel_hw_priv->dma_maps);
+               kfree(accel_hw_priv);
+               return -ENOMEM;
+       }
+
+       bend->buffer_addrs = kzalloc(sizeof(u64) * max_pages, GFP_KERNEL);
+       if (bend->buffer_addrs == NULL) {
+               kfree(bend->buffer_maps);
+               kfree(accel_hw_priv->dma_maps);
+               kfree(accel_hw_priv);
+               return -ENOMEM;
+       }
+
+       bend->accel_hw_priv = accel_hw_priv;
+
+       return 0;
+}
+
+
+static int free_page_state(struct netback_accel *bend)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv;
+
+       DPRINTK("%s: %p\n", __FUNCTION__, bend);
+
+       accel_hw_priv = bend->accel_hw_priv;
+
+       if (accel_hw_priv) {
+               kfree(accel_hw_priv->dma_maps);
+               kfree(bend->buffer_maps);
+               kfree(bend->buffer_addrs);
+               kfree(accel_hw_priv);
+               bend->accel_hw_priv = NULL;
+               bend->max_pages = 0;
+       }
+
+       return 0;
+}
+
+
+/* The timeout event callback for the event q */
+static void bend_evq_timeout(void *context, int is_timeout)
+{
+       struct netback_accel *bend = (struct netback_accel *)context;
+       if (is_timeout) {
+               /* Pass event to vnic front end driver */
+               VPRINTK("timeout event to %d\n", bend->net_channel);
+               NETBACK_ACCEL_STATS_OP(bend->stats.evq_timeouts++);
+               notify_remote_via_irq(bend->net_channel_irq);
+       } else {
+               /* It's a wakeup event, used by Falcon */
+               VPRINTK("wakeup to %d\n", bend->net_channel);
+               NETBACK_ACCEL_STATS_OP(bend->stats.evq_wakeups++);
+               notify_remote_via_irq(bend->net_channel_irq);
+       }
+}
+
+
+/*
+ * Create the eventq and associated gubbins for communication with the
+ * front end vnic driver
+ */
+static int ef_get_vnic(struct netback_accel *bend)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv;
+       int rc = 0;
+
+       BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_NONE);
+
+       /* Allocate page related state and accel_hw_priv */
+       rc = alloc_page_state(bend, bend->max_pages);
+       if (rc != 0) {
+               EPRINTK("Failed to allocate page state: %d\n", rc);
+               return rc;
+       }
+
+       accel_hw_priv = bend->accel_hw_priv;
+
+       rc = efx_vi_alloc(&accel_hw_priv->efx_vih, bend->nic_index);
+       if (rc != 0) {
+               EPRINTK("%s: efx_vi_alloc failed %d\n", __FUNCTION__, rc);
+               free_page_state(bend);
+               return rc;
+       }
+
+       rc = efx_vi_eventq_register_callback(accel_hw_priv->efx_vih,
+                                            bend_evq_timeout,
+                                            bend);
+       if (rc != 0) {
+               EPRINTK("%s: register_callback failed %d\n", __FUNCTION__, rc);
+               efx_vi_free(accel_hw_priv->efx_vih);
+               free_page_state(bend);
+               return rc;
+       }
+
+       bend->hw_state = NETBACK_ACCEL_RES_ALLOC;
+       
+       return 0;
+}
+
+
+static void ef_free_vnic(struct netback_accel *bend)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+
+       BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_ALLOC);
+
+       efx_vi_eventq_kill_callback(accel_hw_priv->efx_vih);
+
+       DPRINTK("Hardware is freeable. Will proceed.\n");
+
+       efx_vi_free(accel_hw_priv->efx_vih);
+       accel_hw_priv->efx_vih = NULL;
+
+       VPRINTK("Free page state...\n");
+       free_page_state(bend);
+
+       bend->hw_state = NETBACK_ACCEL_RES_NONE;
+}
+
+
+static inline void ungrant_or_crash(grant_ref_t gntref, int domain) {
+       if (net_accel_ungrant_page(gntref) == -EBUSY)
+               net_accel_shutdown_remote(domain);
+}
+
+
+static void netback_accel_release_hwinfo(struct netback_accel *bend)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       int i;
+
+       DPRINTK("Remove dma q grants %d %d\n", accel_hw_priv->txdmaq_gnt,
+               accel_hw_priv->rxdmaq_gnt);
+       ungrant_or_crash(accel_hw_priv->txdmaq_gnt, bend->far_end);
+       ungrant_or_crash(accel_hw_priv->rxdmaq_gnt, bend->far_end);
+
+       DPRINTK("Remove doorbell grant %d\n", accel_hw_priv->doorbell_gnt);
+       ungrant_or_crash(accel_hw_priv->doorbell_gnt, bend->far_end);
+
+       if (bend->hw_type == NET_ACCEL_MSG_HWTYPE_FALCON_A) {
+               DPRINTK("Remove rptr grant %d\n", accel_hw_priv->evq_rptr_gnt);
+               ungrant_or_crash(accel_hw_priv->evq_rptr_gnt, bend->far_end);
+       }
+
+       for (i = 0; i < accel_hw_priv->evq_npages; i++) {
+               DPRINTK("Remove evq grant %d\n", 
accel_hw_priv->evq_mem_gnts[i]);
+               ungrant_or_crash(accel_hw_priv->evq_mem_gnts[i], bend->far_end);
+       }
+
+       bend->hw_state = NETBACK_ACCEL_RES_FILTER;
+
+       return;
+}
+
+
+static int ef_bend_hwinfo_falcon_common(struct netback_accel *bend, 
+                                       struct net_accel_hw_falcon_b *hwinfo)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       struct efx_vi_hw_resource_metadata res_mdata;
+       struct efx_vi_hw_resource res_array[EFX_VI_HW_RESOURCE_MAXSIZE];
+       int rc, len = EFX_VI_HW_RESOURCE_MAXSIZE, i, pfn = 0;
+       unsigned long txdmaq_pfn = 0, rxdmaq_pfn = 0;
+
+       rc = efx_vi_hw_resource_get_phys(accel_hw_priv->efx_vih, &res_mdata,
+                                        res_array, &len);
+       if (rc != 0) {
+               DPRINTK("%s: resource_get_phys returned %d\n",
+                       __FUNCTION__, rc);
+               return rc;
+       }
+
+       if (res_mdata.version != 0)
+               return -EPROTO;
+
+       hwinfo->nic_arch = res_mdata.nic_arch;
+       hwinfo->nic_variant = res_mdata.nic_variant;
+       hwinfo->nic_revision = res_mdata.nic_revision;
+
+       hwinfo->evq_order = res_mdata.evq_order;
+       hwinfo->evq_offs = res_mdata.evq_offs;
+       hwinfo->evq_capacity = res_mdata.evq_capacity;
+       hwinfo->instance = res_mdata.instance;
+       hwinfo->rx_capacity = res_mdata.rx_capacity;
+       hwinfo->tx_capacity = res_mdata.tx_capacity;
+
+       VPRINTK("evq_order %d evq_offs %d evq_cap %d inst %d rx_cap %d tx_cap 
%d\n",
+               hwinfo->evq_order, hwinfo->evq_offs, hwinfo->evq_capacity,
+               hwinfo->instance, hwinfo->rx_capacity, hwinfo->tx_capacity);
+
+       for (i = 0; i < len; i++) {
+               struct efx_vi_hw_resource *res = &(res_array[i]);
+               switch (res->type) {
+               case EFX_VI_HW_RESOURCE_TXDMAQ:
+                       txdmaq_pfn = page_to_pfn(virt_to_page(res->address));
+                       break;
+               case EFX_VI_HW_RESOURCE_RXDMAQ: 
+                       rxdmaq_pfn = page_to_pfn(virt_to_page(res->address));
+                       break;
+               case EFX_VI_HW_RESOURCE_EVQTIMER:
+                       break;
+               case EFX_VI_HW_RESOURCE_EVQRPTR:
+               case EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET:
+                       hwinfo->evq_rptr = res->address;
+                       break;
+               case EFX_VI_HW_RESOURCE_EVQMEMKVA: 
+                       accel_hw_priv->evq_npages =  1 << res_mdata.evq_order;
+                       pfn = page_to_pfn(virt_to_page(res->address));
+                       break;
+               case EFX_VI_HW_RESOURCE_BELLPAGE:
+                       hwinfo->doorbell_mfn  = res->address;
+                       break;
+               default:
+                       EPRINTK("%s: Unknown hardware resource type %d\n",
+                               __FUNCTION__, res->type);
+                       break;
+               }
+       }
+
+       VPRINTK("Passing txdmaq page pfn %lx\n", txdmaq_pfn);
+       accel_hw_priv->txdmaq_gnt = hwinfo->txdmaq_gnt = 
+               net_accel_grant_page(bend->hdev_data, pfn_to_mfn(txdmaq_pfn), 
+                                    0);
+
+       VPRINTK("Passing rxdmaq page pfn %lx\n", rxdmaq_pfn);
+       accel_hw_priv->rxdmaq_gnt = hwinfo->rxdmaq_gnt = 
+               net_accel_grant_page(bend->hdev_data, pfn_to_mfn(rxdmaq_pfn), 
+                                    0);
+
+       VPRINTK("Passing doorbell page mfn %x\n", hwinfo->doorbell_mfn);
+       /* Make the relevant H/W pages mappable by the far end */
+       accel_hw_priv->doorbell_gnt = hwinfo->doorbell_gnt = 
+               net_accel_grant_page(bend->hdev_data, hwinfo->doorbell_mfn, 1);
+       
+       /* Now do the same for the memory pages */
+       /* Convert the page + length we got back for the evq to grants. */
+       for (i = 0; i < accel_hw_priv->evq_npages; i++) {
+               accel_hw_priv->evq_mem_gnts[i] = hwinfo->evq_mem_gnts[i] =
+                       net_accel_grant_page(bend->hdev_data, pfn_to_mfn(pfn), 
0);
+               VPRINTK("Got grant %u for evq pfn %x\n", 
hwinfo->evq_mem_gnts[i], 
+                       pfn);
+               pfn++;
+       }
+
+       return 0;
+}
+
+
+static int ef_bend_hwinfo_falcon_a(struct netback_accel *bend, 
+                                  struct net_accel_hw_falcon_a *hwinfo)
+{
+       int rc;
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+
+       if ((rc = ef_bend_hwinfo_falcon_common(bend, &hwinfo->common)) != 0)
+               return rc;
+
+       /*
+        * Note that unlike the above, where the message field is the
+        * page number, here evq_rptr is the entire address because
+        * it is currently a pointer into the densely mapped timer page.
+        */
+       VPRINTK("Passing evq_rptr pfn %x for rptr %x\n", 
+               hwinfo->common.evq_rptr >> PAGE_SHIFT,
+               hwinfo->common.evq_rptr);
+       rc = net_accel_grant_page(bend->hdev_data, 
+                                 hwinfo->common.evq_rptr >> PAGE_SHIFT, 0);
+       if (rc < 0)
+               return rc;
+
+       accel_hw_priv->evq_rptr_gnt = hwinfo->evq_rptr_gnt = rc;
+       VPRINTK("evq_rptr_gnt got %d\n", hwinfo->evq_rptr_gnt);
+       
+       return 0;
+}
+
+
+static int ef_bend_hwinfo_falcon_b(struct netback_accel *bend, 
+                                  struct net_accel_hw_falcon_b *hwinfo)
+{
+       return ef_bend_hwinfo_falcon_common(bend, hwinfo);
+}
+
+
+/*
+ * Fill in the message with a description of the hardware resources, based on
+ * the H/W type
+ */
+static int netback_accel_hwinfo(struct netback_accel *bend, 
+                               struct net_accel_msg_hw *msgvi)
+{
+       int rc = 0;
+       
+       BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_FILTER);
+
+       msgvi->type = bend->hw_type;
+       switch (bend->hw_type) {
+       case NET_ACCEL_MSG_HWTYPE_FALCON_A:
+               rc = ef_bend_hwinfo_falcon_a(bend, &msgvi->resources.falcon_a);
+               break;
+       case NET_ACCEL_MSG_HWTYPE_FALCON_B:
+               rc = ef_bend_hwinfo_falcon_b(bend, &msgvi->resources.falcon_b);
+               break;
+       case NET_ACCEL_MSG_HWTYPE_NONE:
+               /* Nothing to do. The slow path should just work. */
+               break;
+       }
+
+       if (rc == 0)
+               bend->hw_state = NETBACK_ACCEL_RES_HWINFO;
+               
+       return rc;
+}
+
+
+/* Allocate hardware resources and make them available to the client domain */
+int netback_accel_setup_vnic_hw(struct netback_accel *bend)
+{
+       struct net_accel_msg msg;
+       int err;
+
+       /* Allocate the event queue, VI and so on. */
+       err = ef_get_vnic(bend);
+       if (err) {
+               EPRINTK("Failed to allocate hardware resource for bend:"
+                       "error %d\n", err);
+               return err;
+       }
+
+       /* Set up the filter management */
+       err = netback_accel_filter_init(bend);
+       if (err) {
+               EPRINTK("Filter setup failed, error %d", err);
+               ef_free_vnic(bend);
+               return err;
+       }
+
+       net_accel_msg_init(&msg, NET_ACCEL_MSG_SETHW);
+
+       /*
+        * Extract the low-level hardware info we will actually pass to the
+        * other end, and set up the grants/ioremap permissions needed
+        */
+       err = netback_accel_hwinfo(bend, &msg.u.hw);
+
+       if (err != 0) {
+               netback_accel_filter_shutdown(bend);
+               ef_free_vnic(bend);
+               return err;
+       }
+
+       /* Send the message, this is a reply to a hello-reply */
+       err = net_accel_msg_reply_notify(bend->shared_page, 
+                                        bend->msg_channel_irq, 
+                                        &bend->to_domU, &msg);
+
+       /*
+        * The message should succeed as it's logically a reply and we
+        * guarantee space for replies, but a misbehaving frontend
+        * could result in that behaviour, so be tolerant
+        */
+       if (err != 0) {
+               netback_accel_release_hwinfo(bend);
+               netback_accel_filter_shutdown(bend);
+               ef_free_vnic(bend);
+       }
+
+       return err;
+}
+
+
+/* Free hardware resources  */
+void netback_accel_shutdown_vnic_hw(struct netback_accel *bend)
+{
+       /*
+        * Only try and release resources if accel_hw_priv was setup,
+        * otherwise there is nothing to do as we're on "null-op"
+        * acceleration
+        */
+       switch (bend->hw_state) {
+       case NETBACK_ACCEL_RES_HWINFO:
+               VPRINTK("Release hardware resources\n");
+               netback_accel_release_hwinfo(bend);
+               /* deliberate drop through */
+       case NETBACK_ACCEL_RES_FILTER:          
+               VPRINTK("Free filters...\n");
+               netback_accel_filter_shutdown(bend);
+               /* deliberate drop through */
+       case NETBACK_ACCEL_RES_ALLOC:
+               VPRINTK("Free vnic...\n");
+               ef_free_vnic(bend);
+               /* deliberate drop through */
+       case NETBACK_ACCEL_RES_NONE:
+               break;
+       default:
+               BUG();
+       }
+}
+
+/**************************************************************************
+ * 
+ * Buffer table stuff
+ *
+ **************************************************************************/
+
+/*
+ * Undo any allocation that netback_accel_msg_rx_buffer_map() has made
+ * if it fails half way through
+ */
+static inline void buffer_map_cleanup(struct netback_accel *bend, int i)
+{
+       while (i > 0) {
+               i--;
+               bend->buffer_maps_index--;
+               net_accel_unmap_device_page(bend->hdev_data, 
+                                           
bend->buffer_maps[bend->buffer_maps_index],
+                                           
bend->buffer_addrs[bend->buffer_maps_index]);
+       }
+}
+
+
+int netback_accel_add_buffers(struct netback_accel *bend, int pages, int 
log2_pages,
+                             u32 *grants, u32 *buf_addr_out)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       unsigned long long addr_array[NET_ACCEL_MSG_MAX_PAGE_REQ];
+       int rc, i, index;
+       u64 dev_bus_addr;
+
+       /* Make sure we can't overflow the dma_maps array */
+       if (accel_hw_priv->dma_maps_index >= 
+           bend->max_pages / NET_ACCEL_MSG_MAX_PAGE_REQ) {
+               EPRINTK("%s: too many buffer table allocations: %d %d\n",
+                       __FUNCTION__, accel_hw_priv->dma_maps_index, 
+                       bend->max_pages / NET_ACCEL_MSG_MAX_PAGE_REQ);
+               return -EINVAL;
+       }
+
+       /* Make sure we can't overflow the buffer_maps array */
+       if (bend->buffer_maps_index + pages > bend->max_pages) {
+               EPRINTK("%s: too many pages mapped: %d + %d > %d\n", 
+                       __FUNCTION__, bend->buffer_maps_index,
+                       pages, bend->max_pages);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pages; i++) {
+               VPRINTK("%s: mapping page %d\n", __FUNCTION__, i);
+               rc = net_accel_map_device_page
+                       (bend->hdev_data, grants[i],
+                        &bend->buffer_maps[bend->buffer_maps_index],
+                        &dev_bus_addr);
+    
+               if (rc != 0) {
+                       EPRINTK("error in net_accel_map_device_page\n");
+                       buffer_map_cleanup(bend, i);
+                       return rc;
+               }
+               
+               bend->buffer_addrs[bend->buffer_maps_index] = dev_bus_addr;
+
+               bend->buffer_maps_index++;
+
+               addr_array[i] = dev_bus_addr;
+       }
+
+       VPRINTK("%s: mapping dma addresses to vih %p\n", __FUNCTION__, 
+               accel_hw_priv->efx_vih);
+
+       index = accel_hw_priv->dma_maps_index;
+       if ((rc = efx_vi_dma_map_addrs(accel_hw_priv->efx_vih, addr_array, 
pages,
+                                      &(accel_hw_priv->dma_maps[index]))) < 0) 
{
+               EPRINTK("error in dma_map_pages\n");
+               buffer_map_cleanup(bend, i);
+               return rc;
+       }
+
+       accel_hw_priv->dma_maps_index++;
+       NETBACK_ACCEL_STATS_OP(bend->stats.num_buffer_pages += pages);
+
+       //DPRINTK("%s: getting map address\n", __FUNCTION__);
+
+       *buf_addr_out = efx_vi_dma_get_map_addr(accel_hw_priv->efx_vih, 
+                                               accel_hw_priv->dma_maps[index]);
+
+       //DPRINTK("%s: done\n", __FUNCTION__);
+
+       return 0;
+}
+
+
+int netback_accel_remove_buffers(struct netback_accel *bend)
+{
+       /* Only try to free buffers if accel_hw_priv was setup */
+       if (bend->hw_state != NETBACK_ACCEL_RES_NONE) {
+               struct falcon_bend_accel_priv *accel_hw_priv = 
bend->accel_hw_priv;
+               int i;
+
+               efx_vi_reset(accel_hw_priv->efx_vih);
+
+               while (accel_hw_priv->dma_maps_index > 0) {
+                       accel_hw_priv->dma_maps_index--;
+                       i = accel_hw_priv->dma_maps_index;
+                       efx_vi_dma_unmap_addrs(accel_hw_priv->efx_vih, 
+                                              accel_hw_priv->dma_maps[i]);
+               }
+               
+               while (bend->buffer_maps_index > 0) {
+                       VPRINTK("Unmapping granted buffer %d\n", 
+                               bend->buffer_maps_index);
+                       bend->buffer_maps_index--;
+                       i = bend->buffer_maps_index;
+                       net_accel_unmap_device_page(bend->hdev_data, 
+                                                   bend->buffer_maps[i],
+                                                   bend->buffer_addrs[i]);
+               }
+
+               NETBACK_ACCEL_STATS_OP(bend->stats.num_buffer_pages = 0);
+       }
+
+       return 0;
+}
+
+/**************************************************************************
+ * 
+ * Filter stuff
+ *
+ **************************************************************************/
+
+static int netback_accel_filter_init(struct netback_accel *bend)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       int i, rc;
+
+       BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_ALLOC);
+
+       spin_lock_init(&accel_hw_priv->filter_lock);
+
+       if ((rc = cuckoo_hash_init(&accel_hw_priv->filter_hash_table, 
+                                  5 /* space for 32 filters */, 8)) != 0) {
+               EPRINTK("Failed to initialise filter hash table\n");
+               return rc;
+       }
+
+       accel_hw_priv->fspecs = kzalloc(sizeof(struct 
netback_accel_filter_spec) *
+                                       bend->quotas.max_filters,
+                                       GFP_KERNEL);
+
+       if (accel_hw_priv->fspecs == NULL) {
+               EPRINTK("No memory for filter specs.\n");
+               cuckoo_hash_destroy(&accel_hw_priv->filter_hash_table);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < bend->quotas.max_filters; i++) {
+               accel_hw_priv->free_filters |= (1 << i);
+       }
+
+       /* Base mask on highest set bit in max_filters  */
+       accel_hw_priv->filter_idx_mask = (1 << fls(bend->quotas.max_filters)) - 
1;
+       VPRINTK("filter setup: max is %x mask is %x\n",
+               bend->quotas.max_filters, accel_hw_priv->filter_idx_mask);
+
+       bend->hw_state = NETBACK_ACCEL_RES_FILTER;
+
+       return 0;
+}
+
+
+static inline void make_filter_key(cuckoo_hash_ip_key *key,  
+                                  struct netback_accel_filter_spec *filt)
+
+{
+       key->local_ip = filt->destip_be;
+       key->local_port = filt->destport_be;
+       key->proto = filt->proto;
+}
+
+
+static inline 
+void netback_accel_free_filter(struct falcon_bend_accel_priv *accel_hw_priv,
+                              int filter)
+{
+       cuckoo_hash_ip_key filter_key;
+
+       if (!(accel_hw_priv->free_filters & (1 << filter))) {
+               efx_vi_filter_stop(accel_hw_priv->efx_vih, 
+                                  accel_hw_priv->fspecs[filter].filter_handle);
+               make_filter_key(&filter_key, &(accel_hw_priv->fspecs[filter]));
+               if (cuckoo_hash_remove(&accel_hw_priv->filter_hash_table,
+                                      (cuckoo_hash_key *)&filter_key)) {
+                       EPRINTK("%s: Couldn't find filter to remove from 
table\n",
+                               __FUNCTION__);
+                       BUG();
+               }
+       }
+}
+
+
+static void netback_accel_filter_shutdown(struct netback_accel *bend)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       int i;
+       unsigned long flags;
+
+       BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_FILTER);
+
+       spin_lock_irqsave(&accel_hw_priv->filter_lock, flags);
+
+       BUG_ON(accel_hw_priv->fspecs == NULL);
+
+       for (i = 0; i < bend->quotas.max_filters; i++) {
+               netback_accel_free_filter(accel_hw_priv, i);
+       }
+       
+       kfree(accel_hw_priv->fspecs);
+       accel_hw_priv->fspecs = NULL;
+       accel_hw_priv->free_filters = 0;
+       
+       cuckoo_hash_destroy(&accel_hw_priv->filter_hash_table);
+
+       spin_unlock_irqrestore(&accel_hw_priv->filter_lock, flags);
+
+       bend->hw_state = NETBACK_ACCEL_RES_ALLOC;
+}
+
+
+/*! Suggest a filter to replace when we want to insert a new one and have
+ *  none free.
+ */
+static unsigned get_victim_filter(struct netback_accel *bend)
+{
+       /*
+        * We could attempt to get really clever, and may do at some
+        * point, but random replacement is v. cheap and low on
+        * pathological worst cases.
+        */
+       unsigned index, cycles;
+
+       rdtscl(cycles);
+
+       /*
+        * Some doubt about the quality of the bottom few bits, so
+        * throw 'em * away
+        */
+       index = (cycles >> 4) & ((struct falcon_bend_accel_priv *)
+                                bend->accel_hw_priv)->filter_idx_mask;
+       /*
+        * We don't enforce that the number of filters is a power of
+        * two, but the masking gets us to within one subtraction of a
+        * valid index
+        */
+       if (index >= bend->quotas.max_filters)
+               index -= bend->quotas.max_filters;
+       DPRINTK("backend %s->%d has no free filters. Filter %d will be 
evicted\n",
+               bend->nicname, bend->far_end, index);
+       return index;
+}
+
+
+/* Add a filter for the specified IP/port to the backend */
+int 
+netback_accel_filter_check_add(struct netback_accel *bend, 
+                              struct netback_accel_filter_spec *filt)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       struct netback_accel_filter_spec *fs;
+       unsigned filter_index;
+       unsigned long flags;
+       int rc, recycling = 0;
+       cuckoo_hash_ip_key filter_key, evict_key;
+
+       BUG_ON(filt->proto != IPPROTO_TCP && filt->proto != IPPROTO_UDP);
+
+       DPRINTK("Will add %s filter for dst ip %08x and dst port %d\n", 
+               (filt->proto == IPPROTO_TCP) ? "TCP" : "UDP",
+               be32_to_cpu(filt->destip_be), be16_to_cpu(filt->destport_be));
+
+       spin_lock_irqsave(&accel_hw_priv->filter_lock, flags);
+       /*
+        * Check to see if we're already filtering this IP address and
+        * port. Happens if you insert a filter mid-stream as there
+        * are many packets backed up to be delivered to dom0 already
+        */
+       make_filter_key(&filter_key, filt);
+       if (cuckoo_hash_lookup(&accel_hw_priv->filter_hash_table, 
+                              (cuckoo_hash_key *)(&filter_key), 
+                              &filter_index)) {
+               DPRINTK("Found matching filter %d already in table\n", 
+                       filter_index);
+               rc = -1;
+               goto out;
+       }
+
+       if (accel_hw_priv->free_filters == 0) {
+               filter_index = get_victim_filter(bend);
+               recycling = 1;
+       } else {
+               filter_index = __ffs(accel_hw_priv->free_filters);
+               clear_bit(filter_index, &accel_hw_priv->free_filters);
+       }
+
+       fs = &accel_hw_priv->fspecs[filter_index];
+
+       if (recycling) {
+               DPRINTK("Removing filter index %d handle %p\n", filter_index,
+                       fs->filter_handle);
+
+               if ((rc = efx_vi_filter_stop(accel_hw_priv->efx_vih, 
+                                            fs->filter_handle)) != 0) {
+                       EPRINTK("Couldn't clear NIC filter table entry %d\n", 
rc);
+               }
+
+               make_filter_key(&evict_key, fs);
+               if (cuckoo_hash_remove(&accel_hw_priv->filter_hash_table,
+                                      (cuckoo_hash_key *)&evict_key)) {
+                       EPRINTK("Couldn't find filter to remove from table\n");
+                       BUG();
+               }
+               NETBACK_ACCEL_STATS_OP(bend->stats.num_filters--);
+       }
+
+       /* Update the filter spec with new details */
+       *fs = *filt;
+
+       if ((rc = cuckoo_hash_add(&accel_hw_priv->filter_hash_table, 
+                                 (cuckoo_hash_key *)&filter_key, filter_index,
+                                 1)) != 0) {
+               EPRINTK("Error (%d) adding filter to table\n", rc);
+               accel_hw_priv->free_filters |= (1 << filter_index);
+               goto out;
+       }
+
+       rc = efx_vi_filter(accel_hw_priv->efx_vih, filt->proto, filt->destip_be,
+                          filt->destport_be, 
+                          (struct filter_resource_t **)&fs->filter_handle);
+
+       if (rc != 0) {
+               EPRINTK("Hardware filter insertion failed. Error %d\n", rc);
+               accel_hw_priv->free_filters |= (1 << filter_index);
+               cuckoo_hash_remove(&accel_hw_priv->filter_hash_table, 
+                                  (cuckoo_hash_key *)&filter_key);
+               rc = -1;
+               goto out;
+       }
+
+       NETBACK_ACCEL_STATS_OP(bend->stats.num_filters++);
+
+       VPRINTK("%s: success index %d handle %p\n", __FUNCTION__, filter_index, 
+               fs->filter_handle);
+
+       rc = filter_index;
+ out:
+       spin_unlock_irqrestore(&accel_hw_priv->filter_lock, flags);
+       return rc;
+}
+
+
+/* Remove a filter entry for the specific device and IP/port */
+static void netback_accel_filter_remove(struct netback_accel *bend, 
+                                       int filter_index)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+
+       BUG_ON(accel_hw_priv->free_filters & (1 << filter_index));
+       netback_accel_free_filter(accel_hw_priv, filter_index);
+       accel_hw_priv->free_filters |= (1 << filter_index);
+}
+
+
+/* Remove a filter entry for the specific device and IP/port */
+void netback_accel_filter_remove_spec(struct netback_accel *bend, 
+                                     struct netback_accel_filter_spec *filt)
+{
+       struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
+       unsigned filter_found;
+       unsigned long flags;
+       cuckoo_hash_ip_key filter_key;
+       struct netback_accel_filter_spec *fs;
+
+       if (filt->proto == IPPROTO_TCP) {
+               DPRINTK("Remove TCP filter for dst ip %08x and dst port %d\n",
+                       be32_to_cpu(filt->destip_be),
+                       be16_to_cpu(filt->destport_be));
+       } else if (filt->proto == IPPROTO_UDP) {
+               DPRINTK("Remove UDP filter for dst ip %08x and dst port %d\n",
+                       be32_to_cpu(filt->destip_be),
+                       be16_to_cpu(filt->destport_be));
+       } else {
+               /*
+                * This could be provoked by an evil frontend, so can't
+                * BUG(), but harmless as it should fail tests below 
+                */
+               DPRINTK("Non-TCP/UDP filter dst ip %08x and dst port %d\n",
+                       be32_to_cpu(filt->destip_be),
+                       be16_to_cpu(filt->destport_be));
+       }
+
+       spin_lock_irqsave(&accel_hw_priv->filter_lock, flags);
+
+       make_filter_key(&filter_key, filt);
+       if (!cuckoo_hash_lookup(&accel_hw_priv->filter_hash_table, 
+                              (cuckoo_hash_key *)(&filter_key), 
+                              &filter_found)) {
+               EPRINTK("Couldn't find matching filter already in table\n");
+               goto out;
+       }
+       
+       /* Do a full check to make sure we've not had a hash collision */
+       fs = &accel_hw_priv->fspecs[filter_found];
+       if (fs->destip_be == filt->destip_be &&
+           fs->destport_be == filt->destport_be &&
+           fs->proto == filt->proto &&
+           !memcmp(fs->mac, filt->mac, ETH_ALEN)) {
+               netback_accel_filter_remove(bend, filter_found);
+       } else {
+               EPRINTK("Entry in hash table does not match filter spec\n");
+               goto out;
+       }
+
+ out:
+       spin_unlock_irqrestore(&accel_hw_priv->filter_lock, flags);
+}
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel_solarflare.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel_solarflare.h        Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef NETBACK_ACCEL_SOLARFLARE_H
+#define NETBACK_ACCEL_SOLARFLARE_H
+
+#include "accel.h"
+#include "accel_msg_iface.h"
+
+#include "driverlink_api.h"
+
+#define MAX_NICS 5
+#define MAX_PORTS 2
+
+
+extern int netback_accel_sf_init(void);
+extern void netback_accel_sf_shutdown(void);
+extern int netback_accel_sf_hwtype(struct netback_accel *bend);
+
+extern int netback_accel_sf_char_init(void);
+extern void netback_accel_sf_char_shutdown(void);
+
+extern int netback_accel_setup_vnic_hw(struct netback_accel *bend);
+extern void netback_accel_shutdown_vnic_hw(struct netback_accel *bend);
+
+extern int netback_accel_add_buffers(struct netback_accel *bend, int pages, 
+                                    int log2_pages, u32 *grants,
+                                    u32 *buf_addr_out);
+extern int netback_accel_remove_buffers(struct netback_accel *bend);
+
+
+/* Add a filter for the specified IP/port to the backend */
+extern int
+netback_accel_filter_check_add(struct netback_accel *bend, 
+                              struct netback_accel_filter_spec *filt);
+/* Remove a filter entry for the specific device and IP/port */
+extern
+void netback_accel_filter_remove_index(struct netback_accel *bend, 
+                                      int filter_index);
+extern
+void netback_accel_filter_remove_spec(struct netback_accel *bend, 
+                                     struct netback_accel_filter_spec *filt);
+
+/* This is designed to look a bit like a skb */
+struct netback_pkt_buf {
+       union {
+               unsigned char *raw;
+       } mac;
+       union {
+               struct iphdr  *iph;
+               struct arphdr *arph;
+               unsigned char *raw;
+       } nh;
+       int protocol;
+};
+
+/*! \brief Handle a received packet: insert fast path filters as necessary
+ * \param skb The packet buffer
+ */
+extern void netback_accel_rx_packet(struct netback_pkt_buf *skb, void 
*fwd_priv);
+
+/*! \brief Handle a transmitted packet: update fast path filters as necessary
+ * \param skb The packet buffer
+ */
+extern void netback_accel_tx_packet(struct sk_buff *skb, void *fwd_priv);
+
+#endif /* NETBACK_ACCEL_SOLARFLARE_H */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/accel_xenbus.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/accel_xenbus.c    Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,831 @@
+/****************************************************************************
+ * Solarflare driver for Xen network acceleration
+ *
+ * Copyright 2006-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#include <xen/evtchn.h>
+#include <linux/mutex.h>
+
+/* drivers/xen/netback/common.h */
+#include "common.h"
+
+#include "accel.h"
+#include "accel_solarflare.h"
+#include "accel_util.h"
+
+#define NODENAME_PATH_FMT "backend/vif/%d/%d"
+
+#define NETBACK_ACCEL_FROM_XENBUS_DEVICE(_dev) (struct netback_accel *) \
+       ((struct backend_info *)(_dev)->dev.driver_data)->netback_accel_priv
+
+/* List of all the bends currently in existence. */
+struct netback_accel *bend_list = NULL;
+DEFINE_MUTEX(bend_list_mutex);
+
+/* Put in bend_list.  Must hold bend_list_mutex */
+static void link_bend(struct netback_accel *bend)
+{
+       bend->next_bend = bend_list;
+       bend_list = bend;
+}
+
+/* Remove from bend_list,  Must hold bend_list_mutex */
+static void unlink_bend(struct netback_accel *bend)
+{
+       struct netback_accel *tmp = bend_list;
+       struct netback_accel *prev = NULL;
+       while (tmp != NULL) {
+               if (tmp == bend) {
+                       if (prev != NULL)
+                               prev->next_bend = bend->next_bend;
+                       else
+                               bend_list = bend->next_bend;
+                       return;
+               }
+               prev = tmp;
+               tmp = tmp->next_bend;
+       }
+}
+
+
+/* Demultiplex a message IRQ from the frontend driver.  */
+static irqreturn_t msgirq_from_frontend(int irq, void *context, 
+                                    struct pt_regs *unused)
+{
+       struct xenbus_device *dev = context;
+       struct netback_accel *bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev);
+       VPRINTK("irq %d from device %s\n", irq, dev->nodename);
+       schedule_work(&bend->handle_msg);
+       return IRQ_HANDLED;
+}
+
+
+/*
+ * Demultiplex an IRQ from the frontend driver.  This is never used
+ * functionally, but we need it to pass to the bind function, and may
+ * get called spuriously
+ */
+static irqreturn_t netirq_from_frontend(int irq, void *context, 
+                                       struct pt_regs *unused)
+{
+       VPRINTK("netirq %d from device %s\n", irq,
+               ((struct xenbus_device *)context)->nodename);
+       
+       return IRQ_HANDLED;
+}
+
+
+/* Read the limits values of the xenbus structure. */
+static 
+void cfg_hw_quotas(struct xenbus_device *dev, struct netback_accel *bend)
+{
+       int err = xenbus_gather
+               (XBT_NIL, dev->nodename,
+                "limits/max-filters", "%d", &bend->quotas.max_filters,
+                "limits/max-buf-pages", "%d", &bend->quotas.max_buf_pages,
+                "limits/max-mcasts", "%d", &bend->quotas.max_mcasts,
+                NULL);
+       if (err) {
+               /*
+                * TODO what if they have previously been set by the
+                * user?  This will overwrite with defaults.  Maybe
+                * not what we want to do, but useful in startup
+                * case 
+                */
+               DPRINTK("Failed to read quotas from xenbus, using defaults\n");
+               bend->quotas.max_filters = NETBACK_ACCEL_DEFAULT_MAX_FILTERS;
+               bend->quotas.max_buf_pages = max_pages;
+               bend->quotas.max_mcasts = NETBACK_ACCEL_DEFAULT_MAX_MCASTS;
+       }
+
+       return;
+}
+
+
+static void bend_config_accel_change(struct xenbus_watch *watch,
+                                    const char **vec, unsigned int len)
+{
+       struct netback_accel *bend;
+
+       bend = container_of(watch, struct netback_accel, config_accel_watch);
+
+       mutex_lock(&bend->bend_mutex);
+       if (bend->config_accel_watch.node != NULL) {
+               struct xenbus_device *dev = 
+                       (struct xenbus_device *)bend->hdev_data;
+               DPRINTK("Watch matched, got dev %p otherend %p\n",
+                       dev, dev->otherend);
+               if(!xenbus_exists(XBT_NIL, watch->node, "")) {
+                       DPRINTK("Ignoring watch as otherend seems invalid\n");
+                       goto out;
+               }
+               
+               cfg_hw_quotas(dev, bend);
+       }
+ out:
+       mutex_unlock(&bend->bend_mutex);
+       return;
+}
+
+
+/*
+ * Setup watch on "limits" in the backend vif info to know when
+ * configuration has been set
+ */
+static int setup_config_accel_watch(struct xenbus_device *dev,
+                                   struct netback_accel *bend)
+{
+       int err;
+
+       VPRINTK("Setting watch on %s/%s\n", dev->nodename, "limits");
+
+       err = xenbus_watch_path2(dev, dev->nodename, "limits", 
+                                &bend->config_accel_watch, 
+                                bend_config_accel_change);
+
+       if (err) {
+               EPRINTK("%s: Failed to register xenbus watch: %d\n",
+                       __FUNCTION__, err);
+               bend->config_accel_watch.node = NULL;
+               return err;
+       }
+       return 0;
+}
+
+
+static int 
+cfg_frontend_info(struct xenbus_device *dev, struct netback_accel *bend,
+                 int *grants)
+{
+       /* Get some info from xenbus on the event channel and shmem grant */
+       int err = xenbus_gather(XBT_NIL, dev->otherend, 
+                               "accel-msg-channel", "%u", &bend->msg_channel, 
+                               "accel-ctrl-page", "%d", &(grants[0]),
+                               "accel-msg-page", "%d", &(grants[1]),
+                               "accel-net-channel", "%u", &bend->net_channel,
+                               NULL);
+       if (err)
+               EPRINTK("failed to read event channels or shmem grant: %d\n",
+                       err);
+       else
+               DPRINTK("got event chan %d and net chan %d from frontend\n",
+                       bend->msg_channel, bend->net_channel);
+       return err;
+}
+
+
+/* Setup all the comms needed to chat with the front end driver */
+static int setup_vnic(struct xenbus_device *dev)
+{
+       struct netback_accel *bend;
+       int grants[2], err, msgs_per_queue;
+
+       bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev);
+
+       err = cfg_frontend_info(dev, bend, grants);
+       if (err)
+               goto fail1;
+
+       /*
+        * If we get here, both frontend Connected and configuration
+        * options available.  All is well.
+        */
+
+       /* Get the hardware quotas for the VNIC in question.  */
+       cfg_hw_quotas(dev, bend);
+
+       /* Set up the deferred work handlers */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+       INIT_WORK(&bend->handle_msg, 
+                 netback_accel_msg_rx_handler);
+#else
+       INIT_WORK(&bend->handle_msg, 
+                 netback_accel_msg_rx_handler,
+                 (void*)bend);
+#endif
+
+       /* Request the frontend mac */
+       err = net_accel_xen_net_read_mac(dev, bend->mac);
+       if (err)
+               goto fail2;
+
+       /* Set up the shared page. */
+       bend->shared_page = net_accel_map_grants_contig(dev, grants, 2, 
+                                                       &bend->sh_pages_unmap);
+
+       if (bend->shared_page == NULL) {
+               EPRINTK("failed to map shared page for %s\n", dev->otherend);
+               err = -ENOMEM;
+               goto fail2;
+       }
+
+       /* Initialise the shared page(s) used for comms */
+       net_accel_msg_init_page(bend->shared_page, PAGE_SIZE, 
+                               bend->net_dev->flags & IFF_UP);
+
+       msgs_per_queue = (PAGE_SIZE/2) / sizeof(struct net_accel_msg);
+
+       net_accel_msg_init_queue
+               (&bend->to_domU, &bend->shared_page->queue0,
+                (struct net_accel_msg *)((__u8*)bend->shared_page + PAGE_SIZE),
+                msgs_per_queue);
+
+       net_accel_msg_init_queue
+               (&bend->from_domU, &bend->shared_page->queue1, 
+                (struct net_accel_msg *)((__u8*)bend->shared_page + 
+                                         (3 * PAGE_SIZE / 2)),
+                msgs_per_queue);
+
+       /* Bind the message event channel to a handler
+        *
+        * Note that we will probably get a spurious interrupt when we
+        * do this, so it must not be done until we have set up
+        * everything we need to handle it.
+        */
+       err = bind_interdomain_evtchn_to_irqhandler(dev->otherend_id,
+                                                   bend->msg_channel,
+                                                   msgirq_from_frontend,
+                                                   0,
+                                                   "netback_accel",
+                                                   dev);
+       if (err < 0) {
+               EPRINTK("failed to bind event channel: %d\n", err);
+               goto fail3;
+       }
+       else
+               bend->msg_channel_irq = err;
+
+       /* TODO: No need to bind this evtchn to an irq. */
+       err = bind_interdomain_evtchn_to_irqhandler(dev->otherend_id,
+                                                   bend->net_channel,
+                                                   netirq_from_frontend,
+                                                   0,
+                                                   "netback_accel",
+                                                   dev);
+       if (err < 0) {
+               EPRINTK("failed to bind net channel: %d\n", err);
+               goto fail4;
+       }  
+       else
+               bend->net_channel_irq = err;
+
+       /*
+        * Grab ourselves an entry in the forwarding hash table. We do
+        * this now so we don't have the embarassmesnt of sorting out
+        * an allocation failure while at IRQ. Because we pass NULL as
+        * the context, the actual hash lookup will succeed for this
+        * NIC, but the check for somewhere to forward to will
+        * fail. This is necessary to prevent forwarding before
+        * hardware resources are set up
+        */
+       err = netback_accel_fwd_add(bend->mac, NULL, bend->fwd_priv);
+       if (err) {
+               EPRINTK("failed to add to fwd hash table\n");
+               goto fail5;
+       }
+
+       /*
+        * Say hello to frontend.  Important to do this straight after
+        * obtaining the message queue as otherwise we are vulnerable
+        * to an evil frontend sending a HELLO-REPLY before we've sent
+        * the HELLO and confusing us
+        */
+       netback_accel_msg_tx_hello(bend, NET_ACCEL_MSG_VERSION);
+       return 0;
+
+ fail5:
+       unbind_from_irqhandler(bend->net_channel_irq, dev);
+ fail4:
+       unbind_from_irqhandler(bend->msg_channel_irq, dev);
+ fail3:
+       net_accel_unmap_grants_contig(dev, bend->sh_pages_unmap);
+       bend->shared_page = NULL;
+       bend->sh_pages_unmap = NULL;
+ fail2:
+ fail1:
+       return err;
+}
+
+
+static int read_nicname(struct xenbus_device *dev, struct netback_accel *bend)
+{
+       int len;
+
+       /* nic name used to select interface used for acceleration */
+       bend->nicname = xenbus_read(XBT_NIL, dev->nodename, "accel", &len);
+       if (IS_ERR(bend->nicname))
+               return PTR_ERR(bend->nicname);
+
+       return 0;
+}
+
+static const char *frontend_name = "sfc_netfront";
+
+static int publish_frontend_name(struct xenbus_device *dev)
+{
+       struct xenbus_transaction tr;
+       int err;
+       
+       /* Publish the name of the frontend driver */
+       do {
+               err = xenbus_transaction_start(&tr);
+               if (err != 0) { 
+                       EPRINTK("%s: transaction start failed\n", __FUNCTION__);
+                       return err;
+               }
+               err = xenbus_printf(tr, dev->nodename, "accel-frontend", 
+                                   "%s", frontend_name);
+               if (err != 0) {
+                       EPRINTK("%s: xenbus_printf failed\n", __FUNCTION__);
+                       xenbus_transaction_end(tr, 1);
+                       return err;
+               }
+               err = xenbus_transaction_end(tr, 0);
+       } while (err == -EAGAIN);
+       
+       if (err != 0) {
+               EPRINTK("failed to end frontend name transaction\n");
+               return err;
+       }
+       return 0;
+}
+
+
+static int unpublish_frontend_name(struct xenbus_device *dev)
+{
+       struct xenbus_transaction tr;
+       int err;
+
+       do {
+               err = xenbus_transaction_start(&tr);
+               if (err != 0)
+                       break;
+               err = xenbus_rm(tr, dev->nodename, "accel-frontend");
+               if (err != 0) {
+                       xenbus_transaction_end(tr, 1);
+                       break;
+               }
+               err = xenbus_transaction_end(tr, 0);
+       } while (err == -EAGAIN);
+
+       return err;
+}
+
+
+static void cleanup_vnic(struct netback_accel *bend)
+{
+       struct xenbus_device *dev;
+
+       dev = (struct xenbus_device *)bend->hdev_data;
+
+       DPRINTK("%s: bend %p dev %p\n", __FUNCTION__, bend, dev);
+
+       DPRINTK("%s: Remove %p's mac from fwd table...\n", 
+               __FUNCTION__, bend);
+       netback_accel_fwd_remove(bend->mac, bend->fwd_priv);
+
+       /* Free buffer table allocations */
+       netback_accel_remove_buffers(bend);
+
+       DPRINTK("%s: Release hardware resources...\n", __FUNCTION__);
+       if (bend->accel_shutdown)
+               bend->accel_shutdown(bend);
+
+       if (bend->net_channel_irq) {
+               unbind_from_irqhandler(bend->net_channel_irq, dev);
+               bend->net_channel_irq = 0;
+       }
+
+       if (bend->msg_channel_irq) {
+               unbind_from_irqhandler(bend->msg_channel_irq, dev);
+               bend->msg_channel_irq = 0;
+       }
+
+       if (bend->sh_pages_unmap) {
+               DPRINTK("%s: Unmap grants %p\n", __FUNCTION__, 
+                       bend->sh_pages_unmap);
+               net_accel_unmap_grants_contig(dev, bend->sh_pages_unmap);
+               bend->sh_pages_unmap = NULL;
+               bend->shared_page = NULL;
+       }
+}
+
+
+/*************************************************************************/
+
+/*
+ * The following code handles accelstate changes between the frontend
+ * and the backend.  It calls setup_vnic and cleanup_vnic in matching
+ * pairs in response to transitions.
+ *
+ * Valid state transitions for Dom0 are as follows:
+ *
+ * Closed->Init       on probe or in response to Init from domU
+ * Closed->Closing    on error/remove
+ *
+ * Init->Connected    in response to Connected from domU
+ * Init->Closing      on error/remove or in response to Closing from domU
+ *
+ * Connected->Closing on error/remove or in response to Closing from domU
+ *
+ * Closing->Closed    in response to Closed from domU
+ *
+ */
+
+
+static void netback_accel_frontend_changed(struct xenbus_device *dev,
+                                          XenbusState frontend_state)
+{
+       struct netback_accel *bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev);
+       XenbusState backend_state;
+
+       DPRINTK("%s: changing from %s to %s. nodename %s, otherend %s\n",
+               __FUNCTION__, xenbus_strstate(bend->frontend_state),
+               xenbus_strstate(frontend_state),dev->nodename, dev->otherend);
+
+       /*
+        * Ignore duplicate state changes.  This can happen if the
+        * frontend changes state twice in quick succession and the
+        * first watch fires in the backend after the second
+        * transition has completed.
+        */
+       if (bend->frontend_state == frontend_state)
+               return;
+
+       bend->frontend_state = frontend_state;
+       backend_state = bend->backend_state;
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               if (backend_state == XenbusStateClosed &&
+                   !bend->removing)
+                       backend_state = XenbusStateInitialising;
+               break;
+
+       case XenbusStateConnected:
+               if (backend_state == XenbusStateInitialising) {
+                       if (!bend->vnic_is_setup &&
+                           setup_vnic(dev) == 0) {
+                               bend->vnic_is_setup = 1;
+                               backend_state = XenbusStateConnected;
+                       } else {
+                               backend_state = XenbusStateClosing;
+                       }
+               }
+               break;
+
+       case XenbusStateInitWait:
+       case XenbusStateInitialised:
+       default:
+               DPRINTK("Unknown state %s (%d) from frontend.\n",
+                       xenbus_strstate(frontend_state), frontend_state);
+               /* Unknown state.  Fall through. */
+       case XenbusStateClosing:
+               if (backend_state != XenbusStateClosed)
+                       backend_state = XenbusStateClosing;
+
+               /*
+                * The bend will now persist (with watches active) in
+                * case the frontend comes back again, eg. after
+                * frontend module reload or suspend/resume
+                */
+
+               break;
+
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               if (bend->vnic_is_setup) {
+                       bend->vnic_is_setup = 0;
+                       cleanup_vnic(bend);
+               }
+
+               if (backend_state == XenbusStateClosing)
+                       backend_state = XenbusStateClosed;
+               break;
+       }
+
+       if (backend_state != bend->backend_state) {
+               DPRINTK("Switching from state %s (%d) to %s (%d)\n",
+                       xenbus_strstate(bend->backend_state),
+                       bend->backend_state,
+                       xenbus_strstate(backend_state), backend_state);
+               bend->backend_state = backend_state;
+               net_accel_update_state(dev, backend_state);
+       }
+
+       wake_up(&bend->state_wait_queue);
+}
+
+
+/* accelstate on the frontend's xenbus node has changed */
+static void bend_domu_accel_change(struct xenbus_watch *watch,
+                                  const char **vec, unsigned int len)
+{
+       int state;
+       struct netback_accel *bend;
+
+       bend = container_of(watch, struct netback_accel, domu_accel_watch);
+       if (bend->domu_accel_watch.node != NULL) {
+               struct xenbus_device *dev = 
+                       (struct xenbus_device *)bend->hdev_data;
+               VPRINTK("Watch matched, got dev %p otherend %p\n",
+                       dev, dev->otherend);
+               /*
+                * dev->otherend != NULL check to protect against
+                * watch firing when domain goes away and we haven't
+                * yet cleaned up
+                */
+               if (!dev->otherend ||
+                   !xenbus_exists(XBT_NIL, watch->node, "") ||
+                   strncmp(dev->otherend, vec[XS_WATCH_PATH],
+                           strlen(dev->otherend))) {
+                       DPRINTK("Ignoring watch as otherend seems invalid\n");
+                       return;
+               }
+
+               mutex_lock(&bend->bend_mutex);
+
+               xenbus_scanf(XBT_NIL, dev->otherend, "accelstate", "%d", 
+                            &state);
+               netback_accel_frontend_changed(dev, state);
+
+               mutex_unlock(&bend->bend_mutex);
+       }
+}
+
+/* Setup watch on frontend's accelstate */
+static int setup_domu_accel_watch(struct xenbus_device *dev,
+                                 struct netback_accel *bend)
+{
+       int err;
+
+       VPRINTK("Setting watch on %s/%s\n", dev->otherend, "accelstate");
+
+       err = xenbus_watch_path2(dev, dev->otherend, "accelstate", 
+                                &bend->domu_accel_watch, 
+                                bend_domu_accel_change);
+       if (err) {
+               EPRINTK("%s: Failed to register xenbus watch: %d\n",
+                       __FUNCTION__, err);
+               goto fail;
+       }
+       return 0;
+ fail:
+       bend->domu_accel_watch.node = NULL;
+       return err;
+}
+
+
+int netback_accel_probe(struct xenbus_device *dev)
+{
+       struct netback_accel *bend;
+       struct backend_info *binfo;
+       int err;
+
+       DPRINTK("%s: passed device %s\n", __FUNCTION__, dev->nodename);
+
+       /* Allocate structure to store all our state... */
+       bend = kzalloc(sizeof(struct netback_accel), GFP_KERNEL);
+       if (bend == NULL) {
+               DPRINTK("%s: no memory for bend\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+       
+       mutex_init(&bend->bend_mutex);
+
+       mutex_lock(&bend->bend_mutex);
+
+       /* ...and store it where we can get at it */
+       binfo = (struct backend_info *) dev->dev.driver_data;
+       binfo->netback_accel_priv = bend;
+       /* And vice-versa */
+       bend->hdev_data = dev;
+
+       DPRINTK("%s: Adding bend %p to list\n", __FUNCTION__, bend);
+       
+       init_waitqueue_head(&bend->state_wait_queue);
+       bend->vnic_is_setup = 0;
+       bend->frontend_state = XenbusStateUnknown;
+       bend->backend_state = XenbusStateClosed;
+       bend->removing = 0;
+
+       sscanf(dev->nodename, NODENAME_PATH_FMT, &bend->far_end, 
+              &bend->vif_num);
+
+       err = read_nicname(dev, bend);
+       if (err) {
+               /*
+                * Technically not an error, just means we're not 
+                * supposed to accelerate this
+                */
+               DPRINTK("failed to get device name\n");
+               goto fail_nicname;
+       }
+
+       /*
+        * Look up the device name in the list of NICs provided by
+        * driverlink to get the hardware type.
+        */
+       err = netback_accel_sf_hwtype(bend);
+       if (err) {
+               /*
+                * Technically not an error, just means we're not
+                * supposed to accelerate this, probably belongs to
+                * some other backend
+                */
+               DPRINTK("failed to match device name\n");
+               goto fail_init_type;
+       }
+
+       err = publish_frontend_name(dev);
+       if (err)
+               goto fail_publish;
+
+       err = netback_accel_debugfs_create(bend);
+       if (err)
+               goto fail_debugfs;
+       
+       mutex_unlock(&bend->bend_mutex);
+
+       err = setup_config_accel_watch(dev, bend);
+       if (err)
+               goto fail_config_watch;
+
+       err = setup_domu_accel_watch(dev, bend);
+       if (err)
+               goto fail_domu_watch;
+
+       /*
+        * Indicate to the other end that we're ready to start unless
+        * the watch has already fired.
+        */
+       mutex_lock(&bend->bend_mutex);
+       if (bend->backend_state == XenbusStateClosed) {
+               bend->backend_state = XenbusStateInitialising;
+               net_accel_update_state(dev, XenbusStateInitialising);
+       }
+       mutex_unlock(&bend->bend_mutex);
+
+       mutex_lock(&bend_list_mutex);
+       link_bend(bend);
+       mutex_unlock(&bend_list_mutex);
+
+       return 0;
+
+fail_domu_watch:
+
+       unregister_xenbus_watch(&bend->config_accel_watch);
+       kfree(bend->config_accel_watch.node);
+fail_config_watch:
+
+       /*
+        * Flush the scheduled work queue before freeing bend to get
+        * rid of any pending netback_accel_msg_rx_handler()
+        */
+       flush_scheduled_work();
+
+       mutex_lock(&bend->bend_mutex);
+       net_accel_update_state(dev, XenbusStateUnknown);
+       netback_accel_debugfs_remove(bend);
+fail_debugfs:
+
+       unpublish_frontend_name(dev);
+fail_publish:
+
+       /* No need to reverse netback_accel_sf_hwtype. */
+fail_init_type:
+
+       kfree(bend->nicname);
+fail_nicname:
+       binfo->netback_accel_priv = NULL;
+       mutex_unlock(&bend->bend_mutex);
+       kfree(bend);
+       return err;
+}
+
+
+int netback_accel_remove(struct xenbus_device *dev)
+{
+       struct backend_info *binfo;
+       struct netback_accel *bend; 
+       int frontend_state;
+
+       binfo = (struct backend_info *) dev->dev.driver_data;
+       bend = (struct netback_accel *) binfo->netback_accel_priv;
+
+       DPRINTK("%s: dev %p bend %p\n", __FUNCTION__, dev, bend);
+       
+       BUG_ON(bend == NULL);
+       
+       mutex_lock(&bend_list_mutex);
+       unlink_bend(bend);
+       mutex_unlock(&bend_list_mutex);
+
+       mutex_lock(&bend->bend_mutex);
+
+       /* Reject any requests to connect. */
+       bend->removing = 1;
+
+       /*
+        * Switch to closing to tell the other end that we're going
+        * away.
+        */
+       if (bend->backend_state != XenbusStateClosing) {
+               bend->backend_state = XenbusStateClosing;
+               net_accel_update_state(dev, XenbusStateClosing);
+       }
+
+       frontend_state = (int)XenbusStateUnknown;
+       xenbus_scanf(XBT_NIL, dev->otherend, "accelstate", "%d",
+                    &frontend_state);
+
+       mutex_unlock(&bend->bend_mutex);
+
+       /*
+        * Wait until this end goes to the closed state.  This happens
+        * in response to the other end going to the closed state.
+        * Don't bother doing this if the other end is already closed
+        * because if it is then there is nothing to do.
+        */
+       if (frontend_state != (int)XenbusStateClosed &&
+           frontend_state != (int)XenbusStateUnknown)
+               wait_event(bend->state_wait_queue,
+                          bend->backend_state == XenbusStateClosed);
+
+       unregister_xenbus_watch(&bend->domu_accel_watch);
+       kfree(bend->domu_accel_watch.node);
+
+       unregister_xenbus_watch(&bend->config_accel_watch);
+       kfree(bend->config_accel_watch.node);
+
+       /*
+        * Flush the scheduled work queue before freeing bend to get
+        * rid of any pending netback_accel_msg_rx_handler()
+        */
+       flush_scheduled_work();
+
+       mutex_lock(&bend->bend_mutex);
+
+       /* Tear down the vnic if it was set up. */
+       if (bend->vnic_is_setup) {
+               bend->vnic_is_setup = 0;
+               cleanup_vnic(bend);
+       }
+
+       bend->backend_state = XenbusStateUnknown;
+       net_accel_update_state(dev, XenbusStateUnknown);
+
+       netback_accel_debugfs_remove(bend);
+
+       unpublish_frontend_name(dev);
+
+       kfree(bend->nicname);
+
+       binfo->netback_accel_priv = NULL;
+
+       mutex_unlock(&bend->bend_mutex);
+
+       kfree(bend);
+
+       return 0;
+}
+
+
+void netback_accel_shutdown_bends(void)
+{
+       mutex_lock(&bend_list_mutex);
+       /*
+        * I think we should have had a remove callback for all
+        * interfaces before being allowed to unload the module
+        */
+       BUG_ON(bend_list != NULL);
+       mutex_unlock(&bend_list_mutex);
+}
+
+
+void netback_accel_set_closing(struct netback_accel *bend) 
+{
+
+       bend->backend_state = XenbusStateClosing;
+       net_accel_update_state((struct xenbus_device *)bend->hdev_data,
+                              XenbusStateClosing);
+}
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat.h       Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,53 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*
+ * \author  djr
+ *  \brief  Compatability layer.  Provides definitions of fundamental
+ *          types and definitions that are used throughout CI source
+ *          code.  It does not introduce any link time dependencies,
+ *          or include any unnecessary system headers.
+ */
+/*! \cidoxg_include_ci */
+
+#ifndef __CI_COMPAT_H__
+#define __CI_COMPAT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ci/compat/primitive.h>
+#include <ci/compat/sysdep.h>
+#include <ci/compat/utils.h>
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* __CI_COMPAT_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat/gcc.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/gcc.h   Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,158 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_compat  */
+
+#ifndef __CI_COMPAT_GCC_H__
+#define __CI_COMPAT_GCC_H__
+
+
+#define CI_HAVE_INT64
+
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+# include <linux/types.h>
+
+typedef __u64                 ci_uint64;
+typedef __s64                 ci_int64;
+# if BITS_PER_LONG == 32
+typedef __s32                 ci_ptr_arith_t;
+typedef __u32                 ci_uintptr_t;
+# else
+typedef __s64                 ci_ptr_arith_t;
+typedef __u64                 ci_uintptr_t;
+# endif
+
+
+/* it's not obvious to me why the below is wrong for x64_64, but
+ * gcc seems to complain on this platform
+ */
+# if defined(__ia64__)
+#  define CI_PRId64            "ld"
+#  define CI_PRIi64            "li"
+#  define CI_PRIo64            "lo"
+#  define CI_PRIu64            "lu"
+#  define CI_PRIx64            "lx"
+#  define CI_PRIX64            "lX"
+# else
+#  define CI_PRId64            "lld"
+#  define CI_PRIi64            "lli"
+#  define CI_PRIo64            "llo"
+#  define CI_PRIu64            "llu"
+#  define CI_PRIx64            "llx"
+#  define CI_PRIX64            "llX"
+# endif
+
+# define CI_PRId32            "d"
+# define CI_PRIi32            "i"
+# define CI_PRIo32            "o"
+# define CI_PRIu32            "u"
+# define CI_PRIx32            "x"
+# define CI_PRIX32            "X"
+
+#else
+
+# include <stdint.h>
+# include <inttypes.h>
+
+typedef uint64_t              ci_uint64;
+typedef int64_t               ci_int64;
+typedef intptr_t              ci_ptr_arith_t;
+typedef uintptr_t             ci_uintptr_t;
+
+# define CI_PRId64            PRId64
+# define CI_PRIi64            PRIi64
+# define CI_PRIo64            PRIo64
+# define CI_PRIu64            PRIu64
+# define CI_PRIx64            PRIx64
+# define CI_PRIX64            PRIX64
+
+# define CI_PRId32            PRId32
+# define CI_PRIi32            PRIi32
+# define CI_PRIo32            PRIo32
+# define CI_PRIu32            PRIu32
+# define CI_PRIx32            PRIx32
+# define CI_PRIX32            PRIX32
+
+#endif
+
+
+typedef ci_uint64                       ci_fixed_descriptor_t;
+
+#define from_fixed_descriptor(desc) ((ci_uintptr_t)(desc))
+#define to_fixed_descriptor(desc) ((ci_fixed_descriptor_t)(ci_uintptr_t)(desc))
+
+
+#if __GNUC__ >= 3 && !defined(__cplusplus)
+/*
+** Checks that [p_mbr] has the same type as [&c_type::mbr_name].
+*/
+# define CI_CONTAINER(c_type, mbr_name, p_mbr)                         \
+   __builtin_choose_expr(                                              \
+     __builtin_types_compatible_p(__typeof__(&((c_type*)0)->mbr_name), \
+                                __typeof__(p_mbr)),                    \
+     __CI_CONTAINER(c_type, mbr_name, p_mbr), (void)0)
+
+# define ci_restrict  __restrict__
+#endif
+
+
+#if !defined(__KERNEL__) || defined(__unix__)
+#define CI_HAVE_NPRINTF  1
+#endif
+
+
+/* At what version was this introduced? */
+#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ > 91)
+# define CI_LIKELY(t)    __builtin_expect((t), 1)
+# define CI_UNLIKELY(t)  __builtin_expect((t), 0)
+#endif
+
+/**********************************************************************
+ * Attributes
+ */
+#if __GNUC__ >= 3 && defined(NDEBUG)
+# define CI_HF __attribute__((visibility("hidden")))
+# define CI_HV __attribute__((visibility("hidden")))
+#else
+# define CI_HF
+# define CI_HV
+#endif
+
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+# define ci_noinline  static __attribute__((__noinline__))
+/* (Linux 2.6 defines its own "noinline", so we use the "__noinline__" form) */
+#else
+# define ci_noinline  static
+#endif
+
+#define CI_ALIGN(x) __attribute__ ((aligned (x)))
+
+#define CI_PRINTF_LIKE(a,b) __attribute__((format(printf,a,b)))
+
+#endif  /* __CI_COMPAT_GCC_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat/gcc_x86.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/gcc_x86.h       Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_compat  */
+
+#ifndef __CI_COMPAT_GCC_X86_H__
+#define __CI_COMPAT_GCC_X86_H__
+
+/*
+** The facts:
+**
+**   SSE   sfence
+**   SSE2  lfence, mfence, pause
+*/
+
+/* 
+   Barriers to enforce ordering with respect to:
+
+   normal memory use: ci_wmb, ci_rmb, ci_wmb
+   IO bus access use: ci_wiob, ci_riob, ci_iob
+*/
+#if defined(__x86_64__)
+# define ci_x86_mb() __asm__ __volatile__ ("lock; addl $0,0(%%rsp)":::"memory")
+#else
+# define ci_x86_mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)":::"memory")
+#endif
+
+/* ?? measure the impact of latency of sfence on a modern processor before we
+   take a decision on how to integrate with respect to writecombining */
+
+/* DJR: I don't think we need to add "memory" here.  It means the asm does
+** something to memory that GCC doesn't understand.  But all this does is
+** commit changes that GCC thinks have already happened.  NB. GCC will not
+** reorder across a __volatile__ __asm__ anyway.
+*/
+#define ci_gcc_fence()    __asm__ __volatile__ ("")
+
+#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+# define ci_x86_sfence()  __asm__ __volatile__ ("sfence")
+# define ci_x86_lfence()  __asm__ __volatile__ ("lfence")
+# define ci_x86_mfence()  __asm__ __volatile__ ("mfence")
+#else
+# define ci_x86_sfence()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xF8")
+# define ci_x86_lfence()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xE8")
+# define ci_x86_mfence()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xF0")
+#endif
+
+
+/* x86 processors to P4 Xeon store in-order unless executing streaming
+   extensions or when using writecombining 
+
+   Hence we do not define ci_wmb to use sfence by default. Requirement is that
+   we do not use writecombining to memory and any code which uses SSE
+   extensions must call sfence directly 
+
+   We need to track non intel clones which may support out of order store.
+
+*/
+
+#if CI_CPU_OOS
+# if CI_CPU_HAS_SSE
+#  define ci_wmb()     ci_x86_sfence()
+# else
+#  define ci_wmb()     ci_x86_mb()
+# endif
+#else
+# define ci_wmb()       ci_gcc_fence()
+#endif
+
+#if CI_CPU_HAS_SSE2
+# define ci_rmb()      ci_x86_lfence()
+# define ci_mb()       ci_x86_mfence()
+# define ci_riob()     ci_x86_lfence()
+# define ci_wiob()     ci_x86_sfence()
+# define ci_iob()      ci_x86_mfence()
+#else
+# if CI_CPU_HAS_SSE
+#  define ci_wiob()    ci_x86_sfence()
+# else
+#  define ci_wiob()    ci_x86_mb()
+# endif
+# define ci_rmb()      ci_x86_mb()
+# define ci_mb()       ci_x86_mb()
+# define ci_riob()     ci_x86_mb()
+# define ci_iob()      ci_x86_mb()
+#endif
+
+typedef unsigned long   ci_phys_addr_t;
+#define ci_phys_addr_fmt  "%lx"
+
+#endif  /* __CI_COMPAT_GCC_X86_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/compat/primitive.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/primitive.h     Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+/*! \cidoxg_include_ci_compat  */
+
+#ifndef __CI_COMPAT_PRIMITIVE_H__
+#define __CI_COMPAT_PRIMITIVE_H__
+
+
+/**********************************************************************
+ * Primitive types.
+ */
+
+typedef unsigned char                   ci_uint8;
+typedef char                            ci_int8;
+
+typedef unsigned short                  ci_uint16;
+typedef short                           ci_int16;
+
+typedef unsigned int                    ci_uint32;
+typedef int                             ci_int32;
+
+/* 64-bit support is platform dependent. */
+
+
+/**********************************************************************
+ * Other fancy types.
+ */
+
+typedef ci_uint8                        ci_octet;
+
+typedef enum {
+  CI_FALSE = 0,
+  CI_TRUE
+} ci_boolean_t;
+
+
+/**********************************************************************
+ * Some nice types you'd always assumed were standards.
+ * (Really, they are SYSV "standards".)
+ */
+
+#ifdef _WIN32
+typedef unsigned long                   ulong;              
+typedef unsigned int                    uint;
+typedef char*                           caddr_t;
+#elif defined(__linux__) && defined(__KERNEL__)
+#include <linux/types.h>
+#elif defined(__linux__)
+#include <sys/types.h>
+#endif
+
+
+#endif  /* __CI_COMPAT_PRIMITIVE_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat/sysdep.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/sysdep.h        Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_compat  */
+
+#ifndef __CI_COMPAT_SYSDEP_H__
+#define __CI_COMPAT_SYSDEP_H__
+
+
+/**********************************************************************
+ * Platform definition fixups.
+ */
+
+#if defined(__ci_ul_driver__) && !defined(__ci_driver__)
+# define __ci_driver__
+#endif
+
+#if defined(__ci_driver__) && !defined(__ci_ul_driver__) && \
+   !defined(__KERNEL__)
+# define __KERNEL__
+#endif
+
+
+/**********************************************************************
+ * Sanity checks (no cheating!)
+ */
+
+#if defined(__KERNEL__) && !defined(__ci_driver__)
+# error Insane.
+#endif
+
+#if defined(__KERNEL__) && defined(__ci_ul_driver__)
+# error Madness.
+#endif
+
+#if defined(__unix__) && defined(_WIN32)
+# error Strange.
+#endif
+
+#if defined(__GNUC__) && defined(_MSC_VER)
+# error Crazy.
+#endif
+
+
+/**********************************************************************
+ * Compiler and processor dependencies.
+ */
+
+#if defined(__GNUC__)
+
+# include <ci/compat/gcc.h>
+
+# if defined(__i386__)
+#  include <ci/compat/x86.h>
+#  include <ci/compat/gcc_x86.h>
+# elif defined(__x86_64__)
+#  include <ci/compat/x86_64.h>
+#  include <ci/compat/gcc_x86.h>
+# elif defined(__PPC__)
+#  include <ci/compat/ppc.h>
+#  include <ci/compat/gcc_ppc.h>
+# elif defined(__ia64__)
+#  include <ci/compat/ia64.h>
+#  include <ci/compat/gcc_ia64.h>
+# else
+#  error Unknown processor - GNU C
+# endif
+
+#elif defined(_MSC_VER)
+
+# include <ci/compat/msvc.h>
+
+# if defined(__i386__)
+#  include <ci/compat/x86.h>
+#  include <ci/compat/msvc_x86.h>
+# elif defined(__x86_64__)
+#  include <ci/compat/x86_64.h>
+#  include <ci/compat/msvc_x86_64.h>
+# else
+#  error Unknown processor MSC
+# endif
+
+#elif defined(__PGI)
+
+# include <ci/compat/x86.h>
+# include <ci/compat/pg_x86.h>
+
+#elif defined(__INTEL_COMPILER)
+
+/* Intel compilers v7 claim to be very gcc compatible. */
+# if __INTEL_COMPILER >= 700
+#  include <ci/compat/gcc.h>
+#  include <ci/compat/x86.h>
+#  include <ci/compat/gcc_x86.h>
+# else
+#  error Old Intel compiler not supported.  Yet.
+# endif
+
+#else
+# error Unknown compiler.
+#endif
+
+
+/**********************************************************************
+ * Misc stuff (that probably shouldn't be here).
+ */
+
+#ifdef __sun
+# ifdef __KERNEL__
+#  define _KERNEL
+#  define _SYSCALL32
+#  ifdef _LP64
+#   define _SYSCALL32_IMPL
+#  endif
+# else
+#  define _REENTRANT
+# endif
+#endif
+
+
+/**********************************************************************
+ * Defaults for anything left undefined.
+ */
+
+#ifndef  CI_LIKELY
+# define CI_LIKELY(t)    (t)
+# define CI_UNLIKELY(t)  (t)
+#endif
+
+#ifndef  ci_restrict
+# define ci_restrict
+#endif
+
+#ifndef  ci_inline
+# define ci_inline  static inline
+#endif
+
+#ifndef  ci_noinline
+# define ci_noinline  static
+#endif
+
+#endif  /* __CI_COMPAT_SYSDEP_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat/utils.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/utils.h Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,269 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*
+ * \author  djr
+ *  \brief  Handy utility macros.
+ *   \date  2003/01/17
+ */
+
+/*! \cidoxg_include_ci_compat  */
+
+#ifndef __CI_COMPAT_UTILS_H__
+#define __CI_COMPAT_UTILS_H__
+
+
+/**********************************************************************
+ * Alignment -- [align] must be a power of 2.
+ **********************************************************************/
+
+  /*! Align forward onto next boundary. */
+
+#define CI_ALIGN_FWD(p, align)               (((p)+(align)-1u) & ~((align)-1u))
+
+
+  /*! Align back onto prev boundary. */
+
+#define CI_ALIGN_BACK(p, align)              ((p) & ~((align)-1u))
+
+
+  /*! How far to next boundary? */
+
+#define CI_ALIGN_NEEDED(p, align, signed_t)  (-(signed_t)(p) & ((align)-1u))
+
+
+  /*! How far beyond prev boundary? */
+
+#define CI_OFFSET(p, align)                  ((p) & ((align)-1u))
+
+
+  /*! Does object fit in gap before next boundary? */
+
+#define CI_FITS(p, size, align, signed_t)                      \
+  (CI_ALIGN_NEEDED((p) + 1, (align), signed_t) + 1 >= (size))
+
+
+  /*! Align forward onto next boundary. */
+
+#define CI_PTR_ALIGN_FWD(p, align)                                        \
+  ((char*) CI_ALIGN_FWD(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align))))
+
+  /*! Align back onto prev boundary. */
+
+#define CI_PTR_ALIGN_BACK(p, align)                                        \
+  ((char*) CI_ALIGN_BACK(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align))))
+
+  /*! How far to next boundary? */
+
+#define CI_PTR_ALIGN_NEEDED(p, align)                                  \
+  CI_ALIGN_NEEDED(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align)),    \
+                 ci_ptr_arith_t)
+
+  /*! How far to next boundary? NZ = not zero i.e. give align if on boundary  
*/
+
+#define CI_PTR_ALIGN_NEEDED_NZ(p, align)                                       
\
+  ((align) - (((char*)p) -                                                     
 \
+  ((char*) CI_ALIGN_BACK(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align))))))
+
+  /*! How far beyond prev boundary? */
+
+#define CI_PTR_OFFSET(p, align)                                        \
+  CI_OFFSET(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align)))
+
+
+  /* Same as CI_ALIGN_FWD and CI_ALIGN_BACK. */
+
+#define CI_ROUND_UP(i, align)      (((i)+(align)-1u) & ~((align)-1u))
+
+#define CI_ROUND_DOWN(i, align)    ((i) & ~((align)-1u))
+
+
+/**********************************************************************
+ * Byte-order
+ **********************************************************************/
+
+/* These are not flags.  They are enumeration values for use with
+ * CI_MY_BYTE_ORDER. */
+#define CI_BIG_ENDIAN          1
+#define CI_LITTLE_ENDIAN       0
+
+/*
+** Note that these byte-swapping primitives may leave junk in bits above
+** the range they operate on.
+**
+** The CI_BSWAP_nn() routines require that bits above [nn] are zero.  Use
+** CI_BSWAPM_nn(x) if this cannot be guaranteed.
+*/
+
+/* ?? May be able to improve on some of these with inline assembler on some
+** platforms.
+*/
+
+#define CI_BSWAP_16(v)    ((((v) & 0xff) << 8) | ((v) >> 8))
+#define CI_BSWAPM_16(v)   ((((v) & 0xff) << 8) | (((v) & 0xff00) >> 8))
+
+#define CI_BSWAP_32(v)    (((v) >> 24)               |         \
+                          (((v) & 0x00ff0000) >> 8) |  \
+                          (((v) & 0x0000ff00) << 8) |  \
+                          ((v) << 24))
+#define CI_BSWAPM_32(v)   ((((v) & 0xff000000) >> 24) |        \
+                          (((v) & 0x00ff0000) >> 8)  | \
+                          (((v) & 0x0000ff00) << 8)  | \
+                          ((v) << 24))
+
+#define CI_BSWAP_64(v)    (((v) >> 56)                        |        \
+                          (((v) & 0x00ff000000000000) >> 40) | \
+                          (((v) & 0x0000ff0000000000) >> 24) | \
+                          (((v) & 0x000000ff00000000) >> 8)  | \
+                          (((v) & 0x00000000ff000000) << 8)  | \
+                          (((v) & 0x0000000000ff0000) << 24) | \
+                          (((v) & 0x000000000000ff00) << 40) | \
+                          ((v) << 56))
+
+# define CI_BSWAPPED_16_IF(c,v)  ((c) ? CI_BSWAP_16(v) : (v))
+# define CI_BSWAPPED_32_IF(c,v)  ((c) ? CI_BSWAP_32(v) : (v))
+# define CI_BSWAPPED_64_IF(c,v)  ((c) ? CI_BSWAP_64(v) : (v))
+# define CI_BSWAP_16_IF(c,v)     do{ if((c)) (v) = CI_BSWAP_16(v); }while(0)
+# define CI_BSWAP_32_IF(c,v)     do{ if((c)) (v) = CI_BSWAP_32(v); }while(0)
+# define CI_BSWAP_64_IF(c,v)     do{ if((c)) (v) = CI_BSWAP_64(v); }while(0)
+
+#if (CI_MY_BYTE_ORDER == CI_LITTLE_ENDIAN)
+# define CI_BSWAP_LE16(v)    (v)
+# define CI_BSWAP_LE32(v)    (v)
+# define CI_BSWAP_LE64(v)    (v)
+# define CI_BSWAP_BE16(v)    CI_BSWAP_16(v)
+# define CI_BSWAP_BE32(v)    CI_BSWAP_32(v)
+# define CI_BSWAP_BE64(v)    CI_BSWAP_64(v)
+# define CI_BSWAPM_LE16(v)   (v)
+# define CI_BSWAPM_LE32(v)   (v)
+# define CI_BSWAPM_LE64(v)   (v)
+# define CI_BSWAPM_BE16(v)   CI_BSWAPM_16(v)
+# define CI_BSWAPM_BE32(v)   CI_BSWAPM_32(v)
+#elif (CI_MY_BYTE_ORDER == CI_BIG_ENDIAN)
+# define CI_BSWAP_BE16(v)    (v)
+# define CI_BSWAP_BE32(v)    (v)
+# define CI_BSWAP_BE64(v)    (v)
+# define CI_BSWAP_LE16(v)    CI_BSWAP_16(v)
+# define CI_BSWAP_LE32(v)    CI_BSWAP_32(v)
+# define CI_BSWAP_LE64(v)    CI_BSWAP_64(v)
+# define CI_BSWAPM_BE16(v)   (v)
+# define CI_BSWAPM_BE32(v)   (v)
+# define CI_BSWAPM_BE64(v)   (v)
+# define CI_BSWAPM_LE16(v)   CI_BSWAPM_16(v)
+# define CI_BSWAPM_LE32(v)   CI_BSWAPM_32(v)
+#else
+# error Bad endian.
+#endif
+
+
+/**********************************************************************
+ * Get pointer to struct from pointer to member
+ **********************************************************************/
+
+#define CI_MEMBER_OFFSET(c_type, mbr_name)  \
+  ((ci_uint32) (ci_uintptr_t)(&((c_type*)0)->mbr_name))
+
+#define CI_MEMBER_SIZE(c_type, mbr_name)        \
+  sizeof(((c_type*)0)->mbr_name)
+
+#define __CI_CONTAINER(c_type, mbr_name, p_mbr)  \
+  ( (c_type*) ((char*)(p_mbr) - CI_MEMBER_OFFSET(c_type, mbr_name)) )
+
+#ifndef CI_CONTAINER
+# define CI_CONTAINER(t,m,p)  __CI_CONTAINER(t,m,p)
+#endif
+
+
+/**********************************************************************
+ * Structure member initialiser.
+ **********************************************************************/
+
+#ifndef CI_STRUCT_MBR
+# define CI_STRUCT_MBR(name, val)      .name = val
+#endif
+
+
+/**********************************************************************
+ * min / max
+ **********************************************************************/ 
+
+#define CI_MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define CI_MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+/**********************************************************************
+ * abs
+ **********************************************************************/ 
+
+#define CI_ABS(x) (((x) < 0) ? -(x) : (x))
+
+/**********************************************************************
+ * Conditional debugging
+ **********************************************************************/ 
+
+#ifdef NDEBUG
+# define CI_DEBUG(x)
+# define CI_NDEBUG(x)      x
+# define CI_IF_DEBUG(y,n)  (n)
+# define CI_DEBUG_ARG(x)
+#else
+# define CI_DEBUG(x)       x
+# define CI_NDEBUG(x)
+# define CI_IF_DEBUG(y,n)  (y)
+# define CI_DEBUG_ARG(x)   ,x
+#endif
+
+#ifdef __KERNEL__
+#define CI_KERNEL_ARG(x)   ,x
+#else
+#define CI_KERNEL_ARG(x)
+#endif
+
+#ifdef _WIN32
+# define CI_KERNEL_ARG_WIN(x) CI_KERNEL_ARG(x)
+# define CI_ARG_WIN(x) ,x
+#else
+# define CI_KERNEL_ARG_WIN(x)
+# define CI_ARG_WIN(x) 
+#endif
+
+#ifdef __unix__
+# define CI_KERNEL_ARG_UNIX(x) CI_KERNEL_ARG(x)
+# define CI_ARG_UNIX(x) ,x
+#else
+# define CI_KERNEL_ARG_UNIX(x)
+# define CI_ARG_UNIX(x) 
+#endif
+
+#ifdef __linux__
+# define CI_KERNEL_ARG_LINUX(x) CI_KERNEL_ARG(x)
+# define CI_ARG_LINUX(x) ,x
+#else
+# define CI_KERNEL_ARG_LINUX(x)
+# define CI_ARG_LINUX(x) 
+#endif
+
+
+#endif  /* __CI_COMPAT_UTILS_H__ */
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat/x86.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/x86.h   Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_compat  */
+
+#ifndef __CI_COMPAT_X86_H__
+#define __CI_COMPAT_X86_H__
+
+
+#define CI_MY_BYTE_ORDER   CI_LITTLE_ENDIAN
+
+#define CI_WORD_SIZE       4
+#define CI_PTR_SIZE        4
+
+#define CI_PAGE_SIZE       4096
+#define CI_PAGE_SHIFT      12
+#define CI_PAGE_MASK       (~(CI_PAGE_SIZE - 1))
+
+#define CI_CPU_HAS_SSE    1    /* SSE extensions supported */
+#define CI_CPU_HAS_SSE2           0    /* SSE2 extensions supported */
+#define CI_CPU_OOS        0    /* CPU does out of order stores */
+
+
+#endif  /* __CI_COMPAT_X86_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/compat/x86_64.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/compat/x86_64.h        Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,54 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*
+ * \author  djr
+ *  \brief  Arch stuff for AMD x86_64.
+ *   \date  2004/08/17
+ */
+
+/*! \cidoxg_include_ci_compat  */
+#ifndef __CI_COMPAT_X86_64_H__
+#define __CI_COMPAT_X86_64_H__
+
+
+#define CI_MY_BYTE_ORDER       CI_LITTLE_ENDIAN
+
+#define CI_WORD_SIZE           8
+#define CI_PTR_SIZE            8
+
+#define CI_PAGE_SIZE           4096
+#define CI_PAGE_SHIFT          12
+#define CI_PAGE_MASK           (~(CI_PAGE_SIZE - 1))
+
+#define CI_CPU_HAS_SSE         1       /* SSE extensions supported */
+
+/* SSE2 disabled while investigating BUG1060 */
+#define CI_CPU_HAS_SSE2                0       /* SSE2 extensions supported */
+#define CI_CPU_OOS             0       /* CPU does out of order stores */
+
+
+#endif  /* __CI_COMPAT_X86_64_H__ */
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h       Mon Feb 18 
10:31:04 2008 +0000
@@ -0,0 +1,276 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file contains public EFX VI API to Solarflare resource manager.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_DRIVER_RESOURCE_EFX_VI_H__
+#define __CI_DRIVER_RESOURCE_EFX_VI_H__
+
+/* Default size of event queue in the efx_vi resource.  Copied from
+ * CI_CFG_NETIF_EVENTQ_SIZE */
+#define EFX_VI_EVENTQ_SIZE_DEFAULT 1024
+
+extern int efx_vi_eventq_size;
+
+/**************************************************************************
+ * efx_vi_state types, allocation and free
+ **************************************************************************/
+
+/*! Handle for refering to a efx_vi */
+struct efx_vi_state;
+
+/*!
+ * Allocate an efx_vi, including event queue and pt_endpoint
+ *
+ * \param vih_out Pointer to a handle that is set on success
+ * \param nic_index Index of NIC to apply this resource to
+ * \return Zero on success (and vih_out set), non-zero on failure.
+ */
+extern int
+efx_vi_alloc(struct efx_vi_state **vih_out, int nic_index);
+
+/*!
+ * Free a previously allocated efx_vi
+ *
+ * \param vih The handle of the efx_vi to free
+ */
+extern void
+efx_vi_free(struct efx_vi_state *vih);
+
+/*!
+ * Reset a previously allocated efx_vi
+ *
+ * \param vih The handle of the efx_vi to reset
+ */
+extern void
+efx_vi_reset(struct efx_vi_state *vih);
+
+/**************************************************************************
+ * efx_vi_eventq types and functions
+ **************************************************************************/
+
+/*!
+ * Register a function to receive callbacks when event queue timeouts
+ * or wakeups occur.  Only one function per efx_vi can be registered
+ * at once.
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param callback The function to callback
+ * \param context An argument to pass to the callback function
+ * \return Zero on success, non-zero on failure.
+ */
+extern int
+efx_vi_eventq_register_callback(struct efx_vi_state *vih,
+                               void (*callback)(void *context, int is_timeout),
+                               void *context);
+
+/*!
+ * Remove the current eventq timeout or wakeup callback function
+ *
+ * \param vih The handle to identify the efx_vi
+ * \return Zero on success, non-zero on failure
+ */
+extern int
+efx_vi_eventq_kill_callback(struct efx_vi_state *vih);
+
+/**************************************************************************
+ * efx_vi_dma_map types and functions
+ **************************************************************************/
+
+/*!
+ * Handle for refering to a efx_vi
+ */
+struct efx_vi_dma_map_state;
+
+/*!
+ * Map a list of buffer pages so they are registered with the hardware
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param addrs An array of page pointers to map
+ * \param n_addrs Length of the page pointer array.  Must be a power of two.
+ * \param dmh_out Set on success to a handle used to refer to this mapping
+ * \return Zero on success, non-zero on failure.
+ */
+extern int
+efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages,
+                        int n_pages, struct efx_vi_dma_map_state **dmh_out);
+extern int
+efx_vi_dma_map_addrs(struct efx_vi_state *vih,
+                    unsigned long long *dev_bus_addrs, int n_pages,
+                    struct efx_vi_dma_map_state **dmh_out);
+
+/*!
+ * Unmap a previously mapped set of pages so they are no longer registered
+ * with the hardware.
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param dmh The handle to identify the dma mapping
+ */
+extern void
+efx_vi_dma_unmap_pages(struct efx_vi_state *vih,
+                      struct efx_vi_dma_map_state *dmh);
+extern void
+efx_vi_dma_unmap_addrs(struct efx_vi_state *vih,
+                      struct efx_vi_dma_map_state *dmh);
+
+/*!
+ * Retrieve the buffer address of the mapping
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param dmh The handle to identify the buffer mapping
+ * \return The buffer address on success, or zero on failure
+ */
+extern unsigned
+efx_vi_dma_get_map_addr(struct efx_vi_state *vih,
+                       struct efx_vi_dma_map_state *dmh);
+
+/**************************************************************************
+ * efx_vi filter functions
+ **************************************************************************/
+
+#define EFX_VI_STATIC_FILTERS 32
+
+/*! Handle to refer to a filter instance */
+struct filter_resource_t;
+
+/*!
+ * Allocate and add a filter
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param protocol The protocol of the new filter: UDP or TCP
+ * \param ip_addr_be32 The local ip address of the filter
+ * \param port_le16 The local port of the filter
+ * \param fh_out Set on success to be a handle to refer to this filter
+ * \return Zero on success, non-zero on failure.
+ */
+extern int
+efx_vi_filter(struct efx_vi_state *vih, int protocol, unsigned ip_addr_be32,
+             int port_le16, struct filter_resource_t **fh_out);
+
+/*!
+ * Remove a filter and free resources associated with it
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param fh The handle to identify the filter
+ * \return Zero on success, non-zero on failure
+ */
+extern int
+efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh);
+
+/**************************************************************************
+ * efx_vi hw resources types and functions
+ **************************************************************************/
+
+/*! Constants for the type field in efx_vi_hw_resource */
+#define EFX_VI_HW_RESOURCE_TXDMAQ    0x0       /* PFN of TX DMA Q */
+#define EFX_VI_HW_RESOURCE_RXDMAQ    0x1       /* PFN of RX DMA Q */
+#define EFX_VI_HW_RESOURCE_TXBELL    0x2       /* PFN of TX Doorbell (EF1) */
+#define EFX_VI_HW_RESOURCE_RXBELL    0x3       /* PFN of RX Doorbell (EF1) */
+#define EFX_VI_HW_RESOURCE_EVQTIMER  0x4       /* Address of event q timer */
+
+/* Address of event q pointer (EF1) */
+#define EFX_VI_HW_RESOURCE_EVQPTR    0x5
+/* Address of register pointer (Falcon A) */
+#define EFX_VI_HW_RESOURCE_EVQRPTR   0x6
+/* Offset of register pointer (Falcon B) */
+#define EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET 0x7
+/* Address of mem KVA */
+#define EFX_VI_HW_RESOURCE_EVQMEMKVA 0x8
+/* PFN of doorbell page (Falcon) */
+#define EFX_VI_HW_RESOURCE_BELLPAGE  0x9
+
+/*! How large an array to allocate for the get_() functions - smaller
+  than the total number of constants as some are mutually exclusive */
+#define EFX_VI_HW_RESOURCE_MAXSIZE   0x7
+
+/*! Constants for the mem_type field in efx_vi_hw_resource */
+#define EFX_VI_HW_RESOURCE_IOBUFFER   0        /* Host memory */
+#define EFX_VI_HW_RESOURCE_PERIPHERAL 1        /* Card memory/registers */
+
+/*!
+ * Data structure providing information on a hardware resource mapping
+ */
+struct efx_vi_hw_resource {
+       u8 type;                /*!< What this resource represents */
+       u8 mem_type;            /*!< What type of memory is it in, eg,
+                                * host or iomem */
+       u8 more_to_follow;      /*!< Is this part of a multi-region resource */
+       u32 length;             /*!< Length of the resource in bytes */
+       unsigned long address;  /*!< Address of this resource */
+};
+
+/*!
+ * Metadata concerning the list of hardware resource mappings
+ */
+struct efx_vi_hw_resource_metadata {
+       int version;
+       int evq_order;
+       int evq_offs;
+       int evq_capacity;
+       int instance;
+       unsigned rx_capacity;
+       unsigned tx_capacity;
+       int nic_arch;
+       int nic_revision;
+       char nic_variant;
+};
+
+/*!
+ * Obtain a list of hardware resource mappings, using virtual addresses
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param mdata Pointer to a structure to receive the metadata
+ * \param hw_res_array An array to receive the list of hardware resources
+ * \param length The length of hw_res_array.  Updated on success to contain
+ * the number of entries in the supplied array that were used.
+ * \return Zero on success, non-zero on failure
+ */
+extern int
+efx_vi_hw_resource_get_virt(struct efx_vi_state *vih,
+                           struct efx_vi_hw_resource_metadata *mdata,
+                           struct efx_vi_hw_resource *hw_res_array,
+                           int *length);
+
+/*!
+ * Obtain a list of hardware resource mappings, using physical addresses
+ *
+ * \param vih The handle to identify the efx_vi
+ * \param mdata Pointer to a structure to receive the metadata
+ * \param hw_res_array An array to receive the list of hardware resources
+ * \param length The length of hw_res_array.  Updated on success to contain
+ * the number of entries in the supplied array that were used.
+ * \return Zero on success, non-zero on failure
+ */
+extern int
+efx_vi_hw_resource_get_phys(struct efx_vi_state *vih,
+                           struct efx_vi_hw_resource_metadata *mdata,
+                           struct efx_vi_hw_resource *hw_res_array,
+                           int *length);
+
+#endif /* __CI_DRIVER_RESOURCE_EFX_VI_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/efhw/common.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/common.h  Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,102 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides API of the efhw library which may be used both from
+ * the kernel and from the user-space code.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_COMMON_H__
+#define __CI_EFHW_COMMON_H__
+
+#include <ci/efhw/common_sysdep.h>
+
+enum efhw_arch {
+       EFHW_ARCH_FALCON,
+       EFHW_ARCH_SIENA,
+};
+
+typedef uint32_t efhw_buffer_addr_t;
+#define EFHW_BUFFER_ADDR_FMT   "[ba:%"PRIx32"]"
+
+/*! Comment? */
+typedef union {
+       uint64_t u64;
+       struct {
+               uint32_t a;
+               uint32_t b;
+       } opaque;
+       struct {
+               uint32_t code;
+               uint32_t status;
+       } ev1002;
+} efhw_event_t;
+
+/* Flags for TX/RX queues */
+#define EFHW_VI_JUMBO_EN           0x01  /*! scatter RX over multiple desc */
+#define EFHW_VI_ISCSI_RX_HDIG_EN   0x02  /*! iscsi rx header digest */
+#define EFHW_VI_ISCSI_TX_HDIG_EN   0x04  /*! iscsi tx header digest */
+#define EFHW_VI_ISCSI_RX_DDIG_EN   0x08  /*! iscsi rx data digest */
+#define EFHW_VI_ISCSI_TX_DDIG_EN   0x10  /*! iscsi tx data digest */
+#define EFHW_VI_TX_PHYS_ADDR_EN    0x20  /*! TX physical address mode */
+#define EFHW_VI_RX_PHYS_ADDR_EN    0x40  /*! RX physical address mode */
+#define EFHW_VI_RM_WITH_INTERRUPT  0x80  /*! VI with an interrupt */
+#define EFHW_VI_TX_IP_CSUM_DIS     0x100 /*! enable ip checksum generation */
+#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum
+                                          generation */
+#define EFHW_VI_TX_TCPUDP_ONLY     0x400 /*! drop non-tcp/udp packets */
+
+/* Types of hardware filter */
+/* Each of these values implicitly selects scatter filters on B0 - or in
+   EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK if a non-scatter filter is required */
+#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD  (0)  /* dest host only */
+#define EFHW_IP_FILTER_TYPE_UDP_FULL      (1)  /* dest host and port */
+#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD  (2)  /* dest based filter */
+#define EFHW_IP_FILTER_TYPE_TCP_FULL      (3)  /* src  filter */
+/* Same again, but with RSS (for B0 only) */
+#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD_RSS_B0  (4)
+#define EFHW_IP_FILTER_TYPE_UDP_FULL_RSS_B0      (5)
+#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD_RSS_B0  (6)
+#define EFHW_IP_FILTER_TYPE_TCP_FULL_RSS_B0      (7)
+
+#define EFHW_IP_FILTER_TYPE_FULL_MASK      (0x1) /* Mask for full / wildcard */
+#define EFHW_IP_FILTER_TYPE_TCP_MASK       (0x2) /* Mask for TCP type */
+#define EFHW_IP_FILTER_TYPE_RSS_B0_MASK    (0x4) /* Mask for B0 RSS enable */
+#define EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK (0x8) /* Mask for B0 SCATTER dsbl */
+
+#define EFHW_IP_FILTER_TYPE_MASK       (0xffff) /* Mask of types above */
+
+#define EFHW_IP_FILTER_BROADCAST       (0x10000) /* driverlink filter
+                                                    support */
+
+#endif /* __CI_EFHW_COMMON_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/efhw/common_sysdep.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/common_sysdep.h   Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides version-independent Linux kernel API for
+ * userland-to-kernel interfaces.
+ * Only kernels >=2.6.9 are supported.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_COMMON_LINUX_H__
+#define __CI_EFHW_COMMON_LINUX_H__
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+/* Dirty hack, but Linux kernel does not provide DMA_ADDR_T_FMT */
+#if BITS_PER_LONG == 64 || defined(CONFIG_HIGHMEM64G)
+#define DMA_ADDR_T_FMT "%llx"
+#else
+#define DMA_ADDR_T_FMT "%x"
+#endif
+
+/* Linux kernel also does not provide PRIx32... Sigh. */
+#define PRIx32 "x"
+#define PRIx64 "llx"
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+enum {
+       false = 0,
+       true = 1
+};
+
+typedef _Bool bool;
+#endif /* LINUX_VERSION_CODE < 2.6.19 */
+
+#endif /* __CI_EFHW_COMMON_LINUX_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/efhw/debug.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/debug.h   Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,84 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides debug-related API for efhw library using Linux kernel
+ * primitives.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_DEBUG_LINUX_H__
+#define __CI_EFHW_DEBUG_LINUX_H__
+
+#define EFHW_PRINTK_PREFIX "[sfc efhw] "
+
+#define EFHW_PRINTK(level, fmt, ...) \
+       printk(level EFHW_PRINTK_PREFIX fmt "\n", __VA_ARGS__)
+
+/* Following macros should be used with non-zero format parameters
+ * due to __VA_ARGS__ limitations.  Use "%s" with __FUNCTION__ if you can't
+ * find better parameters. */
+#define EFHW_ERR(fmt, ...)     EFHW_PRINTK(KERN_ERR, fmt, __VA_ARGS__)
+#define EFHW_WARN(fmt, ...)    EFHW_PRINTK(KERN_WARNING, fmt, __VA_ARGS__)
+#define EFHW_NOTICE(fmt, ...)  EFHW_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__)
+#if 0 && !defined(NDEBUG)
+#define EFHW_TRACE(fmt, ...) EFHW_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__)
+#else
+#define EFHW_TRACE(fmt, ...)
+#endif
+
+#ifndef NDEBUG
+#define EFHW_ASSERT(cond)  BUG_ON((cond) == 0)
+#define EFHW_DO_DEBUG(expr) expr
+#else
+#define EFHW_ASSERT(cond)
+#define EFHW_DO_DEBUG(expr)
+#endif
+
+#define EFHW_TEST(expr)                        \
+       do {                            \
+               if (unlikely(!(expr)))  \
+               BUG();                  \
+       } while (0)
+
+/* Build time asserts. We paste the line number into the type name
+ * so that the macro can be used more than once per file even if the
+ * compiler objects to multiple identical typedefs. Collisions
+ * between use in different header files is still possible. */
+#ifndef EFHW_BUILD_ASSERT
+#define __EFHW_BUILD_ASSERT_NAME(_x) __EFHW_BUILD_ASSERT_ILOATHECPP(_x)
+#define __EFHW_BUILD_ASSERT_ILOATHECPP(_x)  __EFHW_BUILD_ASSERT__ ##_x
+#define EFHW_BUILD_ASSERT(e) \
+       typedef char __EFHW_BUILD_ASSERT_NAME(__LINE__)[(e) ? 1 : -1]
+#endif
+
+#endif /* __CI_EFHW_DEBUG_LINUX_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/efhw/efhw_config.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/efhw_config.h     Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,43 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides some limits used in both kernel and userland code.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_EFAB_CONFIG_H__
+#define __CI_EFHW_EFAB_CONFIG_H__
+
+#define EFHW_MAX_NR_DEVS 5     /* max number of efhw devices supported */
+
+#endif /* __CI_EFHW_EFAB_CONFIG_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/efhw/efhw_types.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/efhw_types.h      Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,342 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides struct efhw_nic and some related types.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_EFAB_TYPES_H__
+#define __CI_EFHW_EFAB_TYPES_H__
+
+#include <ci/efhw/efhw_config.h>
+#include <ci/efhw/hardware_sysdep.h>
+#include <ci/efhw/iopage_types.h>
+#include <ci/efhw/sysdep.h>
+
+/*--------------------------------------------------------------------
+ *
+ * hardware limits used in the types
+ *
+ *--------------------------------------------------------------------*/
+
+#define EFHW_KEVENTQ_MAX    8
+
+/*--------------------------------------------------------------------
+ *
+ * forward type declarations
+ *
+ *--------------------------------------------------------------------*/
+
+struct efhw_nic;
+
+/*--------------------------------------------------------------------
+ *
+ * Managed interface
+ *
+ *--------------------------------------------------------------------*/
+
+struct efhw_buffer_table_allocation{
+       unsigned base;
+       unsigned order;
+};
+
+struct eventq_resource_hardware {
+       /*!iobuffer allocated for eventq - can be larger than eventq */
+       efhw_iopages_t iobuff;
+       unsigned iobuff_off;
+       struct efhw_buffer_table_allocation buf_tbl_alloc;
+       int capacity;           /*!< capacity of event queue */
+};
+
+/*--------------------------------------------------------------------
+ *
+ * event queues and event driven callbacks
+ *
+ *--------------------------------------------------------------------*/
+
+struct efhw_keventq {
+       volatile int lock;
+       caddr_t evq_base;
+       int32_t evq_ptr;
+       uint32_t evq_mask;
+       unsigned instance;
+       struct eventq_resource_hardware hw;
+       struct efhw_ev_handler *ev_handlers;
+};
+
+/**********************************************************************
+ * Portable HW interface. ***************************************
+ **********************************************************************/
+
+/*--------------------------------------------------------------------
+ *
+ * EtherFabric Functional units - configuration and control
+ *
+ *--------------------------------------------------------------------*/
+
+struct efhw_func_ops {
+
+  /*-------------- Initialisation ------------ */
+
+       /*! close down all hardware functional units - leaves NIC in a safe
+          state for driver unload */
+       void (*close_hardware) (struct efhw_nic *nic);
+
+       /*! initialise all hardware functional units */
+       int (*init_hardware) (struct efhw_nic *nic,
+                             struct efhw_ev_handler *,
+                             const uint8_t *mac_addr);
+
+  /*-------------- Interrupt support  ------------ */
+
+       /*! Main interrupt routine
+        **        This function returns,
+        **  - zero,       if the IRQ was not generated by EF1
+        **  - non-zero,   if EF1 was the source of the IRQ
+        **
+        **
+        ** opaque is an OS provided pointer for use by the OS callbacks
+        ** e.g in Windows used to indicate DPC scheduled
+        */
+       int (*interrupt) (struct efhw_nic *nic);
+
+       /*! Enable given interrupt mask for the given IRQ unit */
+       void (*interrupt_enable) (struct efhw_nic *nic, uint idx);
+
+       /*! Disable given interrupt mask for the given IRQ unit */
+       void (*interrupt_disable) (struct efhw_nic *nic, uint idx);
+
+       /*! Set interrupt moderation strategy for the given IRQ unit
+        ** val is in usec
+        */
+       void (*set_interrupt_moderation)(struct efhw_nic *nic,
+                                        uint idx, uint val);
+
+  /*-------------- Event support  ------------ */
+
+       /*! Enable the given event queue
+          depending on the underlying implementation (EF1 or Falcon) then
+          either a q_base_addr in host memory, or a buffer base id should
+          be proivded
+        */
+       void (*event_queue_enable) (struct efhw_nic *nic,
+                                   uint evq,   /* evnt queue index */
+                                   uint evq_size,      /* units of #entries */
+                                   dma_addr_t q_base_addr, uint buf_base_id);
+
+       /*! Disable the given event queue (and any associated timer) */
+       void (*event_queue_disable) (struct efhw_nic *nic, uint evq,
+                                    int timer_only);
+
+       /*! request wakeup from the NIC on a given event Q */
+       void (*wakeup_request) (struct efhw_nic *nic, dma_addr_t q_base_addr,
+                               int next_i, int evq);
+
+       /*! Push a SW event on a given eventQ */
+       void (*sw_event) (struct efhw_nic *nic, int data, int evq);
+
+  /*-------------- Filter support  ------------ */
+
+       /*! Setup a given filter - The software can request a filter_i,
+        * but some EtherFabric implementations will override with
+        * a more suitable index
+        */
+       int (*ipfilter_set) (struct efhw_nic *nic, int type,
+                            int *filter_i, int dmaq,
+                            unsigned saddr_be32, unsigned sport_be16,
+                            unsigned daddr_be32, unsigned dport_be16);
+
+       /*! Attach a given filter to a DMAQ */
+       void (*ipfilter_attach) (struct efhw_nic *nic, int filter_idx,
+                                int dmaq_idx);
+
+       /*! Detach a filter from its DMAQ */
+       void (*ipfilter_detach) (struct efhw_nic *nic, int filter_idx);
+
+       /*! Clear down a given filter */
+       void (*ipfilter_clear) (struct efhw_nic *nic, int filter_idx);
+
+  /*-------------- DMA support  ------------ */
+
+       /*! Initialise NIC state for a given TX DMAQ */
+       void (*dmaq_tx_q_init) (struct efhw_nic *nic,
+                               uint dmaq, uint evq, uint owner, uint tag,
+                               uint dmaq_size, uint buf_idx, uint flags);
+
+       /*! Initialise NIC state for a given RX DMAQ */
+       void (*dmaq_rx_q_init) (struct efhw_nic *nic,
+                               uint dmaq, uint evq, uint owner, uint tag,
+                               uint dmaq_size, uint buf_idx, uint flags);
+
+       /*! Disable a given TX DMAQ */
+       void (*dmaq_tx_q_disable) (struct efhw_nic *nic, uint dmaq);
+
+       /*! Disable a given RX DMAQ */
+       void (*dmaq_rx_q_disable) (struct efhw_nic *nic, uint dmaq);
+
+       /*! Flush a given TX DMA channel */
+       int (*flush_tx_dma_channel) (struct efhw_nic *nic, uint dmaq);
+
+       /*! Flush a given RX DMA channel */
+       int (*flush_rx_dma_channel) (struct efhw_nic *nic, uint dmaq);
+
+  /*-------------- Buffer table Support ------------ */
+
+       /*! Initialise a buffer table page */
+       void (*buffer_table_set) (struct efhw_nic *nic,
+                                 dma_addr_t dma_addr,
+                                 uint bufsz, uint region,
+                                 int own_id, int buffer_id);
+
+       /*! Initialise a block of buffer table pages */
+       void (*buffer_table_set_n) (struct efhw_nic *nic, int buffer_id,
+                                   dma_addr_t dma_addr,
+                                   uint bufsz, uint region,
+                                   int n_pages, int own_id);
+
+       /*! Clear a block of buffer table pages */
+       void (*buffer_table_clear) (struct efhw_nic *nic, int buffer_id,
+                                   int num);
+
+       /*! Commit a buffer table update  */
+       void (*buffer_table_commit) (struct efhw_nic *nic);
+
+};
+
+
+/*----------------------------------------------------------------------------
+ *
+ * NIC type
+ *
+ *---------------------------------------------------------------------------*/
+
+struct efhw_device_type {
+       int  arch;            /* enum efhw_arch */
+       char variant;         /* 'A', 'B', ... */
+       int  revision;        /* 0, 1, ... */
+};
+
+
+/*----------------------------------------------------------------------------
+ *
+ * EtherFabric NIC instance - nic.c for HW independent functions
+ *
+ *---------------------------------------------------------------------------*/
+
+/*! */
+struct efhw_nic {
+       /*! zero base index in efrm_nic_table.nic array */
+       volatile int index;
+       int ifindex;            /*!< OS level nic index */
+#ifdef HAS_NET_NAMESPACE
+       struct net *nd_net;
+#endif
+
+       struct efhw_device_type devtype;
+
+       /*! Options that can be set by user. */
+       unsigned options;
+# define NIC_OPT_EFTEST             0x1        /* owner is an eftest app */
+
+# define NIC_OPT_DEFAULT            0
+
+       /*! Internal flags that indicate hardware properties at runtime. */
+       unsigned flags;
+# define NIC_FLAG_NO_INTERRUPT          0x01 /* to be set at init time only */
+# define NIC_FLAG_TRY_MSI               0x02
+# define NIC_FLAG_MSI                   0x04
+# define NIC_FLAG_OS_IRQ_EN             0x08
+# define NIC_FLAG_10G                   0x10
+
+       unsigned mtu;           /*!< MAC MTU (includes MAC hdr) */
+
+       /* hardware resources */
+
+       /*! I/O address of the start of the bar */
+       efhw_ioaddr_t bar_ioaddr;
+
+       /*! Bar number of control aperture. */
+       unsigned ctr_ap_bar;
+       /*! Length of control aperture in bytes. */
+       unsigned ctr_ap_bytes;
+
+       uint8_t mac_addr[ETH_ALEN];     /*!< mac address  */
+
+       /*! EtherFabric Functional Units -- functions */
+       const struct efhw_func_ops *efhw_func;
+
+       /* Value read from FPGA version register.  Zero for asic. */
+       unsigned fpga_version;
+
+       /*! This lock protects a number of misc NIC resources.  It should
+        * only be used for things that can be at the bottom of the lock
+        * order.  ie. You mustn't attempt to grab any other lock while
+        * holding this one.
+        */
+       spinlock_t *reg_lock;
+       spinlock_t the_reg_lock;
+
+       int buf_commit_outstanding;     /*!< outstanding buffer commits */
+
+       /*! interrupt callbacks (hard-irq) */
+       void (*irq_handler) (struct efhw_nic *, int unit);
+
+       /*! event queues per driver */
+       struct efhw_keventq evq[EFHW_KEVENTQ_MAX];
+
+/* for marking when we are not using an IRQ unit
+      - 0 is a valid offset to an IRQ unit on EF1! */
+#define EFHW_IRQ_UNIT_UNUSED  0xffff
+       /*! interrupt unit in use  */
+       unsigned int irq_unit[EFHW_KEVENTQ_MAX];
+       efhw_iopage_t irq_iobuff;       /*!<  Falcon SYSERR interrupt */
+
+       /* The new driverlink infrastructure. */
+       struct efx_dl_device *net_driver_dev;
+       struct efx_dlfilt_cb_s *dlfilter_cb;
+
+       /*! Bit masks of the sizes of event queues and dma queues supported
+        * by the nic. */
+       unsigned evq_sizes;
+       unsigned rxq_sizes;
+       unsigned txq_sizes;
+
+       /* Size of filter table (including odd and even banks). */
+       unsigned filter_tbl_size;
+};
+
+
+#define EFHW_KVA(nic)       ((nic)->bar_ioaddr)
+
+
+#endif /* __CI_EFHW_EFHW_TYPES_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,84 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides version-independent Linux kernel API for header files
+ * with hardware-related definitions (in ci/driver/efab/hardware*).
+ * Only kernels >=2.6.9 are supported.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_HARDWARE_LINUX_H__
+#define __CI_EFHW_HARDWARE_LINUX_H__
+
+#include <asm/io.h>
+
+#ifdef __LITTLE_ENDIAN
+#define EFHW_IS_LITTLE_ENDIAN
+#elif __BIG_ENDIAN
+#define EFHW_IS_BIG_ENDIAN
+#else
+#error Unknown endianness
+#endif
+
+#ifndef mmiowb
+       #if defined(__i386__) || defined(__x86_64__)
+               #define mmiowb()
+       #elif defined(__ia64__)
+               #ifndef ia64_mfa
+                       #define ia64_mfa() asm volatile ("mf.a" ::: "memory")
+               #endif
+       #define mmiowb ia64_mfa
+       #else
+       #error "Need definition for mmiowb()"
+       #endif
+#endif
+
+typedef char *efhw_ioaddr_t;
+
+#ifndef readq
+static inline uint64_t __readq(void __iomem *addr)
+{
+       return *(volatile uint64_t *)addr;
+}
+#define readq(x) __readq(x)
+#endif
+
+#ifndef writeq
+static inline void __writeq(uint64_t v, void __iomem *addr)
+{
+       *(volatile uint64_t *)addr = v;
+}
+#define writeq(val, addr) __writeq((val), (addr))
+#endif
+
+#endif /* __CI_EFHW_HARDWARE_LINUX_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/efhw/iopage_types.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/iopage_types.h    Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,188 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides efhw_page_t and efhw_iopage_t for Linux kernel.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_IOPAGE_LINUX_H__
+#define __CI_EFHW_IOPAGE_LINUX_H__
+
+#include <linux/gfp.h>
+#include <linux/hardirq.h>
+#include <ci/efhw/debug.h>
+
+/*--------------------------------------------------------------------
+ *
+ * efhw_page_t: A single page of memory.  Directly mapped in the driver,
+ * and can be mapped to userlevel.
+ *
+ *--------------------------------------------------------------------*/
+
+typedef struct {
+       unsigned long kva;
+} efhw_page_t;
+
+static inline int efhw_page_alloc(efhw_page_t *p)
+{
+       p->kva = __get_free_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
+       return p->kva ? 0 : -ENOMEM;
+}
+
+static inline int efhw_page_alloc_zeroed(efhw_page_t *p)
+{
+       p->kva = get_zeroed_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
+       return p->kva ? 0 : -ENOMEM;
+}
+
+static inline void efhw_page_free(efhw_page_t *p)
+{
+       free_page(p->kva);
+       EFHW_DO_DEBUG(memset(p, 0, sizeof(*p)));
+}
+
+static inline char *efhw_page_ptr(efhw_page_t *p)
+{
+       return (char *)p->kva;
+}
+
+static inline unsigned efhw_page_pfn(efhw_page_t *p)
+{
+       return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
+}
+
+static inline void efhw_page_mark_invalid(efhw_page_t *p)
+{
+       p->kva = 0;
+}
+
+static inline int efhw_page_is_valid(efhw_page_t *p)
+{
+       return p->kva != 0;
+}
+
+static inline void efhw_page_init_from_va(efhw_page_t *p, void *va)
+{
+       p->kva = (unsigned long)va;
+}
+
+/*--------------------------------------------------------------------
+ *
+ * efhw_iopage_t: A single page of memory.  Directly mapped in the driver,
+ * and can be mapped to userlevel.  Can also be accessed by the NIC.
+ *
+ *--------------------------------------------------------------------*/
+
+typedef struct {
+       efhw_page_t p;
+       dma_addr_t dma_addr;
+} efhw_iopage_t;
+
+static inline dma_addr_t efhw_iopage_dma_addr(efhw_iopage_t *p)
+{
+       return p->dma_addr;
+}
+
+#define efhw_iopage_ptr(iop)           efhw_page_ptr(&(iop)->p)
+#define efhw_iopage_pfn(iop)           efhw_page_pfn(&(iop)->p)
+#define efhw_iopage_mark_invalid(iop)  efhw_page_mark_invalid(&(iop)->p)
+#define efhw_iopage_is_valid(iop)      efhw_page_is_valid(&(iop)->p)
+
+/*--------------------------------------------------------------------
+ *
+ * efhw_iopages_t: A set of pages that are contiguous in physical memory.
+ * Directly mapped in the driver, and can be mapped to userlevel.  Can also
+ * be accessed by the NIC.
+ *
+ * NB. The O/S may be unwilling to allocate many, or even any of these.  So
+ * only use this type where the NIC really needs a physically contiguous
+ * buffer.
+ *
+ *--------------------------------------------------------------------*/
+
+typedef struct {
+       caddr_t kva;
+       unsigned order;
+       dma_addr_t dma_addr;
+} efhw_iopages_t;
+
+static inline caddr_t efhw_iopages_ptr(efhw_iopages_t *p)
+{
+       return p->kva;
+}
+
+static inline unsigned efhw_iopages_pfn(efhw_iopages_t *p)
+{
+       return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
+}
+
+static inline dma_addr_t efhw_iopages_dma_addr(efhw_iopages_t *p)
+{
+       return p->dma_addr;
+}
+
+static inline unsigned efhw_iopages_size(efhw_iopages_t *p)
+{
+       return 1u << (p->order + PAGE_SHIFT);
+}
+
+/* efhw_iopage_t <-> efhw_iopages_t conversions for handling physically
+ * contiguous allocations in iobufsets for iSCSI.  This allows the
+ * essential information about contiguous allocations from
+ * efhw_iopages_alloc() to be saved away in the efhw_iopage_t array in an
+ * iobufset.  (Changing the iobufset resource to use a union type would
+ * involve a lot of code changes, and make the iobufset's metadata larger
+ * which could be bad as it's supposed to fit into a single page on some
+ * platforms.)
+ */
+static inline void
+efhw_iopage_init_from_iopages(efhw_iopage_t *iopage,
+                           efhw_iopages_t *iopages, unsigned pageno)
+{
+       iopage->p.kva = ((unsigned long)efhw_iopages_ptr(iopages))
+           + (pageno * PAGE_SIZE);
+       iopage->dma_addr = efhw_iopages_dma_addr(iopages) +
+           (pageno * PAGE_SIZE);
+}
+
+static inline void
+efhw_iopages_init_from_iopage(efhw_iopages_t *iopages,
+                           efhw_iopage_t *iopage, unsigned order)
+{
+       iopages->kva = (caddr_t) efhw_iopage_ptr(iopage);
+       EFHW_ASSERT(iopages->kva);
+       iopages->order = order;
+       iopages->dma_addr = efhw_iopage_dma_addr(iopage);
+}
+
+#endif /* __CI_EFHW_IOPAGE_LINUX_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/efhw/public.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/public.h  Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,83 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides public API of efhw library exported from the SFC
+ * resource driver.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_PUBLIC_H__
+#define __CI_EFHW_PUBLIC_H__
+
+#include <ci/efhw/common.h>
+#include <ci/efhw/efhw_types.h>
+
+/*! Returns true if we have some EtherFabric functional units -
+  whether configured or not */
+static inline int efhw_nic_have_functional_units(struct efhw_nic *nic)
+{
+       return nic->efhw_func != 0;
+}
+
+/*! Returns true if the EtherFabric functional units have been configured  */
+static inline int efhw_nic_have_hw(struct efhw_nic *nic)
+{
+       return efhw_nic_have_functional_units(nic) && (EFHW_KVA(nic) != 0);
+}
+
+/*! Helper function to allocate the iobuffer needed by an eventq
+ *   - it ensures the eventq has the correct alignment for the NIC
+ *
+ * \param rm        Event-queue resource manager
+ * \param instance  Event-queue instance (index)
+ * \param buf_bytes Requested size of eventq
+ * \return          < 0 if iobuffer allocation fails
+ */
+int efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic,
+                                       struct eventq_resource_hardware *h,
+                                       int evq_instance, unsigned buf_bytes);
+
+extern void falcon_nic_set_rx_usr_buf_size(struct efhw_nic *,
+                                          int rx_usr_buf_size);
+
+extern void
+falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full,
+                            uint32_t tcp_wild,
+                            uint32_t udp_full, uint32_t udp_wild);
+
+extern void
+falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full,
+                            uint32_t *tcp_wild,
+                            uint32_t *udp_full, uint32_t *udp_wild);
+
+#endif /* __CI_EFHW_PUBLIC_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/efhw/sysdep.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efhw/sysdep.h  Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides version-independent Linux kernel API for efhw library.
+ * Only kernels >=2.6.9 are supported.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFHW_SYSDEP_LINUX_H__
+#define __CI_EFHW_SYSDEP_LINUX_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+
+#include <linux/netdevice.h> /* necessary for etherdevice.h on some kernels */
+#include <linux/etherdevice.h>
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
+static inline int is_local_ether_addr(const u8 *addr)
+{
+       return (0x02 & addr[0]);
+}
+#endif
+
+typedef unsigned long irq_flags_t;
+
+#define spin_lock_destroy(l_)  do {} while (0)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+#define HAS_NET_NAMESPACE
+#endif
+
+/* Funny, but linux has round_up for x86 only, defined in
+ * x86-specific header */
+#ifndef round_up
+#define round_up(x, y) (((x) + (y) - 1) & ~((y)-1))
+#endif
+
+#endif /* __CI_EFHW_SYSDEP_LINUX_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/efrm/nic_table.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efrm/nic_table.h       Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,98 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides public API for NIC table.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFRM_NIC_TABLE_H__
+#define __CI_EFRM_NIC_TABLE_H__
+
+#include <ci/efhw/efhw_types.h>
+#include <ci/efrm/sysdep.h>
+
+/*--------------------------------------------------------------------
+ *
+ * struct efrm_nic_table - top level driver object keeping all NICs -
+ * implemented in driver_object.c
+ *
+ *--------------------------------------------------------------------*/
+
+/*! Comment? */
+struct efrm_nic_table {
+       /*! nics attached to this driver */
+       struct efhw_nic *nic[EFHW_MAX_NR_DEVS];
+       /*! pointer to an arbitrary struct efhw_nic if one exists;
+        * for code which does not care which NIC it wants but
+        * still needs one. Note you cannot assume nic[0] exists. */
+       struct efhw_nic *a_nic;
+       uint32_t nic_count;     /*!< number of nics attached to this driver */
+       spinlock_t lock;        /*!< lock for table modifications */
+       atomic_t ref_count;     /*!< refcount for users of nic table */
+};
+
+/* Resource driver structures used by other drivers as well */
+extern struct efrm_nic_table efrm_nic_table;
+
+static inline void efrm_nic_table_hold(void)
+{
+       atomic_inc(&efrm_nic_table.ref_count);
+}
+
+static inline void efrm_nic_table_rele(void)
+{
+       atomic_dec(&efrm_nic_table.ref_count);
+}
+
+static inline int efrm_nic_table_held(void)
+{
+       return (atomic_read(&efrm_nic_table.ref_count) != 0);
+}
+
+/* Run code block _x multiple times with variable nic set to each
+ * registered NIC in turn.
+ * DO NOT "break" out of this loop early. */
+#define EFRM_FOR_EACH_NIC(_nic_i, _nic)                                        
\
+       for ((_nic_i) = (efrm_nic_table_hold(), 0);                     \
+            (_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
+            (_nic_i)++)                                                \
+               if (((_nic) = efrm_nic_table.nic[_nic_i]))
+
+#define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic)                       \
+       for ((_i) = (efrm_nic_table_hold(), 0);                         \
+            (_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0);     \
+            ++(_i))                                                    \
+               if (((_nic) = efrm_nic_table.nic[_i]) &&                \
+                   efrm_nic_set_read((_set), (_i)))
+
+#endif /* __CI_EFRM_NIC_TABLE_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/efrm/sysdep.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efrm/sysdep.h  Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,54 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides Linux-like system-independent API for efrm library.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFRM_SYSDEP_H__
+#define __CI_EFRM_SYSDEP_H__
+
+/* Spinlocks are defined in efhw/sysdep.h */
+#include <ci/efhw/sysdep.h>
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+# include <ci/efrm/sysdep_linux.h>
+
+#else
+
+# include <ci/efrm/sysdep_ci2linux.h>
+
+#endif
+
+#endif /* __CI_EFRM_SYSDEP_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h    Mon Feb 18 10:31:04 
2008 +0000
@@ -0,0 +1,248 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers -
+ *          resource management for Xen backend, OpenOnload, etc
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * This file provides version-independent Linux kernel API for efrm library.
+ * Only kernels >=2.6.9 are supported.
+ *
+ * Copyright 2005-2007: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Kfifo API is partially stolen from linux-2.6.22/include/linux/list.h
+ * Copyright (C) 2004 Stelian Pop <stelian@xxxxxxxxxx>
+ *
+ * Developed and maintained by Solarflare Communications:
+ *                      <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *                      <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * Certain parts of the driver were implemented by
+ *          Alexandra Kossovsky <Alexandra.Kossovsky@xxxxxxxxxxxx>
+ *          OKTET Labs Ltd, Russia,
+ *          http://oktetlabs.ru, <info@xxxxxxxxxxxx>
+ *          by request of Solarflare Communications
+ *
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+#ifndef __CI_EFRM_SYSDEP_LINUX_H__
+#define __CI_EFRM_SYSDEP_LINUX_H__
+
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/hardirq.h>
+#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/completion.h>
+#include <linux/in.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+/* get roundup_pow_of_two(), which was in kernel.h in early kernel versions */
+#include <linux/log2.h>
+#endif
+
+/********************************************************************
+ *
+ * List API
+ *
+ ********************************************************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
+static inline void
+list_replace_init(struct list_head *old, struct list_head *new)
+{
+       new->next = old->next;
+       new->next->prev = new;
+       new->prev = old->prev;
+       new->prev->next = new;
+       INIT_LIST_HEAD(old);
+}
+#endif
+
+static inline struct list_head *list_pop(struct list_head *list)
+{
+       struct list_head *link = list->next;
+       list_del(link);
+       return link;
+}
+
+static inline struct list_head *list_pop_tail(struct list_head *list)
+{
+       struct list_head *link = list->prev;
+       list_del(link);
+       return link;
+}
+
+/********************************************************************
+ *
+ * Workqueue API
+ *
+ ********************************************************************/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#define NEED_OLD_WORK_API
+
+/**
+ * The old and new work function prototypes just change
+ * the type of the pointer in the only argument, so it's
+ * safe to cast one function type to the other
+ */
+typedef void (*efrm_old_work_func_t) (void *p);
+
+#undef INIT_WORK
+#define INIT_WORK(_work, _func)                                        \
+       do {                                                    \
+               INIT_LIST_HEAD(&(_work)->entry);                \
+               (_work)->pending = 0;                           \
+               PREPARE_WORK((_work),                           \
+                            (efrm_old_work_func_t) (_func),    \
+                            (_work));                          \
+       } while (0)
+
+#endif
+
+/********************************************************************
+ *
+ * Kfifo API
+ *
+ ********************************************************************/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+
+#if !defined(RHEL_RELEASE_CODE) || (RHEL_RELEASE_CODE < 1029)
+typedef unsigned gfp_t;
+#endif
+
+#define HAS_NO_KFIFO
+
+struct kfifo {
+       unsigned char *buffer;  /* the buffer holding the data */
+       unsigned int size;      /* the size of the allocated buffer */
+       unsigned int in;        /* data is added at offset (in % size) */
+       unsigned int out;       /* data is extracted from off. (out % size) */
+       spinlock_t *lock;       /* protects concurrent modifications */
+};
+
+extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
+                               gfp_t gfp_mask, spinlock_t *lock);
+extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
+                                spinlock_t *lock);
+extern void kfifo_free(struct kfifo *fifo);
+extern unsigned int __kfifo_put(struct kfifo *fifo,
+                               unsigned char *buffer, unsigned int len);
+extern unsigned int __kfifo_get(struct kfifo *fifo,
+                               unsigned char *buffer, unsigned int len);
+
+/**
+ * kfifo_put - puts some data into the FIFO
+ * @fifo: the fifo to be used.
+ * @buffer: the data to be added.
+ * @len: the length of the data to be added.
+ *
+ * This function copies at most @len bytes from the @buffer into
+ * the FIFO depending on the free space, and returns the number of
+ * bytes copied.
+ */
+static inline unsigned int
+kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_put(fifo, buffer, len);
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
+/**
+ * kfifo_get - gets some data from the FIFO
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * @buffer and returns the number of copied bytes.
+ */
+static inline unsigned int
+kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_get(fifo, buffer, len);
+
+       /*
+        * optimization: if the FIFO is empty, set the indices to 0
+        * so we don't wrap the next time
+        */
+       if (fifo->in == fifo->out)
+               fifo->in = fifo->out = 0;
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
+/**
+ * __kfifo_len - returns the number of bytes available in the FIFO, no locking 
version
+ * @fifo: the fifo to be used.
+ */
+static inline unsigned int __kfifo_len(struct kfifo *fifo)
+{
+       return fifo->in - fifo->out;
+}
+
+/**
+ * kfifo_len - returns the number of bytes available in the FIFO
+ * @fifo: the fifo to be used.
+ */
+static inline unsigned int kfifo_len(struct kfifo *fifo)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_len(fifo);
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
+#else
+#include <linux/kfifo.h>
+#endif
+
+static inline void kfifo_vfree(struct kfifo *fifo)
+{
+       vfree(fifo->buffer);
+       kfree(fifo);
+}
+
+#endif /* __CI_EFRM_SYSDEP_LINUX_H__ */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/tools/config.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/tools/config.h Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,49 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_tools */
+
+#ifndef __CI_TOOLS_CONFIG_H__
+#define __CI_TOOLS_CONFIG_H__
+
+
+/**********************************************************************
+ * Debugging.
+ */
+
+#define CI_INCLUDE_ASSERT_VALID           0
+
+/* Set non-zero to allow info about who has allocated what to appear in
+ * /proc/drivers/level5/mem.
+ * However - Note that doing so can lead to segfault when you unload the
+ * driver, and other weirdness.  i.e. I don't think the code for is quite
+ * right (written by Oktet, hacked by gel), but it does work well enough to be
+ * useful.
+ */
+#define CI_MEMLEAK_DEBUG_ALLOC_TABLE     0
+
+
+#endif  /* __CI_TOOLS_CONFIG_H__ */
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/tools/debug.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/tools/debug.h  Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,336 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_tools */
+
+#ifndef __CI_TOOLS_DEBUG_H__
+#define __CI_TOOLS_DEBUG_H__
+
+#define CI_LOG_E(x)       x              /* errors      */
+#define CI_LOG_W(x)       x              /* warnings    */
+#define CI_LOG_I(x)       x              /* information */
+#define CI_LOG_V(x)       x              /* verbose     */
+
+/* Build time asserts. We paste the line number into the type name
+ * so that the macro can be used more than once per file even if the
+ * compiler objects to multiple identical typedefs. Collisions
+ * between use in different header files is still possible. */
+#ifndef CI_BUILD_ASSERT
+#define __CI_BUILD_ASSERT_NAME(_x) __CI_BUILD_ASSERT_ILOATHECPP(_x)
+#define __CI_BUILD_ASSERT_ILOATHECPP(_x)  __CI_BUILD_ASSERT__ ##_x
+#define CI_BUILD_ASSERT(e)\
+ typedef char  __CI_BUILD_ASSERT_NAME(__LINE__)[(e)?1:-1]
+#endif
+
+
+#ifdef NDEBUG
+
+# define _ci_check(exp, file, line)
+# define _ci_assert2(e, x, y, file, line)
+# define _ci_assert(exp, file, line)
+# define _ci_assert_equal(exp1, exp2, file, line)
+# define _ci_assert_equiv(exp1, exp2, file, line)
+# define _ci_assert_nequal(exp1, exp2, file, line)
+# define _ci_assert_le(exp1, exp2, file, line)
+# define _ci_assert_lt(exp1, exp2, file, line)
+# define _ci_assert_ge(exp1, exp2, file, line)
+# define _ci_assert_gt(exp1, exp2, file, line)
+# define _ci_assert_impl(exp1, exp2, file, line)
+
+# define _ci_verify(exp, file, line) \
+  do { \
+    (void)(exp); \
+  } while (0)
+
+# define CI_DEBUG_TRY(exp) \
+  do { \
+    (void)(exp); \
+  } while (0)
+
+#define CI_TRACE(exp,fmt)
+#define CI_TRACE_INT(integer)
+#define CI_TRACE_INT32(integer)
+#define CI_TRACE_INT64(integer)
+#define CI_TRACE_UINT(integer)
+#define CI_TRACE_UINT32(integer)
+#define CI_TRACE_UINT64(integer)
+#define CI_TRACE_HEX(integer)
+#define CI_TRACE_HEX32(integer)
+#define CI_TRACE_HEX64(integer)
+#define CI_TRACE_PTR(pointer)
+#define CI_TRACE_STRING(string)
+#define CI_TRACE_MAC(mac)
+#define CI_TRACE_IP(ip_be32)
+#define CI_TRACE_ARP(arp_pkt)
+
+#else
+
+# define _CI_ASSERT_FMT   "\nfrom %s:%d"
+
+# define _ci_check(exp, file, line)                             \
+  do {                                                          \
+    if (CI_UNLIKELY(!(exp)))                                    \
+      ci_warn(("ci_check(%s)"_CI_ASSERT_FMT, #exp,              \
+               (file), (line)));                                \
+  } while (0)
+
+/*
+ * NOTE: ci_fail() emits the file and line where the assert is actually
+ *       coded.
+ */
+
+# define _ci_assert(exp, file, line)                            \
+  do {                                                          \
+    if (CI_UNLIKELY(!(exp)))                                    \
+      ci_fail(("ci_assert(%s)"_CI_ASSERT_FMT, #exp,            \
+               (file), (line)));                                \
+  } while (0)
+
+# define _ci_assert2(e, x, y, file, line)  do {                 \
+    if(CI_UNLIKELY( ! (e) ))                                    \
+      ci_fail(("ci_assert(%s)\nwhere [%s=%"CI_PRIx64"] "        \
+               "[%s=%"CI_PRIx64"]\nat %s:%d\nfrom %s:%d", #e    \
+               , #x, (ci_uint64)(ci_uintptr_t)(x)               \
+               , #y, (ci_uint64)(ci_uintptr_t)(y),              \
+               __FILE__, __LINE__, (file), (line)));            \
+  } while (0)
+
+# define _ci_verify(exp, file, line)                            \
+  do {                                                          \
+    if (CI_UNLIKELY(!(exp)))                                    \
+      ci_fail(("ci_verify(%s)"_CI_ASSERT_FMT, #exp,             \
+               (file), (line)));                                \
+  } while (0)
+
+# define _ci_assert_equal(x, y, f, l)  _ci_assert2((x)==(y), x, y, (f), (l))
+# define _ci_assert_nequal(x, y, f, l) _ci_assert2((x)!=(y), x, y, (f), (l))
+# define _ci_assert_le(x, y, f, l)     _ci_assert2((x)<=(y), x, y, (f), (l))
+# define _ci_assert_lt(x, y, f, l)     _ci_assert2((x)< (y), x, y, (f), (l))
+# define _ci_assert_ge(x, y, f, l)     _ci_assert2((x)>=(y), x, y, (f), (l))
+# define _ci_assert_gt(x, y, f, l)     _ci_assert2((x)> (y), x, y, (f), (l))
+# define _ci_assert_or(x, y, f, l)     _ci_assert2((x)||(y), x, y, (f), (l))
+# define _ci_assert_impl(x, y, f, l)   _ci_assert2(!(x) || (y), x, y, (f), (l))
+# define _ci_assert_equiv(x, y, f, l)  _ci_assert2(!(x)== !(y), x, y, (f), (l))
+
+#define _ci_assert_equal_msg(exp1, exp2, msg, file, line)       \
+  do {                                                          \
+    if (CI_UNLIKELY((exp1)!=(exp2)))                            \
+      ci_fail(("ci_assert_equal_msg(%s == %s) were "            \
+               "(%"CI_PRIx64":%"CI_PRIx64") with msg[%c%c%c%c]" \
+               _CI_ASSERT_FMT, #exp1, #exp2,                    \
+               (ci_uint64)(ci_uintptr_t)(exp1),                 \
+               (ci_uint64)(ci_uintptr_t)(exp2),                 \
+               (((ci_uint32)msg) >> 24) && 0xff,                \
+               (((ci_uint32)msg) >> 16) && 0xff,                \
+               (((ci_uint32)msg) >> 8 ) && 0xff,                \
+               (((ci_uint32)msg)      ) && 0xff,                \
+               (file), (line)));                                \
+  } while (0)
+
+# define CI_DEBUG_TRY(exp)  CI_TRY(exp)
+
+#define CI_TRACE(exp,fmt)                                              \
+  ci_log("%s:%d:%s] " #exp "=" fmt,                                     \
+         __FILE__, __LINE__, __FUNCTION__, (exp))
+
+
+#define CI_TRACE_INT(integer)                                          \
+  ci_log("%s:%d:%s] " #integer "=%d",                                   \
+         __FILE__, __LINE__, __FUNCTION__, (integer))
+
+
+#define CI_TRACE_INT32(integer)                                                
\
+  ci_log("%s:%d:%s] " #integer "=%d",                                   \
+         __FILE__, __LINE__, __FUNCTION__, ((ci_int32)integer))
+
+
+#define CI_TRACE_INT64(integer)                                                
\
+  ci_log("%s:%d:%s] " #integer "=%lld",                                 \
+         __FILE__, __LINE__, __FUNCTION__, ((ci_int64)integer))
+
+
+#define CI_TRACE_UINT(integer)                                         \
+  ci_log("%s:%d:%s] " #integer "=%ud",                                  \
+         __FILE__, __LINE__, __FUNCTION__, (integer))
+
+
+#define CI_TRACE_UINT32(integer)                                       \
+  ci_log("%s:%d:%s] " #integer "=%ud",                                  \
+         __FILE__, __LINE__, __FUNCTION__, ((ci_uint32)integer))
+
+
+#define CI_TRACE_UINT64(integer)                                       \
+  ci_log("%s:%d:%s] " #integer "=%ulld",                                \
+         __FILE__, __LINE__, __FUNCTION__, ((ci_uint64)integer))
+
+
+#define CI_TRACE_HEX(integer)                                          \
+  ci_log("%s:%d:%s] " #integer "=0x%x",                                 \
+         __FILE__, __LINE__, __FUNCTION__, (integer))
+
+
+#define CI_TRACE_HEX32(integer)                                                
\
+  ci_log("%s:%d:%s] " #integer "=0x%x",                                 \
+         __FILE__, __LINE__, __FUNCTION__, ((ci_uint32)integer))
+
+
+#define CI_TRACE_HEX64(integer)                                                
\
+  ci_log("%s:%d:%s] " #integer "=0x%llx",                               \
+         __FILE__, __LINE__, __FUNCTION__, ((ci_uint64)integer))
+
+
+#define CI_TRACE_PTR(pointer)                                          \
+  ci_log("%s:%d:%s] " #pointer "=0x%p",                                 \
+         __FILE__, __LINE__, __FUNCTION__, (pointer))
+
+
+#define CI_TRACE_STRING(string)                                                
\
+  ci_log("%s:%d:%s] " #string "=%s",                                    \
+         __FILE__, __LINE__, __FUNCTION__, (string))
+
+
+#define CI_TRACE_MAC(mac)                                              \
+  ci_log("%s:%d:%s] " #mac "=" CI_MAC_PRINTF_FORMAT,                    \
+         __FILE__, __LINE__, __FUNCTION__, CI_MAC_PRINTF_ARGS(mac))
+
+
+#define CI_TRACE_IP(ip_be32)                                           \
+  ci_log("%s:%d:%s] " #ip_be32 "=" CI_IP_PRINTF_FORMAT, __FILE__,       \
+         __LINE__, __FUNCTION__, CI_IP_PRINTF_ARGS(&(ip_be32)))
+
+
+#define CI_TRACE_ARP(arp_pkt)                                           \
+  ci_log("%s:%d:%s]\n"CI_ARP_PRINTF_FORMAT,                             \
+         __FILE__, __LINE__, __FUNCTION__, CI_ARP_PRINTF_ARGS(arp_pkt))
+
+#endif  /* NDEBUG */
+
+#define ci_check(exp) \
+        _ci_check(exp, __FILE__, __LINE__)
+
+#define ci_assert(exp) \
+        _ci_assert(exp, __FILE__, __LINE__)
+
+#define ci_verify(exp) \
+        _ci_verify(exp, __FILE__, __LINE__)
+
+#define ci_assert_equal(exp1, exp2) \
+        _ci_assert_equal(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_equal_msg(exp1, exp2, msg) \
+        _ci_assert_equal_msg(exp1, exp2, msg, __FILE__, __LINE__)
+
+#define ci_assert_nequal(exp1, exp2) \
+        _ci_assert_nequal(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_le(exp1, exp2) \
+        _ci_assert_le(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_lt(exp1, exp2) \
+        _ci_assert_lt(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_ge(exp1, exp2) \
+        _ci_assert_ge(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_gt(exp1, exp2) \
+        _ci_assert_gt(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_impl(exp1, exp2) \
+        _ci_assert_impl(exp1, exp2, __FILE__, __LINE__)
+
+#define ci_assert_equiv(exp1, exp2) \
+        _ci_assert_equiv(exp1, exp2, __FILE__, __LINE__)
+
+
+#define CI_TEST(exp)                            \
+  do{                                           \
+    if( CI_UNLIKELY(!(exp)) )                   \
+      ci_fail(("CI_TEST(%s)", #exp));           \
+  }while(0)
+
+
+#define CI_TRY(exp)                            \
+  do{                                          \
+    int _trc;                                  \
+    _trc=(exp);                                        \
+    if( CI_UNLIKELY(_trc < 0) )                        \
+      ci_sys_fail(#exp, _trc);                 \
+  }while(0)
+
+
+#define CI_TRY_RET(exp)                                                        
 \
+  do{                                                                   \
+    int _trc;                                                           \
+    _trc=(exp);                                                                
 \
+    if( CI_UNLIKELY(_trc < 0) ) {                                       \
+      ci_log("%s returned %d at %s:%d", #exp, _trc, __FILE__, __LINE__); \
+      return _trc;                                                      \
+    }                                                                   \
+  }while(0)
+
+#define CI_LOGLEVEL_TRY_RET(logfn, exp)                                    \
+  do{                                                                   \
+    int _trc;                                                           \
+    _trc=(exp);                                                                
 \
+    if( CI_UNLIKELY(_trc < 0) ) {                                       \
+      logfn (ci_log("%s returned %d at %s:%d", #exp, _trc, __FILE__, 
__LINE__)); \
+      return _trc;                                                      \
+    }                                                                   \
+  }while(0)
+
+
+#define CI_SOCK_TRY(exp)                       \
+  do{                                          \
+    ci_sock_err_t _trc;                                \
+    _trc=(exp);                                        \
+    if( CI_UNLIKELY(!ci_sock_errok(_trc)) )    \
+      ci_sys_fail(#exp, _trc.val);             \
+  }while(0)
+
+
+#define CI_SOCK_TRY_RET(exp)                                                \
+  do{                                                                       \
+    ci_sock_err_t _trc;                                                        
     \
+    _trc=(exp);                                                                
     \
+    if( CI_UNLIKELY(!ci_sock_errok(_trc)) ) {                               \
+      ci_log("%s returned %d at %s:%d", #exp, _trc.val, __FILE__, __LINE__); \
+      return ci_sock_errcode(_trc);                                         \
+    }                                                                       \
+  }while(0)
+
+
+#define CI_SOCK_TRY_SOCK_RET(exp)                                           \
+  do{                                                                       \
+    ci_sock_err_t _trc;                                                        
     \
+    _trc=(exp);                                                                
     \
+    if( CI_UNLIKELY(!ci_sock_errok(_trc)) ) {                               \
+      ci_log("%s returned %d at %s:%d", #exp, _trc.val, __FILE__, __LINE__); \
+      return _trc;                                                          \
+    }                                                                       \
+  }while(0)
+
+#endif  /* __CI_TOOLS_DEBUG_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/tools/log.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/tools/log.h    Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,262 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*
+ * \author  djr
+ *  \brief  Functions for logging and pretty-printing.
+ *   \date  2002/08/07
+ */
+
+/*! \cidoxg_include_ci_tools */
+
+#ifndef __CI_TOOLS_LOG_H__
+#define __CI_TOOLS_LOG_H__
+
+#include <stdarg.h>
+
+
+/**********************************************************************
+ * Logging.
+ */
+
+/* size of internal log buffer */ 
+#define  CI_LOG_MAX_LINE        512
+/* uses of ci_log must ensure that all trace messages are shorter than this */ 
+#define  CI_LOG_MAX_MSG_LENGTH        (CI_LOG_MAX_LINE-50)
+
+extern void ci_vlog(const char* fmt, va_list args)  CI_HF;
+extern void ci_log(const char* fmt, ...) CI_PRINTF_LIKE(1,2) CI_HF;
+
+  /*! Set the prefix for log messages.
+  **
+  ** Uses the storage pointed to by \em prefix.  Therefore \em prefix must
+  ** be allocated on the heap, or statically.
+  */
+extern void ci_set_log_prefix(const char* prefix)  CI_HF;
+
+typedef void (*ci_log_fn_t)(const char* msg);
+extern ci_log_fn_t  ci_log_fn  CI_HV;
+
+/* Log functions. */
+extern void ci_log_null(const char* msg) CI_HF;
+extern void ci_log_stderr(const char* msg) CI_HF;
+extern void ci_log_stdout(const char* msg) CI_HF;
+extern void ci_log_syslog(const char* msg) CI_HF;
+
+/*! Call the following to install special logging behaviours. */
+extern void ci_log_buffer_till_fail(void) CI_HF;
+extern void ci_log_buffer_till_exit(void) CI_HF;
+
+extern void __ci_log_unique(const char* msg) CI_HF;
+extern ci_log_fn_t __ci_log_unique_fn CI_HV;
+ci_inline void ci_log_uniquify(void) {
+  if( ci_log_fn != __ci_log_unique ) {
+    __ci_log_unique_fn = ci_log_fn;
+    ci_log_fn = __ci_log_unique;
+  }
+}
+
+extern void ci_log_file(const char* msg) CI_HF;
+extern int  ci_log_file_fd CI_HV;
+
+extern void __ci_log_nth(const char* msg) CI_HF;
+extern ci_log_fn_t __ci_log_nth_fn CI_HV;
+extern int  ci_log_nth_n CI_HV;  /* default 100 */
+ci_inline void ci_log_nth(void) {
+  if( ci_log_fn != __ci_log_nth ) {
+    __ci_log_nth_fn = ci_log_fn;
+    ci_log_fn = __ci_log_nth;
+  }
+}
+
+extern int  ci_log_level  CI_HV;
+
+extern int  ci_log_options  CI_HV;
+#define CI_LOG_PID             0x1
+#define CI_LOG_TID             0x2
+#define CI_LOG_TIME            0x4
+#define CI_LOG_DELTA           0x8
+
+/**********************************************************************
+ * Used to define which mode we are in
+ */
+#if (defined(_WIN32) && !defined(__KERNEL__))
+typedef enum {
+  ci_log_md_NULL=0,
+    ci_log_md_ioctl,
+    ci_log_md_stderr,
+    ci_log_md_stdout,
+    ci_log_md_file,
+    ci_log_md_serial,
+    ci_log_md_syslog,
+    ci_log_md_pidfile
+} ci_log_mode_t;
+extern ci_log_mode_t ci_log_mode;
+#endif
+
+/**********************************************************************
+ * Pretty-printing.
+ */
+
+extern char ci_printable_char(char c) CI_HF;
+
+extern void (*ci_hex_dump_formatter)(char* buf, const ci_octet* s,
+                                    int i, int off, int len) CI_HV;
+extern void ci_hex_dump_format_octets(char*,const ci_octet*,int,int,int) CI_HF;
+extern void ci_hex_dump_format_dwords(char*,const ci_octet*,int,int,int) CI_HF;
+
+extern void ci_hex_dump_row(char* buf, volatile const void* s, int len,
+                           ci_ptr_arith_t address) CI_HF;
+  /*!< A row contains up to 16 bytes.  Row starts at [address & 15u], so
+  ** therefore [len + (address & 15u)] must be <= 16.
+  */
+
+extern void ci_hex_dump(ci_log_fn_t, volatile const void*,
+                       int len, ci_ptr_arith_t address) CI_HF;
+
+extern int  ci_hex_dump_to_raw(const char* src_hex, void* buf,
+                              unsigned* addr_out_opt, int* skip)  CI_HF;
+  /*!< Recovers raw data from a single line of a hex dump.  [buf] must be at
+  ** least 16 bytes long.  Returns the number of bytes written to [buf] (in
+  ** range 1 -> 16), or -1 if [src_hex] doesn't contain hex data.  Does not
+  ** cope with missing bytes at the start of a line.
+  */
+
+extern int ci_format_eth_addr(char* buf, const void* eth_mac_addr,
+                             char sep)  CI_HF;
+  /*!< This will write 18 characters to <buf> including terminating null.
+  ** Returns number of bytes written excluding null.  If [sep] is zero, ':'
+  ** is used.
+  */
+
+extern int ci_parse_eth_addr(void* eth_mac_addr,
+                            const char* str, char sep) CI_HF;
+  /*!< If [sep] is zero, absolutely any separator is accepted (even
+  ** inconsistent separators).  Returns 0 on success, -1 on error.
+  */
+
+extern int ci_format_ip4_addr(char* buf, unsigned addr_be32) CI_HF;
+  /*!< Formats the IP address (in network endian) in dotted-quad.  Returns
+  ** the number of bytes written (up to 15), excluding the null.  [buf]
+  ** must be at least 16 bytes long.
+  */
+
+
+/**********************************************************************
+ * Error checking.
+ */
+
+extern void (*ci_fail_stop_fn)(void) CI_HV;
+
+extern void ci_fail_stop(void) CI_HF;
+extern void ci_fail_hang(void) CI_HF;
+extern void ci_fail_bomb(void) CI_HF;
+extern void ci_backtrace(void) CI_HF;
+
+#if defined __linux__ && !defined __KERNEL__
+extern void ci_fail_abort (void) CI_HF;
+#endif
+
+#ifdef __GNUC__
+extern void
+__ci_fail(const char*, ...) CI_PRINTF_LIKE(1,2) CI_HF;
+#else
+# if _PREFAST_
+  extern void _declspec(noreturn) __ci_fail(const char* fmt, ...);
+# else 
+  extern void __ci_fail(const char* fmt, ...);
+# endif
+
+#endif
+
+#define ci_warn(x)                                                        \
+  do{ ci_log("WARN at %s:%d", __FILE__, __LINE__); }while(0)
+
+#define ci_fail(x)                                                        \
+  do{ ci_log("FAIL at %s:%d", __FILE__, __LINE__);  __ci_fail x; }while(0)
+
+extern void __ci_sys_fail(const char* fn, int rc,
+                         const char* file, int line) CI_HF;
+#define ci_sys_fail(fn, rc)  __ci_sys_fail(fn, rc, __FILE__, __LINE__)
+
+/**********************************************************************
+ * Logging to buffer (src/citools/log_buffer.c)
+ */
+
+/*! Divert ci_log() messages to the log buffer
+ *  normally they go to the  system console */
+extern void ci_log_buffer_till_fail(void) CI_HF;
+
+/*! Dump the contents of the log buffer to the system console */
+extern void ci_log_buffer_dump(void) CI_HF;
+
+
+/**********************************************************************
+ * Some useful pretty-printing.
+ */
+
+#ifdef  __linux__
+# define CI_SOCKCALL_FLAGS_FMT "%s%s%s%s%s%s%s%s%s%s%s"
+
+# define CI_SOCKCALL_FLAGS_PRI_ARG(x)          \
+  (((x) & MSG_OOB         ) ? "OOB "         :""),     \
+  (((x) & MSG_PEEK        ) ? "PEEK "        :""),     \
+  (((x) & MSG_DONTROUTE   ) ? "DONTROUTE "   :""),     \
+  (((x) & MSG_EOR         ) ? "EOR "         :""),     \
+  (((x) & MSG_CTRUNC      ) ? "CTRUNC "      :""),     \
+  (((x) & MSG_TRUNC       ) ? "TRUNC "       :""),     \
+  (((x) & MSG_WAITALL     ) ? "WAITALL "     :""),     \
+  (((x) & MSG_DONTWAIT    ) ? "DONTWAIT "    :""),     \
+  (((x) & MSG_NOSIGNAL    ) ? "NOSIGNAL "    :""),     \
+  (((x) & MSG_ERRQUEUE    ) ? "ERRQUEUE "    :""),     \
+  (((x) & MSG_CONFIRM     ) ? "CONFIRM "     :"")
+#endif
+
+#ifdef  _WIN32
+# define CI_SOCKCALL_FLAGS_FMT "%s%s%s"
+
+# define CI_SOCKCALL_FLAGS_PRI_ARG(x)          \
+  (((x) & MSG_OOB         ) ? "OOB "         :""),     \
+  (((x) & MSG_PEEK        ) ? "PEEK "        :""),     \
+  (((x) & MSG_DONTROUTE   ) ? "DONTROUTE "   :"")
+#endif
+
+#ifdef  __sun__
+# define CI_SOCKCALL_FLAGS_FMT "%s%s%s%s%s%s%s%s%s"
+
+# define CI_SOCKCALL_FLAGS_PRI_ARG(x)          \
+  (((x) & MSG_OOB         ) ? "OOB "         :""),     \
+  (((x) & MSG_PEEK        ) ? "PEEK "        :""),     \
+  (((x) & MSG_DONTROUTE   ) ? "DONTROUTE "   :""),     \
+  (((x) & MSG_EOR         ) ? "EOR "         :""),     \
+  (((x) & MSG_CTRUNC      ) ? "CTRUNC "      :""),     \
+  (((x) & MSG_TRUNC       ) ? "TRUNC "       :""),     \
+  (((x) & MSG_WAITALL     ) ? "WAITALL "     :""),     \
+  (((x) & MSG_DONTWAIT    ) ? "DONTWAIT "    :""),     \
+  (((x) & MSG_NOTIFICATION) ? "NOTIFICATION" :"")
+#endif
+
+#endif  /* __CI_TOOLS_LOG_H__ */
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/tools/platform/gcc_x86.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/tools/platform/gcc_x86.h       Mon Feb 18 
10:31:04 2008 +0000
@@ -0,0 +1,361 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_tools_platform  */
+
+#ifndef __CI_TOOLS_GCC_X86_H__
+#define __CI_TOOLS_GCC_X86_H__
+
+
+/**********************************************************************
+ * Free-running cycle counters.
+ */
+
+#define CI_HAVE_FRC64
+#define CI_HAVE_FRC32
+
+#define ci_frc32(pval)  __asm__ __volatile__("rdtsc" : "=a" (*pval) : : "edx")
+
+#if defined(__x86_64__)
+ci_inline void ci_frc64(ci_uint64* pval) {
+  /* temp fix until we figure how to get this out in one bite */          
+  ci_uint64 low, high;
+  __asm__ __volatile__("rdtsc" : "=a" (low) , "=d" (high));            
+  *pval = (high << 32) | low;
+}
+
+#else
+#define ci_frc64(pval)  __asm__ __volatile__("rdtsc" : "=A" (*pval))
+#endif
+
+#define ci_frc_flush()  /* ?? Need a pipeline barrier. */
+
+
+/**********************************************************************
+ * Atomic integer.
+ */
+
+/*
+** int  ci_atomic_read(a)         { return a->n;        }
+** void ci_atomic_set(a, v)       { a->n = v;           }
+** void ci_atomic_inc(a)          { ++a->n;             }
+** void ci_atomic_dec(a)          { --a->n;             }
+** int  ci_atomic_inc_and_test(a) { return ++a->n == 0; }
+** int  ci_atomic_dec_and_test(a) { return --a->n == 0; }
+** void ci_atomic_and(a, v)       { a->n &= v;          }
+** void ci_atomic_or(a, v)        { a->n |= v;          }
+*/
+
+typedef struct { volatile ci_int32 n; } ci_atomic_t;
+
+#define CI_ATOMIC_INITIALISER(i)  {(i)}
+
+static inline ci_int32  ci_atomic_read(const ci_atomic_t* a) { return a->n; }
+static inline void ci_atomic_set(ci_atomic_t* a, int v) { a->n = v; ci_wmb();  
 }
+
+static inline void ci_atomic_inc(ci_atomic_t* a)
+{ __asm__ __volatile__("lock; incl %0" : "+m" (a->n)); }
+
+ 
+static inline void ci_atomic_dec(ci_atomic_t* a)
+{ __asm__ __volatile__("lock; decl %0" : "+m" (a->n)); }
+
+static inline int ci_atomic_inc_and_test(ci_atomic_t* a) {
+  char r;
+  __asm__ __volatile__("lock; incl %0; sete %1"
+                      : "+m" (a->n), "=qm" (r));
+  return r;
+}
+
+static inline int ci_atomic_dec_and_test(ci_atomic_t* a) {
+  char r;
+  __asm__ __volatile__("lock; decl %0; sete %1"
+                      : "+m" (a->n), "=qm" (r));
+  return r;
+}
+
+ci_inline int
+ci_atomic_xadd (ci_atomic_t *a, int v) {
+   __asm__ ("lock xadd %0, %1" : "=r" (v), "+m" (a->n) : "0" (v));
+  return v;
+}
+ci_inline int
+ci_atomic_xchg (ci_atomic_t *a, int v) {
+   __asm__ ("lock xchg %0, %1" : "=r" (v), "+m" (a->n) : "0" (v));
+  return v;
+}
+
+ci_inline void ci_atomic32_or(volatile ci_uint32* p, ci_uint32 mask)
+{ __asm__ __volatile__("lock; orl %1, %0" : "+m" (*p) : "ir" (mask)); }
+
+ci_inline void ci_atomic32_and(volatile ci_uint32* p, ci_uint32 mask)
+{ __asm__ __volatile__("lock; andl %1, %0" : "+m" (*p) : "ir" (mask)); }
+
+ci_inline void ci_atomic32_add(volatile ci_uint32* p, ci_uint32 v)
+{ __asm__ __volatile__("lock; addl %1, %0" : "+m" (*p) : "ir" (v)); }
+
+#define ci_atomic_or(a, v)   ci_atomic32_or ((ci_uint32*) &(a)->n, (v))
+#define ci_atomic_and(a, v)  ci_atomic32_and((ci_uint32*) &(a)->n, (v))
+#define ci_atomic_add(a, v)  ci_atomic32_add((ci_uint32*) &(a)->n, (v))
+
+extern int ci_glibc_uses_nptl (void) CI_HF;
+extern int ci_glibc_nptl_broken(void) CI_HF;
+extern int ci_glibc_gs_get_is_multihreaded_offset (void) CI_HF;
+extern int ci_glibc_gs_is_multihreaded_offset CI_HV;
+
+#if !defined(__x86_64__)
+#ifdef __GLIBC__
+/* Returns non-zero if the calling process might be mulithreaded, returns 0 if
+ * it definitely isn't (i.e. if reimplementing this function for other
+ * architectures and platforms, you can safely just return 1).
+ */
+static inline int ci_is_multithreaded (void) {
+
+  while (1) {
+    if (ci_glibc_gs_is_multihreaded_offset >= 0) {
+      /* NPTL keeps a variable that tells us this hanging off gs (i.e. in 
thread-
+       * local storage); just return this
+       */
+      int r;
+      __asm__ __volatile__ ("movl %%gs:(%1), %0"
+                            : "=r" (r)
+                            : "r" (ci_glibc_gs_is_multihreaded_offset));
+      return r;
+    }
+
+    if (ci_glibc_gs_is_multihreaded_offset == -2) {
+      /* This means we've already determined that the libc version is NOT good
+       * for our funky "is multithreaded" hack
+       */
+      return 1;
+    }
+
+    /* If we get here, it means this is the first time the function has been
+     * called -- detect the libc version and go around again.
+     */
+    ci_glibc_gs_is_multihreaded_offset = 
ci_glibc_gs_get_is_multihreaded_offset ();
+
+    /* Go around again.  We do the test here rather than at the top so that we 
go
+     * quicker in the common the case
+     */
+  }
+}
+
+#else    /* def __GLIBC__ */
+
+#define ci_is_multithreaded() 1 /* ?? Is the the POSIX way of finding out */
+                                /*    whether the appication is single */
+                                /*    threaded? */
+
+#endif   /* def __GLIBC__ */
+
+#else    /* defined __x86_64__ */
+
+static inline int ci_is_multithreaded (void) {
+  /* Now easy way to tell on x86_64; so assume we're multithreaded */
+  return 1;
+}
+
+#endif    /* defined __x86_64__ */
+
+
+/**********************************************************************
+ * Compare and swap.
+ */
+
+#define CI_HAVE_COMPARE_AND_SWAP
+
+ci_inline int ci_cas32_succeed(volatile ci_int32* p, ci_int32 oldval,
+                               ci_int32 newval) {
+  char ret;
+  ci_int32 prevval;
+  __asm__ __volatile__("lock; cmpxchgl %3, %1; sete %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+ci_inline int ci_cas32_fail(volatile ci_int32* p, ci_int32 oldval,
+                            ci_int32 newval) {
+  char ret;
+  ci_int32 prevval;
+  __asm__ __volatile__("lock; cmpxchgl %3, %1; setne %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+#ifdef __x86_64__
+ci_inline int ci_cas64_succeed(volatile ci_int64* p, ci_int64 oldval,
+                              ci_int64 newval) {
+  char ret;
+  ci_int64 prevval;
+  __asm__ __volatile__("lock; cmpxchgq %3, %1; sete %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+ci_inline int ci_cas64_fail(volatile ci_int64* p, ci_int64 oldval,
+                           ci_int64 newval) {
+  char ret;
+  ci_int64 prevval;
+  __asm__ __volatile__("lock; cmpxchgq %3, %1; setne %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+#endif
+
+ci_inline int ci_cas32u_succeed(volatile ci_uint32* p, ci_uint32 oldval, 
ci_uint32 newval) {
+  char ret;
+  ci_uint32 prevval;
+  __asm__ __volatile__("lock; cmpxchgl %3, %1; sete %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+ci_inline int ci_cas32u_fail(volatile ci_uint32* p, ci_uint32 oldval, 
ci_uint32 newval) {
+  char ret;
+  ci_uint32 prevval;
+  __asm__ __volatile__("lock; cmpxchgl %3, %1; setne %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+ci_inline int ci_cas64u_succeed(volatile ci_uint64* p, ci_uint64 oldval,
+                              ci_uint64 newval) {
+  char ret;
+  ci_uint64 prevval;
+  __asm__ __volatile__("lock; cmpxchgq %3, %1; sete %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+ci_inline int ci_cas64u_fail(volatile ci_uint64* p, ci_uint64 oldval,
+                           ci_uint64 newval) {
+  char ret;
+  ci_uint64 prevval;
+  __asm__ __volatile__("lock; cmpxchgq %3, %1; setne %0"
+                      : "=q"(ret), "+m"(*p), "=a"(prevval)
+                      : "r"(newval), "a"(oldval));
+  return ret;
+}
+
+#ifdef __x86_64__
+
+# define ci_cas_uintptr_succeed(p,o,n)                         \
+    ci_cas64u_succeed((volatile ci_uint64*) (p), (o), (n))
+# define ci_cas_uintptr_fail(p,o,n)                            \
+    ci_cas64u_fail((volatile ci_uint64*) (p), (o), (n))
+
+#else
+
+# define ci_cas_uintptr_succeed(p,o,n)                         \
+    ci_cas32u_succeed((volatile ci_uint32*) (p), (o), (n))
+# define ci_cas_uintptr_fail(p,o,n)                            \
+    ci_cas32u_fail((volatile ci_uint32*) (p), (o), (n))
+
+#endif
+
+
+/**********************************************************************
+ * Atomic bit field.
+ */
+
+typedef ci_uint32  ci_bits;
+#define CI_BITS_N                      32u
+
+#define CI_BITS_DECLARE(name, n)                       \
+  ci_bits name[((n) + CI_BITS_N - 1u) / CI_BITS_N]
+
+ci_inline void ci_bits_clear_all(volatile ci_bits* b, int n_bits)
+{ memset((void*) b, 0, (n_bits+CI_BITS_N-1u) / CI_BITS_N * sizeof(ci_bits)); }
+
+ci_inline void ci_bit_set(volatile ci_bits* b, int i) {
+  __asm__ __volatile__("lock; btsl %1, %0"
+                      : "=m" (*b)
+                      : "Ir" (i));
+}
+
+ci_inline void ci_bit_clear(volatile ci_bits* b, int i) {
+  __asm__ __volatile__("lock; btrl %1, %0"
+                      : "=m" (*b)
+                      : "Ir" (i));
+}
+
+ci_inline int  ci_bit_test(volatile ci_bits* b, int i) {
+  char rc;
+  __asm__("btl %2, %1; setc %0"
+         : "=r" (rc)
+         : "m" (*b), "Ir" (i));
+  return rc;
+}
+
+ci_inline int ci_bit_test_and_set(volatile ci_bits* b, int i) {
+  char rc;
+  __asm__ __volatile__("lock; btsl %2, %1; setc %0"
+                      : "=r" (rc), "+m" (*b)
+                      : "Ir" (i));
+  return rc;
+}
+
+ci_inline int ci_bit_test_and_clear(volatile ci_bits* b, int i) {
+  char rc;
+  __asm__ __volatile__("lock; btrl %2, %1; setc %0"
+                      : "=r" (rc), "+m" (*b)
+                      : "Ir" (i));
+  return rc;
+}
+
+/* These mask ops only work within a single ci_bits word. */
+#define ci_bit_mask_set(b,m)   ci_atomic32_or((b), (m))
+#define ci_bit_mask_clear(b,m) ci_atomic32_and((b), ~(m))
+
+
+/**********************************************************************
+ * Misc.
+ */
+
+#if __GNUC__ >= 3
+# define ci_spinloop_pause()  __asm__("pause") 
+#else
+# define ci_spinloop_pause()  __asm__(".byte 0xf3, 0x90")
+#endif
+
+
+#define CI_HAVE_ADDC32
+#define ci_add_carry32(sum, v)  __asm__("addl %1, %0 ;"                        
  \
+                                       "adcl $0, %0 ;"                   \
+                                       : "=r" (sum)                      \
+                                       : "g" ((ci_uint32) v), "0" (sum))
+
+
+#endif  /* __CI_TOOLS_GCC_X86_H__ */
+
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 
drivers/xen/sfc_netback/ci/tools/platform/linux_kernel.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/tools/platform/linux_kernel.h  Mon Feb 18 
10:31:04 2008 +0000
@@ -0,0 +1,362 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+
+/*! \cidoxg_include_ci_tools_platform  */
+
+#ifndef __CI_TOOLS_LINUX_KERNEL_H__
+#define __CI_TOOLS_LINUX_KERNEL_H__
+
+/**********************************************************************
+ * Need to know the kernel version.
+ */
+
+#ifndef LINUX_VERSION_CODE
+# include <linux/version.h>
+# ifndef UTS_RELEASE
+   /* 2.6.18 onwards defines UTS_RELEASE in a separate header */
+#  include <linux/utsrelease.h>
+# endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || \
+    LINUX_VERSION_CODE >= KERNEL_VERSION(2,7,0)
+# error "Linux 2.6 required"
+#endif
+
+
+#include <linux/slab.h>     /* kmalloc / kfree */
+#include <linux/vmalloc.h>  /* vmalloc / vfree */
+#include <linux/interrupt.h>/* in_interrupt()  */
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/spinlock.h>
+#include <linux/highmem.h>
+#include <linux/smp_lock.h>
+#include <linux/ctype.h>
+#include <linux/uio.h>
+#include <asm/current.h>
+#include <asm/errno.h>
+#include <asm/kmap_types.h>
+#include <asm/semaphore.h>
+
+#include <ci/tools/config.h>
+
+#define ci_in_irq        in_irq
+#define ci_in_interrupt  in_interrupt
+#define ci_in_atomic     in_atomic
+
+
+/**********************************************************************
+ * Misc stuff.
+ */
+
+#ifdef BUG
+# define  CI_BOMB     BUG
+#endif
+
+ci_inline void* __ci_alloc(size_t n)
+{ return kmalloc(n, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)); }
+
+ci_inline void* __ci_atomic_alloc(size_t n)
+{ return kmalloc(n, GFP_ATOMIC ); }
+
+ci_inline void  __ci_free(void* p)     { return kfree(p);   }
+ci_inline void* __ci_vmalloc(size_t n) { return vmalloc(n); }
+ci_inline void  __ci_vfree(void* p)    { return vfree(p);   }
+
+
+#if CI_MEMLEAK_DEBUG_ALLOC_TABLE
+  #define ci_alloc(s)     ci_alloc_memleak_debug (s, __FILE__, __LINE__)
+  #define ci_atomic_alloc(s)  ci_atomic_alloc_memleak_debug(s, __FILE__, 
__LINE__)
+  #define ci_free         ci_free_memleak_debug
+  #define ci_vmalloc(s)   ci_vmalloc_memleak_debug (s, __FILE__,__LINE__)
+  #define ci_vfree        ci_vfree_memleak_debug
+  #define ci_alloc_fn     ci_alloc_fn_memleak_debug
+  #define ci_vmalloc_fn   ci_vmalloc_fn_memleak_debug
+#else /* !CI_MEMLEAK_DEBUG_ALLOC_TABLE */
+  #define ci_alloc_fn     __ci_alloc
+  #define ci_vmalloc_fn   __ci_vmalloc
+#endif 
+
+#ifndef ci_alloc
+  #define ci_atomic_alloc __ci_atomic_alloc
+  #define ci_alloc        __ci_alloc
+  #define ci_free         __ci_free
+  #define ci_vmalloc      __ci_vmalloc
+  #define ci_vmalloc_fn   __ci_vmalloc
+  #define ci_vfree        __ci_vfree
+#endif
+
+#define ci_sprintf        sprintf
+#define ci_vsprintf       vsprintf
+#define ci_snprintf       snprintf
+#define ci_vsnprintf      vsnprintf
+#define ci_sscanf         sscanf
+
+
+#define CI_LOG_FN_DEFAULT  ci_log_syslog
+
+
+/*--------------------------------------------------------------------
+ *
+ * irqs_disabled - needed for kmap helpers on some kernels 
+ *
+ *--------------------------------------------------------------------*/
+#ifdef irqs_disabled
+# define ci_irqs_disabled irqs_disabled
+#else
+# if defined(__i386__) | defined(__x86_64__)
+#   define ci_irqs_disabled(x)                  \
+  ({                                            \
+    unsigned long flags;                        \
+    local_save_flags(flags);                    \
+    !(flags & (1<<9));                          \
+  })
+# else
+#  error "Need to implement irqs_disabled() for your architecture"
+# endif
+#endif
+
+
+/**********************************************************************
+ * kmap helpers. 
+ *
+ * Use ci_k(un)map for code paths which are not in an atomic context.
+ * For atomic code you need to use ci_k(un)map_in_atomic. This will grab
+ * one of the per-CPU kmap slots.
+ *
+ * NB in_interrupt != in_irq. If you don't know the difference then
+ * don't use kmap_in_atomic
+ *
+ * 2.4 allocates kmap slots by function. We are going to re-use the
+ * skb module's slot - we also use the same interlock
+ * 
+ * 2.6 allocates kmap slots by type as well as by function. We are
+ * going to use the currently (2.6.10) unsused SOFTIRQ slot 
+ *
+ */
+
+ci_inline void* ci_kmap(struct page *page) {
+  CI_DEBUG(if( ci_in_atomic() | ci_in_interrupt() | ci_in_irq() )  BUG());
+  return kmap(page);
+}
+
+ci_inline void ci_kunmap(struct page *page) {
+  kunmap(page);
+}
+
+#define CI_KM_SLOT KM_SOFTIRQ0
+
+
+typedef struct semaphore ci_semaphore_t;
+
+ci_inline void
+ci_sem_init (ci_semaphore_t *sem, int val) {
+  sema_init (sem, val);
+}
+
+ci_inline void
+ci_sem_down (ci_semaphore_t *sem) {
+  down (sem);
+}
+
+ci_inline int
+ci_sem_trydown (ci_semaphore_t *sem) {
+  return down_trylock (sem);
+}
+
+ci_inline void
+ci_sem_up (ci_semaphore_t *sem) {
+  up (sem);
+}
+
+ci_inline int
+ci_sem_get_count(ci_semaphore_t *sem) {
+  return sem->count.counter;
+}
+
+ci_inline void* ci_kmap_in_atomic(struct page *page) 
+{
+  CI_DEBUG(if( ci_in_irq() )  BUG());
+
+  /* iSCSI can call without in_interrupt() but with irqs_disabled()
+     and in a context that can't sleep, so we need to check that
+     too */
+  if(ci_in_interrupt() || ci_irqs_disabled())
+    return kmap_atomic(page, CI_KM_SLOT);
+  else
+    return kmap(page);
+}
+
+ci_inline void ci_kunmap_in_atomic(struct page *page, void* kaddr) 
+{
+  CI_DEBUG(if( ci_in_irq() )  BUG());
+
+  /* iSCSI can call without in_interrupt() but with irqs_disabled()
+     and in a context that can't sleep, so we need to check that
+     too */
+  if(ci_in_interrupt() || ci_irqs_disabled())
+    kunmap_atomic(kaddr, CI_KM_SLOT);
+  else
+    kunmap(page);
+}
+
+/**********************************************************************
+ * spinlock implementation: used by <ci/tools/spinlock.h>
+ */
+
+#define CI_HAVE_SPINLOCKS
+
+typedef ci_uintptr_t                           ci_lock_holder_t;
+#define ci_lock_thisthread             (ci_lock_holder_t)current               
        
+#define ci_lock_no_holder     (ci_lock_holder_t)NULL
+
+typedef spinlock_t                     ci_lock_i;
+typedef spinlock_t                     ci_irqlock_i;
+typedef unsigned long                  ci_irqlock_state_t;
+
+#define IRQLOCK_CYCLES  500000
+
+#define ci_lock_ctor_i(l)              spin_lock_init(l)
+#define ci_lock_dtor_i(l)              do{}while(0)
+#define ci_lock_lock_i(l)              spin_lock(l)
+#define ci_lock_trylock_i(l)           spin_trylock(l)
+#define ci_lock_unlock_i(l)            spin_unlock(l)
+
+#define ci_irqlock_ctor_i(l)           spin_lock_init(l)
+#define ci_irqlock_dtor_i(l)           do{}while(0)
+#define ci_irqlock_lock_i(l,s)         spin_lock_irqsave(l,*(s))
+#define ci_irqlock_unlock_i(l,s)       spin_unlock_irqrestore(l, *(s))
+
+
+/**********************************************************************
+ * register access
+ */
+
+#include <asm/io.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
+typedef volatile void __iomem* ioaddr_t;
+#else
+typedef unsigned long ioaddr_t;
+#endif
+
+
+
+/**********************************************************************
+ * thread implementation -- kernel dependancies probably should be
+ * moved to driver/linux_kernel.h
+ */
+
+#define ci_linux_daemonize(name) daemonize(name)
+
+#include <linux/workqueue.h>
+
+
+typedef struct {
+  void*                        (*fn)(void* arg);
+  void*                        arg;
+  const char*          name;
+  int                  thrd_id;
+  struct completion    exit_event;
+  struct work_struct   keventd_witem;
+} ci_kernel_thread_t;
+
+
+typedef ci_kernel_thread_t* cithread_t;
+
+
+extern int cithread_create(cithread_t* tid, void* (*fn)(void*), void* arg,
+                          const char* name);
+extern int cithread_detach(cithread_t kt);
+extern int cithread_join(cithread_t kt);
+
+
+/* Kernel sysctl variables. */
+extern int sysctl_tcp_wmem[3];
+extern int sysctl_tcp_rmem[3];
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+#define LINUX_HAS_SYSCTL_MEM_MAX
+extern ci_uint32 sysctl_wmem_max;
+extern ci_uint32 sysctl_rmem_max;
+#endif
+
+
+/*--------------------------------------------------------------------
+ *
+ * ci_bigbuf_t: An abstraction of a large buffer.  Needed because in the
+ * Linux kernel, large buffers need to be allocated with vmalloc(), whereas
+ * smaller buffers should use kmalloc().  This abstraction chooses the
+ * appropriate mechansim.
+ *
+ *--------------------------------------------------------------------*/
+
+typedef struct {
+  char*                p;
+  int          is_vmalloc;
+} ci_bigbuf_t;
+
+
+ci_inline int ci_bigbuf_alloc(ci_bigbuf_t* bb, size_t bytes) {
+  if( bytes >= CI_PAGE_SIZE && ! ci_in_atomic() ) {
+    bb->is_vmalloc = 1;
+    if( (bb->p = vmalloc(bytes)) )  return 0;
+  }
+  bb->is_vmalloc = 0;
+  bb->p = kmalloc(bytes, ci_in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+  return bb->p ? 0 : -ENOMEM;
+}
+
+ci_inline void ci_bigbuf_free(ci_bigbuf_t* bb) {
+  if( bb->is_vmalloc )  vfree(bb->p);
+  else                  kfree(bb->p);
+}
+
+ci_inline char* ci_bigbuf_ptr(ci_bigbuf_t* bb)
+{ return bb->p; }
+
+/**********************************************************************
+ * struct iovec abstraction (for Windows port)
+ */
+
+typedef struct iovec ci_iovec;
+
+/* Accessors for buffer/length */
+#define CI_IOVEC_BASE(i) ((i)->iov_base)
+#define CI_IOVEC_LEN(i)  ((i)->iov_len)
+
+/**********************************************************************
+ * Signals
+ */
+
+ci_inline void
+ci_send_sig(int signum)
+{
+  send_sig(signum, current, 0);
+}
+
+#endif  /* __CI_TOOLS_LINUX_KERNEL_H__ */
+/*! \cidoxg_end */
diff -r 651fc2abdd5d -r af0d925ba938 drivers/xen/sfc_netback/ci/tools/sysdep.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/xen/sfc_netback/ci/tools/sysdep.h Mon Feb 18 10:31:04 2008 +0000
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * Copyright 2002-2005: Level 5 Networks Inc.
+ * Copyright 2005-2008: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Maintained by Solarflare Communications
+ *  <linux-xen-drivers@xxxxxxxxxxxxxx>
+ *  <onload-dev@xxxxxxxxxxxxxx>
+ *
+ * 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, incorporated herein by reference.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ ****************************************************************************
+ */
+
+/*! \cidoxg_include_ci_tools */
+
+#ifndef __CI_TOOLS_SYSDEP_H__
+#define __CI_TOOLS_SYSDEP_H__
+
+/* Make this header self-sufficient */
+#include <ci/compat.h>
+#include <ci/tools/log.h>
+#include <ci/tools/debug.h>
+
+
+/**********************************************************************
+ * Platform dependencies.
+ */
+
+#if defined(__KERNEL__)
+
+# if defined(__linux__)
+#  include <ci/tools/platform/linux_kernel.h>
+# elif defined(_WIN32)
+#  include <ci/tools/platform/win32_kernel.h>
+# elif defined(__sun__)
+#  include <ci/tools/platform/sunos_kernel.h>
+# else
+#  error Unknown platform.
+# endif
+
+#elif defined(_WIN32)
+
+# include <ci/tools/platform/win32.h>
+
+#elif defined(__unix__)
+
+# include <ci/tools/platform/unix.h>
+
+#else
+
+# error Unknown platform.
+
+#endif
+
+#if defined(__linux__)
+/*! Linux sendfile() support enable/disable. */
+# define CI_HAVE_SENDFILE            /* provide sendfile i/f */
+
+# define CI_HAVE_OS_NOPAGE
+#endif
+
+#if defined(__sun__)
+# define CI_HAVE_SENDFILE           /* provide sendfile i/f */
+# define CI_HAVE_SENDFILEV           /* provide sendfilev i/f */
+
+# define CI_IOCTL_SENDFILE           /*  use efrm CI_SENDFILEV ioctl */
+#endif
+
+#if defined(_WIN32)
+typedef ci_uint32 ci_uerr_t; /* range of OS user-mode return codes */
+typedef ci_uint32 ci_kerr_t; /* range of OS kernel-mode return codes */
+#elif defined(__unix__)
+typedef ci_int32 ci_uerr_t; /* range of OS user-mode return codes */
+typedef ci_int32 ci_kerr_t; /* range of OS kernel-mode return codes */
+#endif
+
+
+/**********************************************************************
+ * Compiler and processor dependencies.
+ */
+
+#if defined(__GNUC__)
+
+#if defined(__i386__) || defined(__x86_64__)
+# include <ci/tools/platform/gcc_x86.h>
+#elif defined(__PPC__)
+#  include <ci/tools/platform/gcc_ppc.h>
+#elif defined(__ia64__)
+#  include <ci/tools/platform/gcc_ia64.h>
+#else
+# error Unknown processor.
+#endif
+
+#elif defined(_MSC_VER)
+
+#if defined(__i386__)
+# include <ci/tools/platform/msvc_x86.h>
+# elif defined(__x86_64__)
+# include <ci/tools/platform/msvc_x86_64.h>
+#else
+# error Unknown processor.
+#endif
+
+#elif defined(__PGI)
+
+# include <ci/tools/platform/pg_x86.h>
+
+#elif defined(__INTEL_COMPILER)
+
+/* Intel compilers v7 claim to be very gcc compatible. */
+# include <ci/tools/platform/gcc_x86.h>
+
+#else
+# error Unknown compiler.
+#endif
+
+
+#endif  /* __CI_TOOLS_SYSDEP_H__ */
+
+/*! \cidoxg_end */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] Solarflare: PV netback accelerator., Xen patchbot-linux-2.6.18-xen <=