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

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



# 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


 


Rackspace

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