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

[Xen-changelog] [linux-2.6.18-xen] Update Solarflare Communications net driver to version 3.0.2.2074



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1262955949 0
# Node ID 0b5ca7cdbdfc8857229475519b23a78401829e91
# Parent  896902106793c0a7e8759cbddc97b9367746863e
Update Solarflare Communications net driver to version 3.0.2.2074
Bring net driver in Xen tree in line with kernel.org tree
Add support for new SFC9000 series NICs

Signed-off-by: Kieran Mansley <kmansley@xxxxxxxxxxxxxx>
---
 drivers/net/sfc/alaska.c         |  159 -
 drivers/net/sfc/boards.c         |  528 ----
 drivers/net/sfc/boards.h         |   51 
 drivers/net/sfc/config.h         |    1 
 drivers/net/sfc/ethtool.h        |   44 
 drivers/net/sfc/extraversion.h   |    4 
 drivers/net/sfc/falcon.h         |  154 -
 drivers/net/sfc/falcon_hwdefs.h  | 1638 -------------
 drivers/net/sfc/falcon_io.h      |  260 --
 drivers/net/sfc/gmii.h           |  212 -
 drivers/net/sfc/i2c-direct.c     |  398 ---
 drivers/net/sfc/i2c-direct.h     |  108 
 drivers/net/sfc/lm87_support.c   |  295 --
 drivers/net/sfc/lm87_support.h   |   58 
 drivers/net/sfc/mentormac.c      |  506 ----
 drivers/net/sfc/phy.c            |   28 
 drivers/net/sfc/pm8358_phy.c     |  204 -
 drivers/net/sfc/rx.h             |   61 
 drivers/net/sfc/sfe4001.c        |  315 --
 drivers/net/sfc/tx.h             |   41 
 drivers/net/sfc/xenpack.h        |   80 
 drivers/net/sfc/xfp_phy.c        |  203 -
 MAINTAINERS                      |   11 
 drivers/net/sfc/Kconfig          |   36 
 drivers/net/sfc/Makefile         |   17 
 drivers/net/sfc/autocompat.h     |   98 
 drivers/net/sfc/bitfield.h       |  257 +-
 drivers/net/sfc/debugfs.c        |  226 +
 drivers/net/sfc/debugfs.h        |  138 -
 drivers/net/sfc/driverlink.c     |  420 +--
 drivers/net/sfc/driverlink.h     |   59 
 drivers/net/sfc/driverlink_api.h |  507 +---
 drivers/net/sfc/efx.c            | 2393 +++++++++++---------
 drivers/net/sfc/efx.h            |  115 
 drivers/net/sfc/efx_ioctl.h      |   71 
 drivers/net/sfc/enum.h           |  153 -
 drivers/net/sfc/ethtool.c        |  623 +++--
 drivers/net/sfc/falcon.c         | 4633 +++++++++++++--------------------------
 drivers/net/sfc/falcon_boards.c  |  739 ++++++
 drivers/net/sfc/falcon_gmac.c    |  314 --
 drivers/net/sfc/falcon_xmac.c    |  814 +-----
 drivers/net/sfc/io.h             |  260 ++
 drivers/net/sfc/ioctl.c          |   70 
 drivers/net/sfc/kernel_compat.c  |  479 +++-
 drivers/net/sfc/kernel_compat.h  | 1217 +++++++++-
 drivers/net/sfc/linux_mdio.c     |  430 +++
 drivers/net/sfc/linux_mdio.h     |  347 ++
 drivers/net/sfc/lm87.c           |  959 ++++++++
 drivers/net/sfc/lm90.c           |  829 ++++++
 drivers/net/sfc/mac.h            |   29 
 drivers/net/sfc/mcdi.c           | 1178 +++++++++
 drivers/net/sfc/mcdi.h           |  131 +
 drivers/net/sfc/mcdi_mac.c       |  152 +
 drivers/net/sfc/mcdi_pcol.h      | 1729 ++++++++++++++
 drivers/net/sfc/mcdi_phy.c       |  616 +++++
 drivers/net/sfc/mdio_10g.c       |  514 +---
 drivers/net/sfc/mdio_10g.h       |  295 --
 drivers/net/sfc/mtd.c            | 1158 +++++----
 drivers/net/sfc/net_driver.h     |  763 +++---
 drivers/net/sfc/nic.c            | 1785 +++++++++++++++
 drivers/net/sfc/nic.h            |  307 ++
 drivers/net/sfc/null_phy.c       |  112 
 drivers/net/sfc/phy.h            |   83 
 drivers/net/sfc/qt202x_phy.c     |  478 ++++
 drivers/net/sfc/regs.h           | 3168 ++++++++++++++++++++++++++
 drivers/net/sfc/rx.c             |  828 +-----
 drivers/net/sfc/selftest.c       | 1039 ++++----
 drivers/net/sfc/selftest.h       |   49 
 drivers/net/sfc/siena.c          |  743 ++++++
 drivers/net/sfc/spi.h            |  178 -
 drivers/net/sfc/tenxpress.c      | 1359 ++++++-----
 drivers/net/sfc/tx.c             | 1005 +++++++-
 drivers/net/sfc/txc43128_phy.c   |  446 +--
 drivers/net/sfc/workarounds.h    |   80 
 74 files changed, 24228 insertions(+), 15560 deletions(-)

diff -r 896902106793 -r 0b5ca7cdbdfc MAINTAINERS
--- a/MAINTAINERS       Fri Jan 08 11:56:04 2010 +0000
+++ b/MAINTAINERS       Fri Jan 08 13:05:49 2010 +0000
@@ -2559,11 +2559,12 @@ S:      Supported
 S:     Supported
 
 SFC NETWORK DRIVER
-P:     Steve Hodgson
-P:     Ben Hutchings
-P:     Robert Stonehouse
-M:     linux-net-drivers@xxxxxxxxxxxxxx
-S:     Supported
+M:     Solarflare linux maintainers <linux-net-drivers@xxxxxxxxxxxxxx>
+M:     Steve Hodgson <shodgson@xxxxxxxxxxxxxx>
+M:     Ben Hutchings <bhutchings@xxxxxxxxxxxxxx>
+L:     netdev@xxxxxxxxxxxxxxx
+S:     Supported
+F:     drivers/net/sfc/
 
 SGI VISUAL WORKSTATION 320 AND 540
 P:     Andrey Panin
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/Kconfig
--- a/drivers/net/sfc/Kconfig   Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/Kconfig   Fri Jan 08 13:05:49 2010 +0000
@@ -1,35 +1,39 @@ config SFC
 config SFC
-       tristate "Solarflare Solarstorm SFC4000 support"
+       tristate "Solarflare Solarstorm SFC4000/SFC9000-family support"
        depends on PCI && INET
-       select MII
        select CRC32
+       select I2C
+       select I2C_ALGOBIT
        help
          This driver supports 10-gigabit Ethernet cards based on
-         the Solarflare Communications Solarstorm SFC4000 controller.
+         the Solarflare Communications Solarstorm SFC4000 and
+         SFC9000-family controllers.
 
          To compile this driver as a module, choose M here.  The module
          will be called sfc.
 
 config SFC_DEBUGFS
-       bool "Solarflare Solarstorm SFC4000 debugging support"
-       depends on SFC && DEBUG_FS
-       default N
-       help
-         This option creates an "sfc" subdirectory of debugfs with
-         debugging information for the SFC4000 driver.
+        bool "Solarflare Solarstorm SFC4000 debugging support"
+        depends on SFC && DEBUG_FS
+        default N
+        help
+          This option creates an "sfc" subdirectory of debugfs with
+          debugging information for the SFC4000 driver.
 
-         If unsure, say N.
+          If unsure, say N.
 
 config SFC_MTD
-       depends on SFC && MTD && MTD_PARTITIONS
-       tristate "Solarflare Solarstorm SFC4000 flash/EEPROM support"
+       bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support"
+       depends on SFC && MTD && !(SFC=y && MTD=m)
+       default y
        help
-         This module exposes the on-board flash and/or EEPROM memory as
-         MTD devices (e.g. /dev/mtd1).  This makes it possible to upload a
-         new boot ROM to the NIC.
+         This exposes the on-board flash and/or EEPROM memory as MTD
+         devices (e.g. /dev/mtd1).  This makes it possible to upload
+         new boot code to the NIC.
 
 config SFC_RESOURCE
         depends on SFC && X86
-        tristate "Solarflare Solarstorm SFC4000 resource driver"
+        tristate "Solarflare Solarstorm SFC4000/SFC9000 resource driver"
         help
           This module provides the SFC resource manager driver.
+
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/Makefile
--- a/drivers/net/sfc/Makefile  Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/Makefile  Fri Jan 08 13:05:49 2010 +0000
@@ -1,13 +1,14 @@ sfc-y                 += efx.o falcon.o tx.o rx.o ment
-sfc-y                  += efx.o falcon.o tx.o rx.o mentormac.o falcon_gmac.o \
-                          falcon_xmac.o alaska.o i2c-direct.o selftest.o \
-                          driverlink.o ethtool.o xfp_phy.o mdio_10g.o \
-                          txc43128_phy.o tenxpress.o lm87_support.o boards.o \
-                          sfe4001.o pm8358_phy.o null_phy.o kernel_compat.o
+
+sfc-y                  += efx.o nic.o falcon.o siena.o tx.o rx.o \
+                          falcon_gmac.o falcon_xmac.o mcdi_mac.o selftest.o \
+                          driverlink.o ethtool.o qt202x_phy.o mdio_10g.o \
+                          tenxpress.o falcon_boards.o mcdi.o linux_mdio.o \
+                          mcdi_phy.o ioctl.o kernel_compat.o lm87.o lm90.o
+sfc-$(CONFIG_SFC_MTD)  += mtd.o
 sfc-$(CONFIG_SFC_DEBUGFS) += debugfs.o
+
 obj-$(CONFIG_SFC)      += sfc.o
-
-sfc_mtd-y = mtd.o
-obj-$(CONFIG_SFC_MTD)  += sfc_mtd.o
 
 obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/
 
+EXTRA_CFLAGS += -DEFX_USE_KCOMPAT=1 -Wno-unused-label
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/alaska.c
--- a/drivers/net/sfc/alaska.c  Fri Jan 08 11:56:04 2010 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005:      Fen Systems Ltd.
- * Copyright 2006-2007: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-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 "net_driver.h"
-#include <linux/ethtool.h>
-#include "gmii.h"
-#include "phy.h"
-
-/* Marvell 88E1111 "Alaska" PHY control */
-#define ALASKA_PHY_SPECIFIC 16
-#define ALASKA_ALLOW_SLEEP 0x0200
-
-#define ALASKA_EXTENDED_CONTROL 20
-#define EXTENDED_LINE_LOOPBACK 0x8000
-
-#define ALASKA_LED_CONTROL 24
-#define LED_BLINK_MASK 0x0700
-#define LED_BLINK_FAST 0x0100
-#define LED_BLINK_SLOW 0x0300
-#define LED_TX_CTRL_MASK 0x0041
-#define LED_TX_CTRL_LINK_AND_ACTIVITY 0x0001
-
-#define ALASKA_LED_OVERRIDE 25
-#define LED_LINK1000_MASK 0x0030
-#define LED_LINK1000_BLINK 0x0010
-#define LED_TX_MASK 0x0003
-#define LED_TX_BLINK 0x0001
-
-static void alaska_reconfigure(struct efx_nic *efx)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       u32 bmcr, phy_ext;
-
-       /* Configure line loopback if requested */
-       phy_ext = gmii->mdio_read(gmii->dev, gmii->phy_id,
-                                 ALASKA_EXTENDED_CONTROL);
-       if (efx->loopback_mode == LOOPBACK_NETWORK)
-               phy_ext |= EXTENDED_LINE_LOOPBACK;
-       else
-               phy_ext &= ~EXTENDED_LINE_LOOPBACK;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_EXTENDED_CONTROL,
-                        phy_ext);
-
-       /* Configure PHY loopback if requested */
-       bmcr = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR);
-       if (efx->loopback_mode == LOOPBACK_PHY)
-               bmcr |= BMCR_LOOPBACK;
-       else
-               bmcr &= ~BMCR_LOOPBACK;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, MII_BMCR, bmcr);
-
-       /* Read link up status */
-       if (efx->loopback_mode == LOOPBACK_NONE)
-               efx->link_up = mii_link_ok(gmii);
-       else
-               efx->link_up = 1;
-
-       /* Determine link options from PHY */
-       if (gmii->force_media) {
-               efx->link_options = gmii_forced_result(bmcr);
-       } else {
-               int lpa = gmii_lpa(gmii);
-               int adv = gmii_advertised(gmii);
-               efx->link_options = gmii_nway_result(adv & lpa);
-       }
-}
-
-static void alaska_clear_interrupt(struct efx_nic *efx)
-{
-       struct mii_if_info *gmii = &efx->mii;
-
-       /* Read interrupt status register to clear */
-       gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_ISR);
-}
-
-static int alaska_init(struct efx_nic *efx)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       u32 ier, leds, ctrl_1g, phy_spec;
-
-       /* Read ISR to clear any outstanding PHY interrupts */
-       gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_ISR);
-
-       /* Enable PHY interrupts */
-       ier = gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_IER);
-       ier |= IER_LINK_CHG;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, GMII_IER, ier);
-
-       /* Remove 1G half-duplex as unsupported in Mentor MAC */
-       ctrl_1g = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
-       ctrl_1g &= ~(ADVERTISE_1000HALF);
-       gmii->mdio_write(gmii->dev, gmii->phy_id, MII_CTRL1000, ctrl_1g);
-
-       /*
-        * The PHY can save power when there is no external connection
-        * (sleep mode).  However, this is incompatible with PHY
-        * loopback, and if enable and disable it quickly the PHY can
-        * go to sleep even when sleep mode is disabled.  (SFC bug
-        * 9309.)  Therefore we disable it all the time.
-        */
-       phy_spec = gmii->mdio_read(gmii->dev, gmii->phy_id,
-                                  ALASKA_PHY_SPECIFIC);
-       phy_spec &= ~ALASKA_ALLOW_SLEEP;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_PHY_SPECIFIC,
-                        phy_spec);
-
-       /* Configure LEDs */
-       leds = gmii->mdio_read(gmii->dev, gmii->phy_id, ALASKA_LED_CONTROL);
-       leds &= ~(LED_BLINK_MASK | LED_TX_CTRL_MASK);
-       leds |= (LED_BLINK_FAST | LED_TX_CTRL_LINK_AND_ACTIVITY);
-       gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_LED_CONTROL, leds);
-
-       return 0;
-}
-
-static void alaska_fini(struct efx_nic *efx)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       u32 ier;
-
-       /* Disable PHY interrupts */
-       ier = gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_IER);
-       ier &= ~IER_LINK_CHG;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, GMII_IER, ier);
-}
-
-
-struct efx_phy_operations alaska_phy_operations = {
-       .init            = alaska_init,
-       .fini            = alaska_fini,
-       .reconfigure     = alaska_reconfigure,
-       .clear_interrupt = alaska_clear_interrupt,
-       .loopbacks       = (1 << LOOPBACK_PHY) | (1 << LOOPBACK_NETWORK),
-       .startup_loopback = LOOPBACK_PHY,
-};
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/autocompat.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/sfc/autocompat.h      Fri Jan 08 13:05:49 2010 +0000
@@ -0,0 +1,98 @@
+#define EFX_HAVE_OLD_NAPI yes
+#define EFX_HAVE_OLD_CSUM yes
+#define EFX_HAVE_OLD_IP_FAST_CSUM yes
+// #define EFX_NEED_BYTEORDER_TYPES
+#define EFX_NEED_CSUM_UNFOLDED yes
+// #define EFX_NEED_CSUM_TCPUDP_NOFOLD
+// #define EFX_NEED_DEV_NOTICE
+// #define EFX_NEED_DUMMY_PCI_DISABLE_MSI
+// #define EFX_NEED_DUMMY_MSIX
+// #define EFX_NEED_ENABLE_MSIX
+// #define EFX_HAVE_GRO
+// #define EFX_NEED_GFP_T
+#define EFX_NEED_HEX_DUMP yes
+// #define EFX_NEED_HEX_DUMP_CONST_FIX
+// #define EFX_NEED_IF_MII
+#define EFX_HAVE_IRQ_HANDLER_REGS yes
+#define EFX_NEED_IRQ_HANDLER_T yes
+// #define EFX_NEED_KZALLOC
+// #define EFX_NEED_MII_CONSTANTS
+#define EFX_NEED_MII_ADVERTISE_FLOWCTRL yes
+#define EFX_NEED_MII_RESOLVE_FLOWCTRL_FDX yes
+// #define EFX_HAVE_LINUX_MDIO_H
+// #define EFX_NEED_MSECS_TO_JIFFIES
+// #define EFX_NEED_MDELAY
+// #define EFX_NEED_MSLEEP
+// #define EFX_NEED_SSLEEP
+// #define EFX_NEED_MTD_ERASE_CALLBACK
+// #define EFX_NEED_MUTEX
+// #define EFX_NEED_NETDEV_ALLOC_SKB
+#define EFX_NEED_NETDEV_TX_T yes
+#define EFX_NEED_NETIF_NAPI_DEL yes
+// #define EFX_NEED_NETIF_TX_LOCK
+#define EFX_NEED_NETIF_ADDR_LOCK yes
+#define EFX_NEED_PCI_CLEAR_MASTER yes
+// #define EFX_NEED_PCI_MATCH_ID
+// #define EFX_NEED_PCI_SAVE_RESTORE_WRAPPERS
+#define EFX_NEED_PRINT_MAC yes
+// #define EFX_NEED_RANDOM_ETHER_ADDR
+// #define EFX_NEED_RESOURCE_SIZE_T
+// #define EFX_NEED_RTNL_TRYLOCK
+// #define EFX_HAVE_ROUND_JIFFIES_UP
+// #define EFX_NEED_SAFE_LISTS
+// #define EFX_NEED_SCHEDULE_TIMEOUT_INTERRUPTIBLE
+// #define EFX_NEED_SCHEDULE_TIMEOUT_UNINTERRUPTIBLE
+// #define EFX_NEED_SETUP_TIMER
+#define EFX_NEED_SKB_HEADER_MACROS yes
+// #define EFX_NEED_ETH_HDR
+#define EFX_NEED_TCP_HDR yes
+#define EFX_NEED_IP_HDR yes
+#define EFX_NEED_IPV6_HDR yes
+#define EFX_NEED_WORK_API_WRAPPERS yes
+// #define EFX_USE_CANCEL_DELAYED_WORK_SYNC
+// #define EFX_USE_CANCEL_WORK_SYNC
+// #define EFX_USE_ETHTOOL_ETH_TP_MDIX
+#define EFX_USE_ETHTOOL_GET_PERM_ADDR yes
+// #define EFX_USE_ETHTOOL_FLAGS
+// #define EFX_USE_ETHTOOL_LP_ADVERTISING
+// #define EFX_USE_ETHTOOL_MDIO_SUPPORT
+#define EFX_USE_LINUX_IO_H yes
+#define EFX_USE_LINUX_UACCESS_H yes
+#define EFX_USE_MTD_ERASE_FAIL_ADDR yes
+#define EFX_USE_MTD_WRITESIZE yes
+// #define EFX_USE_NETDEV_STATS
+// #define EFX_USE_PCI_DEV_REVISION
+// #define EFX_USE_NETDEV_VLAN_FEATURES
+#define EFX_USE_I2C_LEGACY yes
+#define EFX_NEED_I2C_NEW_DUMMY yes
+// #define EFX_HAVE_OLD_I2C_DRIVER_PROBE
+// #define EFX_HAVE_OLD_I2C_NEW_DUMMY
+// #define EFX_USE_I2C_DRIVER_NAME
+#define EFX_HAVE_HWMON_H yes
+// #define EFX_NEED_HWMON_VID
+// #define EFX_HAVE_I2C_SENSOR_H
+#define EFX_HAVE_HWMON_CLASS_DEVICE yes
+// #define EFX_HAVE_OLD_DEVICE_ATTRIBUTE
+#define EFX_NEED_BOOL yes
+// #define EFX_USE_ETHTOOL_GET_SSET_COUNT
+// #define EFX_HAVE_ETHTOOL_RESET
+#define EFX_NEED_I2C_LOCK_ADAPTER yes
+// #define EFX_USE_I2C_BUS_SEMAPHORE
+#define EFX_HAVE_OLD_PCI_DMA_MAPPING_ERROR yes
+// #define EFX_HAVE_LINUX_SEMAPHORE_H
+#define EFX_NEED_DEV_GET_STATS yes
+#define EFX_HAVE_OLD_CPUMASK_SCNPRINTF yes
+#define EFX_USE_PM yes
+// #define EFX_USE_PM_EXT_OPS
+// #define EFX_USE_DEV_PM_OPS
+#define EFX_NEED_ATOMIC_CMPXCHG yes
+#define EFX_NEED_WARN_ON yes
+// #define EFX_NEED_WAIT_EVENT_TIMEOUT
+// #define EFX_NEED_ETHTOOL_CONSTANTS
+#define EFX_NEED_PCI_WAKE_FROM_D3 yes
+// #define EFX_HAVE_DEV_DISABLE_LRO
+#define EFX_NEED_UNMASK_MSIX_VECTORS yes
+// #define EFX_NEED_FOR_EACH_PCI_DEV
+#define EFX_NEED_SCSI_SGLIST yes
+#define EFX_NEED_SG_NEXT yes
+// #define EFX_NEED_KFIFO
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/bitfield.h
--- a/drivers/net/sfc/bitfield.h        Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/bitfield.h        Fri Jan 08 13:05:49 2010 +0000
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2009 Solarflare Communications Inc.
  *
  * 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 EFX_BITFIELD_H
@@ -54,6 +37,8 @@
 #define EFX_DWORD_2_WIDTH 32
 #define EFX_DWORD_3_LBN 96
 #define EFX_DWORD_3_WIDTH 32
+#define EFX_QWORD_0_LBN 0
+#define EFX_QWORD_0_WIDTH 64
 
 /* Specified attribute (e.g. LBN) of the specified field */
 #define EFX_VAL(field, attribute) field ## _ ## attribute
@@ -69,9 +54,9 @@
  *
  * The maximum width mask that can be generated is 64 bits.
  */
-#define EFX_MASK64(field)                                      \
-       (EFX_WIDTH(field) == 64 ? ~((u64) 0) :          \
-        (((((u64) 1) << EFX_WIDTH(field))) - 1))
+#define EFX_MASK64(width)                      \
+       ((width) == 64 ? ~((u64) 0) :           \
+        (((((u64) 1) << (width))) - 1))
 
 /* Mask equal in width to the specified field.
  *
@@ -80,9 +65,9 @@
  * The maximum width mask that can be generated is 32 bits.  Use
  * EFX_MASK64 for higher width fields.
  */
-#define EFX_MASK32(field)                                      \
-       (EFX_WIDTH(field) == 32 ? ~((u32) 0) :          \
-        (((((u32) 1) << EFX_WIDTH(field))) - 1))
+#define EFX_MASK32(width)                      \
+       ((width) == 32 ? ~((u32) 0) :           \
+        (((((u32) 1) << (width))) - 1))
 
 /* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
 typedef union efx_dword {
@@ -155,44 +140,49 @@ typedef union efx_oword {
        EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
 
 #define EFX_EXTRACT_OWORD64(oword, low, high)                          \
-       (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) |              \
-        EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
+       ((EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) |             \
+         EFX_EXTRACT64((oword).u64[1], 64, 127, low, high)) &          \
+        EFX_MASK64(high + 1 - low))
 
 #define EFX_EXTRACT_QWORD64(qword, low, high)                          \
-       EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
+       (EFX_EXTRACT64((qword).u64[0], 0, 63, low, high) &              \
+        EFX_MASK64(high + 1 - low))
 
 #define EFX_EXTRACT_OWORD32(oword, low, high)                          \
-       (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) |              \
-        EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) |             \
-        EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) |             \
-        EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
+       ((EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) |             \
+         EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) |            \
+         EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) |            \
+         EFX_EXTRACT32((oword).u32[3], 96, 127, low, high)) &          \
+        EFX_MASK32(high + 1 - low))
 
 #define EFX_EXTRACT_QWORD32(qword, low, high)                          \
-       (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) |              \
-        EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
-
-#define EFX_EXTRACT_DWORD(dword, low, high)                            \
-       EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
-
-#define EFX_OWORD_FIELD64(oword, field)                                        
\
-       (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-        & EFX_MASK64(field))
-
-#define EFX_QWORD_FIELD64(qword, field)                                        
\
-       (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-        & EFX_MASK64(field))
-
-#define EFX_OWORD_FIELD32(oword, field)                                        
\
-       (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-        & EFX_MASK32(field))
-
-#define EFX_QWORD_FIELD32(qword, field)                                        
\
-       (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-        & EFX_MASK32(field))
-
-#define EFX_DWORD_FIELD(dword, field)                                     \
-       (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
-        & EFX_MASK32(field))
+       ((EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) |             \
+         EFX_EXTRACT32((qword).u32[1], 32, 63, low, high)) &           \
+        EFX_MASK32(high + 1 - low))
+
+#define EFX_EXTRACT_DWORD(dword, low, high)                    \
+       (EFX_EXTRACT32((dword).u32[0], 0, 31, low, high) &      \
+        EFX_MASK32(high + 1 - low))
+
+#define EFX_OWORD_FIELD64(oword, field)                                \
+       EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field),          \
+                           EFX_HIGH_BIT(field))
+
+#define EFX_QWORD_FIELD64(qword, field)                                \
+       EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field),          \
+                           EFX_HIGH_BIT(field))
+
+#define EFX_OWORD_FIELD32(oword, field)                                \
+       EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field),          \
+                           EFX_HIGH_BIT(field))
+
+#define EFX_QWORD_FIELD32(qword, field)                                \
+       EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field),          \
+                           EFX_HIGH_BIT(field))
+
+#define EFX_DWORD_FIELD(dword, field)                          \
+       EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field),            \
+                         EFX_HIGH_BIT(field))
 
 #define EFX_OWORD_IS_ZERO64(oword)                                     \
        (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
@@ -428,68 +418,101 @@ typedef union efx_oword {
  * for read-modify-write operations.
  *
  */
-
 #define EFX_INVERT_OWORD(oword) do {           \
        (oword).u64[0] = ~((oword).u64[0]);     \
        (oword).u64[1] = ~((oword).u64[1]);     \
        } while (0)
 
-#define EFX_INSERT_FIELD64(...)                                        \
-       cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
-
-#define EFX_INSERT_FIELD32(...)                                        \
-       cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
-
-#define EFX_INPLACE_MASK64(min, max, field)                    \
-       EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
-
-#define EFX_INPLACE_MASK32(min, max, field)                    \
-       EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
-
-#define EFX_SET_OWORD_FIELD64(oword, field, value) do {                        
\
+#define EFX_AND_OWORD(oword, from, mask)                       \
+       do {                                                    \
+               (oword).u64[0] = (from).u64[0] & (mask).u64[0]; \
+               (oword).u64[1] = (from).u64[1] & (mask).u64[1]; \
+       } while (0)
+
+#define EFX_OR_OWORD(oword, from, mask)                                \
+       do {                                                    \
+               (oword).u64[0] = (from).u64[0] | (mask).u64[0]; \
+               (oword).u64[1] = (from).u64[1] | (mask).u64[1]; \
+       } while (0)
+
+#define EFX_INSERT64(min, max, low, high, value)                       \
+       cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value))
+
+#define EFX_INSERT32(min, max, low, high, value)                       \
+       cpu_to_le32(EFX_INSERT_NATIVE(min, max, low, high, value))
+
+#define EFX_INPLACE_MASK64(min, max, low, high)                                
\
+       EFX_INSERT64(min, max, low, high, EFX_MASK64(high + 1 - low))
+
+#define EFX_INPLACE_MASK32(min, max, low, high)                                
\
+       EFX_INSERT32(min, max, low, high, EFX_MASK32(high + 1 - low))
+
+#define EFX_SET_OWORD64(oword, low, high, value) do {                  \
        (oword).u64[0] = (((oword).u64[0]                               \
-                          & ~EFX_INPLACE_MASK64(0,  63, field))        \
-                         | EFX_INSERT_FIELD64(0,  63, field, value));  \
+                          & ~EFX_INPLACE_MASK64(0,  63, low, high))    \
+                         | EFX_INSERT64(0,  63, low, high, value));    \
        (oword).u64[1] = (((oword).u64[1]                               \
-                          & ~EFX_INPLACE_MASK64(64, 127, field))       \
-                         | EFX_INSERT_FIELD64(64, 127, field, value)); \
-       } while (0)
-
-#define EFX_SET_QWORD_FIELD64(qword, field, value) do {                        
\
+                          & ~EFX_INPLACE_MASK64(64, 127, low, high))   \
+                         | EFX_INSERT64(64, 127, low, high, value));   \
+       } while (0)
+
+#define EFX_SET_QWORD64(qword, low, high, value) do {                  \
        (qword).u64[0] = (((qword).u64[0]                               \
-                          & ~EFX_INPLACE_MASK64(0, 63, field))         \
-                         | EFX_INSERT_FIELD64(0, 63, field, value));   \
-       } while (0)
-
-#define EFX_SET_OWORD_FIELD32(oword, field, value) do {                        
\
+                          & ~EFX_INPLACE_MASK64(0, 63, low, high))     \
+                         | EFX_INSERT64(0, 63, low, high, value));     \
+       } while (0)
+
+#define EFX_SET_OWORD32(oword, low, high, value) do {                  \
        (oword).u32[0] = (((oword).u32[0]                               \
-                          & ~EFX_INPLACE_MASK32(0, 31, field))         \
-                         | EFX_INSERT_FIELD32(0, 31, field, value));   \
+                          & ~EFX_INPLACE_MASK32(0, 31, low, high))     \
+                         | EFX_INSERT32(0, 31, low, high, value));     \
        (oword).u32[1] = (((oword).u32[1]                               \
-                          & ~EFX_INPLACE_MASK32(32, 63, field))        \
-                         | EFX_INSERT_FIELD32(32, 63, field, value));  \
+                          & ~EFX_INPLACE_MASK32(32, 63, low, high))    \
+                         | EFX_INSERT32(32, 63, low, high, value));    \
        (oword).u32[2] = (((oword).u32[2]                               \
-                          & ~EFX_INPLACE_MASK32(64, 95, field))        \
-                         | EFX_INSERT_FIELD32(64, 95, field, value));  \
+                          & ~EFX_INPLACE_MASK32(64, 95, low, high))    \
+                         | EFX_INSERT32(64, 95, low, high, value));    \
        (oword).u32[3] = (((oword).u32[3]                               \
-                          & ~EFX_INPLACE_MASK32(96, 127, field))       \
-                         | EFX_INSERT_FIELD32(96, 127, field, value)); \
-       } while (0)
-
-#define EFX_SET_QWORD_FIELD32(qword, field, value) do {                        
\
+                          & ~EFX_INPLACE_MASK32(96, 127, low, high))   \
+                         | EFX_INSERT32(96, 127, low, high, value));   \
+       } while (0)
+
+#define EFX_SET_QWORD32(qword, low, high, value) do {                  \
        (qword).u32[0] = (((qword).u32[0]                               \
-                          & ~EFX_INPLACE_MASK32(0, 31, field))         \
-                         | EFX_INSERT_FIELD32(0, 31, field, value));   \
+                          & ~EFX_INPLACE_MASK32(0, 31, low, high))     \
+                         | EFX_INSERT32(0, 31, low, high, value));     \
        (qword).u32[1] = (((qword).u32[1]                               \
-                          & ~EFX_INPLACE_MASK32(32, 63, field))        \
-                         | EFX_INSERT_FIELD32(32, 63, field, value));  \
-       } while (0)
-
-#define EFX_SET_DWORD_FIELD(dword, field, value) do {                  \
-       (dword).u32[0] = (((dword).u32[0]                               \
-                          & ~EFX_INPLACE_MASK32(0, 31, field))         \
-                         | EFX_INSERT_FIELD32(0, 31, field, value));   \
-       } while (0)
+                          & ~EFX_INPLACE_MASK32(32, 63, low, high))    \
+                         | EFX_INSERT32(32, 63, low, high, value));    \
+       } while (0)
+
+#define EFX_SET_DWORD32(dword, low, high, value) do {                  \
+       (dword).u32[0] = (((dword).u32[0]                               \
+                          & ~EFX_INPLACE_MASK32(0, 31, low, high))     \
+                         | EFX_INSERT32(0, 31, low, high, value));     \
+       } while (0)
+
+#define EFX_SET_OWORD_FIELD64(oword, field, value)                     \
+       EFX_SET_OWORD64(oword, EFX_LOW_BIT(field),                      \
+                        EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_QWORD_FIELD64(qword, field, value)                     \
+       EFX_SET_QWORD64(qword, EFX_LOW_BIT(field),                      \
+                        EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_OWORD_FIELD32(oword, field, value)                     \
+       EFX_SET_OWORD32(oword, EFX_LOW_BIT(field),                      \
+                        EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_QWORD_FIELD32(qword, field, value)                     \
+       EFX_SET_QWORD32(qword, EFX_LOW_BIT(field),                      \
+                        EFX_HIGH_BIT(field), value)
+
+#define EFX_SET_DWORD_FIELD(dword, field, value)                       \
+       EFX_SET_DWORD32(dword, EFX_LOW_BIT(field),                      \
+                        EFX_HIGH_BIT(field), value)
+
+
 
 #if BITS_PER_LONG == 64
 #define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
@@ -499,27 +522,17 @@ typedef union efx_oword {
 #define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
 #endif
 
-#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
-       if (FALCON_REV(efx) >= FALCON_REV_B0) {                    \
-               EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
-       } else { \
-               EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
-       } \
-} while (0)
-
-#define EFX_QWORD_FIELD_VER(efx, qword, field) \
-       (FALCON_REV(efx) >= FALCON_REV_B0 ?     \
-        EFX_QWORD_FIELD((qword), field##_B0) : \
-        EFX_QWORD_FIELD((qword), field##_A1))
-
 /* Used to avoid compiler warnings about shift range exceeding width
  * of the data types when dma_addr_t is only 32 bits wide.
  */
 #define DMA_ADDR_T_WIDTH       (8 * sizeof(dma_addr_t))
 #define EFX_DMA_TYPE_WIDTH(width) \
        (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
-#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
-                         ~((u64) 0) : ~((u32) 0))
-#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
+
+
+/* Static initialiser */
+#define EFX_OWORD32(a, b, c, d)                                                
\
+       { .u32 = { __constant_cpu_to_le32(a), __constant_cpu_to_le32(b), \
+                  __constant_cpu_to_le32(c), __constant_cpu_to_le32(d) } }
 
 #endif /* EFX_BITFIELD_H */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/boards.c
--- a/drivers/net/sfc/boards.c  Fri Jan 08 11:56:04 2010 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,528 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2007:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-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 "net_driver.h"
-#include "phy.h"
-#include "lm87_support.h"
-#include "boards.h"
-#include "efx.h"
-
-/* Macros for unpacking the board revision */
-/* The revision info is in host byte order. */
-#define BOARD_TYPE(_rev) (_rev >> 8)
-#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
-#define BOARD_MINOR(_rev) (_rev & 0xf)
-
-/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer 
*/
-#define BLINK_INTERVAL (HZ/2)
-
-static void blink_led_timer(unsigned long context)
-{
-       struct efx_nic *efx = (struct efx_nic *)context;
-       struct efx_blinker *bl = &efx->board_info.blinker;
-       efx->board_info.set_fault_led(efx, bl->state);
-       bl->state = !bl->state;
-       if (bl->resubmit) {
-               bl->timer.expires = jiffies + BLINK_INTERVAL;
-               add_timer(&bl->timer);
-       }
-}
-
-static void board_blink(struct efx_nic *efx, int blink)
-{
-       struct efx_blinker *blinker = &efx->board_info.blinker;
-
-       /* The rtnl mutex serialises all ethtool ioctls, so
-        * nothing special needs doing here. */
-       if (blink) {
-               blinker->resubmit = 1;
-               blinker->state = 0;
-               setup_timer(&blinker->timer, blink_led_timer,
-                           (unsigned long)efx);
-               blinker->timer.expires = jiffies + BLINK_INTERVAL;
-               add_timer(&blinker->timer);
-       } else {
-               blinker->resubmit = 0;
-               if (blinker->timer.function)
-                       del_timer_sync(&blinker->timer);
-               efx->board_info.set_fault_led(efx, 0);
-       }
-}
-
-
-struct sensor_conf {
-       const char *name;
-       const unsigned high;
-       const unsigned low;
-};
-
-#define NO_LIMIT       ((unsigned)-1)
-
-#define LM87_SENSOR_BYTES      (18)
-
-static int sensor_limits_to_bytes(const struct sensor_conf *limits,
-                                 int nlimits, u8 *bytes, int maxbytes)
-{
-       int i, nbytes;
-       nbytes = 0;
-       for (i = 0; i < nlimits; i++) {
-               bytes[nbytes++] = limits[i].high;
-               if (limits[i].low != NO_LIMIT)
-                       bytes[nbytes++] = limits[i].low;
-               /* We may have overrun by one at this point, but this test
-                * should only trigger in development drivers as the sizes
-                * are not dynamic. */
-               if (nbytes > maxbytes) {
-                       printk(KERN_ERR "%s: out of space!\n", __func__);
-                       break;
-               }
-       }
-       return nbytes;
-}
-
-/*****************************************************************************
- * Support for the SFE4002
- *
- */
-/* LM87 configuration data for the sensor on the SFE4002 board */
-static const struct sensor_conf sfe4002_lm87_limits[] = {
-       {"1.8V line", 0x91, 0x83},      /* 2.5V sensor, scaled for 1.8V */
-       {"1.2V line", 0x5a, 0x51},      /* Vccp1 */
-       {"3.3V line", 0xca, 0xb6},
-       {"5V line", 0xc9, 0xb6},
-       {"12V line", 0xe0, 0xb0},
-       {"1V line", 0x4b, 0x44},        /* vccp2 */
-       {"Ext. temp.", 0x46, 0x0a},     /* ASIC temp. */
-       {"Int. temp.", 0x3c, 0x0a},     /* Board temp. */
-       {"1.66V line", 0xb2, NO_LIMIT}, /* AIN1 only takes 1 value */
-       {"1.5V line", 0xa1, NO_LIMIT}   /* AIN2 only takes 1 value */
-};
-
-static const int sfe4002_lm87_nlimits = ARRAY_SIZE(sfe4002_lm87_limits);
-
-static u16 sfe4002_lm87_irq_mask = EFX_LM87_NO_INTS;
-
-/* I2C ID of the onboard LM87 chip. This is board-specific as the bottom two
- * bits are set by strap pins */
-#define SFE4002_LM87_I2C_ID (0x2e)
-
-/****************************************************************************/
-/* LED allocations. Note that on rev A0 boards the schematic and the reality
- * differ: red and green are swapped. Below is the fixed (A1) layout (there
- * are only 3 A0 boards in existence, so no real reason to make this
- * conditional).
- */
-#define SFE4002_FAULT_LED (2)  /* Red */
-#define SFE4002_RX_LED    (0)  /* Green */
-#define SFE4002_TX_LED    (1)  /* Amber */
-
-static int sfe4002_init_leds(struct efx_nic *efx)
-{
-       /* Set the TX and RX LEDs to reflect status and activity, and the
-        * fault LED off */
-       xfp_set_led(efx, SFE4002_TX_LED,
-                   QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
-       xfp_set_led(efx, SFE4002_RX_LED,
-                   QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
-       xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
-       efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
-       return 0;
-}
-
-static void sfe4002_fault_led(struct efx_nic *efx, int state)
-{
-       xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
-                       QUAKE_LED_OFF);
-}
-
-static int sfe4002_sensor_meaning(struct efx_nic *efx, int limit_num,
-                                 unsigned val)
-{
-       const struct sensor_conf *lim = &sfe4002_lm87_limits[limit_num];
-       if (lim->low == NO_LIMIT)
-               EFX_ERR(efx, "%10s  0x%02x (nominal value 0x%02x)\n", lim->name,
-                       val, lim->high);
-       else
-               EFX_ERR(efx, "%10s  0x%02x (nominal range 0x%02x - 0x%02x)\n",
-                       lim->name, val, lim->high, lim->low);
-       return 1;
-}
-
-static int sfe4002_check_hw(struct efx_nic *efx)
-{
-       int rc;
-
-       /* A0 board rev. 4002s  report a temperature fault the whole time
-        * (bad sensor) so we mask it out. */
-       unsigned alarm_mask = (efx->board_info.minor > 0) ?
-               0 : ~EFX_LM87_ETMP_INT;
-
-       /* Check the sensor (NOP if not present). */
-       rc = efx_check_lm87(efx, alarm_mask);
-
-       /* We treat both lm87 interrupts and failure to talk to the lm87
-        * as problems (since failure will only be reported if we did
-        * find the sensor at probe time. */
-       if (rc)
-               EFX_ERR(efx, "sensor alert!\n");
-       return rc;
-}
-
-static int sfe4002_init(struct efx_nic *efx)
-{
-       u8 lm87_bytes[LM87_SENSOR_BYTES];
-       int nbytes;
-       int rc;
-
-       efx->board_info.monitor = sfe4002_check_hw;
-       efx->board_info.interpret_sensor = sfe4002_sensor_meaning;
-       efx->board_info.init_leds = sfe4002_init_leds;
-       efx->board_info.set_fault_led = sfe4002_fault_led;
-       efx->board_info.blink = board_blink;
-       /* To clean up shut down the lm87 (NOP if not present) */
-       efx->board_info.fini = efx_remove_lm87;
-
-       nbytes = sensor_limits_to_bytes(sfe4002_lm87_limits,
-                                       sfe4002_lm87_nlimits, lm87_bytes,
-                                       LM87_SENSOR_BYTES);
-
-       /* Activate the lm87 sensor if present (succeeds if nothing there) */
-       rc = efx_probe_lm87(efx, SFE4002_LM87_I2C_ID,
-                           lm87_bytes, nbytes, sfe4002_lm87_irq_mask);
-
-       return rc;
-}
-
-/*****************************************************************************
- * Support for the SFE4003
- *
- */
-/* LM87 configuration data for the sensor on the SFE4003 board */
-static const struct sensor_conf sfe4003_lm87_limits[] = {
-       {"1.5V line", 0x78, 0x6d},      /* 2.5V input, values scaled for 1.5V */
-       {"1.2V line", 0x5a, 0x51},      /* Vccp1 */
-       {"3.3V line", 0xca, 0xb6},
-       {"5V line", 0xc0, 0x00},        /* Sensor not connected. */
-       {"12V line", 0xe0, 0xb0},
-       {"1V line", 0x4b, 0x44},        /* Vccp2 */
-       {"Ext. temp.", 0x46, 0x0a},     /* ASIC temp. */
-       {"Int. temp.", 0x3c, 0x0a},     /* Board temp. */
-       {"", 0xff, NO_LIMIT},           /* FAN1/AIN1 unused */
-       {"", 0xff, NO_LIMIT}            /* FAN2/AIN2 unused */
-};
-
-static const int sfe4003_lm87_nlimits = ARRAY_SIZE(sfe4003_lm87_limits);
-
-static u16 sfe4003_lm87_irq_mask = EFX_LM87_NO_INTS;
-
-
-static int sfe4003_sensor_meaning(struct efx_nic *efx, int limit_num,
-                                 unsigned val)
-{
-       const struct sensor_conf *lim = &sfe4003_lm87_limits[limit_num];
-       if (lim->low == NO_LIMIT)
-               return 0; /* Neither AIN1 nor AIN2 mean anything to us */
-       else
-               EFX_ERR(efx, "%10s  0x%02x (nominal range 0x%02x - 0x%02x)\n",
-                       lim->name, val, lim->high, lim->low);
-       return 1;
-}
-
-/* I2C ID of the onboard LM87 chip. This is board-specific as the bottom two
- * bits are set by strap pins */
-#define SFE4003_LM87_I2C_ID (0x2e)
-
-/* Board-specific LED info. */
-#define SFE4003_RED_LED_GPIO   (11)
-#define SFE4003_LED_ON         (1)
-#define SFE4003_LED_OFF                (0)
-
-static void sfe4003_fault_led(struct efx_nic *efx, int state)
-{
-       /* The LEDs were not wired to GPIOs before A3 */
-       if (efx->board_info.minor < 3 && efx->board_info.major == 0)
-               return;
-
-       txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO,
-                        state ? SFE4003_LED_ON : SFE4003_LED_OFF);
-}
-
-static int sfe4003_init_leds(struct efx_nic *efx)
-{
-       /* The LEDs were not wired to GPIOs before A3 */
-       if (efx->board_info.minor < 3 && efx->board_info.major == 0)
-               return 0;
-
-       txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT);
-       txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF);
-       return 0;
-}
-
-static int sfe4003_check_hw(struct efx_nic *efx)
-{
-       int rc;
-       /* A0/A1/A2 board rev. 4003s  report a temperature fault the whole time
-        * (bad sensor) so we mask it out. */
-       unsigned alarm_mask =
-               ~(EFX_LM87_ETMP_INT | EFX_LM87_FAN1_INT | EFX_LM87_FAN2_INT);
-
-       /* Check the sensor (NOP if not present). */
-
-       rc = efx_check_lm87(efx, alarm_mask);
-       /* We treat both lm87 interrupts and failure to talk to the lm87
-        * as problems (since failure will only be reported if we did
-        * find the sensor at probe time. */
-       if (rc)
-               EFX_ERR(efx, "sensor alert!\n");
-
-       return rc;
-}
-
-static int sfe4003_init(struct efx_nic *efx)
-{
-       u8 lm87_bytes[LM87_SENSOR_BYTES];
-       int nbytes;
-       int rc;
-       efx->board_info.monitor = sfe4003_check_hw;
-       efx->board_info.interpret_sensor = sfe4003_sensor_meaning;
-       efx->board_info.init_leds = sfe4003_init_leds;
-       efx->board_info.set_fault_led = sfe4003_fault_led;
-       efx->board_info.blink = board_blink;
-       /* To clean up shut down the lm87 (NOP if not present) */
-       efx->board_info.fini = efx_remove_lm87;
-
-       nbytes = sensor_limits_to_bytes(sfe4003_lm87_limits,
-                                       sfe4003_lm87_nlimits, lm87_bytes,
-                                       LM87_SENSOR_BYTES);
-
-       /* Activate the lm87 sensor if present (succeeds if nothing there) */
-       rc = efx_probe_lm87(efx, SFE4003_LM87_I2C_ID,
-                           lm87_bytes, nbytes, sfe4003_lm87_irq_mask);
-
-       if (rc < 0)
-               EFX_ERR(efx, "Temperature sensor probe failure: "
-                       "please check the jumper position\n");
-       return rc;
-}
-
-/*****************************************************************************
- * Support for the SFE4005
- *
- */
-/* LM87 configuration data for the sensor on the SFE4005 board */
-static const u8 sfe4005_lm87_limits[] = {
-       0x51, /* 2.5V high lim. (actually monitor 1.0V line, so 1050mV)  */
-       0x49, /* 2.5V low lim. (950mV) */
-       0xf6, /* Vccp1 high lim. (3.3V rail, 3465 mV) */
-       0xde, /* Vcpp1 low lim. (3.3V rail, 3135 mV) */
-       0xca, /* 3.3V AUX high lim. (3465 mV)  */
-       0xb6, /* 3.3V AUX low lim. (3135mV) */
-       0xc0, /* 5V high lim. not connected) */
-       0x00, /* 5V low lim. (not connected) */
-       0xd0, /* 12V high lim. (13000mV) */
-       0xb0, /* 12V low lim. (11000mV) */
-       0xc0, /* Vccp2 high lim. (unused) */
-       0x00, /* Vccp2 low lim. (unused) */
-       0x46, /* Ext temp 1 (ASIC) high lim. */
-       0x0a, /* Ext temp 1 low lim. */
-       0x3c, /* Int temp (board) high lim. */
-       0x0a, /* Int temp 1 low lim. */
-       0xff, /* Fan 1 high (unused) */
-       0xff, /* Fan 2 high (unused) */
-};
-
-#define SFE4005_LM87_I2C_ID (0x2e)
-
-/* Until the LM87 monitoring is interrupt driven. */
-#define SFE4005_LM87_IRQMASK   EFX_LM87_NO_INTS
-
-#define SFE4005_PCF8575_I2C_ID (0x20)
-/* Definitions for the I/O expander that controls the CX4 chip:
- * which PCF8575 pin maps to which function */
-#define SFE4005_PORT0_EXTLOOP  (1 << 0)
-#define SFE4005_PORT1_EXTLOOP  (1 << 1)
-#define SFE4005_HOSTPROT_LOOP  (1 << 2)
-#define SFE4005_BCAST          (1 << 3) /* TX on both ports */
-#define SFE4005_PORT0_EQ       (1 << 4)
-#define SFE4005_PORT1_EQ       (1 << 5)
-#define SFE4005_HOSTPORT_EQ    (1 << 6)
-#define        SFE4005_PORTSEL         (1 << 7) /* Which port (for RX in BCAST 
mode) */
-#define SFE4005_PORT0_PRE_LBN  (8)      /* Preemphasis on port 0 (2 bits)*/
-#define SFE4005_PORT1_PRE_LBN  (10)     /* Preemphasis on port 1 (2 bits)*/
-#define SFE4005_HOSTPORT_PRE_LBN (12)    /* Preemphasis on host port (2 bits) 
*/
-#define SFE4005_UNUSED         (1 << 14)
-#define SFE4005_CX4uC_nRESET   (1 << 15) /* Reset the controller on CX4 chip */
-
-
-/* By default only turn on host port EQ. Can also OR in SFE4005_PORT0_EQ,
- * SFE4005_PORT1_EQ but this hasn't been seen to make a difference. */
-#define SFE4005_CX4_DEFAULTS (SFE4005_CX4uC_nRESET | SFE4005_HOSTPORT_EQ)
-
-static int sfe4005_write_ioexpander(struct efx_nic *efx)
-{
-       unsigned long iobits = (unsigned long)efx->phy_data;
-       struct efx_i2c_interface *i2c = &efx->i2c;
-       u8 send[2], check[2];
-       int rc;
-       /* Do not, EVER, deassert nRESET as that will reset Falcon too,
-        * and the driver won't know to repush the configuration, so
-        * nothing will work until the next power cycle. */
-       BUG_ON(!(iobits & SFE4005_CX4uC_nRESET));
-       send[0] = (iobits & 0xff);
-       send[1] = ((iobits >> 8) & 0xff);
-       rc = efx_i2c_send_bytes(i2c, SFE4005_PCF8575_I2C_ID, send, 2);
-       if (rc) {
-               EFX_ERR(efx, "failed to write to I/O expander: %d\n", rc);
-               return rc;
-       }
-       /* Paranoia: just check what the I/O expander reads back */
-       rc = efx_i2c_recv_bytes(i2c, SFE4005_PCF8575_I2C_ID, check, 2);
-       if (rc)
-               EFX_ERR(efx, "failed to read back from I/O expander: %d\n", rc);
-       else if (check[0] != send[0] || check[1] != send[1])
-               EFX_ERR(efx, "read back wrong value from I/O expander: "
-                       "wanted %.2x%.2x, got %.2x%.2x\n",
-                       send[1], send[0], check[1], check[0]);
-       return rc;
-}
-
-static int sfe4005_init(struct efx_nic *efx)
-{
-       unsigned long iobits = SFE4005_CX4_DEFAULTS;
-       int rc;
-
-       /* There is no PHY as such on the SFE4005 so phy_data is ours. */
-       efx->phy_data = (void *)iobits;
-
-       /* Push the values */
-       rc = sfe4005_write_ioexpander(efx);
-       if (rc)
-               return rc;
-
-       /* Activate the lm87 sensor if present (succeeds if nothing there) */
-       rc = efx_probe_lm87(efx, SFE4005_LM87_I2C_ID,
-                           sfe4005_lm87_limits,
-                           sizeof(sfe4005_lm87_limits), SFE4005_LM87_IRQMASK);
-
-       /* To clean up shut down the lm87 (NOP if not present) */
-       efx->board_info.fini = efx_remove_lm87;
-
-       return rc;
-}
-
-/* This will get expanded as board-specific details get moved out of the
- * PHY drivers. */
-struct efx_board_data {
-       const char *ref_model;
-       const char *gen_type;
-       int (*init) (struct efx_nic *nic);
-       unsigned mwatts;
-};
-
-static void dummy_fini(struct efx_nic *nic)
-{
-}
-
-static int dummy_init(struct efx_nic *nic)
-{
-       nic->board_info.fini = dummy_fini;
-       return 0;
-}
-
-/* Maximum board power (mW)
- * Falcon controller ASIC accounts for 2.2W
- * 10Xpress PHY accounts for 12W
- *
- */
-#define SFE4001_POWER 18000
-#define SFE4002_POWER 7500
-#define SFE4003_POWER 4500
-#define SFE4005_POWER 4500
-
-static struct efx_board_data board_data[] = {
-       [EFX_BOARD_INVALID] =
-       {NULL,      NULL,                  dummy_init,      0},
-       [EFX_BOARD_SFE4001] =
-       {"SFE4001", "10GBASE-T adapter",   sfe4001_poweron, SFE4001_POWER },
-       [EFX_BOARD_SFE4002] =
-       {"SFE4002", "XFP adapter",         sfe4002_init,    SFE4002_POWER },
-       [EFX_BOARD_SFE4003] =
-       {"SFE4003", "10GBASE-CX4 adapter", sfe4003_init,    SFE4003_POWER },
-       [EFX_BOARD_SFE4005] =
-       {"SFE4005", "10G blade adapter",   sfe4005_init,    SFE4005_POWER },
-};
-
-int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
-{
-       int rc = 0;
-       struct efx_board_data *data;
-
-       if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
-               EFX_ERR(efx, "squashing unknown board type %d\n",
-                       BOARD_TYPE(revision_info));
-               revision_info = 0;
-       }
-
-       if (BOARD_TYPE(revision_info) == 0) {
-               efx->board_info.major = 0;
-               efx->board_info.minor = 0;
-               /* For early boards that don't have revision info. there is
-                * only 1 board for each PHY type, so we can work it out, with
-                * the exception of the PHY-less boards. */
-               switch (efx->phy_type) {
-               case PHY_TYPE_10XPRESS:
-                       efx->board_info.type = EFX_BOARD_SFE4001;
-                       break;
-               case PHY_TYPE_XFP:
-                       efx->board_info.type = EFX_BOARD_SFE4002;
-                       break;
-               case PHY_TYPE_CX4_RTMR:
-                       efx->board_info.type = EFX_BOARD_SFE4003;
-                       break;
-               default:
-                       efx->board_info.type = 0;
-                       break;
-               }
-       } else {
-               efx->board_info.type = BOARD_TYPE(revision_info);
-               efx->board_info.major = BOARD_MAJOR(revision_info);
-               efx->board_info.minor = BOARD_MINOR(revision_info);
-       }
-
-       data = &board_data[efx->board_info.type];
-
-       /* Report the board model number or generic type for recognisable
-        * boards. */
-       if (efx->board_info.type != 0)
-               EFX_INFO(efx, "board is %s rev %c%d\n",
-                        (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
-                        ? data->ref_model : data->gen_type,
-                        'A' + efx->board_info.major, efx->board_info.minor);
-
-       efx->board_info.init = data->init;
-       efx->board_info.mwatts = data->mwatts;
-
-       return rc;
-}
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/boards.h
--- a/drivers/net/sfc/boards.h  Fri Jan 08 11:56:04 2010 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2007:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-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 EFX_BOARDS_H
-#define EFX_BOARDS_H
-
-/* Board IDs (must fit in 8 bits). Note that 0 must never be assigned because
- * on early boards it means there is no revision info. Board types pre 400x
- * are not covered here, but this is not a problem because:
- * - the early Falcon boards (FPGA, 401, 403) don't have any extra H/W we
- * need care about and aren't being updated.
- */
-enum efx_board_type {
-       EFX_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */
-       EFX_BOARD_SFE4001 = 1,
-       EFX_BOARD_SFE4002 = 2,
-       EFX_BOARD_SFE4003 = 3,
-       EFX_BOARD_SFE4005 = 4,
-       /* Insert new types before here */
-       EFX_BOARD_MAX
-};
-
-extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
-
-/* SFE4001 (10GBASE-T) */
-extern int sfe4001_poweron(struct efx_nic *efx);
-extern void sfe4001_poweroff(struct efx_nic *efx);
-
-#endif
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/config.h
--- a/drivers/net/sfc/config.h  Fri Jan 08 11:56:04 2010 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-/* SFC config options can go here */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/debugfs.c
--- a/drivers/net/sfc/debugfs.c Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/debugfs.c Fri Jan 08 13:05:49 2010 +0000
@@ -1,47 +1,34 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2009 Solarflare Communications Inc.
  *
  * 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/module.h>
 #include <linux/pci.h>
+/* For out-of-tree builds we always need procfs, if only for a compatibility
+ * symlink.
+ */
 #include <linux/proc_fs.h>
 #include <linux/dcache.h>
 #include <linux/seq_file.h>
 #include "net_driver.h"
 #include "efx.h"
 #include "debugfs.h"
-#include "falcon.h"
-
-#ifndef PRIu64
-#      if (BITS_PER_LONG == 64)
-#              define PRIu64 "lu"
-#      else
-#              define PRIu64 "llu"
-#      endif
+#include "nic.h"
+
+/* EFX_USE_DEBUGFS is defined by kernel_compat.h so we can't decide whether to
+ * include this earlier.
+ */
+#ifdef EFX_USE_DEBUGFS
+#include <linux/debugfs.h>
 #endif
+
+#ifndef EFX_USE_DEBUGFS
 
 static void efx_debugfs_remove(struct proc_dir_entry *entry)
 {
@@ -53,6 +40,7 @@ static void efx_debugfs_remove(struct pr
 #define debugfs_create_dir proc_mkdir
 #define debugfs_create_symlink proc_symlink
 
+#endif /* !EFX_USE_DEBUGFS */
 
 /* Parameter definition bound to a structure - each file has one of these */
 struct efx_debugfs_bound_param {
@@ -66,19 +54,36 @@ struct efx_debugfs_bound_param {
 
 
 /* Top-level debug directory ([/sys/kernel]/debug/sfc) */
-static struct dentry *efx_debug_root;
+static efx_debugfs_entry *efx_debug_root;
 
 /* "cards" directory ([/sys/kernel]/debug/sfc/cards) */
-static struct dentry *efx_debug_cards;
+static efx_debugfs_entry *efx_debug_cards;
 
 
 /* Sequential file interface to bound parameters */
 
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_DEBUGFS)
+
 static int efx_debugfs_seq_show(struct seq_file *file, void *v)
 {
-       struct proc_dir_entry *entry = (struct proc_dir_entry *)file->private;
-       struct efx_debugfs_parameter *param =
-               (struct efx_debugfs_parameter *)entry->data;
+       struct efx_debugfs_bound_param *binding = file->private;
+
+       return binding->param->reader(file,
+                                     binding->structure +
+                                     binding->param->offset);
+}
+
+static int efx_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, efx_debugfs_seq_show, inode->i_private);
+}
+
+#else /* EFX_USE_KCOMPAT && !EFX_USE_DEBUGFS */
+
+static int efx_debugfs_seq_show(struct seq_file *file, void *v)
+{
+       struct proc_dir_entry *entry = file->private;
+       struct efx_debugfs_parameter *param = entry->data;
        void *structure = (void *)entry->read_proc;
 
        if (!structure)
@@ -91,6 +96,8 @@ static int efx_debugfs_open(struct inode
 {
        return single_open(file, efx_debugfs_seq_show, PROC_I(inode)->pde);
 }
+
+#endif /* !EFX_USE_KCOMPAT || EFX_USE_DEBUGFS */
 
 
 static struct file_operations efx_debugfs_file_ops = {
@@ -102,10 +109,41 @@ static struct file_operations efx_debugf
 };
 
 
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_DEBUGFS)
+
+/**
+ * efx_fini_debugfs_child - remove a named child of a debugfs directory
+ * @dir:               Directory
+ * @name:              Name of child
+ *
+ * This removes the named child from the directory, if it exists.
+ */
+void efx_fini_debugfs_child(efx_debugfs_entry *dir, const char *name)
+{
+       struct qstr child_name;
+       efx_debugfs_entry *child;
+
+       child_name.len = strlen(name);
+       child_name.name = name;
+       child_name.hash = full_name_hash(child_name.name, child_name.len);
+       child = d_lookup(dir, &child_name);
+       if (child) {
+               /* If it's a "regular" file, free its parameter binding */
+               if (S_ISREG(child->d_inode->i_mode))
+                       kfree(child->d_inode->i_private);
+               debugfs_remove(child);
+               dput(child);
+       }
+}
+
+#else /* EFX_USE_KCOMPAT && !EFX_USE_DEBUGFS */
+
 void efx_fini_debugfs_child(struct proc_dir_entry *dir, const char *name)
 {
        remove_proc_entry(name, dir);
 }
+
+#endif /* !EFX_USE_KCOMPAT || EFX_USE_DEBUGFS */
 
 /*
  * Remove a debugfs directory.
@@ -114,7 +152,7 @@ void efx_fini_debugfs_child(struct proc_
  * directory, and the directory itself.  It does not do any recursion
  * to subdirectories.
  */
-static void efx_fini_debugfs_dir(struct dentry *dir,
+static void efx_fini_debugfs_dir(efx_debugfs_entry *dir,
                                 struct efx_debugfs_parameter *params,
                                 const char *const *symlink_names)
 {
@@ -159,6 +197,11 @@ int efx_debugfs_read_dword(struct seq_fi
        return seq_printf(file, "%#x\n", value);
 }
 
+int efx_debugfs_read_bool(struct seq_file *file, void *data)
+{
+       return seq_printf(file, "%d\n", *(bool *)data);
+}
+
 static int efx_debugfs_read_int_mode(struct seq_file *file, void *data)
 {
        unsigned int value = *(enum efx_int_mode *) data;
@@ -182,18 +225,6 @@ static int efx_debugfs_read_loop_mode(st
 #define EFX_LOOPBACK_MODE_PARAMETER(container_type, parameter)         \
        EFX_PARAMETER(container_type, parameter,                        \
                      enum efx_loopback_mode, efx_debugfs_read_loop_mode)
-
-static int efx_debugfs_read_phy_type(struct seq_file *file, void *data)
-{
-       unsigned int value = *(enum phy_type *) data;
-
-       return seq_printf(file, "%d => %s\n", value,
-                         STRING_TABLE_LOOKUP(value, efx_phy_type));
-}
-
-#define EFX_PHY_TYPE_PARAMETER(container_type, parameter)              \
-       EFX_PARAMETER(container_type, parameter,                        \
-                     enum phy_type, efx_debugfs_read_phy_type)
 
 int efx_debugfs_read_string(struct seq_file *file, void *data)
 {
@@ -210,14 +241,30 @@ int efx_debugfs_read_string(struct seq_f
  * Add parameter-files to the given debugfs directory.  Return a
  * negative error code or 0 on success.
  */
-static int efx_init_debugfs_files(struct dentry *parent,
+static int efx_init_debugfs_files(efx_debugfs_entry *parent,
                                  struct efx_debugfs_parameter *params,
                                  void *structure)
 {
        struct efx_debugfs_parameter *param = params;
 
        while (param->name) {
-               struct dentry *entry;
+               efx_debugfs_entry *entry;
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_DEBUGFS)
+               struct efx_debugfs_bound_param *binding;
+
+               binding = kmalloc(sizeof(*binding), GFP_KERNEL);
+               if (!binding)
+                       goto err;
+               binding->param = param;
+               binding->structure = structure;
+
+               entry = debugfs_create_file(param->name, S_IRUGO, parent,
+                                           binding, &efx_debugfs_file_ops);
+               if (!entry) {
+                       kfree(binding);
+                       goto err;
+               }
+#else
                entry = create_proc_entry(param->name, S_IRUGO, parent);
                if (!entry)
                        goto err;
@@ -233,6 +280,7 @@ static int efx_init_debugfs_files(struct
                entry->proc_fops = &efx_debugfs_file_ops;
                smp_wmb();
                entry->read_proc = (read_proc_t *) structure;
+#endif
 
                param++;
        }
@@ -258,7 +306,7 @@ static int efx_init_debugfs_files(struct
  */
 int efx_init_debugfs_netdev(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        char name[EFX_DEBUGFS_NAME_LEN];
        char target[EFX_DEBUGFS_NAME_LEN];
        size_t len;
@@ -298,7 +346,7 @@ int efx_init_debugfs_netdev(struct net_d
  */
 void efx_fini_debugfs_netdev(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
        debugfs_remove(efx->debug_port_symlink);
        efx->debug_port_symlink = NULL;
@@ -309,16 +357,25 @@ void efx_fini_debugfs_netdev(struct net_
 /* Per-port parameters */
 static struct efx_debugfs_parameter efx_debugfs_port_parameters[] = {
        EFX_NAMED_PARAMETER(enabled, struct efx_nic, port_enabled,
-                           int, efx_debugfs_read_int),
-       EFX_INT_PARAMETER(struct efx_nic, rx_checksum_enabled),
+                           bool, efx_debugfs_read_bool),
+#if defined(EFX_USE_KCOMPAT) && !defined(NETIF_F_LRO)
+       EFX_BOOL_PARAMETER(struct efx_nic, lro_enabled),
+#endif
+       EFX_BOOL_PARAMETER(struct efx_nic, rx_checksum_enabled),
        EFX_ATOMIC_PARAMETER(struct efx_nic, netif_stop_count),
-       EFX_INT_PARAMETER(struct efx_nic, link_up),
-       EFX_UINT_PARAMETER(struct efx_nic, link_options),
-       EFX_INT_PARAMETER(struct efx_nic, promiscuous),
-       EFX_UINT_PARAMETER(struct efx_nic, loopback_modes),
+       EFX_NAMED_PARAMETER(link_up, struct efx_nic, link_state.up,
+                           bool, efx_debugfs_read_bool),
+       EFX_BOOL_PARAMETER(struct efx_nic, xmac_poll_required),
+       EFX_NAMED_PARAMETER(link_fd, struct efx_nic, link_state.fd,
+                           bool, efx_debugfs_read_bool),
+       EFX_NAMED_PARAMETER(link_speed, struct efx_nic, link_state.speed,
+                           unsigned int, efx_debugfs_read_uint),
+       EFX_BOOL_PARAMETER(struct efx_nic, promiscuous),
+       EFX_U64_PARAMETER(struct efx_nic, loopback_modes),
        EFX_LOOPBACK_MODE_PARAMETER(struct efx_nic, loopback_mode),
-       EFX_PHY_TYPE_PARAMETER(struct efx_nic, phy_type),
-       EFX_NAMED_PARAMETER(phy_id, struct efx_nic, mii.phy_id,
+       EFX_UINT_PARAMETER(struct efx_nic, phy_type),
+       EFX_STRING_PARAMETER(struct efx_nic, phy_name),
+       EFX_NAMED_PARAMETER(phy_id, struct efx_nic, mdio.prtad,
                            int, efx_debugfs_read_int),
        EFX_UINT_PARAMETER(struct efx_nic, n_link_state_changes),
        {NULL},
@@ -344,7 +401,7 @@ int efx_init_debugfs_port(struct efx_nic
        /* Create files */
        rc = efx_init_debugfs_files(efx->debug_port_dir,
                                    efx_debugfs_port_parameters,
-                                   (void *)efx);
+                                   efx);
        if (rc)
                efx_fini_debugfs_port(efx);
 
@@ -393,7 +450,7 @@ void efx_trim_debugfs_port(struct efx_ni
 void efx_trim_debugfs_port(struct efx_nic *efx,
                           struct efx_debugfs_parameter *params)
 {
-       struct dentry *dir = efx->debug_port_dir;
+       efx_debugfs_entry *dir = efx->debug_port_dir;
 
        if (dir) {
                struct efx_debugfs_parameter *field;
@@ -408,6 +465,9 @@ static struct efx_debugfs_parameter efx_
        EFX_UINT_PARAMETER(struct efx_tx_queue, write_count),
        EFX_UINT_PARAMETER(struct efx_tx_queue, read_count),
        EFX_INT_PARAMETER(struct efx_tx_queue, stopped),
+       EFX_UINT_PARAMETER(struct efx_tx_queue, tso_bursts),
+       EFX_UINT_PARAMETER(struct efx_tx_queue, tso_long_headers),
+       EFX_UINT_PARAMETER(struct efx_tx_queue, tso_packets),
        {NULL},
 };
 
@@ -439,7 +499,7 @@ static int efx_init_debugfs_tx_queue(str
        /* Create files */
        rc = efx_init_debugfs_files(tx_queue->debug_dir,
                                    efx_debugfs_tx_queue_parameters,
-                                   (void *)tx_queue);
+                                   tx_queue);
        if (rc)
                goto err;
 
@@ -527,7 +587,7 @@ static int efx_init_debugfs_rx_queue(str
        /* Create files */
        rc = efx_init_debugfs_files(rx_queue->debug_dir,
                                    efx_debugfs_rx_queue_parameters,
-                                   (void *)rx_queue);
+                                   rx_queue);
        if (rc)
                goto err;
 
@@ -570,29 +630,21 @@ static void efx_fini_debugfs_rx_queue(st
 
 /* Per-channel parameters */
 static struct efx_debugfs_parameter efx_debugfs_channel_parameters[] = {
-       EFX_INT_PARAMETER(struct efx_channel, enabled),
+       EFX_BOOL_PARAMETER(struct efx_channel, enabled),
        EFX_INT_PARAMETER(struct efx_channel, irq),
-       EFX_UINT_PARAMETER(struct efx_channel, has_interrupt),
        EFX_UINT_PARAMETER(struct efx_channel, irq_moderation),
        EFX_UINT_PARAMETER(struct efx_channel, eventq_read_ptr),
        EFX_UINT_PARAMETER(struct efx_channel, n_rx_tobe_disc),
-       EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_frag_err),
+       EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_frag),
        EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_hdr_chksum_err),
        EFX_UINT_PARAMETER(struct efx_channel, n_rx_tcp_udp_chksum_err),
+       EFX_UINT_PARAMETER(struct efx_channel, n_rx_eth_crc_err),
+       EFX_UINT_PARAMETER(struct efx_channel, n_rx_mcast_mismatch),
        EFX_UINT_PARAMETER(struct efx_channel, n_rx_frm_trunc),
        EFX_UINT_PARAMETER(struct efx_channel, n_rx_overlength),
        EFX_UINT_PARAMETER(struct efx_channel, n_skbuff_leaks),
        EFX_INT_PARAMETER(struct efx_channel, rx_alloc_level),
        EFX_INT_PARAMETER(struct efx_channel, rx_alloc_push_pages),
-       EFX_INT_PARAMETER(struct efx_channel, rx_alloc_pop_pages),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_merges),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_bursts),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_slow_start),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_misorder),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_too_many),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_new_stream),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_drop_idle),
-       EFX_UINT_PARAMETER(struct efx_channel, ssr.n_drop_closed),
        {NULL},
 };
 
@@ -622,7 +674,7 @@ static int efx_init_debugfs_channel(stru
        /* Create files */
        rc = efx_init_debugfs_files(channel->debug_dir,
                                    efx_debugfs_channel_parameters,
-                                   (void *)channel);
+                                   channel);
        if (rc)
                goto err;
 
@@ -654,12 +706,13 @@ static void efx_fini_debugfs_channel(str
 /* Per-NIC parameters */
 static struct efx_debugfs_parameter efx_debugfs_nic_parameters[] = {
        EFX_INT_PARAMETER(struct efx_nic, legacy_irq),
-       EFX_INT_PARAMETER(struct efx_nic, rss_queues),
+       EFX_INT_PARAMETER(struct efx_nic, n_rx_queues),
        EFX_UINT_PARAMETER(struct efx_nic, rx_buffer_len),
        EFX_INT_MODE_PARAMETER(struct efx_nic, interrupt_mode),
+       EFX_UINT_PARAMETER(struct efx_nic, state),
        {.name = "hardware_desc",
         .offset = 0,
-        .reader = falcon_debugfs_read_hardware_desc},
+        .reader = efx_nic_debugfs_read_desc},
        {NULL},
 };
 
@@ -763,12 +816,12 @@ int efx_init_debugfs_nic(struct efx_nic 
 
        /* Create files */
        rc = efx_init_debugfs_files(efx->debug_dir,
-                                   efx_debugfs_nic_parameters, (void *)efx);
+                                   efx_debugfs_nic_parameters, efx);
        if (rc)
                goto err;
        rc = efx_init_debugfs_files(efx->errors.debug_dir,
                                    efx_debugfs_nic_error_parameters,
-                                   (void *)&efx->errors);
+                                   &efx->errors);
        if (rc)
                goto err;
 
@@ -807,7 +860,11 @@ int efx_init_debugfs(void)
 int efx_init_debugfs(void)
 {
        /* Create top-level directory */
-       efx_debug_root = proc_mkdir("sfc", proc_root_driver);
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_DEBUGFS)
+       efx_debug_root = debugfs_create_dir("sfc", NULL);
+#else
+       efx_debug_root = proc_mkdir("driver/sfc", NULL);
+#endif
        if (!efx_debug_root)
                goto err;
 
@@ -816,6 +873,11 @@ int efx_init_debugfs(void)
        if (!efx_debug_cards)
                goto err;
 
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_DEBUGFS)
+       /* Create compatibility sym-link */
+       if (!proc_symlink("driver/sfc", NULL, "/sys/kernel/debug/sfc"))
+               goto err;
+#endif
        return 0;
 
  err:
@@ -830,7 +892,9 @@ int efx_init_debugfs(void)
  */
 void efx_fini_debugfs(void)
 {
-       remove_proc_entry("sfc", proc_root_driver);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_DEBUGFS)
+       remove_proc_entry("driver/sfc", NULL);
+#endif
        debugfs_remove(efx_debug_cards);
        efx_debug_cards = NULL;
        debugfs_remove(efx_debug_root);
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/debugfs.h
--- a/drivers/net/sfc/debugfs.h Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/debugfs.h Fri Jan 08 13:05:49 2010 +0000
@@ -1,145 +1,15 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
  *
  * 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 EFX_DEBUGFS_H
 #define EFX_DEBUGFS_H
-
-#ifdef CONFIG_SFC_DEBUGFS
-
-struct seq_file;
-
-struct efx_debugfs_parameter {
-       const char *name;
-       size_t offset;
-       int (*reader)(struct seq_file *, void *);
-};
-
-extern void efx_fini_debugfs_child(struct dentry *dir, const char *name);
-extern int efx_init_debugfs_netdev(struct net_device *net_dev);
-extern void efx_fini_debugfs_netdev(struct net_device *net_dev);
-extern int efx_init_debugfs_port(struct efx_nic *efx);
-extern void efx_fini_debugfs_port(struct efx_nic *efx);
-extern int efx_init_debugfs_nic(struct efx_nic *efx);
-extern void efx_fini_debugfs_nic(struct efx_nic *efx);
-extern int efx_init_debugfs_channels(struct efx_nic *efx);
-extern void efx_fini_debugfs_channels(struct efx_nic *efx);
-extern int efx_init_debugfs(void);
-extern void efx_fini_debugfs(void);
-extern int efx_extend_debugfs_port(struct efx_nic *efx,
-                                  void *context,
-                                  struct efx_debugfs_parameter *params);
-extern void efx_trim_debugfs_port(struct efx_nic *efx,
-                                 struct efx_debugfs_parameter *params);
-
-/* Helpers for handling debugfs entry reads */
-extern int efx_debugfs_read_uint(struct seq_file *, void *);
-extern int efx_debugfs_read_string(struct seq_file *, void *);
-extern int efx_debugfs_read_int(struct seq_file *, void *);
-extern int efx_debugfs_read_atomic(struct seq_file *, void *);
-extern int efx_debugfs_read_dword(struct seq_file *, void *);
-
-/* Handy macros for filling out parameters */
-
-/* Initialiser for a struct efx_debugfs_parameter with type-checking */
-#define EFX_PARAMETER(container_type, parameter, field_type,           \
-                       reader_function) {                              \
-       .name = #parameter,                                             \
-       .offset = ((((field_type *) 0) ==                               \
-                   &((container_type *) 0)->parameter) ?               \
-                  offsetof(container_type, parameter) :                \
-                  offsetof(container_type, parameter)),                \
-       .reader = reader_function,                                      \
-}
-
-/* Likewise, but the file name is not taken from the field name */
-#define EFX_NAMED_PARAMETER(_name, container_type, parameter, field_type, \
-                               reader_function) {                      \
-       .name = #_name,                                                 \
-       .offset = ((((field_type *) 0) ==                               \
-                   &((container_type *) 0)->parameter) ?               \
-                  offsetof(container_type, parameter) :                \
-                  offsetof(container_type, parameter)),                \
-       .reader = reader_function,                                      \
-}
-
-/* Likewise, but with one file for each of 4 lanes */
-#define EFX_PER_LANE_PARAMETER(prefix, suffix, container_type, parameter, \
-                               field_type, reader_function) {          \
-       .name = prefix "0" suffix,                                      \
-       .offset = ((((field_type *) 0) ==                               \
-                     ((container_type *) 0)->parameter) ?              \
-                   offsetof(container_type, parameter[0]) :            \
-                   offsetof(container_type, parameter[0])),            \
-       .reader = reader_function,                                      \
-},  {                                                                  \
-       .name = prefix "1" suffix,                                      \
-       .offset = offsetof(container_type, parameter[1]),               \
-       .reader = reader_function,                                      \
-}, {                                                                   \
-       .name = prefix "2" suffix,                                      \
-       .offset = offsetof(container_type, parameter[2]),               \
-       .reader = reader_function,                                      \
-}, {                                                                   \
-       .name = prefix "3" suffix,                                      \
-       .offset = offsetof(container_type, parameter[3]),               \
-       .reader = reader_function,                                      \
-}
-
-/* A string parameter (string embedded in the structure) */
-#define EFX_STRING_PARAMETER(container_type, parameter) {      \
-       .name = #parameter,                                     \
-       .offset = ((((char *) 0) ==                             \
-                   ((container_type *) 0)->parameter) ?        \
-                  offsetof(container_type, parameter) :        \
-                  offsetof(container_type, parameter)),        \
-       .reader = efx_debugfs_read_string,                      \
-}
-
-/* An unsigned integer parameter */
-#define EFX_UINT_PARAMETER(container_type, parameter)          \
-       EFX_PARAMETER(container_type, parameter,                \
-                     unsigned int, efx_debugfs_read_uint)
-
-/* A dword parameter */
-#define EFX_DWORD_PARAMETER(container_type, parameter)         \
-       EFX_PARAMETER(container_type, parameter,                \
-                     efx_dword_t, efx_debugfs_read_dword)
-
-/* An atomic_t parameter */
-#define EFX_ATOMIC_PARAMETER(container_type, parameter)                \
-       EFX_PARAMETER(container_type, parameter,                \
-                     atomic_t, efx_debugfs_read_atomic)
-
-/* An integer parameter */
-#define EFX_INT_PARAMETER(container_type, parameter)           \
-       EFX_PARAMETER(container_type, parameter,                \
-                     int, efx_debugfs_read_int)
-
-#else /* !CONFIG_SFC_DEBUGFS */
 
 static inline int efx_init_debugfs_netdev(struct net_device *net_dev)
 {
@@ -167,6 +37,4 @@ static inline int efx_init_debugfs(void)
 }
 static inline void efx_fini_debugfs(void) {}
 
-#endif /* CONFIG_SFC_DEBUGFS */
-
 #endif /* EFX_DEBUGFS_H */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/driverlink.c
--- a/drivers/net/sfc/driverlink.c      Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/driverlink.c      Fri Jan 08 13:05:49 2010 +0000
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005:      Fen Systems Ltd.
- * Copyright 2005-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005      Fen Systems Ltd.
+ * Copyright 2005-2009 Solarflare Communications Inc.
  *
  * 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/module.h>
@@ -31,13 +14,10 @@
 #include <linux/rtnetlink.h>
 #include "net_driver.h"
 #include "efx.h"
+#include "driverlink_api.h"
 #include "driverlink.h"
 
-/* Driverlink semaphore
- * This semaphore must be held for any operation that modifies any of
- * the driverlink lists.
- */
-static DEFINE_MUTEX(efx_driverlink_lock);
+/* Global lists are protected by rtnl_lock */
 
 /* List of all registered drivers */
 static LIST_HEAD(efx_driver_list);
@@ -45,28 +25,27 @@ static LIST_HEAD(efx_driver_list);
 /* List of all registered Efx ports */
 static LIST_HEAD(efx_port_list);
 
-/* Driver link handle used internally to track devices */
+/**
+ * Driver link handle used internally to track devices
+ * @efx_dev: driverlink device handle exported to consumers
+ * @efx: efx_nic backing the driverlink device
+ * @port_node: per-device list head
+ * @driver_node: per-driver list head
+ */
 struct efx_dl_handle {
-       /* The efx_dl_device consumers see */
        struct efx_dl_device efx_dev;
-       /* The efx_nic providers provide */
        struct efx_nic *efx;
-       /* Per-device list */
        struct list_head port_node;
-       /* Per-driver list */
        struct list_head driver_node;
 };
 
-/* Get the handle for an efx_dl_device */
 static struct efx_dl_handle *efx_dl_handle(struct efx_dl_device *efx_dev)
 {
        return container_of(efx_dev, struct efx_dl_handle, efx_dev);
 }
 
-/* Remove an Efx device
- * You must hold the efx_driverlink_lock before calling this
- * function.
- */
+/* Remove an Efx device, and call the driver's remove() callback if
+ * present. The caller must hold rtnl_lock. */
 static void efx_dl_del_device(struct efx_dl_device *efx_dev)
 {
        struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
@@ -74,23 +53,18 @@ static void efx_dl_del_device(struct efx
        EFX_INFO(efx_handle->efx, "%s driverlink client unregistering\n",
                 efx_dev->driver->name);
 
-       /* Call driver's remove() routine */
        if (efx_dev->driver->remove)
                efx_dev->driver->remove(efx_dev);
 
-       /* Remove handle from per-driver and per-NIC lists */
        list_del(&efx_handle->driver_node);
        list_del(&efx_handle->port_node);
 
-       /* Free efx_handle structure */
        kfree(efx_handle);
 }
 
-/* Try to add an Efx device
- * Attempt to probe the given device with the driver, creating a
- * new efx_dl_device. If the probe routine fails, because the driver
- * doesn't support this port, then the efx_dl_device is destroyed,
- */
+/* Attempt to probe the given device with the driver, creating a
+ * new &struct efx_dl_device. If the probe routine returns an error,
+ * then the &struct efx_dl_device is destroyed */
 static void efx_dl_try_add_device(struct efx_nic *efx,
                                  struct efx_dl_driver *driver)
 {
@@ -98,8 +72,9 @@ static void efx_dl_try_add_device(struct
        struct efx_dl_device *efx_dev;
        int rc;
 
-       /* Allocate and initialise new efx_dl_device structure */
        efx_handle = kzalloc(sizeof(*efx_handle), GFP_KERNEL);
+       if (!efx_handle)
+               goto fail;
        efx_dev = &efx_handle->efx_dev;
        efx_handle->efx = efx;
        efx_dev->driver = driver;
@@ -107,13 +82,11 @@ static void efx_dl_try_add_device(struct
        INIT_LIST_HEAD(&efx_handle->port_node);
        INIT_LIST_HEAD(&efx_handle->driver_node);
 
-       /* Attempt driver probe */
        rc = driver->probe(efx_dev, efx->net_dev,
-                          efx->dl_info, efx->silicon_rev);
+                          efx->dl_info, efx->type->dl_revision);
        if (rc)
                goto fail;
 
-       /* Add device to per-driver and per-NIC lists */
        list_add_tail(&efx_handle->driver_node, &driver->device_list);
        list_add_tail(&efx_handle->port_node, &efx->dl_device_list);
 
@@ -123,16 +96,11 @@ static void efx_dl_try_add_device(struct
  fail:
        EFX_INFO(efx, "%s driverlink client skipped\n", driver->name);
 
-       kfree(efx_dev);
-}
-
-/**
- * efx_dl_unregister_driver - unregister an Efx device driver
- * @driver:            Efx driverlink driver
- *
- * Unregisters an Efx driver.  The driver's remove() method will be
- * called for all Efx devices currently claimed by the driver.
- */
+       kfree(efx_handle);
+}
+
+/* Unregister a driver from the driverlink layer, calling the
+ * driver's remove() callback for every attached device */
 void efx_dl_unregister_driver(struct efx_dl_driver *driver)
 {
        struct efx_dl_handle *efx_handle, *efx_handle_n;
@@ -140,8 +108,7 @@ void efx_dl_unregister_driver(struct efx
        printk(KERN_INFO "Efx driverlink unregistering %s driver\n",
                 driver->name);
 
-       /* Acquire lock.  We can't return failure */
-       mutex_lock(&efx_driverlink_lock);
+       rtnl_lock();
 
        list_for_each_entry_safe(efx_handle, efx_handle_n,
                                 &driver->device_list, driver_node)
@@ -149,46 +116,29 @@ void efx_dl_unregister_driver(struct efx
 
        list_del(&driver->node);
 
-       mutex_unlock(&efx_driverlink_lock);
+       rtnl_unlock();
 }
 EXPORT_SYMBOL(efx_dl_unregister_driver);
 
-/**
- * efx_dl_register_driver - register an Efx device driver
- * @driver:            Efx driverlink driver
- *
- * Registers a new Efx driver.  The driver's probe() method will be
- * called for all Efx NICs currently registered.
- *
- * Return a negative error code or 0 on success.
- */
+/* Register a new driver with the driverlink layer. The driver's
+ * probe routine will be called for every attached nic. */
 int efx_dl_register_driver(struct efx_dl_driver *driver)
 {
        struct efx_nic *efx;
-       int rc;
 
        printk(KERN_INFO "Efx driverlink registering %s driver\n",
                 driver->name);
 
-       /* Initialise driver list structures */
        INIT_LIST_HEAD(&driver->node);
        INIT_LIST_HEAD(&driver->device_list);
 
-       /* Acquire lock */
-       rc = mutex_lock_interruptible(&efx_driverlink_lock);
-       if (rc)
-               return rc;
-
-       /* Add driver to driver list */
+       rtnl_lock();
+
        list_add_tail(&driver->node, &efx_driver_list);
-
-       /* Feed all existing devices to driver */
        list_for_each_entry(efx, &efx_port_list, dl_node)
                efx_dl_try_add_device(efx, driver);
 
-       /* Release locks */
-       mutex_unlock(&efx_driverlink_lock);
-
+       rtnl_unlock();
        return 0;
 }
 EXPORT_SYMBOL(efx_dl_register_driver);
@@ -197,85 +147,60 @@ void efx_dl_unregister_nic(struct efx_ni
 {
        struct efx_dl_handle *efx_handle, *efx_handle_n;
 
-       if (!efx)
-               return;
-
-       /* Acquire lock.  We can't return failure, so have to use
-        * down() instead of down_interruptible()
-        */
-       mutex_lock(&efx_driverlink_lock);
-
-       /* Remove all devices related to this NIC */
+       ASSERT_RTNL();
+
        list_for_each_entry_safe_reverse(efx_handle, efx_handle_n,
                                         &efx->dl_device_list,
                                         port_node)
                efx_dl_del_device(&efx_handle->efx_dev);
 
-       /* Remove port from port list */
        list_del(&efx->dl_node);
-
-       /* Release lock */
-       mutex_unlock(&efx_driverlink_lock);
-}
-
-int efx_dl_register_nic(struct efx_nic *efx)
+}
+
+void efx_dl_register_nic(struct efx_nic *efx)
 {
        struct efx_dl_driver *driver;
-       int rc;
-
-       /* Acquire lock */
-       rc = mutex_lock_interruptible(&efx_driverlink_lock);
-       if (rc)
-               return rc;
-
-       /* Add port to port list */
+
+       ASSERT_RTNL();
+
        list_add_tail(&efx->dl_node, &efx_port_list);
-
-       /* Feed port to all existing drivers */
        list_for_each_entry(driver, &efx_driver_list, node)
                efx_dl_try_add_device(efx, driver);
-
-       /* Release lock */
-       mutex_unlock(&efx_driverlink_lock);
-
-       return 0;
-}
-
-/*
- * Dummy callback implementations.
- *
+}
+
+/* Dummy callback implementations.
  * To avoid a branch point on the fast-path, the callbacks are always
  * implemented - they are never NULL.
  */
-static enum efx_veto fastcall
-efx_dummy_tx_packet_callback(struct efx_dl_device *efx_dev, struct sk_buff 
*skb)
-{
-       /* Never veto the packet */
+
+static enum efx_veto
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+fastcall
+#endif
+efx_dummy_tx_packet_callback(struct efx_dl_device *efx_dev,
+                                                 struct sk_buff *skb)
+{
        return EFX_ALLOW_PACKET;
 }
 
-static enum efx_veto fastcall
+static enum efx_veto
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+fastcall
+#endif
 efx_dummy_rx_packet_callback(struct efx_dl_device *efx_dev,
-                            const char *pkt_buf, int len)
-{
-       /* Never veto the packet */
+                                                 const char *pkt_buf, int len)
+{
        return EFX_ALLOW_PACKET;
 }
 
-static void
-efx_dummy_link_change_callback(struct efx_dl_device *efx_dev, int link_up)
-{
-}
-
-static int
-efx_dummy_request_mtu_callback(struct efx_dl_device *efx_dev, int new_mtu)
-{
-       /* Always allow */
+static int efx_dummy_request_mtu_callback(struct efx_dl_device *efx_dev,
+                                         int new_mtu)
+{
        return 0;
 }
 
-static void
-efx_dummy_mtu_changed_callback(struct efx_dl_device *efx_dev, int mtu)
+static void efx_dummy_mtu_changed_callback(struct efx_dl_device *efx_dev,
+                                          int mtu)
 {
        return;
 }
@@ -288,106 +213,54 @@ struct efx_dl_callbacks efx_default_call
 struct efx_dl_callbacks efx_default_callbacks = {
        .tx_packet      = efx_dummy_tx_packet_callback,
        .rx_packet      = efx_dummy_rx_packet_callback,
-       .link_change    = efx_dummy_link_change_callback,
        .request_mtu    = efx_dummy_request_mtu_callback,
        .mtu_changed    = efx_dummy_mtu_changed_callback,
        .event          = efx_dummy_event_callback,
 };
 
-#define EFX_DL_UNREGISTER_CALLBACK(_port, _dev, _member)               \
-       do {                                                            \
-               BUG_ON((_port)->dl_cb_dev._member != (_dev));           \
-               (_port)->dl_cb._member =                                \
-                       efx_default_callbacks._member;                  \
-               (_port)->dl_cb_dev._member = NULL;                      \
-       } while (0)
-
-
-#define EFX_DL_REGISTER_CALLBACK(_port, _dev, _from, _member)          \
-       if ((_from)->_member) {                                         \
-               BUG_ON((_port)->dl_cb_dev._member != NULL);             \
-               (_port)->dl_cb._member = (_from)->_member;              \
-               (_port)->dl_cb_dev._member = _dev;                      \
-       }
-
-/**
- * efx_dl_unregister_callbacks - unregister callbacks for an Efx NIC
- * @efx_dev:           Efx driverlink device
- * @callbacks:         Callback list
- *
- * This removes a set of callbacks registered with
- * efx_dl_register_callbacks().  It should be called as part of the
- * client's remove() method.
- *
- * The net driver will ensure that all callback functions have
- * returned to the net driver before efx_dl_unregister_callbacks()
- * returns.  Note that the device itself may still be running when the
- * client's remove() method is called.  The client must therefore
- * unhook its callbacks using efx_dl_unregister_callbacks() and only
- * then ensure that any delayed tasks triggered by callback methods
- * (e.g. scheduled tasklets) have completed.
- */
 void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev,
                                 struct efx_dl_callbacks *callbacks)
 {
        struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
        struct efx_nic *efx = efx_handle->efx;
 
-       /* Suspend net driver operations */
-       efx_suspend(efx);
+       ASSERT_RTNL();
+
+       efx_stop_all(efx);
 
        EFX_INFO(efx, "removing callback hooks into %s driver\n",
                 efx_dev->driver->name);
 
-       if (callbacks->tx_packet)
-               EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, tx_packet);
-
-       if (callbacks->rx_packet)
-               EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, rx_packet);
-
-       if (callbacks->link_change)
-               EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, link_change);
-
-       if (callbacks->request_mtu)
-               EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, request_mtu);
-
-       if (callbacks->mtu_changed)
-               EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, mtu_changed);
-
-       if (callbacks->event)
-               EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, event);
-
-       /* Resume net driver operations */
-       efx_resume(efx);
+       if (callbacks->tx_packet) {
+               BUG_ON(efx->dl_cb_dev.tx_packet != efx_dev);
+               efx->dl_cb.tx_packet = efx_default_callbacks.tx_packet;
+               efx->dl_cb_dev.tx_packet = NULL;
+       }
+       if (callbacks->rx_packet) {
+               BUG_ON(efx->dl_cb_dev.rx_packet != efx_dev);
+               efx->dl_cb.rx_packet = efx_default_callbacks.rx_packet;
+               efx->dl_cb_dev.rx_packet = NULL;
+       }
+       if (callbacks->request_mtu) {
+               BUG_ON(efx->dl_cb_dev.request_mtu != efx_dev);
+               efx->dl_cb.request_mtu = efx_default_callbacks.request_mtu;
+               efx->dl_cb_dev.request_mtu = NULL;
+       }
+       if (callbacks->mtu_changed) {
+               BUG_ON(efx->dl_cb_dev.mtu_changed != efx_dev);
+               efx->dl_cb.mtu_changed = efx_default_callbacks.mtu_changed;
+               efx->dl_cb_dev.mtu_changed = NULL;
+       }
+       if (callbacks->event) {
+               BUG_ON(efx->dl_cb_dev.event != efx_dev);
+               efx->dl_cb.event = efx_default_callbacks.event;
+               efx->dl_cb_dev.event = NULL;
+       }
+
+       efx_start_all(efx);
 }
 EXPORT_SYMBOL(efx_dl_unregister_callbacks);
 
-/**
- * efx_dl_register_callbacks - register callbacks for an Efx NIC
- * @efx_dev:           Efx driverlink device
- * @callbacks:         Callback list
- *
- * This registers a set of callback functions with the net driver.
- * These functions will be called at various key points to allow
- * external code to monitor and/or modify the behaviour of the network
- * driver.  Any of the callback function pointers may be %NULL if a
- * callback is not required.  The intended user of this mechanism is
- * the SFC char driver.
- *
- * This client should call efx_dl_register_callbacks() during its
- * probe() method.  The client must ensure that it also calls
- * efx_dl_unregister_callbacks() as part of its remove() method.
- *
- * Only one function may be registered for each callback per NIC.
- * If a requested callback is already registered for this NIC, this
- * function will return -%EBUSY.
- *
- * The device may already be running, so the client must be prepared
- * for callbacks to be triggered immediately after calling
- * efx_dl_register_callbacks().
- *
- * Return a negative error code or 0 on success.
- */
 int efx_dl_register_callbacks(struct efx_dl_device *efx_dev,
                              struct efx_dl_callbacks *callbacks)
 {
@@ -395,13 +268,13 @@ int efx_dl_register_callbacks(struct efx
        struct efx_nic *efx = efx_handle->efx;
        int rc = 0;
 
-       /* Suspend net driver operations */
-       efx_suspend(efx);
+       ASSERT_RTNL();
+
+       efx_stop_all(efx);
 
        /* Check that the requested callbacks are not already hooked. */
        if ((callbacks->tx_packet && efx->dl_cb_dev.tx_packet) ||
            (callbacks->rx_packet && efx->dl_cb_dev.rx_packet) ||
-           (callbacks->link_change && efx->dl_cb_dev.link_change) ||
            (callbacks->request_mtu && efx->dl_cb_dev.request_mtu) ||
            (callbacks->mtu_changed && efx->dl_cb_dev.mtu_changed) ||
            (callbacks->event && efx->dl_cb_dev.event)) {
@@ -412,35 +285,36 @@ int efx_dl_register_callbacks(struct efx
        EFX_INFO(efx, "adding callback hooks to %s driver\n",
                 efx_dev->driver->name);
 
-       /* Hook in callbacks.  For maximum speed, we never check to
-        * see whether these are NULL before calling; therefore we
-        * must ensure that they are never NULL.  If the set we're
-        * being asked to hook in is sparse, we leave the default
-        * values in place for the empty hooks.
-        */
-       EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, tx_packet);
-       EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, rx_packet);
-       EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, link_change);
-       EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, request_mtu);
-       EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, mtu_changed);
-       EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, event);
+       /* Hook in the requested callbacks, leaving any NULL members
+        * referencing the members of @efx_default_callbacks */
+       if (callbacks->tx_packet) {
+               efx->dl_cb.tx_packet = callbacks->tx_packet;
+               efx->dl_cb_dev.tx_packet = efx_dev;
+       }
+       if (callbacks->rx_packet) {
+               efx->dl_cb.rx_packet = callbacks->rx_packet;
+               efx->dl_cb_dev.rx_packet = efx_dev;
+       }
+       if (callbacks->request_mtu) {
+               efx->dl_cb.request_mtu = callbacks->request_mtu;
+               efx->dl_cb_dev.request_mtu = efx_dev;
+       }
+       if (callbacks->mtu_changed) {
+               efx->dl_cb.mtu_changed = callbacks->mtu_changed;
+               efx->dl_cb_dev.mtu_changed = efx_dev;
+       }
+       if (callbacks->event) {
+               efx->dl_cb.event = callbacks->event;
+               efx->dl_cb_dev.event = efx_dev;
+       }
 
  out:
-       /* Resume net driver operations */
-       efx_resume(efx);
+       efx_start_all(efx);
 
        return rc;
 }
 EXPORT_SYMBOL(efx_dl_register_callbacks);
 
-/**
- * efx_dl_schedule_reset - schedule an Efx NIC reset
- * @efx_dev:           Efx driverlink device
- *
- * This schedules a hardware reset for a short time in the future.  It
- * can be called from any context, and so can be used when
- * efx_dl_reset() cannot be called.
- */
 void efx_dl_schedule_reset(struct efx_dl_device *efx_dev)
 {
        struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
@@ -450,41 +324,15 @@ void efx_dl_schedule_reset(struct efx_dl
 }
 EXPORT_SYMBOL(efx_dl_schedule_reset);
 
-/*
- * Lock the driverlink layer before a reset
- * To avoid deadlock, efx_driverlink_lock needs to be acquired before
- * efx->suspend_lock.
- */
-void efx_dl_reset_lock(void)
-{
-       /* Acquire lock */
-       mutex_lock(&efx_driverlink_lock);
-}
-
-/*
- * Unlock the driverlink layer after a reset
- * This call must be matched against efx_dl_reset_lock.
- */
-void efx_dl_reset_unlock(void)
-{
-       /* Acquire lock */
-       mutex_unlock(&efx_driverlink_lock);
-}
-
-/*
- * Suspend ready for reset
- * This calls the reset_suspend method of all drivers registered to
- * the specified NIC.  It must only be called between
- * efx_dl_reset_lock and efx_dl_reset_unlock.
- */
+/* Suspend ready for reset, calling the reset_suspend() callback of every
+ * registered driver */
 void efx_dl_reset_suspend(struct efx_nic *efx)
 {
        struct efx_dl_handle *efx_handle;
        struct efx_dl_device *efx_dev;
 
-       BUG_ON(!mutex_is_locked(&efx_driverlink_lock));
-
-       /* Call suspend method of each driver in turn */
+       ASSERT_RTNL();
+
        list_for_each_entry_reverse(efx_handle,
                                    &efx->dl_device_list,
                                    port_node) {
@@ -494,20 +342,15 @@ void efx_dl_reset_suspend(struct efx_nic
        }
 }
 
-/*
- * Resume after a reset
- * This calls the reset_resume method of all drivers registered to the
- * specified NIC.  It must only be called between efx_dl_reset_lock
- * and efx_dl_reset_unlock.
- */
+/* Resume after a reset, calling the resume() callback of every registered
+ * driver */
 void efx_dl_reset_resume(struct efx_nic *efx, int ok)
 {
        struct efx_dl_handle *efx_handle;
        struct efx_dl_device *efx_dev;
 
-       BUG_ON(!mutex_is_locked(&efx_driverlink_lock));
-
-       /* Call resume method of each driver in turn */
+       ASSERT_RTNL();
+
        list_for_each_entry(efx_handle, &efx->dl_device_list,
                            port_node) {
                efx_dev = &efx_handle->efx_dev;
@@ -516,14 +359,9 @@ void efx_dl_reset_resume(struct efx_nic 
        }
 }
 
-/**
- * efx_dl_get_nic - obtain the Efx NIC for the given driverlink device
- * @efx_dev:           Efx driverlink device
- *
- * Get a pointer to the &struct efx_nic corresponding to
- * @efx_dev.  This can be used by driverlink clients built along with
- * the sfc driver, which may have intimate knowledge of its internals.
- */
+/* Obtain a pointer to the &struct efx_nic corresponding to @efx_dev. This
+ * can be used by driverlink clients built along with the sfc driver, which
+ * may have initimate knowledge of its internals. */
 struct efx_nic *efx_dl_get_nic(struct efx_dl_device *efx_dev)
 {
        return efx_dl_handle(efx_dev)->efx;
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/driverlink.h
--- a/drivers/net/sfc/driverlink.h      Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/driverlink.h      Fri Jan 08 13:05:49 2010 +0000
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005:      Fen Systems Ltd.
- * Copyright 2006:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005      Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
  *
  * 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 EFX_DRIVERLINK_H
@@ -32,59 +15,29 @@ struct efx_dl_device;
 struct efx_dl_device;
 struct efx_nic;
 
-/*
- * Efx driverlink
- *
- * This header file defines the portions of the Efx driverlink
- * interface that are used only within the sfc module.  It also
- * declares efx_dl_get_nic(), which may be used by sfc_mtd
- * and any other module built along with sfc.
- */
-
-
 /* Efx callback devices
  *
  * A list of the devices that own each callback. The partner to
- * struct efx_dl_callbacks
+ * struct efx_dl_callbacks.
  */
 struct efx_dl_cb_devices {
-       /* Device owning the tx_packet callback */
        struct efx_dl_device *tx_packet;
-       /* Device owning the rx_packet callback */
        struct efx_dl_device *rx_packet;
-       /* Device owning the link_change callback. */
-       struct efx_dl_device *link_change;
-       /* Device owning the request_mtu callback. */
        struct efx_dl_device *request_mtu;
-       /* Device owning the mtu_changed callback. */
        struct efx_dl_device *mtu_changed;
-       /* Device owning the event callback. */
        struct efx_dl_device *event;
 };
 
-/* No-op callbacks used for initialisation */
 extern struct efx_dl_callbacks efx_default_callbacks;
 
-/* Macro used to invoke callbacks */
 #define EFX_DL_CALLBACK(_port, _name, ...)                             \
        (_port)->dl_cb._name((_port)->dl_cb_dev._name, __VA_ARGS__)
 
-/* Register an Efx NIC */
-extern int efx_dl_register_nic(struct efx_nic *efx);
-
-/* Unregister an Efx NIC */
+extern void efx_dl_register_nic(struct efx_nic *efx);
 extern void efx_dl_unregister_nic(struct efx_nic *efx);
 
-/* Lock the driverlink layer prior to a reset */
-extern void efx_dl_reset_lock(void);
-
-/* Unlock the driverlink layer following a reset */
-extern void efx_dl_reset_unlock(void);
-
-/* Suspend all drivers prior to a hardware reset */
+/* Suspend and resume client drivers over a hardware reset */
 extern void efx_dl_reset_suspend(struct efx_nic *efx);
-
-/* Resume all drivers after a hardware reset */
 extern void efx_dl_reset_resume(struct efx_nic *efx, int ok);
 
 /* Obtain the Efx NIC for the given driverlink device. */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/driverlink_api.h
--- a/drivers/net/sfc/driverlink_api.h  Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/driverlink_api.h  Fri Jan 08 13:05:49 2010 +0000
@@ -1,82 +1,24 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2005-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
  *
  * 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 EFX_DRIVERLINK_API_H
 #define EFX_DRIVERLINK_API_H
 
-#include <linux/list.h> /* for struct list_head */
-#include <linux/linkage.h>
-#define EFX_USE_FASTCALL yes
-
-/**
- * DOC: Efx driverlink API
- *
- * This file must be included by any driver that wishes to attach to
- * devices claimed by the Solarflare NIC driver (sfc). It allows separate
- * kernel modules to expose other functionality offered by the NIC, with
- * the sfc driver remaining in overall control.
- *
- * Overview:
- *
- * Driverlink clients define a &struct efx_dl_driver, and register
- * this structure with the driverlink layer using
- * efx_dl_register_driver(), which is exported by the sfc driver.
- *
- * The probe() routine of each driverlink client driver is called by
- * the driverlink layer for each physical port in the system, after
- * the sfc driver has performed start-of-day hardware initialisation
- * and self-test. If ports are added or removed via pci hotplug then
- * the &struct efx_dl_driver probe() or remove() routines are called
- * as appropriate.
- *
- * If the port doesn't provide the necessary hardware resources for a
- * client, then that client can return failure from its probe()
- * routine. Information provided to the client driver at probe time
- * includes
- *
- * Each probe() routine is given a unique &struct efx_dl_device per
- * port, which means it can safely use the @priv member to store any
- * useful state it needs. The probe routine also has the opportunity
- * to provide a &struct efx_dl_callbacks via
- * efx_dl_register_callbacks(), which allows the client to intercept
- * the sfc driver's operations at strategic points.
- *
- * Occasionally, the underlying Efx device may need to be reset to
- * recover from an error condition.  The client's reset_suspend() and
- * reset_resume() methods [if provided] will be called to enable the
- * client to suspend operations and preserve any state before the
- * reset.  The client can itself request a reset using efx_dl_reset()
- * or efx_dl_schedule_reset(), should it detect an error condition
- * necessitating a reset.
- *
- * Example:
- *
- * The MTD driver (mtd.c) uses the driverlink layer.
- */
+#include <linux/list.h>
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_FASTCALL)
+       #include <linux/version.h>
+       #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+               #define EFX_USE_FASTCALL yes
+               #include <linux/linkage.h>
+       #endif
+#endif
 
 /* Forward declarations */
 struct pci_dev;
@@ -85,160 +27,45 @@ struct efx_dl_device;
 struct efx_dl_device;
 struct efx_dl_device_info;
 
-/*
- * This is used to guard against the registration of driverlink
- * clients using an incorrect version of the API.
- */
+/* An extra safeguard in addition to symbol versioning */
 #define EFX_DRIVERLINK_API_VERSION 1
 
-
 /**
  * struct efx_dl_driver - An Efx driverlink device driver
  *
- * This is the analogue of a struct pci_driver for a normal PCI
- * driver.  Driverlink clients should register themselves using
- * efx_dl_register_driver() at module initialisation, and deregister
- * themselves using efx_dl_unregister_driver() at module exit.
- *
- * All calls to members of efx_dl_driver are serialised by a single
- * semaphore, so you are allowed to sleep in these functions. Take care
- * to not call driverlink methods from within these callbacks, otherwise
- * a deadlock is possible.
+ * A driverlink client defines and initializes as many instances of
+ * efx_dl_driver as required, registering each one with
+ * efx_dl_register_driver().
  *
  * @name: Name of the driver
  * @probe: Called when device added
+ *     The client should use the @def_info linked list and @silicon_rev
+ *     to determine if they wish to attach to this device.
+ *     Context: process, rtnl_lock or driverlink mutex held
  * @remove: Called when device removed
+ *     The client must ensure the finish all operations with this
+ *     device before returning from this method.
+ *     Context: process, rtnl_lock or driverlink mutex held
  * @reset_suspend: Called before device is reset
+ *     Called immediately before a hardware reset. The client must stop all
+ *     hardware processing before returning from this method. Callbacks will
+ *     be inactive when this method is called.
+ *     Context: process, rtnl_lock and/or driverlink mutex held
  * @reset_resume: Called after device is reset
+ *     Called after a hardware reset. If @ok is true, the client should
+ *     state and resume normal operations. If @ok is false, the client should
+ *     abandon use of the hardware resources. remove() will still be called.
+ *     Context: process, rtnl_lock and/or driverlink mutex held
  */
 struct efx_dl_driver {
        const char *name;
 
-       /*
-        * probe - Handle device addition.
-        * @efx_dev:            Efx driverlink device
-        * @net_dev:            The net_dev relevant to this port
-        * @dev_info:           A linked list of device information.
-        * @silicon_rev:        Silicon revision name.
-        *
-        * This will be called after driverlink client registration for
-        * every port on the system, and for every port that appears
-        * thereafter via hotplug.
-        *
-        * The client may use either @efx_dev->pci_dev, the dev_info linked
-        * list of available driver information, or the silicon revision
-        * name to determine if they can support this port. If they can,
-        * they should return 0 to indicate the probe was successful. Any
-        * other return code indicates that the probe failed, and the
-        * @efx_dl_dev will be invalidated.
-        *
-        * The client should perform whatever initialisation it
-        * requires, and store a pointer to its private data in
-        * @efx_dl_dev->priv (which is not shared between clients).
-        * It may also wish to hook in a callbacks table using
-        * efx_dl_register_callbacks().
-        *
-        * Return a negative error code or 0 on success.
-        */
        int (*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);
-
-       /*
-        * remove - Handle device removal.
-        * @efx_dev:            Efx driverlink device
-        *
-        * This will be called at driver exit (or hotplug removal) for
-        * each registered driverlink client.
-        *
-        * The client must ensure that it has finished all operations
-        * using this device before returning from this method.  If it
-        * has hooked in a callbacks table using
-        * efx_dl_register_callbacks(), it must unhook it using
-        * efx_dl_unregister_callbacks(), and then ensure that all
-        * callback-triggered operations (e.g. scheduled tasklets)
-        * have completed before returning.  (It does not need to
-        * explicitly wait for callback methods to finish executing,
-        * since efx_dl_unregister_callbacks() will sleep until all
-        * callbacks have returned anyway.)
-        *
-        * Note that the device itself may not have been removed; it
-        * may be simply that the client is being unloaded
-        * via efx_dl_unregister_driver(). In this case other clients
-        * (and the sfc driver itself) will still be using the device,
-        * so the client cannot assume that the device itself is quiescent.
-        * In particular, callbacks may continue to be triggered at any
-        * point until efx_dl_unregister_callbacks() is called.
-        */
        void (*remove) (struct efx_dl_device *efx_dev);
-
-       /*
-        * reset_suspend - Suspend ready for reset.
-        * @efx_dev:            Efx driverlink device
-        *
-        * This method will be called immediately before a hardware
-        * reset (which may or may not have been initiated by the
-        * driverlink client).  This client must save any state that it
-        * will need to restore after the reset, and suspend all
-        * operations that might access the hardware.  It must not
-        * return until the client can guarantee to have stopped
-        * touching the hardware.
-        *
-        * It is guaranteed that callbacks will be inactive by the
-        * time this method is called; the driverlink layer will
-        * already have prevented new callbacks being made and waited
-        * for all callbacks functions to return before calling
-        * reset_suspend().  However, any delayed work scheduled by
-        * the callback functions (e.g. tasklets) may not yet have
-        * completed.
-        *
-        * This method is allowed to sleep, so waiting on tasklets,
-        * work queues etc. is permitted.  There will always be a
-        * corresponding call to the reset_resume() method, so it is
-        * safe to e.g. down a semaphore within reset_suspend() and up
-        * it within reset_resume().  (However, you obviously cannot
-        * do the same with a spinlock).
-        *
-        * Note that the reset operation may be being carried out in
-        * the context of scheduled work, so you cannot use
-        * flush_scheduled_work() to ensure that any work you may have
-        * scheduled has completed.
-        *
-        * During hardware reset, there is a chance of receiving
-        * spurious interrupts, so the client's ISR (if any) should be
-        * unhooked or otherwise disabled.
-        */
        void (*reset_suspend) (struct efx_dl_device *efx_dev);
-
-       /*
-        * reset_resume - Restore after a reset.
-        * @efx_dev:            Efx driverlink device
-        * @ok:                 Reset success indicator
-        *
-        * This method will be called after a hardware reset.  There
-        * will always have been a corresponding call to the
-        * reset_suspend() method beforehand.
-        *
-        * If @ok is non-zero, the client should restore the state
-        * that it saved during the call to reset_suspend() and resume
-        * normal operations.
-        *
-        * If @ok is zero, the reset operation has failed and the
-        * hardware is currently in an unusable state.  In this case,
-        * the client should release any locks taken out by
-        * reset_suspend(), but should not take any other action; in
-        * particular, it must not access the hardware, nor resume
-        * normal operations.  The hardware is effectively dead at
-        * this point, and our sole aim is to avoid deadlocking or
-        * crashing the host.
-        *
-        * The driverlink layer will still be locked when
-        * reset_resume() is called, so the client may not call
-        * driverlink functions.  In particular, if the reset failed,
-        * the client must not call efx_dl_unregister_callbacks() at
-        * this point; it should wait until remove() is called.
-        */
        void (*reset_resume) (struct efx_dl_device *efx_dev, int ok);
 
 /* private: */
@@ -247,23 +74,10 @@ struct efx_dl_driver {
 };
 
 /**
- * DOC: Efx driverlink device information
- *
- * Each &struct efx_dl_device makes certain hardware resources visible
- * to driverlink clients, and they describe which resources are
- * available by passing a linked list of &struct efx_dl_device_info
- * into the probe() routine.
- *
- * The driverlink client's probe function can iterate through the linked list,
- * and provided that it understands the resources that are exported, it can
- * choose to make use of them through an external interface.
- */
-
-/**
  * enum efx_dl_device_info_type - Device information identifier.
  *
- * Each distinct hardware resource API will have a member in this
- * enumeration.
+ * Used to identify each item in the &struct efx_dl_device_info linked list
+ * provided to each driverlink client in the probe() @dev_info member.
  *
  * @EFX_DL_FALCON_RESOURCES: Information type is &struct 
efx_dl_falcon_resources
  */
@@ -274,14 +88,9 @@ enum efx_dl_device_info_type {
 
 /**
  * struct efx_dl_device_info - device information structure
+ *
  * @next: Link to next structure, if any
  * @type: Type code for this structure
- *
- * This structure is embedded in other structures provided by the
- * driverlink device provider, and implements a linked list of
- * resources pertinent to a driverlink client.
- *
- * Example: &struct efx_dl_falcon_resources
  */
 struct efx_dl_device_info {
        struct efx_dl_device_info *next;
@@ -291,18 +100,16 @@ struct efx_dl_device_info {
 /**
  * enum efx_dl_falcon_resource_flags - Falcon resource information flags.
  *
- * Flags that describe hardware variations for the described Falcon based port.
+ * Flags that describe hardware variations for the current Falcon device.
  *
  * @EFX_DL_FALCON_DUAL_FUNC: Port is dual-function.
  *     Certain silicon revisions have two pci functions, and require
  *     certain hardware resources to be accessed via the secondary
- *     function. See the discussion of @pci_dev in &struct efx_dl_device
- *     below.
+ *     function
  * @EFX_DL_FALCON_USE_MSI: Port is initialised to use MSI/MSI-X interrupts.
  *     Falcon supports traditional legacy interrupts and MSI/MSI-X
- *     interrupts. Since the sfc driver supports either, as a run
- *     time configuration, driverlink drivers need to be aware of which
- *     one to use for their interrupting resources.
+ *     interrupts. The choice is made at run time by the sfc driver, and
+ *     notified to the clients by this enumeration
  */
 enum efx_dl_falcon_resource_flags {
        EFX_DL_FALCON_DUAL_FUNC = 0x1,
@@ -336,20 +143,23 @@ struct efx_dl_falcon_resources {
 struct efx_dl_falcon_resources {
        struct efx_dl_device_info hdr;
        spinlock_t *biu_lock;
-       unsigned buffer_table_min, buffer_table_lim;
-       unsigned evq_timer_min, evq_timer_lim;
-       unsigned evq_int_min, evq_int_lim;
-       unsigned rxq_min, rxq_lim;
-       unsigned txq_min, txq_lim;
+       unsigned buffer_table_min;
+       unsigned buffer_table_lim;
+       unsigned evq_timer_min;
+       unsigned evq_timer_lim;
+       unsigned evq_int_min;
+       unsigned evq_int_lim;
+       unsigned rxq_min;
+       unsigned rxq_lim;
+       unsigned txq_min;
+       unsigned txq_lim;
        enum efx_dl_falcon_resource_flags flags;
 };
 
 /**
  * struct efx_dl_device - An Efx driverlink device.
  *
- * @pci_dev: Underlying PCI device.
- *     This is the PCI device used by the sfc driver.  It will
- *     already have been enabled for bus-mastering DMA etc.
+ * @pci_dev: PCI device used by the sfc driver.
  * @priv: Driver private data
  *     Driverlink clients can use this to store a pointer to their
  *     internal per-device data structure. Each (driver, device)
@@ -380,139 +190,57 @@ enum efx_veto {
 /**
  * struct efx_dl_callbacks - Efx callbacks
  *
- * These methods can be hooked in to the sfc driver via
+ * These methods can be hooked into the sfc driver via
  * efx_dl_register_callbacks().  They allow clients to intercept and/or
  * modify the behaviour of the sfc driver at predetermined points.
  *
- * For efficiency, only one client can hook each callback.
- *
- * Since these callbacks are called on packet transmit and reception
- * paths, clients should avoid acquiring locks or allocating memory.
+ * For efficiency, only one client can hook each callback. Since these
+ * callbacks are called on packet transmit and reception paths, and the
+ * sfc driver may have multiple tx and rx queues per port, clients should
+ * avoid acquiring locks or allocating memory.
  *
  * @tx_packet: Called when packet is about to be transmitted
+ *     Called for every packet about to be transmitted, providing means
+ *     for the client to snoop traffic, and veto transmission by returning
+ *     %EFX_VETO_PACKET (the sfc driver will subsequently free the skb).
+ *     Context: tasklet, netif_tx_lock held
  * @rx_packet: Called when packet is received
- * @link_change: Called when link status has changed
- * @request_mtu: Called to request MTU change
- * @mtu_changed: Called when MTU has been changed
- * @event: Called when NIC event is not handled by the sfc driver
+ *     Called for every received packet (after LRO), allowing the client
+ *     to snoop every received packet (on every rx queue), and veto
+ *     reception by returning %EFX_VETO_PACKET.
+ *     Context: tasklet
+ * @link_change: Never used
+ * @request_mtu: Called to request MTU change.
+ *     Called whenever the user requests the net_dev mtu to be changed.
+ *     If the client returns an error, the mtu change is aborted. The sfc
+ *     driver guarantees that no other callbacks are running.
+ *     Context: process, rtnl_lock held.
+ * @mtu_changed: Called when MTU has been changed.
+ *     Called after the mtu has been successfully changed, always after
+ *     a previous call to request_mtu(). The sfc driver guarantees that no
+ *     other callbacks are running.
+ *     Context: process, rtnl_lock held.
+ * @event: Called when a hardware NIC event is not understood by the sfc 
driver.
+ *     Context: tasklet.
  */
 struct efx_dl_callbacks {
-       /*
-        * tx_packet - Packet about to be transmitted.
-        * @efx_dev:            Efx driverlink device
-        * @skb:                Socket buffer containing the packet to be sent
-        *
-        * This method is called for every packet about to be
-        * transmitted.  It allows the client to snoop on traffic sent
-        * via the kernel queues.
-        *
-        * The method may return %EFX_VETO_PACKET in order to prevent
-        * the sfc driver from transmitting the packet.  The net
-        * driver will then discard the packet.  If the client wishes
-        * to retain a reference to the packet data after returning
-        * %EFX_VETO_PACKET, it must obtain its own copy of the
-        * packet (e.g. by calling skb_get(), or by copying out the
-        * packet data to an external buffer).
-        *
-        * This method must return quickly, since it will have a
-        * direct performance impact upon the sfc driver.  It will be
-        * called with interrupts disabled (and may be called in
-        * interrupt context), so may not sleep. Since the sfc driver
-        * may have multiple TX queues, running in parallel, please avoid
-        * the need for locking if it all possible.
-        */
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
        enum efx_veto fastcall (*tx_packet) (struct efx_dl_device *efx_dev,
                                             struct sk_buff *skb);
-
-       /*
-        * rx_packet - Packet received.
-        * @efx_dev:            Efx driverlink device
-        * @pkt_hdr:            Pointer to received packet
-        * @pkt_len:            Length of received packet
-        *
-        * This method is called for every received packet.  It allows
-        * the client to snoop on traffic received by the kernel
-        * queues.
-        *
-        * The method may return %EFX_VETO_PACKET in order to prevent
-        * the sfc driver from passing the packet to the kernel.  The net
-        * driver will then discard the packet.
-        *
-        * This method must return quickly, since it will have a
-        * direct performance impact upon the sfc driver.  It is
-        * called in tasklet context, so may not sleep.  Note that
-        * there are per-channel tasklets in the sfc driver, so
-        * rx_packet() may be called simultaneously on different CPUs
-        * and must lock appropriately.  The design of the sfc driver
-        * allows for lockless operation between receive channels, so
-        * please avoid the need for locking if at all possible.
-        */
+#else
+       enum efx_veto (*tx_packet) (struct efx_dl_device *efx_dev,
+                                   struct sk_buff *skb);
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
        enum efx_veto fastcall (*rx_packet) (struct efx_dl_device *efx_dev,
                                             const char *pkt_hdr, int pkt_len);
-
-       /*
-        * link_change - Link status change.
-        * @efx_dev:            Efx driverlink device
-        * @link_up:            Link up indicator
-        *
-        * This method is called to inform the driverlink client
-        * whenever the PHY link status changes.  By the time this
-        * function is called, the MAC has already been reconfigured
-        * with the new autonegotiation settings from the PHY.
-        *
-        * This method is called from tasklet context and may not
-        * sleep.
-        */
-       void (*link_change) (struct efx_dl_device *efx_dev, int link_up);
-
-       /*
-        * request_mtu: Request MTU change.
-        * @efx_dev:            Efx driverlink device
-        * @new_mtu:            Requested new MTU
-        *
-        * This method is called whenever the user requests an MTU
-        * change on an interface.  The client may return an error, in
-        * which case the MTU change request will be denied.  If the
-        * client returns success, the MAC will be reconfigured with a
-        * new maxmimum frame length equal to
-        * EFX_MAX_FRAME_LEN(new_mtu).  The client will be notified
-        * via the mtu_changed() method once the MAC has been
-        * reconfigured.
-        *
-        * The current MTU for the port can be obtained via
-        * efx_dl_get_netdev(efx_dl_device)->mtu.
-        *
-        * The sfc driver guarantees that no other callback functions
-        * are in progress when this method is called.  This function
-        * is called in process context and may sleep.
-        *
-        * Return a negative error code or 0 on success.
-        */
+#else
+       enum efx_veto (*rx_packet) (struct efx_dl_device *efx_dev,
+                                   const char *pkt_hdr, int pkt_len);
+#endif
+       void (*link_change) (struct efx_dl_device *, int);
        int (*request_mtu) (struct efx_dl_device *efx_dev, int new_mtu);
-
-       /*
-        * mtu_changed - MTU has been changed.
-        * @efx_dev:            Efx driverlink device
-        * @mtu:                The new MTU
-        *
-        * This method is called once the MAC has been reconfigured
-        * with a new MTU.  There will have been a preceding call to
-        * request_mtu().
-        *
-        * The sfc driver guarantees that no other callback functions
-        * are in progress when this method is called.  This function
-        * is called in process context and may sleep.
-        */
        void (*mtu_changed) (struct efx_dl_device *efx_dev, int mtu);
-
-       /*
-        * event - Event callback.
-        * @efx_dev:            Efx driverlink device
-        * @p_event:            Pointer to event
-        *
-        * This method is called for each event that is not handled by the
-        * sfc driver.
-        */
        void (*event) (struct efx_dl_device *efx_dev, void *p_event);
 };
 
@@ -523,16 +251,47 @@ struct efx_dl_callbacks {
        efx_dl_stringify_2(efx_dl_register_driver_api_ver_,     \
                           EFX_DRIVERLINK_API_VERSION)
 
+/**
+ * efx_dl_register_driver() - Register a client driver
+ * @driver: Driver operations structure
+ *
+ * This acquires the rtnl_lock and therefore must be called from
+ * process context.
+ */
 extern int efx_dl_register_driver(struct efx_dl_driver *driver);
 
+/**
+ * efx_dl_unregister_driver() - Unregister a client driver
+ * @driver: Driver operations structure
+ *
+ * This acquires the rtnl_lock and therefore must be called from
+ * process context.
+ */
 extern void efx_dl_unregister_driver(struct efx_dl_driver *driver);
 
+/**
+ * efx_dl_register_callbacks() - Set callback functions for a device
+ * @efx_dev: Device to be affected
+ * @callbacks: Callback functions structure
+ *
+ * This must be called in process context from the driver's probe()
+ * operation.
+ */
 extern int efx_dl_register_callbacks(struct efx_dl_device *efx_dev,
                                     struct efx_dl_callbacks *callbacks);
 
+/**
+ * efx_dl_unregister_callbacks() - Unset callback functions for a device
+ * @efx_dev: Device to be affected
+ * @callbacks: Callback functions structure
+ *
+ * This must be called in process context from the driver's remove()
+ * operation.
+ */
 extern void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev,
                                        struct efx_dl_callbacks *callbacks);
 
+/* Schedule a reset without grabbing any locks */
 extern void efx_dl_schedule_reset(struct efx_dl_device *efx_dev);
 
 /**
@@ -544,19 +303,13 @@ extern void efx_dl_schedule_reset(struct
  * @_p: Iterator variable
  *
  * Example:
- *
- * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info 
...)
- * {
- *        struct efx_dl_falcon_resources *res;
- *
- *        
efx_dl_for_each_device_info_matching(dev_info,EFX_DL_FALCON_RESOURCES,
- *                                             struct efx_dl_falcon_resources,
- *                                             hdr, res) {
- *                if (res->flags & EFX_DL_FALCON_DUAL_FUNC) {
- *                          .....
- *                }
- *        }
- * }
+ *     struct efx_dl_falcon_resources *res;
+ *     efx_dl_for_each_device_info_matching(dev_info, EFX_DL_FALCON_RESOURCES,
+ *                                          struct efx_dl_falcon_resources,
+ *                                          hdr, res) {
+ *             if (res->flags & EFX_DL_FALCON_DUAL_FUNC)
+ *                     ....
+ *     }
  */
 #define efx_dl_for_each_device_info_matching(_dev_info, _type,         \
                                             _info_type, _field, _p)    \
@@ -576,17 +329,11 @@ extern void efx_dl_schedule_reset(struct
  * @_p: Result variable
  *
  * Example:
- *
- * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info 
...)
- * {
- *        struct efx_dl_falcon_resources *res;
- *
- *        efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES,
- *                                  struct efx_dl_falcon_resources, hdr, res);
- *        if (res != NULL) {
- *                 ....
- *        }
- * }
+ *     struct efx_dl_falcon_resources *res;
+ *     efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES,
+ *                               struct efx_dl_falcon_resources, hdr, res);
+ *     if (res)
+ *             ....
  */
 #define efx_dl_search_device_info(_dev_info, _type, _info_type,                
\
                                  _field, _p)                           \
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/efx.c
--- a/drivers/net/sfc/efx.c     Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/efx.c     Fri Jan 08 13:05:49 2010 +0000
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2005-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2009 Solarflare Communications Inc.
  *
  * 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/module.h>
@@ -36,18 +19,16 @@
 #include <linux/in.h>
 #include <linux/crc32.h>
 #include <linux/ethtool.h>
+#include <linux/topology.h>
 #include "net_driver.h"
-#include "gmii.h"
 #include "driverlink.h"
-#include "selftest.h"
 #include "debugfs.h"
-#include "ethtool.h"
-#include "tx.h"
-#include "rx.h"
 #include "efx.h"
 #include "mdio_10g.h"
-#include "falcon.h"
-#include "workarounds.h"
+#include "nic.h"
+#include "efx_ioctl.h"
+
+#include "mcdi.h"
 
 /**************************************************************************
  *
@@ -59,16 +40,33 @@
 /* Loopback mode names (see LOOPBACK_MODE()) */
 const unsigned int efx_loopback_mode_max = LOOPBACK_MAX;
 const char *efx_loopback_mode_names[] = {
-       [LOOPBACK_NONE]    = "NONE",
-       [LOOPBACK_MAC]     = "MAC",
-       [LOOPBACK_XGMII]   = "XGMII",
-       [LOOPBACK_XGXS]    = "XGXS",
-       [LOOPBACK_XAUI]    = "XAUI",
-       [LOOPBACK_PHY]     = "PHY",
-       [LOOPBACK_PHYXS]   = "PHY(XS)",
-       [LOOPBACK_PCS]     = "PHY(PCS)",
-       [LOOPBACK_PMAPMD]  = "PHY(PMAPMD)",
-       [LOOPBACK_NETWORK] = "NETWORK",
+       [LOOPBACK_NONE]         = "NONE",
+       [LOOPBACK_DATA]         = "DATAPATH",
+       [LOOPBACK_GMAC]         = "GMAC",
+       [LOOPBACK_XGMII]        = "XGMII",
+       [LOOPBACK_XGXS]         = "XGXS",
+       [LOOPBACK_XAUI]         = "XAUI",
+       [LOOPBACK_GMII]         = "GMII",
+       [LOOPBACK_SGMII]        = "SGMII",
+       [LOOPBACK_XGBR]         = "XGBR",
+       [LOOPBACK_XFI]          = "XFI",
+       [LOOPBACK_XAUI_FAR]     = "XAUI_FAR",
+       [LOOPBACK_GMII_FAR]     = "GMII_FAR",
+       [LOOPBACK_SGMII_FAR]    = "SGMII_FAR",
+       [LOOPBACK_XFI_FAR]      = "XFI_FAR",
+       [LOOPBACK_GPHY]         = "GPHY",
+       [LOOPBACK_PHYXS]        = "PHYXS",
+       [LOOPBACK_PCS]          = "PCS",
+       [LOOPBACK_PMAPMD]       = "PMA/PMD",
+       [LOOPBACK_XPORT]        = "XPORT",
+       [LOOPBACK_XGMII_WS]     = "XGMII_WS",
+       [LOOPBACK_XAUI_WS]      = "XAUI_WS",
+       [LOOPBACK_XAUI_WS_FAR]  = "XAUI_WS_FAR",
+       [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR",
+       [LOOPBACK_GMII_WS]      = "GMII_WS",
+       [LOOPBACK_XFI_WS]       = "XFI_WS",
+       [LOOPBACK_XFI_WS_FAR]   = "XFI_WS_FAR",
+       [LOOPBACK_PHYXS_WS]     = "PHYXS_WS",
 };
 
 /* Interrupt mode names (see INT_MODE())) */
@@ -79,38 +77,19 @@ const char *efx_interrupt_mode_names[] =
        [EFX_INT_MODE_LEGACY] = "legacy",
 };
 
-/* PHY type names (see PHY_TYPE())) */
-const unsigned int efx_phy_type_max = PHY_TYPE_MAX;
-const char *efx_phy_type_names[] = {
-       [PHY_TYPE_NONE]        = "none",
-       [PHY_TYPE_CX4_RTMR]    = "Mysticom CX4",
-       [PHY_TYPE_1G_ALASKA]   = "1G Alaska",
-       [PHY_TYPE_10XPRESS]    = "SFC 10Xpress",
-       [PHY_TYPE_XFP]         = "Quake XFP",
-       [PHY_TYPE_PM8358]      = "PM8358 XAUI",
-};
-
 const unsigned int efx_reset_type_max = RESET_TYPE_MAX;
 const char *efx_reset_type_names[] = {
        [RESET_TYPE_INVISIBLE]     = "INVISIBLE",
        [RESET_TYPE_ALL]           = "ALL",
        [RESET_TYPE_WORLD]         = "WORLD",
        [RESET_TYPE_DISABLE]       = "DISABLE",
-       [RESET_TYPE_MONITOR]       = "MONITOR",
+       [RESET_TYPE_TX_WATCHDOG]   = "TX_WATCHDOG",
        [RESET_TYPE_INT_ERROR]     = "INT_ERROR",
        [RESET_TYPE_RX_RECOVERY]   = "RX_RECOVERY",
        [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH",
        [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH",
        [RESET_TYPE_TX_SKIP]       = "TX_SKIP",
-};
-
-const unsigned int efx_nic_state_max = STATE_MAX;
-const char *efx_nic_state_names[] = {
-       [STATE_INIT]          = "INIT",
-       [STATE_RUNNING]       = "RUNNING",
-       [STATE_FINI]          = "FINI",
-       [STATE_RESETTING]     = "RESETTING",
-       [STATE_DISABLED]      = "DISABLED",
+       [RESET_TYPE_MC_FAILURE]    = "MC_FAILURE",
 };
 
 #define EFX_MAX_MTU (9 * 1024)
@@ -122,32 +101,42 @@ const char *efx_nic_state_names[] = {
  */
 static struct workqueue_struct *refill_workqueue;
 
+/* Reset workqueue. If any NIC has a hardware failure then a reset will be
+ * queued onto this work queue. This is not a per-nic work queue, because
+ * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
+ */
+static struct workqueue_struct *reset_workqueue;
+
 /**************************************************************************
  *
  * Configurable values
  *
  *************************************************************************/
 
+#if defined(EFX_USE_KCOMPAT) && (defined(EFX_USE_GRO) || 
defined(EFX_USE_SFC_LRO))
 /*
  * Enable large receive offload (LRO) aka soft segment reassembly (SSR)
  *
  * This sets the default for new devices.  It can be controlled later
  * using ethtool.
  */
-static int lro = 1;
+static int lro = true;
 module_param(lro, int, 0644);
 MODULE_PARM_DESC(lro, "Large receive offload acceleration");
+#endif
 
 /*
  * Use separate channels for TX and RX events
  *
- * Set this to 1 to use separate channels for TX and RX. It allows us to
- * apply a higher level of interrupt moderation to TX events.
- *
- * This is forced to 0 for MSI interrupt mode as the interrupt vector
- * is not written
- */
-static unsigned int separate_tx_and_rx_channels = 1;
+ * Set this to 1 to use separate channels for TX and RX. It allows us
+ * to control interrupt affinity separately for TX and RX.
+ *
+ * This is only used in MSI-X interrupt mode
+ */
+static unsigned int separate_tx_channels = false;
+module_param(separate_tx_channels, uint, 0644);
+MODULE_PARM_DESC(separate_tx_channels,
+                "Use separate channels for TX and RX");
 
 /* This is the weight assigned to each of the (per-channel) virtual
  * NAPI devices.
@@ -159,11 +148,6 @@ static int napi_weight = 64;
  * hardware and driver as necessary.
  */
 unsigned int efx_monitor_interval = 1 * HZ;
-
-/* This controls whether or not the hardware monitor will trigger a
- * reset when it detects an error condition.
- */
-static unsigned int monitor_reset = 1;
 
 /* This controls whether or not the driver will initialise devices
  * with invalid MAC addresses stored in the EEPROM or flash.  If true,
@@ -193,13 +177,6 @@ static unsigned int rx_irq_mod_usec = 60
  */
 static unsigned int tx_irq_mod_usec = 150;
 
-/* Ignore online self-test failures at load
- *
- * If set to 1, then the driver will not fail to load
- * if the online self-test fails. Useful only during testing
- */
-static unsigned int allow_load_on_failure;
-
 /* This is the first interrupt mode to try out of:
  * 0 => MSI-X
  * 1 => MSI
@@ -207,22 +184,50 @@ static unsigned int allow_load_on_failur
  */
 static unsigned int interrupt_mode;
 
-/* If set to 1, then the driver will perform an offline self test
- * when each interface first comes up. This will appear like the
- * interface bounces up and down
- */
-static unsigned int onload_offline_selftest = 1;
-
-/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
- * i.e. the number of CPUs among which we may distribute simultaneous
- * interrupt handling.
- *
- * Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
- * The default (0) means to assign an interrupt to each package (level II 
cache)
- */
-static unsigned int rss_cpus;
-module_param(rss_cpus, uint, 0444);
-MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
+/* This is the requested number of CPUs to use for Receive-Side Scaling
+ * (RSS), i.e. the number of CPUs among which we may distribute
+ * simultaneous interrupt handling.  Or alternatively it may be set to
+ * "packages", "cores" or "hyperthreads" to get one receive channel per
+ * package, core or hyperthread.
+ *
+ * Systems without MSI-X will only target one CPU via legacy or MSI
+ * interrupt.  The default is "packages".
+ */
+static char *rss_cpus;
+module_param(rss_cpus, charp, 0444);
+MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling, "
+                "or 'packages', 'cores' or 'hyperthreads'");
+
+enum rss_mode {
+       EFX_RSS_PACKAGES,
+       EFX_RSS_CORES,
+       EFX_RSS_HYPERTHREADS,
+       EFX_RSS_CUSTOM,
+};
+
+static int phy_flash_cfg;
+module_param(phy_flash_cfg, int, 0644);
+MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially");
+
+static unsigned irq_adapt_enable = 1;
+module_param(irq_adapt_enable, uint, 0444);
+MODULE_PARM_DESC(irq_adapt_enable,
+                "Enable adaptive interrupt moderation");
+
+static unsigned irq_adapt_low_thresh = 10000;
+module_param(irq_adapt_low_thresh, uint, 0644);
+MODULE_PARM_DESC(irq_adapt_low_thresh,
+                "Threshold score for reducing IRQ moderation");
+
+static unsigned irq_adapt_high_thresh = 20000;
+module_param(irq_adapt_high_thresh, uint, 0644);
+MODULE_PARM_DESC(irq_adapt_high_thresh,
+                "Threshold score for increasing IRQ moderation");
+
+static unsigned irq_adapt_irqs = 1000;
+module_param(irq_adapt_irqs, uint, 0644);
+MODULE_PARM_DESC(irq_adapt_irqs,
+                "Number of IRQs per IRQ moderation adaptation");
 
 /**************************************************************************
  *
@@ -237,7 +242,7 @@ static void efx_fini_channels(struct efx
 #define EFX_ASSERT_RESET_SERIALISED(efx)               \
        do {                                            \
                if ((efx->state == STATE_RUNNING) ||    \
-                   (efx->state == STATE_RESETTING))    \
+                   (efx->state == STATE_DISABLED))     \
                        ASSERT_RTNL();                  \
        } while (0)
 
@@ -254,16 +259,18 @@ static void efx_fini_channels(struct efx
  * never be concurrently called more than once on the same channel,
  * though different channels may be being processed concurrently.
  */
-static inline int efx_process_channel(struct efx_channel *channel, int 
rx_quota)
-{
-       int rxdmaqs;
-       struct efx_rx_queue *rx_queue;
-
-       if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
+static int efx_process_channel(struct efx_channel *channel, int rx_quota)
+{
+       struct efx_nic *efx = channel->efx;
+       int rx_packets;
+
+       if (unlikely(efx->reset_pending != RESET_TYPE_NONE ||
                     !channel->enabled))
-               return rx_quota;
-
-       rxdmaqs = falcon_process_eventq(channel, &rx_quota);
+               return 0;
+
+       rx_packets = efx_nic_process_eventq(channel, rx_quota);
+       if (rx_packets == 0)
+               return 0;
 
        /* Deliver last RX packet. */
        if (channel->rx_pkt) {
@@ -272,19 +279,11 @@ static inline int efx_process_channel(st
                channel->rx_pkt = NULL;
        }
 
-       efx_flush_lro(channel);
        efx_rx_strategy(channel);
 
-       /* Refill descriptor rings as necessary */
-       rx_queue = &channel->efx->rx_queue[0];
-       while (rxdmaqs) {
-               if (rxdmaqs & 0x01)
-                       efx_fast_push_rx_descriptors(rx_queue);
-               rx_queue++;
-               rxdmaqs >>= 1;
-       }
-
-       return rx_quota;
+       efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+
+       return rx_packets;
 }
 
 /* Mark channel as finished processing
@@ -295,12 +294,13 @@ static inline int efx_process_channel(st
  */
 static inline void efx_channel_processed(struct efx_channel *channel)
 {
-       /* Write to EVQ_RPTR_REG.  If a new event arrived in a race
-        * with finishing processing, a new interrupt will be raised.
-        */
-       channel->work_pending = 0;
-       smp_wmb(); /* Ensure channel updated before any new interrupt. */
-       falcon_eventq_read_ack(channel);
+       /* The interrupt handler for this channel may set work_pending
+        * as soon as we acknowledge the events we've seen.  Make sure
+        * it's cleared before then. */
+       channel->work_pending = false;
+       smp_wmb();
+
+       efx_nic_eventq_read_ack(channel);
 }
 
 /* NAPI poll handler
@@ -308,33 +308,66 @@ static inline void efx_channel_processed
  * NAPI guarantees serialisation of polls of the same device, which
  * provides the guarantee required by efx_process_channel().
  */
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_OLD_NAPI)
+static int efx_poll(struct napi_struct *napi, int budget)
+{
+       struct efx_channel *channel =
+               container_of(napi, struct efx_channel, napi_str);
+#else
 static int efx_poll(struct net_device *napi, int *budget_ret)
 {
-       struct net_device *napi_dev = napi;
-       struct efx_channel *channel = napi_dev->priv;
-       int budget = min(napi_dev->quota, *budget_ret);
-       int unused;
+       struct efx_channel *channel = napi->priv;
+       int budget = min(napi->quota, *budget_ret);
+#endif
        int rx_packets;
 
        EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
                  channel->channel, raw_smp_processor_id());
 
-       unused = efx_process_channel(channel, budget);
-       rx_packets = (budget - unused);
-       napi_dev->quota -= rx_packets;
+       rx_packets = efx_process_channel(channel, budget);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_HAVE_OLD_NAPI)
+       napi->quota -= rx_packets;
        *budget_ret -= rx_packets;
+#endif
 
        if (rx_packets < budget) {
+               struct efx_nic *efx = channel->efx;
+
+               if (channel->used_flags & EFX_USED_BY_RX &&
+                   efx->irq_rx_adaptive &&
+                   unlikely(++channel->irq_count == irq_adapt_irqs)) {
+                       if (unlikely(channel->irq_mod_score <
+                                    irq_adapt_low_thresh)) {
+                               if (channel->irq_moderation > 1) {
+                                       channel->irq_moderation -= 1;
+                                       efx->type->push_irq_moderation(channel);
+                               }
+                       } else if (unlikely(channel->irq_mod_score >
+                                           irq_adapt_high_thresh)) {
+                               if (channel->irq_moderation <
+                                   efx->irq_rx_moderation) {
+                                       channel->irq_moderation += 1;
+                                       efx->type->push_irq_moderation(channel);
+                               }
+                       }
+                       channel->irq_count = 0;
+                       channel->irq_mod_score = 0;
+               }
+
                /* There is no race here; although napi_disable() will
-                * only wait for netif_rx_complete(), this isn't a problem
+                * only wait for napi_complete(), this isn't a problem
                 * since efx_channel_processed() will have no effect if
                 * interrupts have already been disabled.
                 */
-               netif_rx_complete(napi_dev, napi);
+               napi_complete(napi);
                efx_channel_processed(channel);
        }
 
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_OLD_NAPI)
+       return rx_packets;
+#else
        return (rx_packets >= budget);
+#endif
 }
 
 /* Process the eventq of the specified channel immediately on this CPU
@@ -353,27 +386,24 @@ void efx_process_channel_now(struct efx_
        BUG_ON(!channel->enabled);
 
        /* Disable interrupts and wait for ISRs to complete */
-       falcon_disable_interrupts(efx);
+       efx_nic_disable_interrupts(efx);
        if (efx->legacy_irq)
                synchronize_irq(efx->legacy_irq);
-       if (channel->has_interrupt && channel->irq)
+       if (channel->irq)
                synchronize_irq(channel->irq);
 
        /* Wait for any NAPI processing to complete */
        napi_disable(&channel->napi_str);
 
        /* Poll the channel */
-       (void) efx_process_channel(channel, efx->type->evq_size);
+       efx_process_channel(channel, EFX_EVQ_SIZE);
 
        /* Ack the eventq. This may cause an interrupt to be generated
         * when they are reenabled */
        efx_channel_processed(channel);
 
-       /* Reenable NAPI polling */
        napi_enable(&channel->napi_str);
-
-       /* Reenable interrupts */
-       falcon_enable_interrupts(efx);
+       efx_nic_enable_interrupts(efx);
 }
 
 /* Create event queue
@@ -385,32 +415,31 @@ static int efx_probe_eventq(struct efx_c
 {
        EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
 
-       return falcon_probe_eventq(channel);
+       return efx_nic_probe_eventq(channel);
 }
 
 /* Prepare channel's event queue */
-static int efx_init_eventq(struct efx_channel *channel)
+static void efx_init_eventq(struct efx_channel *channel)
 {
        EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
 
-       /* Initialise fields */
        channel->eventq_read_ptr = 0;
 
-       return falcon_init_eventq(channel);
+       efx_nic_init_eventq(channel);
 }
 
 static void efx_fini_eventq(struct efx_channel *channel)
 {
        EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
 
-       falcon_fini_eventq(channel);
+       efx_nic_fini_eventq(channel);
 }
 
 static void efx_remove_eventq(struct efx_channel *channel)
 {
        EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
 
-       falcon_remove_eventq(channel);
+       efx_nic_remove_eventq(channel);
 }
 
 /**************************************************************************
@@ -418,26 +447,6 @@ static void efx_remove_eventq(struct efx
  * Channel handling
  *
  *************************************************************************/
-
-/* Setup per-NIC RX buffer parameters.
- * Calculate the rx buffer allocation parameters required to support
- * the current MTU, including padding for header alignment and overruns.
- */
-static void efx_calc_rx_buffer_params(struct efx_nic *efx)
-{
-       unsigned int order, len;
-
-       len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
-              EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
-              efx->type->rx_buffer_padding);
-
-       /* Calculate page-order */
-       for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order)
-               ;
-
-       efx->rx_buffer_len = len;
-       efx->rx_buffer_order = order;
-}
 
 static int efx_probe_channel(struct efx_channel *channel)
 {
@@ -478,54 +487,64 @@ static int efx_probe_channel(struct efx_
 }
 
 
+static void efx_set_channel_names(struct efx_nic *efx)
+{
+       struct efx_channel *channel;
+       const char *type = "";
+       int number;
+
+       efx_for_each_channel(channel, efx) {
+               number = channel->channel;
+               if (efx->n_channels > efx->n_rx_queues) {
+                       if (channel->channel < efx->n_rx_queues) {
+                               type = "-rx";
+                       } else {
+                               type = "-tx";
+                               number -= efx->n_rx_queues;
+                       }
+               }
+               snprintf(channel->name, sizeof(channel->name),
+                        "%s%s-%d", efx->name, type, number);
+       }
+}
+
 /* Channels are shutdown and reinitialised whilst the NIC is running
  * to propagate configuration changes (mtu, checksum offload), or
  * to clear hardware error conditions
  */
-static int efx_init_channels(struct efx_nic *efx)
+static void efx_init_channels(struct efx_nic *efx)
 {
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
        struct efx_channel *channel;
-       int rc = 0;
-
-       /* Recalculate the rx buffer parameters */
-       efx_calc_rx_buffer_params(efx);
+
+       /* Calculate the rx buffer allocation parameters required to
+        * support the current MTU, including padding for header
+        * alignment and overruns.
+        */
+       efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
+                             EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+                             efx->type->rx_buffer_padding);
+       efx->rx_buffer_order = get_order(efx->rx_buffer_len);
 
        /* Initialise the channels */
        efx_for_each_channel(channel, efx) {
                EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
 
-               rc = efx_init_eventq(channel);
-               if (rc)
-                       goto err;
-
-               efx_for_each_channel_tx_queue(tx_queue, channel) {
-                       rc = efx_init_tx_queue(tx_queue);
-                       if (rc)
-                               goto err;
-               }
+               efx_init_eventq(channel);
+
+               efx_for_each_channel_tx_queue(tx_queue, channel)
+                       efx_init_tx_queue(tx_queue);
 
                /* The rx buffer allocation strategy is MTU dependent */
                efx_rx_strategy(channel);
 
-               efx_for_each_channel_rx_queue(rx_queue, channel) {
-                       rc = efx_init_rx_queue(rx_queue);
-                       if (rc)
-                               goto err;
-               }
+               efx_for_each_channel_rx_queue(rx_queue, channel)
+                       efx_init_rx_queue(rx_queue);
 
                WARN_ON(channel->rx_pkt != NULL);
                efx_rx_strategy(channel);
        }
-
-       return 0;
-
- err:
-       EFX_ERR(efx, "failed to initialise channel %d\n",
-               channel ? channel->channel : -1);
-       efx_fini_channels(efx);
-       return rc;
 }
 
 /* This enables event queue processing and packet transmission.
@@ -539,16 +558,13 @@ static void efx_start_channel(struct efx
 
        EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
 
-       if (!(channel->efx->net_dev->flags & IFF_UP))
-               netif_napi_add(channel->napi_dev, &channel->napi_str,
-                              efx_poll, napi_weight);
-
-       /* Mark channel as enabled */
-       channel->work_pending = 0;
-       channel->enabled = 1;
-       smp_wmb(); /* ensure channel updated before first interrupt */
-
-       /* Enable NAPI poll handler */
+       /* The interrupt handler for this channel may set work_pending
+        * as soon as we enable it.  Make sure it's cleared before
+        * then.  Similarly, make sure it sees the enabled flag set. */
+       channel->work_pending = false;
+       channel->enabled = true;
+       smp_wmb();
+
        napi_enable(&channel->napi_str);
 
        /* Load up RX descriptors */
@@ -569,10 +585,7 @@ static void efx_stop_channel(struct efx_
 
        EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
 
-       /* Mark channel as disabled */
-       channel->enabled = 0;
-
-       /* Wait for any NAPI processing to complete */
+       channel->enabled = false;
        napi_disable(&channel->napi_str);
 
        /* Ensure that any worker threads have exited or will be no-ops */
@@ -587,9 +600,16 @@ static void efx_fini_channels(struct efx
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
+       int rc;
 
        EFX_ASSERT_RESET_SERIALISED(efx);
        BUG_ON(efx->port_enabled);
+
+       rc = efx_nic_flush_queues(efx);
+       if (rc)
+               EFX_ERR(efx, "failed to flush queues\n");
+       else
+               EFX_LOG(efx, "successfully flushed all queues\n");
 
        efx_for_each_channel(channel, efx) {
                EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
@@ -598,13 +618,6 @@ static void efx_fini_channels(struct efx
                        efx_fini_rx_queue(rx_queue);
                efx_for_each_channel_tx_queue(tx_queue, channel)
                        efx_fini_tx_queue(tx_queue);
-       }
-
-       /* Do the event queues last so that we can handle flush events
-        * for all DMA queues. */
-       efx_for_each_channel(channel, efx) {
-               EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel);
-
                efx_fini_eventq(channel);
        }
 }
@@ -640,9 +653,9 @@ void efx_schedule_slow_fill(struct efx_r
  * netif_carrier_on/off) of the link status, and also maintains the
  * link status's stop on the port's TX queue.
  */
-static void efx_link_status_changed(struct efx_nic *efx)
-{
-       int carrier_ok;
+void efx_link_status_changed(struct efx_nic *efx)
+{
+       struct efx_link_state *link_state = &efx->link_state;
 
        /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
         * that no events are triggered between unregister_netdev() and the
@@ -651,119 +664,169 @@ static void efx_link_status_changed(stru
        if (!netif_running(efx->net_dev))
                return;
 
-       carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0;
-       if (efx->link_up != carrier_ok) {
+       if (efx->port_inhibited) {
+               netif_carrier_off(efx->net_dev);
+               return;
+       }
+
+       if (link_state->up != netif_carrier_ok(efx->net_dev)) {
                efx->n_link_state_changes++;
 
-               if (efx->link_up)
+               if (link_state->up)
                        netif_carrier_on(efx->net_dev);
                else
                        netif_carrier_off(efx->net_dev);
        }
 
-       /* Inform driverlink client */
-       EFX_DL_CALLBACK(efx, link_change, efx->link_up);
-
        /* Status message for kernel log */
-       if (efx->link_up) {
-               struct mii_if_info *gmii = &efx->mii;
-               unsigned adv, lpa;
-               /* NONE here means direct XAUI from the controller, with no
-                * MDIO-attached device we can query. */
-               if (efx->phy_type != PHY_TYPE_NONE) {
-                       adv = gmii_advertised(gmii);
-                       lpa = gmii_lpa(gmii);
-               } else {
-                       lpa = GM_LPA_10000 | LPA_DUPLEX;
-                       adv = lpa;
-               }
-               EFX_INFO(efx, "link up at %dMbps %s-duplex "
-                        "(adv %04x lpa %04x) (MTU %d)%s%s%s%s\n",
-                        (efx->link_options & GM_LPA_10000 ? 10000 :
-                         (efx->link_options & GM_LPA_1000 ? 1000 :
-                          (efx->link_options & GM_LPA_100 ? 100 :
-                           10))),
-                        (efx->link_options & GM_LPA_DUPLEX ?
-                         "full" : "half"),
-                        adv, lpa,
+       if (link_state->up) {
+               EFX_INFO(efx, "link up at %uMbps %s-duplex "
+                        "(MTU %d)%s%s%s%s\n",
+                        link_state->speed, link_state->fd ? "full" : "half",
                         efx->net_dev->mtu,
                         (efx->loopback_mode ? " [" : ""),
                         (efx->loopback_mode ? LOOPBACK_MODE(efx) : ""),
                         (efx->loopback_mode ? " LOOPBACK]" : ""),
                         (efx->promiscuous ? " [PROMISC]" : ""));
+
+               if ((efx->wanted_fc & EFX_FC_AUTO) &&
+                   (efx->wanted_fc & EFX_FC_TX) &&
+                   (~efx->link_state.fc & EFX_FC_TX))
+                       /* There is no way to report this state through 
ethtool, so
+                        * print this information to the kernel log */
+                       EFX_ERR(efx, "Flow control autonegotiated "
+                               "tx OFF (wanted ON)\n");
        } else {
                EFX_INFO(efx, "link down%s\n",
-                        efx->phy_powered ? "" : " [OFF]");
-       }
-
-}
-
-/* This call reinitialises the MAC to pick up new PHY settings. The
- * caller must hold the mac_lock */
-static void __efx_reconfigure_port(struct efx_nic *efx)
-{
+                        (efx->phy_mode & PHY_MODE_LOW_POWER) ? " [OFF]" : "");
+       }
+
+}
+
+void efx_link_set_advertising(struct efx_nic *efx, u32 advertising)
+{
+       efx->link_advertising = advertising;
+       if (advertising) {
+               if (advertising & ADVERTISED_Pause)
+                       efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX);
+               else
+                       efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);
+               if (advertising & ADVERTISED_Asym_Pause)
+                       efx->wanted_fc ^= EFX_FC_TX;
+       }
+}
+
+void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc)
+{
+       efx->wanted_fc = wanted_fc;
+       if (efx->link_advertising) {
+               if (wanted_fc & EFX_FC_RX)
+                       efx->link_advertising |= (ADVERTISED_Pause |
+                                                 ADVERTISED_Asym_Pause);
+               else
+                       efx->link_advertising &= ~(ADVERTISED_Pause |
+                                                  ADVERTISED_Asym_Pause);
+               if (wanted_fc & EFX_FC_TX)
+                       efx->link_advertising ^= ADVERTISED_Asym_Pause;
+       }
+}
+
+static void efx_fini_port(struct efx_nic *efx);
+
+/* Push loopback/power/transmit disable settings to the PHY, and reconfigure
+ * the MAC appropriately. All other PHY configuration changes are pushed
+ * through phy_op->set_settings(), and pushed asynchronously to the MAC
+ * through efx_monitor().
+ *
+ * Callers must hold the mac_lock
+ */
+int __efx_reconfigure_port(struct efx_nic *efx)
+{
+       enum efx_phy_mode phy_mode;
+       int rc;
+
        WARN_ON(!mutex_is_locked(&efx->mac_lock));
 
-       EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
-               raw_smp_processor_id());
-
-       efx->mac_op->reconfigure(efx);
-
-       /* Inform kernel of loss/gain of carrier */
-       efx_link_status_changed(efx);
+       /* Serialise the promiscuous flag with efx_set_multicast_list. */
+       if (efx_dev_registered(efx)) {
+               netif_addr_lock_bh(efx->net_dev);
+               netif_addr_unlock_bh(efx->net_dev);
+       }
+
+       /* Disable PHY transmit in mac level loopbacks */
+       phy_mode = efx->phy_mode;
+       if (LOOPBACK_INTERNAL(efx))
+               efx->phy_mode |= PHY_MODE_TX_DISABLED;
+       else
+               efx->phy_mode &= ~PHY_MODE_TX_DISABLED;
+
+       rc = efx->type->reconfigure_port(efx);
+
+       if (rc)
+               efx->phy_mode = phy_mode;
+
+       return rc;
 }
 
 /* Reinitialise the MAC to pick up new PHY settings, even if the port is
  * disabled. */
-void efx_reconfigure_port(struct efx_nic *efx)
-{
+int efx_reconfigure_port(struct efx_nic *efx)
+{
+       int rc;
+
        EFX_ASSERT_RESET_SERIALISED(efx);
 
        mutex_lock(&efx->mac_lock);
-       __efx_reconfigure_port(efx);
+       rc = __efx_reconfigure_port(efx);
        mutex_unlock(&efx->mac_lock);
-}
-
-/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all()
- * we don't efx_reconfigure_port() if the port is disabled. Care is taken
- * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */
-static void efx_reconfigure_work(struct work_struct *data)
-{
-       struct efx_nic *efx = container_of(data, struct efx_nic,
-                                          reconfigure_work);
+
+       return rc;
+}
+
+/* Asynchronous work item for changing MAC promiscuity and multicast
+ * hash.  Avoid a drain/rx_ingress enable by reconfiguring the current
+ * MAC directly. */
+static void efx_mac_work(struct work_struct *data)
+{
+       struct efx_nic *efx = container_of(data, struct efx_nic, mac_work);
 
        mutex_lock(&efx->mac_lock);
-       if (efx->port_enabled)
-               __efx_reconfigure_port(efx);
+       if (efx->port_enabled) {
+               efx->type->push_multicast_hash(efx);
+               efx->mac_op->reconfigure(efx);
+       }
        mutex_unlock(&efx->mac_lock);
 }
 
 static int efx_probe_port(struct efx_nic *efx)
 {
-       unsigned char *dev_addr;
        int rc;
 
        EFX_LOG(efx, "create port\n");
 
-       /* Connect up MAC/PHY operations table and read MAC address */
-       rc = falcon_probe_port(efx);
+       if (phy_flash_cfg)
+               efx->phy_mode = PHY_MODE_SPECIAL;
+
+       /* Connect up MAC/PHY operations table */
+       rc = efx->type->probe_port(efx);
        if (rc)
                goto err;
 
        /* Sanity check MAC address */
-       dev_addr = efx->mac_address;
-       if (!is_valid_ether_addr(dev_addr)) {
+       if (is_valid_ether_addr(efx->mac_address)) {
+               memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
+       } else {
                DECLARE_MAC_BUF(mac);
 
-               EFX_ERR(efx, "invalid MAC address %s\n",
-                       print_mac(mac, dev_addr));
                if (!allow_bad_hwaddr) {
+                       EFX_ERR(efx, "invalid MAC address %s\n",
+                               print_mac(mac, efx->mac_address));
                        rc = -EINVAL;
                        goto err;
                }
-               random_ether_addr(dev_addr);
+               random_ether_addr(efx->net_dev->dev_addr);
                EFX_INFO(efx, "using locally-generated MAC %s\n",
-                        print_mac(mac, dev_addr));
+                        print_mac(mac, efx->net_dev->dev_addr));
        }
 
        /* Register debugfs entries */
@@ -784,52 +847,61 @@ static int efx_init_port(struct efx_nic 
 
        EFX_LOG(efx, "init port\n");
 
-       /* The default power state is ON */
-       efx->phy_powered = 1;
-
-       /* Initialise the MAC and PHY */
-       rc = efx->mac_op->init(efx);
+       mutex_lock(&efx->mac_lock);
+
+       rc = efx->phy_op->init(efx);
        if (rc)
-               return rc;
-
-       efx->port_initialized = 1;
-
-       /* Reconfigure port to program MAC registers */
+               goto fail1;
+
+       efx->port_initialized = true;
+
+       /* Reconfigure the MAC before creating dma queues (required for
+        * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */
        efx->mac_op->reconfigure(efx);
 
+       /* Ensure the PHY advertises the correct flow control settings */
+       rc = efx->phy_op->reconfigure(efx);
+       if (rc)
+               goto fail2;
+
+       mutex_unlock(&efx->mac_lock);
        return 0;
-}
-
-/* Allow efx_reconfigure_port() to be scheduled, and close the window
- * between efx_stop_port and efx_flush_all whereby a previously scheduled
- * efx_reconfigure_port() may have been cancelled */
+
+fail2:
+       efx->phy_op->fini(efx);
+fail1:
+       mutex_unlock(&efx->mac_lock);
+       return rc;
+}
+
 static void efx_start_port(struct efx_nic *efx)
 {
        EFX_LOG(efx, "start port\n");
        BUG_ON(efx->port_enabled);
 
        mutex_lock(&efx->mac_lock);
-       efx->port_enabled = 1;
-       __efx_reconfigure_port(efx);
+       efx->port_enabled = true;
+
+       /* efx_mac_work() might have been scheduled after efx_stop_port(),
+        * and then cancelled by efx_flush_all() */
+       efx->type->push_multicast_hash(efx);
+       efx->mac_op->reconfigure(efx);
+
        mutex_unlock(&efx->mac_lock);
 }
 
-/* Prevent efx_reconfigure_work and efx_monitor() from executing, and
- * efx_set_multicast_list() from scheduling efx_reconfigure_work.
- * efx_reconfigure_work can still be scheduled via NAPI processing
- * until efx_flush_all() is called */
+/* Prevent efx_mac_work() and efx_monitor() from working */
 static void efx_stop_port(struct efx_nic *efx)
 {
        EFX_LOG(efx, "stop port\n");
 
        mutex_lock(&efx->mac_lock);
-       efx->port_enabled = 0;
+       efx->port_enabled = false;
        mutex_unlock(&efx->mac_lock);
 
-       /* Serialise against efx_set_multicast_list() */
-       if (NET_DEV_REGISTERED(efx)) {
-               netif_tx_lock_bh(efx->net_dev);
-               netif_tx_unlock_bh(efx->net_dev);
+       if (efx_dev_registered(efx)) {
+               netif_addr_lock_bh(efx->net_dev);
+               netif_addr_unlock_bh(efx->net_dev);
        }
 }
 
@@ -840,11 +912,10 @@ static void efx_fini_port(struct efx_nic
        if (!efx->port_initialized)
                return;
 
-       efx->mac_op->fini(efx);
-       efx->port_initialized = 0;
-
-       /* Mark the link down */
-       efx->link_up = 0;
+       efx->phy_op->fini(efx);
+       efx->port_initialized = false;
+
+       efx->link_state.up = false;
        efx_link_status_changed(efx);
 }
 
@@ -853,7 +924,7 @@ static void efx_remove_port(struct efx_n
        EFX_LOG(efx, "destroying port\n");
 
        efx_fini_debugfs_port(efx);
-       falcon_remove_port(efx);
+       efx->type->remove_port(efx);
 }
 
 /**************************************************************************
@@ -871,7 +942,6 @@ static int efx_init_io(struct efx_nic *e
 
        EFX_LOG(efx, "initialising I/O\n");
 
-       /* Generic device-enabling code */
        rc = pci_enable_device(pci_dev);
        if (rc) {
                EFX_ERR(efx, "failed to enable PCI device\n");
@@ -906,10 +976,14 @@ static int efx_init_io(struct efx_nic *e
                goto fail2;
        }
 
-       /* Get memory base address */
-       efx->membase_phys = pci_resource_start(efx->pci_dev,
-                                              efx->type->mem_bar);
-       rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc");
+       efx->membase_phys = pci_resource_start(efx->pci_dev, EFX_MEM_BAR);
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_MSIX_TABLE_RESERVED)
+       rc = pci_request_region(pci_dev, EFX_MEM_BAR, "sfc");
+#else
+       if (!request_mem_region(efx->membase_phys, efx->type->mem_map_size,
+                               "sfc"))
+               rc = -EIO;
+#endif
        if (rc) {
                EFX_ERR(efx, "request for memory BAR failed\n");
                rc = -EIO;
@@ -918,23 +992,26 @@ static int efx_init_io(struct efx_nic *e
        efx->membase = ioremap_nocache(efx->membase_phys,
                                       efx->type->mem_map_size);
        if (!efx->membase) {
-               EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n",
-                       efx->type->mem_bar, efx->membase_phys,
+               EFX_ERR(efx, "could not map memory BAR at %llx+%x\n",
+                       (unsigned long long)efx->membase_phys,
                        efx->type->mem_map_size);
                rc = -ENOMEM;
                goto fail4;
        }
-       EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n",
-               efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size,
-               efx->membase);
+       EFX_LOG(efx, "memory BAR at %llx+%x (virtual %p)\n",
+               (unsigned long long)efx->membase_phys,
+               efx->type->mem_map_size, efx->membase);
 
        return 0;
 
  fail4:
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_MSIX_TABLE_RESERVED)
+       pci_release_region(efx->pci_dev, EFX_MEM_BAR);
+#else
        release_mem_region(efx->membase_phys, efx->type->mem_map_size);
+#endif
  fail3:
-       efx->membase_phys = 0UL;
-       /* fall-thru */
+       efx->membase_phys = 0;
  fail2:
        pci_disable_device(efx->pci_dev);
  fail1:
@@ -951,65 +1028,176 @@ static void efx_fini_io(struct efx_nic *
        }
 
        if (efx->membase_phys) {
-               pci_release_region(efx->pci_dev, efx->type->mem_bar);
-               efx->membase_phys = 0UL;
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_MSIX_TABLE_RESERVED)
+               pci_release_region(efx->pci_dev, EFX_MEM_BAR);
+#else
+               release_mem_region(efx->membase_phys, efx->type->mem_map_size);
+#endif
+               efx->membase_phys = 0;
        }
 
        pci_disable_device(efx->pci_dev);
 }
 
-/* Probe the number and type of interrupts we are able to obtain. */
+#if !defined(EFX_USE_KCOMPAT) || (defined(topology_core_siblings) && 
!defined(__VMKLNX__) && !defined(CONFIG_XEN))
+#define HAVE_EFX_NUM_PACKAGES
+static int efx_num_packages(void)
+{
+       cpumask_t core_mask;
+       int count;
+       int cpu;
+
+       cpus_clear(core_mask);
+       count = 0;
+       for_each_online_cpu(cpu) {
+               if (!cpu_isset(cpu, core_mask)) {
+                       ++count;
+                       cpus_or(core_mask, core_mask,
+                               topology_core_siblings(cpu));
+               }
+       }
+
+       /* Create two RSS queues even on a single package host */
+       if (count == 1)
+               count = 2;
+
+       return count;
+}
+#endif
+
+#if !defined(EFX_USE_KCOMPAT) || (defined(topology_thread_siblings) && 
!defined(__VMKLNX__) && !defined(CONFIG_XEN))
+#define HAVE_EFX_NUM_CORES
+static int efx_num_cores(void)
+{
+       cpumask_t core_mask;
+       int count;
+       int cpu;
+
+       cpus_clear(core_mask);
+       count = 0;
+       for_each_online_cpu(cpu) {
+               if (!cpu_isset(cpu, core_mask)) {
+                       ++count;
+                       cpus_or(core_mask, core_mask,
+                               topology_thread_siblings(cpu));
+               }
+       }
+
+       return count;
+}
+#endif
+
+/* Get number of RX queues wanted. */
+static int efx_wanted_rx_queues(struct efx_nic *efx)
+{
+       enum rss_mode rss_mode = EFX_RSS_PACKAGES;
+       bool selected = false;
+       int n_rxq = -1;
+
+       if (rss_cpus == NULL) {
+               /* Leave at default. */
+       } else if (strcmp(rss_cpus, "packages") == 0) {
+               rss_mode = EFX_RSS_PACKAGES;
+               selected = true;
+       } else if (strcmp(rss_cpus, "cores") == 0) {
+               rss_mode = EFX_RSS_CORES;
+               selected = true;
+       } else if (strcmp(rss_cpus, "hyperthreads") == 0) {
+               rss_mode = EFX_RSS_HYPERTHREADS;
+               selected = true;
+       } else if (sscanf(rss_cpus, "%d", &n_rxq) == 1 && n_rxq > 0) {
+               rss_mode = EFX_RSS_CUSTOM;
+               selected = true;
+       } else {
+               EFX_ERR(efx, "ERROR: Bad value for module parameter "
+                       "rss_cpus='%s'\n", rss_cpus);
+       }
+
+       switch (rss_mode) {
+#if defined(HAVE_EFX_NUM_PACKAGES)
+       case EFX_RSS_PACKAGES:
+               n_rxq = efx_num_packages();
+               break;
+#elif defined(CONFIG_XEN)
+       case EFX_RSS_PACKAGES:
+               EFX_ERR(efx, "WARNING: Unable to determine CPU topology on Xen"
+                       "reliably. Using 4 rss channels.\n" );
+               n_rxq = 4;
+               break;
+#endif
+#if defined(HAVE_EFX_NUM_CORES)
+       case EFX_RSS_CORES:
+               n_rxq = efx_num_cores();
+               break;
+#elif defined(CONFIG_XEN)
+       case EFX_RSS_CORES:
+               EFX_ERR(efx, "WARNING: Unable to determine CPU topology on Xen"
+                       "reliably. Assuming hyperthreading enabled.\n");
+               n_rxq = max(1, num_online_cpus() / 2);
+               break;
+#endif
+       case EFX_RSS_HYPERTHREADS:
+               n_rxq = num_online_cpus();
+               break;
+       case EFX_RSS_CUSTOM:
+               break;
+       default:
+               if (selected)
+                       EFX_ERR(efx, "ERROR: Selected rss mode '%s' not "
+                               "available\n", rss_cpus);
+               rss_mode = EFX_RSS_HYPERTHREADS;
+               n_rxq = num_online_cpus();
+               break;
+       }
+
+       if (n_rxq > EFX_MAX_RX_QUEUES) {
+               EFX_ERR(efx, "WARNING: Reducing number of rss channels from "
+                       "%d to %d.\n", n_rxq, EFX_MAX_RX_QUEUES);
+               n_rxq = EFX_MAX_RX_QUEUES;
+       }
+
+       return n_rxq;
+}
+
+/* Probe the number and type of interrupts we are able to obtain, and
+ * the resulting numbers of channels and RX queues.
+ */
 static void efx_probe_interrupts(struct efx_nic *efx)
 {
-       int max_channel = efx->type->phys_addr_channels - 1;
-       struct msix_entry xentries[EFX_MAX_CHANNELS];
+       int max_channels =
+               min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS);
        int rc, i;
 
        if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
-               BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
-
-               if (rss_cpus == 0) {
-#ifdef topology_core_siblings
-                       cpumask_t core_mask;
-                       int cpu;
-
-                       cpus_clear(core_mask);
-                       efx->rss_queues = 0;
-                       for_each_online_cpu(cpu) {
-                               if (!cpu_isset(cpu, core_mask)) {
-                                       ++efx->rss_queues;
-                                       cpus_or(core_mask, core_mask,
-                                               topology_core_siblings(cpu));
-                               }
-                       }
-#else
-                       efx->rss_queues = num_online_cpus();
-#endif
-               } else {
-                       efx->rss_queues = rss_cpus;
+               struct msix_entry xentries[EFX_MAX_CHANNELS];
+               int wanted_ints;
+               int rx_queues;
+
+               /* We will need one interrupt per channel.  We need one
+                * channel per RX queue, and possibly one for TX queues.
+                */
+               rx_queues = efx_wanted_rx_queues(efx);
+               wanted_ints = rx_queues + (separate_tx_channels ? 1 : 0);
+               wanted_ints = min(wanted_ints, max_channels);
+
+               for (i = 0; i < wanted_ints; i++)
+                       xentries[i].entry = i;
+               rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints);
+               if (rc > 0) {
+                       EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors"
+                               " available (%d < %d).\n", rc, wanted_ints);
+                       EFX_ERR(efx, "WARNING: Performance may be reduced.\n");
+                       EFX_BUG_ON_PARANOID(rc >= wanted_ints);
+                       wanted_ints = rc;
+                       rc = pci_enable_msix(efx->pci_dev, xentries,
+                                            wanted_ints);
                }
 
-               /* Limit the number of rss queues appropriately */
-               efx->rss_queues = min(efx->rss_queues, max_channel + 1);
-               efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
-
-               /* Request maximum number of MSI interrupts, and fill out
-                * the channel interrupt information the allowed allocation */
-               for (i = 0; i < efx->rss_queues; i++)
-                       xentries[i].entry = i;
-               rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
-               if (rc > 0) {
-                       EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
-                       efx->rss_queues = rc;
-                       rc = pci_enable_msix(efx->pci_dev, xentries,
-                                            efx->rss_queues);
-               }
-
                if (rc == 0) {
-                       for (i = 0; i < efx->rss_queues; i++) {
-                               efx->channel[i].has_interrupt = 1;
+                       efx->n_rx_queues = min(rx_queues, wanted_ints);
+                       efx->n_channels = wanted_ints;
+                       for (i = 0; i < wanted_ints; i++)
                                efx->channel[i].irq = xentries[i].vector;
-                       }
                } else {
                        /* Fall back to single channel MSI */
                        efx->interrupt_mode = EFX_INT_MODE_MSI;
@@ -1019,11 +1207,11 @@ static void efx_probe_interrupts(struct 
 
        /* Try single interrupt MSI */
        if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
-               efx->rss_queues = 1;
+               efx->n_rx_queues = 1;
+               efx->n_channels = 1;
                rc = pci_enable_msi(efx->pci_dev);
                if (rc == 0) {
                        efx->channel[0].irq = efx->pci_dev->irq;
-                       efx->channel[0].has_interrupt = 1;
                } else {
                        EFX_ERR(efx, "could not enable MSI\n");
                        efx->interrupt_mode = EFX_INT_MODE_LEGACY;
@@ -1032,10 +1220,8 @@ static void efx_probe_interrupts(struct 
 
        /* Assume legacy interrupts */
        if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
-               efx->rss_queues = 1;
-               /* Every channel is interruptible */
-               for (i = 0; i < EFX_MAX_CHANNELS; i++)
-                       efx->channel[i].has_interrupt = 1;
+               efx->n_rx_queues = 1;
+               efx->n_channels = 1 + (separate_tx_channels ? 1 : 0);
                efx->legacy_irq = efx->pci_dev->irq;
        }
 }
@@ -1045,7 +1231,7 @@ static void efx_remove_interrupts(struct
        struct efx_channel *channel;
 
        /* Remove MSI/MSI-X interrupts */
-       efx_for_each_channel_with_interrupt(channel, efx)
+       efx_for_each_channel(channel, efx)
                channel->irq = 0;
        pci_disable_msi(efx->pci_dev);
        pci_disable_msix(efx->pci_dev);
@@ -1054,45 +1240,22 @@ static void efx_remove_interrupts(struct
        efx->legacy_irq = 0;
 }
 
-/* Select number of used resources
- * Should be called after probe_interrupts()
- */
-static void efx_select_used(struct efx_nic *efx)
+static void efx_set_channels(struct efx_nic *efx)
 {
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
-       int i;
-
-       /* TX queues.  One per port per channel with TX capability
-        * (more than one per port won't work on Linux, due to out
-        *  of order issues... but will be fine on Solaris)
-        */
-       tx_queue = &efx->tx_queue[0];
-
-       /* Perform this for each channel with TX capabilities.
-        * At the moment, we only support a single TX queue
-        */
-       tx_queue->used = 1;
-       if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
-               tx_queue->channel = &efx->channel[1];
-       else
-               tx_queue->channel = &efx->channel[0];
-       tx_queue->channel->used_flags |= EFX_USED_BY_TX;
-       tx_queue++;
-
-       /* RX queues.  Each has a dedicated channel. */
-       for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
-               rx_queue = &efx->rx_queue[i];
-
-               if (i < efx->rss_queues) {
-                       rx_queue->used = 1;
-                       /* If we allow multiple RX queues per channel
-                        * we need to decide that here
-                        */
-                       rx_queue->channel = &efx->channel[rx_queue->queue];
-                       rx_queue->channel->used_flags |= EFX_USED_BY_RX;
-                       rx_queue++;
-               }
+
+       efx_for_each_tx_queue(tx_queue, efx) {
+               if (separate_tx_channels)
+                       tx_queue->channel = &efx->channel[efx->n_channels-1];
+               else
+                       tx_queue->channel = &efx->channel[0];
+               tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+       }
+
+       efx_for_each_rx_queue(rx_queue, efx) {
+               rx_queue->channel = &efx->channel[rx_queue->queue];
+               rx_queue->channel->used_flags |= EFX_USED_BY_RX;
        }
 }
 
@@ -1102,8 +1265,13 @@ static int efx_probe_nic(struct efx_nic 
 
        EFX_LOG(efx, "creating NIC\n");
 
+       /* Initialise NIC resource information */
+       efx->resources = efx->type->resources;
+       efx->resources.biu_lock = &efx->biu_lock;
+       efx->dl_info = &efx->resources.hdr;
+
        /* Carry out hardware-type specific initialisation */
-       rc = falcon_probe_nic(efx);
+       rc = efx->type->probe(efx);
        if (rc)
                goto fail1;
 
@@ -1111,22 +1279,26 @@ static int efx_probe_nic(struct efx_nic 
         * in MSI-X interrupts. */
        efx_probe_interrupts(efx);
 
-       /* Determine number of RX queues and TX queues */
-       efx_select_used(efx);
+       if (EFX_INT_MODE_USE_MSI(efx))
+               efx->resources.flags |= EFX_DL_FALCON_USE_MSI;
+
+       efx_set_channels(efx);
 
        /* Register debugfs entries */
        rc = efx_init_debugfs_nic(efx);
        if (rc)
                goto fail2;
        /* Initialise the interrupt moderation settings */
-       efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
+       efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec,
+                               irq_adapt_enable);
 
        return 0;
 
  fail2:
        efx_remove_interrupts(efx);
-       falcon_remove_nic(efx);
+       efx->type->remove(efx);
  fail1:
+       efx->dl_info = NULL;
        return rc;
 }
 
@@ -1135,7 +1307,8 @@ static void efx_remove_nic(struct efx_ni
        EFX_LOG(efx, "destroying NIC\n");
 
        efx_remove_interrupts(efx);
-       falcon_remove_nic(efx);
+       efx->type->remove(efx);
+       efx->dl_info = NULL;
 
        efx_fini_debugfs_nic(efx);
 }
@@ -1174,6 +1347,7 @@ static int efx_probe_all(struct efx_nic 
                        goto fail3;
                }
        }
+       efx_set_channel_names(efx);
 
        return 0;
 
@@ -1192,7 +1366,7 @@ static int efx_probe_all(struct efx_nic 
  * and ensures that the port is scheduled to be reconfigured.
  * This function is safe to call multiple times when the NIC is in any
  * state. */
-static void efx_start_all(struct efx_nic *efx)
+void efx_start_all(struct efx_nic *efx)
 {
        struct efx_channel *channel;
 
@@ -1204,22 +1378,47 @@ static void efx_start_all(struct efx_nic
                return;
        if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT))
                return;
-       if (NET_DEV_REGISTERED(efx) && !netif_running(efx->net_dev))
+       if (efx_dev_registered(efx) && !netif_running(efx->net_dev))
                return;
 
        /* Mark the port as enabled so port reconfigurations can start, then
         * restart the transmit interface early so the watchdog timer stops */
        efx_start_port(efx);
-       efx_wake_queue(efx);
+       if (efx_dev_registered(efx))
+               efx_wake_queue(efx);
 
        efx_for_each_channel(channel, efx)
                efx_start_channel(channel);
 
-       falcon_enable_interrupts(efx);
-
-       /* Start hardware monitor if we're in RUNNING */
-       if (efx->state == STATE_RUNNING)
+       efx_nic_enable_interrupts(efx);
+
+       /* Switch to event based MCDI completions after enabling interrupts.
+        * If a reset has been scheduled, then we need to stay in polled mode.
+        * Rather than serialising efx_mcdi_mode_event() [which sleeps] and
+        * reset_pending [modified from an atomic context], we instead guarantee
+        * that efx_mcdi_mode_poll() isn't reverted erroneously */
+       efx_mcdi_mode_event(efx);
+       if (efx->reset_pending != RESET_TYPE_NONE)
+               efx_mcdi_mode_poll(efx);
+
+       /* Start the hardware monitor if there is one. Otherwise (we're link
+        * event driven), we have to poll the PHY because after an event queue
+        * flush, we could have a missed a link state change */
+       if (efx->type->monitor != NULL) {
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_NEED_WORK_API_WRAPPERS)
+               queue_delayed_work(efx->workqueue, &efx->monitor_work,
+                                  efx_monitor_interval);
+#else
                queue_work(efx->workqueue, &efx->monitor_work);
+#endif
+       } else {
+               mutex_lock(&efx->mac_lock);
+               if (efx->phy_op->poll(efx))
+                       efx_link_status_changed(efx);
+               mutex_unlock(&efx->mac_lock);
+       }
+
+       efx->type->start_stats(efx);
 }
 
 /* Flush all delayed work. Should only be called when no more delayed work
@@ -1227,13 +1426,28 @@ static void efx_start_all(struct efx_nic
  * since we're holding the rtnl_lock at this point. */
 static void efx_flush_all(struct efx_nic *efx)
 {
-       /* Ensure that the hardware monitor and asynchronous port
-        * reconfigurations are complete, which are the only two consumers
-        * of efx->workqueue. Since the hardware monitor runs on a long period,
-        * we put in some effort to cancel the delayed work safely rather
-        * than just flushing the queue twice (which is guaranteed to flush
-        * all the work since both efx_monitor and efx_reconfigure_work disarm
-        * if !efx->port_enabled. */
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
+       struct efx_rx_queue *rx_queue;
+
+       /* Make sure the hardware monitor is stopped */
+       cancel_delayed_work_sync(&efx->monitor_work);
+
+       /* Ensure that all RX slow refills are complete. */
+       efx_for_each_rx_queue(rx_queue, efx)
+               cancel_delayed_work_sync(&rx_queue->work);
+#endif
+
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_CANCEL_WORK_SYNC)
+       /* Stop scheduled port reconfigurations */
+       cancel_work_sync(&efx->mac_work);
+#endif
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
+       /* Ensure efx_monitor() and efx_mac_work() are complete, which
+        * are the only two consumers of efx->workqueue. Since the hardware
+        * monitor runs on a long period, we put in some effort to cancel
+        * the delayed work safely rather than just flushing the queue twice
+        * (which is guaranteed to flush all the work since efx_monitor(),
+        * and efx_mac_work() disarm if !efx->port_enabled). */
        if (timer_pending(&efx->monitor_work.timer))
                cancel_delayed_work(&efx->monitor_work);
        flush_workqueue(efx->workqueue);
@@ -1245,6 +1459,7 @@ static void efx_flush_all(struct efx_nic
         * flush the refill workqueue twice as well. */
        flush_workqueue(refill_workqueue);
        flush_workqueue(refill_workqueue);
+#endif
 }
 
 /* Quiesce hardware and software without bringing the link down.
@@ -1252,7 +1467,7 @@ static void efx_flush_all(struct efx_nic
  * state. The caller is guaranteed to subsequently be in a position
  * to modify any hardware and software state they see fit without
  * taking locks. */
-static void efx_stop_all(struct efx_nic *efx)
+void efx_stop_all(struct efx_nic *efx)
 {
        struct efx_channel *channel;
 
@@ -1262,13 +1477,19 @@ static void efx_stop_all(struct efx_nic 
        if (!efx->port_enabled)
                return;
 
+       efx->type->stop_stats(efx);
+
+       /* Switch to MCDI polling on Siena before disabling interrupts */
+       efx_mcdi_mode_poll(efx);
+
        /* Disable interrupts and wait for ISR to complete */
-       falcon_disable_interrupts(efx);
+       efx_nic_disable_interrupts(efx);
        if (efx->legacy_irq)
                synchronize_irq(efx->legacy_irq);
-       efx_for_each_channel_with_interrupt(channel, efx)
+       efx_for_each_channel(channel, efx) {
                if (channel->irq)
                        synchronize_irq(channel->irq);
+       }
 
        /* Stop all NAPI processing and synchronous rx refills */
        efx_for_each_channel(channel, efx)
@@ -1279,18 +1500,13 @@ static void efx_stop_all(struct efx_nic 
         * window to loose phy events */
        efx_stop_port(efx);
 
-       /* Flush reconfigure_work, refill_workqueue, monitor_work */
+       /* Flush efx_mac_work(), refill_workqueue and efx_monitor_work() */
        efx_flush_all(efx);
-
-       /* Isolate the MAC from the TX and RX engines, so that queue
-        * flushes will complete in a timely fashion. */
-       falcon_deconfigure_mac_wrapper(efx);
-       falcon_drain_tx_fifo(efx);
 
        /* Stop the kernel transmit interface late, so the watchdog
         * timer isn't ticking over the flush */
-       efx_stop_queue(efx);
-       if (NET_DEV_REGISTERED(efx)) {
+       if (efx_dev_registered(efx)) {
+               efx_stop_queue(efx);
                netif_tx_lock_bh(efx->net_dev);
                netif_tx_unlock_bh(efx->net_dev);
        }
@@ -1306,79 +1522,39 @@ static void efx_remove_all(struct efx_ni
        efx_remove_nic(efx);
 }
 
-static int efx_run_selftests(struct efx_nic *efx)
-{
-       struct efx_self_tests tests;
-       unsigned modes = efx->startup_loopbacks & efx->loopback_modes;
-       int rc;
-
-       rc = efx_online_test(efx, &tests);
-       if (rc) {
-               EFX_ERR(efx, "failed self-tests with interrupt_mode of %s\n",
-                       INT_MODE(efx));
-               goto fail;
-       }
-
-       if (onload_offline_selftest && modes) {
-               /* Run offline self test */
-               EFX_LOG(efx, "performing on-load offline self-tests\n");
-               rc = efx_offline_test(efx, &tests, modes);
-               EFX_LOG(efx, "%s on-load offline self-tests\n",
-                       rc ? "FAILED" : "PASSED");
-               if (rc)
-                       goto fail;
-       }
-
-       return 0;
-
- fail:
-       EFX_ERR(efx, "self-tests failed. Given up!\n");
-       if (allow_load_on_failure)
-               rc = 0;
-
-       return rc;
-}
-
-/* A convinience function to safely flush all the queues */
-int efx_flush_queues(struct efx_nic *efx)
-{
-       int rc;
-
-       EFX_ASSERT_RESET_SERIALISED(efx);
-
-       efx_stop_all(efx);
-
-       efx_fini_channels(efx);
-       rc = efx_init_channels(efx);
-       if (rc) {
-               efx_schedule_reset(efx, RESET_TYPE_DISABLE);
-               return rc;
-       }
-
-       efx_start_all(efx);
-
-       return 0;
-}
-
 /**************************************************************************
  *
  * Interrupt moderation
  *
  **************************************************************************/
 
+static unsigned irq_mod_ticks(int usecs, int resolution)
+{
+       if (usecs <= 0)
+               return 0; /* cannot receive interrupts ahead of time :-) */
+       if (usecs < resolution)
+               return 1; /* never round down to 0 */
+       return usecs / resolution;
+}
+
 /* Set interrupt moderation parameters */
-void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
+void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
+                            bool rx_adaptive)
 {
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
+       unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION);
+       unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION);
 
        EFX_ASSERT_RESET_SERIALISED(efx);
 
        efx_for_each_tx_queue(tx_queue, efx)
-               tx_queue->channel->irq_moderation = tx_usecs;
-
+               tx_queue->channel->irq_moderation = tx_ticks;
+
+       efx->irq_rx_adaptive = rx_adaptive;
+       efx->irq_rx_moderation = rx_ticks;
        efx_for_each_rx_queue(rx_queue, efx)
-               rx_queue->channel->irq_moderation = rx_usecs;
+               rx_queue->channel->irq_moderation = rx_ticks;
 }
 
 /**************************************************************************
@@ -1391,35 +1567,40 @@ void efx_init_irq_moderation(struct efx_
  * efx_reconfigure_port via the mac_lock */
 static void efx_monitor(struct work_struct *data)
 {
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_NEED_WORK_API_WRAPPERS)
+       struct efx_nic *efx = container_of(data, struct efx_nic,
+                                          monitor_work.work);
+#else
        struct efx_nic *efx = container_of(data, struct efx_nic,
                                           monitor_work);
-       int rc = 0;
+#endif
 
        EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
                  raw_smp_processor_id());
-
+       BUG_ON(efx->type->monitor == NULL);
+
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
        /* Without cancel_delayed_work_sync(), we have to make sure that
-        * we don't rearm when port_enabled == 0 */
+        * we don't rearm when !port_enabled */
        mutex_lock(&efx->mac_lock);
        if (!efx->port_enabled) {
                mutex_unlock(&efx->mac_lock);
                return;
        }
-
-       rc = efx->mac_op->check_hw(efx);
+#else
+       /* If the mac_lock is already held then it is likely a port
+        * reconfiguration is already in place, which will likely do
+        * most of the work of check_hw() anyway. */
+       if (!mutex_trylock(&efx->mac_lock))
+               goto out_requeue;
+       if (!efx->port_enabled)
+               goto out_unlock;
+#endif
+       efx->type->monitor(efx);
+
+out_unlock:
        mutex_unlock(&efx->mac_lock);
-
-       if (rc) {
-               if (monitor_reset) {
-                       EFX_ERR(efx, "hardware monitor detected a fault: "
-                               "triggering reset\n");
-                       efx_schedule_reset(efx, RESET_TYPE_MONITOR);
-               } else {
-                       EFX_ERR(efx, "hardware monitor detected a fault, "
-                               "skipping reset\n");
-               }
-       }
-
+out_requeue:
        queue_delayed_work(efx->workqueue, &efx->monitor_work,
                           efx_monitor_interval);
 }
@@ -1435,12 +1616,36 @@ static void efx_monitor(struct work_stru
  */
 static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
 {
-       struct efx_nic *efx = net_dev->priv;
-
-       if (!in_interrupt())
-           EFX_ASSERT_RESET_SERIALISED(efx);
-
-       return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
+       struct efx_nic *efx = netdev_priv(net_dev);
+       struct mii_ioctl_data *data = if_mii(ifr);
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_BONDING_HACKS)
+       if (in_interrupt())
+               /* We can't execute mdio requests from an atomic context
+                * on Siena. Luckily, the bonding driver falls back to
+                * the ethtool API if this command fails. */
+               return -ENOSYS;
+#endif
+       EFX_ASSERT_RESET_SERIALISED(efx);
+
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_HAVE_ETHTOOL_RESET)
+       if (cmd == SIOCDEVPRIVATE) {
+               struct efx_sock_ioctl __user *user_data =
+                       (struct efx_sock_ioctl __user *)ifr->ifr_data;
+               u16 efx_cmd;
+
+               if (copy_from_user(&efx_cmd, &user_data->cmd, sizeof(efx_cmd)))
+                       return -EFAULT;
+               return efx_private_ioctl(efx, efx_cmd, &user_data->u);
+       }
+#endif
+
+       /* Convert phy_id from older PRTAD/DEVAD format */
+       if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
+           (data->phy_id & 0xfc00) == 0x0400)
+               data->phy_id ^= MDIO_PHY_ID_C45 | 0x0400;
+
+       return mdio_mii_ioctl(&efx->mdio, data, cmd);
 }
 
 /**************************************************************************
@@ -1449,74 +1654,42 @@ static int efx_ioctl(struct net_device *
  *
  **************************************************************************/
 
-/* Allocate the NAPI dev's.
- * Called after we know how many channels there are.
- */
 static int efx_init_napi(struct efx_nic *efx)
 {
        struct efx_channel *channel;
-       int rc;
-
-       /* Allocate the NAPI dev for the port */
-       efx->net_dev = alloc_etherdev(0);
-       if (!efx->net_dev) {
-               rc = -ENOMEM;
-               goto err;
-       }
-       efx->net_dev->priv = efx;
-       efx->mii.dev = efx->net_dev;
-
-       efx->net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG |
-                                  NETIF_F_HIGHDMA);
-       efx->lro_enabled = lro;
-
-       /* Copy MAC address */
-       memcpy(&efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
-
-       /* Allocate the per channel devs */
+
        efx_for_each_channel(channel, efx) {
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_OLD_NAPI)
+               channel->napi_dev = efx->net_dev;
+#else
                channel->napi_dev = alloc_etherdev(0);
                if (!channel->napi_dev) {
-                       rc = -ENOMEM;
-                       goto err;
+                       efx_fini_napi(efx);
+                       return -ENOMEM;
                }
                channel->napi_dev->priv = channel;
                atomic_set(&channel->napi_dev->refcnt, 1);
-
-               /* Initialise LRO/SSR */
-               rc = efx_ssr_init(&channel->ssr, efx);
-               if (rc)
-                       goto err;
-       }
-
+#endif
+               netif_napi_add(channel->napi_dev, &channel->napi_str,
+                              efx_poll, napi_weight);
+       }
        return 0;
- err:
-       efx_fini_napi(efx);
-       return rc;
-}
-
-/* Free the NAPI state for the port and channels */
+}
+
 static void efx_fini_napi(struct efx_nic *efx)
 {
        struct efx_channel *channel;
 
        efx_for_each_channel(channel, efx) {
-               /* Fini LRO/SSR */
-               efx_ssr_fini(&channel->ssr);
-
-               /* Finish per channel NAPI */
+               if (channel->napi_dev)
+                       netif_napi_del(&channel->napi_str);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_HAVE_OLD_NAPI)
                if (channel->napi_dev) {
                        channel->napi_dev->priv = NULL;
                        free_netdev(channel->napi_dev);
                }
+#endif
                channel->napi_dev = NULL;
-       }
-
-       /* Finish port NAPI */
-       if (efx->net_dev) {
-               efx->net_dev->priv = NULL;
-               free_netdev(efx->net_dev);
-               efx->net_dev = NULL;
        }
 }
 
@@ -1534,10 +1707,10 @@ static void efx_fini_napi(struct efx_nic
  */
 static void efx_netpoll(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_channel *channel;
 
-       efx_for_each_channel_with_interrupt(channel, efx)
+       efx_for_each_channel(channel, efx)
                efx_schedule_channel(channel);
 }
 
@@ -1552,11 +1725,24 @@ static void efx_netpoll(struct net_devic
 /* Context: process, rtnl_lock() held. */
 static int efx_net_open(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        EFX_ASSERT_RESET_SERIALISED(efx);
 
        EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
                raw_smp_processor_id());
+
+       if (efx->state == STATE_DISABLED) {
+               EFX_ERR(efx, "Device is disabled.\n");
+               return -EIO;
+       }
+       if (efx->phy_mode & PHY_MODE_SPECIAL)
+               return -EBUSY;
+       if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL))
+               return -EIO;
+
+       /* Notify the kernel of the link state polled during driver load,
+        * before the monitor starts running */
+       efx_link_status_changed(efx);
 
        efx_start_all(efx);
        return 0;
@@ -1568,36 +1754,35 @@ static int efx_net_open(struct net_devic
  */
 static int efx_net_stop(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
-       int rc;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
        EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
                raw_smp_processor_id());
 
-       /* Stop the device and flush all the channels */
-       efx_stop_all(efx);
-       efx_fini_channels(efx);
-       rc = efx_init_channels(efx);
-       if (rc)
-               efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+       if (efx->state != STATE_DISABLED) {
+               /* Stop the device and flush all the channels */
+               efx_stop_all(efx);
+               efx_fini_channels(efx);
+               efx_init_channels(efx);
+       }
 
        return 0;
 }
 
-/* Context: process, dev_base_lock held, non-blocking. */
+/* Context: process, dev_base_lock or RTNL held, non-blocking. */
 static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_mac_stats *mac_stats = &efx->mac_stats;
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_NETDEV_STATS)
+       struct net_device_stats *stats = &net_dev->stats;
+#else
        struct net_device_stats *stats = &efx->stats;
-
-       if (!spin_trylock(&efx->stats_lock))
-               return stats;
-       if (efx->state == STATE_RUNNING) {
-               efx->mac_op->update_stats(efx);
-               falcon_update_nic_stats(efx);
-       }
-       spin_unlock(&efx->stats_lock);
+#endif
+
+       spin_lock_bh(&efx->stats_lock);
+       efx->type->update_stats(efx);
+       spin_unlock_bh(&efx->stats_lock);
 
        stats->rx_packets = mac_stats->rx_packets;
        stats->tx_packets = mac_stats->tx_packets;
@@ -1630,21 +1815,20 @@ static struct net_device_stats *efx_net_
 /* Context: netif_tx_lock held, BHs disabled. */
 static void efx_watchdog(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
-
-       EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
-               atomic_read(&efx->netif_stop_count), efx->port_enabled,
-               monitor_reset ? "resetting channels" : "skipping reset");
-
-       if (monitor_reset)
-               efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:"
+               " resetting channels\n",
+               atomic_read(&efx->netif_stop_count), efx->port_enabled);
+
+       efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG);
 }
 
 
 /* Context: process, rtnl_lock() held. */
 static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        int rc = 0;
 
        EFX_ASSERT_RESET_SERIALISED(efx);
@@ -1665,10 +1849,15 @@ static int efx_change_mtu(struct net_dev
        EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
 
        efx_fini_channels(efx);
+
+       mutex_lock(&efx->mac_lock);
+       /* Reconfigure the MAC before enabling the dma queues so that
+        * the RX buffers don't overflow */
        net_dev->mtu = new_mtu;
-       rc = efx_init_channels(efx);
-       if (rc)
-               goto fail;
+       efx->mac_op->reconfigure(efx);
+       mutex_unlock(&efx->mac_lock);
+
+       efx_init_channels(efx);
 
        /* Notify driverlink client of new MTU */
        EFX_DL_CALLBACK(efx, mtu_changed, new_mtu);
@@ -1676,17 +1865,13 @@ static int efx_change_mtu(struct net_dev
  out:
        efx_start_all(efx);
        return rc;
-
- fail:
-       efx_schedule_reset(efx, RESET_TYPE_DISABLE);
-       return rc;
 }
 
 static int efx_set_mac_address(struct net_device *net_dev, void *data)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct sockaddr *addr = data;
-       char *new_addr = addr->sa_data;
+       u8 *new_addr = addr->sa_data;
 
        EFX_ASSERT_RESET_SERIALISED(efx);
 
@@ -1700,34 +1885,27 @@ static int efx_set_mac_address(struct ne
        memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
 
        /* Reconfigure the MAC */
-       efx_reconfigure_port(efx);
+       mutex_lock(&efx->mac_lock);
+       efx->mac_op->reconfigure(efx);
+       mutex_unlock(&efx->mac_lock);
 
        return 0;
 }
 
-/* Context: netif_tx_lock held, BHs disabled. */
+/* Context: netif_addr_lock held, BHs disabled. */
 static void efx_set_multicast_list(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct dev_mc_list *mc_list = net_dev->mc_list;
        union efx_multicast_hash *mc_hash = &efx->multicast_hash;
-       int promiscuous;
        u32 crc;
        int bit;
        int i;
 
-       /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */
-       promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0;
-       if (efx->promiscuous != promiscuous) {
-               efx->promiscuous = promiscuous;
-               /* Close the window between efx_stop_port() and efx_flush_all()
-                * by only queuing work when the port is enabled. */
-               if (efx->port_enabled)
-                       queue_work(efx->workqueue, &efx->reconfigure_work);
-       }
+       efx->promiscuous = !!(net_dev->flags & IFF_PROMISC);
 
        /* Build multicast hash table */
-       if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+       if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
                memset(mc_hash, 0xff, sizeof(*mc_hash));
        } else {
                memset(mc_hash, 0x00, sizeof(*mc_hash));
@@ -1737,24 +1915,59 @@ static void efx_set_multicast_list(struc
                        set_bit_le(bit, mc_hash->byte);
                        mc_list = mc_list->next;
                }
-       }
-
-       /* Create and activate new global multicast hash table */
-       falcon_set_multicast_hash(efx);
-}
-
-/* Handle net device notifier events */
+
+               /* Broadcast packets go through the multicast hash filter.
+                * ether_crc_le() of the broadcast address is 0xbe2612ff
+                * so we always add bit 0xff to the mask.
+                */
+               set_bit_le(0xff, mc_hash->byte);
+       }
+
+       if (efx->port_enabled)
+               queue_work(efx->workqueue, &efx->mac_work);
+       /* Otherwise efx_start_port() will do this */
+}
+
+#if !defined(EFX_USE_KCOMPAT) || defined(HAVE_NET_DEVICE_OPS)
+static const struct net_device_ops efx_netdev_ops = {
+       .ndo_open               = efx_net_open,
+       .ndo_stop               = efx_net_stop,
+       .ndo_get_stats          = efx_net_stats,
+       .ndo_tx_timeout         = efx_watchdog,
+       .ndo_start_xmit         = efx_hard_start_xmit,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = efx_ioctl,
+       .ndo_change_mtu         = efx_change_mtu,
+       .ndo_set_mac_address    = efx_set_mac_address,
+       .ndo_set_multicast_list = efx_set_multicast_list,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = efx_netpoll,
+#endif
+};
+#endif
+
+static void efx_update_name(struct efx_nic *efx)
+{
+       strcpy(efx->name, efx->net_dev->name);
+       efx_mtd_rename(efx);
+       efx_set_channel_names(efx);
+}
+
 static int efx_netdev_event(struct notifier_block *this,
                            unsigned long event, void *ptr)
 {
-       struct net_device *net_dev = (struct net_device *)ptr;
-
+       struct net_device *net_dev = ptr;
+
+#if !defined(EFX_USE_KCOMPAT) || defined(HAVE_NET_DEVICE_OPS)
+       if (net_dev->netdev_ops == &efx_netdev_ops &&
+           event == NETDEV_CHANGENAME) {
+#else
        if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
-               struct efx_nic *efx = net_dev->priv;
-
-               strcpy(efx->name, net_dev->name);
-               efx_fini_debugfs_netdev(net_dev);
-               efx_init_debugfs_netdev(net_dev);
+#endif
+               struct efx_nic *efx = netdev_priv(net_dev);
+
+               if (efx->state == STATE_RUNNING)
+                       efx_update_name(efx);
        }
 
        return NOTIFY_DONE;
@@ -1764,6 +1977,7 @@ static struct notifier_block efx_netdev_
        .notifier_call = efx_netdev_event,
 };
 
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_BONDING_HACKS)
 /* Prior to Linux 2.6.24, the bonding driver may call change_mtu()
  * without holding the RTNL, unlike all other callers.  We try to
  * mitigate the risk of a race with other reconfiguration using
@@ -1778,6 +1992,15 @@ static int efx_locked_change_mtu(struct 
        return rc;
 }
 #define efx_change_mtu efx_locked_change_mtu
+#endif
+
+static ssize_t
+show_phy_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       return sprintf(buf, "%d\n", efx->phy_type);
+}
+static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL);
 
 static int efx_register_netdev(struct efx_nic *efx)
 {
@@ -1786,10 +2009,13 @@ static int efx_register_netdev(struct ef
 
        net_dev->watchdog_timeo = 5 * HZ;
        net_dev->irq = efx->pci_dev->irq;
+#if !defined(EFX_USE_KCOMPAT) || defined(HAVE_NET_DEVICE_OPS)
+       net_dev->netdev_ops = &efx_netdev_ops;
+#else
        net_dev->open = efx_net_open;
        net_dev->stop = efx_net_stop;
        net_dev->get_stats = efx_net_stats;
-       net_dev->tx_timeout = &efx_watchdog;
+       net_dev->tx_timeout = efx_watchdog;
        net_dev->hard_start_xmit = efx_hard_start_xmit;
        net_dev->do_ioctl = efx_ioctl;
        net_dev->change_mtu = efx_change_mtu;
@@ -1798,42 +2024,65 @@ static int efx_register_netdev(struct ef
 #ifdef CONFIG_NET_POLL_CONTROLLER
        net_dev->poll_controller = efx_netpoll;
 #endif
+#endif
        SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
        SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
-
-       /* Always start with carrier off; PHY events will detect the link */
-       netif_carrier_off(efx->net_dev);
 
        /* Clear MAC statistics */
        efx->mac_op->update_stats(efx);
        memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
 
-       rc = register_netdev(net_dev);
-       if (rc) {
-               EFX_ERR(efx, "could not register net dev\n");
-               return rc;
-       }
-       strcpy(efx->name, net_dev->name);
+       rtnl_lock();
+
+       rc = dev_alloc_name(net_dev, net_dev->name);
+       if (rc < 0)
+               goto fail_locked;
+       efx_update_name(efx);
+
+       rc = register_netdevice(net_dev);
+       if (rc)
+               goto fail_locked;
+
+       /* Always start with carrier off; PHY events will detect the link */
+       netif_carrier_off(net_dev);
+
+       /* Register with driverlink layer */
+       efx_dl_register_nic(efx);
+
+       rtnl_unlock();
 
        /* Create debugfs symlinks */
        rc = efx_init_debugfs_netdev(net_dev);
        if (rc) {
                EFX_ERR(efx, "failed to init net dev debugfs\n");
-               unregister_netdev(efx->net_dev);
-               return rc;
+               goto fail_registered;
+       }
+
+       rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
+       if (rc) {
+               EFX_ERR(efx, "failed to init net dev attributes\n");
+               goto fail_debugfs;
        }
 
        return 0;
+
+fail_debugfs:
+       efx_fini_debugfs_netdev(net_dev);
+fail_registered:
+       rtnl_lock();
+       efx_dl_unregister_nic(efx);
+       unregister_netdevice(net_dev);
+fail_locked:
+       rtnl_unlock();
+       EFX_ERR(efx, "could not register net dev\n");
+       return rc;
 }
 
 static void efx_unregister_netdev(struct efx_nic *efx)
 {
        struct efx_tx_queue *tx_queue;
 
-       if (!efx->net_dev)
-               return;
-
-       BUG_ON(efx->net_dev->priv != efx);
+       BUG_ON(netdev_priv(efx->net_dev) != efx);
 
        /* Free up any skbs still remaining. This has to happen before
         * we try to unregister the netdev as running their destructors
@@ -1841,8 +2090,9 @@ static void efx_unregister_netdev(struct
        efx_for_each_tx_queue(tx_queue, efx)
                efx_release_tx_buffers(tx_queue);
 
-       if (NET_DEV_REGISTERED(efx)) {
+       if (efx_dev_registered(efx)) {
                strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
+               device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type);
                efx_fini_debugfs_netdev(efx->net_dev);
                unregister_netdev(efx->net_dev);
        }
@@ -1854,122 +2104,93 @@ static void efx_unregister_netdev(struct
  *
  **************************************************************************/
 
-/* Serialise access to the driverlink callbacks, by quiescing event processing
- * (without flushing the descriptor queues), and acquiring the rtnl_lock */
-void efx_suspend(struct efx_nic *efx)
-{
-       EFX_LOG(efx, "suspending operations\n");
-
-       rtnl_lock();
-       efx_stop_all(efx);
-}
-
-void efx_resume(struct efx_nic *efx)
-{
-       EFX_LOG(efx, "resuming operations\n");
-
-       efx_start_all(efx);
-       rtnl_unlock();
-}
-
-/* The final hardware and software finalisation before reset.
- * This function does not handle serialisation with the kernel, it
- * assumes the caller has done this */
-static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
-{
-       int rc;
-
+/* Tears down driverlink clients, the entire software state,
+ * and most of the hardware state before reset.  */
+void efx_reset_down(struct efx_nic *efx, enum reset_type method)
+{
        EFX_ASSERT_RESET_SERIALISED(efx);
-
-       rc = efx->mac_op->get_settings(efx, ecmd);
-       if (rc) {
-               EFX_ERR(efx, "could not back up PHY settings\n");
-               goto fail;
-       }
-
-       efx_fini_channels(efx);
-       return 0;
-
- fail:
-       return rc;
-}
-
-/* The first part of software initialisation after a hardware reset
- * This function does not handle serialisation with the kernel, it
- * assumes the caller has done this */
-static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd)
-{
-       int rc;
-
-       rc = efx_init_channels(efx);
-       if (rc)
-               goto fail1;
-
-       /* Restore MAC and PHY settings. */
-       rc = efx->mac_op->set_settings(efx, ecmd);
-       if (rc) {
-               EFX_ERR(efx, "could not restore PHY settings\n");
-               goto fail2;
-       }
-
-       return 0;
-
- fail2:
-       efx_fini_channels(efx);
- fail1:
-       return rc;
-}
-
-/* Reset the NIC as transparently as possible. Do not reset the PHY
- * Note that the reset may fail, in which case the card will be left
- * in a most-probably-unusable state.
- *
- * This function will sleep.  You cannot reset from within an atomic
- * state; use efx_schedule_reset() instead.
- *
- * Grabs the dl_reset_lock, and to serialise with kernel interfaces the
- * rtnl_lock.
- */
-static int efx_reset(struct efx_nic *efx)
-{
-       struct ethtool_cmd ecmd;
-       enum reset_type method = efx->reset_pending;
-       int rc;
-
-       /* Notify driverlink clients of imminent reset. */
-       efx_dl_reset_lock();
-       efx_dl_reset_suspend(efx);
-
-       /* Serialise with kernel interfaces */
-       rtnl_lock();
-
-       /* If we're not RUNNING then don't reset. Leave the reset_pending
-        * flag set so that efx_pci_probe_main will be retried */
-       if (efx->state != STATE_RUNNING) {
-               EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
-               goto unlock_rtnl;
-       }
-
-       efx->state = STATE_RESETTING;
-       EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
-
-       /* The net_dev->get_stats handler is quite slow, and will fail
-        * if a fetch is pending over reset. Serialise against it. */
-       spin_lock(&efx->stats_lock);
-       spin_unlock(&efx->stats_lock);
 
        efx_stop_all(efx);
        mutex_lock(&efx->mac_lock);
-
-       rc = efx_reset_down(efx, &ecmd);
-       if (rc)
-               goto fail1;
-       falcon_fini_nic(efx);
-
-       rc = falcon_reset_hw(efx, method);
+       mutex_lock(&efx->spi_lock);
+
+       efx_fini_channels(efx);
+       if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
+               efx->phy_op->fini(efx);
+       efx->type->fini(efx);
+}
+
+/* This function will always ensure that the locks acquired in
+ * efx_reset_down() are released. A failure return code indicates
+ * that we were unable to reinitialise the hardware, and the
+ * driver should be disabled. If ok is false, then the rx and tx
+ * engines are not restarted, pending a RESET_DISABLE. */
+int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
+{
+       int rc;
+
+       EFX_ASSERT_RESET_SERIALISED(efx);
+
+       /* Ensure that SRAM is initialised even if we're disabling the device */
+       rc = efx->type->init(efx);
+       if (rc) {
+               EFX_ERR(efx, "failed to initialise NIC\n");
+               goto fail;
+       }
+
+       if (!ok)
+               goto fail;
+
+       if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
+               rc = efx->phy_op->init(efx);
+               if (rc)
+                       goto fail;
+               if (efx->phy_op->reconfigure(efx))
+                       EFX_ERR(efx, "could not restore PHY settings\n");
+       }
+
+       efx->mac_op->reconfigure(efx);
+
+       efx_init_channels(efx);
+
+       mutex_unlock(&efx->spi_lock);
+       mutex_unlock(&efx->mac_lock);
+
+       efx_start_all(efx);
+
+       return 0;
+
+fail:
+       efx->port_initialized = false;
+
+       mutex_unlock(&efx->spi_lock);
+       mutex_unlock(&efx->mac_lock);
+
+       return rc;
+}
+
+/* Reset the NIC using the specified method.  Note that the reset may
+ * fail, in which case the card will be left in an unusable state.
+ *
+ * Caller must hold the rtnl_lock.
+ */
+int efx_reset(struct efx_nic *efx, enum reset_type method)
+{
+       int rc, rc2;
+       bool disabled;
+
+       /* Notify driverlink clients of imminent reset then serialise
+        * against other driver operations */
+       efx_dl_reset_suspend(efx);
+
+       EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
+
+       efx_reset_down(efx, method);
+
+       rc = efx->type->reset(efx, method);
        if (rc) {
                EFX_ERR(efx, "failed to reset hardware\n");
-               goto fail2;
+               goto out;
        }
 
        /* Allow resets to be rescheduled. */
@@ -1981,54 +2202,23 @@ static int efx_reset(struct efx_nic *efx
         * can respond to requests. */
        pci_set_master(efx->pci_dev);
 
-       /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE
-        * case so the driver can talk to external SRAM */
-       rc = falcon_init_nic(efx);
-       if (rc) {
-               EFX_ERR(efx, "failed to initialise NIC\n");
-               goto fail3;
-       }
-
+out:
        /* Leave device stopped if necessary */
-       if (method == RESET_TYPE_DISABLE) {
-               /* Reinitialise the device anyway so the driver unload sequence
-                * can talk to the external SRAM */
-               (void) falcon_init_nic(efx);
-               rc = -EIO;
-               goto fail4;
-       }
-
-       rc = efx_reset_up(efx, &ecmd);
-       if (rc)
-               goto fail5;
-
-       mutex_unlock(&efx->mac_lock);
-       EFX_LOG(efx, "reset complete\n");
-
-       efx->state = STATE_RUNNING;
-       efx_start_all(efx);
-
- unlock_rtnl:
-       rtnl_unlock();
-       efx_dl_reset_resume(efx, 1);
-       efx_dl_reset_unlock();
-       return 0;
-
- fail5:
- fail4:
- fail3:
- fail2:
- fail1:
-       EFX_ERR(efx, "has been disabled\n");
-       efx->state = STATE_DISABLED;
-
-       mutex_unlock(&efx->mac_lock);
-       rtnl_unlock();
-       /* Remove the net_dev */
-       efx_unregister_netdev(efx);
-       efx_fini_port(efx);
-       efx_dl_reset_resume(efx, 0);
-       efx_dl_reset_unlock();
+       disabled = rc || method == RESET_TYPE_DISABLE;
+       rc2 = efx_reset_up(efx, method, !disabled);
+       if (rc2) {
+               disabled = true;
+               if (!rc)
+                       rc = rc2;
+       }
+
+       if (disabled) {
+               EFX_ERR(efx, "has been disabled\n");
+               efx->state = STATE_DISABLED;
+       } else {
+               EFX_LOG(efx, "reset complete\n");
+       }
+       efx_dl_reset_resume(efx, !disabled);
        return rc;
 }
 
@@ -2037,9 +2227,19 @@ static int efx_reset(struct efx_nic *efx
  */
 static void efx_reset_work(struct work_struct *data)
 {
-       struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
-
-       efx_reset(nic);
+       struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
+
+       /* If we're not RUNNING then don't reset. Leave the reset_pending
+        * flag set so that efx_pci_probe_main will be retried */
+       if (efx->state != STATE_RUNNING) {
+               EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
+               return;
+       }
+
+       rtnl_lock();
+       if (efx_reset(efx, efx->reset_pending))
+               dev_close(efx->net_dev);
+       rtnl_unlock();
 }
 
 void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
@@ -2064,6 +2264,7 @@ void efx_schedule_reset(struct efx_nic *
        case RESET_TYPE_TX_SKIP:
                method = RESET_TYPE_INVISIBLE;
                break;
+       case RESET_TYPE_MC_FAILURE:
        default:
                method = RESET_TYPE_ALL;
                break;
@@ -2077,7 +2278,11 @@ void efx_schedule_reset(struct efx_nic *
 
        efx->reset_pending = method;
 
-       queue_work(efx->reset_workqueue, &efx->reset_work);
+       /* efx_process_channel() will no longer read events once a
+        * reset is scheduled. So switch back to poll'd MCDI completions. */
+       efx_mcdi_mode_poll(efx);
+
+       queue_work(reset_workqueue, &efx->reset_work);
 }
 
 /**************************************************************************
@@ -2088,18 +2293,24 @@ void efx_schedule_reset(struct efx_nic *
 
 /* PCI device ID table */
 static struct pci_device_id efx_pci_table[] __devinitdata = {
+#ifndef __VMKERNEL_MODULE__
        {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
-        .driver_data = (unsigned long) &falcon_a_nic_type},
+        .driver_data = (unsigned long) &falcon_a1_nic_type},
+#endif
        {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
-        .driver_data = (unsigned long) &falcon_b_nic_type},
+        .driver_data = (unsigned long) &falcon_b0_nic_type},
+       {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID),
+        .driver_data = (unsigned long) &siena_a0_nic_type},
+       {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID),
+        .driver_data = (unsigned long) &siena_a0_nic_type},
        {0}                     /* end of list */
 };
 
 /**************************************************************************
  *
- * Dummy PHY/MAC/Board operations
- *
- * Can be used where the MAC does not implement this operation
+ * Dummy PHY/MAC operations
+ *
+ * Can be used for some unimplemented operations
  * Needed so all function pointers are valid and do not have to be tested
  * before use
  *
@@ -2109,38 +2320,19 @@ int efx_port_dummy_op_int(struct efx_nic
        return 0;
 }
 void efx_port_dummy_op_void(struct efx_nic *efx) {}
-void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {}
-
-static struct efx_mac_operations efx_dummy_mac_operations = {
-       .init           = efx_port_dummy_op_int,
-       .reconfigure    = efx_port_dummy_op_void,
-       .fini           = efx_port_dummy_op_void,
-};
+void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+}
+bool efx_port_dummy_op_poll(struct efx_nic *efx)
+{
+       return false;
+}
 
 static struct efx_phy_operations efx_dummy_phy_operations = {
        .init            = efx_port_dummy_op_int,
-       .reconfigure     = efx_port_dummy_op_void,
-       .check_hw        = efx_port_dummy_op_int,
+       .reconfigure     = efx_port_dummy_op_int,
+       .poll            = efx_port_dummy_op_poll,
        .fini            = efx_port_dummy_op_void,
-       .clear_interrupt = efx_port_dummy_op_void,
-       .reset_xaui      = efx_port_dummy_op_void,
-};
-
-/* Dummy board operations */
-static int efx_nic_dummy_op_int(struct efx_nic *nic)
-{
-       return 0;
-}
-
-static void efx_nic_dummy_op_void(struct efx_nic *nic) {}
-
-static struct efx_board efx_dummy_board_info = {
-       .init    = efx_nic_dummy_op_int,
-       .init_leds = efx_port_dummy_op_int,
-       .set_fault_led = efx_port_dummy_op_blink,
-       .monitor = efx_nic_dummy_op_int,
-       .blink = efx_port_dummy_op_blink,
-       .fini    = efx_nic_dummy_op_void,
 };
 
 /**************************************************************************
@@ -2153,51 +2345,58 @@ static struct efx_board efx_dummy_board_
  * efx_nic (including all sub-structures).
  */
 static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
-                          struct pci_dev *pci_dev)
+                          struct pci_dev *pci_dev, struct net_device *net_dev)
 {
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
-       int i, rc;
+       int i;
 
        /* Initialise common structures */
        memset(efx, 0, sizeof(*efx));
        spin_lock_init(&efx->biu_lock);
-       spin_lock_init(&efx->phy_lock);
+       mutex_init(&efx->mdio_lock);
        mutex_init(&efx->spi_lock);
+#ifdef CONFIG_SFC_MTD
+       INIT_LIST_HEAD(&efx->mtd_list);
+#endif
        INIT_WORK(&efx->reset_work, efx_reset_work);
        INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
        efx->pci_dev = pci_dev;
        efx->state = STATE_INIT;
        efx->reset_pending = RESET_TYPE_NONE;
        strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
-       efx->board_info = efx_dummy_board_info;
-
-       efx->rx_checksum_enabled = 1;
+
+       efx->net_dev = net_dev;
+       efx->rx_checksum_enabled = true;
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_SFC_LRO) && 
!defined(NETIF_F_LRO)
+       efx->lro_enabled = lro;
+#endif
        spin_lock_init(&efx->netif_stop_lock);
        spin_lock_init(&efx->stats_lock);
        mutex_init(&efx->mac_lock);
-       efx->mac_op = &efx_dummy_mac_operations;
+       efx->mac_op = type->default_mac_ops;
        efx->phy_op = &efx_dummy_phy_operations;
+       efx->mdio.dev = net_dev;
        INIT_LIST_HEAD(&efx->dl_node);
        INIT_LIST_HEAD(&efx->dl_device_list);
        efx->dl_cb = efx_default_callbacks;
-       INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
+       INIT_WORK(&efx->mac_work, efx_mac_work);
        atomic_set(&efx->netif_stop_count, 1);
 
        for (i = 0; i < EFX_MAX_CHANNELS; i++) {
                channel = &efx->channel[i];
                channel->efx = efx;
                channel->channel = i;
-               channel->evqnum = i;
-               channel->work_pending = 0;
-       }
-       for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+               channel->work_pending = false;
+       }
+       for (i = 0; i < EFX_TX_QUEUE_COUNT; i++) {
                tx_queue = &efx->tx_queue[i];
                tx_queue->efx = efx;
                tx_queue->queue = i;
                tx_queue->buffer = NULL;
                tx_queue->channel = &efx->channel[0]; /* for safety */
+               tx_queue->tso_headers_free = NULL;
        }
        for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
                rx_queue = &efx->rx_queue[i];
@@ -2211,52 +2410,37 @@ static int efx_init_struct(struct efx_ni
 
        efx->type = type;
 
-       /* Sanity-check NIC type */
-       EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask &
-                           (efx->type->txd_ring_mask + 1));
-       EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask &
-                           (efx->type->rxd_ring_mask + 1));
-       EFX_BUG_ON_PARANOID(efx->type->evq_size &
-                           (efx->type->evq_size - 1));
        /* As close as we can get to guaranteeing that we don't overflow */
-       EFX_BUG_ON_PARANOID(efx->type->evq_size <
-                           (efx->type->txd_ring_mask + 1 +
-                            efx->type->rxd_ring_mask + 1));
+       BUILD_BUG_ON(EFX_EVQ_SIZE < EFX_TXQ_SIZE + EFX_RXQ_SIZE);
 
        EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS);
 
        /* Higher numbered interrupt modes are less capable! */
        efx->interrupt_mode = max(efx->type->max_interrupt_mode,
                                  interrupt_mode);
-
-       efx->workqueue = create_singlethread_workqueue("sfc_work");
-       if (!efx->workqueue) {
-               rc = -ENOMEM;
-               goto fail1;
-       }
-
-       efx->reset_workqueue = create_singlethread_workqueue("sfc_reset");
-       if (!efx->reset_workqueue) {
-               rc = -ENOMEM;
-               goto fail2;
-       }
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_DUMMY_MSIX)
+       if (efx->interrupt_mode == EFX_INT_MODE_MSIX)
+               efx->interrupt_mode = EFX_INT_MODE_MSI;
+#endif
+
+       /* Would be good to use the net_dev name, but we're too early */
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_HAVE_WORKQUEUE_NAME_LIMIT)
+       snprintf(efx->workqueue_name, 10 + 1, "sfc%02x:%02x.%d",
+                pci_dev->bus->number, PCI_SLOT(pci_dev->devfn),
+                PCI_FUNC(pci_dev->devfn));
+#else
+       snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s",
+                pci_name(pci_dev));
+#endif
+       efx->workqueue = create_singlethread_workqueue(efx->workqueue_name);
+       if (!efx->workqueue)
+               return -ENOMEM;
 
        return 0;
-
- fail2:
-       destroy_workqueue(efx->workqueue);
-       efx->workqueue = NULL;
-
- fail1:
-       return rc;
 }
 
 static void efx_fini_struct(struct efx_nic *efx)
 {
-       if (efx->reset_workqueue) {
-               destroy_workqueue(efx->reset_workqueue);
-               efx->reset_workqueue = NULL;
-       }
        if (efx->workqueue) {
                destroy_workqueue(efx->workqueue);
                efx->workqueue = NULL;
@@ -2274,22 +2458,10 @@ static void efx_fini_struct(struct efx_n
  */
 static void efx_pci_remove_main(struct efx_nic *efx)
 {
-       EFX_ASSERT_RESET_SERIALISED(efx);
-
-       /* Skip everything if we never obtained a valid membase */
-       if (!efx->membase)
-               return;
-
+       efx_nic_fini_interrupt(efx);
        efx_fini_channels(efx);
        efx_fini_port(efx);
-
-       /* Shutdown the board, then the NIC and board state */
-       efx->board_info.fini(efx);
-       falcon_fini_nic(efx);
-       falcon_fini_interrupt(efx);
-       efx->board_info.fini(efx);
-
-       /* Tear down NAPI and LRO */
+       efx->type->fini(efx);
        efx_fini_napi(efx);
        efx_remove_all(efx);
 }
@@ -2305,38 +2477,38 @@ static void efx_pci_remove(struct pci_de
        if (!efx)
                return;
 
-       /* Unregister driver from driverlink layer */
-       efx_dl_unregister_nic(efx);
-
        /* Mark the NIC as fini, then stop the interface */
        rtnl_lock();
+       efx_dl_unregister_nic(efx);
        efx->state = STATE_FINI;
        dev_close(efx->net_dev);
 
        /* Allow any queued efx_resets() to complete */
        rtnl_unlock();
 
-       if (efx->membase == NULL)
-               goto out;
-
        efx_unregister_netdev(efx);
+
+       efx_mtd_remove(efx);
        efx_fini_debugfs_channels(efx);
 
        /* Wait for any scheduled resets to complete. No more will be
         * scheduled from this point because efx_stop_all() has been
         * called, we are no longer registered with driverlink, and
         * the net_device's have been removed. */
-       flush_workqueue(efx->reset_workqueue);
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_CANCEL_WORK_SYNC)
+       cancel_work_sync(&efx->reset_work);
+#else
+       flush_workqueue(reset_workqueue);
+#endif
 
        efx_pci_remove_main(efx);
 
-out:
        efx_fini_io(efx);
        EFX_LOG(efx, "shutdown successful\n");
 
        pci_set_drvdata(pci_dev, NULL);
        efx_fini_struct(efx);
-       kfree(efx);
+       free_netdev(efx->net_dev);
 };
 
 /* Main body of NIC initialisation
@@ -2351,65 +2523,38 @@ static int efx_pci_probe_main(struct efx
        if (rc)
                goto fail1;
 
-       /* Initialise port/channel net_dev's  */
        rc = efx_init_napi(efx);
        if (rc)
                goto fail2;
 
-       /* Initialise the board */
-       rc = efx->board_info.init(efx);
-       if (rc) {
-               EFX_ERR(efx, "failed to initialise board\n");
-               goto fail3;
-       }
-
-       /* Initialise device */
-       rc = falcon_init_nic(efx);
+       rc = efx->type->init(efx);
        if (rc) {
                EFX_ERR(efx, "failed to initialise NIC\n");
-               goto fail4;
-       }
-
-       /* Initialise port */
+               goto fail3;
+       }
+
        rc = efx_init_port(efx);
        if (rc) {
                EFX_ERR(efx, "failed to initialise port\n");
+               goto fail4;
+       }
+
+       efx_init_channels(efx);
+
+       rc = efx_nic_init_interrupt(efx);
+       if (rc)
                goto fail5;
-       }
-
-       /* Initialise channels */
-       rc = efx_init_channels(efx);
-       if (rc)
-               goto fail6;
-
-       rc = falcon_init_interrupt(efx);
-       if (rc)
-               goto fail7;
-
-       /* Start up device - interrupts can occur from this point */
-       efx_start_all(efx);
-
-       /* Check basic functionality and set interrupt mode */
-       rc = efx_run_selftests(efx);
-       if (rc)
-               goto fail8;
-
-       /* Stop the NIC */
+
+       return 0;
+
+ fail6:
        efx_stop_all(efx);
-
-       return 0;
-
- fail8:
-       efx_stop_all(efx);
-       falcon_fini_interrupt(efx);
- fail7:
+       efx_nic_fini_interrupt(efx);
+ fail5:
        efx_fini_channels(efx);
- fail6:
        efx_fini_port(efx);
- fail5:
-       falcon_fini_nic(efx);
  fail4:
-       efx->board_info.fini(efx);
+       efx->type->fini(efx);
  fail3:
        efx_fini_napi(efx);
  fail2:
@@ -2430,103 +2575,288 @@ static int __devinit efx_pci_probe(struc
 static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
                                   const struct pci_device_id *entry)
 {
+       struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
+       struct net_device *net_dev;
        struct efx_nic *efx;
-       struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
        int i, rc;
 
-       /* Allocate and initialise a struct efx_nic */
-       efx = kmalloc(sizeof(*efx), GFP_KERNEL);
-       if (!efx) {
-               rc = -ENOMEM;
+       /* Allocate and initialise a struct net_device and struct efx_nic */
+       net_dev = alloc_etherdev(sizeof(*efx));
+       if (!net_dev)
+               return -ENOMEM;
+       net_dev->features |= (type->offload_features | NETIF_F_SG |
+                             NETIF_F_HIGHDMA | NETIF_F_TSO);
+#if !defined(EFX_USE_KCOMPAT) || defined(NETIF_F_TSO6)
+       if (type->offload_features & NETIF_F_V6_CSUM)
+               net_dev->features |= NETIF_F_TSO6;
+#endif
+#if   defined(EFX_USE_GRO)
+       if (lro)
+               net_dev->features |= NETIF_F_GRO;
+#endif
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_NETDEV_VLAN_FEATURES)
+       /* Mask for features that also apply to VLAN devices */
+       net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG |
+                                  NETIF_F_HIGHDMA | NETIF_F_TSO);
+#endif
+       efx = netdev_priv(net_dev);
+       pci_set_drvdata(pci_dev, efx);
+       rc = efx_init_struct(efx, type, pci_dev, net_dev);
+       if (rc)
                goto fail1;
-       }
-       pci_set_drvdata(pci_dev, efx);
-       rc = efx_init_struct(efx, type, pci_dev);
-       if (rc)
-               goto fail2;
-
-       EFX_INFO(efx, "Solarflare Communications NIC detected\n");
+
+       EFX_INFO(efx, "Solarflare Communications NIC detected PCI(%x:%x)\n",
+                pci_dev->vendor, pci_dev->device);
 
        /* Set up basic I/O (BAR mappings etc) */
        rc = efx_init_io(efx);
        if (rc)
-               goto fail3;
+               goto fail2;
 
        /* No serialisation is required with the reset path because
         * we're in STATE_INIT. */
        for (i = 0; i < 5; i++) {
                rc = efx_pci_probe_main(efx);
-               if (rc == 0)
-                       break;
 
                /* Serialise against efx_reset(). No more resets will be
                 * scheduled since efx_stop_all() has been called, and we
                 * have not and never have been registered with either
                 * the rtnetlink or driverlink layers. */
-               flush_workqueue(efx->reset_workqueue);
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_CANCEL_WORK_SYNC)
+               cancel_work_sync(&efx->reset_work);
+#else
+               flush_workqueue(reset_workqueue);
+#endif
+
+               if (rc == 0) {
+                       if (efx->reset_pending != RESET_TYPE_NONE) {
+                               /* If there was a scheduled reset during
+                                * probe, the NIC is probably hosed anyway */
+                               efx_pci_remove_main(efx);
+                               rc = -EIO;
+                       } else {
+                               break;
+                       }
+               }
 
                /* Retry if a recoverably reset event has been scheduled */
                if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
-                   (efx->reset_pending != RESET_TYPE_ALL))
-                       goto fail4;
+                   (efx->reset_pending != RESET_TYPE_ALL)) {
+                       if (efx->reset_pending != RESET_TYPE_NONE)
+                               EFX_ERR(efx, "Unrecoverable scheduled reset: "
+                                       "%s\n", RESET_TYPE(efx->reset_pending));
+                       goto fail3;
+               }
 
                efx->reset_pending = RESET_TYPE_NONE;
        }
 
        if (rc) {
-               EFX_ERR(efx, "Could not reset NIC\n");
-               goto fail5;
+               EFX_ERR(efx, "Initialisation failed due to persistent reset\n");
+               goto fail4;
        }
 
        /* Self-tests have all passed */
        rc = efx_init_debugfs_channels(efx);
        if (rc)
-               goto fail6;
-
-       /* Switch to the running state before we expose the device to
-        * the OS.  This is to ensure that the initial gathering of
-        * MAC stats succeeds. */
-       rtnl_lock();
+               goto fail5;
+
+       /* Switch to the running state before we expose the device to the OS,
+        * so that dev_open()|efx_start_all() will actually start the device */
        efx->state = STATE_RUNNING;
-       rtnl_unlock();
 
        rc = efx_register_netdev(efx);
        if (rc)
-               goto fail7;
+               goto fail6;
 
        EFX_LOG(efx, "initialisation successful\n");
 
-       /* Register with driverlink layer */
-       rc = efx_dl_register_nic(efx);
-       if (rc)
-               goto fail8;
-
+       rtnl_lock();
+       efx_mtd_probe(efx); /* allowed to fail */
+       rtnl_unlock();
        return 0;
 
- fail8:
-       efx_unregister_netdev(efx);
- fail7:
+ fail6:
        efx_fini_debugfs_channels(efx);
- fail6:
+ fail5:
        efx_pci_remove_main(efx);
- fail5:
  fail4:
+ fail3:
        efx_fini_io(efx);
- fail3:
+ fail2:
        efx_fini_struct(efx);
- fail2:
-       kfree(efx);
  fail1:
        EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+       free_netdev(net_dev);
        return rc;
 }
 
-/* PCI driver definition */
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_PM)
+
+static int efx_pm_freeze(struct device *dev)
+{
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+       rtnl_lock();
+       efx_dl_reset_suspend(efx);
+       rtnl_unlock();
+
+       efx->state = STATE_FINI;
+
+       netif_device_detach(efx->net_dev);
+
+       efx_stop_all(efx);
+       efx_fini_channels(efx);
+
+       return 0;
+}
+
+static int efx_pm_thaw(struct device *dev)
+{
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+
+       efx->state = STATE_INIT;
+
+       efx_init_channels(efx);
+
+       mutex_lock(&efx->mac_lock);
+       efx->phy_op->reconfigure(efx);
+       mutex_unlock(&efx->mac_lock);
+
+       efx_start_all(efx);
+
+       netif_device_attach(efx->net_dev);
+
+       efx->state = STATE_RUNNING;
+
+       rtnl_lock();
+       efx_dl_reset_resume(efx, true);
+       rtnl_unlock();
+
+       efx->type->resume_wol(efx);
+
+       return 0;
+}
+
+static int efx_pm_poweroff(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct efx_nic *efx = pci_get_drvdata(pci_dev);
+
+       efx->type->fini(efx);
+
+       efx->reset_pending = RESET_TYPE_NONE;
+
+       pci_save_state(pci_dev);
+       return pci_set_power_state(pci_dev, PCI_D3hot);
+}
+
+/* Used for both resume and restore */
+static int efx_pm_resume(struct device *dev)
+{
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       struct efx_nic *efx = pci_get_drvdata(pci_dev);
+       int rc;
+
+       rc = pci_set_power_state(pci_dev, PCI_D0);
+       if (rc)
+               goto fail;
+       pci_restore_state(pci_dev);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_UNMASK_MSIX_VECTORS)
+       efx_unmask_msix_vectors(pci_dev);
+#endif
+       rc = pci_enable_device(pci_dev);
+       if (rc)
+               goto fail;
+       pci_set_master(efx->pci_dev);
+       rc = efx->type->reset(efx, RESET_TYPE_ALL);
+       if (rc)
+               goto fail;
+       rc = efx->type->init(efx);
+       if (rc)
+               goto fail;
+       efx_pm_thaw(dev);
+       return 0;
+
+fail:
+       efx_dl_reset_resume(efx, false);
+       return rc;
+}
+
+static int efx_pm_suspend(struct device *dev)
+{
+       int rc;
+
+       efx_pm_freeze(dev);
+       rc = efx_pm_poweroff(dev);
+       if (rc)
+               efx_pm_resume(dev);
+       return rc;
+}
+
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_DEV_PM_OPS)
+
+static struct dev_pm_ops efx_pm_ops = {
+       .suspend        = efx_pm_suspend,
+       .resume         = efx_pm_resume,
+       .freeze         = efx_pm_freeze,
+       .thaw           = efx_pm_thaw,
+       .poweroff       = efx_pm_poweroff,
+       .restore        = efx_pm_resume,
+};
+
+#elif defined(EFX_USE_PM_EXT_OPS)
+
+static struct pm_ext_ops efx_pm_ops = {
+       .base = {
+               .suspend        = efx_pm_suspend,
+               .resume         = efx_pm_resume,
+               .freeze         = efx_pm_freeze,
+               .thaw           = efx_pm_thaw,
+               .poweroff       = efx_pm_poweroff,
+               .restore        = efx_pm_resume,
+       }
+};
+
+#else /* !EFX_USE_DEV_PM_OPS && !EFX_USE_PM_EXT_OPS */
+
+static int efx_pm_old_suspend(struct pci_dev *dev, pm_message_t state)
+{
+       switch (state.event) {
+       case PM_EVENT_FREEZE:
+#if defined(PM_EVENT_QUIESCE)
+       case PM_EVENT_QUIESCE:
+#elif defined(PM_EVENT_PRETHAW)
+       case PM_EVENT_PRETHAW:
+#endif
+               return efx_pm_freeze(&dev->dev);
+       default:
+               return efx_pm_suspend(&dev->dev);
+       }
+}
+
+static int efx_pm_old_resume(struct pci_dev *dev)
+{
+       return efx_pm_resume(&dev->dev);
+}
+
+#endif /* EFX_USE_PM_EXT_OPS */
+
+#endif /* EFX_USE_PM */
+
 static struct pci_driver efx_pci_driver = {
        .name           = EFX_DRIVER_NAME,
        .id_table       = efx_pci_table,
        .probe          = efx_pci_probe,
        .remove         = efx_pci_remove,
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_DEV_PM_OPS)
+       .driver.pm      = &efx_pm_ops,
+#elif defined(EFX_USE_PM_EXT_OPS)
+       .pm             = &efx_pm_ops,
+#elif defined(EFX_USE_PM)
+       .suspend        = efx_pm_old_suspend,
+       .resume         = efx_pm_old_resume,
+#endif
 };
 
 /**************************************************************************
@@ -2538,9 +2868,6 @@ module_param(interrupt_mode, uint, 0444)
 module_param(interrupt_mode, uint, 0444);
 MODULE_PARM_DESC(interrupt_mode,
                 "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
-
-module_param(onload_offline_selftest, uint, 0444);
-MODULE_PARM_DESC(onload_offline_selftest, "Perform offline selftest on load");
 
 static int __init efx_init_module(void)
 {
@@ -2561,6 +2888,27 @@ static int __init efx_init_module(void)
                rc = -ENOMEM;
                goto err_refill;
        }
+       reset_workqueue = create_singlethread_workqueue("sfc_reset");
+       if (!reset_workqueue) {
+               rc = -ENOMEM;
+               goto err_reset;
+       }
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_LM87_DRIVER)
+       rc = i2c_add_driver(&efx_lm87_driver);
+       if (rc < 0)
+               goto err_lm87;
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_LM90_DRIVER)
+       rc = i2c_add_driver(&efx_lm90_driver);
+       if (rc < 0)
+               goto err_lm90;
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_I2C_NEW_DUMMY)
+       rc = i2c_add_driver(&efx_i2c_dummy_driver);
+       if (rc < 0)
+               goto err_i2c_dummy;
+#endif
 
        rc = pci_register_driver(&efx_pci_driver);
        if (rc < 0)
@@ -2569,6 +2917,20 @@ static int __init efx_init_module(void)
        return 0;
 
  err_pci:
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_I2C_NEW_DUMMY)
+       i2c_del_driver(&efx_i2c_dummy_driver);
+ err_i2c_dummy:
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_LM90_DRIVER)
+       i2c_del_driver(&efx_lm90_driver);
+ err_lm90:
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_LM87_DRIVER)
+       i2c_del_driver(&efx_lm87_driver);
+ err_lm87:
+#endif
+       destroy_workqueue(reset_workqueue);
+ err_reset:
        destroy_workqueue(refill_workqueue);
  err_refill:
        unregister_netdevice_notifier(&efx_netdev_notifier);
@@ -2583,6 +2945,16 @@ static void __exit efx_exit_module(void)
        printk(KERN_INFO "Solarflare NET driver unloading\n");
 
        pci_unregister_driver(&efx_pci_driver);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_I2C_NEW_DUMMY)
+       i2c_del_driver(&efx_i2c_dummy_driver);
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_LM90_DRIVER)
+       i2c_del_driver(&efx_lm90_driver);
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_LM87_DRIVER)
+       i2c_del_driver(&efx_lm87_driver);
+#endif
+       destroy_workqueue(reset_workqueue);
        destroy_workqueue(refill_workqueue);
        unregister_netdevice_notifier(&efx_netdev_notifier);
        efx_fini_debugfs();
@@ -2592,8 +2964,9 @@ module_init(efx_init_module);
 module_init(efx_init_module);
 module_exit(efx_exit_module);
 
-MODULE_AUTHOR("Michael Brown <mbrown@xxxxxxxxxxxxxxxx> and "
-             "Solarflare Communications");
+MODULE_AUTHOR("Solarflare Communications and "
+             "Michael Brown <mbrown@xxxxxxxxxxxxxxxx>");
 MODULE_DESCRIPTION("Solarflare Communications network driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, efx_pci_table);
+MODULE_VERSION(EFX_DRIVER_VERSION);
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/efx.h
--- a/drivers/net/sfc/efx.h     Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/efx.h     Fri Jan 08 13:05:49 2010 +0000
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2009 Solarflare Communications Inc.
  *
  * 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 EFX_EFX_H
@@ -35,42 +18,103 @@
 #define FALCON_A_P_DEVID       0x0703
 #define FALCON_A_S_DEVID        0x6703
 #define FALCON_B_P_DEVID        0x0710
+#define BETHPAGE_A_P_DEVID      0x0803
+#define SIENA_A_P_DEVID         0x0813
+
+/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
+#define EFX_MEM_BAR 2
 
 /* TX */
-extern int efx_xmit(struct efx_nic *efx,
-                   struct efx_tx_queue *tx_queue, struct sk_buff *skb);
+extern int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
+extern void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
+extern void efx_init_tx_queue(struct efx_tx_queue *tx_queue);
+extern void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
+extern void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
+extern netdev_tx_t
+efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
+extern netdev_tx_t
+efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+extern void fastcall efx_xmit_done(struct efx_tx_queue *tx_queue,
+                                  unsigned int index);
+#else
+extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
+#endif
 extern void efx_stop_queue(struct efx_nic *efx);
 extern void efx_wake_queue(struct efx_nic *efx);
+#define EFX_TXQ_SIZE 1024
+#define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1)
 
 /* RX */
-extern void fastcall efx_xmit_done(struct efx_tx_queue *tx_queue,
-                                  unsigned int index);
+extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
+extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
+extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
+extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
+extern void efx_rx_strategy(struct efx_channel *channel);
+extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
+extern void efx_rx_work(struct work_struct *data);
+extern void __efx_rx_packet(struct efx_channel *channel,
+                           struct efx_rx_buffer *rx_buf, bool checksummed);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
 extern void fastcall efx_rx_packet(struct efx_rx_queue *rx_queue,
                                   unsigned int index, unsigned int len,
-                                  int checksummed, int discard);
+                                  bool checksummed, bool discard);
+#else
+extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+                         unsigned int len, bool checksummed, bool discard);
+#endif
 extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+#define EFX_RXQ_SIZE 1024
+#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
 
 /* Channels */
 extern void efx_process_channel_now(struct efx_channel *channel);
-extern int efx_flush_queues(struct efx_nic *efx);
+#define EFX_EVQ_SIZE 4096
+#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
 
 /* Ports */
-extern void efx_reconfigure_port(struct efx_nic *efx);
+extern int efx_reconfigure_port(struct efx_nic *efx);
+extern int __efx_reconfigure_port(struct efx_nic *efx);
+
+/* Ethtool support */
+extern int efx_ethtool_get_settings(struct net_device *net_dev,
+                                   struct ethtool_cmd *ecmd);
+extern int efx_ethtool_set_settings(struct net_device *net_dev,
+                                   struct ethtool_cmd *ecmd);
+extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags);
+extern const struct ethtool_ops efx_ethtool_ops;
+
+/* Reset handling */
+extern int efx_reset(struct efx_nic *efx, enum reset_type method);
+extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
+extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
 
 /* Global */
 extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
-extern void efx_suspend(struct efx_nic *efx);
-extern void efx_resume(struct efx_nic *efx);
+extern void efx_start_all(struct efx_nic *efx);
+extern void efx_stop_all(struct efx_nic *efx);
 extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
-                                   int rx_usecs);
+                                   int rx_usecs, bool rx_adaptive);
 extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
 extern void efx_hex_dump(const u8 *, unsigned int, const char *);
 
 /* Dummy PHY ops for PHY drivers */
 extern int efx_port_dummy_op_int(struct efx_nic *efx);
 extern void efx_port_dummy_op_void(struct efx_nic *efx);
-extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
+extern void
+efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
+extern bool efx_port_dummy_op_poll(struct efx_nic *efx);
 
+/* MTD */
+#ifdef CONFIG_SFC_MTD
+extern int efx_mtd_probe(struct efx_nic *efx);
+extern void efx_mtd_rename(struct efx_nic *efx);
+extern void efx_mtd_remove(struct efx_nic *efx);
+#else
+static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; }
+static inline void efx_mtd_rename(struct efx_nic *efx) {}
+static inline void efx_mtd_remove(struct efx_nic *efx) {}
+#endif
 
 extern unsigned int efx_monitor_interval;
 
@@ -78,10 +122,13 @@ static inline void efx_schedule_channel(
 {
        EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
                  channel->channel, raw_smp_processor_id());
-       channel->work_pending = 1;
+       channel->work_pending = true;
 
-       if (!test_and_set_bit(__LINK_STATE_RX_SCHED, &channel->napi_dev->state))
-               __netif_rx_schedule(channel->napi_dev);
+       napi_schedule(&channel->napi_str);
 }
 
+extern void efx_link_status_changed(struct efx_nic *efx);
+extern void efx_link_set_advertising(struct efx_nic *efx, u32);
+extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type);
+
 #endif /* EFX_EFX_H */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/efx_ioctl.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/drivers/net/sfc/efx_ioctl.h       Fri Jan 08 13:05:49 2010 +0000
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005-2006: Fen Systems Ltd.
+ * Copyright 2006-2009: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
+ * Maintained by Solarflare Communications <linux-net-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 EFX_IOCTL_H
+#define EFX_IOCTL_H
+
+#if defined(__KERNEL__)
+#include <linux/if.h>
+#else
+#include <net/if.h>
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H /* prevent <linux/if.h> from conflicting with <net/if.h> */
+#endif
+#endif
+#include <linux/sockios.h>
+#include <linux/types.h>
+
+/*
+ * Efx private ioctls
+ */
+
+/* Reset selected components, like ETHTOOL_RESET ****************************/
+#define EFX_RESET_FLAGS 0xef0d
+struct efx_reset_flags {
+       __u32 flags;
+};
+
+/* Efx private ioctl command structures *************************************/
+
+union efx_ioctl_data {
+       struct efx_reset_flags reset_flags;
+};
+
+struct efx_sock_ioctl {
+       /* Command to run */
+       __u16 cmd;
+       __u16 reserved;
+       /* Parameters */
+       union efx_ioctl_data u;
+};
+
+#ifdef __KERNEL__
+extern int efx_private_ioctl(struct efx_nic *efx, u16 cmd,
+                            union efx_ioctl_data __user *data);
+#endif
+
+#endif /* EFX_IOCTL_H */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/enum.h
--- a/drivers/net/sfc/enum.h    Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/enum.h    Fri Jan 08 13:05:49 2010 +0000
@@ -1,26 +1,10 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2007:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007-2009 Solarflare Communications Inc.
  *
  * 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 EFX_ENUM_H
@@ -29,57 +13,116 @@
 /**
  * enum efx_loopback_mode - loopback modes
  * @LOOPBACK_NONE: no loopback
- * @LOOPBACK_NEAR: loopback nearest to bus
- * @LOOPBACK_MAC: loopback within MAC unspecified level
- * @LOOPBACK_XGMII: loopback within MAC at XGMII level
- * @LOOPBACK_XGXS: loopback within MAC at XGXS level
- * @LOOPBACK_XAUI: loopback within MAC at XAUI level
- * @LOOPBACK_PHY: loopback within PHY unspecified level
- * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level
- * @LOOPBACK_PCS: loopback within PHY at PCS level
- * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level
- * @LOOPBACK_FAR: loopback furthest from bus
- * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
+ * @LOOPBACK_DATA: data path loopback
+ * @LOOPBACK_GMAC: loopback within GMAC
+ * @LOOPBACK_XGMII: loopback after XMAC
+ * @LOOPBACK_XGXS: loopback within BPX after XGXS
+ * @LOOPBACK_XAUI: loopback within BPX before XAUI serdes
+ * @LOOPBACK_GMII: loopback within BPX after GMAC
+ * @LOOPBACK_SGMII: loopback within BPX within SGMII
+ * @LOOPBACK_XGBR: loopback within BPX within XGBR
+ * @LOOPBACK_XFI: loopback within BPX before XFI serdes
+ * @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes
+ * @LOOPBACK_GMII_FAR: loopback within BPX before SGMII
+ * @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII
+ * @LOOPBACK_XFI_FAR: loopback after XFI serdes
+ * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level
+ * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level
+ * @LOOPBACK_PCS: loopback within 10G PHY at PCS level
+ * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level
+ * @LOOPBACK_XPORT: cross port loopback
+ * @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC
+ * @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes
+ * @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes
+ * @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes
+ * @LOOPBACK_GMII_WS: wireside loopback excluding GMAC
+ * @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes
+ * @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes
+ * @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level
  */
-/* Please keep in order and up-to-date w.r.t the following two #defines */
+/* Please keep up-to-date w.r.t the following two #defines */
 enum efx_loopback_mode {
        LOOPBACK_NONE = 0,
-       LOOPBACK_NEAR = 1,
-       LOOPBACK_MAC = 2,
+       LOOPBACK_DATA = 1,
+       LOOPBACK_GMAC = 2,
        LOOPBACK_XGMII = 3,
        LOOPBACK_XGXS = 4,
        LOOPBACK_XAUI = 5,
-       LOOPBACK_PHY = 6,
-       LOOPBACK_PHYXS = 7,
-       LOOPBACK_PCS = 8,
-       LOOPBACK_PMAPMD = 9,
-       LOOPBACK_FAR = 10,
-       LOOPBACK_NETWORK = 11,
+       LOOPBACK_GMII = 6,
+       LOOPBACK_SGMII = 7,
+       LOOPBACK_XGBR = 8,
+       LOOPBACK_XFI = 9,
+       LOOPBACK_XAUI_FAR = 10,
+       LOOPBACK_GMII_FAR = 11,
+       LOOPBACK_SGMII_FAR = 12,
+       LOOPBACK_XFI_FAR = 13,
+       LOOPBACK_GPHY = 14,
+       LOOPBACK_PHYXS = 15,
+       LOOPBACK_PCS = 16,
+       LOOPBACK_PMAPMD = 17,
+       LOOPBACK_XPORT = 18,
+       LOOPBACK_XGMII_WS = 19,
+       LOOPBACK_XAUI_WS = 20,
+       LOOPBACK_XAUI_WS_FAR = 21,
+       LOOPBACK_XAUI_WS_NEAR = 22,
+       LOOPBACK_GMII_WS = 23,
+       LOOPBACK_XFI_WS = 24,
+       LOOPBACK_XFI_WS_FAR = 25,
+       LOOPBACK_PHYXS_WS = 26,
        LOOPBACK_MAX
 };
-#define LOOPBACK_TEST_MAX LOOPBACK_FAR
+#define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD
 
 /* These loopbacks occur within the controller */
-#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \
-                               (1 << LOOPBACK_XGXS) | \
-                               (1 << LOOPBACK_XAUI))
+#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) |             \
+                           (1 << LOOPBACK_GMAC) |              \
+                           (1 << LOOPBACK_XGMII)|              \
+                           (1 << LOOPBACK_XGXS) |              \
+                           (1 << LOOPBACK_XAUI) |              \
+                           (1 << LOOPBACK_GMII) |              \
+                           (1 << LOOPBACK_SGMII) |             \
+                           (1 << LOOPBACK_SGMII) |             \
+                           (1 << LOOPBACK_XGBR) |              \
+                           (1 << LOOPBACK_XFI) |               \
+                           (1 << LOOPBACK_XAUI_FAR) |          \
+                           (1 << LOOPBACK_GMII_FAR) |          \
+                           (1 << LOOPBACK_SGMII_FAR) |         \
+                           (1 << LOOPBACK_XFI_FAR) |           \
+                           (1 << LOOPBACK_XGMII_WS) |          \
+                           (1 << LOOPBACK_XAUI_WS) |           \
+                           (1 << LOOPBACK_XAUI_WS_FAR) |       \
+                           (1 << LOOPBACK_XAUI_WS_NEAR) |      \
+                           (1 << LOOPBACK_GMII_WS) |           \
+                           (1 << LOOPBACK_XFI_WS) |            \
+                           (1 << LOOPBACK_XFI_WS_FAR))
 
-#define LOOPBACKS_1G_INTERNAL (1 << LOOPBACK_MAC)
+#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) |               \
+                     (1 << LOOPBACK_XAUI_WS) |                 \
+                     (1 << LOOPBACK_XAUI_WS_FAR) |             \
+                     (1 << LOOPBACK_XAUI_WS_NEAR) |            \
+                     (1 << LOOPBACK_GMII_WS) |                 \
+                     (1 << LOOPBACK_XFI_WS) |                  \
+                     (1 << LOOPBACK_XFI_WS_FAR) |              \
+                     (1 << LOOPBACK_PHYXS_WS))
+
+#define LOOPBACKS_EXTERNAL(_efx)                                       \
+       ((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL &                 \
+        ~(1 << LOOPBACK_NONE))
 
 #define LOOPBACK_MASK(_efx)                    \
        (1 << (_efx)->loopback_mode)
 
-#define LOOPBACK_INTERNAL(_efx)                                        \
-       (((LOOPBACKS_10G_INTERNAL | LOOPBACKS_1G_INTERNAL) &    \
-         LOOPBACK_MASK(_efx)) ? 1 : 0)
+#define LOOPBACK_INTERNAL(_efx)                                \
+       (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx)))
 
-#define LOOPBACK_CHANGED(_from, _to, _mask)            \
-       ((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) &  \
-        (_mask) ? 1 : 0)
+#define LOOPBACK_EXTERNAL(_efx)                                \
+       (!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx)))
 
-#define LOOPBACK_OUT_OF(_from, _to, _mask)             \
-       (((LOOPBACK_MASK(_from) & (_mask)) &&           \
-         ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0)
+#define LOOPBACK_CHANGED(_from, _to, _mask)                            \
+       (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask)))
+
+#define LOOPBACK_OUT_OF(_from, _to, _mask)                             \
+       ((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
 
 /*****************************************************************************/
 
@@ -95,12 +138,13 @@ enum efx_loopback_mode {
  * @RESET_TYPE_ALL: reset everything but PCI core blocks
  * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
  * @RESET_TYPE_DISABLE: disable NIC
- * @RESET_TYPE_MONITOR: reset due to hardware monitor
+ * @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
  * @RESET_TYPE_INT_ERROR: reset due to internal error
  * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
  * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
  * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
  * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
+ * @RESET_TYPE_MC_FAILURE: MC reboot/assertion
  */
 enum reset_type {
        RESET_TYPE_NONE = -1,
@@ -109,12 +153,13 @@ enum reset_type {
        RESET_TYPE_WORLD = 2,
        RESET_TYPE_DISABLE = 3,
        RESET_TYPE_MAX_METHOD,
-       RESET_TYPE_MONITOR,
+       RESET_TYPE_TX_WATCHDOG,
        RESET_TYPE_INT_ERROR,
        RESET_TYPE_RX_RECOVERY,
        RESET_TYPE_RX_DESC_FETCH,
        RESET_TYPE_TX_DESC_FETCH,
        RESET_TYPE_TX_SKIP,
+       RESET_TYPE_MC_FAILURE,
        RESET_TYPE_MAX,
 };
 
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/ethtool.c
--- a/drivers/net/sfc/ethtool.c Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/ethtool.c Fri Jan 08 13:05:49 2010 +0000
@@ -1,41 +1,23 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2009 Solarflare Communications Inc.
  *
  * 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/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/rtnetlink.h>
 #include "net_driver.h"
+#include "workarounds.h"
 #include "selftest.h"
 #include "efx.h"
-#include "ethtool.h"
-#include "falcon.h"
-#include "gmii.h"
-
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
+#include "nic.h"
+#include "spi.h"
+#include "mdio_10g.h"
 
 struct ethtool_string {
        char name[ETH_GSTRING_LEN];
@@ -170,11 +152,24 @@ static struct efx_ethtool_stat efx_ethto
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
+       EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_eth_crc_err),
+       EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_char_error_lane0),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_char_error_lane1),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_char_error_lane2),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_char_error_lane3),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_disp_error_lane0),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_disp_error_lane1),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_disp_error_lane2),
+       EFX_ETHTOOL_ULONG_MAC_STAT(rx_disp_error_lane3),
+       EFX_ETHTOOL_U64_MAC_STAT(rx_match_fault),
 };
 
 /* Number of ethtool statistics */
 #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
+
+#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB
 
 /**************************************************************************
  *
@@ -184,13 +179,19 @@ static struct efx_ethtool_stat efx_ethto
  */
 
 /* Identify device by flashing LEDs */
-static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
-{
-       struct efx_nic *efx = net_dev->priv;
-
-       efx->board_info.blink(efx, 1);
-       schedule_timeout_interruptible(seconds * HZ);
-       efx->board_info.blink(efx, 0);
+static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       do {
+               efx->type->set_id_led(efx, EFX_LED_ON);
+               schedule_timeout_interruptible(HZ / 2);
+
+               efx->type->set_id_led(efx, EFX_LED_OFF);
+               schedule_timeout_interruptible(HZ / 2);
+       } while (!signal_pending(current) && --count != 0);
+
+       efx->type->set_id_led(efx, EFX_LED_DEFAULT);
        return 0;
 }
 
@@ -198,41 +199,75 @@ int efx_ethtool_get_settings(struct net_
 int efx_ethtool_get_settings(struct net_device *net_dev,
                             struct ethtool_cmd *ecmd)
 {
-       struct efx_nic *efx = net_dev->priv;
-       int rc;
-
-       if (!in_interrupt())
-           mutex_lock(&efx->mac_lock);
-       rc = efx->mac_op->get_settings(efx, ecmd);
-       if (!in_interrupt())
-           mutex_unlock(&efx->mac_lock);
-
-       return rc;
+       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_link_state *link_state = &efx->link_state;
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_BONDING_HACKS)
+       if (in_interrupt()) {
+               memset(ecmd, 0, sizeof(*ecmd));
+               ecmd->speed = link_state->speed;
+               ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
+               return 0;
+       }
+#endif
+
+       mutex_lock(&efx->mac_lock);
+       efx->phy_op->get_settings(efx, ecmd);
+       mutex_unlock(&efx->mac_lock);
+
+       /* GMAC does not support 1000Mbps HD */
+       ecmd->supported &= ~SUPPORTED_1000baseT_Half;
+       /* Both MACs support pause frames (bidirectional and respond-only) */
+       ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+       if (LOOPBACK_INTERNAL(efx)) {
+               ecmd->speed = link_state->speed;
+               ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
+       }
+
+       return 0;
 }
 
 /* This must be called with rtnl_lock held. */
 int efx_ethtool_set_settings(struct net_device *net_dev,
                             struct ethtool_cmd *ecmd)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        int rc;
 
+       /* Older versions of ethtool don't set all the right bits when
+        * turning autoneg on with no speed/duplex specified.  But they
+        * always set more than one bit in this case, so test for that.
+        * Allow overriding this in ethtool 6 by setting
+        * ADVERTISED_Autoneg = 0x40.
+        */
+       if (ecmd->advertising & (ecmd->advertising - 1) &&
+           !(ecmd->advertising & ADVERTISED_Autoneg))
+               ecmd->advertising = ecmd->supported;
+
+       /* GMAC does not support 1000Mbps HD */
+       if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
+               EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
+                       " setting\n");
+               return -EINVAL;
+       }
+
        mutex_lock(&efx->mac_lock);
-       rc = efx->mac_op->set_settings(efx, ecmd);
+       rc = efx->phy_op->set_settings(efx, ecmd);
        mutex_unlock(&efx->mac_lock);
-       if (!rc)
-               efx_reconfigure_port(efx);
-
        return rc;
 }
 
 static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
                                    struct ethtool_drvinfo *info)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
        strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
        strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
+       if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
+               siena_print_fwver(efx, info->fw_version,
+                                 sizeof(info->fw_version));
        strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
 }
 
@@ -242,10 +277,10 @@ static void efx_ethtool_get_drvinfo(stru
  * @strings:           Ethtool strings, or %NULL
  * @data:              Ethtool test results, or %NULL
  * @test:              Pointer to test result (used only if data != %NULL)
- * @unit_format:       Unit name format (e.g. "channel\%d")
- * @unit_id:           Unit id (e.g. 0 for "channel0")
+ * @unit_format:       Unit name format (e.g. "chan\%d")
+ * @unit_id:           Unit id (e.g. 0 for "chan0")
  * @test_format:       Test name format (e.g. "loopback.\%s.tx.sent")
- * @test_id:           Test id (e.g. "PHY" for "loopback.PHY.tx_sent")
+ * @test_id:           Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent")
  *
  * Fill in an individual self-test entry.
  */
@@ -262,17 +297,21 @@ static void efx_fill_test(unsigned int t
 
        /* Fill string, if applicable */
        if (strings) {
-               snprintf(unit_str.name, sizeof(unit_str.name),
-                        unit_format, unit_id);
+               if (strchr(unit_format, '%'))
+                       snprintf(unit_str.name, sizeof(unit_str.name),
+                                unit_format, unit_id);
+               else
+                       strcpy(unit_str.name, unit_format);
                snprintf(test_str.name, sizeof(test_str.name),
                         test_format, test_id);
                snprintf(strings[test_index].name,
                         sizeof(strings[test_index].name),
-                        "%-9s%-17s", unit_str.name, test_str.name);
-       }
-}
-
-#define EFX_PORT_NAME "port%d", 0
+                        "%-6s %-24s", unit_str.name, test_str.name);
+       }
+}
+
+#define EFX_LOOPBACK_NAME(_mode, _counter)                     \
+       "loopback.%s." _counter, STRING_TABLE_LOOKUP(_mode, efx_loopback_mode)
 
 /**
  * efx_fill_loopback_test - fill in a block of loopback self-test entries
@@ -298,24 +337,20 @@ static int efx_fill_loopback_test(struct
                efx_fill_test(test_index++, strings, data,
                              &lb_tests->tx_sent[tx_queue->queue],
                              EFX_TX_QUEUE_NAME(tx_queue),
-                             "loopback.%s.tx_sent",
-                             efx_loopback_mode_names[mode]);
+                             EFX_LOOPBACK_NAME(mode, "tx_sent"));
                efx_fill_test(test_index++, strings, data,
                              &lb_tests->tx_done[tx_queue->queue],
                              EFX_TX_QUEUE_NAME(tx_queue),
-                             "loopback.%s.tx_done",
-                             efx_loopback_mode_names[mode]);
+                             EFX_LOOPBACK_NAME(mode, "tx_done"));
        }
        efx_fill_test(test_index++, strings, data,
                      &lb_tests->rx_good,
-                     EFX_PORT_NAME,
-                     "loopback.%s.rx_good",
-                     efx_loopback_mode_names[mode]);
+                     "rx", 0,
+                     EFX_LOOPBACK_NAME(mode, "rx_good"));
        efx_fill_test(test_index++, strings, data,
                      &lb_tests->rx_bad,
-                     EFX_PORT_NAME,
-                     "loopback.%s.rx_bad",
-                     efx_loopback_mode_names[mode]);
+                     "rx", 0,
+                     EFX_LOOPBACK_NAME(mode, "rx_bad"));
 
        return test_index;
 }
@@ -339,10 +374,13 @@ static int efx_ethtool_fill_self_tests(s
                                       u64 *data)
 {
        struct efx_channel *channel;
-       unsigned int n = 0;
+       unsigned int n = 0, i;
        enum efx_loopback_mode mode;
 
-       /* Interrupt */
+       efx_fill_test(n++, strings, data, &tests->phy_alive,
+                     "phy", 0, "alive", NULL);
+       efx_fill_test(n++, strings, data, &tests->nvram,
+                     "core", 0, "nvram", NULL);
        efx_fill_test(n++, strings, data, &tests->interrupt,
                      "core", 0, "interrupt", NULL);
 
@@ -362,16 +400,29 @@ static int efx_ethtool_fill_self_tests(s
                              "eventq.poll", NULL);
        }
 
-       /* PHY presence */
-       efx_fill_test(n++, strings, data, &tests->phy_ok,
-                     EFX_PORT_NAME, "phy_ok", NULL);
+       efx_fill_test(n++, strings, data, &tests->memory,
+                     "core", 0, "memory", NULL);
+       efx_fill_test(n++, strings, data, &tests->registers,
+                     "core", 0, "registers", NULL);
+
+       if (efx->phy_op->run_tests != NULL) {
+               EFX_BUG_ON_PARANOID(efx->phy_op->test_name == NULL);
+
+               for (i = 0; true; ++i) {
+                       const char *name;
+
+                       EFX_BUG_ON_PARANOID(i >= EFX_MAX_PHY_TESTS);
+                       name = efx->phy_op->test_name(efx, i);
+                       if (name == NULL)
+                               break;
+
+                       efx_fill_test(n++, strings, data, &tests->phy_ext[i],
+                                     "phy", 0, name, NULL);
+               }
+       }
 
        /* Loopback tests */
-       efx_fill_test(n++, strings, data, &tests->loopback_speed,
-                     EFX_PORT_NAME, "loopback.speed", NULL);
-       efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
-                     EFX_PORT_NAME, "loopback.full_duplex", NULL);
-       for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+       for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
                if (!(efx->loopback_modes & (1 << mode)))
                        continue;
                n = efx_fill_loopback_test(efx,
@@ -382,22 +433,35 @@ static int efx_ethtool_fill_self_tests(s
        return n;
 }
 
+static int efx_ethtool_get_sset_count(struct net_device *net_dev,
+                                     int string_set)
+{
+       switch (string_set) {
+       case ETH_SS_STATS:
+               return EFX_ETHTOOL_NUM_STATS;
+       case ETH_SS_TEST:
+               return efx_ethtool_fill_self_tests(netdev_priv(net_dev),
+                                                  NULL, NULL, NULL);
+       default:
+               return -EINVAL;
+       }
+}
+
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_ETHTOOL_GET_SSET_COUNT)
 static int efx_ethtool_get_stats_count(struct net_device *net_dev)
 {
-       return EFX_ETHTOOL_NUM_STATS;
-}
-
+       return efx_ethtool_get_sset_count(net_dev, ETH_SS_STATS);
+}
 static int efx_ethtool_self_test_count(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
-
-       return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
-}
+       return efx_ethtool_get_sset_count(net_dev, ETH_SS_TEST);
+}
+#endif
 
 static void efx_ethtool_get_strings(struct net_device *net_dev,
                                    u32 string_set, u8 *strings)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct ethtool_string *ethtool_strings =
                (struct ethtool_string *)strings;
        int i;
@@ -423,7 +487,7 @@ static void efx_ethtool_get_stats(struct
                                  struct ethtool_stats *stats
                                  __attribute__ ((unused)), u64 *data)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_mac_stats *mac_stats = &efx->mac_stats;
        struct efx_ethtool_stat *stat;
        struct efx_channel *channel;
@@ -432,7 +496,7 @@ static void efx_ethtool_get_stats(struct
        EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
 
        /* Update MAC and NIC statistics */
-       net_dev->get_stats(net_dev);
+       dev_get_stats(net_dev);
 
        /* Fill detailed statistics buffer */
        for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
@@ -455,35 +519,53 @@ static void efx_ethtool_get_stats(struct
        }
 }
 
+static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
+{
+       struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev);
+       unsigned long features;
+
+       features = NETIF_F_TSO;
+#if !defined(EFX_USE_KCOMPAT) || defined(NETIF_F_TSO6)
+       if (efx->type->offload_features & NETIF_F_V6_CSUM)
+               features |= NETIF_F_TSO6;
+#endif
+
+       if (enable)
+               net_dev->features |= features;
+       else
+               net_dev->features &= ~features;
+
+       return 0;
+}
+
 static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
 {
-       struct efx_nic *efx = net_dev->priv;
-       int rc;
-
-       rc = ethtool_op_set_tx_csum(net_dev, enable);
-       if (rc)
-               return rc;
-
-       efx_flush_queues(efx);
+       struct efx_nic *efx = netdev_priv(net_dev);
+       unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM;
+
+       if (enable)
+               net_dev->features |= features;
+       else
+               net_dev->features &= ~features;
 
        return 0;
 }
 
 static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
        /* No way to stop the hardware doing the checks; we just
         * ignore the result.
         */
-       efx->rx_checksum_enabled = (enable ? 1 : 0);
+       efx->rx_checksum_enabled = !!enable;
 
        return 0;
 }
 
 static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
        return efx->rx_checksum_enabled;
 }
@@ -491,71 +573,48 @@ static void efx_ethtool_self_test(struct
 static void efx_ethtool_self_test(struct net_device *net_dev,
                                  struct ethtool_test *test, u64 *data)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_self_tests efx_tests;
-       int offline, already_up;
+       bool already_up;
        int rc;
 
-       /* Make sure we've got rtnl lock since we're playing with
-        * interrupts, and calling efx_process_channel_now and others
-        */
        ASSERT_RTNL();
-
-       /* If the NIC isn't in the RUNNING state then exit */
        if (efx->state != STATE_RUNNING) {
-               rc = -EIO;
-               goto fail1;
-       }
-
-       /* Make sure the interface is up. We need interrupts, NAPI
-        * and some RX buffers so this is helpful.  NB. The caller has
-        * rtnl_lock so nobody else can call dev_open. */
+               rc = -EBUSY;
+               goto out;
+       }
+
+       if (test->flags & ETH_TEST_FL_OFFLINE)
+               efx_dl_reset_suspend(efx);
+
+       /* We need rx buffers and interrupts. */
        already_up = (efx->net_dev->flags & IFF_UP);
        if (!already_up) {
                rc = dev_open(efx->net_dev);
                if (rc) {
                        EFX_ERR(efx, "failed opening device.\n");
-                       goto fail2;
+                       goto out_resume;
                }
        }
 
        memset(&efx_tests, 0, sizeof(efx_tests));
-       offline = (test->flags & ETH_TEST_FL_OFFLINE);
-
-       /* Perform online self tests first */
-       rc = efx_online_test(efx, &efx_tests);
-       if (rc)
-               goto out;
-
-       /* Perform offline tests only if online tests passed */
-       if (offline) {
-               /* Stop the kernel from sending packets during the test. The
-                * selftest will be consistently bringing the port up and down
-                * as it moves between loopback modes, so the watchdog timer
-                * probably won't run anyway */
-               efx_stop_queue(efx);
-
-               rc = efx_flush_queues(efx);
-               if (rc != 0)
-                       goto out_offline;
-
-               rc = efx_offline_test(efx, &efx_tests,
-                                     efx->loopback_modes);
- out_offline:
-               efx_wake_queue(efx);
-       }
-
-       /* fall-thru */
- out:
+
+       rc = efx_selftest(efx, &efx_tests, test->flags);
+
        if (!already_up)
                dev_close(efx->net_dev);
 
-       EFX_LOG(efx, "%s all %sline self-tests\n",
-               rc == 0 ? "passed" : "failed", offline ? "off" : "on");
-
- fail2:
- fail1:
-       /* Fill ethtool results structures */
+       EFX_LOG(efx, "%s %sline self-tests\n",
+               rc == 0 ? "passed" : "failed",
+               (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
+
+out_resume:
+       if (test->flags & ETH_TEST_FL_OFFLINE) {
+               /* Return success because if efx_reset_up() failed, an
+                * EFX_RESET_DISABLE reset will have been scheduled */
+               efx_dl_reset_resume(efx, true);
+       }
+out:
        efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data);
        if (rc)
                test->flags |= ETH_TEST_FL_FAILED;
@@ -564,24 +623,78 @@ static void efx_ethtool_self_test(struct
 /* Restart autonegotiation */
 static int efx_ethtool_nway_reset(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
-
-       return mii_nway_restart(&efx->mii);
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       return mdio45_nway_restart(&efx->mdio);
 }
 
 static u32 efx_ethtool_get_link(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
-
-       return efx->link_up;
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       return efx->link_state.up;
+}
+
+static int efx_ethtool_get_eeprom_len(struct net_device *net_dev)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_spi_device *spi = efx->spi_eeprom;
+
+       if (!spi)
+               return 0;
+       return min(spi->size, EFX_EEPROM_BOOTCONFIG_END) -
+               min(spi->size, EFX_EEPROM_BOOTCONFIG_START);
+}
+
+static int efx_ethtool_get_eeprom(struct net_device *net_dev,
+                                 struct ethtool_eeprom *eeprom, u8 *buf)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_spi_device *spi = efx->spi_eeprom;
+       size_t len;
+       int rc;
+
+       rc = mutex_lock_interruptible(&efx->spi_lock);
+       if (rc)
+               return rc;
+       rc = falcon_spi_read(efx, spi,
+                            eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
+                            eeprom->len, &len, buf);
+       mutex_unlock(&efx->spi_lock);
+
+       eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC;
+       eeprom->len = len;
+       return rc;
+}
+
+static int efx_ethtool_set_eeprom(struct net_device *net_dev,
+                                 struct ethtool_eeprom *eeprom, u8 *buf)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_spi_device *spi = efx->spi_eeprom;
+       size_t len;
+       int rc;
+
+       if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC)
+               return -EINVAL;
+
+       rc = mutex_lock_interruptible(&efx->spi_lock);
+       if (rc)
+               return rc;
+       rc = falcon_spi_write(efx, spi,
+                             eeprom->offset + EFX_EEPROM_BOOTCONFIG_START,
+                             eeprom->len, &len, buf);
+       mutex_unlock(&efx->spi_lock);
+
+       eeprom->len = len;
+       return rc;
 }
 
 static int efx_ethtool_get_coalesce(struct net_device *net_dev,
                                    struct ethtool_coalesce *coalesce)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_tx_queue *tx_queue;
-       struct efx_rx_queue *rx_queue;
        struct efx_channel *channel;
 
        memset(coalesce, 0, sizeof(*coalesce));
@@ -599,14 +712,11 @@ static int efx_ethtool_get_coalesce(stru
                }
        }
 
-       /* Find lowest IRQ moderation across all used RX queues */
-       coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
-       efx_for_each_rx_queue(rx_queue, efx) {
-               channel = rx_queue->channel;
-               if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
-                       coalesce->rx_coalesce_usecs_irq =
-                               channel->irq_moderation;
-       }
+       coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
+       coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
+
+       coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION;
+       coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION;
 
        return 0;
 }
@@ -617,13 +727,12 @@ static int efx_ethtool_set_coalesce(stru
 static int efx_ethtool_set_coalesce(struct net_device *net_dev,
                                    struct ethtool_coalesce *coalesce)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
-       unsigned tx_usecs, rx_usecs;
-
-       if (coalesce->use_adaptive_rx_coalesce ||
-           coalesce->use_adaptive_tx_coalesce)
+       unsigned tx_usecs, rx_usecs, adaptive;
+
+       if (coalesce->use_adaptive_tx_coalesce)
                return -EOPNOTSUPP;
 
        if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
@@ -634,6 +743,7 @@ static int efx_ethtool_set_coalesce(stru
 
        rx_usecs = coalesce->rx_coalesce_usecs_irq;
        tx_usecs = coalesce->tx_coalesce_usecs_irq;
+       adaptive = coalesce->use_adaptive_rx_coalesce;
 
        /* If the channel is shared only allow RX parameters to be set */
        efx_for_each_tx_queue(tx_queue, efx) {
@@ -645,14 +755,9 @@ static int efx_ethtool_set_coalesce(stru
                }
        }
 
-       efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
-
-       /* Reset channel to pick up new moderation value.  Note that
-        * this may change the value of the irq_moderation field
-        * (e.g. to allow for hardware timer granularity).
-        */
+       efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
        efx_for_each_channel(channel, efx)
-               falcon_set_int_moderation(channel);
+               efx->type->push_irq_moderation(channel);
 
        return 0;
 }
@@ -660,22 +765,69 @@ static int efx_ethtool_set_pauseparam(st
 static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
                                      struct ethtool_pauseparam *pause)
 {
-       struct efx_nic *efx = net_dev->priv;
-       enum efx_fc_type flow_control = efx->flow_control;
-       int rc;
-
-       flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
-       flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
-       flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
-       flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
-
-       /* Try to push the pause parameters */
+       struct efx_nic *efx = netdev_priv(net_dev);
+       enum efx_fc_type wanted_fc, old_fc;
+       u32 old_adv;
+       bool reset;
+       int rc = 0;
+
        mutex_lock(&efx->mac_lock);
-       rc = efx->mac_op->set_pause(efx, flow_control);
+
+       wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) |
+                    (pause->tx_pause ? EFX_FC_TX : 0) |
+                    (pause->autoneg ? EFX_FC_AUTO : 0));
+
+       if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {
+               EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n");
+               rc = -EINVAL;
+               goto out;
+       }
+
+       if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) {
+               EFX_LOG(efx, "Autonegotiation is disabled\n");
+               rc = -EINVAL;
+               goto out;
+       }
+
+       /* TX flow control may automatically turn itself off if the
+        * link partner (intermittently) stops responding to pause
+        * frames. There isn't any indication that this has happened,
+        * so the best we do is leave it up to the user to spot this
+        * and fix it be cycling transmit flow control on this end. */
+       reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX);
+       if (EFX_WORKAROUND_11482(efx) && reset) {
+               if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
+                       /* Recover by resetting the EM block */
+                       falcon_stop_nic_stats(efx);
+                       falcon_drain_tx_fifo(efx);
+                       efx->mac_op->reconfigure(efx);
+                       falcon_start_nic_stats(efx);
+               } else {
+                       /* Schedule a reset to recover */
+                       efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
+               }
+       }
+
+       old_adv = efx->link_advertising;
+       old_fc = efx->wanted_fc;
+       efx_link_set_wanted_fc(efx, wanted_fc);
+       if (efx->link_advertising != old_adv ||
+           (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) {
+               rc = efx->phy_op->reconfigure(efx);
+               if (rc) {
+                       EFX_ERR(efx, "Unable to advertise requested flow "
+                               "control setting\n");
+                       goto out;
+               }
+       }
+
+       /* Reconfigure the MAC. The PHY *may* generate a link state change event
+        * if the user just changed the advertised capabilities, but there's no
+        * harm doing this twice */
+       efx->mac_op->reconfigure(efx);
+
+out:
        mutex_unlock(&efx->mac_lock);
-
-       if (!rc)
-               efx_reconfigure_port(efx);
 
        return rc;
 }
@@ -683,31 +835,81 @@ static void efx_ethtool_get_pauseparam(s
 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
                                       struct ethtool_pauseparam *pause)
 {
-       struct efx_nic *efx = net_dev->priv;
-
-       pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
-       pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
-       pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
-}
-
-
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX);
+       pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX);
+       pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO);
+}
+
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_ETHTOOL_GET_PERM_ADDR)
 static int efx_ethtool_op_get_perm_addr(struct net_device *net_dev,
                                        struct ethtool_perm_addr *addr,
                                        u8 *data)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
        memcpy(data, efx->mac_address, ETH_ALEN);
 
        return 0;
 }
-
-struct ethtool_ops efx_ethtool_ops = {
+#endif
+
+
+static void efx_ethtool_get_wol(struct net_device *net_dev,
+                               struct ethtool_wolinfo *wol)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       return efx->type->get_wol(efx, wol);
+}
+
+
+static int efx_ethtool_set_wol(struct net_device *net_dev,
+                              struct ethtool_wolinfo *wol)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       return efx->type->set_wol(efx, wol->wolopts);
+}
+
+extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       enum reset_type method;
+       enum {
+               ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER |
+                                          ETH_RESET_OFFLOAD | ETH_RESET_MAC)
+       };
+
+       /* Check for minimal reset flags */
+       if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE)
+               return -EINVAL;
+       *flags ^= ETH_RESET_EFX_INVISIBLE;
+       method = RESET_TYPE_INVISIBLE;
+
+       if (*flags & ETH_RESET_PHY) {
+               *flags ^= ETH_RESET_PHY;
+               method = RESET_TYPE_ALL;
+       }
+
+       if ((*flags & efx->type->reset_world_flags) ==
+           efx->type->reset_world_flags) {
+               *flags ^= efx->type->reset_world_flags;
+               method = RESET_TYPE_WORLD;
+       }
+
+       return efx_reset(efx, method);
+}
+
+const struct ethtool_ops efx_ethtool_ops = {
        .get_settings           = efx_ethtool_get_settings,
        .set_settings           = efx_ethtool_set_settings,
        .get_drvinfo            = efx_ethtool_get_drvinfo,
        .nway_reset             = efx_ethtool_nway_reset,
        .get_link               = efx_ethtool_get_link,
+       .get_eeprom_len         = efx_ethtool_get_eeprom_len,
+       .get_eeprom             = efx_ethtool_get_eeprom,
+       .set_eeprom             = efx_ethtool_set_eeprom,
        .get_coalesce           = efx_ethtool_get_coalesce,
        .set_coalesce           = efx_ethtool_set_coalesce,
        .get_pauseparam         = efx_ethtool_get_pauseparam,
@@ -715,14 +917,33 @@ struct ethtool_ops efx_ethtool_ops = {
        .get_rx_csum            = efx_ethtool_get_rx_csum,
        .set_rx_csum            = efx_ethtool_set_rx_csum,
        .get_tx_csum            = ethtool_op_get_tx_csum,
+       /* Need to enable/disable IPv6 too */
        .set_tx_csum            = efx_ethtool_set_tx_csum,
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
+       .get_tso                = ethtool_op_get_tso,
+       /* Need to enable/disable TSO-IPv6 too */
+       .set_tso                = efx_ethtool_set_tso,
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_ETHTOOL_FLAGS)
+       .get_flags              = ethtool_op_get_flags,
+       .set_flags              = ethtool_op_set_flags,
+#endif
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_ETHTOOL_GET_SSET_COUNT)
+       .get_sset_count         = efx_ethtool_get_sset_count,
+#else
        .self_test_count        = efx_ethtool_self_test_count,
+       .get_stats_count        = efx_ethtool_get_stats_count,
+#endif
        .self_test              = efx_ethtool_self_test,
        .get_strings            = efx_ethtool_get_strings,
        .phys_id                = efx_ethtool_phys_id,
-       .get_stats_count        = efx_ethtool_get_stats_count,
        .get_ethtool_stats      = efx_ethtool_get_stats,
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_ETHTOOL_GET_PERM_ADDR)
        .get_perm_addr          = efx_ethtool_op_get_perm_addr,
+#endif
+       .get_wol                = efx_ethtool_get_wol,
+       .set_wol                = efx_ethtool_set_wol,
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_HAVE_ETHTOOL_RESET)
+       .reset                  = efx_ethtool_reset,
+#endif
 };
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/ethtool.h
--- a/drivers/net/sfc/ethtool.h Fri Jan 08 11:56:04 2010 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005:      Fen Systems Ltd.
- * Copyright 2006:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-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 EFX_ETHTOOL_H
-#define EFX_ETHTOOL_H
-
-#include "net_driver.h"
-
-/*
- * Ethtool support
- */
-
-extern int efx_ethtool_get_settings(struct net_device *net_dev,
-                                   struct ethtool_cmd *ecmd);
-extern int efx_ethtool_set_settings(struct net_device *net_dev,
-                                   struct ethtool_cmd *ecmd);
-
-extern struct ethtool_ops efx_ethtool_ops;
-
-#endif /* EFX_ETHTOOL_H */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/extraversion.h
--- a/drivers/net/sfc/extraversion.h    Fri Jan 08 11:56:04 2010 +0000
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-/*
- * If compiling on kernels with backported features you may need to
- * define EFX_DIST_KVER_ symbols here
- */
diff -r 896902106793 -r 0b5ca7cdbdfc drivers/net/sfc/falcon.c
--- a/drivers/net/sfc/falcon.c  Fri Jan 08 11:56:04 2010 +0000
+++ b/drivers/net/sfc/falcon.c  Fri Jan 08 13:05:49 2010 +0000
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@xxxxxxxxxxxxxxxx>
- * Maintained by Solarflare Communications <linux-net-drivers@xxxxxxxxxxxxxx>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2009 Solarflare Communications Inc.
  *
  * 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/bitops.h>
@@ -30,63 +13,22 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/i2c.h>
+#include <linux/mii.h>
 #include "net_driver.h"
 #include "bitfield.h"
 #include "efx.h"
 #include "mac.h"
-#include "gmii.h"
 #include "spi.h"
-#include "falcon.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
+#include "nic.h"
+#include "regs.h"
+#include "io.h"
 #include "mdio_10g.h"
 #include "phy.h"
-#include "boards.h"
 #include "driverlink.h"
 #include "workarounds.h"
 
-/* Falcon hardware control.
- * Falcon is the internal codename for the SFC4000 controller that is
- * present in SFE400X evaluation boards
- */
-
-/**
- * struct falcon_nic_data - Falcon NIC state
- * @tx_dc_entries: Number of entries in each TX queue descriptor cache
- * @rx_dc_entries: Number of entries in each RX queue descriptor cache
- * @tx_dc_base: Base address in SRAM of TX queue descriptor caches
- * @rx_dc_base: Base address in SRAM of RX queue descriptor caches
- * @old_loopback_mode: Previous loopback mode used in deconfigure_mac_wrapper
- * @external_sram_cfg: Size and number of banks of external SRAM
- * @pci_dev2: The secondary PCI device if present
- * @resources: Driverlink parameters
- */
-struct falcon_nic_data {
-       unsigned tx_dc_entries;
-       unsigned rx_dc_entries;
-       unsigned tx_dc_base;
-       unsigned rx_dc_base;
-
-       enum efx_loopback_mode old_loopback_mode;
-
-       struct pci_dev *pci_dev2;
-
-       int external_sram_cfg;
-
-       struct efx_dl_falcon_resources resources;
-};
-
-/**************************************************************************
- *
- * Configurable values
- *
- **************************************************************************
- */
-
-static int disable_dma_stats;
-
-/* Specify the size of the RX descriptor cache */
-static int descriptor_cache_size = 64;
+/* Hardware control for SFC4000 (aka Falcon). */
 
 /*
  * Override EEPROM/flash type from non-volatile configuration or GPIO;
@@ -95,152 +37,64 @@ static unsigned int eeprom_type = -1;
 static unsigned int eeprom_type = -1;
 static unsigned int flash_type = -1;
 
-/* RX FIFO XOFF watermark
- *
- * When the amount of the RX FIFO increases used increases past this
- * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
- * This also has an effect on RX/TX arbitration
- */
-static int rx_xoff_thresh_bytes = -1;
-module_param(rx_xoff_thresh_bytes, int, 0644);
-MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
-
-/* RX FIFO XON watermark
- *
- * When the amount of the RX FIFO used decreases below this
- * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
- * This also has an effect on RX/TX arbitration
- */
-static int rx_xon_thresh_bytes = -1;
-module_param(rx_xon_thresh_bytes, int, 0644);
-MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
-
-/* TX descriptor ring size - min 512 max 4k */
-#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K
-#define FALCON_TXD_RING_SIZE 1024
-#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1)
-
-/* RX descriptor ring size - min 512 max 4k */
-#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K
-#define FALCON_RXD_RING_SIZE 1024
-#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1)
-
-/* Event queue size - max 32k */
-#define FALCON_EVQ_ORDER EVQ_SIZE_4K
-#define FALCON_EVQ_SIZE 4096
-#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
-
-/* Max number of internal errors. After this resets will not be performed */
-#define FALCON_MAX_INT_ERRORS 4
-
-/* Maximum period that we wait for flush events. If the flush event
- * doesn't arrive in this period of time then we check if the queue
- * was disabled anyway. */
-#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */
-
-/**************************************************************************
- *
- * Falcon constants
- *
- **************************************************************************
- */
-
-/* DMA address mask (up to 46-bit, avoiding compiler warnings)
- *
- * Note that it is possible to have a platform with 64-bit longs and
- * 32-bit DMA addresses, or vice versa.  EFX_DMA_MASK takes care of the
- * platform DMA mask.
- */
-#if BITS_PER_LONG == 64
-#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL)
-#else
-#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL)
-#endif
-
-/* TX DMA length mask (13-bit) */
-#define FALCON_TX_DMA_MASK (4096 - 1)
-
-/* Size and alignment of special buffers (4KB) */
-#define FALCON_BUF_SIZE 4096
-
-/* Dummy SRAM size code */
-#define SRM_NB_BSZ_ONCHIP_ONLY (-1)
-
-/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
-#define PCI_EXP_DEVCAP_PWR_VAL_LBN     18
-#define PCI_EXP_DEVCAP_PWR_SCL_LBN     26
-#define PCI_EXP_DEVCTL_PAYLOAD_LBN     5
-#define PCI_EXP_LNKSTA_LNK_WID         0x3f0
-#define PCI_EXP_LNKSTA_LNK_WID_LBN     4
-
-#define FALCON_IS_DUAL_FUNC(efx)               \
-       (FALCON_REV(efx) < FALCON_REV_B0)
-
-/**************************************************************************
- *
- * Falcon hardware access
- *
- **************************************************************************/
-
-/* Read the current event from the event queue */
-static inline efx_qword_t *falcon_event(struct efx_channel *channel,
-                                       unsigned int index)
-{
-       return (((efx_qword_t *) (channel->eventq.addr)) + index);
-}
-
-/* See if an event is present
- *
- * We check both the high and low dword of the event for all ones.  We
- * wrote all ones when we cleared the event, and no valid event can
- * have all ones in either its high or low dwords.  This approach is
- * robust against reordering.
- *
- * Note that using a single 64-bit comparison is incorrect; even
- * though the CPU read will be atomic, the DMA write may not be.
- */
-static inline int falcon_event_present(efx_qword_t *event)
-{
-       return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
-                 EFX_DWORD_IS_ALL_ONES(event->dword[1])));
-}
+static const unsigned int
+/* "Small" EEPROM device: Atmel AT25040 or similar
+ * 512 B, 9-bit address, 8 B write block */
+small_eeprom_type = ((9 << SPI_DEV_TYPE_SIZE_LBN)
+                    | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+                    | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)),
+/* "Large" EEPROM device: Atmel AT25640 or similar
+ * 8 KB, 16-bit address, 32 B write block */
+large_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN)
+                    | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+                    | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)),
+/* Default flash device: Atmel AT25F1024
+ * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */
+default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN)
+                     | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
+                     | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
+                     | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
+                     | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN));
+
+/* Dummy SRAM configuration code */
+#define SRAM_CONFIG_INTERNAL (-1)
 
 /* Read dword from a Falcon PCIE core register */
-static void falcon_pcie_core_read_reg(struct efx_nic *efx, int address,
+static void falcon_b0_pcie_core_read_reg(struct efx_nic *efx, int address,
                                      efx_dword_t *result)
 {
        efx_oword_t temp;
 
-       BUG_ON(FALCON_REV(efx) < FALCON_REV_B0);
+       BUG_ON(efx_nic_rev(efx) != EFX_REV_FALCON_B0);
        BUG_ON(address & 3 || address < 0);
 
-       EFX_POPULATE_OWORD_1(temp, PCIE_CORE_ADDR, address);
-
-       falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG);
-       falcon_read(efx, &temp, PCIE_CORE_INDIRECT_REG);
+       EFX_POPULATE_OWORD_1(temp, FRF_BB_PCIE_CORE_TARGET_REG_ADRS, address);
+
+       efx_writeo(efx, &temp, FR_BB_PCIE_CORE_INDIRECT);
+       efx_reado(efx, &temp, FR_BB_PCIE_CORE_INDIRECT);
        /* Extract PCIE_CORE_VALUE without byte-swapping */
-       BUILD_BUG_ON(PCIE_CORE_VALUE_LBN != 32 ||
-                    PCIE_CORE_VALUE_WIDTH != 32);
+       BUILD_BUG_ON(FRF_BB_PCIE_CORE_TARGET_DATA_LBN != 32 ||
+                    FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH != 32);
        result->u32[0] = temp.u32[1];
 }
 
 /* Write dword to a Falcon PCIE core register */
-static void falcon_pcie_core_write_reg(struct efx_nic *efx, int address,
+static void falcon_b0_pcie_core_write_reg(struct efx_nic *efx, int address,
                                       efx_dword_t value)
 {
        efx_oword_t temp;
 
-       BUG_ON(FALCON_REV(efx) < FALCON_REV_B0);
+       BUG_ON(efx_nic_rev(efx) != EFX_REV_FALCON_B0);
        BUG_ON(address & 0x3 || address < 0);
 
        EFX_POPULATE_OWORD_2(temp,
-                            PCIE_CORE_ADDR, address,
-                            PCIE_CORE_RW, 1);
+                            FRF_BB_PCIE_CORE_TARGET_REG_ADRS, address,
+                            FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR, 1);
        /* Fill PCIE_CORE_VALUE without byte-swapping */
-       BUILD_BUG_ON(PCIE_CORE_VALUE_LBN != 32 ||
-                    PCIE_CORE_VALUE_WIDTH != 32);
+       BUILD_BUG_ON(FRF_BB_PCIE_CORE_TARGET_DATA_LBN != 32 ||
+                    FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH != 32);
        temp.u32[1] = value.u32[0];
-       falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG);
+       efx_writeo(efx, &temp, FR_BB_PCIE_CORE_INDIRECT);
 }
 
 /**************************************************************************
@@ -251,1257 +105,87 @@ static void falcon_pcie_core_write_reg(s
  *
  **************************************************************************
  */
-static void falcon_setsdascl(struct efx_i2c_interface *i2c)
-{
+static void falcon_setsda(void *data, int state)
+{
+       struct efx_nic *efx = (struct efx_nic *)data;
        efx_oword_t reg;
 
-       falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
-       EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
-       EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
-       falcon_write(i2c->efx, &reg, GPIO_CTL_REG_KER);
-}
-
-static int falcon_getsda(struct efx_i2c_interface *i2c)
-{
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN, !state);
+       efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
+}
+
+static void falcon_setscl(void *data, int state)
+{
+       struct efx_nic *efx = (struct efx_nic *)data;
        efx_oword_t reg;
 
-       falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
-       return EFX_OWORD_FIELD(reg, GPIO3_IN);
-}
-
-static int falcon_getscl(struct efx_i2c_interface *i2c)
-{
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO0_OEN, !state);
+       efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
+}
+
+static int falcon_getsda(void *data)
+{
+       struct efx_nic *efx = (struct efx_nic *)data;
        efx_oword_t reg;
 
-       falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
-       return EFX_DWORD_FIELD(reg, GPIO0_IN);
-}
-
-static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
-       .setsda         = falcon_setsdascl,
-       .setscl         = falcon_setsdascl,
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       return EFX_OWORD_FIELD(reg, FRF_AB_GPIO3_IN);
+}
+
+static int falcon_getscl(void *data)
+{
+       struct efx_nic *efx = (struct efx_nic *)data;
+       efx_oword_t reg;
+
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN);
+}
+
+static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
+       .setsda         = falcon_setsda,
+       .setscl         = falcon_setscl,
        .getsda         = falcon_getsda,
        .getscl         = falcon_getscl,
-       .udelay         = 100,
-       .mdelay         = 10,
+       .udelay         = 5,
+       /* Wait up to 50 ms for slave to let us pull SCL high */
+       .timeout        = DIV_ROUND_UP(HZ, 20),
 };
 
-/**************************************************************************
- *
- * Falcon special buffer handling
- * Special buffers are used for event queues and the TX and RX
- * descriptor rings.
- *
- *************************************************************************/
-
-/*
- * Initialise a Falcon special buffer
- *
- * This will define a buffer (previously allocated via
- * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
- * it to be used for event queues, descriptor rings etc.
- */
-static int
-falcon_init_special_buffer(struct efx_nic *efx,
-                          struct efx_special_buffer *buffer)
-{
-       efx_qword_t buf_desc;
-       int index;
-       dma_addr_t dma_addr;
-       int i;
-
-       EFX_BUG_ON_PARANOID(!buffer->addr);
-
-       /* Write buffer descriptors to NIC */
-       for (i = 0; i < buffer->entries; i++) {
-               index = buffer->index + i;
-               dma_addr = buffer->dma_addr + (i * 4096);
-               EFX_LOG(efx, "mapping special buffer %d at %llx\n",
-                       index, (unsigned long long)dma_addr);
-               EFX_POPULATE_QWORD_4(buf_desc,
-                                    IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K,
-                                    BUF_ADR_REGION, 0,
-                                    BUF_ADR_FBUF, (dma_addr >> 12),
-                                    BUF_OWNER_ID_FBUF, 0);
-               falcon_write_sram(efx, &buf_desc, index);
-       }
-
-       return 0;
-}
-
-/* Unmaps a buffer from Falcon and clears the buffer table entries */
-static void
-falcon_fini_special_buffer(struct efx_nic *efx,
-                          struct efx_special_buffer *buffer)
-{
-       efx_oword_t buf_tbl_upd;
-       unsigned int start = buffer->index;
-       unsigned int end = (buffer->index + buffer->entries - 1);
-
-       if (!buffer->entries)
-               return;
-
-       EFX_LOG(efx, "unmapping special buffers %d-%d\n",
-               buffer->index, buffer->index + buffer->entries - 1);
-
-       EFX_POPULATE_OWORD_4(buf_tbl_upd,
-                            BUF_UPD_CMD, 0,
-                            BUF_CLR_CMD, 1,
-                            BUF_CLR_END_ID, end,
-                            BUF_CLR_START_ID, start);
-       falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER);
-}
-
-/*
- * Allocate a new Falcon special buffer
- *
- * This allocates memory for a new buffer, clears it and allocates a
- * new buffer ID range.  It does not write into Falcon's buffer table.
- *
- * This call will allocate 4KB buffers, since Falcon can't use 8KB
- * buffers for event queues and descriptor rings.
- */
-static int falcon_alloc_special_buffer(struct efx_nic *efx,
-                                      struct efx_special_buffer *buffer,
-                                      unsigned int len)
-{
-       struct falcon_nic_data *nic_data = efx->nic_data;
-
-       len = ALIGN(len, FALCON_BUF_SIZE);
-
-       /* Allocate buffer as consistent PCI DMA space */
-       buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
-                                           &buffer->dma_addr);
-       if (!buffer->addr)
-               return -ENOMEM;
-       buffer->len = len;
-       buffer->entries = len / FALCON_BUF_SIZE;
-       BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1));
-
-       /* All zeros is a potentially valid event so memset to 0xff */
-       memset(buffer->addr, 0xff, len);
-
-       /* Select new buffer ID */
-       buffer->index = nic_data->resources.buffer_table_min;
-       nic_data->resources.buffer_table_min += buffer->entries;
-
-       EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
-               "(virt %p phys %lx)\n", buffer->index,
-               buffer->index + buffer->entries - 1,
-               (unsigned long long)buffer->dma_addr, len,
-               buffer->addr, virt_to_phys(buffer->addr));
-
-       return 0;
-}
-
-/* Release the buffer memory. */
-static void falcon_free_special_buffer(struct efx_nic *efx,
-                                      struct efx_special_buffer *buffer)
-{
-       if (!buffer->addr)
-               return;
-
-       EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
-               "(virt %p phys %lx)\n", buffer->index,
-               buffer->index + buffer->entries - 1,
-               (unsigned long long)buffer->dma_addr, buffer->len,
-               buffer->addr, virt_to_phys(buffer->addr));
-
-       pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
-                           buffer->dma_addr);
-       buffer->addr = NULL;
-       buffer->entries = 0;
-}
-
-/**************************************************************************
- *
- * Falcon generic buffer handling
- * These buffers are used for interrupt status and MAC stats
- *
- **************************************************************************/
-
-static int falcon_alloc_buffer(struct efx_nic *efx,
-                              struct efx_buffer *buffer, unsigned int len)
-{
-       buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
-                                           &buffer->dma_addr);
-       if (!buffer->addr)
-               return -ENOMEM;
-       buffer->len = len;
-       memset(buffer->addr, 0, len);
-       return 0;
-}
-
-static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
-{
-       if (buffer->addr) {
-               pci_free_consistent(efx->pci_dev, buffer->len,
-                                   buffer->addr, buffer->dma_addr);
-               buffer->addr = NULL;
-       }
-}
-
-/**************************************************************************
- *
- * Falcon TX path
- *
- **************************************************************************/
-
-/* Returns a pointer to the specified transmit descriptor in the TX
- * descriptor queue belonging to the specified channel.
- */
-static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue,
-                                              unsigned int index)
-{
-       return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
-}
-
-/* Update TX descriptor write pointer
- * This writes to the TX_DESC_WPTR register for the specified
- * channel's transmit descriptor ring.
- */
-static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
-{
-       unsigned write_ptr;
-       efx_dword_t reg;
-
-       write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
-       EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr);
-       falcon_writel_page(tx_queue->efx, &reg,
-                          TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue);
-}
-
-
-/* For each entry inserted into the software descriptor ring, create a
- * descriptor in the hardware TX descriptor ring (in host memory), and
- * write a doorbell.
- */
-void fastcall falcon_push_buffers(struct efx_tx_queue *tx_queue)
-{
-
-       struct efx_tx_buffer *buffer;
-       efx_qword_t *txd;
-       unsigned write_ptr;
-
-       BUG_ON(tx_queue->write_count == tx_queue->insert_count);
-
-       do {
-               write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
-               buffer = &tx_queue->buffer[write_ptr];
-               txd = falcon_tx_desc(tx_queue, write_ptr);
-               ++tx_queue->write_count;
-
-               /* Create TX descriptor ring entry */
-               EFX_POPULATE_QWORD_5(*txd,
-                                    TX_KER_PORT, 0,
-                                    TX_KER_CONT, buffer->continuation,
-                                    TX_KER_BYTE_CNT, buffer->len,
-                                    TX_KER_BUF_REGION, 0,
-                                    TX_KER_BUF_ADR, buffer->dma_addr);
-       } while (tx_queue->write_count != tx_queue->insert_count);
-
-       wmb(); /* Ensure descriptors are written before they are fetched */
-       falcon_notify_tx_desc(tx_queue);
-}
-
-/* Allocate hardware resources for a TX queue */
-int falcon_probe_tx(struct efx_tx_queue *tx_queue)
-{
-       struct efx_nic *efx = tx_queue->efx;
-       struct falcon_nic_data *nic_data = efx->nic_data;
-       int rc;
-
-       rc = falcon_alloc_special_buffer(efx, &tx_queue->txd,
-                                        FALCON_TXD_RING_SIZE *
-                                        sizeof(efx_qword_t));
-       if (rc)
-               return rc;
-
-       nic_data->resources.txq_min = max(nic_data->resources.txq_min,
-                                         (unsigned)tx_queue->queue + 1);
-
-       return 0;
-}
-
-/* Prepare channel's TX datapath. */
-int falcon_init_tx(struct efx_tx_queue *tx_queue)
-{
-       efx_oword_t tx_desc_ptr;
-       struct efx_nic *efx = tx_queue->efx;
-       int rc;
-
-       /* Pin TX descriptor ring */
-       rc = falcon_init_special_buffer(efx, &tx_queue->txd);
-       if (rc)
-               return rc;
-
-       /* Push TX descriptor ring to card */
-       EFX_POPULATE_OWORD_10(tx_desc_ptr,
-                             TX_DESCQ_EN, 1,
-                             TX_ISCSI_DDIG_EN, 0,
-                             TX_ISCSI_HDIG_EN, 0,
-                             TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
-                             TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum,
-                             TX_DESCQ_OWNER_ID, 0,
-                             TX_DESCQ_LABEL, tx_queue->queue,
-                             TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
-                             TX_DESCQ_TYPE, 0, /* kernel queue */
-                             TX_NON_IP_DROP_DIS_B0, 1);
-
-       if (FALCON_REV(efx) >= FALCON_REV_B0) {
-               int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
-               EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
-               EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
-       }
-
-       falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
-                          tx_queue->queue);
-
-       if (FALCON_REV(efx) < FALCON_REV_B0) {
-               efx_oword_t reg;
-
-               /* Only 128 bits in this register */
-               BUG_ON(tx_queue->queue >= 128);
-
-               falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
-               if (efx->net_dev->features & NETIF_F_IP_CSUM)
-                       clear_bit_le(tx_queue->queue, (void *)&reg);
-               else
-                       set_bit_le(tx_queue->queue, (void *)&reg);
-               falcon_write(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
-       }
-
-       return 0;
-}
-
-static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
-{
-       struct efx_nic *efx = tx_queue->efx;
-       struct efx_channel *channel = &efx->channel[0];
-       efx_oword_t tx_flush_descq;
-       unsigned int read_ptr, i;
-
-       /* Post a flush command */
-       EFX_POPULATE_OWORD_2(tx_flush_descq,
-                            TX_FLUSH_DESCQ_CMD, 1,
-                            TX_FLUSH_DESCQ, tx_queue->queue);
-       falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
-       msleep(FALCON_FLUSH_TIMEOUT);
-
-       if (EFX_WORKAROUND_7803(efx))
-               return 0;
-
-       /* Look for a flush completed event */
-       read_ptr = channel->eventq_read_ptr;
-       for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
-               efx_qword_t *event = falcon_event(channel, read_ptr);
-               int ev_code, ev_sub_code, ev_queue;
-               if (!falcon_event_present(event))
-                       break;
-
-               ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
-               ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-               ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID);
-               if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) &&
-                   (ev_queue == tx_queue->queue)) {
-                       EFX_LOG(efx, "tx queue %d flush command succesful\n",
-                               tx_queue->queue);
-                       return 0;
-               }
-
-               read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-       }
-
-       if (EFX_WORKAROUND_11557(efx)) {
-               efx_oword_t reg;
-               int enabled;
-
-               falcon_read_table(efx, &reg, efx->type->txd_ptr_tbl_base,
-                                 tx_queue->queue);
-               enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN);
-               if (!enabled) {
-                       EFX_LOG(efx, "tx queue %d disabled without a "
-                               "flush event seen\n", tx_queue->queue);
-                       return 0;
-               }
-       }
-
-       EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
-       return -ETIMEDOUT;
-}
-
-void falcon_fini_tx(struct efx_tx_queue *tx_queue)
-{
-       struct efx_nic *efx = tx_queue->efx;
-       efx_oword_t tx_desc_ptr;
-
-       /* Stop the hardware using the queue */
-       if (falcon_flush_tx_queue(tx_queue))
-               EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue);
-
-       /* Remove TX descriptor ring from card */
-       EFX_ZERO_OWORD(tx_desc_ptr);
-       falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
-                          tx_queue->queue);
-
-       /* Unpin TX descriptor ring */
-       falcon_fini_special_buffer(efx, &tx_queue->txd);
-}
-
-/* Free buffers backing TX queue */
-void falcon_remove_tx(struct efx_tx_queue *tx_queue)
-{
-       falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd);
-}
-
-/**************************************************************************
- *
- * Falcon RX path
- *
- **************************************************************************/
-
-/* Returns a pointer to the specified transmit descriptor in the RX
- * descriptor queue.
- */
-static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue,
-                                              unsigned int index)
-{
-       return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
-}
-
-/* This creates an entry in the RX descriptor queue corresponding to
- * the receive buffer.
- */
-static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
-                                       unsigned index)
-{
-       struct efx_rx_buffer *rx_buf;
-       efx_qword_t *rxd;
-
-       rxd = falcon_rx_desc(rx_queue, index);
-       rx_buf = efx_rx_buffer(rx_queue, index);
-       EFX_POPULATE_QWORD_3(*rxd,
-                            RX_KER_BUF_SIZE,
-                            rx_buf->len -
-                            rx_queue->efx->type->rx_buffer_padding,
-                            RX_KER_BUF_REGION, 0,
-                            RX_KER_BUF_ADR, rx_buf->dma_addr);
-}
-
-/* This writes to the RX_DESC_WPTR register for the specified receive
- * descriptor ring.
- */
-void fastcall falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
-{
-       efx_dword_t reg;
-       unsigned write_ptr;
-
-       while (rx_queue->notified_count != rx_queue->added_count) {
-               falcon_build_rx_desc(rx_queue,
-                                    rx_queue->notified_count &
-                                    FALCON_RXD_RING_MASK);
-               ++rx_queue->notified_count;
-       }
-
-       wmb();
-       write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK;
-       EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr);
-       falcon_writel_page(rx_queue->efx, &reg,
-                          RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue);
-}
-
-int falcon_probe_rx(struct efx_rx_queue *rx_queue)
-{
-       struct efx_nic *efx = rx_queue->efx;
-       struct falcon_nic_data *nic_data = efx->nic_data;
-       int rc;
-
-       rc = falcon_alloc_special_buffer(efx, &rx_queue->rxd,
-                                        FALCON_RXD_RING_SIZE *
-                                        sizeof(efx_qword_t));
-       if (rc)
-               return rc;
-
-       /* Increment the rxq_min counter */
-       nic_data->resources.rxq_min = max(nic_data->resources.rxq_min,
-                                         (unsigned)rx_queue->queue + 1);
-
-       return 0;
-}
-
-int falcon_init_rx(struct efx_rx_queue *rx_queue)
-{
-       efx_oword_t rx_desc_ptr;
-       struct efx_nic *efx = rx_queue->efx;
-       int rc;
-       int is_b0 = FALCON_REV(efx) >= FALCON_REV_B0;
-       int iscsi_digest_en = is_b0;
-
-       EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
-               rx_queue->queue, rx_queue->rxd.index,
-               rx_queue->rxd.index + rx_queue->rxd.entries - 1);
-
-       /* Pin RX descriptor ring */
-       rc = falcon_init_special_buffer(efx, &rx_queue->rxd);
-       if (rc)
-               return rc;
-
-       /* Push RX descriptor ring to card */
-       EFX_POPULATE_OWORD_10(rx_desc_ptr,
-                             RX_ISCSI_DDIG_EN, iscsi_digest_en,
-                             RX_ISCSI_HDIG_EN, iscsi_digest_en,
-                             RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
-                             RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum,
-                             RX_DESCQ_OWNER_ID, 0,
-                             RX_DESCQ_LABEL, rx_queue->queue,
-                             RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
-                             RX_DESCQ_TYPE, 0 /* kernel queue */ ,
-                             /* For >=B0 this is scatter so disable */
-                             RX_DESCQ_JUMBO, !is_b0,
-                             RX_DESCQ_EN, 1);
-       falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
-                          rx_queue->queue);
-       return 0;
-}
-
-static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
-{
-       struct efx_nic *efx = rx_queue->efx;
-       struct efx_channel *channel = &efx->channel[0];
-       unsigned int read_ptr, i;
-       efx_oword_t rx_flush_descq;
-
-       /* Post a flush command */
-       EFX_POPULATE_OWORD_2(rx_flush_descq,
-                            RX_FLUSH_DESCQ_CMD, 1,
-                            RX_FLUSH_DESCQ, rx_queue->queue);
-
-       falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
-       msleep(FALCON_FLUSH_TIMEOUT);
-
-       if (EFX_WORKAROUND_7803(efx))
-               return 0;
-
-       /* Look for a flush completed event */
-       read_ptr = channel->eventq_read_ptr;
-       for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
-               efx_qword_t *event = falcon_event(channel, read_ptr);
-               int ev_code, ev_sub_code, ev_queue, ev_failed;
-               if (!falcon_event_present(event))
-                       break;
-
-               ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
-               ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-               ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID);
-               ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL);
-
-               if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) &&
-                   (ev_queue == rx_queue->queue)) {
-                       if (ev_failed) {
-                               EFX_INFO(efx, "rx queue %d flush command "
-                                        "failed\n", rx_queue->queue);
-                               return -EAGAIN;
-                       } else {
-                               EFX_LOG(efx, "rx queue %d flush command "
-                                       "succesful\n", rx_queue->queue);
-                               return 0;
-                       }
-               }
-
-               read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-       }
-
-       if (EFX_WORKAROUND_11557(efx)) {
-               efx_oword_t reg;
-               int enabled;
-
-               falcon_read_table(efx, &reg, efx->type->rxd_ptr_tbl_base,
-                                 rx_queue->queue);
-               enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN);
-               if (!enabled) {
-                       EFX_LOG(efx, "rx queue %d disabled without a "
-                               "flush event seen\n", rx_queue->queue);
-                       return 0;
-               }
-       }
-
-       EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue);
-       return -ETIMEDOUT;
-}
-
-void falcon_fini_rx(struct efx_rx_queue *rx_queue)
-{
-       efx_oword_t rx_desc_ptr;
-       struct efx_nic *efx = rx_queue->efx;
-       int i, rc;
-
-       /* Try and flush the rx queue. This may need to be repeated */
-       for (i = 0; i < 5; i++) {
-               rc = falcon_flush_rx_queue(rx_queue);
-               if (rc == -EAGAIN)
-                       continue;
-               break;
-       }
-       if (rc) {
-               EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
-               efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
-       }
-
-       /* Remove RX descriptor ring from card */
-       EFX_ZERO_OWORD(rx_desc_ptr);
-       falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
-                          rx_queue->queue);
-
-       /* Unpin RX descriptor ring */
-       falcon_fini_special_buffer(efx, &rx_queue->rxd);
-}
-
-/* Free buffers backing RX queue */
-void falcon_remove_rx(struct efx_rx_queue *rx_queue)
-{
-       falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
-}
-
-/**************************************************************************
- *
- * Falcon event queue processing
- * Event queues are processed by per-channel tasklets.
- *
- **************************************************************************/
-
-/* Update a channel's event queue's read pointer (RPTR) register
- *
- * This writes the EVQ_RPTR_REG register for the specified channel's
- * event queue.
- *
- * Note that EVQ_RPTR_REG contains the index of the "last read" event,
- * whereas channel->eventq_read_ptr contains the index of the "next to
- * read" event.
- */
-void fastcall falcon_eventq_read_ack(struct efx_channel *channel)
-{
-       efx_dword_t reg;
-       struct efx_nic *efx = channel->efx;
-
-       EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
-       falcon_writel_table(efx, &reg, efx->type->evq_rptr_tbl_base,
-                           channel->evqnum);
-}
-
-/* Use HW to insert a SW defined event */
-void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
-{
-       efx_oword_t drv_ev_reg;
-
-       EFX_POPULATE_OWORD_2(drv_ev_reg,
-                            DRV_EV_QID, channel->evqnum,
-                            DRV_EV_DATA,
-                            EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
-       falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
-}
-
-/* Handle a transmit completion event
- *
- * Falcon batches TX completion events; the message we receive is of
- * the form "complete all TX events up to this index".
- */
-static inline void falcon_handle_tx_event(struct efx_channel *channel,
-                                         efx_qword_t *event)
-{
-       unsigned int tx_ev_desc_ptr;
-       unsigned int tx_ev_q_label;
-       struct efx_tx_queue *tx_queue;
-       struct efx_nic *efx = channel->efx;
-
-       if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) {
-               /* Transmit completion */
-               tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
-               tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
-               tx_queue = &efx->tx_queue[tx_ev_q_label];
-               efx_xmit_done(tx_queue, tx_ev_desc_ptr);
-       } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
-               /* Rewrite the FIFO write pointer */
-               tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
-               tx_queue = &efx->tx_queue[tx_ev_q_label];
-
-               if (NET_DEV_REGISTERED(efx))
-                       netif_tx_lock(efx->net_dev);
-               falcon_notify_tx_desc(tx_queue);
-               if (NET_DEV_REGISTERED(efx))
-                       netif_tx_unlock(efx->net_dev);
-       } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
-                  EFX_WORKAROUND_10727(efx)) {
-               efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
-       } else {
-               EFX_ERR(efx, "channel %d unexpected TX event "
-                       EFX_QWORD_FMT"\n", channel->channel,
-                       EFX_QWORD_VAL(*event));
-       }
-}
-
-/* Check received packet's destination MAC address. */
-static int check_dest_mac(struct efx_rx_queue *rx_queue,
-                         const efx_qword_t *event)
-{
-       struct efx_rx_buffer *rx_buf;
-       struct efx_nic *efx = rx_queue->efx;
-       int rx_ev_desc_ptr;
-       struct ethhdr *eh;
-
-       if (efx->promiscuous)
-               return 1;
-
-       rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
-       rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
-       eh = (struct ethhdr *)rx_buf->data;
-       if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
-               return 0;
-       return 1;
-}
-
-/* Detect errors included in the rx_evt_pkt_ok bit. */
-static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
-                                   const efx_qword_t *event,
-                                   unsigned *rx_ev_pkt_ok,
-                                   int *discard, int byte_count)
-{
-       struct efx_nic *efx = rx_queue->efx;
-       unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
-       unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
-       unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
-       unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
-       unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
-       int snap, non_ip;
-
-       rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
-       rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
-       rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC);
-       rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE);
-       rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
-                                                RX_EV_BUF_OWNER_ID_ERR);
-       rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR);
-       rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
-                                                 RX_EV_IP_HDR_CHKSUM_ERR);
-       rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
-                                                  RX_EV_TCP_UDP_CHKSUM_ERR);
-       rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
-       rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
-       rx_ev_drib_nib = ((FALCON_REV(efx) >= FALCON_REV_B0) ?
-                         0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
-       rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
-
-       /* Every error apart from tobe_disc and pause_frm */
-       rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
-                          rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
-                          rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
-
-       snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
-               (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
-       non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
-
-       /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
-        * length field of an LLC frame, which sets TOBE_DISC. We could set
-        * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
-        * protect the RX block).
-        *
-        * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
-        * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
-        *                       LLC can't encapsulate IP, so by definition
-        *                       these packets are NON_IP.
-        *
-        * Unicast mismatch will also cause TOBE_DISC, so the driver needs
-        * to check this.
-        */
-       if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
-               /* If all the other flags are zero then we can state the
-                * entire packet is ok, which will flag to the kernel not
-                * to recalculate checksums.
-                */
-               if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
-                       *rx_ev_pkt_ok = 1;
-
-               rx_ev_tobe_disc = 0;
-
-               /* TOBE_DISC is set for unicast mismatch.  But given that
-                * we can't trust TOBE_DISC here, we must validate the dest
-                * MAC address ourselves.
-                */
-               if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
-                       rx_ev_tobe_disc = 1;
-       }
-
-       /* Count errors that are not in MAC stats. */
-       if (rx_ev_frm_trunc)
-               ++rx_queue->channel->n_rx_frm_trunc;
-       else if (rx_ev_tobe_disc)
-               ++rx_queue->channel->n_rx_tobe_disc;
-       else if (rx_ev_ip_hdr_chksum_err)
-               ++rx_queue->channel->n_rx_ip_hdr_chksum_err;
-       else if (rx_ev_tcp_udp_chksum_err)
-               ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
-       if (rx_ev_ip_frag_err)
-               ++rx_queue->channel->n_rx_ip_frag_err;
-
-       /* The frame must be discarded if any of these are true. */
-       *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
-                   rx_ev_tobe_disc | rx_ev_pause_frm);
-
-       /* TOBE_DISC is expected on unicast mismatches; don't print out an
-        * error message.  FRM_TRUNC indicates RXDP dropped the packet due
-        * to a FIFO overflow.
-        */
-#ifdef EFX_ENABLE_DEBUG
-       if (rx_ev_other_err) {
-               EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
-                           EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
-                           rx_queue->queue, EFX_QWORD_VAL(*event),
-                           rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
-                           rx_ev_ip_hdr_chksum_err ?
-                           " [IP_HDR_CHKSUM_ERR]" : "",
-                           rx_ev_tcp_udp_chksum_err ?
-                           " [TCP_UDP_CHKSUM_ERR]" : "",
-                           rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
-                           rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
-                           rx_ev_drib_nib ? " [DRIB_NIB]" : "",
-                           rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
-                           rx_ev_pause_frm ? " [PAUSE]" : "",
-                           snap ? " [SNAP/LLC]" : "");
-       }
-#endif
-
-       if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) &&
-                    efx->phy_type == PHY_TYPE_10XPRESS))
-               tenxpress_crc_err(efx);
-}
-
-
-/* Handle receive events that are not in-order. */
-static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
-                                      unsigned index)
-{
-       struct efx_nic *efx = rx_queue->efx;
-       unsigned expected, dropped;
-
-       expected = rx_queue->removed_count & FALCON_RXD_RING_MASK;
-       dropped = ((index + FALCON_RXD_RING_SIZE - expected) &
-                  FALCON_RXD_RING_MASK);
-       EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
-               dropped, index, expected);
-
-       atomic_inc(&efx->errors.missing_event);
-       efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
-                          RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
-}
-
-
-/* Handle a packet received event
- *
- * Falcon silicon gives a "discard" flag if it's a unicast packet with the
- * wrong destination address
- * Also "is multicast" and "matches multicast filter" flags can be used to
- * discard non-matching multicast packets.
- */
-static inline int falcon_handle_rx_event(struct efx_channel *channel,
-                                        const efx_qword_t *event)
-{
-       unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
-       unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
-       unsigned expected_ptr;
-       int discard = 0, checksummed;
-       struct efx_rx_queue *rx_queue;
-       struct efx_nic *efx = channel->efx;
-
-       /* Basic packet information */
-       rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT);
-       rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK);
-       rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
-       WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
-       WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
-
-       rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL);
-       rx_queue = &efx->rx_queue[rx_ev_q_label];
-
-       rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
-       expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
-       if (unlikely(rx_ev_desc_ptr != expected_ptr)) {
-               falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
-               return rx_ev_q_label;
-       }
-
-       if (likely(rx_ev_pkt_ok)) {
-               /* If packet is marked as OK and packet type is TCP/IPv4 or
-                * UDP/IPv4, then we can rely on the hardware checksum.
-                */
-               checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
-       } else {
-               falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
-                                       &discard, rx_ev_byte_cnt);
-               checksummed = 0;
-       }
-
-       /* Detect multicast packets that didn't match the filter */
-       rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
-       if (rx_ev_mcast_pkt) {
-               unsigned int rx_ev_mcast_hash_match =
-                       EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
-
-               if (unlikely(!rx_ev_mcast_hash_match))
-                       discard = 1;
-       }
-
-       /* Handle received packet */
-       efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
-                     checksummed, discard);
-
-       return rx_ev_q_label;
-}
-
-/* Global events are basically PHY events */
-static void falcon_handle_global_event(struct efx_channel *channel,
-                                      efx_qword_t *event)
-{
-       struct efx_nic *efx = channel->efx;
-       int is_phy_event = 0, handled = 0;
-
-       /* Check for interrupt on either port.  Some boards have a
-        * single PHY wired to the interrupt line for port 1. */
-       if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
-           EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
-           EFX_QWORD_FIELD(*event, XG_PHY_INTR))
-               is_phy_event = 1;
-
-       if ((FALCON_REV(efx) >= FALCON_REV_B0) &&
-           EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
-               is_phy_event = 1;
-
-       if (is_phy_event) {
-               efx->phy_op->clear_interrupt(efx);
-               queue_work(efx->workqueue, &efx->reconfigure_work);
-               handled = 1;
-       }
-
-       if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
-               EFX_ERR(efx, "channel %d seen global RX_RESET "
-                       "event. Resetting.\n", channel->channel);
-
-               atomic_inc(&efx->errors.rx_reset);
-               efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
-                                  RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
-               handled = 1;
-       }
-
-       if (!handled)
-               EFX_ERR(efx, "channel %d unknown global event "
-                       EFX_QWORD_FMT "\n", channel->channel,
-                       EFX_QWORD_VAL(*event));
-}
-
-static void falcon_handle_driver_event(struct efx_channel *channel,
-                                      efx_qword_t *event)
-{
-       struct efx_nic *efx = channel->efx;
-       unsigned int ev_sub_code;
-       unsigned int ev_sub_data;
-
-       ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-       ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA);
-
-       switch (ev_sub_code) {
-       case TX_DESCQ_FLS_DONE_EV_DECODE:
-               EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
-                         channel->channel, ev_sub_data);
-               EFX_DL_CALLBACK(efx, event, event);
-               break;
-       case RX_DESCQ_FLS_DONE_EV_DECODE:
-               EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
-                         channel->channel, ev_sub_data);
-               EFX_DL_CALLBACK(efx, event, event);
-               break;
-       case EVQ_INIT_DONE_EV_DECODE:
-               EFX_LOG(efx, "channel %d EVQ %d initialised\n",
-                       channel->channel, ev_sub_data);
-               break;
-       case SRM_UPD_DONE_EV_DECODE:
-               EFX_TRACE(efx, "channel %d SRAM update done\n",
-                         channel->channel);
-               EFX_DL_CALLBACK(efx, event, event);
-               break;
-       case WAKE_UP_EV_DECODE:
-               EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
-                         channel->channel, ev_sub_data);
-               EFX_DL_CALLBACK(efx, event, event);
-               break;
-       case TIMER_EV_DECODE:
-               EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
-                         channel->channel, ev_sub_data);
-               EFX_DL_CALLBACK(efx, event, event);
-               break;
-       case RX_RECOVERY_EV_DECODE:
-               EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
-                       "Resetting.\n", channel->channel);
-
-               atomic_inc(&efx->errors.rx_reset);
-               efx_schedule_reset(efx,
-                                  EFX_WORKAROUND_6555(efx) ?
-                                  RESET_TYPE_RX_RECOVERY :
-                                  RESET_TYPE_DISABLE);
-               break;
-       case RX_DSC_ERROR_EV_DECODE:
-               EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
-                       " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
-               atomic_inc(&efx->errors.rx_desc_fetch);
-               efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
-               break;
-       case TX_DSC_ERROR_EV_DECODE:
-               EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
-                       " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
-               atomic_inc(&efx->errors.tx_desc_fetch);
-               efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
-               break;
-       default:
-               EFX_TRACE(efx, "channel %d unknown driver event code %d "
-                         "data %04x\n", channel->channel, ev_sub_code,
-                         ev_sub_data);
-               EFX_DL_CALLBACK(efx, event, event);
-               break;
-       }
-}
-
-int fastcall falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
-{
-       unsigned int read_ptr;
-       efx_qword_t event, *p_event;
-       int ev_code;
-       int rxq;
-       int rxdmaqs = 0;
-
-       read_ptr = channel->eventq_read_ptr;
-
-       do {
-               p_event = falcon_event(channel, read_ptr);
-               event = *p_event;
-
-               if (!falcon_event_present(&event))
-                       /* End of events */
-                       break;
-
-               EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
-                         channel->channel, EFX_QWORD_VAL(event));
-
-               /* Clear this event by marking it all ones */
-               EFX_SET_QWORD(*p_event);
-
-               ev_code = EFX_QWORD_FIELD(event, EV_CODE);
-
-               switch (ev_code) {
-               case RX_IP_EV_DECODE:
-                       rxq = falcon_handle_rx_event(channel, &event);
-                       rxdmaqs |= (1 << rxq);
-                       (*rx_quota)--;
-                       break;
-               case TX_IP_EV_DECODE:
-                       falcon_handle_tx_event(channel, &event);
-                       break;
-               case DRV_GEN_EV_DECODE:
-                       channel->eventq_magic
-                               = EFX_QWORD_FIELD(event, EVQ_MAGIC);
-                       EFX_LOG(channel->efx, "channel %d received generated "
-                               "event "EFX_QWORD_FMT"\n", channel->channel,
-                               EFX_QWORD_VAL(event));
-                       break;
-               case GLOBAL_EV_DECODE:
-                       falcon_handle_global_event(channel, &event);
-                       break;
-               case DRIVER_EV_DECODE:
-                       falcon_handle_driver_event(channel, &event);
-                       break;
-               default:
-                       EFX_ERR(channel->efx, "channel %d unknown event type %d"
-                               " (data " EFX_QWORD_FMT ")\n", channel->channel,
-                               ev_code, EFX_QWORD_VAL(event));
-               }
-
-               /* Increment read pointer */
-               read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-
-       } while (*rx_quota);
-
-       channel->eventq_read_ptr = read_ptr;
-       return rxdmaqs;
-}
-
-void falcon_set_int_moderation(struct efx_channel *channel)
+static void falcon_push_irq_moderation(struct efx_channel *channel)
 {
        efx_dword_t timer_cmd;
        struct efx_nic *efx = channel->efx;
 
        /* Set timer register */
        if (channel->irq_moderation) {
-               /* Round to resolution supported by hardware.  The value we
-                * program is based at 0.  So actual interrupt moderation
-                * achieved is ((x + 1) * res).
-                */
-               unsigned int res = 5;
-               channel->irq_moderation -= (channel->irq_moderation % res);
-               if (channel->irq_moderation < res)
-                       channel->irq_moderation = res;
                EFX_POPULATE_DWORD_2(timer_cmd,
-                                    TIMER_MODE, TIMER_MODE_INT_HLDOFF,
-                                    TIMER_VAL,
-                                    (channel->irq_moderation / res) - 1);
+                                    FRF_AB_TC_TIMER_MODE,
+                                    FFE_BB_TIMER_MODE_INT_HLDOFF,
+                                    FRF_AB_TC_TIMER_VAL,
+                                    channel->irq_moderation - 1);
        } else {
                EFX_POPULATE_DWORD_2(timer_cmd,
-                                    TIMER_MODE, TIMER_MODE_DIS,
-                                    TIMER_VAL, 0);
-       }
-       falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
-                                 channel->evqnum);
-
-}
-
-/* Allocate buffer table entries for event queue */
-int falcon_probe_eventq(struct efx_channel *channel)
-{
-       struct efx_nic *efx = channel->efx;
-       struct falcon_nic_data *nic_data = efx->nic_data;
-       unsigned int evq_size;
-       int rc;
-
-       evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t);
-       rc = falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
-       if (rc)
-               return rc;
-
-       nic_data->resources.evq_int_min = max(nic_data->resources.evq_int_min,
-                                             (unsigned)channel->evqnum + 1);
-
-       return 0;
-}
-
-int falcon_init_eventq(struct efx_channel *channel)
-{
-       efx_oword_t evq_ptr;
-       struct efx_nic *efx = channel->efx;
-       int rc;
-
-       EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
-               channel->channel, channel->eventq.index,
-               channel->eventq.index + channel->eventq.entries - 1);
-
-       /* Pin event queue buffer */
-       rc = falcon_init_special_buffer(efx, &channel->eventq);
-       if (rc)
-               return rc;
-
-       /* Fill event queue with all ones (i.e. empty events) */
-       memset(channel->eventq.addr, 0xff, channel->eventq.len);
-
-       /* Push event queue to card */
-       EFX_POPULATE_OWORD_3(evq_ptr,
-                            EVQ_EN, 1,
-                            EVQ_SIZE, FALCON_EVQ_ORDER,
-                            EVQ_BUF_BASE_ID, channel->eventq.index);
-       falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
-                          channel->evqnum);
-
-       falcon_set_int_moderation(channel);
-
-       return 0;
-}
-
-void falcon_fini_eventq(struct efx_channel *channel)
-{
-       efx_oword_t eventq_ptr;
-       struct efx_nic *efx = channel->efx;
-
-       /* Remove event queue from card */
-       EFX_ZERO_OWORD(eventq_ptr);
-       falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
-                          channel->evqnum);
-
-       /* Unpin event queue */
-       falcon_fini_special_buffer(efx, &channel->eventq);
-}
-
-/* Free buffers backing event queue */
-void falcon_remove_eventq(struct efx_channel *channel)
-{
-       falcon_free_special_buffer(channel->efx, &channel->eventq);
-}
-
-
-/* Generates a test event on the event queue.  A subsequent call to
- * process_eventq() should pick up the event and place the value of
- * "magic" into channel->eventq_magic;
- */
-void falcon_generate_test_event(struct efx_channel *channel, unsigned int 
magic)
-{
-       efx_qword_t test_event;
-
-       EFX_POPULATE_QWORD_2(test_event,
-                            EV_CODE, DRV_GEN_EV_DECODE,
-                            EVQ_MAGIC, magic);
-       falcon_generate_event(channel, &test_event);
-}
-
-
-/**************************************************************************
- *
- * Falcon hardware interrupts
- * The hardware interrupt handler does very little work; all the event
- * queue processing is carried out by per-channel tasklets.
- *
- **************************************************************************/
-
-/* Enable/disable/generate Falcon interrupts */
-static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
-                                    int force)
-{
-       efx_oword_t int_en_reg_ker;
-
-       EFX_POPULATE_OWORD_2(int_en_reg_ker,
-                            KER_INT_KER, force,
-                            DRV_INT_EN_KER, enabled);
-       falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER);
-}
-
-void falcon_enable_interrupts(struct efx_nic *efx)
-{
-       efx_oword_t int_adr_reg_ker;
-       struct efx_channel *channel;
-
-       /* Zero INT_KER */
-       EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
-       wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
-
-       /* Program INT_ADR_KER_REG */
-       EFX_POPULATE_OWORD_2(int_adr_reg_ker,
-                            NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx),
-                            INT_ADR_KER, efx->irq_status.dma_addr);
-       falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER);
-
-       /* Enable interrupts */
-       falcon_interrupts(efx, 1, 0);
-
-       /* Force processing of all the channels to get the EVQ RPTRs up to
-          date */
-       efx_for_each_channel_with_interrupt(channel, efx)
-               efx_schedule_channel(channel);
-}
-
-void falcon_disable_interrupts(struct efx_nic *efx)
-{
-       /* Disable interrupts */
-       falcon_interrupts(efx, 0, 0);
-}
-
-/* Generate a Falcon test interrupt
- * Interrupt must already have been enabled, otherwise nasty things
- * may happen.
- */
-void falcon_generate_interrupt(struct efx_nic *efx)
-{
-       falcon_interrupts(efx, 1, 1);
+                                    FRF_AB_TC_TIMER_MODE,
+                                    FFE_BB_TIMER_MODE_DIS,
+                                    FRF_AB_TC_TIMER_VAL, 0);
+       }
+       BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0);
+       efx_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0,
+                              channel->channel);
+}
+
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+
+static void falcon_prepare_flush(struct efx_nic *efx)
+{
+       falcon_deconfigure_mac_wrapper(efx);
+
+       /* Wait for the tx and rx fifo's to get to the next packet boundary
+        * (~1ms without back-pressure), then to drain the remainder of the
+        * fifo's at data path speeds (negligible), with a healthy margin. */
+       msleep(10);
 }
 
 /* Acknowledge a legacy interrupt from Falcon
@@ -1514,95 +198,54 @@ void falcon_generate_interrupt(struct ef
  *
  * NB most hardware supports MSI interrupts
  */
-static inline void falcon_irq_ack_a1(struct efx_nic *efx)
+inline void falcon_irq_ack_a1(struct efx_nic *efx)
 {
        efx_dword_t reg;
 
-       EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e);
-       falcon_writel(efx, &reg, INT_ACK_REG_KER_A1);
-       falcon_readl(efx, &reg, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1);
-}
-
-/* Process a fatal interrupt
- * Disable bus mastering ASAP and schedule a reset
- */
-static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
-{
-       struct falcon_nic_data *nic_data = efx->nic_data;
-       efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
-       efx_oword_t fatal_intr;
-       int error, mem_perr;
-       static int n_int_errors;
-
-       falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
-       error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
-
-       EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
-               EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
-               EFX_OWORD_VAL(fatal_intr),
-               error ? "disabling bus mastering" : "no recognised error");
-       if (error == 0)
-               goto out;
-
-       /* If this is a memory parity error dump which blocks are offending */
-       mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER);
-       if (mem_perr) {
-               efx_oword_t reg;
-               falcon_read(efx, &reg, MEM_STAT_REG_KER);
-               EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
-                       EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
-       }
-
-       /* Disable DMA bus mastering on both devices */
-       pci_disable_device(efx->pci_dev);
-       if (FALCON_IS_DUAL_FUNC(efx))
-               pci_disable_device(nic_data->pci_dev2);
-
-       if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
-               EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
-               efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
-       } else {
-               EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
-                       "NIC will be disabled\n");
-               efx_schedule_reset(efx, RESET_TYPE_DISABLE);
-       }
-out:
-       return IRQ_HANDLED;
-}
-
-/* Handle a legacy interrupt from Falcon
- * Acknowledges the interrupt and schedule event queue processing.
- *
- * This routine must guarantee not to touch the hardware when
- * interrupts are disabled, to allow for correct semantics of
- * efx_suspend() and efx_resume().
- */
-static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id,
-                                             struct pt_regs *regs
-                                             __attribute__ ((unused)))
-{
-       struct efx_nic *efx = (struct efx_nic *)dev_id;
-       efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+       EFX_POPULATE_DWORD_1(reg, FRF_AA_INT_ACK_KER_FIELD, 0xb7eb7e);
+       efx_writed(efx, &reg, FR_AA_INT_ACK_KER);
+       efx_readd(efx, &reg, FR_AA_WORK_AROUND_BROKEN_PCI_READS);
+}
+
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_IRQ_HANDLER_REGS)
+irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
+#else
+irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id,
+                                      struct pt_regs *regs
+                                      __attribute__ ((unused)))
+#endif
+{
+       struct efx_nic *efx = dev_id;
+       efx_oword_t *int_ker = efx->irq_status.addr;

_______________________________________________
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®.