WARNING - OLD ARCHIVES

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

xen-changelog

[Xen-changelog] [linux-2.6.18-xen] Update Solarflare Communications net

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] Update Solarflare Communications net driver to version 3.0.2.2074
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Sat, 09 Jan 2010 00:20:19 -0800
Delivery-date: Sat, 09 Jan 2010 00:20:35 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] Update Solarflare Communications net driver to version 3.0.2.2074, Xen patchbot-linux-2.6.18-xen <=