]> xenbits.xensource.com Git - legacy/linux-2.6.18-xen.git/commitdiff
Update Solarflare Communications net driver to version 3.0.2.2074
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 8 Jan 2010 13:05:49 +0000 (13:05 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 8 Jan 2010 13:05:49 +0000 (13:05 +0000)
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@solarflare.com>
74 files changed:
MAINTAINERS
drivers/net/sfc/Kconfig
drivers/net/sfc/Makefile
drivers/net/sfc/alaska.c [deleted file]
drivers/net/sfc/autocompat.h [new file with mode: 0644]
drivers/net/sfc/bitfield.h
drivers/net/sfc/boards.c [deleted file]
drivers/net/sfc/boards.h [deleted file]
drivers/net/sfc/config.h [deleted file]
drivers/net/sfc/debugfs.c
drivers/net/sfc/debugfs.h
drivers/net/sfc/driverlink.c
drivers/net/sfc/driverlink.h
drivers/net/sfc/driverlink_api.h
drivers/net/sfc/efx.c
drivers/net/sfc/efx.h
drivers/net/sfc/efx_ioctl.h [new file with mode: 0644]
drivers/net/sfc/enum.h
drivers/net/sfc/ethtool.c
drivers/net/sfc/ethtool.h [deleted file]
drivers/net/sfc/extraversion.h [deleted file]
drivers/net/sfc/falcon.c
drivers/net/sfc/falcon.h [deleted file]
drivers/net/sfc/falcon_boards.c [new file with mode: 0644]
drivers/net/sfc/falcon_gmac.c
drivers/net/sfc/falcon_hwdefs.h [deleted file]
drivers/net/sfc/falcon_io.h [deleted file]
drivers/net/sfc/falcon_xmac.c
drivers/net/sfc/gmii.h [deleted file]
drivers/net/sfc/i2c-direct.c [deleted file]
drivers/net/sfc/i2c-direct.h [deleted file]
drivers/net/sfc/io.h [new file with mode: 0644]
drivers/net/sfc/ioctl.c [new file with mode: 0644]
drivers/net/sfc/kernel_compat.c
drivers/net/sfc/kernel_compat.h
drivers/net/sfc/linux_mdio.c [new file with mode: 0644]
drivers/net/sfc/linux_mdio.h [new file with mode: 0644]
drivers/net/sfc/lm87.c [new file with mode: 0644]
drivers/net/sfc/lm87_support.c [deleted file]
drivers/net/sfc/lm87_support.h [deleted file]
drivers/net/sfc/lm90.c [new file with mode: 0644]
drivers/net/sfc/mac.h
drivers/net/sfc/mcdi.c [new file with mode: 0644]
drivers/net/sfc/mcdi.h [new file with mode: 0644]
drivers/net/sfc/mcdi_mac.c [new file with mode: 0644]
drivers/net/sfc/mcdi_pcol.h [new file with mode: 0644]
drivers/net/sfc/mcdi_phy.c [new file with mode: 0644]
drivers/net/sfc/mdio_10g.c
drivers/net/sfc/mdio_10g.h
drivers/net/sfc/mentormac.c [deleted file]
drivers/net/sfc/mtd.c
drivers/net/sfc/net_driver.h
drivers/net/sfc/nic.c [new file with mode: 0644]
drivers/net/sfc/nic.h [new file with mode: 0644]
drivers/net/sfc/null_phy.c
drivers/net/sfc/phy.c [deleted file]
drivers/net/sfc/phy.h
drivers/net/sfc/pm8358_phy.c [deleted file]
drivers/net/sfc/qt202x_phy.c [new file with mode: 0644]
drivers/net/sfc/regs.h [new file with mode: 0644]
drivers/net/sfc/rx.c
drivers/net/sfc/rx.h [deleted file]
drivers/net/sfc/selftest.c
drivers/net/sfc/selftest.h
drivers/net/sfc/sfe4001.c [deleted file]
drivers/net/sfc/siena.c [new file with mode: 0644]
drivers/net/sfc/spi.h
drivers/net/sfc/tenxpress.c
drivers/net/sfc/tx.c
drivers/net/sfc/tx.h [deleted file]
drivers/net/sfc/txc43128_phy.c
drivers/net/sfc/workarounds.h
drivers/net/sfc/xenpack.h [deleted file]
drivers/net/sfc/xfp_phy.c [deleted file]

index a6aad7e193d997d04b813522aabf18319c658185..23409c599e173053263f4824fe83bc269e67f015 100644 (file)
@@ -2559,11 +2559,12 @@ L:      linux-ia64@vger.kernel.org
 S:     Supported
 
 SFC NETWORK DRIVER
-P:     Steve Hodgson
-P:     Ben Hutchings
-P:     Robert Stonehouse
-M:     linux-net-drivers@solarflare.com
+M:     Solarflare linux maintainers <linux-net-drivers@solarflare.com>
+M:     Steve Hodgson <shodgson@solarflare.com>
+M:     Ben Hutchings <bhutchings@solarflare.com>
+L:     netdev@vger.kernel.org
 S:     Supported
+F:     drivers/net/sfc/
 
 SGI VISUAL WORKSTATION 320 AND 540
 P:     Andrey Panin
index 62997f209de3bca0ef58495689c6ef7355047a0b..847d1395eb66d5b645c59dae3fc4e28ed430b58c 100644 (file)
@@ -1,35 +1,39 @@
 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.
+
index 2f647230da138d92137d43f4a0289de7805e31ea..9eb146c16734db9f3cd8ac79c0350a06e2f5507c 100644 (file)
@@ -1,13 +1,14 @@
-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)      += sfc.o
 
 obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/
 
+EXTRA_CFLAGS += -DEFX_USE_KCOMPAT=1 -Wno-unused-label
diff --git a/drivers/net/sfc/alaska.c b/drivers/net/sfc/alaska.c
deleted file mode 100644 (file)
index 71f66da..0000000
+++ /dev/null
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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 --git a/drivers/net/sfc/autocompat.h b/drivers/net/sfc/autocompat.h
new file mode 100644 (file)
index 0000000..f6114d3
--- /dev/null
@@ -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
index 870ead1dc829e9fa53921f24e749a0d5943b5d58..f70a4cda8ee9a2b839f1eb1360943398e771931c 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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))
+       ((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)
+#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)) \
-        & EFX_MASK64(field))
+#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)) \
-        & EFX_MASK64(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)) \
-        & EFX_MASK32(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)) \
-        & EFX_MASK32(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)) \
-        & EFX_MASK32(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,69 +418,102 @@ 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_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_INSERT_FIELD32(...)                                        \
-       cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+#define EFX_INSERT64(min, max, low, high, value)                       \
+       cpu_to_le64(EFX_INSERT_NATIVE(min, max, low, high, value))
 
-#define EFX_INPLACE_MASK64(min, max, field)                    \
-       EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
+#define EFX_INSERT32(min, max, low, high, value)                       \
+       cpu_to_le32(EFX_INSERT_NATIVE(min, max, low, high, value))
 
-#define EFX_INPLACE_MASK32(min, max, field)                    \
-       EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
+#define EFX_INPLACE_MASK64(min, max, low, high)                                \
+       EFX_INSERT64(min, max, low, high, EFX_MASK64(high + 1 - low))
 
-#define EFX_SET_OWORD_FIELD64(oword, field, value) do {                        \
+#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)); \
+                          & ~EFX_INPLACE_MASK64(64, 127, low, high))   \
+                         | EFX_INSERT64(64, 127, low, high, value));   \
        } while (0)
 
-#define EFX_SET_QWORD_FIELD64(qword, field, value) do {                        \
+#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));   \
+                          & ~EFX_INPLACE_MASK64(0, 63, low, high))     \
+                         | EFX_INSERT64(0, 63, low, high, value));     \
        } while (0)
 
-#define EFX_SET_OWORD_FIELD32(oword, field, value) do {                        \
+#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)); \
+                          & ~EFX_INPLACE_MASK32(96, 127, low, high))   \
+                         | EFX_INSERT32(96, 127, low, high, value));   \
        } while (0)
 
-#define EFX_SET_QWORD_FIELD32(qword, field, value) do {                        \
+#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));  \
+                          & ~EFX_INPLACE_MASK32(32, 63, low, high))    \
+                         | EFX_INSERT32(32, 63, low, high, 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));   \
+#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
 #define EFX_SET_QWORD_FIELD EFX_SET_QWORD_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 --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
deleted file mode 100644 (file)
index ddb5f7e..0000000
+++ /dev/null
@@ -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@solarflare.com>
- *
- * 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 --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
deleted file mode 100644 (file)
index 5a90316..0000000
+++ /dev/null
@@ -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@solarflare.com>
- *
- * 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 --git a/drivers/net/sfc/config.h b/drivers/net/sfc/config.h
deleted file mode 100644 (file)
index 3afeced..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* SFC config options can go here */
index 9e2950d0c007c0b43576e8526032489ab11fdc7d..b378678cca01d6e3d80349f035857377bb6080b2 100644 (file)
@@ -1,48 +1,35 @@
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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)
 {
        if (entry)
@@ -53,6 +40,7 @@ static void efx_debugfs_remove(struct proc_dir_entry *entry)
 #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)
@@ -92,6 +97,8 @@ static int efx_debugfs_open(struct inode *inode, struct file *file)
        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 = {
        .owner   = THIS_MODULE,
@@ -102,11 +109,42 @@ static struct file_operations efx_debugfs_file_ops = {
 };
 
 
+#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_dir_entry *dir, const char *name)
  * 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_file *file, void *data)
        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;
@@ -183,18 +226,6 @@ static int efx_debugfs_read_loop_mode(struct seq_file *file, void *data)
        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)
 {
        return seq_puts(file, (const char *)data);
@@ -210,14 +241,30 @@ int efx_debugfs_read_string(struct seq_file *file, void *data)
  * 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 dentry *parent,
                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 dentry *parent,
  */
 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_device *net_dev)
  */
 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_device *net_dev)
 /* 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 *efx)
        /* 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 @@ int efx_extend_debugfs_port(struct efx_nic *efx,
 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_debugfs_tx_queue_parameters[] = {
        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(struct efx_tx_queue *tx_queue)
        /* 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(struct efx_rx_queue *rx_queue)
        /* 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(struct efx_rx_queue *rx_queue)
 
 /* 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(struct efx_channel *channel)
        /* 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(struct efx_channel *channel)
 /* 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 *efx)
 
        /* 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 @@ void efx_fini_debugfs_nic(struct efx_nic *efx)
 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);
index 061ddc70b6bace431f0a76525a60e474bc4dcab2..9ac72a0fd727b692279800a1e00b95e0c3771a8f 100644 (file)
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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)
 {
        return 0;
@@ -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 */
index 5247ff78fbe3a13ae6c57b17a3c439df712e0a14..aa99c4764490aa36aef430017a47c9d1d64034fd 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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>
 #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_dl_device *efx_dev)
        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 efx_nic *efx,
        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 efx_nic *efx,
        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 efx_nic *efx,
  fail:
        EFX_INFO(efx, "%s driverlink client skipped\n", driver->name);
 
-       kfree(efx_dev);
+       kfree(efx_handle);
 }
 
-/**
- * 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.
- */
+/* 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_dl_driver *driver)
        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_dl_driver *driver)
 
        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;
+       rtnl_lock();
 
-       /* Add driver to driver list */
        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_nic *efx)
 {
        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);
+       ASSERT_RTNL();
 
-       /* Remove all devices related to this NIC */
        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;
+       ASSERT_RTNL();
 
-       /* Add port to port list */
        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)
+
+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)
 {
-       /* Never veto the packet */
        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)
+                                                 const char *pkt_buf, int len)
 {
-       /* Never veto the packet */
        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)
 {
-}
-
-static int
-efx_dummy_request_mtu_callback(struct efx_dl_device *efx_dev, int new_mtu)
-{
-       /* Always allow */
        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 @@ static void efx_dummy_event_callback(struct efx_dl_device *efx_dev, void *event)
 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);
+       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;
+       }
 
-       /* Resume net driver operations */
-       efx_resume(efx);
+       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_dl_device *efx_dev,
        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_dl_device *efx_dev,
        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_device *efx_dev)
 }
 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));
+       ASSERT_RTNL();
 
-       /* Call suspend method of each driver in turn */
        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 *efx)
        }
 }
 
-/*
- * 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));
+       ASSERT_RTNL();
 
-       /* Call resume method of each driver in turn */
        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, int ok)
        }
 }
 
-/**
- * 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;
index 7c4f33237672f8490cc5f220f5683127363c0e3c..a90a7403c022477412dbbca73c8923ff96a079a2 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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
 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. */
index b56201d76bd34eefdde71fffd0097fe188ce1cca..5608d9dca67629d14130451ea086e4ad167aeaf2 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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 sk_buff;
 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: */
@@ -246,24 +73,11 @@ struct efx_dl_driver {
        struct list_head device_list;
 };
 
-/**
- * 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 @@ enum efx_dl_falcon_resource_flags {
 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 efx_dl_device *efx_dev);
  * @_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 efx_dl_device *efx_dev);
  * @_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)                           \
index e9637ff1004843885556fc23bebb95bed9d70f50..4dbace2b41701c7dca36543df0c9f1b09a9170d9 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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>
 #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"
 
 /**************************************************************************
  *
 /* 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.
+ * 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 forced to 0 for MSI interrupt mode as the interrupt vector
- * is not written
+ * This is only used in MSI-X interrupt mode
  */
-static unsigned int separate_tx_and_rx_channels = 1;
+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.
@@ -160,11 +149,6 @@ static int napi_weight = 64;
  */
 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,
  * such devices will be initialised with a random locally-generated
@@ -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_failure;
  */
 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.
+/* 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.
  *
- * 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)
+ * Systems without MSI-X will only target one CPU via legacy or MSI
+ * interrupt.  The default is "packages".
  */
-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");
+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_nic *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_nic *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)
+static int efx_process_channel(struct efx_channel *channel, int rx_quota)
 {
-       int rxdmaqs;
-       struct efx_rx_queue *rx_queue;
+       struct efx_nic *efx = channel->efx;
+       int rx_packets;
 
-       if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
+       if (unlikely(efx->reset_pending != RESET_TYPE_NONE ||
                     !channel->enabled))
-               return rx_quota;
+               return 0;
 
-       rxdmaqs = falcon_process_eventq(channel, &rx_quota);
+       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(struct efx_channel *channel, int rx_quota)
                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;
-       }
+       efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
 
-       return rx_quota;
+       return rx_packets;
 }
 
 /* Mark channel as finished processing
@@ -295,12 +294,13 @@ static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
  */
 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(struct efx_channel *channel)
  * 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_channel *channel)
        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_channel *channel)
 {
        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);
 }
 
 /**************************************************************************
@@ -419,26 +448,6 @@ static void efx_remove_eventq(struct efx_channel *channel)
  *
  *************************************************************************/
 
-/* 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)
 {
        struct efx_tx_queue *tx_queue;
@@ -478,54 +487,64 @@ static int efx_probe_channel(struct efx_channel *channel)
 }
 
 
+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_init_eventq(channel);
 
-               efx_for_each_channel_tx_queue(tx_queue, channel) {
-                       rc = efx_init_tx_queue(tx_queue);
-                       if (rc)
-                               goto err;
-               }
+               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_channel *channel)
 
        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 */
+       /* 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();
 
-       /* Enable NAPI poll handler */
        napi_enable(&channel->napi_str);
 
        /* Load up RX descriptors */
@@ -569,10 +585,7 @@ static void efx_stop_channel(struct efx_channel *channel)
 
        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,10 +600,17 @@ static void efx_fini_channels(struct efx_nic *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_nic *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_rx_queue *rx_queue, int delay)
  * 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)
+void efx_link_status_changed(struct efx_nic *efx)
 {
-       int carrier_ok;
+       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(struct efx_nic *efx)
        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]");
+                        (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;
+       }
 }
 
-/* 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)
+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());
+       /* 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);
+       }
 
-       efx->mac_op->reconfigure(efx);
+       /* 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;
 
-       /* Inform kernel of loss/gain of carrier */
-       efx_link_status_changed(efx);
+       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);
+
+       return rc;
 }
 
-/* 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)
+/* 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,
-                                          reconfigure_work);
+       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)
 
        EFX_LOG(efx, "init port\n");
 
-       /* The default power state is ON */
-       efx->phy_powered = 1;
+       mutex_lock(&efx->mac_lock);
 
-       /* Initialise the MAC and PHY */
-       rc = efx->mac_op->init(efx);
+       rc = efx->phy_op->init(efx);
        if (rc)
-               return rc;
+               goto fail1;
 
-       efx->port_initialized = 1;
+       efx->port_initialized = true;
 
-       /* Reconfigure port to program MAC registers */
+       /* 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;
+
+fail2:
+       efx->phy_op->fini(efx);
+fail1:
+       mutex_unlock(&efx->mac_lock);
+       return rc;
 }
 
-/* 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 */
 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 *efx)
        if (!efx->port_initialized)
                return;
 
-       efx->mac_op->fini(efx);
-       efx->port_initialized = 0;
+       efx->phy_op->fini(efx);
+       efx->port_initialized = false;
 
-       /* Mark the link down */
-       efx->link_up = 0;
+       efx->link_state.up = false;
        efx_link_status_changed(efx);
 }
 
@@ -853,7 +924,7 @@ static void efx_remove_port(struct efx_nic *efx)
        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 *efx)
 
        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 *efx)
                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 *efx)
        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 *efx)
        }
 
        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;
 
-               /* 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);
+               /* 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);
 
-               /* Request maximum number of MSI interrupts, and fill out
-                * the channel interrupt information the allowed allocation */
-               for (i = 0; i < efx->rss_queues; i++)
+               for (i = 0; i < wanted_ints; i++)
                        xentries[i].entry = i;
-               rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
+               rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints);
                if (rc > 0) {
-                       EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
-                       efx->rss_queues = rc;
+                       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,
-                                            efx->rss_queues);
+                                            wanted_ints);
                }
 
                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 efx_nic *efx)
 
        /* 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 efx_nic *efx)
 
        /* 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 efx_nic *efx)
        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_nic *efx)
        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];
+       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;
+       }
 
-               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_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)
 
        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 *efx)
         * 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_nic *efx)
        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 *efx)
                        goto fail3;
                }
        }
+       efx_set_channel_names(efx);
 
        return 0;
 
@@ -1192,7 +1366,7 @@ static int efx_probe_all(struct efx_nic *efx)
  * 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 *efx)
                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 *efx)
  * 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 *efx)
         * 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 *efx)
  * 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 *efx)
        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 *efx)
         * 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,80 +1522,40 @@ static void efx_remove_all(struct efx_nic *efx)
        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;
+/**************************************************************************
+ *
+ * Interrupt moderation
+ *
+ **************************************************************************/
 
-       return rc;
+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;
 }
 
-/* A convinience function to safely flush all the queues */
-int efx_flush_queues(struct efx_nic *efx)
+/* Set interrupt moderation parameters */
+void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
+                            bool rx_adaptive)
 {
-       int rc;
+       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_stop_all(efx);
+       efx_for_each_tx_queue(tx_queue, efx)
+               tx_queue->channel->irq_moderation = tx_ticks;
 
-       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
- *
- **************************************************************************/
-
-/* Set interrupt moderation parameters */
-void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
-{
-       struct efx_tx_queue *tx_queue;
-       struct efx_rx_queue *rx_queue;
-
-       EFX_ASSERT_RESET_SERIALISED(efx);
-
-       efx_for_each_tx_queue(tx_queue, efx)
-               tx_queue->channel->irq_moderation = tx_usecs;
-
-       efx_for_each_rx_queue(rx_queue, efx)
-               rx_queue->channel->irq_moderation = rx_usecs;
-}
+       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_ticks;
+}
 
 /**************************************************************************
  *
@@ -1391,35 +1567,40 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
  * 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;
        }
+#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);
 
-       rc = efx->mac_op->check_hw(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_struct *data)
  */
 static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
 {
-       struct efx_nic *efx = net_dev->priv;
+       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
 
-       if (!in_interrupt())
-           EFX_ASSERT_RESET_SERIALISED(efx);
+       /* 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 generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
+       return mdio_mii_ioctl(&efx->mdio, data, cmd);
 }
 
 /**************************************************************************
@@ -1449,75 +1654,43 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
  *
  **************************************************************************/
 
-/* 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 *efx)
  */
 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,12 +1725,25 @@ static void efx_netpoll(struct net_device *net_dev)
 /* 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_device *net_dev)
  */
 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;
+#endif
 
-       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);
+       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_stats(struct net_device *net_dev)
 /* Context: netif_tx_lock held, BHs disabled. */
 static void efx_watchdog(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
-       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");
+       EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:"
+               " resetting channels\n",
+               atomic_read(&efx->netif_stop_count), efx->port_enabled);
 
-       if (monitor_reset)
-               efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+       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_device *net_dev, int new_mtu)
        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_device *net_dev, int new_mtu)
  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 net_device *net_dev, void *data)
        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(struct net_device *net_dev)
                        set_bit_le(bit, mc_hash->byte);
                        mc_list = mc_list->next;
                }
+
+               /* 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);
        }
 
-       /* Create and activate new global multicast hash table */
-       falcon_set_multicast_hash(efx);
+       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);
 }
 
-/* Handle net device notifier events */
 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;
+#endif
+               struct efx_nic *efx = netdev_priv(net_dev);
 
-               strcpy(efx->name, net_dev->name);
-               efx_fini_debugfs_netdev(net_dev);
-               efx_init_debugfs_netdev(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 = {
        .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 net_device *net_dev, int new_mtu)
        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 efx_nic *efx)
 
        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;
@@ -1797,43 +2023,66 @@ static int efx_register_netdev(struct efx_nic *efx)
        net_dev->set_multicast_list = efx_set_multicast_list;
 #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_nic *efx)
        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 efx_nic *efx)
  *
  **************************************************************************/
 
-/* 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)
+/* 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_LOG(efx, "suspending operations\n");
+       EFX_ASSERT_RESET_SERIALISED(efx);
 
-       rtnl_lock();
        efx_stop_all(efx);
-}
-
-void efx_resume(struct efx_nic *efx)
-{
-       EFX_LOG(efx, "resuming operations\n");
+       mutex_lock(&efx->mac_lock);
+       mutex_lock(&efx->spi_lock);
 
-       efx_start_all(efx);
-       rtnl_unlock();
+       efx_fini_channels(efx);
+       if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
+               efx->phy_op->fini(efx);
+       efx->type->fini(efx);
 }
 
-/* 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)
+/* 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);
 
-       rc = efx->mac_op->get_settings(efx, ecmd);
+       /* Ensure that SRAM is initialised even if we're disabling the device */
+       rc = efx->type->init(efx);
        if (rc) {
-               EFX_ERR(efx, "could not back up PHY settings\n");
+               EFX_ERR(efx, "failed to initialise NIC\n");
                goto fail;
        }
 
-       efx_fini_channels(efx);
-       return 0;
+       if (!ok)
+               goto fail;
 
- fail:
-       return rc;
-}
+       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");
+       }
 
-/* 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;
+       efx->mac_op->reconfigure(efx);
 
-       rc = efx_init_channels(efx);
-       if (rc)
-               goto fail1;
+       efx_init_channels(efx);
 
-       /* 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;
-       }
+       mutex_unlock(&efx->spi_lock);
+       mutex_unlock(&efx->mac_lock);
+
+       efx_start_all(efx);
 
        return 0;
 
- fail2:
-       efx_fini_channels(efx);
- fail1:
+fail:
+       efx->port_initialized = false;
+
+       mutex_unlock(&efx->spi_lock);
+       mutex_unlock(&efx->mac_lock);
+
        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.
+/* 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.
  *
- * 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.
+ * Caller must hold the rtnl_lock.
  */
-static int efx_reset(struct efx_nic *efx)
+int efx_reset(struct efx_nic *efx, enum reset_type method)
 {
-       struct ethtool_cmd ecmd;
-       enum reset_type method = efx->reset_pending;
-       int rc;
+       int rc, rc2;
+       bool disabled;
 
-       /* Notify driverlink clients of imminent reset. */
-       efx_dl_reset_lock();
+       /* Notify driverlink clients of imminent reset then serialise
+        * against other driver operations */
        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_reset_down(efx, method);
 
-       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);
+       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;
+       disabled = rc || method == RESET_TYPE_DISABLE;
+       rc2 = efx_reset_up(efx, method, !disabled);
+       if (rc2) {
+               disabled = true;
+               if (!rc)
+                       rc = rc2;
        }
 
-       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();
+       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);
+       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;
+       }
 
-       efx_reset(nic);
+       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 *efx, enum reset_type type)
        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, enum reset_type type)
 
        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 *efx, enum reset_type type)
 
 /* 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
+ * Dummy PHY/MAC operations
  *
- * Can be used where the MAC does not implement this operation
+ * 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 *efx)
        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_info = {
  * 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;
+               channel->work_pending = false;
        }
-       for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+       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_nic *efx, struct efx_nic_type *type,
 
        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);
+#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
 
-       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;
-       }
+       /* 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_nic *efx)
  */
 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_dev *pci_dev)
        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_nic *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;
+               goto fail3;
        }
 
-       /* Initialise port */
        rc = efx_init_port(efx);
        if (rc) {
                EFX_ERR(efx, "failed to initialise port\n");
-               goto fail5;
+               goto fail4;
        }
 
-       /* 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);
+       efx_init_channels(efx);
 
-       /* Check basic functionality and set interrupt mode */
-       rc = efx_run_selftests(efx);
+       rc = efx_nic_init_interrupt(efx);
        if (rc)
-               goto fail8;
-
-       /* Stop the NIC */
-       efx_stop_all(efx);
+               goto fail5;
 
        return 0;
 
- fail8:
+ fail6:
        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 efx_pci_probe_main(struct efx_nic *efx)
 static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
                                   const struct pci_device_id *entry)
 {
-       struct efx_nic *efx;
        struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
+       struct net_device *net_dev;
+       struct efx_nic *efx;
        int i, rc;
 
-       /* Allocate and initialise a struct efx_nic */
-       efx = kmalloc(sizeof(*efx), GFP_KERNEL);
-       if (!efx) {
-               rc = -ENOMEM;
-               goto fail1;
-       }
+       /* 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);
+       rc = efx_init_struct(efx, type, pci_dev, net_dev);
        if (rc)
-               goto fail2;
+               goto fail1;
 
-       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;
+               goto fail5;
 
-       /* 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();
+       /* 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:
-       efx_fini_debugfs_channels(efx);
  fail6:
-       efx_pci_remove_main(efx);
+       efx_fini_debugfs_channels(efx);
  fail5:
+       efx_pci_remove_main(efx);
  fail4:
-       efx_fini_io(efx);
  fail3:
-       efx_fini_struct(efx);
+       efx_fini_io(efx);
  fail2:
-       kfree(efx);
+       efx_fini_struct(efx);
  fail1:
        EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+       free_netdev(net_dev);
+       return rc;
+}
+
+#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;
 }
 
-/* PCI driver definition */
+#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
 };
 
 /**************************************************************************
@@ -2539,9 +2869,6 @@ 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)
 {
        int rc;
@@ -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 @@ static void __exit efx_exit_module(void)
 module_init(efx_init_module);
 module_exit(efx_exit_module);
 
-MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
-             "Solarflare Communications");
+MODULE_AUTHOR("Solarflare Communications and "
+             "Michael Brown <mbrown@fensystems.co.uk>");
 MODULE_DESCRIPTION("Solarflare Communications network driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, efx_pci_table);
+MODULE_VERSION(EFX_DRIVER_VERSION);
index 7413b65f052fba07638626731a5c9444bd1ef6fd..92b74c2a9e597172f63bbc76ddb6a6205f60f9fa 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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
 #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(struct efx_channel *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 --git a/drivers/net/sfc/efx_ioctl.h b/drivers/net/sfc/efx_ioctl.h
new file mode 100644 (file)
index 0000000..f4412fa
--- /dev/null
@@ -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@fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ *
+ * 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 */
index 92dcb90864ff320cb4baa03e44714e6ce1db47cf..384cfe3b1be133466ab7c77ca1522717b3f116a8 100644 (file)
@@ -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@solarflare.com>
+ * 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
 /**
  * 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_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_1G_INTERNAL (1 << LOOPBACK_MAC)
+#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_EXTERNAL(_efx)                                \
+       (!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx)))
 
-#define LOOPBACK_CHANGED(_from, _to, _mask)            \
-       ((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) &  \
-        (_mask) ? 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)) == 0)) ? 1 : 0)
+#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,
 };
 
index 5a559db7049f4715f5a3a92888f3a23eff509b1d..20bc140c415ac7242f4a67dfc5d2ab105b572085 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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,12 +152,25 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
        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
+
 /**************************************************************************
  *
  * Ethtool operations
@@ -184,13 +179,19 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
  */
 
 /* Identify device by flashing LEDs */
-static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
+static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
 {
-       struct efx_nic *efx = net_dev->priv;
+       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->board_info.blink(efx, 1);
-       schedule_timeout_interruptible(seconds * HZ);
-       efx->board_info.blink(efx, 0);
+       efx->type->set_id_led(efx, EFX_LED_DEFAULT);
        return 0;
 }
 
@@ -198,41 +199,75 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
 int efx_ethtool_get_settings(struct net_device *net_dev,
                             struct ethtool_cmd *ecmd)
 {
-       struct efx_nic *efx = net_dev->priv;
-       int 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);
 
-       if (!in_interrupt())
-           mutex_lock(&efx->mac_lock);
-       rc = efx->mac_op->get_settings(efx, ecmd);
-       if (!in_interrupt())
-           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;
 
-       return rc;
+       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(struct net_device *net_dev,
  * @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 test_index,
 
        /* 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);
+                        "%-6s %-24s", unit_str.name, test_str.name);
        }
 }
 
-#define EFX_PORT_NAME "port%d", 0
+#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_nic *efx,
                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(struct efx_nic *efx,
                                       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(struct efx_nic *efx,
                              "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(struct efx_nic *efx,
        return n;
 }
 
-static int efx_ethtool_get_stats_count(struct net_device *net_dev)
+static int efx_ethtool_get_sset_count(struct net_device *net_dev,
+                                     int string_set)
 {
-       return EFX_ETHTOOL_NUM_STATS;
+       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_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 net_device *net_dev,
                                  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 net_device *net_dev,
        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 net_device *net_dev,
        }
 }
 
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
+static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
 {
-       struct efx_nic *efx = net_dev->priv;
-       int rc;
+       struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev);
+       unsigned long features;
 
-       rc = ethtool_op_set_tx_csum(net_dev, enable);
-       if (rc)
-               return rc;
+       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 = netdev_priv(net_dev);
+       unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM;
 
-       efx_flush_queues(efx);
+       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 u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
 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;
+               rc = -EBUSY;
+               goto out;
        }
 
-       /* 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. */
+       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;
+       rc = efx_selftest(efx, &efx_tests, test->flags);
 
-       /* 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:
        if (!already_up)
                dev_close(efx->net_dev);
 
-       EFX_LOG(efx, "%s all %sline self-tests\n",
-               rc == 0 ? "passed" : "failed", offline ? "off" : "on");
+       EFX_LOG(efx, "%s %sline self-tests\n",
+               rc == 0 ? "passed" : "failed",
+               (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
 
- fail2:
- fail1:
-       /* Fill ethtool results structures */
+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 net_device *net_dev,
 /* Restart autonegotiation */
 static int efx_ethtool_nway_reset(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
-       return mii_nway_restart(&efx->mii);
+       return mdio45_nway_restart(&efx->mdio);
 }
 
 static u32 efx_ethtool_get_link(struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       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;
 
-       return efx->link_up;
+       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(struct net_device *net_dev,
                }
        }
 
-       /* 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_get_coalesce(struct net_device *net_dev,
 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;
+       unsigned tx_usecs, rx_usecs, adaptive;
 
-       if (coalesce->use_adaptive_rx_coalesce ||
-           coalesce->use_adaptive_tx_coalesce)
+       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(struct net_device *net_dev,
 
        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(struct net_device *net_dev,
                }
        }
 
-       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_coalesce(struct net_device *net_dev,
 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;
+       struct efx_nic *efx = netdev_priv(net_dev);
+       enum efx_fc_type wanted_fc, old_fc;
+       u32 old_adv;
+       bool reset;
+       int rc = 0;
 
-       /* Try to push the pause parameters */
        mutex_lock(&efx->mac_lock);
-       rc = efx->mac_op->set_pause(efx, flow_control);
-       mutex_unlock(&efx->mac_lock);
 
-       if (!rc)
-               efx_reconfigure_port(efx);
+       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);
 
        return rc;
 }
@@ -683,31 +835,81 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
 static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
                                       struct ethtool_pauseparam *pause)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
 
-       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;
+       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;
 }
+#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);
+}
 
-struct ethtool_ops efx_ethtool_ops = {
+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 --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h
deleted file mode 100644 (file)
index f7a4249..0000000
+++ /dev/null
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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 --git a/drivers/net/sfc/extraversion.h b/drivers/net/sfc/extraversion.h
deleted file mode 100644 (file)
index c2742e9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/*
- * If compiling on kernels with backported features you may need to
- * define EFX_DIST_KVER_ symbols here
- */
index 4f4d7bb679628f23ba17c74e8b077b6f3cc24743..c6dcb313f34da87d1ec49623c45d0d6047278741 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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>
 #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 int descriptor_cache_size = 64;
 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);
+       EFX_POPULATE_OWORD_1(temp, FRF_BB_PCIE_CORE_TARGET_REG_ADRS, address);
 
-       falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG);
-       falcon_read(efx, &temp, PCIE_CORE_INDIRECT_REG);
+       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,1722 +105,449 @@ static void falcon_pcie_core_write_reg(struct efx_nic *efx, int address,
  *
  **************************************************************************
  */
-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;
+
+       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);
-       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);
+       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(struct efx_i2c_interface *i2c)
+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_OWORD_FIELD(reg, GPIO3_IN);
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       return EFX_OWORD_FIELD(reg, FRF_AB_GPIO3_IN);
 }
 
-static int falcon_getscl(struct efx_i2c_interface *i2c)
+static int falcon_getscl(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);
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN);
 }
 
-static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
-       .setsda         = falcon_setsdascl,
-       .setscl         = falcon_setsdascl,
+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)
+static void falcon_push_irq_moderation(struct efx_channel *channel)
 {
-       efx_qword_t buf_desc;
-       int index;
-       dma_addr_t dma_addr;
-       int i;
+       efx_dword_t timer_cmd;
+       struct efx_nic *efx = channel->efx;
 
-       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);
+       /* Set timer register */
+       if (channel->irq_moderation) {
+               EFX_POPULATE_DWORD_2(timer_cmd,
+                                    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,
+                                    FRF_AB_TC_TIMER_MODE,
+                                    FFE_BB_TIMER_MODE_DIS,
+                                    FRF_AB_TC_TIMER_VAL, 0);
        }
-
-       return 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);
 }
 
-/* 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;
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
 
-       EFX_LOG(efx, "unmapping special buffers %d-%d\n",
-               buffer->index, buffer->index + buffer->entries - 1);
+static void falcon_prepare_flush(struct efx_nic *efx)
+{
+       falcon_deconfigure_mac_wrapper(efx);
 
-       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);
+       /* 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);
 }
 
-/*
- * Allocate a new Falcon special buffer
+/* Acknowledge a legacy interrupt from Falcon
+ *
+ * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
  *
- * 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.
+ * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
+ * BIU. Interrupt acknowledge is read sensitive so must write instead
+ * (then read to ensure the BIU collector is flushed)
  *
- * This call will allocate 4KB buffers, since Falcon can't use 8KB
- * buffers for event queues and descriptor rings.
+ * NB most hardware supports MSI interrupts
  */
-static int falcon_alloc_special_buffer(struct efx_nic *efx,
-                                      struct efx_special_buffer *buffer,
-                                      unsigned int len)
+inline void falcon_irq_ack_a1(struct efx_nic *efx)
 {
-       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));
+       efx_dword_t reg;
 
-       return 0;
+       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);
 }
 
-/* Release the buffer memory. */
-static void falcon_free_special_buffer(struct efx_nic *efx,
-                                      struct efx_special_buffer *buffer)
+#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
 {
-       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));
+       struct efx_nic *efx = dev_id;
+       efx_oword_t *int_ker = efx->irq_status.addr;
+       struct efx_channel *channel;
+       int syserr;
+       int queues;
 
-       pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
-                           buffer->dma_addr);
-       buffer->addr = NULL;
-       buffer->entries = 0;
-}
+       /* Check to see if this is our interrupt.  If it isn't, we
+        * exit without having touched the hardware.
+        */
+       if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
+               EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
+                         raw_smp_processor_id());
+               return IRQ_NONE;
+       }
+       efx->last_irq_cpu = raw_smp_processor_id();
+       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+                 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
-/**************************************************************************
- *
- * Falcon generic buffer handling
- * These buffers are used for interrupt status and MAC stats
- *
- **************************************************************************/
+       /* Check to see if we have a serious error condition */
+       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
+       if (unlikely(syserr))
+               return efx_nic_fatal_interrupt(efx);
 
-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;
-}
+       /* Determine interrupting queues, clear interrupt status
+        * register and acknowledge the device interrupt.
+        */
+       BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS);
+       queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q);
+       EFX_ZERO_OWORD(*int_ker);
+       wmb(); /* Ensure the vector is cleared before interrupt ack */
+       falcon_irq_ack_a1(efx);
 
-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;
+       /* Schedule processing of any interrupting queues */
+       channel = &efx->channel[0];
+       while (queues) {
+               if (queues & 0x01)
+                       efx_schedule_channel(channel);
+               channel++;
+               queues >>= 1;
        }
+
+       return IRQ_HANDLED;
 }
 
 /**************************************************************************
  *
- * Falcon TX path
+ * EEPROM/flash
  *
- **************************************************************************/
-
-/* 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);
-}
 
+#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
 
-/* 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)
+static int falcon_spi_poll(struct efx_nic *efx)
 {
-
-       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);
+       efx_oword_t reg;
+       efx_reado(efx, &reg, FR_AB_EE_SPI_HCMD);
+       return EFX_OWORD_FIELD(reg, FRF_AB_EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0;
 }
 
-/* Allocate hardware resources for a TX queue */
-int falcon_probe_tx(struct efx_tx_queue *tx_queue)
+/* Wait for SPI command completion */
+static int falcon_spi_wait(struct efx_nic *efx)
 {
-       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;
+       /* Most commands will finish quickly, so we start polling at
+        * very short intervals.  Sometimes the command may have to
+        * wait for VPD or expansion ROM access outside of our
+        * control, so we allow up to 100 ms. */
+       unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10);
+       int i;
 
-       nic_data->resources.txq_min = max(nic_data->resources.txq_min,
-                                         (unsigned)tx_queue->queue + 1);
+       for (i = 0; i < 10; i++) {
+               if (!falcon_spi_poll(efx))
+                       return 0;
+               udelay(10);
+       }
 
-       return 0;
+       for (;;) {
+               if (!falcon_spi_poll(efx))
+                       return 0;
+               if (time_after_eq(jiffies, timeout)) {
+                       EFX_ERR(efx, "timed out waiting for SPI\n");
+                       return -ETIMEDOUT;
+               }
+               schedule_timeout_uninterruptible(1);
+       }
 }
 
-/* Prepare channel's TX datapath. */
-int falcon_init_tx(struct efx_tx_queue *tx_queue)
+int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi,
+                  unsigned int command, int address,
+                  const void *in, void *out, size_t len)
 {
-       efx_oword_t tx_desc_ptr;
-       struct efx_nic *efx = tx_queue->efx;
+       bool addressed = (address >= 0);
+       bool reading = (out != NULL);
+       efx_oword_t reg;
        int rc;
 
-       /* Pin TX descriptor ring */
-       rc = falcon_init_special_buffer(efx, &tx_queue->txd);
+       /* Input validation */
+       if (len > FALCON_SPI_MAX_LEN)
+               return -EINVAL;
+       BUG_ON(!mutex_is_locked(&efx->spi_lock));
+
+       /* Check that previous command is not still running */
+       rc = falcon_spi_poll(efx);
        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);
+       /* Program address register, if we have an address */
+       if (addressed) {
+               EFX_POPULATE_OWORD_1(reg, FRF_AB_EE_SPI_HADR_ADR, address);
+               efx_writeo(efx, &reg, FR_AB_EE_SPI_HADR);
        }
 
-       falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
-                          tx_queue->queue);
+       /* Program data register, if we have data */
+       if (in != NULL) {
+               memcpy(&reg, in, len);
+               efx_writeo(efx, &reg, FR_AB_EE_SPI_HDATA);
+       }
 
-       if (FALCON_REV(efx) < FALCON_REV_B0) {
-               efx_oword_t reg;
+       /* Issue read/write command */
+       EFX_POPULATE_OWORD_7(reg,
+                            FRF_AB_EE_SPI_HCMD_CMD_EN, 1,
+                            FRF_AB_EE_SPI_HCMD_SF_SEL, spi->device_id,
+                            FRF_AB_EE_SPI_HCMD_DABCNT, len,
+                            FRF_AB_EE_SPI_HCMD_READ, reading,
+                            FRF_AB_EE_SPI_HCMD_DUBCNT, 0,
+                            FRF_AB_EE_SPI_HCMD_ADBCNT,
+                            (addressed ? spi->addr_len : 0),
+                            FRF_AB_EE_SPI_HCMD_ENC, command);
+       efx_writeo(efx, &reg, FR_AB_EE_SPI_HCMD);
 
-               /* Only 128 bits in this register */
-               BUG_ON(tx_queue->queue >= 128);
+       /* Wait for read/write to complete */
+       rc = falcon_spi_wait(efx);
+       if (rc)
+               return rc;
 
-               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);
+       /* Read data */
+       if (out != NULL) {
+               efx_reado(efx, &reg, FR_AB_EE_SPI_HDATA);
+               memcpy(out, &reg, len);
        }
 
        return 0;
 }
 
-static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
+static size_t
+falcon_spi_write_limit(const struct efx_spi_device *spi, size_t start)
 {
-       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;
+       return min(FALCON_SPI_MAX_LEN,
+                  (spi->block_size - (start & (spi->block_size - 1))));
+}
 
-       /* 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;
+static inline u8
+efx_spi_munge_command(const struct efx_spi_device *spi,
+                     const u8 command, const unsigned int address)
+{
+       return command | (((address >> 8) & spi->munge_address) << 3);
+}
+
+/* Wait up to 10 ms for buffered write completion */
+int
+falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi)
+{
+       unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100);
+       u8 status;
+       int rc;
 
-               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);
+       for (;;) {
+               rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
+                                   &status, sizeof(status));
+               if (rc)
+                       return rc;
+               if (!(status & SPI_STATUS_NRDY))
                        return 0;
+               if (time_after_eq(jiffies, timeout)) {
+                       EFX_ERR(efx, "SPI write timeout on device %d"
+                               " last status=0x%02x\n",
+                               spi->device_id, status);
+                       return -ETIMEDOUT;
                }
-
-               read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+               schedule_timeout_uninterruptible(1);
        }
+}
 
-       if (EFX_WORKAROUND_11557(efx)) {
-               efx_oword_t reg;
-               int enabled;
+int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi,
+                   loff_t start, size_t len, size_t *retlen, u8 *buffer)
+{
+       size_t block_len, pos = 0;
+       unsigned int command;
+       int rc = 0;
 
-               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;
+       while (pos < len) {
+               block_len = min(len - pos, FALCON_SPI_MAX_LEN);
+
+               command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+               rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL,
+                                   buffer + pos, block_len);
+               if (rc)
+                       break;
+               pos += block_len;
+
+               /* Avoid locking up the system */
+               cond_resched();
+               if (signal_pending(current)) {
+                       rc = -EINTR;
+                       break;
                }
        }
 
-       EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
-       return -ETIMEDOUT;
+       if (retlen)
+               *retlen = pos;
+       return rc;
 }
 
-void falcon_fini_tx(struct efx_tx_queue *tx_queue)
+int
+falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi,
+                loff_t start, size_t len, size_t *retlen, const u8 *buffer)
 {
-       struct efx_nic *efx = tx_queue->efx;
-       efx_oword_t tx_desc_ptr;
+       u8 verify_buffer[FALCON_SPI_MAX_LEN];
+       size_t block_len, pos = 0;
+       unsigned int command;
+       int rc = 0;
 
-       /* 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);
+       while (pos < len) {
+               rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
+               if (rc)
+                       break;
 
-       /* 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);
+               block_len = min(len - pos,
+                               falcon_spi_write_limit(spi, start + pos));
+               command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
+               rc = falcon_spi_cmd(efx, spi, command, start + pos,
+                                   buffer + pos, NULL, block_len);
+               if (rc)
+                       break;
 
-       /* Unpin TX descriptor ring */
-       falcon_fini_special_buffer(efx, &tx_queue->txd);
-}
+               rc = falcon_spi_wait_write(efx, spi);
+               if (rc)
+                       break;
 
-/* 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);
+               command = efx_spi_munge_command(spi, SPI_READ, start + pos);
+               rc = falcon_spi_cmd(efx, spi, command, start + pos,
+                                   NULL, verify_buffer, block_len);
+               if (memcmp(verify_buffer, buffer + pos, block_len)) {
+                       rc = -EIO;
+                       break;
+               }
+
+               pos += block_len;
+
+               /* Avoid locking up the system */
+               cond_resched();
+               if (signal_pending(current)) {
+                       rc = -EINTR;
+                       break;
+               }
+       }
+
+       if (retlen)
+               *retlen = pos;
+       return rc;
 }
 
 /**************************************************************************
  *
- * Falcon RX path
+ * MAC wrapper
  *
- **************************************************************************/
-
-/* 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)
+static void falcon_push_multicast_hash(struct efx_nic *efx)
 {
-       efx_dword_t reg;
-       unsigned write_ptr;
+       union efx_multicast_hash *mc_hash = &efx->multicast_hash;
 
-       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;
-       }
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
 
-       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);
+       efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
+       efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
 }
 
-int falcon_probe_rx(struct efx_rx_queue *rx_queue)
+static void falcon_reset_macs(struct efx_nic *efx)
 {
-       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);
+       efx_oword_t reg, mac_ctrl;
+       int count;
 
-       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)
-{
-       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).
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
+               /* It's not safe to use GLB_CTL_REG to reset the
+                * macs, so instead use the internal MAC resets
                 */
-               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);
-       } 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);
-}
-
-/* Acknowledge a legacy interrupt from Falcon
- *
- * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
- *
- * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
- * BIU. Interrupt acknowledge is read sensitive so must write instead
- * (then read to ensure the BIU collector is flushed)
- *
- * NB most hardware supports MSI interrupts
- */
-static 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;
-       struct efx_channel *channel;
-       efx_dword_t reg;
-       u32 queues;
-       int syserr;
-
-       /* Read the ISR which also ACKs the interrupts */
-       falcon_readl(efx, &reg, INT_ISR0_B0);
-       queues = EFX_EXTRACT_DWORD(reg, 0, 31);
-
-       /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
-       if (unlikely(syserr))
-               return falcon_fatal_interrupt(efx);
-
-       if (queues == 0)
-               return IRQ_NONE;
-
-       efx->last_irq_cpu = raw_smp_processor_id();
-       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
-                 irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
-
-       /* Schedule processing of any interrupting queues */
-       channel = &efx->channel[0];
-       while (queues) {
-               if (queues & 0x01)
-                       efx_schedule_channel(channel);
-               channel++;
-               queues >>= 1;
-       }
-
-       return IRQ_HANDLED;
-}
-
-
-static irqreturn_t falcon_legacy_interrupt_a1(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;
-       struct efx_channel *channel;
-       int syserr;
-       int queues;
-
-       /* Check to see if this is our interrupt.  If it isn't, we
-        * exit without having touched the hardware.
-        */
-       if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
-               EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
-                         raw_smp_processor_id());
-               return IRQ_NONE;
-       }
-       efx->last_irq_cpu = raw_smp_processor_id();
-       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
-                 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
-
-       /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
-       if (unlikely(syserr))
-               return falcon_fatal_interrupt(efx);
-
-       /* Determine interrupting queues, clear interrupt status
-        * register and acknowledge the device interrupt.
-        */
-       BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
-       queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
-       EFX_ZERO_OWORD(*int_ker);
-       wmb(); /* Ensure the vector is cleared before interrupt ack */
-       falcon_irq_ack_a1(efx);
-
-       /* Schedule processing of any interrupting queues */
-       channel = &efx->channel[0];
-       while (queues) {
-               if (queues & 0x01)
-                       efx_schedule_channel(channel);
-               channel++;
-               queues >>= 1;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/* Handle an MSI interrupt from Falcon
- *
- * Handle an MSI hardware interrupt.  This routine schedules event
- * queue processing.  No interrupt acknowledgement cycle is necessary.
- * Also, we never need to check that the interrupt is for us, since
- * MSI interrupts cannot be shared.
- *
- * 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_msi_interrupt(int irq, void *dev_id,
-                                       struct pt_regs *regs
-                                       __attribute__ ((unused)))
-{
-       struct efx_channel *channel = (struct efx_channel *)dev_id;
-       struct efx_nic *efx = channel->efx;
-       efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
-       int syserr;
-
-       efx->last_irq_cpu = raw_smp_processor_id();
-       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
-                 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
-
-       /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
-       if (unlikely(syserr))
-               return falcon_fatal_interrupt(efx);
-
-       /* Schedule processing of the channel */
-       efx_schedule_channel(channel);
-
-       return IRQ_HANDLED;
-}
-
-
-/* Setup RSS indirection table.
- * This maps from the hash value of the packet to RXQ
- */
-static void falcon_setup_rss_indir_table(struct efx_nic *efx)
-{
-       int i = 0;
-       unsigned long offset;
-       efx_dword_t dword;
-
-       if (FALCON_REV(efx) < FALCON_REV_B0)
-               return;
-
-       for (offset = RX_RSS_INDIR_TBL_B0;
-            offset < RX_RSS_INDIR_TBL_B0 + 0x800;
-            offset += 0x10) {
-               EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
-                                    i % efx->rss_queues);
-               falcon_writel(efx, &dword, offset);
-               i++;
-       }
-}
-
-/* Hook interrupt handler(s)
- * Try MSI and then legacy interrupts.
- */
-int falcon_init_interrupt(struct efx_nic *efx)
-{
-       struct efx_channel *channel;
-       int rc;
-
-       if (!EFX_INT_MODE_USE_MSI(efx)) {
-               irq_handler_t handler;
-               if (FALCON_REV(efx) >= FALCON_REV_B0)
-                       handler = falcon_legacy_interrupt_b0;
-               else
-                       handler = falcon_legacy_interrupt_a1;
-
-               rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
-                                efx->name, efx);
-               if (rc) {
-                       EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
-                               efx->pci_dev->irq);
-                       goto fail1;
-               }
-               return 0;
-       }
+               if (!EFX_IS10G(efx)) {
+                       EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 1);
+                       efx_writeo(efx, &reg, FR_AB_GM_CFG1);
+                       udelay(1000);
+
+                       EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
+                       efx_writeo(efx, &reg, FR_AB_GM_CFG1);
+                       udelay(1000);
+                       return;
+               } else {
+                       EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
+                       efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
+
+                       for (count = 0; count < 10000; count++) {
+                               efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
+                               if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
+                                   0)
+                                       return;
+                               udelay(10);
+                       }
 
-       /* Hook MSI or MSI-X interrupt */
-       efx_for_each_channel_with_interrupt(channel, efx) {
-               rc = request_irq(channel->irq, falcon_msi_interrupt,
-                                IRQF_PROBE_SHARED, /* Not shared */
-                                efx->name, channel);
-               if (rc) {
-                       EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
-                       goto fail2;
+                       EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
                }
-       }
-
-       return 0;
-
- fail2:
-       efx_for_each_channel_with_interrupt(channel, efx)
-               free_irq(channel->irq, channel);
- fail1:
-       return rc;
-}
-
-void falcon_fini_interrupt(struct efx_nic *efx)
-{
-       struct efx_channel *channel;
-       efx_oword_t reg;
-
-       /* Disable MSI/MSI-X interrupts */
-       efx_for_each_channel_with_interrupt(channel, efx)
-               if (channel->irq)
-                       free_irq(channel->irq, channel);
-
-       /* ACK legacy interrupt */
-       if (FALCON_REV(efx) >= FALCON_REV_B0)
-               falcon_read(efx, &reg, INT_ISR0_B0);
-       else
-               falcon_irq_ack_a1(efx);
-
-       /* Disable legacy interrupt */
-       if (efx->legacy_irq)
-               free_irq(efx->legacy_irq, efx);
-}
-
-/**************************************************************************
- *
- * EEPROM/flash
- *
- **************************************************************************
- */
-
-/* Wait for SPI command completion */
-static int falcon_spi_wait(struct efx_nic *efx)
-{
-       efx_oword_t reg;
-       int cmd_en, timer_active;
-       int count;
-
-       count = 0;
-       do {
-               falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
-               cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
-               timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
-               if (!cmd_en && !timer_active)
-                       return 0;
-               udelay(10);
-       } while (++count < 10000); /* wait upto 100msec */
-       EFX_ERR(efx, "timed out waiting for SPI\n");
-       return -ETIMEDOUT;
-}
-
-static int
-falcon_spi_read(const struct efx_spi_device *spi, struct efx_nic *efx,
-               unsigned int command, int address, void *data, unsigned int len)
-{
-       int addressed = (address >= 0);
-       efx_oword_t reg;
-       int rc;
-
-       /* Input validation */
-       if (len > FALCON_SPI_MAX_LEN)
-               return -EINVAL;
-
-       /* Acquire SPI lock */
-       mutex_lock(&efx->spi_lock);
-
-       /* Check SPI not currently being accessed */
-       rc = falcon_spi_wait(efx);
-       if (rc)
-               goto out;
-
-       /* Program address register, if we have an address */
-       if (addressed) {
-               EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
-               falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
-       }
-
-       /* Issue read command */
-       EFX_POPULATE_OWORD_7(reg,
-                            EE_SPI_HCMD_CMD_EN, 1,
-                            EE_SPI_HCMD_SF_SEL, spi->device_id,
-                            EE_SPI_HCMD_DABCNT, len,
-                            EE_SPI_HCMD_READ, EE_SPI_READ,
-                            EE_SPI_HCMD_DUBCNT, 0,
-                            EE_SPI_HCMD_ADBCNT,
-                            (addressed ? spi->addr_len : 0),
-                            EE_SPI_HCMD_ENC, command);
-       falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
-
-       /* Wait for read to complete */
-       rc = falcon_spi_wait(efx);
-       if (rc)
-               goto out;
-
-       /* Read data */
-       falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
-       memcpy(data, &reg, len);
-
- out:
-       /* Release SPI lock */
-       mutex_unlock(&efx->spi_lock);
-
-       return rc;
-}
-
-static int
-falcon_spi_write(const struct efx_spi_device *spi, struct efx_nic *efx,
-                unsigned int command, int address, const void *data,
-                unsigned int len)
-{
-       int addressed = (address >= 0);
-       efx_oword_t reg;
-       int rc;
-
-       /* Input validation */
-       if (len > (addressed ? efx_spi_write_limit(spi, address)
-                  : FALCON_SPI_MAX_LEN))
-               return -EINVAL;
-
-       /* Acquire SPI lock */
-       mutex_lock(&efx->spi_lock);
-
-       /* Check SPI not currently being accessed */
-       rc = falcon_spi_wait(efx);
-       if (rc)
-               goto out;
-
-       /* Program address register, if we have an address */
-       if (addressed) {
-               EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
-               falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
-       }
-
-       /* Program data register, if we have data */
-       if (data) {
-               memcpy(&reg, data, len);
-               falcon_write(efx, &reg, EE_SPI_HDATA_REG_KER);
-       }
-
-       /* Issue write command */
-       EFX_POPULATE_OWORD_7(reg,
-                            EE_SPI_HCMD_CMD_EN, 1,
-                            EE_SPI_HCMD_SF_SEL, spi->device_id,
-                            EE_SPI_HCMD_DABCNT, len,
-                            EE_SPI_HCMD_READ, EE_SPI_WRITE,
-                            EE_SPI_HCMD_DUBCNT, 0,
-                            EE_SPI_HCMD_ADBCNT,
-                            (addressed ? spi->addr_len : 0),
-                            EE_SPI_HCMD_ENC, command);
-       falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
-
-       /* Wait for write to complete */
-       rc = falcon_spi_wait(efx);
-       if (rc)
-               goto out;
-
- out:
-       /* Release SPI lock */
-       mutex_unlock(&efx->spi_lock);
-
-       return rc;
-}
-
-/**************************************************************************
- *
- * MAC wrapper
- *
- **************************************************************************
- */
-void falcon_drain_tx_fifo(struct efx_nic *efx)
-{
-       efx_oword_t temp;
-       int count;
-
-       if (FALCON_REV(efx) < FALCON_REV_B0)
-               return;
-
-       falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
-       /* There is no point in draining more than once */
-       if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
-               return;
+       }
 
-       /* MAC stats will fail whilst the TX fifo is draining. Serialise
-        * the drain sequence with the statistics fetch */
-       spin_lock(&efx->stats_lock);
+       /* Mac stats will fail whist the TX fifo is draining */
+       WARN_ON(nic_data->stats_disable_count == 0);
 
-       EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
-       falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
+       efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL);
+       EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1);
+       efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 
-       /* Reset the MAC and EM block. */
-       falcon_read(efx, &temp, GLB_CTL_REG_KER);
-       EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
-       EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
-       EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
-       falcon_write(efx, &temp, GLB_CTL_REG_KER);
+       efx_reado(efx, &reg, FR_AB_GLB_CTL);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGRX, 1);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_EM, 1);
+       efx_writeo(efx, &reg, FR_AB_GLB_CTL);
 
        count = 0;
        while (1) {
-               falcon_read(efx, &temp, GLB_CTL_REG_KER);
-               if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
-                   !EFX_OWORD_FIELD(temp, RST_XGRX) &&
-                   !EFX_OWORD_FIELD(temp, RST_EM)) {
+               efx_reado(efx, &reg, FR_AB_GLB_CTL);
+               if (!EFX_OWORD_FIELD(reg, FRF_AB_RST_XGTX) &&
+                   !EFX_OWORD_FIELD(reg, FRF_AB_RST_XGRX) &&
+                   !EFX_OWORD_FIELD(reg, FRF_AB_RST_EM)) {
                        EFX_LOG(efx, "Completed MAC reset after %d loops\n",
                                count);
                        break;
@@ -1979,135 +560,198 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
                udelay(10);
        }
 
-       spin_unlock(&efx->stats_lock);
-
-       /* If we've reset the EM block and the link is up, then
-        * we'll have to kick the XAUI link so the PHY can recover */
-       if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
-               falcon_reset_xaui(efx);
+       /* Ensure the correct MAC is selected before statistics
+        * are re-enabled by the caller */
+       efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 }
 
-void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+void falcon_drain_tx_fifo(struct efx_nic *efx)
 {
-       struct falcon_nic_data *nic_data = efx->nic_data;
-       efx_oword_t temp;
-       int changing_loopback;
+       efx_oword_t reg;
 
-       if (FALCON_REV(efx) < FALCON_REV_B0)
+       if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) ||
+           (efx->loopback_mode != LOOPBACK_NONE))
                return;
 
-       /* Isolate the MAC -> RX */
-       falcon_read(efx, &temp, RX_CFG_REG_KER);
-       EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
-       falcon_write(efx, &temp, RX_CFG_REG_KER);
+       efx_reado(efx, &reg, FR_AB_MAC_CTRL);
+       /* There is no point in draining more than once */
+       if (EFX_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN))
+               return;
 
-       /* Synchronise the EM block against any loopback mode changes by
-        * draining the TX fifo and resetting. */
-       changing_loopback = (efx->loopback_mode != nic_data->old_loopback_mode);
-       nic_data->old_loopback_mode = efx->loopback_mode;
+       falcon_reset_macs(efx);
+}
 
-       if (EFX_WORKAROUND_11667(efx) && (efx->phy_type == PHY_TYPE_10XPRESS)) {
-               if (changing_loopback)
-                       return;
-       }
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+{
+       efx_oword_t reg;
 
-       if (changing_loopback || !efx->link_up)
-               falcon_drain_tx_fifo(efx);
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+               return;
+
+       /* Isolate the MAC -> RX */
+       efx_reado(efx, &reg, FR_AZ_RX_CFG);
+       EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
+       efx_writeo(efx, &reg, FR_AZ_RX_CFG);
+
+       /* Isolate TX -> MAC */
+       falcon_drain_tx_fifo(efx);
 }
 
 void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 {
+       struct efx_link_state *link_state = &efx->link_state;
        efx_oword_t reg;
        int link_speed;
-       unsigned int tx_fc;
-
-       if (efx->link_options & GM_LPA_10000)
-               link_speed = 0x3;
-       else if (efx->link_options & GM_LPA_1000)
-               link_speed = 0x2;
-       else if (efx->link_options & GM_LPA_100)
-               link_speed = 0x1;
-       else
-               link_speed = 0x0;
+
+       switch (link_state->speed) {
+       case 10000: link_speed = 3; break;
+       case 1000:  link_speed = 2; break;
+       case 100:   link_speed = 1; break;
+       default:    link_speed = 0; break;
+       }
+
        /* MAC_LINK_STATUS controls MAC backpressure but doesn't work
         * as advertised.  Disable to ensure packets are not
         * indefinitely held and TX queue can be flushed at any point
         * while the link is down. */
        EFX_POPULATE_OWORD_5(reg,
-                            MAC_XOFF_VAL, 0xffff /* max pause time */,
-                            MAC_BCAD_ACPT, 1,
-                            MAC_UC_PROM, efx->promiscuous,
-                            MAC_LINK_STATUS, 1, /* always set */
-                            MAC_SPEED, link_speed);
+                            FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */,
+                            FRF_AB_MAC_BCAD_ACPT, 1,
+                            FRF_AB_MAC_UC_PROM, efx->promiscuous,
+                            FRF_AB_MAC_LINK_STATUS, 1, /* always set */
+                            FRF_AB_MAC_SPEED, link_speed);
        /* On B0, MAC backpressure can be disabled and packets get
         * discarded. */
-       if (FALCON_REV(efx) >= FALCON_REV_B0) {
-               EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
-                                   !efx->link_up);
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+               EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
+                                   !link_state->up);
        }
 
-       falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
+       efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
 
        /* Restore the multicast hash registers. */
-       falcon_set_multicast_hash(efx);
-
-       /* Transmission of pause frames when RX crosses the threshold is
-        * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
-        * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
-       tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
-       falcon_read(efx, &reg, RX_CFG_REG_KER);
-       EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
+       falcon_push_multicast_hash(efx);
 
+       efx_reado(efx, &reg, FR_AZ_RX_CFG);
+       /* Enable XOFF signal from RX FIFO (we enabled it during NIC
+        * initialisation but it may read back as 0) */
+       EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
        /* Unisolate the MAC -> RX */
-       if (FALCON_REV(efx) >= FALCON_REV_B0)
-               EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
-       falcon_write(efx, &reg, RX_CFG_REG_KER);
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+       efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
-int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
+static void falcon_stats_request(struct efx_nic *efx)
 {
+       struct falcon_nic_data *nic_data = efx->nic_data;
        efx_oword_t reg;
-       u32 *dma_done;
-       int i;
 
-       if (disable_dma_stats)
-               return 0;
+       WARN_ON(nic_data->stats_pending);
+       WARN_ON(nic_data->stats_disable_count);
 
-       /* Statistics fetch will fail if the MAC is in TX drain */
-       if (FALCON_REV(efx) >= FALCON_REV_B0) {
-               efx_oword_t temp;
-               falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
-               if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
-                       return 0;
-       }
+       if (nic_data->stats_dma_done == NULL)
+               return; /* no mac selected */
 
-       /* Clear completion pointer */
-       dma_done = (efx->stats_buffer.addr + done_offset);
-       *dma_done = FALCON_STATS_NOT_DONE;
+       *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE;
+       nic_data->stats_pending = true;
        wmb(); /* ensure done flag is clear */
 
        /* Initiate DMA transfer of stats */
        EFX_POPULATE_OWORD_2(reg,
-                            MAC_STAT_DMA_CMD, 1,
-                            MAC_STAT_DMA_ADR,
+                            FRF_AB_MAC_STAT_DMA_CMD, 1,
+                            FRF_AB_MAC_STAT_DMA_ADR,
                             efx->stats_buffer.dma_addr);
-       falcon_write(efx, &reg, MAC0_STAT_DMA_REG_KER);
+       efx_writeo(efx, &reg, FR_AB_MAC_STAT_DMA);
 
-       /* Wait for transfer to complete */
-       for (i = 0; i < 400; i++) {
-               if (*(volatile u32 *)dma_done == FALCON_STATS_DONE)
-                       return 0;
-               udelay(10);
-       }
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_HAVE_ROUND_JIFFIES_UP)
+       mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2));
+#else
+       mod_timer(&nic_data->stats_timer, jiffies + HZ);
+#endif
+}
+
+static void falcon_stats_complete(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+
+       if (!nic_data->stats_pending)
+               return;
 
-       if (EFX_WORKAROUND_8419(efx)) {
-               disable_dma_stats = 1;
-               EFX_INFO(efx, "MAC stats DMA disabled\n");
+       nic_data->stats_pending = 0;
+       if (*nic_data->stats_dma_done == FALCON_STATS_DONE) {
+               rmb(); /* read the done flag before the stats */
+               efx->mac_op->update_stats(efx);
        } else {
                EFX_ERR(efx, "timed out waiting for statistics\n");
        }
+}
 
-       return -ETIMEDOUT;
+static void falcon_stats_timer_func(unsigned long context)
+{
+       struct efx_nic *efx = (struct efx_nic *)context;
+       struct falcon_nic_data *nic_data = efx->nic_data;
+
+       spin_lock(&efx->stats_lock);
+
+       falcon_stats_complete(efx);
+       if (nic_data->stats_disable_count == 0)
+               falcon_stats_request(efx);
+
+       spin_unlock(&efx->stats_lock);
+}
+
+static void falcon_switch_mac(struct efx_nic *efx);
+
+static bool falcon_loopback_link_poll(struct efx_nic *efx)
+{
+       struct efx_link_state old_state = efx->link_state;
+
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+       WARN_ON(!LOOPBACK_INTERNAL(efx));
+
+       efx->link_state.fd = true;
+       efx->link_state.fc = efx->wanted_fc;
+       efx->link_state.up = true;
+
+       if (efx->loopback_mode == LOOPBACK_GMAC)
+               efx->link_state.speed = 1000;
+       else
+               efx->link_state.speed = 10000;
+
+       return !efx_link_state_equal(&efx->link_state, &old_state);
+}
+
+static int falcon_reconfigure_port(struct efx_nic *efx)
+{
+       int rc;
+
+       WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0);
+
+       /* Poll the PHY link state *before* reconfiguring it. This means we
+        * will pick up the correct speed (in loopback) to select the correct
+        * MAC.
+        */
+       if (LOOPBACK_INTERNAL(efx))
+               falcon_loopback_link_poll(efx);
+       else
+               efx->phy_op->poll(efx);
+
+       falcon_stop_nic_stats(efx);
+       falcon_deconfigure_mac_wrapper(efx);
+
+       falcon_switch_mac(efx);
+
+       efx->phy_op->reconfigure(efx);
+       rc = efx->mac_op->reconfigure(efx);
+       BUG_ON(rc);
+
+       falcon_start_nic_stats(efx);
+
+       /* Synchronise efx->link_state with the kernel */
+       efx_link_status_changed(efx);
+
+       return 0;
 }
 
 /**************************************************************************
@@ -2117,40 +761,21 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
  **************************************************************************
  */
 
-/* Use the top bit of the MII PHY id to indicate the PHY type
- * (1G/10G), with the remaining bits as the actual PHY id.
- *
- * This allows us to avoid leaking information from the mii_if_info
- * structure into other data structures.
- */
-#define FALCON_PHY_ID_ID_WIDTH  EFX_WIDTH(MD_PRT_DEV_ADR)
-#define FALCON_PHY_ID_ID_MASK   ((1 << FALCON_PHY_ID_ID_WIDTH) - 1)
-#define FALCON_PHY_ID_WIDTH     (FALCON_PHY_ID_ID_WIDTH + 1)
-#define FALCON_PHY_ID_MASK      ((1 << FALCON_PHY_ID_WIDTH) - 1)
-#define FALCON_PHY_ID_10G       (1 << (FALCON_PHY_ID_WIDTH - 1))
-
-
-/* Packing the clause 45 port and device fields into a single value */
-#define MD_PRT_ADR_COMP_LBN   (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN)
-#define MD_PRT_ADR_COMP_WIDTH  MD_PRT_ADR_WIDTH
-#define MD_DEV_ADR_COMP_LBN    0
-#define MD_DEV_ADR_COMP_WIDTH  MD_DEV_ADR_WIDTH
-
-
 /* Wait for GMII access to complete */
 static int falcon_gmii_wait(struct efx_nic *efx)
 {
-       efx_dword_t md_stat;
+       efx_oword_t md_stat;
        int count;
 
-       for (count = 0; count < 1000; count++) {        /* wait upto 10ms */
-               falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
-               if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
-                       if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
-                           EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) {
+       /* wait upto 50ms - taken max from datasheet */
+       for (count = 0; count < 5000; count++) {
+               efx_reado(efx, &md_stat, FR_AB_MD_STAT);
+               if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
+                       if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
+                           EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
                                EFX_ERR(efx, "error from GMII access "
-                                       EFX_DWORD_FMT"\n",
-                                       EFX_DWORD_VAL(md_stat));
+                                       EFX_OWORD_FMT"\n",
+                                       EFX_OWORD_VAL(md_stat));
                                return -EIO;
                        }
                        return 0;
@@ -2161,386 +786,442 @@ static int falcon_gmii_wait(struct efx_nic *efx)
        return -ETIMEDOUT;
 }
 
-/* Writes a GMII register of a PHY connected to Falcon using MDIO. */
-static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
-                             int addr, int value)
+/* Write an MDIO register of a PHY connected to Falcon. */
+static int falcon_mdio_write(struct net_device *net_dev,
+                            int prtad, int devad, u16 addr, u16 value)
 {
-       struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
-       unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
-       unsigned int phy_10g = phy_id & FALCON_PHY_ID_10G;
+       struct efx_nic *efx = netdev_priv(net_dev);
        efx_oword_t reg;
+       int rc;
 
-       /* The 'generic' prt/dev packing in mdio_10g.h is conveniently
-        * chosen so that the only current user, Falcon, can take the
-        * packed value and use them directly.
-        * Fail to build if this assumption is broken.
-        */
-       BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G);
-       BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH);
-       BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN);
-       BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN);
-
-       if (phy_id2 == PHY_ADDR_INVALID)
-               return;
-
-       /* See falcon_mdio_read for an explanation. */
-       if (EFX_ISCLAUSE45(efx) && !phy_10g) {
-               int mmd = ffs(efx->phy_op->mmds) - 1;
-               EFX_TRACE(efx, "Fixing erroneous clause22 write\n");
-               phy_id2 = mdio_clause45_pack(phy_id2, mmd)
-                       & FALCON_PHY_ID_ID_MASK;
-               phy_10g = 1;
-       }
-
-       EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id,
-                   addr, value);
+       EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n",
+                   prtad, devad, addr, value);
 
-       /* Obtain PHY lock */
-       spin_lock_bh(&efx->phy_lock);
+       mutex_lock(&efx->mdio_lock);
 
-       /* Check MII not currently being accessed */
-       if (falcon_gmii_wait(efx) != 0)
+       /* Check MDIO not currently being accessed */
+       rc = falcon_gmii_wait(efx);
+       if (rc)
                goto out;
 
        /* Write the address/ID register */
-       EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
-       falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr);
+       efx_writeo(efx, &reg, FR_AB_MD_PHY_ADR);
 
-       if (phy_10g)
-               EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2);
-       else
-               /* MDIO clause 22 */
-               EFX_POPULATE_OWORD_2(reg,
-                                    MD_PRT_ADR, phy_id2,
-                                    MD_DEV_ADR, addr);
-       falcon_write(efx, &reg, MD_ID_REG_KER);
+       EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad,
+                            FRF_AB_MD_DEV_ADR, devad);
+       efx_writeo(efx, &reg, FR_AB_MD_ID);
 
        /* Write data */
-       EFX_POPULATE_OWORD_1(reg, MD_TXD, value);
-       falcon_write(efx, &reg, MD_TXD_REG_KER);
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_TXD, value);
+       efx_writeo(efx, &reg, FR_AB_MD_TXD);
 
        EFX_POPULATE_OWORD_2(reg,
-                            MD_WRC, 1,
-                            MD_GC, (phy_10g ? 0 : 1));
-       falcon_write(efx, &reg, MD_CS_REG_KER);
+                            FRF_AB_MD_WRC, 1,
+                            FRF_AB_MD_GC, 0);
+       efx_writeo(efx, &reg, FR_AB_MD_CS);
 
        /* Wait for data to be written */
-       if (falcon_gmii_wait(efx) != 0) {
+       rc = falcon_gmii_wait(efx);
+       if (rc) {
                /* Abort the write operation */
                EFX_POPULATE_OWORD_2(reg,
-                                    MD_WRC, 0,
-                                    MD_GC, 1);
-               falcon_write(efx, &reg, MD_CS_REG_KER);
+                                    FRF_AB_MD_WRC, 0,
+                                    FRF_AB_MD_GC, 1);
+               efx_writeo(efx, &reg, FR_AB_MD_CS);
                udelay(10);
        }
 
- out:
-       /* Release PHY lock */
-       spin_unlock_bh(&efx->phy_lock);
+out:
+       mutex_unlock(&efx->mdio_lock);
+       return rc;
 }
 
-/* Reads a GMII register from a PHY connected to Falcon.  If no value
- * could be read, -1 will be returned. */
-static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
+/* Read an MDIO register of a PHY connected to Falcon. */
+static int falcon_mdio_read(struct net_device *net_dev,
+                           int prtad, int devad, u16 addr)
 {
-       struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
-       unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
-       unsigned int phy_10g = phy_id & FALCON_PHY_ID_10G;
+       struct efx_nic *efx = netdev_priv(net_dev);
        efx_oword_t reg;
-       int value = -1;
-
-       if (phy_addr == PHY_ADDR_INVALID)
-               return -1;
-
-       /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G)
-        * but the generic Linux code does not make any distinction or have
-        * any state for this.
-        * We spot the case where someone tried to talk 22 to a 45 PHY and
-        * redirect the request to the lowest numbered MMD as a clause45
-        * request. This is enough to allow simple queries like id and link
-        * state to succeed. TODO: We may need to do more in future.
-        */
-       if (EFX_ISCLAUSE45(efx) && !phy_10g) {
-               int mmd = ffs(efx->phy_op->mmds) - 1;
-               EFX_TRACE(efx, "Fixing erroneous clause22 read\n");
-               phy_addr = mdio_clause45_pack(phy_addr, mmd)
-                       & FALCON_PHY_ID_ID_MASK;
-               phy_10g = 1;
-       }
+       int rc;
 
-       /* Obtain PHY lock */
-       spin_lock_bh(&efx->phy_lock);
+       mutex_lock(&efx->mdio_lock);
 
-       /* Check MII not currently being accessed */
-       if (falcon_gmii_wait(efx) != 0)
+       /* Check MDIO not currently being accessed */
+       rc = falcon_gmii_wait(efx);
+       if (rc)
                goto out;
 
-       if (!phy_10g) {
-               /* Write the address registers */
-               EFX_POPULATE_OWORD_2(reg,
-                                    MD_PRT_ADR, phy_addr,
-                                    MD_DEV_ADR, addr);
-               falcon_write(efx, &reg, MD_ID_REG_KER);
-               /* Request data to be read */
-               EFX_POPULATE_OWORD_2(reg,
-                                    MD_RIC, 1,
-                                    MD_GC, 1);
-       } else {
-               EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
-               falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_MD_PHY_ADR, addr);
+       efx_writeo(efx, &reg, FR_AB_MD_PHY_ADR);
 
-               EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr);
-               falcon_write(efx, &reg, MD_ID_REG_KER);
+       EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_PRT_ADR, prtad,
+                            FRF_AB_MD_DEV_ADR, devad);
+       efx_writeo(efx, &reg, FR_AB_MD_ID);
 
-               /* Request data to be read */
-               EFX_POPULATE_OWORD_2(reg,
-                                    MD_RDC, 1,
-                                    MD_GC, 0);
-       }
-       falcon_write(efx, &reg, MD_CS_REG_KER);
+       /* Request data to be read */
+       EFX_POPULATE_OWORD_2(reg, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0);
+       efx_writeo(efx, &reg, FR_AB_MD_CS);
 
        /* Wait for data to become available */
-       value = falcon_gmii_wait(efx);
-       if (value == 0) {
-               falcon_read(efx, &reg, MD_RXD_REG_KER);
-               value = EFX_OWORD_FIELD(reg, MD_RXD);
-               EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n",
-                           phy_id, addr, value);
+       rc = falcon_gmii_wait(efx);
+       if (rc == 0) {
+               efx_reado(efx, &reg, FR_AB_MD_RXD);
+               rc = EFX_OWORD_FIELD(reg, FRF_AB_MD_RXD);
+               EFX_REGDUMP(efx, "read from MDIO %d register %d.%d, got %04x\n",
+                           prtad, devad, addr, rc);
        } else {
                /* Abort the read operation */
                EFX_POPULATE_OWORD_2(reg,
-                                    MD_RIC, 0,
-                                    MD_GC, 1);
-               falcon_write(efx, &reg, MD_CS_REG_KER);
+                                    FRF_AB_MD_RIC, 0,
+                                    FRF_AB_MD_GC, 1);
+               efx_writeo(efx, &reg, FR_AB_MD_CS);
 
-               EFX_LOG(efx, "read from GMII 0x%x register %02x, got "
-                       "error %d\n", phy_id, addr, value);
+               EFX_LOG(efx, "read from MDIO %d register %d.%d, got error %d\n",
+                       prtad, devad, addr, rc);
        }
 
- out:
-       /* Release PHY lock */
-       spin_unlock_bh(&efx->phy_lock);
-
-       return value;
-}
-
-static void falcon_init_mdio(struct mii_if_info *gmii)
-{
-       gmii->mdio_read = falcon_mdio_read;
-       gmii->mdio_write = falcon_mdio_write;
-       gmii->phy_id_mask = FALCON_PHY_ID_MASK;
-       gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1);
+out:
+       mutex_unlock(&efx->mdio_lock);
+       return rc;
 }
 
-static int falcon_probe_gmac_port(struct efx_nic *efx)
+static void falcon_clock_mac(struct efx_nic *efx)
 {
-       struct efx_phy_operations *phy_op = efx->phy_op;
+       unsigned strap_val;
+       efx_oword_t nic_stat;
 
-       efx->mac_op = &falcon_gmac_operations;
-       efx->loopback_modes = LOOPBACKS_1G_INTERNAL | phy_op->loopbacks;
-       efx->startup_loopbacks = ((1 << LOOPBACK_MAC) |
-                                 (1 << phy_op->startup_loopback));
-       return 0;
+       /* Configure the NIC generated MAC clock correctly */
+       efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
+       strap_val = EFX_IS10G(efx) ? 5 : 3;
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+               EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1);
+               EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val);
+               efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT);
+       } else {
+               /* Falcon A1 does not support 1G/10G speed switching
+                * and must not be used with a PHY that does. */
+               BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) !=
+                      strap_val);
+       }
 }
 
-static int falcon_probe_xmac_port(struct efx_nic *efx)
+static void falcon_switch_mac(struct efx_nic *efx)
 {
-       struct efx_phy_operations *phy_op = efx->phy_op;
+       struct efx_mac_operations *old_mac_op = efx->mac_op;
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       unsigned int stats_done_offset;
 
-       efx->mac_op = &falcon_xmac_operations;
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+       WARN_ON(nic_data->stats_disable_count == 0);
 
-       /* The Falcon B0 FPGA only supports XGMII loopback */
-       if (FALCON_REV(efx) >= FALCON_REV_B0 && !efx->is_asic)
-               efx->loopback_modes = (1 << LOOPBACK_XGMII);
+       efx->mac_op = (EFX_IS10G(efx) ?
+                      &falcon_xmac_operations : &falcon_gmac_operations);
+
+       if (EFX_IS10G(efx))
+               stats_done_offset = XgDmaDone_offset;
        else
-               efx->loopback_modes = LOOPBACKS_10G_INTERNAL;
-       efx->loopback_modes |= phy_op->loopbacks;
+               stats_done_offset = GDmaDone_offset;
+       nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
 
-       efx->startup_loopbacks = ((1 << LOOPBACK_XGMII) |
-                                 (1 << phy_op->startup_loopback));
-       return 0;
+       if (old_mac_op == efx->mac_op)
+               return;
+
+       falcon_clock_mac(efx);
+
+       EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
+       /* Not all macs support a mac-level link state */
+       efx->xmac_poll_required = false;
+       falcon_reset_macs(efx);
 }
 
-static int falcon_probe_phy(struct efx_nic *efx)
+/* This call is responsible for hooking in the MAC and PHY operations */
+static int falcon_probe_port(struct efx_nic *efx)
 {
+       int rc;
+
+       /* Hook in PHY operations table */
        switch (efx->phy_type) {
-       case PHY_TYPE_1G_ALASKA:
-               efx->phy_op = &alaska_phy_operations;
+       case PHY_TYPE_SFX7101:
+               efx->phy_op = &falcon_sfx7101_phy_ops;
                break;
-       case PHY_TYPE_10XPRESS:
-               efx->phy_op = &falcon_tenxpress_phy_ops;
+       case PHY_TYPE_SFT9001A:
+       case PHY_TYPE_SFT9001B:
+               efx->phy_op = &falcon_sft9001_phy_ops;
                break;
-       case PHY_TYPE_NONE:
-               efx->phy_op = &falcon_null_phy_ops;
-               break;
-       case PHY_TYPE_XFP:
-               efx->phy_op = &falcon_xfp_phy_ops;
-               break;
-       case PHY_TYPE_CX4_RTMR:
-               efx->phy_op = &falcon_txc_phy_ops;
-               break;
-       case PHY_TYPE_PM8358:
-               efx->phy_op = &falcon_pm8358_phy_ops;
+       case PHY_TYPE_QT2022C2:
+       case PHY_TYPE_QT2025C:
+               efx->phy_op = &falcon_qt202x_phy_ops;
                break;
        default:
                EFX_ERR(efx, "Unknown PHY type %d\n",
                        efx->phy_type);
-               return -1;
+               return -ENODEV;
        }
-       return 0;
-}
-
-/* This call is responsible for hooking in the MAC and PHY operations */
-int falcon_probe_port(struct efx_nic *efx)
-{
-       int rc;
-
-       /* Hook in PHY operations table */
-       rc = falcon_probe_phy(efx);
-       if (rc)
-               return rc;
 
-       /* Hook in MAC operations table */
-       if (EFX_IS10G(efx))
-               rc = falcon_probe_xmac_port(efx);
-       else
-               rc = falcon_probe_gmac_port(efx);
-       if (rc)
+       /* Fill out MDIO structure and loopback modes */
+       efx->mdio.mdio_read = falcon_mdio_read;
+       efx->mdio.mdio_write = falcon_mdio_write;
+       rc = efx->phy_op->probe(efx);
+       if (rc != 0)
                return rc;
 
-       EFX_LOG(efx, "created port using %cMAC\n",
-               EFX_IS10G(efx) ? 'X' : 'G');
-
-       /* Set up GMII structure for PHY */
-       efx->mii.supports_gmii = 1;
-       falcon_init_mdio(&efx->mii);
+       /* Initial assumption */
+       efx->link_state.speed = 10000;
+       efx->link_state.fd = true;
 
        /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
-       if (FALCON_REV(efx) >= FALCON_REV_B0)
-               efx->flow_control = EFX_FC_RX | EFX_FC_TX;
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+               efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
        else
-               efx->flow_control = EFX_FC_RX;
+               efx->wanted_fc = EFX_FC_RX;
+       if (efx->mdio.mmds & MDIO_DEVS_AN)
+               efx->wanted_fc |= EFX_FC_AUTO;
 
        /* Allocate buffer for stats */
-       rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
-                                FALCON_MAC_STATS_SIZE);
+       rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
+                                 FALCON_MAC_STATS_SIZE);
        if (rc)
                return rc;
-       EFX_LOG(efx, "stats buffer at %llx (virt %p phys %lx)\n",
-               (unsigned long long)efx->stats_buffer.dma_addr,
+       EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
+               (u64)efx->stats_buffer.dma_addr,
                efx->stats_buffer.addr,
-               virt_to_phys(efx->stats_buffer.addr));
+               (u64)virt_to_phys(efx->stats_buffer.addr));
 
        return 0;
 }
 
-void falcon_remove_port(struct efx_nic *efx)
+static void falcon_remove_port(struct efx_nic *efx)
 {
-       /* Free stats buffer */
-       falcon_free_buffer(efx, &efx->stats_buffer);
+       efx->phy_op->remove(efx);
+       efx_nic_free_buffer(efx, &efx->stats_buffer);
 }
 
 /**************************************************************************
  *
- * Multicast filtering
+ * Falcon test code
  *
- **************************************************************************
- */
+ **************************************************************************/
 
-void falcon_set_multicast_hash(struct efx_nic *efx)
+/* Read and verify the correctness of the nvram, optionally returning a copy
+ * of the nvram configuration section if appropriate */
+int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
 {
-       union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+       struct falcon_nvconfig *nvconfig;
+       struct efx_spi_device *spi;
+       void *region;
+       int rc, magic_num, struct_ver;
+       __le16 *word, *limit;
+       u32 csum;
 
-       /* 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);
+       spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
+       if (!spi)
+               return -EINVAL;
 
-       falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER);
-       falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER);
-}
+       region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL);
+       if (!region)
+               return -ENOMEM;
+       nvconfig = region + FALCON_NVCONFIG_OFFSET;
 
-/**************************************************************************
- *
- * Device reset
- *
- **************************************************************************
- */
+       mutex_lock(&efx->spi_lock);
+       rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region);
+       mutex_unlock(&efx->spi_lock);
+       if (rc) {
+               EFX_ERR(efx, "Failed to read %s\n",
+                       efx->spi_flash ? "flash" : "EEPROM");
+               rc = -EIO;
+               goto out;
+       }
 
-static int falcon_clear_b0_memories(struct efx_nic *efx)
-{
-       /* Need to clear memories after a reset. On B0 we can do this
-        * via the net function.
-        */
-       int rc = 0, offset;
-       efx_oword_t blanko;
-       efx_dword_t blankd;
-       unsigned long membase_phys, membase_len;
-       void __iomem *membase_orig;
-       unsigned long flags __attribute__ ((unused));
-
-       EFX_ZERO_OWORD(blanko);
-       EFX_ZERO_DWORD(blankd);
-       membase_orig = efx->membase;
-       membase_phys = pci_resource_start(efx->pci_dev, efx->type->mem_bar);
-
-       for (offset = RX_FILTER_TBL0;
-            offset < RX_RSS_INDIR_TBL_B0;
-            offset += 0x10)
-               falcon_write(efx, &blanko, offset);
-
-       /* Clear RSS indirection table */
-       for (offset = RX_RSS_INDIR_TBL_B0;
-            offset < RX_RSS_INDIR_TBL_B0 + 0x800;
-            offset += 0x10)
-               /* Clear 6 bits every 16 bytes */
-               falcon_writel(efx, &blankd, offset);
-
-       /* Need to split this into several mappings so MSI-X table and PBA
-        * never get mapped
-        */
-       membase_phys = membase_phys + 0x2800000;
-       membase_len = 0x3000000 - 0x2800000;
-
-       efx->membase = ioremap_nocache(membase_phys, membase_len);
-       if (efx->membase == NULL) {
-               EFX_ERR(efx, "could not map memory BAR %d at %lx+%lx\n",
-                       efx->type->mem_bar, membase_phys, membase_len);
-               rc = -ENOMEM;
+       magic_num = le16_to_cpu(nvconfig->board_magic_num);
+       struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
+
+       rc = -EINVAL;
+       if (magic_num != FALCON_NVCONFIG_BOARD_MAGIC_NUM) {
+               EFX_ERR(efx, "NVRAM bad magic 0x%x\n", magic_num);
                goto out;
        }
-       /* Clear the buffer table.  The first 7/8 of it is a duplicate
-        * of the mapping at 0x800000 and must be accessed 2 DWORDs at
-        * a time.  The final 1/8 must be accessed 4 DWORDs at a time.
-        * We make sure to obey both rules at the same time.
-        */
-       for (offset = 0; offset < membase_len; offset += 0x10) {
-               spin_lock_irqsave(&efx->biu_lock, flags);
-               _falcon_writel(efx, 0, offset + 0x0);
-               wmb();
-               _falcon_writel(efx, 0, offset + 0x4);
-               wmb();
-               _falcon_writel(efx, 0, offset + 0x8);
-               wmb();
-               _falcon_writel(efx, 0, offset + 0xc);
-               mmiowb();
-               spin_unlock_irqrestore(&efx->biu_lock, flags);
+       if (struct_ver < 2) {
+               EFX_ERR(efx, "NVRAM has ancient version 0x%x\n", struct_ver);
+               goto out;
+       } else if (struct_ver < 4) {
+               word = &nvconfig->board_magic_num;
+               limit = (__le16 *) (nvconfig + 1);
+       } else {
+               word = region;
+               limit = region + FALCON_NVCONFIG_END;
        }
+       for (csum = 0; word < limit; ++word)
+               csum += le16_to_cpu(*word);
 
-       iounmap(efx->membase);
+       if (~csum & 0xffff) {
+               EFX_ERR(efx, "NVRAM has incorrect checksum\n");
+               goto out;
+       }
 
-out:
-       /* Restore */
-       efx->membase = membase_orig;
+       rc = 0;
+       if (nvconfig_out)
+               memcpy(nvconfig_out, nvconfig, sizeof(*nvconfig));
+
+ out:
+       kfree(region);
+       return rc;
+}
+
+static int
+falcon_b0_test_sram(struct efx_nic *efx,
+                   void (*pattern)(unsigned, efx_qword_t *, int, int),
+                   int a, int b)
+{
+       efx_qword_t buf1, buf2;
+       int wptr, rptr, finish, rc = 0;
+       void __iomem *membase;
+
+       /* So we can test the sram allocated to descriptor caches, access
+        * via SRAM_DBG_REG rather than BUF_FULL_TBL. */
+       BUG_ON(efx->port_enabled);
+       membase = ioremap_nocache(efx->membase_phys + FR_BZ_SRM_DBG,
+                                 efx->sram_lim);
+       if (!membase) {
+               EFX_ERR(efx, "Unable to map SRAM_DBG\n");
+               return -EIO;
+       }
+
+       finish = efx->sram_lim / sizeof(buf1) - 1;
+
+       /* write and verify the pattern in 64 8-byte chunks, to avoid
+        * potentially overrunning the sram update fifo */
+       for (rptr = 0, wptr = 0; wptr <= finish; ++wptr) {
+               pattern(wptr, &buf1, a, b);
+               efx_sram_writeq(efx, membase, &buf1, wptr);
+
+               if (((wptr - rptr) < 64) && (wptr < finish))
+                       continue;
+
+               for (; rptr <= wptr; ++rptr) {
+                       pattern(rptr, &buf1, a, b);
+                       efx_sram_readq(efx, membase, &buf2, rptr);
+
+                       if (!memcmp(&buf1, &buf2, sizeof(buf1)))
+                               continue;
+
+                       EFX_ERR(efx, "sram test failed at index 0x%x. "
+                               "wrote "EFX_QWORD_FMT" read "EFX_QWORD_FMT"\n",
+                               rptr, EFX_QWORD_VAL(buf1), EFX_QWORD_VAL(buf2));
+                       rc = -EIO;
+                       goto out_unmap;
+               }
+       }
+
+out_unmap:
+       iounmap(membase);
 
        return rc;
 }
 
+static int falcon_test_nvram(struct efx_nic *efx)
+{
+       return falcon_read_nvram(efx, NULL);
+}
+
+static const struct efx_nic_register_test falcon_b0_register_tests[] = {
+       { FR_AZ_ADR_REGION,
+         EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
+       { FR_AZ_RX_CFG,
+         EFX_OWORD32(0xFFFFFFFE, 0x00017FFF, 0x00000000, 0x00000000) },
+       { FR_AZ_TX_CFG,
+         EFX_OWORD32(0x7FFF0037, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_TX_RESERVED,
+         EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) },
+       { FR_AB_MAC_CTRL,
+         EFX_OWORD32(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_SRM_TX_DC_CFG,
+         EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_RX_DC_CFG,
+         EFX_OWORD32(0x0000000F, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_RX_DC_PF_WM,
+         EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_BZ_DP_CTRL,
+         EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_GM_CFG2,
+         EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_GMF_CFG0,
+         EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XM_GLB_CFG,
+         EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XM_TX_CFG,
+         EFX_OWORD32(0x00080164, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XM_RX_CFG,
+         EFX_OWORD32(0x07100A0C, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XM_RX_PARAM,
+         EFX_OWORD32(0x00001FF8, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XM_FC,
+         EFX_OWORD32(0xFFFF0001, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XM_ADR_LO,
+         EFX_OWORD32(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AB_XX_SD_CTL,
+         EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) },
+};
+
+static const struct efx_nic_table_test falcon_b0_table_tests[] = {
+       { FR_BZ_RX_FILTER_TBL0, FR_BZ_RX_FILTER_TBL0_STEP,
+         FR_BZ_RX_FILTER_TBL0_ROWS,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF) },
+       { FR_BB_RX_FILTER_TBL1, FR_BB_RX_FILTER_TBL1_STEP,
+         FR_BB_RX_FILTER_TBL1_ROWS,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF) },
+       { FR_BZ_RX_DESC_PTR_TBL, FR_BZ_RX_DESC_PTR_TBL_STEP,
+         FR_BB_RX_DESC_PTR_TBL_ROWS,
+         EFX_OWORD32(0xFFFFFFFF, 0x0FFFFFFF, 0x01800000, 0x00000000) },
+       { FR_BZ_TX_DESC_PTR_TBL, FR_BZ_TX_DESC_PTR_TBL_STEP,
+         FR_BB_TX_DESC_PTR_TBL_ROWS,
+         EFX_OWORD32(0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000) },
+};
+
+static int falcon_b0_test_registers(struct efx_nic *efx)
+{
+       return efx_nic_test_registers(efx, falcon_b0_register_tests,
+                                     ARRAY_SIZE(falcon_b0_register_tests));
+}
+
+static int
+falcon_b0_test_memory(struct efx_nic *efx,
+                     void (*pattern)(unsigned, efx_qword_t *, int, int),
+                     int a, int b)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       int rc, i;
+
+       rc = falcon_b0_test_sram(efx, pattern, a, b);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < ARRAY_SIZE(falcon_b0_table_tests); i++) {
+               /* In internal SRAM mode, the odd filter bank is
+                * remapped as a descriptor cache */
+               if (falcon_b0_table_tests[i].address == FR_BB_RX_FILTER_TBL1 &&
+                   nic_data->sram_config == SRAM_CONFIG_INTERNAL)
+                       continue;
+
+               rc = efx_nic_test_table(efx, &falcon_b0_table_tests[i],
+                                       pattern, a, b);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+/**************************************************************************
+ *
+ * Device reset
+ *
+ **************************************************************************
+ */
 
 /* Resets NIC to known state.  This routine must be called in process
  * context and is allowed to sleep. */
-int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
        efx_oword_t glb_ctl_reg_ker;
@@ -2550,14 +1231,13 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 
        /* Initiate device reset */
        if (method == RESET_TYPE_WORLD) {
-               /* Save PCI config space */
                rc = pci_save_state(efx->pci_dev);
                if (rc) {
                        EFX_ERR(efx, "failed to backup PCI state of primary "
                                "function prior to hardware reset\n");
                        goto fail1;
                }
-               if (FALCON_IS_DUAL_FUNC(efx)) {
+               if (efx_nic_is_dual_func(efx)) {
                        rc = pci_save_state(nic_data->pci_dev2);
                        if (rc) {
                                EFX_ERR(efx, "failed to backup PCI state of "
@@ -2568,30 +1248,31 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
                }
 
                EFX_POPULATE_OWORD_2(glb_ctl_reg_ker,
-                                    EXT_PHY_RST_DUR, 0x7,
-                                    SWRST, 1);
+                                    FRF_AB_EXT_PHY_RST_DUR,
+                                    FFE_AB_EXT_PHY_RST_DUR_10240US,
+                                    FRF_AB_SWRST, 1);
        } else {
-               int reset_phy = (method == RESET_TYPE_INVISIBLE ?
-                                EXCLUDE_FROM_RESET : 0);
-
                EFX_POPULATE_OWORD_7(glb_ctl_reg_ker,
-                                    EXT_PHY_RST_CTL, reset_phy,
-                                    PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
-                                    PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
-                                    PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
-                                    EE_RST_CTL, EXCLUDE_FROM_RESET,
-                                    EXT_PHY_RST_DUR, 0x7 /* 10ms */,
-                                    SWRST, 1);
-       }
-       falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+                                    /* exclude PHY from "invisible" reset */
+                                    FRF_AB_EXT_PHY_RST_CTL,
+                                    method == RESET_TYPE_INVISIBLE,
+                                    /* exclude EEPROM/flash and PCIe */
+                                    FRF_AB_PCIE_CORE_RST_CTL, 1,
+                                    FRF_AB_PCIE_NSTKY_RST_CTL, 1,
+                                    FRF_AB_PCIE_SD_RST_CTL, 1,
+                                    FRF_AB_EE_RST_CTL, 1,
+                                    FRF_AB_EXT_PHY_RST_DUR,
+                                    FFE_AB_EXT_PHY_RST_DUR_10240US,
+                                    FRF_AB_SWRST, 1);
+       }
+       efx_writeo(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
 
-       /* Wait for 50ms for the chip to come out of reset */
        EFX_LOG(efx, "waiting for hardware reset\n");
        schedule_timeout_uninterruptible(HZ / 20);
 
        /* Restore PCI configuration if needed */
        if (method == RESET_TYPE_WORLD) {
-               if (FALCON_IS_DUAL_FUNC(efx)) {
+               if (efx_nic_is_dual_func(efx)) {
                        rc = pci_restore_state(nic_data->pci_dev2);
                        if (rc) {
                                EFX_ERR(efx, "failed to restore PCI config for "
@@ -2609,59 +1290,77 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
        }
 
        /* Assert that reset complete */
-       falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
-       if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) {
+       efx_reado(efx, &glb_ctl_reg_ker, FR_AB_GLB_CTL);
+       if (EFX_OWORD_FIELD(glb_ctl_reg_ker, FRF_AB_SWRST) != 0) {
                rc = -ETIMEDOUT;
                EFX_ERR(efx, "timed out waiting for hardware reset\n");
                goto fail5;
        }
        EFX_LOG(efx, "hardware reset complete\n");
 
-       if (EFX_WORKAROUND_8202(efx)) {
-               rc = falcon_clear_b0_memories(efx);
-               if (rc)
-                       goto fail6;
-       }
-
        return 0;
 
        /* pci_save_state() and pci_restore_state() MUST be called in pairs */
 fail2:
 fail3:
        pci_restore_state(efx->pci_dev);
-       /* fall-thru */
 fail1:
 fail4:
 fail5:
-fail6:
        return rc;
 }
 
+static void falcon_monitor(struct efx_nic *efx)
+{
+       bool link_changed;
+       int rc;
+
+       BUG_ON(!mutex_is_locked(&efx->mac_lock));
+
+       rc = falcon_board(efx)->type->monitor(efx);
+       if (rc) {
+               EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
+                       (rc == -ERANGE) ? "reported fault" : "failed");
+               efx->phy_mode |= PHY_MODE_LOW_POWER;
+               rc = __efx_reconfigure_port(efx);
+               WARN_ON(rc);
+       }
+
+       if (LOOPBACK_INTERNAL(efx))
+               link_changed = falcon_loopback_link_poll(efx);
+       else
+               link_changed = efx->phy_op->poll(efx);
+
+       if (link_changed) {
+               falcon_stop_nic_stats(efx);
+               falcon_deconfigure_mac_wrapper(efx);
+
+               falcon_switch_mac(efx);
+               rc = efx->mac_op->reconfigure(efx);
+               BUG_ON(rc);
+
+               falcon_start_nic_stats(efx);
+
+               efx_link_status_changed(efx);
+       }
+
+       if (EFX_IS10G(efx))
+               falcon_poll_xmac(efx);
+}
+
 /* Zeroes out the SRAM contents.  This routine must be called in
  * process context and is allowed to sleep.
  */
-static int falcon_reset_sram(struct efx_nic *efx)
+static int falcon_reset_sram(struct efx_nic *efx, int sram_config)
 {
-       struct falcon_nic_data *nic_data = efx->nic_data;
-       efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker;
-       int count, onchip, sram_cfg_val;
-
-       /* Set the SRAM wake/sleep GPIO appropriately. */
-       onchip = (nic_data->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY);
-       falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
-       EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1);
-       EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, onchip ? 1 : 0);
-       falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+       efx_oword_t srm_cfg_reg_ker;
+       int count;
 
        /* Initiate SRAM reset */
-       sram_cfg_val = nic_data->external_sram_cfg;
-       if (nic_data->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY)
-               sram_cfg_val = 0;
-
        EFX_POPULATE_OWORD_2(srm_cfg_reg_ker,
-                            SRAM_OOB_BT_INIT_EN, 1,
-                            SRM_NUM_BANKS_AND_BANK_SIZE, sram_cfg_val);
-       falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+                            FRF_AZ_SRM_INIT_EN, 1,
+                            FRF_AZ_SRM_NB_SZ, sram_config);
+       efx_writeo(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
 
        /* Wait for SRAM reset to complete */
        count = 0;
@@ -2672,8 +1371,8 @@ static int falcon_reset_sram(struct efx_nic *efx)
                schedule_timeout_uninterruptible(HZ / 50);
 
                /* Check for reset complete */
-               falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
-               if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) {
+               efx_reado(efx, &srm_cfg_reg_ker, FR_AZ_SRM_CFG);
+               if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, FRF_AZ_SRM_INIT_EN)) {
                        EFX_LOG(efx, "SRAM reset complete\n");
 
                        return 0;
@@ -2684,13 +1383,16 @@ static int falcon_reset_sram(struct efx_nic *efx)
        return -ETIMEDOUT;
 }
 
-static void falcon_spi_device_init(struct efx_spi_device **spi_device_ret,
-                                  unsigned int device_id, u32 device_type)
+static int falcon_spi_device_init(struct efx_nic *efx,
+                                 struct efx_spi_device **spi_device_ret,
+                                 unsigned int device_id, u32 device_type)
 {
        struct efx_spi_device *spi_device;
 
        if (device_type != 0) {
-               spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL);
+               spi_device = kzalloc(sizeof(*spi_device), GFP_KERNEL);
+               if (!spi_device)
+                       return -ENOMEM;
                spi_device->device_id = device_id;
                spi_device->size =
                        1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
@@ -2706,14 +1408,21 @@ static void falcon_spi_device_init(struct efx_spi_device **spi_device_ret,
                spi_device->block_size =
                        1 << SPI_DEV_TYPE_FIELD(device_type,
                                                SPI_DEV_TYPE_BLOCK_SIZE);
-               spi_device->read = falcon_spi_read;
-               spi_device->write = falcon_spi_write;
        } else {
                spi_device = NULL;
        }
 
-       kfree(*spi_device_ret);
-       *spi_device_ret = spi_device;
+       kfree(*spi_device_ret);
+       *spi_device_ret = spi_device;
+       return 0;
+}
+
+static void falcon_remove_spi_devices(struct efx_nic *efx)
+{
+       kfree(efx->spi_eeprom);
+       efx->spi_eeprom = NULL;
+       kfree(efx->spi_flash);
+       efx->spi_flash = NULL;
 }
 
 /* Extract non-volatile configuration */
@@ -2721,449 +1430,205 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
        struct falcon_nvconfig *nvconfig;
-       struct efx_spi_device *spi;
-       size_t offset, len;
-       int magic_num, struct_ver, board_rev, onchip_sram;
        int rc;
 
        nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
+       if (!nvconfig)
+               return -ENOMEM;
 
-       /* Read the whole configuration structure into memory.  It's
-        * in Falcon's boot device, which may be either flash or
-        * EEPROM, but if both are present Falcon prefers flash.  The
-        * boot device is always too large for 9-bit addressing, so we
-        * don't have to munge commands.
-        */
-       spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
-       for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
-               len = min(sizeof(*nvconfig) - offset,
-                         (size_t) FALCON_SPI_MAX_LEN);
-               rc = falcon_spi_read(spi, efx, SPI_READ,
-                                    NVCONFIG_BASE + offset,
-                                    (char *)nvconfig + offset, len);
-               if (rc)
-                       goto out;
-       }
+       rc = falcon_read_nvram(efx, nvconfig);
+       if (rc)
+               goto out;
 
-       /* Read the MAC addresses */
        memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
 
-       /* Read the board configuration. */
-       magic_num = le16_to_cpu(nvconfig->board_magic_num);
-       struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
+       efx->phy_type = nvconfig->board_v2.port0_phy_type;
+       efx->mdio.prtad = nvconfig->board_v2.port0_phy_addr;
+       EFX_LOG(efx, "PHY is %s(%d) phy_id %d\n", efx->phy_name,
+               efx->phy_type, efx->mdio.prtad);
 
-       if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) {
-               EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x "
-                       "therefore using defaults\n", magic_num, struct_ver);
-               efx->phy_type = PHY_TYPE_NONE;
-               efx->mii.phy_id = PHY_ADDR_INVALID;
-               board_rev = 0;
-               onchip_sram = 1;
+       falcon_probe_board(efx, le16_to_cpu(nvconfig->board_v2.board_revision));
 
-       } else {
-               struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
-               struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
-
-               efx->phy_type = v2->port0_phy_type;
-               efx->mii.phy_id = v2->port0_phy_addr;
-               board_rev = le16_to_cpu(v2->board_revision);
-               onchip_sram = EFX_OWORD_FIELD(nvconfig->nic_stat_reg,
-                                             ONCHIP_SRAM);
-
-               if (struct_ver >= 3) {
-                       __le32 fl = v3->spi_device_type[EE_SPI_FLASH];
-                       __le32 ee = v3->spi_device_type[EE_SPI_EEPROM];
-                       falcon_spi_device_init(&efx->spi_flash, EE_SPI_FLASH,
-                                              le32_to_cpu(fl));
-                       falcon_spi_device_init(&efx->spi_eeprom, EE_SPI_EEPROM,
-                                              le32_to_cpu(ee));
-               }
+       if (le16_to_cpu(nvconfig->board_struct_ver) >= 3) {
+               rc = falcon_spi_device_init(
+                       efx, &efx->spi_flash, FFE_AB_SPI_DEVICE_FLASH,
+                       le32_to_cpu(nvconfig->board_v3
+                                   .spi_device_type[FFE_AB_SPI_DEVICE_FLASH]));
+               if (rc)
+                       goto out;
+               rc = falcon_spi_device_init(
+                       efx, &efx->spi_eeprom, FFE_AB_SPI_DEVICE_EEPROM,
+                       le32_to_cpu(nvconfig->board_v3
+                                   .spi_device_type[FFE_AB_SPI_DEVICE_EEPROM]));
+               if (rc)
+                       goto out;
        }
 
-       EFX_LOG(efx, "PHY is %s(%d) phy_id %d\n",
-               PHY_TYPE(efx), efx->phy_type,
-               efx->mii.phy_id);
-
-       efx_set_board_info(efx, board_rev);
-
        /* Read the SRAM configuration.  The register is initialised
         * automatically but might may been reset since boot.
         */
-       if (onchip_sram) {
-               nic_data->external_sram_cfg = SRM_NB_BSZ_ONCHIP_ONLY;
+       if (EFX_OWORD_FIELD(nvconfig->nic_stat_reg, FRF_AB_ONCHIP_SRAM)) {
+               nic_data->sram_config = SRAM_CONFIG_INTERNAL;
        } else {
-               nic_data->external_sram_cfg =
-                       EFX_OWORD_FIELD(nvconfig->srm_cfg_reg,
-                                       SRM_NUM_BANKS_AND_BANK_SIZE);
-               WARN_ON(nic_data->external_sram_cfg == SRM_NB_BSZ_RESERVED);
+               nic_data->sram_config = EFX_OWORD_FIELD(nvconfig->srm_cfg_reg,
+                                                       FRF_AZ_SRM_NB_SZ);
+               WARN_ON(nic_data->sram_config == FFE_AB_SRM_NB_SZ_RES);
                /* Replace invalid setting with the smallest defaults */
-               if (nic_data->external_sram_cfg == SRM_NB_BSZ_DEFAULT)
-                       nic_data->external_sram_cfg = SRM_NB_BSZ_1BANKS_2M;
+               if (nic_data->sram_config == FFE_AB_SRM_NB_SZ_DEF)
+                       nic_data->sram_config = FFE_AB_SRM_NB1_SZ2M;
        }
-       EFX_LOG(efx, "external_sram_cfg=%d (>=0 is external)\n",
-               nic_data->external_sram_cfg);
+       EFX_LOG(efx, "sram_config=%d (>=0 is external)\n",
+               nic_data->sram_config);
 
- out:
+out:
        kfree(nvconfig);
        return rc;
 }
 
-/* Looks at available SRAM resources and silicon revision, and works out
- * how many queues we can support, and where things like descriptor caches
- * should live. */
 static int falcon_dimension_resources(struct efx_nic *efx)
 {
-       unsigned buffer_entry_bytes, internal_dcs_entries, dcs;
        struct falcon_nic_data *nic_data = efx->nic_data;
-       struct efx_dl_falcon_resources *res = &nic_data->resources;
-
-       /* Fill out the driverlink resource list */
-       res->hdr.type = EFX_DL_FALCON_RESOURCES;
-       res->biu_lock = &efx->biu_lock;
-       efx->dl_info = &res->hdr;
-
-       /* This is set to 16 for a good reason.  In summary, if larger than
-        * 16, the descriptor cache holds more than a default socket
-        * buffer's worth of packets (for UDP we can only have at most one
-        * socket buffer's worth outstanding).  This combined with the fact
-        * that we only get 1 TX event per descriptor cache means the NIC
-        * goes idle.
-        * 16 gives us up to 256 TXQs on Falcon B in internal-SRAM mode,
-        * and up to 512 on Falcon A.
-        */
-       nic_data->tx_dc_entries = 16;
-
-       /* Set the RX descriptor cache size.  Values 16, 32 and 64 are
-        * supported (8 won't work).  Bigger is better, especially on B
-        * silicon.
-        */
-       nic_data->rx_dc_entries = descriptor_cache_size;
-       dcs = ffs(nic_data->rx_dc_entries);
-       if ((dcs < 5) || (dcs > 7) ||
-           ((1 << (dcs - 1)) != nic_data->rx_dc_entries)) {
-               EFX_ERR(efx, "bad descriptor_cache_size=%d (dcs=%d)\n",
-                       nic_data->rx_dc_entries, dcs);
-               return -EINVAL;
-       }
-
-       /* NB. The minimum values get increased as this driver initialises
-        * its resources, so this should prevent any overlap.
-        */
-       switch (FALCON_REV(efx)) {
-       case FALCON_REV_A1:
-               res->rxq_min = 16;
-               res->txq_min = 16;
-               res->evq_int_min = 4;
-               res->evq_int_lim = 5;
-               res->evq_timer_min = 5;
-               res->evq_timer_lim = 4096;
-               internal_dcs_entries = 8192;
-               break;
-       case FALCON_REV_B0:
-       default:
-               res->rxq_min = 0;
-               res->txq_min = 0;
-               res->evq_int_min = 0;
-               res->evq_int_lim = 64;
-               res->evq_timer_min = 64;
-               res->evq_timer_lim = 4096;
-               internal_dcs_entries = 4096;
-               break;
-       }
-
-       buffer_entry_bytes = 8;
 
-       if (nic_data->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY) {
-               res->rxq_lim = internal_dcs_entries / nic_data->rx_dc_entries;
-               res->txq_lim = internal_dcs_entries / nic_data->tx_dc_entries;
-               /* Prog model says 8K entries for buffer table in internal
-                * mode.  But does this not depend on full/half mode?
-                */
+       if (nic_data->sram_config == SRAM_CONFIG_INTERNAL) {
+               /* We scavenge internal memories to serve as the
+                * buffer table and descriptor caches. */
+               struct efx_dl_falcon_resources *res = &efx->resources;
+               unsigned internal_dcs_entries =
+                       (efx_nic_rev(efx) == EFX_REV_FALCON_A1) ? 8192 : 4096;
+
+               efx->rx_dc_entries = 64;
+               efx->tx_dc_entries = 16;
+               res->rxq_lim = internal_dcs_entries / efx->rx_dc_entries;
+               res->txq_lim = internal_dcs_entries / efx->tx_dc_entries;
                res->buffer_table_lim = 8192;
-               nic_data->tx_dc_base = 0x130000;
-               nic_data->rx_dc_base = 0x100000;
+               efx->rx_dc_base = 0x100000;
+               efx->tx_dc_base = 0x130000;
+               efx->sram_lim = 0x140000;
+               return 0;
        } else {
-               unsigned sram_bytes, vnic_bytes, max_vnics, n_vnics;
+               /* Otherwise we have a large block of external SRAM */
+               size_t sram_size;
 
-               /* Determine how much SRAM we have to play with.  We have
-                * to fit buffer table and descriptor caches in.
-                */
-               switch (nic_data->external_sram_cfg) {
-               case SRM_NB_BSZ_1BANKS_2M:
+               switch (nic_data->sram_config) {
+               case FFE_AB_SRM_NB1_SZ2M:
                default:
-                       sram_bytes = 2 * 1024 * 1024;
+                       sram_size = 2 * 1024 * 1024;
                        break;
-               case SRM_NB_BSZ_1BANKS_4M:
-               case SRM_NB_BSZ_2BANKS_4M:
-                       sram_bytes = 4 * 1024 * 1024;
+               case FFE_AB_SRM_NB1_SZ4M:
+               case FFE_AB_SRM_NB2_SZ4M:
+                       sram_size = 4 * 1024 * 1024;
                        break;
-               case SRM_NB_BSZ_1BANKS_8M:
-               case SRM_NB_BSZ_2BANKS_8M:
-                       sram_bytes = 8 * 1024 * 1024;
+               case FFE_AB_SRM_NB1_SZ8M:
+               case FFE_AB_SRM_NB2_SZ8M:
+                       sram_size = 8 * 1024 * 1024;
                        break;
-               case SRM_NB_BSZ_2BANKS_16M:
-                       sram_bytes = 16 * 1024 * 1024;
+               case FFE_AB_SRM_NB2_SZ16M:
+                       sram_size = 16 * 1024 * 1024;
                        break;
                }
-               /* For each VNIC allow at least 512 buffer table entries
-                * and descriptor cache for an rxq and txq.  Buffer table
-                * space for evqs and dmaqs is relatively trivial, so not
-                * considered in this calculation.
-                */
-               vnic_bytes = (512 * buffer_entry_bytes
-                             + nic_data->rx_dc_entries * 8
-                             + nic_data->tx_dc_entries * 8);
-               max_vnics = sram_bytes / vnic_bytes;
-               for (n_vnics = 1; n_vnics < res->evq_timer_min + max_vnics;)
-                       n_vnics *= 2;
-               res->rxq_lim = n_vnics;
-               res->txq_lim = n_vnics;
-
-               dcs = n_vnics * nic_data->tx_dc_entries * 8;
-               nic_data->tx_dc_base = sram_bytes - dcs;
-               dcs = n_vnics * nic_data->rx_dc_entries * 8;
-               nic_data->rx_dc_base = nic_data->tx_dc_base - dcs;
-               res->buffer_table_lim = nic_data->rx_dc_base / 8;
-       }
-
-       if (FALCON_IS_DUAL_FUNC(efx))
-               res->flags |= EFX_DL_FALCON_DUAL_FUNC;
-
-       if (EFX_INT_MODE_USE_MSI(efx))
-               res->flags |= EFX_DL_FALCON_USE_MSI;
-
-       return 0;
-}
-
-/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
- * count, port speed).  Set workaround and feature flags accordingly.
- */
-static int falcon_probe_nic_variant(struct efx_nic *efx)
-{
-       efx_oword_t altera_build;
-
-       falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
-       efx->is_asic = EFX_OWORD_FIELD(altera_build, VER_ALL) == 0;
-
-       {
-               int rc;
-               rc = pci_read_config_byte(efx->pci_dev, PCI_CLASS_REVISION,
-                                         &efx->revision);
-               if (rc)
-                       return rc;
-       }
-
-       switch (FALCON_REV(efx)) {
-       case FALCON_REV_A0:
-       case 0xff:
-               EFX_ERR(efx, "Falcon rev A0 not supported\n");
-               return -ENODEV;
-
-       case FALCON_REV_A1:{
-               efx_oword_t nic_stat;
-
-               falcon_read(efx, &nic_stat, NIC_STAT_REG);
-
-               if (!efx->is_asic) {
-                       EFX_ERR(efx, "Falcon rev A1 FPGA not supported\n");
-                       return -ENODEV;
-               }
-               if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
-                       EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
-                       return -ENODEV;
-               }
-               efx->is_10g = EFX_OWORD_FIELD(nic_stat, STRAP_10G);
-               efx->silicon_rev = "falcon/a1";
-               break;
-       }
-
-       case FALCON_REV_B0:{
-               efx->is_10g = 1;
-               efx->silicon_rev = "falcon/b0";
-               break;
-       }
-
-       default:
-               EFX_ERR(efx, "Unknown Falcon rev %d\n", FALCON_REV(efx));
-               return -ENODEV;
+               return efx_nic_dimension_resources(efx, sram_size, 512);
        }
-
-       return 0;
 }
 
 /* Probe all SPI devices on the NIC */
 static void falcon_probe_spi_devices(struct efx_nic *efx)
 {
        efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
-       unsigned int has_flash, has_eeprom, boot_is_external;
-
-       falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
-       falcon_read(efx, &nic_stat, NIC_STAT_REG);
-       falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
-
-       has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST);
-       has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST);
-       boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE);
-
-       if (has_flash) {
-               u32 flash_device_type;
-
-               if (flash_type == -1) {
-                       /* Default flash SPI device: Atmel AT25F1024
-                        * 128 KB, 24-bit address, 32 KB erase block,
-                        * 256 B write block
-                        */
-                       flash_device_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);
-               } else {
-                       flash_device_type = flash_type;
-               }
-
-               falcon_spi_device_init(&efx->spi_flash, EE_SPI_FLASH,
-                                      flash_device_type);
-
-               if (!boot_is_external) {
-                       /* Disable VPD and set clock dividers to safe
-                        * values for initial programming.
-                        */
-                       EFX_LOG(efx, "Booted from internal ASIC settings;"
-                               " setting SPI config\n");
-                       EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
-                                            /* 125 MHz / 7 ~= 20 MHz */
-                                            EE_SF_CLOCK_DIV, 7,
-                                            /* 125 MHz / 63 ~= 2 MHz */
-                                            EE_EE_CLOCK_DIV, 63);
-                       falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
-               }
-       }
+       int boot_dev;
 
-       if (has_eeprom) {
-               u32 eeprom_device_type;
+       efx_reado(efx, &gpio_ctl, FR_AB_GPIO_CTL);
+       efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
+       efx_reado(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
 
+       if (EFX_OWORD_FIELD(gpio_ctl, FRF_AB_GPIO3_PWRUP_VALUE)) {
+               boot_dev = (EFX_OWORD_FIELD(nic_stat, FRF_AB_SF_PRST) ?
+                           FFE_AB_SPI_DEVICE_FLASH : FFE_AB_SPI_DEVICE_EEPROM);
+               EFX_LOG(efx, "Booted from %s\n",
+                       boot_dev == FFE_AB_SPI_DEVICE_FLASH ? "flash" : "EEPROM");
+       } else {
+               /* Disable VPD and set clock dividers to safe
+                * values for initial programming. */
+               boot_dev = -1;
+               EFX_LOG(efx, "Booted from internal ASIC settings;"
+                       " setting SPI config\n");
+               EFX_POPULATE_OWORD_3(ee_vpd_cfg, FRF_AB_EE_VPD_EN, 0,
+                                    /* 125 MHz / 7 ~= 20 MHz */
+                                    FRF_AB_EE_SF_CLOCK_DIV, 7,
+                                    /* 125 MHz / 63 ~= 2 MHz */
+                                    FRF_AB_EE_EE_CLOCK_DIV, 63);
+               efx_writeo(efx, &ee_vpd_cfg, FR_AB_EE_VPD_CFG0);
+       }
+
+       if (boot_dev == FFE_AB_SPI_DEVICE_FLASH || flash_type != -1) {
+               u32 nic_flash_type =
+                       flash_type == -1 ? default_flash_type : flash_type;
+               falcon_spi_device_init(efx, &efx->spi_flash,
+                                      FFE_AB_SPI_DEVICE_FLASH,
+                                      nic_flash_type);
+       }
+
+       if (boot_dev == FFE_AB_SPI_DEVICE_EEPROM || eeprom_type != -1) {
                /* eeprom_type may be -1 (default) for automatic detection,
                 * 0 or 1 to select the default or large EEPROM, or
                 * some larger number to specify the precise configuration
                 */
-               if (eeprom_type == -1 || eeprom_type <= 1) {
-                       /* If it has no flash, it must have a large EEPROM
-                        * for chip config; otherwise check whether 9-bit
-                        * addressing is used for VPD configuration
-                        */
-                       if (eeprom_type == 0 ||
-                           (eeprom_type == -1 && has_flash &&
-                            (!boot_is_external ||
-                             EFX_OWORD_FIELD(ee_vpd_cfg,
-                                             EE_VPD_EN_AD9_MODE)))) {
-                               /* Default SPI device: Atmel AT25040 or similar
-                                * 512 B, 9-bit address, 8 B write block
-                                */
-                               eeprom_device_type =
-                                       (9 << SPI_DEV_TYPE_SIZE_LBN)
-                                       | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
-                                       | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
-                       } else {
-                               /* "Large" SPI device: Atmel AT25640 or similar
-                                * 8 KB, 16-bit address, 32 B write block
-                                */
-                               eeprom_device_type =
-                                       (13 << SPI_DEV_TYPE_SIZE_LBN)
-                                       | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
-                                       | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
-                       }
-               } else {
-                       eeprom_device_type = eeprom_type;
-               }
-
-               falcon_spi_device_init(&efx->spi_eeprom, EE_SPI_EEPROM,
-                                      eeprom_device_type);
-       }
-
-       EFX_LOG(efx, "flash is %s, EEPROM is %s\n",
-               (has_flash ? "present" : "absent"),
-               (has_eeprom ? "present" : "absent"));
-}
-
-static void falcon_remove_spi_devices(struct efx_nic *efx)
-{
-       kfree(efx->spi_eeprom);
-       efx->spi_eeprom = NULL;
-       kfree(efx->spi_flash);
-       efx->spi_flash = NULL;
-}
-
-#ifdef CONFIG_SFC_DEBUGFS
-
-/* Generate a hardware revision string */
-int falcon_debugfs_read_hardware_desc(struct seq_file *file, void *data)
-{
-       struct efx_nic *efx = data;
-       efx_oword_t altera_build;
-       int major, minor, build;
-       int rc, len;
-
-       if (efx->is_asic) {
-               rc = seq_puts(file, "Falcon ASIC");
-       } else {
-               falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
-
-               major = EFX_OWORD_FIELD(altera_build, VER_MAJOR);
-               minor = EFX_OWORD_FIELD(altera_build, VER_MINOR);
-               build = EFX_OWORD_FIELD(altera_build, VER_BUILD);
-               rc = seq_printf(file, "Falcon FPGA v%x.%x.%x",
-                               major, minor, build);
-       }
-       len = rc;
-
-       switch (FALCON_REV(efx)) {
-       case FALCON_REV_A1:
-               rc = seq_puts(file, " rev A1 ");
-               break;
-       case FALCON_REV_B0:
-               rc = seq_puts(file, " rev B0 ");
-               break;
-       default:
-               rc = seq_puts(file, " rev ?? ");
-               break;
+               u32 nic_eeprom_type;
+               if (eeprom_type == 0)
+                       nic_eeprom_type = small_eeprom_type;
+               else if (eeprom_type == -1 || eeprom_type == 1)
+                       nic_eeprom_type = large_eeprom_type;
+               else
+                       nic_eeprom_type = eeprom_type;
+               falcon_spi_device_init(efx, &efx->spi_eeprom,
+                                      FFE_AB_SPI_DEVICE_EEPROM,
+                                      nic_eeprom_type);
        }
-       len += rc;
-
-       rc = seq_printf(file, "%s %s\n",
-                       efx->is_10g ? "10G" : "1G", PHY_TYPE(efx));
-       len += rc;
-
-       return rc < 0 ? rc : len;
 }
 
-#endif /* CONFIG_SFC_DEBUGFS */
-
-int falcon_probe_nic(struct efx_nic *efx)
+static int falcon_probe_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data;
+       struct falcon_board *board;
        int rc;
 
-       /* Initialise I2C interface state */
-       efx->i2c.efx = efx;
-       efx->i2c.op = &falcon_i2c_bit_operations;
-       efx->i2c.sda = 1;
-       efx->i2c.scl = 1;
-
        /* Allocate storage for hardware specific data */
        nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
-       efx->nic_data = (void *) nic_data;
+       if (!nic_data)
+               return -ENOMEM;
+       efx->nic_data = nic_data;
 
-       /* Determine number of ports etc. */
-       rc = falcon_probe_nic_variant(efx);
-       if (rc)
+       rc = -ENODEV;
+
+       if (efx_nic_fpga_ver(efx) != 0) {
+               EFX_ERR(efx, "Falcon FPGA not supported\n");
                goto fail1;
+       }
+
+       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
+               efx_oword_t nic_stat;
+               struct pci_dev *dev;
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_PCI_DEV_REVISION)
+               u8 pci_rev;
+               pci_read_config_byte(efx->pci_dev, PCI_CLASS_REVISION, &pci_rev);
+#else
+               u8 pci_rev = efx->pci_dev->revision;
+#endif
 
-       /* Probe secondary function if expected */
-       if (FALCON_IS_DUAL_FUNC(efx)) {
-               struct pci_dev *dev = pci_dev_get(efx->pci_dev);
+               if ((pci_rev == 0xff) || (pci_rev == 0)) {
+                       EFX_ERR(efx, "Falcon rev A0 not supported\n");
+                       goto fail1;
+               }
+               efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
+               if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
+                       EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
+                       goto fail1;
+               }
+               if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
+                       EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+                       goto fail1;
+               }
 
+               dev = pci_dev_get(efx->pci_dev);
                while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
                                             dev))) {
                        if (dev->bus == efx->pci_dev->bus &&
@@ -3174,8 +1639,7 @@ int falcon_probe_nic(struct efx_nic *efx)
                }
                if (!nic_data->pci_dev2) {
                        EFX_ERR(efx, "failed to find secondary function\n");
-                       rc = -ENODEV;
-                       goto fail2;
+                       goto fail1;
                }
        }
 
@@ -3183,94 +1647,80 @@ int falcon_probe_nic(struct efx_nic *efx)
        rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
        if (rc) {
                EFX_ERR(efx, "failed to reset NIC\n");
-               goto fail3;
+               goto fail2;
        }
 
        /* Allocate memory for INT_KER */
-       rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
+       rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
        if (rc)
-               goto fail4;
+               goto fail3;
        BUG_ON(efx->irq_status.dma_addr & 0x0f);
 
-       EFX_LOG(efx, "INT_KER at %llx (virt %p phys %lx)\n",
-               (unsigned long long)efx->irq_status.dma_addr,
-               efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
+       EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n",
+               (u64)efx->irq_status.dma_addr,
+               efx->irq_status.addr, (u64)virt_to_phys(efx->irq_status.addr));
 
-       /* Determine attached SPI devices */
        falcon_probe_spi_devices(efx);
 
        /* Read in the non-volatile configuration */
        rc = falcon_probe_nvconfig(efx);
-       if (rc)
-               goto fail5;
-
-       if (!efx->is_10g && efx->phy_type != PHY_TYPE_1G_ALASKA) {
-               /* Actually using 1G port, not 10G port */
-               efx->phy_type = PHY_TYPE_1G_ALASKA;
-               efx->mii.phy_id = 2;
+       if (rc == -EINVAL) {
+               EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+               efx->phy_type = PHY_TYPE_NONE;
+               efx->mdio.prtad = MDIO_PRTAD_NONE;
+               nic_data->sram_config = SRAM_CONFIG_INTERNAL;
+       } else if (rc) {
+               goto fail4;
        }
 
        rc = falcon_dimension_resources(efx);
        if (rc)
+               goto fail5;
+
+       /* Initialise I2C adapter */
+       board = falcon_board(efx);
+       board->i2c_adap.owner = THIS_MODULE;
+       board->i2c_data = falcon_i2c_bit_operations;
+       board->i2c_data.data = efx;
+       board->i2c_adap.algo_data = &board->i2c_data;
+       board->i2c_adap.dev.parent = &efx->pci_dev->dev;
+       strlcpy(board->i2c_adap.name, "SFC4000 GPIO",
+               sizeof(board->i2c_adap.name));
+       rc = i2c_bit_add_bus(&board->i2c_adap);
+       if (rc)
+               goto fail5;
+
+       rc = falcon_board(efx)->type->init(efx);
+       if (rc) {
+               EFX_ERR(efx, "failed to initialise board\n");
                goto fail6;
+       }
+
+       nic_data->stats_disable_count = 1;
+       setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func,
+                   (unsigned long)efx);
 
        return 0;
 
- fail6:
-       efx->dl_info = NULL;
- fail5:
+fail6:
+       BUG_ON(i2c_del_adapter(&board->i2c_adap));
+       memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
+fail5:
+fail4:
        falcon_remove_spi_devices(efx);
-       falcon_free_buffer(efx, &efx->irq_status);
- fail4:
-       /* fall-thru */
- fail3:
+       efx_nic_free_buffer(efx, &efx->irq_status);
+fail3:
+fail2:
        if (nic_data->pci_dev2) {
                pci_dev_put(nic_data->pci_dev2);
                nic_data->pci_dev2 = NULL;
        }
- fail2:
-       /* fall-thru */
- fail1:
-       kfree(efx->nic_data);
+fail1:
+       kfree(nic_data);
        return rc;
 }
 
-static int falcon_check_power_limit(struct efx_nic *efx)
-{
-       int pciecap_offset = pci_find_capability(efx->pci_dev, PCI_CAP_ID_EXP);
-       u32 pcie_devcap;
-       unsigned val, scale;
-       int rc;
-
-       if (!pciecap_offset)
-               return -EIO;
-       rc = pci_read_config_dword(efx->pci_dev,
-                                  (pciecap_offset + PCI_EXP_DEVCAP),
-                                  &pcie_devcap);
-       if (rc)
-               return rc;
-
-       val = ((pcie_devcap & PCI_EXP_DEVCAP_PWR_VAL) >>
-              PCI_EXP_DEVCAP_PWR_VAL_LBN);
-       scale = ((pcie_devcap & PCI_EXP_DEVCAP_PWR_SCL) >>
-                PCI_EXP_DEVCAP_PWR_SCL_LBN);
-
-       /* Re-scale to milliwatts if necessary */
-       while (scale != 3) {
-               val *= 10;
-               scale++;
-       }
-
-       if (val != 0 && efx->board_info.mwatts > val) {
-               EFX_ERR(efx, "board needs %d mW but only %d mW available\n",
-                       efx->board_info.mwatts, val);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void falcon_init_ack_repl_timer(struct efx_nic *efx, int num_lanes)
+static void falcon_b0_init_ack_repl_timer(struct efx_nic *efx, int num_lanes)
 {
        unsigned tlp_size;
        efx_dword_t pcie_ack_rpl_reg;
@@ -3293,29 +1743,27 @@ static void falcon_init_ack_repl_timer(struct efx_nic *efx, int num_lanes)
        struct efx_tlp_ack_factor *tlp_ack_factor;
 
        /* Get TLP size */
-       falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT,
-                                 &pcie_ctrl_stat_reg);
+       falcon_b0_pcie_core_read_reg(efx, FPCR_BB_PCIE_DEVICE_CTRL_STAT,
+                                    &pcie_ctrl_stat_reg);
        pcie_devicectrl = (u16) EFX_EXTRACT_DWORD(pcie_ctrl_stat_reg, 0, 15);
        tlp_size = ((PCI_EXP_DEVCTL_PAYLOAD & pcie_devicectrl) >>
-                   PCI_EXP_DEVCTL_PAYLOAD_LBN);
+                   __ffs(PCI_EXP_DEVCTL_PAYLOAD));
        EFX_WARN_ON_PARANOID(tlp_size > 3); /* => 1024 bytes */
        tlp_ack_factor = &tlp_ack_factor_lut[tlp_size & 0x3];
        tlp_size_decoded = tlp_ack_factor->tlp;
 
        /* Get actual ack & actual and expected replay settings */
-       falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_RPL_TIMER,
-                                 &pcie_ack_rpl_reg);
-       current_replay = EFX_DWORD_FIELD(pcie_ack_rpl_reg, PCIE_CORE_RPL_TL);
-       current_ack_timer = EFX_DWORD_FIELD(pcie_ack_rpl_reg,
-                                           PCIE_CORE_ACK_TL);
+       falcon_b0_pcie_core_read_reg(efx, FPCR_BB_ACK_RPL_TIMER,
+                                    &pcie_ack_rpl_reg);
+       current_replay = EFX_DWORD_FIELD(pcie_ack_rpl_reg, FPCRF_BB_RPL_TL);
+       current_ack_timer = EFX_DWORD_FIELD(pcie_ack_rpl_reg, FPCRF_BB_ACK_TL);
 
        lut_index = ffs(num_lanes) - 1;
        expected_replay = tlp_ack_factor->replay[lut_index & 0x3];
 
-       falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
-                                 &pcie_ack_freq_reg);
+       falcon_b0_pcie_core_read_reg(efx, FPCR_BB_ACK_FREQ, &pcie_ack_freq_reg);
        current_ack_freq = EFX_DWORD_FIELD(pcie_ack_freq_reg,
-                                          PCIE_CORE_ACK_FREQ);
+                                          FPCRF_BB_ACK_FREQ);
 
        EFX_LOG(efx, "pcie x%d tlp=%d replay_reg=" EFX_DWORD_FMT " { ack=%d "
                "current_replay=%d expected_replay=%d } ack_reg="
@@ -3327,60 +1775,30 @@ static void falcon_init_ack_repl_timer(struct efx_nic *efx, int num_lanes)
 
        /* If expected replay setting needs to be bigger then set it */
        if (expected_replay > current_replay) {
-               EFX_SET_DWORD_FIELD(pcie_ack_rpl_reg, PCIE_CORE_RPL_TL,
+               EFX_SET_DWORD_FIELD(pcie_ack_rpl_reg, FPCRF_BB_RPL_TL,
                                    expected_replay);
 
-               falcon_pcie_core_write_reg(efx, PCIE_CORE_ADDR_ACK_RPL_TIMER,
-                                          pcie_ack_rpl_reg);
+               falcon_b0_pcie_core_write_reg(efx, FPCR_BB_ACK_RPL_TIMER,
+                                             pcie_ack_rpl_reg);
        }
 }
 
 static int falcon_init_pcie_core(struct efx_nic *efx)
 {
-       int pciecap_offset;
-       unsigned num_lanes = 0;
-
-       /* Get num lanes */
-       pciecap_offset = pci_find_capability(efx->pci_dev, PCI_CAP_ID_EXP);
-       if (pciecap_offset) {
-               u16 pcie_linkstat;
-               int rc, link_sta;
-
-               link_sta = pciecap_offset + PCI_EXP_LNKSTA;
-               rc = pci_read_config_word(efx->pci_dev, link_sta,
-                                         &pcie_linkstat);
-               if (rc)
-                       return rc;
-
-               num_lanes = ((pcie_linkstat & PCI_EXP_LNKSTA_LNK_WID)
-                            >> PCI_EXP_LNKSTA_LNK_WID_LBN);
-               EFX_BUG_ON_PARANOID(num_lanes <= 0 || num_lanes > 8);
-
-               if (num_lanes < 8)
-                       EFX_ERR(efx, "WARNING: the Solarflare Network Adapter "
-                               "has been plugged into a PCI-Express slot with "
-                               "less than 8 lanes (%d detected). This will "
-                               "limit the maximum achievable bandwidth! "
-                               "Consult your motherboard documentation to "
-                               "find a slot that is 8 lanes electrically and "
-                               "physically\n", num_lanes);
-       }
-
-       if (FALCON_REV(efx) <= FALCON_REV_A1)
-               return 0;
+       unsigned num_lanes = efx_nic_check_pcie_link(efx, 8, 1);
 
        if (EFX_WORKAROUND_6943(efx) && num_lanes > 0)
-               falcon_init_ack_repl_timer(efx, num_lanes);
+               falcon_b0_init_ack_repl_timer(efx, num_lanes);
 
        if (EFX_WORKAROUND_9096(efx)) {
                efx_dword_t pcie_ack_freq_reg;
 
                /* ensure ack freq timer is 0 = always ack after timeout */
-               falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
-                                         &pcie_ack_freq_reg);
-               EFX_SET_DWORD_FIELD(pcie_ack_freq_reg, PCIE_CORE_ACK_FREQ, 0);
-               falcon_pcie_core_write_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
-                                          pcie_ack_freq_reg);
+               falcon_b0_pcie_core_read_reg(efx, FPCR_BB_ACK_FREQ,
+                                            &pcie_ack_freq_reg);
+               EFX_SET_DWORD_FIELD(pcie_ack_freq_reg, FPCRF_BB_ACK_FREQ, 0);
+               falcon_b0_pcie_core_write_reg(efx, FPCR_BB_ACK_FREQ,
+                                             pcie_ack_freq_reg);
        }
 
        return 0;
@@ -3390,208 +1808,197 @@ static void falcon_fini_pcie_core(struct efx_nic *efx)
 {
        efx_dword_t pcie_ack_freq_reg;
 
-       if (FALCON_REV(efx) <= FALCON_REV_A1)
-               return;
-
        if (EFX_WORKAROUND_9096(efx)) {
                /* Set the ACK frequency timer to 1, so TLP's are acked in
                 * a timely fashion.
                 */
-               falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
-                                         &pcie_ack_freq_reg);
-               EFX_SET_DWORD_FIELD(pcie_ack_freq_reg, PCIE_CORE_ACK_FREQ, 1);
-               falcon_pcie_core_write_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
-                                          pcie_ack_freq_reg);
-       }
+               falcon_b0_pcie_core_read_reg(efx, FPCR_BB_ACK_FREQ,
+                                            &pcie_ack_freq_reg);
+               EFX_SET_DWORD_FIELD(pcie_ack_freq_reg, FPCRF_BB_ACK_FREQ, 1);
+               falcon_b0_pcie_core_write_reg(efx, FPCR_BB_ACK_FREQ,
+                                             pcie_ack_freq_reg);
+       }
+}
+
+static void falcon_init_rx_cfg(struct efx_nic *efx)
+{
+       /* Prior to Siena the RX DMA engine will split each frame at
+        * intervals of RX_USR_BUF_SIZE (32-byte units). We set it to
+        * be so large that that never happens. */
+       const unsigned huge_buf_size = (3 * 4096) >> 5;
+       /* RX control FIFO thresholds (32 entries) */
+       const unsigned ctrl_xon_thr = 20;
+       const unsigned ctrl_xoff_thr = 25;
+       /* RX data FIFO thresholds (256-byte units; size varies) */
+       int data_xon_thr = efx_nic_rx_xon_thresh >> 8;
+       int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8;
+       efx_oword_t reg;
+
+       efx_reado(efx, &reg, FR_AZ_RX_CFG);
+       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
+               /* Data FIFO size is 5.5K */
+               if (data_xon_thr < 0)
+                       data_xon_thr = 512 >> 8;
+               if (data_xoff_thr < 0)
+                       data_xoff_thr = 2048 >> 8;
+               EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0);
+               EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE,
+                                   huge_buf_size);
+               EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, data_xon_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, data_xoff_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_TX_TH, ctrl_xoff_thr);
+       } else {
+               /* Data FIFO size is 80K; register fields moved */
+               if (data_xon_thr < 0)
+                       data_xon_thr = 27648 >> 8; /* ~3*max MTU */
+               if (data_xoff_thr < 0)
+                       data_xoff_thr = 54272 >> 8; /* ~80Kb - 3*max MTU */
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE,
+                                   huge_buf_size);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, data_xon_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, data_xoff_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_TX_TH, ctrl_xon_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
+               EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+       }
+       /* Always enable XOFF signal from RX FIFO.  We enable
+        * or disable transmission of pause frames at the MAC. */
+       EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
+       efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
 /* This call performs hardware-specific global initialisation, such as
  * defining the descriptor cache sizes and number of RSS channels.
  * It does not set up any buffers, descriptor rings or event queues.
  */
-int falcon_init_nic(struct efx_nic *efx)
+static int falcon_init_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
-       struct falcon_nic_data *data;
        efx_oword_t temp;
-       unsigned thresh;
        int rc;
 
-       data = (struct falcon_nic_data *)efx->nic_data;
+       /* Use on-chip SRAM if needed */
+       efx_reado(efx, &temp, FR_AB_NIC_STAT);
+       EFX_SET_OWORD_FIELD(temp, FRF_AB_ONCHIP_SRAM,
+                           nic_data->sram_config == SRAM_CONFIG_INTERNAL);
+       efx_writeo(efx, &temp, FR_AB_NIC_STAT);
 
-       /* Set up the address region register. This is only needed
-        * for the B0 FPGA, but since we are just pushing in the
-        * reset defaults this may as well be unconditional. */
-       EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0,
-                                  ADR_REGION1, (1 << 16),
-                                  ADR_REGION2, (2 << 16),
-                                  ADR_REGION3, (3 << 16));
-       falcon_write(efx, &temp, ADR_REGION_REG_KER);
-
-       /* Use on-chip SRAM if needed.
-        */
-       falcon_read(efx, &temp, NIC_STAT_REG);
-       if (nic_data->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY)
-               EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
-       else
-               EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 0);
-       falcon_write(efx, &temp, NIC_STAT_REG);
+       /* Set the source of the GMAC clock */
+       if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
+               efx_reado(efx, &temp, FR_AB_GPIO_CTL);
+               EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true);
+               efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
+       }
 
-       /* Check power requirements against PCIe power budgeting */
-       rc = falcon_check_power_limit(efx);
-       if (rc)
-               return rc;
+       /* Select the correct MAC */
+       falcon_clock_mac(efx);
 
        /* Warn if <8 lanes of PCIe detected & set pcie timers */
        rc = falcon_init_pcie_core(efx);
        if (rc)
-               return rc;
-
-       /* Set buffer table mode */
-       EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
-       falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
+               goto fail1;
 
-       rc = falcon_reset_sram(efx);
+       /* Set the SRAM wake/sleep GPIO appropriately. */
+       efx_reado(efx, &temp, FR_AB_GPIO_CTL);
+       EFX_SET_OWORD_FIELD(temp, FRF_AB_GPIO1_OEN, 1);
+       EFX_SET_OWORD_FIELD(temp, FRF_AB_GPIO1_OUT,
+                           nic_data->sram_config == SRAM_CONFIG_INTERNAL);
+       efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
+
+       rc = falcon_reset_sram(efx,
+                              nic_data->sram_config != SRAM_CONFIG_INTERNAL ?
+                              nic_data->sram_config : 0);
        if (rc)
-               return rc;
-
-       /* Set positions of descriptor caches in SRAM. */
-       EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, data->tx_dc_base / 8);
-       falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER);
-       EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, data->rx_dc_base / 8);
-       falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER);
-
-       /* Set TX descriptor cache size. */
-       EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, ffs(data->tx_dc_entries) - 4);
-       falcon_write(efx, &temp, TX_DC_CFG_REG_KER);
-
-       /* Set RX descriptor cache size.  Set low watermark to size-8, as
-        * this allows most efficient prefetching.
-        */
-       EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, ffs(data->rx_dc_entries) - 4);
-       falcon_write(efx, &temp, RX_DC_CFG_REG_KER);
-       EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, data->rx_dc_entries - 8);
-       falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER);
+               goto fail2;
 
        /* Clear the parity enables on the TX data fifos as
         * they produce false parity errors because of timing issues
         */
        if (EFX_WORKAROUND_5129(efx)) {
-               falcon_read(efx, &temp, SPARE_REG_KER);
-               EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0);
-               falcon_write(efx, &temp, SPARE_REG_KER);
+               efx_reado(efx, &temp, FR_AZ_CSR_SPARE);
+               EFX_SET_OWORD_FIELD(temp, FRF_AB_MEM_PERR_EN_TX_DATA, 0);
+               efx_writeo(efx, &temp, FR_AZ_CSR_SPARE);
        }
 
-       /* Enable all the genuinely fatal interrupts.  (They are still
-        * masked by the overall interrupt mask, controlled by
-        * falcon_interrupts()).
-        *
-        * Note: All other fatal interrupts are enabled
-        */
-       EFX_POPULATE_OWORD_3(temp,
-                            ILL_ADR_INT_KER_EN, 1,
-                            RBUF_OWN_INT_KER_EN, 1,
-                            TBUF_OWN_INT_KER_EN, 1);
-       EFX_INVERT_OWORD(temp);
-       falcon_write(efx, &temp, FATAL_INTR_REG_KER);
-
-       /* Set number of RSS queues for receive path. */
-       falcon_read(efx, &temp, RX_FILTER_CTL_REG);
-       if (FALCON_REV(efx) >= FALCON_REV_B0)
-               EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
-       else
-               EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
        if (EFX_WORKAROUND_7244(efx)) {
-               EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
-               EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
-               EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
-               EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
+               efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL);
+               EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8);
+               EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_WILD_SRCH_LIMIT, 8);
+               EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_FULL_SRCH_LIMIT, 8);
+               EFX_SET_OWORD_FIELD(temp, FRF_BZ_TCP_WILD_SRCH_LIMIT, 8);
+               efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL);
        }
-       falcon_write(efx, &temp, RX_FILTER_CTL_REG);
 
-       falcon_setup_rss_indir_table(efx);
+       if (EFX_WORKAROUND_11368(efx)) {
+               /* Ensure that invalid BAR accesses are detected in
+                * time (prevents denial of service by vNIC users).
+                */
+               efx_reado(efx, &temp, FR_AZ_HW_INIT);
+               EFX_SET_OWORD_FIELD(temp, FRF_AZ_POST_WR_MASK, 0x0f);
+               EFX_SET_OWORD_FIELD(temp, FRF_AZ_WD_TIMER, 0x10);
+               efx_writeo(efx, &temp, FR_AZ_HW_INIT);
+       }
 
+       /* XXX This is documented only for Falcon A0/A1 */
        /* Setup RX.  Wait for descriptor is broken and must
         * be disabled.  RXDP recovery shouldn't be needed, but is.
         */
-       falcon_read(efx, &temp, RX_SELF_RST_REG_KER);
-       EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1);
-       EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1);
+       efx_reado(efx, &temp, FR_AA_RX_SELF_RST);
+       EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_NODESC_WAIT_DIS, 1);
+       EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_SELF_RST_EN, 1);
        if (EFX_WORKAROUND_5583(efx))
-               EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1);
-       falcon_write(efx, &temp, RX_SELF_RST_REG_KER);
-
-       /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
-        * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
-        */
-       falcon_read(efx, &temp, TX_CFG2_REG_KER);
-       EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe);
-       EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1);
-       EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1);
-       EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0);
-       EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1);
-       /* Enable SW_EV to inherit in char driver - assume harmless here */
-       EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1);
-       /* Prefetch threshold 2 => fetch when descriptor cache half empty */
-       EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
-       if (EFX_WORKAROUND_9008(efx))
-               EFX_SET_OWORD_FIELD(temp, TX_PREF_WD_TMR, (unsigned)0x3fffff);
-       /* Squash TX of packets of 16 bytes or less */
-       if (FALCON_REV(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
-               EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
-       falcon_write(efx, &temp, TX_CFG2_REG_KER);
+               EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1);
+       efx_writeo(efx, &temp, FR_AA_RX_SELF_RST);
 
        /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
         * descriptors (which is bad).
         */
-       falcon_read(efx, &temp, TX_CFG_REG_KER);
-       EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0);
-       falcon_write(efx, &temp, TX_CFG_REG_KER);
-
-       /* RX config */
-       falcon_read(efx, &temp, RX_CFG_REG_KER);
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0);
-       if (EFX_WORKAROUND_7575(efx))
-               EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
-                                       (3 * 4096) / 32);
-       if (FALCON_REV(efx) >= FALCON_REV_B0)
-               EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
-
-       /* RX FIFO flow control thresholds */
-       thresh = ((rx_xon_thresh_bytes >= 0) ?
-                 rx_xon_thresh_bytes : efx->type->rx_xon_thresh);
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256);
-       thresh = ((rx_xoff_thresh_bytes >= 0) ?
-                 rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
-       /* RX control FIFO thresholds [32 entries] */
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
-       EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
-       falcon_write(efx, &temp, RX_CFG_REG_KER);
+       efx_reado(efx, &temp, FR_AZ_TX_CFG);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
+       efx_writeo(efx, &temp, FR_AZ_TX_CFG);
+
+       falcon_init_rx_cfg(efx);
 
        /* Set destination of both TX and RX Flush events */
-       if (FALCON_REV(efx) >= FALCON_REV_B0) {
-               EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
-               falcon_write(efx, &temp, DP_CTRL_REG);
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+               EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
+               efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
        }
 
+       efx_nic_init_common(efx);
+
        return 0;
+
+fail2:
+fail1:
+       falcon_fini_pcie_core(efx);
+       return rc;
 }
 
-void falcon_fini_nic(struct efx_nic *efx)
+static void falcon_fini_nic(struct efx_nic *efx)
 {
        falcon_fini_pcie_core(efx);
 }
 
-void falcon_remove_nic(struct efx_nic *efx)
+static void falcon_remove_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
+       struct falcon_board *board = falcon_board(efx);
+       int rc;
+
+       board->type->fini(efx);
+
+       /* Remove I2C adapter and clear it in preparation for a retry */
+       rc = i2c_del_adapter(&board->i2c_adap);
+       BUG_ON(rc);
+       memset(&board->i2c_adap, 0, sizeof(board->i2c_adap));
 
        falcon_remove_spi_devices(efx);
-       falcon_free_buffer(efx, &efx->irq_status);
+       efx_nic_free_buffer(efx, &efx->irq_status);
 
-       /* Reset the NIC finally */
-       (void) falcon_reset_hw(efx, RESET_TYPE_ALL);
+       falcon_reset_hw(efx, RESET_TYPE_ALL);
 
        /* Release the second function after the reset */
        if (nic_data->pci_dev2) {
@@ -3601,70 +2008,196 @@ void falcon_remove_nic(struct efx_nic *efx)
 
        /* Tear down the private nic state, and the driverlink nic params */
        kfree(efx->nic_data);
-       efx->nic_data = efx->dl_info = NULL;
+       efx->nic_data = NULL;
 }
 
-void falcon_update_nic_stats(struct efx_nic *efx)
+static void falcon_update_nic_stats(struct efx_nic *efx)
 {
+       struct falcon_nic_data *nic_data = efx->nic_data;
        efx_oword_t cnt;
 
-       /* Read the RX drop counter */
-       falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER);
-       efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT);
+       if (nic_data->stats_disable_count)
+               return;
+
+       efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP);
+       efx->n_rx_nodesc_drop_cnt +=
+               EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT);
+
+       if (nic_data->stats_pending &&
+           *nic_data->stats_dma_done == FALCON_STATS_DONE) {
+               nic_data->stats_pending = false;
+               rmb(); /* read the done flag before the stats */
+               efx->mac_op->update_stats(efx);
+       }
+}
+
+void falcon_start_nic_stats(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+
+       spin_lock_bh(&efx->stats_lock);
+       if (--nic_data->stats_disable_count == 0)
+               falcon_stats_request(efx);
+       spin_unlock_bh(&efx->stats_lock);
+}
+
+void falcon_stop_nic_stats(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       int i;
+
+       might_sleep();
+
+       spin_lock_bh(&efx->stats_lock);
+       ++nic_data->stats_disable_count;
+       spin_unlock_bh(&efx->stats_lock);
+
+       del_timer_sync(&nic_data->stats_timer);
+
+       /* Wait enough time for the most recent transfer to
+        * complete. */
+       for (i = 0; i < 4 && nic_data->stats_pending; i++) {
+               if (*nic_data->stats_dma_done == FALCON_STATS_DONE)
+                       break;
+               msleep(1);
+       }
+
+       spin_lock_bh(&efx->stats_lock);
+       falcon_stats_complete(efx);
+       spin_unlock_bh(&efx->stats_lock);
+}
+
+static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+       falcon_board(efx)->type->set_id_led(efx, mode);
+}
+
+/**************************************************************************
+ *
+ * Wake on LAN
+ *
+ **************************************************************************
+ */
+
+static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol)
+{
+       wol->supported = 0;
+       wol->wolopts = 0;
+       memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int falcon_set_wol(struct efx_nic *efx, u32 type)
+{
+       if (type != 0)
+               return -EINVAL;
+       return 0;
 }
 
 /**************************************************************************
  *
- * Revision-dependent attributes used by efx.c
+ * Revision-dependent attributes used by efx.c and nic.c
  *
  **************************************************************************
  */
 
-struct efx_nic_type falcon_a_nic_type = {
-       .mem_bar = 2,
+struct efx_nic_type falcon_a1_nic_type = {
+       .probe = falcon_probe_nic,
+       .remove = falcon_remove_nic,
+       .init = falcon_init_nic,
+       .fini = falcon_fini_nic,
+       .monitor = falcon_monitor,
+       .reset = falcon_reset_hw,
+       .probe_port = falcon_probe_port,
+       .remove_port = falcon_remove_port,
+       .prepare_flush = falcon_prepare_flush,
+       .update_stats = falcon_update_nic_stats,
+       .start_stats = falcon_start_nic_stats,
+       .stop_stats = falcon_stop_nic_stats,
+       .set_id_led = falcon_set_id_led,
+       .push_irq_moderation = falcon_push_irq_moderation,
+       .push_multicast_hash = falcon_push_multicast_hash,
+       .reconfigure_port = falcon_reconfigure_port,
+       .get_wol = falcon_get_wol,
+       .set_wol = falcon_set_wol,
+       .resume_wol = efx_port_dummy_op_void,
+       .test_nvram = falcon_test_nvram,
+       .default_mac_ops = &falcon_xmac_operations,
+
+       .revision = EFX_REV_FALCON_A1,
+       .dl_revision = "falcon/a1",
        .mem_map_size = 0x20000,
-       .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1,
-       .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1,
-       .buf_tbl_base = BUF_TBL_KER_A1,
-       .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1,
-       .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1,
-       .txd_ring_mask = FALCON_TXD_RING_MASK,
-       .rxd_ring_mask = FALCON_RXD_RING_MASK,
-       .evq_size = FALCON_EVQ_SIZE,
-       .max_dma_mask = FALCON_DMA_MASK,
-       .tx_dma_mask = FALCON_TX_DMA_MASK,
-       .bug5391_mask = 0xf,
-       .rx_xoff_thresh = 2048,
-       .rx_xon_thresh = 512,
+       .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
+       .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER,
+       .buf_tbl_base = FR_AA_BUF_FULL_TBL_KER,
+       .evq_ptr_tbl_base = FR_AA_EVQ_PTR_TBL_KER,
+       .evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER,
+       .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
        .rx_buffer_padding = 0x24,
        .max_interrupt_mode = EFX_INT_MODE_MSI,
        .phys_addr_channels = 4,
+       .resources = {
+               .hdr.type = EFX_DL_FALCON_RESOURCES,
+               .flags = EFX_DL_FALCON_DUAL_FUNC,
+               .rxq_min = 16, .rxq_lim = 4096,
+               .txq_min = 16, .txq_lim = 4096,
+               .evq_int_min = 4, .evq_int_lim = 5,
+               .evq_timer_min = 5, .evq_timer_lim = 4096,
+       },
+       .offload_features = NETIF_F_IP_CSUM,
+       .reset_world_flags = ETH_RESET_IRQ,
 };
 
-struct efx_nic_type falcon_b_nic_type = {
-       .mem_bar = 2,
+struct efx_nic_type falcon_b0_nic_type = {
+       .probe = falcon_probe_nic,
+       .remove = falcon_remove_nic,
+       .init = falcon_init_nic,
+       .fini = falcon_fini_nic,
+       .monitor = falcon_monitor,
+       .reset = falcon_reset_hw,
+       .probe_port = falcon_probe_port,
+       .remove_port = falcon_remove_port,
+       .prepare_flush = falcon_prepare_flush,
+       .update_stats = falcon_update_nic_stats,
+       .start_stats = falcon_start_nic_stats,
+       .stop_stats = falcon_stop_nic_stats,
+       .set_id_led = falcon_set_id_led,
+       .push_irq_moderation = falcon_push_irq_moderation,
+       .push_multicast_hash = falcon_push_multicast_hash,
+       .reconfigure_port = falcon_reconfigure_port,
+       .get_wol = falcon_get_wol,
+       .set_wol = falcon_set_wol,
+       .resume_wol = efx_port_dummy_op_void,
+       .test_registers = falcon_b0_test_registers,
+       .test_memory = falcon_b0_test_memory,
+       .test_nvram = falcon_test_nvram,
+       .default_mac_ops = &falcon_xmac_operations,
+
+       .revision = EFX_REV_FALCON_B0,
+       .dl_revision = "falcon/b0",
        /* Map everything up to and including the RSS indirection
         * table.  Don't map MSI-X table, MSI-X PBA since Linux
         * requires that they not be mapped.  */
-       .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800,
-       .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0,
-       .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0,
-       .buf_tbl_base = BUF_TBL_KER_B0,
-       .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0,
-       .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0,
-       .txd_ring_mask = FALCON_TXD_RING_MASK,
-       .rxd_ring_mask = FALCON_RXD_RING_MASK,
-       .evq_size = FALCON_EVQ_SIZE,
-       .max_dma_mask = FALCON_DMA_MASK,
-       .tx_dma_mask = FALCON_TX_DMA_MASK,
-       .bug5391_mask = 0,
-       .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */
-       .rx_xon_thresh = 27648,  /* ~3*max MTU */
+       .mem_map_size = (FR_BZ_RX_INDIRECTION_TBL +
+                        FR_BZ_RX_INDIRECTION_TBL_STEP *
+                        FR_BZ_RX_INDIRECTION_TBL_ROWS),
+       .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
+       .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
+       .buf_tbl_base = FR_BZ_BUF_FULL_TBL,
+       .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
+       .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
+       .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
        .rx_buffer_padding = 0,
        .max_interrupt_mode = EFX_INT_MODE_MSIX,
        .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
                                   * interrupt handler only supports 32
                                   * channels */
-
+       .resources = {
+               .hdr.type = EFX_DL_FALCON_RESOURCES,
+               .rxq_min = 0, .rxq_lim = 4096,
+               .txq_min = 0, .txq_lim = 4096,
+               .evq_int_min = 0, .evq_int_lim = 64,
+               .evq_timer_min = 64, .evq_timer_lim = 4096,
+       },
+       .offload_features = NETIF_F_IP_CSUM,
+       .reset_world_flags = ETH_RESET_IRQ,
 };
-
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
deleted file mode 100644 (file)
index 9187f55..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_FALCON_H
-#define EFX_FALCON_H
-
-#include "net_driver.h"
-
-/*
- * Falcon hardware control
- */
-
-enum falcon_revision {
-       FALCON_REV_A0 = 0,
-       FALCON_REV_A1 = 1,
-       FALCON_REV_B0 = 2,
-};
-
-#define FALCON_REV(efx) ((efx)->revision)
-
-extern struct efx_nic_type falcon_a_nic_type;
-extern struct efx_nic_type falcon_b_nic_type;
-
-/**************************************************************************
- *
- * Externs
- *
- **************************************************************************
- */
-
-/* TX data path */
-extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
-extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
-extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
-extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
-extern void fastcall falcon_push_buffers(struct efx_tx_queue *tx_queue);
-
-/* RX data path */
-extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
-extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
-extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
-extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
-extern void fastcall falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
-
-/* Event data path */
-extern int falcon_probe_eventq(struct efx_channel *channel);
-extern int falcon_init_eventq(struct efx_channel *channel);
-extern void falcon_fini_eventq(struct efx_channel *channel);
-extern void falcon_remove_eventq(struct efx_channel *channel);
-extern int fastcall falcon_process_eventq(struct efx_channel *channel,
-                                         int *rx_quota);
-extern void fastcall falcon_eventq_read_ack(struct efx_channel *channel);
-
-/* Ports */
-extern int falcon_probe_port(struct efx_nic *efx);
-extern void falcon_remove_port(struct efx_nic *efx);
-
-/* MAC/PHY */
-extern int falcon_xaui_link_ok(struct efx_nic *efx);
-extern int falcon_dma_stats(struct efx_nic *efx,
-                           unsigned int done_offset);
-extern void falcon_drain_tx_fifo(struct efx_nic *efx);
-extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
-extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
-
-/* Interrupts and test events */
-extern int falcon_init_interrupt(struct efx_nic *efx);
-extern void falcon_enable_interrupts(struct efx_nic *efx);
-extern void falcon_generate_test_event(struct efx_channel *channel,
-                                      unsigned int magic);
-extern void falcon_generate_interrupt(struct efx_nic *efx);
-extern void falcon_set_int_moderation(struct efx_channel *channel);
-extern void falcon_disable_interrupts(struct efx_nic *efx);
-extern void falcon_fini_interrupt(struct efx_nic *efx);
-
-/* Global Resources */
-extern int falcon_probe_nic(struct efx_nic *efx);
-extern int falcon_probe_resources(struct efx_nic *efx);
-extern int falcon_init_nic(struct efx_nic *efx);
-extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
-extern void falcon_fini_nic(struct efx_nic *efx);
-extern void falcon_remove_resources(struct efx_nic *efx);
-extern void falcon_remove_nic(struct efx_nic *efx);
-extern void falcon_update_nic_stats(struct efx_nic *efx);
-extern void falcon_set_multicast_hash(struct efx_nic *efx);
-extern int falcon_reset_xaui(struct efx_nic *efx);
-
-/**************************************************************************
- *
- * Falcon MAC stats
- *
- **************************************************************************
- */
-
-#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
-#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
-
-/* Retrieve statistic from statistics block */
-#define FALCON_STAT(efx, falcon_stat, efx_stat) do {           \
-       if (FALCON_STAT_WIDTH(falcon_stat) == 16)               \
-               (efx)->mac_stats.efx_stat += le16_to_cpu(       \
-                       *((__force __le16 *)                            \
-                         (efx->stats_buffer.addr +             \
-                          FALCON_STAT_OFFSET(falcon_stat))));  \
-       else if (FALCON_STAT_WIDTH(falcon_stat) == 32)          \
-               (efx)->mac_stats.efx_stat += le32_to_cpu(       \
-                       *((__force __le32 *)                            \
-                         (efx->stats_buffer.addr +             \
-                          FALCON_STAT_OFFSET(falcon_stat))));  \
-       else                                                    \
-               (efx)->mac_stats.efx_stat += le64_to_cpu(       \
-                       *((__force __le64 *)                            \
-                         (efx->stats_buffer.addr +             \
-                          FALCON_STAT_OFFSET(falcon_stat))));  \
-       } while (0)
-
-#define FALCON_MAC_STATS_SIZE 0x100
-
-#define MAC_DATA_LBN 0
-#define MAC_DATA_WIDTH 32
-
-extern void falcon_generate_event(struct efx_channel *channel,
-                                 efx_qword_t *event);
-
-#ifdef CONFIG_SFC_DEBUGFS
-struct seq_file;
-extern int falcon_debugfs_read_hardware_desc(struct seq_file *file, void *data);
-#endif
-
-#endif /* EFX_FALCON_H */
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
new file mode 100644 (file)
index 0000000..40249d9
--- /dev/null
@@ -0,0 +1,739 @@
+/****************************************************************************
+ * 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.
+ */
+
+#include "net_driver.h"
+#include "phy.h"
+#include "efx.h"
+#include "nic.h"
+#include "regs.h"
+#include "io.h"
+#include "workarounds.h"
+
+/* Macros for unpacking the board revision */
+/* The revision info is in host byte order. */
+#define FALCON_BOARD_TYPE(_rev) (_rev >> 8)
+#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
+#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf)
+
+/* Board types */
+#define FALCON_BOARD_SFE4001 0x01
+#define FALCON_BOARD_SFE4002 0x02
+#define FALCON_BOARD_SFN4111T 0x51
+#define FALCON_BOARD_SFN4112F 0x52
+
+/*****************************************************************************
+ * Support for LM87 sensor chip used on several boards
+ */
+#define LM87_REG_ALARMS1               0x41
+#define LM87_REG_ALARMS2               0x42
+#define LM87_IN_LIMITS(nr, _min, _max)                 \
+       0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
+#define LM87_AIN_LIMITS(nr, _min, _max)                        \
+       0x3B + (nr), _max, 0x1A + (nr), _min
+#define LM87_TEMP_INT_LIMITS(_min, _max)               \
+       0x39, _max, 0x3A, _min
+#define LM87_TEMP_EXT1_LIMITS(_min, _max)              \
+       0x37, _max, 0x38, _min
+
+#define LM87_ALARM_TEMP_INT            0x10
+#define LM87_ALARM_TEMP_EXT1           0x20
+
+static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+                        const u8 *reg_values)
+{
+       struct falcon_board *board = falcon_board(efx);
+       struct i2c_client *client = i2c_new_device(&board->i2c_adap, info);
+       int rc;
+
+       if (!client)
+               return -EIO;
+
+       while (*reg_values) {
+               u8 reg = *reg_values++;
+               u8 value = *reg_values++;
+               rc = i2c_smbus_write_byte_data(client, reg, value);
+               if (rc)
+                       goto err;
+       }
+
+       board->hwmon_client = client;
+       return 0;
+
+err:
+       i2c_unregister_device(client);
+       return rc;
+}
+
+static void efx_fini_lm87(struct efx_nic *efx)
+{
+       i2c_unregister_device(falcon_board(efx)->hwmon_client);
+}
+
+static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+       struct i2c_client *client = falcon_board(efx)->hwmon_client;
+       s32 alarms1, alarms2;
+
+       /* If link is up then do not monitor temperature */
+       if (EFX_WORKAROUND_7884(efx) && efx->link_state.up)
+               return 0;
+
+       alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
+       alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
+       if (alarms1 < 0)
+               return alarms1;
+       if (alarms2 < 0)
+               return alarms2;
+       alarms1 &= mask;
+       alarms2 &= mask >> 8;
+       if (alarms1 || alarms2) {
+               EFX_ERR(efx,
+                       "LM87 detected a hardware failure (status %02x:%02x)"
+                       "%s%s\n",
+                       alarms1, alarms2,
+                       (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
+                       (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
+               return -ERANGE;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************
+ * Support for the SFE4001 and SFN4111T NICs.
+ *
+ * The SFE4001 does not power-up fully at reset due to its high power
+ * consumption.  We control its power via a PCA9539 I/O expander.
+ * Both boards have a MAX6647 temperature monitor which we expose to
+ * the lm90 driver.
+ *
+ * This also provides minimal support for reflashing the PHY, which is
+ * initiated by resetting it with the FLASH_CFG_1 pin pulled down.
+ * On SFE4001 rev A2 and later this is connected to the 3V3X output of
+ * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3.
+ * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually
+ * exclusive with the network device being open.
+ */
+
+/**************************************************************************
+ * Support for I2C IO Expander device on SFE4001
+ */
+#define        PCA9539 0x74
+
+#define        P0_IN 0x00
+#define        P0_OUT 0x02
+#define        P0_INVERT 0x04
+#define        P0_CONFIG 0x06
+
+#define        P0_EN_1V0X_LBN 0
+#define        P0_EN_1V0X_WIDTH 1
+#define        P0_EN_1V2_LBN 1
+#define        P0_EN_1V2_WIDTH 1
+#define        P0_EN_2V5_LBN 2
+#define        P0_EN_2V5_WIDTH 1
+#define        P0_EN_3V3X_LBN 3
+#define        P0_EN_3V3X_WIDTH 1
+#define        P0_EN_5V_LBN 4
+#define        P0_EN_5V_WIDTH 1
+#define        P0_SHORTEN_JTAG_LBN 5
+#define        P0_SHORTEN_JTAG_WIDTH 1
+#define        P0_X_TRST_LBN 6
+#define        P0_X_TRST_WIDTH 1
+#define        P0_DSP_RESET_LBN 7
+#define        P0_DSP_RESET_WIDTH 1
+
+#define        P1_IN 0x01
+#define        P1_OUT 0x03
+#define        P1_INVERT 0x05
+#define        P1_CONFIG 0x07
+
+#define        P1_AFE_PWD_LBN 0
+#define        P1_AFE_PWD_WIDTH 1
+#define        P1_DSP_PWD25_LBN 1
+#define        P1_DSP_PWD25_WIDTH 1
+#define        P1_RESERVED_LBN 2
+#define        P1_RESERVED_WIDTH 2
+#define        P1_SPARE_LBN 4
+#define        P1_SPARE_WIDTH 4
+
+/* Temperature Sensor */
+#define MAX664X_REG_RSL                0x02
+#define MAX664X_REG_WLHO       0x0B
+
+static void sfe4001_poweroff(struct efx_nic *efx)
+{
+       struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client;
+       struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client;
+
+       /* Turn off all power rails and disable outputs */
+       i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
+       i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
+       i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
+
+       /* Clear any over-temperature alert */
+       i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
+}
+
+static int sfe4001_poweron(struct efx_nic *efx)
+{
+       struct i2c_client *ioexp_client = falcon_board(efx)->ioexp_client;
+       struct i2c_client *hwmon_client = falcon_board(efx)->hwmon_client;
+       unsigned int i, j;
+       int rc;
+       u8 out;
+
+       /* Clear any previous over-temperature alert */
+       rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
+       if (rc < 0)
+               return rc;
+
+       /* Enable port 0 and port 1 outputs on IO expander */
+       rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
+       if (rc)
+               return rc;
+       rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
+                                      0xff & ~(1 << P1_SPARE_LBN));
+       if (rc)
+               goto fail_on;
+
+       /* If PHY power is on, turn it all off and wait 1 second to
+        * ensure a full reset.
+        */
+       rc = i2c_smbus_read_byte_data(ioexp_client, P0_OUT);
+       if (rc < 0)
+               goto fail_on;
+       out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+                      (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+                      (0 << P0_EN_1V0X_LBN));
+       if (rc != out) {
+               EFX_INFO(efx, "power-cycling PHY\n");
+               rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
+               if (rc)
+                       goto fail_on;
+               schedule_timeout_uninterruptible(HZ);
+       }
+
+       for (i = 0; i < 20; ++i) {
+               /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+               out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+                              (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+                              (1 << P0_X_TRST_LBN));
+               if (efx->phy_mode & PHY_MODE_SPECIAL)
+                       out |= 1 << P0_EN_3V3X_LBN;
+
+               rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
+               if (rc)
+                       goto fail_on;
+               msleep(10);
+
+               /* Turn on 1V power rail */
+               out &= ~(1 << P0_EN_1V0X_LBN);
+               rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
+               if (rc)
+                       goto fail_on;
+
+               EFX_INFO(efx, "waiting for DSP boot (attempt %d)...\n", i);
+
+               /* In flash config mode, DSP does not turn on AFE, so
+                * just wait 1 second.
+                */
+               if (efx->phy_mode & PHY_MODE_SPECIAL) {
+                       schedule_timeout_uninterruptible(HZ);
+                       return 0;
+               }
+
+               for (j = 0; j < 10; ++j) {
+                       msleep(100);
+
+                       /* Check DSP has asserted AFE power line */
+                       rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
+                       if (rc < 0)
+                               goto fail_on;
+                       if (rc & (1 << P1_AFE_PWD_LBN))
+                               return 0;
+               }
+       }
+
+       EFX_INFO(efx, "timed out waiting for DSP boot\n");
+       rc = -ETIMEDOUT;
+fail_on:
+       sfe4001_poweroff(efx);
+       return rc;
+}
+
+static int sfn4111t_reset(struct efx_nic *efx)
+{
+       struct falcon_board *board = falcon_board(efx);
+       efx_oword_t reg;
+
+       /* GPIO 3 and the GPIO register are shared with I2C, so block that */
+       i2c_lock_adapter(&board->i2c_adap);
+
+       /* Pull RST_N (GPIO 2) low then let it up again, setting the
+        * FLASH_CFG_1 strap (GPIO 3) appropriately.  Only change the
+        * output enables; the output levels should always be 0 (low)
+        * and we rely on external pull-ups. */
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true);
+       efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
+       msleep(1000);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, false);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN,
+                           !!(efx->phy_mode & PHY_MODE_SPECIAL));
+       efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
+       msleep(1);
+
+       i2c_unlock_adapter(&board->i2c_adap);
+
+       ssleep(1);
+       return 0;
+}
+
+static ssize_t show_phy_flash_cfg(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_mode & PHY_MODE_SPECIAL));
+}
+
+static ssize_t set_phy_flash_cfg(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       enum efx_phy_mode old_mode, new_mode;
+       int err;
+
+       rtnl_lock();
+       old_mode = efx->phy_mode;
+       if (count == 0 || *buf == '0')
+               new_mode = old_mode & ~PHY_MODE_SPECIAL;
+       else
+               new_mode = PHY_MODE_SPECIAL;
+       if (old_mode == new_mode) {
+               err = 0;
+       } else if (efx->state != STATE_RUNNING || netif_running(efx->net_dev)) {
+               err = -EBUSY;
+       } else {
+               /* Reset the PHY, reconfigure the MAC and enable/disable
+                * MAC stats accordingly. */
+               efx->phy_mode = new_mode;
+               if (new_mode & PHY_MODE_SPECIAL)
+                       falcon_stop_nic_stats(efx);
+               if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001)
+                       err = sfe4001_poweron(efx);
+               else
+                       err = sfn4111t_reset(efx);
+               if (!err)
+                       err = efx_reconfigure_port(efx);
+               if (!(new_mode & PHY_MODE_SPECIAL))
+                       falcon_start_nic_stats(efx);
+       }
+       rtnl_unlock();
+
+       return err ? err : count;
+}
+
+static DEVICE_ATTR(phy_flash_cfg, 0644, show_phy_flash_cfg, set_phy_flash_cfg);
+
+static void sfe4001_fini(struct efx_nic *efx)
+{
+       struct falcon_board *board = falcon_board(efx);
+
+       EFX_INFO(efx, "%s\n", __func__);
+
+       device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+       sfe4001_poweroff(efx);
+       i2c_unregister_device(board->ioexp_client);
+       i2c_unregister_device(board->hwmon_client);
+}
+
+static int sfe4001_check_hw(struct efx_nic *efx)
+{
+       s32 status;
+
+       /* If XAUI link is up then do not monitor */
+       if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required)
+               return 0;
+       if (efx->phy_mode != PHY_MODE_NORMAL)
+               return 0;
+
+       /* Check the powered status of the PHY. Lack of power implies that
+        * the MAX6647 has shut down power to it, probably due to a temp.
+        * alarm. Reading the power status rather than the MAX6647 status
+        * directly because the later is read-to-clear and would thus
+        * start to power up the PHY again when polled, causing us to blip
+        * the power undesirably.
+        * We know we can read from the IO expander because we did
+        * it during power-on. Assume failure now is bad news. */
+       status = i2c_smbus_read_byte_data(falcon_board(efx)->ioexp_client, P1_IN);
+       if (status >= 0 &&
+           (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0)
+               return 0;
+
+       /* Use board power control, not PHY power control */
+       sfe4001_poweroff(efx);
+       efx->phy_mode = PHY_MODE_OFF;
+
+       return (status < 0) ? -EIO : -ERANGE;
+}
+
+static struct i2c_board_info sfe4001_hwmon_info = {
+       I2C_BOARD_INFO("max6647", 0x4e),
+};
+
+/* This board uses an I2C expander to provider power to the PHY, which needs to
+ * be turned on before the PHY can be used.
+ * Context: Process context, rtnl lock held
+ */
+static int sfe4001_init(struct efx_nic *efx)
+{
+       struct falcon_board *board = falcon_board(efx);
+       int rc;
+
+       board->hwmon_client =
+               i2c_new_device(&board->i2c_adap, &sfe4001_hwmon_info);
+       if (!board->hwmon_client)
+               return -EIO;
+
+       /* Raise board/PHY high limit from 85 to 90 degrees Celsius */
+       rc = i2c_smbus_write_byte_data(board->hwmon_client,
+                                      MAX664X_REG_WLHO, 90);
+       if (rc)
+               goto fail_hwmon;
+
+       board->ioexp_client = i2c_new_dummy(&board->i2c_adap, PCA9539);
+       if (!board->ioexp_client) {
+               rc = -EIO;
+               goto fail_hwmon;
+       }
+
+       if (efx->phy_mode & PHY_MODE_SPECIAL) {
+               /* PHY won't generate a 156.25 MHz clock and MAC stats fetch
+                * will fail. */
+               falcon_stop_nic_stats(efx);
+       }
+       rc = sfe4001_poweron(efx);
+       if (rc)
+               goto fail_ioexp;
+
+       rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+       if (rc)
+               goto fail_on;
+
+       EFX_INFO(efx, "PHY is powered on\n");
+       return 0;
+
+fail_on:
+       sfe4001_poweroff(efx);
+fail_ioexp:
+       i2c_unregister_device(board->ioexp_client);
+fail_hwmon:
+       i2c_unregister_device(board->hwmon_client);
+       return rc;
+}
+
+static int sfn4111t_check_hw(struct efx_nic *efx)
+{
+       s32 status;
+
+       /* If XAUI link is up then do not monitor */
+       if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required)
+               return 0;
+
+       /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */
+       status = i2c_smbus_read_byte_data(falcon_board(efx)->hwmon_client,
+                                         MAX664X_REG_RSL);
+       if (status < 0)
+               return -EIO;
+       if (status & 0x57)
+               return -ERANGE;
+       return 0;
+}
+
+static void sfn4111t_fini(struct efx_nic *efx)
+{
+       EFX_INFO(efx, "%s\n", __func__);
+
+       device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+       i2c_unregister_device(falcon_board(efx)->hwmon_client);
+}
+
+static struct i2c_board_info sfn4111t_a0_hwmon_info = {
+       I2C_BOARD_INFO("max6647", 0x4e),
+};
+
+static struct i2c_board_info sfn4111t_r5_hwmon_info = {
+       I2C_BOARD_INFO("max6646", 0x4d),
+};
+
+static void sfn4111t_init_phy(struct efx_nic *efx)
+{
+       if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
+               if (sft9001_wait_boot(efx) != -EINVAL)
+                       return;
+
+               efx->phy_mode = PHY_MODE_SPECIAL;
+               falcon_stop_nic_stats(efx);
+       }
+
+       sfn4111t_reset(efx);
+       sft9001_wait_boot(efx);
+}
+
+static int sfn4111t_init(struct efx_nic *efx)
+{
+       struct falcon_board *board = falcon_board(efx);
+       int rc;
+
+       board->hwmon_client =
+               i2c_new_device(&board->i2c_adap,
+                              (board->minor < 5) ?
+                              &sfn4111t_a0_hwmon_info :
+                              &sfn4111t_r5_hwmon_info);
+       if (!board->hwmon_client)
+               return -EIO;
+
+       rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
+       if (rc)
+               goto fail_hwmon;
+
+       if (efx->phy_mode & PHY_MODE_SPECIAL)
+               /* PHY may not generate a 156.25 MHz clock and MAC
+                * stats fetch will fail. */
+               falcon_stop_nic_stats(efx);
+
+       return 0;
+
+fail_hwmon:
+       i2c_unregister_device(board->hwmon_client);
+       return rc;
+}
+
+/*****************************************************************************
+ * Support for the SFE4002
+ *
+ */
+static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfe4002_lm87_regs[] = {
+       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
+       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
+       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
+       LM87_IN_LIMITS(3, 0xb0, 0xc9),          /* 5V:    4.6-5.2V */
+       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
+       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
+       LM87_AIN_LIMITS(0, 0xa0, 0xb2),         /* AIN1:  1.66V +/- 5% */
+       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
+       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
+       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       0
+};
+
+static struct i2c_board_info sfe4002_hwmon_info = {
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_NEED_LM87_DRIVER)
+       I2C_BOARD_INFO("lm87", 0x2e),
+#else
+       I2C_BOARD_INFO("sfc_lm87", 0x2e),
+#endif
+       .platform_data  = &sfe4002_lm87_channel,
+};
+
+/****************************************************************************/
+/* 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 void sfe4002_init_phy(struct efx_nic *efx)
+{
+       /* Set the TX and RX LEDs to reflect status and activity, and the
+        * fault LED off */
+       falcon_qt202x_set_led(efx, SFE4002_TX_LED,
+                             QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
+       falcon_qt202x_set_led(efx, SFE4002_RX_LED,
+                             QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
+       falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
+}
+
+static void sfe4002_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+       falcon_qt202x_set_led(
+               efx, SFE4002_FAULT_LED,
+               (mode == EFX_LED_ON) ? QUAKE_LED_ON : QUAKE_LED_OFF);
+}
+
+static int sfe4002_check_hw(struct efx_nic *efx)
+{
+       struct falcon_board *board = falcon_board(efx);
+
+       /* A0 board rev. 4002s report a temperature fault the whole time
+        * (bad sensor) so we mask it out. */
+       unsigned alarm_mask =
+               (board->major == 0 && board->minor == 0) ?
+               ~LM87_ALARM_TEMP_EXT1 : ~0;
+
+       return efx_check_lm87(efx, alarm_mask);
+}
+
+static int sfe4002_init(struct efx_nic *efx)
+{
+       return efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
+}
+
+/*****************************************************************************
+ * Support for the SFN4112F
+ *
+ */
+static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfn4112f_lm87_regs[] = {
+       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
+       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
+       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
+       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
+       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
+       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
+       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
+       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       0
+};
+
+static struct i2c_board_info sfn4112f_hwmon_info = {
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_NEED_LM87_DRIVER)
+       I2C_BOARD_INFO("lm87", 0x2e),
+#else
+       I2C_BOARD_INFO("sfc_lm87", 0x2e),
+#endif
+       .platform_data  = &sfn4112f_lm87_channel,
+};
+
+#define SFN4112F_ACT_LED       0
+#define SFN4112F_LINK_LED      1
+
+static void sfn4112f_init_phy(struct efx_nic *efx)
+{
+       falcon_qt202x_set_led(efx, SFN4112F_ACT_LED,
+                             QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT);
+       falcon_qt202x_set_led(efx, SFN4112F_LINK_LED,
+                             QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT);
+}
+
+static void sfn4112f_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+       int reg;
+
+       switch (mode) {
+       case EFX_LED_OFF:
+               reg = QUAKE_LED_OFF;
+               break;
+       case EFX_LED_ON:
+               reg = QUAKE_LED_ON;
+               break;
+       default:
+               reg = QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT;
+               break;
+       }
+
+       falcon_qt202x_set_led(efx, SFN4112F_LINK_LED, reg);
+}
+
+static int sfn4112f_check_hw(struct efx_nic *efx)
+{
+       /* Mask out unused sensors */
+       return efx_check_lm87(efx, ~0x48);
+}
+
+static int sfn4112f_init(struct efx_nic *efx)
+{
+       return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
+}
+
+static const struct falcon_board_type board_types[] = {
+       {
+               .id             = FALCON_BOARD_SFE4001,
+               .mwatts         = 18000,
+               .ref_model      = "SFE4001",
+               .gen_type       = "10GBASE-T adapter",
+               .init           = sfe4001_init,
+               .init_phy       = efx_port_dummy_op_void,
+               .fini           = sfe4001_fini,
+               .set_id_led     = tenxpress_set_id_led,
+               .monitor        = sfe4001_check_hw,
+       },
+       {
+               .id             = FALCON_BOARD_SFE4002,
+               .mwatts         = 7500,
+               .ref_model      = "SFE4002",
+               .gen_type       = "XFP adapter",
+               .init           = sfe4002_init,
+               .init_phy       = sfe4002_init_phy,
+               .fini           = efx_fini_lm87,
+               .set_id_led     = sfe4002_set_id_led,
+               .monitor        = sfe4002_check_hw,
+       },
+       {
+               .id             = FALCON_BOARD_SFN4111T,
+               .mwatts         = 10000,
+               .ref_model      = "SFN4111T",
+               .gen_type       = "100/1000/10GBASE-T adapter",
+               .init           = sfn4111t_init,
+               .init_phy       = sfn4111t_init_phy,
+               .fini           = sfn4111t_fini,
+               .set_id_led     = tenxpress_set_id_led,
+               .monitor        = sfn4111t_check_hw,
+       },
+       {
+               .id             = FALCON_BOARD_SFN4112F,
+               .mwatts         = 7500,
+               .ref_model      = "SFN4112F",
+               .gen_type       = "SFP+ adapter",
+               .init           = sfn4112f_init,
+               .init_phy       = sfn4112f_init_phy,
+               .fini           = efx_fini_lm87,
+               .set_id_led     = sfn4112f_set_id_led,
+               .monitor        = sfn4112f_check_hw,
+       },
+};
+
+static const struct falcon_board_type falcon_dummy_board = {
+       .init           = efx_port_dummy_op_int,
+       .init_phy       = efx_port_dummy_op_void,
+       .fini           = efx_port_dummy_op_void,
+       .set_id_led     = efx_port_dummy_op_set_id_led,
+       .monitor        = efx_port_dummy_op_int,
+};
+
+void falcon_probe_board(struct efx_nic *efx, u16 revision_info)
+{
+       struct falcon_board *board = falcon_board(efx);
+       u8 type_id = FALCON_BOARD_TYPE(revision_info);
+       int i;
+
+       board->major = FALCON_BOARD_MAJOR(revision_info);
+       board->minor = FALCON_BOARD_MINOR(revision_info);
+
+       for (i = 0; i < ARRAY_SIZE(board_types); i++)
+               if (board_types[i].id == type_id)
+                       board->type = &board_types[i];
+
+       if (board->type) {
+               EFX_INFO(efx, "board is %s rev %c%d\n",
+                        (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
+                        ? board->type->ref_model : board->type->gen_type,
+                        'A' + board->major, board->minor);
+       } else {
+               EFX_ERR(efx, "unknown board type %d\n", type_id);
+               board->type = &falcon_dummy_board;
+       }
+}
index 1c9a0a881aa7611adfc5259a80c52e34da6b8dcd..7dadfcbd6ce7e75e8c22a1e3a6a4ce89de1ce21e 100644 (file)
@@ -1,66 +1,20 @@
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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/delay.h>
 #include "net_driver.h"
 #include "efx.h"
-#include "falcon.h"
+#include "nic.h"
 #include "mac.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
-#include "gmii.h"
-
-/**************************************************************************
- *
- * MAC register access
- *
- **************************************************************************/
-
-/* Offset of a GMAC register within Falcon */
-#define FALCON_GMAC_REG(mac_reg)                                       \
-       (FALCON_GMAC_REGBANK + ((mac_reg) * FALCON_GMAC_REG_SIZE))
-
-static void falcon_gmac_writel(struct efx_nic *efx,
-                              efx_dword_t *value, unsigned int mac_reg)
-{
-       efx_oword_t temp;
-
-       EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
-       falcon_write(efx, &temp, FALCON_GMAC_REG(mac_reg));
-}
-
-static void falcon_gmac_readl(struct efx_nic *efx,
-                             efx_dword_t *value, unsigned int mac_reg)
-{
-       efx_oword_t temp;
-
-       falcon_read(efx, &temp, FALCON_GMAC_REG(mac_reg));
-       EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
-}
+#include "regs.h"
+#include "io.h"
 
 /**************************************************************************
  *
@@ -68,47 +22,109 @@ static void falcon_gmac_readl(struct efx_nic *efx,
  *
  *************************************************************************/
 
-static int falcon_init_gmac(struct efx_nic *efx)
+static int falcon_reconfigure_gmac(struct efx_nic *efx)
 {
-       int rc;
+       struct efx_link_state *link_state = &efx->link_state;
+       bool loopback, tx_fc, rx_fc, bytemode;
+       int if_mode;
+       unsigned int max_frame_len;
+       efx_oword_t reg;
+
+       /* Configuration register 1 */
+       tx_fc = (link_state->fc & EFX_FC_TX) || !link_state->fd;
+       rx_fc = !!(link_state->fc & EFX_FC_RX);
+       loopback = (efx->loopback_mode == LOOPBACK_GMAC);
+       bytemode = (link_state->speed == 1000);
+
+       EFX_POPULATE_OWORD_5(reg,
+                            FRF_AB_GM_LOOP, loopback,
+                            FRF_AB_GM_TX_EN, 1,
+                            FRF_AB_GM_TX_FC_EN, tx_fc,
+                            FRF_AB_GM_RX_EN, 1,
+                            FRF_AB_GM_RX_FC_EN, rx_fc);
+       efx_writeo(efx, &reg, FR_AB_GM_CFG1);
+       udelay(10);
+
+       /* Configuration register 2 */
+       if_mode = (bytemode) ? 2 : 1;
+       EFX_POPULATE_OWORD_5(reg,
+                            FRF_AB_GM_IF_MODE, if_mode,
+                            FRF_AB_GM_PAD_CRC_EN, 1,
+                            FRF_AB_GM_LEN_CHK, 1,
+                            FRF_AB_GM_FD, link_state->fd,
+                            FRF_AB_GM_PAMBL_LEN, 0x7/*datasheet recommended */);
+
+       efx_writeo(efx, &reg, FR_AB_GM_CFG2);
+       udelay(10);
+
+       /* Max frame len register */
+       max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_MAX_FLEN, max_frame_len);
+       efx_writeo(efx, &reg, FR_AB_GM_MAX_FLEN);
+       udelay(10);
+
+       /* FIFO configuration register 0 */
+       EFX_POPULATE_OWORD_5(reg,
+                            FRF_AB_GMF_FTFENREQ, 1,
+                            FRF_AB_GMF_STFENREQ, 1,
+                            FRF_AB_GMF_FRFENREQ, 1,
+                            FRF_AB_GMF_SRFENREQ, 1,
+                            FRF_AB_GMF_WTMENREQ, 1);
+       efx_writeo(efx, &reg, FR_AB_GMF_CFG0);
+       udelay(10);
+
+       /* FIFO configuration register 1 */
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_GMF_CFGFRTH, 0x12,
+                            FRF_AB_GMF_CFGXOFFRTX, 0xffff);
+       efx_writeo(efx, &reg, FR_AB_GMF_CFG1);
+       udelay(10);
+
+       /* FIFO configuration register 2 */
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_GMF_CFGHWM, 0x3f,
+                            FRF_AB_GMF_CFGLWM, 0xa);
+       efx_writeo(efx, &reg, FR_AB_GMF_CFG2);
+       udelay(10);
+
+       /* FIFO configuration register 3 */
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_GMF_CFGHWMFT, 0x1c,
+                            FRF_AB_GMF_CFGFTTH, 0x08);
+       efx_writeo(efx, &reg, FR_AB_GMF_CFG3);
+       udelay(10);
+
+       /* FIFO configuration register 4 */
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_GMF_HSTFLTRFRM_PAUSE, 1);
+       efx_writeo(efx, &reg, FR_AB_GMF_CFG4);
+       udelay(10);
+
+       /* FIFO configuration register 5 */
+       efx_reado(efx, &reg, FR_AB_GMF_CFG5);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGBYTMODE, bytemode);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_CFGHDPLX, !link_state->fd);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTDRPLT64, !link_state->fd);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GMF_HSTFLTRFRMDC_PAUSE, 0);
+       efx_writeo(efx, &reg, FR_AB_GMF_CFG5);
+       udelay(10);
+
+       /* MAC address */
+       EFX_POPULATE_OWORD_4(reg,
+                            FRF_AB_GM_ADR_B0, efx->net_dev->dev_addr[5],
+                            FRF_AB_GM_ADR_B1, efx->net_dev->dev_addr[4],
+                            FRF_AB_GM_ADR_B2, efx->net_dev->dev_addr[3],
+                            FRF_AB_GM_ADR_B3, efx->net_dev->dev_addr[2]);
+       efx_writeo(efx, &reg, FR_AB_GM_ADR1);
+       udelay(10);
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_GM_ADR_B4, efx->net_dev->dev_addr[1],
+                            FRF_AB_GM_ADR_B5, efx->net_dev->dev_addr[0]);
+       efx_writeo(efx, &reg, FR_AB_GM_ADR2);
+       udelay(10);
 
-       /* Reset the MAC */
-       mentormac_reset(efx);
-
-       /* Initialise PHY */
-       rc = efx->phy_op->init(efx);
-       if (rc)
-               return rc;
-
-       return 0;
-}
-
-static void falcon_reconfigure_gmac(struct efx_nic *efx)
-{
-       /* Reconfigure PHY and pick up PHY parameters.  This updates
-        * the link status. */
-       efx->phy_op->reconfigure(efx);
-
-       /* Isolate the MAC. */
-       falcon_deconfigure_mac_wrapper(efx);
-
-       /* Reconfigure MAC */
-       mentormac_reconfigure(efx);
-
-       /* Reconfigure MAC wrapper */
        falcon_reconfigure_mac_wrapper(efx);
-}
-
-static void falcon_fini_gmac(struct efx_nic *efx)
-{
-       /* Isolate the MAC - PHY */
-       falcon_deconfigure_mac_wrapper(efx);
 
-       /* Shut down PHY */
-       efx->phy_op->fini(efx);
-
-       /* Reset MAC */
-       mentormac_reset(efx);
+       return 0;
 }
 
 static void falcon_update_stats_gmac(struct efx_nic *efx)
@@ -116,11 +132,6 @@ static void falcon_update_stats_gmac(struct efx_nic *efx)
        struct efx_mac_stats *mac_stats = &efx->mac_stats;
        unsigned long old_rx_pause, old_tx_pause;
        unsigned long new_rx_pause, new_tx_pause;
-       int rc;
-
-       rc = falcon_dma_stats(efx, GDmaDone_offset);
-       if (rc)
-               return;
 
        /* Pause frames are erroneously counted as errors (SFC bug 3269) */
        old_rx_pause = mac_stats->rx_pause;
@@ -207,114 +218,13 @@ static void falcon_update_stats_gmac(struct efx_nic *efx)
        mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64;
 }
 
-static int falcon_check_gmac(struct efx_nic *efx)
-{
-       /* Nothing to do */
-       return 0;
-}
-
-static void falcon_gmac_sim_phy_event(struct efx_nic *efx)
+static bool falcon_gmac_check_fault(struct efx_nic *efx)
 {
-       efx_qword_t phy_event;
-
-       EFX_POPULATE_QWORD_2(phy_event,
-                            EV_CODE, GLOBAL_EV_DECODE,
-                            G_PHY0_INTR, 1);
-       falcon_generate_event(&efx->channel[0], &phy_event);
+       return false;
 }
 
-static void falcon_gmac_reset_phy(struct efx_nic *efx)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       int bmcr, i;
-
-       /* Perform software reset to make new settings take effect */
-       bmcr = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR);
-       bmcr |= BMCR_RESET;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, MII_BMCR, bmcr);
-
-       /* Wait for the reset to deassert */
-       for (i = 20; i; --i) {
-               udelay(10);
-               if ((gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR) &
-                   BMCR_RESET) == 0)
-                       return;
-       }
-
-       EFX_ERR(efx, "wait for PHY reset timed out\n");
-}
-
-
-static int falcon_gmac_get_settings(struct efx_nic *efx,
-                                   struct ethtool_cmd *ecmd)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       int rc;
-
-       rc = mii_ethtool_gset(gmii, ecmd);
-       ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
-       return rc;
-}
-
-static int falcon_gmac_set_settings(struct efx_nic *efx,
-                                   struct ethtool_cmd *ecmd)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       int rc;
-
-       /* 1000Mbps half-duplex is technically legal, but none of our
-        * current hardware supports it, so just disallow it. */
-       if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
-               EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
-                       " setting\n");
-               return -EINVAL;
-       }
-
-       /* Use MII to set all other settings */
-       rc = mii_ethtool_sset(gmii, ecmd);
-       if (rc)
-               return rc;
-
-       /* Reset the PHY */
-       falcon_gmac_reset_phy(efx);
-
-       return 0;
-}
-
-static int falcon_gmac_set_pause(struct efx_nic *efx,
-                                enum efx_fc_type flow_control)
-{
-       struct mii_if_info *gmii = &efx->mii;
-       int adv;
-
-       /* GMAC has tiny MAC FIFO, so TX flow control won't work */
-       if (flow_control & EFX_FC_TX)
-               return -EINVAL;
-
-       efx->flow_control = flow_control;
-
-       /* Push autonegotiation to PHY */
-       adv = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
-       adv &= ~GM_ADVERTISE_PAUSE_CAP;
-       adv |= (flow_control & EFX_FC_AUTO) ? GM_ADVERTISE_PAUSE_CAP : 0;
-       gmii->mdio_write(gmii->dev, gmii->phy_id, MII_ADVERTISE, adv);
-
-       falcon_gmac_reset_phy(efx);
-
-       return 0;
-}
-
-
 struct efx_mac_operations falcon_gmac_operations = {
-       .mac_writel     = falcon_gmac_writel,
-       .mac_readl      = falcon_gmac_readl,
-       .init           = falcon_init_gmac,
        .reconfigure    = falcon_reconfigure_gmac,
        .update_stats   = falcon_update_stats_gmac,
-       .fini           = falcon_fini_gmac,
-       .check_hw       = falcon_check_gmac,
-       .fake_phy_event = falcon_gmac_sim_phy_event,
-       .get_settings   = falcon_gmac_get_settings,
-       .set_settings   = falcon_gmac_set_settings,
-       .set_pause      = falcon_gmac_set_pause,
+       .check_fault    = falcon_gmac_check_fault,
 };
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
deleted file mode 100644 (file)
index d4265d4..0000000
+++ /dev/null
@@ -1,1638 +0,0 @@
-/****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_FALCON_HWDEFS_H
-#define EFX_FALCON_HWDEFS_H
-
-/*
- * Falcon hardware value definitions.
- * Falcon is the internal codename for the SFC4000 controller that is
- * present in SFE400X evaluation boards
- */
-
-/**************************************************************************
- *
- * Falcon registers
- *
- **************************************************************************
- */
-
-/* Address region register */
-#define ADR_REGION_REG_KER     0x00
-#define ADR_REGION0_LBN        0
-#define ADR_REGION0_WIDTH      18
-#define ADR_REGION1_LBN        32
-#define ADR_REGION1_WIDTH      18
-#define ADR_REGION2_LBN        64
-#define ADR_REGION2_WIDTH      18
-#define ADR_REGION3_LBN        96
-#define ADR_REGION3_WIDTH      18
-
-/* Interrupt enable register */
-#define INT_EN_REG_KER 0x0010
-#define INT_LEVEL_SEL_LBN 8
-#define INT_LEVEL_SEL_WIDTH 6
-#define MEM_PERR_INT_EN_KER_LBN 5
-#define MEM_PERR_INT_EN_KER_WIDTH 1
-#define KER_INT_CHAR_LBN 4
-#define KER_INT_CHAR_WIDTH 1
-#define KER_INT_KER_LBN 3
-#define KER_INT_KER_WIDTH 1
-#define ILL_ADR_ERR_INT_EN_KER_LBN 2
-#define ILL_ADR_ERR_INT_EN_KER_WIDTH 1
-#define SRM_PERR_INT_EN_KER_LBN 1
-#define SRM_PERR_INT_EN_KER_WIDTH 1
-#define DRV_INT_EN_KER_LBN 0
-#define DRV_INT_EN_KER_WIDTH 1
-
-/* Interrupt status address register */
-#define INT_ADR_REG_KER        0x0030
-#define NORM_INT_VEC_DIS_KER_LBN 64
-#define NORM_INT_VEC_DIS_KER_WIDTH 1
-#define INT_ADR_KER_LBN 0
-#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */
-
-/* Interrupt status register (B0 only) */
-#define INT_ISR0_B0 0x90
-#define INT_ISR1_B0 0xA0
-
-/* Interrupt acknowledge register (A0/A1 only) */
-#define INT_ACK_REG_KER_A1 0x0050
-#define INT_ACK_DUMMY_DATA_LBN 0
-#define INT_ACK_DUMMY_DATA_WIDTH 32
-
-/* Interrupt acknowledge work-around register (A0/A1 only )*/
-#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
-
-/* Hardware initialisation register */
-#define HW_INIT_REG_KER 0x00c0
-#define BCSR_TARGET_MASK_LBN 101
-#define BCSR_TARGET_MASK_WIDTH 4
-#define PCIE_TIMEOUT_DIS_LBN 123
-#define PCIE_TIMEOUT_DIS_WIDTH 1
-#define B2B_REQ_EN_B0_LBN 45
-#define B2B_REQ_EN_B0_WIDTH 1
-#define FC_BLOCKING_EN_B0_LBN 44
-#define FC_BLOCKING_EN_B0_WIDTH 1
-
-/* SPI host command register */
-#define EE_SPI_HCMD_REG_KER 0x0100
-#define EE_SPI_HCMD_CMD_EN_LBN 31
-#define EE_SPI_HCMD_CMD_EN_WIDTH 1
-#define EE_WR_TIMER_ACTIVE_LBN 28
-#define EE_WR_TIMER_ACTIVE_WIDTH 1
-#define EE_SPI_HCMD_SF_SEL_LBN 24
-#define EE_SPI_HCMD_SF_SEL_WIDTH 1
-#define EE_SPI_EEPROM 0
-#define EE_SPI_FLASH 1
-#define EE_SPI_HCMD_DABCNT_LBN 16
-#define EE_SPI_HCMD_DABCNT_WIDTH 5
-#define EE_SPI_HCMD_READ_LBN 15
-#define EE_SPI_HCMD_READ_WIDTH 1
-#define EE_SPI_READ 1
-#define EE_SPI_WRITE 0
-#define EE_SPI_HCMD_DUBCNT_LBN 12
-#define EE_SPI_HCMD_DUBCNT_WIDTH 2
-#define EE_SPI_HCMD_ADBCNT_LBN 8
-#define EE_SPI_HCMD_ADBCNT_WIDTH 2
-#define EE_SPI_HCMD_ENC_LBN 0
-#define EE_SPI_HCMD_ENC_WIDTH 8
-
-/* SPI host address register */
-#define EE_SPI_HADR_REG_KER 0x0110
-#define EE_SPI_HADR_DUBYTE_LBN 24
-#define EE_SPI_HADR_DUBYTE_WIDTH 8
-#define EE_SPI_HADR_ADR_LBN 0
-#define EE_SPI_HADR_ADR_WIDTH 24
-
-/* SPI host data register */
-#define EE_SPI_HDATA_REG_KER 0x0120
-#define EE_SPI_HDATA3_LBN 96
-#define EE_SPI_HDATA3_WIDTH 32
-#define EE_SPI_HDATA2_LBN 64
-#define EE_SPI_HDATA2_WIDTH 32
-#define EE_SPI_HDATA1_LBN 32
-#define EE_SPI_HDATA1_WIDTH 32
-#define EE_SPI_HDATA0_LBN 0
-#define EE_SPI_HDATA0_WIDTH 32
-
-/* SPI/VPD config register */
-#define EE_VPD_CFG_REG_KER 0x0140
-#define EE_VPD_EN_LBN 0
-#define EE_VPD_EN_WIDTH 1
-#define EE_VPD_EN_AD9_MODE_LBN 1
-#define EE_VPD_EN_AD9_MODE_WIDTH 1
-#define EE_EE_CLOCK_DIV_LBN 112
-#define EE_EE_CLOCK_DIV_WIDTH 7
-#define EE_SF_CLOCK_DIV_LBN 120
-#define EE_SF_CLOCK_DIV_WIDTH 7
-
-/* PCIE CORE ACCESS REG */
-#define PCIE_CORE_INDIRECT_REG 0x01f0
-#define PCIE_CORE_ADDR_LBN 0
-#define PCIE_CORE_ADDR_WIDTH 12
-#define PCIE_CORE_RW_LBN 15
-#define PCIE_CORE_RW_WIDTH 1
-#define PCIE_CORE_VALUE_LBN 32
-#define PCIE_CORE_VALUE_WIDTH 32
-
-#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
-#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
-#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700
-#define PCIE_CORE_ACK_TL_LBN 0
-#define PCIE_CORE_ACK_TL_WIDTH 16
-#define PCIE_CORE_RPL_TL_LBN 16
-#define PCIE_CORE_RPL_TL_WIDTH 16
-
-#define PCIE_CORE_ADDR_ACK_FREQ 0x70C
-#define PCIE_CORE_ACK_FREQ_LBN 0
-#define PCIE_CORE_ACK_FREQ_WIDTH 7
-
-
-/* NIC status register */
-#define NIC_STAT_REG 0x0200
-#define EE_STRAP_EN_LBN 31
-#define EE_STRAP_EN_WIDTH 1
-#define EE_STRAP_OVR_LBN 24
-#define EE_STRAP_OVR_WIDTH 4
-#define ONCHIP_SRAM_LBN 16
-#define ONCHIP_SRAM_WIDTH 1
-#define SF_PRST_LBN 9
-#define SF_PRST_WIDTH 1
-#define EE_PRST_LBN 8
-#define EE_PRST_WIDTH 1
-#define EE_STRAP_LBN 7
-#define EE_STRAP_WIDTH 1
-/* See pic_mode_t for decoding of this field */
-#define STRAP_ISCSI_EN_LBN 3
-#define STRAP_ISCSI_EN_WIDTH 1
-#define STRAP_PINS_LBN 0
-#define STRAP_PINS_WIDTH 3
-/* These bit definitions are extrapolated from the list of numerical
- * values for STRAP_PINS.
- */
-#define STRAP_10G_LBN 2
-#define STRAP_10G_WIDTH 1
-#define STRAP_DUAL_PORT_LBN 1
-#define STRAP_DUAL_PORT_WIDTH 1
-#define STRAP_PCIE_LBN 0
-#define STRAP_PCIE_WIDTH 1
-
-#define FLASH_PRESENT_LBN 7
-#define FLASH_PRESENT_WIDTH 1
-#define EEPROM_PRESENT_LBN 6
-#define EEPROM_PRESENT_WIDTH 1
-#define BOOTED_USING_NVDEVICE_LBN 3
-#define BOOTED_USING_NVDEVICE_WIDTH 1
-
-/* GPIO control register */
-
-#define GPIO_CTL_REG_KER 0x0210
-
-#define GPIO_USE_NIC_CLK_LBN (30)
-#define GPIO_USE_NIC_CLK_WIDTH (1)
-
-#define GPIO_OUTPUTS_LBN   (16)
-#define GPIO_OUTPUTS_WIDTH (4)
-
-#define GPIO_INPUTS_LBN (8)
-#define GPIO_INPUT_WIDTH (4)
-
-#define GPIO_DIRECTION_LBN (24)
-#define GPIO_DIRECTION_WIDTH (4)
-#define GPIO_DIRECTION_OUT (1)
-#define GPIO_SRAM_SLEEP (1 << 1)
-
-#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3)
-#define        GPIO3_OEN_WIDTH 1
-#define        GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2)
-#define        GPIO2_OEN_WIDTH 1
-#define        GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1)
-#define        GPIO1_OEN_WIDTH 1
-#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0)
-#define        GPIO0_OEN_WIDTH 1
-
-#define        GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3)
-#define        GPIO3_OUT_WIDTH 1
-#define        GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2)
-#define        GPIO2_OUT_WIDTH 1
-#define        GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1)
-#define        GPIO1_OUT_WIDTH 1
-#define        GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0)
-#define        GPIO0_OUT_WIDTH 1
-
-#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3)
-#define        GPIO3_IN_WIDTH 1
-#define GPIO2_IN_LBN (GPIO_INPUTS_LBN + 2)
-#define        GPIO2_IN_WIDTH 1
-#define GPIO1_IN_LBN (GPIO_INPUTS_LBN + 1)
-#define        GPIO1_IN_WIDTH 1
-#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0)
-#define        GPIO0_IN_WIDTH 1
-
-/* Global control register */
-#define GLB_CTL_REG_KER        0x0220
-#define EXT_PHY_RST_CTL_LBN 63
-#define EXT_PHY_RST_CTL_WIDTH 1
-#define PCIE_SD_RST_CTL_LBN 61
-#define PCIE_SD_RST_CTL_WIDTH 1
-#define PCIX_RST_CTL_LBN 60
-#define PCIX_RST_CTL_WIDTH 1
-#define PCIE_STCK_RST_CTL_LBN 59
-
-#define PCIE_STCK_RST_CTL_WIDTH 1
-#define PCIE_NSTCK_RST_CTL_LBN 58
-#define PCIE_NSTCK_RST_CTL_WIDTH 1
-#define PCIE_CORE_RST_CTL_LBN 57
-#define PCIE_CORE_RST_CTL_WIDTH 1
-#define EE_RST_CTL_LBN 49
-#define EE_RST_CTL_WIDTH 1
-#define CS_RST_CTL_LBN 48
-#define CS_RST_CTL_WIDTH 1
-#define RST_EXT_PHY_LBN 31
-#define RST_EXT_PHY_WIDTH 1
-#define RST_XGRX_LBN 24
-#define RST_XGRX_WIDTH 1
-#define RST_XGTX_LBN 23
-#define RST_XGTX_WIDTH 1
-#define RST_EM_LBN 22
-#define RST_EM_WIDTH 1
-#define INT_RST_DUR_LBN 4
-#define INT_RST_DUR_WIDTH 3
-#define EXT_PHY_RST_DUR_LBN 1
-#define EXT_PHY_RST_DUR_WIDTH 3
-#define SWRST_LBN 0
-#define SWRST_WIDTH 1
-#define INCLUDE_IN_RESET 0
-#define EXCLUDE_FROM_RESET 1
-
-/* Fatal interrupt register */
-#define FATAL_INTR_REG_KER 0x0230
-#define PCI_BUSERR_INT_KER_EN_LBN 43
-#define PCI_BUSERR_INT_KER_EN_WIDTH 1
-#define SRAM_OOB_INT_KER_EN_LBN 42
-#define SRAM_OOB_INT_KER_EN_WIDTH 1
-#define BUFID_OOB_INT_KER_EN_LBN 41
-#define BUFID_OOB_INT_KER_EN_WIDTH 1
-#define MEM_PERR_INT_KER_EN_LBN 40
-#define MEM_PERR_INT_KER_EN_WIDTH 1
-#define RBUF_OWN_INT_KER_EN_LBN 39
-#define RBUF_OWN_INT_KER_EN_WIDTH 1
-#define TBUF_OWN_INT_KER_EN_LBN 38
-#define TBUF_OWN_INT_KER_EN_WIDTH 1
-#define RDESCQ_OWN_INT_KER_EN_LBN 37
-#define RDESCQ_OWN_INT_KER_EN_WIDTH 1
-#define TDESCQ_OWN_INT_KER_EN_LBN 36
-#define TDESCQ_OWN_INT_KER_EN_WIDTH 1
-#define EVQ_OWN_INT_KER_EN_LBN 35
-#define EVQ_OWN_INT_KER_EN_WIDTH 1
-#define EVFF_OFLO_INT_KER_EN_LBN 34
-#define EVFF_OFLO_INT_KER_EN_WIDTH 1
-#define ILL_ADR_INT_KER_EN_LBN 33
-#define ILL_ADR_INT_KER_EN_WIDTH 1
-#define SRM_PERR_INT_KER_EN_LBN 32
-#define SRM_PERR_INT_KER_EN_WIDTH 1
-#define MEM_PERR_INT_KER_LBN 8
-#define MEM_PERR_INT_KER_WIDTH 1
-#define INT_KER_ERROR_LBN 0
-#define INT_KER_ERROR_WIDTH 12
-
-#define DP_CTRL_REG 0x250
-#define FLS_EVQ_ID_LBN 0
-#define FLS_EVQ_ID_WIDTH 11
-
-#define MEM_STAT_REG_KER 0x260
-
-/* Debug probe register */
-#define DEBUG_REG_KER 0x0270
-#define DEBUG_BLK_SEL2_LBN 47
-#define DEBUG_BLK_SEL2_WIDTH 3
-#define DEBUG_BLK_SEL1_LBN 44
-#define DEBUG_BLK_SEL1_WIDTH 3
-#define DEBUG_BLK_SEL0_LBN 41
-#define DEBUG_BLK_SEL0_WIDTH 3
-#define DEBUG_BLK_SEL_MISC 7
-#define DEBUG_BLK_SEL_SERDES 6
-#define DEBUG_BLK_SEL_EM 5
-#define DEBUG_BLK_SEL_SR 4
-#define DEBUG_BLK_SEL_EV 3
-#define DEBUG_BLK_SEL_RX 2
-#define DEBUG_BLK_SEL_TX 1
-#define DEBUG_BLK_SEL_BIU 0
-#define MISC_DEBUG_ADDR_LBN 36
-#define MISC_DEBUG_ADDR_WIDTH 5
-#define SERDES_DEBUG_ADDR_LBN 31
-#define SERDES_DEBUG_ADDR_WIDTH 5
-#define EM_DEBUG_ADDR_LBN 26
-#define EM_DEBUG_ADDR_WIDTH 5
-#define SR_DEBUG_ADDR_LBN 21
-#define SR_DEBUG_ADDR_WIDTH 5
-#define EV_DEBUG_ADDR_LBN 16
-#define EV_DEBUG_ADDR_WIDTH 5
-#define RX_DEBUG_ADDR_LBN 11
-#define RX_DEBUG_ADDR_WIDTH 5
-#define TX_DEBUG_ADDR_LBN 5
-#define TX_DEBUG_ADDR_WIDTH 5
-#define BIU_DEBUG_ADDR_LBN 1
-#define BIU_DEBUG_ADDR_WIDTH 5
-#define DEBUG_DIS_LBN 0
-#define DEBUG_DIS_WIDTH 1
-
-/* Scratch register 0 */
-#define DRIVER_REG0_KER 0x0280
-#define DRIVER_DW0_LBN 0
-#define DRIVER_DW0_WIDTH 32
-
-/* Scratch register 1 */
-#define DRIVER_REG1_KER 0x0290
-#define DRIVER_DW1_LBN 0
-#define DRIVER_DW1_WIDTH 32
-
-/* Scratch register 2 */
-#define DRIVER_REG2_KER 0x02A0
-#define DRIVER_DW2_LBN 0
-#define DRIVER_DW2_WIDTH 32
-
-/* Scratch register 3 */
-#define DRIVER_REG3_KER 0x02B0
-#define DRIVER_DW3_LBN 0
-#define DRIVER_DW3_WIDTH 32
-
-/* Scratch register 4 */
-#define DRIVER_REG4_KER 0x02C0
-#define DRIVER_DW3_LBN 0
-#define DRIVER_DW3_WIDTH 32
-
-/* Scratch register 5 */
-#define DRIVER_REG5_KER 0x02D0
-#define DRIVER_DW3_LBN 0
-#define DRIVER_DW3_WIDTH 32
-
-/* Scratch register 6 */
-#define DRIVER_REG6_KER 0x02E0
-#define DRIVER_DW3_LBN 0
-#define DRIVER_DW3_WIDTH 32
-
-/* Scratch register 7 */
-#define DRIVER_REG7_KER 0x02F0
-#define DRIVER_DW3_LBN 0
-#define DRIVER_DW3_WIDTH 32
-
-/* FPGA build version */
-#define ALTERA_BUILD_REG_KER 0x0300
-#define VER_MAJOR_LBN 24
-#define VER_MAJOR_WIDTH 8
-#define VER_MINOR_LBN 16
-#define VER_MINOR_WIDTH 8
-#define VER_BUILD_LBN 0
-#define VER_BUILD_WIDTH 16
-#define VER_ALL_LBN 0
-#define VER_ALL_WIDTH 32
-
-/* Spare EEPROM bits register (flash 0x390) */
-#define SPARE_REG_KER 0x310
-#define MEM_PERR_EN_LBN 64
-#define MEM_PERR_EN_WIDTH 38
-#define MEM_PERR_EN_TX_DATA_LBN 72
-#define MEM_PERR_EN_TX_DATA_WIDTH 2
-#define SPARE_EE_BITS_LBN 1
-#define SPARE_EE_BITS_WIDTH 31
-#define PCIE_LEGACY_ENDPOINT_LBN 0
-#define PCIE_LEGACY_ENDPOINT_WIDTH 1
-
-/* Page mapped view of bottom 1024 EVQ RPTRS */
-#define EVQ_RPTR_REG_P0        0x400
-/* Bit definitions are as for the densely mapped
- * RPTR registers. */
-
-/* Timer table for kernel access */
-#define TIMER_CMD_REG_KER 0x420
-#define TIMER_MODE_LBN 12
-#define TIMER_MODE_WIDTH 2
-#define TIMER_MODE_DIS 0
-#define TIMER_MODE_INT_HLDOFF 2
-#define TIMER_VAL_LBN 0
-#define TIMER_VAL_WIDTH 12
-
-/* Driver generated event register */
-#define DRV_EV_REG_KER 0x440
-#define DRV_EV_QID_LBN 64
-#define DRV_EV_QID_WIDTH 12
-#define DRV_EV_DATA_LBN 0
-#define DRV_EV_DATA_WIDTH 64
-
-/* Event Queue control register */
-#define EVQ_CTL_REG_KER 0x450
-#define EVQ_FIFO_NOTAF_TH_LBN 0
-#define EVQ_FIFO_NOTAF_TH_WIDTH 6
-#define EVQ_FIFO_AF_TH_LBN 8
-#define EVQ_FIFO_AF_TH_WIDTH 6
-
-/* Buffer table configuration register */
-#define BUF_TBL_CFG_REG_KER 0x600
-#define BUF_TBL_MODE_LBN 3
-#define BUF_TBL_MODE_WIDTH 1
-#define BUF_TBL_MODE_HALF 0
-#define BUF_TBL_MODE_FULL 1
-
-/* SRAM receive descriptor cache configuration register */
-#define SRM_RX_DC_CFG_REG_KER 0x610
-#define SRM_RX_DC_BASE_ADR_LBN 0
-#define SRM_RX_DC_BASE_ADR_WIDTH 21
-
-/* SRAM transmit descriptor cache configuration register */
-#define SRM_TX_DC_CFG_REG_KER 0x620
-#define SRM_TX_DC_BASE_ADR_LBN 0
-#define SRM_TX_DC_BASE_ADR_WIDTH 21
-
-/* SRAM configuration register */
-#define SRM_CFG_REG_KER 0x630
-#define SRAM_OOB_ADR_INTEN_LBN 5
-#define SRAM_OOB_ADR_INTEN_WIDTH 1
-#define SRAM_OOB_BUF_INTEN_LBN 4
-#define SRAM_OOB_BUF_INTEN_WIDTH 1
-#define SRAM_OOB_BT_INIT_EN_LBN 3
-#define SRAM_OOB_BT_INIT_EN_WIDTH 1
-#define SRM_NUM_BANK_LBN 2
-#define SRM_NUM_BANK_WIDTH 1
-#define SRM_BANK_SIZE_LBN 0
-#define SRM_BANK_SIZE_WIDTH 2
-#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
-#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
-#define SRM_NB_BSZ_1BANKS_2M 0
-#define SRM_NB_BSZ_1BANKS_4M 1
-#define SRM_NB_BSZ_1BANKS_8M 2
-#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */
-#define SRM_NB_BSZ_2BANKS_4M 4
-#define SRM_NB_BSZ_2BANKS_8M 5
-#define SRM_NB_BSZ_2BANKS_16M 6
-#define SRM_NB_BSZ_RESERVED 7
-
-/* Special buffer table update register */
-#define BUF_TBL_UPD_REG_KER 0x0650
-#define BUF_UPD_CMD_LBN 63
-#define BUF_UPD_CMD_WIDTH 1
-#define BUF_CLR_CMD_LBN 62
-#define BUF_CLR_CMD_WIDTH 1
-#define BUF_CLR_END_ID_LBN 32
-#define BUF_CLR_END_ID_WIDTH 20
-#define BUF_CLR_START_ID_LBN 0
-#define BUF_CLR_START_ID_WIDTH 20
-
-/* Receive configuration register */
-#define RX_CFG_REG_KER 0x800
-
-/* B0 */
-#define RX_TOEP_TCP_SUPPRESS_B0_LBN 48
-#define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
-#define RX_INGR_EN_B0_LBN 47
-#define RX_INGR_EN_B0_WIDTH 1
-#define RX_TOEP_IPV4_B0_LBN 46
-#define RX_TOEP_IPV4_B0_WIDTH 1
-#define RX_HASH_ALG_B0_LBN 45
-#define RX_HASH_ALG_B0_WIDTH 1
-#define RX_HASH_INSERT_HDR_B0_LBN 44
-#define RX_HASH_INSERT_HDR_B0_WIDTH 1
-#define RX_DESC_PUSH_EN_B0_LBN 43
-#define RX_DESC_PUSH_EN_B0_WIDTH 1
-#define RX_RDW_PATCH_EN_LBN 42 /* Non head of line blocking */
-#define RX_RDW_PATCH_EN_WIDTH 1
-#define RX_PCI_BURST_SIZE_B0_LBN 39
-#define RX_PCI_BURST_SIZE_B0_WIDTH 3
-#define RX_OWNERR_CTL_B0_LBN 38
-#define RX_OWNERR_CTL_B0_WIDTH 1
-#define RX_XON_TX_TH_B0_LBN 33
-#define RX_XON_TX_TH_B0_WIDTH 5
-#define RX_XOFF_TX_TH_B0_LBN 28
-#define RX_XOFF_TX_TH_B0_WIDTH 5
-#define RX_USR_BUF_SIZE_B0_LBN 19
-#define RX_USR_BUF_SIZE_B0_WIDTH 9
-#define RX_XON_MAC_TH_B0_LBN 10
-#define RX_XON_MAC_TH_B0_WIDTH 9
-#define RX_XOFF_MAC_TH_B0_LBN 1
-#define RX_XOFF_MAC_TH_B0_WIDTH 9
-#define RX_XOFF_MAC_EN_B0_LBN 0
-#define RX_XOFF_MAC_EN_B0_WIDTH 1
-
-/* A1 */
-#define RX_DESC_PUSH_EN_A1_LBN 35
-#define RX_DESC_PUSH_EN_A1_WIDTH 1
-#define RX_PCI_BURST_SIZE_A1_LBN 31
-#define RX_PCI_BURST_SIZE_A1_WIDTH 3
-#define RX_OWNERR_CTL_A1_LBN 30
-#define RX_OWNERR_CTL_A1_WIDTH 1
-#define RX_XON_TX_TH_A1_LBN 25
-#define RX_XON_TX_TH_A1_WIDTH 5
-#define RX_XOFF_TX_TH_A1_LBN 20
-#define RX_XOFF_TX_TH_A1_WIDTH 5
-#define RX_USR_BUF_SIZE_A1_LBN 11
-#define RX_USR_BUF_SIZE_A1_WIDTH 9
-#define RX_XON_MAC_TH_A1_LBN 6
-#define RX_XON_MAC_TH_A1_WIDTH 5
-#define RX_XOFF_MAC_TH_A1_LBN 1
-#define RX_XOFF_MAC_TH_A1_WIDTH 5
-#define RX_XOFF_MAC_EN_A1_LBN 0
-#define RX_XOFF_MAC_EN_A1_WIDTH 1
-
-/* Receive filter control register */
-#define RX_FILTER_CTL_REG 0x810
-#define SCATTER_ENBL_NO_MATCH_Q_B0_LBN 40
-#define SCATTER_ENBL_NO_MATCH_Q_B0_WIDTH 1
-#define UDP_FULL_SRCH_LIMIT_LBN 32
-#define UDP_FULL_SRCH_LIMIT_WIDTH 8
-#define NUM_KER_LBN 24
-#define NUM_KER_WIDTH 2
-#define UDP_WILD_SRCH_LIMIT_LBN 16
-#define UDP_WILD_SRCH_LIMIT_WIDTH 8
-#define TCP_WILD_SRCH_LIMIT_LBN 8
-#define TCP_WILD_SRCH_LIMIT_WIDTH 8
-#define TCP_FULL_SRCH_LIMIT_LBN 0
-#define TCP_FULL_SRCH_LIMIT_WIDTH 8
-
-/* RX queue flush register */
-#define RX_FLUSH_DESCQ_REG_KER 0x0820
-#define RX_FLUSH_DESCQ_CMD_LBN 24
-#define RX_FLUSH_DESCQ_CMD_WIDTH 1
-#define RX_FLUSH_DESCQ_LBN 0
-#define RX_FLUSH_DESCQ_WIDTH 12
-
-/* Receive descriptor update register */
-#define RX_DESC_UPD_REG_KER 0x0830
-#define RX_DESC_WPTR_LBN 96
-#define RX_DESC_WPTR_WIDTH 12
-#define RX_DESC_UPD_REG_KER_DWORD (RX_DESC_UPD_REG_KER + 12)
-#define RX_DESC_WPTR_DWORD_LBN 0
-#define RX_DESC_WPTR_DWORD_WIDTH 12
-
-/* Receive descriptor cache configuration register */
-#define RX_DC_CFG_REG_KER 0x840
-#define RX_DC_SIZE_LBN 0
-#define RX_DC_SIZE_WIDTH 2
-
-#define RX_DC_PF_WM_REG_KER 0x850
-#define RX_DC_PF_LWM_LBN 0
-#define RX_DC_PF_LWM_WIDTH 6
-
-/* RX no descriptor drop counter */
-#define RX_NODESC_DROP_REG_KER 0x880
-#define RX_NODESC_DROP_CNT_LBN 0
-#define RX_NODESC_DROP_CNT_WIDTH 16
-
-/* RX black magic register */
-#define RX_SELF_RST_REG_KER 0x890
-#define RX_ISCSI_DIS_LBN 17
-#define RX_ISCSI_DIS_WIDTH 1
-#define RX_PREFETCH_TIMEOUT_EN_LBN 10
-#define RX_PREFETCH_TIMEOUT_EN_WIDTH 1
-#define RX_NODESC_WAIT_DIS_LBN 9
-#define RX_NODESC_WAIT_DIS_WIDTH 1
-#define RX_RECOVERY_EN_LBN 8
-#define RX_RECOVERY_EN_WIDTH 1
-#define RX_SHUTDOWN_REASON_LBN 0
-#define RX_SHUTDOWN_REASON_WIDTH (3)
-
-/* TX queue flush register */
-#define TX_FLUSH_DESCQ_REG_KER 0x0a00
-#define TX_FLUSH_DESCQ_CMD_LBN 12
-#define TX_FLUSH_DESCQ_CMD_WIDTH 1
-#define TX_FLUSH_DESCQ_LBN 0
-#define TX_FLUSH_DESCQ_WIDTH 12
-
-/* Transmit descriptor update register */
-#define TX_DESC_UPD_REG_KER 0x0a10
-#define TX_DESC_WPTR_LBN 96
-#define TX_DESC_WPTR_WIDTH 12
-#define TX_DESC_UPD_REG_KER_DWORD (TX_DESC_UPD_REG_KER + 12)
-#define TX_DESC_WPTR_DWORD_LBN 0
-#define TX_DESC_WPTR_DWORD_WIDTH 12
-
-/* Transmit descriptor cache configuration register */
-#define TX_DC_CFG_REG_KER 0xa20
-#define TX_DC_SIZE_LBN 0
-#define TX_DC_SIZE_WIDTH 2
-
-/* Transmit checksum configuration register (A0/A1 only) */
-#define TX_CHKSM_CFG_REG_KER_A1 0xa30
-
-/* Transmit configuration register */
-#define TX_CFG_REG_KER 0xa50
-#define TX_NO_EOP_DISC_EN_LBN 5
-#define TX_NO_EOP_DISC_EN_WIDTH 1
-
-/* Transmit configuration register 2 */
-#define TX_CFG2_REG_KER 0xa80
-#define TX_CSR_PUSH_EN_LBN 89
-#define TX_CSR_PUSH_EN_WIDTH 1
-#define TX_RX_SPACER_LBN 64
-#define TX_RX_SPACER_WIDTH 8
-#define TX_SW_EV_EN_LBN 59
-#define TX_SW_EV_EN_WIDTH 1
-#define TX_RX_SPACER_EN_LBN 57
-#define TX_RX_SPACER_EN_WIDTH 1
-#define TX_PREF_WD_TMR_LBN 22
-#define TX_PREF_WD_TMR_WIDTH 22
-#define TX_PREF_THRESHOLD_LBN 19
-#define TX_PREF_THRESHOLD_WIDTH 2
-#define TX_ONE_PKT_PER_Q_LBN 18
-#define TX_ONE_PKT_PER_Q_WIDTH 1
-#define TX_DIS_NON_IP_EV_LBN 17
-#define TX_DIS_NON_IP_EV_WIDTH 1
-#define TX_DMA_SPACER_LBN 8
-#define TX_DMA_SPACER_WIDTH 8
-#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
-#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
-#define TX_TCP_DIS_A1_LBN 7
-#define TX_TCP_DIS_A1_WIDTH 1
-#define TX_IP_DIS_A1_LBN 6
-#define TX_IP_DIS_A1_WIDTH 1
-#define TX_MAX_CPL_LBN 2
-#define TX_MAX_CPL_WIDTH 2
-#define TX_MAX_PREF_LBN 0
-#define TX_MAX_PREF_WIDTH 2
-
-/* Transmit VLAN filter control register */
-#define TX_VLAN_REG 0xae0
-
-/* PHY management transmit data register */
-#define MD_TXD_REG_KER 0xc00
-#define MD_TXD_LBN 0
-#define MD_TXD_WIDTH 16
-
-/* PHY management receive data register */
-#define MD_RXD_REG_KER 0xc10
-#define MD_RXD_LBN 0
-#define MD_RXD_WIDTH 16
-
-/* PHY management configuration & status register */
-#define MD_CS_REG_KER 0xc20
-#define MD_PT_LBN 7
-#define MD_PT_WIDTH 3
-#define MD_PL_LBN 6
-#define MD_PL_WIDTH 1
-#define MD_INT_CLR_LBN 5
-#define MD_INT_CLR_WIDTH 1
-#define MD_GC_LBN 4
-#define MD_GC_WIDTH 1
-#define MD_PRSP_LBN 3
-#define MD_PRSP_WIDTH 1
-#define MD_RIC_LBN 2
-#define MD_RIC_WIDTH 1
-#define MD_RDC_LBN 1
-#define MD_RDC_WIDTH 1
-#define MD_WRC_LBN 0
-#define MD_WRC_WIDTH 1
-
-/* PHY management PHY address register */
-#define MD_PHY_ADR_REG_KER 0xc30
-#define MD_PHY_ADR_LBN 0
-#define MD_PHY_ADR_WIDTH 16
-
-/* PHY management ID register */
-#define MD_ID_REG_KER 0xc40
-#define MD_PRT_ADR_LBN 11
-#define MD_PRT_ADR_WIDTH 5
-#define MD_DEV_ADR_LBN 6
-#define MD_DEV_ADR_WIDTH 5
-/* Used for writing both at once */
-#define MD_PRT_DEV_ADR_LBN 6
-#define MD_PRT_DEV_ADR_WIDTH 10
-
-/* PHY management status & mask register (DWORD read only) */
-#define MD_STAT_REG_KER 0xc50
-#define MD_PINT_LBN 4
-#define MD_PINT_WIDTH 1
-#define MD_DONE_LBN 3
-#define MD_DONE_WIDTH 1
-#define MD_BSERR_LBN 2
-#define MD_BSERR_WIDTH 1
-#define MD_LNFL_LBN 1
-#define MD_LNFL_WIDTH 1
-#define MD_BSY_LBN 0
-#define MD_BSY_WIDTH 1
-
-/* Port 0 and 1 MAC stats registers */
-#define MAC0_STAT_DMA_REG_KER 0xc60
-#define MAC1_STAT_DMA_REG_KER 0xc70
-#define MAC_STAT_DMA_CMD_LBN 48
-#define MAC_STAT_DMA_CMD_WIDTH 1
-#define MAC_STAT_DMA_REGION_LBN 46
-#define MAC_STAT_DMA_REGION_WIDTH 2
-#define MAC_STAT_DMA_ADR_LBN 0
-#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
-
-/* Port 0 and 1 MAC control registers */
-#define MAC0_CTRL_REG_KER 0xc80
-#define MAC1_CTRL_REG_KER 0xc90
-#define MAC_XOFF_VAL_LBN 16
-#define MAC_XOFF_VAL_WIDTH 16
-#define TXFIFO_DRAIN_EN_B0_LBN 7
-#define TXFIFO_DRAIN_EN_B0_WIDTH 1
-#define MAC_XG_DISTXCRC_LBN 5
-#define MAC_XG_DISTXCRC_WIDTH 1
-#define MAC_BCAD_ACPT_LBN 4
-#define MAC_BCAD_ACPT_WIDTH 1
-#define MAC_UC_PROM_LBN 3
-#define MAC_UC_PROM_WIDTH 1
-#define MAC_LINK_STATUS_LBN 2
-#define MAC_LINK_STATUS_WIDTH 1
-#define MAC_SPEED_LBN 0
-#define MAC_SPEED_WIDTH 2
-
-/* External interrupt control (replaces MAC1_CTRL in B0) */
-#define GEN_MODE_REG_KER 0xc90
-#define XFP_PHY_INT_POL_SEL_LBN 3
-#define XFP_PHY_INT_POL_SEL_WIDTH 1
-#define XG_PHY_INT_POL_SEL_LBN 2
-#define XG_PHY_INT_POL_SEL_WIDTH 1
-#define XFP_PHY_INT_MASK_LBN 1
-#define XFP_PHY_INT_MASK_WIDTH 1
-#define XG_PHY_INT_MASK_LBN 0
-#define XG_PHY_INT_MASK_WIDTH 1
-
-
-/* 10G XAUI XGXS default values */
-#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
-#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
-#define XX_SD_CTL_DRV_DEFAULT 0  /* 20mA */
-
-/* Multicast address hash table */
-#define MAC_MCAST_HASH_REG0_KER 0xca0
-#define MAC_MCAST_HASH_REG1_KER 0xcb0
-
-/* MAC test register. */
-#define MAC_TEST_REG_KER 0xcc0
-#define MAC_PTLOOP_EN_LBN 0
-#define MAC_PTLOOP_EN_WIDTH 1
-
-/* GMAC registers */
-#define FALCON_GMAC_REGBANK 0xe00
-#define FALCON_GMAC_REGBANK_SIZE 0x200
-#define FALCON_GMAC_REG_SIZE 0x10
-
-/* Source MAC filter control register */
-#define TX_SRC_MAC_CTRL_REG 0x1100
-
-/* XMAC registers */
-#define FALCON_XMAC_REGBANK 0x1200
-#define FALCON_XMAC_REGBANK_SIZE 0x200
-#define FALCON_XMAC_REG_SIZE 0x10
-
-/* XGMAC address register low */
-#define XM_ADR_LO_REG_MAC 0x00
-#define XM_ADR_3_LBN 24
-#define XM_ADR_3_WIDTH 8
-#define XM_ADR_2_LBN 16
-#define XM_ADR_2_WIDTH 8
-#define XM_ADR_1_LBN 8
-#define XM_ADR_1_WIDTH 8
-#define XM_ADR_0_LBN 0
-#define XM_ADR_0_WIDTH 8
-
-/* XGMAC address register high */
-#define XM_ADR_HI_REG_MAC 0x01
-#define XM_ADR_5_LBN 8
-#define XM_ADR_5_WIDTH 8
-#define XM_ADR_4_LBN 0
-#define XM_ADR_4_WIDTH 8
-
-/* XGMAC global configuration */
-#define XM_GLB_CFG_REG_MAC 0x02
-#define XM_LINE_LB_DEEP_RSVD_LBN 28
-#define XM_LINE_LB_DEEP_RSVD_WIDTH 1
-#define XM_RMTFLT_GEN_LBN 17
-#define XM_RMTFLT_GEN_WIDTH 1
-#define XM_DEBUG_MODE_LBN 16
-#define XM_DEBUG_MODE_WIDTH 1
-#define XM_RX_STAT_EN_LBN 11
-#define XM_RX_STAT_EN_WIDTH 1
-#define XM_TX_STAT_EN_LBN 10
-#define XM_TX_STAT_EN_WIDTH 1
-#define XM_RX_JUMBO_MODE_LBN 6
-#define XM_RX_JUMBO_MODE_WIDTH 1
-#define XM_WAN_MODE_LBN 5
-#define XM_WAN_MODE_WIDTH 1
-#define XM_AUTOCLR_MODE_LBN 4
-#define XM_AUTOCLR_MODE_WIDTH 1
-#define XM_INTCLR_MODE_LBN 3
-#define XM_INTCLR_MODE_WIDTH 1
-#define XM_CORE_RST_LBN 0
-#define XM_CORE_RST_WIDTH 1
-
-/* XGMAC transmit configuration */
-#define XM_TX_CFG_REG_MAC 0x03
-#define XM_TX_PROG_LBN 24
-#define XM_TX_PROG_WIDTH 1
-#define XM_IPG_LBN 16
-#define XM_IPG_WIDTH 4
-#define XM_FCNTL_LBN 10
-#define XM_FCNTL_WIDTH 1
-#define XM_TXCRC_LBN 8
-#define XM_TXCRC_WIDTH 1
-#define XM_EDRC_LBN 6
-#define XM_EDRC_WIDTH 1
-#define XM_AUTO_PAD_LBN 5
-#define XM_AUTO_PAD_WIDTH 1
-#define XM_TX_PRMBL_LBN 2
-#define XM_TX_PRMBL_WIDTH 1
-#define XM_TXEN_LBN 1
-#define XM_TXEN_WIDTH 1
-#define XM_TX_RST_LBN 0
-#define XM_TX_RST_WIDTH 1
-
-/* XGMAC receive configuration */
-#define XM_RX_CFG_REG_MAC 0x04
-#define XM_PASS_LENERR_LBN 26
-#define XM_PASS_LENERR_WIDTH 1
-#define XM_PASS_CRC_ERR_LBN 25
-#define XM_PASS_CRC_ERR_WIDTH 1
-#define XM_PASS_PRMBLE_ERR_LBN 24
-#define XM_PASS_PRMBLE_ERR_WIDTH 1
-#define XM_ACPT_ALL_MCAST_LBN 11
-#define XM_ACPT_ALL_MCAST_WIDTH 1
-#define XM_ACPT_ALL_UCAST_LBN 9
-#define XM_ACPT_ALL_UCAST_WIDTH 1
-#define XM_AUTO_DEPAD_LBN 8
-#define XM_AUTO_DEPAD_WIDTH 1
-#define XM_RXCRC_LBN 3
-#define XM_RXCRC_WIDTH 1
-#define XM_RX_PRMBL_LBN 2
-#define XM_RX_PRMBL_WIDTH 1
-#define XM_RXEN_LBN 1
-#define XM_RXEN_WIDTH 1
-#define XM_RX_RST_LBN 0
-#define XM_RX_RST_WIDTH 1
-
-/* XGMAC flow control register */
-#define XM_FC_REG_MAC 0x7
-#define XM_PAUSE_TIME_LBN 16
-#define XM_PAUSE_TIME_WIDTH 16
-#define XM_DIS_FCNTL_LBN 0
-#define XM_DIS_FCNTL_WIDTH 1
-
-/* XGMAC pause time count register */
-/* XGMAC management interrupt mask register */
-#define XM_MGT_INT_MSK_REG_MAC_B0 0x5
-#define XM_MSK_PRMBLE_ERR_LBN 2
-#define XM_MSK_PRMBLE_ERR_WIDTH 1
-#define XM_MSK_RMTFLT_LBN 1
-#define XM_MSK_RMTFLT_WIDTH 1
-#define XM_MSK_LCLFLT_LBN 0
-#define XM_MSK_LCLFLT_WIDTH 1
-
-#define XM_PAUSE_TIME_REG_MAC 0x9
-#define XM_TX_PAUSE_CNT_LBN 16
-#define XM_TX_PAUSE_CNT_WIDTH 16
-#define XM_RX_PAUSE_CNT_LBN 0
-#define XM_RX_PAUSE_CNT_WIDTH 16
-
-/* XGMAC transmit parameter register */
-#define XM_TX_PARAM_REG_MAC 0x0d
-#define XM_TX_JUMBO_MODE_LBN 31
-#define XM_TX_JUMBO_MODE_WIDTH 1
-#define XM_MAX_TX_FRM_SIZE_LBN 16
-#define XM_MAX_TX_FRM_SIZE_WIDTH 14
-#define XM_PAD_CHAR_LBN 0
-#define XM_PAD_CHAR_WIDTH 8
-
-/* XGMAC receive parameter register */
-#define XM_RX_PARAM_REG_MAC 0x0e
-#define XM_MAX_RX_FRM_SIZE_LBN 0
-#define XM_MAX_RX_FRM_SIZE_WIDTH 14
-
-/* XGXS/XAUI powerdown/reset register */
-#define XX_PWR_RST_REG_MAC 0x10
-
-#define XX_PWRDND_EN_LBN 15
-#define XX_PWRDND_EN_WIDTH 1
-#define XX_PWRDNC_EN_LBN 14
-#define XX_PWRDNC_EN_WIDTH 1
-#define XX_PWRDNB_EN_LBN 13
-/* XGMAC management interrupt status register */
-#define XM_MGT_INT_REG_MAC_B0 0x0f
-#define XM_PRMBLE_ERR 2
-#define XM_PRMBLE_WIDTH 1
-#define XM_RMTFLT_LBN 1
-#define XM_RMTFLT_WIDTH 1
-#define XM_LCLFLT_LBN 0
-#define XM_LCLFLT_WIDTH 1
-
-#define XX_PWRDNB_EN_WIDTH 1
-#define XX_PWRDNA_EN_LBN 12
-#define XX_PWRDNA_EN_WIDTH 1
-#define XX_RSTPLLCD_EN_LBN 9
-#define XX_RSTPLLCD_EN_WIDTH 1
-#define XX_RSTPLLAB_EN_LBN 8
-#define XX_RSTPLLAB_EN_WIDTH 1
-#define XX_RESETD_EN_LBN 7
-#define XX_RESETD_EN_WIDTH 1
-#define XX_RESETC_EN_LBN 6
-#define XX_RESETC_EN_WIDTH 1
-#define XX_RESETB_EN_LBN 5
-#define XX_RESETB_EN_WIDTH 1
-#define XX_RESETA_EN_LBN 4
-#define XX_RESETA_EN_WIDTH 1
-#define XX_RSTXGXSRX_EN_LBN 2
-#define XX_RSTXGXSRX_EN_WIDTH 1
-#define XX_RSTXGXSTX_EN_LBN 1
-#define XX_RSTXGXSTX_EN_WIDTH 1
-#define XX_RST_XX_EN_LBN 0
-#define XX_RST_XX_EN_WIDTH 1
-
-/* XGXS/XAUI powerdown/reset control register */
-#define XX_SD_CTL_REG_MAC 0x11
-#define XX_TERMADJ1_LBN 17
-#define XX_TERMADJ1_WIDTH 1
-#define XX_TERMADJ0_LBN 16
-#define XX_TERMADJ0_WIDTH 1
-#define XX_HIDRVD_LBN 15
-#define XX_HIDRVD_WIDTH 1
-#define XX_LODRVD_LBN 14
-#define XX_LODRVD_WIDTH 1
-#define XX_HIDRVC_LBN 13
-#define XX_HIDRVC_WIDTH 1
-#define XX_LODRVC_LBN 12
-#define XX_LODRVC_WIDTH 1
-#define XX_HIDRVB_LBN 11
-#define XX_HIDRVB_WIDTH 1
-#define XX_LODRVB_LBN 10
-#define XX_LODRVB_WIDTH 1
-#define XX_HIDRVA_LBN 9
-#define XX_HIDRVA_WIDTH 1
-#define XX_LODRVA_LBN 8
-#define XX_LODRVA_WIDTH 1
-#define XX_LPBKD_LBN 3
-#define XX_LPBKD_WIDTH 1
-#define XX_LPBKC_LBN 2
-#define XX_LPBKC_WIDTH 1
-#define XX_LPBKB_LBN 1
-#define XX_LPBKB_WIDTH 1
-#define XX_LPBKA_LBN 0
-#define XX_LPBKA_WIDTH 1
-
-#define XX_TXDRV_CTL_REG_MAC 0x12
-#define XX_DEQD_LBN 28
-#define XX_DEQD_WIDTH 4
-#define XX_DEQC_LBN 24
-#define XX_DEQC_WIDTH 4
-#define XX_DEQB_LBN 20
-#define XX_DEQB_WIDTH 4
-#define XX_DEQA_LBN 16
-#define XX_DEQA_WIDTH 4
-#define XX_DTXD_LBN 12
-#define XX_DTXD_WIDTH 4
-#define XX_DTXC_LBN 8
-#define XX_DTXC_WIDTH 4
-#define XX_DTXB_LBN 4
-#define XX_DTXB_WIDTH 4
-#define XX_DTXA_LBN 0
-#define XX_DTXA_WIDTH 4
-
-/* XAUI XGXS core status register */
-#define XX_FORCE_SIG_LBN 24
-#define XX_FORCE_SIG_WIDTH 8
-#define XX_FORCE_SIG_DECODE_FORCED 0xff
-#define XX_XGXS_LB_EN_LBN 23
-#define XX_XGXS_LB_EN_WIDTH 1
-#define XX_XGMII_LB_EN_LBN 22
-#define XX_XGMII_LB_EN_WIDTH 1
-#define XX_CORE_STAT_REG_MAC 0x16
-#define XX_ALIGN_DONE_LBN 20
-#define XX_ALIGN_DONE_WIDTH 1
-#define XX_SYNC_STAT_LBN 16
-#define XX_SYNC_STAT_WIDTH 4
-#define XX_SYNC_STAT_DECODE_SYNCED 0xf
-#define XX_COMMA_DET_LBN 12
-#define XX_COMMA_DET_WIDTH 4
-#define XX_COMMA_DET_DECODE_DETECTED 0xf
-#define XX_COMMA_DET_RESET 0xf
-#define XX_CHARERR_LBN 4
-#define XX_CHARERR_WIDTH 4
-#define XX_CHARERR_RESET 0xf
-#define XX_DISPERR_LBN 0
-#define XX_DISPERR_WIDTH 4
-#define XX_DISPERR_RESET 0xf
-
-/* Receive filter table */
-#define RX_FILTER_TBL0 0xF00000
-
-/* Receive descriptor pointer table */
-#define RX_DESC_PTR_TBL_KER_A1 0x11800
-#define RX_DESC_PTR_TBL_KER_B0 0xF40000
-#define RX_DESC_PTR_TBL_KER_P0 0x900
-#define RX_ISCSI_DDIG_EN_LBN 88
-#define RX_ISCSI_DDIG_EN_WIDTH 1
-#define RX_ISCSI_HDIG_EN_LBN 87
-#define RX_ISCSI_HDIG_EN_WIDTH 1
-#define RX_DESC_PREF_ACT_LBN 86
-#define RX_DESC_PREF_ACT_WIDTH 1
-#define RX_DC_HW_RPTR_LBN 80
-#define RX_DC_HW_RPTR_WIDTH 6
-#define RX_DESCQ_HW_RPTR_LBN 68
-#define RX_DESCQ_HW_RPTR_WIDTH 12
-#define RX_DESCQ_SW_WPTR_LBN 56
-#define RX_DESCQ_SW_WPTR_WIDTH 12
-#define RX_DESCQ_BUF_BASE_ID_LBN 36
-#define RX_DESCQ_BUF_BASE_ID_WIDTH 20
-#define RX_DESCQ_EVQ_ID_LBN 24
-#define RX_DESCQ_EVQ_ID_WIDTH 12
-#define RX_DESCQ_OWNER_ID_LBN 10
-#define RX_DESCQ_OWNER_ID_WIDTH 14
-#define RX_DESCQ_LABEL_LBN 5
-#define RX_DESCQ_LABEL_WIDTH 5
-#define RX_DESCQ_SIZE_LBN 3
-#define RX_DESCQ_SIZE_WIDTH 2
-#define RX_DESCQ_SIZE_4K 3
-#define RX_DESCQ_SIZE_2K 2
-#define RX_DESCQ_SIZE_1K 1
-#define RX_DESCQ_SIZE_512 0
-#define RX_DESCQ_TYPE_LBN 2
-#define RX_DESCQ_TYPE_WIDTH 1
-#define RX_DESCQ_JUMBO_LBN 1
-#define RX_DESCQ_JUMBO_WIDTH 1
-#define RX_DESCQ_EN_LBN 0
-#define RX_DESCQ_EN_WIDTH 1
-
-/* Transmit descriptor pointer table */
-#define TX_DESC_PTR_TBL_KER_A1 0x11900
-#define TX_DESC_PTR_TBL_KER_B0 0xF50000
-#define TX_DESC_PTR_TBL_KER_P0 0xa40
-#define TX_NON_IP_DROP_DIS_B0_LBN 91
-#define TX_NON_IP_DROP_DIS_B0_WIDTH 1
-#define TX_IP_CHKSM_DIS_B0_LBN 90
-#define TX_IP_CHKSM_DIS_B0_WIDTH 1
-#define TX_TCP_CHKSM_DIS_B0_LBN 89
-#define TX_TCP_CHKSM_DIS_B0_WIDTH 1
-#define TX_DESCQ_EN_LBN 88
-#define TX_DESCQ_EN_WIDTH 1
-#define TX_ISCSI_DDIG_EN_LBN 87
-#define TX_ISCSI_DDIG_EN_WIDTH 1
-#define TX_ISCSI_HDIG_EN_LBN 86
-#define TX_ISCSI_HDIG_EN_WIDTH 1
-#define TX_DC_HW_RPTR_LBN 80
-#define TX_DC_HW_RPTR_WIDTH 6
-#define TX_DESCQ_HW_RPTR_LBN 68
-#define TX_DESCQ_HW_RPTR_WIDTH 12
-#define TX_DESCQ_SW_WPTR_LBN 56
-#define TX_DESCQ_SW_WPTR_WIDTH 12
-#define TX_DESCQ_BUF_BASE_ID_LBN 36
-#define TX_DESCQ_BUF_BASE_ID_WIDTH 20
-#define TX_DESCQ_EVQ_ID_LBN 24
-#define TX_DESCQ_EVQ_ID_WIDTH 12
-#define TX_DESCQ_OWNER_ID_LBN 10
-#define TX_DESCQ_OWNER_ID_WIDTH 14
-#define TX_DESCQ_LABEL_LBN 5
-#define TX_DESCQ_LABEL_WIDTH 5
-#define TX_DESCQ_SIZE_LBN 3
-#define TX_DESCQ_SIZE_WIDTH 2
-#define TX_DESCQ_SIZE_4K 3
-#define TX_DESCQ_SIZE_2K 2
-#define TX_DESCQ_SIZE_1K 1
-#define TX_DESCQ_SIZE_512 0
-#define TX_DESCQ_TYPE_LBN 1
-#define TX_DESCQ_TYPE_WIDTH 2
-#define TX_DESCQ_FLUSH_LBN 0
-#define TX_DESCQ_FLUSH_WIDTH 1
-
-/* Event queue pointer */
-#define EVQ_PTR_TBL_KER_A1 0x11a00
-#define EVQ_PTR_TBL_KER_B0 0xf60000
-#define EVQ_PTR_TBL_KER_P0 0x500
-#define EVQ_WKUP_OR_INT_EN_LBN 39
-#define EVQ_WKUP_OR_INT_EN_WIDTH 1
-#define EVQ_NXT_WPTR_LBN 24
-#define EVQ_NXT_WPTR_WIDTH 15
-#define EVQ_EN_LBN 23
-#define EVQ_EN_WIDTH 1
-#define EVQ_SIZE_LBN 20
-#define EVQ_SIZE_WIDTH 3
-#define EVQ_SIZE_32K 6
-#define EVQ_SIZE_16K 5
-#define EVQ_SIZE_8K 4
-#define EVQ_SIZE_4K 3
-#define EVQ_SIZE_2K 2
-#define EVQ_SIZE_1K 1
-#define EVQ_SIZE_512 0
-#define EVQ_BUF_BASE_ID_LBN 0
-#define EVQ_BUF_BASE_ID_WIDTH 20
-
-/* Event queue read pointer */
-#define EVQ_RPTR_REG_KER_A1 0x11b00
-#define EVQ_RPTR_REG_KER_B0 0xfa0000
-#define EVQ_RPTR_LBN 0
-#define EVQ_RPTR_WIDTH 14
-#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0)
-#define EVQ_RPTR_DWORD_LBN 0
-#define EVQ_RPTR_DWORD_WIDTH 14
-
-/* RSS indirection table */
-#define RX_RSS_INDIR_TBL_B0 0xFB0000
-#define RX_RSS_INDIR_ENT_B0_LBN 0
-#define RX_RSS_INDIR_ENT_B0_WIDTH 6
-
-/* Special buffer descriptors (full-mode) */
-#define BUF_FULL_TBL_KER_A1 0x8000
-#define BUF_FULL_TBL_KER_B0 0x800000
-#define IP_DAT_BUF_SIZE_LBN 50
-#define IP_DAT_BUF_SIZE_WIDTH 1
-#define IP_DAT_BUF_SIZE_8K 1
-#define IP_DAT_BUF_SIZE_4K 0
-#define BUF_ADR_REGION_LBN 48
-#define BUF_ADR_REGION_WIDTH 2
-#define BUF_ADR_FBUF_LBN 14
-#define BUF_ADR_FBUF_WIDTH 34
-#define BUF_OWNER_ID_FBUF_LBN 0
-#define BUF_OWNER_ID_FBUF_WIDTH 14
-
-/* Special buffer descriptors (half-mode) */
-#define BUF_HALF_TBL_KER_A1 0x8000
-#define BUF_HALF_TBL_KER_B0 0x800000
-#define BUF_ADR_HBUF_ODD_LBN 44
-#define BUF_ADR_HBUF_ODD_WIDTH 20
-#define BUF_OWNER_ID_HBUF_ODD_LBN 32
-#define BUF_OWNER_ID_HBUF_ODD_WIDTH 12
-#define BUF_ADR_HBUF_EVEN_LBN 12
-#define BUF_ADR_HBUF_EVEN_WIDTH 20
-#define BUF_OWNER_ID_HBUF_EVEN_LBN 0
-#define BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
-
-#define SRM_DBG_REG_B0 0x3000000
-
-/* Transmit descriptor */
-#define TX_KER_PORT_LBN 63
-#define TX_KER_PORT_WIDTH 1
-#define TX_KER_CONT_LBN 62
-#define TX_KER_CONT_WIDTH 1
-#define TX_KER_BYTE_CNT_LBN 48
-#define TX_KER_BYTE_CNT_WIDTH 14
-#define TX_KER_BUF_REGION_LBN 46
-#define TX_KER_BUF_REGION_WIDTH 2
-#define TX_KER_BUF_REGION0_DECODE 0
-#define TX_KER_BUF_REGION1_DECODE 1
-#define TX_KER_BUF_REGION2_DECODE 2
-#define TX_KER_BUF_REGION3_DECODE 3
-#define TX_KER_BUF_ADR_LBN 0
-#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
-
-/* Receive descriptor */
-#define RX_KER_BUF_SIZE_LBN 48
-#define RX_KER_BUF_SIZE_WIDTH 14
-#define RX_KER_BUF_REGION_LBN 46
-#define RX_KER_BUF_REGION_WIDTH 2
-#define RX_KER_BUF_REGION0_DECODE 0
-#define RX_KER_BUF_REGION1_DECODE 1
-#define RX_KER_BUF_REGION2_DECODE 2
-#define RX_KER_BUF_REGION3_DECODE 3
-#define RX_KER_BUF_ADR_LBN 0
-#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
-
-/**************************************************************************
- *
- * Falcon events
- *
- **************************************************************************
- */
-
-/* Event queue entries */
-#define EV_CODE_LBN 60
-#define EV_CODE_WIDTH 4
-#define RX_IP_EV_DECODE 0
-#define TX_IP_EV_DECODE 2
-#define DRIVER_EV_DECODE 5
-#define GLOBAL_EV_DECODE 6
-#define DRV_GEN_EV_DECODE 7
-#define WHOLE_EVENT_LBN 0
-#define WHOLE_EVENT_WIDTH 64
-
-/* Receive events */
-#define RX_EV_PKT_OK_LBN 56
-#define RX_EV_PKT_OK_WIDTH 1
-#define RX_EV_PAUSE_FRM_ERR_LBN 55
-#define RX_EV_PAUSE_FRM_ERR_WIDTH 1
-#define RX_EV_BUF_OWNER_ID_ERR_LBN 54
-#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
-#define RX_EV_IF_FRAG_ERR_LBN 53
-#define RX_EV_IF_FRAG_ERR_WIDTH 1
-#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
-#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
-#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
-#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
-#define RX_EV_ETH_CRC_ERR_LBN 50
-#define RX_EV_ETH_CRC_ERR_WIDTH 1
-#define RX_EV_FRM_TRUNC_LBN 49
-#define RX_EV_FRM_TRUNC_WIDTH 1
-#define RX_EV_DRIB_NIB_LBN 48
-#define RX_EV_DRIB_NIB_WIDTH 1
-#define RX_EV_TOBE_DISC_LBN 47
-#define RX_EV_TOBE_DISC_WIDTH 1
-#define RX_EV_PKT_TYPE_LBN 44
-#define RX_EV_PKT_TYPE_WIDTH 3
-#define RX_EV_PKT_TYPE_ETH_DECODE 0
-#define RX_EV_PKT_TYPE_LLC_DECODE 1
-#define RX_EV_PKT_TYPE_JUMBO_DECODE 2
-#define RX_EV_PKT_TYPE_VLAN_DECODE 3
-#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
-#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
-#define RX_EV_HDR_TYPE_LBN 42
-#define RX_EV_HDR_TYPE_WIDTH 2
-#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
-#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
-#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
-#define RX_EV_HDR_TYPE_NON_IP_DECODE 3
-#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \
-       ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE)
-#define RX_EV_DESC_Q_EMPTY_LBN 41
-#define RX_EV_DESC_Q_EMPTY_WIDTH 1
-#define RX_EV_MCAST_HASH_MATCH_LBN 40
-#define RX_EV_MCAST_HASH_MATCH_WIDTH 1
-#define RX_EV_MCAST_PKT_LBN 39
-#define RX_EV_MCAST_PKT_WIDTH 1
-#define RX_EV_RECOVERY_FLAG_LBN 37
-#define RX_EV_RECOVERY_FLAG_WIDTH 1
-#define RX_EV_Q_LABEL_LBN 32
-#define RX_EV_Q_LABEL_WIDTH 5
-#define RX_EV_JUMBO_CONT_LBN 31
-#define RX_EV_JUMBO_CONT_WIDTH 1
-#define RX_EV_PORT_LBN 30
-#define RX_EV_PORT_WIDTH 1
-#define RX_EV_BYTE_CNT_LBN 16
-#define RX_EV_BYTE_CNT_WIDTH 14
-#define RX_EV_SOP_LBN 15
-#define RX_EV_SOP_WIDTH 1
-#define RX_ISCSI_DDIG_ERR_LBN 13
-#define RX_ISCSI_DDIG_ERR_WIDTH 1
-#define RX_ISCSI_HDIG_ERR_LBN 12
-#define RX_ISCSI_HDIG_ERR_WIDTH 1
-#define RX_EV_DESC_PTR_LBN 0
-#define RX_EV_DESC_PTR_WIDTH 12
-
-/* Transmit events */
-#define TX_EV_PKT_ERR_LBN 38
-#define TX_EV_PKT_ERR_WIDTH 1
-#define TX_EV_PKT_TOO_BIG_LBN 37
-#define TX_EV_PKT_TOO_BIG_WIDTH 1
-#define TX_EV_Q_LABEL_LBN 32
-#define TX_EV_Q_LABEL_WIDTH 5
-#define TX_EV_PORT_LBN 16
-#define TX_EV_PORT_WIDTH 1
-#define TX_EV_WQ_FF_FULL_LBN 15
-#define TX_EV_WQ_FF_FULL_WIDTH 1
-#define TX_EV_BUF_OWNER_ID_ERR_LBN 14
-#define TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
-#define TX_EV_COMP_LBN 12
-#define TX_EV_COMP_WIDTH 1
-#define TX_EV_DESC_PTR_LBN 0
-#define TX_EV_DESC_PTR_WIDTH 12
-
-/* Driver events */
-#define DRIVER_EV_SUB_CODE_LBN 56
-#define DRIVER_EV_SUB_CODE_WIDTH 4
-#define DRIVER_EV_SUB_DATA_LBN 0
-#define DRIVER_EV_SUB_DATA_WIDTH 14
-#define TX_DESCQ_FLS_DONE_EV_DECODE 0
-#define RX_DESCQ_FLS_DONE_EV_DECODE 1
-#define EVQ_INIT_DONE_EV_DECODE 2
-#define EVQ_NOT_EN_EV_DECODE 3
-#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4
-#define SRM_UPD_DONE_EV_DECODE 5
-#define WAKE_UP_EV_DECODE 6
-#define TX_PKT_NON_TCP_UDP_DECODE 9
-#define TIMER_EV_DECODE 10
-#define RX_RECOVERY_EV_DECODE 11
-#define RX_DSC_ERROR_EV_DECODE 14
-#define TX_DSC_ERROR_EV_DECODE 15
-#define DRIVER_EV_TX_DESCQ_ID_LBN 0
-#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
-#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12
-#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
-#define DRIVER_EV_RX_DESCQ_ID_LBN 0
-#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
-#define DRIVER_EV_EVQ_ID_LBN 0
-#define DRIVER_EV_EVQ_ID_WIDTH 12
-#define DRIVER_EV_SRM_UPD_LBN 0
-#define DRIVER_EV_SRM_UPD_WIDTH 2
-#define SRM_CLR_EV_DECODE 0
-#define SRM_UPD_EV_DECODE 1
-#define SRM_ILLCLR_EV_DECODE 2
-
-/* Global events */
-#define RX_RECOVERY_B0_LBN 12
-#define RX_RECOVERY_B0_WIDTH 1
-#define XG_MNT_INTR_B0_LBN 11
-#define XG_MNT_INTR_B0_WIDTH 1
-
-#define RX_RECOVERY_A1_LBN 11
-#define RX_RECOVERY_A1_WIDTH 1
-
-#define XFP_PHY_INTR_LBN 10
-#define XFP_PHY_INTR_WIDTH 1
-#define XG_PHY_INTR_LBN 9
-#define XG_PHY_INTR_WIDTH 1
-#define G_PHY1_INTR_LBN 8
-#define G_PHY1_INTR_WIDTH 1
-#define G_PHY0_INTR_LBN 7
-#define G_PHY0_INTR_WIDTH 1
-
-/* Driver-generated test events */
-#define DRV_GEN_EV_CODE_LBN 60
-#define DRV_GEN_EV_CODE_WIDTH 4
-#define DRV_GEN_EV_DATA_LBN 0
-#define DRV_GEN_EV_DATA_WIDTH 60
-#define EVQ_MAGIC_LBN 0
-#define EVQ_MAGIC_WIDTH 32
-
-/**************************************************************************
- *
- * Falcon MAC stats
- *
- **************************************************************************
- *
- */
-
-#define GRxGoodOct_offset 0x0
-#define GRxGoodOct_WIDTH 48
-#define GRxBadOct_offset 0x8
-#define GRxBadOct_WIDTH 48
-#define GRxMissPkt_offset 0x10
-#define GRxMissPkt_WIDTH 32
-#define GRxFalseCRS_offset 0x14
-#define GRxFalseCRS_WIDTH 32
-#define GRxPausePkt_offset 0x18
-#define GRxPausePkt_WIDTH 32
-#define GRxBadPkt_offset 0x1C
-#define GRxBadPkt_WIDTH 32
-#define GRxUcastPkt_offset 0x20
-#define GRxUcastPkt_WIDTH 32
-#define GRxMcastPkt_offset 0x24
-#define GRxMcastPkt_WIDTH 32
-#define GRxBcastPkt_offset 0x28
-#define GRxBcastPkt_WIDTH 32
-#define GRxGoodLt64Pkt_offset 0x2C
-#define GRxGoodLt64Pkt_WIDTH 32
-#define GRxBadLt64Pkt_offset 0x30
-#define GRxBadLt64Pkt_WIDTH 32
-#define GRx64Pkt_offset 0x34
-#define GRx64Pkt_WIDTH 32
-#define GRx65to127Pkt_offset 0x38
-#define GRx65to127Pkt_WIDTH 32
-#define GRx128to255Pkt_offset 0x3C
-#define GRx128to255Pkt_WIDTH 32
-#define GRx256to511Pkt_offset 0x40
-#define GRx256to511Pkt_WIDTH 32
-#define GRx512to1023Pkt_offset 0x44
-#define GRx512to1023Pkt_WIDTH 32
-#define GRx1024to15xxPkt_offset 0x48
-#define GRx1024to15xxPkt_WIDTH 32
-#define GRx15xxtoJumboPkt_offset 0x4C
-#define GRx15xxtoJumboPkt_WIDTH 32
-#define GRxGtJumboPkt_offset 0x50
-#define GRxGtJumboPkt_WIDTH 32
-#define GRxFcsErr64to15xxPkt_offset 0x54
-#define GRxFcsErr64to15xxPkt_WIDTH 32
-#define GRxFcsErr15xxtoJumboPkt_offset 0x58
-#define GRxFcsErr15xxtoJumboPkt_WIDTH 32
-#define GRxFcsErrGtJumboPkt_offset 0x5C
-#define GRxFcsErrGtJumboPkt_WIDTH 32
-#define GTxGoodBadOct_offset 0x80
-#define GTxGoodBadOct_WIDTH 48
-#define GTxGoodOct_offset 0x88
-#define GTxGoodOct_WIDTH 48
-#define GTxSglColPkt_offset 0x90
-#define GTxSglColPkt_WIDTH 32
-#define GTxMultColPkt_offset 0x94
-#define GTxMultColPkt_WIDTH 32
-#define GTxExColPkt_offset 0x98
-#define GTxExColPkt_WIDTH 32
-#define GTxDefPkt_offset 0x9C
-#define GTxDefPkt_WIDTH 32
-#define GTxLateCol_offset 0xA0
-#define GTxLateCol_WIDTH 32
-#define GTxExDefPkt_offset 0xA4
-#define GTxExDefPkt_WIDTH 32
-#define GTxPausePkt_offset 0xA8
-#define GTxPausePkt_WIDTH 32
-#define GTxBadPkt_offset 0xAC
-#define GTxBadPkt_WIDTH 32
-#define GTxUcastPkt_offset 0xB0
-#define GTxUcastPkt_WIDTH 32
-#define GTxMcastPkt_offset 0xB4
-#define GTxMcastPkt_WIDTH 32
-#define GTxBcastPkt_offset 0xB8
-#define GTxBcastPkt_WIDTH 32
-#define GTxLt64Pkt_offset 0xBC
-#define GTxLt64Pkt_WIDTH 32
-#define GTx64Pkt_offset 0xC0
-#define GTx64Pkt_WIDTH 32
-#define GTx65to127Pkt_offset 0xC4
-#define GTx65to127Pkt_WIDTH 32
-#define GTx128to255Pkt_offset 0xC8
-#define GTx128to255Pkt_WIDTH 32
-#define GTx256to511Pkt_offset 0xCC
-#define GTx256to511Pkt_WIDTH 32
-#define GTx512to1023Pkt_offset 0xD0
-#define GTx512to1023Pkt_WIDTH 32
-#define GTx1024to15xxPkt_offset 0xD4
-#define GTx1024to15xxPkt_WIDTH 32
-#define GTx15xxtoJumboPkt_offset 0xD8
-#define GTx15xxtoJumboPkt_WIDTH 32
-#define GTxGtJumboPkt_offset 0xDC
-#define GTxGtJumboPkt_WIDTH 32
-#define GTxNonTcpUdpPkt_offset 0xE0
-#define GTxNonTcpUdpPkt_WIDTH 16
-#define GTxMacSrcErrPkt_offset 0xE4
-#define GTxMacSrcErrPkt_WIDTH 16
-#define GTxIpSrcErrPkt_offset 0xE8
-#define GTxIpSrcErrPkt_WIDTH 16
-#define GDmaDone_offset 0xEC
-#define GDmaDone_WIDTH 32
-
-#define XgRxOctets_offset 0x0
-#define XgRxOctets_WIDTH 48
-#define XgRxOctetsOK_offset 0x8
-#define XgRxOctetsOK_WIDTH 48
-#define XgRxPkts_offset 0x10
-#define XgRxPkts_WIDTH 32
-#define XgRxPktsOK_offset 0x14
-#define XgRxPktsOK_WIDTH 32
-#define XgRxBroadcastPkts_offset 0x18
-#define XgRxBroadcastPkts_WIDTH 32
-#define XgRxMulticastPkts_offset 0x1C
-#define XgRxMulticastPkts_WIDTH 32
-#define XgRxUnicastPkts_offset 0x20
-#define XgRxUnicastPkts_WIDTH 32
-#define XgRxUndersizePkts_offset 0x24
-#define XgRxUndersizePkts_WIDTH 32
-#define XgRxOversizePkts_offset 0x28
-#define XgRxOversizePkts_WIDTH 32
-#define XgRxJabberPkts_offset 0x2C
-#define XgRxJabberPkts_WIDTH 32
-#define XgRxUndersizeFCSerrorPkts_offset 0x30
-#define XgRxUndersizeFCSerrorPkts_WIDTH 32
-#define XgRxDropEvents_offset 0x34
-#define XgRxDropEvents_WIDTH 32
-#define XgRxFCSerrorPkts_offset 0x38
-#define XgRxFCSerrorPkts_WIDTH 32
-#define XgRxAlignError_offset 0x3C
-#define XgRxAlignError_WIDTH 32
-#define XgRxSymbolError_offset 0x40
-#define XgRxSymbolError_WIDTH 32
-#define XgRxInternalMACError_offset 0x44
-#define XgRxInternalMACError_WIDTH 32
-#define XgRxControlPkts_offset 0x48
-#define XgRxControlPkts_WIDTH 32
-#define XgRxPausePkts_offset 0x4C
-#define XgRxPausePkts_WIDTH 32
-#define XgRxPkts64Octets_offset 0x50
-#define XgRxPkts64Octets_WIDTH 32
-#define XgRxPkts65to127Octets_offset 0x54
-#define XgRxPkts65to127Octets_WIDTH 32
-#define XgRxPkts128to255Octets_offset 0x58
-#define XgRxPkts128to255Octets_WIDTH 32
-#define XgRxPkts256to511Octets_offset 0x5C
-#define XgRxPkts256to511Octets_WIDTH 32
-#define XgRxPkts512to1023Octets_offset 0x60
-#define XgRxPkts512to1023Octets_WIDTH 32
-#define XgRxPkts1024to15xxOctets_offset 0x64
-#define XgRxPkts1024to15xxOctets_WIDTH 32
-#define XgRxPkts15xxtoMaxOctets_offset 0x68
-#define XgRxPkts15xxtoMaxOctets_WIDTH 32
-#define XgRxLengthError_offset 0x6C
-#define XgRxLengthError_WIDTH 32
-#define XgTxPkts_offset 0x80
-#define XgTxPkts_WIDTH 32
-#define XgTxOctets_offset 0x88
-#define XgTxOctets_WIDTH 48
-#define XgTxMulticastPkts_offset 0x90
-#define XgTxMulticastPkts_WIDTH 32
-#define XgTxBroadcastPkts_offset 0x94
-#define XgTxBroadcastPkts_WIDTH 32
-#define XgTxUnicastPkts_offset 0x98
-#define XgTxUnicastPkts_WIDTH 32
-#define XgTxControlPkts_offset 0x9C
-#define XgTxControlPkts_WIDTH 32
-#define XgTxPausePkts_offset 0xA0
-#define XgTxPausePkts_WIDTH 32
-#define XgTxPkts64Octets_offset 0xA4
-#define XgTxPkts64Octets_WIDTH 32
-#define XgTxPkts65to127Octets_offset 0xA8
-#define XgTxPkts65to127Octets_WIDTH 32
-#define XgTxPkts128to255Octets_offset 0xAC
-#define XgTxPkts128to255Octets_WIDTH 32
-#define XgTxPkts256to511Octets_offset 0xB0
-#define XgTxPkts256to511Octets_WIDTH 32
-#define XgTxPkts512to1023Octets_offset 0xB4
-#define XgTxPkts512to1023Octets_WIDTH 32
-#define XgTxPkts1024to15xxOctets_offset 0xB8
-#define XgTxPkts1024to15xxOctets_WIDTH 32
-#define XgTxPkts1519toMaxOctets_offset 0xBC
-#define XgTxPkts1519toMaxOctets_WIDTH 32
-#define XgTxUndersizePkts_offset 0xC0
-#define XgTxUndersizePkts_WIDTH 32
-#define XgTxOversizePkts_offset 0xC4
-#define XgTxOversizePkts_WIDTH 32
-#define XgTxNonTcpUdpPkt_offset 0xC8
-#define XgTxNonTcpUdpPkt_WIDTH 16
-#define XgTxMacSrcErrPkt_offset 0xCC
-#define XgTxMacSrcErrPkt_WIDTH 16
-#define XgTxIpSrcErrPkt_offset 0xD0
-#define XgTxIpSrcErrPkt_WIDTH 16
-#define XgDmaDone_offset 0xD4
-#define XgDmaDone_WIDTH 32
-
-#define FALCON_STATS_NOT_DONE 0x00000000
-#define FALCON_STATS_DONE 0xffffffff
-
-/* Interrupt status register bits */
-#define FATAL_INT_LBN 64
-#define FATAL_INT_WIDTH 1
-#define INT_EVQS_LBN 40
-#define INT_EVQS_WIDTH 4
-#define INT_FLAG_LBN 32
-#define INT_FLAG_WIDTH 1
-#define EVQ_FIFO_HF_LBN 1
-#define EVQ_FIFO_HF_WIDTH 1
-#define EVQ_FIFO_AF_LBN 0
-#define EVQ_FIFO_AF_WIDTH 1
-
-/**************************************************************************
- *
- * Falcon non-volatile configuration
- *
- **************************************************************************
- */
-
-/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
-struct falcon_nvconfig_board_v2 {
-       __le16 nports;
-       u8 port0_phy_addr;
-       u8 port0_phy_type;
-       u8 port1_phy_addr;
-       u8 port1_phy_type;
-       __le16 asic_sub_revision;
-       __le16 board_revision;
-} __attribute__ ((packed));
-
-/* Board configuration v3 extra information */
-struct falcon_nvconfig_board_v3 {
-       __le32 spi_device_type[2];
-} __attribute__ ((packed));
-
-/* Bit numbers for spi_device_type */
-#define SPI_DEV_TYPE_SIZE_LBN 0
-#define SPI_DEV_TYPE_SIZE_WIDTH 5
-#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
-#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
-#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
-#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
-#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
-#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
-#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
-#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
-#define SPI_DEV_TYPE_FIELD(type, field) \
-       (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(field))
-
-#define NVCONFIG_BASE 0x300
-#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
-struct falcon_nvconfig {
-       efx_oword_t ee_vpd_cfg_reg;                     /* 0x300 */
-       u8 mac_address[2][8];                   /* 0x310 */
-       efx_oword_t pcie_sd_ctl0123_reg;                /* 0x320 */
-       efx_oword_t pcie_sd_ctl45_reg;                  /* 0x330 */
-       efx_oword_t pcie_pcs_ctl_stat_reg;              /* 0x340 */
-       efx_oword_t hw_init_reg;                        /* 0x350 */
-       efx_oword_t nic_stat_reg;                       /* 0x360 */
-       efx_oword_t glb_ctl_reg;                        /* 0x370 */
-       efx_oword_t srm_cfg_reg;                        /* 0x380 */
-       efx_oword_t spare_reg;                          /* 0x390 */
-       __le16 board_magic_num;                 /* 0x3A0 */
-       __le16 board_struct_ver;
-       __le16 board_checksum;
-       struct falcon_nvconfig_board_v2 board_v2;
-       efx_oword_t ee_base_page_reg;                   /* 0x3B0 */
-       struct falcon_nvconfig_board_v3 board_v3;       /* 0x3C0 */
-} __attribute__ ((packed));
-
-#endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
deleted file mode 100644 (file)
index 2660e24..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_FALCON_IO_H
-#define EFX_FALCON_IO_H
-
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include "net_driver.h"
-
-/**************************************************************************
- *
- * Falcon hardware access
- *
- **************************************************************************
- *
- * Notes on locking strategy:
- *
- * Most Falcon registers require 16-byte (or 8-byte, for SRAM
- * registers) atomic writes which necessitates locking.
- * Under normal operation few writes to the Falcon BAR are made and these
- * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
- * cased to allow 4-byte (hence lockless) accesses.
- *
- * It *is* safe to write to these 4-byte registers in the middle of an
- * access to an 8-byte or 16-byte register.  We therefore use a
- * spinlock to protect accesses to the larger registers, but no locks
- * for the 4-byte registers.
- *
- * A write barrier is needed to ensure that DW3 is written after DW0/1/2
- * due to the way the 16byte registers are "collected" in the Falcon BIU
- *
- * We also lock when carrying out reads, to ensure consistency of the
- * data (made possible since the BIU reads all 128 bits into a cache).
- * Reads are very rare, so this isn't a significant performance
- * impact.  (Most data transferred from NIC to host is DMAed directly
- * into host memory).
- *
- * I/O BAR access uses locks for both reads and writes (but is only provided
- * for testing purposes).
- */
-
-/* Special buffer descriptors (Falcon SRAM) */
-#define BUF_TBL_KER_A1 0x18000
-#define BUF_TBL_KER_B0 0x800000
-
-
-#if BITS_PER_LONG == 64
-#define FALCON_USE_QWORD_IO 1
-#endif
-
-#define _falcon_writeq(efx, value, reg) \
-       __raw_writeq((__force u64) (value), (efx)->membase + (reg))
-#define _falcon_writel(efx, value, reg) \
-       __raw_writel((__force u32) (value), (efx)->membase + (reg))
-#define _falcon_readq(efx, reg) \
-       ((__force __le64) __raw_readq((efx)->membase + (reg)))
-#define _falcon_readl(efx, reg) \
-       ((__force __le32) __raw_readl((efx)->membase + (reg)))
-
-/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
-static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
-                               unsigned int reg)
-{
-       unsigned long flags __attribute__ ((unused));
-
-       EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
-                   EFX_OWORD_VAL(*value));
-
-       spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef FALCON_USE_QWORD_IO
-       _falcon_writeq(efx, value->u64[0], reg + 0);
-       wmb();
-       _falcon_writeq(efx, value->u64[1], reg + 8);
-#else
-       _falcon_writel(efx, value->u32[0], reg + 0);
-       _falcon_writel(efx, value->u32[1], reg + 4);
-       _falcon_writel(efx, value->u32[2], reg + 8);
-       wmb();
-       _falcon_writel(efx, value->u32[3], reg + 12);
-#endif
-       mmiowb();
-       spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
-/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
-static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
-                                    unsigned int index)
-{
-       unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
-       unsigned long flags __attribute__ ((unused));
-
-       EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
-                   reg, EFX_QWORD_VAL(*value));
-
-       spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef FALCON_USE_QWORD_IO
-       _falcon_writeq(efx, value->u64[0], reg + 0);
-#else
-       _falcon_writel(efx, value->u32[0], reg + 0);
-       wmb();
-       _falcon_writel(efx, value->u32[1], reg + 4);
-#endif
-       mmiowb();
-       spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
-/* Write dword to Falcon register that allows partial writes
- *
- * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
- * TX_DESC_UPD_REG) can be written to as a single dword.  This allows
- * for lockless writes.
- */
-static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
-                                unsigned int reg)
-{
-       EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
-                   reg, EFX_DWORD_VAL(*value));
-
-       /* No lock required */
-       _falcon_writel(efx, value->u32[0], reg);
-}
-
-/* Read from a Falcon register
- *
- * This reads an entire 16-byte Falcon register in one go, locking as
- * appropriate.  It is essential to read the first dword first, as this
- * prompts Falcon to load the current value into the shadow register.
- */
-static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
-                              unsigned int reg)
-{
-       unsigned long flags __attribute__ ((unused));
-
-       spin_lock_irqsave(&efx->biu_lock, flags);
-       value->u32[0] = _falcon_readl(efx, reg + 0);
-       rmb();
-       value->u32[1] = _falcon_readl(efx, reg + 4);
-       value->u32[2] = _falcon_readl(efx, reg + 8);
-       value->u32[3] = _falcon_readl(efx, reg + 12);
-       spin_unlock_irqrestore(&efx->biu_lock, flags);
-
-       EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
-                   EFX_OWORD_VAL(*value));
-}
-
-/* This reads an 8-byte Falcon SRAM entry in one go. */
-static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
-                                   unsigned int index)
-{
-       unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
-       unsigned long flags __attribute__ ((unused));
-
-       spin_lock_irqsave(&efx->biu_lock, flags);
-#ifdef FALCON_USE_QWORD_IO
-       value->u64[0] = _falcon_readq(efx, reg + 0);
-#else
-       value->u32[0] = _falcon_readl(efx, reg + 0);
-       rmb();
-       value->u32[1] = _falcon_readl(efx, reg + 4);
-#endif
-       spin_unlock_irqrestore(&efx->biu_lock, flags);
-
-       EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
-                   reg, EFX_QWORD_VAL(*value));
-}
-
-/* Read dword from Falcon register that allows partial writes (sic) */
-static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
-                               unsigned int reg)
-{
-       value->u32[0] = _falcon_readl(efx, reg);
-       EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
-                   reg, EFX_DWORD_VAL(*value));
-}
-
-/* Write to a register forming part of a table */
-static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
-                                     unsigned int reg, unsigned int index)
-{
-       falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Read to a register forming part of a table */
-static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
-                                    unsigned int reg, unsigned int index)
-{
-       falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Write to a dword register forming part of a table */
-static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
-                                      unsigned int reg, unsigned int index)
-{
-       falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
-}
-
-/* Page-mapped register block size */
-#define FALCON_PAGE_BLOCK_SIZE 0x2000
-
-/* Calculate offset to page-mapped register block */
-#define FALCON_PAGED_REG(page, reg) \
-       ((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
-
-/* As for falcon_write(), but for a page-mapped register. */
-static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
-                                    unsigned int reg, unsigned int page)
-{
-       falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
-}
-
-/* As for falcon_writel(), but for a page-mapped register. */
-static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
-                                     unsigned int reg, unsigned int page)
-{
-       falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
-}
-
-/* Write dword to Falcon page-mapped register with an extra lock.
- *
- * As for falcon_writel_page(), but for a register that suffers from
- * SFC bug 3181. Take out a lock so the BIU collector cannot be
- * confused. */
-static inline void falcon_writel_page_locked(struct efx_nic *efx,
-                                            efx_dword_t *value,
-                                            unsigned int reg,
-                                            unsigned int page)
-{
-       unsigned long flags __attribute__ ((unused));
-
-       spin_lock_irqsave(&efx->biu_lock, flags);
-       falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
-       spin_unlock_irqrestore(&efx->biu_lock, flags);
-}
-
-#endif /* EFX_FALCON_IO_H */
index 37d3cae80f4207d02192ab43bd2f710ac5ecba6f..8ccab2c67a2094680ef743df277cd7e20a8d16c2 100644 (file)
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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/delay.h>
 #include "net_driver.h"
 #include "efx.h"
-#include "falcon.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
+#include "nic.h"
+#include "regs.h"
+#include "io.h"
 #include "mac.h"
-#include "gmii.h"
 #include "mdio_10g.h"
 #include "phy.h"
-#include "boards.h"
 #include "workarounds.h"
 
-/**************************************************************************
- *
- * MAC register access
- *
- **************************************************************************/
-
-/* Offset of an XMAC register within Falcon */
-#define FALCON_XMAC_REG(mac_reg)                                       \
-       (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
-
-static void falcon_xmac_writel(struct efx_nic *efx,
-                              efx_dword_t *value, unsigned int mac_reg)
-{
-       efx_oword_t temp;
-
-       EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
-       falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
-}
-
-static void falcon_xmac_readl(struct efx_nic *efx,
-                             efx_dword_t *value, unsigned int mac_reg)
-{
-       efx_oword_t temp;
-
-       falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
-       EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
-}
-
 /**************************************************************************
  *
  * MAC operations
  *
  *************************************************************************/
-static int falcon_reset_xmac(struct efx_nic *efx)
-{
-       efx_dword_t reg;
-       int count;
-
-       EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
-       efx->mac_op->mac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
-
-       for (count = 0; count < 10000; count++) {       /* wait upto 100ms */
-               efx->mac_op->mac_readl(efx, &reg, XM_GLB_CFG_REG_MAC);
-               if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
-                       return 0;
-               udelay(10);
-       }
-
-       EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
-       return -ETIMEDOUT;
-}
 
 /* Configure the XAUI driver that is an output from Falcon */
 static void falcon_setup_xaui(struct efx_nic *efx)
 {
-       efx_dword_t sdctl, txdrv;
+       efx_oword_t sdctl, txdrv;
 
        /* Move the XAUI into low power, unless there is no PHY, in
         * which case the XAUI will have to drive a cable. */
        if (efx->phy_type == PHY_TYPE_NONE)
                return;
 
-       efx->mac_op->mac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
-       EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
-       EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
-       efx->mac_op->mac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
-
-       EFX_POPULATE_DWORD_8(txdrv,
-                            XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
-                            XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
-                            XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
-                            XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
-                            XX_DTXD, XX_TXDRV_DTX_DEFAULT,
-                            XX_DTXC, XX_TXDRV_DTX_DEFAULT,
-                            XX_DTXB, XX_TXDRV_DTX_DEFAULT,
-                            XX_DTXA, XX_TXDRV_DTX_DEFAULT);
-       efx->mac_op->mac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
+       efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
+       EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
+       efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL);
+
+       EFX_POPULATE_OWORD_8(txdrv,
+                            FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF,
+                            FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF,
+                            FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF,
+                            FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF,
+                            FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF,
+                            FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF,
+                            FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF,
+                            FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF);
+       efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL);
 }
 
-static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
-{
-       efx_dword_t reg;
-
-       EFX_ZERO_DWORD(reg);
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
-       EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-}
-
-static int _falcon_reset_xaui_a(struct efx_nic *efx)
-{
-       efx_dword_t reg;
-
-       if (!efx->is_asic)
-               return 0;
-
-       falcon_hold_xaui_in_rst(efx);
-       efx->mac_op->mac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
-
-       /* Follow the RAMBUS XAUI data reset sequencing
-        * Channels A and B first: power down, reset PLL, reset, clear
-        */
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
-       EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       /* Channels C and D: power down, reset PLL, reset, clear */
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
-       EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
-       EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       /* Setup XAUI */
-       falcon_setup_xaui(efx);
-       udelay(10);
-
-       /* Take XGXS out of reset */
-       EFX_ZERO_DWORD(reg);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       return 0;
-}
-
-static int _falcon_reset_xaui_b(struct efx_nic *efx)
+int falcon_reset_xaui(struct efx_nic *efx)
 {
-       efx_dword_t reg;
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       efx_oword_t reg;
        int count;
 
-       if (!efx->is_asic)
-               return 0;
+       /* Don't fetch MAC statistics over an XMAC reset */
+       WARN_ON(nic_data->stats_disable_count == 0);
 
-       EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
+       /* Start reset sequence */
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
+       efx_writeo(efx, &reg, FR_AB_XX_PWR_RST);
 
-       /* Give some time for the link to establish */
-       for (count = 0; count < 1000; count++) { /* wait upto 10ms */
-               efx->mac_op->mac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
-               if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
+       /* Wait up to 10 ms for completion, then reinitialise */
+       for (count = 0; count < 1000; count++) {
+               efx_reado(efx, &reg, FR_AB_XX_PWR_RST);
+               if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 &&
+                   EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) {
                        falcon_setup_xaui(efx);
                        return 0;
                }
@@ -222,345 +85,220 @@ static int _falcon_reset_xaui_b(struct efx_nic *efx)
        return -ETIMEDOUT;
 }
 
-int falcon_reset_xaui(struct efx_nic *efx)
+static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
 {
-       int rc;
-
-       if (EFX_WORKAROUND_9388(efx)) {
-               falcon_hold_xaui_in_rst(efx);
-               efx->phy_op->reset_xaui(efx);
-               rc = _falcon_reset_xaui_a(efx);
-       } else {
-               rc = _falcon_reset_xaui_b(efx);
-       }
-       return rc;
-}
-
-static int falcon_xgmii_status(struct efx_nic *efx)
-{
-       efx_dword_t reg;
-
-       if (FALCON_REV(efx) < FALCON_REV_B0)
-               return 1;
+       efx_oword_t reg;
 
-       /* The ISR latches, so clear it and re-read */
-       efx->mac_op->mac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
-       efx->mac_op->mac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
-
-       if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
-           EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
-               EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
-               return 0;
-       }
-
-       return 1;
-}
+       if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
+               return;
 
-static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
-{
-       efx_dword_t reg;
+       /* We expect xgmii faults if the wireside link is up */
+       if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up)
+               return;
 
-       if ((FALCON_REV(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+       /* We can only use this interrupt to signal the negative edge of
+        * xaui_align [we have to poll the positive edge]. */
+       if (efx->xmac_poll_required)
                return;
 
        /* Flush the ISR */
        if (enable)
-               efx->mac_op->mac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
+               efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
 
-       EFX_POPULATE_DWORD_2(reg,
-                            XM_MSK_RMTFLT, !enable,
-                            XM_MSK_LCLFLT, !enable);
-       efx->mac_op->mac_writel(efx, &reg, XM_MGT_INT_MSK_REG_MAC_B0);
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_XM_MSK_RMTFLT, !enable,
+                            FRF_AB_XM_MSK_LCLFLT, !enable);
+       efx_writeo(efx, &reg, FR_AB_XM_MGT_INT_MASK);
 }
 
-static int falcon_init_xmac(struct efx_nic *efx)
+static bool falcon_xgxs_link_ok(struct efx_nic *efx)
 {
-       int rc;
-
-       /* Initialize the PHY first so the clock is around */
-       rc = efx->phy_op->init(efx);
-       if (rc)
-               goto fail1;
+       efx_oword_t reg;
+       bool align_done, link_ok = false;
+       int sync_status;
 
-       rc = falcon_reset_xaui(efx);
-       if (rc)
-               goto fail2;
-
-       /* Wait again. Give the PHY and MAC time to faff */
-       schedule_timeout_uninterruptible(HZ / 10);
+       /* Read link status */
+       efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
 
-       /* Reset the MAC */
-       rc = falcon_reset_xmac(efx);
-       if (rc)
-               goto fail2;
+       align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE);
+       sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT);
+       if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES))
+               link_ok = true;
 
-       falcon_mask_status_intr(efx, 1);
-       return 0;
+       /* Clear link status ready for next read */
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES);
+       efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
 
- fail2:
-       efx->phy_op->fini(efx);
- fail1:
-       return rc;
+       return link_ok;
 }
 
-/* Get status of XAUI link */
-int falcon_xaui_link_ok(struct efx_nic *efx)
+static bool falcon_xmac_link_ok(struct efx_nic *efx)
 {
-       efx_dword_t reg;
-       int align_done, sync_status, link_ok = 0;
-
-       /* If we're in internal loopback, then the link is up.
-        * The A1 FPGA/4G has RX and TX XAUI wired together, so the link is up.
-        * The B0 FPGA has XAUI offchip, so it is always up.
+       /*
+        * Check MAC's XGXS link status except when using XGMII loopback
+        * which bypasses the XGXS block.
+        * If possible, check PHY's XGXS link status except when using
+        * MAC loopback.
         */
-       if (!efx->is_asic || LOOPBACK_INTERNAL(efx))
-               return 1;
-
-       /* Read link status */
-       efx->mac_op->mac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
-
-       align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
-       sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
-       if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
-               link_ok = 1;
-
-       /* Clear link status ready for next read */
-       EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
-       EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
-       EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
-       efx->mac_op->mac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
-
-       /* If the link is up, then check the phy side of the xaui link
-        * (error conditions from the wire side propoagate back through
-        * the phy to the xaui side). */
-       if (efx->link_up && link_ok) {
-               int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
-               if (has_phyxs)
-                       link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
-       }
-
-       /* If the PHY and XAUI links are up, then check the mac's xgmii
-        * fault state */
-       if (efx->link_up && link_ok)
-               link_ok = falcon_xgmii_status(efx);
-
-       return link_ok;
+       return (efx->loopback_mode == LOOPBACK_XGMII ||
+               falcon_xgxs_link_ok(efx)) &&
+               (!(efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) ||
+                LOOPBACK_INTERNAL(efx) || 
+                efx_mdio_phyxgxs_lane_sync(efx));
 }
 
-static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+void falcon_reconfigure_xmac_core(struct efx_nic *efx)
 {
        unsigned int max_frame_len;
-       efx_dword_t reg;
-       efx_oword_t mac_test_reg;
-       int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
-
-       if (FALCON_REV(efx) <= FALCON_REV_A1 && !efx->is_asic) {
-               /* 10G FPGA's have the XAUI TX and RX wired together. Fake
-                * the link status and configure the link options before
-                * the MAC wrapper is configured */
-               efx->link_options = GM_LPA_10000FULL;
-               efx->link_up = 1;
-       }
+       efx_oword_t reg;
+       bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX);
+       bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX);
 
        /* Configure MAC  - cut-thru mode is hard wired on */
-       EFX_POPULATE_DWORD_3(reg,
-                            XM_RX_JUMBO_MODE, 1,
-                            XM_TX_STAT_EN, 1,
-                            XM_RX_STAT_EN, 1);
-       efx->mac_op->mac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
+       EFX_POPULATE_OWORD_3(reg,
+                            FRF_AB_XM_RX_JUMBO_MODE, 1,
+                            FRF_AB_XM_TX_STAT_EN, 1,
+                            FRF_AB_XM_RX_STAT_EN, 1);
+       efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
 
        /* Configure TX */
-       EFX_POPULATE_DWORD_6(reg,
-                            XM_TXEN, 1,
-                            XM_TX_PRMBL, 1,
-                            XM_AUTO_PAD, 1,
-                            XM_TXCRC, 1,
-                            XM_FCNTL, 1,
-                            XM_IPG, 0x3);
-       efx->mac_op->mac_writel(efx, &reg, XM_TX_CFG_REG_MAC);
+       EFX_POPULATE_OWORD_6(reg,
+                            FRF_AB_XM_TXEN, 1,
+                            FRF_AB_XM_TX_PRMBL, 1,
+                            FRF_AB_XM_AUTO_PAD, 1,
+                            FRF_AB_XM_TXCRC, 1,
+                            FRF_AB_XM_FCNTL, tx_fc,
+                            FRF_AB_XM_IPG, 0x3);
+       efx_writeo(efx, &reg, FR_AB_XM_TX_CFG);
 
        /* Configure RX */
-       EFX_POPULATE_DWORD_5(reg,
-                            XM_RXEN, 1,
-                            XM_AUTO_DEPAD, 0,
-                            XM_ACPT_ALL_MCAST, 1,
-                            XM_ACPT_ALL_UCAST, efx->promiscuous,
-                            XM_PASS_CRC_ERR, 1);
-       efx->mac_op->mac_writel(efx, &reg, XM_RX_CFG_REG_MAC);
+       EFX_POPULATE_OWORD_5(reg,
+                            FRF_AB_XM_RXEN, 1,
+                            FRF_AB_XM_AUTO_DEPAD, 0,
+                            FRF_AB_XM_ACPT_ALL_MCAST, 1,
+                            FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous,
+                            FRF_AB_XM_PASS_CRC_ERR, 1);
+       efx_writeo(efx, &reg, FR_AB_XM_RX_CFG);
 
        /* Set frame length */
        max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
-       EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
-       efx->mac_op->mac_writel(efx, &reg, XM_RX_PARAM_REG_MAC);
-       EFX_POPULATE_DWORD_2(reg,
-                            XM_MAX_TX_FRM_SIZE, max_frame_len,
-                            XM_TX_JUMBO_MODE, 1);
-       efx->mac_op->mac_writel(efx, &reg, XM_TX_PARAM_REG_MAC);
-
-       EFX_POPULATE_DWORD_2(reg,
-                            XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
-                            XM_DIS_FCNTL, rx_fc ? 0 : 1);
-       efx->mac_op->mac_writel(efx, &reg, XM_FC_REG_MAC);
+       EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
+       efx_writeo(efx, &reg, FR_AB_XM_RX_PARAM);
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len,
+                            FRF_AB_XM_TX_JUMBO_MODE, 1);
+       efx_writeo(efx, &reg, FR_AB_XM_TX_PARAM);
+
+       EFX_POPULATE_OWORD_2(reg,
+                            FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
+                            FRF_AB_XM_DIS_FCNTL, !rx_fc);
+       efx_writeo(efx, &reg, FR_AB_XM_FC);
 
        /* Set MAC address */
-       EFX_POPULATE_DWORD_4(reg,
-                            XM_ADR_0, efx->net_dev->dev_addr[0],
-                            XM_ADR_1, efx->net_dev->dev_addr[1],
-                            XM_ADR_2, efx->net_dev->dev_addr[2],
-                            XM_ADR_3, efx->net_dev->dev_addr[3]);
-       efx->mac_op->mac_writel(efx, &reg, XM_ADR_LO_REG_MAC);
-       EFX_POPULATE_DWORD_2(reg,
-                            XM_ADR_4, efx->net_dev->dev_addr[4],
-                            XM_ADR_5, efx->net_dev->dev_addr[5]);
-       efx->mac_op->mac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
-
-       /* Handle B0 FPGA loopback where RAMBUS XGXS block not present */
-       if (FALCON_REV(efx) >= FALCON_REV_B0 && !efx->is_asic) {
-               int xgmii_loopback =
-                       (efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
-
-               /* Set the MAC loopback bit. */
-               EFX_POPULATE_OWORD_1(mac_test_reg,
-                                    MAC_PTLOOP_EN, xgmii_loopback);
-               falcon_write(efx, &mac_test_reg, MAC_TEST_REG_KER);
-       }
+       memcpy(&reg, &efx->net_dev->dev_addr[0], 4);
+       efx_writeo(efx, &reg, FR_AB_XM_ADR_LO);
+       memcpy(&reg, &efx->net_dev->dev_addr[4], 2);
+       efx_writeo(efx, &reg, FR_AB_XM_ADR_HI);
 }
 
 static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
 {
-       efx_dword_t reg;
-       int xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS) ? 1 : 0;
-       int xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI) ? 1 : 0;
-       int xgmii_loopback =
-               (efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
-
-       if (FALCON_REV(efx) >= FALCON_REV_B0 && !efx->is_asic)
-               /* RAMBUS XGXS block is not present */
-               return;
+       efx_oword_t reg;
+       bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS);
+       bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI);
+       bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII);
 
        /* XGXS block is flaky and will need to be reset if moving
         * into our out of XGMII, XGXS or XAUI loopbacks. */
        if (EFX_WORKAROUND_5147(efx)) {
-               int old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
-               int reset_xgxs;
+               bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
+               bool reset_xgxs;
 
-               efx->mac_op->mac_readl(efx, &reg,
-                                           XX_CORE_STAT_REG_MAC);
-               old_xgxs_loopback = EFX_DWORD_FIELD(reg, XX_XGXS_LB_EN);
-               old_xgmii_loopback = EFX_DWORD_FIELD(reg, XX_XGMII_LB_EN);
+               efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
+               old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN);
+               old_xgmii_loopback =
+                       EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN);
 
-               efx->mac_op->mac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
-               old_xaui_loopback = EFX_DWORD_FIELD(reg, XX_LPBKA);
+               efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
+               old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA);
 
                /* The PHY driver may have turned XAUI off */
                reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
                              (xaui_loopback != old_xaui_loopback) ||
                              (xgmii_loopback != old_xgmii_loopback));
-               if (reset_xgxs) {
-                       efx->mac_op->mac_readl(efx, &reg,
-                                                   XX_PWR_RST_REG_MAC);
-                       EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
-                       EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
-                       efx->mac_op->mac_writel(efx, &reg,
-                                                    XX_PWR_RST_REG_MAC);
-                       udelay(1);
-                       EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0);
-                       EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0);
-                       efx->mac_op->mac_writel(efx, &reg,
-                                                    XX_PWR_RST_REG_MAC);
-                       udelay(1);
-               }
+
+               if (reset_xgxs)
+                       falcon_reset_xaui(efx);
        }
 
-       efx->mac_op->mac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
-       EFX_SET_DWORD_FIELD(reg, XX_FORCE_SIG,
+       efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG,
                            (xgxs_loopback || xaui_loopback) ?
-                           XX_FORCE_SIG_DECODE_FORCED : 0);
-       EFX_SET_DWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
-       EFX_SET_DWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
-       efx->mac_op->mac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
-
-       efx->mac_op->mac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
-       EFX_SET_DWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
-       EFX_SET_DWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
-       EFX_SET_DWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
-       EFX_SET_DWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
-       efx->mac_op->mac_writel(efx, &reg, XX_SD_CTL_REG_MAC);
+                           FFE_AB_XX_FORCE_SIG_ALL_LANES : 0);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback);
+       efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
+
+       efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback);
+       efx_writeo(efx, &reg, FR_AB_XX_SD_CTL);
 }
 
 
-/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
- * to come back up. Bash it until it comes back up */
-static int falcon_check_xaui_link_up(struct efx_nic *efx)
+/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */
+static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries)
 {
-       int max_tries, tries;
-       tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
-       max_tries = tries;
-
-       if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
-           (efx->phy_type == PHY_TYPE_NONE) ||
-           !efx->phy_powered)
-               return 0;
-
-       while (tries) {
-               if (falcon_xaui_link_ok(efx))
-                       return 1;
-
-               EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
-                       __func__, tries);
-               (void) falcon_reset_xaui(efx);
+       bool mac_up = falcon_xmac_link_ok(efx);
+
+       if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS ||
+           efx_phy_mode_disabled(efx->phy_mode))
+               /* XAUI link is expected to be down */
+               return mac_up;
+
+       falcon_stop_nic_stats(efx);
+
+       while (!mac_up && tries) {
+               EFX_LOG(efx, "bashing xaui\n");
+               falcon_reset_xaui(efx);
                udelay(200);
-               tries--;
+
+               mac_up = falcon_xmac_link_ok(efx);
+               --tries;
        }
 
-       EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n",
-               max_tries);
-       return 0;
+       falcon_start_nic_stats(efx);
+
+       return mac_up;
 }
 
-static void falcon_reconfigure_xmac(struct efx_nic *efx)
+static bool falcon_xmac_check_fault(struct efx_nic *efx)
 {
-       int xaui_link_ok;
-
-       falcon_mask_status_intr(efx, 0);
-
-       /* Deconfigure the mac wrapper, draining the tx fifo if necessary */
-       falcon_deconfigure_mac_wrapper(efx);
+       return !falcon_xmac_link_ok_retry(efx, 5);
+}
 
-       /* Reconfigure the PHY, disabling transmit in mac level loopback. */
-       efx->tx_disabled = LOOPBACK_INTERNAL(efx);
-       efx->phy_op->reconfigure(efx);
+static int falcon_reconfigure_xmac(struct efx_nic *efx)
+{
+       falcon_mask_status_intr(efx, false);
 
        falcon_reconfigure_xgxs_core(efx);
        falcon_reconfigure_xmac_core(efx);
 
-       /* Reconfigure MAC wrapper */
        falcon_reconfigure_mac_wrapper(efx);
 
-       /* Ensure XAUI link is up */
-       xaui_link_ok = falcon_check_xaui_link_up(efx);
+       efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
+       falcon_mask_status_intr(efx, true);
 
-       if (xaui_link_ok && efx->link_up)
-               falcon_mask_status_intr(efx, 1);
-}
-
-static void falcon_fini_xmac(struct efx_nic *efx)
-{
-       /* Isolate the MAC - PHY */
-       falcon_deconfigure_mac_wrapper(efx);
-
-       /* Potentially power down the PHY */
-       efx->phy_op->fini(efx);
+       return 0;
 }
 
 static void falcon_update_stats_xmac(struct efx_nic *efx)
 {
        struct efx_mac_stats *mac_stats = &efx->mac_stats;
-       int rc;
-
-       rc = falcon_dma_stats(efx, XgDmaDone_offset);
-       if (rc)
-               return;
 
        /* Update MAC stats from DMAed values */
        FALCON_STAT(efx, XgRxOctets, rx_bytes);
@@ -611,122 +349,26 @@ static void falcon_update_stats_xmac(struct efx_nic *efx)
 
        /* Update derived statistics */
        mac_stats->tx_good_bytes =
-               (mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
+               (mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
+                mac_stats->tx_control * 64);
        mac_stats->rx_bad_bytes =
-               (mac_stats->rx_bytes - mac_stats->rx_good_bytes);
+               (mac_stats->rx_bytes - mac_stats->rx_good_bytes -
+                mac_stats->rx_control * 64);
 }
 
-#define EFX_XAUI_RETRAIN_MAX 8
-
-static int falcon_check_xmac(struct efx_nic *efx)
-{
-       unsigned xaui_link_ok;
-       int rc;
-
-       if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
-           (efx->phy_type == PHY_TYPE_NONE) ||
-           !efx->phy_powered)
-               return 0;
-
-       falcon_mask_status_intr(efx, 0);
-       xaui_link_ok = falcon_xaui_link_ok(efx);
-
-       if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
-               (void) falcon_reset_xaui(efx);
-
-       /* Call the PHY check_hw routine */
-       rc = efx->phy_op->check_hw(efx);
-
-       /* Unmask interrupt if everything was (and still is) ok */
-       if (xaui_link_ok && efx->link_up)
-               falcon_mask_status_intr(efx, 1);
-
-       return rc;
-}
-
-/* Simulate a PHY event */
-static void falcon_xmac_sim_phy_event(struct efx_nic *efx)
-{
-       efx_qword_t phy_event;
-
-       EFX_POPULATE_QWORD_2(phy_event,
-                            EV_CODE, GLOBAL_EV_DECODE,
-                            XG_PHY_INTR, 1);
-       falcon_generate_event(&efx->channel[0], &phy_event);
-}
-
-static int falcon_xmac_get_settings(struct efx_nic *efx,
-                                   struct ethtool_cmd *ecmd)
-{
-       mdio_clause45_get_settings(efx, ecmd);
-       ecmd->transceiver = XCVR_INTERNAL;
-       ecmd->phy_address = efx->mii.phy_id;
-       ecmd->autoneg = AUTONEG_DISABLE;
-       ecmd->duplex = DUPLEX_FULL;
-       return 0;
-}
-
-static int falcon_xmac_set_settings(struct efx_nic *efx,
-                                   struct ethtool_cmd *ecmd)
-{
-       if (ecmd->transceiver != XCVR_INTERNAL)
-               return -EINVAL;
-       if (ecmd->autoneg != AUTONEG_DISABLE)
-               return -EINVAL;
-       if (ecmd->duplex != DUPLEX_FULL)
-               return -EINVAL;
-
-       return mdio_clause45_set_settings(efx, ecmd);
-}
-
-
-static int falcon_xmac_set_pause(struct efx_nic *efx,
-                                enum efx_fc_type flow_control)
+void falcon_poll_xmac(struct efx_nic *efx)
 {
-       int reset;
-
-       if (flow_control & EFX_FC_AUTO) {
-               EFX_LOG(efx, "10G does not support flow control "
-                       "autonegotiation\n");
-               return -EINVAL;
-       }
-
-       if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
-               return -EINVAL;
-
-       /* 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 = ((flow_control & EFX_FC_TX) &&
-                !(efx->flow_control & EFX_FC_TX));
-       if (EFX_WORKAROUND_11482(efx) && reset) {
-               if (FALCON_REV(efx) >= FALCON_REV_B0) {
-                       /* Recover by resetting the EM block */
-                       if (efx->link_up)
-                               falcon_drain_tx_fifo(efx);
-               } else {
-                       /* Schedule a reset to recover */
-                       efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
-               }
-       }
-
-       efx->flow_control = flow_control;
+       if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up ||
+           !efx->xmac_poll_required)
+               return;
 
-       return 0;
+       falcon_mask_status_intr(efx, false);
+       efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
+       falcon_mask_status_intr(efx, true);
 }
 
 struct efx_mac_operations falcon_xmac_operations = {
-       .mac_writel     = falcon_xmac_writel,
-       .mac_readl      = falcon_xmac_readl,
-       .init           = falcon_init_xmac,
        .reconfigure    = falcon_reconfigure_xmac,
        .update_stats   = falcon_update_stats_xmac,
-       .fini           = falcon_fini_xmac,
-       .check_hw       = falcon_check_xmac,
-       .fake_phy_event = falcon_xmac_sim_phy_event,
-       .get_settings   = falcon_xmac_get_settings,
-       .set_settings   = falcon_xmac_set_settings,
-       .set_pause      = falcon_xmac_set_pause,
+       .check_fault    = falcon_xmac_check_fault,
 };
diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h
deleted file mode 100644 (file)
index 64c2c81..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_GMII_H
-#define EFX_GMII_H
-
-/*
- * GMII interface
- */
-
-#include <linux/mii.h>
-
-/* GMII registers, excluding registers already defined as MII
- * registers in mii.h
- */
-#define GMII_IER               0x12    /* Interrupt enable register */
-#define GMII_ISR               0x13    /* Interrupt status register */
-
-/* Interrupt enable register */
-#define IER_ANEG_ERR           0x8000  /* Bit 15 - autonegotiation error */
-#define IER_SPEED_CHG          0x4000  /* Bit 14 - speed changed */
-#define IER_DUPLEX_CHG         0x2000  /* Bit 13 - duplex changed */
-#define IER_PAGE_RCVD          0x1000  /* Bit 12 - page received */
-#define IER_ANEG_DONE          0x0800  /* Bit 11 - autonegotiation complete */
-#define IER_LINK_CHG           0x0400  /* Bit 10 - link status changed */
-#define IER_SYM_ERR            0x0200  /* Bit 9 - symbol error */
-#define IER_FALSE_CARRIER      0x0100  /* Bit 8 - false carrier */
-#define IER_FIFO_ERR           0x0080  /* Bit 7 - FIFO over/underflow */
-#define IER_MDIX_CHG           0x0040  /* Bit 6 - MDI crossover changed */
-#define IER_DOWNSHIFT          0x0020  /* Bit 5 - downshift */
-#define IER_ENERGY             0x0010  /* Bit 4 - energy detect */
-#define IER_DTE_POWER          0x0004  /* Bit 2 - DTE power detect */
-#define IER_POLARITY_CHG       0x0002  /* Bit 1 - polarity changed */
-#define IER_JABBER             0x0001  /* Bit 0 - jabber */
-
-/* Interrupt status register */
-#define ISR_ANEG_ERR           0x8000  /* Bit 15 - autonegotiation error */
-#define ISR_SPEED_CHG          0x4000  /* Bit 14 - speed changed */
-#define ISR_DUPLEX_CHG         0x2000  /* Bit 13 - duplex changed */
-#define ISR_PAGE_RCVD          0x1000  /* Bit 12 - page received */
-#define ISR_ANEG_DONE          0x0800  /* Bit 11 - autonegotiation complete */
-#define ISR_LINK_CHG           0x0400  /* Bit 10 - link status changed */
-#define ISR_SYM_ERR            0x0200  /* Bit 9 - symbol error */
-#define ISR_FALSE_CARRIER      0x0100  /* Bit 8 - false carrier */
-#define ISR_FIFO_ERR           0x0080  /* Bit 7 - FIFO over/underflow */
-#define ISR_MDIX_CHG           0x0040  /* Bit 6 - MDI crossover changed */
-#define ISR_DOWNSHIFT          0x0020  /* Bit 5 - downshift */
-#define ISR_ENERGY             0x0010  /* Bit 4 - energy detect */
-#define ISR_DTE_POWER          0x0004  /* Bit 2 - DTE power detect */
-#define ISR_POLARITY_CHG       0x0002  /* Bit 1 - polarity changed */
-#define ISR_JABBER             0x0001  /* Bit 0 - jabber */
-
-/* Logically extended advertisement register */
-#define GM_ADVERTISE_SLCT              ADVERTISE_SLCT
-#define GM_ADVERTISE_CSMA              ADVERTISE_CSMA
-#define GM_ADVERTISE_10HALF            ADVERTISE_10HALF
-#define GM_ADVERTISE_1000XFULL         ADVERTISE_1000XFULL
-#define GM_ADVERTISE_10FULL            ADVERTISE_10FULL
-#define GM_ADVERTISE_1000XHALF         ADVERTISE_1000XHALF
-#define GM_ADVERTISE_100HALF           ADVERTISE_100HALF
-#define GM_ADVERTISE_1000XPAUSE                ADVERTISE_1000XPAUSE
-#define GM_ADVERTISE_100FULL           ADVERTISE_100FULL
-#define GM_ADVERTISE_1000XPSE_ASYM     ADVERTISE_1000XPSE_ASYM
-#define GM_ADVERTISE_100BASE4          ADVERTISE_100BASE4
-#define GM_ADVERTISE_PAUSE_CAP         ADVERTISE_PAUSE_CAP
-#define GM_ADVERTISE_PAUSE_ASYM                ADVERTISE_PAUSE_ASYM
-#define GM_ADVERTISE_RESV              ADVERTISE_RESV
-#define GM_ADVERTISE_RFAULT            ADVERTISE_RFAULT
-#define GM_ADVERTISE_LPACK             ADVERTISE_LPACK
-#define GM_ADVERTISE_NPAGE             ADVERTISE_NPAGE
-#define GM_ADVERTISE_1000FULL          (ADVERTISE_1000FULL << 8)
-#define GM_ADVERTISE_1000HALF          (ADVERTISE_1000HALF << 8)
-#define GM_ADVERTISE_1000              (GM_ADVERTISE_1000FULL | \
-                                        GM_ADVERTISE_1000HALF)
-#define GM_ADVERTISE_FULL              (GM_ADVERTISE_1000FULL | \
-                                        ADVERTISE_FULL)
-#define GM_ADVERTISE_ALL               (GM_ADVERTISE_1000FULL | \
-                                        GM_ADVERTISE_1000HALF | \
-                                        ADVERTISE_ALL)
-
-/* Logically extended link partner ability register */
-#define GM_LPA_SLCT                    LPA_SLCT
-#define GM_LPA_10HALF                  LPA_10HALF
-#define GM_LPA_1000XFULL               LPA_1000XFULL
-#define GM_LPA_10FULL                  LPA_10FULL
-#define GM_LPA_1000XHALF               LPA_1000XHALF
-#define GM_LPA_100HALF                 LPA_100HALF
-#define GM_LPA_1000XPAUSE              LPA_1000XPAUSE
-#define GM_LPA_100FULL                 LPA_100FULL
-#define GM_LPA_1000XPAUSE_ASYM         LPA_1000XPAUSE_ASYM
-#define GM_LPA_100BASE4                        LPA_100BASE4
-#define GM_LPA_PAUSE_CAP               LPA_PAUSE_CAP
-#define GM_LPA_PAUSE_ASYM              LPA_PAUSE_ASYM
-#define GM_LPA_RESV                    LPA_RESV
-#define GM_LPA_RFAULT                  LPA_RFAULT
-#define GM_LPA_LPACK                   LPA_LPACK
-#define GM_LPA_NPAGE                   LPA_NPAGE
-#define GM_LPA_1000FULL                        (LPA_1000FULL << 6)
-#define GM_LPA_1000HALF                        (LPA_1000HALF << 6)
-#define GM_LPA_10000FULL               0x00040000
-#define GM_LPA_10000HALF               0x00080000
-#define GM_LPA_DUPLEX                  (GM_LPA_1000FULL | GM_LPA_10000FULL \
-                                        | LPA_DUPLEX)
-#define GM_LPA_10                      (LPA_10FULL | LPA_10HALF)
-#define GM_LPA_100                     LPA_100
-#define GM_LPA_1000                    (GM_LPA_1000FULL | GM_LPA_1000HALF)
-#define GM_LPA_10000                   (GM_LPA_10000FULL | GM_LPA_10000HALF)
-
-/* Retrieve GMII autonegotiation advertised abilities
- *
- * The MII advertisment register (MII_ADVERTISE) is logically extended
- * to include advertisement bits ADVERTISE_1000FULL and
- * ADVERTISE_1000HALF from MII_CTRL1000.  The result can be tested
- * against the GM_ADVERTISE_xxx constants.
- */
-static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
-{
-       unsigned int advertise;
-       unsigned int ctrl1000;
-
-       advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
-       ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
-       return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
-}
-
-/* Retrieve GMII autonegotiation link partner abilities
- *
- * The MII link partner ability register (MII_LPA) is logically
- * extended by adding bits LPA_1000HALF and LPA_1000FULL from
- * MII_STAT1000.  The result can be tested against the GM_LPA_xxx
- * constants.
- */
-static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
-{
-       unsigned int lpa;
-       unsigned int stat1000;
-
-       lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
-       stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
-       return (((stat1000 << 6) & GM_LPA_1000) | lpa);
-}
-
-/* Calculate GMII autonegotiated link technology
- *
- * "negotiated" should be the result of gmii_advertised() logically
- * ANDed with the result of gmii_lpa().
- *
- * "tech" will be negotiated with the unused bits masked out.  For
- * example, if both ends of the link are capable of both
- * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
- * out.
- */
-static inline unsigned int gmii_nway_result(unsigned int negotiated)
-{
-       unsigned int other_bits;
-
-       /* Mask out the speed and duplexity bits */
-       other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
-
-       if (negotiated & GM_LPA_1000FULL)
-               return (other_bits | GM_LPA_1000FULL);
-       else if (negotiated & GM_LPA_1000HALF)
-               return (other_bits | GM_LPA_1000HALF);
-       else
-               return (other_bits | mii_nway_result(negotiated));
-}
-
-/* Calculate GMII non-autonegotiated link technology
- *
- * This provides an equivalent to gmii_nway_result for the case when
- * autonegotiation is disabled.
- */
-static inline unsigned int gmii_forced_result(unsigned int bmcr)
-{
-       unsigned int result;
-       int full_duplex;
-
-       full_duplex = bmcr & BMCR_FULLDPLX;
-       if (bmcr & BMCR_SPEED1000)
-               result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
-       else if (bmcr & BMCR_SPEED100)
-               result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
-       else
-               result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
-       return result;
-}
-
-#endif /* EFX_GMII_H */
diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c
deleted file mode 100644 (file)
index 6ada2ef..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005:      Fen Systems Ltd.
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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/delay.h>
-#include "net_driver.h"
-#include "i2c-direct.h"
-
-/*
- * I2C data (SDA) and clock (SCL) line read/writes with appropriate
- * delays.
- */
-
-static inline void setsda(struct efx_i2c_interface *i2c, int state)
-{
-       udelay(i2c->op->udelay);
-       i2c->sda = state;
-       i2c->op->setsda(i2c);
-       udelay(i2c->op->udelay);
-}
-
-static inline void setscl(struct efx_i2c_interface *i2c, int state)
-{
-       udelay(i2c->op->udelay);
-       i2c->scl = state;
-       i2c->op->setscl(i2c);
-       udelay(i2c->op->udelay);
-}
-
-static inline int getsda(struct efx_i2c_interface *i2c)
-{
-       int sda;
-
-       udelay(i2c->op->udelay);
-       sda = i2c->op->getsda(i2c);
-       udelay(i2c->op->udelay);
-       return sda;
-}
-
-static inline int getscl(struct efx_i2c_interface *i2c)
-{
-       int scl;
-
-       udelay(i2c->op->udelay);
-       scl = i2c->op->getscl(i2c);
-       udelay(i2c->op->udelay);
-       return scl;
-}
-
-/*
- * I2C low-level protocol operations
- *
- */
-
-static inline void i2c_release(struct efx_i2c_interface *i2c)
-{
-       EFX_WARN_ON_PARANOID(!i2c->scl);
-       EFX_WARN_ON_PARANOID(!i2c->sda);
-       /* Devices may time out if operations do not end */
-       setscl(i2c, 1);
-       setsda(i2c, 1);
-       EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
-       EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
-}
-
-static inline void i2c_start(struct efx_i2c_interface *i2c)
-{
-       /* We may be restarting immediately after a {send,recv}_bit,
-        * so SCL will not necessarily already be high.
-        */
-       EFX_WARN_ON_PARANOID(!i2c->sda);
-       setscl(i2c, 1);
-       setsda(i2c, 0);
-       setscl(i2c, 0);
-       setsda(i2c, 1);
-}
-
-static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
-{
-       EFX_WARN_ON_PARANOID(i2c->scl != 0);
-       setsda(i2c, bit);
-       setscl(i2c, 1);
-       setscl(i2c, 0);
-       setsda(i2c, 1);
-}
-
-static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
-{
-       int bit;
-
-       EFX_WARN_ON_PARANOID(i2c->scl != 0);
-       EFX_WARN_ON_PARANOID(!i2c->sda);
-       setscl(i2c, 1);
-       bit = getsda(i2c);
-       setscl(i2c, 0);
-       return bit;
-}
-
-static inline void i2c_stop(struct efx_i2c_interface *i2c)
-{
-       EFX_WARN_ON_PARANOID(i2c->scl != 0);
-       setsda(i2c, 0);
-       setscl(i2c, 1);
-       setsda(i2c, 1);
-}
-
-/*
- * I2C mid-level protocol operations
- *
- */
-
-/* Sends a byte via the I2C bus and checks for an acknowledgement from
- * the slave device.
- */
-static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
-{
-       int i;
-
-       /* Send byte */
-       for (i = 0; i < 8; i++) {
-               i2c_send_bit(i2c, !!(byte & 0x80));
-               byte <<= 1;
-       }
-
-       /* Check for acknowledgement from slave */
-       return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
-}
-
-/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
-static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
-{
-       u8 value = 0;
-       int i;
-
-       /* Receive byte */
-       for (i = 0; i < 8; i++)
-               value = (value << 1) | i2c_recv_bit(i2c);
-
-       /* Send ACK/NACK */
-       i2c_send_bit(i2c, (ack ? 0 : 1));
-
-       return value;
-}
-
-/* Calculate command byte for a read operation */
-static inline u8 i2c_read_cmd(u8 device_id)
-{
-       return ((device_id << 1) | 1);
-}
-
-/* Calculate command byte for a write operation */
-static inline u8 i2c_write_cmd(u8 device_id)
-{
-       return ((device_id << 1) | 0);
-}
-
-int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
-{
-       int rc;
-
-       /* If someone is driving the bus low we just give up. */
-       if (getsda(i2c) == 0 || getscl(i2c) == 0) {
-               EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
-                       " Giving up.\n", __func__);
-               return -EFAULT;
-       }
-
-       /* Pretend to initiate a device write */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
-       if (rc)
-               goto out;
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* This performs a fast read of one or more consecutive bytes from an
- * I2C device.  Not all devices support consecutive reads of more than
- * one byte; for these devices use efx_i2c_read() instead.
- */
-int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
-                     u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
-       int i;
-       int rc;
-
-       EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
-       EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
-       EFX_WARN_ON_PARANOID(data == NULL);
-       EFX_WARN_ON_PARANOID(len < 1);
-
-       /* Select device and starting offset */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
-       if (rc)
-               goto out;
-       rc = i2c_send_byte(i2c, offset);
-       if (rc)
-               goto out;
-
-       /* Read data from device */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
-       if (rc)
-               goto out;
-       for (i = 0; i < (len - 1); i++)
-               /* Read and acknowledge all but the last byte */
-               data[i] = i2c_recv_byte(i2c, 1);
-       /* Read last byte with no acknowledgement */
-       data[i] = i2c_recv_byte(i2c, 0);
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* This performs a fast write of one or more consecutive bytes to an
- * I2C device.  Not all devices support consecutive writes of more
- * than one byte; for these devices use efx_i2c_write() instead.
- */
-int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
-                      u8 device_id, u8 offset,
-                      const u8 *data, unsigned int len)
-{
-       int i;
-       int rc;
-
-       EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
-       EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
-       EFX_WARN_ON_PARANOID(len < 1);
-
-       /* Select device and starting offset */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
-       if (rc)
-               goto out;
-       rc = i2c_send_byte(i2c, offset);
-       if (rc)
-               goto out;
-
-       /* Write data to device */
-       for (i = 0; i < len; i++) {
-               rc = i2c_send_byte(i2c, data[i]);
-               if (rc)
-                       goto out;
-       }
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* I2C byte-by-byte read */
-int efx_i2c_read(struct efx_i2c_interface *i2c,
-                u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
-       int rc;
-
-       /* i2c_fast_read with length 1 is a single byte read */
-       for (; len > 0; offset++, data++, len--) {
-               rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
-               if (rc)
-                       return rc;
-       }
-
-       return 0;
-}
-
-/* I2C byte-by-byte write */
-int efx_i2c_write(struct efx_i2c_interface *i2c,
-                 u8 device_id, u8 offset, const u8 *data, unsigned int len)
-{
-       int rc;
-
-       /* i2c_fast_write with length 1 is a single byte write */
-       for (; len > 0; offset++, data++, len--) {
-               rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
-               if (rc)
-                       return rc;
-               mdelay(i2c->op->mdelay);
-       }
-
-       return 0;
-}
-
-
-/* This is just a slightly neater wrapper round efx_i2c_fast_write
- * in the case where the target doesn't take an offset
- */
-int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
-                      u8 device_id, const u8 *data, unsigned int len)
-{
-       return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
-}
-
-/* I2C receiving of bytes - does not send an offset byte */
-int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
-                      u8 *bytes, unsigned int len)
-{
-       int i;
-       int rc;
-
-       EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
-       EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
-       EFX_WARN_ON_PARANOID(len < 1);
-
-       /* Select device */
-       i2c_start(i2c);
-
-       /* Read data from device */
-       rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
-       if (rc)
-               goto out;
-
-       for (i = 0; i < (len - 1); i++)
-               /* Read and acknowledge all but the last byte */
-               bytes[i] = i2c_recv_byte(i2c, 1);
-       /* Read last byte with no acknowledgement */
-       bytes[i] = i2c_recv_byte(i2c, 0);
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* SMBus and some I2C devices will time out if the I2C clock is
- * held low for too long. This is most likely to happen in virtualised
- * systems (when the entire domain is descheduled) but could in
- * principle happen due to preemption on any busy system (and given the
- * potential length of an I2C operation turning preemption off is not
- * a sensible option). The following functions deal with the failure by
- * retrying up to a fixed number of times.
-  */
-
-#define I2C_MAX_RETRIES        (10)
-
-/* The timeout problem will result in -EIO. If the wrapped function
- * returns any other error, pass this up and do not retry. */
-#define RETRY_WRAPPER(_f) \
-       int retries = I2C_MAX_RETRIES; \
-       int rc; \
-       while (retries) { \
-               rc = _f; \
-               if (rc != -EIO) \
-                       return rc; \
-               retries--; \
-       } \
-       return rc; \
-
-int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
-{
-       RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
-}
-
-int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
-                u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
-       RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
-}
-
-int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
-                 u8 device_id, u8 offset, const u8 *data, unsigned int len)
-{
-       RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
-}
diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h
deleted file mode 100644 (file)
index 78c6cf1..0000000
+++ /dev/null
@@ -1,108 +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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_I2C_DIRECT_H
-#define EFX_I2C_DIRECT_H
-
-#include "net_driver.h"
-
-/*
- * Direct control of an I2C bus
- */
-
-struct efx_i2c_interface;
-
-/**
- * struct efx_i2c_bit_operations - I2C bus direct control methods
- *
- * I2C bus direct control methods.
- *
- * @setsda: Set state of SDA line
- * @setscl: Set state of SCL line
- * @getsda: Get state of SDA line
- * @getscl: Get state of SCL line
- * @udelay: Delay between each bit operation
- * @mdelay: Delay between each byte write
- */
-struct efx_i2c_bit_operations {
-       void (*setsda) (struct efx_i2c_interface *i2c);
-       void (*setscl) (struct efx_i2c_interface *i2c);
-       int (*getsda) (struct efx_i2c_interface *i2c);
-       int (*getscl) (struct efx_i2c_interface *i2c);
-       unsigned int udelay;
-       unsigned int mdelay;
-};
-
-/**
- * struct efx_i2c_interface - an I2C interface
- *
- * An I2C interface.
- *
- * @efx: Attached Efx NIC
- * @op: I2C bus control methods
- * @sda: Current output state of SDA line
- * @scl: Current output state of SCL line
- */
-struct efx_i2c_interface {
-       struct efx_nic *efx;
-       struct efx_i2c_bit_operations *op;
-       unsigned int sda:1;
-       unsigned int scl:1;
-};
-
-extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
-extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
-                            u8 device_id, u8 offset,
-                            u8 *data, unsigned int len);
-extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
-                             u8 device_id, u8 offset,
-                             const u8 *data, unsigned int len);
-extern int efx_i2c_read(struct efx_i2c_interface *i2c,
-                       u8 device_id, u8 offset, u8 *data, unsigned int len);
-extern int efx_i2c_write(struct efx_i2c_interface *i2c,
-                        u8 device_id, u8 offset,
-                        const u8 *data, unsigned int len);
-
-extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
-                             const u8 *bytes, unsigned int len);
-
-extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
-                             u8 *bytes, unsigned int len);
-
-
-/* Versions of the API that retry on failure. */
-extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
-                                       u8 device_id);
-
-extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
-                       u8 device_id, u8 offset, u8 *data, unsigned int len);
-
-extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
-                        u8 device_id, u8 offset,
-                        const u8 *data, unsigned int len);
-
-#endif /* EFX_I2C_DIRECT_H */
diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h
new file mode 100644 (file)
index 0000000..9e60924
--- /dev/null
@@ -0,0 +1,260 @@
+/****************************************************************************
+ * 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.
+ */
+
+#ifndef EFX_IO_H
+#define EFX_IO_H
+
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_LINUX_IO_H)
+#include <linux/io.h>
+#else
+#include <asm/io.h>
+#endif
+#include <linux/spinlock.h>
+
+/**************************************************************************
+ *
+ * NIC register I/O
+ *
+ **************************************************************************
+ *
+ * Notes on locking strategy:
+ *
+ * Most NIC registers require 16-byte (or 8-byte, for SRAM) atomic writes
+ * which necessitates locking.
+ * Under normal operation few writes to NIC registers are made and these
+ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
+ * cased to allow 4-byte (hence lockless) accesses.
+ *
+ * It *is* safe to write to these 4-byte registers in the middle of an
+ * access to an 8-byte or 16-byte register.  We therefore use a
+ * spinlock to protect accesses to the larger registers, but no locks
+ * for the 4-byte registers.
+ *
+ * A write barrier is needed to ensure that DW3 is written after DW0/1/2
+ * due to the way the 16byte registers are "collected" in the BIU.
+ *
+ * We also lock when carrying out reads, to ensure consistency of the
+ * data (made possible since the BIU reads all 128 bits into a cache).
+ * Reads are very rare, so this isn't a significant performance
+ * impact.  (Most data transferred from NIC to host is DMAed directly
+ * into host memory).
+ *
+ * I/O BAR access uses locks for both reads and writes (but is only provided
+ * for testing purposes).
+ */
+
+#if BITS_PER_LONG == 64
+#define EFX_USE_QWORD_IO 1
+#endif
+
+#ifdef EFX_USE_QWORD_IO
+static inline void _efx_writeq(struct efx_nic *efx, __le64 value,
+                                 unsigned int reg)
+{
+       __raw_writeq((__force u64)value, efx->membase + reg);
+}
+static inline __le64 _efx_readq(struct efx_nic *efx, unsigned int reg)
+{
+       return (__force __le64)__raw_readq(efx->membase + reg);
+}
+#endif
+
+static inline void _efx_writed(struct efx_nic *efx, __le32 value,
+                                 unsigned int reg)
+{
+       __raw_writel((__force u32)value, efx->membase + reg);
+}
+static inline __le32 _efx_readd(struct efx_nic *efx, unsigned int reg)
+{
+       return (__force __le32)__raw_readl(efx->membase + reg);
+}
+
+/* Writes to a normal 16-byte Efx register, locking as appropriate. */
+static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value,
+                             unsigned int reg)
+{
+       unsigned long flags __attribute__ ((unused));
+
+       EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
+                   EFX_OWORD_VAL(*value));
+
+       spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef EFX_USE_QWORD_IO
+       _efx_writeq(efx, value->u64[0], reg + 0);
+       wmb();
+       _efx_writeq(efx, value->u64[1], reg + 8);
+#else
+       _efx_writed(efx, value->u32[0], reg + 0);
+       _efx_writed(efx, value->u32[1], reg + 4);
+       _efx_writed(efx, value->u32[2], reg + 8);
+       wmb();
+       _efx_writed(efx, value->u32[3], reg + 12);
+#endif
+       mmiowb();
+       spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write an 8-byte NIC SRAM entry through the supplied mapping,
+ * locking as appropriate. */
+static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase,
+                                  efx_qword_t *value, unsigned int index)
+{
+       unsigned int addr = index * sizeof(*value);
+       unsigned long flags __attribute__ ((unused));
+
+       EFX_REGDUMP(efx, "writing SRAM address %x with " EFX_QWORD_FMT "\n",
+                   addr, EFX_QWORD_VAL(*value));
+
+       spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef EFX_USE_QWORD_IO
+       __raw_writeq((__force u64)value->u64[0], membase + addr);
+#else
+       __raw_writel((__force u32)value->u32[0], membase + addr);
+       wmb();
+       __raw_writel((__force u32)value->u32[1], membase + addr + 4);
+#endif
+       mmiowb();
+       spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write dword to NIC register that allows partial writes
+ *
+ * Some registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
+ * TX_DESC_UPD_REG) can be written to as a single dword.  This allows
+ * for lockless writes.
+ */
+static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value,
+                             unsigned int reg)
+{
+       EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
+                   reg, EFX_DWORD_VAL(*value));
+
+       /* No lock required */
+       _efx_writed(efx, value->u32[0], reg);
+}
+
+/* Read from a NIC register
+ *
+ * This reads an entire 16-byte register in one go, locking as
+ * appropriate.  It is essential to read the first dword first, as this
+ * prompts the NIC to load the current value into the shadow register.
+ */
+static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value,
+                            unsigned int reg)
+{
+       unsigned long flags __attribute__ ((unused));
+
+       spin_lock_irqsave(&efx->biu_lock, flags);
+       value->u32[0] = _efx_readd(efx, reg + 0);
+       rmb();
+       value->u32[1] = _efx_readd(efx, reg + 4);
+       value->u32[2] = _efx_readd(efx, reg + 8);
+       value->u32[3] = _efx_readd(efx, reg + 12);
+       spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+       EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+                   EFX_OWORD_VAL(*value));
+}
+
+/* Read an 8-byte SRAM entry through supplied mapping,
+ * locking as appropriate. */
+static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase,
+                                 efx_qword_t *value, unsigned int index)
+{
+       unsigned int addr = index * sizeof(*value);
+       unsigned long flags __attribute__ ((unused));
+
+       spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef EFX_USE_QWORD_IO
+       value->u64[0] = (__force __le64)__raw_readq(membase + addr);
+#else
+       value->u32[0] = (__force __le32)__raw_readl(membase + addr);
+       rmb();
+       value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4);
+#endif
+       spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+       EFX_REGDUMP(efx, "read from SRAM address %x, got "EFX_QWORD_FMT"\n",
+                   addr, EFX_QWORD_VAL(*value));
+}
+
+/* Read dword from register that allows partial writes (sic) */
+static inline void efx_readd(struct efx_nic *efx, efx_dword_t *value,
+                               unsigned int reg)
+{
+       value->u32[0] = _efx_readd(efx, reg);
+       EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
+                   reg, EFX_DWORD_VAL(*value));
+}
+
+/* Write to a register forming part of a table */
+static inline void efx_writeo_table(struct efx_nic *efx, efx_oword_t *value,
+                                     unsigned int reg, unsigned int index)
+{
+       efx_writeo(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Read to a register forming part of a table */
+static inline void efx_reado_table(struct efx_nic *efx, efx_oword_t *value,
+                                    unsigned int reg, unsigned int index)
+{
+       efx_reado(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Write to a dword register forming part of a table */
+static inline void efx_writed_table(struct efx_nic *efx, efx_dword_t *value,
+                                      unsigned int reg, unsigned int index)
+{
+       efx_writed(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Page-mapped register block size */
+#define EFX_PAGE_BLOCK_SIZE 0x2000
+
+/* Calculate offset to page-mapped register block */
+#define EFX_PAGED_REG(page, reg) \
+       ((page) * EFX_PAGE_BLOCK_SIZE + (reg))
+
+/* As for efx_writeo(), but for a page-mapped register. */
+static inline void efx_writeo_page(struct efx_nic *efx, efx_oword_t *value,
+                                  unsigned int reg, unsigned int page)
+{
+       efx_writeo(efx, value, EFX_PAGED_REG(page, reg));
+}
+
+/* As for efx_writed(), but for a page-mapped register. */
+static inline void efx_writed_page(struct efx_nic *efx, efx_dword_t *value,
+                                  unsigned int reg, unsigned int page)
+{
+       efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+}
+
+/* Write dword to page-mapped register with an extra lock.
+ *
+ * As for efx_writed_page(), but for a register that suffers from
+ * SFC bug 3181. Take out a lock so the BIU collector cannot be
+ * confused. */
+static inline void efx_writed_page_locked(struct efx_nic *efx,
+                                         efx_dword_t *value,
+                                         unsigned int reg,
+                                         unsigned int page)
+{
+       unsigned long flags __attribute__ ((unused));
+
+       if (page == 0) {
+               spin_lock_irqsave(&efx->biu_lock, flags);
+               efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+               spin_unlock_irqrestore(&efx->biu_lock, flags);
+       } else {
+               efx_writed(efx, value, EFX_PAGED_REG(page, reg));
+       }
+}
+
+#endif /* EFX_IO_H */
diff --git a/drivers/net/sfc/ioctl.c b/drivers/net/sfc/ioctl.c
new file mode 100644 (file)
index 0000000..94af182
--- /dev/null
@@ -0,0 +1,70 @@
+/****************************************************************************
+ * Driver for Solarflare network controllers
+ *           (including support for SFE4001 10GBT NIC)
+ *
+ * Copyright 2005-2006: Fen Systems Ltd.
+ * Copyright 2005-2009: Solarflare Communications Inc,
+ *                      9501 Jeronimo Road, Suite 250,
+ *                      Irvine, CA 92618, USA
+ *
+ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
+ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ *
+ * 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 "efx.h"
+#include "efx_ioctl.h"
+#include "nic.h"
+
+static int
+efx_ioctl_reset_flags(struct efx_nic *efx, union efx_ioctl_data *data)
+{
+       return efx_ethtool_reset(efx->net_dev, &data->reset_flags.flags);
+}
+
+/*****************************************************************************/
+
+int efx_private_ioctl(struct efx_nic *efx, u16 cmd,
+                     union efx_ioctl_data __user *user_data)
+{
+       int (*op)(struct efx_nic *, union efx_ioctl_data *);
+       union efx_ioctl_data data;
+       size_t size;
+       int rc;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       switch (cmd) {
+       case EFX_RESET_FLAGS:
+               size = sizeof(data.reset_flags);
+               op = efx_ioctl_reset_flags;
+               break;
+       default:
+               EFX_ERR(efx, "unknown private ioctl cmd %x\n", cmd);
+               return -EOPNOTSUPP;
+       }
+
+       if (copy_from_user(&data, user_data, size))
+               return -EFAULT;
+       rc = op(efx, &data);
+       if (rc)
+               return rc;
+       if (copy_to_user(user_data, &data, size))
+               return -EFAULT;
+       return 0;
+}
+
index a41d9d3b5eb7be8cc9a92693c0906d299971e6ab..a0c37448fdb7426e80de35c1d23579d856420da6 100644 (file)
@@ -1,31 +1,16 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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 "net_driver.h"
+#define EFX_IN_KCOMPAT_C 1
+
+#include "efx.h"
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/random.h>
@@ -34,8 +19,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/bootmem.h>
 #include <asm/uaccess.h>
-#include "gmii.h"
-#include "ethtool.h"
 
 /*
  * Kernel backwards compatibility
  * This file provides functionality missing from earlier kernels.
  */
 
+/**************************************************************************
+ *
+ * unregister_netdevice_notifier : Has a race before 2.6.17
+ *
+ **************************************************************************
+ *
+ */
+
+#ifdef EFX_NEED_UNREGISTER_NETDEVICE_NOTIFIER_FIX
+/**
+ * efx_unregister_netdevice_notifier - fixed unregister_netdevice_notifier
+ * @nb:                notifier to unregister
+ *
+ * unregister_netdevice_notifier() does not wait for the notifier
+ * to be unused before 2.6.17.  This wrapper fixes that.
+ */
+int efx_unregister_netdevice_notifier(struct notifier_block *nb)
+{
+       int res;
+
+       res = unregister_netdevice_notifier(nb);
+       /* Ensure any outstanding calls complete. */
+       rtnl_lock();
+       rtnl_unlock();
+       return res;
+}
+#endif /* NEED_EFX_UNREGISTER_NETDEVICE_NOTIFIER */
+
+#ifdef EFX_NEED_COMPOUND_PAGE_FIX
+
+void efx_compound_page_destructor(struct page *page)
+{
+       /* Fake up page state to keep __free_pages happy */
+       set_page_count(page, 1);
+       page[1].mapping = NULL;
+
+       __free_pages(page, (unsigned long)page[1].index);
+}
+
+#endif /* NEED_COMPOUND_PAGE_FIX */
+
+/**************************************************************************
+ *
+ * print_hex_dump, taken from lib/hexdump.c.
+ *
+ **************************************************************************
+ *
+ */
+#ifdef EFX_NEED_HEX_DUMP
+
+#define hex_asc(x)     "0123456789abcdef"[x]
+#define isascii(c) (((unsigned char)(c))<=0x7f)
+
+static void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
+                              int groupsize, char *linebuf, size_t linebuflen,
+                              int ascii)
+{
+        const u8 *ptr = buf;
+        u8 ch;
+        int j, lx = 0;
+        int ascii_column;
+
+        if (rowsize != 16 && rowsize != 32)
+                rowsize = 16;
+
+        if (!len)
+                goto nil;
+        if (len > rowsize)              /* limit to one line at a time */
+                len = rowsize;
+        if ((len % groupsize) != 0)     /* no mixed size output */
+                groupsize = 1;
+
+        switch (groupsize) {
+        case 8: {
+                const u64 *ptr8 = buf;
+                int ngroups = len / groupsize;
+
+                for (j = 0; j < ngroups; j++)
+                        lx += scnprintf(linebuf + lx, linebuflen - lx,
+                               "%16.16llx ", (unsigned long long)*(ptr8 + j));
+                ascii_column = 17 * ngroups + 2;
+                break;
+        }
+
+        case 4: {
+                const u32 *ptr4 = buf;
+                int ngroups = len / groupsize;
+
+                for (j = 0; j < ngroups; j++)
+                        lx += scnprintf(linebuf + lx, linebuflen - lx,
+                               "%8.8x ", *(ptr4 + j));
+                ascii_column = 9 * ngroups + 2;
+                break;
+        }
+
+        case 2: {
+                const u16 *ptr2 = buf;
+                int ngroups = len / groupsize;
+
+                for (j = 0; j < ngroups; j++)
+                        lx += scnprintf(linebuf + lx, linebuflen - lx,
+                               "%4.4x ", *(ptr2 + j));
+                ascii_column = 5 * ngroups + 2;
+                break;
+        }
+
+        default:
+                for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
+                     j++) {
+                        ch = ptr[j];
+                        linebuf[lx++] = hex_asc(ch >> 4);
+                        linebuf[lx++] = hex_asc(ch & 0x0f);
+                        linebuf[lx++] = ' ';
+                }
+                ascii_column = 3 * rowsize + 2;
+                break;
+        }
+        if (!ascii)
+                goto nil;
+
+        while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
+                linebuf[lx++] = ' ';
+       /* Removed is_print() check */
+        for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
+                linebuf[lx++] = isascii(ptr[j]) ? ptr[j] : '.';
+nil:
+        linebuf[lx++] = '\0';
+}
+
+void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
+                   int rowsize, int groupsize,
+                   const void *buf, size_t len, int ascii)
+{
+        const u8 *ptr = buf;
+        int i, linelen, remaining = len;
+        char linebuf[200];
+
+        if (rowsize != 16 && rowsize != 32)
+                rowsize = 16;
+
+        for (i = 0; i < len; i += rowsize) {
+                linelen = min(remaining, rowsize);
+                remaining -= rowsize;
+                hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
+                                  linebuf, sizeof(linebuf), ascii);
+
+                switch (prefix_type) {
+                case DUMP_PREFIX_ADDRESS:
+                        printk("%s%s%*p: %s\n", level, prefix_str,
+                              (int)(2 * sizeof(void *)), ptr + i, linebuf);
+                        break;
+                case DUMP_PREFIX_OFFSET:
+                        printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
+                        break;
+                default:
+                        printk("%s%s%s\n", level, prefix_str, linebuf);
+                        break;
+                }
+        }
+}
+
+#endif /* EFX_NEED_HEX_DUMP */
+
 /**************************************************************************
  *
  * print_mac, from net/ethernet/eth.c in v2.6.24
  **************************************************************************
  *
  */
+#ifdef EFX_NEED_PRINT_MAC
 char *print_mac(char *buf, const u8 *addr)
 {
         sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
                 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
         return buf;
 }
+#endif /* EFX_NEED_PRINT_MAC */
 
 #ifdef EFX_NEED_CSUM_TCPUDP_NOFOLD
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+__wsum
+csum_tcpudp_nofold (__be32 saddr, __be32 daddr, unsigned short len,
+                   unsigned short proto, __wsum sum)
+#else
 __wsum
 csum_tcpudp_nofold (unsigned long saddr, unsigned long daddr,
                    unsigned short len, unsigned short proto, __wsum sum)
+#endif
 {
        unsigned long result;
 
@@ -76,3 +230,278 @@ csum_tcpudp_nofold (unsigned long saddr, unsigned long daddr,
 
 }
 #endif /* EFX_NEED_CSUM_TCPUDP_NOFOLD */
+
+#ifdef EFX_NEED_RANDOM_ETHER_ADDR
+/* Generate random MAC address */
+void efx_random_ether_addr(uint8_t *addr) {
+        get_random_bytes (addr, ETH_ALEN);
+       addr [0] &= 0xfe;       /* clear multicast bit */
+       addr [0] |= 0x02;       /* set local assignment bit (IEEE802) */
+}
+#endif /* EFX_NEED_RANDOM_ETHER_ADDR */
+
+#ifdef EFX_NEED_MSECS_TO_JIFFIES
+/*
+ * When we convert to jiffies then we interpret incoming values
+ * the following way:
+ *
+ * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET)
+ *
+ * - 'too large' values [that would result in larger than
+ *   MAX_JIFFY_OFFSET values] mean 'infinite timeout' too.
+ *
+ * - all other values are converted to jiffies by either multiplying
+ *   the input value by a factor or dividing it with a factor
+ *
+ * We must also be careful about 32-bit overflows.
+ */
+#ifndef MSEC_PER_SEC
+#define MSEC_PER_SEC   1000L
+#endif
+unsigned long msecs_to_jiffies(const unsigned int m)
+{
+       /*
+        * Negative value, means infinite timeout:
+        */
+       if ((int)m < 0)
+               return MAX_JIFFY_OFFSET;
+
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+       /*
+        * HZ is equal to or smaller than 1000, and 1000 is a nice
+        * round multiple of HZ, divide with the factor between them,
+        * but round upwards:
+        */
+       return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+       /*
+        * HZ is larger than 1000, and HZ is a nice round multiple of
+        * 1000 - simply multiply with the factor between them.
+        *
+        * But first make sure the multiplication result cannot
+        * overflow:
+        */
+       if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+               return MAX_JIFFY_OFFSET;
+
+       return m * (HZ / MSEC_PER_SEC);
+#else
+       /*
+        * Generic case - multiply, round and divide. But first
+        * check that if we are doing a net multiplication, that
+        * we wouldnt overflow:
+        */
+       if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
+               return MAX_JIFFY_OFFSET;
+
+       return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
+#endif
+}
+#endif /* EFX_NEED_MSECS_TO_JIFFIES */
+
+#ifdef EFX_NEED_MSLEEP
+/**
+ * msleep - sleep safely even with waitqueue interruptions
+ * @msecs: Time in milliseconds to sleep for
+ */
+void msleep(unsigned int msecs)
+{
+       unsigned long timeout = msecs_to_jiffies(msecs) + 1;
+
+       while (timeout)
+               timeout = schedule_timeout_uninterruptible(timeout);
+}
+#endif
+
+#ifdef EFX_USE_I2C_LEGACY
+
+struct i2c_client *i2c_new_device(struct i2c_adapter *adap,
+                                 struct i2c_board_info *info)
+{
+       return i2c_new_probed_device(adap, info, NULL);
+}
+
+struct i2c_client *i2c_new_probed_device(struct i2c_adapter *adap,
+                                        struct i2c_board_info *info,
+                                        const unsigned short *addr_list)
+{
+       int (*probe)(struct i2c_client *, const struct i2c_device_id *);
+       struct i2c_client *client;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (!client)
+               return NULL;
+
+       client->adapter = adap;
+       client->dev.platform_data = info->platform_data;
+       client->flags = info->flags;
+       client->addr = addr_list ? addr_list[0] : info->addr; /* FIXME */
+       strlcpy(client->name, info->type, sizeof client->name);
+
+       if (!strcmp(client->name, "sfc_lm87")) {
+               client->driver = &efx_lm87_driver;
+               probe = efx_lm87_probe;
+       } else if (!strcmp(client->name, "max6646") ||
+                  !strcmp(client->name, "max6647")) {
+               client->driver = &efx_lm90_driver;
+               probe = efx_lm90_probe;
+       } else {
+               BUG();
+               probe = NULL;
+       }
+
+       if (i2c_attach_client(client))
+               goto fail_client;
+
+       if (probe(client, NULL))
+               goto fail_attached;
+
+       return client;
+
+fail_attached:
+       i2c_detach_client(client);
+fail_client:
+       kfree(client);
+       return NULL;
+}
+
+void i2c_unregister_device(struct i2c_client *client)
+{
+       if (client->driver->detach_client) {
+               client->driver->detach_client(client);
+       } else {
+               if (!i2c_detach_client(client))
+                       kfree(client);
+       }
+}
+
+#endif /* EFX_USE_I2C_LEGACY */
+
+#ifdef EFX_NEED_I2C_NEW_DUMMY
+
+struct i2c_driver efx_i2c_dummy_driver = {
+#ifdef EFX_USE_I2C_DRIVER_NAME
+       .name = "sfc_i2c_dummy"
+#else
+       .driver.name = "sfc_i2c_dummy"
+#endif
+};
+
+struct i2c_client *efx_i2c_new_dummy(struct i2c_adapter *adap, u16 address)
+{
+       struct i2c_client *client;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (!client)
+               return NULL;
+
+       client->adapter = adap;
+       client->addr = address;
+       strcpy(client->name, efx_i2c_dummy_driver.driver.name);
+
+       client->driver = &efx_i2c_dummy_driver;
+
+       if (i2c_attach_client(client)) {
+               kfree(client);
+               return NULL;
+       }
+
+       return client;
+}
+
+#endif /* EFX_NEED_I2C_NEW_DUMMY */
+
+#ifdef EFX_NEED_PCI_CLEAR_MASTER
+
+void pci_clear_master(struct pci_dev *dev)
+{
+       u16 old_cmd, cmd;
+
+       pci_read_config_word(dev, PCI_COMMAND, &old_cmd);
+       cmd = old_cmd & ~PCI_COMMAND_MASTER;
+       if (cmd != old_cmd) {
+               dev_dbg(&dev->dev, "disabling bus mastering\n");
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       dev->is_busmaster = false;
+}
+
+#endif /* EFX_NEED_PCI_CLEAR_MASTER */
+
+
+#ifdef EFX_NEED_PCI_WAKE_FROM_D3
+
+#ifndef PCI_D3hot
+#define PCI_D3hot 3
+#endif
+
+int pci_wake_from_d3(struct pci_dev *dev, bool enable)
+{
+       /* We always support waking from D3hot on boards that do WoL,
+        * so no need to check capabilities */
+       return pci_enable_wake(dev, PCI_D3hot, enable);
+}
+
+#endif /* EFX_NEED_PCI_WAKE_FROM_D3 */
+
+#ifdef EFX_NEED_UNMASK_MSIX_VECTORS
+
+#ifdef EFX_HAVE_MSIX_TABLE_RESERVED
+
+void efx_unmask_msix_vectors(struct pci_dev *pci_dev)
+{
+       dev_dbg(&pci_dev->dev, "cannot unmask MSI-X interrupt\n");
+}
+
+#else
+
+#include <linux/pci_regs.h>
+
+#define PCI_MSIX_TABLE         4
+#define PCI_MSIX_PBA           8
+#define  PCI_MSIX_BIR          0x7
+
+void efx_unmask_msix_vectors(struct pci_dev *pci_dev)
+{
+       struct efx_nic *efx = pci_get_drvdata(pci_dev);
+       resource_size_t membase_phys;
+       void __iomem *membase;
+       int msix, offset, bar, length, i;
+       u32 dword, mask;
+
+       if (efx->interrupt_mode != EFX_INT_MODE_MSIX)
+               return;
+
+       /* Find the location (bar, offset) of the MSI-X table */
+       msix = pci_find_capability(pci_dev, PCI_CAP_ID_MSIX);
+       if (!msix)
+               return;
+       pci_read_config_dword(pci_dev, msix + PCI_MSIX_TABLE, &dword);
+       bar = dword & PCI_MSIX_BIR;
+       offset = dword & ~PCI_MSIX_BIR;
+
+       /* Map enough of the table for all our interrupts */
+       membase_phys = pci_resource_start(pci_dev, bar);
+       length = efx->n_channels * 0x10;
+       membase = ioremap_nocache(membase_phys + offset, length);
+       if (!membase) {
+               dev_dbg(&pci_dev->dev, "failed to remap MSI-X table\n");
+               return;
+       }
+
+       /* Unmask every vector */
+       for (i = 0; i < efx->n_channels; i++) {
+               offset = (i << 4) + 0xc;
+               mask = readl(membase + offset);
+               writel(mask & ~0x1, membase + offset);
+               dev_dbg(&pci_dev->dev, "writing value %d for channel %d\n",
+                       mask & ~0x1, i);
+       }
+
+       /* Release the mapping */
+       iounmap(membase);
+}
+
+#endif /* EFX_HAVE_MSIX_TABLE_RESERVED */
+
+#endif /* EFX_NEED_UNMASK_MSIX_VECTORS */
index df699fdc58a546cf0d20597b86b4e1d00e87ae9f..a59bafd7807afc18486fa9641d290c28f8c8f982 100644 (file)
@@ -1,34 +1,18 @@
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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_KERNEL_COMPAT_H
 #define EFX_KERNEL_COMPAT_H
 
 #include <linux/version.h>
+#include <linux/autoconf.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/i2c.h>
+#include <linux/sysfs.h>
+#include <linux/stringify.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+
+/**************************************************************************
+ *
+ * Autoconf compatability
+ *
+ **************************************************************************/
+
+#include "autocompat.h"
 
-/*
- * Kernel backwards compatibility
+/**************************************************************************
+ *
+ * Version/config/architecture compatability.
  *
- * This file provides macros to facilitate backporting the driver.
+ **************************************************************************
+ *
+ * The preferred kernel compatability mechanism is through the autoconf
+ * layer above. For compatability fixes that are safe to apply to any kernel
+ * version, or those that are impossible (or slow) to determine in autconf,
+ * it is acceptable to have a version check here.
  */
 
-#ifdef __ia64__
-       /* csum_tcpudp_nofold() is extern but not exported */
-       #define EFX_NEED_CSUM_TCPUDP_NOFOLD yes
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
+       #error "This kernel version is now unsupported"
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
+       #define EFX_HAVE_MSIX_TABLE_RESERVED yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
+       #define EFX_HAVE_WORKQUEUE_NAME_LIMIT yes
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) || defined(CONFIG_HUGETLB_PAGE)
+       #define EFX_USE_COMPOUND_PAGES yes
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) && defined(EFX_USE_COMPOUND_PAGES)
+       #define EFX_NEED_COMPOUND_PAGE_FIX
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+       #define EFX_NEED_UNREGISTER_NETDEVICE_NOTIFIER_FIX yes
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+       #define EFX_USE_GSO_SIZE_FOR_MSS yes
+#else
+       #define EFX_HAVE_NONCONST_ETHTOOL_OPS yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+       #define EFX_USE_FASTCALL yes
 #endif
+
+/* debugfs only supports sym-links from 2.6.21 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) && defined(CONFIG_DEBUG_FS)
+       #define EFX_USE_DEBUGFS yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+       #define EFX_NEED_BONDING_HACKS yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+       #define EFX_NEED_LM87_DRIVER yes
+       #define EFX_NEED_LM90_DRIVER yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
+       #define EFX_USE_NET_DEVICE_LAST_RX yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
+       #define EFX_USE_NET_DEVICE_TRANS_START yes
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+       #ifdef EFX_HAVE_LINUX_MDIO_H
+               /* mdio module has some bugs in pause frame advertising */
+               #define EFX_NEED_MDIO45_FLOW_CONTROL_HACKS yes
+       #endif
+#endif
+
 #ifdef CONFIG_PPC64
        /* __raw_writel and friends are broken on ppc64 */
        #define EFX_NEED_RAW_READ_AND_WRITE_FIX yes
 #endif
 
-typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *);
+/**************************************************************************
+ *
+ * Definitions of missing constants, types, functions and macros
+ *
+ **************************************************************************
+ *
+ */
+
+#ifndef spin_trylock_irqsave
+       #define spin_trylock_irqsave(lock, flags)       \
+       ({                                              \
+               local_irq_save(flags);                  \
+               spin_trylock(lock) ?                    \
+               1 : ({local_irq_restore(flags); 0;});   \
+       })
+#endif
+
+#ifndef raw_smp_processor_id
+       #define raw_smp_processor_id() (current_thread_info()->cpu)
+#endif
+
+#ifndef NETIF_F_GEN_CSUM
+       #define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
+#endif
+#ifndef NETIF_F_V4_CSUM
+       #define NETIF_F_V4_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
+#endif
+#ifndef NETIF_F_V6_CSUM
+       #define NETIF_F_V6_CSUM  NETIF_F_GEN_CSUM
+#endif
+#ifndef NETIF_F_ALL_CSUM
+       #define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
+#endif
+
+/* Cope with small changes in PCI constants between minor kernel revisions */
+#if PCI_X_STATUS != 4
+       #undef PCI_X_STATUS
+       #define PCI_X_STATUS 4
+       #undef PCI_X_STATUS_MAX_SPLIT
+       #define PCI_X_STATUS_MAX_SPLIT 0x03800000
+#endif
+
+#ifndef __GFP_COMP
+       #define __GFP_COMP 0
+#endif
+
+#ifndef __iomem
+       #define __iomem
+#endif
+
+#ifndef NET_IP_ALIGN
+       #define NET_IP_ALIGN 2
+#endif
+
+#ifndef PCI_EXP_FLAGS
+       #define PCI_EXP_FLAGS           2       /* Capabilities register */
+       #define PCI_EXP_FLAGS_TYPE      0x00f0  /* Device/Port type */
+       #define  PCI_EXP_TYPE_ENDPOINT  0x0     /* Express Endpoint */
+       #define  PCI_EXP_TYPE_LEG_END   0x1     /* Legacy Endpoint */
+       #define  PCI_EXP_TYPE_ROOT_PORT 0x4     /* Root Port */
+#endif
+
+#ifndef PCI_EXP_DEVCAP
+       #define PCI_EXP_DEVCAP          4       /* Device capabilities */
+       #define  PCI_EXP_DEVCAP_PAYLOAD 0x07    /* Max_Payload_Size */
+       #define  PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
+       #define  PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
+#endif
+
+#ifndef PCI_EXP_DEVCTL
+       #define PCI_EXP_DEVCTL          8       /* Device Control */
+       #define  PCI_EXP_DEVCTL_PAYLOAD 0x00e0  /* Max_Payload_Size */
+       #define  PCI_EXP_DEVCTL_READRQ  0x7000  /* Max_Read_Request_Size */
+#endif
+
+#ifndef PCI_EXP_LNKSTA
+       #define PCI_EXP_LNKSTA          18      /* Link Status */
+#endif
+#ifndef PCI_EXP_LNKSTA_CLS
+       #define  PCI_EXP_LNKSTA_CLS     0x000f  /* Current Link Speed */
+#endif
+#ifndef PCI_EXP_LNKSTA_NLW
+       #define  PCI_EXP_LNKSTA_NLW     0x03f0  /* Nogotiated Link Width */
+#endif
+
+#ifndef NETDEV_TX_OK
+       #define NETDEV_TX_OK 0
+#endif
+
+#ifndef NETDEV_TX_BUSY
+       #define NETDEV_TX_BUSY 1
+#endif
+
+#ifndef __force
+       #define __force
+#endif
+
+#if ! defined(for_each_cpu_mask) && ! defined(CONFIG_SMP)
+       #define for_each_cpu_mask(cpu, mask)            \
+               for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
+#endif
+
+#ifndef IRQF_PROBE_SHARED
+       #ifdef SA_PROBEIRQ
+               #define IRQF_PROBE_SHARED  SA_PROBEIRQ
+       #else
+               #define IRQF_PROBE_SHARED  0
+       #endif
+#endif
+
+#ifndef IRQF_SHARED
+       #define IRQF_SHARED        SA_SHIRQ
+#endif
+
+#ifndef mmiowb
+       #if defined(__i386__) || defined(__x86_64__)
+               #define mmiowb()
+       #elif defined(__ia64__)
+               #ifndef ia64_mfa
+                       #define ia64_mfa() asm volatile ("mf.a" ::: "memory")
+               #endif
+               #define mmiowb ia64_mfa
+       #else
+               #error "Need definition for mmiowb()"
+       #endif
+#endif
+
+#ifndef CHECKSUM_PARTIAL
+       #define CHECKSUM_PARTIAL CHECKSUM_HW
+#endif
+
+#ifndef DMA_BIT_MASK
+       #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+#endif
+
+#if defined(__GNUC__) && !defined(inline)
+       #define inline inline __attribute__ ((always_inline))
+#endif
+
+#if defined(__GNUC__) && !defined(__packed)
+       #define __packed __attribute__((packed))
+#endif
+
+#ifndef DIV_ROUND_UP
+       #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#endif
+
+#ifndef __ATTR
+       #define __ATTR(_name,_mode,_show,_store) {                      \
+               .attr = {.name = __stringify(_name), .mode = _mode },   \
+               .show   = _show,                                        \
+               .store  = _store,                                       \
+       }
+#endif
+
+#ifndef DEVICE_ATTR
+       #define DEVICE_ATTR(_name, _mode, _show, _store)                \
+               struct device_attribute dev_attr_ ## _name =            \
+                       __ATTR(_name, _mode, _show, _store)
+#endif
+
+#ifndef to_i2c_adapter
+       #define to_i2c_adapter dev_to_i2c_adapter
+#endif
+
+#if defined(CONFIG_X86) && !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+       #define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#endif
+
+#ifndef BUILD_BUG_ON_ZERO
+       #define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
+#endif
+
+#ifndef __bitwise
+       #define __bitwise
+#endif
+
+#ifdef EFX_NEED_ATOMIC_CMPXCHG
+       #define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#endif
+
+/**************************************************************************/
+
+#ifdef EFX_NEED_IRQ_HANDLER_T
+       typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *);
+#endif
+
+/* linux_mdio.h needs this */
+#ifdef EFX_NEED_BOOL
+       typedef _Bool bool;
+       enum { false, true };
+#endif
+
+#ifdef EFX_HAVE_LINUX_MDIO_H
+       #include <linux/mdio.h>
+#else
+       #include "linux_mdio.h"
+#endif
+
+#ifdef EFX_NEED_MII_CONSTANTS
+       #define BMCR_SPEED1000          0x0040
+       #define ADVERTISE_PAUSE_ASYM    0x0800
+       #define ADVERTISE_PAUSE_CAP     0x0400
+#endif
+
+#ifdef EFX_NEED_ETHTOOL_CONSTANTS
+       #define ADVERTISED_Pause        (1 << 13)
+       #define ADVERTISED_Asym_Pause   (1 << 14)
+#endif
+
+#ifndef EFX_HAVE_ETHTOOL_RESET
+       enum ethtool_reset_flags {
+               /* These flags represent components dedicated to the interface
+                * the command is addressed to.  Shift any flag left by
+                * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+                * same type.
+                */
+               ETH_RESET_MGMT          = 1 << 0,       /* Management processor */
+               ETH_RESET_IRQ           = 1 << 1,       /* Interrupt requester */
+               ETH_RESET_DMA           = 1 << 2,       /* DMA engine */
+               ETH_RESET_FILTER        = 1 << 3,       /* Filtering/flow direction */
+               ETH_RESET_OFFLOAD       = 1 << 4,       /* Protocol offload */
+               ETH_RESET_MAC           = 1 << 5,       /* Media access controller */
+               ETH_RESET_PHY           = 1 << 6,       /* Transceiver/PHY */
+               ETH_RESET_RAM           = 1 << 7,       /* RAM shared between
+                                                        * multiple components */
+
+               ETH_RESET_DEDICATED     = 0x0000ffff,   /* All components dedicated to
+                                                        * this interface */
+               ETH_RESET_ALL           = 0xffffffff,   /* All components used by this
+                                                        * interface, even if shared */
+       };
+       #define ETH_RESET_SHARED_SHIFT  16
+#endif
+
+#ifndef FLOW_CTRL_TX
+       #define FLOW_CTRL_TX            0x01
+       #define FLOW_CTRL_RX            0x02
+#endif
+
+#ifdef EFX_NEED_MII_RESOLVE_FLOWCTRL_FDX
+       /**
+        * mii_resolve_flowctrl_fdx
+        * @lcladv: value of MII ADVERTISE register
+        * @rmtadv: value of MII LPA register
+        *
+        * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3
+        */
+       static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
+       {
+               u8 cap = 0;
+
+               if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) {
+                       cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+               } else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) {
+                       if (lcladv & ADVERTISE_PAUSE_CAP)
+                               cap = FLOW_CTRL_RX;
+                       else if (rmtadv & ADVERTISE_PAUSE_CAP)
+                               cap = FLOW_CTRL_TX;
+               }
+
+               return cap;
+       }
+#endif
+
+#ifdef EFX_NEED_MII_ADVERTISE_FLOWCTRL
+       /**
+        * mii_advertise_flowctrl - get flow control advertisement flags
+        * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
+        */
+       static inline u16 mii_advertise_flowctrl(int cap)
+       {
+               u16 adv = 0;
+
+               if (cap & FLOW_CTRL_RX)
+                       adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+               if (cap & FLOW_CTRL_TX)
+                       adv ^= ADVERTISE_PAUSE_ASYM;
+
+               return adv;
+       }
+#endif
+
+#ifndef PORT_OTHER
+       #define PORT_OTHER              0xff
+#endif
+
+#ifndef SUPPORTED_Pause
+       #define SUPPORTED_Pause                 (1 << 13)
+       #define SUPPORTED_Asym_Pause            (1 << 14)
+#endif
+
+#ifndef SUPPORTED_Backplane
+       #define SUPPORTED_Backplane             (1 << 16)
+       #define SUPPORTED_1000baseKX_Full       (1 << 17)
+       #define SUPPORTED_10000baseKX4_Full     (1 << 18)
+       #define SUPPORTED_10000baseKR_Full      (1 << 19)
+       #define SUPPORTED_10000baseR_FEC        (1 << 20)
+#endif
+
+#ifdef EFX_NEED_SKB_HEADER_MACROS
+       #define skb_mac_header(skb)     ((skb)->mac.raw)
+       #define skb_network_header(skb) ((skb)->nh.raw)
+       #define skb_tail_pointer(skb)   ((skb)->tail)
+#endif
+
+#ifdef EFX_NEED_ETH_HDR
+       #define eth_hdr(skb)            ((struct ethhdr *)skb_mac_header(skb))
+#endif
 
-#define skb_mac_header(skb)    (skb)->mac.raw
-#define skb_network_header(skb) (skb)->nh.raw
-#define eth_hdr(skb)           ((struct ethhdr *)skb_mac_header(skb))
-#define tcp_hdr(skb)           (skb)->h.th
-#define ip_hdr(skb)            (skb)->nh.iph
-#define skb_tail_pointer(skb)   (skb)->tail
+#ifdef EFX_NEED_TCP_HDR
+       #define tcp_hdr(skb)            ((skb)->h.th)
+#endif
 
+#ifdef EFX_NEED_IP_HDR
+       #define ip_hdr(skb)             ((skb)->nh.iph)
+#endif
+
+#ifdef EFX_NEED_IPV6_HDR
+       #define ipv6_hdr(skb)           ((skb)->nh.ipv6h)
+#endif
 
 #ifdef EFX_NEED_RAW_READ_AND_WRITE_FIX
        #include <asm/io.h>
@@ -125,60 +499,725 @@ typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *);
        #define __raw_readq efx_raw_readq
 #endif
 
-typedef u32 __wsum;
-#define csum_unfold(x) ((__force __wsum) x)
+#ifdef EFX_NEED_SCHEDULE_TIMEOUT_INTERRUPTIBLE
+       static inline signed long
+       schedule_timeout_interruptible(signed long timeout)
+       {
+               set_current_state(TASK_INTERRUPTIBLE);
+               return schedule_timeout(timeout);
+       }
+#endif
+
+#ifdef EFX_NEED_SCHEDULE_TIMEOUT_UNINTERRUPTIBLE
+       static inline signed long
+       schedule_timeout_uninterruptible(signed long timeout)
+       {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               return schedule_timeout(timeout);
+       }
+#endif
+
+#ifdef EFX_NEED_KZALLOC
+       static inline void *kzalloc(size_t size, int flags)
+       {
+               void *buf = kmalloc(size, flags);
+               if (buf)
+                       memset(buf, 0,size);
+               return buf;
+       }
+#endif
+
+#ifdef EFX_NEED_SETUP_TIMER
+       static inline void setup_timer(struct timer_list * timer,
+                                      void (*function)(unsigned long),
+                                      unsigned long data)
+       {
+               timer->function = function;
+               timer->data = data;
+               init_timer(timer);
+       }
+#endif
+
+#ifdef EFX_NEED_MUTEX
+       #define EFX_DEFINE_MUTEX(x) DECLARE_MUTEX(x)
+       #undef DEFINE_MUTEX
+       #define DEFINE_MUTEX EFX_DEFINE_MUTEX
+
+       #define efx_mutex semaphore
+       #undef mutex
+       #define mutex efx_mutex
+
+       #define efx_mutex_init(x) init_MUTEX(x)
+       #undef mutex_init
+       #define mutex_init efx_mutex_init
+
+       #define efx_mutex_destroy(x) do { } while(0)
+       #undef mutex_destroy
+       #define mutex_destroy efx_mutex_destroy
+
+       #define efx_mutex_lock(x) down(x)
+       #undef mutex_lock
+       #define mutex_lock efx_mutex_lock
+
+       #define efx_mutex_lock_interruptible(x) down_interruptible(x)
+       #undef mutex_lock_interruptible
+       #define mutex_lock_interruptible efx_mutex_lock_interruptible
+
+       #define efx_mutex_unlock(x) up(x)
+       #undef mutex_unlock
+       #define mutex_unlock efx_mutex_unlock
+
+       #define efx_mutex_trylock(x) (!down_trylock(x))
+       #undef mutex_trylock
+       #define mutex_trylock efx_mutex_trylock
+
+       static inline int efx_mutex_is_locked(struct efx_mutex *m)
+       {
+               /* NB. This is quite inefficient, but it's the best we
+                * can do with the semaphore API. */
+               if ( down_trylock(m) )
+                       return 1;
+               /* Undo the effect of down_trylock. */
+               up(m);
+               return 0;
+       }
+       #undef mutex_is_locked
+       #define mutex_is_locked efx_mutex_is_locked
+#endif
+
+#ifndef NETIF_F_GSO
+       #define efx_gso_size tso_size
+       #undef gso_size
+       #define gso_size efx_gso_size
+       #define efx_gso_segs tso_segs
+       #undef gso_segs
+       #define gso_segs efx_gso_segs
+#endif
+
+#ifdef EFX_NEED_NETDEV_ALLOC_SKB
+       #ifndef NET_SKB_PAD
+               #define NET_SKB_PAD 16
+       #endif
+
+       static inline
+       struct sk_buff *netdev_alloc_skb(struct net_device *dev,
+                                        unsigned int length)
+       {
+               struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD,
+                                               GFP_ATOMIC | __GFP_COLD);
+               if (likely(skb)) {
+                       skb_reserve(skb, NET_SKB_PAD);
+                       skb->dev = dev;
+               }
+               return skb;
+       }
+#endif
+
+#ifdef EFX_NEED_NETDEV_TX_T
+       typedef int netdev_tx_t;
+#endif
+
+#ifdef EFX_HAVE_NONCONST_ETHTOOL_OPS
+       #undef SET_ETHTOOL_OPS
+       #define SET_ETHTOOL_OPS(netdev, ops)                            \
+               ((netdev)->ethtool_ops = (struct ethtool_ops *)(ops))
+#endif
+
+#ifdef EFX_NEED_RTNL_TRYLOCK
+       static inline int rtnl_trylock(void) {
+               return !rtnl_shlock_nowait();
+       }
+#endif
+
+#ifdef EFX_NEED_NETIF_TX_LOCK
+       static inline void netif_tx_lock(struct net_device *dev)
+       {
+               spin_lock(&dev->xmit_lock);
+               dev->xmit_lock_owner = smp_processor_id();
+       }
+       static inline void netif_tx_lock_bh(struct net_device *dev)
+       {
+               spin_lock_bh(&dev->xmit_lock);
+               dev->xmit_lock_owner = smp_processor_id();
+       }
+       static inline void netif_tx_unlock_bh(struct net_device *dev)
+       {
+               dev->xmit_lock_owner = -1;
+               spin_unlock_bh(&dev->xmit_lock);
+       }
+       static inline void netif_tx_unlock(struct net_device *dev)
+       {
+               dev->xmit_lock_owner = -1;
+               spin_unlock(&dev->xmit_lock);
+       }
+#endif
+
+#ifdef EFX_NEED_NETIF_ADDR_LOCK
+       static inline void netif_addr_lock(struct net_device *dev)
+       {
+               netif_tx_lock(dev);
+       }
+       static inline void netif_addr_lock_bh(struct net_device *dev)
+       {
+               netif_tx_lock_bh(dev);
+       }
+       static inline void netif_addr_unlock_bh(struct net_device *dev)
+       {
+               netif_tx_unlock_bh(dev);
+       }
+       static inline void netif_addr_unlock(struct net_device *dev)
+       {
+               netif_tx_unlock(dev);
+       }
+#endif
+
+#ifdef EFX_NEED_DEV_GET_STATS
+       static inline const struct net_device_stats *
+       dev_get_stats(struct net_device *dev)
+       {
+               return dev->get_stats(dev);
+       }
+#endif
+
+#ifdef EFX_HAVE_OLD_IP_FAST_CSUM
+       #define ip_fast_csum(iph, ihl) ip_fast_csum((unsigned char *)iph, ihl)
+#endif
+
+#ifdef EFX_HAVE_OLD_CSUM
+       typedef u16 __sum16;
+       typedef u32 __wsum;
+       #define csum_unfold(x) ((__force __wsum) x)
+#endif
+
+#ifdef EFX_NEED_HEX_DUMP
+       enum {
+               DUMP_PREFIX_NONE,
+               DUMP_PREFIX_ADDRESS,
+               DUMP_PREFIX_OFFSET
+       };
+#endif
+
+#ifndef DECLARE_MAC_BUF
+       #define DECLARE_MAC_BUF(var) char var[18] __attribute__((unused))
+#endif
+
+#ifdef EFX_NEED_GFP_T
+       typedef unsigned int gfp_t;
+#endif
+
+#ifdef EFX_NEED_SAFE_LISTS
+       #define list_for_each_entry_safe_reverse(pos, n, head, member)       \
+               for (pos = list_entry((head)->prev, typeof(*pos), member),   \
+                    n = list_entry(pos->member.prev, typeof(*pos), member); \
+                    &pos->member != (head);                                 \
+                    pos = n,                                                \
+                    n = list_entry(n->member.prev, typeof(*n), member))
+#endif
+
+#ifdef EFX_NEED_DEV_NOTICE
+       #define dev_notice dev_warn
+#endif
+
+#ifdef EFX_NEED_IF_MII
+       #include <linux/mii.h>
+       static inline struct mii_ioctl_data *efx_if_mii ( struct ifreq *rq ) {
+               return ( struct mii_ioctl_data * ) &rq->ifr_ifru;
+       }
+       #undef if_mii
+       #define if_mii efx_if_mii
+#endif
+
+#ifdef EFX_NEED_MTD_ERASE_CALLBACK
+       #include <linux/mtd/mtd.h>
+       static inline void efx_mtd_erase_callback(struct erase_info *instr) {
+               if ( instr->callback )
+                       instr->callback ( instr );
+       }
+       #undef mtd_erase_callback
+       #define mtd_erase_callback efx_mtd_erase_callback
+#endif
+
+#ifdef EFX_NEED_DUMMY_PCI_DISABLE_MSI
+       #include <linux/pci.h>
+       static inline void dummy_pci_disable_msi ( struct pci_dev *dev ) {
+               /* Do nothing */
+       }
+       #undef pci_disable_msi
+       #define pci_disable_msi dummy_pci_disable_msi
+#endif
 
-#define DECLARE_MAC_BUF(var) char var[18] __attribute__((unused))
-extern char *print_mac(char *buf, const u8 *addr);
+#ifdef EFX_NEED_DUMMY_MSIX
+       struct msix_entry {
+               u16     vector; /* kernel uses to write allocated vector */
+               u16     entry;  /* driver uses to specify entry, OS writes */
+       };
+       static inline int pci_enable_msix(struct pci_dev* dev,
+                                         struct msix_entry *entries, int nvec)
+               {return -1;}
+       static inline void pci_disable_msix(struct pci_dev *dev) { /* Do nothing */}
+#endif
+
+#ifdef EFX_NEED_BYTEORDER_TYPES
+       typedef __u16 __be16;
+       typedef __u32 __be32;
+       typedef __u64 __be64;
+       typedef __u16 __le16;
+       typedef __u32 __le32;
+       typedef __u64 __le64;
+#endif
+
+#ifdef EFX_NEED_RESOURCE_SIZE_T
+       typedef unsigned long resource_size_t;
+#endif
+
+#ifdef EFX_USE_I2C_LEGACY
+       struct i2c_board_info {
+               char type[I2C_NAME_SIZE];
+               unsigned short flags;
+               unsigned short addr;
+               void *platform_data;
+               int irq;
+       };
+       #define I2C_BOARD_INFO(dev_type, dev_addr) \
+               .type = (dev_type), .addr = (dev_addr)
+       struct i2c_client *
+       i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info *info);
+       struct i2c_client *
+       i2c_new_probed_device(struct i2c_adapter *adap,
+                             struct i2c_board_info *info,
+                             const unsigned short *addr_list);
+       void i2c_unregister_device(struct i2c_client *);
+       struct i2c_device_id;
+#endif
+
+#ifdef EFX_NEED_I2C_NEW_DUMMY
+       extern struct i2c_driver efx_i2c_dummy_driver;
+       struct i2c_client *
+       efx_i2c_new_dummy(struct i2c_adapter *adap, u16 address);
+       #undef i2c_new_dummy
+       #define i2c_new_dummy efx_i2c_new_dummy
+#endif
+
+#ifdef EFX_HAVE_OLD_I2C_NEW_DUMMY
+       static inline struct i2c_client *
+       efx_i2c_new_dummy(struct i2c_adapter *adap, u16 address)
+       {
+               return i2c_new_dummy(adap, address, "dummy");
+       }
+       #undef i2c_new_dummy
+       #define i2c_new_dummy efx_i2c_new_dummy
+#endif
+
+#ifdef EFX_NEED_I2C_LOCK_ADAPTER
+       #ifdef EFX_USE_I2C_BUS_SEMAPHORE
+               static inline void i2c_lock_adapter(struct i2c_adapter *adap)
+               {
+                       down(&adap->bus_lock);
+               }
+               static inline void i2c_unlock_adapter(struct i2c_adapter *adap)
+               {
+                       up(&adap->bus_lock);
+               }
+       #else
+               static inline void i2c_lock_adapter(struct i2c_adapter *adap)
+               {
+                       mutex_lock(&adap->bus_lock);
+               }
+               static inline void i2c_unlock_adapter(struct i2c_adapter *adap)
+               {
+                       mutex_unlock(&adap->bus_lock);
+               }
+       #endif
+#endif
+
+#ifdef EFX_HAVE_OLD_PCI_DMA_MAPPING_ERROR
+       static inline int
+       efx_pci_dma_mapping_error(struct pci_dev *dev, dma_addr_t dma_addr)
+       {
+               return pci_dma_mapping_error(dma_addr);
+       }
+       #undef pci_dma_mapping_error
+       #define pci_dma_mapping_error efx_pci_dma_mapping_error
+#endif
+
+#ifdef EFX_NEED_FOR_EACH_PCI_DEV
+       #define for_each_pci_dev(d)                             \
+               while ((d = pci_get_device(PCI_ANY_ID,          \
+                       PCI_ANY_ID, d)) != NULL)
+#endif
+
+#ifdef EFX_NEED_LM87_DRIVER
+#ifdef EFX_HAVE_OLD_I2C_DRIVER_PROBE
+int efx_lm87_probe(struct i2c_client *client);
+#else
+int efx_lm87_probe(struct i2c_client *client, const struct i2c_device_id *);
+#endif
+extern struct i2c_driver efx_lm87_driver;
+#endif
+
+#ifdef EFX_NEED_LM90_DRIVER
+#ifdef EFX_HAVE_OLD_I2C_DRIVER_PROBE
+int efx_lm90_probe(struct i2c_client *client);
+#else
+int efx_lm90_probe(struct i2c_client *client, const struct i2c_device_id *);
+#endif
+extern struct i2c_driver efx_lm90_driver;
+#endif
+
+#ifdef EFX_NEED_WAIT_EVENT_TIMEOUT
+#define __wait_event_timeout(wq, condition, ret)                        \
+do {                                                                    \
+        DEFINE_WAIT(__wait);                                            \
+                                                                        \
+        for (;;) {                                                      \
+                prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
+                if (condition)                                          \
+                        break;                                          \
+                ret = schedule_timeout(ret);                            \
+                if (!ret)                                               \
+                        break;                                          \
+        }                                                               \
+        finish_wait(&wq, &__wait);                                      \
+} while (0)
 
 /**
- * queue_delayed_work in pre 2.6.20 can't rearm from inside
- * the work member. So instead do a rather hacky sleep
+ * wait_event_timeout - sleep until a condition gets true or a timeout elapses
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the
+ * @condition evaluates to true. The @condition is checked each time
+ * the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * The function returns 0 if the @timeout elapsed, and the remaining
+ * jiffies if the condition evaluated to true before the timeout elapsed.
  */
-#define delayed_work work_struct
-#define INIT_DELAYED_WORK INIT_WORK
-
-static int inline efx_queue_delayed_work(struct workqueue_struct *wq,
-                                        struct work_struct *work,
-                                        unsigned long delay)
-{
-       if (unlikely(delay > 0))
-               schedule_timeout_uninterruptible(delay);
-       return queue_work(wq, work);
-}
-#define queue_delayed_work efx_queue_delayed_work
+#define wait_event_timeout(wq, condition, timeout)                      \
+({                                                                      \
+        long __ret = timeout;                                           \
+        if (!(condition))                                               \
+                __wait_event_timeout(wq, condition, __ret);             \
+        __ret;                                                          \
+})
+#endif
 
-/**
- * The old and new work-function prototypes just differ
- * in the type of the pointer returned, so it's safe
- * to cast between the prototypes.
+/**************************************************************************
+ *
+ * Missing functions provided by kernel_compat.c
+ *
+ **************************************************************************
+ *
  */
-typedef void (*efx_old_work_func_t)(void *p);
-
-#undef INIT_WORK
-#define INIT_WORK(_work, _func)                                        \
-       do {                                                    \
-               INIT_LIST_HEAD(&(_work)->entry);                \
-               (_work)->pending = 0;                           \
-               PREPARE_WORK((_work),                           \
-                            (efx_old_work_func_t) (_func),     \
-                            (_work));                          \
-       } while (0)
-
-#define napi_str napi_dev[0]
-
-static inline void netif_napi_add(struct net_device *dev,
-                                 struct net_device *dummy,
-                                 int (*poll) (struct net_device *, int *),
-                                 int weight)
-{
-       dev->weight = weight;
-       dev->poll = poll;
-}
-
-#define napi_enable netif_poll_enable
-#define napi_disable netif_poll_disable
-
-#define netif_rx_complete(dev, dummy) netif_rx_complete(dev)
+#ifdef EFX_NEED_RANDOM_ETHER_ADDR
+       extern void efx_random_ether_addr(uint8_t *addr);
+       #ifndef EFX_IN_KCOMPAT_C
+               #undef random_ether_addr
+               #define random_ether_addr efx_random_ether_addr
+       #endif
+#endif
+
+#ifdef EFX_NEED_UNREGISTER_NETDEVICE_NOTIFIER_FIX
+       extern int efx_unregister_netdevice_notifier(struct notifier_block *nb);
+       #ifndef EFX_IN_KCOMPAT_C
+               #undef unregister_netdevice_notifier
+               #define unregister_netdevice_notifier \
+                               efx_unregister_netdevice_notifier
+       #endif
+#endif
+
+#ifdef EFX_NEED_PRINT_MAC
+       extern char *print_mac(char *buf, const u8 *addr);
+#endif
+
+#ifdef EFX_NEED_COMPOUND_PAGE_FIX
+       extern void efx_compound_page_destructor(struct page *page);
+#endif
+
+#ifdef EFX_NEED_HEX_DUMP
+       extern void
+       print_hex_dump(const char *level, const char *prefix_str,
+                      int prefix_type, int rowsize, int groupsize,
+                      const void *buf, size_t len, int ascii);
+#endif
+
+#ifdef EFX_NEED_PCI_CLEAR_MASTER
+       extern void pci_clear_master(struct pci_dev *dev);
+#endif
+
+#ifdef EFX_NEED_PCI_WAKE_FROM_D3
+       extern int pci_wake_from_d3(struct pci_dev *dev, bool enable);
+#endif
+
+#ifdef EFX_NEED_MSECS_TO_JIFFIES
+       extern unsigned long msecs_to_jiffies(const unsigned int m);
+#endif
+
+#ifdef EFX_NEED_MSLEEP
+       extern void msleep(unsigned int msecs);
+#endif
+
+#ifdef EFX_NEED_SSLEEP
+       static inline void ssleep(unsigned int seconds)
+       {
+               msleep(seconds * 1000);
+       }
+#endif
+
+#ifdef EFX_NEED_MDELAY
+       #include <linux/delay.h>
+       #undef mdelay
+       #define mdelay(_n)                              \
+               do {                                    \
+                       unsigned long __ms = _n;        \
+                       while (__ms--) udelay(1000);    \
+               } while (0);
+#endif
+
+#ifdef EFX_NEED_UNMASK_MSIX_VECTORS
+       extern void efx_unmask_msix_vectors(struct pci_dev *dev);
+#endif
+
+/**************************************************************************
+ *
+ * Wrappers to fix bugs and parameter changes
+ *
+ **************************************************************************
+ *
+ */
+#ifdef EFX_NEED_PCI_SAVE_RESTORE_WRAPPERS
+       #define pci_save_state(_dev)                                    \
+               pci_save_state(_dev, (_dev)->saved_config_space)
+
+       #define pci_restore_state(_dev)                                 \
+               pci_restore_state(_dev, (_dev)->saved_config_space)
+#endif
+
+#ifdef EFX_NEED_PCI_MATCH_ID
+       #define pci_match_id pci_match_device
+#endif
+
+#ifdef EFX_NEED_WORK_API_WRAPPERS
+       #define delayed_work work_struct
+       #define INIT_DELAYED_WORK INIT_WORK
+
+       /**
+        * The old and new work-function prototypes just differ
+        * in the type of the pointer returned, so it's safe
+        * to cast between the prototypes.
+        */
+       typedef void (*efx_old_work_func_t)(void *p);
+
+       #undef INIT_WORK
+       #define INIT_WORK(_work, _func)                                 \
+               do {                                                    \
+                       INIT_LIST_HEAD(&(_work)->entry);                \
+                       (_work)->pending = 0;                           \
+                       PREPARE_WORK((_work),                           \
+                                    (efx_old_work_func_t) (_func),     \
+                                    (_work));                          \
+                       init_timer(&(_work)->timer);                    \
+               } while (0)
+#endif
+
+#if defined(EFX_HAVE_OLD_NAPI)
+       #define napi_str napi_dev[0]
+
+       static inline void netif_napi_add(struct net_device *dev,
+                                         struct net_device *dummy,
+                                         int (*poll) (struct net_device *,
+                                                      int *),
+                                         int weight)
+       {
+               dev->weight = weight;
+               dev->poll = poll;
+       }
+       static inline void netif_napi_del(struct net_device *dev) {}
+
+       #define napi_enable netif_poll_enable
+       #define napi_disable netif_poll_disable
+       #define napi_complete netif_rx_complete
+
+       static inline void napi_schedule(struct net_device *dev)
+       {
+               if (!test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state))
+                       __netif_rx_schedule(dev);
+       }
+#elif defined(EFX_NEED_NETIF_NAPI_DEL)
+       static inline void netif_napi_del(struct napi_struct *napi)
+       {
+       #ifdef CONFIG_NETPOLL
+               list_del(&napi->dev_list);
+       #endif
+       }
+#endif
+
+#ifdef EFX_NEED_COMPOUND_PAGE_FIX
+       static inline
+       struct page *efx_alloc_pages(gfp_t flags, unsigned int order)
+       {
+               struct page *p = alloc_pages(flags, order);
+               if ((flags & __GFP_COMP) && (p != NULL) && (order > 0))
+                       p[1].mapping = (void *)efx_compound_page_destructor;
+               return p;
+       }
+       #undef alloc_pages
+       #define alloc_pages efx_alloc_pages
+
+       static inline
+       void efx_free_pages(struct page *p, unsigned int order)
+       {
+               if ((order > 0) && (page_count(p) == 1))
+                       p[1].mapping = NULL;
+               __free_pages(p, order);
+       }
+       #define __free_pages efx_free_pages
+#endif
+
+#ifdef EFX_NEED_HEX_DUMP_CONST_FIX
+       #define print_hex_dump(v,s,t,r,g,b,l,a) \
+               print_hex_dump((v),(s),(t),(r),(g),(void*)(b),(l),(a))
+#endif
+
+#ifndef EFX_HAVE_HWMON_H
+       static inline struct device *hwmon_device_register(struct device *dev)
+       {
+               return dev;
+       }
+       static inline void hwmon_device_unregister(struct device *cdev)
+       {
+       }
+#endif
+
+#ifdef EFX_NEED_HWMON_VID
+       #include <linux/i2c-vid.h>
+       static inline u8 efx_vid_which_vrm(void)
+       {
+               /* we don't use i2c on the cpu */
+               return 0;
+       }
+       #define vid_which_vrm efx_vid_which_vrm
+#endif
+
+#ifdef EFX_HAVE_OLD_DEVICE_ATTRIBUTE
+       /*
+        * show and store methods do not receive a pointer to the
+        * device_attribute.  We have to add wrapper functions.
+        */
+
+       #undef DEVICE_ATTR
+       #define DEVICE_ATTR(_name, _mode, _show, _store)                \
+               /*static*/ ssize_t __##_name##_##show(struct device *dev, \
+                                                     char *buf)        \
+               {                                                       \
+                       return _show(dev, NULL, buf);                   \
+               }                                                       \
+               static ssize_t __##_name##_##store(struct device *dev,  \
+                                                  const char *buf,     \
+                                                  size_t count)        \
+               {                                                       \
+                       ssize_t (*fn)(struct device *dev,               \
+                                     struct device_attribute *attr,    \
+                                     const char *buf,                  \
+                                     size_t count) = _store;           \
+                       return fn(dev, NULL, buf, count);               \
+               }                                                       \
+               static ssize_t __##_name##_##store(struct device *,     \
+                                                  const char *, size_t) \
+                       __attribute__((unused));                        \
+               static struct device_attribute dev_attr_##_name =       \
+                       __ATTR(_name, _mode, __##_name##_##show,        \
+                              __builtin_choose_expr                    \
+                              (__builtin_constant_p(_store) && _store == NULL, \
+                               NULL, __##_name##_##store))
+
+       struct sensor_device_attribute {
+               struct device_attribute dev_attr;
+               int index;
+       };
+
+       #define SENSOR_ATTR(_name, _mode, _show, _store, _index)        \
+       { .dev_attr = __ATTR(_name, _mode, _show, _store),              \
+         .index = _index }
+
+       #define SENSOR_DEVICE_ATTR(_name, _mode, _show, \
+                                  _store, _index)                      \
+               /*static*/ ssize_t __##_name##_show_##_index(struct device *dev, \
+                                                            char *buf) \
+               {                                                       \
+                       struct sensor_device_attribute attr;            \
+                       attr.index = _index;                            \
+                       return _show(dev, &attr.dev_attr, buf);         \
+               }                                                       \
+               static ssize_t __##_name##_store_##_index(struct device *dev, \
+                                                         const char *buf, \
+                                                         size_t count) \
+               {                                                       \
+                       ssize_t (*fn)(struct device *dev,               \
+                                     struct device_attribute *attr,    \
+                                     const char *buf,                  \
+                                     size_t count) = _store;           \
+                       struct sensor_device_attribute attr;            \
+                       attr.index = _index;                            \
+                       return fn(dev, &attr.dev_attr, buf, count);     \
+               }                                                       \
+               static ssize_t __##_name##_store_##_index(struct device *, \
+                                                         const char *, size_t) \
+                       __attribute__((unused));                        \
+               static struct sensor_device_attribute                   \
+                       sensor_dev_attr_##_name =                       \
+                       SENSOR_ATTR(_name, _mode,                       \
+                                   __##_name##_show_##_index,          \
+                                   __builtin_choose_expr               \
+                                   (__builtin_constant_p(_store) && _store == NULL, \
+                                    NULL, __##_name##_store_##_index), \
+                                   _index)
+
+       #define to_sensor_dev_attr(_dev_attr) \
+               container_of(_dev_attr, struct sensor_device_attribute, \
+                            dev_attr)
+
+#endif
+
+
+#ifdef EFX_NEED_SCSI_SGLIST
+       #include <scsi/scsi.h>
+       #include <scsi/scsi_cmnd.h>
+       #define scsi_sglist(sc)    ((struct scatterlist *)((sc)->request_buffer))
+       #define scsi_bufflen(sc)   ((sc)->request_bufflen)
+       #define scsi_sg_count(sc)  ((sc)->use_sg)
+       static inline void scsi_set_resid(struct scsi_cmnd *sc, int resid)
+       {
+               sc->resid = resid;
+       }
+       static inline int scsi_get_resid(struct scsi_cmnd *sc)
+       {
+               return sc->resid;
+       }
+#endif
+
+
+#ifdef EFX_NEED_SG_NEXT
+       #define sg_page(sg) ((sg)->page)
+       #define sg_next(sg) ((sg) + 1)
+       #define for_each_sg(sglist, sg, nr, __i) \
+         for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
+#endif
+
+#ifdef EFX_NEED_WARN_ON
+       #undef WARN_ON
+       #define WARN_ON(condition) ({                           \
+               typeof(condition) __ret_warn_on = (condition);  \
+               if (unlikely(__ret_warn_on)) {                  \
+                       printk("BUG: warning at %s:%d/%s()\n",  \
+                       __FILE__, __LINE__, __FUNCTION__);      \
+                               dump_stack();                   \
+               }                                               \
+               unlikely(__ret_warn_on);                        \
+       })
+#endif
 
 #endif /* EFX_KERNEL_COMPAT_H */
diff --git a/drivers/net/sfc/linux_mdio.c b/drivers/net/sfc/linux_mdio.c
new file mode 100644 (file)
index 0000000..c1bd9a3
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * mdio.c: Generic support for MDIO-compatible transceivers
+ * 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.
+ */
+
+#include "kernel_compat.h"
+
+#ifndef EFX_HAVE_LINUX_MDIO_H
+
+#include <linux/kernel.h>
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/ethtool.h>
+#include "linux_mdio.h"
+#include <linux/module.h>
+
+/**
+ * mdio45_probe - probe for an MDIO (clause 45) device
+ * @mdio: MDIO interface
+ * @prtad: Expected PHY address
+ *
+ * This sets @prtad and @mmds in the MDIO interface if successful.
+ * Returns 0 on success, negative on error.
+ */
+int mdio45_probe(struct mdio_if_info *mdio, int prtad)
+{
+       int mmd, stat2, devs1, devs2;
+
+       /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY
+        * XS or DTE XS; give up if none is present. */
+       for (mmd = 1; mmd <= 5; mmd++) {
+               /* Is this MMD present? */
+               stat2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_STAT2);
+               if (stat2 < 0 ||
+                   (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL)
+                       continue;
+
+               /* It should tell us about all the other MMDs */
+               devs1 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS1);
+               devs2 = mdio->mdio_read(mdio->dev, prtad, mmd, MDIO_DEVS2);
+               if (devs1 < 0 || devs2 < 0)
+                       continue;
+
+               mdio->prtad = prtad;
+               mdio->mmds = devs1 | (devs2 << 16);
+               return 0;
+       }
+
+       return -ENODEV;
+}
+/*EXPORT_SYMBOL(mdio45_probe);*/
+
+/**
+ * mdio_set_flag - set or clear flag in an MDIO register
+ * @mdio: MDIO interface
+ * @prtad: PHY address
+ * @devad: MMD address
+ * @addr: Register address
+ * @mask: Mask for flag (single bit set)
+ * @sense: New value of flag
+ *
+ * This debounces changes: it does not write the register if the flag
+ * already has the proper value.  Returns 0 on success, negative on error.
+ */
+int mdio_set_flag(const struct mdio_if_info *mdio,
+                 int prtad, int devad, u16 addr, int mask,
+                 bool sense)
+{
+       int old_val = mdio->mdio_read(mdio->dev, prtad, devad, addr);
+       int new_val;
+
+       if (old_val < 0)
+               return old_val;
+       if (sense)
+               new_val = old_val | mask;
+       else
+               new_val = old_val & ~mask;
+       if (old_val == new_val)
+               return 0;
+       return mdio->mdio_write(mdio->dev, prtad, devad, addr, new_val);
+}
+/*EXPORT_SYMBOL(mdio_set_flag);*/
+
+/**
+ * mdio_link_ok - is link status up/OK
+ * @mdio: MDIO interface
+ * @mmd_mask: Mask for MMDs to check
+ *
+ * Returns 1 if the PHY reports link status up/OK, 0 otherwise.
+ * @mmd_mask is normally @mdio->mmds, but if loopback is enabled
+ * the MMDs being bypassed should be excluded from the mask.
+ */
+int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmd_mask)
+{
+       int devad, reg;
+
+       if (!mmd_mask) {
+               /* Use absence of XGMII faults in lieu of link state */
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad,
+                                     MDIO_MMD_PHYXS, MDIO_STAT2);
+               return reg >= 0 && !(reg & MDIO_STAT2_RXFAULT);
+       }
+
+       for (devad = 0; mmd_mask; devad++) {
+               if (mmd_mask & (1 << devad)) {
+                       mmd_mask &= ~(1 << devad);
+
+                       /* Reset the latched status and fault flags */
+                       mdio->mdio_read(mdio->dev, mdio->prtad,
+                                       devad, MDIO_STAT1);
+                       if (devad == MDIO_MMD_PMAPMD || devad == MDIO_MMD_PCS ||
+                           devad == MDIO_MMD_PHYXS || devad == MDIO_MMD_DTEXS)
+                               mdio->mdio_read(mdio->dev, mdio->prtad,
+                                               devad, MDIO_STAT2);
+
+                       /* Check the current status and fault flags */
+                       reg = mdio->mdio_read(mdio->dev, mdio->prtad,
+                                             devad, MDIO_STAT1);
+                       if (reg < 0 ||
+                           (reg & (MDIO_STAT1_FAULT | MDIO_STAT1_LSTATUS)) !=
+                           MDIO_STAT1_LSTATUS)
+                               return false;
+               }
+       }
+
+       return true;
+}
+/*EXPORT_SYMBOL(mdio45_links_ok);*/
+
+/**
+ * mdio45_nway_restart - restart auto-negotiation for this interface
+ * @mdio: MDIO interface
+ *
+ * Returns 0 on success, negative on error.
+ */
+int mdio45_nway_restart(const struct mdio_if_info *mdio)
+{
+       if (!(mdio->mmds & MDIO_DEVS_AN))
+               return -EOPNOTSUPP;
+
+       mdio_set_flag(mdio, mdio->prtad, MDIO_MMD_AN, MDIO_CTRL1,
+                     MDIO_AN_CTRL1_RESTART, true);
+       return 0;
+}
+/*EXPORT_SYMBOL(mdio45_nway_restart);*/
+
+static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
+{
+       u32 result = 0;
+       int reg;
+
+       reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, addr);
+       if (reg & ADVERTISE_10HALF)
+               result |= ADVERTISED_10baseT_Half;
+       if (reg & ADVERTISE_10FULL)
+               result |= ADVERTISED_10baseT_Full;
+       if (reg & ADVERTISE_100HALF)
+               result |= ADVERTISED_100baseT_Half;
+       if (reg & ADVERTISE_100FULL)
+               result |= ADVERTISED_100baseT_Full;
+       if (reg & ADVERTISE_PAUSE_CAP)
+               result |= ADVERTISED_Pause;
+       if (reg & ADVERTISE_PAUSE_ASYM)
+               result |= ADVERTISED_Asym_Pause;
+       return result;
+}
+
+/**
+ * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET
+ * @mdio: MDIO interface
+ * @ecmd: Ethtool request structure
+ * @npage_adv: Modes currently advertised on next pages
+ * @npage_lpa: Modes advertised by link partner on next pages
+ *
+ * Since the CSRs for auto-negotiation using next pages are not fully
+ * standardised, this function does not attempt to decode them.  The
+ * caller must pass them in.
+ */
+void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
+                              struct ethtool_cmd *ecmd,
+                              u32 npage_adv, u32 npage_lpa)
+{
+       int reg;
+
+       ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->phy_address = mdio->prtad;
+       /*ecmd->mdio_support =
+               mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22);*/
+
+       reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
+                             MDIO_CTRL2);
+       switch (reg & MDIO_PMA_CTRL2_TYPE) {
+       case MDIO_PMA_CTRL2_10GBT:
+       case MDIO_PMA_CTRL2_1000BT:
+       case MDIO_PMA_CTRL2_100BTX:
+       case MDIO_PMA_CTRL2_10BT:
+               ecmd->port = PORT_TP;
+               ecmd->supported = SUPPORTED_TP;
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
+                                     MDIO_SPEED);
+               if (reg & MDIO_SPEED_10G)
+                       ecmd->supported |= SUPPORTED_10000baseT_Full;
+               if (reg & MDIO_PMA_SPEED_1000)
+                       ecmd->supported |= (SUPPORTED_1000baseT_Full |
+                                           SUPPORTED_1000baseT_Half);
+               if (reg & MDIO_PMA_SPEED_100)
+                       ecmd->supported |= (SUPPORTED_100baseT_Full |
+                                           SUPPORTED_100baseT_Half);
+               if (reg & MDIO_PMA_SPEED_10)
+                       ecmd->supported |= (SUPPORTED_10baseT_Full |
+                                           SUPPORTED_10baseT_Half);
+               ecmd->advertising = ADVERTISED_TP;
+               break;
+
+       case MDIO_PMA_CTRL2_10GBCX4:
+               ecmd->port = PORT_OTHER;
+               ecmd->supported = 0;
+               ecmd->advertising = 0;
+               break;
+
+/*
+       case MDIO_PMA_CTRL2_10GBKX4:
+       case MDIO_PMA_CTRL2_10GBKR:
+       case MDIO_PMA_CTRL2_1000BKX:
+               ecmd->port = PORT_OTHER;
+               ecmd->supported = SUPPORTED_Backplane;
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
+                                     MDIO_PMA_EXTABLE);
+               if (reg & MDIO_PMA_EXTABLE_10GBKX4)
+                       ecmd->supported |= SUPPORTED_10000baseKX4_Full;
+               if (reg & MDIO_PMA_EXTABLE_10GBKR)
+                       ecmd->supported |= SUPPORTED_10000baseKR_Full;
+               if (reg & MDIO_PMA_EXTABLE_1000BKX)
+                       ecmd->supported |= SUPPORTED_1000baseKX_Full;
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
+                                     MDIO_PMA_10GBR_FECABLE);
+               if (reg & MDIO_PMA_10GBR_FECABLE_ABLE)
+                       ecmd->supported |= SUPPORTED_10000baseR_FEC;
+               ecmd->advertising = ADVERTISED_Backplane;
+               break;
+*/
+
+       /* All the other defined modes are flavours of optical */
+       default:
+               ecmd->port = PORT_FIBRE;
+               ecmd->supported = SUPPORTED_FIBRE;
+               ecmd->advertising = ADVERTISED_FIBRE;
+               break;
+       }
+
+       if (mdio->mmds & MDIO_DEVS_AN) {
+               ecmd->supported |= SUPPORTED_Autoneg;
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
+                                     MDIO_CTRL1);
+               if (reg & MDIO_AN_CTRL1_ENABLE) {
+                       ecmd->autoneg = AUTONEG_ENABLE;
+                       ecmd->advertising |=
+                               ADVERTISED_Autoneg |
+                               mdio45_get_an(mdio, MDIO_AN_ADVERTISE) |
+                               npage_adv;
+               } else {
+                       ecmd->autoneg = AUTONEG_DISABLE;
+               }
+       } else {
+               ecmd->autoneg = AUTONEG_DISABLE;
+       }
+
+       if (ecmd->autoneg) {
+               u32 modes = 0;
+               int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad,
+                                             MDIO_MMD_AN, MDIO_STAT1);
+
+               /* If AN is complete and successful, report best common
+                * mode, otherwise report best advertised mode. */
+               if (an_stat & MDIO_AN_STAT1_COMPLETE) {
+                       u32 lp_advertising;
+                       /*ecmd->*/lp_advertising =
+                               mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa;
+                       /*if (an_stat & MDIO_AN_STAT1_LPABLE)
+                               ecmd->lp_advertising |= ADVERTISED_Autoneg;*/
+                       modes = ecmd->advertising & /*ecmd->*/lp_advertising;
+               }
+               if ((modes & ~ADVERTISED_Autoneg) == 0)
+                       modes = ecmd->advertising;
+
+               if (modes & (ADVERTISED_10000baseT_Full/* |
+                            ADVERTISED_10000baseKX4_Full |
+                            ADVERTISED_10000baseKR_Full*/)) {
+                       ecmd->speed = SPEED_10000;
+                       ecmd->duplex = DUPLEX_FULL;
+               } else if (modes & (ADVERTISED_1000baseT_Full |
+                                   ADVERTISED_1000baseT_Half/* |
+                                   ADVERTISED_1000baseKX_Full*/)) {
+                       ecmd->speed = SPEED_1000;
+                       ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half);
+               } else if (modes & (ADVERTISED_100baseT_Full |
+                                   ADVERTISED_100baseT_Half)) {
+                       ecmd->speed = SPEED_100;
+                       ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
+               } else {
+                       ecmd->speed = SPEED_10;
+                       ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
+               }
+       } else {
+               /* Report forced settings */
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
+                                     MDIO_CTRL1);
+               ecmd->speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) *
+                              ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10));
+               ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX ||
+                               ecmd->speed == SPEED_10000);
+       }
+
+}
+/*EXPORT_SYMBOL(mdio45_ethtool_gset_npage);*/
+
+/**
+ * mdio45_ethtool_spauseparam_an - set auto-negotiated pause parameters
+ * @mdio: MDIO interface
+ * @ecmd: Ethtool request structure
+ *
+ * This function assumes that the PHY has an auto-negotiation MMD.  It
+ * will enable and disable advertising of flow control as appropriate.
+ */
+void mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio,
+                                  const struct ethtool_pauseparam *ecmd)
+{
+       int adv, old_adv;
+
+       WARN_ON(!(mdio->mmds & MDIO_DEVS_AN));
+
+       old_adv = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
+                                 MDIO_AN_ADVERTISE);
+       adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) |
+              mii_advertise_flowctrl((ecmd->rx_pause ? FLOW_CTRL_RX : 0) |
+                                     (ecmd->tx_pause ? FLOW_CTRL_TX : 0)));
+       if (adv != old_adv) {
+               mdio->mdio_write(mdio->dev, mdio->prtad, MDIO_MMD_AN,
+                                MDIO_AN_ADVERTISE, adv);
+               mdio45_nway_restart(mdio);
+       }
+}
+/*EXPORT_SYMBOL(mdio45_ethtool_spauseparam_an);*/
+
+/**
+ * mdio_mii_ioctl - MII ioctl interface for MDIO (clause 22 or 45) PHYs
+ * @mdio: MDIO interface
+ * @mii_data: MII ioctl data structure
+ * @cmd: MII ioctl command
+ *
+ * Returns 0 on success, negative on error.
+ */
+int mdio_mii_ioctl(const struct mdio_if_info *mdio,
+                  struct mii_ioctl_data *mii_data, int cmd)
+{
+       int prtad, devad;
+       u16 addr = mii_data->reg_num;
+
+       /* Validate/convert cmd to one of SIOC{G,S}MIIREG */
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               if (mdio->prtad == MDIO_PRTAD_NONE)
+                       return -EOPNOTSUPP;
+               mii_data->phy_id = mdio->prtad;
+               cmd = SIOCGMIIREG;
+               break;
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       /* Validate/convert phy_id */
+       if ((mdio->mode_support & MDIO_SUPPORTS_C45) &&
+           mdio_phy_id_is_c45(mii_data->phy_id)) {
+               prtad = mdio_phy_id_prtad(mii_data->phy_id);
+               devad = mdio_phy_id_devad(mii_data->phy_id);
+       } else if ((mdio->mode_support & MDIO_SUPPORTS_C22) &&
+                  mii_data->phy_id < 0x20) {
+               prtad = mii_data->phy_id;
+               devad = MDIO_DEVAD_NONE;
+               addr &= 0x1f;
+       } else if ((mdio->mode_support & MDIO_EMULATE_C22) &&
+                  mdio->prtad != MDIO_PRTAD_NONE &&
+                  mii_data->phy_id == mdio->prtad) {
+               /* Remap commonly-used MII registers. */
+               prtad = mdio->prtad;
+               switch (addr) {
+               case MII_BMCR:
+               case MII_BMSR:
+               case MII_PHYSID1:
+               case MII_PHYSID2:
+                       devad = __ffs(mdio->mmds);
+                       break;
+               case MII_ADVERTISE:
+               case MII_LPA:
+                       if (!(mdio->mmds & MDIO_DEVS_AN))
+                               return -EINVAL;
+                       devad = MDIO_MMD_AN;
+                       if (addr == MII_ADVERTISE)
+                               addr = MDIO_AN_ADVERTISE;
+                       else
+                               addr = MDIO_AN_LPA;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               return -EINVAL;
+       }
+
+       if (cmd == SIOCGMIIREG) {
+               int rc = mdio->mdio_read(mdio->dev, prtad, devad, addr);
+               if (rc < 0)
+                       return rc;
+               mii_data->val_out = rc;
+               return 0;
+       } else {
+               return mdio->mdio_write(mdio->dev, prtad, devad, addr,
+                                       mii_data->val_in);
+       }
+}
+/*EXPORT_SYMBOL(mdio_mii_ioctl);*/
+
+#endif /* EFX_HAVE_LINUX_MDIO_H */
diff --git a/drivers/net/sfc/linux_mdio.h b/drivers/net/sfc/linux_mdio.h
new file mode 100644 (file)
index 0000000..e869a91
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * linux/mdio.h: definitions for MDIO (clause 45) transceivers
+ * 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.
+ */
+
+#ifndef __LINUX_MDIO_H__
+#define __LINUX_MDIO_H__
+
+#include <linux/mii.h>
+
+/* MDIO Manageable Devices (MMDs). */
+#define MDIO_MMD_PMAPMD                1       /* Physical Medium Attachment/
+                                        * Physical Medium Dependent */
+#define MDIO_MMD_WIS           2       /* WAN Interface Sublayer */
+#define MDIO_MMD_PCS           3       /* Physical Coding Sublayer */
+#define MDIO_MMD_PHYXS         4       /* PHY Extender Sublayer */
+#define MDIO_MMD_DTEXS         5       /* DTE Extender Sublayer */
+#define MDIO_MMD_TC            6       /* Transmission Convergence */
+#define MDIO_MMD_AN            7       /* Auto-Negotiation */
+#define MDIO_MMD_C22EXT                29      /* Clause 22 extension */
+#define MDIO_MMD_VEND1         30      /* Vendor specific 1 */
+#define MDIO_MMD_VEND2         31      /* Vendor specific 2 */
+
+/* Generic MDIO registers. */
+#define MDIO_CTRL1             MII_BMCR
+#define MDIO_STAT1             MII_BMSR
+#define MDIO_DEVID1            MII_PHYSID1
+#define MDIO_DEVID2            MII_PHYSID2
+#define MDIO_SPEED             4       /* Speed ability */
+#define MDIO_DEVS1             5       /* Devices in package */
+#define MDIO_DEVS2             6
+#define MDIO_CTRL2             7       /* 10G control 2 */
+#define MDIO_STAT2             8       /* 10G status 2 */
+#define MDIO_PMA_TXDIS         9       /* 10G PMA/PMD transmit disable */
+#define MDIO_PMA_RXDET         10      /* 10G PMA/PMD receive signal detect */
+#define MDIO_PMA_EXTABLE       11      /* 10G PMA/PMD extended ability */
+#define MDIO_PKGID1            14      /* Package identifier */
+#define MDIO_PKGID2            15
+#define MDIO_AN_ADVERTISE      16      /* AN advertising (base page) */
+#define MDIO_AN_LPA            19      /* AN LP abilities (base page) */
+#define MDIO_PHYXS_LNSTAT      24      /* PHY XGXS lane state */
+
+/* Media-dependent registers. */
+#define MDIO_PMA_10GBT_TXPWR   131     /* 10GBASE-T TX power control */
+#define MDIO_PMA_10GBT_SNR     133     /* 10GBASE-T SNR margin, lane A.
+                                        * Lanes B-D are numbered 134-136. */
+#define MDIO_PMA_10GBR_FECABLE 170     /* 10GBASE-R FEC ability */
+#define MDIO_PCS_10GBX_STAT1   24      /* 10GBASE-X PCS status 1 */
+#define MDIO_PCS_10GBRT_STAT1  32      /* 10GBASE-R/-T PCS status 1 */
+#define MDIO_PCS_10GBRT_STAT2  33      /* 10GBASE-R/-T PCS status 2 */
+#define MDIO_AN_10GBT_CTRL     32      /* 10GBASE-T auto-negotiation control */
+#define MDIO_AN_10GBT_STAT     33      /* 10GBASE-T auto-negotiation status */
+
+/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */
+#define MDIO_PMA_LASI_RXCTRL   0x9000  /* RX_ALARM control */
+#define MDIO_PMA_LASI_TXCTRL   0x9001  /* TX_ALARM control */
+#define MDIO_PMA_LASI_CTRL     0x9002  /* LASI control */
+#define MDIO_PMA_LASI_RXSTAT   0x9003  /* RX_ALARM status */
+#define MDIO_PMA_LASI_TXSTAT   0x9004  /* TX_ALARM status */
+#define MDIO_PMA_LASI_STAT     0x9005  /* LASI status */
+
+/* Control register 1. */
+/* Enable extended speed selection */
+#define MDIO_CTRL1_SPEEDSELEXT         (BMCR_SPEED1000 | BMCR_SPEED100)
+/* All speed selection bits */
+#define MDIO_CTRL1_SPEEDSEL            (MDIO_CTRL1_SPEEDSELEXT | 0x003c)
+#define MDIO_CTRL1_FULLDPLX            BMCR_FULLDPLX
+#define MDIO_CTRL1_LPOWER              BMCR_PDOWN
+#define MDIO_CTRL1_RESET               BMCR_RESET
+#define MDIO_PMA_CTRL1_LOOPBACK                0x0001
+#define MDIO_PMA_CTRL1_SPEED1000       BMCR_SPEED1000
+#define MDIO_PMA_CTRL1_SPEED100                BMCR_SPEED100
+#define MDIO_PCS_CTRL1_LOOPBACK                BMCR_LOOPBACK
+#define MDIO_PHYXS_CTRL1_LOOPBACK      BMCR_LOOPBACK
+#define MDIO_AN_CTRL1_RESTART          BMCR_ANRESTART
+#define MDIO_AN_CTRL1_ENABLE           BMCR_ANENABLE
+#define MDIO_AN_CTRL1_XNP              0x2000  /* Enable extended next page */
+
+/* 10 Gb/s */
+#define MDIO_CTRL1_SPEED10G            (MDIO_CTRL1_SPEEDSELEXT | 0x00)
+/* 10PASS-TS/2BASE-TL */
+#define MDIO_CTRL1_SPEED10P2B          (MDIO_CTRL1_SPEEDSELEXT | 0x04)
+
+/* Status register 1. */
+#define MDIO_STAT1_LPOWERABLE          0x0002  /* Low-power ability */
+#define MDIO_STAT1_LSTATUS             BMSR_LSTATUS
+#define MDIO_STAT1_FAULT               0x0080  /* Fault */
+#define MDIO_AN_STAT1_LPABLE           0x0001  /* Link partner AN ability */
+#define MDIO_AN_STAT1_ABLE             BMSR_ANEGCAPABLE
+#define MDIO_AN_STAT1_RFAULT           BMSR_RFAULT
+#define MDIO_AN_STAT1_COMPLETE         BMSR_ANEGCOMPLETE
+#define MDIO_AN_STAT1_PAGE             0x0040  /* Page received */
+#define MDIO_AN_STAT1_XNP              0x0080  /* Extended next page status */
+
+/* Speed register. */
+#define MDIO_SPEED_10G                 0x0001  /* 10G capable */
+#define MDIO_PMA_SPEED_2B              0x0002  /* 2BASE-TL capable */
+#define MDIO_PMA_SPEED_10P             0x0004  /* 10PASS-TS capable */
+#define MDIO_PMA_SPEED_1000            0x0010  /* 1000M capable */
+#define MDIO_PMA_SPEED_100             0x0020  /* 100M capable */
+#define MDIO_PMA_SPEED_10              0x0040  /* 10M capable */
+#define MDIO_PCS_SPEED_10P2B           0x0002  /* 10PASS-TS/2BASE-TL capable */
+
+/* Device present registers. */
+#define MDIO_DEVS_PRESENT(devad)       (1 << (devad))
+#define MDIO_DEVS_PMAPMD               MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD)
+#define MDIO_DEVS_WIS                  MDIO_DEVS_PRESENT(MDIO_MMD_WIS)
+#define MDIO_DEVS_PCS                  MDIO_DEVS_PRESENT(MDIO_MMD_PCS)
+#define MDIO_DEVS_PHYXS                        MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS)
+#define MDIO_DEVS_DTEXS                        MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS)
+#define MDIO_DEVS_TC                   MDIO_DEVS_PRESENT(MDIO_MMD_TC)
+#define MDIO_DEVS_AN                   MDIO_DEVS_PRESENT(MDIO_MMD_AN)
+#define MDIO_DEVS_C22EXT               MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT)
+
+/* Control register 2. */
+#define MDIO_PMA_CTRL2_TYPE            0x000f  /* PMA/PMD type selection */
+#define MDIO_PMA_CTRL2_10GBCX4         0x0000  /* 10GBASE-CX4 type */
+#define MDIO_PMA_CTRL2_10GBEW          0x0001  /* 10GBASE-EW type */
+#define MDIO_PMA_CTRL2_10GBLW          0x0002  /* 10GBASE-LW type */
+#define MDIO_PMA_CTRL2_10GBSW          0x0003  /* 10GBASE-SW type */
+#define MDIO_PMA_CTRL2_10GBLX4         0x0004  /* 10GBASE-LX4 type */
+#define MDIO_PMA_CTRL2_10GBER          0x0005  /* 10GBASE-ER type */
+#define MDIO_PMA_CTRL2_10GBLR          0x0006  /* 10GBASE-LR type */
+#define MDIO_PMA_CTRL2_10GBSR          0x0007  /* 10GBASE-SR type */
+#define MDIO_PMA_CTRL2_10GBLRM         0x0008  /* 10GBASE-LRM type */
+#define MDIO_PMA_CTRL2_10GBT           0x0009  /* 10GBASE-T type */
+#define MDIO_PMA_CTRL2_10GBKX4         0x000a  /* 10GBASE-KX4 type */
+#define MDIO_PMA_CTRL2_10GBKR          0x000b  /* 10GBASE-KR type */
+#define MDIO_PMA_CTRL2_1000BT          0x000c  /* 1000BASE-T type */
+#define MDIO_PMA_CTRL2_1000BKX         0x000d  /* 1000BASE-KX type */
+#define MDIO_PMA_CTRL2_100BTX          0x000e  /* 100BASE-TX type */
+#define MDIO_PMA_CTRL2_10BT            0x000f  /* 10BASE-T type */
+#define MDIO_PCS_CTRL2_TYPE            0x0003  /* PCS type selection */
+#define MDIO_PCS_CTRL2_10GBR           0x0000  /* 10GBASE-R type */
+#define MDIO_PCS_CTRL2_10GBX           0x0001  /* 10GBASE-X type */
+#define MDIO_PCS_CTRL2_10GBW           0x0002  /* 10GBASE-W type */
+#define MDIO_PCS_CTRL2_10GBT           0x0003  /* 10GBASE-T type */
+
+/* Status register 2. */
+#define MDIO_STAT2_RXFAULT             0x0400  /* Receive fault */
+#define MDIO_STAT2_TXFAULT             0x0800  /* Transmit fault */
+#define MDIO_STAT2_DEVPRST             0xc000  /* Device present */
+#define MDIO_STAT2_DEVPRST_VAL         0x8000  /* Device present value */
+#define MDIO_PMA_STAT2_LBABLE          0x0001  /* PMA loopback ability */
+#define MDIO_PMA_STAT2_10GBEW          0x0002  /* 10GBASE-EW ability */
+#define MDIO_PMA_STAT2_10GBLW          0x0004  /* 10GBASE-LW ability */
+#define MDIO_PMA_STAT2_10GBSW          0x0008  /* 10GBASE-SW ability */
+#define MDIO_PMA_STAT2_10GBLX4         0x0010  /* 10GBASE-LX4 ability */
+#define MDIO_PMA_STAT2_10GBER          0x0020  /* 10GBASE-ER ability */
+#define MDIO_PMA_STAT2_10GBLR          0x0040  /* 10GBASE-LR ability */
+#define MDIO_PMA_STAT2_10GBSR          0x0080  /* 10GBASE-SR ability */
+#define MDIO_PMD_STAT2_TXDISAB         0x0100  /* PMD TX disable ability */
+#define MDIO_PMA_STAT2_EXTABLE         0x0200  /* Extended abilities */
+#define MDIO_PMA_STAT2_RXFLTABLE       0x1000  /* Receive fault ability */
+#define MDIO_PMA_STAT2_TXFLTABLE       0x2000  /* Transmit fault ability */
+#define MDIO_PCS_STAT2_10GBR           0x0001  /* 10GBASE-R capable */
+#define MDIO_PCS_STAT2_10GBX           0x0002  /* 10GBASE-X capable */
+#define MDIO_PCS_STAT2_10GBW           0x0004  /* 10GBASE-W capable */
+#define MDIO_PCS_STAT2_RXFLTABLE       0x1000  /* Receive fault ability */
+#define MDIO_PCS_STAT2_TXFLTABLE       0x2000  /* Transmit fault ability */
+
+/* Transmit disable register. */
+#define MDIO_PMD_TXDIS_GLOBAL          0x0001  /* Global PMD TX disable */
+#define MDIO_PMD_TXDIS_0               0x0002  /* PMD TX disable 0 */
+#define MDIO_PMD_TXDIS_1               0x0004  /* PMD TX disable 1 */
+#define MDIO_PMD_TXDIS_2               0x0008  /* PMD TX disable 2 */
+#define MDIO_PMD_TXDIS_3               0x0010  /* PMD TX disable 3 */
+
+/* Receive signal detect register. */
+#define MDIO_PMD_RXDET_GLOBAL          0x0001  /* Global PMD RX signal detect */
+#define MDIO_PMD_RXDET_0               0x0002  /* PMD RX signal detect 0 */
+#define MDIO_PMD_RXDET_1               0x0004  /* PMD RX signal detect 1 */
+#define MDIO_PMD_RXDET_2               0x0008  /* PMD RX signal detect 2 */
+#define MDIO_PMD_RXDET_3               0x0010  /* PMD RX signal detect 3 */
+
+/* Extended abilities register. */
+#define MDIO_PMA_EXTABLE_10GCX4                0x0001  /* 10GBASE-CX4 ability */
+#define MDIO_PMA_EXTABLE_10GBLRM       0x0002  /* 10GBASE-LRM ability */
+#define MDIO_PMA_EXTABLE_10GBT         0x0004  /* 10GBASE-T ability */
+#define MDIO_PMA_EXTABLE_10GBKX4       0x0008  /* 10GBASE-KX4 ability */
+#define MDIO_PMA_EXTABLE_10GBKR                0x0010  /* 10GBASE-KR ability */
+#define MDIO_PMA_EXTABLE_1000BT                0x0020  /* 1000BASE-T ability */
+#define MDIO_PMA_EXTABLE_1000BKX       0x0040  /* 1000BASE-KX ability */
+#define MDIO_PMA_EXTABLE_100BTX                0x0080  /* 100BASE-TX ability */
+#define MDIO_PMA_EXTABLE_10BT          0x0100  /* 10BASE-T ability */
+
+/* PHY XGXS lane state register. */
+#define MDIO_PHYXS_LNSTAT_SYNC0                0x0001
+#define MDIO_PHYXS_LNSTAT_SYNC1                0x0002
+#define MDIO_PHYXS_LNSTAT_SYNC2                0x0004
+#define MDIO_PHYXS_LNSTAT_SYNC3                0x0008
+#define MDIO_PHYXS_LNSTAT_ALIGN                0x1000
+
+/* PMA 10GBASE-T TX power register. */
+#define MDIO_PMA_10GBT_TXPWR_SHORT     0x0001  /* Short-reach mode */
+
+/* PMA 10GBASE-T SNR registers. */
+/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */
+#define MDIO_PMA_10GBT_SNR_BIAS                0x8000
+#define MDIO_PMA_10GBT_SNR_MAX         127
+
+/* PMA 10GBASE-R FEC ability register. */
+#define MDIO_PMA_10GBR_FECABLE_ABLE    0x0001  /* FEC ability */
+#define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002  /* FEC error indic. ability */
+
+/* PCS 10GBASE-R/-T status register 1. */
+#define MDIO_PCS_10GBRT_STAT1_BLKLK    0x0001  /* Block lock attained */
+
+/* PCS 10GBASE-R/-T status register 2. */
+#define MDIO_PCS_10GBRT_STAT2_ERR      0x00ff
+#define MDIO_PCS_10GBRT_STAT2_BER      0x3f00
+
+/* AN 10GBASE-T control register. */
+#define MDIO_AN_10GBT_CTRL_ADV10G      0x1000  /* Advertise 10GBASE-T */
+
+/* AN 10GBASE-T status register. */
+#define MDIO_AN_10GBT_STAT_LPTRR       0x0200  /* LP training reset req. */
+#define MDIO_AN_10GBT_STAT_LPLTABLE    0x0400  /* LP loop timing ability */
+#define MDIO_AN_10GBT_STAT_LP10G       0x0800  /* LP is 10GBT capable */
+#define MDIO_AN_10GBT_STAT_REMOK       0x1000  /* Remote OK */
+#define MDIO_AN_10GBT_STAT_LOCOK       0x2000  /* Local OK */
+#define MDIO_AN_10GBT_STAT_MS          0x4000  /* Master/slave config */
+#define MDIO_AN_10GBT_STAT_MSFLT       0x8000  /* Master/slave config fault */
+
+/* LASI RX_ALARM control/status registers. */
+#define MDIO_PMA_LASI_RX_PHYXSLFLT     0x0001  /* PHY XS RX local fault */
+#define MDIO_PMA_LASI_RX_PCSLFLT       0x0008  /* PCS RX local fault */
+#define MDIO_PMA_LASI_RX_PMALFLT       0x0010  /* PMA/PMD RX local fault */
+#define MDIO_PMA_LASI_RX_OPTICPOWERFLT 0x0020  /* RX optical power fault */
+#define MDIO_PMA_LASI_RX_WISLFLT       0x0200  /* WIS local fault */
+
+/* LASI TX_ALARM control/status registers. */
+#define MDIO_PMA_LASI_TX_PHYXSLFLT     0x0001  /* PHY XS TX local fault */
+#define MDIO_PMA_LASI_TX_PCSLFLT       0x0008  /* PCS TX local fault */
+#define MDIO_PMA_LASI_TX_PMALFLT       0x0010  /* PMA/PMD TX local fault */
+#define MDIO_PMA_LASI_TX_LASERPOWERFLT 0x0080  /* Laser output power fault */
+#define MDIO_PMA_LASI_TX_LASERTEMPFLT  0x0100  /* Laser temperature fault */
+#define MDIO_PMA_LASI_TX_LASERBICURRFLT        0x0200  /* Laser bias current fault */
+
+/* LASI control/status registers. */
+#define MDIO_PMA_LASI_LSALARM          0x0001  /* LS_ALARM enable/status */
+#define MDIO_PMA_LASI_TXALARM          0x0002  /* TX_ALARM enable/status */
+#define MDIO_PMA_LASI_RXALARM          0x0004  /* RX_ALARM enable/status */
+
+/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */
+
+#define MDIO_PHY_ID_C45                        0x8000
+#define MDIO_PHY_ID_PRTAD              0x03e0
+#define MDIO_PHY_ID_DEVAD              0x001f
+#define MDIO_PHY_ID_C45_MASK                                           \
+       (MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD)
+
+static inline __u16 mdio_phy_id_c45(int prtad, int devad)
+{
+       return MDIO_PHY_ID_C45 | (prtad << 5) | devad;
+}
+
+static inline bool mdio_phy_id_is_c45(int phy_id)
+{
+       return (phy_id & MDIO_PHY_ID_C45) && !(phy_id & ~MDIO_PHY_ID_C45_MASK);
+}
+
+static inline __u16 mdio_phy_id_prtad(int phy_id)
+{
+       return (phy_id & MDIO_PHY_ID_PRTAD) >> 5;
+}
+
+static inline __u16 mdio_phy_id_devad(int phy_id)
+{
+       return phy_id & MDIO_PHY_ID_DEVAD;
+}
+
+#define MDIO_SUPPORTS_C22              1
+#define MDIO_SUPPORTS_C45              2
+
+#ifdef __KERNEL__ 
+
+/**
+ * struct mdio_if_info - Ethernet controller MDIO interface
+ * @prtad: PRTAD of the PHY (%MDIO_PRTAD_NONE if not present/unknown)
+ * @mmds: Mask of MMDs expected to be present in the PHY.  This must be
+ *     non-zero unless @prtad = %MDIO_PRTAD_NONE.
+ * @mode_support: MDIO modes supported.  If %MDIO_SUPPORTS_C22 is set then
+ *     MII register access will be passed through with @devad =
+ *     %MDIO_DEVAD_NONE.  If %MDIO_EMULATE_C22 is set then access to
+ *     commonly used clause 22 registers will be translated into
+ *     clause 45 registers.
+ * @dev: Net device structure
+ * @mdio_read: Register read function; returns value or negative error code
+ * @mdio_write: Register write function; returns 0 or negative error code
+ */
+struct mdio_if_info {
+       int prtad;
+       u32 mmds;
+       unsigned mode_support;
+
+       struct net_device *dev;
+       int (*mdio_read)(struct net_device *dev, int prtad, int devad,
+                        u16 addr);
+       int (*mdio_write)(struct net_device *dev, int prtad, int devad,
+                         u16 addr, u16 val);
+};
+
+#define MDIO_PRTAD_NONE                        (-1)
+#define MDIO_DEVAD_NONE                        (-1)
+#define MDIO_EMULATE_C22               4
+
+struct ethtool_cmd;
+struct ethtool_pauseparam;
+extern int mdio45_probe(struct mdio_if_info *mdio, int prtad);
+extern int mdio_set_flag(const struct mdio_if_info *mdio,
+                        int prtad, int devad, u16 addr, int mask,
+                        bool sense);
+extern int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmds);
+extern int mdio45_nway_restart(const struct mdio_if_info *mdio);
+extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
+                                     struct ethtool_cmd *ecmd,
+                                     u32 npage_adv, u32 npage_lpa);
+extern void
+mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio,
+                             const struct ethtool_pauseparam *ecmd);
+
+/**
+ * mdio45_ethtool_gset - get settings for ETHTOOL_GSET
+ * @mdio: MDIO interface
+ * @ecmd: Ethtool request structure
+ *
+ * Since the CSRs for auto-negotiation using next pages are not fully
+ * standardised, this function does not attempt to decode them.  Use
+ * mdio45_ethtool_gset_npage() to specify advertisement bits from next
+ * pages.
+ */
+static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio,
+                                      struct ethtool_cmd *ecmd)
+{
+       mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0);
+}
+
+extern int mdio_mii_ioctl(const struct mdio_if_info *mdio,
+                         struct mii_ioctl_data *mii_data, int cmd);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_MDIO_H__ */
diff --git a/drivers/net/sfc/lm87.c b/drivers/net/sfc/lm87.c
new file mode 100644 (file)
index 0000000..51f9028
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * lm87.c
+ *
+ * Copyright (C) 2000       Frodo Looijaard <frodol@dds.nl>
+ *                          Philip Edelbrock <phil@netroedge.com>
+ *                          Stephen Rousset <stephen.rousset@rocketlogix.com>
+ *                          Dan Eaton <dan.eaton@rocketlogix.com>
+ * Copyright (C) 2004-2008  Jean Delvare <khali@linux-fr.org>
+ *
+ * Original port to Linux 2.6 by Jeff Oliver.
+ *
+ * The LM87 is a sensor chip made by National Semiconductor. It monitors up
+ * to 8 voltages (including its own power source), up to three temperatures
+ * (its own plus up to two external ones) and up to two fans. The default
+ * configuration is 6 voltages, two temperatures and two fans (see below).
+ * Voltages are scaled internally with ratios such that the nominal value of
+ * each voltage correspond to a register value of 192 (which means a
+ * resolution of about 0.5% of the nominal value). Temperature values are
+ * reported with a 1 deg resolution and a 3-4 deg accuracy. Complete
+ * datasheet can be obtained from National's website at:
+ *   http://www.national.com/pf/LM/LM87.html
+ *
+ * Some functions share pins, so not all functions are available at the same
+ * time. Which are depends on the hardware setup. This driver normally
+ * assumes that firmware configured the chip correctly. Where this is not
+ * the case, platform code must set the I2C client's platform_data to point
+ * to a u8 value to be written to the channel register.
+ * For reference, here is the list of exclusive functions:
+ *  - in0+in5 (default) or temp3
+ *  - fan1 (default) or in6
+ *  - fan2 (default) or in7
+ *  - VID lines (default) or IRQ lines (not handled by this driver)
+ *
+ * The LM87 additionally features an analog output, supposedly usable to
+ * control the speed of a fan. All new chips use pulse width modulation
+ * instead. The LM87 is the only hardware monitoring chipset I know of
+ * which uses amplitude modulation. Be careful when using this feature.
+ *
+ * This driver also supports the ADM1024, a sensor chip made by Analog
+ * Devices. That chip is fully compatible with the LM87. Complete
+ * datasheet can be obtained from Analog's website at:
+ *   http://www.analog.com/en/prod/0,2877,ADM1024,00.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include "kernel_compat.h"
+#ifdef EFX_HAVE_HWMON_H
+#include <linux/hwmon.h>
+#endif
+#ifdef EFX_HAVE_I2C_SENSOR_H
+#include <linux/i2c-sensor.h>
+#endif
+#ifndef EFX_HAVE_OLD_DEVICE_ATTRIBUTE
+#include <linux/hwmon-sysfs.h>
+#endif
+#ifndef EFX_NEED_HWMON_VID
+#include <linux/hwmon-vid.h>
+#endif
+
+#ifdef EFX_NEED_LM87_DRIVER
+
+/*
+ * The LM87 registers
+ */
+
+/* nr in 0..5 */
+#define LM87_REG_IN(nr)                        (0x20 + (nr))
+#define LM87_REG_IN_MAX(nr)            (0x2B + (nr) * 2)
+#define LM87_REG_IN_MIN(nr)            (0x2C + (nr) * 2)
+/* nr in 0..1 */
+#define LM87_REG_AIN(nr)               (0x28 + (nr))
+#define LM87_REG_AIN_MIN(nr)           (0x1A + (nr))
+#define LM87_REG_AIN_MAX(nr)           (0x3B + (nr))
+
+static u8 LM87_REG_TEMP[3] = { 0x27, 0x26, 0x20 };
+static u8 LM87_REG_TEMP_HIGH[3] = { 0x39, 0x37, 0x2B };
+static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
+
+#define LM87_REG_TEMP_HW_INT_LOCK      0x13
+#define LM87_REG_TEMP_HW_EXT_LOCK      0x14
+#define LM87_REG_TEMP_HW_INT           0x17
+#define LM87_REG_TEMP_HW_EXT           0x18
+
+/* nr in 0..1 */
+#define LM87_REG_FAN(nr)               (0x28 + (nr))
+#define LM87_REG_FAN_MIN(nr)           (0x3B + (nr))
+#define LM87_REG_AOUT                  0x19
+
+#define LM87_REG_CONFIG                        0x40
+#define LM87_REG_CHANNEL_MODE          0x16
+#define LM87_REG_VID_FAN_DIV           0x47
+#define LM87_REG_VID4                  0x49
+
+#define LM87_REG_ALARMS1               0x41
+#define LM87_REG_ALARMS2               0x42
+
+#define LM87_REG_COMPANY_ID            0x3E
+#define LM87_REG_REVISION              0x3F
+
+/*
+ * Conversions and various macros
+ * The LM87 uses signed 8-bit values for temperatures.
+ */
+
+#define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192)
+#define IN_TO_REG(val,scale)   ((val) <= 0 ? 0 : \
+                                (val) * 192 >= (scale) * 255 ? 255 : \
+                                ((val) * 192 + (scale)/2) / (scale))
+
+#define TEMP_FROM_REG(reg)     ((reg) * 1000)
+#define TEMP_TO_REG(val)       ((val) <= -127500 ? -128 : \
+                                (val) >= 126500 ? 127 : \
+                                (((val) < 0 ? (val)-500 : (val)+500) / 1000))
+
+#define FAN_FROM_REG(reg,div)  ((reg) == 255 || (reg) == 0 ? 0 : \
+                                (1350000 + (reg)*(div) / 2) / ((reg)*(div)))
+#define FAN_TO_REG(val,div)    ((val)*(div) * 255 <= 1350000 ? 255 : \
+                                (1350000 + (val)*(div) / 2) / ((val)*(div)))
+
+#define FAN_DIV_FROM_REG(reg)  (1 << (reg))
+
+/* analog out is 9.80mV/LSB */
+#define AOUT_FROM_REG(reg)     (((reg) * 98 + 5) / 10)
+#define AOUT_TO_REG(val)       ((val) <= 0 ? 0 : \
+                                (val) >= 2500 ? 255 : \
+                                ((val) * 10 + 49) / 98)
+
+/* nr in 0..1 */
+#define CHAN_NO_FAN(nr)                (1 << (nr))
+#define CHAN_TEMP3             (1 << 2)
+#define CHAN_VCC_5V            (1 << 3)
+#define CHAN_NO_VID            (1 << 7)
+
+/*
+ * Functions declaration
+ */
+
+static void lm87_init_client(struct i2c_client *client);
+static int lm87_remove(struct i2c_client *client);
+static struct lm87_data *lm87_update_device(struct device *dev);
+#ifdef EFX_USE_I2C_LEGACY
+static int lm87_detach_client(struct i2c_client *client);
+#endif
+
+/*
+ * Driver data (common to all clients)
+ */
+
+#if !defined(EFX_USE_I2C_LEGACY) && !defined(EFX_HAVE_OLD_I2C_DRIVER_PROBE)
+static const struct i2c_device_id lm87_id[] = {
+       { "sfc_lm87" },
+       { }
+};
+#endif
+
+struct i2c_driver efx_lm87_driver = {
+#ifdef EFX_USE_I2C_DRIVER_NAME
+       .name           = "sfc_lm87",
+#else
+       .driver.name    = "sfc_lm87",
+#endif
+#ifdef EFX_USE_I2C_LEGACY
+       .detach_client  = lm87_detach_client,
+#else
+       .probe          = efx_lm87_probe,
+       .remove         = lm87_remove,
+#ifndef EFX_HAVE_OLD_I2C_DRIVER_PROBE
+       .id_table       = lm87_id,
+#endif
+#endif
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm87_data {
+#ifdef EFX_HAVE_HWMON_CLASS_DEVICE
+       struct class_device *hwmon_dev;
+#else
+       struct device *hwmon_dev;
+#endif
+       struct mutex update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* In jiffies */
+
+       u8 channel;             /* register value */
+       u8 config;              /* original register value */
+
+       u8 in[8];               /* register value */
+       u8 in_max[8];           /* register value */
+       u8 in_min[8];           /* register value */
+       u16 in_scale[8];
+
+       s8 temp[3];             /* register value */
+       s8 temp_high[3];        /* register value */
+       s8 temp_low[3];         /* register value */
+       s8 temp_crit_int;       /* min of two register values */
+       s8 temp_crit_ext;       /* min of two register values */
+
+       u8 fan[2];              /* register value */
+       u8 fan_min[2];          /* register value */
+       u8 fan_div[2];          /* register value, shifted right */
+       u8 aout;                /* register value */
+
+       u16 alarms;             /* register values, combined */
+       u8 vid;                 /* register values, combined */
+       u8 vrm;
+};
+
+/*
+ * Sysfs stuff
+ */
+
+static inline int lm87_read_value(struct i2c_client *client, u8 reg)
+{
+       return i2c_smbus_read_byte_data(client, reg);
+}
+
+static inline int lm87_write_value(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+#define show_in(offset) \
+static ssize_t show_in##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \
+                      data->in_scale[offset])); \
+} \
+static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \
+                      data->in_scale[offset])); \
+} \
+static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \
+                      data->in_scale[offset])); \
+} \
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+               show_in##offset##_input, NULL);
+show_in(0);
+show_in(1);
+show_in(2);
+show_in(3);
+show_in(4);
+show_in(5);
+show_in(6);
+show_in(7);
+
+static void set_in_min(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->in_min[nr] = IN_TO_REG(val, data->in_scale[nr]);
+       lm87_write_value(client, nr<6 ? LM87_REG_IN_MIN(nr) :
+                        LM87_REG_AIN_MIN(nr-6), data->in_min[nr]);
+       mutex_unlock(&data->update_lock);
+}
+
+static void set_in_max(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->in_max[nr] = IN_TO_REG(val, data->in_scale[nr]);
+       lm87_write_value(client, nr<6 ? LM87_REG_IN_MAX(nr) :
+                        LM87_REG_AIN_MAX(nr-6), data->in_max[nr]);
+       mutex_unlock(&data->update_lock);
+}
+
+#define set_in(offset) \
+static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, \
+               const char *buf, size_t count) \
+{ \
+       set_in_min(dev, buf, offset); \
+       return count; \
+} \
+static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, \
+               const char *buf, size_t count) \
+{ \
+       set_in_max(dev, buf, offset); \
+       return count; \
+} \
+static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+               show_in##offset##_min, set_in##offset##_min); \
+static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+               show_in##offset##_max, set_in##offset##_max);
+set_in(0);
+set_in(1);
+set_in(2);
+set_in(3);
+set_in(4);
+set_in(5);
+set_in(6);
+set_in(7);
+
+#define show_temp(offset) \
+static ssize_t show_temp##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \
+} \
+static ssize_t show_temp##offset##_low(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[offset-1])); \
+} \
+static ssize_t show_temp##offset##_high(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[offset-1])); \
+}\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+               show_temp##offset##_input, NULL);
+show_temp(1);
+show_temp(2);
+show_temp(3);
+
+static void set_temp_low(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->temp_low[nr] = TEMP_TO_REG(val);
+       lm87_write_value(client, LM87_REG_TEMP_LOW[nr], data->temp_low[nr]);
+       mutex_unlock(&data->update_lock);
+}
+
+static void set_temp_high(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->temp_high[nr] = TEMP_TO_REG(val);
+       lm87_write_value(client, LM87_REG_TEMP_HIGH[nr], data->temp_high[nr]);
+       mutex_unlock(&data->update_lock);
+}
+
+#define set_temp(offset) \
+static ssize_t set_temp##offset##_low(struct device *dev, struct device_attribute *attr, \
+               const char *buf, size_t count) \
+{ \
+       set_temp_low(dev, buf, offset-1); \
+       return count; \
+} \
+static ssize_t set_temp##offset##_high(struct device *dev, struct device_attribute *attr, \
+               const char *buf, size_t count) \
+{ \
+       set_temp_high(dev, buf, offset-1); \
+       return count; \
+} \
+static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+               show_temp##offset##_high, set_temp##offset##_high); \
+static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+               show_temp##offset##_low, set_temp##offset##_low);
+set_temp(1);
+set_temp(2);
+set_temp(3);
+
+static ssize_t show_temp_crit_int(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int));
+}
+
+static ssize_t show_temp_crit_ext(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext));
+}
+
+static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL);
+static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL);
+static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL);
+
+#define show_fan(offset) \
+static ssize_t show_fan##offset##_input(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[offset-1], \
+                      FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \
+} \
+static ssize_t show_fan##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[offset-1], \
+                      FAN_DIV_FROM_REG(data->fan_div[offset-1]))); \
+} \
+static ssize_t show_fan##offset##_div(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       struct lm87_data *data = lm87_update_device(dev); \
+       return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[offset-1])); \
+} \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+               show_fan##offset##_input, NULL);
+show_fan(1);
+show_fan(2);
+
+static void set_fan_min(struct device *dev, const char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->fan_min[nr] = FAN_TO_REG(val,
+                           FAN_DIV_FROM_REG(data->fan_div[nr]));
+       lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);
+       mutex_unlock(&data->update_lock);
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+   determined in part by the fan clock divider.  This follows the principle
+   of least surprise; the user doesn't expect the fan minimum to change just
+   because the divider changed. */
+static ssize_t set_fan_div(struct device *dev, const char *buf,
+               size_t count, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       unsigned long min;
+       u8 reg;
+
+       mutex_lock(&data->update_lock);
+       min = FAN_FROM_REG(data->fan_min[nr],
+                          FAN_DIV_FROM_REG(data->fan_div[nr]));
+
+       switch (val) {
+       case 1: data->fan_div[nr] = 0; break;
+       case 2: data->fan_div[nr] = 1; break;
+       case 4: data->fan_div[nr] = 2; break;
+       case 8: data->fan_div[nr] = 3; break;
+       default:
+               mutex_unlock(&data->update_lock);
+               return -EINVAL;
+       }
+
+       reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
+       switch (nr) {
+       case 0:
+           reg = (reg & 0xCF) | (data->fan_div[0] << 4);
+           break;
+       case 1:
+           reg = (reg & 0x3F) | (data->fan_div[1] << 6);
+           break;
+       }
+       lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg);
+
+       data->fan_min[nr] = FAN_TO_REG(min, val);
+       lm87_write_value(client, LM87_REG_FAN_MIN(nr),
+                        data->fan_min[nr]);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+#define set_fan(offset) \
+static ssize_t set_fan##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \
+               size_t count) \
+{ \
+       set_fan_min(dev, buf, offset-1); \
+       return count; \
+} \
+static ssize_t set_fan##offset##_div(struct device *dev, struct device_attribute *attr, const char *buf, \
+               size_t count) \
+{ \
+       return set_fan_div(dev, buf, count, offset-1); \
+} \
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+               show_fan##offset##_min, set_fan##offset##_min); \
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+               show_fan##offset##_div, set_fan##offset##_div);
+set_fan(1);
+set_fan(2);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", data->alarms);
+}
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct lm87_data *data = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct lm87_data *data = dev_get_drvdata(dev);
+       data->vrm = simple_strtoul(buf, NULL, 10);
+       return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
+}
+static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+
+       mutex_lock(&data->update_lock);
+       data->aout = AOUT_TO_REG(val);
+       lm87_write_value(client, LM87_REG_AOUT, data->aout);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct lm87_data *data = lm87_update_device(dev);
+       int bitnr = to_sensor_dev_attr(attr)->index;
+       return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+
+/*
+ * Real code
+ */
+
+static struct attribute *lm87_attributes[] = {
+       &dev_attr_in1_input.attr,
+       &dev_attr_in1_min.attr,
+       &dev_attr_in1_max.attr,
+       &sensor_dev_attr_in1_alarm.dev_attr.attr,
+       &dev_attr_in2_input.attr,
+       &dev_attr_in2_min.attr,
+       &dev_attr_in2_max.attr,
+       &sensor_dev_attr_in2_alarm.dev_attr.attr,
+       &dev_attr_in3_input.attr,
+       &dev_attr_in3_min.attr,
+       &dev_attr_in3_max.attr,
+       &sensor_dev_attr_in3_alarm.dev_attr.attr,
+       &dev_attr_in4_input.attr,
+       &dev_attr_in4_min.attr,
+       &dev_attr_in4_max.attr,
+       &sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp1_max.attr,
+       &dev_attr_temp1_min.attr,
+       &dev_attr_temp1_crit.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       &dev_attr_temp2_input.attr,
+       &dev_attr_temp2_max.attr,
+       &dev_attr_temp2_min.attr,
+       &dev_attr_temp2_crit.attr,
+       &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+       &dev_attr_alarms.attr,
+       &dev_attr_aout_output.attr,
+
+       NULL
+};
+
+static const struct attribute_group lm87_group = {
+       .attrs = lm87_attributes,
+};
+
+static struct attribute *lm87_attributes_opt[] = {
+       &dev_attr_in6_input.attr,
+       &dev_attr_in6_min.attr,
+       &dev_attr_in6_max.attr,
+       &sensor_dev_attr_in6_alarm.dev_attr.attr,
+
+       &dev_attr_fan1_input.attr,
+       &dev_attr_fan1_min.attr,
+       &dev_attr_fan1_div.attr,
+       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+
+       &dev_attr_in7_input.attr,
+       &dev_attr_in7_min.attr,
+       &dev_attr_in7_max.attr,
+       &sensor_dev_attr_in7_alarm.dev_attr.attr,
+
+       &dev_attr_fan2_input.attr,
+       &dev_attr_fan2_min.attr,
+       &dev_attr_fan2_div.attr,
+       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+
+       &dev_attr_temp3_input.attr,
+       &dev_attr_temp3_max.attr,
+       &dev_attr_temp3_min.attr,
+       &dev_attr_temp3_crit.attr,
+       &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+       &dev_attr_in0_input.attr,
+       &dev_attr_in0_min.attr,
+       &dev_attr_in0_max.attr,
+       &sensor_dev_attr_in0_alarm.dev_attr.attr,
+       &dev_attr_in5_input.attr,
+       &dev_attr_in5_min.attr,
+       &dev_attr_in5_max.attr,
+       &sensor_dev_attr_in5_alarm.dev_attr.attr,
+
+       &dev_attr_cpu0_vid.attr,
+       &dev_attr_vrm.attr,
+
+       NULL
+};
+
+static const struct attribute_group lm87_group_opt = {
+       .attrs = lm87_attributes_opt,
+};
+
+#ifdef EFX_HAVE_OLD_I2C_DRIVER_PROBE
+int efx_lm87_probe(struct i2c_client *new_client)
+#else
+int efx_lm87_probe(struct i2c_client *new_client,
+                  const struct i2c_device_id *id)
+#endif
+{
+       struct lm87_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(new_client, data);
+       data->valid = 0;
+       mutex_init(&data->update_lock);
+
+       /* Initialize the LM87 chip */
+       lm87_init_client(new_client);
+
+       data->in_scale[0] = 2500;
+       data->in_scale[1] = 2700;
+       data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300;
+       data->in_scale[3] = 5000;
+       data->in_scale[4] = 12000;
+       data->in_scale[5] = 2700;
+       data->in_scale[6] = 1875;
+       data->in_scale[7] = 1875;
+
+       /* Register sysfs hooks */
+       if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
+               goto exit_free;
+
+       if (data->channel & CHAN_NO_FAN(0)) {
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_in6_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in6_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in6_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in6_alarm.dev_attr)))
+                       goto exit_remove;
+       } else {
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_fan1_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_fan1_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_fan1_div))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_fan1_alarm.dev_attr)))
+                       goto exit_remove;
+       }
+
+       if (data->channel & CHAN_NO_FAN(1)) {
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_in7_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in7_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in7_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in7_alarm.dev_attr)))
+                       goto exit_remove;
+       } else {
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_fan2_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_fan2_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_fan2_div))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_fan2_alarm.dev_attr)))
+                       goto exit_remove;
+       }
+
+       if (data->channel & CHAN_TEMP3) {
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_temp3_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_temp3_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_temp3_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_temp3_crit))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_temp3_alarm.dev_attr))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_temp3_fault.dev_attr)))
+                       goto exit_remove;
+       } else {
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_in0_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in0_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in0_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in0_alarm.dev_attr))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in5_input))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in5_min))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_in5_max))
+                || (err = device_create_file(&new_client->dev,
+                                       &sensor_dev_attr_in5_alarm.dev_attr)))
+                       goto exit_remove;
+       }
+
+       if (!(data->channel & CHAN_NO_VID)) {
+               data->vrm = vid_which_vrm();
+               if ((err = device_create_file(&new_client->dev,
+                                       &dev_attr_cpu0_vid))
+                || (err = device_create_file(&new_client->dev,
+                                       &dev_attr_vrm)))
+                       goto exit_remove;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+exit_remove:
+       sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
+       sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
+exit_free:
+       lm87_write_value(new_client, LM87_REG_CONFIG, data->config);
+       kfree(data);
+exit:
+       return err;
+}
+
+static void lm87_init_client(struct i2c_client *client)
+{
+       struct lm87_data *data = i2c_get_clientdata(client);
+
+       if (client->dev.platform_data) {
+               data->channel = *(u8 *)client->dev.platform_data;
+               lm87_write_value(client,
+                                LM87_REG_CHANNEL_MODE, data->channel);
+       } else {
+               data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
+       }
+       data->config = lm87_read_value(client, LM87_REG_CONFIG);
+
+       if (!(data->config & 0x01)) {
+               int i;
+
+               /* Limits are left uninitialized after power-up */
+               for (i = 1; i < 6; i++) {
+                       lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00);
+                       lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF);
+               }
+               for (i = 0; i < 2; i++) {
+                       lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F);
+                       lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00);
+                       lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00);
+                       lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF);
+               }
+               if (data->channel & CHAN_TEMP3) {
+                       lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F);
+                       lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00);
+               } else {
+                       lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00);
+                       lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF);
+               }
+       }
+
+       /* Make sure Start is set and INT#_Clear is clear */
+       if ((data->config & 0x09) != 0x01)
+               lm87_write_value(client, LM87_REG_CONFIG,
+                                (data->config & 0x77) | 0x01);
+}
+
+static int lm87_remove(struct i2c_client *client)
+{
+       struct lm87_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm87_group);
+       sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
+
+       lm87_write_value(client, LM87_REG_CONFIG, data->config);
+       kfree(data);
+       return 0;
+}
+
+#ifdef EFX_USE_I2C_LEGACY
+static int lm87_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       lm87_remove(client);
+       err = i2c_detach_client(client);
+       if (!err)
+               kfree(client);
+       return err;
+}
+#endif
+
+static struct lm87_data *lm87_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm87_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               int i, j;
+
+               dev_dbg(&client->dev, "Updating data.\n");
+
+               i = (data->channel & CHAN_TEMP3) ? 1 : 0;
+               j = (data->channel & CHAN_TEMP3) ? 5 : 6;
+               for (; i < j; i++) {
+                       data->in[i] = lm87_read_value(client,
+                                     LM87_REG_IN(i));
+                       data->in_min[i] = lm87_read_value(client,
+                                         LM87_REG_IN_MIN(i));
+                       data->in_max[i] = lm87_read_value(client,
+                                         LM87_REG_IN_MAX(i));
+               }
+
+               for (i = 0; i < 2; i++) {
+                       if (data->channel & CHAN_NO_FAN(i)) {
+                               data->in[6+i] = lm87_read_value(client,
+                                               LM87_REG_AIN(i));
+                               data->in_max[6+i] = lm87_read_value(client,
+                                                   LM87_REG_AIN_MAX(i));
+                               data->in_min[6+i] = lm87_read_value(client,
+                                                   LM87_REG_AIN_MIN(i));
+
+                       } else {
+                               data->fan[i] = lm87_read_value(client,
+                                              LM87_REG_FAN(i));
+                               data->fan_min[i] = lm87_read_value(client,
+                                                  LM87_REG_FAN_MIN(i));
+                       }
+               }
+
+               j = (data->channel & CHAN_TEMP3) ? 3 : 2;
+               for (i = 0 ; i < j; i++) {
+                       data->temp[i] = lm87_read_value(client,
+                                       LM87_REG_TEMP[i]);
+                       data->temp_high[i] = lm87_read_value(client,
+                                            LM87_REG_TEMP_HIGH[i]);
+                       data->temp_low[i] = lm87_read_value(client,
+                                           LM87_REG_TEMP_LOW[i]);
+               }
+
+               i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK);
+               j = lm87_read_value(client, LM87_REG_TEMP_HW_INT);
+               data->temp_crit_int = min(i, j);
+
+               i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK);
+               j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT);
+               data->temp_crit_ext = min(i, j);
+
+               i = lm87_read_value(client, LM87_REG_VID_FAN_DIV);
+               data->fan_div[0] = (i >> 4) & 0x03;
+               data->fan_div[1] = (i >> 6) & 0x03;
+               data->vid = (i & 0x0F)
+                         | (lm87_read_value(client, LM87_REG_VID4) & 0x01)
+                            << 4;
+
+               data->alarms = lm87_read_value(client, LM87_REG_ALARMS1)
+                            | (lm87_read_value(client, LM87_REG_ALARMS2)
+                               << 8);
+               data->aout = lm87_read_value(client, LM87_REG_AOUT);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+#endif /* EFX_NEED_LM87_DRIVER */
diff --git a/drivers/net/sfc/lm87_support.c b/drivers/net/sfc/lm87_support.c
deleted file mode 100644 (file)
index eae3863..0000000
+++ /dev/null
@@ -1,295 +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@solarflare.com>
- *
- * 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 "lm87_support.h"
-#include "workarounds.h"
-
-/* Setting this to 1 will cause efx_check_lm87 to dump the status when it
- * detects an alarm. This will result in the canonical name (i.e. that in
- * the LM87 data book) being printed for each set status bit, along with
- * the reading for that sensor value, if applicable. If set to 0 only the
- * raw status1 and status2 register values are printed. */
-#define LM87_VERBOSE_ALARMS    1
-
-/**************************************************************************
- *
- * Onboard LM87 temperature and voltage monitor
- *
- **************************************************************************
- */
-
-/* LM87 channel mode: all current boards either do not use AIN1/FAN1 and 2
- * or use them as AIN. */
-#define LM87_CHANNEL_MODE 0x16
-#define LM87_CHANNEL_AIN1 1
-#define LM87_CHANNEL_AIN2 2
-#define LM87_CHANNEL_INIT (LM87_CHANNEL_AIN2 | LM87_CHANNEL_AIN1)
-
-/* LM87 configuration register 1 */
-#define LM87_CONFIG_1 0x40
-#define LM87_START 0x01
-#define LM87_INTEN 0x02
-#define LM87_INITIALIZATION 0x80
-
-/* LM87 interrupt status register 1 */
-#define LM87_INT_STATUS_1 0x41
-
-/* LM87 interrupt status register 2 */
-#define LM87_INT_STATUS_2 0x42
-
-/* LM87 interrupt mask register 1 */
-#define LM87_INT_MASK_1 0x43
-
-/* LM87 interrupt mask register 2 */
-#define LM87_INT_MASK_2 0x44
-
-/* LM87 monitoring limits */
-#define LM87_LIMITS 0x2b
-
-
-int efx_probe_lm87(struct efx_nic *efx, int addr,
-                  const u8 *limits, int nlimits, const u16 irqmask)
-{
-       struct efx_i2c_interface *i2c = &efx->i2c;
-       u8 byte;
-       int rc;
-
-       /* Check for onboard LM87 */
-       rc = efx_i2c_check_presence_retry(i2c, addr);
-       if (rc) {
-               /* Not an error to lack an LM87, but failure to probe the
-                * bus is worrying. */
-               if (rc == -EFAULT) {
-                       EFX_ERR(efx, "Failed to probe I2C bus for LM87!\n");
-                       return rc;
-               } else {
-                       EFX_LOG(efx, "has no onboard LM87 chip\n");
-                       return 0;
-               }
-       }
-       efx->board_info.lm87_addr = addr;
-       EFX_LOG(efx, "detected onboard LM87 chip at 0x%2x\n", addr);
-
-       /* Reset chip */
-       byte = LM87_INITIALIZATION;
-       rc = efx_i2c_write_retry(i2c, addr, LM87_CONFIG_1, &byte, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not reset LM87\n");
-               return rc;
-       }
-
-       /* Configure channel mode: currently hardwire to make pins 5 and 6
-        * AIN1 and AIN2 rather than FAN1, FAN2. */
-       byte = LM87_CHANNEL_INIT;
-       rc = efx_i2c_write_retry(i2c, addr, LM87_CHANNEL_MODE, &byte, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not program LM87 chan. mode\n");
-               return rc;
-       }
-
-       /* Configure limits */
-       rc = efx_i2c_write_retry(i2c, addr, LM87_LIMITS, limits, nlimits);
-       if (rc) {
-               EFX_ERR(efx, "could not program LM87 limits\n");
-               return rc;
-       }
-
-       /* Mask off unwanted interrupts */
-       byte = (irqmask & 0xff);
-       rc = efx_i2c_write_retry(i2c, addr, LM87_INT_MASK_1, &byte, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not mask LM87 interrupts\n");
-               return rc;
-       }
-
-       byte = (irqmask >> 8);
-       rc = efx_i2c_write_retry(i2c, addr, LM87_INT_MASK_2, &byte, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not mask LM87 interrupts\n");
-               return rc;
-       }
-
-       /* Start monitoring */
-       byte = LM87_START;
-       if (irqmask != EFX_LM87_NO_INTS)
-               byte |= LM87_INTEN;
-
-       rc = efx_i2c_write_retry(i2c, addr, LM87_CONFIG_1, &byte, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not start LM87\n");
-               return rc;
-       }
-
-       return rc;
-}
-
-void efx_remove_lm87(struct efx_nic *efx)
-{
-       struct efx_i2c_interface *i2c = &efx->i2c;
-       u8 byte;
-
-       if (!efx->board_info.lm87_addr)
-               return;
-
-       /* Reset chip */
-       byte = LM87_INITIALIZATION;
-       if (efx_i2c_write_retry(i2c, efx->board_info.lm87_addr,
-                               LM87_CONFIG_1, &byte, 1) != 0)
-               EFX_ERR(efx, "could not reset LM87 on exit\n");
-}
-
-#if LM87_VERBOSE_ALARMS
-/* Bit number to name mapping for status1 */
-static const char *lm_stat_names[] = {
-/* Status 1 contents */
-       "+2.5Vin",
-       "Vccp1",
-       "Vcc",
-       "+5Vin",
-       "Int. Temp.",
-       "Ext. Temp.",
-       "FAN1/AIN1",
-       "FAN2/AIN2",
-/* Status 2 contents */
-       "+12Vin",
-       "Vccp2",
-       "Reserved",
-       "Reserved",
-       "CI",
-       "THERM#",
-       "D1 Fault",
-       "D2 Fault"
-};
-
-/* Where to read the value corresponding to an alarm bit. */
-static const int lm_stat_regs[] = {
-       0x20, 0x21, 0x22, 0x23, 0x27, 0x26, 0x28, 0x29,
-       0x24, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-/* The positions of the alarm bits do not correspond exactly to the
- * order of the limit values. Convert so the user only needs to maintain
- * one array */
-static int lm_bit_to_lim[] = {
-       0, /* 2.5V */
-       1, /* Vccp1 */
-       2, /* Vcc */
-       3, /* 5V */
-       7, /* Int temp. */
-       6, /* Ext temp. */
-       8, /* AIN1 */
-       9, /* AIN2 */
-       4, /* 12V */
-       5  /* Vccp2 */
-};
-
-/* These are bit numbers. I feel justified in hardwiring the max. */
-static const int lm_stat_max = 16;
-
-static void lm87_show_alarm(struct efx_nic *efx, int bit)
-{
-       char valbuf[8];
-       u8 val;
-
-       if (lm_stat_regs[bit] != 0xff) {
-               efx_i2c_read_retry(&efx->i2c, efx->board_info.lm87_addr,
-                                  lm_stat_regs[bit], &val, 1);
-               sprintf(valbuf, "0x%02x  ", val);
-       } else {
-               strcpy(valbuf, "----  ");
-       }
-       /* If the board code knows what this sensor is wired to, let it tell
-        * us, else just print the LM87 datasheet name of the input, and the
-        * value. */
-       if (efx->board_info.interpret_sensor == NULL ||
-           (bit < ARRAY_SIZE(lm_bit_to_lim) &&
-            efx->board_info.interpret_sensor(efx, lm_bit_to_lim[bit], val)
-            == 0))
-               EFX_ERR(efx, ": %10s  %4s\n",
-                       STRING_TABLE_LOOKUP(bit, lm_stat), valbuf);
-}
-
-static void lm87_dump_alarms(struct efx_nic *efx, int stat1, int stat2)
-{
-       int i;
-       EFX_ERR(efx, "   NAME    value\n");
-       for (i = 0; i < 8; i++) {
-               if (stat1 & (1 << i))
-                       lm87_show_alarm(efx, i);
-               if (stat2 & (1 << i))
-                       lm87_show_alarm(efx, i + 8);
-       }
-}
-
-#else
-#define lm87_dump_alarms(_name, _stat1, _stat2) do {} while (0)
-#endif
-
-/* Read onboard LM87 (if present)
- * Return error code if lm87 could not be read (-EIO)
- * _or_ is raising an alarm (-ERANGE). 0 if AOK.
- */
-int efx_check_lm87(struct efx_nic *efx, unsigned mask)
-{
-       struct efx_i2c_interface *i2c = &efx->i2c;
-       u8 int_status_1, int_status_2;
-       unsigned ints;
-       int rc = 0;
-
-       /* If link is up then do not monitor temperature */
-       if (EFX_WORKAROUND_7884(efx) && efx->link_up)
-               return 0;
-
-       if (!efx->board_info.lm87_addr)
-               return 0;
-
-       /* Read interrupt status registers */
-       rc = efx_i2c_read_retry(i2c, efx->board_info.lm87_addr,
-                               LM87_INT_STATUS_1, &int_status_1, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not read LM87 INT status 1\n");
-               return rc;
-       }
-       rc = efx_i2c_read_retry(i2c, efx->board_info.lm87_addr,
-                               LM87_INT_STATUS_2, &int_status_2, 1);
-       if (rc) {
-               EFX_ERR(efx, "could not read LM87 INT status 2\n");
-               return rc;
-       }
-
-       int_status_1 &= mask;
-       int_status_2 &= (mask >> 8);
-       ints = ((int_status_2 << 8) | int_status_1);
-
-       /* Check interrupt status */
-       if (ints == 0)
-               return 0;
-
-       EFX_ERR(efx, "LM87 detected a hardware failure (status %02x:%02x)\n",
-               int_status_1, int_status_2);
-       lm87_dump_alarms(efx, int_status_1, int_status_2);
-
-       return -ERANGE;
-}
diff --git a/drivers/net/sfc/lm87_support.h b/drivers/net/sfc/lm87_support.h
deleted file mode 100644 (file)
index a9064ad..0000000
+++ /dev/null
@@ -1,58 +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@solarflare.com>
- *
- * 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_LM87_SUPPORT_H
-#define EFX_LM87_SUPPORT_H
-
-/* The interrupt bit masks. These are the same in the interrupt status and
- * interrupt mask registers. */
-/* Register 1 bits */
-#define EFX_LM87_2_5V_INT      (1)
-#define EFX_LM87_VCCP1_INT     (2)
-#define EFX_LM87_VCC_INT       (4)
-#define EFX_LM87_5_V_INT       (8)
-#define EFX_LM87_ITMP_INT      (0x10)
-#define EFX_LM87_ETMP_INT      (0x20)
-#define EFX_LM87_FAN1_INT      (0x40)
-#define EFX_LM87_FAN2_INT      (0x80)
-/* Register 2 bits */
-#define EFX_LM87_12V_INT       (0x100)
-#define EFX_LM87_VCCP2_INT     (0x200)
-/* Bits 2 and 3 are reserved. */
-#define EFX_LM87_CI_INT                (0x1000)
-#define EFX_LM87_THERM_INT     (0x2000)
-#define EFX_LM87_D1_INT                (0x4000)
-#define EFX_LM87_D2_INT                (0x8000)
-
-#define EFX_LM87_NO_INTS       ((u16)-1)
-
-extern
-int efx_probe_lm87(struct efx_nic *efx, int addr, const u8 *limits,
-                  int nlimits, const u16 irqmask);
-
-extern void efx_remove_lm87(struct efx_nic *efx);
-
-extern int efx_check_lm87(struct efx_nic *efx, unsigned mask);
-
-#endif /* EFX_LM87_SUPPORT_H */
diff --git a/drivers/net/sfc/lm90.c b/drivers/net/sfc/lm90.c
new file mode 100644 (file)
index 0000000..8de9773
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * lm90.c - Part of lm_sensors, Linux kernel modules for hardware
+ *          monitoring
+ * Copyright (C) 2003-2008  Jean Delvare <khali@linux-fr.org>
+ *
+ * Based on the lm83 driver. The LM90 is a sensor chip made by National
+ * Semiconductor. It reports up to two temperatures (its own plus up to
+ * one external one) with a 0.125 deg resolution (1 deg for local
+ * temperature) and a 3-4 deg accuracy.
+ *
+ * This driver also supports the LM89 and LM99, two other sensor chips
+ * made by National Semiconductor. Both have an increased remote
+ * temperature measurement accuracy (1 degree), and the LM99
+ * additionally shifts remote temperatures (measured and limits) by 16
+ * degrees, which allows for higher temperatures measurement. The
+ * driver doesn't handle it since it can be done easily in user-space.
+ * Note that there is no way to differentiate between both chips.
+ *
+ * This driver also supports the LM86, another sensor chip made by
+ * National Semiconductor. It is exactly similar to the LM90 except it
+ * has a higher accuracy.
+ *
+ * This driver also supports the ADM1032, a sensor chip made by Analog
+ * Devices. That chip is similar to the LM90, with a few differences
+ * that are not handled by this driver. Among others, it has a higher
+ * accuracy than the LM90, much like the LM86 does.
+ *
+ * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor
+ * chips made by Maxim. These chips are similar to the LM86.
+ * Note that there is no easy way to differentiate between the three
+ * variants. The extra address and features of the MAX6659 are not
+ * supported by this driver. These chips lack the remote temperature
+ * offset feature.
+ *
+ * This driver also supports the MAX6646, MAX6647 and MAX6649 chips
+ * made by Maxim.  These are again similar to the LM86, but they use
+ * unsigned temperature values and can report temperatures from 0 to
+ * 145 degrees.
+ *
+ * This driver also supports the MAX6680 and MAX6681, two other sensor
+ * chips made by Maxim. These are quite similar to the other Maxim
+ * chips. The MAX6680 and MAX6681 only differ in the pinout so they can
+ * be treated identically.
+ *
+ * This driver also supports the ADT7461 chip from Analog Devices.
+ * It's supported in both compatibility and extended mode. It is mostly
+ * compatible with LM90 except for a data format difference for the
+ * temperature value registers.
+ *
+ * Since the LM90 was the first chipset supported by this driver, most
+ * comments will refer to this chipset, but are actually general and
+ * concern all supported chipsets, unless mentioned otherwise.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+
+#include "kernel_compat.h"
+#ifndef EFX_HAVE_OLD_DEVICE_ATTRIBUTE
+#include <linux/hwmon-sysfs.h>
+#endif
+#ifdef EFX_HAVE_HWMON_H
+#include <linux/hwmon.h>
+#endif
+#ifdef EFX_HAVE_I2C_SENSOR_H
+#include <linux/i2c-sensor.h>
+#endif
+
+#ifdef EFX_NEED_LM90_DRIVER
+
+enum { lm90 = 1, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646 };
+
+/*
+ * The LM90 registers
+ */
+
+#define LM90_REG_R_MAN_ID              0xFE
+#define LM90_REG_R_CHIP_ID             0xFF
+#define LM90_REG_R_CONFIG1             0x03
+#define LM90_REG_W_CONFIG1             0x09
+#define LM90_REG_R_CONFIG2             0xBF
+#define LM90_REG_W_CONFIG2             0xBF
+#define LM90_REG_R_CONVRATE            0x04
+#define LM90_REG_W_CONVRATE            0x0A
+#define LM90_REG_R_STATUS              0x02
+#define LM90_REG_R_LOCAL_TEMP          0x00
+#define LM90_REG_R_LOCAL_HIGH          0x05
+#define LM90_REG_W_LOCAL_HIGH          0x0B
+#define LM90_REG_R_LOCAL_LOW           0x06
+#define LM90_REG_W_LOCAL_LOW           0x0C
+#define LM90_REG_R_LOCAL_CRIT          0x20
+#define LM90_REG_W_LOCAL_CRIT          0x20
+#define LM90_REG_R_REMOTE_TEMPH                0x01
+#define LM90_REG_R_REMOTE_TEMPL                0x10
+#define LM90_REG_R_REMOTE_OFFSH                0x11
+#define LM90_REG_W_REMOTE_OFFSH                0x11
+#define LM90_REG_R_REMOTE_OFFSL                0x12
+#define LM90_REG_W_REMOTE_OFFSL                0x12
+#define LM90_REG_R_REMOTE_HIGHH                0x07
+#define LM90_REG_W_REMOTE_HIGHH                0x0D
+#define LM90_REG_R_REMOTE_HIGHL                0x13
+#define LM90_REG_W_REMOTE_HIGHL                0x13
+#define LM90_REG_R_REMOTE_LOWH         0x08
+#define LM90_REG_W_REMOTE_LOWH         0x0E
+#define LM90_REG_R_REMOTE_LOWL         0x14
+#define LM90_REG_W_REMOTE_LOWL         0x14
+#define LM90_REG_R_REMOTE_CRIT         0x19
+#define LM90_REG_W_REMOTE_CRIT         0x19
+#define LM90_REG_R_TCRIT_HYST          0x21
+#define LM90_REG_W_TCRIT_HYST          0x21
+
+/* MAX6646/6647/6649/6657/6658/6659 registers */
+
+#define MAX6657_REG_R_LOCAL_TEMPL      0x11
+
+/*
+ * Device flags
+ */
+#define LM90_FLAG_ADT7461_EXT          0x01    /* ADT7461 extended mode */
+
+/*
+ * Functions declaration
+ */
+
+static void lm90_init_client(struct i2c_client *client);
+static int lm90_remove(struct i2c_client *client);
+#ifdef EFX_USE_I2C_LEGACY
+static int lm90_detach_client(struct i2c_client *client);
+#endif
+static struct lm90_data *lm90_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+#if !defined(EFX_USE_I2C_LEGACY) && !defined(EFX_HAVE_OLD_I2C_DRIVER_PROBE)
+static const struct i2c_device_id lm90_id[] = {
+        { "sfc_max6647" },
+        { }
+};
+#endif
+
+struct i2c_driver efx_lm90_driver = {
+#ifdef EFX_USE_I2C_DRIVER_NAME
+       .name           = "sfc_lm90",
+#else
+       .driver.name    = "sfc_lm90",
+#endif
+#ifdef EFX_USE_I2C_LEGACY
+        .detach_client  = lm90_detach_client,
+#else
+       .probe          = efx_lm90_probe,
+       .remove         = lm90_remove,
+#ifndef EFX_HAVE_OLD_I2C_DRIVER_PROBE
+       .id_table       = lm90_id,
+#endif
+#endif
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct lm90_data {
+#ifdef EFX_HAVE_HWMON_CLASS_DEVICE
+        struct class_device *hwmon_dev;
+#else
+       struct device *hwmon_dev;
+#endif
+       struct mutex update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+       int kind;
+       int flags;
+
+       /* registers values */
+       s8 temp8[4];    /* 0: local low limit
+                          1: local high limit
+                          2: local critical limit
+                          3: remote critical limit */
+       s16 temp11[5];  /* 0: remote input
+                          1: remote low limit
+                          2: remote high limit
+                          3: remote offset (except max6646 and max6657)
+                          4: local input */
+       u8 temp_hyst;
+       u8 alarms; /* bitvector */
+};
+
+/*
+ * Conversions
+ * For local temperatures and limits, critical limits and the hysteresis
+ * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
+ * For remote temperatures and limits, it uses signed 11-bit values with
+ * LSB = 0.125 degree Celsius, left-justified in 16-bit registers.  Some
+ * Maxim chips use unsigned values.
+ */
+
+static inline int temp_from_s8(s8 val)
+{
+       return val * 1000;
+}
+
+static inline int temp_from_u8(u8 val)
+{
+       return val * 1000;
+}
+
+static inline int temp_from_s16(s16 val)
+{
+       return val / 32 * 125;
+}
+
+static inline int temp_from_u16(u16 val)
+{
+       return val / 32 * 125;
+}
+
+static s8 temp_to_s8(long val)
+{
+       if (val <= -128000)
+               return -128;
+       if (val >= 127000)
+               return 127;
+       if (val < 0)
+               return (val - 500) / 1000;
+       return (val + 500) / 1000;
+}
+
+static u8 temp_to_u8(long val)
+{
+       if (val <= 0)
+               return 0;
+       if (val >= 255000)
+               return 255;
+       return (val + 500) / 1000;
+}
+
+static s16 temp_to_s16(long val)
+{
+       if (val <= -128000)
+               return 0x8000;
+       if (val >= 127875)
+               return 0x7FE0;
+       if (val < 0)
+               return (val - 62) / 125 * 32;
+       return (val + 62) / 125 * 32;
+}
+
+static u8 hyst_to_reg(long val)
+{
+       if (val <= 0)
+               return 0;
+       if (val >= 30500)
+               return 31;
+       return (val + 500) / 1000;
+}
+
+/*
+ * ADT7461 in compatibility mode is almost identical to LM90 except that
+ * attempts to write values that are outside the range 0 < temp < 127 are
+ * treated as the boundary value.
+ *
+ * ADT7461 in "extended mode" operation uses unsigned integers offset by
+ * 64 (e.g., 0 -> -64 degC).  The range is restricted to -64..191 degC.
+ */
+static inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val)
+{
+       if (data->flags & LM90_FLAG_ADT7461_EXT)
+               return (val - 64) * 1000;
+       else
+               return temp_from_s8(val);
+}
+
+static inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val)
+{
+       if (data->flags & LM90_FLAG_ADT7461_EXT)
+               return (val - 0x4000) / 64 * 250;
+       else
+               return temp_from_s16(val);
+}
+
+static u8 temp_to_u8_adt7461(struct lm90_data *data, long val)
+{
+       if (data->flags & LM90_FLAG_ADT7461_EXT) {
+               if (val <= -64000)
+                       return 0;
+               if (val >= 191000)
+                       return 0xFF;
+               return (val + 500 + 64000) / 1000;
+       } else {
+               if (val <= 0)
+                       return 0;
+               if (val >= 127000)
+                       return 127;
+               return (val + 500) / 1000;
+       }
+}
+
+static u16 temp_to_u16_adt7461(struct lm90_data *data, long val)
+{
+       if (data->flags & LM90_FLAG_ADT7461_EXT) {
+               if (val <= -64000)
+                       return 0;
+               if (val >= 191750)
+                       return 0xFFC0;
+               return (val + 64000 + 125) / 250 * 64;
+       } else {
+               if (val <= 0)
+                       return 0;
+               if (val >= 127750)
+                       return 0x7FC0;
+               return (val + 125) / 250 * 64;
+       }
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
+                         char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm90_data *data = lm90_update_device(dev);
+       int temp;
+
+       if (data->kind == adt7461)
+               temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
+       else if (data->kind == max6646)
+               temp = temp_from_u8(data->temp8[attr->index]);
+       else
+               temp = temp_from_s8(data->temp8[attr->index]);
+
+       return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+                        const char *buf, size_t count)
+{
+       static const u8 reg[4] = {
+               LM90_REG_W_LOCAL_LOW,
+               LM90_REG_W_LOCAL_HIGH,
+               LM90_REG_W_LOCAL_CRIT,
+               LM90_REG_W_REMOTE_CRIT,
+       };
+
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm90_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       int nr = attr->index;
+
+       mutex_lock(&data->update_lock);
+       if (data->kind == adt7461)
+               data->temp8[nr] = temp_to_u8_adt7461(data, val);
+       else if (data->kind == max6646)
+               data->temp8[nr] = temp_to_u8(val);
+       else
+               data->temp8[nr] = temp_to_s8(val);
+       i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
+                          char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm90_data *data = lm90_update_device(dev);
+       int temp;
+
+       if (data->kind == adt7461)
+               temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
+       else if (data->kind == max6646)
+               temp = temp_from_u16(data->temp11[attr->index]);
+       else
+               temp = temp_from_s16(data->temp11[attr->index]);
+
+       return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
+                         const char *buf, size_t count)
+{
+       static const u8 reg[6] = {
+               LM90_REG_W_REMOTE_LOWH,
+               LM90_REG_W_REMOTE_LOWL,
+               LM90_REG_W_REMOTE_HIGHH,
+               LM90_REG_W_REMOTE_HIGHL,
+               LM90_REG_W_REMOTE_OFFSH,
+               LM90_REG_W_REMOTE_OFFSL,
+       };
+
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm90_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       int nr = attr->index;
+
+       mutex_lock(&data->update_lock);
+       if (data->kind == adt7461)
+               data->temp11[nr] = temp_to_u16_adt7461(data, val);
+       else if (data->kind == max6657 || data->kind == max6680)
+               data->temp11[nr] = temp_to_s8(val) << 8;
+       else if (data->kind == max6646)
+               data->temp11[nr] = temp_to_u8(val) << 8;
+       else
+               data->temp11[nr] = temp_to_s16(val);
+
+       i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
+                                 data->temp11[nr] >> 8);
+       if (data->kind != max6657 && data->kind != max6680
+           && data->kind != max6646)
+               i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
+                                         data->temp11[nr] & 0xff);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr,
+                            char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm90_data *data = lm90_update_device(dev);
+       int temp;
+
+       if (data->kind == adt7461)
+               temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
+       else
+               temp = temp_from_s8(data->temp8[attr->index]);
+
+       return sprintf(buf, "%d\n", temp - temp_from_s8(data->temp_hyst));
+}
+
+static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm90_data *data = i2c_get_clientdata(client);
+       long val = simple_strtol(buf, NULL, 10);
+       long hyst;
+
+       mutex_lock(&data->update_lock);
+       hyst = temp_from_s8(data->temp8[2]) - val;
+       i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
+                                 hyst_to_reg(hyst));
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
+                          char *buf)
+{
+       struct lm90_data *data = lm90_update_device(dev);
+       return sprintf(buf, "%d\n", data->alarms);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+                         *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm90_data *data = lm90_update_device(dev);
+       int bitnr = attr->index;
+
+       return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
+       set_temp8, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
+       set_temp11, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
+       set_temp8, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
+       set_temp11, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
+       set_temp8, 2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
+       set_temp8, 3);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
+       set_temphyst, 2);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+       set_temp11, 3);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm90_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &dev_attr_alarms.attr,
+       NULL
+};
+
+static const struct attribute_group lm90_group = {
+       .attrs = lm90_attributes,
+};
+
+/* pec used for ADM1032 only */
+static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
+                       char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
+}
+
+static ssize_t set_pec(struct device *dev, struct device_attribute *dummy,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       long val = simple_strtol(buf, NULL, 10);
+
+       switch (val) {
+       case 0:
+               client->flags &= ~I2C_CLIENT_PEC;
+               break;
+       case 1:
+               client->flags |= I2C_CLIENT_PEC;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
+
+/*
+ * Real code
+ */
+
+/* The ADM1032 supports PEC but not on write byte transactions, so we need
+   to explicitly ask for a transaction without PEC. */
+static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
+{
+       return i2c_smbus_xfer(client->adapter, client->addr,
+                             client->flags & ~I2C_CLIENT_PEC,
+                             I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
+}
+
+/* It is assumed that client->update_lock is held (unless we are in
+   detection or initialization steps). This matters when PEC is enabled,
+   because we don't want the address pointer to change between the write
+   byte and the read byte transactions. */
+static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value)
+{
+       int err;
+
+       if (client->flags & I2C_CLIENT_PEC) {
+               err = adm1032_write_byte(client, reg);
+               if (err >= 0)
+                       err = i2c_smbus_read_byte(client);
+       } else
+               err = i2c_smbus_read_byte_data(client, reg);
+
+       if (err < 0) {
+               dev_warn(&client->dev, "Register %#02x read failed (%d)\n",
+                        reg, err);
+               return err;
+       }
+       *value = err;
+
+       return 0;
+}
+
+#ifdef EFX_HAVE_OLD_I2C_DRIVER_PROBE
+int efx_lm90_probe(struct i2c_client *new_client)
+#else
+int efx_lm90_probe(struct i2c_client *new_client,
+                  const struct i2c_device_id *id)
+#endif
+{
+       struct lm90_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       i2c_set_clientdata(new_client, data);
+       mutex_init(&data->update_lock);
+
+       /* Set the device type */
+       data->kind = max6646;
+
+       /* Initialize the LM90 chip */
+       lm90_init_client(new_client);
+
+       /* Register sysfs hooks */
+       if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
+               goto exit_free;
+       if (new_client->flags & I2C_CLIENT_PEC) {
+               if ((err = device_create_file(&new_client->dev,
+                                             &dev_attr_pec)))
+                       goto exit_remove_files;
+       }
+       if (data->kind != max6657 && data->kind != max6646) {
+               if ((err = device_create_file(&new_client->dev,
+                               &sensor_dev_attr_temp2_offset.dev_attr)))
+                       goto exit_remove_files;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
+       device_remove_file(&new_client->dev, &dev_attr_pec);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static void lm90_init_client(struct i2c_client *client)
+{
+       u8 config, config_orig;
+       struct lm90_data *data = i2c_get_clientdata(client);
+
+       /*
+        * Start the conversions.
+        */
+       i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
+                                 5); /* 2 Hz */
+       if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
+               dev_warn(&client->dev, "Initialization failed!\n");
+               return;
+       }
+       config_orig = config;
+
+       /* Check Temperature Range Select */
+       if (data->kind == adt7461) {
+               if (config & 0x04)
+                       data->flags |= LM90_FLAG_ADT7461_EXT;
+       }
+
+       /*
+        * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+        * 0.125 degree resolution) and range (0x08, extend range
+        * to -64 degree) mode for the remote temperature sensor.
+        */
+       if (data->kind == max6680) {
+               config |= 0x18;
+       }
+
+       config &= 0xBF; /* run */
+       if (config != config_orig) /* Only write if changed */
+               i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+}
+
+static int lm90_remove(struct i2c_client *client)
+{
+       struct lm90_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm90_group);
+       device_remove_file(&client->dev, &dev_attr_pec);
+       if (data->kind != max6657 && data->kind != max6646)
+               device_remove_file(&client->dev,
+                                  &sensor_dev_attr_temp2_offset.dev_attr);
+
+       kfree(data);
+       return 0;
+}
+
+#ifdef EFX_USE_I2C_LEGACY
+static int lm90_detach_client(struct i2c_client *client)
+{
+        int err;
+
+        lm90_remove(client);
+        err = i2c_detach_client(client);
+        if (!err)
+                kfree(client);
+        return err;
+}
+#endif
+
+static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
+{
+       int err;
+       u8 oldh, newh, l;
+
+       /*
+        * There is a trick here. We have to read two registers to have the
+        * sensor temperature, but we have to beware a conversion could occur
+        * inbetween the readings. The datasheet says we should either use
+        * the one-shot conversion register, which we don't want to do
+        * (disables hardware monitoring) or monitor the busy bit, which is
+        * impossible (we can't read the values and monitor that bit at the
+        * exact same time). So the solution used here is to read the high
+        * byte once, then the low byte, then the high byte again. If the new
+        * high byte matches the old one, then we have a valid reading. Else
+        * we have to read the low byte again, and now we believe we have a
+        * correct reading.
+        */
+       if ((err = lm90_read_reg(client, regh, &oldh))
+        || (err = lm90_read_reg(client, regl, &l))
+        || (err = lm90_read_reg(client, regh, &newh)))
+               return err;
+       if (oldh != newh) {
+               err = lm90_read_reg(client, regl, &l);
+               if (err)
+                       return err;
+       }
+       *value = (newh << 8) | l;
+
+       return 0;
+}
+
+static struct lm90_data *lm90_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm90_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
+               u8 h, l;
+
+               dev_dbg(&client->dev, "Updating lm90 data.\n");
+               lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[0]);
+               lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, &data->temp8[1]);
+               lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, &data->temp8[2]);
+               lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]);
+               lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
+
+               if (data->kind == max6657 || data->kind == max6646) {
+                       lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
+                                   MAX6657_REG_R_LOCAL_TEMPL,
+                                   &data->temp11[4]);
+               } else {
+                       if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP,
+                                         &h) == 0)
+                               data->temp11[4] = h << 8;
+               }
+               lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
+                           LM90_REG_R_REMOTE_TEMPL, &data->temp11[0]);
+
+               if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) {
+                       data->temp11[1] = h << 8;
+                       if (data->kind != max6657 && data->kind != max6680
+                        && data->kind != max6646
+                        && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL,
+                                         &l) == 0)
+                               data->temp11[1] |= l;
+               }
+               if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) {
+                       data->temp11[2] = h << 8;
+                       if (data->kind != max6657 && data->kind != max6680
+                        && data->kind != max6646
+                        && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL,
+                                         &l) == 0)
+                               data->temp11[2] |= l;
+               }
+
+               if (data->kind != max6657 && data->kind != max6646) {
+                       if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
+                                         &h) == 0
+                        && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
+                                         &l) == 0)
+                               data->temp11[3] = (h << 8) | l;
+               }
+               lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+#endif /* EFX_NEED_LM90_DRIVER */
index 2273686b7acb3bec4de0d91212a1478466724111..f1aa5f37489036adb028b6d306a04e5a7d15203c 100644 (file)
@@ -1,28 +1,11 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2005-2006: Fen Systems Ltd.
- * Copyright 2006-2007: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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_MAC_H
 
 #include "net_driver.h"
 
-extern void mentormac_reset(struct efx_nic *efx);
-extern void mentormac_reconfigure(struct efx_nic *efx);
 extern struct efx_mac_operations falcon_gmac_operations;
 extern struct efx_mac_operations falcon_xmac_operations;
+extern struct efx_mac_operations efx_mcdi_mac_operations;
+extern void falcon_reconfigure_xmac_core(struct efx_nic *efx);
+extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
+                             u32 dma_len, int enable, int clear);
 
 #endif
diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c
new file mode 100644 (file)
index 0000000..2c1f0d1
--- /dev/null
@@ -0,0 +1,1178 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2008-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.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "nic.h"
+#include "io.h"
+#include "regs.h"
+#include "mcdi_pcol.h"
+#include "phy.h"
+
+/**************************************************************************
+ *
+ * Management-Controller-to-Driver Interface
+ *
+ **************************************************************************
+ */
+
+/* Software-defined structure to the shared-memory */
+#define CMD_NOTIFY_PORT0 0
+#define CMD_NOTIFY_PORT1 4
+#define CMD_PDU_PORT0    0x008
+#define CMD_PDU_PORT1    0x108
+#define REBOOT_FLAG_PORT0 0x3f8
+#define REBOOT_FLAG_PORT1 0x3fc
+
+#define MCDI_RPC_TIMEOUT       10 /*seconds */
+
+#define MCDI_PDU(efx)                                                  \
+       (efx_port_num(efx) ? CMD_PDU_PORT1 : CMD_PDU_PORT0)
+#define MCDI_DOORBELL(efx)                                             \
+       (efx_port_num(efx) ? CMD_NOTIFY_PORT1 : CMD_NOTIFY_PORT0)
+#define MCDI_REBOOT_FLAG(efx)                                          \
+       (efx_port_num(efx) ? REBOOT_FLAG_PORT1 : REBOOT_FLAG_PORT0)
+
+#define SEQ_MASK                                                       \
+       EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ))
+
+static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
+{
+       struct siena_nic_data *nic_data;
+       EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
+       nic_data = efx->nic_data;
+       return &nic_data->mcdi;
+}
+
+void efx_mcdi_init(struct efx_nic *efx)
+{
+       struct efx_mcdi_iface *mcdi;
+
+       if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
+               return;
+
+       mcdi = efx_mcdi(efx);
+       init_waitqueue_head(&mcdi->wq);
+       spin_lock_init(&mcdi->iface_lock);
+       atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
+       mcdi->mode = MCDI_MODE_POLL;
+
+       (void) efx_mcdi_poll_reboot(efx);
+}
+
+static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd,
+                           const u8 *inbuf, size_t inlen)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+       unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+       unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx);
+       unsigned int i;
+       efx_dword_t hdr;
+       u32 xflags, seqno;
+
+       BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
+       BUG_ON(inlen & 3 || inlen >= 0x100);
+
+       seqno = mcdi->seqno & SEQ_MASK;
+       xflags = 0;
+       if (mcdi->mode == MCDI_MODE_EVENTS)
+               xflags |= MCDI_HEADER_XFLAGS_EVREQ;
+
+       EFX_POPULATE_DWORD_6(hdr,
+                            MCDI_HEADER_RESPONSE, 0,
+                            MCDI_HEADER_RESYNC, 1,
+                            MCDI_HEADER_CODE, cmd,
+                            MCDI_HEADER_DATALEN, inlen,
+                            MCDI_HEADER_SEQ, seqno,
+                            MCDI_HEADER_XFLAGS, xflags);
+
+       efx_writed(efx, &hdr, pdu);
+
+       for (i = 0; i < inlen; i += 4)
+               _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i);
+
+       /* Ensure the payload is written out before the header */
+       wmb();
+
+       /* ring the doorbell with a distinctive value */
+       _efx_writed(efx, (__force __le32) 0x45789abc, doorbell);
+}
+
+static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+       unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+       int i;
+
+       BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT);
+       BUG_ON(outlen & 3 || outlen >= 0x100);
+
+       for (i = 0; i < outlen; i += 4)
+               *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i);
+}
+
+static int efx_mcdi_poll(struct efx_nic *efx)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+       unsigned int time, finish;
+       unsigned int respseq, respcmd, error;
+       unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx);
+       unsigned int rc, spins;
+       efx_dword_t reg;
+
+       /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
+       rc = efx_mcdi_poll_reboot(efx);
+       if (rc)
+               goto out;
+
+       /* Poll for completion. Poll quickly (once a us) for the 1st jiffy,
+        * because generally mcdi responses are fast. After that, back off
+        * and poll once a jiffy (approximately)
+        */
+       spins = TICK_USEC;
+       finish = get_seconds() + MCDI_RPC_TIMEOUT;
+
+       while (1) {
+               if (spins != 0) {
+                       --spins;
+                       udelay(1);
+               } else
+                       schedule();
+
+               time = get_seconds();
+
+               rmb();
+               efx_readd(efx, &reg, pdu);
+
+               /* All 1's indicates that shared memory is in reset (and is
+                * not a valid header). Wait for it to come out reset before
+                * completing the command */
+               if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) != 0xffffffff &&
+                   EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE))
+                       break;
+
+               if (time >= finish)
+                       return -ETIMEDOUT;
+       }
+
+       mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN);
+       respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ);
+       respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE);
+       error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR);
+
+       if (error && mcdi->resplen == 0) {
+               EFX_ERR(efx, "MC rebooted\n");
+               rc = EIO;
+       } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) {
+               EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx seq 0x%x\n",
+                       respseq, mcdi->seqno);
+               rc = EIO;
+       } else if (error) {
+               efx_readd(efx, &reg, pdu + 4);
+               switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) {
+#define TRANSLATE_ERROR(name)                                  \
+               case MC_CMD_ERR_ ## name:                       \
+                       rc = name;                              \
+                       break
+                       TRANSLATE_ERROR(ENOENT);
+                       TRANSLATE_ERROR(EINTR);
+                       TRANSLATE_ERROR(EACCES);
+                       TRANSLATE_ERROR(EBUSY);
+                       TRANSLATE_ERROR(EINVAL);
+                       TRANSLATE_ERROR(EDEADLK);
+                       TRANSLATE_ERROR(ENOSYS);
+                       TRANSLATE_ERROR(ETIME);
+#undef TRANSLATE_ERROR
+               default:
+                       rc = EIO;
+                       break;
+               }
+       } else
+               rc = 0;
+
+out:
+       mcdi->resprc = rc;
+       if (rc)
+               mcdi->resplen = 0;
+
+       /* Return rc=0 like wait_event_timeout() */
+       return 0;
+}
+
+/* Test and clear MC-rebooted flag for this port/function */
+int efx_mcdi_poll_reboot(struct efx_nic *efx)
+{
+       unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx);
+       efx_dword_t reg;
+       uint32_t value;
+
+       if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
+               return false;
+
+       efx_readd(efx, &reg, addr);
+       value = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
+
+       if (value == 0)
+               return 0;
+
+       EFX_ZERO_DWORD(reg);
+       efx_writed(efx, &reg, addr);
+
+       if (value == MC_STATUS_DWORD_ASSERT)
+               return -EINTR;
+       else
+               return -EIO;
+}
+
+static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi)
+{
+       /* Wait until the interface becomes QUIESCENT and we win the race
+        * to mark it RUNNING. */
+       wait_event(mcdi->wq,
+                  atomic_cmpxchg(&mcdi->state,
+                                 MCDI_STATE_QUIESCENT,
+                                 MCDI_STATE_RUNNING)
+                  == MCDI_STATE_QUIESCENT);
+}
+
+static int efx_mcdi_await_completion(struct efx_nic *efx)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+
+       if (wait_event_timeout(
+                   mcdi->wq,
+                   atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED,
+                   msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0)
+               return -ETIMEDOUT;
+
+       /* Check if efx_mcdi_set_mode() switched us back to polled completions.
+        * In which case, poll for completions directly. If efx_mcdi_ev_cpl()
+        * completed the request first, then we'll just end up completing the
+        * request again, which is safe.
+        *
+        * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which
+        * wait_event_timeout() implicitly provides.
+        */
+       if (mcdi->mode == MCDI_MODE_POLL)
+               return efx_mcdi_poll(efx);
+
+       return 0;
+}
+
+static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi)
+{
+       /* If the interface is RUNNING, then move to COMPLETED and wake any
+        * waiters. If the interface isn't in RUNNING then we've received a
+        * duplicate completion after we've already transitioned back to
+        * QUIESCENT. [A subsequent invocation would increment seqno, so would
+        * have failed the seqno check].
+        */
+       if (atomic_cmpxchg(&mcdi->state,
+                          MCDI_STATE_RUNNING,
+                          MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) {
+               wake_up(&mcdi->wq);
+               return true;
+       }
+
+       return false;
+}
+
+static void efx_mcdi_release(struct efx_mcdi_iface *mcdi)
+{
+       atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT);
+       wake_up(&mcdi->wq);
+}
+
+static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno,
+                           unsigned int datalen, unsigned int errno)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+       bool wake = false;
+
+       spin_lock(&mcdi->iface_lock);
+
+       if ((seqno ^ mcdi->seqno) & SEQ_MASK) {
+               if (mcdi->credits)
+                       /* The request has been cancelled */
+                       --mcdi->credits;
+               else
+                       EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx "
+                               "seq 0x%x\n", seqno, mcdi->seqno);
+       } else {
+               mcdi->resprc = errno;
+               mcdi->resplen = datalen;
+
+               wake = true;
+       }
+
+       spin_unlock(&mcdi->iface_lock);
+
+       if (wake)
+               efx_mcdi_complete(mcdi);
+}
+
+/* Issue the given command by writing the data into the shared memory PDU,
+ * ring the doorbell and wait for completion. Copyout the result. */
+int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
+                const u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen,
+                size_t *outlen_actual)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+       int rc;
+       BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
+
+       efx_mcdi_acquire(mcdi);
+
+       /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
+       spin_lock_bh(&mcdi->iface_lock);
+       ++mcdi->seqno;
+       spin_unlock_bh(&mcdi->iface_lock);
+
+       efx_mcdi_copyin(efx, cmd, inbuf, inlen);
+
+       if (mcdi->mode == MCDI_MODE_POLL)
+               rc = efx_mcdi_poll(efx);
+       else
+               rc = efx_mcdi_await_completion(efx);
+
+       if (rc != 0) {
+               /* Close the race with efx_mcdi_ev_cpl() executing just too late
+                * and completing a request we've just cancelled, by ensuring
+                * that the seqno check therein fails.
+                */
+               spin_lock_bh(&mcdi->iface_lock);
+               ++mcdi->seqno;
+               ++mcdi->credits;
+               spin_unlock_bh(&mcdi->iface_lock);
+
+               EFX_ERR(efx, "MC command 0x%x inlen %d mode %d timed out\n",
+                       cmd, (int)inlen, mcdi->mode);
+       } else {
+               size_t resplen;
+
+               /* At the very least we need a memory barrier here to ensure
+                * we pick up changes from efx_mcdi_ev_cpl(). Protect against
+                * a spurious efx_mcdi_ev_cpl() running concurrently by
+                * acquiring the iface_lock. */
+               spin_lock_bh(&mcdi->iface_lock);
+               rc = -mcdi->resprc;
+               resplen = mcdi->resplen;
+               spin_unlock_bh(&mcdi->iface_lock);
+
+               if (rc == 0) {
+                       efx_mcdi_copyout(efx, outbuf,
+                                        min(outlen, mcdi->resplen + 3) & ~0x3);
+                       if (outlen_actual != NULL)
+                               *outlen_actual = resplen;
+               } else if (cmd == MC_CMD_REBOOT && rc == -EIO)
+                       ; /* Don't reset if MC_CMD_REBOOT returns EIO */
+               else if (rc == -EIO || rc == -EINTR) {
+                       EFX_ERR(efx, "MC fatal error %d\n", -rc);
+                       efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
+               } else
+                       EFX_ERR(efx, "MC command 0x%x inlen %d failed rc=%d\n",
+                               cmd, (int)inlen, -rc);
+       }
+
+       efx_mcdi_release(mcdi);
+       return rc;
+}
+
+void efx_mcdi_mode_poll(struct efx_nic *efx)
+{
+       struct efx_mcdi_iface *mcdi;
+
+       if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
+               return;
+
+       mcdi = efx_mcdi(efx);
+       if (mcdi->mode == MCDI_MODE_POLL)
+               return;
+
+       /* We can switch from event completion to polled completion, because
+        * mcdi requests are always completed in shared memory. We do this by
+        * switching the mode to POLL'd then completing the request.
+        * efx_mcdi_await_completion() will then call efx_mcdi_poll().
+        *
+        * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(),
+        * which efx_mcdi_complete() provides for us.
+        */
+       mcdi->mode = MCDI_MODE_POLL;
+
+       efx_mcdi_complete(mcdi);
+}
+
+void efx_mcdi_mode_event(struct efx_nic *efx)
+{
+       struct efx_mcdi_iface *mcdi;
+
+       if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
+               return;
+
+       mcdi = efx_mcdi(efx);
+
+       if (mcdi->mode == MCDI_MODE_EVENTS)
+               return;
+
+       /* We can't switch from polled to event completion in the middle of a
+        * request, because the completion method is specified in the request.
+        * So acquire the interface to serialise the requestors. We don't need
+        * to acquire the iface_lock to change the mode here, but we do need a
+        * write memory barrier ensure that efx_mcdi_rpc() sees it, which
+        * efx_mcdi_acquire() provides.
+        */
+       efx_mcdi_acquire(mcdi);
+       mcdi->mode = MCDI_MODE_EVENTS;
+       efx_mcdi_release(mcdi);
+}
+
+static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
+{
+       struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
+
+       /* If there is an outstanding MCDI request, it has been terminated
+        * either by a BADASSERT or REBOOT event. If the mcdi interface is
+        * in polled mode, then do nothing because the MC reboot handler will
+        * set the header correctly. However, if the mcdi interface is waiting
+        * for a CMDDONE event it won't receive it [and since all MCDI events
+        * are sent to the same queue, we can't be racing with
+        * efx_mcdi_ev_cpl()]
+        *
+        * There's a race here with efx_mcdi_rpc(), because we might receive
+        * a REBOOT event *before* the request has been copied out. In polled
+        * mode (during startup) this is irrelevent, because efx_mcdi_complete()
+        * is ignored. In event mode, this condition is just an edge-case of
+        * receiving a REBOOT event after posting the MCDI request. Did the mc
+        * reboot before or after the copyout? The best we can do always is
+        * just return failure.
+        */
+       spin_lock(&mcdi->iface_lock);
+       if (efx_mcdi_complete(mcdi)) {
+               if (mcdi->mode == MCDI_MODE_EVENTS) {
+                       mcdi->resprc = rc;
+                       mcdi->resplen = 0;
+               }
+       } else
+               /* Nobody was waiting for an MCDI request, so trigger a reset */
+               efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
+
+       spin_unlock(&mcdi->iface_lock);
+}
+
+static unsigned int efx_mcdi_event_link_speed[] = {
+       [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100,
+       [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000,
+       [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000,
+};
+
+
+static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
+{
+       u32 flags, fcntl, speed, lpa;
+
+       speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED);
+       EFX_BUG_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed));
+       speed = efx_mcdi_event_link_speed[speed];
+
+       flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS);
+       fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL);
+       lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP);
+
+       /* efx->link_state is only modified by efx_mcdi_phy_get_link(),
+        * which is only run after flushing the event queues. Therefore, it
+        * is safe to modify the link state outside of the mac_lock here.
+        */
+       efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl);
+
+       efx_mcdi_phy_check_fcntl(efx, lpa);
+
+       efx_link_status_changed(efx);
+}
+
+static const char *sensor_names[] = {
+       [MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor",
+       [MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor",
+       [MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling",
+       [MC_CMD_SENSOR_PHY0_TEMP] = "PHY 0 temp. sensor",
+       [MC_CMD_SENSOR_PHY0_COOLING] = "PHY 0 cooling",
+       [MC_CMD_SENSOR_PHY1_TEMP] = "PHY 1 temp. sensor",
+       [MC_CMD_SENSOR_PHY1_COOLING] = "PHY 1 cooling",
+       [MC_CMD_SENSOR_IN_1V0] = "1.0V supply sensor",
+       [MC_CMD_SENSOR_IN_1V2] = "1.2V supply sensor",
+       [MC_CMD_SENSOR_IN_1V8] = "1.8V supply sensor",
+       [MC_CMD_SENSOR_IN_2V5] = "2.5V supply sensor",
+       [MC_CMD_SENSOR_IN_3V3] = "3.3V supply sensor",
+       [MC_CMD_SENSOR_IN_12V0] = "12V supply sensor"
+};
+
+static const char *sensor_status_names[] = {
+       [MC_CMD_SENSOR_STATE_OK] = "OK",
+       [MC_CMD_SENSOR_STATE_WARNING] = "Warning",
+       [MC_CMD_SENSOR_STATE_FATAL] = "Fatal",
+       [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",
+};
+
+static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
+{
+       unsigned int monitor, state, value;
+       const char *name, *state_txt;
+       monitor = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
+       state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
+       value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);
+       /* Deal gracefully with the board having more drivers than we
+        * know about, but do not expect new sensor states. */
+       name = (monitor >= ARRAY_SIZE(sensor_names))
+                                   ? "No sensor name available" :
+                                   sensor_names[monitor];
+       EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
+       state_txt = sensor_status_names[state];
+
+       EFX_ERR(efx, "Sensor %d (%s) reports condition '%s' for raw value %d\n",
+               monitor, name, state_txt, value);
+}
+
+/* Called from  falcon_process_eventq for MCDI events */
+void efx_mcdi_process_event(struct efx_channel *channel,
+                           efx_qword_t *event)
+{
+       struct efx_nic *efx = channel->efx;
+       int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE);
+       u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA);
+
+       switch (code) {
+       case MCDI_EVENT_CODE_BADSSERT:
+               EFX_ERR(efx, "MC watchdog or assertion failure at 0x%x\n", data);
+               efx_mcdi_ev_death(efx, EINTR);
+               break;
+
+       case MCDI_EVENT_CODE_PMNOTICE:
+               EFX_INFO(efx, "MCDI PM event.\n");
+               break;
+
+       case MCDI_EVENT_CODE_CMDDONE:
+               efx_mcdi_ev_cpl(efx,
+                               MCDI_EVENT_FIELD(*event, CMDDONE_SEQ),
+                               MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN),
+                               MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO));
+               break;
+
+       case MCDI_EVENT_CODE_LINKCHANGE:
+               efx_mcdi_process_link_change(efx, event);
+               break;
+       case MCDI_EVENT_CODE_SENSOREVT:
+               efx_mcdi_sensor_event(efx, event);
+               break;
+       case MCDI_EVENT_CODE_SCHEDERR:
+               EFX_INFO(efx, "MC Scheduler error address=0x%x\n", data);
+               break;
+       case MCDI_EVENT_CODE_REBOOT:
+               EFX_INFO(efx, "MC Reboot\n");
+               efx_mcdi_ev_death(efx, EIO);
+               break;
+       case MCDI_EVENT_CODE_MAC_STATS_DMA:
+               /* MAC stats are gather lazily.  We can ignore this. */
+               break;
+
+       default:
+               EFX_ERR(efx, "Unknown MCDI event 0x%x\n", code);
+       }
+}
+
+/**************************************************************************
+ *
+ * Specific request functions
+ *
+ **************************************************************************
+ */
+
+int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build)
+{
+       u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)];
+       size_t outlength;
+       const __le16 *ver_words;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlength);
+       if (rc)
+               goto fail;
+
+       if (outlength == MC_CMD_GET_VERSION_V0_OUT_LEN) {
+               *version = 0;
+               *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE);
+               return 0;
+       }
+
+       if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) {
+               rc = -EMSGSIZE;
+               goto fail;
+       }
+
+       ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
+       *version = (((u64)le16_to_cpu(ver_words[0]) << 48) |
+                   ((u64)le16_to_cpu(ver_words[1]) << 32) |
+                   ((u64)le16_to_cpu(ver_words[2]) << 16) |
+                   le16_to_cpu(ver_words[3]));
+       *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE);
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
+                       bool *was_attached)
+{
+       u8 inbuf[MC_CMD_DRV_ATTACH_IN_LEN];
+       u8 outbuf[MC_CMD_DRV_ATTACH_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE,
+                      driver_operating ? 1 : 0);
+       MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+       if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN)
+               goto fail;
+
+       if (was_attached != NULL)
+               *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
+                          u16 *fw_subtype_list)
+{
+       uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN];
+       size_t outlen;
+       int port_num = efx_port_num(efx);
+       int offset;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LEN) {
+               rc = -EMSGSIZE;
+               goto fail;
+       }
+
+       offset = (port_num)
+               ? MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST
+               : MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST;
+       if (mac_address)
+               memcpy(mac_address, outbuf + offset, ETH_ALEN);
+       if (fw_subtype_list)
+               memcpy(fw_subtype_list,
+                      outbuf + MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST,
+                      MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN);
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d len=%d\n", __func__, rc, (int)outlen);
+
+       return rc;
+}
+
+int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
+{
+       u8 inbuf[MC_CMD_LOG_CTRL_IN_LEN];
+       u32 dest = 0;
+       int rc;
+
+       if (uart)
+               dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART;
+       if (evq)
+               dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ;
+
+       MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest);
+       MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq);
+
+       BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
+{
+       u8 outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+       if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN)
+               goto fail;
+
+       *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n",
+               __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
+                       size_t *size_out, size_t *erase_size_out,
+                       bool *protected_out)
+{
+       u8 inbuf[MC_CMD_NVRAM_INFO_IN_LEN];
+       u8 outbuf[MC_CMD_NVRAM_INFO_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+       if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN)
+               goto fail;
+
+       *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
+       *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
+       *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) &
+                               (1 << MC_CMD_NVRAM_PROTECTED_LBN));
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
+{
+       u8 inbuf[MC_CMD_NVRAM_UPDATE_START_IN_LEN];
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type);
+
+       BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
+                       loff_t offset, u8 *buffer, size_t length)
+{
+       u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN];
+       u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(length)];
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type);
+       MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset);
+       MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
+                          loff_t offset, const u8 *buffer, size_t length)
+{
+       u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(length)];
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type);
+       MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset);
+       MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length);
+       memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length);
+
+       BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
+                        loff_t offset, size_t length)
+{
+       u8 inbuf[MC_CMD_NVRAM_ERASE_IN_LEN];
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type);
+       MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset);
+       MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length);
+
+       BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
+{
+       u8 inbuf[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN];
+       u32 reboot;
+       int rc;
+
+       /* Reboot PHY's into the new firmware. mcfw reboot is handled
+        * explicity via ethtool. */
+       reboot = (type == MC_CMD_NVRAM_TYPE_PHY_PORT0 ||
+                 type == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||
+                 type == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);
+       MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type);
+       MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot);
+
+       BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type)
+{
+       u8 inbuf[MC_CMD_NVRAM_TEST_IN_LEN];
+       u8 outbuf[MC_CMD_NVRAM_TEST_OUT_LEN];
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), NULL);
+       if (rc)
+               return rc;
+
+       switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) {
+       case MC_CMD_NVRAM_TEST_PASS:
+       case MC_CMD_NVRAM_TEST_NOTSUPP:
+               return 0;
+       default:
+               return -EIO;
+       }
+}
+
+int efx_mcdi_nvram_test_all(struct efx_nic *efx)
+{
+       u32 nvram_types;
+       unsigned int type;
+       int rc;
+
+       rc = efx_mcdi_nvram_types(efx, &nvram_types);
+       if (rc)
+               return rc;
+
+       type = 0;
+       while (nvram_types != 0) {
+               if (nvram_types & 1) {
+                       rc = efx_mcdi_nvram_test(efx, type);
+                       if (rc)
+                               return rc;
+               }
+               type++;
+               nvram_types >>= 1;
+       }
+
+       return 0;
+}
+
+static int efx_mcdi_read_assertion(struct efx_nic *efx)
+{
+       u8 inbuf[MC_CMD_GET_ASSERTS_IN_LEN];
+       u8 outbuf[MC_CMD_GET_ASSERTS_OUT_LEN];
+       unsigned int flags, index, ofst;
+       const char *reason;
+       size_t outlen;
+       int retry;
+       int rc;
+
+       /* Attempt to read any stored assertion state before we reboot
+        * the mcfw out of the assertion handler. Retry twice, once
+        * because a boot-time assertion might cause this command to fail
+        * with EINTR. And once again because GET_ASSERTS can race with
+        * MC_CMD_REBOOT running on the other port. */
+       retry = 2;
+       do {
+               MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
+               rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
+                                 inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
+                                 outbuf, sizeof(outbuf), &outlen);
+       } while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
+
+       if (rc)
+               return rc;
+       if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
+               return -EINVAL;
+
+       /* Print out any recorded assertion state */
+       flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
+       if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
+               return 0;
+
+       reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
+               ? "system-level assertion"
+               : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
+               ? "thread-level assertion"
+               : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
+               ? "watchdog reset"
+               : "unknown assertion";
+       EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason,
+               MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS),
+               MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS));
+
+       /* Print out the registers */
+       ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
+       for (index = 1; index < 32; index++) {
+               EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index,
+                       MCDI_DWORD2(outbuf, ofst));
+               ofst += sizeof(efx_dword_t);
+       }
+
+       return 0;
+}
+
+static void efx_mcdi_exit_assertion(struct efx_nic *efx)
+{
+       u8 inbuf[MC_CMD_REBOOT_IN_LEN];
+
+       /* Atomically reboot the mcfw out of the assertion handler */
+       BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
+       MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS,
+                      MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION);
+       efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, MC_CMD_REBOOT_IN_LEN,
+                    NULL, 0, NULL);
+}
+
+int efx_mcdi_handle_assertion(struct efx_nic *efx)
+{
+       int rc;
+
+       rc = efx_mcdi_read_assertion(efx);
+       if (rc)
+               return rc;
+
+       efx_mcdi_exit_assertion(efx);
+
+       return 0;
+}
+
+void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+       u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN];
+       int rc;
+
+       BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF);
+       BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON);
+       BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT);
+
+       BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0);
+
+       MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+}
+
+int efx_mcdi_reset_port(struct efx_nic *efx)
+{
+       int rc = efx_mcdi_rpc(efx, MC_CMD_PORT_RESET, NULL, 0, NULL, 0, NULL);
+       if (rc)
+               EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_reset_mc(struct efx_nic *efx)
+{
+       u8 inbuf[MC_CMD_REBOOT_IN_LEN];
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0);
+       MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0);
+       rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       /* White is black, and up is down */
+       if (rc == -EIO)
+               return 0;
+       if (rc == 0)
+               rc = -EIO;
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
+                           const u8 *mac, int *id_out)
+{
+       u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN];
+       u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
+       MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
+                      MC_CMD_FILTER_MODE_SIMPLE);
+       memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
+               rc = -EMSGSIZE;
+               goto fail;
+       }
+
+       *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID);
+
+       return 0;
+
+fail:
+       *id_out = -1;
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+
+}
+
+
+int
+efx_mcdi_wol_filter_set_magic(struct efx_nic *efx,  const u8 *mac, int *id_out)
+{
+       return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out);
+}
+
+
+int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
+{
+       u8 outbuf[MC_CMD_WOL_FILTER_GET_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
+               rc = -EMSGSIZE;
+               goto fail;
+       }
+
+       *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID);
+
+       return 0;
+
+fail:
+       *id_out = -1;
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+
+int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
+{
+       u8 inbuf[MC_CMD_WOL_FILTER_REMOVE_IN_LEN];
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+
+int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
+{
+       int rc;
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h
new file mode 100644 (file)
index 0000000..2ca225d
--- /dev/null
@@ -0,0 +1,131 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2008-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.
+ */
+
+#ifndef EFX_MCDI_H
+#define EFX_MCDI_H
+
+/**
+ * enum efx_mcdi_state
+ * @MCDI_STATE_QUIESCENT: No pending MCDI requests. If the caller holds the
+ *     mcdi_lock then they are able to move to MCDI_STATE_RUNNING
+ * @MCDI_STATE_RUNNING: There is an MCDI request pending. Only the thread that
+ *     moved into this state is allowed to move out of it.
+ * @MCDI_STATE_COMPLETED: An MCDI request has completed, but the owning thread
+ *     has not yet consumed the result. For all other threads, equivalent to
+ *     MCDI_STATE_RUNNING.
+ */
+enum efx_mcdi_state {
+       MCDI_STATE_QUIESCENT,
+       MCDI_STATE_RUNNING,
+       MCDI_STATE_COMPLETED,
+};
+
+enum efx_mcdi_mode {
+       MCDI_MODE_POLL,
+       MCDI_MODE_EVENTS,
+};
+
+/**
+ * struct efx_mcdi_iface
+ * @state: Interface state. Waited for by mcdi_wq.
+ * @wq: Wait queue for threads waiting for state != STATE_RUNNING
+ * @iface_lock: Protects @credits, @seqno, @resprc, @resplen
+ * @mode: Poll for mcdi completion, or wait for an mcdi_event.
+ *     Serialised by @lock
+ * @seqno: The next sequence number to use for mcdi requests.
+ *     Serialised by @lock
+ * @credits: Number of spurious MCDI completion events allowed before we
+ *     trigger a fatal error. Protected by @lock
+ * @resprc: Returned MCDI completion
+ * @resplen: Returned payload length
+ */
+struct efx_mcdi_iface {
+       atomic_t state;
+       wait_queue_head_t wq;
+       spinlock_t iface_lock;
+       enum efx_mcdi_mode mode;
+       unsigned int credits;
+       unsigned int seqno;
+       unsigned int resprc;
+       size_t resplen;
+};
+
+extern void efx_mcdi_init(struct efx_nic *efx);
+
+extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf,
+                       size_t inlen, u8 *outbuf, size_t outlen,
+                       size_t *outlen_actual);
+
+extern int efx_mcdi_poll_reboot(struct efx_nic *efx);
+extern void efx_mcdi_mode_poll(struct efx_nic *efx);
+extern void efx_mcdi_mode_event(struct efx_nic *efx);
+
+extern void efx_mcdi_process_event(struct efx_channel *channel,
+                                  efx_qword_t *event);
+
+#define MCDI_PTR2(_buf, _ofst)                                         \
+       (((u8 *)_buf) + _ofst)
+#define MCDI_SET_DWORD2(_buf, _ofst, _value)                           \
+       EFX_POPULATE_DWORD_1(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)),  \
+                            EFX_DWORD_0, _value)
+#define MCDI_DWORD2(_buf, _ofst)                                       \
+       EFX_DWORD_FIELD(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)),       \
+                       EFX_DWORD_0)
+#define MCDI_QWORD2(_buf, _ofst)                                       \
+       EFX_QWORD_FIELD64(*((efx_qword_t *)MCDI_PTR2(_buf, _ofst)),     \
+                         EFX_QWORD_0)
+
+#define MCDI_PTR(_buf, _ofst)                                          \
+       MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST)
+#define MCDI_SET_DWORD(_buf, _ofst, _value)                            \
+       MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value)
+#define MCDI_DWORD(_buf, _ofst)                                                \
+       MCDI_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST)
+#define MCDI_QWORD(_buf, _ofst)                                                \
+       MCDI_QWORD2(_buf, MC_CMD_ ## _ofst ## _OFST)
+
+#define MCDI_EVENT_FIELD(_ev, _field)                  \
+       EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field)
+
+extern int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build);
+extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
+                              bool *was_attached_out);
+extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
+                                 u16 *fw_subtype_list);
+extern int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart,
+                            u32 dest_evq);
+extern int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out);
+extern int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
+                              size_t *size_out, size_t *erase_size_out,
+                              bool *protected_out);
+extern int efx_mcdi_nvram_update_start(struct efx_nic *efx,
+                                      unsigned int type);
+extern int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
+                              loff_t offset, u8 *buffer, size_t length);
+extern int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
+                               loff_t offset, const u8 *buffer,
+                               size_t length);
+extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
+                               loff_t offset, size_t length);
+extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx,
+                                       unsigned int type);
+extern int efx_mcdi_nvram_test_all(struct efx_nic *efx);
+extern int efx_mcdi_handle_assertion(struct efx_nic *efx);
+extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
+extern int efx_mcdi_reset_port(struct efx_nic *efx);
+extern int efx_mcdi_reset_mc(struct efx_nic *efx);
+extern int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
+                                  const u8 *mac, int *id_out);
+extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx,
+                                        const u8 *mac, int *id_out);
+extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out);
+extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id);
+extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx);
+
+#endif /* EFX_MCDI_H */
diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c
new file mode 100644 (file)
index 0000000..06d24a1
--- /dev/null
@@ -0,0 +1,152 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 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.
+ */
+
+#include "net_driver.h"
+#include "efx.h"
+#include "mac.h"
+#include "mcdi.h"
+#include "mcdi_pcol.h"
+
+static int efx_mcdi_set_mac(struct efx_nic *efx)
+{
+       u32 reject, fcntl;
+       u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN];
+
+       memcpy(cmdbytes + MC_CMD_SET_MAC_IN_ADDR_OFST,
+              efx->net_dev->dev_addr, ETH_ALEN);
+
+       MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU,
+                       EFX_MAX_FRAME_LEN(efx->net_dev->mtu));
+       MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0);
+
+       /* The MCDI command provides for controlling accept/reject
+        * of broadcast packets too, but the driver doesn't currently
+        * expose this. */
+       reject = (efx->promiscuous) ? 0 :
+               (1 << MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN);
+       MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_REJECT, reject);
+
+       switch (efx->wanted_fc) {
+       case EFX_FC_RX | EFX_FC_TX:
+               fcntl = MC_CMD_FCNTL_BIDIR;
+               break;
+       case EFX_FC_RX:
+               fcntl = MC_CMD_FCNTL_RESPOND;
+               break;
+       default:
+               fcntl = MC_CMD_FCNTL_OFF;
+               break;
+       }
+       if (efx->wanted_fc & EFX_FC_AUTO)
+               fcntl = MC_CMD_FCNTL_AUTO;
+
+       MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl);
+
+       return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes),
+                           NULL, 0, NULL);
+}
+
+static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults)
+{
+       u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
+       size_t outlength;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlength);
+       if (rc)
+               goto fail;
+
+       *faults = MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT);
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n",
+               __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
+                      u32 dma_len, int enable, int clear)
+{
+       u8 inbuf[MC_CMD_MAC_STATS_IN_LEN];
+       int rc;
+       efx_dword_t *cmd_ptr;
+       int period = 1000;
+       u32 addr_hi;
+       u32 addr_lo;
+
+       BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_LEN != 0);
+
+       addr_lo = ((u64)dma_addr) >> 0;
+       addr_hi = ((u64)dma_addr) >> 32;
+
+       MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo);
+       MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi);
+       cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD);
+       if (enable)
+               EFX_POPULATE_DWORD_6(*cmd_ptr,
+                                    MC_CMD_MAC_STATS_CMD_DMA, 1,
+                                    MC_CMD_MAC_STATS_CMD_CLEAR, clear,
+                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1,
+                                    MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 1,
+                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0,
+                                    MC_CMD_MAC_STATS_CMD_PERIOD_MS, period);
+       else
+               EFX_POPULATE_DWORD_5(*cmd_ptr,
+                                    MC_CMD_MAC_STATS_CMD_DMA, 0,
+                                    MC_CMD_MAC_STATS_CMD_CLEAR, clear,
+                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1,
+                                    MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 0,
+                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0);
+       MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: %s failed rc=%d\n",
+               __func__, enable ? "enable" : "disable", rc);
+       return rc;
+}
+
+static int efx_mcdi_mac_reconfigure(struct efx_nic *efx)
+{
+       int rc;
+
+       rc = efx_mcdi_set_mac(efx);
+       if (rc != 0)
+               return rc;
+
+       /* Restore the multicast hash registers. */
+       efx->type->push_multicast_hash(efx);
+
+       return 0;
+}
+
+
+static bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
+{
+       u32 faults;
+       int rc = efx_mcdi_get_mac_faults(efx, &faults);
+       return (rc != 0) || (faults != 0);
+}
+
+
+struct efx_mac_operations efx_mcdi_mac_operations = {
+       .reconfigure    = efx_mcdi_mac_reconfigure,
+       .update_stats   = efx_port_dummy_op_void,
+       .check_fault    = efx_mcdi_mac_check_fault,
+};
diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h
new file mode 100644 (file)
index 0000000..b6239e6
--- /dev/null
@@ -0,0 +1,1729 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 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.
+ */
+
+
+#ifndef MCDI_PCOL_H
+#define MCDI_PCOL_H
+
+/* Values to be written into FMCR_CZ_RESET_STATE_REG to control boot. */
+/* Power-on reset state */
+#define MC_FW_STATE_POR (1)
+/* If this is set in MC_RESET_STATE_REG then it should be
+ * possible to jump into IMEM without loading code from flash. */
+#define MC_FW_WARM_BOOT_OK (2)
+/* The MC main image has started to boot. */
+#define MC_FW_STATE_BOOTING (4)
+/* The Scheduler has started. */
+#define MC_FW_STATE_SCHED (8)
+
+/* Values to be written to the per-port status dword in shared
+ * memory on reboot and assert */
+#define MC_STATUS_DWORD_REBOOT (0xb007b007)
+#define MC_STATUS_DWORD_ASSERT (0xdeaddead)
+
+/* The current version of the MCDI protocol.
+ *
+ * Note that the ROM burnt into the card only talks V0, so at the very
+ * least every driver must support version 0 and MCDI_PCOL_VERSION
+ */
+#define MCDI_PCOL_VERSION 1
+
+/**
+ * MCDI version 1
+ *
+ * Each MCDI request starts with an MCDI_HEADER, which is a 32byte
+ * structure, filled in by the client.
+ *
+ *       0       7  8     16    20     22  23  24    31
+ *      | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS |
+ *               |                      |   |
+ *               |                      |   \--- Response
+ *               |                      \------- Error
+ *               \------------------------------ Resync (always set)
+ *
+ * The client writes it's request into MC shared memory, and rings the
+ * doorbell. Each request is completed by either by the MC writting
+ * back into shared memory, or by writting out an event.
+ *
+ * All MCDI commands support completion by shared memory response. Each
+ * request may also contain additional data (accounted for by HEADER.LEN),
+ * and some response's may also contain additional data (again, accounted
+ * for by HEADER.LEN).
+ *
+ * Some MCDI commands support completion by event, in which any associated
+ * response data is included in the event.
+ *
+ * The protocol requires one response to be delivered for every request, a
+ * request should not be sent unless the response for the previous request
+ * has been received (either by polling shared memory, or by receiving
+ * an event).
+ */
+
+/** Request/Response structure */
+#define MCDI_HEADER_OFST 0
+#define MCDI_HEADER_CODE_LBN 0
+#define MCDI_HEADER_CODE_WIDTH 7
+#define MCDI_HEADER_RESYNC_LBN 7
+#define MCDI_HEADER_RESYNC_WIDTH 1
+#define MCDI_HEADER_DATALEN_LBN 8
+#define MCDI_HEADER_DATALEN_WIDTH 8
+#define MCDI_HEADER_SEQ_LBN 16
+#define MCDI_HEADER_RSVD_LBN 20
+#define MCDI_HEADER_RSVD_WIDTH 2
+#define MCDI_HEADER_SEQ_WIDTH 4
+#define MCDI_HEADER_ERROR_LBN 22
+#define MCDI_HEADER_ERROR_WIDTH 1
+#define MCDI_HEADER_RESPONSE_LBN 23
+#define MCDI_HEADER_RESPONSE_WIDTH 1
+#define MCDI_HEADER_XFLAGS_LBN 24
+#define MCDI_HEADER_XFLAGS_WIDTH 8
+/* Request response using event */
+#define MCDI_HEADER_XFLAGS_EVREQ 0x01
+
+/* Maximum number of payload bytes */
+#define MCDI_CTL_SDU_LEN_MAX 0xfc
+
+/* The MC can generate events for two reasons:
+ *   - To complete a shared memory request if XFLAGS_EVREQ was set
+ *   - As a notification (link state, i2c event), controlled
+ *     via MC_CMD_LOG_CTRL
+ *
+ * Both events share a common structure:
+ *
+ *  0      32     33      36    44     52     60
+ * | Data | Cont | Level | Src | Code | Rsvd |
+ *           |
+ *           \ There is another event pending in this notification
+ *
+ * If Code==CMDDONE, then the fields are further interpreted as:
+ *
+ *   - LEVEL==INFO    Command succeded
+ *   - LEVEL==ERR     Command failed
+ *
+ *    0     8         16      24     32
+ *   | Seq | Datalen | Errno | Rsvd |
+ *
+ *   These fields are taken directly out of the standard MCDI header, i.e.,
+ *   LEVEL==ERR, Datalen == 0 => Reboot
+ *
+ * Events can be squirted out of the UART (using LOG_CTRL) without a
+ * MCDI header.  An event can be distinguished from a MCDI response by
+ * examining the first byte which is 0xc0.  This corresponds to the
+ * non-existent MCDI command MC_CMD_DEBUG_LOG.
+ *
+ *      0         7        8
+ *     | command | Resync |     = 0xc0
+ *
+ * Since the event is written in big-endian byte order, this works
+ * providing bits 56-63 of the event are 0xc0.
+ *
+ *      56     60  63
+ *     | Rsvd | Code |    = 0xc0
+ *
+ * Which means for convenience the event code is 0xc for all MC
+ * generated events.
+ */
+#define FSE_AZ_EV_CODE_MCDI_EVRESPONSE 0xc
+
+#define MCDI_EVENT_DATA_LBN 0
+#define MCDI_EVENT_DATA_WIDTH 32
+#define MCDI_EVENT_CONT_LBN 32
+#define MCDI_EVENT_CONT_WIDTH 1
+#define MCDI_EVENT_LEVEL_LBN 33
+#define MCDI_EVENT_LEVEL_WIDTH 3
+#define MCDI_EVENT_LEVEL_INFO (0)
+#define MCDI_EVENT_LEVEL_WARN (1)
+#define MCDI_EVENT_LEVEL_ERR (2)
+#define MCDI_EVENT_LEVEL_FATAL (3)
+#define MCDI_EVENT_SRC_LBN 36
+#define MCDI_EVENT_SRC_WIDTH 8
+#define MCDI_EVENT_CODE_LBN 44
+#define MCDI_EVENT_CODE_WIDTH 8
+#define MCDI_EVENT_CODE_BADSSERT (1)
+#define MCDI_EVENT_CODE_PMNOTICE (2)
+#define MCDI_EVENT_CODE_CMDDONE (3)
+#define  MCDI_EVENT_CMDDONE_SEQ_LBN 0
+#define  MCDI_EVENT_CMDDONE_SEQ_WIDTH 8
+#define  MCDI_EVENT_CMDDONE_DATALEN_LBN 8
+#define  MCDI_EVENT_CMDDONE_DATALEN_WIDTH 8
+#define  MCDI_EVENT_CMDDONE_ERRNO_LBN 16
+#define  MCDI_EVENT_CMDDONE_ERRNO_WIDTH 8
+#define MCDI_EVENT_CODE_LINKCHANGE (4)
+#define  MCDI_EVENT_LINKCHANGE_LP_CAP_LBN 0
+#define  MCDI_EVENT_LINKCHANGE_LP_CAP_WIDTH 16
+#define  MCDI_EVENT_LINKCHANGE_SPEED_LBN 16
+#define  MCDI_EVENT_LINKCHANGE_SPEED_WIDTH 4
+#define  MCDI_EVENT_LINKCHANGE_SPEED_100M 1
+#define  MCDI_EVENT_LINKCHANGE_SPEED_1G 2
+#define  MCDI_EVENT_LINKCHANGE_SPEED_10G 3
+#define  MCDI_EVENT_LINKCHANGE_FCNTL_LBN 20
+#define  MCDI_EVENT_LINKCHANGE_FCNTL_WIDTH 4
+#define  MCDI_EVENT_LINKCHANGE_LINK_FLAGS_LBN 24
+#define  MCDI_EVENT_LINKCHANGE_LINK_FLAGS_WIDTH 8
+#define MCDI_EVENT_CODE_SENSOREVT (5)
+#define  MCDI_EVENT_SENSOREVT_MONITOR_LBN 0
+#define  MCDI_EVENT_SENSOREVT_MONITOR_WIDTH 8
+#define  MCDI_EVENT_SENSOREVT_STATE_LBN 8
+#define  MCDI_EVENT_SENSOREVT_STATE_WIDTH 8
+#define  MCDI_EVENT_SENSOREVT_VALUE_LBN 16
+#define  MCDI_EVENT_SENSOREVT_VALUE_WIDTH 16
+#define MCDI_EVENT_CODE_SCHEDERR (6)
+#define MCDI_EVENT_CODE_REBOOT (7)
+#define MCDI_EVENT_CODE_MAC_STATS_DMA (8)
+#define  MCDI_EVENT_MAC_STATS_DMA_GENERATION_LBN 0
+#define  MCDI_EVENT_MAC_STATS_DMA_GENERATION_WIDTH 32
+
+/* Non-existent command target */
+#define MC_CMD_ERR_ENOENT 2
+/* assert() has killed the MC */
+#define MC_CMD_ERR_EINTR 4
+/* Caller does not hold required locks */
+#define MC_CMD_ERR_EACCES 13
+/* Resource is currently unavailable (e.g. lock contention) */
+#define MC_CMD_ERR_EBUSY 16
+/* Invalid argument to target */
+#define MC_CMD_ERR_EINVAL 22
+/* Non-recursive resource is already acquired */
+#define MC_CMD_ERR_EDEADLK 35
+/* Operation not implemented */
+#define MC_CMD_ERR_ENOSYS 38
+/* Operation timed out */
+#define MC_CMD_ERR_ETIME 62
+
+#define MC_CMD_ERR_CODE_OFST 0
+
+
+/* MC_CMD_READ32: (debug, variadic out)
+ * Read multiple 32byte words from MC memory
+ */
+#define MC_CMD_READ32 0x01
+#define MC_CMD_READ32_IN_LEN 8
+#define MC_CMD_READ32_IN_ADDR_OFST 0
+#define MC_CMD_READ32_IN_NUMWORDS_OFST 4
+#define MC_CMD_READ32_OUT_LEN(_numwords) \
+       (4 * (_numwords))
+#define MC_CMD_READ32_OUT_BUFFER_OFST 0
+
+/* MC_CMD_WRITE32: (debug, variadic in)
+ * Write multiple 32byte words to MC memory
+ */
+#define MC_CMD_WRITE32 0x02
+#define MC_CMD_WRITE32_IN_LEN(_numwords) (((_numwords) * 4) + 4)
+#define MC_CMD_WRITE32_IN_ADDR_OFST 0
+#define MC_CMD_WRITE32_IN_BUFFER_OFST 4
+#define MC_CMD_WRITE32_OUT_LEN 0
+
+/* MC_CMD_COPYCODE: (debug)
+ * Copy MC code between two locations and jump
+ */
+#define MC_CMD_COPYCODE 0x03
+#define MC_CMD_COPYCODE_IN_LEN 16
+#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0
+#define MC_CMD_COPYCODE_IN_DEST_ADDR_OFST 4
+#define MC_CMD_COPYCODE_IN_NUMWORDS_OFST 8
+#define MC_CMD_COPYCODE_IN_JUMP_OFST 12
+/* Control should return to the caller rather than jumping */
+#define MC_CMD_COPYCODE_JUMP_NONE 1
+#define MC_CMD_COPYCODE_OUT_LEN 0
+
+/* MC_CMD_SET_FUNC: (debug)
+ * Select function for function-specific commands.
+ */
+#define MC_CMD_SET_FUNC 0x04
+#define MC_CMD_SET_FUNC_IN_LEN 4
+#define MC_CMD_SET_FUNC_IN_FUNC_OFST 0
+#define MC_CMD_SET_FUNC_OUT_LEN 0
+
+/* MC_CMD_GET_BOOT_STATUS:
+ * Get the instruction address from which the MC booted.
+ */
+#define MC_CMD_GET_BOOT_STATUS 0x05
+#define MC_CMD_GET_BOOT_STATUS_IN_LEN 0
+#define MC_CMD_GET_BOOT_STATUS_OUT_LEN 8
+#define MC_CMD_GET_BOOT_STATUS_OUT_BOOT_OFFSET_OFST 0
+#define MC_CMD_GET_BOOT_STATUS_OUT_FLAGS_OFST 4
+/* Reboot caused by watchdog */
+#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_LBN   (0)
+#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_WIDTH (1)
+/* MC booted from primary flash partition */
+#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_LBN    (1)
+#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_WIDTH  (1)
+/* MC booted from backup flash partition */
+#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_LBN     (2)
+#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_WIDTH   (1)
+
+/* MC_CMD_GET_ASSERTS: (debug, variadic out)
+ * Get (and optionally clear) the current assertion status.
+ *
+ * Only OUT.GLOBAL_FLAGS is guaranteed to exist in the completion
+ * payload. The other fields will only be present if
+ * OUT.GLOBAL_FLAGS != NO_FAILS
+ */
+#define MC_CMD_GET_ASSERTS 0x06
+#define MC_CMD_GET_ASSERTS_IN_LEN 4
+#define MC_CMD_GET_ASSERTS_IN_CLEAR_OFST 0
+#define MC_CMD_GET_ASSERTS_OUT_LEN 140
+/* Assertion status flag */
+#define MC_CMD_GET_ASSERTS_OUT_GLOBAL_FLAGS_OFST 0
+/*! No assertions have failed. */
+#define MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS 1
+/*! A system-level assertion has failed. */
+#define MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL 2
+/*! A thread-level assertion has failed. */
+#define MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL 3
+/*! The system was reset by the watchdog. */
+#define MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED 4
+/* Failing PC value */
+#define MC_CMD_GET_ASSERTS_OUT_SAVED_PC_OFFS_OFST 4
+/* Saved GP regs */
+#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST 8
+#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_LEN 124
+/* Failing thread address */
+#define MC_CMD_GET_ASSERTS_OUT_THREAD_OFFS_OFST 132
+
+/* MC_CMD_LOG_CTRL:
+ * Determine the output stream for various events and messages
+ */
+#define MC_CMD_LOG_CTRL 0x07
+#define MC_CMD_LOG_CTRL_IN_LEN 8
+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_OFST 0
+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_UART (1)
+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ (2)
+#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ_OFST 4
+#define MC_CMD_LOG_CTRL_OUT_LEN 0
+
+/* MC_CMD_GET_VERSION:
+ * Get version information about the MC firmware
+ */
+#define MC_CMD_GET_VERSION 0x08
+#define MC_CMD_GET_VERSION_IN_LEN 0
+#define MC_CMD_GET_VERSION_V0_OUT_LEN 4
+#define MC_CMD_GET_VERSION_V1_OUT_LEN 32
+#define MC_CMD_GET_VERSION_OUT_FIRMWARE_OFST 0
+/* Reserved version number to indicate "any" version. */
+#define MC_CMD_GET_VERSION_OUT_FIRMWARE_ANY 0xffffffff
+/* The version response of a boot ROM awaiting rescue */
+#define MC_CMD_GET_VERSION_OUT_FIRMWARE_BOOTROM 0xb0070000
+#define MC_CMD_GET_VERSION_V1_OUT_PCOL_OFST 4
+/* 128bit mask of functions supported by the current firmware */
+#define MC_CMD_GET_VERSION_V1_OUT_SUPPORTED_FUNCS_OFST 8
+/* The command set exported by the boot ROM (MCDI v0) */
+#define MC_CMD_GET_VERSION_V0_SUPPORTED_FUNCS {                \
+       (1 << MC_CMD_READ32)    |                       \
+       (1 << MC_CMD_WRITE32)   |                       \
+       (1 << MC_CMD_COPYCODE)  |                       \
+       (1 << MC_CMD_GET_VERSION),                      \
+       0, 0, 0 }
+#define MC_CMD_GET_VERSION_OUT_VERSION_OFST 24
+
+/* Vectors in the boot ROM */
+/* Point to the copycode entry point. */
+#define MC_BOOTROM_COPYCODE_VEC (0x7f4)
+/* Points to the recovery mode entry point. */
+#define MC_BOOTROM_NOFLASH_VEC (0x7f8)
+
+/* Test execution limits */
+#define MC_TESTEXEC_VARIANT_COUNT 16
+#define MC_TESTEXEC_RESULT_COUNT 7
+
+/* MC_CMD_SET_TESTVARS: (debug, variadic in)
+ * Write variant words for test.
+ *
+ * The user supplies a bitmap of the variants they wish to set.
+ * They must ensure that IN.LEN >= 4 + 4 * ffs(BITMAP)
+ */
+#define MC_CMD_SET_TESTVARS 0x09
+#define MC_CMD_SET_TESTVARS_IN_LEN(_numwords)  \
+  (4 + 4*(_numwords))
+#define MC_CMD_SET_TESTVARS_IN_ARGS_BITMAP_OFST 0
+/* Up to MC_TESTEXEC_VARIANT_COUNT of 32byte words start here */
+#define MC_CMD_SET_TESTVARS_IN_ARGS_BUFFER_OFST 4
+#define MC_CMD_SET_TESTVARS_OUT_LEN 0
+
+/* MC_CMD_GET_TESTRCS: (debug, variadic out)
+ * Return result words from test.
+ */
+#define MC_CMD_GET_TESTRCS 0x0a
+#define MC_CMD_GET_TESTRCS_IN_LEN 4
+#define MC_CMD_GET_TESTRCS_IN_NUMWORDS_OFST 0
+#define MC_CMD_GET_TESTRCS_OUT_LEN(_numwords) \
+       (4 * (_numwords))
+#define MC_CMD_GET_TESTRCS_OUT_BUFFER_OFST 0
+
+/* MC_CMD_RUN_TEST: (debug)
+ * Run the test exported by this firmware image
+ */
+#define MC_CMD_RUN_TEST 0x0b
+#define MC_CMD_RUN_TEST_IN_LEN 0
+#define MC_CMD_RUN_TEST_OUT_LEN 0
+
+/* MC_CMD_CSR_READ32: (debug, variadic out)
+ * Read 32bit words from the indirect memory map
+ */
+#define MC_CMD_CSR_READ32 0x0c
+#define MC_CMD_CSR_READ32_IN_LEN 12
+#define MC_CMD_CSR_READ32_IN_ADDR_OFST 0
+#define MC_CMD_CSR_READ32_IN_STEP_OFST 4
+#define MC_CMD_CSR_READ32_IN_NUMWORDS_OFST 8
+#define MC_CMD_CSR_READ32_OUT_LEN(_numwords)   \
+       (((_numwords) * 4) + 4)
+/* IN.NUMWORDS of 32bit words start here */
+#define MC_CMD_CSR_READ32_OUT_BUFFER_OFST 0
+#define MC_CMD_CSR_READ32_OUT_IREG_STATUS_OFST(_numwords)      \
+       ((_numwords) * 4)
+
+/* MC_CMD_CSR_WRITE32: (debug, variadic in)
+ * Write 32bit dwords to the indirect memory map
+ */
+#define MC_CMD_CSR_WRITE32 0x0d
+#define MC_CMD_CSR_WRITE32_IN_LEN(_numwords)   \
+       (((_numwords) * 4) + 8)
+#define MC_CMD_CSR_WRITE32_IN_ADDR_OFST 0
+#define MC_CMD_CSR_WRITE32_IN_STEP_OFST 4
+/* Multiple 32bit words of data to write start here */
+#define MC_CMD_CSR_WRITE32_IN_BUFFER_OFST 8
+#define MC_CMD_CSR_WRITE32_OUT_LEN 4
+#define MC_CMD_CSR_WRITE32_OUT_STATUS_OFST 0
+
+/* MC_CMD_JTAG_WORK: (debug, fpga only)
+ * Process JTAG work buffer for RBF acceleration.
+ *
+ *  Host: bit count, (up to) 32 words of data to clock out to JTAG
+ *   (bits 1,0=TMS,TDO for first bit; bits 3,2=TMS,TDO for second bit, etc.)
+ *  MC: bit count, (up to) 32 words of data clocked in from JTAG
+ *   (bit 0=TDI for first bit, bit 1=TDI for second bit, etc.; [31:16] unused)
+ */
+#define MC_CMD_JTAG_WORK 0x0e
+
+/* MC_CMD_STACKINFO: (debug, variadic out)
+ * Get stack information
+ *
+ * Host: nothing
+ * MC: (thread ptr, stack size, free space) for each thread in system
+ */
+#define MC_CMD_STACKINFO 0x0f
+
+/* MC_CMD_MDIO_READ:
+ * MDIO register read
+ */
+#define MC_CMD_MDIO_READ 0x10
+#define MC_CMD_MDIO_READ_IN_LEN 16
+#define MC_CMD_MDIO_READ_IN_BUS_OFST 0
+#define MC_CMD_MDIO_READ_IN_PRTAD_OFST 4
+#define MC_CMD_MDIO_READ_IN_DEVAD_OFST 8
+#define MC_CMD_MDIO_READ_IN_ADDR_OFST 12
+#define MC_CMD_MDIO_READ_OUT_LEN 8
+#define MC_CMD_MDIO_READ_OUT_VALUE_OFST 0
+#define MC_CMD_MDIO_READ_OUT_STATUS_OFST 4
+
+/* MC_CMD_MDIO_WRITE:
+ * MDIO register write
+ */
+#define MC_CMD_MDIO_WRITE 0x11
+#define MC_CMD_MDIO_WRITE_IN_LEN 20
+#define MC_CMD_MDIO_WRITE_IN_BUS_OFST 0
+#define MC_CMD_MDIO_WRITE_IN_PRTAD_OFST 4
+#define MC_CMD_MDIO_WRITE_IN_DEVAD_OFST 8
+#define MC_CMD_MDIO_WRITE_IN_ADDR_OFST 12
+#define MC_CMD_MDIO_WRITE_IN_VALUE_OFST 16
+#define MC_CMD_MDIO_WRITE_OUT_LEN 4
+#define MC_CMD_MDIO_WRITE_OUT_STATUS_OFST 0
+
+/* By default all the MCDI MDIO operations perform clause45 mode.
+ * If you want to use clause22 then set DEVAD = MC_CMD_MDIO_CLAUSE22.
+ */
+#define MC_CMD_MDIO_CLAUSE22 32
+
+/* There are two MDIO buses: one for the internal PHY, and one for external
+ * devices.
+ */
+#define MC_CMD_MDIO_BUS_INTERNAL 0
+#define MC_CMD_MDIO_BUS_EXTERNAL 1
+
+/* The MDIO commands return the raw status bits from the MDIO block.  A "good"
+ * transaction should have the DONE bit set and all other bits clear.
+ */
+#define MC_CMD_MDIO_STATUS_GOOD 0x08
+
+
+/* MC_CMD_DBI_WRITE: (debug)
+ * Write DBI register(s)
+ *
+ * Host: address, byte-enables (and VF selection, and cs2 flag),
+ *       value [,address ...]
+ * MC: nothing
+ */
+#define MC_CMD_DBI_WRITE 0x12
+#define MC_CMD_DBI_WRITE_IN_LEN(_numwords)             \
+       (12 * (_numwords))
+#define MC_CMD_DBI_WRITE_IN_ADDRESS_OFST(_word)                \
+       (((_word) * 12) + 0)
+#define MC_CMD_DBI_WRITE_IN_BYTE_MASK_OFST(_word)      \
+       (((_word) * 12) + 4)
+#define MC_CMD_DBI_WRITE_IN_VALUE_OFST(_word)          \
+       (((_word) * 12) + 8)
+#define MC_CMD_DBI_WRITE_OUT_LEN 0
+
+/* MC_CMD_DBI_READ: (debug)
+ * Read DBI register(s)
+ *
+ * Host: address, [,address ...]
+ * MC: value [,value ...]
+ * (note: this does not support reading from VFs, but is retained for backwards
+ * compatibility; see MC_CMD_DBI_READX below)
+ */
+#define MC_CMD_DBI_READ 0x13
+#define MC_CMD_DBI_READ_IN_LEN(_numwords)              \
+       (4 * (_numwords))
+#define MC_CMD_DBI_READ_OUT_LEN(_numwords)             \
+       (4 * (_numwords))
+
+/* MC_CMD_PORT_READ32: (debug)
+ * Read a 32-bit register from the indirect port register map.
+ *
+ * The port to access is implied by the Shared memory channel used.
+ */
+#define MC_CMD_PORT_READ32 0x14
+#define MC_CMD_PORT_READ32_IN_LEN 4
+#define MC_CMD_PORT_READ32_IN_ADDR_OFST 0
+#define MC_CMD_PORT_READ32_OUT_LEN 8
+#define MC_CMD_PORT_READ32_OUT_VALUE_OFST 0
+#define MC_CMD_PORT_READ32_OUT_STATUS_OFST 4
+
+/* MC_CMD_PORT_WRITE32: (debug)
+ * Write a 32-bit register to the indirect port register map.
+ *
+ * The port to access is implied by the Shared memory channel used.
+ */
+#define MC_CMD_PORT_WRITE32 0x15
+#define MC_CMD_PORT_WRITE32_IN_LEN 8
+#define MC_CMD_PORT_WRITE32_IN_ADDR_OFST 0
+#define MC_CMD_PORT_WRITE32_IN_VALUE_OFST 4
+#define MC_CMD_PORT_WRITE32_OUT_LEN 4
+#define MC_CMD_PORT_WRITE32_OUT_STATUS_OFST 0
+
+/* MC_CMD_PORT_READ128: (debug)
+ * Read a 128-bit register from indirect port register map
+ *
+ * The port to access is implied by the Shared memory channel used.
+ */
+#define MC_CMD_PORT_READ128 0x16
+#define MC_CMD_PORT_READ128_IN_LEN 4
+#define MC_CMD_PORT_READ128_IN_ADDR_OFST 0
+#define MC_CMD_PORT_READ128_OUT_LEN 20
+#define MC_CMD_PORT_READ128_OUT_VALUE_OFST 0
+#define MC_CMD_PORT_READ128_OUT_STATUS_OFST 16
+
+/* MC_CMD_PORT_WRITE128: (debug)
+ * Write a 128-bit register to indirect port register map.
+ *
+ * The port to access is implied by the Shared memory channel used.
+ */
+#define MC_CMD_PORT_WRITE128 0x17
+#define MC_CMD_PORT_WRITE128_IN_LEN 20
+#define MC_CMD_PORT_WRITE128_IN_ADDR_OFST 0
+#define MC_CMD_PORT_WRITE128_IN_VALUE_OFST 4
+#define MC_CMD_PORT_WRITE128_OUT_LEN 4
+#define MC_CMD_PORT_WRITE128_OUT_STATUS_OFST 0
+
+/* MC_CMD_GET_BOARD_CFG:
+ * Returns the MC firmware configuration structure
+ *
+ * The FW_SUBTYPE_LIST contains a 16-bit value for each of the 12 types of
+ * NVRAM area.  The values are defined in the firmware/mc/platform/<xxx>.c file
+ * for a specific board type, but otherwise have no meaning to the MC; they
+ * are used by the driver to manage selection of appropriate firmware updates.
+ */
+#define MC_CMD_GET_BOARD_CFG 0x18
+#define MC_CMD_GET_BOARD_CFG_IN_LEN 0
+#define MC_CMD_GET_BOARD_CFG_OUT_LEN 96
+#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_TYPE_OFST 0
+#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_OFST 4
+#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_LEN 32
+#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT0_OFST 36
+#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT1_OFST 40
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST 44
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_LEN 6
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST 50
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_LEN 6
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT0_OFST 56
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT1_OFST 60
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT0_OFST 64
+#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT1_OFST 68
+#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST 72
+#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN 24
+
+/* MC_CMD_DBI_READX: (debug)
+ * Read DBI register(s) -- extended functionality
+ *
+ * Host: vf selection, address, [,vf selection ...]
+ * MC: value [,value ...]
+ */
+#define MC_CMD_DBI_READX 0x19
+#define MC_CMD_DBI_READX_IN_LEN(_numwords)     \
+  (8*(_numwords))
+#define MC_CMD_DBI_READX_OUT_LEN(_numwords)    \
+  (4*(_numwords))
+
+/* MC_CMD_SET_RAND_SEED:
+ * Set the 16byte seed for the MC psuedo-random generator
+ */
+#define MC_CMD_SET_RAND_SEED 0x1a
+#define MC_CMD_SET_RAND_SEED_IN_LEN 16
+#define MC_CMD_SET_RAND_SEED_IN_SEED_OFST 0
+#define MC_CMD_SET_RAND_SEED_OUT_LEN 0
+
+/* MC_CMD_LTSSM_HIST: (debug)
+ * Retrieve the history of the LTSSM, if the build supports it.
+ *
+ * Host: nothing
+ * MC: variable number of LTSSM values, as bytes
+ * The history is read-to-clear.
+ */
+#define MC_CMD_LTSSM_HIST 0x1b
+
+/* MC_CMD_DRV_ATTACH:
+ * Inform MCPU that this port is managed on the host (i.e. driver active)
+ */
+#define MC_CMD_DRV_ATTACH 0x1c
+#define MC_CMD_DRV_ATTACH_IN_LEN 8
+#define MC_CMD_DRV_ATTACH_IN_NEW_STATE_OFST 0
+#define MC_CMD_DRV_ATTACH_IN_UPDATE_OFST 4
+#define MC_CMD_DRV_ATTACH_OUT_LEN 4
+#define MC_CMD_DRV_ATTACH_OUT_OLD_STATE_OFST 0
+
+/* MC_CMD_NCSI_PROD: (debug)
+ * Trigger an NC-SI event (and possibly an AEN in response)
+ */
+#define MC_CMD_NCSI_PROD 0x1d
+#define MC_CMD_NCSI_PROD_IN_LEN 4
+#define MC_CMD_NCSI_PROD_IN_EVENTS_OFST 0
+#define MC_CMD_NCSI_PROD_LINKCHANGE_LBN 0
+#define MC_CMD_NCSI_PROD_LINKCHANGE_WIDTH 1
+#define MC_CMD_NCSI_PROD_RESET_LBN 1
+#define MC_CMD_NCSI_PROD_RESET_WIDTH 1
+#define MC_CMD_NCSI_PROD_DRVATTACH_LBN 2
+#define MC_CMD_NCSI_PROD_DRVATTACH_WIDTH 1
+#define MC_CMD_NCSI_PROD_OUT_LEN 0
+
+/* Enumeration */
+#define MC_CMD_NCSI_PROD_LINKCHANGE 0
+#define MC_CMD_NCSI_PROD_RESET 1
+#define MC_CMD_NCSI_PROD_DRVATTACH 2
+
+/* MC_CMD_DEVEL: (debug)
+ * Reserved for development
+ */
+#define MC_CMD_DEVEL 0x1e
+
+/* MC_CMD_SHMUART: (debug)
+ * Route UART output to circular buffer in shared memory instead.
+ */
+#define MC_CMD_SHMUART 0x1f
+#define MC_CMD_SHMUART_IN_FLAG_OFST 0
+#define MC_CMD_SHMUART_IN_LEN 4
+#define MC_CMD_SHMUART_OUT_LEN 0
+
+/* MC_CMD_PORT_RESET:
+ * Generic per-port reset. There is no equivalent for per-board reset.
+ *
+ * Locks required: None
+ * Return code: 0, ETIME
+ */
+#define MC_CMD_PORT_RESET 0x20
+#define MC_CMD_PORT_RESET_IN_LEN 0
+#define MC_CMD_PORT_RESET_OUT_LEN 0
+
+/* MC_CMD_RESOURCE_LOCK:
+ * Generic resource lock/unlock interface.
+ *
+ * Locks required: None
+ * Return code: 0,
+ *              EBUSY (if trylock is contended by other port),
+ *              EDEADLK (if trylock is already acquired by this port)
+ *              EINVAL (if unlock doesn't own the lock)
+ */
+#define MC_CMD_RESOURCE_LOCK 0x21
+#define MC_CMD_RESOURCE_LOCK_IN_LEN 8
+#define MC_CMD_RESOURCE_LOCK_IN_ACTION_OFST 0
+#define MC_CMD_RESOURCE_LOCK_ACTION_TRYLOCK 1
+#define MC_CMD_RESOURCE_LOCK_ACTION_UNLOCK 0
+#define MC_CMD_RESOURCE_LOCK_IN_RESOURCE_OFST 4
+#define MC_CMD_RESOURCE_LOCK_I2C 2
+#define MC_CMD_RESOURCE_LOCK_PHY 3
+#define MC_CMD_RESOURCE_LOCK_OUT_LEN 0
+
+/* MC_CMD_SPI_COMMAND: (variadic in, variadic out)
+ * Read/Write to/from the SPI device.
+ *
+ * Locks required: SPI_LOCK
+ * Return code: 0, ETIME, EINVAL, EACCES (if SPI_LOCK is not held)
+ */
+#define MC_CMD_SPI_COMMAND 0x22
+#define MC_CMD_SPI_COMMAND_IN_LEN(_write_bytes)        (12 + (_write_bytes))
+#define MC_CMD_SPI_COMMAND_IN_ARGS_OFST 0
+#define MC_CMD_SPI_COMMAND_IN_ARGS_ADDRESS_OFST 0
+#define MC_CMD_SPI_COMMAND_IN_ARGS_READ_BYTES_OFST 4
+#define MC_CMD_SPI_COMMAND_IN_ARGS_CHIP_SELECT_OFST 8
+/* Data to write here */
+#define MC_CMD_SPI_COMMAND_IN_WRITE_BUFFER_OFST 12
+#define MC_CMD_SPI_COMMAND_OUT_LEN(_read_bytes) (_read_bytes)
+/* Data read here */
+#define MC_CMD_SPI_COMMAND_OUT_READ_BUFFER_OFST 0
+
+/* MC_CMD_I2C_READ_WRITE: (variadic in, variadic out)
+ * Read/Write to/from the I2C bus.
+ *
+ * Locks required: I2C_LOCK
+ * Return code: 0, ETIME, EINVAL, EACCES (if I2C_LOCK is not held)
+ */
+#define MC_CMD_I2C_RW 0x23
+#define MC_CMD_I2C_RW_IN_LEN(_write_bytes) (8 + (_write_bytes))
+#define MC_CMD_I2C_RW_IN_ARGS_OFST 0
+#define MC_CMD_I2C_RW_IN_ARGS_ADDR_OFST 0
+#define MC_CMD_I2C_RW_IN_ARGS_READ_BYTES_OFST 4
+/* Data to write here */
+#define MC_CMD_I2C_RW_IN_WRITE_BUFFER_OFSET 8
+#define MC_CMD_I2C_RW_OUT_LEN(_read_bytes) (_read_bytes)
+/* Data read here */
+#define MC_CMD_I2C_RW_OUT_READ_BUFFER_OFST 0
+
+/* Generic phy capability bitmask */
+#define MC_CMD_PHY_CAP_10HDX_LBN 1
+#define MC_CMD_PHY_CAP_10HDX_WIDTH 1
+#define MC_CMD_PHY_CAP_10FDX_LBN 2
+#define MC_CMD_PHY_CAP_10FDX_WIDTH 1
+#define MC_CMD_PHY_CAP_100HDX_LBN 3
+#define MC_CMD_PHY_CAP_100HDX_WIDTH 1
+#define MC_CMD_PHY_CAP_100FDX_LBN 4
+#define MC_CMD_PHY_CAP_100FDX_WIDTH 1
+#define MC_CMD_PHY_CAP_1000HDX_LBN 5
+#define MC_CMD_PHY_CAP_1000HDX_WIDTH 1
+#define MC_CMD_PHY_CAP_1000FDX_LBN 6
+#define MC_CMD_PHY_CAP_1000FDX_WIDTH 1
+#define MC_CMD_PHY_CAP_10000FDX_LBN 7
+#define MC_CMD_PHY_CAP_10000FDX_WIDTH 1
+#define MC_CMD_PHY_CAP_PAUSE_LBN 8
+#define MC_CMD_PHY_CAP_PAUSE_WIDTH 1
+#define MC_CMD_PHY_CAP_ASYM_LBN 9
+#define MC_CMD_PHY_CAP_ASYM_WIDTH 1
+#define MC_CMD_PHY_CAP_AN_LBN 10
+#define MC_CMD_PHY_CAP_AN_WIDTH 1
+
+/* Generic loopback enumeration */
+#define MC_CMD_LOOPBACK_NONE 0
+#define MC_CMD_LOOPBACK_DATA 1
+#define MC_CMD_LOOPBACK_GMAC 2
+#define MC_CMD_LOOPBACK_XGMII 3
+#define MC_CMD_LOOPBACK_XGXS 4
+#define MC_CMD_LOOPBACK_XAUI 5
+#define MC_CMD_LOOPBACK_GMII 6
+#define MC_CMD_LOOPBACK_SGMII 7
+#define MC_CMD_LOOPBACK_XGBR 8
+#define MC_CMD_LOOPBACK_XFI 9
+#define MC_CMD_LOOPBACK_XAUI_FAR 10
+#define MC_CMD_LOOPBACK_GMII_FAR 11
+#define MC_CMD_LOOPBACK_SGMII_FAR 12
+#define MC_CMD_LOOPBACK_XFI_FAR 13
+#define MC_CMD_LOOPBACK_GPHY 14
+#define MC_CMD_LOOPBACK_PHYXS 15
+#define MC_CMD_LOOPBACK_PCS 16
+#define MC_CMD_LOOPBACK_PMAPMD 17
+#define MC_CMD_LOOPBACK_XPORT 18
+#define MC_CMD_LOOPBACK_XGMII_WS 19
+#define MC_CMD_LOOPBACK_XAUI_WS 20
+#define MC_CMD_LOOPBACK_XAUI_WS_FAR 21
+#define MC_CMD_LOOPBACK_XAUI_WS_NEAR 22
+#define MC_CMD_LOOPBACK_GMII_WS 23
+#define MC_CMD_LOOPBACK_XFI_WS 24
+#define MC_CMD_LOOPBACK_XFI_WS_FAR 25
+#define MC_CMD_LOOPBACK_PHYXS_WS 26
+
+/* Generic PHY statistics enumeration */
+#define MC_CMD_OUI 0
+#define MC_CMD_PMA_PMD_LINK_UP 1
+#define MC_CMD_PMA_PMD_RX_FAULT 2
+#define MC_CMD_PMA_PMD_TX_FAULT 3
+#define MC_CMD_PMA_PMD_SIGNAL 4
+#define MC_CMD_PMA_PMD_SNR_A 5
+#define MC_CMD_PMA_PMD_SNR_B 6
+#define MC_CMD_PMA_PMD_SNR_C 7
+#define MC_CMD_PMA_PMD_SNR_D 8
+#define MC_CMD_PCS_LINK_UP 9
+#define MC_CMD_PCS_RX_FAULT 10
+#define MC_CMD_PCS_TX_FAULT 11
+#define MC_CMD_PCS_BER 12
+#define MC_CMD_PCS_BLOCK_ERRORS 13
+#define MC_CMD_PHYXS_LINK_UP 14
+#define MC_CMD_PHYXS_RX_FAULT 15
+#define MC_CMD_PHYXS_TX_FAULT 16
+#define MC_CMD_PHYXS_ALIGN 17
+#define MC_CMD_PHYXS_SYNC 18
+#define MC_CMD_AN_LINK_UP 19
+#define MC_CMD_AN_COMPLETE 20
+#define MC_CMD_AN_10GBT_STATUS 21
+#define MC_CMD_CL22_LINK_UP 22
+#define MC_CMD_PHY_NSTATS 23
+
+/* MC_CMD_GET_PHY_CFG:
+ * Report PHY configuration.  This guarantees to succeed even if the PHY is in
+ * a "zombie" state.
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_GET_PHY_CFG 0x24
+
+#define MC_CMD_GET_PHY_CFG_IN_LEN 0
+#define MC_CMD_GET_PHY_CFG_OUT_LEN 72
+
+#define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0
+#define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0
+#define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN 2
+#define MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3
+#define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4
+#define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5
+#define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_BIST_LBN 6
+#define MC_CMD_GET_PHY_CFG_BIST_WIDTH 1
+#define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4
+/* Bitmask of supported capabilities */
+#define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8
+#define MC_CMD_GET_PHY_CFG_OUT_CHANNEL_OFST 12
+#define MC_CMD_GET_PHY_CFG_OUT_PRT_OFST 16
+/* PHY statistics bitmap */
+#define MC_CMD_GET_PHY_CFG_OUT_STATS_MASK_OFST 20
+/* PHY type/name string */
+#define MC_CMD_GET_PHY_CFG_OUT_NAME_OFST 24
+#define MC_CMD_GET_PHY_CFG_OUT_NAME_LEN 20
+#define MC_CMD_GET_PHY_CFG_OUT_MEDIA_TYPE_OFST 44
+#define MC_CMD_MEDIA_XAUI 1
+#define MC_CMD_MEDIA_CX4 2
+#define MC_CMD_MEDIA_KX4 3
+#define MC_CMD_MEDIA_XFP 4
+#define MC_CMD_MEDIA_SFP_PLUS 5
+#define MC_CMD_MEDIA_BASE_T 6
+/* MDIO "MMDS" supported */
+#define MC_CMD_GET_PHY_CFG_OUT_MMD_MASK_OFST 48
+/* Native clause 22 */
+#define MC_CMD_MMD_CLAUSE22  0
+#define MC_CMD_MMD_CLAUSE45_PMAPMD 1
+#define MC_CMD_MMD_CLAUSE45_WIS 2
+#define MC_CMD_MMD_CLAUSE45_PCS 3
+#define MC_CMD_MMD_CLAUSE45_PHYXS 4
+#define MC_CMD_MMD_CLAUSE45_DTEXS 5
+#define MC_CMD_MMD_CLAUSE45_TC 6
+#define MC_CMD_MMD_CLAUSE45_AN 7
+/* Clause22 proxied over clause45 by PHY */
+#define MC_CMD_MMD_CLAUSE45_C22EXT 29
+#define MC_CMD_MMD_CLAUSE45_VEND1 30
+#define MC_CMD_MMD_CLAUSE45_VEND2 31
+/* PHY stepping version */
+#define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52
+#define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20
+
+/* MC_CMD_START_BIST:
+ * Start a BIST test on the PHY.
+ *
+ * Locks required: PHY_LOCK if doing a  PHY BIST
+ * Return code: 0, EINVAL, EACCES (if PHY_LOCK is not held)
+ */
+#define MC_CMD_START_BIST 0x25
+#define MC_CMD_START_BIST_IN_LEN 4
+#define MC_CMD_START_BIST_IN_TYPE_OFST 0
+#define MC_CMD_START_BIST_OUT_LEN 0
+
+/* Run the PHY's short cable BIST */
+#define MC_CMD_PHY_BIST_CABLE_SHORT  1
+/* Run the PHY's long cable BIST */
+#define MC_CMD_PHY_BIST_CABLE_LONG   2
+/* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */
+#define MC_CMD_BPX_SERDES_BIST 3
+/* Run the MC loopback tests */
+#define MC_CMD_MC_LOOPBACK_BIST 4
+/* Run the PHY's standard BIST */
+#define MC_CMD_PHY_BIST 5
+
+/* MC_CMD_POLL_PHY_BIST: (variadic output)
+ * Poll for BIST completion
+ *
+ * Returns a single status code, and optionally some PHY specific
+ * bist output. The driver should only consume the BIST output
+ * after validating OUTLEN and PHY_CFG.PHY_TYPE.
+ *
+ * If a driver can't succesfully parse the BIST output, it should
+ * still respect the pass/Fail in OUT.RESULT
+ *
+ * Locks required: PHY_LOCK if doing a  PHY BIST
+ * Return code: 0, EACCES (if PHY_LOCK is not held)
+ */
+#define MC_CMD_POLL_BIST 0x26
+#define MC_CMD_POLL_BIST_IN_LEN 0
+#define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN
+#define MC_CMD_POLL_BIST_OUT_SFT9001_LEN 40
+#define MC_CMD_POLL_BIST_OUT_MRSFP_LEN 8
+#define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0
+#define MC_CMD_POLL_BIST_RUNNING 1
+#define MC_CMD_POLL_BIST_PASSED 2
+#define MC_CMD_POLL_BIST_FAILED 3
+#define MC_CMD_POLL_BIST_TIMEOUT 4
+/* Generic: */
+#define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4
+/* SFT9001-specific: */
+/* (offset 4 unused?) */
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A_OFST 8
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 12
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 16
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 20
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 24
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 28
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 32
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 36
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_OK 1
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN 2
+#define MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT 3
+#define MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT 4
+#define MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY 9
+/* mrsfp "PHY" driver: */
+#define MC_CMD_POLL_BIST_OUT_MRSFP_TEST_OFST 4
+#define MC_CMD_POLL_BIST_MRSFP_TEST_COMPLETE 0
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_WRITE 1
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_IO_EXP 2
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_OFF_I2C_NO_ACCESS_MODULE 3
+#define MC_CMD_POLL_BIST_MRSFP_TEST_IO_EXP_I2C_CONFIGURE 4
+#define MC_CMD_POLL_BIST_MRSFP_TEST_BUS_SWITCH_I2C_NO_CROSSTALK 5
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_PRESENCE 6
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_I2C_ACCESS 7
+#define MC_CMD_POLL_BIST_MRSFP_TEST_MODULE_ID_SANE_VALUE 8
+
+/* MC_CMD_PHY_SPI: (variadic in, variadic out)
+ * Read/Write/Erase the PHY SPI device
+ *
+ * Locks required: PHY_LOCK
+ * Return code: 0, ETIME, EINVAL, EACCES (if PHY_LOCK is not held)
+ */
+#define MC_CMD_PHY_SPI 0x27
+#define MC_CMD_PHY_SPI_IN_LEN(_write_bytes) (12 + (_write_bytes))
+#define MC_CMD_PHY_SPI_IN_ARGS_OFST 0
+#define MC_CMD_PHY_SPI_IN_ARGS_ADDR_OFST 0
+#define MC_CMD_PHY_SPI_IN_ARGS_READ_BYTES_OFST 4
+#define MC_CMD_PHY_SPI_IN_ARGS_ERASE_ALL_OFST 8
+/* Data to write here */
+#define MC_CMD_PHY_SPI_IN_WRITE_BUFFER_OFSET 12
+#define MC_CMD_PHY_SPI_OUT_LEN(_read_bytes) (_read_bytes)
+/* Data read here */
+#define MC_CMD_PHY_SPI_OUT_READ_BUFFER_OFST 0
+
+
+/* MC_CMD_GET_LOOPBACK_MODES:
+ * Returns a bitmask of loopback modes evailable at each speed.
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_GET_LOOPBACK_MODES 0x28
+#define MC_CMD_GET_LOOPBACK_MODES_IN_LEN 0
+#define MC_CMD_GET_LOOPBACK_MODES_OUT_LEN 32
+#define MC_CMD_GET_LOOPBACK_MODES_100M_OFST 0
+#define MC_CMD_GET_LOOPBACK_MODES_1G_OFST 8
+#define MC_CMD_GET_LOOPBACK_MODES_10G_OFST 16
+#define MC_CMD_GET_LOOPBACK_MODES_SUGGESTED_OFST 24
+
+/* Flow control enumeration */
+#define MC_CMD_FCNTL_OFF 0
+#define MC_CMD_FCNTL_RESPOND 1
+#define MC_CMD_FCNTL_BIDIR 2
+/* Auto - Use what the link has autonegotiated
+ *      - The driver should modify the advertised capabilities via SET_LINK.CAP
+ *        to control the negotiated flow control mode.
+ *      - Can only be set if the PHY supports PAUSE+ASYM capabilities
+ *      - Never returned by GET_LINK as the value programmed into the MAC
+ */
+#define MC_CMD_FCNTL_AUTO 3
+
+/* Generic mac fault bitmask */
+#define MC_CMD_MAC_FAULT_XGMII_LOCAL_LBN 0
+#define MC_CMD_MAC_FAULT_XGMII_LOCAL_WIDTH 1
+#define MC_CMD_MAC_FAULT_XGMII_REMOTE_LBN 1
+#define MC_CMD_MAC_FAULT_XGMII_REMOTE_WIDTH 1
+#define MC_CMD_MAC_FAULT_SGMII_REMOTE_LBN 2
+#define MC_CMD_MAC_FAULT_SGMII_REMOTE_WIDTH 1
+
+/* MC_CMD_GET_LINK:
+ * Read the unified MAC/PHY link state
+ *
+ * Locks required: None
+ * Return code: 0, ETIME
+ */
+#define MC_CMD_GET_LINK 0x29
+#define MC_CMD_GET_LINK_IN_LEN 0
+#define MC_CMD_GET_LINK_OUT_LEN 28
+/* near-side and link-partner advertised capabilities */
+#define MC_CMD_GET_LINK_OUT_CAP_OFST 0
+#define MC_CMD_GET_LINK_OUT_LP_CAP_OFST 4
+/* Autonegotiated speed in mbit/s. The link may still be down
+ * even if this reads non-zero */
+#define MC_CMD_GET_LINK_OUT_LINK_SPEED_OFST 8
+#define MC_CMD_GET_LINK_OUT_LOOPBACK_MODE_OFST 12
+#define MC_CMD_GET_LINK_OUT_FLAGS_OFST 16
+/* Whether we have overall link up */
+#define MC_CMD_GET_LINK_LINK_UP_LBN 0
+#define MC_CMD_GET_LINK_LINK_UP_WIDTH 1
+#define MC_CMD_GET_LINK_FULL_DUPLEX_LBN 1
+#define MC_CMD_GET_LINK_FULL_DUPLEX_WIDTH 1
+/* Whether we have link at the layers provided by the BPX */
+#define MC_CMD_GET_LINK_BPX_LINK_LBN 2
+#define MC_CMD_GET_LINK_BPX_LINK_WIDTH 1
+/* Whether the PHY has external link */
+#define MC_CMD_GET_LINK_PHY_LINK_LBN 3
+#define MC_CMD_GET_LINK_PHY_LINK_WIDTH 1
+#define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20
+#define MC_CMD_GET_LINK_OUT_MAC_FAULT_OFST 24
+
+/* MC_CMD_SET_LINK:
+ * Write the unified MAC/PHY link configuration
+ *
+ * A loopback speed of "0" is supported, and means
+ * (choose any available speed)
+ *
+ * Locks required: None
+ * Return code: 0, EINVAL, ETIME
+ */
+#define MC_CMD_SET_LINK 0x2a
+#define MC_CMD_SET_LINK_IN_LEN 16
+#define MC_CMD_SET_LINK_IN_CAP_OFST 0
+#define MC_CMD_SET_LINK_IN_FLAGS_OFST 4
+#define MC_CMD_SET_LINK_LOWPOWER_LBN 0
+#define MC_CMD_SET_LINK_LOWPOWER_WIDTH 1
+#define MC_CMD_SET_LINK_POWEROFF_LBN 1
+#define MC_CMD_SET_LINK_POWEROFF_WIDTH 1
+#define MC_CMD_SET_LINK_TXDIS_LBN 2
+#define MC_CMD_SET_LINK_TXDIS_WIDTH 1
+#define MC_CMD_SET_LINK_IN_LOOPBACK_MODE_OFST 8
+#define MC_CMD_SET_LINK_IN_LOOPBACK_SPEED_OFST 12
+#define MC_CMD_SET_LINK_OUT_LEN 0
+
+/* MC_CMD_SET_ID_LED:
+ * Set indentification LED state
+ *
+ * Locks required: None
+ * Return code: 0, EINVAL
+ */
+#define MC_CMD_SET_ID_LED 0x2b
+#define MC_CMD_SET_ID_LED_IN_LEN 4
+#define MC_CMD_SET_ID_LED_IN_STATE_OFST 0
+#define  MC_CMD_LED_OFF 0
+#define  MC_CMD_LED_ON 1
+#define  MC_CMD_LED_DEFAULT 2
+#define MC_CMD_SET_ID_LED_OUT_LEN 0
+
+/* MC_CMD_SET_MAC:
+ * Set MAC configuration
+ *
+ * The MTU is the MTU programmed directly into the XMAC/GMAC
+ * (inclusive of EtherII, VLAN, bug16011 padding)
+ *
+ * Locks required: None
+ * Return code: 0, EINVAL
+ */
+#define MC_CMD_SET_MAC 0x2c
+#define MC_CMD_SET_MAC_IN_LEN 24
+#define MC_CMD_SET_MAC_IN_MTU_OFST 0
+#define MC_CMD_SET_MAC_IN_DRAIN_OFST 4
+#define MC_CMD_SET_MAC_IN_ADDR_OFST 8
+#define MC_CMD_SET_MAC_IN_REJECT_OFST 16
+#define MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN 0
+#define MC_CMD_SET_MAC_IN_REJECT_UNCST_WIDTH 1
+#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_LBN 1
+#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_WIDTH 1
+#define MC_CMD_SET_MAC_IN_FCNTL_OFST 20
+#define MC_CMD_SET_MAC_OUT_LEN 0
+
+/* MC_CMD_PHY_STATS:
+ * Get generic PHY statistics
+ *
+ * This call returns the statistics for a generic PHY, by direct DMA
+ * into host memory, in a sparse array (indexed by the enumerate).
+ * Each value is represented by a 32bit number.
+ *
+ * Locks required: None
+ * Returns: 0, ETIME
+ * Response methods: shared memory, event
+ */
+#define MC_CMD_PHY_STATS 0x2d
+#define MC_CMD_PHY_STATS_IN_LEN 8
+#define MC_CMD_PHY_STATS_IN_DMA_ADDR_LO_OFST 0
+#define MC_CMD_PHY_STATS_IN_DMA_ADDR_HI_OFST 4
+#define MC_CMD_PHY_STATS_OUT_LEN 0
+
+/* Unified MAC statistics enumeration */
+#define MC_CMD_MAC_GENERATION_START 0
+#define MC_CMD_MAC_TX_PKTS 1
+#define MC_CMD_MAC_TX_PAUSE_PKTS 2
+#define MC_CMD_MAC_TX_CONTROL_PKTS 3
+#define MC_CMD_MAC_TX_UNICAST_PKTS 4
+#define MC_CMD_MAC_TX_MULTICAST_PKTS 5
+#define MC_CMD_MAC_TX_BROADCAST_PKTS 6
+#define MC_CMD_MAC_TX_BYTES 7
+#define MC_CMD_MAC_TX_BAD_BYTES 8
+#define MC_CMD_MAC_TX_LT64_PKTS 9
+#define MC_CMD_MAC_TX_64_PKTS 10
+#define MC_CMD_MAC_TX_65_TO_127_PKTS 11
+#define MC_CMD_MAC_TX_128_TO_255_PKTS 12
+#define MC_CMD_MAC_TX_256_TO_511_PKTS 13
+#define MC_CMD_MAC_TX_512_TO_1023_PKTS 14
+#define MC_CMD_MAC_TX_1024_TO_15XX_PKTS 15
+#define MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS 16
+#define MC_CMD_MAC_TX_GTJUMBO_PKTS 17
+#define MC_CMD_MAC_TX_BAD_FCS_PKTS 18
+#define MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS 19
+#define MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS 20
+#define MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS 21
+#define MC_CMD_MAC_TX_LATE_COLLISION_PKTS 22
+#define MC_CMD_MAC_TX_DEFERRED_PKTS 23
+#define MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS 24
+#define MC_CMD_MAC_TX_NON_TCPUDP_PKTS 25
+#define MC_CMD_MAC_TX_MAC_SRC_ERR_PKTS 26
+#define MC_CMD_MAC_TX_IP_SRC_ERR_PKTS 27
+#define MC_CMD_MAC_RX_PKTS 28
+#define MC_CMD_MAC_RX_PAUSE_PKTS 29
+#define MC_CMD_MAC_RX_GOOD_PKTS 30
+#define MC_CMD_MAC_RX_CONTROL_PKTS 31
+#define MC_CMD_MAC_RX_UNICAST_PKTS 32
+#define MC_CMD_MAC_RX_MULTICAST_PKTS 33
+#define MC_CMD_MAC_RX_BROADCAST_PKTS 34
+#define MC_CMD_MAC_RX_BYTES 35
+#define MC_CMD_MAC_RX_BAD_BYTES 36
+#define MC_CMD_MAC_RX_64_PKTS 37
+#define MC_CMD_MAC_RX_65_TO_127_PKTS 38
+#define MC_CMD_MAC_RX_128_TO_255_PKTS 39
+#define MC_CMD_MAC_RX_256_TO_511_PKTS 40
+#define MC_CMD_MAC_RX_512_TO_1023_PKTS 41
+#define MC_CMD_MAC_RX_1024_TO_15XX_PKTS 42
+#define MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS 43
+#define MC_CMD_MAC_RX_GTJUMBO_PKTS 44
+#define MC_CMD_MAC_RX_UNDERSIZE_PKTS 45
+#define MC_CMD_MAC_RX_BAD_FCS_PKTS 46
+#define MC_CMD_MAC_RX_OVERFLOW_PKTS 47
+#define MC_CMD_MAC_RX_FALSE_CARRIER_PKTS 48
+#define MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS 49
+#define MC_CMD_MAC_RX_ALIGN_ERROR_PKTS 50
+#define MC_CMD_MAC_RX_LENGTH_ERROR_PKTS 51
+#define MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS 52
+#define MC_CMD_MAC_RX_JABBER_PKTS 53
+#define MC_CMD_MAC_RX_NODESC_DROPS 54
+#define MC_CMD_MAC_RX_LANES01_CHAR_ERR 55
+#define MC_CMD_MAC_RX_LANES23_CHAR_ERR 56
+#define MC_CMD_MAC_RX_LANES01_DISP_ERR 57
+#define MC_CMD_MAC_RX_LANES23_DISP_ERR 58
+#define MC_CMD_MAC_RX_MATCH_FAULT 59
+/* Insert new members here. */
+#define MC_CMD_MAC_GENERATION_END 60
+#define MC_CMD_MAC_NSTATS (MC_CMD_MAC_GENERATION_END+1)
+
+/* MC_CMD_MAC_STATS:
+ * Get unified GMAC/XMAC statistics
+ *
+ * This call returns unified statistics maintained by the MC as it
+ * switches between the GMAC and XMAC. The MC will write out all
+ * supported stats.  The driver should zero initialise the buffer to
+ * guarantee consistent results.
+ *
+ * Locks required: None
+ * Returns: 0
+ * Response methods: shared memory, event
+ */
+#define MC_CMD_MAC_STATS 0x2e
+#define MC_CMD_MAC_STATS_IN_LEN 16
+#define MC_CMD_MAC_STATS_IN_DMA_ADDR_LO_OFST 0
+#define MC_CMD_MAC_STATS_IN_DMA_ADDR_HI_OFST 4
+#define MC_CMD_MAC_STATS_IN_CMD_OFST 8
+#define MC_CMD_MAC_STATS_CMD_DMA_LBN 0
+#define MC_CMD_MAC_STATS_CMD_DMA_WIDTH 1
+#define MC_CMD_MAC_STATS_CMD_CLEAR_LBN 1
+#define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1
+/* Fields only relevent when PERIODIC_CHANGE is set */
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_WIDTH 1
+#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_LBN 16
+#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_WIDTH 16
+#define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12
+
+#define MC_CMD_MAC_STATS_OUT_LEN 0
+
+/* Callisto flags */
+#define MC_CMD_SFT9001_ROBUST_LBN 0
+#define MC_CMD_SFT9001_ROBUST_WIDTH 1
+#define MC_CMD_SFT9001_SHORT_REACH_LBN 1
+#define MC_CMD_SFT9001_SHORT_REACH_WIDTH 1
+
+/* MC_CMD_SFT9001_GET:
+ * Read current callisto specific setting
+ *
+ * Locks required: None
+ * Returns: 0, ETIME
+ */
+#define MC_CMD_SFT9001_GET 0x30
+#define MC_CMD_SFT9001_GET_IN_LEN 0
+#define MC_CMD_SFT9001_GET_OUT_LEN 4
+#define MC_CMD_SFT9001_GET_OUT_FLAGS_OFST 0
+
+/* MC_CMD_SFT9001_SET:
+ * Write current callisto specific setting
+ *
+ * Locks required: None
+ * Returns: 0, ETIME, EINVAL
+ */
+#define MC_CMD_SFT9001_SET 0x31
+#define MC_CMD_SFT9001_SET_IN_LEN 4
+#define MC_CMD_SFT9001_SET_IN_FLAGS_OFST 0
+#define MC_CMD_SFT9001_SET_OUT_LEN 0
+
+
+/* MC_CMD_WOL_FILTER_SET:
+ * Set a WoL filter
+ *
+ * Locks required: None
+ * Returns: 0, EBUSY, EINVAL, ENOSYS
+ */
+#define MC_CMD_WOL_FILTER_SET 0x32
+#define MC_CMD_WOL_FILTER_SET_IN_LEN 192 /* 190 rounded up to a word */
+#define MC_CMD_WOL_FILTER_SET_IN_FILTER_MODE_OFST 0
+#define MC_CMD_WOL_FILTER_SET_IN_WOL_TYPE_OFST 4
+
+/* There is a union at offset 8, following defines overlap due to
+ * this */
+#define MC_CMD_WOL_FILTER_SET_IN_DATA_OFST 8
+
+#define MC_CMD_WOL_FILTER_SET_IN_MAGIC_MAC_OFST                \
+       MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+
+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_IP_OFST   \
+       MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_IP_OFST   \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 4)
+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_PORT_OFST \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 8)
+#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_PORT_OFST \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 10)
+
+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_IP_OFST   \
+       MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_IP_OFST   \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 16)
+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_PORT_OFST \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 32)
+#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_PORT_OFST \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 34)
+
+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_MASK_OFST      \
+       MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_OFST           \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 48)
+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LEN_OFST       \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 176)
+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER3_OFST    \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 177)
+#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST    \
+       (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178)
+
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_MASK_OFST        \
+       MC_CMD_WOL_FILTER_SET_IN_DATA_OFST
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_UP_LBN   0
+#define MC_CMD_WOL_FILTER_SET_IN_LINK_DOWN_LBN 1
+
+#define MC_CMD_WOL_FILTER_SET_OUT_LEN 4
+#define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0
+
+/* WOL Filter types enumeration */
+#define MC_CMD_WOL_TYPE_MAGIC      0x0
+                        /* unused 0x1 */
+#define MC_CMD_WOL_TYPE_WIN_MAGIC  0x2
+#define MC_CMD_WOL_TYPE_IPV4_SYN   0x3
+#define MC_CMD_WOL_TYPE_IPV6_SYN   0x4
+#define MC_CMD_WOL_TYPE_BITMAP     0x5
+#define MC_CMD_WOL_TYPE_LINK       0x6
+#define MC_CMD_WOL_TYPE_MAX        0x7
+
+#define MC_CMD_FILTER_MODE_SIMPLE     0x0
+#define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff
+
+/* MC_CMD_WOL_FILTER_REMOVE:
+ * Remove a WoL filter
+ *
+ * Locks required: None
+ * Returns: 0, EINVAL, ENOSYS
+ */
+#define MC_CMD_WOL_FILTER_REMOVE 0x33
+#define MC_CMD_WOL_FILTER_REMOVE_IN_LEN 4
+#define MC_CMD_WOL_FILTER_REMOVE_IN_FILTER_ID_OFST 0
+#define MC_CMD_WOL_FILTER_REMOVE_OUT_LEN 0
+
+
+/* MC_CMD_WOL_FILTER_RESET:
+ * Reset (i.e. remove all) WoL filters
+ *
+ * Locks required: None
+ * Returns: 0, ENOSYS
+ */
+#define MC_CMD_WOL_FILTER_RESET 0x34
+#define MC_CMD_WOL_FILTER_RESET_IN_LEN 0
+#define MC_CMD_WOL_FILTER_RESET_OUT_LEN 0
+
+/* MC_CMD_SET_MCAST_HASH:
+ * Set the MCASH hash value without otherwise
+ * reconfiguring the MAC
+ */
+#define MC_CMD_SET_MCAST_HASH 0x35
+#define MC_CMD_SET_MCAST_HASH_IN_LEN 32
+#define MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST 0
+#define MC_CMD_SET_MCAST_HASH_IN_HASH1_OFST 16
+#define MC_CMD_SET_MCAST_HASH_OUT_LEN 0
+
+/* MC_CMD_NVRAM_TYPES:
+ * Return bitfield indicating available types of virtual NVRAM partitions
+ *
+ * Locks required: none
+ * Returns: 0
+ */
+#define MC_CMD_NVRAM_TYPES 0x36
+#define MC_CMD_NVRAM_TYPES_IN_LEN 0
+#define MC_CMD_NVRAM_TYPES_OUT_LEN 4
+#define MC_CMD_NVRAM_TYPES_OUT_TYPES_OFST 0
+
+/* Supported NVRAM types */
+#define MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO 0
+#define MC_CMD_NVRAM_TYPE_MC_FW 1
+#define MC_CMD_NVRAM_TYPE_MC_FW_BACKUP 2
+#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 3
+#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1 4
+#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 5
+#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1 6
+#define MC_CMD_NVRAM_TYPE_EXP_ROM 7
+#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0 8
+#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1 9
+#define MC_CMD_NVRAM_TYPE_PHY_PORT0 10
+#define MC_CMD_NVRAM_TYPE_PHY_PORT1 11
+#define MC_CMD_NVRAM_TYPE_LOG 12
+
+/* MC_CMD_NVRAM_INFO:
+ * Read info about a virtual NVRAM partition
+ *
+ * Locks required: none
+ * Returns: 0, EINVAL (bad type)
+ */
+#define MC_CMD_NVRAM_INFO 0x37
+#define MC_CMD_NVRAM_INFO_IN_LEN 4
+#define MC_CMD_NVRAM_INFO_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_INFO_OUT_LEN 24
+#define MC_CMD_NVRAM_INFO_OUT_TYPE_OFST 0
+#define MC_CMD_NVRAM_INFO_OUT_SIZE_OFST 4
+#define MC_CMD_NVRAM_INFO_OUT_ERASESIZE_OFST 8
+#define MC_CMD_NVRAM_INFO_OUT_FLAGS_OFST 12
+#define   MC_CMD_NVRAM_PROTECTED_LBN 0
+#define   MC_CMD_NVRAM_PROTECTED_WIDTH 1
+#define MC_CMD_NVRAM_INFO_OUT_PHYSDEV_OFST 16
+#define MC_CMD_NVRAM_INFO_OUT_PHYSADDR_OFST 20
+
+/* MC_CMD_NVRAM_UPDATE_START:
+ * Start a group of update operations on a virtual NVRAM partition
+ *
+ * Locks required: PHY_LOCK if type==*PHY*
+ * Returns: 0, EINVAL (bad type), EACCES (if PHY_LOCK required and not held)
+ */
+#define MC_CMD_NVRAM_UPDATE_START 0x38
+#define MC_CMD_NVRAM_UPDATE_START_IN_LEN 4
+#define MC_CMD_NVRAM_UPDATE_START_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_UPDATE_START_OUT_LEN 0
+
+/* MC_CMD_NVRAM_READ:
+ * Read data from a virtual NVRAM partition
+ *
+ * Locks required: PHY_LOCK if type==*PHY*
+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held)
+ */
+#define MC_CMD_NVRAM_READ 0x39
+#define MC_CMD_NVRAM_READ_IN_LEN 12
+#define MC_CMD_NVRAM_READ_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_READ_IN_OFFSET_OFST 4
+#define MC_CMD_NVRAM_READ_IN_LENGTH_OFST 8
+#define MC_CMD_NVRAM_READ_OUT_LEN(_read_bytes) (_read_bytes)
+#define MC_CMD_NVRAM_READ_OUT_READ_BUFFER_OFST 0
+
+/* MC_CMD_NVRAM_WRITE:
+ * Write data to a virtual NVRAM partition
+ *
+ * Locks required: PHY_LOCK if type==*PHY*
+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held)
+ */
+#define MC_CMD_NVRAM_WRITE 0x3a
+#define MC_CMD_NVRAM_WRITE_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_WRITE_IN_OFFSET_OFST 4
+#define MC_CMD_NVRAM_WRITE_IN_LENGTH_OFST 8
+#define MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_OFST 12
+#define MC_CMD_NVRAM_WRITE_IN_LEN(_write_bytes) (12 + _write_bytes)
+#define MC_CMD_NVRAM_WRITE_OUT_LEN 0
+
+/* MC_CMD_NVRAM_ERASE:
+ * Erase sector(s) from a virtual NVRAM partition
+ *
+ * Locks required: PHY_LOCK if type==*PHY*
+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held)
+ */
+#define MC_CMD_NVRAM_ERASE 0x3b
+#define MC_CMD_NVRAM_ERASE_IN_LEN 12
+#define MC_CMD_NVRAM_ERASE_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_ERASE_IN_OFFSET_OFST 4
+#define MC_CMD_NVRAM_ERASE_IN_LENGTH_OFST 8
+#define MC_CMD_NVRAM_ERASE_OUT_LEN 0
+
+/* MC_CMD_NVRAM_UPDATE_FINISH:
+ * Finish a group of update operations on a virtual NVRAM partition
+ *
+ * Locks required: PHY_LOCK if type==*PHY*
+ * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held)
+ */
+#define MC_CMD_NVRAM_UPDATE_FINISH 0x3c
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 8
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_UPDATE_FINISH_IN_REBOOT_OFST 4
+#define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0
+
+/* MC_CMD_REBOOT:
+ * Reboot the MC.
+ *
+ * The AFTER_ASSERTION flag is intended to be used when the driver notices
+ * an assertion failure (at which point it is expected to perform a complete
+ * tear down and reinitialise), to allow both ports to reset the MC once
+ * in an atomic fashion.
+ *
+ * Production mc firmwares are generally compiled with REBOOT_ON_ASSERT=1,
+ * which means that they will automatically reboot out of the assertion
+ * handler, so this is in practise an optional operation. It is still
+ * recommended that drivers execute this to support custom firmwares
+ * with REBOOT_ON_ASSERT=0.
+ *
+ * Locks required: NONE
+ * Returns: Nothing. You get back a response with ERR=1, DATALEN=0
+ */
+#define MC_CMD_REBOOT 0x3d
+#define MC_CMD_REBOOT_IN_LEN 4
+#define MC_CMD_REBOOT_IN_FLAGS_OFST 0
+#define MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION 1
+#define MC_CMD_REBOOT_OUT_LEN 0
+
+/* MC_CMD_SCHEDINFO:
+ * Request scheduler info. from the MC.
+ *
+ * Locks required: NONE
+ * Returns: An array of (timeslice,maximum overrun), one for each thread,
+ * in ascending order of thread address.s
+ */
+#define MC_CMD_SCHEDINFO 0x3e
+#define MC_CMD_SCHEDINFO_IN_LEN 0
+
+
+/* MC_CMD_SET_REBOOT_MODE: (debug)
+ * Set the mode for the next MC reboot.
+ *
+ * Locks required: NONE
+ *
+ * Sets the reboot mode to the specified value.  Returns the old mode.
+ */
+#define MC_CMD_REBOOT_MODE 0x3f
+#define MC_CMD_REBOOT_MODE_IN_LEN 4
+#define MC_CMD_REBOOT_MODE_IN_VALUE_OFST 0
+#define MC_CMD_REBOOT_MODE_OUT_LEN 4
+#define MC_CMD_REBOOT_MODE_OUT_VALUE_OFST 0
+#define   MC_CMD_REBOOT_MODE_NORMAL 0
+#define   MC_CMD_REBOOT_MODE_SNAPPER 3
+
+/* MC_CMD_DEBUG_LOG:
+ * Null request/response command (debug)
+ * - sequence number is always zero
+ * - only supported on the UART interface
+ * (the same set of bytes is delivered as an
+ * event over PCI)
+ */
+#define MC_CMD_DEBUG_LOG 0x40
+#define MC_CMD_DEBUG_LOG_IN_LEN 0
+#define MC_CMD_DEBUG_LOG_OUT_LEN 0
+
+/* Generic sensor enumeration. Note that a dual port NIC
+ * will EITHER expose PHY_COMMON_TEMP OR PHY0_TEMP and
+ * PHY1_TEMP depending on whether there is a single sensor
+ * in the vicinity of the two port, or one per port.
+ */
+#define MC_CMD_SENSOR_CONTROLLER_TEMP 0                /* degC */
+#define MC_CMD_SENSOR_PHY_COMMON_TEMP 1                /* degC */
+#define MC_CMD_SENSOR_CONTROLLER_COOLING 2     /* bool */
+#define MC_CMD_SENSOR_PHY0_TEMP 3              /* degC */
+#define MC_CMD_SENSOR_PHY0_COOLING 4           /* bool */
+#define MC_CMD_SENSOR_PHY1_TEMP 5              /* degC */
+#define MC_CMD_SENSOR_PHY1_COOLING 6           /* bool */
+#define MC_CMD_SENSOR_IN_1V0 7                 /* mV */
+#define MC_CMD_SENSOR_IN_1V2 8                 /* mV */
+#define MC_CMD_SENSOR_IN_1V8 9                 /* mV */
+#define MC_CMD_SENSOR_IN_2V5 10                        /* mV */
+#define MC_CMD_SENSOR_IN_3V3 11                        /* mV */
+#define MC_CMD_SENSOR_IN_12V0 12               /* mV */
+
+
+/* Sensor state */
+#define MC_CMD_SENSOR_STATE_OK 0
+#define MC_CMD_SENSOR_STATE_WARNING 1
+#define MC_CMD_SENSOR_STATE_FATAL 2
+#define MC_CMD_SENSOR_STATE_BROKEN 3
+
+/* MC_CMD_SENSOR_INFO:
+ * Returns information about every available sensor.
+ *
+ * Each sensor has a single (16bit) value, and a corresponding state.
+ * The mapping between value and sensor is nominally determined by the
+ * MC, but in practise is implemented as zero (BROKEN), one (TEMPERATURE),
+ * or two (VOLTAGE) ranges per sensor per state.
+ *
+ * This call returns a mask (32bit) of the sensors that are supported
+ * by this platform, then an array (indexed by MC_CMD_SENSOR) of byte
+ * offsets to the per-sensor arrays. Each sensor array has four 16bit
+ * numbers, min1, max1, min2, max2.
+ *
+ * Locks required: None
+ * Returns: 0
+ */
+#define MC_CMD_SENSOR_INFO 0x41
+#define MC_CMD_SENSOR_INFO_IN_LEN 0
+#define MC_CMD_SENSOR_INFO_OUT_MASK_OFST 0
+#define MC_CMD_SENSOR_INFO_OUT_OFFSET_OFST(_x) \
+       (4 + (_x))
+#define MC_CMD_SENSOR_INFO_OUT_MIN1_OFST(_ofst) \
+       ((_ofst) + 0)
+#define MC_CMD_SENSOR_INFO_OUT_MAX1_OFST(_ofst) \
+       ((_ofst) + 2)
+#define MC_CMD_SENSOR_INFO_OUT_MIN2_OFST(_ofst) \
+       ((_ofst) + 4)
+#define MC_CMD_SENSOR_INFO_OUT_MAX2_OFST(_ofst) \
+       ((_ofst) + 6)
+
+/* MC_CMD_READ_SENSORS
+ * Returns the current reading from each sensor
+ *
+ * Returns a sparse array of sensor readings (indexed by the sensor
+ * type) into host memory.  Each array element is a dword.
+ *
+ * The MC will send a SENSOREVT event every time any sensor changes state. The
+ * driver is responsible for ensuring that it doesn't miss any events. The board
+ * will function normally if all sensors are in STATE_OK or state_WARNING.
+ * Otherwise the board should not be expected to function.
+ */
+#define MC_CMD_READ_SENSORS 0x42
+#define MC_CMD_READ_SENSORS_IN_LEN 8
+#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_LO_OFST 0
+#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4
+#define MC_CMD_READ_SENSORS_OUT_LEN 0
+
+/* Sensor reading fields */
+#define MC_CMD_READ_SENSOR_VALUE_LBN 0
+#define MC_CMD_READ_SENSOR_VALUE_WIDTH 16
+#define MC_CMD_READ_SENSOR_STATE_LBN 16
+#define MC_CMD_READ_SENSOR_STATE_WIDTH 8
+
+
+/* MC_CMD_GET_PHY_STATE:
+ * Report current state of PHY.  A "zombie" PHY is a PHY that has failed to
+ * boot (e.g. due to missing or corrupted firmware).
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_GET_PHY_STATE 0x43
+
+#define MC_CMD_GET_PHY_STATE_IN_LEN 0
+#define MC_CMD_GET_PHY_STATE_OUT_LEN 4
+#define MC_CMD_GET_PHY_STATE_STATE_OFST 0
+/* PHY state enumeration: */
+#define MC_CMD_PHY_STATE_OK 1
+#define MC_CMD_PHY_STATE_ZOMBIE 2
+
+
+/* 802.1Qbb control. 8 Tx queues that map to priorities 0 - 7. Use all 1s to
+ * disable 802.Qbb for a given priority. */
+#define MC_CMD_SETUP_8021QBB 0x44
+#define MC_CMD_SETUP_8021QBB_IN_LEN 32
+#define MC_CMD_SETUP_8021QBB_OUT_LEN 0
+#define MC_CMD_SETUP_8021QBB_IN_TXQS_OFFST 0
+
+
+/* MC_CMD_WOL_FILTER_GET:
+ * Retrieve ID of any WoL filters
+ *
+ * Locks required: None
+ * Returns: 0, ENOSYS
+ */
+#define MC_CMD_WOL_FILTER_GET 0x45
+#define MC_CMD_WOL_FILTER_GET_IN_LEN 0
+#define MC_CMD_WOL_FILTER_GET_OUT_LEN 4
+#define MC_CMD_WOL_FILTER_GET_OUT_FILTER_ID_OFST 0
+
+
+/* MC_CMD_ADD_LIGHTSOUT_OFFLOAD:
+ * Offload a protocol to NIC for lights-out state
+ *
+ * Locks required: None
+ * Returns: 0, ENOSYS
+ */
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD 0x46
+
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_LEN 16
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0
+
+/* There is a union at offset 4, following defines overlap due to
+ * this */
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_DATA_OFST 4
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPMAC_OFST 4
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPIP_OFST 10
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSMAC_OFST 4
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSSNIPV6_OFST 10
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSIPV6_OFST 26
+
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN 4
+#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID_OFST 0
+
+
+/* MC_CMD_REMOVE_LIGHTSOUT_PROTOCOL_OFFLOAD:
+ * Offload a protocol to NIC for lights-out state
+ *
+ * Locks required: None
+ * Returns: 0, ENOSYS
+ */
+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD 0x47
+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN 8
+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN 0
+
+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0
+#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID_OFST 4
+
+/* Lights-out offload protocols enumeration */
+#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP 0x1
+#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS  0x2
+
+
+/* MC_CMD_MAC_RESET_RESTORE:
+ * Restore MAC after block reset
+ *
+ * Locks required: None
+ * Returns: 0
+ */
+
+#define MC_CMD_MAC_RESET_RESTORE 0x48
+#define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0
+#define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0
+
+
+/* MC_CMD_TEST_ASSERT:
+ * Deliberately trigger an assert-detonation in the firmware for testing
+ * purposes (i.e. to allow tests that the driver copes gracefully).
+ *
+ * Locks required: None
+ * Returns: 0
+ */
+
+#define MC_CMD_TESTASSERT 0x49
+#define MC_CMD_TESTASSERT_IN_LEN 0
+#define MC_CMD_TESTASSERT_OUT_LEN 0
+
+/* MC_CMD_WORKAROUND 0x4a
+ *
+ * Enable/Disable a given workaround. The mcfw will return EINVAL if it
+ * doesn't understand the given workaround number - which should not
+ * be treated as a hard error by client code.
+ *
+ * This op does not imply any semantics about each workaround, that's between
+ * the driver and the mcfw on a per-workaround basis.
+ *
+ * Locks required: None
+ * Returns: 0, EINVAL
+ */
+#define MC_CMD_WORKAROUND 0x4a
+#define MC_CMD_WORKAROUND_IN_LEN 8
+#define MC_CMD_WORKAROUND_IN_TYPE_OFST 0
+#define MC_CMD_WORKAROUND_BUG17230 1
+#define MC_CMD_WORKAROUND_IN_ENABLED_OFST 4
+#define MC_CMD_WORKAROUND_OUT_LEN 0
+
+/* MC_CMD_GET_PHY_MEDIA_INFO:
+ * Read media-specific data from PHY (e.g. SFP/SFP+ module ID information for
+ * SFP+ PHYs).
+ *
+ * The "media type" can be found via GET_PHY_CFG (GET_PHY_CFG_OUT_MEDIA_TYPE);
+ * the valid "page number" input values, and the output data, are interpreted
+ * on a per-type basis.
+ *
+ * For SFP+: PAGE=0 or 1 returns a 128-byte block read from module I2C address
+ *           0xA0 offset 0 or 0x80.
+ * Anything else: currently undefined.
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_GET_PHY_MEDIA_INFO 0x4b
+#define MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN 4
+#define MC_CMD_GET_PHY_MEDIA_INFO_IN_PAGE_OFST 0
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(_num_bytes) (4 + (_num_bytes))
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATALEN_OFST 0
+#define MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST 4
+
+/* MC_CMD_NVRAM_TEST:
+ * Test a particular NVRAM partition for valid contents (where "valid"
+ * depends on the type of partition).
+ *
+ * Locks required: None
+ * Return code: 0
+ */
+#define MC_CMD_NVRAM_TEST 0x4c
+#define MC_CMD_NVRAM_TEST_IN_LEN 4
+#define MC_CMD_NVRAM_TEST_IN_TYPE_OFST 0
+#define MC_CMD_NVRAM_TEST_OUT_LEN 4
+#define MC_CMD_NVRAM_TEST_OUT_RESULT_OFST 0
+#define MC_CMD_NVRAM_TEST_PASS 0
+#define MC_CMD_NVRAM_TEST_FAIL 1
+#define MC_CMD_NVRAM_TEST_NOTSUPP 2
+
+/* MC_CMD_MRSFP_TWEAK: (debug)
+ * Read status and/or set parameters for the "mrsfp" driver in mr_rusty builds.
+ * I2C I/O expander bits are always read; if equaliser parameters are supplied,
+ * they are configured first.
+ *
+ * Locks required: None
+ * Return code: 0, EINVAL
+ */
+#define MC_CMD_MRSFP_TWEAK 0x4d
+#define MC_CMD_MRSFP_TWEAK_IN_LEN_READ_ONLY 0
+#define MC_CMD_MRSFP_TWEAK_IN_LEN_EQ_CONFIG 16
+#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_LEVEL_OFST 0    /* 0-6 dB de-emphasis */
+#define MC_CMD_MRSFP_TWEAK_IN_TXEQ_DT_CFG_OFST 4   /* 0-8 low->high ref.V */
+#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_BOOST_OFST 8    /* 0-8 dB boost */
+#define MC_CMD_MRSFP_TWEAK_IN_RXEQ_DT_CFG_OFST 12  /* 0-8 low->high ref.V */
+#define MC_CMD_MRSFP_TWEAK_OUT_LEN 12
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_INPUTS_OFST 0     /* input bits */
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_OUTPUTS_OFST 4    /* output bits */
+#define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_DIRECTION_OFST 8  /* dirs: 0=out, 1=in */
+
+
+#endif /* MCDI_PCOL_H */
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
new file mode 100644 (file)
index 0000000..ab8a87b
--- /dev/null
@@ -0,0 +1,616 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 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.
+ */
+
+/*
+ * Driver for PHY related operations via MCDI.
+ */
+
+#include "efx.h"
+#include "phy.h"
+#include "mcdi.h"
+#include "mcdi_pcol.h"
+#include "mdio_10g.h"
+
+struct efx_mcdi_phy_cfg {
+       u32 flags;
+       u32 type;
+       u32 supported_cap;
+       u32 channel;
+       u32 port;
+       u32 stats_mask;
+       u8 name[20];
+       u32 media;
+       u32 mmd_mask;
+       u8 revision[20];
+       u32 forced_cap;
+};
+
+static int
+efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
+{
+       u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0);
+       BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name));
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) {
+               rc = -EMSGSIZE;
+               goto fail;
+       }
+
+       cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS);
+       cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE);
+       cfg->supported_cap =
+               MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP);
+       cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL);
+       cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT);
+       cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK);
+       memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME),
+              sizeof(cfg->name));
+       cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE);
+       cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK);
+       memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION),
+              sizeof(cfg->revision));
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,
+                            u32 flags, u32 loopback_mode,
+                            u32 loopback_speed)
+{
+       u8 inbuf[MC_CMD_SET_LINK_IN_LEN];
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0);
+
+       MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities);
+       MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags);
+       MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode);
+       MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf),
+                         NULL, 0, NULL);
+       if (rc)
+               goto fail;
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes)
+{
+       u8 outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) {
+               rc = -EMSGSIZE;
+               goto fail;
+       }
+
+       *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_SUGGESTED);
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus,
+                        unsigned int prtad, unsigned int devad, u16 addr,
+                        u16 *value_out, u32 *status_out)
+{
+       u8 inbuf[MC_CMD_MDIO_READ_IN_LEN];
+       u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus);
+       MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad);
+       MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad);
+       MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE);
+       *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS);
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus,
+                         unsigned int prtad, unsigned int devad, u16 addr,
+                         u16 value, u32 *status_out)
+{
+       u8 inbuf[MC_CMD_MDIO_WRITE_IN_LEN];
+       u8 outbuf[MC_CMD_MDIO_WRITE_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, bus);
+       MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad);
+       MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad);
+       MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr);
+       MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf),
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               goto fail;
+
+       *status_out = MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS);
+       return 0;
+
+fail:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
+}
+
+static u32 mcdi_to_ethtool_cap(u32 media, u32 cap)
+{
+       u32 result = 0;
+
+       switch (media) {
+       case MC_CMD_MEDIA_KX4:
+               result |= SUPPORTED_Backplane;
+               if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
+                       result |= SUPPORTED_1000baseKX_Full;
+               if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
+                       result |= SUPPORTED_10000baseKX4_Full;
+               break;
+
+       case MC_CMD_MEDIA_XFP:
+       case MC_CMD_MEDIA_SFP_PLUS:
+               result |= SUPPORTED_FIBRE;
+               break;
+
+       case MC_CMD_MEDIA_BASE_T:
+               result |= SUPPORTED_TP;
+               if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
+                       result |= SUPPORTED_10baseT_Half;
+               if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
+                       result |= SUPPORTED_10baseT_Full;
+               if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
+                       result |= SUPPORTED_100baseT_Half;
+               if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
+                       result |= SUPPORTED_100baseT_Full;
+               if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
+                       result |= SUPPORTED_1000baseT_Half;
+               if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
+                       result |= SUPPORTED_1000baseT_Full;
+               if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
+                       result |= SUPPORTED_10000baseT_Full;
+               break;
+       }
+
+       if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
+               result |= SUPPORTED_Pause;
+       if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
+               result |= SUPPORTED_Asym_Pause;
+       if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
+               result |= SUPPORTED_Autoneg;
+
+       return result;
+}
+
+static u32 ethtool_to_mcdi_cap(u32 cap)
+{
+       u32 result = 0;
+
+       if (cap & SUPPORTED_10baseT_Half)
+               result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN);
+       if (cap & SUPPORTED_10baseT_Full)
+               result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN);
+       if (cap & SUPPORTED_100baseT_Half)
+               result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN);
+       if (cap & SUPPORTED_100baseT_Full)
+               result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN);
+       if (cap & SUPPORTED_1000baseT_Half)
+               result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN);
+       if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full))
+               result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN);
+       if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full))
+               result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN);
+       if (cap & SUPPORTED_Pause)
+               result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN);
+       if (cap & SUPPORTED_Asym_Pause)
+               result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN);
+       if (cap & SUPPORTED_Autoneg)
+               result |= (1 << MC_CMD_PHY_CAP_AN_LBN);
+
+       return result;
+}
+
+static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+       enum efx_phy_mode mode, supported;
+       u32 flags;
+
+       /* TODO: Advertise the capabilities supported by this PHY */
+       supported = 0;
+       if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_TXDIS_LBN))
+               supported |= PHY_MODE_TX_DISABLED;
+       if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_LOWPOWER_LBN))
+               supported |= PHY_MODE_LOW_POWER;
+       if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_POWEROFF_LBN))
+               supported |= PHY_MODE_OFF;
+
+       mode = efx->phy_mode & supported;
+
+       flags = 0;
+       if (mode & PHY_MODE_TX_DISABLED)
+               flags |= (1 << MC_CMD_SET_LINK_TXDIS_LBN);
+       if (mode & PHY_MODE_LOW_POWER)
+               flags |= (1 << MC_CMD_SET_LINK_LOWPOWER_LBN);
+       if (mode & PHY_MODE_OFF)
+               flags |= (1 << MC_CMD_SET_LINK_POWEROFF_LBN);
+
+       return flags;
+}
+
+static u32 mcdi_to_ethtool_media(u32 media)
+{
+       switch (media) {
+       case MC_CMD_MEDIA_XAUI:
+       case MC_CMD_MEDIA_CX4:
+       case MC_CMD_MEDIA_KX4:
+               return PORT_OTHER;
+
+       case MC_CMD_MEDIA_XFP:
+       case MC_CMD_MEDIA_SFP_PLUS:
+               return PORT_FIBRE;
+
+       case MC_CMD_MEDIA_BASE_T:
+               return PORT_TP;
+
+       default:
+               return PORT_OTHER;
+       }
+}
+
+static int efx_mcdi_phy_probe(struct efx_nic *efx)
+{
+       struct efx_mcdi_phy_cfg *phy_data;
+       u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
+       u32 caps;
+       int rc;
+
+       /* Initialise and populate phy_data */
+       phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+       if (phy_data == NULL)
+               return -ENOMEM;
+
+       rc = efx_mcdi_get_phy_cfg(efx, phy_data);
+       if (rc != 0)
+               goto fail;
+
+       /* Read initial link advertisement */
+       BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
+                         outbuf, sizeof(outbuf), NULL);
+       if (rc)
+               goto fail;
+
+       /* Fill out nic state */
+       efx->phy_data = phy_data;
+       efx->phy_type = phy_data->type;
+       strlcpy(efx->phy_name, phy_data->name, sizeof(efx->phy_name));
+
+       efx->mdio_bus = phy_data->channel;
+       efx->mdio.prtad = phy_data->port;
+       efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22);
+       efx->mdio.mode_support = 0;
+       if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22))
+               efx->mdio.mode_support |= MDIO_SUPPORTS_C22;
+       if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22))
+               efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+
+       caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);
+       if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))
+               efx->link_advertising =
+                       mcdi_to_ethtool_cap(phy_data->media, caps);
+       else
+               phy_data->forced_cap = caps;
+
+       /* Assert that we can map efx -> mcdi loopback modes */
+       BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE);
+       BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA);
+       BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC);
+       BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII);
+       BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS);
+       BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI);
+       BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII);
+       BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII);
+       BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR);
+       BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI);
+       BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR);
+       BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR);
+       BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR);
+       BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR);
+       BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY);
+       BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS);
+       BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS);
+       BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD);
+       BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT);
+       BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS);
+       BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS);
+       BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR);
+       BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR);
+       BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS);
+       BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS);
+       BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR);
+       BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS);
+
+       rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes);
+       if (rc != 0)
+               goto fail;
+       /* The MC indicates that LOOPBACK_NONE is a valid loopback mode,
+        * but by convention we don't */
+       efx->loopback_modes &= ~(1 << LOOPBACK_NONE);
+       efx->startup_loopback_mode = __ffs(efx->loopback_modes);
+
+       /* Set the initial link mode */
+       efx_mcdi_phy_decode_link(
+               efx, &efx->link_state,
+               MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
+               MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
+               MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
+
+       /* Default to Autonegotiated flow control if the PHY supports it */
+       efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
+       if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
+               efx->wanted_fc |= EFX_FC_AUTO;
+
+       return 0;
+
+fail:
+       kfree(phy_data);
+       return rc;
+}
+
+int efx_mcdi_phy_reconfigure(struct efx_nic *efx)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+       u32 caps = (efx->link_advertising ?
+                   ethtool_to_mcdi_cap(efx->link_advertising) :
+                   phy_cfg->forced_cap);
+
+       return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
+                                efx->loopback_mode, 0);
+}
+
+void efx_mcdi_phy_decode_link(struct efx_nic *efx,
+                             struct efx_link_state *link_state,
+                             u32 speed, u32 flags, u32 fcntl)
+{
+       switch (fcntl) {
+       case MC_CMD_FCNTL_AUTO:
+               WARN_ON(1);     /* This is not a link mode */
+               link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX;
+               break;
+       case MC_CMD_FCNTL_BIDIR:
+               link_state->fc = EFX_FC_TX | EFX_FC_RX;
+               break;
+       case MC_CMD_FCNTL_RESPOND:
+               link_state->fc = EFX_FC_RX;
+               break;
+       default:
+               WARN_ON(1);
+       case MC_CMD_FCNTL_OFF:
+               link_state->fc = 0;
+               break;
+       }
+
+       link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_LINK_UP_LBN));
+       link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_FULL_DUPLEX_LBN));
+       link_state->speed = speed;
+}
+
+/* Verify that the forced flow control settings (!EFX_FC_AUTO) are
+ * supported by the link partner. Warn the user if this isn't the case
+ */
+void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+       u32 rmtadv;
+
+       /* The link partner capabilities are only relevent if the
+        * link supports flow control autonegotiation */
+       if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
+               return;
+
+       /* If flow control autoneg is supported and enabled, then fine */
+       if (efx->wanted_fc & EFX_FC_AUTO)
+               return;
+
+       rmtadv = 0;
+       if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
+               rmtadv |= ADVERTISED_Pause;
+       if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
+               rmtadv |=  ADVERTISED_Asym_Pause;
+
+       if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause)
+               EFX_ERR(efx, "warning: link partner doesn't support "
+                       "pause frames");
+}
+
+static bool efx_mcdi_phy_poll(struct efx_nic *efx)
+{
+       struct efx_link_state old_state = efx->link_state;
+       u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
+       int rc;
+
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+       BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
+                         outbuf, sizeof(outbuf), NULL);
+       if (rc) {
+               EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+               efx->link_state.up = false;
+       } else {
+               efx_mcdi_phy_decode_link(
+                       efx, &efx->link_state,
+                       MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
+                       MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
+                       MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
+       }
+
+       return !efx_link_state_equal(&efx->link_state, &old_state);
+}
+
+static void efx_mcdi_phy_remove(struct efx_nic *efx)
+{
+       struct efx_mcdi_phy_data *phy_data = efx->phy_data;
+
+       efx->phy_data = NULL;
+       kfree(phy_data);
+}
+
+static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_ETHTOOL_LP_ADVERTISING)
+       u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
+       int rc;
+#endif
+
+       ecmd->supported =
+               mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
+       ecmd->advertising = efx->link_advertising;
+       ecmd->speed = efx->link_state.speed;
+       ecmd->duplex = efx->link_state.fd;
+       ecmd->port = mcdi_to_ethtool_media(phy_cfg->media);
+       ecmd->phy_address = phy_cfg->port;
+       ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg);
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_ETHTOOL_MDIO_SUPPORT)
+       ecmd->mdio_support = (efx->mdio.mode_support &
+                             (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));
+#endif
+
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_ETHTOOL_LP_ADVERTISING)
+       BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
+                         outbuf, sizeof(outbuf), NULL);
+       if (rc) {
+               EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+               return;
+       }
+       ecmd->lp_advertising =
+               mcdi_to_ethtool_cap(phy_cfg->media,
+                                   MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
+#endif
+}
+
+static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+       u32 caps;
+       int rc;
+
+       if (ecmd->autoneg) {
+               caps = (ethtool_to_mcdi_cap(ecmd->advertising) |
+                        1 << MC_CMD_PHY_CAP_AN_LBN);
+       } else if (ecmd->duplex) {
+               switch (ecmd->speed) {
+               case 10:    caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN;    break;
+               case 100:   caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN;   break;
+               case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN;  break;
+               case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break;
+               default:    return -EINVAL;
+               }
+       } else {
+               switch (ecmd->speed) {
+               case 10:    caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN;    break;
+               case 100:   caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN;   break;
+               case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN;  break;
+               default:    return -EINVAL;
+               }
+       }
+
+       rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
+                              efx->loopback_mode, 0);
+       if (rc)
+               return rc;
+
+       if (ecmd->autoneg) {
+               efx_link_set_advertising(
+                       efx, ecmd->advertising | ADVERTISED_Autoneg);
+               phy_cfg->forced_cap = 0;
+       } else {
+               efx_link_set_advertising(efx, 0);
+               phy_cfg->forced_cap = caps;
+       }
+       return 0;
+}
+
+static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
+{
+       u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
+       size_t outlen;
+       int rc;
+
+       BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);
+
+       rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,
+                         outbuf, sizeof(outbuf), &outlen);
+       if (rc)
+               return rc;
+
+       if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
+               return -EMSGSIZE;
+       if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK)
+               return -EINVAL;
+
+       return 0;
+}
+
+struct efx_phy_operations efx_mcdi_phy_ops = {
+       .probe          = efx_mcdi_phy_probe,
+       .init           = efx_port_dummy_op_int,
+       .reconfigure    = efx_mcdi_phy_reconfigure,
+       .poll           = efx_mcdi_phy_poll,
+       .fini           = efx_port_dummy_op_void,
+       .remove         = efx_mcdi_phy_remove,
+       .get_settings   = efx_mcdi_phy_get_settings,
+       .set_settings   = efx_mcdi_phy_set_settings,
+       .test_alive     = efx_mcdi_phy_test_alive,
+       .run_tests      = NULL,
+       .test_name      = NULL,
+};
index cfdd7422aeddc506cdf1937c3806550eda09ff74..c1d5281fb8187a96056336c6bda7c4bb5dea07a5 100644 (file)
@@ -1,26 +1,10 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * 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
- ****************************************************************************
  */
 /*
  * Useful functions for working with MDIO clause 45 PHYs
@@ -30,7 +14,8 @@
 #include <linux/delay.h>
 #include "net_driver.h"
 #include "mdio_10g.h"
-#include "boards.h"
+#include "workarounds.h"
+#include "nic.h"
 
 static const char *mmd_block_names[] = {
        [0]               = "(illegal)",
@@ -41,58 +26,70 @@ static const char *mmd_block_names[] = {
        [MDIO_MMD_DTEXS]  = "DTE XS",
        [MDIO_MMD_TC]     = "TC",
        [MDIO_MMD_AN]     = "AN",
+       [MDIO_MMD_C22EXT] = "c22 ext",
 };
 static const int mmd_block_max = ARRAY_SIZE(mmd_block_names);
 
-const char *mdio_clause45_mmd_name(int mmd)
+const char *efx_mdio_mmd_name(int mmd)
 {
        return STRING_TABLE_LOOKUP(mmd, mmd_block);
 }
 
-int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
-                           int spins, int spintime)
+unsigned efx_mdio_id_oui(u32 id)
+{
+       unsigned oui = 0;
+       int i;
+
+       /* The bits of the OUI are designated a..x, with a=0 and b variable.
+        * In the id register c is the MSB but the OUI is conventionally
+        * written as bytes h..a, p..i, x..q.  Reorder the bits accordingly. */
+       for (i = 0; i < 22; ++i)
+               if (id & (1 << (i + 10)))
+                       oui |= 1 << (i ^ 7);
+
+       return oui;
+}
+
+int efx_mdio_reset_mmd(struct efx_nic *port, int mmd,
+                      int spins, int spintime)
 {
        u32 ctrl;
-       int phy_id = port->mii.phy_id;
 
        /* Catch callers passing values in the wrong units (or just silly) */
        EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
 
-       mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
-                           (1 << MDIO_MMDREG_CTRL1_RESET_LBN));
+       efx_mdio_write(port, mmd, MDIO_CTRL1, MDIO_CTRL1_RESET);
        /* Wait for the reset bit to clear. */
        do {
                msleep(spintime);
-               ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
+               ctrl = efx_mdio_read(port, mmd, MDIO_CTRL1);
                spins--;
 
-       } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
+       } while (spins && (ctrl & MDIO_CTRL1_RESET));
 
        return spins ? spins : -ETIMEDOUT;
 }
 
-static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
-                                  int fault_fatal)
+static int efx_mdio_check_mmd(struct efx_nic *efx, int mmd, int fault_fatal)
 {
        int status;
-       int phy_id = efx->mii.phy_id;
        const char *mmdname = STRING_TABLE_LOOKUP(mmd, mmd_block);
 
        if (LOOPBACK_INTERNAL(efx))
                return 0;
 
-       /* Read MMD STATUS2 to check it is responding. */
-       status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
-       if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
-            ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
-           MDIO_MMDREG_STAT2_PRESENT_VAL) {
-               EFX_ERR(efx, "PHY MMD %s not responding.\n", mmdname);
-               return -EIO;
+       if (mmd != MDIO_MMD_AN) {
+               /* Read MMD STATUS2 to check it is responding. */
+               status = efx_mdio_read(efx, mmd, MDIO_STAT2);
+               if ((status & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) {
+                       EFX_ERR(efx, "PHY MMD %s not responding.\n", mmdname);
+                       return -EIO;
+               }
        }
 
        /* Read MMD STATUS 1 to check for fault. */
-       status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
-       if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
+       status = efx_mdio_read(efx, mmd, MDIO_STAT1);
+       if (status & MDIO_STAT1_FAULT) {
                if (fault_fatal) {
                        EFX_ERR(efx, "PHY MMD %s reporting fatal"
                                " fault: status %x\n", mmdname, status);
@@ -109,8 +106,7 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
 #define MDIO45_RESET_TIME      1000 /* ms */
 #define MDIO45_RESET_ITERS     100
 
-int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
-                                 unsigned int mmd_mask)
+int efx_mdio_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask)
 {
        const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
        int tries = MDIO45_RESET_ITERS;
@@ -124,10 +120,7 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
                in_reset = 0;
                while (mask) {
                        if (mask & 1) {
-                               stat = mdio_clause45_read(efx,
-                                                         efx->mii.phy_id,
-                                                         mmd,
-                                                         MDIO_MMDREG_CTRL1);
+                               stat = efx_mdio_read(efx, mmd, MDIO_CTRL1);
                                if (stat < 0) {
                                        EFX_ERR(efx, "failed to read"
                                                " status of MMD %s\n",
@@ -135,7 +128,7 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
                                                                    mmd_block));
                                        return -EIO;
                                }
-                               if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+                               if (stat & MDIO_CTRL1_RESET)
                                        in_reset |= (1 << mmd);
                        }
                        mask = mask >> 1;
@@ -151,28 +144,32 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
                        " MMDs still in reset: %x\n", in_reset);
                rc = -ETIMEDOUT;
        }
+       else
+               EFX_INFO(efx, "mmds %x came out of reset in %d ms\n",
+                       mmd_mask, spintime * (MDIO45_RESET_ITERS - tries));
        return rc;
 }
 
-int mdio_clause45_check_mmds(struct efx_nic *efx,
-                            unsigned int mmd_mask, unsigned int fatal_mask)
+int efx_mdio_check_mmds(struct efx_nic *efx,
+                       unsigned int mmd_mask, unsigned int fatal_mask)
 {
-       int devices, mmd = 0;
-       int probe_mmd;
+       int mmd = 0, probe_mmd, devs1, devs2;
+       u32 devices;
 
        /* Historically we have probed the PHYXS to find out what devices are
         * present,but that doesn't work so well if the PHYXS isn't expected
         * to exist, if so just find the first item in the list supplied. */
-       probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
+       probe_mmd = (mmd_mask & MDIO_DEVS_PHYXS) ? MDIO_MMD_PHYXS :
            __ffs(mmd_mask);
-       devices = mdio_clause45_read(efx, efx->mii.phy_id,
-                                    probe_mmd, MDIO_MMDREG_DEVS0);
 
        /* Check all the expected MMDs are present */
-       if (devices < 0) {
+       devs1 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS1);
+       devs2 = efx_mdio_read(efx, probe_mmd, MDIO_DEVS2);
+       if (devs1 < 0 || devs2 < 0) {
                EFX_ERR(efx, "failed to read devices present\n");
                return -EIO;
        }
+       devices = devs1 | (devs2 << 16);
        if ((devices & mmd_mask) != mmd_mask) {
                EFX_ERR(efx, "required MMDs not present: got %x, "
                        "wanted %x\n", devices, mmd_mask);
@@ -184,7 +181,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx,
        while (mmd_mask) {
                if (mmd_mask & 1) {
                        int fault_fatal = fatal_mask & 1;
-                       if (mdio_clause45_check_mmd(efx, mmd, fault_fatal))
+                       if (efx_mdio_check_mmd(efx, mmd, fault_fatal))
                                return -EIO;
                }
                mmd_mask = mmd_mask >> 1;
@@ -195,247 +192,198 @@ int mdio_clause45_check_mmds(struct efx_nic *efx,
        return 0;
 }
 
-int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
+bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
 {
-       int phy_id = efx->mii.phy_id;
-       int status;
-       int ok = 1;
-       int mmd = 0;
-       int good;
+       WARN_ON(LOOPBACK_INTERNAL(efx));
 
        /* If the port is in loopback, then we should only consider a subset
         * of mmd's */
        if (LOOPBACK_INTERNAL(efx))
-               return 1;
-       else if (efx->loopback_mode == LOOPBACK_NETWORK)
-               return 0;
-       else if (!efx->phy_powered)
-               return 0;
+               return true;
+       else if ((1 << efx->loopback_mode) & LOOPBACKS_WS)
+               return false;
+       else if (efx_phy_mode_disabled(efx->phy_mode))
+               return false;
        else if (efx->loopback_mode == LOOPBACK_PHYXS)
-               mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS |
-                             MDIO_MMDREG_DEVS0_PCS |
-                             MDIO_MMDREG_DEVS0_PMAPMD);
+               mmd_mask &= ~(MDIO_DEVS_PHYXS |
+                             MDIO_DEVS_PCS |
+                             MDIO_DEVS_PMAPMD |
+                             MDIO_DEVS_AN);
        else if (efx->loopback_mode == LOOPBACK_PCS)
-               mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS |
-                             MDIO_MMDREG_DEVS0_PMAPMD);
+               mmd_mask &= ~(MDIO_DEVS_PCS |
+                             MDIO_DEVS_PMAPMD |
+                             MDIO_DEVS_AN);
        else if (efx->loopback_mode == LOOPBACK_PMAPMD)
-               mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD;
+               mmd_mask &= ~(MDIO_DEVS_PMAPMD |
+                             MDIO_DEVS_AN);
 
-       while (mmd_mask) {
-               if (mmd_mask & 1) {
-                       /* Double reads because link state is latched, and a
-                        * read moves the current state into the register */
-                       status = mdio_clause45_read(efx, phy_id,
-                                                   mmd, MDIO_MMDREG_STAT1);
-                       status = mdio_clause45_read(efx, phy_id,
-                                                   mmd, MDIO_MMDREG_STAT1);
-
-                       good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
-                       ok = ok && good;
-               }
-               mmd_mask = (mmd_mask >> 1);
-               mmd++;
-       }
-       return ok;
+       return mdio45_links_ok(&efx->mdio, mmd_mask);
 }
 
-void mdio_clause45_transmit_disable(struct efx_nic *efx, int disable)
+void efx_mdio_transmit_disable(struct efx_nic *efx)
 {
-       int phy_id = efx->mii.phy_id;
-       int ctrl1, ctrl2;
-
-       ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
-                                          MDIO_MMDREG_TXDIS);
-       if (disable)
-               ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
-       else
-               ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
-       if (ctrl1 != ctrl2)
-               mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
-                                   MDIO_MMDREG_TXDIS, ctrl2);
+       efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
+                         MDIO_PMA_TXDIS, MDIO_PMD_TXDIS_GLOBAL,
+                         efx->phy_mode & PHY_MODE_TX_DISABLED);
 }
 
-void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
+void efx_mdio_phy_reconfigure(struct efx_nic *efx)
 {
-       int phy_id = efx->mii.phy_id;
-       int ctrl1, ctrl2;
-
-       /* Handle (with debouncing) PMA/PMD loopback */
-       ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
-                                          MDIO_MMDREG_CTRL1);
-
-       if (efx->loopback_mode == LOOPBACK_PMAPMD)
-               ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
-       else
-               ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
-
-       if (ctrl1 != ctrl2)
-               mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
-                                   MDIO_MMDREG_CTRL1, ctrl2);
-
-       /* Handle (with debouncing) PCS loopback */
-       ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
-                                          MDIO_MMDREG_CTRL1);
-       if (efx->loopback_mode == LOOPBACK_PCS)
-               ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-       else
-               ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-
-       if (ctrl1 != ctrl2)
-               mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS,
-                                   MDIO_MMDREG_CTRL1, ctrl2);
-
-       /* Handle (with debouncing) PHYXS network loopback */
-       ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
-                                          MDIO_MMDREG_CTRL1);
-       if (efx->loopback_mode == LOOPBACK_NETWORK)
-               ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-       else
-               ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-
-       if (ctrl1 != ctrl2)
-               mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
-                                   MDIO_MMDREG_CTRL1, ctrl2);
+       efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD,
+                         MDIO_CTRL1, MDIO_PMA_CTRL1_LOOPBACK,
+                         efx->loopback_mode == LOOPBACK_PMAPMD);
+       efx_mdio_set_flag(efx, MDIO_MMD_PCS,
+                         MDIO_CTRL1, MDIO_PCS_CTRL1_LOOPBACK,
+                         efx->loopback_mode == LOOPBACK_PCS);
+       efx_mdio_set_flag(efx, MDIO_MMD_PHYXS,
+                         MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK,
+                         efx->loopback_mode == LOOPBACK_PHYXS_WS);
 }
 
-static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx,
-                                        int lpower, int mmd)
+static void efx_mdio_set_mmd_lpower(struct efx_nic *efx,
+                                   int lpower, int mmd)
 {
-       const char *mmdname = STRING_TABLE_LOOKUP(mmd, mmd_block);
-       int phy = efx->mii.phy_id;
-       int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
-       int ctrl1, ctrl2;
+       const char *mmdname __attribute__((unused)) =
+               STRING_TABLE_LOOKUP(mmd, mmd_block);
+       int stat = efx_mdio_read(efx, mmd, MDIO_STAT1);
 
        EFX_TRACE(efx, "Setting low power mode for MMD %s to %d\n",
                  mmdname, lpower);
 
-       if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) {
-               ctrl1 = ctrl2 = mdio_clause45_read(efx, phy,
-                                                  mmd, MDIO_MMDREG_CTRL1);
-               if (lpower)
-                       ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
-               else
-                       ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
-               if (ctrl1 != ctrl2)
-                       mdio_clause45_write(efx, phy, mmd,
-                                           MDIO_MMDREG_CTRL1, ctrl2);
-       } else {
-               /* If we ever want a completely generic PHY driver
-                * that which just does clause 45, we may consider not
-                * complaining, but for now expect the driver to know
-                * which MMDs to apply this to. */
-               EFX_ERR(efx, "Attempt change power setting of MMD %s"
-                       " which doesn't support it.\n", mmdname);
+       if (stat & MDIO_STAT1_LPOWERABLE) {
+               efx_mdio_set_flag(efx, mmd, MDIO_CTRL1,
+                                 MDIO_CTRL1_LPOWER, lpower);
        }
 }
 
-void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
-                                  int low_power, unsigned int mmd_mask)
+void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
+                             int low_power, unsigned int mmd_mask)
 {
        int mmd = 0;
+       mmd_mask &= ~MDIO_DEVS_AN;
        while (mmd_mask) {
                if (mmd_mask & 1)
-                       mdio_clause45_set_mmd_lpower(efx, low_power, mmd);
+                       efx_mdio_set_mmd_lpower(efx, low_power, mmd);
                mmd_mask = (mmd_mask >> 1);
                mmd++;
        }
 }
 
 /**
- * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
+ * efx_mdio_set_settings - Set (some of) the PHY settings over MDIO.
  * @efx:               Efx NIC
- * @ecmd:              Buffer for settings
- *
- * On return the 'port', 'speed', 'supported' and 'advertising' fields of
- * ecmd have been filled out based on the PMA type.
+ * @ecmd:              New settings
  */
-void mdio_clause45_get_settings(struct efx_nic *efx,
-                               struct ethtool_cmd *ecmd)
+int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
-       int pma_type;
-
-       /* If no PMA is present we are presumably talking something XAUI-ish
-        * like CX4. Which we report as FIBRE (see below) */
-       if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
-               ecmd->speed = SPEED_10000;
-               ecmd->port = PORT_FIBRE;
-               ecmd->supported = SUPPORTED_FIBRE;
-               ecmd->advertising = ADVERTISED_FIBRE;
-               return;
-       }
+       struct ethtool_cmd prev;
 
-       pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
-                                     MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
-       pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
-
-       switch (pma_type) {
-               /* We represent CX4 as fibre in the absence of anything
-                  better. */
-       case MDIO_PMAPMD_CTRL2_10G_CX4:
-               ecmd->speed = SPEED_10000;
-               ecmd->port = PORT_FIBRE;
-               ecmd->supported = SUPPORTED_FIBRE;
-               ecmd->advertising = ADVERTISED_FIBRE;
-               break;
-               /* 10G Base-T */
-       case MDIO_PMAPMD_CTRL2_10G_BT:
-               ecmd->speed = SPEED_10000;
-               ecmd->port = PORT_TP;
-               ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
-               ecmd->advertising = (ADVERTISED_FIBRE
-                                    | ADVERTISED_10000baseT_Full);
-               break;
-       case MDIO_PMAPMD_CTRL2_1G_BT:
-               ecmd->speed = SPEED_1000;
-               ecmd->port = PORT_TP;
-               ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
-               ecmd->advertising = (ADVERTISED_FIBRE
-                                    | ADVERTISED_1000baseT_Full);
-               break;
-       case MDIO_PMAPMD_CTRL2_100_BT:
-               ecmd->speed = SPEED_100;
-               ecmd->port = PORT_TP;
-               ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
-               ecmd->advertising = (ADVERTISED_FIBRE
-                                    | ADVERTISED_100baseT_Full);
-               break;
-       case MDIO_PMAPMD_CTRL2_10_BT:
-               ecmd->speed = SPEED_10;
-               ecmd->port = PORT_TP;
-               ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
-               ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
-               break;
-       /* All the other defined modes are flavours of
-        * 10G optical */
-       default:
-               ecmd->speed = SPEED_10000;
-               ecmd->port = PORT_FIBRE;
-               ecmd->supported = SUPPORTED_FIBRE;
-               ecmd->advertising = ADVERTISED_FIBRE;
-               break;
-       }
+       efx->phy_op->get_settings(efx, &prev);
+
+       if (ecmd->advertising == prev.advertising &&
+           ecmd->speed == prev.speed &&
+           ecmd->duplex == prev.duplex &&
+           ecmd->port == prev.port &&
+           ecmd->autoneg == prev.autoneg)
+               return 0;
+
+       /* We can only change these settings for -T PHYs */
+       if (prev.port != PORT_TP || ecmd->port != PORT_TP)
+               return -EINVAL;
+
+       /* Check that PHY supports these settings */
+       if (!ecmd->autoneg ||
+           (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported)
+               return -EINVAL;
+
+       efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg);
+       efx_mdio_an_reconfigure(efx);
+       return 0;
 }
 
 /**
- * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
+ * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation
  * @efx:               Efx NIC
- * @ecmd:              New settings
- *
- * Currently this just enforces that we are _not_ changing the
- * 'port', 'speed', 'supported' or 'advertising' settings as these
- * cannot be changed on any currently supported PHY.
  */
-int mdio_clause45_set_settings(struct efx_nic *efx,
-                              struct ethtool_cmd *ecmd)
+void efx_mdio_an_reconfigure(struct efx_nic *efx)
 {
-       struct ethtool_cmd tmpcmd;
-       mdio_clause45_get_settings(efx, &tmpcmd);
-       /* None of the current PHYs support more than one mode
-        * of operation (and only 10GBT ever will), so keep things
-        * simple for now */
-       if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
-           (ecmd->supported == tmpcmd.supported) &&
-           (ecmd->advertising == tmpcmd.advertising))
-               return 0;
-       return -EOPNOTSUPP;
+       bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full
+                   || EFX_WORKAROUND_13204(efx));
+       int reg;
+
+       WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
+
+       /* Set up the base page */
+       reg = ADVERTISE_CSMA;
+       if (efx->link_advertising & ADVERTISED_10baseT_Half)
+               reg |= ADVERTISE_10HALF;
+       if (efx->link_advertising & ADVERTISED_10baseT_Full)
+               reg |= ADVERTISE_10FULL;
+       if (efx->link_advertising & ADVERTISED_100baseT_Half)
+               reg |= ADVERTISE_100HALF;
+       if (efx->link_advertising & ADVERTISED_100baseT_Full)
+               reg |= ADVERTISE_100FULL;
+       if (xnp)
+               reg |= ADVERTISE_RESV;
+       else if (efx->link_advertising & (ADVERTISED_1000baseT_Half |
+                                         ADVERTISED_1000baseT_Full))
+               reg |= ADVERTISE_NPAGE;
+       if (efx->link_advertising & ADVERTISED_Pause)
+               reg |= ADVERTISE_PAUSE_CAP;
+       if (efx->link_advertising & ADVERTISED_Asym_Pause)
+               reg |= ADVERTISE_PAUSE_ASYM;
+       efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
+
+       /* Set up the (extended) next page if necessary */
+       if (efx->phy_op->set_npage_adv)
+               efx->phy_op->set_npage_adv(efx, efx->link_advertising);
+
+       /* Enable and restart AN */
+       reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1);
+       reg |= MDIO_AN_CTRL1_ENABLE;
+       if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx)))
+               reg |= MDIO_AN_CTRL1_RESTART;
+       if (xnp)
+               reg |= MDIO_AN_CTRL1_XNP;
+       else
+               reg &= ~MDIO_AN_CTRL1_XNP;
+       efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
+}
+
+enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
+{
+       BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX));
+
+       if (!(efx->wanted_fc & EFX_FC_AUTO))
+               return efx->wanted_fc;
+
+       WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN));
+
+       return mii_resolve_flowctrl_fdx(
+               mii_advertise_flowctrl(efx->wanted_fc),
+               efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_LPA));
+}
+
+int efx_mdio_test_alive(struct efx_nic *efx)
+{
+       int rc;
+       int devad = __ffs(efx->mdio.mmds);
+       u16 physid1, physid2;
+
+       mutex_lock(&efx->mac_lock);
+
+       physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1);
+       physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2);
+
+       if ((physid1 == 0x0000) || (physid1 == 0xffff) ||
+           (physid2 == 0x0000) || (physid2 == 0xffff)) {
+               EFX_ERR(efx, "no MDIO PHY present with ID %d\n",
+                       efx->mdio.prtad);
+               rc = -EINVAL;
+       } else {
+               rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0);
+       }
+
+       mutex_unlock(&efx->mac_lock);
+       return rc;
 }
index 61bff7b1b3ffb94fe9f4c620d8cf58c2d9162152..64df16883ff2446f736574cd31cefd6e6a05baa2 100644 (file)
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * 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_MDIO_10G_H
 #define EFX_MDIO_10G_H
 
+#include "kernel_compat.h"
+
 /*
- * Definitions needed for doing 10G MDIO as specified in clause 45
- * MDIO, which do not appear in Linux yet. Also some helper functions.
+ * Helper functions for doing 10G MDIO as specified in IEEE 802.3 clause 45.
  */
 
 #include "efx.h"
-#include "boards.h"
-
-/* Numbering of the MDIO Manageable Devices (MMDs) */
-/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
-#define MDIO_MMD_PMAPMD        (1)
-/* WAN Interface Sublayer */
-#define MDIO_MMD_WIS   (2)
-/* Physical Coding Sublayer */
-#define MDIO_MMD_PCS   (3)
-/* PHY Extender Sublayer */
-#define MDIO_MMD_PHYXS (4)
-/* Extender Sublayer */
-#define MDIO_MMD_DTEXS (5)
-/* Transmission convergence */
-#define MDIO_MMD_TC    (6)
-/* Auto negotiation */
-#define MDIO_MMD_AN    (7)
-
-/* Generic register locations */
-#define MDIO_MMDREG_CTRL1      (0)
-#define MDIO_MMDREG_STAT1      (1)
-#define MDIO_MMDREG_IDHI       (2)
-#define MDIO_MMDREG_IDLOW      (3)
-#define MDIO_MMDREG_SPEED      (4)
-#define MDIO_MMDREG_DEVS0      (5)
-#define MDIO_MMDREG_DEVS1      (6)
-#define MDIO_MMDREG_CTRL2      (7)
-#define MDIO_MMDREG_STAT2      (8)
-#define MDIO_MMDREG_TXDIS      (9)
-
-/* Bits in MMDREG_CTRL1 */
-/* Reset */
-#define MDIO_MMDREG_CTRL1_RESET_LBN    (15)
-#define MDIO_MMDREG_CTRL1_RESET_WIDTH  (1)
-/* Loopback */
-/* Note that while WIS, PCS, PHYXS and DTEXS have the loopback bit here,
- * the PMA/PMD does not. */
-#define MDIO_MMDREG_CTRL1_LBACK_LBN    (14)
-#define MDIO_MMDREG_CTRL1_LBACK_WIDTH  (1)
-/* Low power */
-#define MDIO_MMDREG_CTRL1_LPOWER_LBN   (11)
-#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1)
-
-/* Bits in MMDREG_STAT1 */
-#define MDIO_MMDREG_STAT1_FAULT_LBN    (7)
-#define MDIO_MMDREG_STAT1_FAULT_WIDTH  (1)
-/* Link state */
-#define MDIO_MMDREG_STAT1_LINK_LBN     (2)
-#define MDIO_MMDREG_STAT1_LINK_WIDTH   (1)
-/* Low power ability */
-#define MDIO_MMDREG_STAT1_LPABLE_LBN   (1)
-#define MDIO_MMDREG_STAT1_LPABLE_WIDTH (1)
-
-/* Bits in ID reg */
-#define MDIO_ID_REV(_id32)     (_id32 & 0xf)
-#define MDIO_ID_MODEL(_id32)   ((_id32 >> 4) & 0x3f)
-#define MDIO_ID_OUI(_id32)     (_id32 >> 10)
-
-/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
- * so the 'bit present' bit number of an MMD is the number of
- * that MMD */
-#define DEV_PRESENT_BIT(_b) (1 << _b)
-
-#define MDIO_MMDREG_DEVS0_DTEXS         DEV_PRESENT_BIT(MDIO_MMD_DTEXS)
-#define MDIO_MMDREG_DEVS0_PHYXS         DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
-#define MDIO_MMDREG_DEVS0_PCS   DEV_PRESENT_BIT(MDIO_MMD_PCS)
-#define MDIO_MMDREG_DEVS0_WIS   DEV_PRESENT_BIT(MDIO_MMD_WIS)
-#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
-#define MDIO_MMDREG_DEVS0_AN     DEV_PRESENT_BIT(MDIO_MMD_AN)
-
-
-/* Bits in MMDREG_STAT2 */
-#define MDIO_MMDREG_STAT2_PRESENT_VAL  (2)
-#define MDIO_MMDREG_STAT2_PRESENT_LBN  (14)
-#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
-
-/* Bits in MMDREG_TXDIS */
-#define MDIO_MMDREG_TXDIS_GLOBAL_LBN    (0)
-#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH  (1)
-
-/* MMD-specific bits, ordered by MMD, then register */
-#define MDIO_PMAPMD_CTRL1_LBACK_LBN    (0)
-#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH  (1)
-
-/* PMA type (4 bits) */
-#define MDIO_PMAPMD_CTRL2_10G_CX4      (0x0)
-#define MDIO_PMAPMD_CTRL2_10G_EW       (0x1)
-#define MDIO_PMAPMD_CTRL2_10G_LW       (0x2)
-#define MDIO_PMAPMD_CTRL2_10G_SW       (0x3)
-#define MDIO_PMAPMD_CTRL2_10G_LX4      (0x4)
-#define MDIO_PMAPMD_CTRL2_10G_ER       (0x5)
-#define MDIO_PMAPMD_CTRL2_10G_LR       (0x6)
-#define MDIO_PMAPMD_CTRL2_10G_SR       (0x7)
-/* Reserved */
-#define MDIO_PMAPMD_CTRL2_10G_BT       (0x9)
-/* Reserved */
-/* Reserved */
-#define MDIO_PMAPMD_CTRL2_1G_BT                (0xc)
-/* Reserved */
-#define MDIO_PMAPMD_CTRL2_100_BT       (0xe)
-#define MDIO_PMAPMD_CTRL2_10_BT                (0xf)
-#define MDIO_PMAPMD_CTRL2_TYPE_MASK    (0xf)
-
-/* PCS 10GBT registers */
-#define MDIO_PCS_10GBT_STATUS          (32)
-#define MDIO_PCS_10GBT_STATUS2         (33)
-#define MDIO_PCS_10GBT_STATUS2_BER_LBN (8)
-#define MDIO_PCS_10GBT_STATUS2_BER_WIDTH       (6)
-#define MDIO_PCS_10GBT_STATUS2_ERR_LBN (0)
-#define MDIO_PCS_10GBT_STATUS2_ERR_WIDTH       (8)
-
-/* PHY XGXS lane state */
-#define MDIO_PHYXS_LANE_STATE          (0x18)
-#define MDIO_PHYXS_LANE_ALIGNED_LBN    (12)
-#define MDIO_PHYXS_LANE_SYNC0_LBN      (0)
-#define MDIO_PHYXS_LANE_SYNC1_LBN      (1)
-#define MDIO_PHYXS_LANE_SYNC2_LBN      (2)
-#define MDIO_PHYXS_LANE_SYNC3_LBN      (3)
-
-/* AN registers */
-#define MDIO_AN_STATUS                 (1)
-#define MDIO_AN_STATUS_XNP_LBN         (7)
-#define MDIO_AN_STATUS_PAGE_LBN                (6)
-#define MDIO_AN_STATUS_AN_DONE_LBN     (5)
-#define MDIO_AN_STATUS_LP_AN_CAP_LBN   (0)
-
-#define MDIO_AN_10GBT_STATUS           (33)
-#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
-#define MDIO_AN_10GBT_STATUS_MS_LBN     (14) /* MASTER/SLAVE config */
-#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
-#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
-#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
-#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
-#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9)  /* LP Training Reset Request */
 
+static inline unsigned efx_mdio_id_rev(u32 id) { return id & 0xf; }
+static inline unsigned efx_mdio_id_model(u32 id) { return (id >> 4) & 0x3f; }
+extern unsigned efx_mdio_id_oui(u32 id);
 
-/* Packing of the prt and dev arguments of clause 45 style MDIO into a
- * single int so they can be passed into the mdio_read/write functions
- * that currently exist. Note that as Falcon is the only current user,
- * the packed form is chosen to match what Falcon needs to write into
- * a register. This is checked at compile-time so do not change it. If
- * your target chip needs things layed out differently you will need
- * to unpack the arguments in your chip-specific mdio functions.
- */
- /* These are defined by the standard. */
-#define MDIO45_PRT_ID_WIDTH  (5)
-#define MDIO45_DEV_ID_WIDTH  (5)
-
-/* The prt ID is just packed in immediately to the left of the dev ID */
-#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
-
-#define MDIO45_PRT_ID_MASK   ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
-/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
-#define MDIO45_XPRT_ID_WIDTH   (MDIO45_PRT_DEV_WIDTH + 1)
-#define MDIO45_XPRT_ID_MASK   ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
-#define MDIO45_XPRT_ID_IS10G   (1 << (MDIO45_XPRT_ID_WIDTH - 1))
-
-
-#define MDIO45_PRT_ID_COMP_LBN   MDIO45_DEV_ID_WIDTH
-#define MDIO45_PRT_ID_COMP_WIDTH  MDIO45_PRT_ID_WIDTH
-#define MDIO45_DEV_ID_COMP_LBN    0
-#define MDIO45_DEV_ID_COMP_WIDTH  MDIO45_DEV_ID_WIDTH
-
-/* Compose port and device into a phy_id */
-static inline int mdio_clause45_pack(u8 prt, u8 dev)
+static inline int efx_mdio_read(struct efx_nic *efx, int devad, int addr)
 {
-       efx_dword_t phy_id;
-       EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
-                            MDIO45_DEV_ID_COMP, dev);
-       return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
+       return efx->mdio.mdio_read(efx->net_dev, efx->mdio.prtad, devad, addr);
 }
 
-static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
+static inline void
+efx_mdio_write(struct efx_nic *efx, int devad, int addr, int value)
 {
-       efx_dword_t phy_id;
-       EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
-       *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
-       *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
+       efx->mdio.mdio_write(efx->net_dev, efx->mdio.prtad, devad, addr, value);
 }
 
-static inline int mdio_clause45_read(struct efx_nic *efx,
-                                    u8 prt, u8 dev, u16 addr)
+static inline u32 efx_mdio_read_id(struct efx_nic *efx, int mmd)
 {
-       return efx->mii.mdio_read(efx->net_dev,
-                                 mdio_clause45_pack(prt, dev), addr);
-}
-
-static inline void mdio_clause45_write(struct efx_nic *efx,
-                                      u8 prt, u8 dev, u16 addr, int value)
-{
-       efx->mii.mdio_write(efx->net_dev,
-                           mdio_clause45_pack(prt, dev), addr, value);
-}
-
-
-static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
-{
-       int phy_id = efx->mii.phy_id;
-       u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
-       u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
+       u16 id_low = efx_mdio_read(efx, mmd, MDIO_DEVID2);
+       u16 id_hi = efx_mdio_read(efx, mmd, MDIO_DEVID1);
        return (id_hi << 16) | (id_low);
 }
 
-static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
+static inline bool efx_mdio_phyxgxs_lane_sync(struct efx_nic *efx)
 {
-       int i, sync, lane_status;
+       int i, lane_status;
+       bool sync;
 
        for (i = 0; i < 2; ++i)
-               lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
-                                                MDIO_MMD_PHYXS,
-                                                MDIO_PHYXS_LANE_STATE);
+               lane_status = efx_mdio_read(efx, MDIO_MMD_PHYXS,
+                                           MDIO_PHYXS_LNSTAT);
 
-       sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
+       sync = !!(lane_status & MDIO_PHYXS_LNSTAT_ALIGN);
        if (!sync)
-               EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
+               EFX_LOG(efx, "XGXS lane status: %x\n", lane_status);
        return sync;
 }
 
-extern const char *mdio_clause45_mmd_name(int mmd);
+extern const char *efx_mdio_mmd_name(int mmd);
 
 /*
  * Reset a specific MMD and wait for reset to clear.
@@ -258,38 +63,50 @@ extern const char *mdio_clause45_mmd_name(int mmd);
  *
  * This function will sleep
  */
-extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
-                                  int spins, int spintime);
+extern int efx_mdio_reset_mmd(struct efx_nic *efx, int mmd,
+                             int spins, int spintime);
 
-/* As mdio_clause45_check_mmd but for multiple MMDs */
-int mdio_clause45_check_mmds(struct efx_nic *efx,
-                            unsigned int mmd_mask, unsigned int fatal_mask);
+/* As efx_mdio_check_mmd but for multiple MMDs */
+int efx_mdio_check_mmds(struct efx_nic *efx,
+                       unsigned int mmd_mask, unsigned int fatal_mask);
 
 /* Check the link status of specified mmds in bit mask */
-extern int mdio_clause45_links_ok(struct efx_nic *efx,
-                                 unsigned int mmd_mask);
+extern bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask);
 
 /* Generic transmit disable support though PMAPMD */
-extern void mdio_clause45_transmit_disable(struct efx_nic *efx,
-                                          int disable);
+extern void efx_mdio_transmit_disable(struct efx_nic *efx);
 
 /* Generic part of reconfigure: set/clear loopback bits */
-extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
+extern void efx_mdio_phy_reconfigure(struct efx_nic *efx);
 
 /* Set the power state of the specified MMDs */
-extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
-                                         int low_power, unsigned int mmd_mask);
-
-/* Read (some of) the PHY settings over MDIO */
-extern void mdio_clause45_get_settings(struct efx_nic *efx,
-                                      struct ethtool_cmd *ecmd);
+extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
+                                    int low_power, unsigned int mmd_mask);
 
 /* Set (some of) the PHY settings over MDIO */
-extern int mdio_clause45_set_settings(struct efx_nic *efx,
-                                     struct ethtool_cmd *ecmd);
+extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
+
+/* Push advertising flags and restart autonegotiation */
+extern void efx_mdio_an_reconfigure(struct efx_nic *efx);
+
+/* Get pause parameters from AN if available (otherwise return
+ * requested pause parameters)
+ */
+enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx);
 
 /* Wait for specified MMDs to exit reset within a timeout */
-extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
-                                        unsigned int mmd_mask);
+extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx,
+                                   unsigned int mmd_mask);
+
+/* Set or clear flag, debouncing */
+static inline void
+efx_mdio_set_flag(struct efx_nic *efx, int devad, int addr,
+                 int mask, bool state)
+{
+       mdio_set_flag(&efx->mdio, efx->mdio.prtad, devad, addr, mask, state);
+}
+
+/* Liveness self-test for MDIO PHYs */
+extern int efx_mdio_test_alive(struct efx_nic *efx);
 
 #endif /* EFX_MDIO_10G_H */
diff --git a/drivers/net/sfc/mentormac.c b/drivers/net/sfc/mentormac.c
deleted file mode 100644 (file)
index cc76dff..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-/****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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/delay.h>
-#include "net_driver.h"
-#include "gmii.h"
-#include "mac.h"
-
-/*
- * Mentor MAC control
- */
-
-/**************************************************************************
- *
- * Mentor MAC registers
- *
- **************************************************************************
- *
- * Register addresses are Mentor MAC register numbers.  Falcon maps these
- * registers in at 16-byte intervals.  The mac_writel() and mac_readl()
- * methods take care of abstracting away this difference.
- */
-
-/* GMAC configuration register 1 */
-#define GM_CFG1_REG_MAC 0x00
-#define GM_SW_RST_LBN 31
-#define GM_SW_RST_WIDTH 1
-#define GM_SIM_RST_LBN 30
-#define GM_SIM_RST_WIDTH 1
-#define GM_RST_RX_MAC_CTL_LBN 19
-#define GM_RST_RX_MAC_CTL_WIDTH 1
-#define GM_RST_TX_MAC_CTL_LBN 18
-#define GM_RST_TX_MAC_CTL_WIDTH 1
-#define GM_RST_RX_FUNC_LBN 17
-#define GM_RST_RX_FUNC_WIDTH 1
-#define GM_RST_TX_FUNC_LBN 16
-#define GM_RST_TX_FUNC_WIDTH 1
-#define GM_LOOP_LBN 8
-#define GM_LOOP_WIDTH 1
-#define GM_RX_FC_EN_LBN 5
-#define GM_RX_FC_EN_WIDTH 1
-#define GM_TX_FC_EN_LBN 4
-#define GM_TX_FC_EN_WIDTH 1
-#define GM_SYNC_RXEN_LBN 3
-#define GM_SYNC_RXEN_WIDTH 1
-#define GM_RX_EN_LBN 2
-#define GM_RX_EN_WIDTH 1
-#define GM_SYNC_TXEN_LBN 1
-#define GM_SYNC_TXEN_WIDTH 1
-#define GM_TX_EN_LBN 0
-#define GM_TX_EN_WIDTH 1
-
-/* GMAC configuration register 2 */
-#define GM_CFG2_REG_MAC 0x01
-#define GM_PAMBL_LEN_LBN 12
-#define GM_PAMBL_LEN_WIDTH 4
-#define GM_IF_MODE_LBN 8
-#define GM_IF_MODE_WIDTH 2
-#define GM_HUGE_FRM_EN_LBN 5
-#define GM_HUGE_FRM_EN_WIDTH 1
-#define GM_LEN_CHK_LBN 4
-#define GM_LEN_CHK_WIDTH 1
-#define GM_PAD_CRC_EN_LBN 2
-#define GM_PAD_CRC_EN_WIDTH 1
-#define GM_CRC_EN_LBN 1
-#define GM_CRC_EN_WIDTH 1
-#define GM_FD_LBN 0
-#define GM_FD_WIDTH 1
-
-/* GMAC maximum frame length register */
-#define GM_MAX_FLEN_REG_MAC 0x04
-#define GM_MAX_FLEN_LBN 0
-#define GM_MAX_FLEN_WIDTH 16
-
-/* GMAC MII management configuration register */
-#define GM_MII_MGMT_CFG_REG_MAC 0x08
-#define GM_RST_MII_MGMT_LBN 31
-#define GM_RST_MII_MGMT_WIDTH 1
-#define GM_MGMT_SCAN_AUTO_INC_LBN 5
-#define GM_MGMT_SCAN_AUTO_INC_WIDTH 1
-#define GM_MGMT_PREM_SUPR_LBN 4
-#define GM_MGMT_PREM_SUPR_WIDTH 1
-#define GM_MGMT_CLK_SEL_LBN 0
-#define GM_MGMT_CLK_SEL_WIDTH 3
-
-/* GMAC MII management command register */
-#define GM_MII_MGMT_CMD_REG_MAC 0x09
-#define GM_MGMT_SCAN_CYC_LBN 1
-#define GM_MGMT_SCAN_CYC_WIDTH 1
-#define GM_MGMT_RD_CYC_LBN 0
-#define GM_MGMT_RD_CYC_WIDTH 1
-
-/* GMAC MII management address register */
-#define GM_MII_MGMT_ADR_REG_MAC 0x0a
-#define GM_MGMT_PHY_ADDR_LBN 8
-#define GM_MGMT_PHY_ADDR_WIDTH 5
-#define GM_MGMT_REG_ADDR_LBN 0
-#define GM_MGMT_REG_ADDR_WIDTH 5
-
-/* GMAC MII management control register */
-#define GM_MII_MGMT_CTL_REG_MAC 0x0b
-#define GM_MGMT_CTL_LBN 0
-#define GM_MGMT_CTL_WIDTH 16
-
-/* GMAC MII management status register */
-#define GM_MII_MGMT_STAT_REG_MAC 0x0c
-#define GM_MGMT_STAT_LBN 0
-#define GM_MGMT_STAT_WIDTH 16
-
-/* GMAC MII management indicators register */
-#define GM_MII_MGMT_IND_REG_MAC 0x0d
-#define GM_MGMT_NOT_VLD_LBN 2
-#define GM_MGMT_NOT_VLD_WIDTH 1
-#define GM_MGMT_SCANNING_LBN 1
-#define GM_MGMT_SCANNING_WIDTH 1
-#define GM_MGMT_BUSY_LBN 0
-#define GM_MGMT_BUSY_WIDTH 1
-
-/* GMAC station address register 1 */
-#define GM_ADR1_REG_MAC 0x10
-#define GM_HWADDR_5_LBN 24
-#define GM_HWADDR_5_WIDTH 8
-#define GM_HWADDR_4_LBN 16
-#define GM_HWADDR_4_WIDTH 8
-#define GM_HWADDR_3_LBN 8
-#define GM_HWADDR_3_WIDTH 8
-#define GM_HWADDR_2_LBN 0
-#define GM_HWADDR_2_WIDTH 8
-
-/* GMAC station address register 2 */
-#define GM_ADR2_REG_MAC 0x11
-#define GM_HWADDR_1_LBN 24
-#define GM_HWADDR_1_WIDTH 8
-#define GM_HWADDR_0_LBN 16
-#define GM_HWADDR_0_WIDTH 8
-
-/* GMAC FIFO configuration register 0 */
-#define GMF_CFG0_REG_MAC 0x12
-#define GMF_FTFENRPLY_LBN 20
-#define GMF_FTFENRPLY_WIDTH 1
-#define GMF_STFENRPLY_LBN 19
-#define GMF_STFENRPLY_WIDTH 1
-#define GMF_FRFENRPLY_LBN 18
-#define GMF_FRFENRPLY_WIDTH 1
-#define GMF_SRFENRPLY_LBN 17
-#define GMF_SRFENRPLY_WIDTH 1
-#define GMF_WTMENRPLY_LBN 16
-#define GMF_WTMENRPLY_WIDTH 1
-#define GMF_FTFENREQ_LBN 12
-#define GMF_FTFENREQ_WIDTH 1
-#define GMF_STFENREQ_LBN 11
-#define GMF_STFENREQ_WIDTH 1
-#define GMF_FRFENREQ_LBN 10
-#define GMF_FRFENREQ_WIDTH 1
-#define GMF_SRFENREQ_LBN 9
-#define GMF_SRFENREQ_WIDTH 1
-#define GMF_WTMENREQ_LBN 8
-#define GMF_WTMENREQ_WIDTH 1
-#define GMF_HSTRSTFT_LBN 4
-#define GMF_HSTRSTFT_WIDTH 1
-#define GMF_HSTRSTST_LBN 3
-#define GMF_HSTRSTST_WIDTH 1
-#define GMF_HSTRSTFR_LBN 2
-#define GMF_HSTRSTFR_WIDTH 1
-#define GMF_HSTRSTSR_LBN 1
-#define GMF_HSTRSTSR_WIDTH 1
-#define GMF_HSTRSTWT_LBN 0
-#define GMF_HSTRSTWT_WIDTH 1
-
-/* GMAC FIFO configuration register 1 */
-#define GMF_CFG1_REG_MAC 0x13
-#define GMF_CFGFRTH_LBN 16
-#define GMF_CFGFRTH_WIDTH 5
-#define GMF_CFGXOFFRTX_LBN 0
-#define GMF_CFGXOFFRTX_WIDTH 16
-
-/* GMAC FIFO configuration register 2 */
-#define GMF_CFG2_REG_MAC 0x14
-#define GMF_CFGHWM_LBN 16
-#define GMF_CFGHWM_WIDTH 6
-#define GMF_CFGLWM_LBN 0
-#define GMF_CFGLWM_WIDTH 6
-
-/* GMAC FIFO configuration register 3 */
-#define GMF_CFG3_REG_MAC 0x15
-#define GMF_CFGHWMFT_LBN 16
-#define GMF_CFGHWMFT_WIDTH 6
-#define GMF_CFGFTTH_LBN 0
-#define GMF_CFGFTTH_WIDTH 6
-
-/* GMAC FIFO configuration register 4 */
-#define GMF_CFG4_REG_MAC 0x16
-#define GMF_HSTFLTRFRM_LBN 0
-#define GMF_HSTFLTRFRM_WIDTH 18
-#define GMF_HSTFLTRFRM_PAUSE_LBN 12
-#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
-
-/* GMAC FIFO configuration register 5 */
-#define GMF_CFG5_REG_MAC 0x17
-#define GMF_CFGHDPLX_LBN 22
-#define GMF_CFGHDPLX_WIDTH 1
-#define GMF_SRFULL_LBN 21
-#define GMF_SRFULL_WIDTH 1
-#define GMF_HSTSRFULLCLR_LBN 20
-#define GMF_HSTSRFULLCLR_WIDTH 1
-#define GMF_CFGBYTMODE_LBN 19
-#define GMF_CFGBYTMODE_WIDTH 1
-#define GMF_HSTDRPLT64_LBN 18
-#define GMF_HSTDRPLT64_WIDTH 1
-#define GMF_HSTFLTRFRMDC_LBN 0
-#define GMF_HSTFLTRFRMDC_WIDTH 18
-#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
-#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
-
-/* TX total octet count */
-#define GM_TX_OCT_CNT_REG_MAC 0x40
-#define GM_STAT_LBN 0
-#define GM_STAT_WIDTH 32
-
-/* TX good octet count */
-#define GM_TX_GOOD_OCT_CNT_REG_MAC 0x41
-
-/* TX single collision packet count */
-#define GM_TX_SGLCOL_PKT_CNT_REG_MAC 0x42
-
-/* TX multiple collision packet count */
-#define GM_TX_MULTCOL_PKT_CNT_REG_MAC 0x43
-
-/* TX excessive collision packet count */
-#define GM_TX_EXCOL_PKT_CNT_REG_MAC 0x44
-
-/* TX deferred packet count */
-#define GM_TX_DEF_PKT_CNT_REG_MAC 0x45
-
-/* TX late packet count */
-#define GM_TX_LATECOL_PKT_CNT_REG_MAC 0x46
-
-/* TX excessive deferral packet count */
-#define GM_TX_EXDEF_PKT_CNT_REG_MAC 0x47
-
-/* TX pause packet count */
-#define GM_TX_PAUSE_PKT_CNT_REG_MAC 0x48
-
-/* TX bad packet count */
-#define GM_TX_BAD_PKT_CNT_REG_MAC 0x49
-
-/* TX unicast packet count */
-#define GM_TX_UCAST_PKT_CNT_REG_MAC 0x4a
-
-/* TX multicast packet count */
-#define GM_TX_MCAST_PKT_CNT_REG_MAC 0x4b
-
-/* TX broadcast packet count */
-#define GM_TX_BCAST_PKT_CNT_REG_MAC 0x4c
-
-/* TX <64-byte packet count */
-#define GM_TX_LT64_PKT_CNT_REG_MAC 0x4d
-
-/* TX 64-byte packet count */
-#define GM_TX_64_PKT_CNT_REG_MAC 0x4e
-
-/* TX 65-byte to 127-byte packet count */
-#define GM_TX_65_TO_127_PKT_CNT_REG_MAC 0x4f
-
-/* TX 128-byte to 255-byte packet count */
-#define GM_TX_128_TO_255_PKT_CNT_REG_MAC 0x50
-
-/* TX 256-byte to 511-byte packet count */
-#define GM_TX_256_TO_511_PKT_CNT_REG_MAC 0x51
-
-/* TX 512-byte to 1023-byte packet count */
-#define GM_TX_512_TO_1023_PKT_CNT_REG_MAC 0x52
-
-/* TX 1024-byte to 15xx-byte packet count */
-#define GM_TX_1024_TO_15XX_PKT_CNT_REG_MAC 0x53
-
-/* TX 15xx-byte to jumbo packet count */
-#define GM_TX_15XX_TO_JUMBO_PKT_CNT_REG_MAC 0x54
-
-/* TX >jumbo packet count */
-#define GM_TX_GTJUMBO_PKT_CNT_REG_MAC 0x55
-
-/* RX good octet count */
-#define GM_RX_GOOD_OCT_CNT_REG_MAC 0x60
-
-/* RX bad octet count */
-#define GM_RX_BAD_OCT_CNT_REG_MAC 0x61
-
-/* RX missed packet count */
-#define GM_RX_MISS_PKT_CNT_REG_MAC 0x62
-
-/* RX false carrier count */
-#define GM_RX_FALSE_CRS_CNT_REG_MAC 0x63
-
-/* RX pause packet count */
-#define GM_RX_PAUSE_PKT_CNT_REG_MAC 0x64
-
-/* RX bad packet count */
-#define GM_RX_BAD_PKT_CNT_REG_MAC 0x65
-
-/* RX unicast packet count */
-#define GM_RX_UCAST_PKT_CNT_REG_MAC 0x66
-
-/* RX multicast packet count */
-#define GM_RX_MCAST_PKT_CNT_REG_MAC 0x67
-
-/* RX broadcast packet count */
-#define GM_RX_BCAST_PKT_CNT_REG_MAC 0x68
-
-/* RX <64-byte good packet count */
-#define GM_RX_GOOD_LT64_PKT_CNT_REG_MAC 0x69
-
-/* RX <64-byte bad packet count */
-#define GM_RX_BAD_LT64_PKT_CNT_REG_MAC 0x6a
-
-/* RX 64-byte packet count */
-#define GM_RX_64_PKT_CNT_REG_MAC 0x6b
-
-/* RX 65-byte to 127-byte packet count */
-#define GM_RX_65_TO_127_PKT_CNT_REG_MAC 0x6c
-
-/* RX 128-byte to 255-byte packet count*/
-#define GM_RX_128_TO_255_PKT_CNT_REG_MAC 0x6d
-
-/* RX 256-byte to 511-byte packet count */
-#define GM_RX_256_TO_511_PKT_CNT_REG_MAC 0x6e
-
-/* RX 512-byte to 1023-byte packet count */
-#define GM_RX_512_TO_1023_PKT_CNT_REG_MAC 0x6f
-
-/* RX 1024-byte to 15xx-byte packet count */
-#define GM_RX_1024_TO_15XX_PKT_CNT_REG_MAC 0x70
-
-/* RX 15xx-byte to jumbo packet count */
-#define GM_RX_15XX_TO_JUMBO_PKT_CNT_REG_MAC 0x71
-
-/* RX >jumbo packet count */
-#define GM_RX_GTJUMBO_PKT_CNT_REG_MAC 0x72
-
-/* RX 64-byte to 15xx-byte bad crc packet count */
-#define GM_RX_BAD_64_TO_15XX_PKT_CNT_REG_MAC 0x73
-
-/* RX 15xx-byte to jumbo bad crc packet count */
-#define GM_RX_BAD_15XX_TO_JUMBO_PKT_CNT_REG_MAC 0x74
-
-/* RX >jumbo bad crc packet count */
-#define GM_RX_BAD_GTJUMBO_PKT_CNT_REG_MAC 0x75
-
-/**************************************************************************
- *
- * GMII access to PHY
- *
- **************************************************************************
- */
-
-/* This does not reset the PHY, only the MAC.  However, TX and RX will
- * both be disabled on the MAC after this, so the state of the PHY is
- * somewhat irrelevant until the MAC is reinitialised.
- */
-void mentormac_reset(struct efx_nic *efx)
-{
-       efx_dword_t reg;
-
-       EFX_POPULATE_DWORD_1(reg, GM_SW_RST, 1);
-       efx->mac_op->mac_writel(efx, &reg, GM_CFG1_REG_MAC);
-       udelay(1000);
-
-       EFX_POPULATE_DWORD_1(reg, GM_SW_RST, 0);
-       efx->mac_op->mac_writel(efx, &reg, GM_CFG1_REG_MAC);
-       udelay(1000);
-
-       /* Configure GMII interface so PHY is accessible */
-       EFX_POPULATE_DWORD_1(reg, GM_MGMT_CLK_SEL, 0x4);
-       efx->mac_op->mac_writel(efx, &reg,
-                                    GM_MII_MGMT_CFG_REG_MAC);
-       udelay(10);
-}
-
-void mentormac_reconfigure(struct efx_nic *efx)
-{
-       int loopback, tx_fc, rx_fc, if_mode, full_duplex, bytemode, half_duplex;
-       unsigned int max_frame_len;
-       efx_dword_t reg;
-
-       /* Configuration register 1 */
-       tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
-       rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
-       loopback = (efx->loopback_mode == LOOPBACK_MAC) ? 1 : 0;
-       bytemode = (efx->link_options & GM_LPA_1000) ? 1 : 0;
-
-       if (efx->loopback_mode != LOOPBACK_NONE)
-               bytemode = 1;
-       if (!(efx->link_options & GM_LPA_DUPLEX))
-               /* Half-duplex operation requires TX flow control */
-               tx_fc = 1;
-       EFX_POPULATE_DWORD_5(reg,
-                            GM_LOOP, loopback,
-                            GM_TX_EN, 1,
-                            GM_TX_FC_EN, tx_fc,
-                            GM_RX_EN, 1,
-                            GM_RX_FC_EN, rx_fc);
-       efx->mac_op->mac_writel(efx, &reg, GM_CFG1_REG_MAC);
-       udelay(10);
-
-       /* Configuration register 2 */
-       if_mode = (bytemode) ? 2 : 1;
-       full_duplex = (efx->link_options & GM_LPA_DUPLEX) ? 1 : 0;
-       EFX_POPULATE_DWORD_4(reg,
-                            GM_IF_MODE, if_mode,
-                            GM_PAD_CRC_EN, 1,
-                            GM_FD, full_duplex,
-                            GM_PAMBL_LEN, 0x7/*datasheet recommended */);
-
-       efx->mac_op->mac_writel(efx, &reg, GM_CFG2_REG_MAC);
-       udelay(10);
-
-       /* Max frame len register */
-       max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
-       EFX_POPULATE_DWORD_1(reg, GM_MAX_FLEN, max_frame_len);
-       efx->mac_op->mac_writel(efx, &reg, GM_MAX_FLEN_REG_MAC);
-       udelay(10);
-
-       /* FIFO configuration register 0 */
-       EFX_POPULATE_DWORD_5(reg,
-                            GMF_FTFENREQ, 1,
-                            GMF_STFENREQ, 1,
-                            GMF_FRFENREQ, 1,
-                            GMF_SRFENREQ, 1,
-                            GMF_WTMENREQ, 1);
-       efx->mac_op->mac_writel(efx, &reg, GMF_CFG0_REG_MAC);
-       udelay(10);
-
-       /* FIFO configuration register 1 */
-       EFX_POPULATE_DWORD_2(reg,
-                            GMF_CFGFRTH, 0x12,
-                            GMF_CFGXOFFRTX, 0xffff);
-       efx->mac_op->mac_writel(efx, &reg, GMF_CFG1_REG_MAC);
-       udelay(10);
-
-       /* FIFO configuration register 2 */
-       EFX_POPULATE_DWORD_2(reg,
-                            GMF_CFGHWM, 0x3f,
-                            GMF_CFGLWM, 0xa);
-       efx->mac_op->mac_writel(efx, &reg, GMF_CFG2_REG_MAC);
-       udelay(10);
-
-       /* FIFO configuration register 3 */
-       EFX_POPULATE_DWORD_2(reg,
-                            GMF_CFGHWMFT, 0x1c,
-                            GMF_CFGFTTH, 0x08);
-       efx->mac_op->mac_writel(efx, &reg, GMF_CFG3_REG_MAC);
-       udelay(10);
-
-       /* FIFO configuration register 4 */
-       EFX_POPULATE_DWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1);
-       efx->mac_op->mac_writel(efx, &reg, GMF_CFG4_REG_MAC);
-       udelay(10);
-
-       /* FIFO configuration register 5 */
-       half_duplex = (efx->link_options & GM_LPA_DUPLEX) ? 0 : 1;
-       efx->mac_op->mac_readl(efx, &reg, GMF_CFG5_REG_MAC);
-       EFX_SET_DWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode);
-       EFX_SET_DWORD_FIELD(reg, GMF_CFGHDPLX, half_duplex);
-       EFX_SET_DWORD_FIELD(reg, GMF_HSTDRPLT64, half_duplex);
-       EFX_SET_DWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0);
-       efx->mac_op->mac_writel(efx, &reg, GMF_CFG5_REG_MAC);
-       udelay(10);
-
-       /* MAC address */
-       EFX_POPULATE_DWORD_4(reg,
-                            GM_HWADDR_5, efx->net_dev->dev_addr[5],
-                            GM_HWADDR_4, efx->net_dev->dev_addr[4],
-                            GM_HWADDR_3, efx->net_dev->dev_addr[3],
-                            GM_HWADDR_2, efx->net_dev->dev_addr[2]);
-       efx->mac_op->mac_writel(efx, &reg, GM_ADR1_REG_MAC);
-       udelay(10);
-       EFX_POPULATE_DWORD_2(reg,
-                            GM_HWADDR_1, efx->net_dev->dev_addr[1],
-                            GM_HWADDR_0, efx->net_dev->dev_addr[0]);
-       efx->mac_op->mac_writel(efx, &reg, GM_ADR2_REG_MAC);
-       udelay(10);
-}
index 10a1ae6ea86a8a2e7d77fe766510003bc7cd52ec..34102c92c1f416cbfb2cd50bd9db7d11518a6ae4 100644 (file)
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 
 #define EFX_DRIVER_NAME "sfc_mtd"
-#include "driverlink_api.h"
 #include "net_driver.h"
 #include "spi.h"
+#include "efx.h"
+#include "nic.h"
+#include "mcdi.h"
+#include "mcdi_pcol.h"
 
-/*
- * Flash and EEPROM (MTD) device driver
- *
- * This file provides a separate kernel module (sfc_mtd) which
- * exposes the flash and EEPROM devices present on Solarflare NICs as
- * MTD devices, enabling you to reflash the boot ROM code (or use the
- * remaining space on the flash as a jffs2 filesystem, should you want
- * to do so).
- */
-
-#define EFX_MTD_VERIFY_BUF_LEN 16
-#define EFX_MAX_PARTITIONS 2
-#define EFX_FLASH_BOOTROM_OFFSET 0x8000U
+#define EFX_SPI_VERIFY_BUF_LEN 16
+#define EFX_MCDI_CHUNK_LEN 128
 
-/* Write enable for EEPROM/flash configuration area
- *
- * Normally, writes to parts of non-volatile storage which contain
- * critical configuration are disabled to prevent accidents.  This
- * parameter allows enabling of such writes.
+/* Some partitions should only be written during manufacturing.  Not
+ * only should they not be rewritten later, but exposing all of them
+ * can easily fill up the MTD table (16 or 32 entries).
  */
 static unsigned int efx_allow_nvconfig_writes;
 
-struct efx_mtd {
+struct efx_mtd_partition {
        struct mtd_info mtd;
-       struct mtd_partition part[EFX_MAX_PARTITIONS];
-       char part_name[EFX_MAX_PARTITIONS][32];
-       char name[32];
-       struct efx_dl_device *efx_dev;
+       union {
+               struct {
+                       bool updating;
+                       u8 nvram_type;
+                       u16 fw_subtype;
+               } mcdi;
+               size_t offset;
+       };
+       const char *type_name;
+       char name[IFNAMSIZ + 20];
+};
+
+struct efx_mtd_ops {
+       int (*read)(struct mtd_info *mtd, loff_t start, size_t len,
+                   size_t *retlen, u8 *buffer);
+       int (*erase)(struct mtd_info *mtd, loff_t start, size_t len);
+       int (*write)(struct mtd_info *mtd, loff_t start, size_t len,
+                    size_t *retlen, const u8 *buffer);
+       int (*sync)(struct mtd_info *mtd);
+};
+
+struct efx_mtd {
+       struct list_head node;
        struct efx_nic *efx;
-       /* This must be held when using *spi; it guards against races
-        * with device reset and between sequences of dependent
-        * commands. */
-       struct semaphore access_lock;
-       struct efx_spi_device *spi;
+       const struct efx_spi_device *spi;
+       const char *name;
+       const struct efx_mtd_ops *ops;
+       size_t n_parts;
+       struct efx_mtd_partition part[0];
 };
 
-/* SPI utilities */
+#define efx_for_each_partition(part, efx_mtd)                  \
+       for ((part) = &(efx_mtd)->part[0];                      \
+            (part) != &(efx_mtd)->part[(efx_mtd)->n_parts];    \
+            (part)++)
 
-static int efx_spi_fast_wait(struct efx_mtd *efx_mtd)
-{
-       struct efx_spi_device *spi = efx_mtd->spi;
-       u8 status;
-       int i, rc;
+#define to_efx_mtd_partition(mtd)                              \
+       container_of(mtd, struct efx_mtd_partition, mtd)
 
-       /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
-       for (i = 0; i < 50; i++) {
-               udelay(20);
+static int falcon_mtd_probe(struct efx_nic *efx);
+static int siena_mtd_probe(struct efx_nic *efx);
 
-               rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
-                              &status, sizeof(status));
-               if (rc)
-                       return rc;
-               if (!(status & SPI_STATUS_NRDY))
-                       return 0;
-       }
-       EFX_ERR(efx_mtd->efx, "timed out waiting for %s last status=0x%02x\n",
-               efx_mtd->name, status);
-       return -ETIMEDOUT;
-}
+/* SPI utilities */
 
-static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, int uninterruptible)
+static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible)
 {
-       struct efx_spi_device *spi = efx_mtd->spi;
+       const struct efx_spi_device *spi = efx_mtd->spi;
+       struct efx_nic *efx = efx_mtd->efx;
        u8 status;
        int rc, i;
 
@@ -106,8 +88,8 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, int uninterruptible)
                __set_current_state(uninterruptible ?
                                    TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
                schedule_timeout(HZ / 10);
-               rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
-                              &status, sizeof(status));
+               rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
+                                   &status, sizeof(status));
                if (rc)
                        return rc;
                if (!(status & SPI_STATUS_NRDY))
@@ -115,484 +97,650 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, int uninterruptible)
                if (signal_pending(current))
                        return -EINTR;
        }
-       EFX_ERR(efx_mtd->efx, "timed out waiting for %s\n", efx_mtd->name);
+       EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name);
        return -ETIMEDOUT;
 }
 
 static int
-efx_spi_write_enable(struct efx_mtd *efx_mtd)
-{
-       struct efx_spi_device *spi = efx_mtd->spi;
-
-       return spi->write(spi, efx_mtd->efx, SPI_WREN, -1, NULL, 0);
-}
-
-static int efx_spi_unlock(struct efx_mtd *efx_mtd)
+efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi)
 {
-       struct efx_spi_device *spi = efx_mtd->spi;
        const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
-                                    SPI_STATUS_BP0);
+                               SPI_STATUS_BP0);
        u8 status;
        int rc;
 
-       rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1, &status,
-                      sizeof(status));
+       rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL,
+                           &status, sizeof(status));
        if (rc)
                return rc;
 
        if (!(status & unlock_mask))
                return 0; /* already unlocked */
 
-       rc = efx_spi_write_enable(efx_mtd);
+       rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
        if (rc)
                return rc;
-       rc = spi->write(spi, efx_mtd->efx, SPI_SST_EWSR, -1, NULL, 0);
+       rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0);
        if (rc)
                return rc;
 
        status &= ~unlock_mask;
-       rc = spi->write(spi, efx_mtd->efx, SPI_WRSR, -1, &status,
-                       sizeof(status));
+       rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status,
+                           NULL, sizeof(status));
        if (rc)
                return rc;
-       rc = efx_spi_fast_wait(efx_mtd);
+       rc = falcon_spi_wait_write(efx, spi);
        if (rc)
                return rc;
 
        return 0;
 }
 
-/* Dummy device used in case of a failed reset */
-
-static int efx_spi_dummy_read(const struct efx_spi_device *spi,
-                             struct efx_nic *efx, unsigned int command,
-                             int address, void *data, unsigned int len)
+static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len)
 {
-       return -EIO;
-}
-
-static int efx_spi_dummy_write(const struct efx_spi_device *spi,
-                              struct efx_nic *efx, unsigned int command,
-                              int address, const void *data, unsigned int len)
-{
-       return -EIO;
-}
-
-static struct efx_spi_device efx_spi_dummy_device = {
-       .block_size     = 1,
-       .erase_command  = 0xff,
-       .read           = efx_spi_dummy_read,
-       .write          = efx_spi_dummy_write,
-};
+       const struct efx_spi_device *spi = efx_mtd->spi;
+       struct efx_nic *efx = efx_mtd->efx;
+       unsigned pos, block_len;
+       u8 empty[EFX_SPI_VERIFY_BUF_LEN];
+       u8 buffer[EFX_SPI_VERIFY_BUF_LEN];
+       int rc;
 
-/* MTD interface */
+       if (len != spi->erase_size)
+               return -EINVAL;
 
-static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
-                       size_t *retlen, u8 *buffer)
-{
-       struct efx_mtd *efx_mtd = mtd->priv;
-       struct efx_spi_device *spi;
-       unsigned int command;
-       unsigned int block_len;
-       unsigned int pos = 0;
-       int rc;
+       if (spi->erase_command == 0)
+               return -EOPNOTSUPP;
 
-       rc = down_interruptible(&efx_mtd->access_lock);
+       rc = efx_spi_unlock(efx, spi);
+       if (rc)
+               return rc;
+       rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0);
+       if (rc)
+               return rc;
+       rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL,
+                           NULL, 0);
        if (rc)
-               goto out;
-       spi = efx_mtd->spi;
-
-       while (pos < len) {
-               block_len = min((unsigned int)len - pos,
-                               efx_spi_read_limit(spi, start + pos));
-               command = efx_spi_munge_command(spi, SPI_READ, start + pos);
-               rc = spi->read(spi, efx_mtd->efx, command, start + pos,
-                              buffer + pos, block_len);
+               return rc;
+       rc = efx_spi_slow_wait(efx_mtd, false);
+
+       /* Verify the entire region has been wiped */
+       memset(empty, 0xff, sizeof(empty));
+       for (pos = 0; pos < len; pos += block_len) {
+               block_len = min(len - pos, sizeof(buffer));
+               rc = falcon_spi_read(efx, spi, start + pos, block_len,
+                                    NULL, buffer);
                if (rc)
-                       break;
-               pos += block_len;
+                       return rc;
+               if (memcmp(empty, buffer, block_len))
+                       return -EIO;
 
                /* Avoid locking up the system */
                cond_resched();
-               if (signal_pending(current)) {
-                       rc = -EINTR;
-                       break;
-               }
+               if (signal_pending(current))
+                       return -EINTR;
        }
 
-       up(&efx_mtd->access_lock);
-out:
-       *retlen = pos;
        return rc;
 }
 
-/* Check that device contents match buffer.  If repeat is true, buffer
- * contains a pattern of length EFX_MTD_VERIFY_BUF_LEN which the
- * device contents should match repeatedly.
- */
-static int efx_mtd_verify(struct mtd_info *mtd, loff_t start,
-                         size_t len, const u8 *buffer, int repeat)
-{
-       u8 verify_buffer[EFX_MTD_VERIFY_BUF_LEN];
-       unsigned int block_len;
-       size_t read_len;
-       unsigned int pos = 0;
-       int rc = 0;
-
-       while (pos < len) {
-               block_len = min(len - pos, sizeof(verify_buffer));
-               rc = efx_mtd_read(mtd, start + pos, block_len, &read_len,
-                                 verify_buffer);
-               if (rc)
-                       return rc;
-               if (memcmp(repeat ? buffer : buffer + pos, verify_buffer,
-                          block_len))
-                       return -EIO;
-               pos += block_len;
-       }
-
-       return 0;
-}
+/* MTD interface */
 
 static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
 {
        struct efx_mtd *efx_mtd = mtd->priv;
-       struct efx_spi_device *spi;
-       u8 empty[EFX_MTD_VERIFY_BUF_LEN];
        int rc;
 
-       if (erase->len != mtd->erasesize) {
-               rc = -EINVAL;
-               goto out;
-       }
-
-       rc = down_interruptible(&efx_mtd->access_lock);
-       if (rc)
-               goto out;
-       spi = efx_mtd->spi;
-       if (spi->erase_command == 0) {
-               rc = -EOPNOTSUPP;
-               goto out_up;
-       }
-
-       rc = efx_spi_unlock(efx_mtd);
-       if (rc)
-               goto out_up;
-       rc = efx_spi_write_enable(efx_mtd);
-       if (rc)
-               goto out_up;
-       rc = spi->write(spi, efx_mtd->efx, spi->erase_command, erase->addr,
-                       NULL, 0);
-       if (rc)
-               goto out_up;
-       rc = efx_spi_slow_wait(efx_mtd, 0);
-
-out_up:
-       up(&efx_mtd->access_lock);
-       if (rc)
-               goto out;
-
-       memset(empty, 0xff, sizeof(empty));
-       rc = efx_mtd_verify(mtd, erase->addr, erase->len, empty, 1);
-
-out:
+       rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len);
        if (rc == 0) {
                erase->state = MTD_ERASE_DONE;
        } else {
                erase->state = MTD_ERASE_FAILED;
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_MTD_ERASE_FAIL_ADDR)
                erase->fail_addr = 0xffffffff;
+#endif
        }
        mtd_erase_callback(erase);
        return rc;
 }
 
-static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
-                        size_t len, size_t *retlen, const u8 *buffer)
+static void efx_mtd_sync(struct mtd_info *mtd)
 {
        struct efx_mtd *efx_mtd = mtd->priv;
-       struct efx_spi_device *spi;
-       unsigned int command;
-       unsigned int block_len;
-       unsigned int pos = 0;
+       struct efx_nic *efx = efx_mtd->efx;
        int rc;
 
-       rc = down_interruptible(&efx_mtd->access_lock);
+       rc = efx_mtd->ops->sync(mtd);
        if (rc)
-               goto out;
-       spi = efx_mtd->spi;
+               EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc);
+}
 
-       rc = efx_spi_unlock(efx_mtd);
-       if (rc)
-               goto out_up;
+static void efx_mtd_remove_partition(struct efx_mtd_partition *part)
+{
+       int rc;
 
-       while (pos < len) {
-               rc = efx_spi_write_enable(efx_mtd);
-               if (rc)
+       for (;;) {
+               rc = del_mtd_device(&part->mtd);
+               if (rc != -EBUSY)
                        break;
+               ssleep(1);
+       }
+       WARN_ON(rc);
+}
 
-               block_len = min((unsigned int)len - pos,
-                               efx_spi_write_limit(spi, start + pos));
-               command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
-               rc = spi->write(spi, efx_mtd->efx, command, start + pos,
-                               buffer + pos, block_len);
-               if (rc)
-                       break;
-               pos += block_len;
+static void efx_mtd_remove_device(struct efx_mtd *efx_mtd)
+{
+       struct efx_mtd_partition *part;
 
-               rc = efx_spi_fast_wait(efx_mtd);
-               if (rc)
-                       break;
+       efx_for_each_partition(part, efx_mtd)
+               efx_mtd_remove_partition(part);
+       list_del(&efx_mtd->node);
+       kfree(efx_mtd);
+}
 
-               /* Avoid locking up the system */
-               cond_resched();
-               if (signal_pending(current)) {
-                       rc = -EINTR;
-                       break;
-               }
+static void efx_mtd_rename_device(struct efx_mtd *efx_mtd)
+{
+       struct efx_mtd_partition *part;
+
+       efx_for_each_partition(part, efx_mtd)
+               if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0)
+                       snprintf(part->name, sizeof(part->name),
+                                "%s %s:%02x", efx_mtd->efx->name,
+                                part->type_name, part->mcdi.fw_subtype);
+               else
+                       snprintf(part->name, sizeof(part->name),
+                                "%s %s", efx_mtd->efx->name,
+                                part->type_name);
+}
+
+static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd)
+{
+       struct efx_mtd_partition *part;
+
+       efx_mtd->efx = efx;
+
+       efx_mtd_rename_device(efx_mtd);
+
+       efx_for_each_partition(part, efx_mtd) {
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_MTD_WRITESIZE)
+               part->mtd.writesize = 1;
+#endif
+               if (efx_allow_nvconfig_writes)
+                       part->mtd.flags |= MTD_WRITEABLE;
+
+               part->mtd.owner = THIS_MODULE;
+               part->mtd.priv = efx_mtd;
+               part->mtd.name = part->name;
+               part->mtd.erase = efx_mtd_erase;
+               part->mtd.read = efx_mtd->ops->read;
+               part->mtd.write = efx_mtd->ops->write;
+               part->mtd.sync = efx_mtd_sync;
+
+               if (add_mtd_device(&part->mtd))
+                       goto fail;
        }
 
-out_up:
-       up(&efx_mtd->access_lock);
-       if (rc == 0)
-               rc = efx_mtd_verify(mtd, start, len, buffer, 0);
-out:
-       *retlen = pos;
-       return rc;
+       list_add(&efx_mtd->node, &efx->mtd_list);
+       return 0;
+
+fail:
+       while (part != &efx_mtd->part[0]) {
+               --part;
+               efx_mtd_remove_partition(part);
+       }
+       /* add_mtd_device() returns 1 if the MTD table is full */
+       return -ENOMEM;
 }
 
-static void efx_mtd_sync(struct mtd_info *mtd)
+void efx_mtd_remove(struct efx_nic *efx)
 {
-       struct efx_mtd *efx_mtd = mtd->priv;
-       int rc;
+       struct efx_mtd *efx_mtd, *next;
 
-       down(&efx_mtd->access_lock);
-       rc = efx_spi_slow_wait(efx_mtd, 1);
-       if (rc)
-               EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
-                       efx_mtd->name, rc);
-       up(&efx_mtd->access_lock);
-}
+       WARN_ON(efx_dev_registered(efx));
 
-/* Driverlink interface */
+       list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node)
+               efx_mtd_remove_device(efx_mtd);
+}
 
-static void efx_mtd_reset_suspend(struct efx_dl_device *efx_dev)
+void efx_mtd_rename(struct efx_nic *efx)
 {
-       struct efx_mtd *efx_mtd = efx_dev->priv;
+       struct efx_mtd *efx_mtd;
 
-       if (!efx_mtd)
-               return;
+       ASSERT_RTNL();
 
-       /* Acquire lock to ensure that any in-progress operations have
-        * completed, and no new ones can start.
-        */
-       down(&efx_mtd->access_lock);
+       list_for_each_entry(efx_mtd, &efx->mtd_list, node)
+               efx_mtd_rename_device(efx_mtd);
 }
 
-static void efx_mtd_reset_resume(struct efx_dl_device *efx_dev, int ok)
+int efx_mtd_probe(struct efx_nic *efx)
 {
-       struct efx_mtd *efx_mtd = efx_dev->priv;
+       if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
+               return siena_mtd_probe(efx);
+       else
+               return falcon_mtd_probe(efx);
+}
 
-       if (!efx_mtd)
-               return;
-
-       /* If device reset failed already, or SPI device doesn't
-        * become ready, disable device.
-        */
-       if (!ok || efx_spi_slow_wait(efx_mtd, 1) != 0) {
-               efx_mtd->spi = &efx_spi_dummy_device;
-               EFX_ERR(efx_mtd->efx, "%s disabled after failed reset\n",
-                       efx_mtd->name);
-       }
+/* Implementation of MTD operations for Falcon */
 
-       up(&efx_mtd->access_lock);
+static int falcon_mtd_read(struct mtd_info *mtd, loff_t start,
+                          size_t len, size_t *retlen, u8 *buffer)
+{
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       const struct efx_spi_device *spi = efx_mtd->spi;
+       struct efx_nic *efx = efx_mtd->efx;
+       int rc;
+
+       rc = mutex_lock_interruptible(&efx->spi_lock);
+       if (rc)
+               return rc;
+       rc = falcon_spi_read(efx, spi, part->offset + start, len,
+                            retlen, buffer);
+       mutex_unlock(&efx->spi_lock);
+       return rc;
 }
 
-static void efx_mtd_remove(struct efx_dl_device *efx_dev)
+static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
 {
-       struct efx_mtd *efx_mtd = efx_dev->priv;
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       struct efx_nic *efx = efx_mtd->efx;
+       int rc;
 
-       del_mtd_partitions(&efx_mtd->mtd);
-       kfree(efx_mtd);
-       efx_dev->priv = NULL;
+       rc = mutex_lock_interruptible(&efx->spi_lock);
+       if (rc)
+               return rc;
+       rc = efx_spi_erase(efx_mtd, part->offset + start, len);
+       mutex_unlock(&efx->spi_lock);
+       return rc;
 }
 
-static __devinit int efx_mtd_register(struct efx_mtd *efx_mtd,
-                                     struct efx_dl_device *efx_dev,
-                                     struct efx_nic *efx,
-                                     struct efx_spi_device *spi,
-                                     const char *type_name,
-                                     const char **part_type_name,
-                                     unsigned int num_parts)
+static int falcon_mtd_write(struct mtd_info *mtd, loff_t start,
+                           size_t len, size_t *retlen, const u8 *buffer)
 {
-       int i;
-
-       efx_dev->priv = efx_mtd;
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       const struct efx_spi_device *spi = efx_mtd->spi;
+       struct efx_nic *efx = efx_mtd->efx;
+       int rc;
 
-       efx_mtd->efx_dev = efx_dev;
-       efx_mtd->efx = efx;
-       efx_mtd->spi = spi;
-       sema_init(&efx_mtd->access_lock, 1);
-
-       efx_mtd->mtd.size = spi->size;
-       efx_mtd->mtd.erasesize = spi->erase_size;
-       efx_mtd->mtd.writesize = 1;
-       if (snprintf(efx_mtd->name, sizeof(efx_mtd->name),
-                    "%s %s", efx->name, type_name) >=
-           sizeof(efx_mtd->name))
-               return -ENAMETOOLONG;
-
-       efx_mtd->mtd.priv = efx_mtd;
-       efx_mtd->mtd.name = efx_mtd->name;
-       efx_mtd->mtd.erase = efx_mtd_erase;
-       efx_mtd->mtd.read = efx_mtd_read;
-       efx_mtd->mtd.write = efx_mtd_write;
-       efx_mtd->mtd.sync = efx_mtd_sync;
-
-       for (i = 0; i < num_parts; i++) {
-               efx_mtd->part[i].name = efx_mtd->part_name[i];
-               if (snprintf(efx_mtd->part_name[i],
-                            sizeof(efx_mtd->part_name[i]),
-                            "%s %s", efx->name, part_type_name[i]) >=
-                   sizeof(efx_mtd->part_name[i]))
-                       return -ENAMETOOLONG;
+       rc = mutex_lock_interruptible(&efx->spi_lock);
+       if (rc)
+               return rc;
+       rc = falcon_spi_write(efx, spi, part->offset + start, len,
+                             retlen, buffer);
+       mutex_unlock(&efx->spi_lock);
+       return rc;
+}
 
-               if (efx_allow_nvconfig_writes)
-                       efx_mtd->part[i].mask_flags &= ~MTD_WRITEABLE;
-       }
+static int falcon_mtd_sync(struct mtd_info *mtd)
+{
+       struct efx_mtd *efx_mtd = mtd->priv;
+       struct efx_nic *efx = efx_mtd->efx;
+       int rc;
 
-       return add_mtd_partitions(&efx_mtd->mtd, efx_mtd->part, num_parts);
+       mutex_lock(&efx->spi_lock);
+       rc = efx_spi_slow_wait(efx_mtd, true);
+       mutex_unlock(&efx->spi_lock);
+       return rc;
 }
 
-static int __devinit
-efx_flash_probe(struct efx_dl_device *efx_dev,
-               const struct net_device *net_dev,
-               const struct efx_dl_device_info *dev_info,
-               const char *silicon_rev)
+static struct efx_mtd_ops falcon_mtd_ops = {
+       .read   = falcon_mtd_read,
+       .erase  = falcon_mtd_erase,
+       .write  = falcon_mtd_write,
+       .sync   = falcon_mtd_sync,
+};
+
+static int falcon_mtd_probe(struct efx_nic *efx)
 {
-       struct efx_nic *efx = efx_dl_get_nic(efx_dev);
        struct efx_mtd *efx_mtd;
-       const char *part_type_name[2];
-       unsigned int num_parts;
-       int rc;
+       int rc = -ENODEV;
+
+       ASSERT_RTNL();
+
+       if (efx->spi_flash) {
+               size_t n_parts =
+                       (efx->spi_flash->size > FALCON_FLASH_BOOTCODE_START)
+                       ? 2 : 1;
+
+               efx_mtd = kzalloc(sizeof(*efx_mtd) +
+                                 n_parts * sizeof(efx_mtd->part[0]),
+                                 GFP_KERNEL);
+               if (!efx_mtd)
+                       return -ENOMEM;
+
+               efx_mtd->spi = efx->spi_flash;
+               efx_mtd->name = "flash";
+
+               efx_mtd->ops = &falcon_mtd_ops;
+
+               efx_mtd->n_parts = n_parts;
+
+               efx_mtd->part[0].mtd.type = MTD_NORFLASH;
+               efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH & ~MTD_WRITEABLE;
+               efx_mtd->part[0].mtd.size = min(efx->spi_flash->size,
+                                               FALCON_FLASH_BOOTCODE_START);
+               efx_mtd->part[0].mtd.erasesize = efx->spi_flash->erase_size;
+               efx_mtd->part[0].offset = 0;
+               efx_mtd->part[0].type_name = "sfc_flash_config";
+
+               if (n_parts > 1) {
+                       efx_mtd->part[1].mtd.type = MTD_NORFLASH;
+                       efx_mtd->part[1].mtd.flags = MTD_CAP_NORFLASH;
+                       efx_mtd->part[1].mtd.size = (efx->spi_flash->size
+                                                    - FALCON_FLASH_BOOTCODE_START);
+                       efx_mtd->part[1].mtd.erasesize =
+                                               efx->spi_flash->erase_size;
+                       efx_mtd->part[1].offset = FALCON_FLASH_BOOTCODE_START;
+                       efx_mtd->part[1].type_name = "sfc_flash_bootrom";
+               }
 
-       if (!efx->spi_flash)
-               return -ENODEV;
+               rc = efx_mtd_probe_device(efx, efx_mtd);
+               if (rc) {
+                       kfree(efx_mtd);
+                       return rc;
+               }
+       }
 
-       efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
-       if (!efx_mtd)
-               return -ENOMEM;
+       if (efx->spi_eeprom) {
+               size_t n_parts =
+                       (efx->spi_eeprom->size > EFX_EEPROM_BOOTCONFIG_END)
+                       ? 3
+                       : (efx->spi_eeprom->size > EFX_EEPROM_BOOTCONFIG_START)
+                       ? 2 : 1;
+               efx_mtd = kzalloc(sizeof(*efx_mtd) +
+                                 n_parts * sizeof(efx_mtd->part[0]),
+                                 GFP_KERNEL);
+               if (!efx_mtd)
+                       return -ENOMEM;
+
+               efx_mtd->spi = efx->spi_eeprom;
+               efx_mtd->name = "EEPROM";
+
+               efx_mtd->ops = &falcon_mtd_ops;
+
+               efx_mtd->n_parts = n_parts;
+
+               efx_mtd->part[0].mtd.type = MTD_RAM;
+               efx_mtd->part[0].mtd.flags = MTD_CAP_RAM;
+               efx_mtd->part[0].mtd.size = min(efx->spi_eeprom->size,
+                                               EFX_EEPROM_BOOTCONFIG_START);
+               efx_mtd->part[0].mtd.erasesize = efx->spi_eeprom->erase_size;
+               efx_mtd->part[0].offset = 0;
+               if (efx->spi_eeprom->size >= FALCON_NVCONFIG_END) {
+                       /* Chip and board config are in EEPROM */
+                       efx_mtd->part[0].mtd.flags &= ~MTD_WRITEABLE;
+                       efx_mtd->part[0].type_name = "sfc_large_config";
+               } else {
+                       efx_mtd->part[0].type_name = "sfc_small_config";
+               }
 
-       efx_mtd->mtd.type = MTD_NORFLASH;
-       efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
+               if (n_parts > 1) {
+                       efx_mtd->part[1].mtd.type = MTD_RAM;
+                       efx_mtd->part[1].mtd.flags = MTD_CAP_RAM;
+                       efx_mtd->part[1].mtd.size =
+                               min(efx->spi_eeprom->size, EFX_EEPROM_BOOTCONFIG_END) -
+                               EFX_EEPROM_BOOTCONFIG_START;
+                       efx_mtd->part[1].mtd.erasesize =
+                                               efx->spi_eeprom->erase_size;
+                       efx_mtd->part[1].offset = EFX_EEPROM_BOOTCONFIG_START;
+                       efx_mtd->part[1].type_name = "sfc_bootconfig";
+               }
 
-       part_type_name[0] = "sfc_flash_config";
-       efx_mtd->part[0].offset = 0;
-       efx_mtd->part[0].size = min(efx->spi_flash->size,
-                                   EFX_FLASH_BOOTROM_OFFSET);
-       efx_mtd->part[0].mask_flags = MTD_WRITEABLE;
+               if (n_parts > 2) {
+                       efx_mtd->part[2].mtd.type = MTD_RAM;
+                       efx_mtd->part[2].mtd.flags = MTD_CAP_RAM;
+                       efx_mtd->part[2].mtd.size =
+                               efx->spi_eeprom->size - EFX_EEPROM_BOOTCONFIG_END;
+                       efx_mtd->part[2].mtd.erasesize =
+                                               efx->spi_eeprom->erase_size;
+                       efx_mtd->part[2].offset = EFX_EEPROM_BOOTCONFIG_END;
+                       efx_mtd->part[2].type_name = "sfc_eeprom_spare";
+               }
 
-       if (efx->spi_flash->size <= EFX_FLASH_BOOTROM_OFFSET) {
-               num_parts = 1;
-       } else {
-               part_type_name[1] = "sfc_flash_bootrom";
-               efx_mtd->part[1].offset = EFX_FLASH_BOOTROM_OFFSET;
-               efx_mtd->part[1].size = (efx->spi_flash->size
-                                        - EFX_FLASH_BOOTROM_OFFSET);
-               num_parts = 2;
+               rc = efx_mtd_probe_device(efx, efx_mtd);
+               if (rc) {
+                       kfree(efx_mtd);
+                       return rc;
+               }
        }
 
-       rc = efx_mtd_register(efx_mtd, efx_dev, efx, efx->spi_flash,
-                             "sfc_flash", part_type_name, num_parts);
-       if (rc)
-               kfree(efx_mtd);
        return rc;
 }
 
-static struct efx_dl_driver efx_flash_driver = {
-       .name           = "sfc_flash",
-       .probe          = efx_flash_probe,
-       .remove         = efx_mtd_remove,
-       .reset_suspend  = efx_mtd_reset_suspend,
-       .reset_resume   = efx_mtd_reset_resume,
-};
+/* Implementation of MTD operations for Siena */
 
-static int __devinit
-efx_eeprom_probe(struct efx_dl_device *efx_dev,
-                const struct net_device *net_dev,
-                const struct efx_dl_device_info *dev_info,
-                const char *silicon_rev)
+static int siena_mtd_read(struct mtd_info *mtd, loff_t start,
+                         size_t len, size_t *retlen, u8 *buffer)
 {
-       struct efx_nic *efx = efx_dl_get_nic(efx_dev);
-       struct efx_mtd *efx_mtd;
-       const char *type_name;
-       const char *part_type_name[1];
-       int rc;
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       struct efx_nic *efx = efx_mtd->efx;
+       loff_t offset = start;
+       loff_t end = min_t(loff_t, start + len, mtd->size);
+       size_t chunk;
+       int rc = 0;
 
-       if (!efx->spi_eeprom)
-               return -ENODEV;
+       while (offset < end) {
+               chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN);
+               rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset,
+                                        buffer, chunk);
+               if (rc)
+                       goto out;
+               offset += chunk;
+               buffer += chunk;
+       }
+out:
+       *retlen = offset - start;
+       return rc;
+}
 
-       efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
-       if (!efx_mtd)
-               return -ENOMEM;
+static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
+{
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       struct efx_nic *efx = efx_mtd->efx;
+       loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
+       loff_t end = min_t(loff_t, start + len, mtd->size);
+       size_t chunk = part->mtd.erasesize;
+       int rc = 0;
+
+       if (!part->mcdi.updating) {
+               rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type);
+               if (rc)
+                       goto out;
+               part->mcdi.updating = 1;
+       }
+
+       /* The MCDI interface can in fact do multiple erase blocks at once;
+        * but erasing may be slow, so we make multiple calls here to avoid
+        * tripping the MCDI RPC timeout. */
+       while (offset < end) {
+               rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset,
+                                         chunk);
+               if (rc)
+                       goto out;
+               offset += chunk;
+       }
+out:
+       return rc;
+}
 
-       efx_mtd->mtd.type = MTD_RAM;
-       efx_mtd->mtd.flags = MTD_CAP_RAM;
+static int siena_mtd_write(struct mtd_info *mtd, loff_t start,
+                          size_t len, size_t *retlen, const u8 *buffer)
+{
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       struct efx_nic *efx = efx_mtd->efx;
+       loff_t offset = start;
+       loff_t end = min_t(loff_t, start + len, mtd->size);
+       size_t chunk;
+       int rc = 0;
 
-       efx_mtd->part[0].offset = 0;
-       efx_mtd->part[0].size = efx->spi_eeprom->size;
-       efx_mtd->part[0].mask_flags = MTD_WRITEABLE;
+       if (!part->mcdi.updating) {
+               rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type);
+               if (rc)
+                       goto out;
+               part->mcdi.updating = 1;
+       }
 
-       if (efx->spi_eeprom->size <= 0x200) {
-               type_name = "sfc_small_eeprom";
-               part_type_name[0] = "sfc_small_config";
-       } else {
-               type_name = "sfc_large_eeprom";
-               part_type_name[0] = "sfc_large_config";
+       while (offset < end) {
+               chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN);
+               rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset,
+                                         buffer, chunk);
+               if (rc)
+                       goto out;
+               offset += chunk;
+               buffer += chunk;
+       }
+out:
+       *retlen = offset - start;
+       return rc;
+}
+
+static int siena_mtd_sync(struct mtd_info *mtd)
+{
+       struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
+       struct efx_mtd *efx_mtd = mtd->priv;
+       struct efx_nic *efx = efx_mtd->efx;
+       int rc = 0;
+
+       if (part->mcdi.updating) {
+               part->mcdi.updating = 0;
+               rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type);
        }
 
-       rc = efx_mtd_register(efx_mtd, efx_dev, efx, efx->spi_eeprom,
-                             type_name, part_type_name, 1);
-       if (rc)
-               kfree(efx_mtd);
        return rc;
 }
 
-static struct efx_dl_driver efx_eeprom_driver = {
-       .name           = "sfc_eeprom",
-       .probe          = efx_eeprom_probe,
-       .remove         = efx_mtd_remove,
-       .reset_suspend  = efx_mtd_reset_suspend,
-       .reset_resume   = efx_mtd_reset_resume,
+static struct efx_mtd_ops siena_mtd_ops = {
+       .read   = siena_mtd_read,
+       .erase  = siena_mtd_erase,
+       .write  = siena_mtd_write,
+       .sync   = siena_mtd_sync,
+};
+
+struct siena_nvram_type_info {
+       int port;
+       const char *name;
 };
 
-/* Kernel module interface */
+static struct siena_nvram_type_info siena_nvram_types[] = {
+       [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO]   = { 0, "sfc_dummy_phy" },
+       [MC_CMD_NVRAM_TYPE_MC_FW]               = { 0, "sfc_mcfw" },
+       [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP]        = { 0, "sfc_mcfw_backup" },
+       [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0]    = { 0, "sfc_static_cfg" },
+       [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1]    = { 1, "sfc_static_cfg" },
+       [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0]   = { 0, "sfc_dynamic_cfg" },
+       [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1]   = { 1, "sfc_dynamic_cfg" },
+       [MC_CMD_NVRAM_TYPE_EXP_ROM]             = { 0, "sfc_exp_rom" },
+       [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0]   = { 0, "sfc_exp_rom_cfg" },
+       [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1]   = { 1, "sfc_exp_rom_cfg" },
+       [MC_CMD_NVRAM_TYPE_PHY_PORT0]           = { 0, "sfc_phy_fw" },
+       [MC_CMD_NVRAM_TYPE_PHY_PORT1]           = { 1, "sfc_phy_fw" },
+};
 
-static int __init efx_mtd_init_module(void)
+static int siena_mtd_probe_partition(struct efx_nic *efx,
+                                    struct efx_mtd *efx_mtd,
+                                    unsigned int part_id,
+                                    unsigned int type)
 {
+       struct efx_mtd_partition *part = &efx_mtd->part[part_id];
+       struct siena_nvram_type_info *info;
+       size_t size, erase_size;
+       bool protected;
        int rc;
 
-       rc = efx_dl_register_driver(&efx_flash_driver);
+       if (type >= ARRAY_SIZE(siena_nvram_types))
+               return -ENODEV;
+
+       info = &siena_nvram_types[type];
+
+       if (info->port != efx_port_num(efx))
+               return -ENODEV;
+
+       rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
        if (rc)
                return rc;
-       rc = efx_dl_register_driver(&efx_eeprom_driver);
-       if (rc) {
-               efx_dl_unregister_driver(&efx_flash_driver);
-               return rc;
-       }
+       if (protected && !efx_allow_nvconfig_writes)
+               return -ENODEV; /* hide it */
+
+       part->mcdi.nvram_type = type;
+       part->type_name = info->name;
+
+       part->mtd.type = MTD_NORFLASH;
+       part->mtd.flags = MTD_CAP_NORFLASH;
+       part->mtd.size = size;
+       part->mtd.erasesize = erase_size;
 
        return 0;
 }
 
-static void __exit efx_mtd_exit_module(void)
+static int siena_mtd_get_fw_subtypes(struct efx_nic *efx,
+                                    struct efx_mtd *efx_mtd)
 {
-       efx_dl_unregister_driver(&efx_eeprom_driver);
-       efx_dl_unregister_driver(&efx_flash_driver);
+       struct efx_mtd_partition *part;
+       uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN /
+                                sizeof(uint16_t)];
+       int rc;
+
+       rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list);
+       if (rc)
+               return rc;
+
+       efx_for_each_partition(part, efx_mtd)
+               part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type];
+
+       return 0;
 }
 
-module_init(efx_mtd_init_module);
-module_exit(efx_mtd_exit_module);
+static int siena_mtd_probe(struct efx_nic *efx)
+{
+       struct efx_mtd *efx_mtd;
+       int rc = -ENODEV;
+       u32 nvram_types;
+       unsigned int type;
+
+       ASSERT_RTNL();
+
+       rc = efx_mcdi_nvram_types(efx, &nvram_types);
+       if (rc)
+               return rc;
+
+       efx_mtd = kzalloc(sizeof(*efx_mtd) +
+                         hweight32(nvram_types) * sizeof(efx_mtd->part[0]),
+                         GFP_KERNEL);
+       if (!efx_mtd)
+               return -ENOMEM;
+
+       efx_mtd->name = "Siena NVRAM manager";
+
+       efx_mtd->ops = &siena_mtd_ops;
+
+       type = 0;
+       efx_mtd->n_parts = 0;
+
+       while (nvram_types != 0) {
+               if (nvram_types & 1) {
+                       rc = siena_mtd_probe_partition(efx, efx_mtd,
+                                                      efx_mtd->n_parts, type);
+                       if (rc == 0)
+                               efx_mtd->n_parts++;
+                       else if (rc != -ENODEV)
+                               goto fail;
+               }
+               type++;
+               nvram_types >>= 1;
+       }
+
+       rc = siena_mtd_get_fw_subtypes(efx, efx_mtd);
+       if (rc)
+               goto fail;
+
+       rc = efx_mtd_probe_device(efx, efx_mtd);
+fail:
+       if (rc)
+               kfree(efx_mtd);
+       return rc;
+}
 
-MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
-             "Solarflare Communications");
-MODULE_DESCRIPTION("SFC MTD driver");
-MODULE_LICENSE("GPL");
index f46147d8b50683017bfd901ddd288c9fa6e21cc4..ed5b894b8278500e0070260d71439f99222f4bba 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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
- ****************************************************************************
  */
 
 /* Common definitions for all Efx net driver code */
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
-#include <linux/timer.h>
-#include <linux/mii.h>
 #include <linux/list.h>
 #include <linux/pci.h>
 #include <linux/device.h>
+#include <linux/i2c.h>
 
 /* Must come before other headers */
 #include "kernel_compat.h"
 #include "bitfield.h"
 #include "driverlink_api.h"
 #include "driverlink.h"
-#include "i2c-direct.h"
 
-/* Sick, but we have no other use for dentry */
-#define dentry proc_dir_entry
+       #ifdef EFX_USE_DEBUGFS
+               struct dentry;
+               typedef struct dentry efx_debugfs_entry;
+       #else
+               struct proc_dir_entry;
+               typedef struct proc_dir_entry efx_debugfs_entry;
+       #endif
 
 /**************************************************************************
  *
@@ -61,7 +47,7 @@
 #ifndef EFX_DRIVER_NAME
 #define EFX_DRIVER_NAME        "sfc"
 #endif
-#define EFX_DRIVER_VERSION     "2.2.0204"
+#define EFX_DRIVER_VERSION     "3.0.2.2074"
 
 #ifdef EFX_ENABLE_DEBUG
 #define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
 #define EFX_WARN_ON_PARANOID(x) do {} while (0)
 #endif
 
-#define NET_DEV_REGISTERED(efx)                                        \
-       ((efx)->net_dev &&                                      \
-        ((efx)->net_dev->reg_state == NETREG_REGISTERED))
-
-/* Include net device name in log messages if it has been registered.
- * Use efx->name not efx->net_dev->name so that races with (un)registration
- * are harmless.
- */
-#define NET_DEV_NAME(efx) (NET_DEV_REGISTERED(efx) ? (efx)->name : "")
-
 /* Un-rate-limited logging */
 #define EFX_ERR(efx, fmt, args...) \
-dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, efx_dev_name(efx), ##args)
 
 #define EFX_INFO(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, efx_dev_name(efx), ##args)
 
 #ifdef EFX_ENABLE_DEBUG
 #define EFX_LOG(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
 #else
 #define EFX_LOG(efx, fmt, args...) \
-dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
 #endif
 
 #define EFX_TRACE(efx, fmt, args...) do {} while (0)
@@ -110,11 +86,6 @@ do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
 #define EFX_LOG_RL(efx, fmt, args...) \
 do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
 
-/* Kernel headers may redefine inline anyway */
-#ifndef inline
-#define inline inline __attribute__ ((always_inline))
-#endif
-
 /**************************************************************************
  *
  * Efx data structures
@@ -122,9 +93,12 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
  **************************************************************************/
 
 #define EFX_MAX_CHANNELS 32
-#define EFX_MAX_TX_QUEUES 1
 #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
 
+#define EFX_TX_QUEUE_OFFLOAD_CSUM      0
+#define EFX_TX_QUEUE_NO_CSUM           1
+#define EFX_TX_QUEUE_COUNT             2
+
 /**
  * struct efx_special_buffer - An Efx special buffer
  * @addr: CPU base address of the buffer
@@ -137,7 +111,7 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
  * descriptor queues for each channel.  They are *not* used for the
  * actual transmit and receive buffers.
  *
- * Note that for Falcon, TX and RX descriptor queues live in host memory.
+ * Note that for TX and RX descriptor queues live in host memory.
  * Allocation and freeing procedures must take this into account.
  */
 struct efx_special_buffer {
@@ -148,27 +122,35 @@ struct efx_special_buffer {
        int entries;
 };
 
+enum efx_flush_state {
+       FLUSH_NONE,
+       FLUSH_PENDING,
+       FLUSH_FAILED,
+       FLUSH_DONE,
+};
+
 /**
  * struct efx_tx_buffer - An Efx TX buffer
  * @skb: The associated socket buffer.
  *     Set only on the final fragment of a packet; %NULL for all other
  *     fragments.  When this fragment completes, then we can free this
  *     skb.
+ * @tsoh: The associated TSO header structure, or %NULL if this
+ *     buffer is not a TSO header.
  * @dma_addr: DMA address of the fragment.
  * @len: Length of this fragment.
  *     This field is zero when the queue slot is empty.
  * @continuation: True if this fragment is not the end of a packet.
  * @unmap_single: True if pci_unmap_single should be used.
- * @unmap_addr: DMA address to unmap
  * @unmap_len: Length of this fragment to unmap
  */
 struct efx_tx_buffer {
        const struct sk_buff *skb;
+       struct efx_tso_header *tsoh;
        dma_addr_t dma_addr;
        unsigned short len;
-       unsigned char continuation;
-       unsigned char unmap_single;
-       dma_addr_t unmap_addr;
+       bool continuation;
+       bool unmap_single;
        unsigned short unmap_len;
 };
 
@@ -187,14 +169,14 @@ struct efx_tx_buffer {
  *
  * @efx: The associated Efx NIC
  * @queue: DMA queue number
- * @used: Queue is used by net driver
  * @channel: The associated channel
  * @buffer: The software buffer ring
  * @txd: The hardware descriptor ring
  * @debug_dir: debugfs directory
+ * @flushed: Used when handling queue flushing
  * @read_count: Current read pointer.
  *     This is the number of buffers that have been removed from both rings.
- * @stopped: Stopped flag.
+ * @stopped: Stopped count.
  *     Set if this TX queue is currently stopping its port.
  * @insert_count: Current insert pointer
  *     This is the number of buffers that have been added to the
@@ -208,19 +190,23 @@ struct efx_tx_buffer {
  *     variable indicates that the queue is full.  This is to
  *     avoid cache-line ping-pong between the xmit path and the
  *     completion path.
+ * @tso_headers_free: A list of TSO headers allocated for this TX queue
+ *     that are not in use, and so available for new TSO sends. The list
+ *     is protected by the TX queue lock.
+ * @tso_bursts: Number of times TSO xmit invoked by kernel
+ * @tso_long_headers: Number of packets with headers too long for standard
+ *     blocks
+ * @tso_packets: Number of packets via the TSO xmit path
  */
 struct efx_tx_queue {
        /* Members which don't change on the fast path */
        struct efx_nic *efx ____cacheline_aligned_in_smp;
        int queue;
-       int used;
        struct efx_channel *channel;
        struct efx_nic *nic;
        struct efx_tx_buffer *buffer;
        struct efx_special_buffer txd;
-#ifdef CONFIG_SFC_DEBUGFS
-       struct dentry *debug_dir;
-#endif
+       enum efx_flush_state flushed;
 
        /* Members used mainly on the completion path */
        unsigned int read_count ____cacheline_aligned_in_smp;
@@ -230,6 +216,10 @@ struct efx_tx_queue {
        unsigned int insert_count ____cacheline_aligned_in_smp;
        unsigned int write_count;
        unsigned int old_read_count;
+       struct efx_tso_header *tso_headers_free;
+       unsigned int tso_bursts;
+       unsigned int tso_long_headers;
+       unsigned int tso_packets;
 };
 
 /**
@@ -256,7 +246,6 @@ struct efx_rx_buffer {
  * struct efx_rx_queue - An Efx RX queue
  * @efx: The associated Efx NIC
  * @queue: DMA queue number
- * @used: Queue is used by net driver
  * @channel: The associated channel
  * @buffer: The software buffer ring
  * @rxd: The hardware descriptor ring
@@ -286,12 +275,12 @@ struct efx_rx_buffer {
  *     the remaining space in the allocation.
  * @buf_dma_addr: Page's DMA address.
  * @buf_data: Page's host address.
+ * @flushed: Use when handling queue flushing
  * @debug_dir: debugfs directory
  */
 struct efx_rx_queue {
        struct efx_nic *efx;
        int queue;
-       int used;
        struct efx_channel *channel;
        struct efx_rx_buffer *buffer;
        struct efx_special_buffer rxd;
@@ -313,10 +302,8 @@ struct efx_rx_queue {
        struct page *buf_page;
        dma_addr_t buf_dma_addr;
        char *buf_data;
+       enum efx_flush_state flushed;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       struct dentry *debug_dir;
-#endif
 };
 
 /**
@@ -325,7 +312,7 @@ struct efx_rx_queue {
  * @dma_addr: DMA base address of the buffer
  * @len: Buffer length, in bytes
  *
- * Falcon uses these buffers for its interrupt status registers and
+ * The NIC uses these buffers for its interrupt status registers and
  * MAC stats dumps.
  */
 struct efx_buffer {
@@ -335,83 +322,6 @@ struct efx_buffer {
 };
 
 
-
-/**
- * struct efx_ssr_conn - Connection state for Soft Segment Reassembly (SSR) aka LRO
- * @link: Link for hash table and free list.
- * @active_link: Link for active_conns list
- * @saddr: Source IP address
- * @daddr: Destination IP address
- * @source: Source TCP port number
- * @dest: Destination TCP port number
- * @n_in_order_pkts: Number of in-order packets we've seen with payload.
- * @next_seq: Next in-order sequence number.
- * @last_pkt_jiffies: Time we last saw a packet on this connection.
- * @skb: The SKB we are currently holding.
- *     If %NULL, then all following fields are undefined.
- * @skb_tail: The tail of the frag_list of SKBs we're holding.
- *     Only valid after at least one merge.
- * @eh: The ethernet header of the skb we are holding.
- * @iph: The IP header of the skb we are holding.
- * @th: The TCP header of the skb we are holding.
- * @th_last: The TCP header of the last packet merged.
- */
-struct efx_ssr_conn {
-       struct list_head link;
-       struct list_head active_link;
-       unsigned saddr, daddr;
-       unsigned short source, dest;
-       unsigned n_in_order_pkts;
-       unsigned next_seq;
-       unsigned long last_pkt_jiffies;
-       struct sk_buff *skb;
-       struct sk_buff *skb_tail;
-       struct ethhdr *eh;
-       struct iphdr *iph;
-       struct tcphdr *th;
-       struct tcphdr *th_last;
-};
-
-/**
- * struct efx_ssr_state - Port state for Soft Segment Reassembly (SSR) aka LRO
- * @efx: The associated NIC.
- * @conns_mask: Number of hash buckets - 1.
- * @conns: Hash buckets for tracked connections.
- * @conns_n: Length of linked list for each hash bucket.
- * @active_conns: Connections that are holding a packet.
- *     Connections are self-linked when not in this list.
- * @free_conns: Free efx_ssr_conn instances.
- * @last_purge_jiffies: The value of jiffies last time we purged idle
- *     connections.
- * @n_merges: Number of packets absorbed by SSR.
- * @n_bursts: Number of bursts spotted by SSR.
- * @n_slow_start: Number of packets not merged because connection may be in
- *     slow-start.
- * @n_misorder: Number of out-of-order packets seen in tracked streams.
- * @n_too_many: Incremented when we're trying to track too many streams.
- * @n_new_stream: Number of distinct streams we've tracked.
- * @n_drop_idle: Number of streams discarded because they went idle.
- * @n_drop_closed: Number of streams that have seen a FIN or RST.
- */
-struct efx_ssr_state {
-       struct efx_nic *efx;
-       unsigned conns_mask;
-       struct list_head *conns;
-       unsigned *conns_n;
-       struct list_head active_conns;
-       struct list_head free_conns;
-       unsigned long last_purge_jiffies;
-       unsigned n_merges;
-       unsigned n_bursts;
-       unsigned n_slow_start;
-       unsigned n_misorder;
-       unsigned n_too_many;
-       unsigned n_new_stream;
-       unsigned n_drop_idle;
-       unsigned n_drop_closed;
-};
-
-
 /* Flags for channel->used_flags */
 #define EFX_USED_BY_RX 1
 #define EFX_USED_BY_TX 2
@@ -431,13 +341,12 @@ enum efx_rx_alloc_method {
  * queue.
  *
  * @efx: Associated Efx NIC
- * @evqnum: Event queue number
  * @channel: Channel instance number
+ * @name: Name for channel and IRQ
  * @used_flags: Channel is used by net driver
  * @enabled: Channel enabled indicator
  * @irq: IRQ number (MSI and MSI-X only)
- * @has_interrupt: Channel has an interrupt
- * @irq_moderation: IRQ moderation value (in us)
+ * @irq_moderation: IRQ moderation value (in hardware ticks)
  * @napi_dev: Net device used with NAPI
  * @napi_str: NAPI control structure
  * @reset_work: Scheduled reset work thread
@@ -446,52 +355,53 @@ enum efx_rx_alloc_method {
  * @eventq_read_ptr: Event queue read pointer
  * @last_eventq_read_ptr: Last event queue read pointer value.
  * @eventq_magic: Event queue magic value for driver-generated test events
+ * @irq_count: Number of IRQs since last adaptive moderation decision
+ * @irq_mod_score: IRQ moderation score
  * @debug_dir: debugfs directory
- * @ssr: LRO/SSR state
  * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
  *     and diagnostic counters
  * @rx_alloc_push_pages: RX allocation method currently in use for pushing
  *     descriptors
- * @rx_alloc_pop_pages: RX allocation method currently in use for popping
- *     descriptors
  * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
- * @n_rx_ip_frag_err: Count of RX IP fragment errors
+ * @n_rx_ip_frag: Count of RX packets containing fragmented IP
  * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
  * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
+ * @n_rx_eth_crc_err: Count of RX CRC errors
+ * @n_rx_mcast_mismatch: Count of unmatched multicast frames
  * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
  * @n_rx_overlength: Count of RX_OVERLENGTH errors
  * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
  */
 struct efx_channel {
        struct efx_nic *efx;
-       int evqnum;
        int channel;
+       char name[IFNAMSIZ + 6];
        int used_flags;
-       int enabled;
+       bool enabled;
        int irq;
-       unsigned int has_interrupt;
        unsigned int irq_moderation;
        struct net_device *napi_dev;
-       struct work_struct reset_work;
-       int work_pending;
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_OLD_NAPI)
+       struct napi_struct napi_str;
+#endif
+       bool work_pending;
        struct efx_special_buffer eventq;
        unsigned int eventq_read_ptr;
        unsigned int last_eventq_read_ptr;
        unsigned int eventq_magic;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       struct dentry *debug_dir;
-#endif
+       unsigned int irq_count;
+       unsigned int irq_mod_score;
 
-       struct efx_ssr_state ssr;
        int rx_alloc_level;
        int rx_alloc_push_pages;
-       int rx_alloc_pop_pages;
 
        unsigned n_rx_tobe_disc;
-       unsigned n_rx_ip_frag_err;
+       unsigned n_rx_ip_frag;
        unsigned n_rx_ip_hdr_chksum_err;
        unsigned n_rx_tcp_udp_chksum_err;
+       unsigned n_rx_eth_crc_err;
+       unsigned n_rx_mcast_mismatch;
        unsigned n_rx_frm_trunc;
        unsigned n_rx_overlength;
        unsigned n_skbuff_leaks;
@@ -500,59 +410,14 @@ struct efx_channel {
         * access with prefetches.
         */
        struct efx_rx_buffer *rx_pkt;
-       int rx_pkt_csummed;
-
-};
+       bool rx_pkt_csummed;
 
-/**
- * struct efx_blinker - S/W LED blinking context
- * @led_num: LED ID (board-specific meaning)
- * @state: Current state - on or off
- * @resubmit: Timer resubmission flag
- * @timer: Control timer for blinking
- */
-struct efx_blinker {
-       int led_num;
-       int state;
-       int resubmit;
-       struct timer_list timer;
 };
 
-
-/**
- * struct efx_board - board information
- * @type: Board model type
- * @major: Major rev. ('A', 'B' ...)
- * @minor: Minor rev. (0, 1, ...)
- * @init: Initialisation function
- * @init_leds: Sets up board LEDs
- * @set_fault_led: Turns the fault LED on or off
- * @blink: Starts/stops blinking
- * @monitor: Board-specific health check function
- * @fini: Cleanup function
- * @interpret_sensor: Function to interpret LM87 sensor meanings.
- *     Returns %FALSE if no board-specific meaning.
- * @mwatts: Power requirements (mW)
- * @blinker: used to blink LEDs in software
- * @lm87_addr: I2C address of LM87 monitoring chip (0 if absent)
- */
-struct efx_board {
-       int type;
-       int major;
-       int minor;
-       int (*init) (struct efx_nic *nic);
-       /* As the LEDs are typically attached to the PHY, LEDs
-        * have a separate init callback that happens later than
-        * board init. */
-       int (*init_leds)(struct efx_nic *efx);
-       int (*monitor) (struct efx_nic *nic);
-       void (*set_fault_led) (struct efx_nic *efx, int state);
-       void (*blink) (struct efx_nic *efx, int start);
-       void (*fini) (struct efx_nic *nic);
-       int (*interpret_sensor) (struct efx_nic *nic, int num, unsigned val);
-       unsigned mwatts;
-       struct efx_blinker blinker;
-       unsigned int lm87_addr;
+enum efx_led_mode {
+       EFX_LED_OFF     = 0,
+       EFX_LED_ON      = 1,
+       EFX_LED_DEFAULT = 2
 };
 
 #define STRING_TABLE_LOOKUP(val, member) \
@@ -573,16 +438,6 @@ extern const unsigned int efx_reset_type_max;
 #define RESET_TYPE(type) \
        STRING_TABLE_LOOKUP(type, efx_reset_type)
 
-extern const char *efx_phy_type_names[];
-extern const unsigned int efx_phy_type_max;
-#define PHY_TYPE(efx) \
-       STRING_TABLE_LOOKUP((efx)->phy_type, efx_phy_type)
-
-extern const char *efx_nic_state_names[];
-extern const unsigned int efx_nic_state_max;
-#define STATE_NAME(efx)        \
-       STRING_TABLE_LOOKUP((efx)->state, efx_nic_state)
-
 enum efx_int_mode {
        /* Be careful if altering to correct macro below */
        EFX_INT_MODE_MSIX = 0,
@@ -592,27 +447,13 @@ enum efx_int_mode {
 };
 #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
 
-enum phy_type {
-       PHY_TYPE_NONE = 0,
-       PHY_TYPE_CX4_RTMR = 1,
-       PHY_TYPE_1G_ALASKA = 2,
-       PHY_TYPE_10XPRESS = 3,
-       PHY_TYPE_XFP = 4,
-       PHY_TYPE_PM8358 = 6,
-       PHY_TYPE_MAX    /* Insert any new items before this */
-};
-
-#define PHY_ADDR_INVALID 0xff
-
-#define EFX_IS10G(efx) ((efx)->is_10g)
-#define EFX_ISCLAUSE45(efx) ((efx)->phy_type != PHY_TYPE_1G_ALASKA)
+#define EFX_IS10G(efx) ((efx)->link_state.speed == 10000)
 
 enum nic_state {
        STATE_INIT = 0,
        STATE_RUNNING = 1,
        STATE_FINI = 2,
-       STATE_RESETTING = 3, /* rtnl_lock always held */
-       STATE_DISABLED = 4,
+       STATE_DISABLED = 3,
        STATE_MAX,
 };
 
@@ -623,7 +464,7 @@ enum nic_state {
  * This is the equivalent of NET_IP_ALIGN [which controls the alignment
  * of the skb->head for hardware DMA].
  */
-#if defined(__i386__) || defined(__x86_64__)
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 #define EFX_PAGE_IP_ALIGN 0
 #else
 #define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
@@ -643,70 +484,100 @@ struct efx_nic;
 
 /* Pseudo bit-mask flow control field */
 enum efx_fc_type {
-       EFX_FC_RX = 1,
-       EFX_FC_TX = 2,
+       EFX_FC_RX = FLOW_CTRL_RX,
+       EFX_FC_TX = FLOW_CTRL_TX,
        EFX_FC_AUTO = 4,
 };
 
+/**
+ * struct efx_link_state - Current state of the link
+ * @up: Link is up
+ * @fd: Link is full-duplex
+ * @fc: Actual flow control flags
+ * @speed: Link speed (Mbps)
+ */
+struct efx_link_state {
+       bool up;
+       bool fd;
+       enum efx_fc_type fc;
+       unsigned int speed;
+};
+
+static inline bool efx_link_state_equal(const struct efx_link_state *left,
+                                       const struct efx_link_state *right)
+{
+       return left->up == right->up && left->fd == right->fd &&
+               left->fc == right->fc && left->speed == right->speed;
+}
+
 /**
  * struct efx_mac_operations - Efx MAC operations table
- * @mac_writel: Write dword to MAC register
- * @mac_readl: Read dword from a MAC register
- * @init: Initialise MAC and PHY
- * @reconfigure: Reconfigure MAC and PHY. Serialised by the mac_lock
+ * @reconfigure: Reconfigure MAC. Serialised by the mac_lock
  * @update_stats: Update statistics
- * @fini: Shut down MAC and PHY
- * @check_hw: Check hardware. Serialised by the mac_lock
- * @fake_phy_event: Simulate a PHY event on a port
- * @get_settings: Get ethtool settings. Serialised by the mac_lock
- * @set_settings: Set ethtool settings. Serialised by the mac_lock
- * @set_pause: Set pause parameters. Serialised by the mac_lock
+ * @check_fault: Check fault state. True if fault present.
  */
 struct efx_mac_operations {
-       void (*mac_writel) (struct efx_nic *efx,
-                           efx_dword_t *value, unsigned int mac_reg);
-       void (*mac_readl) (struct efx_nic *efx,
-                          efx_dword_t *value, unsigned int mac_reg);
-       int (*init) (struct efx_nic *efx);
-       void (*reconfigure) (struct efx_nic *efx);
+       int (*reconfigure) (struct efx_nic *efx);
        void (*update_stats) (struct efx_nic *efx);
-       void (*fini) (struct efx_nic *efx);
-       int (*check_hw) (struct efx_nic *efx);
-       void (*fake_phy_event) (struct efx_nic *efx);
-
-       int (*get_settings) (struct efx_nic *efx,
-                            struct ethtool_cmd *ecmd);
-       int (*set_settings) (struct efx_nic *efx,
-                            struct ethtool_cmd *ecmd);
-       int (*set_pause) (struct efx_nic *efx,
-                         enum efx_fc_type pause_params);
+       bool (*check_fault)(struct efx_nic *efx);
 };
 
 /**
  * struct efx_phy_operations - Efx PHY operations table
+ * @probe: Probe PHY and initialise efx->mdio.mode_support, efx->mdio.mmds,
+ *     efx->loopback_modes.
  * @init: Initialise PHY
  * @fini: Shut down PHY
  * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
- * @clear_interrupt: Clear down interrupt
- * @blink: Blink LEDs
- * @check_hw: Check hardware
- * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
- * @mmds: MMD presence mask
- * @loopbacks: Supported loopback modes mask
- * @startup_loopback: Loopback mode for start-of-day self-test
+ * @poll: Update @link_state and report whether it changed.
+ *     Serialised by the mac_lock.
+ * @get_settings: Get ethtool settings. Serialised by the mac_lock.
+ * @set_settings: Set ethtool settings. Serialised by the mac_lock.
+ * @set_npage_adv: Set abilities advertised in (Extended) Next Page
+ *     (only needed where AN bit is set in mmds)
+ * @test_alive: Test that PHY is 'alive' (online)
+ * @test_name: Get the name of a PHY-specific test/result
+ * @run_tests: Run tests and record results as appropriate (offline).
+ *     Flags are the ethtool tests flags.
  */
 struct efx_phy_operations {
+       int (*probe) (struct efx_nic *efx);
        int (*init) (struct efx_nic *efx);
        void (*fini) (struct efx_nic *efx);
-       void (*reconfigure) (struct efx_nic *efx);
-       void (*clear_interrupt) (struct efx_nic *efx);
-       int (*check_hw) (struct efx_nic *efx);
-       void (*reset_xaui) (struct efx_nic *efx);
-       int mmds;
-       unsigned loopbacks;
-       unsigned startup_loopback;
+       void (*remove) (struct efx_nic *efx);
+       int (*reconfigure) (struct efx_nic *efx);
+       bool (*poll) (struct efx_nic *efx);
+       void (*get_settings) (struct efx_nic *efx,
+                             struct ethtool_cmd *ecmd);
+       int (*set_settings) (struct efx_nic *efx,
+                            struct ethtool_cmd *ecmd);
+       void (*set_npage_adv) (struct efx_nic *efx, u32);
+       int (*test_alive) (struct efx_nic *efx);
+       const char *(*test_name) (struct efx_nic *efx, unsigned int index);
+       int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
+};
+
+/**
+ * @enum efx_phy_mode - PHY operating mode flags
+ * @PHY_MODE_NORMAL: on and should pass traffic
+ * @PHY_MODE_TX_DISABLED: on with TX disabled
+ * @PHY_MODE_LOW_POWER: set to low power through MDIO
+ * @PHY_MODE_OFF: switched off through external control
+ * @PHY_MODE_SPECIAL: on but will not pass traffic
+ */
+enum efx_phy_mode {
+       PHY_MODE_NORMAL         = 0,
+       PHY_MODE_TX_DISABLED    = 1,
+       PHY_MODE_LOW_POWER      = 2,
+       PHY_MODE_OFF            = 4,
+       PHY_MODE_SPECIAL        = 8,
 };
 
+static inline bool efx_phy_mode_disabled(enum efx_phy_mode mode)
+{
+       return !!(mode & ~PHY_MODE_TX_DISABLED);
+}
+
 /*
  * Efx extended statistics
  *
@@ -776,6 +647,15 @@ struct efx_mac_stats {
        unsigned long rx_length_error;
        unsigned long rx_internal_error;
        unsigned long rx_good_lt64;
+       unsigned long rx_char_error_lane0;
+       unsigned long rx_char_error_lane1;
+       unsigned long rx_char_error_lane2;
+       unsigned long rx_char_error_lane3;
+       unsigned long rx_disp_error_lane0;
+       unsigned long rx_disp_error_lane1;
+       unsigned long rx_disp_error_lane2;
+       unsigned long rx_disp_error_lane3;
+       u64 rx_match_fault;
 };
 
 /* Number of bits used in a multicast filter hash address */
@@ -798,56 +678,67 @@ struct efx_nic_errors {
        atomic_t tx_desc_fetch;
        atomic_t spurious_tx;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       struct dentry *debug_dir;
-#endif
 };
 
 /**
  * struct efx_nic - an Efx NIC
  * @name: Device name (net device name or bus id before net device registered)
  * @pci_dev: The PCI device
+ * @revision: Hardware architecture revision
+ * @dl_revision: Revision name for driverlink
  * @type: Controller type attributes
  * @legacy_irq: IRQ number
- * @workqueue: Workqueue for resets, port reconfigures and the HW monitor
+ * @workqueue: Workqueue for port reconfigures and the HW monitor.
+ *     Work items do not hold and must not acquire RTNL.
+ * @workqueue_name: Name of workqueue
  * @reset_work: Scheduled reset workitem
  * @monitor_work: Hardware monitor workitem
  * @membase_phys: Memory BAR value as physical address
  * @membase: Memory BAR value
  * @biu_lock: BIU (bus interface unit) lock
  * @interrupt_mode: Interrupt mode
- * @is_asic: Is ASIC (else FPGA)
- * @is_10g: Is set to 10G (else 1G)
- * @i2c: I2C interface
- * @board_info: Board-level information
+ * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
+ * @irq_rx_moderation: IRQ moderation time for RX event queues
  * @state: Device state flag. Serialised by the rtnl_lock.
  * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
  * @tx_queue: TX DMA queues
  * @rx_queue: RX DMA queues
  * @channel: Channels
- * @rss_queues: Number of RSS queues
+ * @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
+ * @sram_lim: High address limit of SRAM
+ * @resources: Driverlink parameters
+ * @n_rx_queues: Number of RX queues
+ * @n_channels: Number of channels in use
  * @rx_buffer_len: RX buffer length
  * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
  * @errors: Error condition stats
+ * @int_error_count: Number of internal errors seen recently
+ * @int_error_expire: Time at which error count will be expired
  * @irq_status: Interrupt status buffer
  * @last_irq_cpu: Last CPU to handle interrupt.
  *     This register is written with the SMP processor ID whenever an
- *     interrupt is handled.  It is used by falcon_test_interrupt()
+ *     interrupt is handled.  It is used by efx_nic_test_interrupt()
  *     to verify that an interrupt has occurred.
  * @spi_flash: SPI flash device
- *     This field will be %NULL if no flash device is present.
+ *     This field will be %NULL if no flash device is present (or for Siena).
  * @spi_eeprom: SPI EEPROM device
- *     This field will be %NULL if no EEPROM device is present.
+ *     This field will be %NULL if no EEPROM device is present (or for Siena).
  * @spi_lock: SPI bus lock
+ * @mtd_list: List of MTDs attached to the NIC
  * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
  * @nic_data: Hardware dependant state
- * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
- *     efx_reconfigure_port()
+ * @mac_lock: MAC access lock. Protects @port_enabled, @link_up, @phy_mode,
+ *     @port_inhibited, efx_monitor() and efx_mac_work()
+ * @mac_work: Work item for changing MAC promiscuity and multicast hash
  * @port_enabled: Port enabled indicator.
- *     Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
- *     efx_reconfigure_work with kernel interfaces. Safe to read under any
+ *     Serialises efx_stop_all(), efx_start_all(), efx_monitor() and
+ *     efx_mac_work() with kernel interfaces. Safe to read under any
  *     one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
  *     be held to modify it.
+ * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock
  * @port_initialized: Port initialized?
  * @net_dev: Operating system network device. Consider holding the rtnl lock
  * @rx_checksum_enabled: RX checksumming enabled
@@ -857,27 +748,26 @@ struct efx_nic_errors {
  *     can provide.  Generic code converts these into a standard
  *     &struct net_device_stats.
  * @stats_buffer: DMA buffer for statistics
- * @stats_lock: Statistics update lock
+ * @stats_lock: Statistics update lock. Serialises statistics fetches
  * @mac_op: MAC interface
  * @mac_address: Permanent MAC address
  * @phy_type: PHY type
- * @phy_lock: PHY access lock
+ * @mdio_lock: MDIO lock
  * @phy_op: PHY interface
  * @phy_data: PHY private data (including PHY-specific stats)
- * @mii: PHY interface
- * @phy_powered: PHY power state
- * @tx_disabled: PHY transmitter turned off
- * @link_up: Link status
- * @link_options: Link options (MII/GMII format)
+ * @mdio: PHY MDIO interface
+ * @mdio_bus: PHY MDIO bus ID (only used by Siena)
+ * @phy_mode: PHY operating mode. Serialised by @mac_lock.
+ * @xmac_poll_required: XMAC link state needs polling
+ * @link_advertising: Autonegotiation advertising flags
+ * @link_state: Current state of the link
  * @n_link_state_changes: Number of times the link has changed state
  * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
  * @multicast_hash: Multicast hash table
- * @flow_control: Flow control flags - separate RX/TX so can't use link_options
- * @reconfigure_work: work item for dealing with PHY events
+ * @wanted_fc: Wanted flow control flags
  * @loopback_mode: Loopback status
  * @loopback_modes: Supported loopback mode bitmask
  * @loopback_selftest: Offline self-test private state
- * @silicon_rev: Silicon revision description for driverlink
  * @dl_info: Linked list of hardware parameters exposed through driverlink
  * @dl_node: Driverlink port list
  * @dl_device_list: Driverlink device list
@@ -888,157 +778,230 @@ struct efx_nic_errors {
  * @debug_port_dir: Port debugfs directory
  * @debug_port_symlink: Port debugfs sym-link (if_eth\%d)
  *
- * The @priv field of the corresponding &struct net_device points to
- * this.
+ * This is stored in the private area of the &struct net_device.
  */
 struct efx_nic {
        char name[IFNAMSIZ];
        struct pci_dev *pci_dev;
-       u8 revision;
        const struct efx_nic_type *type;
        int legacy_irq;
        struct workqueue_struct *workqueue;
-       /* Since we can't use cancel_delayed_work_sync efx_reset() has to
-        * flush efx->workqueue to serialise against efx_reconfigure_port
-        * and efx_monitor. So it can't also run on workqueue */
-       struct workqueue_struct *reset_workqueue;
+       char workqueue_name[16];
        struct work_struct reset_work;
        struct delayed_work monitor_work;
-       unsigned long membase_phys;
+       resource_size_t membase_phys;
        void __iomem *membase;
        spinlock_t biu_lock;
        enum efx_int_mode interrupt_mode;
-       unsigned int is_asic:1;
-       unsigned int is_10g:1;
-
-       struct efx_i2c_interface i2c;
-       struct efx_board board_info;
+       bool irq_rx_adaptive;
+       unsigned int irq_rx_moderation;
 
        enum nic_state state;
        enum reset_type reset_pending;
 
-       struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
+       struct efx_tx_queue tx_queue[EFX_TX_QUEUE_COUNT];
        struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
        struct efx_channel channel[EFX_MAX_CHANNELS];
 
-       int rss_queues;
+       unsigned tx_dc_entries;
+       unsigned rx_dc_entries;
+       unsigned tx_dc_base;
+       unsigned rx_dc_base;
+       unsigned sram_lim;
+       struct efx_dl_falcon_resources resources;
+
+       int n_rx_queues;
+       int n_channels;
        unsigned int rx_buffer_len;
        unsigned int rx_buffer_order;
 
        struct efx_nic_errors errors;
+       unsigned int_error_count;
+       unsigned long int_error_expire;
 
        struct efx_buffer irq_status;
        volatile signed int last_irq_cpu;
+       unsigned long irq_zero_count;
 
        struct efx_spi_device *spi_flash;
        struct efx_spi_device *spi_eeprom;
        struct mutex spi_lock;
+#ifdef CONFIG_SFC_MTD
+       struct list_head mtd_list;
+#endif
 
        unsigned n_rx_nodesc_drop_cnt;
 
        void *nic_data;
 
        struct mutex mac_lock;
-       int port_enabled;
+       struct work_struct mac_work;
+       bool port_enabled;
+       bool port_inhibited;
 
-       int port_initialized;
+       bool port_initialized;
        struct net_device *net_dev;
-       int rx_checksum_enabled;
-       int lro_enabled;
+       bool rx_checksum_enabled;
+#if defined(EFX_USE_KCOMPAT) && !defined(NETIF_F_LRO)
+       bool lro_enabled;
+#endif
 
        atomic_t netif_stop_count;
        spinlock_t netif_stop_lock;
 
        struct efx_mac_stats mac_stats;
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_NETDEV_STATS)
        struct net_device_stats stats;
+#endif
        struct efx_buffer stats_buffer;
        spinlock_t stats_lock;
 
        struct efx_mac_operations *mac_op;
        unsigned char mac_address[ETH_ALEN];
 
-       enum phy_type phy_type;
-       spinlock_t phy_lock;
+       unsigned int phy_type;
+       char phy_name[20];
+       struct mutex mdio_lock;
        struct efx_phy_operations *phy_op;
        void *phy_data;
-       struct mii_if_info mii;
-       unsigned phy_powered;
-       unsigned tx_disabled;
+       struct mdio_if_info mdio;
+       unsigned int mdio_bus;
+       enum efx_phy_mode phy_mode;
 
-       int link_up;
-       unsigned int link_options;
+       bool xmac_poll_required;
+       u32 link_advertising;
+       struct efx_link_state link_state;
        unsigned int n_link_state_changes;
 
-       int promiscuous;
+       bool promiscuous;
        union efx_multicast_hash multicast_hash;
-       enum efx_fc_type flow_control;
-       struct work_struct reconfigure_work;
+       enum efx_fc_type wanted_fc;
 
        enum efx_loopback_mode loopback_mode;
-       unsigned int loopback_modes;
-       unsigned int startup_loopbacks;
-
+       u64 loopback_modes;
+       unsigned int startup_loopback_mode;
        void *loopback_selftest;
 
-       const char *silicon_rev;
        struct efx_dl_device_info *dl_info;
        struct list_head dl_node;
        struct list_head dl_device_list;
        struct efx_dl_callbacks dl_cb;
        struct efx_dl_cb_devices dl_cb_dev;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       struct dentry *debug_dir;
-       struct dentry *debug_symlink;
-       struct dentry *debug_port_dir;
-       struct dentry *debug_port_symlink;
-#endif
 };
 
+static inline int efx_dev_registered(struct efx_nic *efx)
+{
+       return efx->net_dev->reg_state == NETREG_REGISTERED;
+}
+
+/* Net device name, for inclusion in log messages if it has been registered.
+ * Use efx->name not efx->net_dev->name so that races with (un)registration
+ * are harmless.
+ */
+static inline const char *efx_dev_name(struct efx_nic *efx)
+{
+       return efx_dev_registered(efx) ? efx->name : "";
+}
+
+static inline unsigned int efx_port_num(struct efx_nic *efx)
+{
+       return PCI_FUNC(efx->pci_dev->devfn);
+}
+
+struct efx_nic_register_mask;
+struct efx_nic_table_mask;
+
 /**
  * struct efx_nic_type - Efx device type definition
- * @mem_bar: Memory BAR number
+ * @probe: Probe the controller
+ * @remove: Free resources allocated by probe()
+ * @init: Initialise the controller
+ * @fini: Shut down the controller
+ * @monitor: Periodic function for polling link state and hardware monitor
+ * @reset: Reset the controller hardware and possibly the PHY.  This will
+ *     be called while the controller is uninitialised.
+ * @probe_port: Probe the MAC and PHY
+ * @remove_port: Free resources allocated by probe_port()
+ * @prepare_flush: Prepare the hardware for flushing the DMA queues
+ * @update_stats: Update statistics not provided by event handling
+ * @start_stats: Start the regular fetching of statistics
+ * @stop_stats: Stop the regular fetching of statistics
+ * @set_id_led: Set state of identifying LED or revert to automatic function
+ * @push_irq_moderation: Apply interrupt moderation value
+ * @push_multicast_hash: Apply multicast hash table
+ * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY
+ * @get_wol: Get WoL configuration from driver state
+ * @set_wol: Push WoL configuration to the NIC
+ * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
+ * @test_registers: Test read/write functionality of control registers
+ * @test_memory: Test read/write functionality of memory blocks, using
+ *     the given test pattern generator
+ * @test_nvram: Test validity of NVRAM contents
+ * @default_mac_ops: efx_mac_operations to set at startup
+ * @revision: Hardware architecture revision
+ * @dl_revision: Driverlink revision string
  * @mem_map_size: Memory BAR mapped size
  * @txd_ptr_tbl_base: TX descriptor ring base address
  * @rxd_ptr_tbl_base: RX descriptor ring base address
  * @buf_tbl_base: Buffer table base address
  * @evq_ptr_tbl_base: Event queue pointer table base address
  * @evq_rptr_tbl_base: Event queue read-pointer table base address
- * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
- * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
- * @evq_size: Event queue size (must be a power of two)
  * @max_dma_mask: Maximum possible DMA mask
- * @tx_dma_mask: TX DMA mask
- * @bug5391_mask: Address mask for bug 5391 workaround
- * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
- * @rx_xon_thresh: RX FIFO XON watermark (bytes)
  * @rx_buffer_padding: Padding added to each RX buffer
  * @max_interrupt_mode: Highest capability interrupt mode supported
  *     from &enum efx_init_mode.
  * @phys_addr_channels: Number of channels with physically addressed
  *     descriptors
+ * @resources: Resources to be shared via driverlink (copied and
+ *     updated as efx_nic::resources)
+ * @offload_features: net_device feature flags for protocol offload
+ *     features implemented in hardware
+ * @reset_world_flags: Flags for additional components covered by
+ *     reset method RESET_TYPE_WORLD
  */
 struct efx_nic_type {
-       unsigned int mem_bar;
+       int (*probe)(struct efx_nic *efx);
+       void (*remove)(struct efx_nic *efx);
+       int (*init)(struct efx_nic *efx);
+       void (*fini)(struct efx_nic *efx);
+       void (*monitor)(struct efx_nic *efx);
+       int (*reset)(struct efx_nic *efx, enum reset_type method);
+       int (*probe_port)(struct efx_nic *efx);
+       void (*remove_port)(struct efx_nic *efx);
+       void (*prepare_flush)(struct efx_nic *efx);
+       void (*update_stats)(struct efx_nic *efx);
+       void (*start_stats)(struct efx_nic *efx);
+       void (*stop_stats)(struct efx_nic *efx);
+       void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode);
+       void (*push_irq_moderation)(struct efx_channel *channel);
+       void (*push_multicast_hash)(struct efx_nic *efx);
+       int (*reconfigure_port)(struct efx_nic *efx);
+       void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
+       int (*set_wol)(struct efx_nic *efx, u32 type);
+       void (*resume_wol)(struct efx_nic *efx);
+       int (*test_registers)(struct efx_nic *efx);
+       int (*test_memory)(struct efx_nic *efx,
+                          void (*pattern)(unsigned, efx_qword_t *, int, int),
+                          int a, int b);
+       int (*test_nvram)(struct efx_nic *efx);
+       struct efx_mac_operations *default_mac_ops;
+
+       int revision;
+       const char *dl_revision;
        unsigned int mem_map_size;
        unsigned int txd_ptr_tbl_base;
        unsigned int rxd_ptr_tbl_base;
        unsigned int buf_tbl_base;
        unsigned int evq_ptr_tbl_base;
        unsigned int evq_rptr_tbl_base;
-
-       unsigned int txd_ring_mask;
-       unsigned int rxd_ring_mask;
-       unsigned int evq_size;
-       dma_addr_t max_dma_mask;
-       unsigned int tx_dma_mask;
-       unsigned bug5391_mask;
-
-       int rx_xoff_thresh;
-       int rx_xon_thresh;
+       u64 max_dma_mask;
        unsigned int rx_buffer_padding;
        unsigned int max_interrupt_mode;
        unsigned int phys_addr_channels;
+       struct efx_dl_falcon_resources resources;
+       unsigned long offload_features;
+       u32 reset_world_flags;
 };
 
 /**************************************************************************
@@ -1056,55 +1019,38 @@ struct efx_nic_type {
                        continue;                                       \
                else
 
-/* Iterate over all used channels with interrupts */
-#define efx_for_each_channel_with_interrupt(_channel, _efx)            \
-       for (_channel = &_efx->channel[0];                              \
-            _channel < &_efx->channel[EFX_MAX_CHANNELS];               \
-            _channel++)                                                \
-               if (!(_channel->used_flags && _channel->has_interrupt)) \
-                       continue;                                       \
-               else
-
 /* Iterate over all used TX queues */
 #define efx_for_each_tx_queue(_tx_queue, _efx)                         \
        for (_tx_queue = &_efx->tx_queue[0];                            \
-            _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES];            \
-            _tx_queue++)                                               \
-               if (!_tx_queue->used)                                   \
-                       continue;                                       \
-               else
+            _tx_queue < &_efx->tx_queue[EFX_TX_QUEUE_COUNT];           \
+            _tx_queue++)
 
 /* Iterate over all TX queues belonging to a channel */
 #define efx_for_each_channel_tx_queue(_tx_queue, _channel)             \
        for (_tx_queue = &_channel->efx->tx_queue[0];                   \
-            _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES];   \
+            _tx_queue < &_channel->efx->tx_queue[EFX_TX_QUEUE_COUNT];  \
             _tx_queue++)                                               \
-               if ((!_tx_queue->used) ||                               \
-                   (_tx_queue->channel != _channel))                   \
+               if (_tx_queue->channel != _channel)                     \
                        continue;                                       \
                else
 
 /* Iterate over all used RX queues */
 #define efx_for_each_rx_queue(_rx_queue, _efx)                         \
        for (_rx_queue = &_efx->rx_queue[0];                            \
-            _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES];            \
-            _rx_queue++)                                               \
-               if (!_rx_queue->used)                                   \
-                       continue;                                       \
-               else
+            _rx_queue < &_efx->rx_queue[_efx->n_rx_queues];            \
+            _rx_queue++)
 
 /* Iterate over all RX queues belonging to a channel */
 #define efx_for_each_channel_rx_queue(_rx_queue, _channel)             \
-       for (_rx_queue = &_channel->efx->rx_queue[0];                   \
-            _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES];   \
-            _rx_queue++)                                               \
-               if ((!_rx_queue->used) ||                               \
-                   (_rx_queue->channel != _channel))                   \
+       for (_rx_queue = &_channel->efx->rx_queue[_channel->channel];   \
+            _rx_queue;                                                 \
+            _rx_queue = NULL)                                          \
+               if (_rx_queue->channel != _channel)                     \
                        continue;                                       \
                else
 
 /* Name formats */
-#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel
+#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel
 #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
 #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
 
@@ -1118,13 +1064,13 @@ static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
 }
 
 /* Set bit in a little-endian bitfield */
-static inline void set_bit_le(int nr, unsigned char *addr)
+static inline void set_bit_le(unsigned nr, unsigned char *addr)
 {
        addr[nr / 8] |= (1 << (nr % 8));
 }
 
 /* Clear bit in a little-endian bitfield */
-static inline void clear_bit_le(int nr, unsigned char *addr)
+static inline void clear_bit_le(unsigned nr, unsigned char *addr)
 {
        addr[nr / 8] &= ~(1 << (nr % 8));
 }
@@ -1139,11 +1085,16 @@ static inline void clear_bit_le(int nr, unsigned char *addr)
  * that the net driver will program into the MAC as the maximum frame
  * length.
  *
- * The 10G MAC used in Falcon requires 8-byte alignment on the frame
+ * The 10G MAC requires 8-byte alignment on the frame
  * length, so we round up to the nearest 8.
+ *
+ * Re-clocking by the XGXS on RX can reduce an IPG to 32 bits (half an
+ * XGMII cycle).  If the frame length reaches the maximum value in the
+ * same cycle, the XMAC can miss the IPG altogether.  We work around
+ * this by adding a further 16 bytes.
  */
 #define EFX_MAX_FRAME_LEN(mtu) \
-       ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7)
+       ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */ + 7) & ~7) + 16)
 
 
 #endif /* EFX_NET_DRIVER_H */
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
new file mode 100644 (file)
index 0000000..0c206a7
--- /dev/null
@@ -0,0 +1,1785 @@
+/****************************************************************************
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include "net_driver.h"
+#include "bitfield.h"
+#include "efx.h"
+#include "nic.h"
+#include "regs.h"
+#include "io.h"
+#include "workarounds.h"
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ **************************************************************************
+ */
+
+/* Specify the size of the RX descriptor cache.
+ * Values 16, 32 and 64 are supported (8 won't work).
+ */
+static int rx_desc_cache_size = 64;
+
+/* This is set to 16 for a good reason.  In summary, if larger than
+ * 16, the descriptor cache holds more than a default socket
+ * buffer's worth of packets (for UDP we can only have at most one
+ * socket buffer's worth outstanding).  This combined with the fact
+ * that we only get 1 TX event per descriptor cache means the NIC
+ * goes idle.
+ * 16 gives us up to 256 TXQs on Falcon B in internal-SRAM mode,
+ * and up to 512 on Falcon A.
+ */
+static int tx_desc_cache_size = 16;
+
+
+/* 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
+ */
+int efx_nic_rx_xoff_thresh = -1;
+module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, 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
+ */
+int efx_nic_rx_xon_thresh = -1;
+module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644);
+MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
+
+/* If EFX_MAX_INT_ERRORS internal errors occur within
+ * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
+ * disable it.
+ */
+#define EFX_INT_ERROR_EXPIRE 3600
+#define EFX_MAX_INT_ERRORS 5
+
+/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
+ */
+#define EFX_FLUSH_INTERVAL 10
+#define EFX_FLUSH_POLL_COUNT 100
+
+/* Size and alignment of special buffers (4KB) */
+#define EFX_BUF_SIZE 4096
+
+/* Depth of RX flush request fifo */
+#define EFX_RX_FLUSH_COUNT 4
+
+/**************************************************************************
+ *
+ * Solarstorm hardware access
+ *
+ **************************************************************************/
+
+/* Write to a buffer table entry, locking as appropriate. */
+static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value,
+                                    unsigned int index)
+{
+       efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base,
+                       value, index);
+}
+
+/* Read the current event from the event queue */
+static inline efx_qword_t *efx_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 efx_event_present(efx_qword_t *event)
+{
+       return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
+                 EFX_DWORD_IS_ALL_ONES(event->dword[1])));
+}
+
+static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b,
+                                    const efx_oword_t *mask)
+{
+       return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) ||
+               ((a->u64[1] ^ b->u64[1]) & mask->u64[1]);
+}
+
+int efx_nic_test_registers(struct efx_nic *efx,
+                          const struct efx_nic_register_test *regs,
+                          size_t n_regs)
+{
+       unsigned address = 0, i, j;
+       efx_oword_t mask, imask, original, reg, buf;
+
+       /* Falcon should be in loopback to isolate the XMAC from the PHY */
+       WARN_ON(!LOOPBACK_INTERNAL(efx));
+
+       for (i = 0; i < n_regs; ++i) {
+               address = regs[i].address;
+               mask = imask = regs[i].mask;
+               EFX_INVERT_OWORD(imask);
+
+               efx_reado(efx, &original, address);
+
+               /* bit sweep on and off */
+               for (j = 0; j < 128; j++) {
+                       if (!EFX_EXTRACT_OWORD32(mask, j, j))
+                               continue;
+
+                       /* Test this testable bit can be set in isolation */
+                       EFX_AND_OWORD(reg, original, mask);
+                       EFX_SET_OWORD32(reg, j, j, 1);
+
+                       efx_writeo(efx, &reg, address);
+                       efx_reado(efx, &buf, address);
+
+                       if (efx_masked_compare_oword(&reg, &buf, &mask))
+                               goto fail;
+
+                       /* Test this testable bit can be cleared in isolation */
+                       EFX_OR_OWORD(reg, original, mask);
+                       EFX_SET_OWORD32(reg, j, j, 0);
+
+                       efx_writeo(efx, &reg, address);
+                       efx_reado(efx, &buf, address);
+
+                       if (efx_masked_compare_oword(&reg, &buf, &mask))
+                               goto fail;
+               }
+
+               efx_writeo(efx, &original, address);
+       }
+
+       return 0;
+
+fail:
+       EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT
+               " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg),
+               EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask));
+       return -EIO;
+}
+
+int efx_nic_test_table(struct efx_nic *efx,
+                      const struct efx_nic_table_test *table,
+                      void (*pattern)(unsigned, efx_qword_t *, int, int),
+                      int a, int b)
+{
+       efx_oword_t reg, buf;
+       int index;
+
+       /* write */
+       for (index = 0; index < table->rows; index += table->step) {
+               pattern(2 * index + 0, &reg.qword[0], a, b);
+               pattern(2 * index + 1, &reg.qword[1], a, b);
+               reg.u64[0] &= table->mask.u64[0];
+               reg.u64[1] &= table->mask.u64[1];
+
+               efx_writeo_table(efx, &reg, table->address, index);
+       }
+
+       /* verify */
+       for (index = 0; index < table->rows; index += table->step) {
+               pattern(2 * index + 0, &reg.qword[0], a, b);
+               pattern(2 * index + 1, &reg.qword[1], a, b);
+               reg.u64[0] &= table->mask.u64[0];
+               reg.u64[1] &= table->mask.u64[1];
+
+               efx_reado_table(efx, &buf, table->address, index);
+               if (memcmp(&reg, &buf, sizeof(reg))) {
+                       EFX_ERR(efx, "table test failed at address 0x%x"
+                               " index 0x%x. wrote "EFX_OWORD_FMT
+                               " read "EFX_OWORD_FMT"\n",
+                               table->address, index,
+                               EFX_OWORD_VAL(reg), EFX_OWORD_VAL(buf));
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+/**************************************************************************
+ *
+ * Special buffer handling
+ * Special buffers are used for event queues and the TX and RX
+ * descriptor rings.
+ *
+ *************************************************************************/
+
+/*
+ * Initialise a special buffer
+ *
+ * This will define a buffer (previously allocated via
+ * efx_alloc_special_buffer()) in the buffer table, allowing
+ * it to be used for event queues, descriptor rings etc.
+ */
+static void
+efx_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_3(buf_desc,
+                                    FRF_AZ_BUF_ADR_REGION, 0,
+                                    FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12,
+                                    FRF_AZ_BUF_OWNER_ID_FBUF, 0);
+               efx_write_buf_tbl(efx, &buf_desc, index);
+       }
+}
+
+/* Unmaps a buffer and clears the buffer table entries */
+static void
+efx_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,
+                            FRF_AZ_BUF_UPD_CMD, 0,
+                            FRF_AZ_BUF_CLR_CMD, 1,
+                            FRF_AZ_BUF_CLR_END_ID, end,
+                            FRF_AZ_BUF_CLR_START_ID, start);
+       efx_writeo(efx, &buf_tbl_upd, FR_AZ_BUF_TBL_UPD);
+}
+
+/*
+ * Allocate a new special buffer
+ *
+ * This allocates memory for a new buffer, clears it and allocates a
+ * new buffer ID range.  It does not write into the buffer table.
+ *
+ * This call will allocate 4KB buffers, since 8KB buffers can't be
+ * used for event queues and descriptor rings.
+ */
+static int efx_alloc_special_buffer(struct efx_nic *efx,
+                                   struct efx_special_buffer *buffer,
+                                   unsigned int len)
+{
+       len = ALIGN(len, EFX_BUF_SIZE);
+
+       buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+                                           &buffer->dma_addr);
+       if (!buffer->addr)
+               return -ENOMEM;
+       buffer->len = len;
+       buffer->entries = len / EFX_BUF_SIZE;
+       BUG_ON(buffer->dma_addr & (EFX_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 = efx->resources.buffer_table_min;
+       efx->resources.buffer_table_min += buffer->entries;
+
+       EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
+               "(virt %p phys %llx)\n", buffer->index,
+               buffer->index + buffer->entries - 1,
+               (u64)buffer->dma_addr, len,
+               buffer->addr, (u64)virt_to_phys(buffer->addr));
+
+       return 0;
+}
+
+static void
+efx_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 %llx)\n", buffer->index,
+               buffer->index + buffer->entries - 1,
+               (u64)buffer->dma_addr, buffer->len,
+               buffer->addr, (u64)virt_to_phys(buffer->addr));
+
+       pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
+                           buffer->dma_addr);
+       buffer->addr = NULL;
+       buffer->entries = 0;
+}
+
+/**************************************************************************
+ *
+ * Generic buffer handling
+ * These buffers are used for interrupt status and MAC stats
+ *
+ **************************************************************************/
+
+int efx_nic_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;
+}
+
+void efx_nic_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;
+       }
+}
+
+/**************************************************************************
+ *
+ * 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 *
+efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index)
+{
+       return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
+}
+
+/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */
+static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue)
+{
+       unsigned write_ptr;
+       efx_dword_t reg;
+
+       write_ptr = tx_queue->write_count & EFX_TXQ_MASK;
+       EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr);
+       efx_writed_page(tx_queue->efx, &reg,
+                       FR_AZ_TX_DESC_UPD_DWORD_P0, 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.
+ */
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+void fastcall efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
+#else
+void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
+#endif
+{
+
+       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 & EFX_TXQ_MASK;
+               buffer = &tx_queue->buffer[write_ptr];
+               txd = efx_tx_desc(tx_queue, write_ptr);
+               ++tx_queue->write_count;
+
+               /* Create TX descriptor ring entry */
+               EFX_POPULATE_QWORD_4(*txd,
+                                    FSF_AZ_TX_KER_CONT, buffer->continuation,
+                                    FSF_AZ_TX_KER_BYTE_COUNT, buffer->len,
+                                    FSF_AZ_TX_KER_BUF_REGION, 0,
+                                    FSF_AZ_TX_KER_BUF_ADDR, buffer->dma_addr);
+       } while (tx_queue->write_count != tx_queue->insert_count);
+
+       wmb(); /* Ensure descriptors are written before they are fetched */
+       efx_notify_tx_desc(tx_queue);
+}
+
+/* Allocate hardware resources for a TX queue */
+int efx_nic_probe_tx(struct efx_tx_queue *tx_queue)
+{
+       struct efx_nic *efx = tx_queue->efx;
+       int rc;
+
+       BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 ||
+                    EFX_TXQ_SIZE & EFX_TXQ_MASK);
+       rc = efx_alloc_special_buffer(efx, &tx_queue->txd,
+                                     EFX_TXQ_SIZE * sizeof(efx_qword_t));
+       if (rc)
+               return rc;
+
+       efx->resources.txq_min = max(efx->resources.txq_min,
+                                    (unsigned)tx_queue->queue + 1);
+
+       return 0;
+}
+
+void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
+{
+       efx_oword_t tx_desc_ptr;
+       struct efx_nic *efx = tx_queue->efx;
+
+       tx_queue->flushed = FLUSH_NONE;
+
+       /* Pin TX descriptor ring */
+       efx_init_special_buffer(efx, &tx_queue->txd);
+
+       /* Push TX descriptor ring to card */
+       EFX_POPULATE_OWORD_10(tx_desc_ptr,
+                             FRF_AZ_TX_DESCQ_EN, 1,
+                             FRF_AZ_TX_ISCSI_DDIG_EN, 0,
+                             FRF_AZ_TX_ISCSI_HDIG_EN, 0,
+                             FRF_AZ_TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
+                             FRF_AZ_TX_DESCQ_EVQ_ID,
+                             tx_queue->channel->channel,
+                             FRF_AZ_TX_DESCQ_OWNER_ID, 0,
+                             FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue,
+                             FRF_AZ_TX_DESCQ_SIZE,
+                             __ffs(tx_queue->txd.entries),
+                             FRF_AZ_TX_DESCQ_TYPE, 0,
+                             FRF_BZ_TX_NON_IP_DROP_DIS, 1);
+
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+               int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
+               EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum);
+               EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS,
+                                   !csum);
+       }
+
+       efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+                        tx_queue->queue);
+
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
+               efx_oword_t reg;
+
+               /* Only 128 bits in this register */
+               BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128);
+
+               efx_reado(efx, &reg, FR_AA_TX_CHKSM_CFG);
+               if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM)
+                       clear_bit_le(tx_queue->queue, (void *)&reg);
+               else
+                       set_bit_le(tx_queue->queue, (void *)&reg);
+               efx_writeo(efx, &reg, FR_AA_TX_CHKSM_CFG);
+       }
+}
+
+static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue)
+{
+       struct efx_nic *efx = tx_queue->efx;
+       efx_oword_t tx_flush_descq;
+
+       tx_queue->flushed = FLUSH_PENDING;
+
+       /* Post a flush command */
+       EFX_POPULATE_OWORD_2(tx_flush_descq,
+                            FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
+                            FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue);
+       efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ);
+}
+
+void efx_nic_fini_tx(struct efx_tx_queue *tx_queue)
+{
+       struct efx_nic *efx = tx_queue->efx;
+       efx_oword_t tx_desc_ptr;
+
+       /* The queue should have been flushed */
+       WARN_ON(tx_queue->flushed != FLUSH_DONE);
+
+       /* Remove TX descriptor ring from card */
+       EFX_ZERO_OWORD(tx_desc_ptr);
+       efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+                        tx_queue->queue);
+
+       /* Unpin TX descriptor ring */
+       efx_fini_special_buffer(efx, &tx_queue->txd);
+}
+
+/* Free buffers backing TX queue */
+void efx_nic_remove_tx(struct efx_tx_queue *tx_queue)
+{
+       efx_free_special_buffer(tx_queue->efx, &tx_queue->txd);
+}
+
+/**************************************************************************
+ *
+ * RX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified descriptor in the RX descriptor queue */
+static inline efx_qword_t *
+efx_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 */
+static inline void
+efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index)
+{
+       struct efx_rx_buffer *rx_buf;
+       efx_qword_t *rxd;
+
+       rxd = efx_rx_desc(rx_queue, index);
+       rx_buf = efx_rx_buffer(rx_queue, index);
+       EFX_POPULATE_QWORD_3(*rxd,
+                            FSF_AZ_RX_KER_BUF_SIZE,
+                            rx_buf->len -
+                            rx_queue->efx->type->rx_buffer_padding,
+                            FSF_AZ_RX_KER_BUF_REGION, 0,
+                            FSF_AZ_RX_KER_BUF_ADDR, rx_buf->dma_addr);
+}
+
+/* This writes to the RX_DESC_WPTR register for the specified receive
+ * descriptor ring.
+ */
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+void fastcall efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue)
+#else
+void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue)
+#endif
+{
+       efx_dword_t reg;
+       unsigned write_ptr;
+
+       while (rx_queue->notified_count != rx_queue->added_count) {
+               efx_build_rx_desc(rx_queue,
+                                 rx_queue->notified_count &
+                                 EFX_RXQ_MASK);
+               ++rx_queue->notified_count;
+       }
+
+       wmb();
+       write_ptr = rx_queue->added_count & EFX_RXQ_MASK;
+       EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr);
+       efx_writed_page(rx_queue->efx, &reg,
+                       FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue);
+}
+
+int efx_nic_probe_rx(struct efx_rx_queue *rx_queue)
+{
+       struct efx_nic *efx = rx_queue->efx;
+       int rc;
+
+       BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 ||
+                    EFX_RXQ_SIZE & EFX_RXQ_MASK);
+       rc = efx_alloc_special_buffer(efx, &rx_queue->rxd,
+                                     EFX_RXQ_SIZE * sizeof(efx_qword_t));
+       if (rc)
+               return rc;
+
+       /* Increment the rxq_min counter */
+       efx->resources.rxq_min = max(efx->resources.rxq_min,
+                                    (unsigned)rx_queue->queue + 1);
+
+       return 0;
+}
+
+void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
+{
+       efx_oword_t rx_desc_ptr;
+       struct efx_nic *efx = rx_queue->efx;
+       bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0;
+       bool 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);
+
+       rx_queue->flushed = FLUSH_NONE;
+
+       /* Pin RX descriptor ring */
+       efx_init_special_buffer(efx, &rx_queue->rxd);
+
+       /* Push RX descriptor ring to card */
+       EFX_POPULATE_OWORD_10(rx_desc_ptr,
+                             FRF_AZ_RX_ISCSI_DDIG_EN, iscsi_digest_en,
+                             FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en,
+                             FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
+                             FRF_AZ_RX_DESCQ_EVQ_ID,
+                             rx_queue->channel->channel,
+                             FRF_AZ_RX_DESCQ_OWNER_ID, 0,
+                             FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue,
+                             FRF_AZ_RX_DESCQ_SIZE,
+                             __ffs(rx_queue->rxd.entries),
+                             FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ ,
+                             /* For >=B0 this is scatter so disable */
+                             FRF_AZ_RX_DESCQ_JUMBO, !is_b0,
+                             FRF_AZ_RX_DESCQ_EN, 1);
+       efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+                        rx_queue->queue);
+}
+
+static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue)
+{
+       struct efx_nic *efx = rx_queue->efx;
+       efx_oword_t rx_flush_descq;
+
+       rx_queue->flushed = FLUSH_PENDING;
+
+       /* Post a flush command */
+       EFX_POPULATE_OWORD_2(rx_flush_descq,
+                            FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
+                            FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue);
+       efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ);
+}
+
+void efx_nic_fini_rx(struct efx_rx_queue *rx_queue)
+{
+       efx_oword_t rx_desc_ptr;
+       struct efx_nic *efx = rx_queue->efx;
+
+       /* The queue should already have been flushed */
+       WARN_ON(rx_queue->flushed != FLUSH_DONE);
+
+       /* Remove RX descriptor ring from card */
+       EFX_ZERO_OWORD(rx_desc_ptr);
+       efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+                        rx_queue->queue);
+
+       /* Unpin RX descriptor ring */
+       efx_fini_special_buffer(efx, &rx_queue->rxd);
+}
+
+/* Free buffers backing RX queue */
+void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
+{
+       efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
+}
+
+/**************************************************************************
+ *
+ * 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.
+ */
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+void fastcall efx_nic_eventq_read_ack(struct efx_channel *channel)
+#else
+void efx_nic_eventq_read_ack(struct efx_channel *channel)
+#endif
+{
+       efx_dword_t reg;
+       struct efx_nic *efx = channel->efx;
+
+       EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr);
+       efx_writed_table(efx, &reg, efx->type->evq_rptr_tbl_base,
+                        channel->channel);
+}
+
+/* Use HW to insert a SW defined event */
+void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
+{
+       efx_oword_t drv_ev_reg;
+
+       BUILD_BUG_ON(FRF_AZ_DRV_EV_DATA_LBN != 0 ||
+                    FRF_AZ_DRV_EV_DATA_WIDTH != 64);
+       drv_ev_reg.u32[0] = event->u32[0];
+       drv_ev_reg.u32[1] = event->u32[1];
+       drv_ev_reg.u32[2] = 0;
+       drv_ev_reg.u32[3] = 0;
+       EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel);
+       efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV);
+}
+
+/* Handle a transmit completion event
+ *
+ * The NIC batches TX completion events; the message we receive is of
+ * the form "complete all TX events up to this index".
+ */
+static void
+efx_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, FSF_AZ_TX_EV_COMP))) {
+               /* Transmit completion */
+               tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR);
+               tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
+               tx_queue = &efx->tx_queue[tx_ev_q_label];
+               channel->irq_mod_score +=
+                       (tx_ev_desc_ptr - tx_queue->read_count) &
+                       EFX_TXQ_MASK;
+               efx_xmit_done(tx_queue, tx_ev_desc_ptr);
+       } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) {
+               /* Rewrite the FIFO write pointer */
+               tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
+               tx_queue = &efx->tx_queue[tx_ev_q_label];
+
+               if (efx_dev_registered(efx))
+                       netif_tx_lock(efx->net_dev);
+               efx_notify_tx_desc(tx_queue);
+               if (efx_dev_registered(efx))
+                       netif_tx_unlock(efx->net_dev);
+       } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) &&
+                  EFX_WORKAROUND_10727(efx)) {
+               EFX_ERR(efx, "TX DMA Q reports TX_EV_PKT_ERR.\n");
+               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));
+       }
+}
+
+/* Detect errors included in the rx_evt_pkt_ok bit. */
+static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
+                                const efx_qword_t *event,
+                                bool *rx_ev_pkt_ok,
+                                bool *discard)
+{
+       struct efx_nic *efx = rx_queue->efx;
+       bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+       bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
+       bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
+       bool rx_ev_other_err, rx_ev_pause_frm;
+       bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+       unsigned rx_ev_pkt_type;
+
+       rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
+       rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT);
+       rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC);
+       rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE);
+       rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
+                                                FSF_AZ_RX_EV_BUF_OWNER_ID_ERR);
+       rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_IP_FRAG_ERR);
+       rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
+                                                 FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR);
+       rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
+                                                  FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR);
+       rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR);
+       rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC);
+       rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ?
+                         0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB));
+       rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_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);
+
+       /* Count errors that are not in MAC stats.  Ignore expected
+        * checksum errors during self-test. */
+       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 (!efx->loopback_selftest) {
+               if (rx_ev_eth_crc_err)
+                       ++rx_queue->channel->n_rx_eth_crc_err;
+               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;
+
+       /* 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\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]" : "");
+       }
+#endif
+}
+
+/* Handle receive events that are not in-order. */
+static void
+efx_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 & EFX_RXQ_MASK;
+       dropped = (index - expected) & EFX_RXQ_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
+ *
+ * The NIC 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 void
+efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
+{
+       unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt;
+       unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt;
+       unsigned expected_ptr;
+       bool rx_ev_pkt_ok, discard = false, checksummed;
+       struct efx_rx_queue *rx_queue;
+       struct efx_nic *efx = channel->efx;
+
+       /* Basic packet information */
+       rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
+       rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK);
+       rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
+       WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT));
+       WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1);
+       WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) !=
+               channel->channel);
+
+       rx_queue = &efx->rx_queue[channel->channel];
+
+       rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR);
+       expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK;
+       if (unlikely(rx_ev_desc_ptr != expected_ptr))
+               efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
+
+       if (likely(rx_ev_pkt_ok)) {
+               /* If packet is marked as OK and packet type is TCP/IP or
+                * UDP/IP, then we can rely on the hardware checksum.
+                */
+               checksummed =
+                       likely(efx->rx_checksum_enabled) &&
+                       (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP ||
+                        rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP);
+       } else {
+               efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard);
+               checksummed = false;
+       }
+
+       /* Detect multicast packets that didn't match the filter */
+       rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT);
+       if (rx_ev_mcast_pkt) {
+               unsigned int rx_ev_mcast_hash_match =
+                       EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH);
+
+               if (unlikely(!rx_ev_mcast_hash_match)) {
+                       ++channel->n_rx_mcast_mismatch;
+                       discard = true;
+               }
+       }
+
+       channel->irq_mod_score += 2;
+
+       /* Handle received packet */
+       efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
+                     checksummed, discard);
+}
+
+/* Global events are basically PHY events */
+static void
+efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
+{
+       struct efx_nic *efx = channel->efx;
+       bool handled = false;
+
+       if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
+           EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
+           EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
+               /* Ignored */
+               handled = true;
+       }
+
+       if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) &&
+           EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
+               efx->xmac_poll_required = true;
+               handled = true;
+       }
+
+       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
+           EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
+           EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_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 = true;
+       }
+
+       if (!handled)
+               EFX_ERR(efx, "channel %d unknown global event "
+                       EFX_QWORD_FMT "\n", channel->channel,
+                       EFX_QWORD_VAL(*event));
+}
+
+static void
+efx_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, FSF_AZ_DRIVER_EV_SUBCODE);
+       ev_sub_data = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
+
+       switch (ev_sub_code) {
+       case FSE_AZ_TX_DESCQ_FLS_DONE_EV:
+               EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
+                         channel->channel, ev_sub_data);
+               EFX_DL_CALLBACK(efx, event, event);
+               break;
+       case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
+               EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
+                         channel->channel, ev_sub_data);
+               EFX_DL_CALLBACK(efx, event, event);
+               break;
+       case FSE_AZ_EVQ_INIT_DONE_EV:
+               EFX_LOG(efx, "channel %d EVQ %d initialised\n",
+                       channel->channel, ev_sub_data);
+               break;
+       case FSE_AZ_SRM_UPD_DONE_EV:
+               EFX_TRACE(efx, "channel %d SRAM update done\n",
+                         channel->channel);
+               EFX_DL_CALLBACK(efx, event, event);
+               break;
+       case FSE_AZ_WAKE_UP_EV:
+               EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
+                         channel->channel, ev_sub_data);
+               EFX_DL_CALLBACK(efx, event, event);
+               break;
+       case FSE_AZ_TIMER_EV:
+               EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
+                         channel->channel, ev_sub_data);
+               EFX_DL_CALLBACK(efx, event, event);
+               break;
+       case FSE_AA_RX_RECOVER_EV:
+               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 FSE_BZ_RX_DSC_ERROR_EV:
+               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 FSE_BZ_TX_DSC_ERROR_EV:
+               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;
+       }
+}
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+int fastcall efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
+#else
+int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
+#endif
+{
+       unsigned int read_ptr;
+       efx_qword_t event, *p_event;
+       int ev_code;
+       int rx_packets = 0;
+
+       read_ptr = channel->eventq_read_ptr;
+
+       do {
+               p_event = efx_event(channel, read_ptr);
+               event = *p_event;
+
+               if (!efx_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, FSF_AZ_EV_CODE);
+
+               switch (ev_code) {
+               case FSE_AZ_EV_CODE_RX_EV:
+                       efx_handle_rx_event(channel, &event);
+                       ++rx_packets;
+                       break;
+               case FSE_AZ_EV_CODE_TX_EV:
+                       efx_handle_tx_event(channel, &event);
+                       break;
+               case FSE_AZ_EV_CODE_DRV_GEN_EV:
+                       channel->eventq_magic = EFX_QWORD_FIELD(
+                               event, FSF_AZ_DRV_GEN_EV_MAGIC);
+                       EFX_LOG(channel->efx, "channel %d received generated "
+                               "event "EFX_QWORD_FMT"\n", channel->channel,
+                               EFX_QWORD_VAL(event));
+                       break;
+               case FSE_AZ_EV_CODE_GLOBAL_EV:
+                       efx_handle_global_event(channel, &event);
+                       break;
+               case FSE_AZ_EV_CODE_DRIVER_EV:
+                       efx_handle_driver_event(channel, &event);
+                       break;
+               case FSE_CZ_EV_CODE_MCDI_EV:
+                       efx_mcdi_process_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) & EFX_EVQ_MASK;
+
+       } while (rx_packets < rx_quota);
+
+       channel->eventq_read_ptr = read_ptr;
+       return rx_packets;
+}
+
+
+/* Allocate buffer table entries for event queue */
+int efx_nic_probe_eventq(struct efx_channel *channel)
+{
+       struct efx_nic *efx = channel->efx;
+       int rc;
+
+       BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 ||
+                    EFX_EVQ_SIZE & EFX_EVQ_MASK);
+       rc = efx_alloc_special_buffer(efx, &channel->eventq,
+                                     EFX_EVQ_SIZE * sizeof(efx_qword_t));
+       if (rc)
+               return rc;
+
+       efx->resources.evq_int_min = max(efx->resources.evq_int_min,
+                                        (unsigned)channel->channel + 1);
+
+       return 0;
+}
+
+void efx_nic_init_eventq(struct efx_channel *channel)
+{
+       efx_oword_t reg;
+       struct efx_nic *efx = channel->efx;
+
+       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);
+
+       if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
+               EFX_POPULATE_OWORD_3(reg,
+                                    FRF_CZ_TIMER_Q_EN, 1,
+                                    FRF_CZ_HOST_NOTIFY_MODE, 0,
+                                    FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS);
+               efx_writeo_table(efx, &reg, FR_BZ_TIMER_TBL, channel->channel);
+       }
+
+       /* Pin event queue buffer */
+       efx_init_special_buffer(efx, &channel->eventq);
+
+       /* 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(reg,
+                            FRF_AZ_EVQ_EN, 1,
+                            FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries),
+                            FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index);
+       efx_writeo_table(efx, &reg, efx->type->evq_ptr_tbl_base,
+                        channel->channel);
+
+       efx->type->push_irq_moderation(channel);
+}
+
+void efx_nic_fini_eventq(struct efx_channel *channel)
+{
+       efx_oword_t reg;
+       struct efx_nic *efx = channel->efx;
+
+       /* Remove event queue from card */
+       EFX_ZERO_OWORD(reg);
+       efx_writeo_table(efx, &reg, efx->type->evq_ptr_tbl_base,
+                        channel->channel);
+       if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
+               efx_writeo_table(efx, &reg, FR_BZ_TIMER_TBL, channel->channel);
+
+       /* Unpin event queue */
+       efx_fini_special_buffer(efx, &channel->eventq);
+}
+
+/* Free buffers backing event queue */
+void efx_nic_remove_eventq(struct efx_channel *channel)
+{
+       efx_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 efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic)
+{
+       efx_qword_t test_event;
+
+       EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
+                            FSE_AZ_EV_CODE_DRV_GEN_EV,
+                            FSF_AZ_DRV_GEN_EV_MAGIC, magic);
+       efx_generate_event(channel, &test_event);
+}
+
+/**************************************************************************
+ *
+ * Flush handling
+ *
+ **************************************************************************/
+
+
+static void efx_poll_flush_events(struct efx_nic *efx)
+{
+       struct efx_channel *channel = &efx->channel[0];
+       struct efx_tx_queue *tx_queue;
+       struct efx_rx_queue *rx_queue;
+       unsigned int read_ptr = channel->eventq_read_ptr;
+       unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK;
+
+       do {
+               efx_qword_t *event = efx_event(channel, read_ptr);
+               int ev_code, ev_sub_code, ev_queue;
+               bool ev_failed;
+
+               if (!efx_event_present(event))
+                       break;
+
+               ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE);
+               ev_sub_code = EFX_QWORD_FIELD(*event,
+                                             FSF_AZ_DRIVER_EV_SUBCODE);
+               if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
+                   ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) {
+                       ev_queue = EFX_QWORD_FIELD(*event,
+                                                  FSF_AZ_DRIVER_EV_SUBDATA);
+                       if (ev_queue < EFX_TX_QUEUE_COUNT) {
+                               tx_queue = efx->tx_queue + ev_queue;
+                               tx_queue->flushed = FLUSH_DONE;
+                       }
+               } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
+                          ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) {
+                       ev_queue = EFX_QWORD_FIELD(
+                               *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
+                       ev_failed = EFX_QWORD_FIELD(
+                               *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
+                       if (ev_queue < efx->n_rx_queues) {
+                               rx_queue = efx->rx_queue + ev_queue;
+                               rx_queue->flushed =
+                                       ev_failed ? FLUSH_FAILED : FLUSH_DONE;
+                       }
+               }
+
+               /* We're about to destroy the queue anyway, so
+                * it's ok to throw away every non-flush event */
+               EFX_SET_QWORD(*event);
+
+               read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
+       } while (read_ptr != end_ptr);
+
+       channel->eventq_read_ptr = read_ptr;
+}
+
+/* Handle tx and rx flushes at the same time, since they run in
+ * parallel in the hardware and there's no reason for us to
+ * serialise them */
+int efx_nic_flush_queues(struct efx_nic *efx)
+{
+       struct efx_rx_queue *rx_queue;
+       struct efx_tx_queue *tx_queue;
+       int i, tx_pending, rx_pending;
+
+       /* If necessary prepare the hardware for flushing */
+       efx->type->prepare_flush(efx);
+
+       /* Flush all tx queues in parallel */
+       efx_for_each_tx_queue(tx_queue, efx)
+               efx_flush_tx_queue(tx_queue);
+
+       /* The hardware supports four concurrent rx flushes, each of which may
+        * need to be retried if there is an outstanding descriptor fetch */
+       for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) {
+               rx_pending = tx_pending = 0;
+               efx_for_each_rx_queue(rx_queue, efx) {
+                       if (rx_queue->flushed == FLUSH_PENDING)
+                               ++rx_pending;
+               }
+               efx_for_each_rx_queue(rx_queue, efx) {
+                       if (rx_pending == EFX_RX_FLUSH_COUNT)
+                               break;
+                       if (rx_queue->flushed == FLUSH_FAILED ||
+                           rx_queue->flushed == FLUSH_NONE) {
+                               efx_flush_rx_queue(rx_queue);
+                               ++rx_pending;
+                       }
+               }
+               efx_for_each_tx_queue(tx_queue, efx) {
+                       if (tx_queue->flushed != FLUSH_DONE)
+                               ++tx_pending;
+               }
+
+               if (rx_pending == 0 && tx_pending == 0)
+                       return 0;
+
+               msleep(EFX_FLUSH_INTERVAL);
+               efx_poll_flush_events(efx);
+       }
+
+       /* Mark the queues as all flushed. We're going to return failure
+        * leading to a reset, or fake up success anyway */
+       efx_for_each_tx_queue(tx_queue, efx) {
+               if (tx_queue->flushed != FLUSH_DONE)
+                       EFX_ERR(efx, "tx queue %d flush command timed out\n",
+                               tx_queue->queue);
+               tx_queue->flushed = FLUSH_DONE;
+       }
+       efx_for_each_rx_queue(rx_queue, efx) {
+               if (rx_queue->flushed != FLUSH_DONE)
+                       EFX_ERR(efx, "rx queue %d flush command timed out\n",
+                               rx_queue->queue);
+               rx_queue->flushed = FLUSH_DONE;
+       }
+
+       if (EFX_WORKAROUND_7803(efx))
+               return 0;
+
+       return -ETIMEDOUT;
+}
+
+/**************************************************************************
+ *
+ * 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 interrupts */
+static inline void efx_nic_interrupts(struct efx_nic *efx,
+                                     bool enabled, bool force)
+{
+       efx_oword_t int_en_reg_ker;
+       unsigned int level = 0;
+
+       if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx))
+               /* Set the level always even if we're generating a test
+                * interrupt, because our legacy interrupt handler is safe */
+               level = 0x1f;
+
+       EFX_POPULATE_OWORD_3(int_en_reg_ker,
+                            FRF_AZ_KER_INT_LEVE_SEL, level,
+                            FRF_AZ_KER_INT_KER, force,
+                            FRF_AZ_DRV_INT_EN_KER, enabled);
+       efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
+}
+
+void efx_nic_enable_interrupts(struct efx_nic *efx)
+{
+       struct efx_channel *channel;
+
+       EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
+       wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
+
+       /* Enable interrupts */
+       efx_nic_interrupts(efx, true, false);
+
+       /* Force processing of all the channels to get the EVQ RPTRs up to
+          date */
+       efx_for_each_channel(channel, efx)
+               efx_schedule_channel(channel);
+}
+
+void efx_nic_disable_interrupts(struct efx_nic *efx)
+{
+       /* Disable interrupts */
+       efx_nic_interrupts(efx, false, false);
+}
+
+/* Generate a test interrupt
+ * Interrupt must already have been enabled, otherwise nasty things
+ * may happen.
+ */
+void efx_nic_generate_interrupt(struct efx_nic *efx)
+{
+       efx_nic_interrupts(efx, true, true);
+}
+
+/* Process a fatal interrupt
+ * Disable bus mastering ASAP and schedule a reset
+ */
+irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       efx_oword_t *int_ker = efx->irq_status.addr;
+       efx_oword_t fatal_intr;
+       int error, mem_perr;
+
+       efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER);
+       error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR);
+
+       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, FRF_AZ_MEM_PERR_INT_KER);
+       if (mem_perr) {
+               efx_oword_t reg;
+               efx_reado(efx, &reg, FR_AZ_MEM_STAT);
+               EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
+                       EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
+       }
+
+       /* Disable both devices */
+       pci_clear_master(efx->pci_dev);
+       if (efx_nic_is_dual_func(efx))
+               pci_clear_master(nic_data->pci_dev2);
+       efx_nic_disable_interrupts(efx);
+
+       /* Count errors and reset or disable the NIC accordingly */
+       if (efx->int_error_count == 0 ||
+           time_after(jiffies, efx->int_error_expire)) {
+               efx->int_error_count = 0;
+               efx->int_error_expire =
+                       jiffies + EFX_INT_ERROR_EXPIRE * HZ;
+       }
+       if (++efx->int_error_count < EFX_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
+ * 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().
+ */
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_IRQ_HANDLER_REGS)
+static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
+#else
+static irqreturn_t efx_legacy_interrupt(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;
+       irqreturn_t result = IRQ_NONE;
+       struct efx_channel *channel;
+       efx_dword_t reg;
+       u32 queues;
+       int syserr;
+
+       /* Read the ISR which also ACKs the interrupts */
+       efx_readd(efx, &reg, FR_BZ_INT_ISR0);
+       queues = EFX_EXTRACT_DWORD(reg, 0, 31);
+
+       /* Check to see if we have a serious error condition */
+       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
+       if (unlikely(syserr))
+               return efx_nic_fatal_interrupt(efx);
+
+       if (queues != 0) {
+               if (EFX_WORKAROUND_15783(efx))
+                       efx->irq_zero_count = 0;
+
+               /* Schedule processing of any interrupting queues */
+               efx_for_each_channel(channel, efx) {
+                       if (queues & 1)
+                               efx_schedule_channel(channel);
+                       queues >>= 1;
+               }
+               result = IRQ_HANDLED;
+
+       } else if (EFX_WORKAROUND_15783(efx) &&
+                  efx->irq_zero_count++ == 0) {
+               efx_qword_t *event;
+
+               /* Ensure we rearm all event queues */
+               efx_for_each_channel(channel, efx) {
+                       event = efx_event(channel, channel->eventq_read_ptr);
+                       if (efx_event_present(event))
+                               efx_schedule_channel(channel);
+               }
+
+               result = IRQ_HANDLED;
+       }
+
+       if (result == IRQ_HANDLED) {
+               efx->last_irq_cpu = raw_smp_processor_id();
+               EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+                         irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+       } else if (EFX_WORKAROUND_15783(efx)){
+               /* We can't return IRQ_HANDLED more than once on seeing ISR0=0
+                * because this might be a shared interrupt, but we do need to
+                * check the channel every time and preemptively rearm it if
+                * it's idle. */
+               efx_for_each_channel(channel, efx) {
+                       if (!channel->work_pending)
+                               efx_nic_eventq_read_ack(channel);
+               }
+       }
+
+       return result;
+}
+
+/* Handle an MSI interrupt
+ *
+ * Handle an MSI hardware interrupt.  This routine schedules event
+ * queue processing.  No interrupt acknowledgement cycle is necessary.
+ * Also, we never need to check that the interrupt is for us, since
+ * MSI interrupts cannot be shared.
+ *
+ * This routine must guarantee not to touch the hardware when
+ * interrupts are disabled, to allow for correct semantics of
+ * efx_suspend() and efx_resume().
+ */
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_IRQ_HANDLER_REGS)
+static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
+#else
+static irqreturn_t efx_msi_interrupt(int irq, void *dev_id,
+                                    struct pt_regs *regs
+                                    __attribute__ ((unused)))
+#endif
+{
+       struct efx_channel *channel = dev_id;
+       struct efx_nic *efx = channel->efx;
+       efx_oword_t *int_ker = efx->irq_status.addr;
+       int syserr;
+
+       efx->last_irq_cpu = raw_smp_processor_id();
+       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+                 irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+       /* Check to see if we have a serious error condition */
+       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
+       if (unlikely(syserr))
+               return efx_nic_fatal_interrupt(efx);
+
+       /* Schedule processing of the channel */
+       efx_schedule_channel(channel);
+
+       return IRQ_HANDLED;
+}
+
+/* Setup RSS indirection table.
+ * This maps from the hash value of the packet to RXQ
+ */
+static void efx_setup_rss_indir_table(struct efx_nic *efx)
+{
+       int i = 0;
+       unsigned long offset;
+       efx_dword_t dword;
+
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
+               return;
+
+       for (offset = FR_BZ_RX_INDIRECTION_TBL;
+            offset < FR_BZ_RX_INDIRECTION_TBL + 0x800;
+            offset += 0x10) {
+               EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
+                                    i % efx->n_rx_queues);
+               efx_writed(efx, &dword, offset);
+               i++;
+       }
+}
+
+/* Hook interrupt handler(s)
+ * Try MSI and then legacy interrupts.
+ */
+int efx_nic_init_interrupt(struct efx_nic *efx)
+{
+       struct efx_channel *channel;
+       int rc;
+
+       if (!EFX_INT_MODE_USE_MSI(efx)) {
+               irq_handler_t handler;
+               if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+                       handler = efx_legacy_interrupt;
+               else
+                       handler = falcon_legacy_interrupt_a1;
+
+               rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
+                                efx->name, efx);
+               if (rc) {
+                       EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
+                               efx->pci_dev->irq);
+                       goto fail1;
+               }
+               return 0;
+       }
+
+       /* Hook MSI or MSI-X interrupt */
+       efx_for_each_channel(channel, efx) {
+               rc = request_irq(channel->irq, efx_msi_interrupt,
+                                IRQF_PROBE_SHARED, /* Not shared */
+                                channel->name, channel);
+               if (rc) {
+                       EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
+                       goto fail2;
+               }
+       }
+
+       return 0;
+
+ fail2:
+       efx_for_each_channel(channel, efx)
+               free_irq(channel->irq, channel);
+ fail1:
+       return rc;
+}
+
+void efx_nic_fini_interrupt(struct efx_nic *efx)
+{
+       struct efx_channel *channel;
+       efx_oword_t reg;
+
+       /* Disable MSI/MSI-X interrupts */
+       efx_for_each_channel(channel, efx) {
+               if (channel->irq)
+                       free_irq(channel->irq, channel);
+       }
+
+       /* ACK legacy interrupt */
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+               efx_reado(efx, &reg, FR_BZ_INT_ISR0);
+       else
+               falcon_irq_ack_a1(efx);
+
+       /* Disable legacy interrupt */
+       if (efx->legacy_irq)
+               free_irq(efx->legacy_irq, efx);
+}
+
+/* Looks at available SRAM resources and works out how many queues we
+ * can support, and where things like descriptor caches should live. */
+/* TODO: Improve the allocation heuristic and remove the buffers_per_vnic
+ * parameter */
+int efx_nic_dimension_resources(struct efx_nic *efx, size_t sram_size,
+                               unsigned buffers_per_vnic)
+{
+       struct efx_dl_falcon_resources *res = &efx->resources;
+       unsigned dcs, vnic_bytes, max_vnics, n_vnics;
+
+       efx->sram_lim = sram_size;
+
+       efx->rx_dc_entries = rx_desc_cache_size;
+
+       efx->tx_dc_entries = tx_desc_cache_size;
+
+       /* Buffer table space for evqs and dmaqs is relatively
+        * trivial, so not considered in this calculation. */
+       vnic_bytes = (buffers_per_vnic
+                     + efx->rx_dc_entries
+                     + efx->tx_dc_entries) * 8;
+       max_vnics = res->evq_timer_min + sram_size / vnic_bytes;
+       for (n_vnics = 1; (n_vnics * 2) < max_vnics; n_vnics *= 2)
+               ;
+       if (!WARN_ON(n_vnics > res->rxq_lim))
+               res->rxq_lim = n_vnics;
+       if (!WARN_ON(n_vnics > res->txq_lim))
+               res->txq_lim = n_vnics;
+
+       dcs = n_vnics * efx->tx_dc_entries * 8;
+       efx->tx_dc_base = sram_size - dcs;
+       dcs = n_vnics * efx->rx_dc_entries * 8;
+       efx->rx_dc_base = efx->tx_dc_base - dcs;
+       res->buffer_table_lim = efx->rx_dc_base / 8;
+
+       EFX_LOG(efx, "Available resources: %u RXQs, %u TXQs,"
+               " %u buffer table entries\n",
+               res->rxq_lim, res->txq_lim, res->buffer_table_lim);
+
+       return 0;
+}
+
+u32 efx_nic_fpga_ver(struct efx_nic *efx)
+{
+       efx_oword_t altera_build;
+       efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD);
+       return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER);
+}
+
+void efx_nic_init_common(struct efx_nic *efx)
+{
+       efx_oword_t temp;
+
+       /* Set positions of descriptor caches in SRAM. */
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR,
+                            efx->tx_dc_base / 8);
+       efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG);
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR,
+                            efx->rx_dc_base / 8);
+       efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG);
+
+       /* Set TX descriptor cache size. */
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_TX_DC_SIZE,
+                            ffs(efx->tx_dc_entries) - 4);
+       efx_writeo(efx, &temp, FR_AZ_TX_DC_CFG);
+
+       /* Set RX descriptor cache size.  Set low watermark to size-8, as
+        * this allows most efficient prefetching.
+        */
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_SIZE,
+                            ffs(efx->rx_dc_entries) - 4);
+       efx_writeo(efx, &temp, FR_AZ_RX_DC_CFG);
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM,
+                            efx->rx_dc_entries - 8);
+       efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM);
+
+       /* Program INT_KER address */
+       EFX_POPULATE_OWORD_2(temp,
+                            FRF_AZ_NORM_INT_VEC_DIS_KER,
+                            EFX_INT_MODE_USE_MSI(efx),
+                            FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
+       efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER);
+
+       /* Enable all the genuinely fatal interrupts.  (They are still
+        * masked by the overall interrupt mask, controlled by
+        * falcon_interrupts()).
+        *
+        * Note: All other fatal interrupts are enabled
+        */
+       EFX_POPULATE_OWORD_3(temp,
+                            FRF_AZ_ILL_ADR_INT_KER_EN, 1,
+                            FRF_AZ_RBUF_OWN_INT_KER_EN, 1,
+                            FRF_AZ_TBUF_OWN_INT_KER_EN, 1);
+       EFX_INVERT_OWORD(temp);
+       efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER);
+
+       efx_setup_rss_indir_table(efx);
+
+       /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
+        * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
+        */
+       efx_reado(efx, &temp, FR_AZ_TX_RESERVED);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1);
+       /* Enable SW_EV to inherit in char driver - assume harmless here */
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1);
+       /* Prefetch threshold 2 => fetch when descriptor cache half empty */
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
+       /* Disable hardware watchdog which can misfire */
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff);
+       /* Squash TX of packets of 16 bytes or less */
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
+               EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
+       efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
+}
+
+unsigned
+efx_nic_check_pcie_link(struct efx_nic *efx,
+                       unsigned full_width, unsigned full_speed)
+{
+       int cap = pci_find_capability(efx->pci_dev, PCI_CAP_ID_EXP);
+       u16 stat;
+       unsigned width, speed;
+
+       if (!cap ||
+           pci_read_config_word(efx->pci_dev, cap + PCI_EXP_LNKSTA, &stat))
+               return 0;
+
+       width = (stat & PCI_EXP_LNKSTA_NLW) >> __ffs(PCI_EXP_LNKSTA_NLW);
+       EFX_WARN_ON_PARANOID(width == 0 || width > full_width);
+       speed = stat & PCI_EXP_LNKSTA_CLS;
+       EFX_WARN_ON_PARANOID(speed == 0 || speed > full_speed);
+
+       if (width < full_width || speed < full_speed)
+
+               EFX_ERR(efx, "This Solarflare Network Adapter requires a "
+                       "slot with %d lanes at PCI Express %d speed for "
+                       "full performance, but is currently limited to "
+                       "%d lanes at PCI Express %d speed. Consult your "
+                       "motherboard documentation to find a more "
+                       "suitable slot\n",
+                       full_width, full_speed, width, speed);
+
+       return width;
+}
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
new file mode 100644 (file)
index 0000000..2dc8fba
--- /dev/null
@@ -0,0 +1,307 @@
+/****************************************************************************
+ * 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.
+ */
+
+#ifndef EFX_NIC_H
+#define EFX_NIC_H
+
+#include <linux/i2c-algo-bit.h>
+#include <linux/timer.h>
+
+#include "net_driver.h"
+#include "efx.h"
+#include "mcdi.h"
+
+/*
+ * Falcon hardware control
+ */
+
+enum {
+       EFX_REV_FALCON_A0 = 0,
+       EFX_REV_FALCON_A1 = 1,
+       EFX_REV_FALCON_B0 = 2,
+       EFX_REV_SIENA_A0 = 3,
+};
+
+static inline int efx_nic_rev(struct efx_nic *efx)
+{
+       return efx->type->revision;
+}
+
+extern u32 efx_nic_fpga_ver(struct efx_nic *efx);
+
+static inline bool efx_nic_has_mc(struct efx_nic *efx)
+{
+       return efx_nic_rev(efx) >= EFX_REV_SIENA_A0;
+}
+/* NIC has two interlinked PCI functions for the same port. */
+static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
+{
+       return efx_nic_rev(efx) < EFX_REV_FALCON_B0;
+}
+
+enum {
+       PHY_TYPE_NONE = 0,
+       PHY_TYPE_TXC43128 = 1,
+       PHY_TYPE_88E1111 = 2,
+       PHY_TYPE_SFX7101 = 3,
+       PHY_TYPE_QT2022C2 = 4,
+       PHY_TYPE_PM8358 = 6,
+       PHY_TYPE_SFT9001A = 8,
+       PHY_TYPE_QT2025C = 9,
+       PHY_TYPE_SFT9001B = 10,
+};
+
+#define FALCON_XMAC_LOOPBACKS                  \
+       ((1 << LOOPBACK_XGMII) |                \
+        (1 << LOOPBACK_XGXS) |                 \
+        (1 << LOOPBACK_XAUI))
+
+#define FALCON_GMAC_LOOPBACKS                  \
+       (1 << LOOPBACK_GMAC)
+
+/**
+ * struct falcon_board_type - board operations and type information
+ * @id: Board type id, as found in NVRAM
+ * @mwatts: Power requirements (mW)
+ * @ref_model: Model number of Solarflare reference design
+ * @gen_type: Generic board type description
+ * @init: Allocate resources and initialise peripheral hardware
+ * @init_phy: Do board-specific PHY initialisation
+ * @fini: Shut down hardware and free resources
+ * @set_id_led: Set state of identifying LED or revert to automatic function
+ * @monitor: Board-specific health check function
+ */
+struct falcon_board_type {
+       u8 id;
+       unsigned mwatts;
+       const char *ref_model;
+       const char *gen_type;
+       int (*init) (struct efx_nic *nic);
+       void (*init_phy) (struct efx_nic *efx);
+       void (*fini) (struct efx_nic *nic);
+       void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode);
+       int (*monitor) (struct efx_nic *nic);
+};
+
+/**
+ * struct falcon_board - board information
+ * @type: Type of board
+ * @major: Major rev. ('A', 'B' ...)
+ * @minor: Minor rev. (0, 1, ...)
+ * @i2c_adap: I2C adapter for on-board peripherals
+ * @i2c_data: Data for bit-banging algorithm
+ * @hwmon_client: I2C client for hardware monitor
+ * @ioexp_client: I2C client for power/port control
+ */
+struct falcon_board {
+       const struct falcon_board_type *type;
+       int major;
+       int minor;
+       struct i2c_adapter i2c_adap;
+       struct i2c_algo_bit_data i2c_data;
+       struct i2c_client *hwmon_client;
+       struct i2c_client *ioexp_client;
+};
+
+/**
+ * struct falcon_nic_data - Falcon NIC state
+ * @sram_config: NIC SRAM configuration code
+ * @pci_dev2: Secondary function of Falcon A
+ * @board: Board state and functions
+ * @stats_disable_count: Nest count for disabling statistics fetches
+ * @stats_pending: Is there a pending DMA of MAC statistics.
+ * @stats_timer: A timer for regularly fetching MAC statistics.
+ * @stats_dma_done: Pointer to the flag which indicates DMA completion.
+ */
+struct falcon_nic_data {
+       int sram_config;
+       struct pci_dev *pci_dev2;
+       struct falcon_board board;
+       unsigned int stats_disable_count;
+       bool stats_pending;
+       struct timer_list stats_timer;
+       u32 *stats_dma_done;
+};
+
+static inline struct falcon_board *falcon_board(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data;
+       EFX_BUG_ON_PARANOID(efx_nic_rev(efx) > EFX_REV_FALCON_B0);
+       nic_data = efx->nic_data;
+       return &nic_data->board;
+}
+
+/**
+ * struct siena_nic_data - Siena NIC state
+ * @fw_version: Management controller firmware version
+ * @fw_build: Firmware build number
+ * @mcdi: Management-Controller-to-Driver Interface
+ * @wol_filter_id: Wake-on-LAN packet filter id
+ */
+struct siena_nic_data {
+       u64 fw_version;
+       u32 fw_build;
+       struct efx_mcdi_iface mcdi;
+       int wol_filter_id;
+};
+
+extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len);
+
+extern struct efx_nic_type falcon_a1_nic_type;
+extern struct efx_nic_type falcon_b0_nic_type;
+extern struct efx_nic_type siena_a0_nic_type;
+
+/**************************************************************************
+ *
+ * Externs
+ *
+ **************************************************************************
+ */
+
+extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info);
+
+/* TX data path */
+extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue);
+extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+extern void fastcall efx_nic_push_buffers(struct efx_tx_queue *tx_queue);
+#else
+extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue);
+#endif
+
+/* RX data path */
+extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue);
+extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+extern void fastcall efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue);
+#else
+extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue);
+#endif
+
+/* Event data path */
+extern int efx_nic_probe_eventq(struct efx_channel *channel);
+extern void efx_nic_init_eventq(struct efx_channel *channel);
+extern void efx_nic_fini_eventq(struct efx_channel *channel);
+extern void efx_nic_remove_eventq(struct efx_channel *channel);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+extern int fastcall efx_nic_process_eventq(struct efx_channel *channel,
+                                          int rx_quota);
+#else
+extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota);
+#endif
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
+extern void fastcall efx_nic_eventq_read_ack(struct efx_channel *channel);
+#else
+extern void efx_nic_eventq_read_ack(struct efx_channel *channel);
+#endif
+
+/* MAC/PHY */
+extern void falcon_drain_tx_fifo(struct efx_nic *efx);
+extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
+extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
+
+/* Interrupts and test events */
+extern int efx_nic_init_interrupt(struct efx_nic *efx);
+extern void efx_nic_enable_interrupts(struct efx_nic *efx);
+extern void efx_nic_generate_test_event(struct efx_channel *channel,
+                                       unsigned int magic);
+extern void efx_nic_generate_interrupt(struct efx_nic *efx);
+extern void efx_nic_disable_interrupts(struct efx_nic *efx);
+extern void efx_nic_fini_interrupt(struct efx_nic *efx);
+extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx);
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_IRQ_HANDLER_REGS)
+extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id);
+#else
+extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id,
+                                             struct pt_regs *);
+#endif
+extern void falcon_irq_ack_a1(struct efx_nic *efx);
+
+#define EFX_IRQ_MOD_RESOLUTION 5
+
+/* Global Resources */
+extern int efx_nic_flush_queues(struct efx_nic *efx);
+extern void falcon_start_nic_stats(struct efx_nic *efx);
+extern void falcon_stop_nic_stats(struct efx_nic *efx);
+extern int falcon_reset_xaui(struct efx_nic *efx);
+extern int efx_nic_dimension_resources(struct efx_nic *efx, size_t sram_size,
+                                      unsigned buffers_per_vnic);
+extern void efx_nic_init_common(struct efx_nic *efx);
+extern unsigned efx_nic_check_pcie_link(struct efx_nic *efx,
+                                       unsigned full_width,
+                                       unsigned full_speed);
+
+int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
+                        unsigned int len);
+void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer);
+
+/* Tests */
+struct efx_nic_register_test {
+       unsigned address;
+       efx_oword_t mask;
+};
+struct efx_nic_table_test {
+       unsigned address;
+       unsigned step;
+       unsigned rows;
+       efx_oword_t mask;
+};
+extern int efx_nic_test_registers(struct efx_nic *efx,
+                                 const struct efx_nic_register_test *regs,
+                                 size_t n_regs);
+extern int efx_nic_test_table(struct efx_nic *efx,
+                             const struct efx_nic_table_test *table,
+                             void (*pattern)(unsigned, efx_qword_t *, int, int),
+                             int a, int b);
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ */
+
+#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
+#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
+
+/* Retrieve statistic from statistics block */
+#define FALCON_STAT(efx, falcon_stat, efx_stat) do {           \
+       if (FALCON_STAT_WIDTH(falcon_stat) == 16)               \
+               (efx)->mac_stats.efx_stat += le16_to_cpu(       \
+                       *((__force __le16 *)                            \
+                         (efx->stats_buffer.addr +             \
+                          FALCON_STAT_OFFSET(falcon_stat))));  \
+       else if (FALCON_STAT_WIDTH(falcon_stat) == 32)          \
+               (efx)->mac_stats.efx_stat += le32_to_cpu(       \
+                       *((__force __le32 *)                            \
+                         (efx->stats_buffer.addr +             \
+                          FALCON_STAT_OFFSET(falcon_stat))));  \
+       else                                                    \
+               (efx)->mac_stats.efx_stat += le64_to_cpu(       \
+                       *((__force __le64 *)                            \
+                         (efx->stats_buffer.addr +             \
+                          FALCON_STAT_OFFSET(falcon_stat))));  \
+       } while (0)
+
+#define FALCON_MAC_STATS_SIZE 0x100
+
+#define MAC_DATA_LBN 0
+#define MAC_DATA_WIDTH 32
+
+extern void efx_nic_generate_event(struct efx_channel *channel,
+                                  efx_qword_t *event);
+
+extern void falcon_poll_xmac(struct efx_nic *efx);
+
+#endif /* EFX_NIC_H */
index 395c27bee6190098681476066b554f0efa0fa2d9..def2db289f68b3f9a01c02522d0f72c45c986481 100644 (file)
@@ -1,60 +1,96 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * 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 "efx.h"
-#include "falcon.h"
-#include "gmii.h"
+#include "nic.h"
 #include "phy.h"
 
-static int falcon_null_phy_check_hw(struct efx_nic *efx)
+static int falcon_null_phy_probe(struct efx_nic *efx)
 {
-       int link_ok = falcon_xaui_link_ok(efx);
+       efx->mdio.mmds = 0;
+       efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+
+       efx->loopback_modes = FALCON_XMAC_LOOPBACKS;
+       efx->startup_loopback_mode = LOOPBACK_XGMII;
 
-       /* Generate PHY event that a PHY would have generated */
-       if (link_ok != efx->link_up)
-               efx->mac_op->fake_phy_event(efx);
+       strlcpy(efx->phy_name, "none", sizeof(efx->phy_name));
 
        return 0;
 }
 
-static void falcon_null_phy_reconfigure(struct efx_nic *efx)
+static bool falcon_null_phy_poll(struct efx_nic *efx)
 {
-       /* CX4 is always 10000FD only */
-       efx->link_options = GM_LPA_10000FULL;
+       bool was_up = efx->link_state.up;
 
-       efx->link_up = falcon_xaui_link_ok(efx);
+       efx->link_state.speed = 10000;
+       efx->link_state.fd = true;
+       efx->link_state.fc = efx->wanted_fc;
+       efx->link_state.up = !efx->xmac_poll_required;
+
+       return efx->link_state.up != was_up;
+}
+
+static void falcon_null_phy_get_settings(struct efx_nic *efx,
+                                        struct ethtool_cmd *ecmd)
+{
+       struct efx_link_state *link_state = &efx->link_state;
+
+       /* There is no port type for this so we fudge it as fibre. */
+       ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->phy_address = MDIO_PRTAD_NONE;
+       ecmd->supported = SUPPORTED_FIBRE;
+       ecmd->advertising = ADVERTISED_FIBRE;
+       ecmd->port = PORT_FIBRE;
+       ecmd->autoneg = AUTONEG_DISABLE;
+
+       ecmd->duplex = link_state->fd;
+       ecmd->speed = link_state->speed;
+}
+
+static int falcon_null_phy_set_settings(struct efx_nic *efx,
+                                       struct ethtool_cmd *ecmd)
+{
+       struct efx_link_state *link_state = &efx->link_state;
+
+       switch (ecmd->speed) {
+       case 10:
+       case 100:
+       case 1000:
+               /* TODO: verify PCS mode */
+               if (efx_nic_rev(efx) < EFX_REV_SIENA_A0)
+                       return -EOPNOTSUPP;
+               /* fall through */
+       case 10000:
+               link_state->speed = ecmd->speed;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       if (ecmd->transceiver != XCVR_INTERNAL ||
+           ecmd->phy_address != (u8)MDIO_PRTAD_NONE ||
+           ecmd->supported != SUPPORTED_FIBRE ||
+           ecmd->advertising != ADVERTISED_FIBRE ||
+           ecmd->duplex != DUPLEX_FULL ||
+           ecmd->port != PORT_FIBRE ||
+           ecmd->autoneg != AUTONEG_DISABLE)
+               return -EOPNOTSUPP;
+       return 0;
 }
 
 struct efx_phy_operations falcon_null_phy_ops = {
-       .reconfigure     = falcon_null_phy_reconfigure,
-       .check_hw        = falcon_null_phy_check_hw,
-       .fini            = efx_port_dummy_op_void,
-       .clear_interrupt = efx_port_dummy_op_void,
-       .init            = efx_port_dummy_op_int,
-       .reset_xaui      = efx_port_dummy_op_void,
-       .mmds            = 0,
-       .loopbacks       = 0,
-       .startup_loopback = 0,
+       .probe          = falcon_null_phy_probe,
+       .init           = efx_port_dummy_op_int,
+       .reconfigure    = efx_port_dummy_op_int,
+       .poll           = falcon_null_phy_poll,
+       .fini           = efx_port_dummy_op_void,
+       .remove         = efx_port_dummy_op_void,
+       .get_settings   = falcon_null_phy_get_settings,
+       .set_settings   = falcon_null_phy_set_settings,
 };
diff --git a/drivers/net/sfc/phy.c b/drivers/net/sfc/phy.c
deleted file mode 100644 (file)
index 872db0c..0000000
+++ /dev/null
@@ -1,28 +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@solarflare.com>
- *
- * 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"
-
index e2cd30ae2d8584fd55738ce32f8892c61069077e..5bc26137257b3ea4909e924165c1298a5f2c7267 100644 (file)
@@ -1,74 +1,33 @@
 /****************************************************************************
- * 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@solarflare.com>
+ * 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_PHY_H
 #define EFX_PHY_H
 
 /****************************************************************************
- * 10Xpress (SFX7101) PHY
- */
-extern struct efx_phy_operations falcon_tenxpress_phy_ops;
-
-enum tenxpress_state {
-       TENXPRESS_STATUS_OFF = 0,
-       TENXPRESS_STATUS_OTEMP = 1,
-       TENXPRESS_STATUS_NORMAL = 2,
-};
-
-extern void tenxpress_set_state(struct efx_nic *efx,
-                               enum tenxpress_state state);
-extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
-extern void tenxpress_crc_err(struct efx_nic *efx);
-
-/****************************************************************************
- * Marvell 88E1111 "Alaska" PHY control
+ * 10Xpress (SFX7101 and SFT9001) PHYs
  */
-extern struct efx_phy_operations alaska_phy_operations;
-
-/****************************************************************************
-* Exported functions from the driver for Transwitch CX4 retimer
-*/
-extern struct efx_phy_operations falcon_txc_phy_ops;
+extern struct efx_phy_operations falcon_sfx7101_phy_ops;
+extern struct efx_phy_operations falcon_sft9001_phy_ops;
 
-#define TXC_GPIO_DIR_INPUT  (0)
-#define TXC_GPIO_DIR_OUTPUT (1)
+extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
 
-extern void txc_set_gpio_dir(struct efx_nic *p, int pin, int dir);
-extern void txc_set_gpio_val(struct efx_nic *p, int pin, int val);
-
-/****************************************************************************
- * Exported functions from the driver for PMC PM8358 PHY
- */
-extern struct efx_phy_operations falcon_pm8358_phy_ops;
+/* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed
+ * to boot due to corrupt flash, or some other negative error code. */
+extern int sft9001_wait_boot(struct efx_nic *efx);
 
 /****************************************************************************
- * Exported functions from the driver for XFP optical PHYs
+ * AMCC/Quake QT202x PHYs
  */
-extern struct efx_phy_operations falcon_xfp_phy_ops;
+extern struct efx_phy_operations falcon_qt202x_phy_ops;
 
-/* The QUAKE XFP PHY provides various H/W control states for LEDs */
+/* These PHYs provide various H/W control states for LEDs */
 #define QUAKE_LED_LINK_INVAL   (0)
 #define QUAKE_LED_LINK_STAT    (1)
 #define QUAKE_LED_LINK_ACT     (2)
@@ -80,11 +39,23 @@ extern struct efx_phy_operations falcon_xfp_phy_ops;
 #define QUAKE_LED_TXLINK       (0)
 #define QUAKE_LED_RXLINK       (8)
 
-extern void xfp_set_led(struct efx_nic *p, int led, int state);
+extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state);
 
 /****************************************************************************
- * NULL PHY ops
+ * Siena managed PHYs
  */
-extern struct efx_phy_operations falcon_null_phy_ops;
+extern struct efx_phy_operations efx_mcdi_phy_ops;
+
+extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus,
+                             unsigned int prtad, unsigned int devad,
+                             u16 addr, u16 *value_out, u32 *status_out);
+extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus,
+                              unsigned int prtad, unsigned int devad,
+                              u16 addr, u16 value, u32 *status_out);
+extern void efx_mcdi_phy_decode_link(struct efx_nic *efx,
+                                    struct efx_link_state *link_state,
+                                    u32 speed, u32 flags, u32 fcntl);
+extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx);
+extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa);
 
 #endif
diff --git a/drivers/net/sfc/pm8358_phy.c b/drivers/net/sfc/pm8358_phy.c
deleted file mode 100644 (file)
index 8ad58b5..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/* Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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
- ****************************************************************************
- */
-/*
- *  Driver for PMC-Sierra PM8358 XAUI PHY
- */
-
-#include <linux/delay.h>
-#include "efx.h"
-#include "gmii.h"
-#include "mdio_10g.h"
-#include "phy.h"
-
-#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS)
-#define PM8358_LOOPBACKS (1 << LOOPBACK_PHY)
-
-/* PHY-specific definitions */
-/* Master ID and Global Performance Monitor Update */
-#define PMC_MASTER_REG (0xd000)
-/* Analog TX/RX settings under software control */
-#define PMC_MASTER_ANLG_CTRL (1 << 11)
-
-#define PMC_MCONF2_REG (0xd002)
-/* Drive TX off centre of data eye (1) vs. clock edge (0) */
-#define        PMC_MCONF2_TEDGE (1 << 2)
-/* Drive RX off centre of data eye (1) vs. clock edge (0) */
-#define PMC_MCONF2_REDGE (1 << 3)
-
-/* Analog RX settings */
-#define PMC_ANALOG_RX_CFG0   (0xd025)
-#define PMC_ANALOG_RX_CFG1   (0xd02d)
-#define PMC_ANALOG_RX_CFG2   (0xd035)
-#define PMC_ANALOG_RX_CFG3   (0xd03d)
-#define PMC_ANALOG_RX_TERM     (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms
-                                           float, 1 for 50 to 1.2V */
-#define PMC_ANALOG_RX_EQ_MASK (3 << 8)
-#define PMC_ANALOG_RX_EQ_NONE (0 << 8)
-#define PMC_ANALOG_RX_EQ_HALF (1 << 8)
-#define PMC_ANALOG_RX_EQ_FULL (2 << 8)
-#define PMC_ANALOG_RX_EQ_RSVD (3 << 8)
-
-/* Reset the DTE XS MMD. */
-#define PMC_MAX_RESET_TIME 500
-#define PMC_RESET_WAIT 10
-
-static int pmc_reset_phy(struct efx_nic *efx)
-{
-       int rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_DTEXS,
-                                        PMC_MAX_RESET_TIME / PMC_RESET_WAIT,
-                                        PMC_RESET_WAIT);
-       if (rc >= 0) {
-               EFX_TRACE(efx, "PMC8358: came out of reset with "
-                         "%d0 ms left\n", rc);
-               rc = 0;
-       } else {
-               EFX_ERR(efx, "PMC8358: reset timed out!\n");
-       }
-       return rc;
-}
-
-
-static void pmc_full_rx_eq(struct efx_nic *efx)
-{
-       int i, reg;
-
-       /* Enable software control of analog settings */
-       reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                MDIO_MMD_DTEXS, PMC_MASTER_REG);
-       reg |= PMC_MASTER_ANLG_CTRL;
-
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           MDIO_MMD_DTEXS, PMC_MASTER_REG, reg);
-
-       /* Turn RX eq on full for all channels. */
-       for (i = 0; i < 3; i++) {
-               /* The analog CFG registers are evenly spaced 8 apart */
-               u16 addr = PMC_ANALOG_RX_CFG0 + 8 * i;
-
-               reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                        MDIO_MMD_DTEXS, addr);
-               reg = (reg & ~PMC_ANALOG_RX_EQ_MASK) | PMC_ANALOG_RX_EQ_FULL;
-               mdio_clause45_write(efx, efx->mii.phy_id,
-                                   MDIO_MMD_DTEXS, addr, reg);
-       }
-}
-
-static void pmc_set_data_edges(struct efx_nic *efx)
-{
-       int reg;
-       /* Set TEDGE, clear REDGE */
-       reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                MDIO_MMD_DTEXS, PMC_MCONF2_REG);
-       reg &= ~PMC_MCONF2_REDGE;
-       reg |= PMC_MCONF2_TEDGE;
-
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg);
-}
-
-static int pm8358_phy_init(struct efx_nic *efx)
-{
-       u32 devid;
-       int rc;
-
-       /* The GLB_CTL reset line has been pulled before this is called,
-        * and it may take up to 5ms for the PLL's to synchronise after
-        * this is done. Best to wait 10ms here */
-       schedule_timeout_uninterruptible(HZ / 100);
-
-       rc = pmc_reset_phy(efx);
-       if (rc < 0)
-               return rc;
-
-       /* Check that all the MMDs we expect are present and responding. We
-        * expect faults on some if the link is down, but not on the PHY XS */
-       rc = mdio_clause45_check_mmds(efx, PM8358_REQUIRED_DEVS, 0);
-       if (rc < 0)
-               return rc;
-
-       devid = mdio_clause45_read_id(efx, MDIO_MMD_DTEXS);
-       EFX_LOG(efx, "PM8358: PHY ID reg %x (OUI %x model %x revision"
-               " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
-               MDIO_ID_REV(devid));
-
-       /* Turn on full RX equalisation */
-       pmc_full_rx_eq(efx);
-
-       /* Adjust RX and TX data edge position */
-       pmc_set_data_edges(efx);
-
-       EFX_LOG(efx, "PM8358: PHY init successful.\n");
-       return rc;
-}
-
-static int pm8358_link_ok(struct efx_nic *efx)
-{
-       return mdio_clause45_links_ok(efx, PM8358_REQUIRED_DEVS);
-}
-
-static int pm8358_phy_check_hw(struct efx_nic *efx)
-{
-       int rc = 0;
-       int link_up = pm8358_link_ok(efx);
-       /* Simulate a PHY event if link state has changed */
-       if (link_up != efx->link_up)
-               efx->mac_op->fake_phy_event(efx);
-
-       return rc;
-}
-
-static void pm8358_phy_reconfigure(struct efx_nic *efx)
-{
-       int phy_id = efx->mii.phy_id;
-       int ctrl;
-       /* Handle DTE loopback */
-       ctrl = mdio_clause45_read(efx, phy_id, MDIO_MMD_DTEXS,
-                                 MDIO_MMDREG_CTRL1);
-       if (efx->loopback_mode == LOOPBACK_PHY) {
-               EFX_TRACE(efx, "PM8358: setting DTE loopback\n");
-               ctrl |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-       } else {
-               if (ctrl & (1 << MDIO_MMDREG_CTRL1_LBACK_LBN))
-                       EFX_TRACE(efx,
-                                 "PM8358: clearing DTE loopback\n");
-               ctrl &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
-       }
-       mdio_clause45_write(efx, phy_id, MDIO_MMD_DTEXS,
-                           MDIO_MMDREG_CTRL1, ctrl);
-
-       efx->link_up = pm8358_link_ok(efx);
-       efx->link_options = GM_LPA_10000FULL;
-}
-
-struct efx_phy_operations falcon_pm8358_phy_ops = {
-       .init            = pm8358_phy_init,
-       .reconfigure     = pm8358_phy_reconfigure,
-       .check_hw        = pm8358_phy_check_hw,
-       .fini            = efx_port_dummy_op_void,
-       .clear_interrupt = efx_port_dummy_op_void,
-       .reset_xaui      = efx_port_dummy_op_void,
-       .mmds            = PM8358_REQUIRED_DEVS,
-       .loopbacks       = PM8358_LOOPBACKS,
-       .startup_loopback = LOOPBACK_PHY,
-};
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
new file mode 100644 (file)
index 0000000..9633abc
--- /dev/null
@@ -0,0 +1,478 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * 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.
+ */
+/*
+ * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details
+ */
+
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include "efx.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "nic.h"
+
+#define QT202X_REQUIRED_DEVS (MDIO_DEVS_PCS |          \
+                             MDIO_DEVS_PMAPMD |        \
+                             MDIO_DEVS_PHYXS)
+
+#define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) |                \
+                         (1 << LOOPBACK_PMAPMD) |      \
+                         (1 << LOOPBACK_PHYXS_WS))
+
+/****************************************************************************/
+/* Quake-specific MDIO registers */
+#define MDIO_QUAKE_LED0_REG    (0xD006)
+
+/* QT2025C only */
+#define PCS_FW_HEARTBEAT_REG   0xd7ee
+#define PCS_FW_HEARTB_LBN      0
+#define PCS_FW_HEARTB_WIDTH    8
+#define PCS_FW_PRODUCT_CODE_1  0xd7f0
+#define PCS_FW_VERSION_1       0xd7f3
+#define PCS_FW_BUILD_1         0xd7f6
+#define PCS_UC8051_STATUS_REG  0xd7fd
+#define PCS_UC_STATUS_LBN      0
+#define PCS_UC_STATUS_WIDTH    8
+#define PCS_UC_STATUS_FW_SAVE  0x20
+#define PMA_PMD_FTX_CTRL2_REG  0xc309
+#define PMA_PMD_FTX_STATIC_LBN 13
+#define PMA_PMD_VEND1_REG      0xc001
+#define PMA_PMD_VEND1_LBTXD_LBN        15
+#define PCS_VEND1_REG          0xc000
+#define PCS_VEND1_LBTXD_LBN    5
+
+void falcon_qt202x_set_led(struct efx_nic *p, int led, int mode)
+{
+       int addr = MDIO_QUAKE_LED0_REG + led;
+       efx_mdio_write(p, MDIO_MMD_PMAPMD, addr, mode);
+}
+
+struct qt202x_phy_data {
+       enum efx_phy_mode phy_mode;
+       bool bug17190_in_bad_state;
+       unsigned long bug17190_timer;
+       u32 firmware_ver;
+};
+
+#define QT2022C2_MAX_RESET_TIME 500
+#define QT2022C2_RESET_WAIT 10
+
+#define QT2025C_MAX_HEARTB_TIME (5 * HZ)
+#define QT2025C_HEARTB_WAIT 100
+#define QT2025C_MAX_FWSTART_TIME (25 * HZ / 10)
+#define QT2025C_FWSTART_WAIT 100
+
+#define BUG17190_INTERVAL (2 * HZ)
+
+static int qt2025c_wait_heartbeat(struct efx_nic *efx)
+{
+       unsigned long timeout = jiffies + QT2025C_MAX_HEARTB_TIME;
+       int reg, old_counter = 0;
+
+       /* Wait for firmware heartbeat to start */
+       for (;;) {
+               int counter;
+               reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_FW_HEARTBEAT_REG);
+               if (reg < 0)
+                       return reg;
+               counter = ((reg >> PCS_FW_HEARTB_LBN) &
+                           ((1 << PCS_FW_HEARTB_WIDTH) - 1));
+               if (old_counter == 0)
+                       old_counter = counter;
+               else if (counter != old_counter)
+                       break;
+               if (time_after(jiffies, timeout)) {
+                       /* Some cables have EEPROMs that conflict with the
+                        * PHY's on-board EEPROM so it cannot load firmware */
+                       EFX_ERR(efx, "If an SFP+ direct attach cable is"
+                               " connected, please check that it complies"
+                               " with the SFP+ specification\n");
+                       return -ETIMEDOUT;
+               }
+               msleep(QT2025C_HEARTB_WAIT);
+       }
+
+       return 0;
+}
+
+static int qt2025c_wait_fw_status_good(struct efx_nic *efx)
+{
+       unsigned long timeout = jiffies + QT2025C_MAX_FWSTART_TIME;
+       int reg;
+
+       /* Wait for firmware status to look good */
+       for (;;) {
+               reg = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_UC8051_STATUS_REG);
+               if (reg < 0)
+                       return reg;
+               if ((reg &
+                    ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >=
+                   PCS_UC_STATUS_FW_SAVE)
+                       break;
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               msleep(QT2025C_FWSTART_WAIT);
+       }
+
+       return 0;
+}
+
+static void qt2025c_restart_firmware(struct efx_nic *efx)
+{
+       /* Restart microcontroller execution of firmware from RAM */
+       efx_mdio_write(efx, 3, 0xe854, 0x00c0);
+       efx_mdio_write(efx, 3, 0xe854, 0x0040);
+       msleep(50);
+}
+
+static int qt2025c_wait_reset(struct efx_nic *efx)
+{
+       int rc;
+
+       rc = qt2025c_wait_heartbeat(efx);
+       if (rc != 0)
+               return rc;
+
+       rc = qt2025c_wait_fw_status_good(efx);
+       if (rc == -ETIMEDOUT) {
+               /* Bug 17689: occasionally heartbeat starts but firmware status
+                * code never progresses beyond 0x00.  Try again, once, after
+                * restarting execution of the firmware image. */
+               EFX_LOG(efx, "bashing QT2025C microcontroller\n");
+               qt2025c_restart_firmware(efx);
+               rc = qt2025c_wait_heartbeat(efx);
+               if (rc != 0)
+                       return rc;
+               rc = qt2025c_wait_fw_status_good(efx);
+       }
+
+       return rc;
+}
+
+static void qt2025c_firmware_id(struct efx_nic *efx)
+{
+       struct qt202x_phy_data *phy_data = efx->phy_data;
+       u8 firmware_id[9];
+       size_t i;
+
+       for (i = 0; i < sizeof(firmware_id); i++)
+               firmware_id[i] = efx_mdio_read(efx, MDIO_MMD_PCS,
+                                              PCS_FW_PRODUCT_CODE_1 + i);
+       EFX_INFO(efx, "QT2025C firmware %xr%d v%d.%d.%d.%d [20%02d-%02d-%02d]\n",
+                (firmware_id[0] << 8) | firmware_id[1], firmware_id[2],
+                firmware_id[3] >> 4, firmware_id[3] & 0xf,
+                firmware_id[4], firmware_id[5],
+                firmware_id[6], firmware_id[7], firmware_id[8]);
+       phy_data->firmware_ver = ((firmware_id[3] & 0xf0) << 20) |
+                                ((firmware_id[3] & 0x0f) << 16) |
+                                (firmware_id[4] << 8) | firmware_id[5];
+}
+
+static void qt2025c_bug17190_workaround_init(struct efx_nic *efx)
+{
+       struct qt202x_phy_data *phy_data = efx->phy_data;
+
+       phy_data->bug17190_in_bad_state = false;
+       phy_data->bug17190_timer = 0;
+}
+
+static void qt2025c_bug17190_workaround(struct efx_nic *efx)
+{
+       struct qt202x_phy_data *phy_data = efx->phy_data;
+
+       /* The PHY can get stuck in a state where it reports PHY_XS and PMA/PMD
+        * layers up, but PCS down (no block_lock).  If we notice this state
+        * persisting for a couple of seconds, we switch PMA/PMD loopback
+        * briefly on and then off again, which is normally sufficient to
+        * recover it.
+        */
+       if (efx->link_state.up ||
+           !efx_mdio_links_ok(efx, MDIO_DEVS_PMAPMD | MDIO_DEVS_PHYXS)) {
+               phy_data->bug17190_in_bad_state = false;
+               return;
+       }
+
+       if (!phy_data->bug17190_in_bad_state) {
+               phy_data->bug17190_in_bad_state = true;
+               phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL;
+               return;
+       }
+
+       if (time_after_eq(jiffies, phy_data->bug17190_timer)) {
+               EFX_LOG(efx, "bashing QT2025C PMA/PMD\n");
+               efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+                                 MDIO_PMA_CTRL1_LOOPBACK, true);
+               msleep(100);
+               efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+                                 MDIO_PMA_CTRL1_LOOPBACK, false);
+               phy_data->bug17190_timer = jiffies + BUG17190_INTERVAL;
+       }
+}
+
+static int qt2025c_select_phy_mode(struct efx_nic *efx)
+{
+       struct qt202x_phy_data *phy_data = efx->phy_data;
+       struct falcon_board *board = falcon_board(efx);
+       int reg, rc, i;
+       uint16_t phy_op_mode;
+
+       /* Only 2.0.1.0+ PHY firmware supports the more optimal SFP+
+        * Self-Configure mode.  Don't attempt any switching if we encounter
+        * older firmware. */
+       if (phy_data->firmware_ver < 0x02000100)
+               return 0;
+
+       /* In general we will get optimal behaviour in "SFP+ Self-Configure"
+        * mode; however, that powers down most of the PHY when no module is
+        * present, so we must use a different mode (any fixed mode will do)
+        * to be sure that loopbacks will work. */
+       phy_op_mode = (efx->loopback_mode == LOOPBACK_NONE) ? 0x0038 : 0x0020;
+
+       /* Only change mode if really necessary */
+       reg = efx_mdio_read(efx, 1, 0xc319);
+       if ((reg & 0x0038) == phy_op_mode)
+               return 0;
+       EFX_LOG(efx, "Switching PHY to mode 0x%04x\n", phy_op_mode);
+
+       /* This sequence replicates the register writes configured in the boot
+        * EEPROM (including the differences between board revisions), except
+        * that the operating mode is changed, and the PHY is prevented from
+        * unnecessarily reloading the main firmware image again. */
+       efx_mdio_write(efx, 1, 0xc300, 0x0000);
+       /* (Note: this portion of the boot EEPROM sequence, which bit-bashes 9
+        * STOPs onto the firmware/module I2C bus to reset it, varies across
+        * board revisions, as the bus is connected to different GPIO/LED
+        * outputs on the PHY.) */
+       if (board->major == 0 && board->minor < 2) {
+               efx_mdio_write(efx, 1, 0xc303, 0x4498);
+               for (i = 0; i < 9; i++) {
+                       efx_mdio_write(efx, 1, 0xc303, 0x4488);
+                       efx_mdio_write(efx, 1, 0xc303, 0x4480);
+                       efx_mdio_write(efx, 1, 0xc303, 0x4490);
+                       efx_mdio_write(efx, 1, 0xc303, 0x4498);
+               }
+       } else {
+               efx_mdio_write(efx, 1, 0xc303, 0x0920);
+               efx_mdio_write(efx, 1, 0xd008, 0x0004);
+               for (i = 0; i < 9; i++) {
+                       efx_mdio_write(efx, 1, 0xc303, 0x0900);
+                       efx_mdio_write(efx, 1, 0xd008, 0x0005);
+                       efx_mdio_write(efx, 1, 0xc303, 0x0920);
+                       efx_mdio_write(efx, 1, 0xd008, 0x0004);
+               }
+               efx_mdio_write(efx, 1, 0xc303, 0x4900);
+       }
+       efx_mdio_write(efx, 1, 0xc303, 0x4900);
+       efx_mdio_write(efx, 1, 0xc302, 0x0004);
+       efx_mdio_write(efx, 1, 0xc316, 0x0013);
+       efx_mdio_write(efx, 1, 0xc318, 0x0054);
+       efx_mdio_write(efx, 1, 0xc319, phy_op_mode);
+       efx_mdio_write(efx, 1, 0xc31a, 0x0098);
+       efx_mdio_write(efx, 3, 0x0026, 0x0e00);
+       efx_mdio_write(efx, 3, 0x0027, 0x0013);
+       efx_mdio_write(efx, 3, 0x0028, 0xa528);
+       efx_mdio_write(efx, 1, 0xd006, 0x000a);
+       efx_mdio_write(efx, 1, 0xd007, 0x0009);
+       efx_mdio_write(efx, 1, 0xd008, 0x0004);
+       /* This additional write is not present in the boot EEPROM.  It
+        * prevents the PHY's internal boot ROM doing another pointless (and
+        * slow) reload of the firmware image (the microcontroller's code
+        * memory is not affected by the microcontroller reset). */
+       efx_mdio_write(efx, 1, 0xc317, 0x00ff);
+       efx_mdio_write(efx, 1, 0xc300, 0x0002);
+       msleep(20);
+
+       /* Restart microcontroller execution of firmware from RAM */
+       qt2025c_restart_firmware(efx);
+
+       /* Wait for the microcontroller to be ready again */
+       rc = qt2025c_wait_reset(efx);
+       if (rc < 0) {
+               EFX_ERR(efx, "PHY microcontroller reset during mode switch "
+                               "timed out\n");
+               return rc;
+       }
+
+       return 0;
+}
+
+static int qt202x_reset_phy(struct efx_nic *efx)
+{
+       int rc;
+
+       if (efx->phy_type == PHY_TYPE_QT2025C) {
+               /* Wait for the reset triggered by falcon_reset_hw()
+                * to complete */
+               rc = qt2025c_wait_reset(efx);
+               if (rc < 0)
+                       goto fail;
+       } else {
+               /* Reset the PHYXS MMD. This is documented as doing
+                * a complete soft reset. */
+               rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PHYXS,
+                                       QT2022C2_MAX_RESET_TIME /
+                                       QT2022C2_RESET_WAIT,
+                                       QT2022C2_RESET_WAIT);
+               if (rc < 0)
+                       goto fail;
+       }
+
+       /* Wait 250ms for the PHY to complete bootup */
+       msleep(250);
+
+       /* Check that all the MMDs we expect are present and responding. We
+        * expect faults on some if the link is down, but not on the PHY XS */
+       rc = efx_mdio_check_mmds(efx, QT202X_REQUIRED_DEVS, MDIO_DEVS_PHYXS);
+       if (rc < 0)
+               goto fail;
+
+       falcon_board(efx)->type->init_phy(efx);
+
+       return rc;
+
+ fail:
+       EFX_ERR(efx, "PHY reset timed out\n");
+       return rc;
+}
+
+static int qt202x_phy_probe(struct efx_nic *efx)
+{
+       struct qt202x_phy_data *phy_data;
+
+       phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL);
+       if (!phy_data)
+               return -ENOMEM;
+       efx->phy_data = phy_data;
+       phy_data->phy_mode = efx->phy_mode;
+
+       if (efx->phy_type == PHY_TYPE_QT2025C)
+               qt2025c_bug17190_workaround_init(efx);
+
+       efx->mdio.mmds = QT202X_REQUIRED_DEVS;
+       efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+
+       efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+       efx->startup_loopback_mode = LOOPBACK_PCS;
+
+       strlcpy(efx->phy_name,
+               (efx->phy_type == PHY_TYPE_QT2025C) ? "Quake SFP+" : "Quake XFP",
+               sizeof(efx->phy_name));
+
+       return 0;
+}
+
+static int qt202x_phy_init(struct efx_nic *efx)
+{
+       u32 devid;
+       int rc;
+
+       /* Reset the PHY before reading the firmware version */
+       rc = qt202x_reset_phy(efx);
+       if (rc) {
+               EFX_ERR(efx, "PHY init failed\n");
+               return rc;
+       }
+
+       devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
+       EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
+                devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid),
+                efx_mdio_id_rev(devid));
+       if (efx->phy_type == PHY_TYPE_QT2025C)
+               qt2025c_firmware_id(efx);
+
+       return 0;
+}
+
+static int qt202x_link_ok(struct efx_nic *efx)
+{
+       return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS);
+}
+
+static bool qt202x_phy_poll(struct efx_nic *efx)
+{
+       bool was_up = efx->link_state.up;
+
+       efx->link_state.up = qt202x_link_ok(efx);
+       efx->link_state.speed = 10000;
+       efx->link_state.fd = true;
+       efx->link_state.fc = efx->wanted_fc;
+
+       if (efx->phy_type == PHY_TYPE_QT2025C)
+               qt2025c_bug17190_workaround(efx);
+
+       return efx->link_state.up != was_up;
+}
+
+static int qt202x_phy_reconfigure(struct efx_nic *efx)
+{
+       struct qt202x_phy_data *phy_data = efx->phy_data;
+
+       if (efx->phy_type == PHY_TYPE_QT2025C) {
+               int rc = qt2025c_select_phy_mode(efx);
+               if (rc)
+                       return rc;
+
+               /* There are several different register bits which can
+                * disable TX (and save power) on direct-attach cables
+                * or optical transceivers, varying somewhat between
+                * firmware versions.  Only 'static mode' appears to
+                * cover everything. */
+               mdio_set_flag(
+                       &efx->mdio, efx->mdio.prtad, MDIO_MMD_PMAPMD,
+                       PMA_PMD_FTX_CTRL2_REG, 1 << PMA_PMD_FTX_STATIC_LBN,
+                       efx->phy_mode & PHY_MODE_TX_DISABLED ||
+                       efx->phy_mode & PHY_MODE_LOW_POWER ||
+                       efx->loopback_mode == LOOPBACK_PCS ||
+                       efx->loopback_mode == LOOPBACK_PMAPMD);
+       } else {
+               /* Reset the PHY when moving from transmitter off or powered
+                * off, to transmitter on and powered on */
+               unsigned mask = PHY_MODE_TX_DISABLED | PHY_MODE_LOW_POWER;
+               if (!(efx->phy_mode & mask) && (phy_data->phy_mode & mask)) {
+                       int rc = qt202x_reset_phy(efx);
+                       if (rc)
+                               EFX_ERR(efx, "Error resetting phy\n");
+               }
+
+               efx_mdio_transmit_disable(efx);
+               efx_mdio_set_mmds_lpower(efx,
+                                        !!(efx->phy_mode & PHY_MODE_LOW_POWER),
+                                        QT202X_REQUIRED_DEVS);
+       }
+
+       efx_mdio_phy_reconfigure(efx);
+
+       phy_data->phy_mode = efx->phy_mode;
+
+       return 0;
+}
+
+static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       mdio45_ethtool_gset(&efx->mdio, ecmd);
+}
+
+static void qt202x_phy_remove(struct efx_nic *efx)
+{
+       /* Free the context block */
+       kfree(efx->phy_data);
+       efx->phy_data = NULL;
+}
+
+struct efx_phy_operations falcon_qt202x_phy_ops = {
+       .probe           = qt202x_phy_probe,
+       .init            = qt202x_phy_init,
+       .reconfigure     = qt202x_phy_reconfigure,
+       .poll            = qt202x_phy_poll,
+       .fini            = efx_port_dummy_op_void,
+       .remove          = qt202x_phy_remove,
+       .get_settings    = qt202x_phy_get_settings,
+       .set_settings    = efx_mdio_set_settings,
+       .test_alive      = efx_mdio_test_alive,
+};
diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h
new file mode 100644 (file)
index 0000000..28413cb
--- /dev/null
@@ -0,0 +1,3168 @@
+/****************************************************************************
+ * 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.
+ */
+
+#ifndef EFX_REGS_H
+#define EFX_REGS_H
+
+/*
+ * Falcon hardware architecture definitions have a name prefix following
+ * the format:
+ *
+ *     F<type>_<min-rev><max-rev>_
+ *
+ * The following <type> strings are used:
+ *
+ *             MMIO register  MC register  Host memory structure
+ * -------------------------------------------------------------
+ * Address     R              MCR
+ * Bitfield    RF             MCRF         SF
+ * Enumerator  FE             MCFE         SE
+ *
+ * <min-rev> is the first revision to which the definition applies:
+ *
+ *     A: Falcon A1 (SFC4000AB)
+ *     B: Falcon B0 (SFC4000BA)
+ *     C: Siena A0 (SFL9021AA)
+ *
+ * If the definition has been changed or removed in later revisions
+ * then <max-rev> is the last revision to which the definition applies;
+ * otherwise it is "Z".
+ */
+
+/**************************************************************************
+ *
+ * Falcon/Siena registers and descriptors
+ *
+ **************************************************************************
+ */
+
+/* ADR_REGION_REG: Address region register */
+#define        FR_AZ_ADR_REGION 0x00000000
+#define        FRF_AZ_ADR_REGION3_LBN 96
+#define        FRF_AZ_ADR_REGION3_WIDTH 18
+#define        FRF_AZ_ADR_REGION2_LBN 64
+#define        FRF_AZ_ADR_REGION2_WIDTH 18
+#define        FRF_AZ_ADR_REGION1_LBN 32
+#define        FRF_AZ_ADR_REGION1_WIDTH 18
+#define        FRF_AZ_ADR_REGION0_LBN 0
+#define        FRF_AZ_ADR_REGION0_WIDTH 18
+
+/* INT_EN_REG_KER: Kernel driver Interrupt enable register */
+#define        FR_AZ_INT_EN_KER 0x00000010
+#define        FRF_AZ_KER_INT_LEVE_SEL_LBN 8
+#define        FRF_AZ_KER_INT_LEVE_SEL_WIDTH 6
+#define        FRF_AZ_KER_INT_CHAR_LBN 4
+#define        FRF_AZ_KER_INT_CHAR_WIDTH 1
+#define        FRF_AZ_KER_INT_KER_LBN 3
+#define        FRF_AZ_KER_INT_KER_WIDTH 1
+#define        FRF_AZ_DRV_INT_EN_KER_LBN 0
+#define        FRF_AZ_DRV_INT_EN_KER_WIDTH 1
+
+/* INT_EN_REG_CHAR: Char Driver interrupt enable register */
+#define        FR_BZ_INT_EN_CHAR 0x00000020
+#define        FRF_BZ_CHAR_INT_LEVE_SEL_LBN 8
+#define        FRF_BZ_CHAR_INT_LEVE_SEL_WIDTH 6
+#define        FRF_BZ_CHAR_INT_CHAR_LBN 4
+#define        FRF_BZ_CHAR_INT_CHAR_WIDTH 1
+#define        FRF_BZ_CHAR_INT_KER_LBN 3
+#define        FRF_BZ_CHAR_INT_KER_WIDTH 1
+#define        FRF_BZ_DRV_INT_EN_CHAR_LBN 0
+#define        FRF_BZ_DRV_INT_EN_CHAR_WIDTH 1
+
+/* INT_ADR_REG_KER: Interrupt host address for Kernel driver */
+#define        FR_AZ_INT_ADR_KER 0x00000030
+#define        FRF_AZ_NORM_INT_VEC_DIS_KER_LBN 64
+#define        FRF_AZ_NORM_INT_VEC_DIS_KER_WIDTH 1
+#define        FRF_AZ_INT_ADR_KER_LBN 0
+#define        FRF_AZ_INT_ADR_KER_WIDTH 64
+
+/* INT_ADR_REG_CHAR: Interrupt host address for Char driver */
+#define        FR_BZ_INT_ADR_CHAR 0x00000040
+#define        FRF_BZ_NORM_INT_VEC_DIS_CHAR_LBN 64
+#define        FRF_BZ_NORM_INT_VEC_DIS_CHAR_WIDTH 1
+#define        FRF_BZ_INT_ADR_CHAR_LBN 0
+#define        FRF_BZ_INT_ADR_CHAR_WIDTH 64
+
+/* INT_ACK_KER: Kernel interrupt acknowledge register */
+#define        FR_AA_INT_ACK_KER 0x00000050
+#define        FRF_AA_INT_ACK_KER_FIELD_LBN 0
+#define        FRF_AA_INT_ACK_KER_FIELD_WIDTH 32
+
+/* INT_ISR0_REG: Function 0 Interrupt Acknowlege Status register */
+#define        FR_BZ_INT_ISR0 0x00000090
+#define        FRF_BZ_INT_ISR_REG_LBN 0
+#define        FRF_BZ_INT_ISR_REG_WIDTH 64
+
+/* HW_INIT_REG: Hardware initialization register */
+#define        FR_AZ_HW_INIT 0x000000c0
+#define        FRF_BB_BDMRD_CPLF_FULL_LBN 124
+#define        FRF_BB_BDMRD_CPLF_FULL_WIDTH 1
+#define        FRF_BB_PCIE_CPL_TIMEOUT_CTRL_LBN 121
+#define        FRF_BB_PCIE_CPL_TIMEOUT_CTRL_WIDTH 3
+#define        FRF_CZ_TX_MRG_TAGS_LBN 120
+#define        FRF_CZ_TX_MRG_TAGS_WIDTH 1
+#define        FRF_AB_TRGT_MASK_ALL_LBN 100
+#define        FRF_AB_TRGT_MASK_ALL_WIDTH 1
+#define        FRF_AZ_DOORBELL_DROP_LBN 92
+#define        FRF_AZ_DOORBELL_DROP_WIDTH 8
+#define        FRF_AB_TX_RREQ_MASK_EN_LBN 76
+#define        FRF_AB_TX_RREQ_MASK_EN_WIDTH 1
+#define        FRF_AB_PE_EIDLE_DIS_LBN 75
+#define        FRF_AB_PE_EIDLE_DIS_WIDTH 1
+#define        FRF_AA_FC_BLOCKING_EN_LBN 45
+#define        FRF_AA_FC_BLOCKING_EN_WIDTH 1
+#define        FRF_BZ_B2B_REQ_EN_LBN 45
+#define        FRF_BZ_B2B_REQ_EN_WIDTH 1
+#define        FRF_AA_B2B_REQ_EN_LBN 44
+#define        FRF_AA_B2B_REQ_EN_WIDTH 1
+#define        FRF_BB_FC_BLOCKING_EN_LBN 44
+#define        FRF_BB_FC_BLOCKING_EN_WIDTH 1
+#define        FRF_AZ_POST_WR_MASK_LBN 40
+#define        FRF_AZ_POST_WR_MASK_WIDTH 4
+#define        FRF_AZ_TLP_TC_LBN 34
+#define        FRF_AZ_TLP_TC_WIDTH 3
+#define        FRF_AZ_TLP_ATTR_LBN 32
+#define        FRF_AZ_TLP_ATTR_WIDTH 2
+#define        FRF_AB_INTB_VEC_LBN 24
+#define        FRF_AB_INTB_VEC_WIDTH 5
+#define        FRF_AB_INTA_VEC_LBN 16
+#define        FRF_AB_INTA_VEC_WIDTH 5
+#define        FRF_AZ_WD_TIMER_LBN 8
+#define        FRF_AZ_WD_TIMER_WIDTH 8
+#define        FRF_AZ_US_DISABLE_LBN 5
+#define        FRF_AZ_US_DISABLE_WIDTH 1
+#define        FRF_AZ_TLP_EP_LBN 4
+#define        FRF_AZ_TLP_EP_WIDTH 1
+#define        FRF_AZ_ATTR_SEL_LBN 3
+#define        FRF_AZ_ATTR_SEL_WIDTH 1
+#define        FRF_AZ_TD_SEL_LBN 1
+#define        FRF_AZ_TD_SEL_WIDTH 1
+#define        FRF_AZ_TLP_TD_LBN 0
+#define        FRF_AZ_TLP_TD_WIDTH 1
+
+/* EE_SPI_HCMD_REG: SPI host command register */
+#define        FR_AB_EE_SPI_HCMD 0x00000100
+#define        FRF_AB_EE_SPI_HCMD_CMD_EN_LBN 31
+#define        FRF_AB_EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define        FRF_AB_EE_WR_TIMER_ACTIVE_LBN 28
+#define        FRF_AB_EE_WR_TIMER_ACTIVE_WIDTH 1
+#define        FRF_AB_EE_SPI_HCMD_SF_SEL_LBN 24
+#define        FRF_AB_EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define        FRF_AB_EE_SPI_HCMD_DABCNT_LBN 16
+#define        FRF_AB_EE_SPI_HCMD_DABCNT_WIDTH 5
+#define        FRF_AB_EE_SPI_HCMD_READ_LBN 15
+#define        FRF_AB_EE_SPI_HCMD_READ_WIDTH 1
+#define        FRF_AB_EE_SPI_HCMD_DUBCNT_LBN 12
+#define        FRF_AB_EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define        FRF_AB_EE_SPI_HCMD_ADBCNT_LBN 8
+#define        FRF_AB_EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define        FRF_AB_EE_SPI_HCMD_ENC_LBN 0
+#define        FRF_AB_EE_SPI_HCMD_ENC_WIDTH 8
+
+/* USR_EV_CFG: User Level Event Configuration register */
+#define        FR_CZ_USR_EV_CFG 0x00000100
+#define        FRF_CZ_USREV_DIS_LBN 16
+#define        FRF_CZ_USREV_DIS_WIDTH 1
+#define        FRF_CZ_DFLT_EVQ_LBN 0
+#define        FRF_CZ_DFLT_EVQ_WIDTH 10
+
+/* EE_SPI_HADR_REG: SPI host address register */
+#define        FR_AB_EE_SPI_HADR 0x00000110
+#define        FRF_AB_EE_SPI_HADR_DUBYTE_LBN 24
+#define        FRF_AB_EE_SPI_HADR_DUBYTE_WIDTH 8
+#define        FRF_AB_EE_SPI_HADR_ADR_LBN 0
+#define        FRF_AB_EE_SPI_HADR_ADR_WIDTH 24
+
+/* EE_SPI_HDATA_REG: SPI host data register */
+#define        FR_AB_EE_SPI_HDATA 0x00000120
+#define        FRF_AB_EE_SPI_HDATA3_LBN 96
+#define        FRF_AB_EE_SPI_HDATA3_WIDTH 32
+#define        FRF_AB_EE_SPI_HDATA2_LBN 64
+#define        FRF_AB_EE_SPI_HDATA2_WIDTH 32
+#define        FRF_AB_EE_SPI_HDATA1_LBN 32
+#define        FRF_AB_EE_SPI_HDATA1_WIDTH 32
+#define        FRF_AB_EE_SPI_HDATA0_LBN 0
+#define        FRF_AB_EE_SPI_HDATA0_WIDTH 32
+
+/* EE_BASE_PAGE_REG: Expansion ROM base mirror register */
+#define        FR_AB_EE_BASE_PAGE 0x00000130
+#define        FRF_AB_EE_EXPROM_MASK_LBN 16
+#define        FRF_AB_EE_EXPROM_MASK_WIDTH 13
+#define        FRF_AB_EE_EXP_ROM_WINDOW_BASE_LBN 0
+#define        FRF_AB_EE_EXP_ROM_WINDOW_BASE_WIDTH 13
+
+/* EE_VPD_CFG0_REG: SPI/VPD configuration register 0 */
+#define        FR_AB_EE_VPD_CFG0 0x00000140
+#define        FRF_AB_EE_SF_FASTRD_EN_LBN 127
+#define        FRF_AB_EE_SF_FASTRD_EN_WIDTH 1
+#define        FRF_AB_EE_SF_CLOCK_DIV_LBN 120
+#define        FRF_AB_EE_SF_CLOCK_DIV_WIDTH 7
+#define        FRF_AB_EE_VPD_WIP_POLL_LBN 119
+#define        FRF_AB_EE_VPD_WIP_POLL_WIDTH 1
+#define        FRF_AB_EE_EE_CLOCK_DIV_LBN 112
+#define        FRF_AB_EE_EE_CLOCK_DIV_WIDTH 7
+#define        FRF_AB_EE_EE_WR_TMR_VALUE_LBN 96
+#define        FRF_AB_EE_EE_WR_TMR_VALUE_WIDTH 16
+#define        FRF_AB_EE_VPDW_LENGTH_LBN 80
+#define        FRF_AB_EE_VPDW_LENGTH_WIDTH 15
+#define        FRF_AB_EE_VPDW_BASE_LBN 64
+#define        FRF_AB_EE_VPDW_BASE_WIDTH 15
+#define        FRF_AB_EE_VPD_WR_CMD_EN_LBN 56
+#define        FRF_AB_EE_VPD_WR_CMD_EN_WIDTH 8
+#define        FRF_AB_EE_VPD_BASE_LBN 32
+#define        FRF_AB_EE_VPD_BASE_WIDTH 24
+#define        FRF_AB_EE_VPD_LENGTH_LBN 16
+#define        FRF_AB_EE_VPD_LENGTH_WIDTH 15
+#define        FRF_AB_EE_VPD_AD_SIZE_LBN 8
+#define        FRF_AB_EE_VPD_AD_SIZE_WIDTH 5
+#define        FRF_AB_EE_VPD_ACCESS_ON_LBN 5
+#define        FRF_AB_EE_VPD_ACCESS_ON_WIDTH 1
+#define        FRF_AB_EE_VPD_ACCESS_BLOCK_LBN 4
+#define        FRF_AB_EE_VPD_ACCESS_BLOCK_WIDTH 1
+#define        FRF_AB_EE_VPD_DEV_SF_SEL_LBN 2
+#define        FRF_AB_EE_VPD_DEV_SF_SEL_WIDTH 1
+#define        FRF_AB_EE_VPD_EN_AD9_MODE_LBN 1
+#define        FRF_AB_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define        FRF_AB_EE_VPD_EN_LBN 0
+#define        FRF_AB_EE_VPD_EN_WIDTH 1
+
+/* EE_VPD_SW_CNTL_REG: VPD access SW control register */
+#define        FR_AB_EE_VPD_SW_CNTL 0x00000150
+#define        FRF_AB_EE_VPD_CYCLE_PENDING_LBN 31
+#define        FRF_AB_EE_VPD_CYCLE_PENDING_WIDTH 1
+#define        FRF_AB_EE_VPD_CYC_WRITE_LBN 28
+#define        FRF_AB_EE_VPD_CYC_WRITE_WIDTH 1
+#define        FRF_AB_EE_VPD_CYC_ADR_LBN 0
+#define        FRF_AB_EE_VPD_CYC_ADR_WIDTH 15
+
+/* EE_VPD_SW_DATA_REG: VPD access SW data register */
+#define        FR_AB_EE_VPD_SW_DATA 0x00000160
+#define        FRF_AB_EE_VPD_CYC_DAT_LBN 0
+#define        FRF_AB_EE_VPD_CYC_DAT_WIDTH 32
+
+/* PBMX_DBG_IADDR_REG: Capture Module address register */
+#define        FR_CZ_PBMX_DBG_IADDR 0x000001f0
+#define        FRF_CZ_PBMX_DBG_IADDR_LBN 0
+#define        FRF_CZ_PBMX_DBG_IADDR_WIDTH 32
+
+/* PCIE_CORE_INDIRECT_REG: Indirect Access to PCIE Core registers */
+#define        FR_BB_PCIE_CORE_INDIRECT 0x000001f0
+#define        FRF_BB_PCIE_CORE_TARGET_DATA_LBN 32
+#define        FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH 32
+#define        FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_LBN 15
+#define        FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_WIDTH 1
+#define        FRF_BB_PCIE_CORE_TARGET_REG_ADRS_LBN 0
+#define        FRF_BB_PCIE_CORE_TARGET_REG_ADRS_WIDTH 12
+
+/* PBMX_DBG_IDATA_REG: Capture Module data register */
+#define        FR_CZ_PBMX_DBG_IDATA 0x000001f8
+#define        FRF_CZ_PBMX_DBG_IDATA_LBN 0
+#define        FRF_CZ_PBMX_DBG_IDATA_WIDTH 64
+
+/* NIC_STAT_REG: NIC status register */
+#define        FR_AB_NIC_STAT 0x00000200
+#define        FRF_BB_AER_DIS_LBN 34
+#define        FRF_BB_AER_DIS_WIDTH 1
+#define        FRF_BB_EE_STRAP_EN_LBN 31
+#define        FRF_BB_EE_STRAP_EN_WIDTH 1
+#define        FRF_BB_EE_STRAP_LBN 24
+#define        FRF_BB_EE_STRAP_WIDTH 4
+#define        FRF_BB_REVISION_ID_LBN 17
+#define        FRF_BB_REVISION_ID_WIDTH 7
+#define        FRF_AB_ONCHIP_SRAM_LBN 16
+#define        FRF_AB_ONCHIP_SRAM_WIDTH 1
+#define        FRF_AB_SF_PRST_LBN 9
+#define        FRF_AB_SF_PRST_WIDTH 1
+#define        FRF_AB_EE_PRST_LBN 8
+#define        FRF_AB_EE_PRST_WIDTH 1
+#define        FRF_AB_ATE_MODE_LBN 3
+#define        FRF_AB_ATE_MODE_WIDTH 1
+#define        FRF_AB_STRAP_PINS_LBN 0
+#define        FRF_AB_STRAP_PINS_WIDTH 3
+
+/* GPIO_CTL_REG: GPIO control register */
+#define        FR_AB_GPIO_CTL 0x00000210
+#define        FRF_AB_GPIO_OUT3_LBN 112
+#define        FRF_AB_GPIO_OUT3_WIDTH 16
+#define        FRF_AB_GPIO_IN3_LBN 104
+#define        FRF_AB_GPIO_IN3_WIDTH 8
+#define        FRF_AB_GPIO_PWRUP_VALUE3_LBN 96
+#define        FRF_AB_GPIO_PWRUP_VALUE3_WIDTH 8
+#define        FRF_AB_GPIO_OUT2_LBN 80
+#define        FRF_AB_GPIO_OUT2_WIDTH 16
+#define        FRF_AB_GPIO_IN2_LBN 72
+#define        FRF_AB_GPIO_IN2_WIDTH 8
+#define        FRF_AB_GPIO_PWRUP_VALUE2_LBN 64
+#define        FRF_AB_GPIO_PWRUP_VALUE2_WIDTH 8
+#define        FRF_AB_GPIO15_OEN_LBN 63
+#define        FRF_AB_GPIO15_OEN_WIDTH 1
+#define        FRF_AB_GPIO14_OEN_LBN 62
+#define        FRF_AB_GPIO14_OEN_WIDTH 1
+#define        FRF_AB_GPIO13_OEN_LBN 61
+#define        FRF_AB_GPIO13_OEN_WIDTH 1
+#define        FRF_AB_GPIO12_OEN_LBN 60
+#define        FRF_AB_GPIO12_OEN_WIDTH 1
+#define        FRF_AB_GPIO11_OEN_LBN 59
+#define        FRF_AB_GPIO11_OEN_WIDTH 1
+#define        FRF_AB_GPIO10_OEN_LBN 58
+#define        FRF_AB_GPIO10_OEN_WIDTH 1
+#define        FRF_AB_GPIO9_OEN_LBN 57
+#define        FRF_AB_GPIO9_OEN_WIDTH 1
+#define        FRF_AB_GPIO8_OEN_LBN 56
+#define        FRF_AB_GPIO8_OEN_WIDTH 1
+#define        FRF_AB_GPIO15_OUT_LBN 55
+#define        FRF_AB_GPIO15_OUT_WIDTH 1
+#define        FRF_AB_GPIO14_OUT_LBN 54
+#define        FRF_AB_GPIO14_OUT_WIDTH 1
+#define        FRF_AB_GPIO13_OUT_LBN 53
+#define        FRF_AB_GPIO13_OUT_WIDTH 1
+#define        FRF_AB_GPIO12_OUT_LBN 52
+#define        FRF_AB_GPIO12_OUT_WIDTH 1
+#define        FRF_AB_GPIO11_OUT_LBN 51
+#define        FRF_AB_GPIO11_OUT_WIDTH 1
+#define        FRF_AB_GPIO10_OUT_LBN 50
+#define        FRF_AB_GPIO10_OUT_WIDTH 1
+#define        FRF_AB_GPIO9_OUT_LBN 49
+#define        FRF_AB_GPIO9_OUT_WIDTH 1
+#define        FRF_AB_GPIO8_OUT_LBN 48
+#define        FRF_AB_GPIO8_OUT_WIDTH 1
+#define        FRF_AB_GPIO15_IN_LBN 47
+#define        FRF_AB_GPIO15_IN_WIDTH 1
+#define        FRF_AB_GPIO14_IN_LBN 46
+#define        FRF_AB_GPIO14_IN_WIDTH 1
+#define        FRF_AB_GPIO13_IN_LBN 45
+#define        FRF_AB_GPIO13_IN_WIDTH 1
+#define        FRF_AB_GPIO12_IN_LBN 44
+#define        FRF_AB_GPIO12_IN_WIDTH 1
+#define        FRF_AB_GPIO11_IN_LBN 43
+#define        FRF_AB_GPIO11_IN_WIDTH 1
+#define        FRF_AB_GPIO10_IN_LBN 42
+#define        FRF_AB_GPIO10_IN_WIDTH 1
+#define        FRF_AB_GPIO9_IN_LBN 41
+#define        FRF_AB_GPIO9_IN_WIDTH 1
+#define        FRF_AB_GPIO8_IN_LBN 40
+#define        FRF_AB_GPIO8_IN_WIDTH 1
+#define        FRF_AB_GPIO15_PWRUP_VALUE_LBN 39
+#define        FRF_AB_GPIO15_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO14_PWRUP_VALUE_LBN 38
+#define        FRF_AB_GPIO14_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO13_PWRUP_VALUE_LBN 37
+#define        FRF_AB_GPIO13_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO12_PWRUP_VALUE_LBN 36
+#define        FRF_AB_GPIO12_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO11_PWRUP_VALUE_LBN 35
+#define        FRF_AB_GPIO11_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO10_PWRUP_VALUE_LBN 34
+#define        FRF_AB_GPIO10_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO9_PWRUP_VALUE_LBN 33
+#define        FRF_AB_GPIO9_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO8_PWRUP_VALUE_LBN 32
+#define        FRF_AB_GPIO8_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_CLK156_OUT_EN_LBN 31
+#define        FRF_AB_CLK156_OUT_EN_WIDTH 1
+#define        FRF_AB_USE_NIC_CLK_LBN 30
+#define        FRF_AB_USE_NIC_CLK_WIDTH 1
+#define        FRF_AB_GPIO5_OEN_LBN 29
+#define        FRF_AB_GPIO5_OEN_WIDTH 1
+#define        FRF_AB_GPIO4_OEN_LBN 28
+#define        FRF_AB_GPIO4_OEN_WIDTH 1
+#define        FRF_AB_GPIO3_OEN_LBN 27
+#define        FRF_AB_GPIO3_OEN_WIDTH 1
+#define        FRF_AB_GPIO2_OEN_LBN 26
+#define        FRF_AB_GPIO2_OEN_WIDTH 1
+#define        FRF_AB_GPIO1_OEN_LBN 25
+#define        FRF_AB_GPIO1_OEN_WIDTH 1
+#define        FRF_AB_GPIO0_OEN_LBN 24
+#define        FRF_AB_GPIO0_OEN_WIDTH 1
+#define        FRF_AB_GPIO7_OUT_LBN 23
+#define        FRF_AB_GPIO7_OUT_WIDTH 1
+#define        FRF_AB_GPIO6_OUT_LBN 22
+#define        FRF_AB_GPIO6_OUT_WIDTH 1
+#define        FRF_AB_GPIO5_OUT_LBN 21
+#define        FRF_AB_GPIO5_OUT_WIDTH 1
+#define        FRF_AB_GPIO4_OUT_LBN 20
+#define        FRF_AB_GPIO4_OUT_WIDTH 1
+#define        FRF_AB_GPIO3_OUT_LBN 19
+#define        FRF_AB_GPIO3_OUT_WIDTH 1
+#define        FRF_AB_GPIO2_OUT_LBN 18
+#define        FRF_AB_GPIO2_OUT_WIDTH 1
+#define        FRF_AB_GPIO1_OUT_LBN 17
+#define        FRF_AB_GPIO1_OUT_WIDTH 1
+#define        FRF_AB_GPIO0_OUT_LBN 16
+#define        FRF_AB_GPIO0_OUT_WIDTH 1
+#define        FRF_AB_GPIO7_IN_LBN 15
+#define        FRF_AB_GPIO7_IN_WIDTH 1
+#define        FRF_AB_GPIO6_IN_LBN 14
+#define        FRF_AB_GPIO6_IN_WIDTH 1
+#define        FRF_AB_GPIO5_IN_LBN 13
+#define        FRF_AB_GPIO5_IN_WIDTH 1
+#define        FRF_AB_GPIO4_IN_LBN 12
+#define        FRF_AB_GPIO4_IN_WIDTH 1
+#define        FRF_AB_GPIO3_IN_LBN 11
+#define        FRF_AB_GPIO3_IN_WIDTH 1
+#define        FRF_AB_GPIO2_IN_LBN 10
+#define        FRF_AB_GPIO2_IN_WIDTH 1
+#define        FRF_AB_GPIO1_IN_LBN 9
+#define        FRF_AB_GPIO1_IN_WIDTH 1
+#define        FRF_AB_GPIO0_IN_LBN 8
+#define        FRF_AB_GPIO0_IN_WIDTH 1
+#define        FRF_AB_GPIO7_PWRUP_VALUE_LBN 7
+#define        FRF_AB_GPIO7_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO6_PWRUP_VALUE_LBN 6
+#define        FRF_AB_GPIO6_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO5_PWRUP_VALUE_LBN 5
+#define        FRF_AB_GPIO5_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO4_PWRUP_VALUE_LBN 4
+#define        FRF_AB_GPIO4_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO3_PWRUP_VALUE_LBN 3
+#define        FRF_AB_GPIO3_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO2_PWRUP_VALUE_LBN 2
+#define        FRF_AB_GPIO2_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO1_PWRUP_VALUE_LBN 1
+#define        FRF_AB_GPIO1_PWRUP_VALUE_WIDTH 1
+#define        FRF_AB_GPIO0_PWRUP_VALUE_LBN 0
+#define        FRF_AB_GPIO0_PWRUP_VALUE_WIDTH 1
+
+/* GLB_CTL_REG: Global control register */
+#define        FR_AB_GLB_CTL 0x00000220
+#define        FRF_AB_EXT_PHY_RST_CTL_LBN 63
+#define        FRF_AB_EXT_PHY_RST_CTL_WIDTH 1
+#define        FRF_AB_XAUI_SD_RST_CTL_LBN 62
+#define        FRF_AB_XAUI_SD_RST_CTL_WIDTH 1
+#define        FRF_AB_PCIE_SD_RST_CTL_LBN 61
+#define        FRF_AB_PCIE_SD_RST_CTL_WIDTH 1
+#define        FRF_AA_PCIX_RST_CTL_LBN 60
+#define        FRF_AA_PCIX_RST_CTL_WIDTH 1
+#define        FRF_BB_BIU_RST_CTL_LBN 60
+#define        FRF_BB_BIU_RST_CTL_WIDTH 1
+#define        FRF_AB_PCIE_STKY_RST_CTL_LBN 59
+#define        FRF_AB_PCIE_STKY_RST_CTL_WIDTH 1
+#define        FRF_AB_PCIE_NSTKY_RST_CTL_LBN 58
+#define        FRF_AB_PCIE_NSTKY_RST_CTL_WIDTH 1
+#define        FRF_AB_PCIE_CORE_RST_CTL_LBN 57
+#define        FRF_AB_PCIE_CORE_RST_CTL_WIDTH 1
+#define        FRF_AB_XGRX_RST_CTL_LBN 56
+#define        FRF_AB_XGRX_RST_CTL_WIDTH 1
+#define        FRF_AB_XGTX_RST_CTL_LBN 55
+#define        FRF_AB_XGTX_RST_CTL_WIDTH 1
+#define        FRF_AB_EM_RST_CTL_LBN 54
+#define        FRF_AB_EM_RST_CTL_WIDTH 1
+#define        FRF_AB_EV_RST_CTL_LBN 53
+#define        FRF_AB_EV_RST_CTL_WIDTH 1
+#define        FRF_AB_SR_RST_CTL_LBN 52
+#define        FRF_AB_SR_RST_CTL_WIDTH 1
+#define        FRF_AB_RX_RST_CTL_LBN 51
+#define        FRF_AB_RX_RST_CTL_WIDTH 1
+#define        FRF_AB_TX_RST_CTL_LBN 50
+#define        FRF_AB_TX_RST_CTL_WIDTH 1
+#define        FRF_AB_EE_RST_CTL_LBN 49
+#define        FRF_AB_EE_RST_CTL_WIDTH 1
+#define        FRF_AB_CS_RST_CTL_LBN 48
+#define        FRF_AB_CS_RST_CTL_WIDTH 1
+#define        FRF_AB_HOT_RST_CTL_LBN 40
+#define        FRF_AB_HOT_RST_CTL_WIDTH 2
+#define        FRF_AB_RST_EXT_PHY_LBN 31
+#define        FRF_AB_RST_EXT_PHY_WIDTH 1
+#define        FRF_AB_RST_XAUI_SD_LBN 30
+#define        FRF_AB_RST_XAUI_SD_WIDTH 1
+#define        FRF_AB_RST_PCIE_SD_LBN 29
+#define        FRF_AB_RST_PCIE_SD_WIDTH 1
+#define        FRF_AA_RST_PCIX_LBN 28
+#define        FRF_AA_RST_PCIX_WIDTH 1
+#define        FRF_BB_RST_BIU_LBN 28
+#define        FRF_BB_RST_BIU_WIDTH 1
+#define        FRF_AB_RST_PCIE_STKY_LBN 27
+#define        FRF_AB_RST_PCIE_STKY_WIDTH 1
+#define        FRF_AB_RST_PCIE_NSTKY_LBN 26
+#define        FRF_AB_RST_PCIE_NSTKY_WIDTH 1
+#define        FRF_AB_RST_PCIE_CORE_LBN 25
+#define        FRF_AB_RST_PCIE_CORE_WIDTH 1
+#define        FRF_AB_RST_XGRX_LBN 24
+#define        FRF_AB_RST_XGRX_WIDTH 1
+#define        FRF_AB_RST_XGTX_LBN 23
+#define        FRF_AB_RST_XGTX_WIDTH 1
+#define        FRF_AB_RST_EM_LBN 22
+#define        FRF_AB_RST_EM_WIDTH 1
+#define        FRF_AB_RST_EV_LBN 21
+#define        FRF_AB_RST_EV_WIDTH 1
+#define        FRF_AB_RST_SR_LBN 20
+#define        FRF_AB_RST_SR_WIDTH 1
+#define        FRF_AB_RST_RX_LBN 19
+#define        FRF_AB_RST_RX_WIDTH 1
+#define        FRF_AB_RST_TX_LBN 18
+#define        FRF_AB_RST_TX_WIDTH 1
+#define        FRF_AB_RST_SF_LBN 17
+#define        FRF_AB_RST_SF_WIDTH 1
+#define        FRF_AB_RST_CS_LBN 16
+#define        FRF_AB_RST_CS_WIDTH 1
+#define        FRF_AB_INT_RST_DUR_LBN 4
+#define        FRF_AB_INT_RST_DUR_WIDTH 3
+#define        FRF_AB_EXT_PHY_RST_DUR_LBN 1
+#define        FRF_AB_EXT_PHY_RST_DUR_WIDTH 3
+#define        FFE_AB_EXT_PHY_RST_DUR_10240US 7
+#define        FFE_AB_EXT_PHY_RST_DUR_5120US 6
+#define        FFE_AB_EXT_PHY_RST_DUR_2560US 5
+#define        FFE_AB_EXT_PHY_RST_DUR_1280US 4
+#define        FFE_AB_EXT_PHY_RST_DUR_640US 3
+#define        FFE_AB_EXT_PHY_RST_DUR_320US 2
+#define        FFE_AB_EXT_PHY_RST_DUR_160US 1
+#define        FFE_AB_EXT_PHY_RST_DUR_80US 0
+#define        FRF_AB_SWRST_LBN 0
+#define        FRF_AB_SWRST_WIDTH 1
+
+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
+#define        FR_AZ_FATAL_INTR_KER 0x00000230
+#define        FRF_CZ_SRAM_PERR_INT_P_KER_EN_LBN 44
+#define        FRF_CZ_SRAM_PERR_INT_P_KER_EN_WIDTH 1
+#define        FRF_AB_PCI_BUSERR_INT_KER_EN_LBN 43
+#define        FRF_AB_PCI_BUSERR_INT_KER_EN_WIDTH 1
+#define        FRF_CZ_MBU_PERR_INT_KER_EN_LBN 43
+#define        FRF_CZ_MBU_PERR_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_SRAM_OOB_INT_KER_EN_LBN 42
+#define        FRF_AZ_SRAM_OOB_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_BUFID_OOB_INT_KER_EN_LBN 41
+#define        FRF_AZ_BUFID_OOB_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_MEM_PERR_INT_KER_EN_LBN 40
+#define        FRF_AZ_MEM_PERR_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_RBUF_OWN_INT_KER_EN_LBN 39
+#define        FRF_AZ_RBUF_OWN_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_TBUF_OWN_INT_KER_EN_LBN 38
+#define        FRF_AZ_TBUF_OWN_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_RDESCQ_OWN_INT_KER_EN_LBN 37
+#define        FRF_AZ_RDESCQ_OWN_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_TDESCQ_OWN_INT_KER_EN_LBN 36
+#define        FRF_AZ_TDESCQ_OWN_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_EVQ_OWN_INT_KER_EN_LBN 35
+#define        FRF_AZ_EVQ_OWN_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_EVF_OFLO_INT_KER_EN_LBN 34
+#define        FRF_AZ_EVF_OFLO_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_ILL_ADR_INT_KER_EN_LBN 33
+#define        FRF_AZ_ILL_ADR_INT_KER_EN_WIDTH 1
+#define        FRF_AZ_SRM_PERR_INT_KER_EN_LBN 32
+#define        FRF_AZ_SRM_PERR_INT_KER_EN_WIDTH 1
+#define        FRF_CZ_SRAM_PERR_INT_P_KER_LBN 12
+#define        FRF_CZ_SRAM_PERR_INT_P_KER_WIDTH 1
+#define        FRF_AB_PCI_BUSERR_INT_KER_LBN 11
+#define        FRF_AB_PCI_BUSERR_INT_KER_WIDTH 1
+#define        FRF_CZ_MBU_PERR_INT_KER_LBN 11
+#define        FRF_CZ_MBU_PERR_INT_KER_WIDTH 1
+#define        FRF_AZ_SRAM_OOB_INT_KER_LBN 10
+#define        FRF_AZ_SRAM_OOB_INT_KER_WIDTH 1
+#define        FRF_AZ_BUFID_DC_OOB_INT_KER_LBN 9
+#define        FRF_AZ_BUFID_DC_OOB_INT_KER_WIDTH 1
+#define        FRF_AZ_MEM_PERR_INT_KER_LBN 8
+#define        FRF_AZ_MEM_PERR_INT_KER_WIDTH 1
+#define        FRF_AZ_RBUF_OWN_INT_KER_LBN 7
+#define        FRF_AZ_RBUF_OWN_INT_KER_WIDTH 1
+#define        FRF_AZ_TBUF_OWN_INT_KER_LBN 6
+#define        FRF_AZ_TBUF_OWN_INT_KER_WIDTH 1
+#define        FRF_AZ_RDESCQ_OWN_INT_KER_LBN 5
+#define        FRF_AZ_RDESCQ_OWN_INT_KER_WIDTH 1
+#define        FRF_AZ_TDESCQ_OWN_INT_KER_LBN 4
+#define        FRF_AZ_TDESCQ_OWN_INT_KER_WIDTH 1
+#define        FRF_AZ_EVQ_OWN_INT_KER_LBN 3
+#define        FRF_AZ_EVQ_OWN_INT_KER_WIDTH 1
+#define        FRF_AZ_EVF_OFLO_INT_KER_LBN 2
+#define        FRF_AZ_EVF_OFLO_INT_KER_WIDTH 1
+#define        FRF_AZ_ILL_ADR_INT_KER_LBN 1
+#define        FRF_AZ_ILL_ADR_INT_KER_WIDTH 1
+#define        FRF_AZ_SRM_PERR_INT_KER_LBN 0
+#define        FRF_AZ_SRM_PERR_INT_KER_WIDTH 1
+
+/* FATAL_INTR_REG_CHAR: Fatal interrupt register for Char */
+#define        FR_BZ_FATAL_INTR_CHAR 0x00000240
+#define        FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_LBN 44
+#define        FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_WIDTH 1
+#define        FRF_BB_PCI_BUSERR_INT_CHAR_EN_LBN 43
+#define        FRF_BB_PCI_BUSERR_INT_CHAR_EN_WIDTH 1
+#define        FRF_CZ_MBU_PERR_INT_CHAR_EN_LBN 43
+#define        FRF_CZ_MBU_PERR_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_SRAM_OOB_INT_CHAR_EN_LBN 42
+#define        FRF_BZ_SRAM_OOB_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_BUFID_OOB_INT_CHAR_EN_LBN 41
+#define        FRF_BZ_BUFID_OOB_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_MEM_PERR_INT_CHAR_EN_LBN 40
+#define        FRF_BZ_MEM_PERR_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_RBUF_OWN_INT_CHAR_EN_LBN 39
+#define        FRF_BZ_RBUF_OWN_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_TBUF_OWN_INT_CHAR_EN_LBN 38
+#define        FRF_BZ_TBUF_OWN_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_LBN 37
+#define        FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_LBN 36
+#define        FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_EVQ_OWN_INT_CHAR_EN_LBN 35
+#define        FRF_BZ_EVQ_OWN_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_EVF_OFLO_INT_CHAR_EN_LBN 34
+#define        FRF_BZ_EVF_OFLO_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_ILL_ADR_INT_CHAR_EN_LBN 33
+#define        FRF_BZ_ILL_ADR_INT_CHAR_EN_WIDTH 1
+#define        FRF_BZ_SRM_PERR_INT_CHAR_EN_LBN 32
+#define        FRF_BZ_SRM_PERR_INT_CHAR_EN_WIDTH 1
+#define        FRF_CZ_SRAM_PERR_INT_P_CHAR_LBN 12
+#define        FRF_CZ_SRAM_PERR_INT_P_CHAR_WIDTH 1
+#define        FRF_BB_PCI_BUSERR_INT_CHAR_LBN 11
+#define        FRF_BB_PCI_BUSERR_INT_CHAR_WIDTH 1
+#define        FRF_CZ_MBU_PERR_INT_CHAR_LBN 11
+#define        FRF_CZ_MBU_PERR_INT_CHAR_WIDTH 1
+#define        FRF_BZ_SRAM_OOB_INT_CHAR_LBN 10
+#define        FRF_BZ_SRAM_OOB_INT_CHAR_WIDTH 1
+#define        FRF_BZ_BUFID_DC_OOB_INT_CHAR_LBN 9
+#define        FRF_BZ_BUFID_DC_OOB_INT_CHAR_WIDTH 1
+#define        FRF_BZ_MEM_PERR_INT_CHAR_LBN 8
+#define        FRF_BZ_MEM_PERR_INT_CHAR_WIDTH 1
+#define        FRF_BZ_RBUF_OWN_INT_CHAR_LBN 7
+#define        FRF_BZ_RBUF_OWN_INT_CHAR_WIDTH 1
+#define        FRF_BZ_TBUF_OWN_INT_CHAR_LBN 6
+#define        FRF_BZ_TBUF_OWN_INT_CHAR_WIDTH 1
+#define        FRF_BZ_RDESCQ_OWN_INT_CHAR_LBN 5
+#define        FRF_BZ_RDESCQ_OWN_INT_CHAR_WIDTH 1
+#define        FRF_BZ_TDESCQ_OWN_INT_CHAR_LBN 4
+#define        FRF_BZ_TDESCQ_OWN_INT_CHAR_WIDTH 1
+#define        FRF_BZ_EVQ_OWN_INT_CHAR_LBN 3
+#define        FRF_BZ_EVQ_OWN_INT_CHAR_WIDTH 1
+#define        FRF_BZ_EVF_OFLO_INT_CHAR_LBN 2
+#define        FRF_BZ_EVF_OFLO_INT_CHAR_WIDTH 1
+#define        FRF_BZ_ILL_ADR_INT_CHAR_LBN 1
+#define        FRF_BZ_ILL_ADR_INT_CHAR_WIDTH 1
+#define        FRF_BZ_SRM_PERR_INT_CHAR_LBN 0
+#define        FRF_BZ_SRM_PERR_INT_CHAR_WIDTH 1
+
+/* DP_CTRL_REG: Datapath control register */
+#define        FR_BZ_DP_CTRL 0x00000250
+#define        FRF_BZ_FLS_EVQ_ID_LBN 0
+#define        FRF_BZ_FLS_EVQ_ID_WIDTH 12
+
+/* MEM_STAT_REG: Memory status register */
+#define        FR_AZ_MEM_STAT 0x00000260
+#define        FRF_AB_MEM_PERR_VEC_LBN 53
+#define        FRF_AB_MEM_PERR_VEC_WIDTH 38
+#define        FRF_AB_MBIST_CORR_LBN 38
+#define        FRF_AB_MBIST_CORR_WIDTH 15
+#define        FRF_AB_MBIST_ERR_LBN 0
+#define        FRF_AB_MBIST_ERR_WIDTH 40
+#define        FRF_CZ_MEM_PERR_VEC_LBN 0
+#define        FRF_CZ_MEM_PERR_VEC_WIDTH 35
+
+/* CS_DEBUG_REG: Debug register */
+#define        FR_AZ_CS_DEBUG 0x00000270
+#define        FRF_AB_GLB_DEBUG2_SEL_LBN 50
+#define        FRF_AB_GLB_DEBUG2_SEL_WIDTH 3
+#define        FRF_AB_DEBUG_BLK_SEL2_LBN 47
+#define        FRF_AB_DEBUG_BLK_SEL2_WIDTH 3
+#define        FRF_AB_DEBUG_BLK_SEL1_LBN 44
+#define        FRF_AB_DEBUG_BLK_SEL1_WIDTH 3
+#define        FRF_AB_DEBUG_BLK_SEL0_LBN 41
+#define        FRF_AB_DEBUG_BLK_SEL0_WIDTH 3
+#define        FRF_CZ_CS_PORT_NUM_LBN 40
+#define        FRF_CZ_CS_PORT_NUM_WIDTH 2
+#define        FRF_AB_MISC_DEBUG_ADDR_LBN 36
+#define        FRF_AB_MISC_DEBUG_ADDR_WIDTH 5
+#define        FRF_AB_SERDES_DEBUG_ADDR_LBN 31
+#define        FRF_AB_SERDES_DEBUG_ADDR_WIDTH 5
+#define        FRF_CZ_CS_PORT_FPE_LBN 1
+#define        FRF_CZ_CS_PORT_FPE_WIDTH 35
+#define        FRF_AB_EM_DEBUG_ADDR_LBN 26
+#define        FRF_AB_EM_DEBUG_ADDR_WIDTH 5
+#define        FRF_AB_SR_DEBUG_ADDR_LBN 21
+#define        FRF_AB_SR_DEBUG_ADDR_WIDTH 5
+#define        FRF_AB_EV_DEBUG_ADDR_LBN 16
+#define        FRF_AB_EV_DEBUG_ADDR_WIDTH 5
+#define        FRF_AB_RX_DEBUG_ADDR_LBN 11
+#define        FRF_AB_RX_DEBUG_ADDR_WIDTH 5
+#define        FRF_AB_TX_DEBUG_ADDR_LBN 6
+#define        FRF_AB_TX_DEBUG_ADDR_WIDTH 5
+#define        FRF_AB_CS_BIU_DEBUG_ADDR_LBN 1
+#define        FRF_AB_CS_BIU_DEBUG_ADDR_WIDTH 5
+#define        FRF_AZ_CS_DEBUG_EN_LBN 0
+#define        FRF_AZ_CS_DEBUG_EN_WIDTH 1
+
+/* DRIVER_REG: Driver scratch register [0-7] */
+#define        FR_AZ_DRIVER 0x00000280
+#define        FR_AZ_DRIVER_STEP 16
+#define        FR_AZ_DRIVER_ROWS 8
+#define        FRF_AZ_DRIVER_DW0_LBN 0
+#define        FRF_AZ_DRIVER_DW0_WIDTH 32
+
+/* ALTERA_BUILD_REG: Altera build register */
+#define        FR_AZ_ALTERA_BUILD 0x00000300
+#define        FRF_AZ_ALTERA_BUILD_VER_LBN 0
+#define        FRF_AZ_ALTERA_BUILD_VER_WIDTH 32
+
+/* CSR_SPARE_REG: Spare register */
+#define        FR_AZ_CSR_SPARE 0x00000310
+#define        FRF_AB_MEM_PERR_EN_LBN 64
+#define        FRF_AB_MEM_PERR_EN_WIDTH 38
+#define        FRF_CZ_MEM_PERR_EN_LBN 64
+#define        FRF_CZ_MEM_PERR_EN_WIDTH 35
+#define        FRF_AB_MEM_PERR_EN_TX_DATA_LBN 72
+#define        FRF_AB_MEM_PERR_EN_TX_DATA_WIDTH 2
+#define        FRF_AZ_CSR_SPARE_BITS_LBN 0
+#define        FRF_AZ_CSR_SPARE_BITS_WIDTH 32
+
+/* PCIE_SD_CTL0123_REG: PCIE SerDes control register 0 to 3 */
+#define        FR_AB_PCIE_SD_CTL0123 0x00000320
+#define        FRF_AB_PCIE_TESTSIG_H_LBN 96
+#define        FRF_AB_PCIE_TESTSIG_H_WIDTH 19
+#define        FRF_AB_PCIE_TESTSIG_L_LBN 64
+#define        FRF_AB_PCIE_TESTSIG_L_WIDTH 19
+#define        FRF_AB_PCIE_OFFSET_LBN 56
+#define        FRF_AB_PCIE_OFFSET_WIDTH 8
+#define        FRF_AB_PCIE_OFFSETEN_H_LBN 55
+#define        FRF_AB_PCIE_OFFSETEN_H_WIDTH 1
+#define        FRF_AB_PCIE_OFFSETEN_L_LBN 54
+#define        FRF_AB_PCIE_OFFSETEN_L_WIDTH 1
+#define        FRF_AB_PCIE_HIVMODE_H_LBN 53
+#define        FRF_AB_PCIE_HIVMODE_H_WIDTH 1
+#define        FRF_AB_PCIE_HIVMODE_L_LBN 52
+#define        FRF_AB_PCIE_HIVMODE_L_WIDTH 1
+#define        FRF_AB_PCIE_PARRESET_H_LBN 51
+#define        FRF_AB_PCIE_PARRESET_H_WIDTH 1
+#define        FRF_AB_PCIE_PARRESET_L_LBN 50
+#define        FRF_AB_PCIE_PARRESET_L_WIDTH 1
+#define        FRF_AB_PCIE_LPBKWDRV_H_LBN 49
+#define        FRF_AB_PCIE_LPBKWDRV_H_WIDTH 1
+#define        FRF_AB_PCIE_LPBKWDRV_L_LBN 48
+#define        FRF_AB_PCIE_LPBKWDRV_L_WIDTH 1
+#define        FRF_AB_PCIE_LPBK_LBN 40
+#define        FRF_AB_PCIE_LPBK_WIDTH 8
+#define        FRF_AB_PCIE_PARLPBK_LBN 32
+#define        FRF_AB_PCIE_PARLPBK_WIDTH 8
+#define        FRF_AB_PCIE_RXTERMADJ_H_LBN 30
+#define        FRF_AB_PCIE_RXTERMADJ_H_WIDTH 2
+#define        FRF_AB_PCIE_RXTERMADJ_L_LBN 28
+#define        FRF_AB_PCIE_RXTERMADJ_L_WIDTH 2
+#define        FFE_AB_PCIE_RXTERMADJ_MIN15PCNT 3
+#define        FFE_AB_PCIE_RXTERMADJ_PL10PCNT 2
+#define        FFE_AB_PCIE_RXTERMADJ_MIN17PCNT 1
+#define        FFE_AB_PCIE_RXTERMADJ_NOMNL 0
+#define        FRF_AB_PCIE_TXTERMADJ_H_LBN 26
+#define        FRF_AB_PCIE_TXTERMADJ_H_WIDTH 2
+#define        FRF_AB_PCIE_TXTERMADJ_L_LBN 24
+#define        FRF_AB_PCIE_TXTERMADJ_L_WIDTH 2
+#define        FFE_AB_PCIE_TXTERMADJ_MIN15PCNT 3
+#define        FFE_AB_PCIE_TXTERMADJ_PL10PCNT 2
+#define        FFE_AB_PCIE_TXTERMADJ_MIN17PCNT 1
+#define        FFE_AB_PCIE_TXTERMADJ_NOMNL 0
+#define        FRF_AB_PCIE_RXEQCTL_H_LBN 18
+#define        FRF_AB_PCIE_RXEQCTL_H_WIDTH 2
+#define        FRF_AB_PCIE_RXEQCTL_L_LBN 16
+#define        FRF_AB_PCIE_RXEQCTL_L_WIDTH 2
+#define        FFE_AB_PCIE_RXEQCTL_OFF_ALT 3
+#define        FFE_AB_PCIE_RXEQCTL_OFF 2
+#define        FFE_AB_PCIE_RXEQCTL_MIN 1
+#define        FFE_AB_PCIE_RXEQCTL_MAX 0
+#define        FRF_AB_PCIE_HIDRV_LBN 8
+#define        FRF_AB_PCIE_HIDRV_WIDTH 8
+#define        FRF_AB_PCIE_LODRV_LBN 0
+#define        FRF_AB_PCIE_LODRV_WIDTH 8
+
+/* PCIE_SD_CTL45_REG: PCIE SerDes control register 4 and 5 */
+#define        FR_AB_PCIE_SD_CTL45 0x00000330
+#define        FRF_AB_PCIE_DTX7_LBN 60
+#define        FRF_AB_PCIE_DTX7_WIDTH 4
+#define        FRF_AB_PCIE_DTX6_LBN 56
+#define        FRF_AB_PCIE_DTX6_WIDTH 4
+#define        FRF_AB_PCIE_DTX5_LBN 52
+#define        FRF_AB_PCIE_DTX5_WIDTH 4
+#define        FRF_AB_PCIE_DTX4_LBN 48
+#define        FRF_AB_PCIE_DTX4_WIDTH 4
+#define        FRF_AB_PCIE_DTX3_LBN 44
+#define        FRF_AB_PCIE_DTX3_WIDTH 4
+#define        FRF_AB_PCIE_DTX2_LBN 40
+#define        FRF_AB_PCIE_DTX2_WIDTH 4
+#define        FRF_AB_PCIE_DTX1_LBN 36
+#define        FRF_AB_PCIE_DTX1_WIDTH 4
+#define        FRF_AB_PCIE_DTX0_LBN 32
+#define        FRF_AB_PCIE_DTX0_WIDTH 4
+#define        FRF_AB_PCIE_DEQ7_LBN 28
+#define        FRF_AB_PCIE_DEQ7_WIDTH 4
+#define        FRF_AB_PCIE_DEQ6_LBN 24
+#define        FRF_AB_PCIE_DEQ6_WIDTH 4
+#define        FRF_AB_PCIE_DEQ5_LBN 20
+#define        FRF_AB_PCIE_DEQ5_WIDTH 4
+#define        FRF_AB_PCIE_DEQ4_LBN 16
+#define        FRF_AB_PCIE_DEQ4_WIDTH 4
+#define        FRF_AB_PCIE_DEQ3_LBN 12
+#define        FRF_AB_PCIE_DEQ3_WIDTH 4
+#define        FRF_AB_PCIE_DEQ2_LBN 8
+#define        FRF_AB_PCIE_DEQ2_WIDTH 4
+#define        FRF_AB_PCIE_DEQ1_LBN 4
+#define        FRF_AB_PCIE_DEQ1_WIDTH 4
+#define        FRF_AB_PCIE_DEQ0_LBN 0
+#define        FRF_AB_PCIE_DEQ0_WIDTH 4
+
+/* PCIE_PCS_CTL_STAT_REG: PCIE PCS control and status register */
+#define        FR_AB_PCIE_PCS_CTL_STAT 0x00000340
+#define        FRF_AB_PCIE_PRBSERRCOUNT0_H_LBN 52
+#define        FRF_AB_PCIE_PRBSERRCOUNT0_H_WIDTH 4
+#define        FRF_AB_PCIE_PRBSERRCOUNT0_L_LBN 48
+#define        FRF_AB_PCIE_PRBSERRCOUNT0_L_WIDTH 4
+#define        FRF_AB_PCIE_PRBSERR_LBN 40
+#define        FRF_AB_PCIE_PRBSERR_WIDTH 8
+#define        FRF_AB_PCIE_PRBSERRH0_LBN 32
+#define        FRF_AB_PCIE_PRBSERRH0_WIDTH 8
+#define        FRF_AB_PCIE_FASTINIT_H_LBN 15
+#define        FRF_AB_PCIE_FASTINIT_H_WIDTH 1
+#define        FRF_AB_PCIE_FASTINIT_L_LBN 14
+#define        FRF_AB_PCIE_FASTINIT_L_WIDTH 1
+#define        FRF_AB_PCIE_CTCDISABLE_H_LBN 13
+#define        FRF_AB_PCIE_CTCDISABLE_H_WIDTH 1
+#define        FRF_AB_PCIE_CTCDISABLE_L_LBN 12
+#define        FRF_AB_PCIE_CTCDISABLE_L_WIDTH 1
+#define        FRF_AB_PCIE_PRBSSYNC_H_LBN 11
+#define        FRF_AB_PCIE_PRBSSYNC_H_WIDTH 1
+#define        FRF_AB_PCIE_PRBSSYNC_L_LBN 10
+#define        FRF_AB_PCIE_PRBSSYNC_L_WIDTH 1
+#define        FRF_AB_PCIE_PRBSERRACK_H_LBN 9
+#define        FRF_AB_PCIE_PRBSERRACK_H_WIDTH 1
+#define        FRF_AB_PCIE_PRBSERRACK_L_LBN 8
+#define        FRF_AB_PCIE_PRBSERRACK_L_WIDTH 1
+#define        FRF_AB_PCIE_PRBSSEL_LBN 0
+#define        FRF_AB_PCIE_PRBSSEL_WIDTH 8
+
+/* DEBUG_DATA_OUT_REG: Live Debug and Debug 2 out ports */
+#define        FR_BB_DEBUG_DATA_OUT 0x00000350
+#define        FRF_BB_DEBUG2_PORT_LBN 25
+#define        FRF_BB_DEBUG2_PORT_WIDTH 15
+#define        FRF_BB_DEBUG1_PORT_LBN 0
+#define        FRF_BB_DEBUG1_PORT_WIDTH 25
+
+/* EVQ_RPTR_REGP0: Event queue read pointer register */
+#define        FR_BZ_EVQ_RPTR_P0 0x00000400
+#define        FR_BZ_EVQ_RPTR_P0_STEP 8192
+#define        FR_BZ_EVQ_RPTR_P0_ROWS 1024
+/* EVQ_RPTR_REG_KER: Event queue read pointer register */
+#define        FR_AA_EVQ_RPTR_KER 0x00011b00
+#define        FR_AA_EVQ_RPTR_KER_STEP 4
+#define        FR_AA_EVQ_RPTR_KER_ROWS 4
+/* EVQ_RPTR_REG: Event queue read pointer register */
+#define        FR_BZ_EVQ_RPTR 0x00fa0000
+#define        FR_BZ_EVQ_RPTR_STEP 16
+#define        FR_BB_EVQ_RPTR_ROWS 4096
+#define        FR_CZ_EVQ_RPTR_ROWS 1024
+/* EVQ_RPTR_REGP123: Event queue read pointer register */
+#define        FR_BB_EVQ_RPTR_P123 0x01000400
+#define        FR_BB_EVQ_RPTR_P123_STEP 8192
+#define        FR_BB_EVQ_RPTR_P123_ROWS 3072
+#define        FRF_AZ_EVQ_RPTR_VLD_LBN 15
+#define        FRF_AZ_EVQ_RPTR_VLD_WIDTH 1
+#define        FRF_AZ_EVQ_RPTR_LBN 0
+#define        FRF_AZ_EVQ_RPTR_WIDTH 15
+
+/* TIMER_COMMAND_REGP0: Timer Command Registers */
+#define        FR_BZ_TIMER_COMMAND_P0 0x00000420
+#define        FR_BZ_TIMER_COMMAND_P0_STEP 8192
+#define        FR_BZ_TIMER_COMMAND_P0_ROWS 1024
+/* TIMER_COMMAND_REG_KER: Timer Command Registers */
+#define        FR_AA_TIMER_COMMAND_KER 0x00000420
+#define        FR_AA_TIMER_COMMAND_KER_STEP 8192
+#define        FR_AA_TIMER_COMMAND_KER_ROWS 4
+/* TIMER_COMMAND_REGP123: Timer Command Registers */
+#define        FR_BB_TIMER_COMMAND_P123 0x01000420
+#define        FR_BB_TIMER_COMMAND_P123_STEP 8192
+#define        FR_BB_TIMER_COMMAND_P123_ROWS 3072
+#define        FRF_CZ_TC_TIMER_MODE_LBN 14
+#define        FRF_CZ_TC_TIMER_MODE_WIDTH 2
+#define        FRF_AB_TC_TIMER_MODE_LBN 12
+#define        FRF_AB_TC_TIMER_MODE_WIDTH 2
+#define        FRF_CZ_TC_TIMER_VAL_LBN 0
+#define        FRF_CZ_TC_TIMER_VAL_WIDTH 14
+#define        FRF_AB_TC_TIMER_VAL_LBN 0
+#define        FRF_AB_TC_TIMER_VAL_WIDTH 12
+
+/* DRV_EV_REG: Driver generated event register */
+#define        FR_AZ_DRV_EV 0x00000440
+#define        FRF_AZ_DRV_EV_QID_LBN 64
+#define        FRF_AZ_DRV_EV_QID_WIDTH 12
+#define        FRF_AZ_DRV_EV_DATA_LBN 0
+#define        FRF_AZ_DRV_EV_DATA_WIDTH 64
+
+/* EVQ_CTL_REG: Event queue control register */
+#define        FR_AZ_EVQ_CTL 0x00000450
+#define        FRF_CZ_RX_EVQ_WAKEUP_MASK_LBN 15
+#define        FRF_CZ_RX_EVQ_WAKEUP_MASK_WIDTH 10
+#define        FRF_BB_RX_EVQ_WAKEUP_MASK_LBN 15
+#define        FRF_BB_RX_EVQ_WAKEUP_MASK_WIDTH 6
+#define        FRF_AZ_EVQ_OWNERR_CTL_LBN 14
+#define        FRF_AZ_EVQ_OWNERR_CTL_WIDTH 1
+#define        FRF_AZ_EVQ_FIFO_AF_TH_LBN 7
+#define        FRF_AZ_EVQ_FIFO_AF_TH_WIDTH 7
+#define        FRF_AZ_EVQ_FIFO_NOTAF_TH_LBN 0
+#define        FRF_AZ_EVQ_FIFO_NOTAF_TH_WIDTH 7
+
+/* EVQ_CNT1_REG: Event counter 1 register */
+#define        FR_AZ_EVQ_CNT1 0x00000460
+#define        FRF_AZ_EVQ_CNT_PRE_FIFO_LBN 120
+#define        FRF_AZ_EVQ_CNT_PRE_FIFO_WIDTH 7
+#define        FRF_AZ_EVQ_CNT_TOBIU_LBN 100
+#define        FRF_AZ_EVQ_CNT_TOBIU_WIDTH 20
+#define        FRF_AZ_EVQ_TX_REQ_CNT_LBN 80
+#define        FRF_AZ_EVQ_TX_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_RX_REQ_CNT_LBN 60
+#define        FRF_AZ_EVQ_RX_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_EM_REQ_CNT_LBN 40
+#define        FRF_AZ_EVQ_EM_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_CSR_REQ_CNT_LBN 20
+#define        FRF_AZ_EVQ_CSR_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_ERR_REQ_CNT_LBN 0
+#define        FRF_AZ_EVQ_ERR_REQ_CNT_WIDTH 20
+
+/* EVQ_CNT2_REG: Event counter 2 register */
+#define        FR_AZ_EVQ_CNT2 0x00000470
+#define        FRF_AZ_EVQ_UPD_REQ_CNT_LBN 104
+#define        FRF_AZ_EVQ_UPD_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_CLR_REQ_CNT_LBN 84
+#define        FRF_AZ_EVQ_CLR_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_RDY_CNT_LBN 80
+#define        FRF_AZ_EVQ_RDY_CNT_WIDTH 4
+#define        FRF_AZ_EVQ_WU_REQ_CNT_LBN 60
+#define        FRF_AZ_EVQ_WU_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_WET_REQ_CNT_LBN 40
+#define        FRF_AZ_EVQ_WET_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_INIT_REQ_CNT_LBN 20
+#define        FRF_AZ_EVQ_INIT_REQ_CNT_WIDTH 20
+#define        FRF_AZ_EVQ_TM_REQ_CNT_LBN 0
+#define        FRF_AZ_EVQ_TM_REQ_CNT_WIDTH 20
+
+/* USR_EV_REG: Event mailbox register */
+#define        FR_CZ_USR_EV 0x00000540
+#define        FR_CZ_USR_EV_STEP 8192
+#define        FR_CZ_USR_EV_ROWS 1024
+#define        FRF_CZ_USR_EV_DATA_LBN 0
+#define        FRF_CZ_USR_EV_DATA_WIDTH 32
+
+/* BUF_TBL_CFG_REG: Buffer table configuration register */
+#define        FR_AZ_BUF_TBL_CFG 0x00000600
+#define        FRF_AZ_BUF_TBL_MODE_LBN 3
+#define        FRF_AZ_BUF_TBL_MODE_WIDTH 1
+
+/* SRM_RX_DC_CFG_REG: SRAM receive descriptor cache configuration register */
+#define        FR_AZ_SRM_RX_DC_CFG 0x00000610
+#define        FRF_AZ_SRM_CLK_TMP_EN_LBN 21
+#define        FRF_AZ_SRM_CLK_TMP_EN_WIDTH 1
+#define        FRF_AZ_SRM_RX_DC_BASE_ADR_LBN 0
+#define        FRF_AZ_SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRM_TX_DC_CFG_REG: SRAM transmit descriptor cache configuration register */
+#define        FR_AZ_SRM_TX_DC_CFG 0x00000620
+#define        FRF_AZ_SRM_TX_DC_BASE_ADR_LBN 0
+#define        FRF_AZ_SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRM_CFG_REG: SRAM configuration register */
+#define        FR_AZ_SRM_CFG 0x00000630
+#define        FRF_AZ_SRM_OOB_ADR_INTEN_LBN 5
+#define        FRF_AZ_SRM_OOB_ADR_INTEN_WIDTH 1
+#define        FRF_AZ_SRM_OOB_BUF_INTEN_LBN 4
+#define        FRF_AZ_SRM_OOB_BUF_INTEN_WIDTH 1
+#define        FRF_AZ_SRM_INIT_EN_LBN 3
+#define        FRF_AZ_SRM_INIT_EN_WIDTH 1
+#define        FRF_AZ_SRM_NUM_BANK_LBN 2
+#define        FRF_AZ_SRM_NUM_BANK_WIDTH 1
+#define        FRF_AZ_SRM_BANK_SIZE_LBN 0
+#define        FRF_AZ_SRM_BANK_SIZE_WIDTH 2
+
+/* BUF_TBL_UPD_REG: Buffer table update register */
+#define        FR_AZ_BUF_TBL_UPD 0x00000650
+#define        FRF_AZ_BUF_UPD_CMD_LBN 63
+#define        FRF_AZ_BUF_UPD_CMD_WIDTH 1
+#define        FRF_AZ_BUF_CLR_CMD_LBN 62
+#define        FRF_AZ_BUF_CLR_CMD_WIDTH 1
+#define        FRF_AZ_BUF_CLR_END_ID_LBN 32
+#define        FRF_AZ_BUF_CLR_END_ID_WIDTH 20
+#define        FRF_AZ_BUF_CLR_START_ID_LBN 0
+#define        FRF_AZ_BUF_CLR_START_ID_WIDTH 20
+
+/* SRM_UPD_EVQ_REG: Buffer table update register */
+#define        FR_AZ_SRM_UPD_EVQ 0x00000660
+#define        FRF_AZ_SRM_UPD_EVQ_ID_LBN 0
+#define        FRF_AZ_SRM_UPD_EVQ_ID_WIDTH 12
+
+/* SRAM_PARITY_REG: SRAM parity register. */
+#define        FR_AZ_SRAM_PARITY 0x00000670
+#define        FRF_CZ_BYPASS_ECC_LBN 3
+#define        FRF_CZ_BYPASS_ECC_WIDTH 1
+#define        FRF_CZ_SEC_INT_LBN 2
+#define        FRF_CZ_SEC_INT_WIDTH 1
+#define        FRF_CZ_FORCE_SRAM_DOUBLE_ERR_LBN 1
+#define        FRF_CZ_FORCE_SRAM_DOUBLE_ERR_WIDTH 1
+#define        FRF_AB_FORCE_SRAM_PERR_LBN 0
+#define        FRF_AB_FORCE_SRAM_PERR_WIDTH 1
+#define        FRF_CZ_FORCE_SRAM_SINGLE_ERR_LBN 0
+#define        FRF_CZ_FORCE_SRAM_SINGLE_ERR_WIDTH 1
+
+/* RX_CFG_REG: Receive configuration register */
+#define        FR_AZ_RX_CFG 0x00000800
+#define        FRF_CZ_RX_MIN_KBUF_SIZE_LBN 72
+#define        FRF_CZ_RX_MIN_KBUF_SIZE_WIDTH 14
+#define        FRF_CZ_RX_HDR_SPLIT_EN_LBN 71
+#define        FRF_CZ_RX_HDR_SPLIT_EN_WIDTH 1
+#define        FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_LBN 62
+#define        FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_WIDTH 9
+#define        FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_LBN 53
+#define        FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_WIDTH 9
+#define        FRF_CZ_RX_PRE_RFF_IPG_LBN 49
+#define        FRF_CZ_RX_PRE_RFF_IPG_WIDTH 4
+#define        FRF_BZ_RX_TCP_SUP_LBN 48
+#define        FRF_BZ_RX_TCP_SUP_WIDTH 1
+#define        FRF_BZ_RX_INGR_EN_LBN 47
+#define        FRF_BZ_RX_INGR_EN_WIDTH 1
+#define        FRF_BZ_RX_IP_HASH_LBN 46
+#define        FRF_BZ_RX_IP_HASH_WIDTH 1
+#define        FRF_BZ_RX_HASH_ALG_LBN 45
+#define        FRF_BZ_RX_HASH_ALG_WIDTH 1
+#define        FRF_BZ_RX_HASH_INSRT_HDR_LBN 44
+#define        FRF_BZ_RX_HASH_INSRT_HDR_WIDTH 1
+#define        FRF_BZ_RX_DESC_PUSH_EN_LBN 43
+#define        FRF_BZ_RX_DESC_PUSH_EN_WIDTH 1
+#define        FRF_BZ_RX_RDW_PATCH_EN_LBN 42
+#define        FRF_BZ_RX_RDW_PATCH_EN_WIDTH 1
+#define        FRF_BB_RX_PCI_BURST_SIZE_LBN 39
+#define        FRF_BB_RX_PCI_BURST_SIZE_WIDTH 3
+#define        FRF_BZ_RX_OWNERR_CTL_LBN 38
+#define        FRF_BZ_RX_OWNERR_CTL_WIDTH 1
+#define        FRF_BZ_RX_XON_TX_TH_LBN 33
+#define        FRF_BZ_RX_XON_TX_TH_WIDTH 5
+#define        FRF_AA_RX_DESC_PUSH_EN_LBN 35
+#define        FRF_AA_RX_DESC_PUSH_EN_WIDTH 1
+#define        FRF_AA_RX_RDW_PATCH_EN_LBN 34
+#define        FRF_AA_RX_RDW_PATCH_EN_WIDTH 1
+#define        FRF_AA_RX_PCI_BURST_SIZE_LBN 31
+#define        FRF_AA_RX_PCI_BURST_SIZE_WIDTH 3
+#define        FRF_BZ_RX_XOFF_TX_TH_LBN 28
+#define        FRF_BZ_RX_XOFF_TX_TH_WIDTH 5
+#define        FRF_AA_RX_OWNERR_CTL_LBN 30
+#define        FRF_AA_RX_OWNERR_CTL_WIDTH 1
+#define        FRF_AA_RX_XON_TX_TH_LBN 25
+#define        FRF_AA_RX_XON_TX_TH_WIDTH 5
+#define        FRF_BZ_RX_USR_BUF_SIZE_LBN 19
+#define        FRF_BZ_RX_USR_BUF_SIZE_WIDTH 9
+#define        FRF_AA_RX_XOFF_TX_TH_LBN 20
+#define        FRF_AA_RX_XOFF_TX_TH_WIDTH 5
+#define        FRF_AA_RX_USR_BUF_SIZE_LBN 11
+#define        FRF_AA_RX_USR_BUF_SIZE_WIDTH 9
+#define        FRF_BZ_RX_XON_MAC_TH_LBN 10
+#define        FRF_BZ_RX_XON_MAC_TH_WIDTH 9
+#define        FRF_AA_RX_XON_MAC_TH_LBN 6
+#define        FRF_AA_RX_XON_MAC_TH_WIDTH 5
+#define        FRF_BZ_RX_XOFF_MAC_TH_LBN 1
+#define        FRF_BZ_RX_XOFF_MAC_TH_WIDTH 9
+#define        FRF_AA_RX_XOFF_MAC_TH_LBN 1
+#define        FRF_AA_RX_XOFF_MAC_TH_WIDTH 5
+#define        FRF_AZ_RX_XOFF_MAC_EN_LBN 0
+#define        FRF_AZ_RX_XOFF_MAC_EN_WIDTH 1
+
+/* RX_FILTER_CTL_REG: Receive filter control registers */
+#define        FR_BZ_RX_FILTER_CTL 0x00000810
+#define        FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_LBN 94
+#define        FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_WIDTH 8
+#define        FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_LBN 86
+#define        FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_WIDTH 8
+#define        FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_LBN 85
+#define        FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_WIDTH 1
+#define        FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_LBN 69
+#define        FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_WIDTH 16
+#define        FRF_CZ_MULTICAST_NOMATCH_Q_ID_LBN 57
+#define        FRF_CZ_MULTICAST_NOMATCH_Q_ID_WIDTH 12
+#define        FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_LBN 56
+#define        FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_WIDTH 1
+#define        FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_LBN 55
+#define        FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
+#define        FRF_CZ_UNICAST_NOMATCH_Q_ID_LBN 43
+#define        FRF_CZ_UNICAST_NOMATCH_Q_ID_WIDTH 12
+#define        FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_LBN 42
+#define        FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_WIDTH 1
+#define        FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_LBN 41
+#define        FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
+#define        FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_LBN 40
+#define        FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_WIDTH 1
+#define        FRF_BZ_UDP_FULL_SRCH_LIMIT_LBN 32
+#define        FRF_BZ_UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define        FRF_BZ_NUM_KER_LBN 24
+#define        FRF_BZ_NUM_KER_WIDTH 2
+#define        FRF_BZ_UDP_WILD_SRCH_LIMIT_LBN 16
+#define        FRF_BZ_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define        FRF_BZ_TCP_WILD_SRCH_LIMIT_LBN 8
+#define        FRF_BZ_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define        FRF_BZ_TCP_FULL_SRCH_LIMIT_LBN 0
+#define        FRF_BZ_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX_FLUSH_DESCQ_REG: Receive flush descriptor queue register */
+#define        FR_AZ_RX_FLUSH_DESCQ 0x00000820
+#define        FRF_AZ_RX_FLUSH_DESCQ_CMD_LBN 24
+#define        FRF_AZ_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define        FRF_AZ_RX_FLUSH_DESCQ_LBN 0
+#define        FRF_AZ_RX_FLUSH_DESCQ_WIDTH 12
+
+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
+#define        FR_BZ_RX_DESC_UPD_P0 0x00000830
+#define        FR_BZ_RX_DESC_UPD_P0_STEP 8192
+#define        FR_BZ_RX_DESC_UPD_P0_ROWS 1024
+/* RX_DESC_UPD_REG_KER: Receive descriptor update register. */
+#define        FR_AA_RX_DESC_UPD_KER 0x00000830
+#define        FR_AA_RX_DESC_UPD_KER_STEP 8192
+#define        FR_AA_RX_DESC_UPD_KER_ROWS 4
+/* RX_DESC_UPD_REGP123: Receive descriptor update register. */
+#define        FR_BB_RX_DESC_UPD_P123 0x01000830
+#define        FR_BB_RX_DESC_UPD_P123_STEP 8192
+#define        FR_BB_RX_DESC_UPD_P123_ROWS 3072
+#define        FRF_AZ_RX_DESC_WPTR_LBN 96
+#define        FRF_AZ_RX_DESC_WPTR_WIDTH 12
+#define        FRF_AZ_RX_DESC_PUSH_CMD_LBN 95
+#define        FRF_AZ_RX_DESC_PUSH_CMD_WIDTH 1
+#define        FRF_AZ_RX_DESC_LBN 0
+#define        FRF_AZ_RX_DESC_WIDTH 64
+
+/* RX_DC_CFG_REG: Receive descriptor cache configuration register */
+#define        FR_AZ_RX_DC_CFG 0x00000840
+#define        FRF_AB_RX_MAX_PF_LBN 2
+#define        FRF_AB_RX_MAX_PF_WIDTH 2
+#define        FRF_AZ_RX_DC_SIZE_LBN 0
+#define        FRF_AZ_RX_DC_SIZE_WIDTH 2
+#define        FFE_AZ_RX_DC_SIZE_64 3
+#define        FFE_AZ_RX_DC_SIZE_32 2
+#define        FFE_AZ_RX_DC_SIZE_16 1
+#define        FFE_AZ_RX_DC_SIZE_8 0
+
+/* RX_DC_PF_WM_REG: Receive descriptor cache pre-fetch watermark register */
+#define        FR_AZ_RX_DC_PF_WM 0x00000850
+#define        FRF_AZ_RX_DC_PF_HWM_LBN 6
+#define        FRF_AZ_RX_DC_PF_HWM_WIDTH 6
+#define        FRF_AZ_RX_DC_PF_LWM_LBN 0
+#define        FRF_AZ_RX_DC_PF_LWM_WIDTH 6
+
+/* RX_RSS_TKEY_REG: RSS Toeplitz hash key */
+#define        FR_BZ_RX_RSS_TKEY 0x00000860
+#define        FRF_BZ_RX_RSS_TKEY_HI_LBN 64
+#define        FRF_BZ_RX_RSS_TKEY_HI_WIDTH 64
+#define        FRF_BZ_RX_RSS_TKEY_LO_LBN 0
+#define        FRF_BZ_RX_RSS_TKEY_LO_WIDTH 64
+
+/* RX_NODESC_DROP_REG: Receive dropped packet counter register */
+#define        FR_AZ_RX_NODESC_DROP 0x00000880
+#define        FRF_CZ_RX_NODESC_DROP_CNT_LBN 0
+#define        FRF_CZ_RX_NODESC_DROP_CNT_WIDTH 32
+#define        FRF_AB_RX_NODESC_DROP_CNT_LBN 0
+#define        FRF_AB_RX_NODESC_DROP_CNT_WIDTH 16
+
+/* RX_SELF_RST_REG: Receive self reset register */
+#define        FR_AA_RX_SELF_RST 0x00000890
+#define        FRF_AA_RX_ISCSI_DIS_LBN 17
+#define        FRF_AA_RX_ISCSI_DIS_WIDTH 1
+#define        FRF_AA_RX_SW_RST_REG_LBN 16
+#define        FRF_AA_RX_SW_RST_REG_WIDTH 1
+#define        FRF_AA_RX_NODESC_WAIT_DIS_LBN 9
+#define        FRF_AA_RX_NODESC_WAIT_DIS_WIDTH 1
+#define        FRF_AA_RX_SELF_RST_EN_LBN 8
+#define        FRF_AA_RX_SELF_RST_EN_WIDTH 1
+#define        FRF_AA_RX_MAX_PF_LAT_LBN 4
+#define        FRF_AA_RX_MAX_PF_LAT_WIDTH 4
+#define        FRF_AA_RX_MAX_LU_LAT_LBN 0
+#define        FRF_AA_RX_MAX_LU_LAT_WIDTH 4
+
+/* RX_DEBUG_REG: undocumented register */
+#define        FR_AZ_RX_DEBUG 0x000008a0
+#define        FRF_AZ_RX_DEBUG_LBN 0
+#define        FRF_AZ_RX_DEBUG_WIDTH 64
+
+/* RX_PUSH_DROP_REG: Receive descriptor push dropped counter register */
+#define        FR_AZ_RX_PUSH_DROP 0x000008b0
+#define        FRF_AZ_RX_PUSH_DROP_CNT_LBN 0
+#define        FRF_AZ_RX_PUSH_DROP_CNT_WIDTH 32
+
+/* RX_RSS_IPV6_REG1: IPv6 RSS Toeplitz hash key low bytes */
+#define        FR_CZ_RX_RSS_IPV6_REG1 0x000008d0
+#define        FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN 0
+#define        FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH 128
+
+/* RX_RSS_IPV6_REG2: IPv6 RSS Toeplitz hash key middle bytes */
+#define        FR_CZ_RX_RSS_IPV6_REG2 0x000008e0
+#define        FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN 0
+#define        FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH 128
+
+/* RX_RSS_IPV6_REG3: IPv6 RSS Toeplitz hash key upper bytes and IPv6 RSS settings */
+#define        FR_CZ_RX_RSS_IPV6_REG3 0x000008f0
+#define        FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_LBN 66
+#define        FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_WIDTH 1
+#define        FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_LBN 65
+#define        FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_WIDTH 1
+#define        FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_LBN 64
+#define        FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_WIDTH 1
+#define        FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN 0
+#define        FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH 64
+
+/* TX_FLUSH_DESCQ_REG: Transmit flush descriptor queue register */
+#define        FR_AZ_TX_FLUSH_DESCQ 0x00000a00
+#define        FRF_AZ_TX_FLUSH_DESCQ_CMD_LBN 12
+#define        FRF_AZ_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define        FRF_AZ_TX_FLUSH_DESCQ_LBN 0
+#define        FRF_AZ_TX_FLUSH_DESCQ_WIDTH 12
+
+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
+#define        FR_BZ_TX_DESC_UPD_P0 0x00000a10
+#define        FR_BZ_TX_DESC_UPD_P0_STEP 8192
+#define        FR_BZ_TX_DESC_UPD_P0_ROWS 1024
+/* TX_DESC_UPD_REG_KER: Transmit descriptor update register. */
+#define        FR_AA_TX_DESC_UPD_KER 0x00000a10
+#define        FR_AA_TX_DESC_UPD_KER_STEP 8192
+#define        FR_AA_TX_DESC_UPD_KER_ROWS 8
+/* TX_DESC_UPD_REGP123: Transmit descriptor update register. */
+#define        FR_BB_TX_DESC_UPD_P123 0x01000a10
+#define        FR_BB_TX_DESC_UPD_P123_STEP 8192
+#define        FR_BB_TX_DESC_UPD_P123_ROWS 3072
+#define        FRF_AZ_TX_DESC_WPTR_LBN 96
+#define        FRF_AZ_TX_DESC_WPTR_WIDTH 12
+#define        FRF_AZ_TX_DESC_PUSH_CMD_LBN 95
+#define        FRF_AZ_TX_DESC_PUSH_CMD_WIDTH 1
+#define        FRF_AZ_TX_DESC_LBN 0
+#define        FRF_AZ_TX_DESC_WIDTH 95
+
+/* TX_DC_CFG_REG: Transmit descriptor cache configuration register */
+#define        FR_AZ_TX_DC_CFG 0x00000a20
+#define        FRF_AZ_TX_DC_SIZE_LBN 0
+#define        FRF_AZ_TX_DC_SIZE_WIDTH 2
+#define        FFE_AZ_TX_DC_SIZE_32 2
+#define        FFE_AZ_TX_DC_SIZE_16 1
+#define        FFE_AZ_TX_DC_SIZE_8 0
+
+/* TX_CHKSM_CFG_REG: Transmit checksum configuration register */
+#define        FR_AA_TX_CHKSM_CFG 0x00000a30
+#define        FRF_AA_TX_Q_CHKSM_DIS_96_127_LBN 96
+#define        FRF_AA_TX_Q_CHKSM_DIS_96_127_WIDTH 32
+#define        FRF_AA_TX_Q_CHKSM_DIS_64_95_LBN 64
+#define        FRF_AA_TX_Q_CHKSM_DIS_64_95_WIDTH 32
+#define        FRF_AA_TX_Q_CHKSM_DIS_32_63_LBN 32
+#define        FRF_AA_TX_Q_CHKSM_DIS_32_63_WIDTH 32
+#define        FRF_AA_TX_Q_CHKSM_DIS_0_31_LBN 0
+#define        FRF_AA_TX_Q_CHKSM_DIS_0_31_WIDTH 32
+
+/* TX_CFG_REG: Transmit configuration register */
+#define        FR_AZ_TX_CFG 0x00000a50
+#define        FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_LBN 114
+#define        FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_FILTER_TEST_MODE_BIT_LBN 113
+#define        FRF_CZ_TX_FILTER_TEST_MODE_BIT_WIDTH 1
+#define        FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_LBN 105
+#define        FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_LBN 97
+#define        FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_LBN 89
+#define        FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_LBN 81
+#define        FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_LBN 73
+#define        FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_LBN 65
+#define        FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define        FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_LBN 64
+#define        FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_WIDTH 1
+#define        FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_LBN 48
+#define        FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_WIDTH 16
+#define        FRF_CZ_TX_FILTER_EN_BIT_LBN 47
+#define        FRF_CZ_TX_FILTER_EN_BIT_WIDTH 1
+#define        FRF_AZ_TX_IP_ID_P0_OFS_LBN 16
+#define        FRF_AZ_TX_IP_ID_P0_OFS_WIDTH 15
+#define        FRF_AZ_TX_NO_EOP_DISC_EN_LBN 5
+#define        FRF_AZ_TX_NO_EOP_DISC_EN_WIDTH 1
+#define        FRF_AZ_TX_P1_PRI_EN_LBN 4
+#define        FRF_AZ_TX_P1_PRI_EN_WIDTH 1
+#define        FRF_AZ_TX_OWNERR_CTL_LBN 2
+#define        FRF_AZ_TX_OWNERR_CTL_WIDTH 1
+#define        FRF_AA_TX_NON_IP_DROP_DIS_LBN 1
+#define        FRF_AA_TX_NON_IP_DROP_DIS_WIDTH 1
+#define        FRF_AZ_TX_IP_ID_REP_EN_LBN 0
+#define        FRF_AZ_TX_IP_ID_REP_EN_WIDTH 1
+
+/* TX_PUSH_DROP_REG: Transmit push dropped register */
+#define        FR_AZ_TX_PUSH_DROP 0x00000a60
+#define        FRF_AZ_TX_PUSH_DROP_CNT_LBN 0
+#define        FRF_AZ_TX_PUSH_DROP_CNT_WIDTH 32
+
+/* TX_RESERVED_REG: Transmit configuration register */
+#define        FR_AZ_TX_RESERVED 0x00000a80
+#define        FRF_AZ_TX_EVT_CNT_LBN 121
+#define        FRF_AZ_TX_EVT_CNT_WIDTH 7
+#define        FRF_AZ_TX_PREF_AGE_CNT_LBN 119
+#define        FRF_AZ_TX_PREF_AGE_CNT_WIDTH 2
+#define        FRF_AZ_TX_RD_COMP_TMR_LBN 96
+#define        FRF_AZ_TX_RD_COMP_TMR_WIDTH 23
+#define        FRF_AZ_TX_PUSH_EN_LBN 89
+#define        FRF_AZ_TX_PUSH_EN_WIDTH 1
+#define        FRF_AZ_TX_PUSH_CHK_DIS_LBN 88
+#define        FRF_AZ_TX_PUSH_CHK_DIS_WIDTH 1
+#define        FRF_AZ_TX_D_FF_FULL_P0_LBN 85
+#define        FRF_AZ_TX_D_FF_FULL_P0_WIDTH 1
+#define        FRF_AZ_TX_DMAR_ST_P0_LBN 81
+#define        FRF_AZ_TX_DMAR_ST_P0_WIDTH 1
+#define        FRF_AZ_TX_DMAQ_ST_LBN 78
+#define        FRF_AZ_TX_DMAQ_ST_WIDTH 1
+#define        FRF_AZ_TX_RX_SPACER_LBN 64
+#define        FRF_AZ_TX_RX_SPACER_WIDTH 8
+#define        FRF_AZ_TX_DROP_ABORT_EN_LBN 60
+#define        FRF_AZ_TX_DROP_ABORT_EN_WIDTH 1
+#define        FRF_AZ_TX_SOFT_EVT_EN_LBN 59
+#define        FRF_AZ_TX_SOFT_EVT_EN_WIDTH 1
+#define        FRF_AZ_TX_PS_EVT_DIS_LBN 58
+#define        FRF_AZ_TX_PS_EVT_DIS_WIDTH 1
+#define        FRF_AZ_TX_RX_SPACER_EN_LBN 57
+#define        FRF_AZ_TX_RX_SPACER_EN_WIDTH 1
+#define        FRF_AZ_TX_XP_TIMER_LBN 52
+#define        FRF_AZ_TX_XP_TIMER_WIDTH 5
+#define        FRF_AZ_TX_PREF_SPACER_LBN 44
+#define        FRF_AZ_TX_PREF_SPACER_WIDTH 8
+#define        FRF_AZ_TX_PREF_WD_TMR_LBN 22
+#define        FRF_AZ_TX_PREF_WD_TMR_WIDTH 22
+#define        FRF_AZ_TX_ONLY1TAG_LBN 21
+#define        FRF_AZ_TX_ONLY1TAG_WIDTH 1
+#define        FRF_AZ_TX_PREF_THRESHOLD_LBN 19
+#define        FRF_AZ_TX_PREF_THRESHOLD_WIDTH 2
+#define        FRF_AZ_TX_ONE_PKT_PER_Q_LBN 18
+#define        FRF_AZ_TX_ONE_PKT_PER_Q_WIDTH 1
+#define        FRF_AZ_TX_DIS_NON_IP_EV_LBN 17
+#define        FRF_AZ_TX_DIS_NON_IP_EV_WIDTH 1
+#define        FRF_AA_TX_DMA_FF_THR_LBN 16
+#define        FRF_AA_TX_DMA_FF_THR_WIDTH 1
+#define        FRF_AZ_TX_DMA_SPACER_LBN 8
+#define        FRF_AZ_TX_DMA_SPACER_WIDTH 8
+#define        FRF_AA_TX_TCP_DIS_LBN 7
+#define        FRF_AA_TX_TCP_DIS_WIDTH 1
+#define        FRF_BZ_TX_FLUSH_MIN_LEN_EN_LBN 7
+#define        FRF_BZ_TX_FLUSH_MIN_LEN_EN_WIDTH 1
+#define        FRF_AA_TX_IP_DIS_LBN 6
+#define        FRF_AA_TX_IP_DIS_WIDTH 1
+#define        FRF_AZ_TX_MAX_CPL_LBN 2
+#define        FRF_AZ_TX_MAX_CPL_WIDTH 2
+#define        FFE_AZ_TX_MAX_CPL_16 3
+#define        FFE_AZ_TX_MAX_CPL_8 2
+#define        FFE_AZ_TX_MAX_CPL_4 1
+#define        FFE_AZ_TX_MAX_CPL_NOLIMIT 0
+#define        FRF_AZ_TX_MAX_PREF_LBN 0
+#define        FRF_AZ_TX_MAX_PREF_WIDTH 2
+#define        FFE_AZ_TX_MAX_PREF_32 3
+#define        FFE_AZ_TX_MAX_PREF_16 2
+#define        FFE_AZ_TX_MAX_PREF_8 1
+#define        FFE_AZ_TX_MAX_PREF_OFF 0
+
+/* TX_PACE_REG: Transmit pace control register */
+#define        FR_BZ_TX_PACE 0x00000a90
+#define        FRF_BZ_TX_PACE_SB_NOT_AF_LBN 19
+#define        FRF_BZ_TX_PACE_SB_NOT_AF_WIDTH 10
+#define        FRF_BZ_TX_PACE_SB_AF_LBN 9
+#define        FRF_BZ_TX_PACE_SB_AF_WIDTH 10
+#define        FRF_BZ_TX_PACE_FB_BASE_LBN 5
+#define        FRF_BZ_TX_PACE_FB_BASE_WIDTH 4
+#define        FRF_BZ_TX_PACE_BIN_TH_LBN 0
+#define        FRF_BZ_TX_PACE_BIN_TH_WIDTH 5
+
+/* TX_PACE_DROP_QID_REG: PACE Drop QID Counter */
+#define        FR_BZ_TX_PACE_DROP_QID 0x00000aa0
+#define        FRF_BZ_TX_PACE_QID_DRP_CNT_LBN 0
+#define        FRF_BZ_TX_PACE_QID_DRP_CNT_WIDTH 16
+
+/* TX_VLAN_REG: Transmit VLAN tag register */
+#define        FR_BB_TX_VLAN 0x00000ae0
+#define        FRF_BB_TX_VLAN_EN_LBN 127
+#define        FRF_BB_TX_VLAN_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN7_PORT1_EN_LBN 125
+#define        FRF_BB_TX_VLAN7_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN7_PORT0_EN_LBN 124
+#define        FRF_BB_TX_VLAN7_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN7_LBN 112
+#define        FRF_BB_TX_VLAN7_WIDTH 12
+#define        FRF_BB_TX_VLAN6_PORT1_EN_LBN 109
+#define        FRF_BB_TX_VLAN6_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN6_PORT0_EN_LBN 108
+#define        FRF_BB_TX_VLAN6_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN6_LBN 96
+#define        FRF_BB_TX_VLAN6_WIDTH 12
+#define        FRF_BB_TX_VLAN5_PORT1_EN_LBN 93
+#define        FRF_BB_TX_VLAN5_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN5_PORT0_EN_LBN 92
+#define        FRF_BB_TX_VLAN5_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN5_LBN 80
+#define        FRF_BB_TX_VLAN5_WIDTH 12
+#define        FRF_BB_TX_VLAN4_PORT1_EN_LBN 77
+#define        FRF_BB_TX_VLAN4_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN4_PORT0_EN_LBN 76
+#define        FRF_BB_TX_VLAN4_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN4_LBN 64
+#define        FRF_BB_TX_VLAN4_WIDTH 12
+#define        FRF_BB_TX_VLAN3_PORT1_EN_LBN 61
+#define        FRF_BB_TX_VLAN3_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN3_PORT0_EN_LBN 60
+#define        FRF_BB_TX_VLAN3_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN3_LBN 48
+#define        FRF_BB_TX_VLAN3_WIDTH 12
+#define        FRF_BB_TX_VLAN2_PORT1_EN_LBN 45
+#define        FRF_BB_TX_VLAN2_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN2_PORT0_EN_LBN 44
+#define        FRF_BB_TX_VLAN2_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN2_LBN 32
+#define        FRF_BB_TX_VLAN2_WIDTH 12
+#define        FRF_BB_TX_VLAN1_PORT1_EN_LBN 29
+#define        FRF_BB_TX_VLAN1_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN1_PORT0_EN_LBN 28
+#define        FRF_BB_TX_VLAN1_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN1_LBN 16
+#define        FRF_BB_TX_VLAN1_WIDTH 12
+#define        FRF_BB_TX_VLAN0_PORT1_EN_LBN 13
+#define        FRF_BB_TX_VLAN0_PORT1_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN0_PORT0_EN_LBN 12
+#define        FRF_BB_TX_VLAN0_PORT0_EN_WIDTH 1
+#define        FRF_BB_TX_VLAN0_LBN 0
+#define        FRF_BB_TX_VLAN0_WIDTH 12
+
+/* TX_IPFIL_PORTEN_REG: Transmit filter control register */
+#define        FR_BZ_TX_IPFIL_PORTEN 0x00000af0
+#define        FRF_BZ_TX_MADR0_FIL_EN_LBN 64
+#define        FRF_BZ_TX_MADR0_FIL_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL31_PORT_EN_LBN 62
+#define        FRF_BB_TX_IPFIL31_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL30_PORT_EN_LBN 60
+#define        FRF_BB_TX_IPFIL30_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL29_PORT_EN_LBN 58
+#define        FRF_BB_TX_IPFIL29_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL28_PORT_EN_LBN 56
+#define        FRF_BB_TX_IPFIL28_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL27_PORT_EN_LBN 54
+#define        FRF_BB_TX_IPFIL27_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL26_PORT_EN_LBN 52
+#define        FRF_BB_TX_IPFIL26_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL25_PORT_EN_LBN 50
+#define        FRF_BB_TX_IPFIL25_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL24_PORT_EN_LBN 48
+#define        FRF_BB_TX_IPFIL24_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL23_PORT_EN_LBN 46
+#define        FRF_BB_TX_IPFIL23_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL22_PORT_EN_LBN 44
+#define        FRF_BB_TX_IPFIL22_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL21_PORT_EN_LBN 42
+#define        FRF_BB_TX_IPFIL21_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL20_PORT_EN_LBN 40
+#define        FRF_BB_TX_IPFIL20_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL19_PORT_EN_LBN 38
+#define        FRF_BB_TX_IPFIL19_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL18_PORT_EN_LBN 36
+#define        FRF_BB_TX_IPFIL18_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL17_PORT_EN_LBN 34
+#define        FRF_BB_TX_IPFIL17_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL16_PORT_EN_LBN 32
+#define        FRF_BB_TX_IPFIL16_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL15_PORT_EN_LBN 30
+#define        FRF_BB_TX_IPFIL15_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL14_PORT_EN_LBN 28
+#define        FRF_BB_TX_IPFIL14_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL13_PORT_EN_LBN 26
+#define        FRF_BB_TX_IPFIL13_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL12_PORT_EN_LBN 24
+#define        FRF_BB_TX_IPFIL12_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL11_PORT_EN_LBN 22
+#define        FRF_BB_TX_IPFIL11_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL10_PORT_EN_LBN 20
+#define        FRF_BB_TX_IPFIL10_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL9_PORT_EN_LBN 18
+#define        FRF_BB_TX_IPFIL9_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL8_PORT_EN_LBN 16
+#define        FRF_BB_TX_IPFIL8_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL7_PORT_EN_LBN 14
+#define        FRF_BB_TX_IPFIL7_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL6_PORT_EN_LBN 12
+#define        FRF_BB_TX_IPFIL6_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL5_PORT_EN_LBN 10
+#define        FRF_BB_TX_IPFIL5_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL4_PORT_EN_LBN 8
+#define        FRF_BB_TX_IPFIL4_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL3_PORT_EN_LBN 6
+#define        FRF_BB_TX_IPFIL3_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL2_PORT_EN_LBN 4
+#define        FRF_BB_TX_IPFIL2_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL1_PORT_EN_LBN 2
+#define        FRF_BB_TX_IPFIL1_PORT_EN_WIDTH 1
+#define        FRF_BB_TX_IPFIL0_PORT_EN_LBN 0
+#define        FRF_BB_TX_IPFIL0_PORT_EN_WIDTH 1
+
+/* TX_IPFIL_TBL: Transmit IP source address filter table */
+#define        FR_BB_TX_IPFIL_TBL 0x00000b00
+#define        FR_BB_TX_IPFIL_TBL_STEP 16
+#define        FR_BB_TX_IPFIL_TBL_ROWS 16
+#define        FRF_BB_TX_IPFIL_MASK_1_LBN 96
+#define        FRF_BB_TX_IPFIL_MASK_1_WIDTH 32
+#define        FRF_BB_TX_IP_SRC_ADR_1_LBN 64
+#define        FRF_BB_TX_IP_SRC_ADR_1_WIDTH 32
+#define        FRF_BB_TX_IPFIL_MASK_0_LBN 32
+#define        FRF_BB_TX_IPFIL_MASK_0_WIDTH 32
+#define        FRF_BB_TX_IP_SRC_ADR_0_LBN 0
+#define        FRF_BB_TX_IP_SRC_ADR_0_WIDTH 32
+
+/* MD_TXD_REG: PHY management transmit data register */
+#define        FR_AB_MD_TXD 0x00000c00
+#define        FRF_AB_MD_TXD_LBN 0
+#define        FRF_AB_MD_TXD_WIDTH 16
+
+/* MD_RXD_REG: PHY management receive data register */
+#define        FR_AB_MD_RXD 0x00000c10
+#define        FRF_AB_MD_RXD_LBN 0
+#define        FRF_AB_MD_RXD_WIDTH 16
+
+/* MD_CS_REG: PHY management configuration & status register */
+#define        FR_AB_MD_CS 0x00000c20
+#define        FRF_AB_MD_RD_EN_CMD_LBN 15
+#define        FRF_AB_MD_RD_EN_CMD_WIDTH 1
+#define        FRF_AB_MD_WR_EN_CMD_LBN 14
+#define        FRF_AB_MD_WR_EN_CMD_WIDTH 1
+#define        FRF_AB_MD_ADDR_CMD_LBN 13
+#define        FRF_AB_MD_ADDR_CMD_WIDTH 1
+#define        FRF_AB_MD_PT_LBN 7
+#define        FRF_AB_MD_PT_WIDTH 3
+#define        FRF_AB_MD_PL_LBN 6
+#define        FRF_AB_MD_PL_WIDTH 1
+#define        FRF_AB_MD_INT_CLR_LBN 5
+#define        FRF_AB_MD_INT_CLR_WIDTH 1
+#define        FRF_AB_MD_GC_LBN 4
+#define        FRF_AB_MD_GC_WIDTH 1
+#define        FRF_AB_MD_PRSP_LBN 3
+#define        FRF_AB_MD_PRSP_WIDTH 1
+#define        FRF_AB_MD_RIC_LBN 2
+#define        FRF_AB_MD_RIC_WIDTH 1
+#define        FRF_AB_MD_RDC_LBN 1
+#define        FRF_AB_MD_RDC_WIDTH 1
+#define        FRF_AB_MD_WRC_LBN 0
+#define        FRF_AB_MD_WRC_WIDTH 1
+
+/* MD_PHY_ADR_REG: PHY management PHY address register */
+#define        FR_AB_MD_PHY_ADR 0x00000c30
+#define        FRF_AB_MD_PHY_ADR_LBN 0
+#define        FRF_AB_MD_PHY_ADR_WIDTH 16
+
+/* MD_ID_REG: PHY management ID register */
+#define        FR_AB_MD_ID 0x00000c40
+#define        FRF_AB_MD_PRT_ADR_LBN 11
+#define        FRF_AB_MD_PRT_ADR_WIDTH 5
+#define        FRF_AB_MD_DEV_ADR_LBN 6
+#define        FRF_AB_MD_DEV_ADR_WIDTH 5
+
+/* MD_STAT_REG: PHY management status & mask register */
+#define        FR_AB_MD_STAT 0x00000c50
+#define        FRF_AB_MD_PINT_LBN 4
+#define        FRF_AB_MD_PINT_WIDTH 1
+#define        FRF_AB_MD_DONE_LBN 3
+#define        FRF_AB_MD_DONE_WIDTH 1
+#define        FRF_AB_MD_BSERR_LBN 2
+#define        FRF_AB_MD_BSERR_WIDTH 1
+#define        FRF_AB_MD_LNFL_LBN 1
+#define        FRF_AB_MD_LNFL_WIDTH 1
+#define        FRF_AB_MD_BSY_LBN 0
+#define        FRF_AB_MD_BSY_WIDTH 1
+
+/* MAC_STAT_DMA_REG: Port MAC statistical counter DMA register */
+#define        FR_AB_MAC_STAT_DMA 0x00000c60
+#define        FRF_AB_MAC_STAT_DMA_CMD_LBN 48
+#define        FRF_AB_MAC_STAT_DMA_CMD_WIDTH 1
+#define        FRF_AB_MAC_STAT_DMA_ADR_LBN 0
+#define        FRF_AB_MAC_STAT_DMA_ADR_WIDTH 48
+
+/* MAC_CTRL_REG: Port MAC control register */
+#define        FR_AB_MAC_CTRL 0x00000c80
+#define        FRF_AB_MAC_XOFF_VAL_LBN 16
+#define        FRF_AB_MAC_XOFF_VAL_WIDTH 16
+#define        FRF_BB_TXFIFO_DRAIN_EN_LBN 7
+#define        FRF_BB_TXFIFO_DRAIN_EN_WIDTH 1
+#define        FRF_AB_MAC_XG_DISTXCRC_LBN 5
+#define        FRF_AB_MAC_XG_DISTXCRC_WIDTH 1
+#define        FRF_AB_MAC_BCAD_ACPT_LBN 4
+#define        FRF_AB_MAC_BCAD_ACPT_WIDTH 1
+#define        FRF_AB_MAC_UC_PROM_LBN 3
+#define        FRF_AB_MAC_UC_PROM_WIDTH 1
+#define        FRF_AB_MAC_LINK_STATUS_LBN 2
+#define        FRF_AB_MAC_LINK_STATUS_WIDTH 1
+#define        FRF_AB_MAC_SPEED_LBN 0
+#define        FRF_AB_MAC_SPEED_WIDTH 2
+#define        FFE_AB_MAC_SPEED_10G 3
+#define        FFE_AB_MAC_SPEED_1G 2
+#define        FFE_AB_MAC_SPEED_100M 1
+#define        FFE_AB_MAC_SPEED_10M 0
+
+/* GEN_MODE_REG: General Purpose mode register (external interrupt mask) */
+#define        FR_BB_GEN_MODE 0x00000c90
+#define        FRF_BB_XFP_PHY_INT_POL_SEL_LBN 3
+#define        FRF_BB_XFP_PHY_INT_POL_SEL_WIDTH 1
+#define        FRF_BB_XG_PHY_INT_POL_SEL_LBN 2
+#define        FRF_BB_XG_PHY_INT_POL_SEL_WIDTH 1
+#define        FRF_BB_XFP_PHY_INT_MASK_LBN 1
+#define        FRF_BB_XFP_PHY_INT_MASK_WIDTH 1
+#define        FRF_BB_XG_PHY_INT_MASK_LBN 0
+#define        FRF_BB_XG_PHY_INT_MASK_WIDTH 1
+
+/* MAC_MC_HASH_REG0: Multicast address hash table */
+#define        FR_AB_MAC_MC_HASH_REG0 0x00000ca0
+#define        FRF_AB_MAC_MCAST_HASH0_LBN 0
+#define        FRF_AB_MAC_MCAST_HASH0_WIDTH 128
+
+/* MAC_MC_HASH_REG1: Multicast address hash table */
+#define        FR_AB_MAC_MC_HASH_REG1 0x00000cb0
+#define        FRF_AB_MAC_MCAST_HASH1_LBN 0
+#define        FRF_AB_MAC_MCAST_HASH1_WIDTH 128
+
+/* GM_CFG1_REG: GMAC configuration register 1 */
+#define        FR_AB_GM_CFG1 0x00000e00
+#define        FRF_AB_GM_SW_RST_LBN 31
+#define        FRF_AB_GM_SW_RST_WIDTH 1
+#define        FRF_AB_GM_SIM_RST_LBN 30
+#define        FRF_AB_GM_SIM_RST_WIDTH 1
+#define        FRF_AB_GM_RST_RX_MAC_CTL_LBN 19
+#define        FRF_AB_GM_RST_RX_MAC_CTL_WIDTH 1
+#define        FRF_AB_GM_RST_TX_MAC_CTL_LBN 18
+#define        FRF_AB_GM_RST_TX_MAC_CTL_WIDTH 1
+#define        FRF_AB_GM_RST_RX_FUNC_LBN 17
+#define        FRF_AB_GM_RST_RX_FUNC_WIDTH 1
+#define        FRF_AB_GM_RST_TX_FUNC_LBN 16
+#define        FRF_AB_GM_RST_TX_FUNC_WIDTH 1
+#define        FRF_AB_GM_LOOP_LBN 8
+#define        FRF_AB_GM_LOOP_WIDTH 1
+#define        FRF_AB_GM_RX_FC_EN_LBN 5
+#define        FRF_AB_GM_RX_FC_EN_WIDTH 1
+#define        FRF_AB_GM_TX_FC_EN_LBN 4
+#define        FRF_AB_GM_TX_FC_EN_WIDTH 1
+#define        FRF_AB_GM_SYNC_RXEN_LBN 3
+#define        FRF_AB_GM_SYNC_RXEN_WIDTH 1
+#define        FRF_AB_GM_RX_EN_LBN 2
+#define        FRF_AB_GM_RX_EN_WIDTH 1
+#define        FRF_AB_GM_SYNC_TXEN_LBN 1
+#define        FRF_AB_GM_SYNC_TXEN_WIDTH 1
+#define        FRF_AB_GM_TX_EN_LBN 0
+#define        FRF_AB_GM_TX_EN_WIDTH 1
+
+/* GM_CFG2_REG: GMAC configuration register 2 */
+#define        FR_AB_GM_CFG2 0x00000e10
+#define        FRF_AB_GM_PAMBL_LEN_LBN 12
+#define        FRF_AB_GM_PAMBL_LEN_WIDTH 4
+#define        FRF_AB_GM_IF_MODE_LBN 8
+#define        FRF_AB_GM_IF_MODE_WIDTH 2
+#define        FFE_AB_IF_MODE_BYTE_MODE 2
+#define        FFE_AB_IF_MODE_NIBBLE_MODE 1
+#define        FRF_AB_GM_HUGE_FRM_EN_LBN 5
+#define        FRF_AB_GM_HUGE_FRM_EN_WIDTH 1
+#define        FRF_AB_GM_LEN_CHK_LBN 4
+#define        FRF_AB_GM_LEN_CHK_WIDTH 1
+#define        FRF_AB_GM_PAD_CRC_EN_LBN 2
+#define        FRF_AB_GM_PAD_CRC_EN_WIDTH 1
+#define        FRF_AB_GM_CRC_EN_LBN 1
+#define        FRF_AB_GM_CRC_EN_WIDTH 1
+#define        FRF_AB_GM_FD_LBN 0
+#define        FRF_AB_GM_FD_WIDTH 1
+
+/* GM_IPG_REG: GMAC IPG register */
+#define        FR_AB_GM_IPG 0x00000e20
+#define        FRF_AB_GM_NONB2B_IPG1_LBN 24
+#define        FRF_AB_GM_NONB2B_IPG1_WIDTH 7
+#define        FRF_AB_GM_NONB2B_IPG2_LBN 16
+#define        FRF_AB_GM_NONB2B_IPG2_WIDTH 7
+#define        FRF_AB_GM_MIN_IPG_ENF_LBN 8
+#define        FRF_AB_GM_MIN_IPG_ENF_WIDTH 8
+#define        FRF_AB_GM_B2B_IPG_LBN 0
+#define        FRF_AB_GM_B2B_IPG_WIDTH 7
+
+/* GM_HD_REG: GMAC half duplex register */
+#define        FR_AB_GM_HD 0x00000e30
+#define        FRF_AB_GM_ALT_BOFF_VAL_LBN 20
+#define        FRF_AB_GM_ALT_BOFF_VAL_WIDTH 4
+#define        FRF_AB_GM_ALT_BOFF_EN_LBN 19
+#define        FRF_AB_GM_ALT_BOFF_EN_WIDTH 1
+#define        FRF_AB_GM_BP_NO_BOFF_LBN 18
+#define        FRF_AB_GM_BP_NO_BOFF_WIDTH 1
+#define        FRF_AB_GM_DIS_BOFF_LBN 17
+#define        FRF_AB_GM_DIS_BOFF_WIDTH 1
+#define        FRF_AB_GM_EXDEF_TX_EN_LBN 16
+#define        FRF_AB_GM_EXDEF_TX_EN_WIDTH 1
+#define        FRF_AB_GM_RTRY_LIMIT_LBN 12
+#define        FRF_AB_GM_RTRY_LIMIT_WIDTH 4
+#define        FRF_AB_GM_COL_WIN_LBN 0
+#define        FRF_AB_GM_COL_WIN_WIDTH 10
+
+/* GM_MAX_FLEN_REG: GMAC maximum frame length register */
+#define        FR_AB_GM_MAX_FLEN 0x00000e40
+#define        FRF_AB_GM_MAX_FLEN_LBN 0
+#define        FRF_AB_GM_MAX_FLEN_WIDTH 16
+
+/* GM_TEST_REG: GMAC test register */
+#define        FR_AB_GM_TEST 0x00000e70
+#define        FRF_AB_GM_MAX_BOFF_LBN 3
+#define        FRF_AB_GM_MAX_BOFF_WIDTH 1
+#define        FRF_AB_GM_REG_TX_FLOW_EN_LBN 2
+#define        FRF_AB_GM_REG_TX_FLOW_EN_WIDTH 1
+#define        FRF_AB_GM_TEST_PAUSE_LBN 1
+#define        FRF_AB_GM_TEST_PAUSE_WIDTH 1
+#define        FRF_AB_GM_SHORT_SLOT_LBN 0
+#define        FRF_AB_GM_SHORT_SLOT_WIDTH 1
+
+/* GM_ADR1_REG: GMAC station address register 1 */
+#define        FR_AB_GM_ADR1 0x00000f00
+#define        FRF_AB_GM_ADR_B0_LBN 24
+#define        FRF_AB_GM_ADR_B0_WIDTH 8
+#define        FRF_AB_GM_ADR_B1_LBN 16
+#define        FRF_AB_GM_ADR_B1_WIDTH 8
+#define        FRF_AB_GM_ADR_B2_LBN 8
+#define        FRF_AB_GM_ADR_B2_WIDTH 8
+#define        FRF_AB_GM_ADR_B3_LBN 0
+#define        FRF_AB_GM_ADR_B3_WIDTH 8
+
+/* GM_ADR2_REG: GMAC station address register 2 */
+#define        FR_AB_GM_ADR2 0x00000f10
+#define        FRF_AB_GM_ADR_B4_LBN 24
+#define        FRF_AB_GM_ADR_B4_WIDTH 8
+#define        FRF_AB_GM_ADR_B5_LBN 16
+#define        FRF_AB_GM_ADR_B5_WIDTH 8
+
+/* GMF_CFG0_REG: GMAC FIFO configuration register 0 */
+#define        FR_AB_GMF_CFG0 0x00000f20
+#define        FRF_AB_GMF_FTFENRPLY_LBN 20
+#define        FRF_AB_GMF_FTFENRPLY_WIDTH 1
+#define        FRF_AB_GMF_STFENRPLY_LBN 19
+#define        FRF_AB_GMF_STFENRPLY_WIDTH 1
+#define        FRF_AB_GMF_FRFENRPLY_LBN 18
+#define        FRF_AB_GMF_FRFENRPLY_WIDTH 1
+#define        FRF_AB_GMF_SRFENRPLY_LBN 17
+#define        FRF_AB_GMF_SRFENRPLY_WIDTH 1
+#define        FRF_AB_GMF_WTMENRPLY_LBN 16
+#define        FRF_AB_GMF_WTMENRPLY_WIDTH 1
+#define        FRF_AB_GMF_FTFENREQ_LBN 12
+#define        FRF_AB_GMF_FTFENREQ_WIDTH 1
+#define        FRF_AB_GMF_STFENREQ_LBN 11
+#define        FRF_AB_GMF_STFENREQ_WIDTH 1
+#define        FRF_AB_GMF_FRFENREQ_LBN 10
+#define        FRF_AB_GMF_FRFENREQ_WIDTH 1
+#define        FRF_AB_GMF_SRFENREQ_LBN 9
+#define        FRF_AB_GMF_SRFENREQ_WIDTH 1
+#define        FRF_AB_GMF_WTMENREQ_LBN 8
+#define        FRF_AB_GMF_WTMENREQ_WIDTH 1
+#define        FRF_AB_GMF_HSTRSTFT_LBN 4
+#define        FRF_AB_GMF_HSTRSTFT_WIDTH 1
+#define        FRF_AB_GMF_HSTRSTST_LBN 3
+#define        FRF_AB_GMF_HSTRSTST_WIDTH 1
+#define        FRF_AB_GMF_HSTRSTFR_LBN 2
+#define        FRF_AB_GMF_HSTRSTFR_WIDTH 1
+#define        FRF_AB_GMF_HSTRSTSR_LBN 1
+#define        FRF_AB_GMF_HSTRSTSR_WIDTH 1
+#define        FRF_AB_GMF_HSTRSTWT_LBN 0
+#define        FRF_AB_GMF_HSTRSTWT_WIDTH 1
+
+/* GMF_CFG1_REG: GMAC FIFO configuration register 1 */
+#define        FR_AB_GMF_CFG1 0x00000f30
+#define        FRF_AB_GMF_CFGFRTH_LBN 16
+#define        FRF_AB_GMF_CFGFRTH_WIDTH 5
+#define        FRF_AB_GMF_CFGXOFFRTX_LBN 0
+#define        FRF_AB_GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMF_CFG2_REG: GMAC FIFO configuration register 2 */
+#define        FR_AB_GMF_CFG2 0x00000f40
+#define        FRF_AB_GMF_CFGHWM_LBN 16
+#define        FRF_AB_GMF_CFGHWM_WIDTH 6
+#define        FRF_AB_GMF_CFGLWM_LBN 0
+#define        FRF_AB_GMF_CFGLWM_WIDTH 6
+
+/* GMF_CFG3_REG: GMAC FIFO configuration register 3 */
+#define        FR_AB_GMF_CFG3 0x00000f50
+#define        FRF_AB_GMF_CFGHWMFT_LBN 16
+#define        FRF_AB_GMF_CFGHWMFT_WIDTH 6
+#define        FRF_AB_GMF_CFGFTTH_LBN 0
+#define        FRF_AB_GMF_CFGFTTH_WIDTH 6
+
+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
+#define        FR_AB_GMF_CFG4 0x00000f60
+#define        FRF_AB_GMF_HSTFLTRFRM_LBN 0
+#define        FRF_AB_GMF_HSTFLTRFRM_WIDTH 18
+
+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
+#define        FR_AB_GMF_CFG5 0x00000f70
+#define        FRF_AB_GMF_CFGHDPLX_LBN 22
+#define        FRF_AB_GMF_CFGHDPLX_WIDTH 1
+#define        FRF_AB_GMF_SRFULL_LBN 21
+#define        FRF_AB_GMF_SRFULL_WIDTH 1
+#define        FRF_AB_GMF_HSTSRFULLCLR_LBN 20
+#define        FRF_AB_GMF_HSTSRFULLCLR_WIDTH 1
+#define        FRF_AB_GMF_CFGBYTMODE_LBN 19
+#define        FRF_AB_GMF_CFGBYTMODE_WIDTH 1
+#define        FRF_AB_GMF_HSTDRPLT64_LBN 18
+#define        FRF_AB_GMF_HSTDRPLT64_WIDTH 1
+#define        FRF_AB_GMF_HSTFLTRFRMDC_LBN 0
+#define        FRF_AB_GMF_HSTFLTRFRMDC_WIDTH 18
+
+/* TX_SRC_MAC_TBL: Transmit IP source address filter table */
+#define        FR_BB_TX_SRC_MAC_TBL 0x00001000
+#define        FR_BB_TX_SRC_MAC_TBL_STEP 16
+#define        FR_BB_TX_SRC_MAC_TBL_ROWS 16
+#define        FRF_BB_TX_SRC_MAC_ADR_1_LBN 64
+#define        FRF_BB_TX_SRC_MAC_ADR_1_WIDTH 48
+#define        FRF_BB_TX_SRC_MAC_ADR_0_LBN 0
+#define        FRF_BB_TX_SRC_MAC_ADR_0_WIDTH 48
+
+/* TX_SRC_MAC_CTL_REG: Transmit MAC source address filter control */
+#define        FR_BB_TX_SRC_MAC_CTL 0x00001100
+#define        FRF_BB_TX_SRC_DROP_CTR_LBN 16
+#define        FRF_BB_TX_SRC_DROP_CTR_WIDTH 16
+#define        FRF_BB_TX_SRC_FLTR_EN_LBN 15
+#define        FRF_BB_TX_SRC_FLTR_EN_WIDTH 1
+#define        FRF_BB_TX_DROP_CTR_CLR_LBN 12
+#define        FRF_BB_TX_DROP_CTR_CLR_WIDTH 1
+#define        FRF_BB_TX_MAC_QID_SEL_LBN 0
+#define        FRF_BB_TX_MAC_QID_SEL_WIDTH 3
+
+/* XM_ADR_LO_REG: XGMAC address register low */
+#define        FR_AB_XM_ADR_LO 0x00001200
+#define        FRF_AB_XM_ADR_LO_LBN 0
+#define        FRF_AB_XM_ADR_LO_WIDTH 32
+
+/* XM_ADR_HI_REG: XGMAC address register high */
+#define        FR_AB_XM_ADR_HI 0x00001210
+#define        FRF_AB_XM_ADR_HI_LBN 0
+#define        FRF_AB_XM_ADR_HI_WIDTH 16
+
+/* XM_GLB_CFG_REG: XGMAC global configuration */
+#define        FR_AB_XM_GLB_CFG 0x00001220
+#define        FRF_AB_XM_RMTFLT_GEN_LBN 17
+#define        FRF_AB_XM_RMTFLT_GEN_WIDTH 1
+#define        FRF_AB_XM_DEBUG_MODE_LBN 16
+#define        FRF_AB_XM_DEBUG_MODE_WIDTH 1
+#define        FRF_AB_XM_RX_STAT_EN_LBN 11
+#define        FRF_AB_XM_RX_STAT_EN_WIDTH 1
+#define        FRF_AB_XM_TX_STAT_EN_LBN 10
+#define        FRF_AB_XM_TX_STAT_EN_WIDTH 1
+#define        FRF_AB_XM_RX_JUMBO_MODE_LBN 6
+#define        FRF_AB_XM_RX_JUMBO_MODE_WIDTH 1
+#define        FRF_AB_XM_WAN_MODE_LBN 5
+#define        FRF_AB_XM_WAN_MODE_WIDTH 1
+#define        FRF_AB_XM_INTCLR_MODE_LBN 3
+#define        FRF_AB_XM_INTCLR_MODE_WIDTH 1
+#define        FRF_AB_XM_CORE_RST_LBN 0
+#define        FRF_AB_XM_CORE_RST_WIDTH 1
+
+/* XM_TX_CFG_REG: XGMAC transmit configuration */
+#define        FR_AB_XM_TX_CFG 0x00001230
+#define        FRF_AB_XM_TX_PROG_LBN 24
+#define        FRF_AB_XM_TX_PROG_WIDTH 1
+#define        FRF_AB_XM_IPG_LBN 16
+#define        FRF_AB_XM_IPG_WIDTH 4
+#define        FRF_AB_XM_FCNTL_LBN 10
+#define        FRF_AB_XM_FCNTL_WIDTH 1
+#define        FRF_AB_XM_TXCRC_LBN 8
+#define        FRF_AB_XM_TXCRC_WIDTH 1
+#define        FRF_AB_XM_EDRC_LBN 6
+#define        FRF_AB_XM_EDRC_WIDTH 1
+#define        FRF_AB_XM_AUTO_PAD_LBN 5
+#define        FRF_AB_XM_AUTO_PAD_WIDTH 1
+#define        FRF_AB_XM_TX_PRMBL_LBN 2
+#define        FRF_AB_XM_TX_PRMBL_WIDTH 1
+#define        FRF_AB_XM_TXEN_LBN 1
+#define        FRF_AB_XM_TXEN_WIDTH 1
+#define        FRF_AB_XM_TX_RST_LBN 0
+#define        FRF_AB_XM_TX_RST_WIDTH 1
+
+/* XM_RX_CFG_REG: XGMAC receive configuration */
+#define        FR_AB_XM_RX_CFG 0x00001240
+#define        FRF_AB_XM_PASS_LENERR_LBN 26
+#define        FRF_AB_XM_PASS_LENERR_WIDTH 1
+#define        FRF_AB_XM_PASS_CRC_ERR_LBN 25
+#define        FRF_AB_XM_PASS_CRC_ERR_WIDTH 1
+#define        FRF_AB_XM_PASS_PRMBLE_ERR_LBN 24
+#define        FRF_AB_XM_PASS_PRMBLE_ERR_WIDTH 1
+#define        FRF_AB_XM_REJ_BCAST_LBN 20
+#define        FRF_AB_XM_REJ_BCAST_WIDTH 1
+#define        FRF_AB_XM_ACPT_ALL_MCAST_LBN 11
+#define        FRF_AB_XM_ACPT_ALL_MCAST_WIDTH 1
+#define        FRF_AB_XM_ACPT_ALL_UCAST_LBN 9
+#define        FRF_AB_XM_ACPT_ALL_UCAST_WIDTH 1
+#define        FRF_AB_XM_AUTO_DEPAD_LBN 8
+#define        FRF_AB_XM_AUTO_DEPAD_WIDTH 1
+#define        FRF_AB_XM_RXCRC_LBN 3
+#define        FRF_AB_XM_RXCRC_WIDTH 1
+#define        FRF_AB_XM_RX_PRMBL_LBN 2
+#define        FRF_AB_XM_RX_PRMBL_WIDTH 1
+#define        FRF_AB_XM_RXEN_LBN 1
+#define        FRF_AB_XM_RXEN_WIDTH 1
+#define        FRF_AB_XM_RX_RST_LBN 0
+#define        FRF_AB_XM_RX_RST_WIDTH 1
+
+/* XM_MGT_INT_MASK: documentation to be written for sum_XM_MGT_INT_MASK */
+#define        FR_AB_XM_MGT_INT_MASK 0x00001250
+#define        FRF_AB_XM_MSK_STA_INTR_LBN 16
+#define        FRF_AB_XM_MSK_STA_INTR_WIDTH 1
+#define        FRF_AB_XM_MSK_STAT_CNTR_HF_LBN 9
+#define        FRF_AB_XM_MSK_STAT_CNTR_HF_WIDTH 1
+#define        FRF_AB_XM_MSK_STAT_CNTR_OF_LBN 8
+#define        FRF_AB_XM_MSK_STAT_CNTR_OF_WIDTH 1
+#define        FRF_AB_XM_MSK_PRMBLE_ERR_LBN 2
+#define        FRF_AB_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define        FRF_AB_XM_MSK_RMTFLT_LBN 1
+#define        FRF_AB_XM_MSK_RMTFLT_WIDTH 1
+#define        FRF_AB_XM_MSK_LCLFLT_LBN 0
+#define        FRF_AB_XM_MSK_LCLFLT_WIDTH 1
+
+/* XM_FC_REG: XGMAC flow control register */
+#define        FR_AB_XM_FC 0x00001270
+#define        FRF_AB_XM_PAUSE_TIME_LBN 16
+#define        FRF_AB_XM_PAUSE_TIME_WIDTH 16
+#define        FRF_AB_XM_RX_MAC_STAT_LBN 11
+#define        FRF_AB_XM_RX_MAC_STAT_WIDTH 1
+#define        FRF_AB_XM_TX_MAC_STAT_LBN 10
+#define        FRF_AB_XM_TX_MAC_STAT_WIDTH 1
+#define        FRF_AB_XM_MCNTL_PASS_LBN 8
+#define        FRF_AB_XM_MCNTL_PASS_WIDTH 2
+#define        FRF_AB_XM_REJ_CNTL_UCAST_LBN 6
+#define        FRF_AB_XM_REJ_CNTL_UCAST_WIDTH 1
+#define        FRF_AB_XM_REJ_CNTL_MCAST_LBN 5
+#define        FRF_AB_XM_REJ_CNTL_MCAST_WIDTH 1
+#define        FRF_AB_XM_ZPAUSE_LBN 2
+#define        FRF_AB_XM_ZPAUSE_WIDTH 1
+#define        FRF_AB_XM_XMIT_PAUSE_LBN 1
+#define        FRF_AB_XM_XMIT_PAUSE_WIDTH 1
+#define        FRF_AB_XM_DIS_FCNTL_LBN 0
+#define        FRF_AB_XM_DIS_FCNTL_WIDTH 1
+
+/* XM_PAUSE_TIME_REG: XGMAC pause time register */
+#define        FR_AB_XM_PAUSE_TIME 0x00001290
+#define        FRF_AB_XM_TX_PAUSE_CNT_LBN 16
+#define        FRF_AB_XM_TX_PAUSE_CNT_WIDTH 16
+#define        FRF_AB_XM_RX_PAUSE_CNT_LBN 0
+#define        FRF_AB_XM_RX_PAUSE_CNT_WIDTH 16
+
+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
+#define        FR_AB_XM_TX_PARAM 0x000012d0
+#define        FRF_AB_XM_TX_JUMBO_MODE_LBN 31
+#define        FRF_AB_XM_TX_JUMBO_MODE_WIDTH 1
+#define        FRF_AB_XM_MAX_TX_FRM_SIZE_HI_LBN 19
+#define        FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH 11
+#define        FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN 16
+#define        FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH 3
+#define        FRF_AB_XM_PAD_CHAR_LBN 0
+#define        FRF_AB_XM_PAD_CHAR_WIDTH 8
+
+/* XM_RX_PARAM_REG: XGMAC receive parameter register */
+#define        FR_AB_XM_RX_PARAM 0x000012e0
+#define        FRF_AB_XM_MAX_RX_FRM_SIZE_HI_LBN 3
+#define        FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH 11
+#define        FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN 0
+#define        FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH 3
+
+/* XM_MGT_INT_MSK_REG: XGMAC management interrupt mask register */
+#define        FR_AB_XM_MGT_INT_MSK 0x000012f0
+#define        FRF_AB_XM_STAT_CNTR_OF_LBN 9
+#define        FRF_AB_XM_STAT_CNTR_OF_WIDTH 1
+#define        FRF_AB_XM_STAT_CNTR_HF_LBN 8
+#define        FRF_AB_XM_STAT_CNTR_HF_WIDTH 1
+#define        FRF_AB_XM_PRMBLE_ERR_LBN 2
+#define        FRF_AB_XM_PRMBLE_ERR_WIDTH 1
+#define        FRF_AB_XM_RMTFLT_LBN 1
+#define        FRF_AB_XM_RMTFLT_WIDTH 1
+#define        FRF_AB_XM_LCLFLT_LBN 0
+#define        FRF_AB_XM_LCLFLT_WIDTH 1
+
+/* XX_PWR_RST_REG: XGXS/XAUI powerdown/reset register */
+#define        FR_AB_XX_PWR_RST 0x00001300
+#define        FRF_AB_XX_PWRDND_SIG_LBN 31
+#define        FRF_AB_XX_PWRDND_SIG_WIDTH 1
+#define        FRF_AB_XX_PWRDNC_SIG_LBN 30
+#define        FRF_AB_XX_PWRDNC_SIG_WIDTH 1
+#define        FRF_AB_XX_PWRDNB_SIG_LBN 29
+#define        FRF_AB_XX_PWRDNB_SIG_WIDTH 1
+#define        FRF_AB_XX_PWRDNA_SIG_LBN 28
+#define        FRF_AB_XX_PWRDNA_SIG_WIDTH 1
+#define        FRF_AB_XX_SIM_MODE_LBN 27
+#define        FRF_AB_XX_SIM_MODE_WIDTH 1
+#define        FRF_AB_XX_RSTPLLCD_SIG_LBN 25
+#define        FRF_AB_XX_RSTPLLCD_SIG_WIDTH 1
+#define        FRF_AB_XX_RSTPLLAB_SIG_LBN 24
+#define        FRF_AB_XX_RSTPLLAB_SIG_WIDTH 1
+#define        FRF_AB_XX_RESETD_SIG_LBN 23
+#define        FRF_AB_XX_RESETD_SIG_WIDTH 1
+#define        FRF_AB_XX_RESETC_SIG_LBN 22
+#define        FRF_AB_XX_RESETC_SIG_WIDTH 1
+#define        FRF_AB_XX_RESETB_SIG_LBN 21
+#define        FRF_AB_XX_RESETB_SIG_WIDTH 1
+#define        FRF_AB_XX_RESETA_SIG_LBN 20
+#define        FRF_AB_XX_RESETA_SIG_WIDTH 1
+#define        FRF_AB_XX_RSTXGXSRX_SIG_LBN 18
+#define        FRF_AB_XX_RSTXGXSRX_SIG_WIDTH 1
+#define        FRF_AB_XX_RSTXGXSTX_SIG_LBN 17
+#define        FRF_AB_XX_RSTXGXSTX_SIG_WIDTH 1
+#define        FRF_AB_XX_SD_RST_ACT_LBN 16
+#define        FRF_AB_XX_SD_RST_ACT_WIDTH 1
+#define        FRF_AB_XX_PWRDND_EN_LBN 15
+#define        FRF_AB_XX_PWRDND_EN_WIDTH 1
+#define        FRF_AB_XX_PWRDNC_EN_LBN 14
+#define        FRF_AB_XX_PWRDNC_EN_WIDTH 1
+#define        FRF_AB_XX_PWRDNB_EN_LBN 13
+#define        FRF_AB_XX_PWRDNB_EN_WIDTH 1
+#define        FRF_AB_XX_PWRDNA_EN_LBN 12
+#define        FRF_AB_XX_PWRDNA_EN_WIDTH 1
+#define        FRF_AB_XX_RSTPLLCD_EN_LBN 9
+#define        FRF_AB_XX_RSTPLLCD_EN_WIDTH 1
+#define        FRF_AB_XX_RSTPLLAB_EN_LBN 8
+#define        FRF_AB_XX_RSTPLLAB_EN_WIDTH 1
+#define        FRF_AB_XX_RESETD_EN_LBN 7
+#define        FRF_AB_XX_RESETD_EN_WIDTH 1
+#define        FRF_AB_XX_RESETC_EN_LBN 6
+#define        FRF_AB_XX_RESETC_EN_WIDTH 1
+#define        FRF_AB_XX_RESETB_EN_LBN 5
+#define        FRF_AB_XX_RESETB_EN_WIDTH 1
+#define        FRF_AB_XX_RESETA_EN_LBN 4
+#define        FRF_AB_XX_RESETA_EN_WIDTH 1
+#define        FRF_AB_XX_RSTXGXSRX_EN_LBN 2
+#define        FRF_AB_XX_RSTXGXSRX_EN_WIDTH 1
+#define        FRF_AB_XX_RSTXGXSTX_EN_LBN 1
+#define        FRF_AB_XX_RSTXGXSTX_EN_WIDTH 1
+#define        FRF_AB_XX_RST_XX_EN_LBN 0
+#define        FRF_AB_XX_RST_XX_EN_WIDTH 1
+
+/* XX_SD_CTL_REG: XGXS/XAUI powerdown/reset control register */
+#define        FR_AB_XX_SD_CTL 0x00001310
+#define        FRF_AB_XX_TERMADJ1_LBN 17
+#define        FRF_AB_XX_TERMADJ1_WIDTH 1
+#define        FRF_AB_XX_TERMADJ0_LBN 16
+#define        FRF_AB_XX_TERMADJ0_WIDTH 1
+#define        FRF_AB_XX_HIDRVD_LBN 15
+#define        FRF_AB_XX_HIDRVD_WIDTH 1
+#define        FRF_AB_XX_LODRVD_LBN 14
+#define        FRF_AB_XX_LODRVD_WIDTH 1
+#define        FRF_AB_XX_HIDRVC_LBN 13
+#define        FRF_AB_XX_HIDRVC_WIDTH 1
+#define        FRF_AB_XX_LODRVC_LBN 12
+#define        FRF_AB_XX_LODRVC_WIDTH 1
+#define        FRF_AB_XX_HIDRVB_LBN 11
+#define        FRF_AB_XX_HIDRVB_WIDTH 1
+#define        FRF_AB_XX_LODRVB_LBN 10
+#define        FRF_AB_XX_LODRVB_WIDTH 1
+#define        FRF_AB_XX_HIDRVA_LBN 9
+#define        FRF_AB_XX_HIDRVA_WIDTH 1
+#define        FRF_AB_XX_LODRVA_LBN 8
+#define        FRF_AB_XX_LODRVA_WIDTH 1
+#define        FRF_AB_XX_LPBKD_LBN 3
+#define        FRF_AB_XX_LPBKD_WIDTH 1
+#define        FRF_AB_XX_LPBKC_LBN 2
+#define        FRF_AB_XX_LPBKC_WIDTH 1
+#define        FRF_AB_XX_LPBKB_LBN 1
+#define        FRF_AB_XX_LPBKB_WIDTH 1
+#define        FRF_AB_XX_LPBKA_LBN 0
+#define        FRF_AB_XX_LPBKA_WIDTH 1
+
+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
+#define        FR_AB_XX_TXDRV_CTL 0x00001320
+#define        FRF_AB_XX_DEQD_LBN 28
+#define        FRF_AB_XX_DEQD_WIDTH 4
+#define        FRF_AB_XX_DEQC_LBN 24
+#define        FRF_AB_XX_DEQC_WIDTH 4
+#define        FRF_AB_XX_DEQB_LBN 20
+#define        FRF_AB_XX_DEQB_WIDTH 4
+#define        FRF_AB_XX_DEQA_LBN 16
+#define        FRF_AB_XX_DEQA_WIDTH 4
+#define        FRF_AB_XX_DTXD_LBN 12
+#define        FRF_AB_XX_DTXD_WIDTH 4
+#define        FRF_AB_XX_DTXC_LBN 8
+#define        FRF_AB_XX_DTXC_WIDTH 4
+#define        FRF_AB_XX_DTXB_LBN 4
+#define        FRF_AB_XX_DTXB_WIDTH 4
+#define        FRF_AB_XX_DTXA_LBN 0
+#define        FRF_AB_XX_DTXA_WIDTH 4
+
+/* XX_PRBS_CTL_REG: documentation to be written for sum_XX_PRBS_CTL_REG */
+#define        FR_AB_XX_PRBS_CTL 0x00001330
+#define        FRF_AB_XX_CH3_RX_PRBS_SEL_LBN 30
+#define        FRF_AB_XX_CH3_RX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH3_RX_PRBS_INV_LBN 29
+#define        FRF_AB_XX_CH3_RX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH3_RX_PRBS_CHKEN_LBN 28
+#define        FRF_AB_XX_CH3_RX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH2_RX_PRBS_SEL_LBN 26
+#define        FRF_AB_XX_CH2_RX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH2_RX_PRBS_INV_LBN 25
+#define        FRF_AB_XX_CH2_RX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH2_RX_PRBS_CHKEN_LBN 24
+#define        FRF_AB_XX_CH2_RX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH1_RX_PRBS_SEL_LBN 22
+#define        FRF_AB_XX_CH1_RX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH1_RX_PRBS_INV_LBN 21
+#define        FRF_AB_XX_CH1_RX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH1_RX_PRBS_CHKEN_LBN 20
+#define        FRF_AB_XX_CH1_RX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH0_RX_PRBS_SEL_LBN 18
+#define        FRF_AB_XX_CH0_RX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH0_RX_PRBS_INV_LBN 17
+#define        FRF_AB_XX_CH0_RX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH0_RX_PRBS_CHKEN_LBN 16
+#define        FRF_AB_XX_CH0_RX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH3_TX_PRBS_SEL_LBN 14
+#define        FRF_AB_XX_CH3_TX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH3_TX_PRBS_INV_LBN 13
+#define        FRF_AB_XX_CH3_TX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH3_TX_PRBS_CHKEN_LBN 12
+#define        FRF_AB_XX_CH3_TX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH2_TX_PRBS_SEL_LBN 10
+#define        FRF_AB_XX_CH2_TX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH2_TX_PRBS_INV_LBN 9
+#define        FRF_AB_XX_CH2_TX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH2_TX_PRBS_CHKEN_LBN 8
+#define        FRF_AB_XX_CH2_TX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH1_TX_PRBS_SEL_LBN 6
+#define        FRF_AB_XX_CH1_TX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH1_TX_PRBS_INV_LBN 5
+#define        FRF_AB_XX_CH1_TX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH1_TX_PRBS_CHKEN_LBN 4
+#define        FRF_AB_XX_CH1_TX_PRBS_CHKEN_WIDTH 1
+#define        FRF_AB_XX_CH0_TX_PRBS_SEL_LBN 2
+#define        FRF_AB_XX_CH0_TX_PRBS_SEL_WIDTH 2
+#define        FRF_AB_XX_CH0_TX_PRBS_INV_LBN 1
+#define        FRF_AB_XX_CH0_TX_PRBS_INV_WIDTH 1
+#define        FRF_AB_XX_CH0_TX_PRBS_CHKEN_LBN 0
+#define        FRF_AB_XX_CH0_TX_PRBS_CHKEN_WIDTH 1
+
+/* XX_PRBS_CHK_REG: documentation to be written for sum_XX_PRBS_CHK_REG */
+#define        FR_AB_XX_PRBS_CHK 0x00001340
+#define        FRF_AB_XX_REV_LB_EN_LBN 16
+#define        FRF_AB_XX_REV_LB_EN_WIDTH 1
+#define        FRF_AB_XX_CH3_DEG_DET_LBN 15
+#define        FRF_AB_XX_CH3_DEG_DET_WIDTH 1
+#define        FRF_AB_XX_CH3_LFSR_LOCK_IND_LBN 14
+#define        FRF_AB_XX_CH3_LFSR_LOCK_IND_WIDTH 1
+#define        FRF_AB_XX_CH3_PRBS_FRUN_LBN 13
+#define        FRF_AB_XX_CH3_PRBS_FRUN_WIDTH 1
+#define        FRF_AB_XX_CH3_ERR_CHK_LBN 12
+#define        FRF_AB_XX_CH3_ERR_CHK_WIDTH 1
+#define        FRF_AB_XX_CH2_DEG_DET_LBN 11
+#define        FRF_AB_XX_CH2_DEG_DET_WIDTH 1
+#define        FRF_AB_XX_CH2_LFSR_LOCK_IND_LBN 10
+#define        FRF_AB_XX_CH2_LFSR_LOCK_IND_WIDTH 1
+#define        FRF_AB_XX_CH2_PRBS_FRUN_LBN 9
+#define        FRF_AB_XX_CH2_PRBS_FRUN_WIDTH 1
+#define        FRF_AB_XX_CH2_ERR_CHK_LBN 8
+#define        FRF_AB_XX_CH2_ERR_CHK_WIDTH 1
+#define        FRF_AB_XX_CH1_DEG_DET_LBN 7
+#define        FRF_AB_XX_CH1_DEG_DET_WIDTH 1
+#define        FRF_AB_XX_CH1_LFSR_LOCK_IND_LBN 6
+#define        FRF_AB_XX_CH1_LFSR_LOCK_IND_WIDTH 1
+#define        FRF_AB_XX_CH1_PRBS_FRUN_LBN 5
+#define        FRF_AB_XX_CH1_PRBS_FRUN_WIDTH 1
+#define        FRF_AB_XX_CH1_ERR_CHK_LBN 4
+#define        FRF_AB_XX_CH1_ERR_CHK_WIDTH 1
+#define        FRF_AB_XX_CH0_DEG_DET_LBN 3
+#define        FRF_AB_XX_CH0_DEG_DET_WIDTH 1
+#define        FRF_AB_XX_CH0_LFSR_LOCK_IND_LBN 2
+#define        FRF_AB_XX_CH0_LFSR_LOCK_IND_WIDTH 1
+#define        FRF_AB_XX_CH0_PRBS_FRUN_LBN 1
+#define        FRF_AB_XX_CH0_PRBS_FRUN_WIDTH 1
+#define        FRF_AB_XX_CH0_ERR_CHK_LBN 0
+#define        FRF_AB_XX_CH0_ERR_CHK_WIDTH 1
+
+/* XX_PRBS_ERR_REG: documentation to be written for sum_XX_PRBS_ERR_REG */
+#define        FR_AB_XX_PRBS_ERR 0x00001350
+#define        FRF_AB_XX_CH3_PRBS_ERR_CNT_LBN 24
+#define        FRF_AB_XX_CH3_PRBS_ERR_CNT_WIDTH 8
+#define        FRF_AB_XX_CH2_PRBS_ERR_CNT_LBN 16
+#define        FRF_AB_XX_CH2_PRBS_ERR_CNT_WIDTH 8
+#define        FRF_AB_XX_CH1_PRBS_ERR_CNT_LBN 8
+#define        FRF_AB_XX_CH1_PRBS_ERR_CNT_WIDTH 8
+#define        FRF_AB_XX_CH0_PRBS_ERR_CNT_LBN 0
+#define        FRF_AB_XX_CH0_PRBS_ERR_CNT_WIDTH 8
+
+/* XX_CORE_STAT_REG: XAUI XGXS core status register */
+#define        FR_AB_XX_CORE_STAT 0x00001360
+#define        FRF_AB_XX_FORCE_SIG3_LBN 31
+#define        FRF_AB_XX_FORCE_SIG3_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG3_VAL_LBN 30
+#define        FRF_AB_XX_FORCE_SIG3_VAL_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG2_LBN 29
+#define        FRF_AB_XX_FORCE_SIG2_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG2_VAL_LBN 28
+#define        FRF_AB_XX_FORCE_SIG2_VAL_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG1_LBN 27
+#define        FRF_AB_XX_FORCE_SIG1_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG1_VAL_LBN 26
+#define        FRF_AB_XX_FORCE_SIG1_VAL_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG0_LBN 25
+#define        FRF_AB_XX_FORCE_SIG0_WIDTH 1
+#define        FRF_AB_XX_FORCE_SIG0_VAL_LBN 24
+#define        FRF_AB_XX_FORCE_SIG0_VAL_WIDTH 1
+#define        FRF_AB_XX_XGXS_LB_EN_LBN 23
+#define        FRF_AB_XX_XGXS_LB_EN_WIDTH 1
+#define        FRF_AB_XX_XGMII_LB_EN_LBN 22
+#define        FRF_AB_XX_XGMII_LB_EN_WIDTH 1
+#define        FRF_AB_XX_MATCH_FAULT_LBN 21
+#define        FRF_AB_XX_MATCH_FAULT_WIDTH 1
+#define        FRF_AB_XX_ALIGN_DONE_LBN 20
+#define        FRF_AB_XX_ALIGN_DONE_WIDTH 1
+#define        FRF_AB_XX_SYNC_STAT3_LBN 19
+#define        FRF_AB_XX_SYNC_STAT3_WIDTH 1
+#define        FRF_AB_XX_SYNC_STAT2_LBN 18
+#define        FRF_AB_XX_SYNC_STAT2_WIDTH 1
+#define        FRF_AB_XX_SYNC_STAT1_LBN 17
+#define        FRF_AB_XX_SYNC_STAT1_WIDTH 1
+#define        FRF_AB_XX_SYNC_STAT0_LBN 16
+#define        FRF_AB_XX_SYNC_STAT0_WIDTH 1
+#define        FRF_AB_XX_COMMA_DET_CH3_LBN 15
+#define        FRF_AB_XX_COMMA_DET_CH3_WIDTH 1
+#define        FRF_AB_XX_COMMA_DET_CH2_LBN 14
+#define        FRF_AB_XX_COMMA_DET_CH2_WIDTH 1
+#define        FRF_AB_XX_COMMA_DET_CH1_LBN 13
+#define        FRF_AB_XX_COMMA_DET_CH1_WIDTH 1
+#define        FRF_AB_XX_COMMA_DET_CH0_LBN 12
+#define        FRF_AB_XX_COMMA_DET_CH0_WIDTH 1
+#define        FRF_AB_XX_CGRP_ALIGN_CH3_LBN 11
+#define        FRF_AB_XX_CGRP_ALIGN_CH3_WIDTH 1
+#define        FRF_AB_XX_CGRP_ALIGN_CH2_LBN 10
+#define        FRF_AB_XX_CGRP_ALIGN_CH2_WIDTH 1
+#define        FRF_AB_XX_CGRP_ALIGN_CH1_LBN 9
+#define        FRF_AB_XX_CGRP_ALIGN_CH1_WIDTH 1
+#define        FRF_AB_XX_CGRP_ALIGN_CH0_LBN 8
+#define        FRF_AB_XX_CGRP_ALIGN_CH0_WIDTH 1
+#define        FRF_AB_XX_CHAR_ERR_CH3_LBN 7
+#define        FRF_AB_XX_CHAR_ERR_CH3_WIDTH 1
+#define        FRF_AB_XX_CHAR_ERR_CH2_LBN 6
+#define        FRF_AB_XX_CHAR_ERR_CH2_WIDTH 1
+#define        FRF_AB_XX_CHAR_ERR_CH1_LBN 5
+#define        FRF_AB_XX_CHAR_ERR_CH1_WIDTH 1
+#define        FRF_AB_XX_CHAR_ERR_CH0_LBN 4
+#define        FRF_AB_XX_CHAR_ERR_CH0_WIDTH 1
+#define        FRF_AB_XX_DISPERR_CH3_LBN 3
+#define        FRF_AB_XX_DISPERR_CH3_WIDTH 1
+#define        FRF_AB_XX_DISPERR_CH2_LBN 2
+#define        FRF_AB_XX_DISPERR_CH2_WIDTH 1
+#define        FRF_AB_XX_DISPERR_CH1_LBN 1
+#define        FRF_AB_XX_DISPERR_CH1_WIDTH 1
+#define        FRF_AB_XX_DISPERR_CH0_LBN 0
+#define        FRF_AB_XX_DISPERR_CH0_WIDTH 1
+
+/* RX_DESC_PTR_TBL_KER: Receive descriptor pointer table */
+#define        FR_AA_RX_DESC_PTR_TBL_KER 0x00011800
+#define        FR_AA_RX_DESC_PTR_TBL_KER_STEP 16
+#define        FR_AA_RX_DESC_PTR_TBL_KER_ROWS 4
+/* RX_DESC_PTR_TBL: Receive descriptor pointer table */
+#define        FR_BZ_RX_DESC_PTR_TBL 0x00f40000
+#define        FR_BZ_RX_DESC_PTR_TBL_STEP 16
+#define        FR_BB_RX_DESC_PTR_TBL_ROWS 4096
+#define        FR_CZ_RX_DESC_PTR_TBL_ROWS 1024
+#define        FRF_CZ_RX_HDR_SPLIT_LBN 90
+#define        FRF_CZ_RX_HDR_SPLIT_WIDTH 1
+#define        FRF_AA_RX_RESET_LBN 89
+#define        FRF_AA_RX_RESET_WIDTH 1
+#define        FRF_AZ_RX_ISCSI_DDIG_EN_LBN 88
+#define        FRF_AZ_RX_ISCSI_DDIG_EN_WIDTH 1
+#define        FRF_AZ_RX_ISCSI_HDIG_EN_LBN 87
+#define        FRF_AZ_RX_ISCSI_HDIG_EN_WIDTH 1
+#define        FRF_AZ_RX_DESC_PREF_ACT_LBN 86
+#define        FRF_AZ_RX_DESC_PREF_ACT_WIDTH 1
+#define        FRF_AZ_RX_DC_HW_RPTR_LBN 80
+#define        FRF_AZ_RX_DC_HW_RPTR_WIDTH 6
+#define        FRF_AZ_RX_DESCQ_HW_RPTR_LBN 68
+#define        FRF_AZ_RX_DESCQ_HW_RPTR_WIDTH 12
+#define        FRF_AZ_RX_DESCQ_SW_WPTR_LBN 56
+#define        FRF_AZ_RX_DESCQ_SW_WPTR_WIDTH 12
+#define        FRF_AZ_RX_DESCQ_BUF_BASE_ID_LBN 36
+#define        FRF_AZ_RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define        FRF_AZ_RX_DESCQ_EVQ_ID_LBN 24
+#define        FRF_AZ_RX_DESCQ_EVQ_ID_WIDTH 12
+#define        FRF_AZ_RX_DESCQ_OWNER_ID_LBN 10
+#define        FRF_AZ_RX_DESCQ_OWNER_ID_WIDTH 14
+#define        FRF_AZ_RX_DESCQ_LABEL_LBN 5
+#define        FRF_AZ_RX_DESCQ_LABEL_WIDTH 5
+#define        FRF_AZ_RX_DESCQ_SIZE_LBN 3
+#define        FRF_AZ_RX_DESCQ_SIZE_WIDTH 2
+#define        FFE_AZ_RX_DESCQ_SIZE_4K 3
+#define        FFE_AZ_RX_DESCQ_SIZE_2K 2
+#define        FFE_AZ_RX_DESCQ_SIZE_1K 1
+#define        FFE_AZ_RX_DESCQ_SIZE_512 0
+#define        FRF_AZ_RX_DESCQ_TYPE_LBN 2
+#define        FRF_AZ_RX_DESCQ_TYPE_WIDTH 1
+#define        FRF_AZ_RX_DESCQ_JUMBO_LBN 1
+#define        FRF_AZ_RX_DESCQ_JUMBO_WIDTH 1
+#define        FRF_AZ_RX_DESCQ_EN_LBN 0
+#define        FRF_AZ_RX_DESCQ_EN_WIDTH 1
+
+/* TX_DESC_PTR_TBL_KER: Transmit descriptor pointer */
+#define        FR_AA_TX_DESC_PTR_TBL_KER 0x00011900
+#define        FR_AA_TX_DESC_PTR_TBL_KER_STEP 16
+#define        FR_AA_TX_DESC_PTR_TBL_KER_ROWS 8
+/* TX_DESC_PTR_TBL: Transmit descriptor pointer */
+#define        FR_BZ_TX_DESC_PTR_TBL 0x00f50000
+#define        FR_BZ_TX_DESC_PTR_TBL_STEP 16
+#define        FR_BB_TX_DESC_PTR_TBL_ROWS 4096
+#define        FR_CZ_TX_DESC_PTR_TBL_ROWS 1024
+#define        FRF_CZ_TX_DPT_Q_MASK_WIDTH_LBN 94
+#define        FRF_CZ_TX_DPT_Q_MASK_WIDTH_WIDTH 2
+#define        FRF_CZ_TX_DPT_ETH_FILT_EN_LBN 93
+#define        FRF_CZ_TX_DPT_ETH_FILT_EN_WIDTH 1
+#define        FRF_CZ_TX_DPT_IP_FILT_EN_LBN 92
+#define        FRF_CZ_TX_DPT_IP_FILT_EN_WIDTH 1
+#define        FRF_BZ_TX_NON_IP_DROP_DIS_LBN 91
+#define        FRF_BZ_TX_NON_IP_DROP_DIS_WIDTH 1
+#define        FRF_BZ_TX_IP_CHKSM_DIS_LBN 90
+#define        FRF_BZ_TX_IP_CHKSM_DIS_WIDTH 1
+#define        FRF_BZ_TX_TCP_CHKSM_DIS_LBN 89
+#define        FRF_BZ_TX_TCP_CHKSM_DIS_WIDTH 1
+#define        FRF_AZ_TX_DESCQ_EN_LBN 88
+#define        FRF_AZ_TX_DESCQ_EN_WIDTH 1
+#define        FRF_AZ_TX_ISCSI_DDIG_EN_LBN 87
+#define        FRF_AZ_TX_ISCSI_DDIG_EN_WIDTH 1
+#define        FRF_AZ_TX_ISCSI_HDIG_EN_LBN 86
+#define        FRF_AZ_TX_ISCSI_HDIG_EN_WIDTH 1
+#define        FRF_AZ_TX_DC_HW_RPTR_LBN 80
+#define        FRF_AZ_TX_DC_HW_RPTR_WIDTH 6
+#define        FRF_AZ_TX_DESCQ_HW_RPTR_LBN 68
+#define        FRF_AZ_TX_DESCQ_HW_RPTR_WIDTH 12
+#define        FRF_AZ_TX_DESCQ_SW_WPTR_LBN 56
+#define        FRF_AZ_TX_DESCQ_SW_WPTR_WIDTH 12
+#define        FRF_AZ_TX_DESCQ_BUF_BASE_ID_LBN 36
+#define        FRF_AZ_TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define        FRF_AZ_TX_DESCQ_EVQ_ID_LBN 24
+#define        FRF_AZ_TX_DESCQ_EVQ_ID_WIDTH 12
+#define        FRF_AZ_TX_DESCQ_OWNER_ID_LBN 10
+#define        FRF_AZ_TX_DESCQ_OWNER_ID_WIDTH 14
+#define        FRF_AZ_TX_DESCQ_LABEL_LBN 5
+#define        FRF_AZ_TX_DESCQ_LABEL_WIDTH 5
+#define        FRF_AZ_TX_DESCQ_SIZE_LBN 3
+#define        FRF_AZ_TX_DESCQ_SIZE_WIDTH 2
+#define        FFE_AZ_TX_DESCQ_SIZE_4K 3
+#define        FFE_AZ_TX_DESCQ_SIZE_2K 2
+#define        FFE_AZ_TX_DESCQ_SIZE_1K 1
+#define        FFE_AZ_TX_DESCQ_SIZE_512 0
+#define        FRF_AZ_TX_DESCQ_TYPE_LBN 1
+#define        FRF_AZ_TX_DESCQ_TYPE_WIDTH 2
+#define        FRF_AZ_TX_DESCQ_FLUSH_LBN 0
+#define        FRF_AZ_TX_DESCQ_FLUSH_WIDTH 1
+
+/* EVQ_PTR_TBL_KER: Event queue pointer table */
+#define        FR_AA_EVQ_PTR_TBL_KER 0x00011a00
+#define        FR_AA_EVQ_PTR_TBL_KER_STEP 16
+#define        FR_AA_EVQ_PTR_TBL_KER_ROWS 4
+/* EVQ_PTR_TBL: Event queue pointer table */
+#define        FR_BZ_EVQ_PTR_TBL 0x00f60000
+#define        FR_BZ_EVQ_PTR_TBL_STEP 16
+#define        FR_CZ_EVQ_PTR_TBL_ROWS 1024
+#define        FR_BB_EVQ_PTR_TBL_ROWS 4096
+#define        FRF_BZ_EVQ_RPTR_IGN_LBN 40
+#define        FRF_BZ_EVQ_RPTR_IGN_WIDTH 1
+#define        FRF_AB_EVQ_WKUP_OR_INT_EN_LBN 39
+#define        FRF_AB_EVQ_WKUP_OR_INT_EN_WIDTH 1
+#define        FRF_CZ_EVQ_DOS_PROTECT_EN_LBN 39
+#define        FRF_CZ_EVQ_DOS_PROTECT_EN_WIDTH 1
+#define        FRF_AZ_EVQ_NXT_WPTR_LBN 24
+#define        FRF_AZ_EVQ_NXT_WPTR_WIDTH 15
+#define        FRF_AZ_EVQ_EN_LBN 23
+#define        FRF_AZ_EVQ_EN_WIDTH 1
+#define        FRF_AZ_EVQ_SIZE_LBN 20
+#define        FRF_AZ_EVQ_SIZE_WIDTH 3
+#define        FFE_AZ_EVQ_SIZE_32K 6
+#define        FFE_AZ_EVQ_SIZE_16K 5
+#define        FFE_AZ_EVQ_SIZE_8K 4
+#define        FFE_AZ_EVQ_SIZE_4K 3
+#define        FFE_AZ_EVQ_SIZE_2K 2
+#define        FFE_AZ_EVQ_SIZE_1K 1
+#define        FFE_AZ_EVQ_SIZE_512 0
+#define        FRF_AZ_EVQ_BUF_BASE_ID_LBN 0
+#define        FRF_AZ_EVQ_BUF_BASE_ID_WIDTH 20
+
+/* BUF_HALF_TBL_KER: Buffer table in half buffer table mode direct access by driver */
+#define        FR_AA_BUF_HALF_TBL_KER 0x00018000
+#define        FR_AA_BUF_HALF_TBL_KER_STEP 8
+#define        FR_AA_BUF_HALF_TBL_KER_ROWS 4096
+/* BUF_HALF_TBL: Buffer table in half buffer table mode direct access by driver */
+#define        FR_BZ_BUF_HALF_TBL 0x00800000
+#define        FR_BZ_BUF_HALF_TBL_STEP 8
+#define        FR_CZ_BUF_HALF_TBL_ROWS 147456
+#define        FR_BB_BUF_HALF_TBL_ROWS 524288
+#define        FRF_AZ_BUF_ADR_HBUF_ODD_LBN 44
+#define        FRF_AZ_BUF_ADR_HBUF_ODD_WIDTH 20
+#define        FRF_AZ_BUF_OWNER_ID_HBUF_ODD_LBN 32
+#define        FRF_AZ_BUF_OWNER_ID_HBUF_ODD_WIDTH 12
+#define        FRF_AZ_BUF_ADR_HBUF_EVEN_LBN 12
+#define        FRF_AZ_BUF_ADR_HBUF_EVEN_WIDTH 20
+#define        FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_LBN 0
+#define        FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
+
+/* BUF_FULL_TBL_KER: Buffer table in full buffer table mode direct access by driver */
+#define        FR_AA_BUF_FULL_TBL_KER 0x00018000
+#define        FR_AA_BUF_FULL_TBL_KER_STEP 8
+#define        FR_AA_BUF_FULL_TBL_KER_ROWS 4096
+/* BUF_FULL_TBL: Buffer table in full buffer table mode direct access by driver */
+#define        FR_BZ_BUF_FULL_TBL 0x00800000
+#define        FR_BZ_BUF_FULL_TBL_STEP 8
+#define        FR_CZ_BUF_FULL_TBL_ROWS 147456
+#define        FR_BB_BUF_FULL_TBL_ROWS 917504
+#define        FRF_AZ_BUF_FULL_UNUSED_LBN 51
+#define        FRF_AZ_BUF_FULL_UNUSED_WIDTH 13
+#define        FRF_AZ_IP_DAT_BUF_SIZE_LBN 50
+#define        FRF_AZ_IP_DAT_BUF_SIZE_WIDTH 1
+#define        FRF_AZ_BUF_ADR_REGION_LBN 48
+#define        FRF_AZ_BUF_ADR_REGION_WIDTH 2
+#define        FFE_AZ_BUF_ADR_REGN3 3
+#define        FFE_AZ_BUF_ADR_REGN2 2
+#define        FFE_AZ_BUF_ADR_REGN1 1
+#define        FFE_AZ_BUF_ADR_REGN0 0
+#define        FRF_AZ_BUF_ADR_FBUF_LBN 14
+#define        FRF_AZ_BUF_ADR_FBUF_WIDTH 34
+#define        FRF_AZ_BUF_OWNER_ID_FBUF_LBN 0
+#define        FRF_AZ_BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* RX_FILTER_TBL0: TCP/IPv4 Receive filter table */
+#define        FR_BZ_RX_FILTER_TBL0 0x00f00000
+#define        FR_BZ_RX_FILTER_TBL0_STEP 32
+#define        FR_BZ_RX_FILTER_TBL0_ROWS 8192
+/* RX_FILTER_TBL1: TCP/IPv4 Receive filter table */
+#define        FR_BB_RX_FILTER_TBL1 0x00f00010
+#define        FR_BB_RX_FILTER_TBL1_STEP 32
+#define        FR_BB_RX_FILTER_TBL1_ROWS 8192
+#define        FRF_BZ_RSS_EN_LBN 110
+#define        FRF_BZ_RSS_EN_WIDTH 1
+#define        FRF_BZ_SCATTER_EN_LBN 109
+#define        FRF_BZ_SCATTER_EN_WIDTH 1
+#define        FRF_BZ_TCP_UDP_LBN 108
+#define        FRF_BZ_TCP_UDP_WIDTH 1
+#define        FRF_BZ_RXQ_ID_LBN 96
+#define        FRF_BZ_RXQ_ID_WIDTH 12
+#define        FRF_BZ_DEST_IP_LBN 64
+#define        FRF_BZ_DEST_IP_WIDTH 32
+#define        FRF_BZ_DEST_PORT_TCP_LBN 48
+#define        FRF_BZ_DEST_PORT_TCP_WIDTH 16
+#define        FRF_BZ_SRC_IP_LBN 16
+#define        FRF_BZ_SRC_IP_WIDTH 32
+#define        FRF_BZ_SRC_TCP_DEST_UDP_LBN 0
+#define        FRF_BZ_SRC_TCP_DEST_UDP_WIDTH 16
+
+/* RX_MAC_FILTER_TBL0: Receive Ethernet filter table */
+#define        FR_CZ_RX_MAC_FILTER_TBL0 0x00f00010
+#define        FR_CZ_RX_MAC_FILTER_TBL0_STEP 32
+#define        FR_CZ_RX_MAC_FILTER_TBL0_ROWS 512
+#define        FRF_CZ_RMFT_RSS_EN_LBN 75
+#define        FRF_CZ_RMFT_RSS_EN_WIDTH 1
+#define        FRF_CZ_RMFT_SCATTER_EN_LBN 74
+#define        FRF_CZ_RMFT_SCATTER_EN_WIDTH 1
+#define        FRF_CZ_RMFT_IP_OVERRIDE_LBN 73
+#define        FRF_CZ_RMFT_IP_OVERRIDE_WIDTH 1
+#define        FRF_CZ_RMFT_RXQ_ID_LBN 61
+#define        FRF_CZ_RMFT_RXQ_ID_WIDTH 12
+#define        FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60
+#define        FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1
+#define        FRF_CZ_RMFT_DEST_MAC_LBN 16
+#define        FRF_CZ_RMFT_DEST_MAC_WIDTH 44
+#define        FRF_CZ_RMFT_VLAN_ID_LBN 0
+#define        FRF_CZ_RMFT_VLAN_ID_WIDTH 12
+
+/* TIMER_TBL: Timer table */
+#define        FR_BZ_TIMER_TBL 0x00f70000
+#define        FR_BZ_TIMER_TBL_STEP 16
+#define        FR_CZ_TIMER_TBL_ROWS 1024
+#define        FR_BB_TIMER_TBL_ROWS 4096
+#define        FRF_CZ_TIMER_Q_EN_LBN 33
+#define        FRF_CZ_TIMER_Q_EN_WIDTH 1
+#define        FRF_CZ_INT_ARMD_LBN 32
+#define        FRF_CZ_INT_ARMD_WIDTH 1
+#define        FRF_CZ_INT_PEND_LBN 31
+#define        FRF_CZ_INT_PEND_WIDTH 1
+#define        FRF_CZ_HOST_NOTIFY_MODE_LBN 30
+#define        FRF_CZ_HOST_NOTIFY_MODE_WIDTH 1
+#define        FRF_CZ_RELOAD_TIMER_VAL_LBN 16
+#define        FRF_CZ_RELOAD_TIMER_VAL_WIDTH 14
+#define        FRF_CZ_TIMER_MODE_LBN 14
+#define        FRF_CZ_TIMER_MODE_WIDTH 2
+#define        FFE_CZ_TIMER_MODE_INT_HLDOFF 3
+#define        FFE_CZ_TIMER_MODE_TRIG_START 2
+#define        FFE_CZ_TIMER_MODE_IMMED_START 1
+#define        FFE_CZ_TIMER_MODE_DIS 0
+#define        FRF_BB_TIMER_MODE_LBN 12
+#define        FRF_BB_TIMER_MODE_WIDTH 2
+#define        FFE_BB_TIMER_MODE_INT_HLDOFF 2
+#define        FFE_BB_TIMER_MODE_TRIG_START 2
+#define        FFE_BB_TIMER_MODE_IMMED_START 1
+#define        FFE_BB_TIMER_MODE_DIS 0
+#define        FRF_CZ_TIMER_VAL_LBN 0
+#define        FRF_CZ_TIMER_VAL_WIDTH 14
+#define        FRF_BB_TIMER_VAL_LBN 0
+#define        FRF_BB_TIMER_VAL_WIDTH 12
+
+/* TX_PACE_TBL: Transmit pacing table */
+#define        FR_BZ_TX_PACE_TBL 0x00f80000
+#define        FR_BZ_TX_PACE_TBL_STEP 16
+#define        FR_CZ_TX_PACE_TBL_ROWS 1024
+#define        FR_BB_TX_PACE_TBL_ROWS 4096
+#define        FRF_BZ_TX_PACE_LBN 0
+#define        FRF_BZ_TX_PACE_WIDTH 5
+
+/* RX_INDIRECTION_TBL: RX Indirection Table */
+#define        FR_BZ_RX_INDIRECTION_TBL 0x00fb0000
+#define        FR_BZ_RX_INDIRECTION_TBL_STEP 16
+#define        FR_BZ_RX_INDIRECTION_TBL_ROWS 128
+#define        FRF_BZ_IT_QUEUE_LBN 0
+#define        FRF_BZ_IT_QUEUE_WIDTH 6
+
+/* TX_FILTER_TBL0: TCP/IPv4 Transmit filter table */
+#define        FR_CZ_TX_FILTER_TBL0 0x00fc0000
+#define        FR_CZ_TX_FILTER_TBL0_STEP 16
+#define        FR_CZ_TX_FILTER_TBL0_ROWS 8192
+#define        FRF_CZ_TIFT_TCP_UDP_LBN 108
+#define        FRF_CZ_TIFT_TCP_UDP_WIDTH 1
+#define        FRF_CZ_TIFT_TXQ_ID_LBN 96
+#define        FRF_CZ_TIFT_TXQ_ID_WIDTH 12
+#define        FRF_CZ_TIFT_DEST_IP_LBN 64
+#define        FRF_CZ_TIFT_DEST_IP_WIDTH 32
+#define        FRF_CZ_TIFT_DEST_PORT_TCP_LBN 48
+#define        FRF_CZ_TIFT_DEST_PORT_TCP_WIDTH 16
+#define        FRF_CZ_TIFT_SRC_IP_LBN 16
+#define        FRF_CZ_TIFT_SRC_IP_WIDTH 32
+#define        FRF_CZ_TIFT_SRC_TCP_DEST_UDP_LBN 0
+#define        FRF_CZ_TIFT_SRC_TCP_DEST_UDP_WIDTH 16
+
+/* TX_MAC_FILTER_TBL0: Transmit Ethernet filter table */
+#define        FR_CZ_TX_MAC_FILTER_TBL0 0x00fe0000
+#define        FR_CZ_TX_MAC_FILTER_TBL0_STEP 16
+#define        FR_CZ_TX_MAC_FILTER_TBL0_ROWS 512
+#define        FRF_CZ_TMFT_TXQ_ID_LBN 61
+#define        FRF_CZ_TMFT_TXQ_ID_WIDTH 12
+#define        FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60
+#define        FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1
+#define        FRF_CZ_TMFT_SRC_MAC_LBN 16
+#define        FRF_CZ_TMFT_SRC_MAC_WIDTH 44
+#define        FRF_CZ_TMFT_VLAN_ID_LBN 0
+#define        FRF_CZ_TMFT_VLAN_ID_WIDTH 12
+
+/* MC_TREG_SMEM: MC Shared Memory */
+#define        FR_CZ_MC_TREG_SMEM 0x00ff0000
+#define        FR_CZ_MC_TREG_SMEM_STEP 4
+#define        FR_CZ_MC_TREG_SMEM_ROWS 512
+#define        FRF_CZ_MC_TREG_SMEM_ROW_LBN 0
+#define        FRF_CZ_MC_TREG_SMEM_ROW_WIDTH 32
+
+/* MSIX_VECTOR_TABLE: MSIX Vector Table */
+#define        FR_BB_MSIX_VECTOR_TABLE 0x00ff0000
+#define        FR_BZ_MSIX_VECTOR_TABLE_STEP 16
+#define        FR_BB_MSIX_VECTOR_TABLE_ROWS 64
+/* MSIX_VECTOR_TABLE: MSIX Vector Table */
+#define        FR_CZ_MSIX_VECTOR_TABLE 0x00000000
+/* FR_BZ_MSIX_VECTOR_TABLE_STEP 16 */
+#define        FR_CZ_MSIX_VECTOR_TABLE_ROWS 1024
+#define        FRF_BZ_MSIX_VECTOR_RESERVED_LBN 97
+#define        FRF_BZ_MSIX_VECTOR_RESERVED_WIDTH 31
+#define        FRF_BZ_MSIX_VECTOR_MASK_LBN 96
+#define        FRF_BZ_MSIX_VECTOR_MASK_WIDTH 1
+#define        FRF_BZ_MSIX_MESSAGE_DATA_LBN 64
+#define        FRF_BZ_MSIX_MESSAGE_DATA_WIDTH 32
+#define        FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_LBN 32
+#define        FRF_BZ_MSIX_MESSAGE_ADDRESS_HI_WIDTH 32
+#define        FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_LBN 0
+#define        FRF_BZ_MSIX_MESSAGE_ADDRESS_LO_WIDTH 32
+
+/* MSIX_PBA_TABLE: MSIX Pending Bit Array */
+#define        FR_BB_MSIX_PBA_TABLE 0x00ff2000
+#define        FR_BZ_MSIX_PBA_TABLE_STEP 4
+#define        FR_BB_MSIX_PBA_TABLE_ROWS 2
+/* MSIX_PBA_TABLE: MSIX Pending Bit Array */
+#define        FR_CZ_MSIX_PBA_TABLE 0x00008000
+/* FR_BZ_MSIX_PBA_TABLE_STEP 4 */
+#define        FR_CZ_MSIX_PBA_TABLE_ROWS 32
+#define        FRF_BZ_MSIX_PBA_PEND_DWORD_LBN 0
+#define        FRF_BZ_MSIX_PBA_PEND_DWORD_WIDTH 32
+
+/* SRM_DBG_REG: SRAM debug access */
+#define        FR_BZ_SRM_DBG 0x03000000
+#define        FR_BZ_SRM_DBG_STEP 8
+#define        FR_CZ_SRM_DBG_ROWS 262144
+#define        FR_BB_SRM_DBG_ROWS 2097152
+#define        FRF_BZ_SRM_DBG_LBN 0
+#define        FRF_BZ_SRM_DBG_WIDTH 64
+
+/* TB_MSIX_PBA_TABLE: MSIX Pending Bit Array */
+#define        FR_CZ_TB_MSIX_PBA_TABLE 0x00008000
+#define        FR_CZ_TB_MSIX_PBA_TABLE_STEP 4
+#define        FR_CZ_TB_MSIX_PBA_TABLE_ROWS 1024
+#define        FRF_CZ_TB_MSIX_PBA_PEND_DWORD_LBN 0
+#define        FRF_CZ_TB_MSIX_PBA_PEND_DWORD_WIDTH 32
+
+/* DRIVER_EV */
+#define        FSF_AZ_DRIVER_EV_SUBCODE_LBN 56
+#define        FSF_AZ_DRIVER_EV_SUBCODE_WIDTH 4
+#define        FSE_BZ_TX_DSC_ERROR_EV 15
+#define        FSE_BZ_RX_DSC_ERROR_EV 14
+#define        FSE_AA_RX_RECOVER_EV 11
+#define        FSE_AZ_TIMER_EV 10
+#define        FSE_AZ_TX_PKT_NON_TCP_UDP 9
+#define        FSE_AZ_WAKE_UP_EV 6
+#define        FSE_AZ_SRM_UPD_DONE_EV 5
+#define        FSE_AB_EVQ_NOT_EN_EV 3
+#define        FSE_AZ_EVQ_INIT_DONE_EV 2
+#define        FSE_AZ_RX_DESCQ_FLS_DONE_EV 1
+#define        FSE_AZ_TX_DESCQ_FLS_DONE_EV 0
+#define        FSF_AZ_DRIVER_EV_SUBDATA_LBN 0
+#define        FSF_AZ_DRIVER_EV_SUBDATA_WIDTH 14
+
+/* EVENT_ENTRY */
+#define        FSF_AZ_EV_CODE_LBN 60
+#define        FSF_AZ_EV_CODE_WIDTH 4
+#define        FSE_CZ_EV_CODE_MCDI_EV 12
+#define        FSE_CZ_EV_CODE_USER_EV 8
+#define        FSE_AZ_EV_CODE_DRV_GEN_EV 7
+#define        FSE_AZ_EV_CODE_GLOBAL_EV 6
+#define        FSE_AZ_EV_CODE_DRIVER_EV 5
+#define        FSE_AZ_EV_CODE_TX_EV 2
+#define        FSE_AZ_EV_CODE_RX_EV 0
+#define        FSF_AZ_EV_DATA_LBN 0
+#define        FSF_AZ_EV_DATA_WIDTH 60
+
+/* GLOBAL_EV */
+#define        FSF_BB_GLB_EV_RX_RECOVERY_LBN 12
+#define        FSF_BB_GLB_EV_RX_RECOVERY_WIDTH 1
+#define        FSF_AA_GLB_EV_RX_RECOVERY_LBN 11
+#define        FSF_AA_GLB_EV_RX_RECOVERY_WIDTH 1
+#define        FSF_BB_GLB_EV_XG_MGT_INTR_LBN 11
+#define        FSF_BB_GLB_EV_XG_MGT_INTR_WIDTH 1
+#define        FSF_AB_GLB_EV_XFP_PHY0_INTR_LBN 10
+#define        FSF_AB_GLB_EV_XFP_PHY0_INTR_WIDTH 1
+#define        FSF_AB_GLB_EV_XG_PHY0_INTR_LBN 9
+#define        FSF_AB_GLB_EV_XG_PHY0_INTR_WIDTH 1
+#define        FSF_AB_GLB_EV_G_PHY0_INTR_LBN 7
+#define        FSF_AB_GLB_EV_G_PHY0_INTR_WIDTH 1
+
+/* LEGACY_INT_VEC */
+#define        FSF_AZ_NET_IVEC_FATAL_INT_LBN 64
+#define        FSF_AZ_NET_IVEC_FATAL_INT_WIDTH 1
+#define        FSF_AZ_NET_IVEC_INT_Q_LBN 40
+#define        FSF_AZ_NET_IVEC_INT_Q_WIDTH 4
+#define        FSF_AZ_NET_IVEC_INT_FLAG_LBN 32
+#define        FSF_AZ_NET_IVEC_INT_FLAG_WIDTH 1
+#define        FSF_AZ_NET_IVEC_EVQ_FIFO_HF_LBN 1
+#define        FSF_AZ_NET_IVEC_EVQ_FIFO_HF_WIDTH 1
+#define        FSF_AZ_NET_IVEC_EVQ_FIFO_AF_LBN 0
+#define        FSF_AZ_NET_IVEC_EVQ_FIFO_AF_WIDTH 1
+
+/* MC_XGMAC_FLTR_RULE_DEF */
+#define        FSF_CZ_MC_XFRC_MODE_LBN 416
+#define        FSF_CZ_MC_XFRC_MODE_WIDTH 1
+#define        FSE_CZ_MC_XFRC_MODE_LAYERED 1
+#define        FSE_CZ_MC_XFRC_MODE_SIMPLE 0
+#define        FSF_CZ_MC_XFRC_HASH_LBN 384
+#define        FSF_CZ_MC_XFRC_HASH_WIDTH 32
+#define        FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_LBN 256
+#define        FSF_CZ_MC_XFRC_LAYER4_BYTE_MASK_WIDTH 128
+#define        FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_LBN 128
+#define        FSF_CZ_MC_XFRC_LAYER3_BYTE_MASK_WIDTH 128
+#define        FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_LBN 0
+#define        FSF_CZ_MC_XFRC_LAYER2_OR_SIMPLE_BYTE_MASK_WIDTH 128
+
+/* RX_EV */
+#define        FSF_CZ_RX_EV_PKT_NOT_PARSED_LBN 58
+#define        FSF_CZ_RX_EV_PKT_NOT_PARSED_WIDTH 1
+#define        FSF_CZ_RX_EV_IPV6_PKT_LBN 57
+#define        FSF_CZ_RX_EV_IPV6_PKT_WIDTH 1
+#define        FSF_AZ_RX_EV_PKT_OK_LBN 56
+#define        FSF_AZ_RX_EV_PKT_OK_WIDTH 1
+#define        FSF_AZ_RX_EV_PAUSE_FRM_ERR_LBN 55
+#define        FSF_AZ_RX_EV_PAUSE_FRM_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_LBN 54
+#define        FSF_AZ_RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_IP_FRAG_ERR_LBN 53
+#define        FSF_AZ_RX_EV_IP_FRAG_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
+#define        FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
+#define        FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_ETH_CRC_ERR_LBN 50
+#define        FSF_AZ_RX_EV_ETH_CRC_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_FRM_TRUNC_LBN 49
+#define        FSF_AZ_RX_EV_FRM_TRUNC_WIDTH 1
+#define        FSF_AA_RX_EV_DRIB_NIB_LBN 49
+#define        FSF_AA_RX_EV_DRIB_NIB_WIDTH 1
+#define        FSF_AZ_RX_EV_TOBE_DISC_LBN 47
+#define        FSF_AZ_RX_EV_TOBE_DISC_WIDTH 1
+#define        FSF_AZ_RX_EV_PKT_TYPE_LBN 44
+#define        FSF_AZ_RX_EV_PKT_TYPE_WIDTH 3
+#define        FSE_AZ_RX_EV_PKT_TYPE_VLAN_JUMBO 5
+#define        FSE_AZ_RX_EV_PKT_TYPE_VLAN_LLC 4
+#define        FSE_AZ_RX_EV_PKT_TYPE_VLAN 3
+#define        FSE_AZ_RX_EV_PKT_TYPE_JUMBO 2
+#define        FSE_AZ_RX_EV_PKT_TYPE_LLC 1
+#define        FSE_AZ_RX_EV_PKT_TYPE_ETH 0
+#define        FSF_AZ_RX_EV_HDR_TYPE_LBN 42
+#define        FSF_AZ_RX_EV_HDR_TYPE_WIDTH 2
+#define        FSE_AZ_RX_EV_HDR_TYPE_OTHER 3
+#define        FSE_AB_RX_EV_HDR_TYPE_IPV4_OTHER 2
+#define        FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_OTHER 2
+#define        FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP 1
+#define        FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP 1
+#define        FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP 0
+#define        FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP 0
+#define        FSF_AZ_RX_EV_DESC_Q_EMPTY_LBN 41
+#define        FSF_AZ_RX_EV_DESC_Q_EMPTY_WIDTH 1
+#define        FSF_AZ_RX_EV_MCAST_HASH_MATCH_LBN 40
+#define        FSF_AZ_RX_EV_MCAST_HASH_MATCH_WIDTH 1
+#define        FSF_AZ_RX_EV_MCAST_PKT_LBN 39
+#define        FSF_AZ_RX_EV_MCAST_PKT_WIDTH 1
+#define        FSF_AA_RX_EV_RECOVERY_FLAG_LBN 37
+#define        FSF_AA_RX_EV_RECOVERY_FLAG_WIDTH 1
+#define        FSF_AZ_RX_EV_Q_LABEL_LBN 32
+#define        FSF_AZ_RX_EV_Q_LABEL_WIDTH 5
+#define        FSF_AZ_RX_EV_JUMBO_CONT_LBN 31
+#define        FSF_AZ_RX_EV_JUMBO_CONT_WIDTH 1
+#define        FSF_AZ_RX_EV_PORT_LBN 30
+#define        FSF_AZ_RX_EV_PORT_WIDTH 1
+#define        FSF_AZ_RX_EV_BYTE_CNT_LBN 16
+#define        FSF_AZ_RX_EV_BYTE_CNT_WIDTH 14
+#define        FSF_AZ_RX_EV_SOP_LBN 15
+#define        FSF_AZ_RX_EV_SOP_WIDTH 1
+#define        FSF_AZ_RX_EV_ISCSI_PKT_OK_LBN 14
+#define        FSF_AZ_RX_EV_ISCSI_PKT_OK_WIDTH 1
+#define        FSF_AZ_RX_EV_ISCSI_DDIG_ERR_LBN 13
+#define        FSF_AZ_RX_EV_ISCSI_DDIG_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_ISCSI_HDIG_ERR_LBN 12
+#define        FSF_AZ_RX_EV_ISCSI_HDIG_ERR_WIDTH 1
+#define        FSF_AZ_RX_EV_DESC_PTR_LBN 0
+#define        FSF_AZ_RX_EV_DESC_PTR_WIDTH 12
+
+/* RX_KER_DESC */
+#define        FSF_AZ_RX_KER_BUF_SIZE_LBN 48
+#define        FSF_AZ_RX_KER_BUF_SIZE_WIDTH 14
+#define        FSF_AZ_RX_KER_BUF_REGION_LBN 46
+#define        FSF_AZ_RX_KER_BUF_REGION_WIDTH 2
+#define        FSF_AZ_RX_KER_BUF_ADDR_LBN 0
+#define        FSF_AZ_RX_KER_BUF_ADDR_WIDTH 46
+
+/* RX_USER_DESC */
+#define        FSF_AZ_RX_USER_2BYTE_OFFSET_LBN 20
+#define        FSF_AZ_RX_USER_2BYTE_OFFSET_WIDTH 12
+#define        FSF_AZ_RX_USER_BUF_ID_LBN 0
+#define        FSF_AZ_RX_USER_BUF_ID_WIDTH 20
+
+/* TX_EV */
+#define        FSF_AZ_TX_EV_PKT_ERR_LBN 38
+#define        FSF_AZ_TX_EV_PKT_ERR_WIDTH 1
+#define        FSF_AZ_TX_EV_PKT_TOO_BIG_LBN 37
+#define        FSF_AZ_TX_EV_PKT_TOO_BIG_WIDTH 1
+#define        FSF_AZ_TX_EV_Q_LABEL_LBN 32
+#define        FSF_AZ_TX_EV_Q_LABEL_WIDTH 5
+#define        FSF_AZ_TX_EV_PORT_LBN 16
+#define        FSF_AZ_TX_EV_PORT_WIDTH 1
+#define        FSF_AZ_TX_EV_WQ_FF_FULL_LBN 15
+#define        FSF_AZ_TX_EV_WQ_FF_FULL_WIDTH 1
+#define        FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_LBN 14
+#define        FSF_AZ_TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define        FSF_AZ_TX_EV_COMP_LBN 12
+#define        FSF_AZ_TX_EV_COMP_WIDTH 1
+#define        FSF_AZ_TX_EV_DESC_PTR_LBN 0
+#define        FSF_AZ_TX_EV_DESC_PTR_WIDTH 12
+
+/* TX_KER_DESC */
+#define        FSF_AZ_TX_KER_CONT_LBN 62
+#define        FSF_AZ_TX_KER_CONT_WIDTH 1
+#define        FSF_AZ_TX_KER_BYTE_COUNT_LBN 48
+#define        FSF_AZ_TX_KER_BYTE_COUNT_WIDTH 14
+#define        FSF_AZ_TX_KER_BUF_REGION_LBN 46
+#define        FSF_AZ_TX_KER_BUF_REGION_WIDTH 2
+#define        FSF_AZ_TX_KER_BUF_ADDR_LBN 0
+#define        FSF_AZ_TX_KER_BUF_ADDR_WIDTH 46
+
+/* TX_USER_DESC */
+#define        FSF_AZ_TX_USER_SW_EV_EN_LBN 48
+#define        FSF_AZ_TX_USER_SW_EV_EN_WIDTH 1
+#define        FSF_AZ_TX_USER_CONT_LBN 46
+#define        FSF_AZ_TX_USER_CONT_WIDTH 1
+#define        FSF_AZ_TX_USER_BYTE_CNT_LBN 33
+#define        FSF_AZ_TX_USER_BYTE_CNT_WIDTH 13
+#define        FSF_AZ_TX_USER_BUF_ID_LBN 13
+#define        FSF_AZ_TX_USER_BUF_ID_WIDTH 20
+#define        FSF_AZ_TX_USER_BYTE_OFS_LBN 0
+#define        FSF_AZ_TX_USER_BYTE_OFS_WIDTH 13
+
+/* USER_EV */
+#define        FSF_CZ_USER_QID_LBN 32
+#define        FSF_CZ_USER_QID_WIDTH 10
+#define        FSF_CZ_USER_EV_REG_VALUE_LBN 0
+#define        FSF_CZ_USER_EV_REG_VALUE_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon B0 PCIe core indirect registers
+ *
+ **************************************************************************
+ */
+
+#define FPCR_BB_PCIE_DEVICE_CTRL_STAT 0x68
+
+#define FPCR_BB_PCIE_LINK_CTRL_STAT 0x70
+
+#define FPCR_BB_ACK_RPL_TIMER 0x700
+#define FPCRF_BB_ACK_TL_LBN 0
+#define FPCRF_BB_ACK_TL_WIDTH 16
+#define FPCRF_BB_RPL_TL_LBN 16
+#define FPCRF_BB_RPL_TL_WIDTH 16
+
+#define FPCR_BB_ACK_FREQ 0x70C
+#define FPCRF_BB_ACK_FREQ_LBN 0
+#define FPCRF_BB_ACK_FREQ_WIDTH 7
+
+/**************************************************************************
+ *
+ * Pseudo-registers and fields
+ *
+ **************************************************************************
+ */
+
+/* Interrupt acknowledge work-around register (A0/A1 only) */
+#define FR_AA_WORK_AROUND_BROKEN_PCI_READS 0x0070
+
+/* EE_SPI_HCMD_REG: SPI host command register */
+/* Values for the EE_SPI_HCMD_SF_SEL register field */
+#define FFE_AB_SPI_DEVICE_EEPROM 0
+#define FFE_AB_SPI_DEVICE_FLASH 1
+
+/* NIC_STAT_REG: NIC status register */
+#define FRF_AB_STRAP_10G_LBN 2
+#define FRF_AB_STRAP_10G_WIDTH 1
+#define FRF_AA_STRAP_PCIE_LBN 0
+#define FRF_AA_STRAP_PCIE_WIDTH 1
+
+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
+#define FRF_AZ_FATAL_INTR_LBN 0
+#define FRF_AZ_FATAL_INTR_WIDTH 12
+
+/* SRM_CFG_REG: SRAM configuration register */
+/* We treat the number of SRAM banks and bank size as a single field */
+#define        FRF_AZ_SRM_NB_SZ_LBN FRF_AZ_SRM_BANK_SIZE_LBN
+#define        FRF_AZ_SRM_NB_SZ_WIDTH \
+       (FRF_AZ_SRM_BANK_SIZE_WIDTH + FRF_AZ_SRM_NUM_BANK_WIDTH)
+#define FFE_AB_SRM_NB1_SZ2M 0
+#define FFE_AB_SRM_NB1_SZ4M 1
+#define FFE_AB_SRM_NB1_SZ8M 2
+#define FFE_AB_SRM_NB_SZ_DEF 3
+#define FFE_AB_SRM_NB2_SZ4M 4
+#define FFE_AB_SRM_NB2_SZ8M 5
+#define FFE_AB_SRM_NB2_SZ16M 6
+#define FFE_AB_SRM_NB_SZ_RES 7
+
+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
+/* We write just the last dword of these registers */
+#define        FR_AZ_RX_DESC_UPD_DWORD_P0 \
+       (BUILD_BUG_ON_ZERO(FR_AA_RX_DESC_UPD_KER != FR_BZ_RX_DESC_UPD_P0) + \
+        FR_BZ_RX_DESC_UPD_P0 + 3 * 4)
+#define        FRF_AZ_RX_DESC_WPTR_DWORD_LBN (FRF_AZ_RX_DESC_WPTR_LBN - 3 * 32)
+#define        FRF_AZ_RX_DESC_WPTR_DWORD_WIDTH FRF_AZ_RX_DESC_WPTR_WIDTH
+
+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
+#define FR_AZ_TX_DESC_UPD_DWORD_P0 \
+       (BUILD_BUG_ON_ZERO(FR_AA_TX_DESC_UPD_KER != FR_BZ_TX_DESC_UPD_P0) + \
+        FR_BZ_TX_DESC_UPD_P0 + 3 * 4)
+#define        FRF_AZ_TX_DESC_WPTR_DWORD_LBN (FRF_AZ_TX_DESC_WPTR_LBN - 3 * 32)
+#define        FRF_AZ_TX_DESC_WPTR_DWORD_WIDTH FRF_AZ_TX_DESC_WPTR_WIDTH
+
+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
+#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define FRF_AB_GMF_HSTFLTRFRM_PAUSE_WIDTH 1
+
+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
+#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define FRF_AB_GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
+#define        FRF_AB_XM_MAX_TX_FRM_SIZE_LBN FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN
+#define        FRF_AB_XM_MAX_TX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH + \
+                                        FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH)
+
+/* XM_RX_PARAM_REG: XGMAC receive parameter register */
+#define        FRF_AB_XM_MAX_RX_FRM_SIZE_LBN FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN
+#define        FRF_AB_XM_MAX_RX_FRM_SIZE_WIDTH (FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH + \
+                                        FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH)
+
+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
+/* Default values */
+#define FFE_AB_XX_TXDRV_DEQ_DEF 0xe /* deq=.6 */
+#define FFE_AB_XX_TXDRV_DTX_DEF 0x5 /* 1.25 */
+#define FFE_AB_XX_SD_CTL_DRV_DEF 0  /* 20mA */
+
+/* XX_CORE_STAT_REG: XAUI XGXS core status register */
+/* XGXS all-lanes status fields */
+#define        FRF_AB_XX_SYNC_STAT_LBN FRF_AB_XX_SYNC_STAT0_LBN
+#define        FRF_AB_XX_SYNC_STAT_WIDTH 4
+#define        FRF_AB_XX_COMMA_DET_LBN FRF_AB_XX_COMMA_DET_CH0_LBN
+#define        FRF_AB_XX_COMMA_DET_WIDTH 4
+#define        FRF_AB_XX_CHAR_ERR_LBN FRF_AB_XX_CHAR_ERR_CH0_LBN
+#define        FRF_AB_XX_CHAR_ERR_WIDTH 4
+#define        FRF_AB_XX_DISPERR_LBN FRF_AB_XX_DISPERR_CH0_LBN
+#define        FRF_AB_XX_DISPERR_WIDTH 4
+#define        FFE_AB_XX_STAT_ALL_LANES 0xf
+#define        FRF_AB_XX_FORCE_SIG_LBN FRF_AB_XX_FORCE_SIG0_VAL_LBN
+#define        FRF_AB_XX_FORCE_SIG_WIDTH 8
+#define        FFE_AB_XX_FORCE_SIG_ALL_LANES 0xff
+
+/* DRIVER_EV */
+/* Sub-fields of an RX flush completion event */
+#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_LBN 12
+#define FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
+#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_LBN 0
+#define FSF_AZ_DRIVER_EV_RX_DESCQ_ID_WIDTH 12
+
+/* EVENT_ENTRY */
+/* Magic number field for event test */
+#define FSF_AZ_DRV_GEN_EV_MAGIC_LBN 0
+#define FSF_AZ_DRV_GEN_EV_MAGIC_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ *
+ */
+
+#define GRxGoodOct_offset 0x0
+#define GRxGoodOct_WIDTH 48
+#define GRxBadOct_offset 0x8
+#define GRxBadOct_WIDTH 48
+#define GRxMissPkt_offset 0x10
+#define GRxMissPkt_WIDTH 32
+#define GRxFalseCRS_offset 0x14
+#define GRxFalseCRS_WIDTH 32
+#define GRxPausePkt_offset 0x18
+#define GRxPausePkt_WIDTH 32
+#define GRxBadPkt_offset 0x1C
+#define GRxBadPkt_WIDTH 32
+#define GRxUcastPkt_offset 0x20
+#define GRxUcastPkt_WIDTH 32
+#define GRxMcastPkt_offset 0x24
+#define GRxMcastPkt_WIDTH 32
+#define GRxBcastPkt_offset 0x28
+#define GRxBcastPkt_WIDTH 32
+#define GRxGoodLt64Pkt_offset 0x2C
+#define GRxGoodLt64Pkt_WIDTH 32
+#define GRxBadLt64Pkt_offset 0x30
+#define GRxBadLt64Pkt_WIDTH 32
+#define GRx64Pkt_offset 0x34
+#define GRx64Pkt_WIDTH 32
+#define GRx65to127Pkt_offset 0x38
+#define GRx65to127Pkt_WIDTH 32
+#define GRx128to255Pkt_offset 0x3C
+#define GRx128to255Pkt_WIDTH 32
+#define GRx256to511Pkt_offset 0x40
+#define GRx256to511Pkt_WIDTH 32
+#define GRx512to1023Pkt_offset 0x44
+#define GRx512to1023Pkt_WIDTH 32
+#define GRx1024to15xxPkt_offset 0x48
+#define GRx1024to15xxPkt_WIDTH 32
+#define GRx15xxtoJumboPkt_offset 0x4C
+#define GRx15xxtoJumboPkt_WIDTH 32
+#define GRxGtJumboPkt_offset 0x50
+#define GRxGtJumboPkt_WIDTH 32
+#define GRxFcsErr64to15xxPkt_offset 0x54
+#define GRxFcsErr64to15xxPkt_WIDTH 32
+#define GRxFcsErr15xxtoJumboPkt_offset 0x58
+#define GRxFcsErr15xxtoJumboPkt_WIDTH 32
+#define GRxFcsErrGtJumboPkt_offset 0x5C
+#define GRxFcsErrGtJumboPkt_WIDTH 32
+#define GTxGoodBadOct_offset 0x80
+#define GTxGoodBadOct_WIDTH 48
+#define GTxGoodOct_offset 0x88
+#define GTxGoodOct_WIDTH 48
+#define GTxSglColPkt_offset 0x90
+#define GTxSglColPkt_WIDTH 32
+#define GTxMultColPkt_offset 0x94
+#define GTxMultColPkt_WIDTH 32
+#define GTxExColPkt_offset 0x98
+#define GTxExColPkt_WIDTH 32
+#define GTxDefPkt_offset 0x9C
+#define GTxDefPkt_WIDTH 32
+#define GTxLateCol_offset 0xA0
+#define GTxLateCol_WIDTH 32
+#define GTxExDefPkt_offset 0xA4
+#define GTxExDefPkt_WIDTH 32
+#define GTxPausePkt_offset 0xA8
+#define GTxPausePkt_WIDTH 32
+#define GTxBadPkt_offset 0xAC
+#define GTxBadPkt_WIDTH 32
+#define GTxUcastPkt_offset 0xB0
+#define GTxUcastPkt_WIDTH 32
+#define GTxMcastPkt_offset 0xB4
+#define GTxMcastPkt_WIDTH 32
+#define GTxBcastPkt_offset 0xB8
+#define GTxBcastPkt_WIDTH 32
+#define GTxLt64Pkt_offset 0xBC
+#define GTxLt64Pkt_WIDTH 32
+#define GTx64Pkt_offset 0xC0
+#define GTx64Pkt_WIDTH 32
+#define GTx65to127Pkt_offset 0xC4
+#define GTx65to127Pkt_WIDTH 32
+#define GTx128to255Pkt_offset 0xC8
+#define GTx128to255Pkt_WIDTH 32
+#define GTx256to511Pkt_offset 0xCC
+#define GTx256to511Pkt_WIDTH 32
+#define GTx512to1023Pkt_offset 0xD0
+#define GTx512to1023Pkt_WIDTH 32
+#define GTx1024to15xxPkt_offset 0xD4
+#define GTx1024to15xxPkt_WIDTH 32
+#define GTx15xxtoJumboPkt_offset 0xD8
+#define GTx15xxtoJumboPkt_WIDTH 32
+#define GTxGtJumboPkt_offset 0xDC
+#define GTxGtJumboPkt_WIDTH 32
+#define GTxNonTcpUdpPkt_offset 0xE0
+#define GTxNonTcpUdpPkt_WIDTH 16
+#define GTxMacSrcErrPkt_offset 0xE4
+#define GTxMacSrcErrPkt_WIDTH 16
+#define GTxIpSrcErrPkt_offset 0xE8
+#define GTxIpSrcErrPkt_WIDTH 16
+#define GDmaDone_offset 0xEC
+#define GDmaDone_WIDTH 32
+
+#define XgRxOctets_offset 0x0
+#define XgRxOctets_WIDTH 48
+#define XgRxOctetsOK_offset 0x8
+#define XgRxOctetsOK_WIDTH 48
+#define XgRxPkts_offset 0x10
+#define XgRxPkts_WIDTH 32
+#define XgRxPktsOK_offset 0x14
+#define XgRxPktsOK_WIDTH 32
+#define XgRxBroadcastPkts_offset 0x18
+#define XgRxBroadcastPkts_WIDTH 32
+#define XgRxMulticastPkts_offset 0x1C
+#define XgRxMulticastPkts_WIDTH 32
+#define XgRxUnicastPkts_offset 0x20
+#define XgRxUnicastPkts_WIDTH 32
+#define XgRxUndersizePkts_offset 0x24
+#define XgRxUndersizePkts_WIDTH 32
+#define XgRxOversizePkts_offset 0x28
+#define XgRxOversizePkts_WIDTH 32
+#define XgRxJabberPkts_offset 0x2C
+#define XgRxJabberPkts_WIDTH 32
+#define XgRxUndersizeFCSerrorPkts_offset 0x30
+#define XgRxUndersizeFCSerrorPkts_WIDTH 32
+#define XgRxDropEvents_offset 0x34
+#define XgRxDropEvents_WIDTH 32
+#define XgRxFCSerrorPkts_offset 0x38
+#define XgRxFCSerrorPkts_WIDTH 32
+#define XgRxAlignError_offset 0x3C
+#define XgRxAlignError_WIDTH 32
+#define XgRxSymbolError_offset 0x40
+#define XgRxSymbolError_WIDTH 32
+#define XgRxInternalMACError_offset 0x44
+#define XgRxInternalMACError_WIDTH 32
+#define XgRxControlPkts_offset 0x48
+#define XgRxControlPkts_WIDTH 32
+#define XgRxPausePkts_offset 0x4C
+#define XgRxPausePkts_WIDTH 32
+#define XgRxPkts64Octets_offset 0x50
+#define XgRxPkts64Octets_WIDTH 32
+#define XgRxPkts65to127Octets_offset 0x54
+#define XgRxPkts65to127Octets_WIDTH 32
+#define XgRxPkts128to255Octets_offset 0x58
+#define XgRxPkts128to255Octets_WIDTH 32
+#define XgRxPkts256to511Octets_offset 0x5C
+#define XgRxPkts256to511Octets_WIDTH 32
+#define XgRxPkts512to1023Octets_offset 0x60
+#define XgRxPkts512to1023Octets_WIDTH 32
+#define XgRxPkts1024to15xxOctets_offset 0x64
+#define XgRxPkts1024to15xxOctets_WIDTH 32
+#define XgRxPkts15xxtoMaxOctets_offset 0x68
+#define XgRxPkts15xxtoMaxOctets_WIDTH 32
+#define XgRxLengthError_offset 0x6C
+#define XgRxLengthError_WIDTH 32
+#define XgTxPkts_offset 0x80
+#define XgTxPkts_WIDTH 32
+#define XgTxOctets_offset 0x88
+#define XgTxOctets_WIDTH 48
+#define XgTxMulticastPkts_offset 0x90
+#define XgTxMulticastPkts_WIDTH 32
+#define XgTxBroadcastPkts_offset 0x94
+#define XgTxBroadcastPkts_WIDTH 32
+#define XgTxUnicastPkts_offset 0x98
+#define XgTxUnicastPkts_WIDTH 32
+#define XgTxControlPkts_offset 0x9C
+#define XgTxControlPkts_WIDTH 32
+#define XgTxPausePkts_offset 0xA0
+#define XgTxPausePkts_WIDTH 32
+#define XgTxPkts64Octets_offset 0xA4
+#define XgTxPkts64Octets_WIDTH 32
+#define XgTxPkts65to127Octets_offset 0xA8
+#define XgTxPkts65to127Octets_WIDTH 32
+#define XgTxPkts128to255Octets_offset 0xAC
+#define XgTxPkts128to255Octets_WIDTH 32
+#define XgTxPkts256to511Octets_offset 0xB0
+#define XgTxPkts256to511Octets_WIDTH 32
+#define XgTxPkts512to1023Octets_offset 0xB4
+#define XgTxPkts512to1023Octets_WIDTH 32
+#define XgTxPkts1024to15xxOctets_offset 0xB8
+#define XgTxPkts1024to15xxOctets_WIDTH 32
+#define XgTxPkts1519toMaxOctets_offset 0xBC
+#define XgTxPkts1519toMaxOctets_WIDTH 32
+#define XgTxUndersizePkts_offset 0xC0
+#define XgTxUndersizePkts_WIDTH 32
+#define XgTxOversizePkts_offset 0xC4
+#define XgTxOversizePkts_WIDTH 32
+#define XgTxNonTcpUdpPkt_offset 0xC8
+#define XgTxNonTcpUdpPkt_WIDTH 16
+#define XgTxMacSrcErrPkt_offset 0xCC
+#define XgTxMacSrcErrPkt_WIDTH 16
+#define XgTxIpSrcErrPkt_offset 0xD0
+#define XgTxIpSrcErrPkt_WIDTH 16
+#define XgDmaDone_offset 0xD4
+#define XgDmaDone_WIDTH 32
+
+#define FALCON_STATS_NOT_DONE 0x00000000
+#define FALCON_STATS_DONE 0xffffffff
+
+/**************************************************************************
+ *
+ * Falcon non-volatile configuration
+ *
+ **************************************************************************
+ */
+
+/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
+struct falcon_nvconfig_board_v2 {
+       __le16 nports;
+       u8 port0_phy_addr;
+       u8 port0_phy_type;
+       u8 port1_phy_addr;
+       u8 port1_phy_type;
+       __le16 asic_sub_revision;
+       __le16 board_revision;
+} __packed;
+
+/* Board configuration v3 extra information */
+struct falcon_nvconfig_board_v3 {
+       __le32 spi_device_type[2];
+} __packed;
+
+/* Bit numbers for spi_device_type */
+#define SPI_DEV_TYPE_SIZE_LBN 0
+#define SPI_DEV_TYPE_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
+#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
+#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
+#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
+#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
+#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
+#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
+#define SPI_DEV_TYPE_FIELD(type, field)                                        \
+       (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field)))
+
+#define FALCON_NVCONFIG_OFFSET 0x300
+
+#define FALCON_NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
+struct falcon_nvconfig {
+       efx_oword_t ee_vpd_cfg_reg;                     /* 0x300 */
+       u8 mac_address[2][8];                   /* 0x310 */
+       efx_oword_t pcie_sd_ctl0123_reg;                /* 0x320 */
+       efx_oword_t pcie_sd_ctl45_reg;                  /* 0x330 */
+       efx_oword_t pcie_pcs_ctl_stat_reg;              /* 0x340 */
+       efx_oword_t hw_init_reg;                        /* 0x350 */
+       efx_oword_t nic_stat_reg;                       /* 0x360 */
+       efx_oword_t glb_ctl_reg;                        /* 0x370 */
+       efx_oword_t srm_cfg_reg;                        /* 0x380 */
+       efx_oword_t spare_reg;                          /* 0x390 */
+       __le16 board_magic_num;                 /* 0x3A0 */
+       __le16 board_struct_ver;
+       __le16 board_checksum;
+       struct falcon_nvconfig_board_v2 board_v2;
+       efx_oword_t ee_base_page_reg;                   /* 0x3B0 */
+       struct falcon_nvconfig_board_v3 board_v3;       /* 0x3C0 */
+} __packed;
+
+#endif /* EFX_REGS_H */
index 1bc991201f3673d06d8fc2854d659afa5bb3ca0e..892bc21ab2bb0e11a1e7249b739d3237e0837b92 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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/socket.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <net/ip.h>
+#include <net/tcp.h>
 #include <net/checksum.h>
 #include "net_driver.h"
-#include "rx.h"
 #include "efx.h"
-#include "falcon.h"
+#include "nic.h"
 #include "selftest.h"
 #include "workarounds.h"
 
-
 /* Number of RX descriptors pushed at once. */
 #define EFX_RX_BATCH  8
 
  *   rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
  *                      RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
  */
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_GRO) || defined(EFX_HAVE_DEV_DISABLE_LRO)
+static int rx_alloc_method = RX_ALLOC_METHOD_AUTO;
+#else
+/* LRO using SKB chaining will cause a BUG() if bridging is used. This was
+ * fixed by GRO, and worked around by dev_disable_lro(). Change the default
+ * to avoid the BUG(), but allow the user to override this.
+ */
 static int rx_alloc_method = RX_ALLOC_METHOD_PAGE;
+#endif
 
 #define RX_ALLOC_LEVEL_LRO 0x2000
 #define RX_ALLOC_LEVEL_MAX 0x3000
@@ -104,14 +94,17 @@ static unsigned int rx_refill_limit = 95;
  */
 #define EFX_RXD_HEAD_ROOM 2
 
-/* Macros for zero-order pages (potentially) containing multiple RX buffers */
-#define RX_DATA_OFFSET(_data)                          \
-       (((unsigned long) (_data)) & (PAGE_SIZE-1))
-#define RX_BUF_OFFSET(_rx_buf)                         \
-       RX_DATA_OFFSET((_rx_buf)->data)
-
-#define RX_PAGE_SIZE(_efx)                             \
-       (PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
+static inline unsigned int efx_rx_buf_offset(struct efx_rx_buffer *buf)
+{
+       /* Offset is always within one page, so we don't need to consider
+        * the page order.
+        */
+       return (__force unsigned long) buf->data & (PAGE_SIZE - 1);
+}
+static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
+{
+       return PAGE_SIZE << efx->rx_buffer_order;
+}
 
 
 /**
@@ -124,8 +117,8 @@ static unsigned int rx_refill_limit = 95;
  * and populates a struct efx_rx_buffer with the relevant
  * information.  Return a negative error code or 0 on success.
  */
-static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
-                                        struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
+                                 struct efx_rx_buffer *rx_buf)
 {
        struct efx_nic *efx = rx_queue->efx;
        struct net_device *net_dev = efx->net_dev;
@@ -139,16 +132,13 @@ static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
        skb_reserve(rx_buf->skb, NET_IP_ALIGN);
        rx_buf->len = skb_len - NET_IP_ALIGN;
        rx_buf->data = (char *)rx_buf->skb->data;
-
        rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-       /* Map for DMA */
        rx_buf->dma_addr = pci_map_single(efx->pci_dev,
                                          rx_buf->data, rx_buf->len,
                                          PCI_DMA_FROMDEVICE);
 
-       if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) {
-               /* Free the SKB */
+       if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) {
                dev_kfree_skb_any(rx_buf->skb);
                rx_buf->skb = NULL;
                return -EIO;
@@ -167,8 +157,8 @@ static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
  * and populates a struct efx_rx_buffer with the relevant
  * information.  Return a negative error code or 0 on success.
  */
-static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
-                                         struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
+                                  struct efx_rx_buffer *rx_buf)
 {
        struct efx_nic *efx = rx_queue->efx;
        int bytes, space, offset;
@@ -186,12 +176,11 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
                if (unlikely(rx_buf->page == NULL))
                        return -ENOMEM;
 
-               /* Map the entire page for DMA */
                dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
-                                       0, RX_PAGE_SIZE(efx),
+                                       0, efx_rx_buf_size(efx),
                                        PCI_DMA_FROMDEVICE);
 
-               if (unlikely(pci_dma_mapping_error(dma_addr))) {
+               if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
                        __free_pages(rx_buf->page, efx->rx_buffer_order);
                        rx_buf->page = NULL;
                        return -EIO;
@@ -199,14 +188,14 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
 
                rx_queue->buf_page = rx_buf->page;
                rx_queue->buf_dma_addr = dma_addr;
-               rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
+               rx_queue->buf_data = (page_address(rx_buf->page) +
                                      EFX_PAGE_IP_ALIGN);
        }
 
-       offset = RX_DATA_OFFSET(rx_queue->buf_data);
        rx_buf->len = bytes;
-       rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
        rx_buf->data = rx_queue->buf_data;
+       offset = efx_rx_buf_offset(rx_buf);
+       rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
 
        /* Try to pack multiple buffers per page */
        if (efx->rx_buffer_order == 0) {
@@ -214,7 +203,7 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
                rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
                offset += ((bytes + 0x1ff) & ~0x1ff);
 
-               space = RX_PAGE_SIZE(efx) - offset;
+               space = efx_rx_buf_size(efx) - offset;
                if (space >= bytes) {
                        /* Refs dropped on kernel releasing each skb */
                        get_page(rx_queue->buf_page);
@@ -235,8 +224,8 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
  * and populates a struct efx_rx_buffer with the relevant
  * information.
  */
-static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
-                                    struct efx_rx_buffer *new_rx_buf)
+static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
+                             struct efx_rx_buffer *new_rx_buf)
 {
        int rc = 0;
 
@@ -256,14 +245,15 @@ static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
        return rc;
 }
 
-static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
-                                      struct efx_rx_buffer *rx_buf)
+static void efx_unmap_rx_buffer(struct efx_nic *efx,
+                               struct efx_rx_buffer *rx_buf)
 {
        if (rx_buf->page) {
                EFX_BUG_ON_PARANOID(rx_buf->skb);
                if (rx_buf->unmap_addr) {
                        pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
-                                      RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
+                                      efx_rx_buf_size(efx),
+                                      PCI_DMA_FROMDEVICE);
                        rx_buf->unmap_addr = 0;
                }
        } else if (likely(rx_buf->skb)) {
@@ -272,8 +262,8 @@ static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
        }
 }
 
-static inline void efx_free_rx_buffer(struct efx_nic *efx,
-                                     struct efx_rx_buffer *rx_buf)
+static void efx_free_rx_buffer(struct efx_nic *efx,
+                              struct efx_rx_buffer *rx_buf)
 {
        if (rx_buf->page) {
                __free_pages(rx_buf->page, efx->rx_buffer_order);
@@ -284,13 +274,10 @@ static inline void efx_free_rx_buffer(struct efx_nic *efx,
        }
 }
 
-static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
-                                     struct efx_rx_buffer *rx_buf)
+static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
+                              struct efx_rx_buffer *rx_buf)
 {
-       /* Unmap for DMA */
        efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
-
-       /* Free the skb/page */
        efx_free_rx_buffer(rx_queue->efx, rx_buf);
 }
 
@@ -314,17 +301,17 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
         * fill anyway.
         */
        fill_level = (rx_queue->added_count - rx_queue->removed_count);
-       EFX_BUG_ON_PARANOID(fill_level >
-                           rx_queue->efx->type->rxd_ring_mask + 1);
+       EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
 
        /* Don't fill if we don't need to */
        if (fill_level >= rx_queue->fast_fill_trigger)
                return 0;
 
        /* Record minimum fill level */
-       if (unlikely(fill_level < rx_queue->min_fill))
+       if (unlikely(fill_level < rx_queue->min_fill)) {
                if (fill_level)
                        rx_queue->min_fill = fill_level;
+       }
 
        /* Acquire RX add lock.  If this lock is contended, then a fast
         * fill must already be in progress (e.g. in the refill
@@ -336,8 +323,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
  retry:
        /* Recalculate current fill level now that we have the lock */
        fill_level = (rx_queue->added_count - rx_queue->removed_count);
-       EFX_BUG_ON_PARANOID(fill_level >
-                           rx_queue->efx->type->rxd_ring_mask + 1);
+       EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
        space = rx_queue->fast_fill_limit - fill_level;
        if (space < EFX_RX_BATCH)
                goto out_unlock;
@@ -349,8 +335,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
 
        do {
                for (i = 0; i < EFX_RX_BATCH; ++i) {
-                       index = (rx_queue->added_count &
-                                rx_queue->efx->type->rxd_ring_mask);
+                       index = rx_queue->added_count & EFX_RXQ_MASK;
                        rx_buf = efx_rx_buffer(rx_queue, index);
                        rc = efx_init_rx_buffer(rx_queue, rx_buf);
                        if (unlikely(rc))
@@ -365,7 +350,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
 
  out:
        /* Send write pointer to card. */
-       falcon_notify_rx_desc(rx_queue);
+       efx_nic_notify_rx_desc(rx_queue);
 
        /* If the fast fill is running inside from the refill tasklet, then
         * for SMP systems it may be running on a different CPU to
@@ -375,7 +360,6 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
                goto retry;
 
  out_unlock:
-       /* Release RX add lock */
        spin_unlock_bh(&rx_queue->add_lock);
 
        return rc;
@@ -408,7 +392,11 @@ void efx_rx_work(struct work_struct *data)
        struct efx_rx_queue *rx_queue;
        int rc;
 
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_NEED_WORK_API_WRAPPERS)
+       rx_queue = container_of(data, struct efx_rx_queue, work.work);
+#else
        rx_queue = container_of(data, struct efx_rx_queue, work);
+#endif
 
        if (unlikely(!rx_queue->channel->enabled))
                return;
@@ -424,10 +412,10 @@ void efx_rx_work(struct work_struct *data)
                efx_schedule_slow_fill(rx_queue, 1);
 }
 
-static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
-                                           struct efx_rx_buffer *rx_buf,
-                                           int len, int *discard,
-                                           int *leak_packet)
+static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
+                                    struct efx_rx_buffer *rx_buf,
+                                    int len, bool *discard,
+                                    bool *leak_packet)
 {
        struct efx_nic *efx = rx_queue->efx;
        unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
@@ -438,7 +426,7 @@ static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
        /* The packet must be discarded, but this is only a fatal error
         * if the caller indicated it was
         */
-       *discard = 1;
+       *discard = true;
 
        if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
                EFX_ERR_RL(efx, " RX queue %d seriously overlength "
@@ -459,10 +447,74 @@ static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
        rx_queue->channel->n_rx_overlength++;
 }
 
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_GRO)
+
+/* Pass a received packet up through the generic LRO stack
+ *
+ * Handles driverlink veto, and passes the fragment up via
+ * the appropriate LRO method
+ */
+static void efx_rx_packet_lro(struct efx_channel *channel,
+                             struct efx_rx_buffer *rx_buf,
+                             bool checksummed)
+{
+       struct efx_nic *efx = channel->efx;
+       struct napi_struct *napi = &channel->napi_str;
+       int veto;
+
+       /* It would be faster if we had access to packets at the
+        * other side of generic LRO. Unfortunately, there isn't
+        * an obvious interface to this, so veto packets before LRO */
+       veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len);
+       if (unlikely(veto)) {
+               EFX_LOG(efx, "LRO RX vetoed by driverlink %s driver\n",
+                       efx->dl_cb_dev.rx_packet->driver->name);
+               /* Free the buffer now */
+               efx_free_rx_buffer(efx, rx_buf);
+               return;
+       }
+
+       /* Pass the skb/page into the LRO engine */
+       if (rx_buf->page) {
+               struct sk_buff *skb = napi_get_frags(napi);
+
+               if (!skb) {
+                       put_page(rx_buf->page);
+                       goto out;
+               }
+
+               skb_shinfo(skb)->frags[0].page = rx_buf->page;
+               skb_shinfo(skb)->frags[0].page_offset =
+                       efx_rx_buf_offset(rx_buf);
+               skb_shinfo(skb)->frags[0].size = rx_buf->len;
+               skb_shinfo(skb)->nr_frags = 1;
+
+               skb->len = rx_buf->len;
+               skb->data_len = rx_buf->len;
+               skb->truesize += rx_buf->len;
+               skb->ip_summed =
+                       checksummed ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
+
+               napi_gro_frags(napi);
+
+out:
+               EFX_BUG_ON_PARANOID(rx_buf->skb);
+               rx_buf->page = NULL;
+       } else {
+               EFX_BUG_ON_PARANOID(!rx_buf->skb);
+               EFX_BUG_ON_PARANOID(!checksummed);
+
+               napi_gro_receive(napi, rx_buf->skb);
+               rx_buf->skb = NULL;
+       }
+}
+
+#else /* EFX_USE_KCOMPAT && !EFX_USE_GRO */
+
 /* Allocate and construct an SKB around a struct page.*/
-static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
-                                           struct efx_nic *efx,
-                                           int hdr_len)
+static struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
+                                    struct efx_nic *efx,
+                                    int hdr_len)
 {
        struct sk_buff *skb;
 
@@ -488,7 +540,7 @@ static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
        if (unlikely(rx_buf->len > hdr_len)) {
                struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
                frag->page = rx_buf->page;
-               frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
+               frag->page_offset = efx_rx_buf_offset(rx_buf) + hdr_len;
                frag->size = skb->len - hdr_len;
                skb_shinfo(skb)->nr_frags = 1;
                skb->data_len = frag->size;
@@ -506,13 +558,20 @@ static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
        return skb;
 }
 
+#endif /* !EFX_USE_KCOMPAT || EFX_USE_GRO */
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
 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
+void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+                  unsigned int len, bool checksummed, bool discard)
+#endif
 {
        struct efx_nic *efx = rx_queue->efx;
        struct efx_rx_buffer *rx_buf;
-       int leak_packet = 0;
+       bool leak_packet = false;
 
        rx_buf = efx_rx_buffer(rx_queue, index);
        EFX_BUG_ON_PARANOID(!rx_buf->data);
@@ -568,52 +627,12 @@ void fastcall efx_rx_packet(struct efx_rx_queue *rx_queue,
        rx_queue->channel->rx_pkt_csummed = checksummed;
 }
 
-/* Handle a received packet.  Second half: Touches packet payload. */
-void __efx_rx_packet(struct efx_channel *channel,
-                    struct efx_rx_buffer *rx_buf, int checksummed)
+static void efx_rx_deliver(struct efx_channel *channel,
+                          struct efx_rx_buffer *rx_buf, int checksummed)
 {
        struct efx_nic *efx = channel->efx;
-       enum efx_veto veto;
        struct sk_buff *skb;
-       int lro = efx->lro_enabled;
-
-       /* If we're in loopback test, then pass the packet directly to the
-        * loopback layer, and free the rx_buf here
-        */
-       if (unlikely(efx->loopback_selftest)) {
-               efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
-               efx_free_rx_buffer(efx, rx_buf);
-               goto done;
-       }
-
-       if (rx_buf->skb) {
-               /* Prefetch more information */
-               prefetch(skb_shinfo(rx_buf->skb));
-
-               /* Reserve space for the data */
-               skb_put(rx_buf->skb, rx_buf->len);
-
-               /* Move past the ethernet header. rx_buf->data still points
-                * at the ethernet header */
-               rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
-                                                      efx->net_dev);
-       }
-
-       /* Both our generic-LRO and SFC-SSR support skb and page based
-        * allocation, but neither support switching from one to the
-        * other on the fly. If we spot that the allocation mode has
-        * changed, then flush the LRO state.
-        */
-       if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
-               efx_flush_lro(channel);
-               channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
-       }
-       if (likely(checksummed && lro)) {
-               if (efx_ssr(&channel->ssr, rx_buf)) {
-                       channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
-                       goto done;
-               }
-       }
+       enum efx_veto veto;
 
        /* Allow callback to veto the packet */
        veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len);
@@ -622,41 +641,78 @@ void __efx_rx_packet(struct efx_channel *channel,
                        efx->dl_cb_dev.rx_packet->driver->name);
                /* Free the buffer now */
                efx_free_rx_buffer(efx, rx_buf);
-               goto done;
+               return;
        }
 
+       /* We now own the SKB */
+       skb = rx_buf->skb;
+       rx_buf->skb = NULL;
+
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_GRO)
        /* Form an skb if required */
        if (rx_buf->page) {
                int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
                skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
                if (unlikely(skb == NULL)) {
                        efx_free_rx_buffer(efx, rx_buf);
-                       goto done;
+                       return;
                }
-       } else {
-               /* We now own the SKB */
-               skb = rx_buf->skb;
-               rx_buf->skb = NULL;
        }
+#endif
 
        EFX_BUG_ON_PARANOID(rx_buf->page);
        EFX_BUG_ON_PARANOID(rx_buf->skb);
        EFX_BUG_ON_PARANOID(!skb);
 
        /* Set the SKB flags */
-       if (unlikely(!checksummed || !efx->rx_checksum_enabled))
-               skb->ip_summed = CHECKSUM_NONE;
+#if defined(EFX_USE_KCOMPAT) && !defined(EFX_USE_GRO)
+       if (unlikely(!checksummed))
+               /* fall through to next statement, else skip */
+#endif
+       skb->ip_summed = CHECKSUM_NONE;
 
        /* Pass the packet up */
        netif_receive_skb(skb);
 
        /* Update allocation strategy method */
        channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+}
+
+/* Handle a received packet.  Second half: Touches packet payload. */
+void __efx_rx_packet(struct efx_channel *channel,
+                    struct efx_rx_buffer *rx_buf, bool checksummed)
+{
+       struct efx_nic *efx = channel->efx;
+
+       /* If we're in loopback test, then pass the packet directly to the
+        * loopback layer, and free the rx_buf here
+        */
+       if (unlikely(efx->loopback_selftest)) {
+               efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
+               efx_free_rx_buffer(efx, rx_buf);
+               return;
+       }
+
+       if (rx_buf->skb) {
+               prefetch(skb_shinfo(rx_buf->skb));
+
+               skb_put(rx_buf->skb, rx_buf->len);
+
+               /* Move past the ethernet header. rx_buf->data still points
+                * at the ethernet header */
+               rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
+                                                      efx->net_dev);
+       }
 
-       /* fall-thru */
-done:
-       /* Update statistics */
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_GRO)
+       if (likely(checksummed || rx_buf->page))
+               efx_rx_packet_lro(channel, rx_buf, checksummed);
+       else
+#endif
+               efx_rx_deliver(channel, rx_buf, checksummed);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_NET_DEVICE_LAST_RX)
        efx->net_dev->last_rx = jiffies;
+#endif
 }
 
 void efx_rx_strategy(struct efx_channel *channel)
@@ -664,7 +720,11 @@ void efx_rx_strategy(struct efx_channel *channel)
        enum efx_rx_alloc_method method = rx_alloc_method;
 
        /* Only makes sense to use page based allocation if LRO is enabled */
-       if (!(channel->efx->lro_enabled)) {
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_GRO)
+       if (!(channel->efx->net_dev->features & NETIF_F_GRO)) {
+#else
+       if (1) {
+#endif
                method = RX_ALLOC_METHOD_SKB;
        } else if (method == RX_ALLOC_METHOD_AUTO) {
                /* Constrain the rx_alloc_level */
@@ -691,32 +751,21 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
        EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
 
        /* Allocate RX buffers */
-       rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
+       rxq_size = EFX_RXQ_SIZE * sizeof(*rx_queue->buffer);
        rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
-       if (!rx_queue->buffer) {
-               rc = -ENOMEM;
-               goto fail1;
-       }
-
-       rc = falcon_probe_rx(rx_queue);
-       if (rc)
-               goto fail2;
-
-       return 0;
-
- fail2:
-       kfree(rx_queue->buffer);
-       rx_queue->buffer = NULL;
- fail1:
-       /* Mark queue as unused */
-       rx_queue->used = 0;
+       if (!rx_queue->buffer)
+               return -ENOMEM;
 
+       rc = efx_nic_probe_rx(rx_queue);
+       if (rc) {
+               kfree(rx_queue->buffer);
+               rx_queue->buffer = NULL;
+       }
        return rc;
 }
 
-int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
+void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
 {
-       struct efx_nic *efx = rx_queue->efx;
        unsigned int max_fill, trigger, limit;
 
        EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
@@ -729,7 +778,7 @@ int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
        rx_queue->min_overfill = -1U;
 
        /* Initialise limit fields */
-       max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
+       max_fill = EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM;
        trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
        limit = max_fill * min(rx_refill_limit, 100U) / 100U;
 
@@ -738,7 +787,7 @@ int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
        rx_queue->fast_fill_limit = limit;
 
        /* Set up RX descriptor ring */
-       return falcon_init_rx(rx_queue);
+       efx_nic_init_rx(rx_queue);
 }
 
 void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
@@ -748,12 +797,11 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
 
        EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
 
-       /* Flush RX queue and remove descriptor ring */
-       falcon_fini_rx(rx_queue);
+       efx_nic_fini_rx(rx_queue);
 
        /* Release RX buffers NB start at index 0 not current HW ptr */
        if (rx_queue->buffer) {
-               for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
+               for (i = 0; i <= EFX_RXQ_MASK; i++) {
                        rx_buf = efx_rx_buffer(rx_queue, i);
                        efx_fini_rx_buffer(rx_queue, rx_buf);
                }
@@ -762,7 +810,8 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
        /* For a page that is part-way through splitting into RX buffers */
        if (rx_queue->buf_page != NULL) {
                pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
-                              RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
+                              efx_rx_buf_size(rx_queue->efx),
+                              PCI_DMA_FROMDEVICE);
                __free_pages(rx_queue->buf_page,
                             rx_queue->efx->rx_buffer_order);
                rx_queue->buf_page = NULL;
@@ -773,17 +822,10 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
 {
        EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
 
-       falcon_remove_rx(rx_queue);
+       efx_nic_remove_rx(rx_queue);
 
        kfree(rx_queue->buffer);
        rx_queue->buffer = NULL;
-       rx_queue->used = 0;
-}
-
-/* Flush LRO/SSR state for the given channel */
-void efx_flush_lro(struct efx_channel *channel)
-{
-       efx_ssr_end_of_burst(&channel->ssr);
 }
 
 
@@ -794,441 +836,3 @@ module_param(rx_refill_threshold, uint, 0444);
 MODULE_PARM_DESC(rx_refill_threshold,
                 "RX descriptor ring fast/slow fill threshold (%)");
 
-
-
-/* Size of the LRO hash table.  Must be a power of 2.  A larger table
- * means we can accelerate a larger number of streams.
- */
-static unsigned lro_table_size = 128;
-module_param(lro_table_size, uint, 0644);
-MODULE_PARM_DESC(lro_table_size,
-                "Size of the LRO hash table.  Must be a power of 2");
-
-/* Maximum length of a hash chain.  If chains get too long then the lookup
- * time increases and may exceed the benefit of LRO.
- */
-static unsigned lro_chain_max = 20;
-module_param(lro_chain_max, uint, 0644);
-MODULE_PARM_DESC(lro_chain_max,
-                "Maximum length of chains in the LRO hash table");
-
-
-/* Maximum time (in jiffies) that a connection can be idle before it's LRO
- * state is discarded.
- */
-static unsigned lro_idle_jiffies = HZ / 10 + 1;        /* 100ms */
-module_param(lro_idle_jiffies, uint, 0644);
-MODULE_PARM_DESC(lro_idle_jiffies, "Time (in jiffies) after which an"
-                " idle connection's LRO state is discarded");
-
-
-/* Number of packets with payload that must arrive in-order before a
- * connection is eligible for LRO.  The idea is we should avoid coalescing
- * segments when the sender is in slow-start because reducing the ACK rate
- * can damage performance.
- */
-static unsigned lro_slow_start_packets = 20;
-module_param(lro_slow_start_packets, uint, 0644);
-MODULE_PARM_DESC(lro_slow_start_packets, "Number of packets that must "
-                "pass in-order before starting LRO.");
-
-
-int efx_ssr_init(struct efx_ssr_state *st, struct efx_nic *efx)
-{
-       unsigned i;
-       st->conns_mask = lro_table_size - 1;
-       if ((st->conns_mask + 1) & st->conns_mask) {
-               EFX_ERR(efx, "lro_table_size(=%u) must be a power of 2\n",
-                       lro_table_size);
-               return -EINVAL;
-       }
-       st->efx = efx;
-       st->conns = kmalloc((st->conns_mask + 1)
-                           * sizeof(st->conns[0]), GFP_KERNEL);
-       if (st->conns == NULL)
-               return -ENOMEM;
-       st->conns_n = kmalloc((st->conns_mask + 1)
-                             * sizeof(st->conns_n[0]), GFP_KERNEL);
-       if (st->conns_n == NULL) {
-               kfree(st->conns);
-               st->conns = NULL;
-               return -ENOMEM;
-       }
-       for (i = 0; i <= st->conns_mask; ++i) {
-               INIT_LIST_HEAD(&st->conns[i]);
-               st->conns_n[i] = 0;
-       }
-       INIT_LIST_HEAD(&st->active_conns);
-       INIT_LIST_HEAD(&st->free_conns);
-       return 0;
-}
-
-/* Drop the given connection, and add it to the free list */
-static inline void efx_ssr_drop(struct efx_ssr_state *st,
-                               struct efx_ssr_conn *c, unsigned conn_hash)
-{
-       EFX_BUG_ON_PARANOID(c->skb);
-       EFX_BUG_ON_PARANOID(st->conns_n[conn_hash] <= 0);
-       --st->conns_n[conn_hash];
-       list_del(&c->link);
-       list_add(&c->link, &st->free_conns);
-}
-
-void efx_ssr_fini(struct efx_ssr_state *st)
-{
-       struct efx_ssr_conn *c;
-       unsigned i;
-
-       /* Return cleanly if efx_ssr_init() has not been called. */
-       if (st->conns == NULL)
-               return;
-
-       EFX_BUG_ON_PARANOID(!list_empty(&st->active_conns));
-
-       for (i = 0; i <= st->conns_mask; ++i)
-               while (!list_empty(&st->conns[i])) {
-                       c = list_entry(st->conns[i].prev,
-                                      struct efx_ssr_conn, link);
-                       efx_ssr_drop(st, c, i);
-               }
-
-       while (!list_empty(&st->free_conns)) {
-               c = list_entry(st->free_conns.prev, struct efx_ssr_conn, link);
-               list_del(&c->link);
-               EFX_BUG_ON_PARANOID(c->skb);
-               kfree(c);
-       }
-
-       kfree(st->conns_n);
-       kfree(st->conns);
-       st->conns = NULL;
-}
-
-/* Calc IP checksum and deliver to the OS */
-static void efx_ssr_deliver(struct efx_ssr_state *st, struct efx_ssr_conn *c)
-{
-       struct efx_nic *efx = st->efx;
-       int veto, len;
-
-       EFX_BUG_ON_PARANOID(!c->skb);
-
-       ++st->n_bursts;
-
-       /* Finish off packet munging and recalculate IP header checksum. */
-       c->iph->tot_len = htons(c->iph->tot_len);
-       c->iph->check = 0;
-       c->iph->check = ip_fast_csum((u8 *) c->iph, c->iph->ihl);
-
-       len = c->skb->len + ((char *)c->iph - (char *)c->eh);
-       c->skb->truesize = len + sizeof(struct sk_buff);
-
-       c->th->window = c->th_last->window;
-       c->th->ack_seq = c->th_last->ack_seq;
-       if (c->th->doff == c->th_last->doff) {
-               /* Copy TCP options (take care to avoid going negative). */
-               len = ((c->th->doff - 5) & 0xf) << 2u;
-               memcpy(c->th + 1, c->th_last + 1, len);
-       }
-
-       /* Allow callback to veto the packet. */
-       veto = EFX_DL_CALLBACK(efx, rx_packet, (char *)c->eh, len);
-       if (unlikely(veto)) {
-               EFX_LOG(efx, "RX vetoed by driverlink %s driver\n",
-                       efx->dl_cb_dev.rx_packet->driver->name);
-               dev_kfree_skb_any(c->skb);
-       } else {
-               netif_receive_skb(c->skb);
-       }
-
-       c->skb = NULL;
-       list_del_init(&c->active_link);
-}
-
-/* Stop tracking connections that have gone idle in order to keep hash
- * chains short.
- */
-static void efx_ssr_purge_idle(struct efx_ssr_state *st, unsigned now)
-{
-       struct efx_ssr_conn *c;
-       unsigned i;
-
-       EFX_BUG_ON_PARANOID(!list_empty(&st->active_conns));
-
-       st->last_purge_jiffies = now;
-       for (i = 0; i <= st->conns_mask; ++i) {
-               if (list_empty(&st->conns[i]))
-                       continue;
-
-               c = list_entry(st->conns[i].prev, struct efx_ssr_conn, link);
-               if (now - c->last_pkt_jiffies > lro_idle_jiffies) {
-                       ++st->n_drop_idle;
-                       efx_ssr_drop(st, c, i);
-               }
-       }
-}
-
-/* Push held skbs down into network stack.
- * Only called when active list is non-empty.
- */
-void __efx_ssr_end_of_burst(struct efx_ssr_state *st)
-{
-       struct efx_ssr_conn *c;
-       unsigned j;
-
-       EFX_BUG_ON_PARANOID(list_empty(&st->active_conns));
-
-       do {
-               c = list_entry(st->active_conns.next, struct efx_ssr_conn,
-                              active_link);
-               EFX_BUG_ON_PARANOID(!c->skb);
-               efx_ssr_deliver(st, c);
-       } while (!list_empty(&st->active_conns));
-
-       j = jiffies;
-       if (unlikely(j != st->last_purge_jiffies))
-               efx_ssr_purge_idle(st, j);
-}
-
-/* Construct an skb Push held skbs down into network stack.
- * Only called when active list is non-empty.
- */
-static inline int
-efx_ssr_merge(struct efx_ssr_state *st, struct efx_ssr_conn *c,
-             struct tcphdr *th, int data_length)
-{
-       /* Increase lengths appropriately */
-       c->skb->len += data_length;
-       c->skb->data_len += data_length;
-
-       /*
-        * Keep track of max MSS seen and store in
-        * gso_size for kernel to use
-        */
-       if (data_length > skb_shinfo(c->skb)->gso_size)
-               skb_shinfo(c->skb)->gso_size = data_length;
-
-       /* Update the connection state flags */
-       c->iph->tot_len += data_length;
-       c->th->psh |= th->psh;
-       c->th_last = th;
-       ++st->n_merges;
-
-       /* Pass packet up now if another segment could overflow the IP
-        * length.
-        */
-       return (c->skb->len > 65536 - 9200);
-}
-
-static inline void
-efx_ssr_start(struct efx_ssr_state *st, struct efx_ssr_conn *c,
-             struct tcphdr *th, int data_length)
-{
-       /* Initialise gso_size appropriately */
-       skb_shinfo(c->skb)->gso_size = data_length;
-
-       /* Mangle header fields for later processing */
-       c->iph->tot_len = ntohs(c->iph->tot_len);
-
-       /* Move this connection the head of the active list */
-       list_del(&c->active_link);
-       list_add(&c->active_link, &st->active_conns);
-}
-
-static inline int
-efx_ssr_conn_page(struct efx_ssr_state *st, struct efx_ssr_conn *c,
-                 struct efx_rx_buffer *rx_buf, struct tcphdr *th,
-                 int hdr_length, int data_length)
-{
-       if (likely(c->skb)) {
-               struct skb_frag_struct *frag;
-               frag = skb_shinfo(c->skb)->frags;
-               frag += skb_shinfo(c->skb)->nr_frags;
-               frag->page = rx_buf->page;
-               frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_length;
-               frag->size = data_length;
-               ++skb_shinfo(c->skb)->nr_frags;
-               rx_buf->page = NULL;
-
-               if (efx_ssr_merge(st, c, th, data_length) ||
-                   (skb_shinfo(c->skb)->nr_frags == MAX_SKB_FRAGS))
-                       efx_ssr_deliver(st, c);
-
-               return 1;
-       } else {
-               c->skb = efx_rx_mk_skb(rx_buf, st->efx, hdr_length);
-               if (unlikely(c->skb == NULL))
-                       return 0;
-
-               c->eh = eth_hdr(c->skb);
-               c->iph = (struct iphdr *)c->skb->data;
-               c->th = (struct tcphdr *)((u8 *) c->iph + c->iph->ihl * 4);
-               c->th_last = c->th;
-
-               efx_ssr_start(st, c, th, data_length);
-
-               return 1;
-       }
-}
-
-static inline void
-efx_ssr_conn_skb(struct efx_ssr_state *st, struct efx_ssr_conn *c,
-                struct efx_rx_buffer *rx_buf, struct ethhdr *eh,
-                struct iphdr *iph, struct tcphdr *th, int data_length)
-{
-       /* Transfer ownership of the rx_buf->skb to the LRO chain */
-       struct sk_buff *skb = rx_buf->skb;
-       rx_buf->skb = NULL;
-
-       if (likely(c->skb)) {
-               /* Remove the headers */
-               skb_pull(skb, skb->len - data_length);
-
-               /* Tack the new skb onto the head skb's frag_list. */
-               EFX_BUG_ON_PARANOID(skb->next);
-               if (!skb_shinfo(c->skb)->frag_list)
-                       skb_shinfo(c->skb)->frag_list = skb;
-               else
-                       c->skb_tail->next = skb;
-               c->skb_tail = skb;
-
-               if (efx_ssr_merge(st, c, th, data_length))
-                       efx_ssr_deliver(st, c);
-       } else {
-               c->skb = skb;
-               c->eh = eh;
-               c->iph = iph;
-               c->th = th;
-               c->th_last = th;
-
-               efx_ssr_start(st, c, th, data_length);
-       }
-}
-
-/* Process SKB and decide whether to dispatch it to the stack now or
- * later.
- */
-int efx_ssr(struct efx_ssr_state *st, struct efx_rx_buffer *rx_buf)
-{
-
-       int eh_proto, data_length, hdr_length, dont_merge;
-       struct efx_ssr_conn *c;
-       struct ethhdr *eh;
-       struct iphdr *iph;
-       struct tcphdr *th;
-       unsigned th_seq, conn_hash, pkt_length;
-
-       /* This does not handle VLAN code */
-       /* Find the IP header. The ethernet header is always at rx_buf->data */
-       eh = (struct ethhdr *)rx_buf->data;
-       if (rx_buf->page) {
-               eh_proto = eh->h_proto;
-               iph = (struct iphdr *)(eh + 1);
-       } else {
-               /* The skb head is at the IP header */
-               eh_proto = rx_buf->skb->protocol;
-               iph = (struct iphdr *)rx_buf->skb->data;
-       }
-
-       /* We're not interested if it isn't TCP over IPv4, or if fragged. */
-       if ((eh_proto - htons(ETH_P_IP)) |
-           (iph->protocol - IPPROTO_TCP) |
-           (iph->frag_off & htons(IP_MF | IP_OFFSET)))
-               return 0;
-
-       /* Get the TCP protocol */
-       th = (struct tcphdr *)((u8 *) iph + iph->ihl * 4);
-       hdr_length = (u8 *) th + th->doff * 4 - (u8 *) eh;
-       /* Cope with padding after IP header */
-       pkt_length = ntohs(iph->tot_len) + (u8 *)iph - (u8 *)eh;
-       rx_buf->len = min(pkt_length, rx_buf->len);
-       data_length = rx_buf->len - hdr_length;
-       th_seq = ntohl(th->seq);
-       dont_merge = ((data_length <= 0)
-                     | th->urg | th->syn | th->rst | th->fin);
-
-       /* Very cheap and crude hash. */
-       conn_hash = (th->source ^ th->dest) & st->conns_mask;
-
-       list_for_each_entry(c, &st->conns[conn_hash], link) {
-               if ((c->saddr - iph->saddr) | (c->daddr - iph->daddr) |
-                   (c->source - th->source) | (c->dest - th->dest))
-                       continue;
-
-               /* Re-insert at head of list to reduce lookup time. */
-               list_del(&c->link);
-               list_add(&c->link, &st->conns[conn_hash]);
-
-               if (unlikely(th_seq - c->next_seq)) {
-                       /* Out-of-order, so start counting again. */
-                       if (c->skb)
-                               efx_ssr_deliver(st, c);
-                       c->n_in_order_pkts = 0;
-                       c->next_seq = th_seq + data_length;
-                       ++st->n_misorder;
-                       return 0;
-               }
-               c->next_seq = th_seq + data_length;
-               c->last_pkt_jiffies = jiffies;
-
-               if (c->n_in_order_pkts < lro_slow_start_packets) {
-                       /* May be in slow-start, so don't merge. */
-                       ++st->n_slow_start;
-                       ++c->n_in_order_pkts;
-                       return 0;
-               }
-
-               if (unlikely(dont_merge)) {
-                       if (c->skb)
-                               efx_ssr_deliver(st, c);
-                       if (th->fin || th->rst) {
-                               ++st->n_drop_closed;
-                               efx_ssr_drop(st, c, conn_hash);
-                       }
-                       return 0;
-               }
-
-               if (rx_buf->page) {
-                       return efx_ssr_conn_page(st, c, rx_buf, th, hdr_length,
-                                                data_length);
-               } else {
-                       efx_ssr_conn_skb(st, c, rx_buf, eh, iph, th,
-                                        data_length);
-                       return 1;
-               }
-       }
-
-       /* We're not yet tracking this connection. */
-       if (dont_merge)
-               return 0;
-
-       if (st->conns_n[conn_hash] >= lro_chain_max) {
-               ++st->n_too_many;
-               return 0;
-       }
-
-       if (!list_empty(&st->free_conns)) {
-               c = list_entry(st->free_conns.next, struct efx_ssr_conn, link);
-               list_del(&c->link);
-       } else {
-               c = kmalloc(sizeof(*c), GFP_ATOMIC);
-               if (c == NULL)
-                       return 0;
-               c->skb = NULL;
-               INIT_LIST_HEAD(&c->active_link);
-       }
-
-       /* Create the connection tracking data */
-       ++st->conns_n[conn_hash];
-       list_add(&c->link, &st->conns[conn_hash]);
-       c->saddr = iph->saddr;
-       c->daddr = iph->daddr;
-       c->source = th->source;
-       c->dest = th->dest;
-       c->next_seq = th_seq + data_length;
-       c->n_in_order_pkts = 0;
-       EFX_BUG_ON_PARANOID(c->skb);
-       ++st->n_new_stream;
-       return 0;
-}
-
-
diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h
deleted file mode 100644 (file)
index c1c2bfd..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_RX_H
-#define EFX_RX_H
-
-#include <linux/skbuff.h>
-#include "net_driver.h"
-
-
-int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
-void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
-int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
-void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
-
-void efx_flush_lro(struct efx_channel *channel);
-void efx_rx_strategy(struct efx_channel *channel);
-void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
-void efx_rx_work(struct work_struct *data);
-void __efx_rx_packet(struct efx_channel *channel,
-                    struct efx_rx_buffer *rx_buf, int checksummed);
-
-
-
-extern int efx_ssr_init(struct efx_ssr_state *st, struct efx_nic *efx);
-extern void efx_ssr_fini(struct efx_ssr_state *st);
-
-extern void __efx_ssr_end_of_burst(struct efx_ssr_state *st);
-extern int efx_ssr(struct efx_ssr_state *st, struct efx_rx_buffer *rx_buf);
-
-
-static inline void efx_ssr_end_of_burst(struct efx_ssr_state *st)
-{
-       if (!list_empty(&st->active_conns))
-               __efx_ssr_end_of_burst(st);
-}
-
-
-#endif /* EFX_RX_H */
index b01a8fd3b43a94bb01c6051a52419a62c67bbdca..f56b1886f83521cb45b7259b38f6799636e63f6b 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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/in.h>
 #include <linux/udp.h>
 #include <linux/rtnetlink.h>
+#include <asm/io.h>
 #include "net_driver.h"
-#include "ethtool.h"
 #include "efx.h"
-#include "falcon.h"
+#include "nic.h"
 #include "selftest.h"
-#include "boards.h"
 #include "workarounds.h"
-
-/* Self tests */
+#include "mdio_10g.h"
 
 /*
  * Loopback test packet structure
@@ -64,43 +45,138 @@ static const unsigned char payload_source[ETH_ALEN] = {
        0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
 };
 
-static const char *payload_msg =
+static const char payload_msg[] =
        "Hello world! This is an Efx loopback test in progress!";
 
-struct efx_selftest_state {
-       /* Drop all packets in  efx_loopback_rx_packet */
-       int flush;
-
-       /* Number of packets being used in this test */
+/**
+ * efx_loopback_state - persistent state during a loopback selftest
+ * @flush:             Drop all packets in efx_loopback_rx_packet
+ * @packet_count:      Number of packets being used in this test
+ * @skbs:              An array of skbs transmitted
+ * @offload_csum:      Checksums are being offloaded
+ * @rx_good:           RX good packet count
+ * @rx_bad:            RX bad packet count
+ * @payload:           Payload used in tests
+ */
+struct efx_loopback_state {
+       bool flush;
        int packet_count;
-
-       /* RX good packet count */
+       struct sk_buff **skbs;
+       bool offload_csum;
        atomic_t rx_good;
-
-       /* RX bad packet count */
        atomic_t rx_bad;
-
-       /* Payload used in tests */
        struct efx_loopback_payload payload;
 };
 
+/* How long to wait for all the packets to arrive (in ms) */
+#define LOOPBACK_TIMEOUT_MS (100)
+
 /**************************************************************************
  *
- * Configurable values
+ * MII, NVRAM and register tests
  *
  **************************************************************************/
 
-/* Level of loopback testing
- *
- * The maximum packet burst length is 16**(n-1), i.e.
- *
- * - Level 0 : no packets
- * - Level 1 : 1 packet
- * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets)
- * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets)
- *
- */
-static unsigned int loopback_test_level = 3;
+static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+       int rc = 0;
+
+       if (efx->phy_op->test_alive) {
+               rc = efx->phy_op->test_alive(efx);
+               EFX_LOG(efx, "%s PHY liveness selftest\n",
+                       rc ? "Failed" : "Passed");
+               tests->phy_alive = rc ? -1 : 1;
+       }
+
+       return rc;
+}
+
+static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+       int rc = 0;
+
+       if (efx->type->test_nvram) {
+               rc = efx->type->test_nvram(efx);
+               tests->nvram = rc ? -1 : 1;
+       }
+
+       return rc;
+}
+
+static void memtest_simple(unsigned id, efx_qword_t *reg, int a, int b)
+{
+       EFX_POPULATE_QWORD_2(*reg, EFX_DWORD_0, a, EFX_DWORD_1, b);
+}
+
+static void memtest_changing_bytes(unsigned id, efx_qword_t *reg,
+                                  int a, int b)
+{
+       int i;
+       u8 *byte;
+       for (i = 0; i < sizeof(efx_qword_t); i++) {
+               unsigned int addr = id * sizeof(efx_qword_t) + i;
+               byte = (u8 *)reg + i;
+               if ((addr >> 8) == 0)
+                       *byte = (u8) (addr % 257);
+               else
+                       *byte = (u8) ~((addr >> 8) % 257);
+
+               if (addr & 0x40)
+                       *byte = ~*byte;
+       }
+}
+
+static void memtest_bit_sweep(unsigned int id, efx_qword_t *reg,
+                             int a, int b)
+{
+       int bit = id % 64;
+       int xor = (id & 64) ? ~0 : 0;
+
+       EFX_POPULATE_QWORD_2(*reg,
+                            EFX_DWORD_0, (bit < 32 ? bit : 0) ^ xor,
+                            EFX_DWORD_1, (bit >= 32 ? bit - 32 : 0) ^ xor);
+}
+
+struct memtest {
+       void (*pattern)(unsigned id, efx_qword_t *reg, int a, int b);
+       int a;
+       int b;
+};
+
+static struct memtest memtests[] = {
+       {memtest_simple, 0x55AA55AA, 0x55AA55AA},
+       {memtest_simple, 0xAA55AA55, 0xAA55AA55},
+       {memtest_changing_bytes, 0, 0},
+       {memtest_bit_sweep, 0, 0},
+};
+
+static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
+{
+       int rc, i;
+
+       /* Test SRAM and register tables */
+       if (efx->type->test_memory) {
+               for (i = 0; i < ARRAY_SIZE(memtests); ++i) {
+                       rc = efx->type->test_memory(
+                               efx, memtests[i].pattern,
+                               memtests[i].a, memtests[i].b);
+                       if (rc)
+                               break;
+               }
+               EFX_LOG(efx, "%s memory selftest\n", rc ? "Failed" : "Passed");
+               tests->memory = rc ? -1 : 1;
+       }
+
+       /* Test register access */
+       if (efx->type->test_registers) {
+               rc = efx->type->test_registers(efx);
+               EFX_LOG(efx, "%s register selftest\n",
+                       rc ? "Failed" : "Passed");
+               tests->registers = rc ? -1 : 1;
+       }
+
+       return (tests->memory >= 0 && tests->registers >= 0) ? 0 : -EIO;
+}
 
 /**************************************************************************
  *
@@ -108,18 +184,11 @@ static unsigned int loopback_test_level = 3;
  *
  **************************************************************************/
 
-/*
- * Test interrupts
- *
- * This generates a test interrupt and waits for it to be received by
- * a CPU.  This routine must be called from process context and will
- * sleep.
- */
+/* Test generation and receipt of interrupts */
 static int efx_test_interrupts(struct efx_nic *efx,
                               struct efx_self_tests *tests)
 {
        struct efx_channel *channel;
-       unsigned long j_start;
 
        EFX_LOG(efx, "testing interrupts\n");
        tests->interrupt = -1;
@@ -128,24 +197,16 @@ static int efx_test_interrupts(struct efx_nic *efx,
        efx->last_irq_cpu = -1;
        smp_wmb();
 
-       /* To guarantee that an interrupt is received make sure that the
-        * channels are ack'd at least once, reenabling interrupts.
-        * We will then receive an interrupt, either by explicitly
-        * requesting one, or receiving traffic.
-        */
-       efx_for_each_channel_with_interrupt(channel, efx) {
-               /* Process the eventq synchronously */
+       /* ACK each interrupting event queue. Receiving an interrupt due to
+        * traffic before a test event is raised is considered a pass */
+       efx_for_each_channel(channel, efx) {
                if (channel->work_pending)
                        efx_process_channel_now(channel);
-               /* Check if we haven't already received an interrupt */
                if (efx->last_irq_cpu >= 0)
                        goto success;
        }
 
-       j_start = jiffies;
-
-       /* Generate test interrupt. */
-       falcon_generate_interrupt(efx);
+       efx_nic_generate_interrupt(efx);
 
        /* Wait for arrival of test interrupt. */
        EFX_LOG(efx, "waiting for test interrupt\n");
@@ -153,8 +214,7 @@ static int efx_test_interrupts(struct efx_nic *efx,
        if (efx->last_irq_cpu >= 0)
                goto success;
 
-       EFX_ERR(efx, "timed out in %ld jiffies waiting for interrupt\n",
-               jiffies - j_start);
+       EFX_ERR(efx, "timed out waiting for interrupt\n");
        return -ETIMEDOUT;
 
  success:
@@ -164,58 +224,11 @@ static int efx_test_interrupts(struct efx_nic *efx,
        return 0;
 }
 
-/*
- * Test capability of events to receive events
- * This generates a test event and waits for it to be processed
- * This routine must be called from process context and will sleep.
- */
-static int efx_test_eventq(struct efx_channel *channel,
-                          struct efx_self_tests *tests)
-{
-       unsigned int magic;
-
-       /* Channel specific code, limited to 20 bits */
-       magic = (0x00010150 + channel->channel);
-       EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
-               channel->channel, magic);
-
-       tests->eventq_dma[channel->channel] = -1;
-       tests->eventq_int[channel->channel] = 1;        /* fake pass */
-       tests->eventq_poll[channel->channel] = 1;       /* fake pass */
-
-       /* Reset flag and zero magic word */
-       channel->efx->last_irq_cpu = -1;
-       channel->eventq_magic = 0;
-       smp_wmb();
-
-       /* Generate test event */
-       falcon_generate_test_event(channel, magic);
-       udelay(1);
-
-       efx_process_channel_now(channel);
-       if (channel->eventq_magic != magic) {
-               EFX_ERR(channel->efx, "channel %d  failed to see test event\n",
-                       channel->channel);
-               return -ETIMEDOUT;
-       } else {
-               tests->eventq_dma[channel->channel] = 1;
-       }
-
-       return 0;
-}
-
-
-/*
- * Test capability of events to generate interrupts
- * This generates a test event and waits for it to be processed by an
- * ISR.  This routine must be called from process context and will
- * sleep.
- */
+/* Test generation and receipt of interrupting events */
 static int efx_test_eventq_irq(struct efx_channel *channel,
                               struct efx_self_tests *tests)
 {
        unsigned int magic, count;
-       unsigned long j_start = jiffies;
 
        /* Channel specific code, limited to 20 bits */
        magic = (0x00010150 + channel->channel);
@@ -231,8 +244,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
        channel->eventq_magic = 0;
        smp_wmb();
 
-       /* Generate test event */
-       falcon_generate_test_event(channel, magic);
+       efx_nic_generate_test_event(channel, magic);
 
        /* Wait for arrival of interrupt */
        count = 0;
@@ -246,8 +258,8 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
                        goto eventq_ok;
        } while (++count < 2);
 
-       EFX_ERR(channel->efx, "channel %d timed out in %ld jiffies waiting for"
-               " event queue\n", channel->channel, jiffies - j_start);
+       EFX_ERR(channel->efx, "channel %d timed out waiting for event queue\n",
+               channel->channel);
 
        /* See if interrupt arrived */
        if (channel->efx->last_irq_cpu >= 0) {
@@ -275,44 +287,19 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
        return 0;
 }
 
-/**************************************************************************
- *
- * PHY testing
- *
- **************************************************************************/
-
-/*
- * Check PHY presence
- * This reads the PHY ID registers via GMII and checks that neither
- * are all-zeroes or all-ones (indicating a nonexistent or
- * uncommunicative PHY).
- */
-static int efx_test_phy(struct efx_nic *efx,
-                       struct efx_self_tests *tests)
+static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests,
+                       unsigned flags)
 {
-       u16 physid1, physid2;
-       struct mii_if_info *mii = &efx->mii;
-       struct net_device *net_dev = efx->net_dev;
+       int rc;
 
-       if (efx->phy_type == PHY_TYPE_NONE)
+       if (!efx->phy_op->run_tests)
                return 0;
 
-       EFX_LOG(efx, "testing PHY presence\n");
-       tests->phy_ok = -1;
-
-       physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
-       physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
-
-       if ((physid1 != 0x0000) && (physid1 != 0xffff) &&
-           (physid2 != 0x0000) && (physid2 != 0xffff)) {
-               EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n",
-                       mii->phy_id, physid1, physid2);
-               tests->phy_ok = 1;
-               return 0;
-       }
-
-       EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id);
-       return -ENODEV;
+       mutex_lock(&efx->mac_lock);
+       rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags);
+       mutex_unlock(&efx->mac_lock);
+       EFX_INFO(efx, "%s phy selftest\n", rc ? "Failed" : "Passed");
+       return rc;
 }
 
 /**************************************************************************
@@ -328,7 +315,7 @@ static int efx_test_phy(struct efx_nic *efx,
 void efx_loopback_rx_packet(struct efx_nic *efx,
                            const char *buf_ptr, int pkt_len)
 {
-       struct efx_selftest_state *state = efx->loopback_selftest;
+       struct efx_loopback_state *state = efx->loopback_selftest;
        struct efx_loopback_payload *received;
        struct efx_loopback_payload *payload;
 
@@ -340,62 +327,52 @@ void efx_loopback_rx_packet(struct efx_nic *efx,
 
        payload = &state->payload;
 
-       /* The packet should have been passed up to us before any LRO/SSR, so
-        * we should be able to compare the data directly. Since the packet
-        * is going to be thrown away by the caller, modify it in place.
-        * efx_test_loopback guarantees to not touch state->payload during
-        * the test */
-       received = (struct efx_loopback_payload *)(char *)buf_ptr;
+       received = (struct efx_loopback_payload *) buf_ptr;
        received->ip.saddr = payload->ip.saddr;
-       received->ip.check = payload->ip.check;
+       if (state->offload_csum)
+               received->ip.check = payload->ip.check;
 
        /* Check that header exists */
        if (pkt_len < sizeof(received->header)) {
-               EFX_ERR(efx, "saw runt RX packet (length %d) "
-                       "in %s loopback test\n", pkt_len,
-                       LOOPBACK_MODE(efx));
+               EFX_ERR(efx, "saw runt RX packet (length %d) in %s loopback "
+                       "test\n", pkt_len, LOOPBACK_MODE(efx));
                goto err;
        }
 
-       /* Check that header matches */
+       /* Check that the ethernet header exists */
        if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) {
-               EFX_ERR(efx, "saw non-loopback RX packet in"
-                       " %s loopback test\n",
+               EFX_ERR(efx, "saw non-loopback RX packet in %s loopback test\n",
                        LOOPBACK_MODE(efx));
                goto err;
        }
 
        /* Check packet length */
        if (pkt_len != sizeof(*payload)) {
-               EFX_ERR(efx, "saw incorrect RX packet length"
-                       " %d (wanted %d) in %s loopback test\n",
-                       pkt_len, (int)sizeof(*payload),
+               EFX_ERR(efx, "saw incorrect RX packet length %d (wanted %d) in "
+                       "%s loopback test\n", pkt_len, (int)sizeof(*payload),
                        LOOPBACK_MODE(efx));
                goto err;
        }
 
        /* Check that IP header matches */
        if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) {
-               EFX_ERR(efx, "saw corrupted IP header in %s "
-                       "loopback test\n",
+               EFX_ERR(efx, "saw corrupted IP header in %s loopback test\n",
                        LOOPBACK_MODE(efx));
                goto err;
        }
 
        /* Check that msg and padding matches */
        if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) {
-               EFX_ERR(efx, "saw corrupted RX packet in %s "
-                       "loopback test\n",
+               EFX_ERR(efx, "saw corrupted RX packet in %s loopback test\n",
                        LOOPBACK_MODE(efx));
                goto err;
        }
 
        /* Check that iteration matches */
        if (received->iteration != payload->iteration) {
-               EFX_ERR(efx, "saw RX packet from iteration %d"
-                       " (wanted %d) in %s loopback test\n",
-                       ntohs(received->iteration), ntohs(payload->iteration),
-                       LOOPBACK_MODE(efx));
+               EFX_ERR(efx, "saw RX packet from iteration %d (wanted %d) in "
+                       "%s loopback test\n", ntohs(received->iteration),
+                       ntohs(payload->iteration), LOOPBACK_MODE(efx));
                goto err;
        }
 
@@ -423,7 +400,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx,
 /* Initialise an efx_selftest_state for a new iteration */
 static void efx_iterate_state(struct efx_nic *efx)
 {
-       struct efx_selftest_state *state = efx->loopback_selftest;
+       struct efx_loopback_state *state = efx->loopback_selftest;
        struct net_device *net_dev = efx->net_dev;
        struct efx_loopback_payload *payload = &state->payload;
 
@@ -435,7 +412,7 @@ static void efx_iterate_state(struct efx_nic *efx)
        /* saddr set later and used as incrementing count */
        payload->ip.daddr = htonl(INADDR_LOOPBACK);
        payload->ip.ihl = 5;
-       payload->ip.check = 0;          /* offloaded */
+       payload->ip.check = htons(0xdead);
        payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr));
        payload->ip.version = IPVERSION;
        payload->ip.protocol = IPPROTO_UDP;
@@ -456,86 +433,117 @@ static void efx_iterate_state(struct efx_nic *efx)
        smp_wmb();
 }
 
-/*
- * Perform loopback test with N packets
- *
- * This will transmit "num_packets" copies of a test packet, and check
- * that they were both transmitted (i.e. a TX completion event was
- * received) and received (i.e. the data arrived intact via loopback).
- * The port must have already been placed into the desired loopback
- * mode.
- */
-static int efx_test_loopback(struct efx_nic *efx,
-                            struct efx_tx_queue *tx_queue,
-                            struct efx_loopback_self_tests *lb_tests)
+static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
 {
-       struct efx_selftest_state *state = efx->loopback_selftest;
+       struct efx_nic *efx = tx_queue->efx;
+       struct efx_loopback_state *state = efx->loopback_selftest;
        struct efx_loopback_payload *payload;
        struct sk_buff *skb;
-       int rc = 0, i, tx_done, rx_good, rx_bad;
-
-       /* Fill out the packet contents */
-       efx_iterate_state(efx);
-
-       /* Create and fill skb */
-       skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
-       if (!skb) {
-               rc = -ENOMEM;
-               goto out1;
-       }
-       payload = ((struct efx_loopback_payload *)
-                  skb_put(skb, sizeof(state->payload)));
-       memcpy(payload, &state->payload, sizeof(state->payload));
+       int i;
+       netdev_tx_t rc;
 
        /* Transmit N copies of buffer */
        for (i = 0; i < state->packet_count; i++) {
-               /* Set the source address in the copy of the packet.
-                * Incrementing the source address on a per-packet basis
-                * should ensure that we stress all RSS vectors */
-               payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2));
+               /* Allocate an skb, holding an extra reference for
+                * transmit completion counting */
+               skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
+               if (!skb)
+                       return -ENOMEM;
+               state->skbs[i] = skb;
                skb_get(skb);
 
-               if (efx_xmit(efx, tx_queue, skb) != NETDEV_TX_OK) {
-                       EFX_ERR(efx, "TX queue %d could not transmit "
-                               "packet %d of %d in %s loopback test\n",
-                               tx_queue->queue, i + 1,
-                               state->packet_count, LOOPBACK_MODE(efx));
-                       rc = -EPIPE;
-                       goto out2;
+               /* Copy the payload in, incrementing the source address to
+                * exercise the rss vectors */
+               payload = ((struct efx_loopback_payload *)
+                          skb_put(skb, sizeof(state->payload)));
+               memcpy(payload, &state->payload, sizeof(state->payload));
+               payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2));
+
+               /* Ensure everything we've written is visible to the
+                * interrupt handler. */
+               smp_wmb();
+
+               if (efx_dev_registered(efx))
+                       netif_tx_lock_bh(efx->net_dev);
+               rc = efx_enqueue_skb(tx_queue, skb);
+               if (efx_dev_registered(efx))
+                       netif_tx_unlock_bh(efx->net_dev);
+
+               if (rc != NETDEV_TX_OK) {
+                       EFX_ERR(efx, "TX queue %d could not transmit packet %d "
+                               "of %d in %s loopback test\n", tx_queue->queue,
+                               i + 1, state->packet_count, LOOPBACK_MODE(efx));
+
+                       /* Defer cleaning up the other skbs for the caller */
+                       kfree_skb(skb);
+                       return -EPIPE;
                }
+       }
 
-               /* Avoid hogging the PCI bus */
-               udelay(10);
+       return 0;
+}
+
+static int efx_poll_loopback(struct efx_nic *efx)
+{
+       struct efx_loopback_state *state = efx->loopback_selftest;
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_OLD_NAPI)
+       struct efx_channel *channel;
+
+       /* NAPI polling is not enabled, so process channels
+        * synchronously */
+       efx_for_each_channel(channel, efx) {
+               if (channel->work_pending)
+                       efx_process_channel_now(channel);
        }
+#endif
+       return atomic_read(&state->rx_good) == state->packet_count;
+}
 
-       /* Allow time for processing */
-       schedule_timeout_uninterruptible(HZ / 10);
+static int efx_end_loopback(struct efx_tx_queue *tx_queue,
+                           struct efx_loopback_self_tests *lb_tests)
+{
+       struct efx_nic *efx = tx_queue->efx;
+       struct efx_loopback_state *state = efx->loopback_selftest;
+       struct sk_buff *skb;
+       int tx_done = 0, rx_good, rx_bad;
+       int i, rc = 0;
+
+       if (efx_dev_registered(efx))
+               netif_tx_lock_bh(efx->net_dev);
+
+       /* Count the number of tx completions, and decrement the refcnt. Any
+        * skbs not already completed will be free'd when the queue is flushed */
+       for (i=0; i < state->packet_count; i++) {
+               skb = state->skbs[i];
+               if (skb && !skb_shared(skb))
+                       ++tx_done;
+               dev_kfree_skb_any(skb);
+       }
 
-       if (state->flush)
-               goto out3;
+       if (efx_dev_registered(efx))
+               netif_tx_unlock_bh(efx->net_dev);
 
        /* Check TX completion and received packet counts */
-       tx_done = state->packet_count - (atomic_read(&skb->users) - 1);
        rx_good = atomic_read(&state->rx_good);
        rx_bad = atomic_read(&state->rx_bad);
        if (tx_done != state->packet_count) {
                /* Don't free the skbs; they will be picked up on TX
                 * overflow or channel teardown.
                 */
-               EFX_ERR(efx, "TX queue %d saw only %d out of an "
-                       "expected %d TX completion events in %s loopback "
-                       "test\n", tx_queue->queue, tx_done,
-                       state->packet_count, LOOPBACK_MODE(efx));
+               EFX_ERR(efx, "TX queue %d saw only %d out of an expected %d "
+                       "TX completion events in %s loopback test\n",
+                       tx_queue->queue, tx_done, state->packet_count,
+                       LOOPBACK_MODE(efx));
                rc = -ETIMEDOUT;
                /* Allow to fall through so we see the RX errors as well */
        }
 
        /* We may always be up to a flush away from our desired packet total */
        if (rx_good != state->packet_count) {
-               EFX_LOG(efx, "TX queue %d saw only %d out of an "
-                       "expected %d received packets in %s loopback "
-                       "test\n", tx_queue->queue, rx_good,
-                       state->packet_count, LOOPBACK_MODE(efx));
+               EFX_LOG(efx, "TX queue %d saw only %d out of an expected %d "
+                       "received packets in %s loopback test\n",
+                       tx_queue->queue, rx_good, state->packet_count,
+                       LOOPBACK_MODE(efx));
                rc = -ETIMEDOUT;
                /* Fall through */
        }
@@ -546,262 +554,295 @@ static int efx_test_loopback(struct efx_nic *efx,
        lb_tests->rx_good += rx_good;
        lb_tests->rx_bad += rx_bad;
 
- out3:
- out2:
-       /* Free skb */
-       if (skb) {
-               /* If the selftest failed then the skb needs its reference
-                * count decreasing */
-               while (skb_shared(skb))
-                       kfree_skb(skb);
-               dev_kfree_skb_any(skb);
-       }
-
- out1:
        return rc;
 }
 
-/* Perform loopback test safely
- *
- * This performs a safe loopback test by starting with a single packet
- * and only increasing the number of packets while the tests are
- * passing.  This avoids flooding a network with garbage packets if
- * e.g. setting the loopback mode fails.
- */
 static int
-efx_test_loopback_safely(struct efx_nic *efx,
-                        struct efx_tx_queue *tx_queue,
-                        struct efx_loopback_self_tests *lb_tests)
+efx_test_loopback(struct efx_tx_queue *tx_queue,
+                 struct efx_loopback_self_tests *lb_tests,
+                 int level)
 {
-       struct efx_selftest_state *state = efx->loopback_selftest;
-       int i, rc = 0;
+       struct efx_nic *efx = tx_queue->efx;
+       struct efx_loopback_state *state = efx->loopback_selftest;
+       int i, begin_rc, end_rc;
 
-       for (i = 0; i < loopback_test_level; i++) {
-               /* Determine how many packets to send */
-               state->packet_count = (efx->type->txd_ring_mask + 1) / 3;
+       for (i = 0; i < level; i++) {
+               /* Determine how many packets to send - up to 16**(level-1) */
+               state->packet_count = EFX_TXQ_SIZE / 3;
                state->packet_count = min(1 << (i << 2), state->packet_count);
-               state->flush = 0;
+               state->skbs = kzalloc(sizeof(state->skbs[0]) *
+                                     state->packet_count, GFP_KERNEL);
+               if (!state->skbs)
+                       return -ENOMEM;
+               state->flush = false;
+
+               EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
+                       "packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+                       state->packet_count);
+
+               efx_iterate_state(efx);
+               begin_rc = efx_begin_loopback(tx_queue);
+
+               /* This will normally complete very quickly, but be
+                * prepared to wait much longer. */
+               msleep(1);
+               if (!efx_poll_loopback(efx)) {
+                       msleep(LOOPBACK_TIMEOUT_MS);
+                       efx_poll_loopback(efx);
+               }
 
-               EFX_LOG(efx, "TX queue %d testing %s loopback"
-                       " with %d packets\n", tx_queue->queue,
-                       LOOPBACK_MODE(efx), state->packet_count);
+               end_rc = efx_end_loopback(tx_queue, lb_tests);
+               kfree(state->skbs);
 
-               rc = efx_test_loopback(efx, tx_queue, lb_tests);
-               if (rc) {
+               if (begin_rc || end_rc) {
                        /* Wait a while to ensure there are no packets
-                        * floating around after a failure.
-                        */
-                       schedule_timeout_uninterruptible(HZ / 5);
-                       return rc;
+                        * floating around after a failure. */
+                       schedule_timeout_uninterruptible(HZ / 10);
+                       return begin_rc ? begin_rc : end_rc;
                }
        }
 
-       EFX_LOG(efx, "TX queue %d passed %s loopback test "
-               "with a burst length of %d packets\n",
-               tx_queue->queue, LOOPBACK_MODE(efx), state->packet_count);
+       EFX_LOG(efx, "TX queue %d passed %s loopback test with a burst length "
+               "of %d packets\n", tx_queue->queue, LOOPBACK_MODE(efx),
+               state->packet_count);
 
-       return rc;
+       return 0;
 }
 
-static int efx_test_loopbacks(struct efx_nic *efx,
-                             struct efx_self_tests *tests,
-                             unsigned int loopback_modes)
+/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but
+ * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it
+ * to delay and retry. Therefore, it's safer to just poll directly. Wait
+ * for link up and any faults to dissipate. */
+static int efx_wait_for_link(struct efx_nic *efx)
 {
-       struct efx_selftest_state *state = efx->loopback_selftest;
-       struct ethtool_cmd ecmd, ecmd_loopback;
-       struct efx_tx_queue *tx_queue;
-       enum efx_loopback_mode old_mode, mode;
-       int old_powered, count, rc = 0, link_up;
-       int retry = EFX_WORKAROUND_8909(efx);
-
-       /* Get current PHY settings */
-       rc = efx_ethtool_get_settings(efx->net_dev, &ecmd);
-       if (rc) {
-               EFX_ERR(efx, "could not get GMII settings\n");
-               return rc;
-       }
-       old_mode = efx->loopback_mode;
-       old_powered = efx->phy_powered;
-
-       /* Disable autonegotiation for the purposes of loopback */
-       memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback));
-       if (ecmd_loopback.autoneg == AUTONEG_ENABLE) {
-               ecmd_loopback.autoneg = AUTONEG_DISABLE;
-               ecmd_loopback.duplex = DUPLEX_FULL;
-               ecmd_loopback.speed = EFX_IS10G(efx) ?
-                       SPEED_10000 : SPEED_1000;
-       }
+       struct efx_link_state *link_state = &efx->link_state;
+       int count;
+       bool link_up;
+
+       for (count = 0; count < 40; count++) {
+               schedule_timeout_uninterruptible(HZ / 10);
+
+               if (efx->type->monitor != NULL) {
+                       mutex_lock(&efx->mac_lock);
+                       efx->type->monitor(efx);
+                       mutex_unlock(&efx->mac_lock);
+               } else {
+#if !defined(EFX_USE_KCOMPAT) || !defined(EFX_HAVE_OLD_NAPI)
+                       struct efx_channel *channel = &efx->channel[0];
+                       if (channel->work_pending)
+                               efx_process_channel_now(channel);
+#endif
+               }
+
+               mutex_lock(&efx->mac_lock);
+               link_up = link_state->up;
+               if (link_up)
+                       link_up = !efx->mac_op->check_fault(efx);
+               mutex_unlock(&efx->mac_lock);
 
-       rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback);
-       if (rc) {
-               EFX_ERR(efx, "could not disable autonegotiation\n");
-               goto out;
+               if (link_up)
+                       return 0;
        }
-       tests->loopback_speed = ecmd_loopback.speed;
-       tests->loopback_full_duplex = ecmd_loopback.duplex;
+
+       return -ETIMEDOUT;
+}
+
+static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
+                             unsigned int loopback_modes, int level)
+{
+       enum efx_loopback_mode mode;
+       struct efx_loopback_state *state;
+       struct efx_tx_queue *tx_queue;
+       int rc = 0;
+       bool retry;
+
+       /* Set the port loopback_selftest member. From this point on
+        * all received packets will be dropped. Mark the state as
+        * "flushing" so all inflight packets are dropped */
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (state == NULL)
+               return -ENOMEM;
+       BUG_ON(efx->loopback_selftest);
+       state->flush = true;
+       efx->loopback_selftest = state;
 
        /* Test all supported loopback modes */
-       for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
+       for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
                if (!(loopback_modes & (1 << mode)))
                        continue;
 
+               retry = EFX_WORKAROUND_8568(efx);
+       set_loopback:
                /* Move the port into the specified loopback mode. */
-               state->flush = 1;
-               efx->phy_powered = 1;
+               state->flush = true;
+               mutex_lock(&efx->mac_lock);
                efx->loopback_mode = mode;
-               efx_reconfigure_port(efx);
-
-               /* Wait for the PHY to signal the link is up */
-               count = 0;
-               do {
-                       struct efx_channel *channel = &efx->channel[0];
+               rc = __efx_reconfigure_port(efx);
+               mutex_unlock(&efx->mac_lock);
+               if (rc) {
+                       EFX_ERR(efx, "unable to move into %s loopback\n",
+                               LOOPBACK_MODE(efx));
+                       goto out;
+               }
 
-                       (void) efx->mac_op->check_hw(efx);
-                       schedule_timeout_uninterruptible(HZ / 10);
-                       if (channel->work_pending)
-                               efx_process_channel_now(channel);
-                       /* Wait for PHY events to be processed */
-                       flush_workqueue(efx->workqueue);
-                       rmb();
-
-                       /* efx->link_up can be 1 even if the XAUI link is down,
-                        * (bug5762). Usually, it's not worth bothering with the
-                        * difference, but for selftests, we need that extra
-                        * guarantee that the link is really, really, up.
-                        */
-                       link_up = efx->link_up;
-                       if (EFX_IS10G(efx) && !falcon_xaui_link_ok(efx))
-                               link_up = 0;
-
-               } while ((++count < 20) && !link_up);
-
-               /* The link should now be up. If it isn't, there is no point
-                * in attempting a loopback test */
-               if (!link_up) {
+               rc = efx_wait_for_link(efx);
+               if (rc) {
                        EFX_ERR(efx, "loopback %s never came up\n",
                                LOOPBACK_MODE(efx));
-                       rc = -EIO;
                        goto out;
                }
 
-               EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
-                       LOOPBACK_MODE(efx), count);
-
                /* Test every TX queue */
                efx_for_each_tx_queue(tx_queue, efx) {
-                       rc |= efx_test_loopback_safely(efx, tx_queue,
-                                                      &tests->loopback[mode]);
-                       if (rc)
-                               goto fail;
+                       state->offload_csum = (tx_queue->queue ==
+                                              EFX_TX_QUEUE_OFFLOAD_CSUM);
+                       rc = efx_test_loopback(tx_queue,
+                                              &tests->loopback[mode],
+                                              level);
+                       if (rc && !retry)
+                               goto out;
+                       if (rc) {
+                               /* Give the PHY a kick by moving into
+                                * a Falcon internal loopback mode and
+                                * then back out */
+                               int first = ffs(efx->loopback_modes) - 1;
+
+                               EFX_INFO(efx, "retrying %s loopback\n",
+                                        LOOPBACK_MODE(efx));
+
+                               state->flush = true;
+                               mutex_lock(&efx->mac_lock);
+                               efx->loopback_mode = first;
+                               __efx_reconfigure_port(efx);
+                               mutex_unlock(&efx->mac_lock);
+
+                               memset(&tests->loopback[mode], 0,
+                                      sizeof(tests->loopback[mode]));
+                               retry = false;
+                               goto set_loopback;
+                       }
                }
-
-               continue;
-
-fail:
-               if (retry) {
-                       /* Give the PHY a kick by pretending to move into
-                        * a Falcon internal loopback mode, then back out */
-                       int first = ffs(efx->loopback_modes) - 1;
-
-                       EFX_INFO(efx, "retrying %s loopback\n",
-                                LOOPBACK_MODE(efx));
-
-                       state->flush = 1;
-                       efx->loopback_mode = first;
-                       efx_reconfigure_port(efx);
-
-                       retry = rc = 0;
-                       --mode;
-                       continue;
-               }
-               break;
        }
 
  out:
-       /* Take out of loopback and restore PHY settings */
-       state->flush = 1;
-       efx->loopback_mode = old_mode;
-       efx->phy_powered = old_powered;
-       /* Push the loopback change, and restore any other
-        * settings we may have trodden on */
-       (void) efx_ethtool_set_settings(efx->net_dev, &ecmd);
+       /* Remove the flush. The caller will remove the loopback setting */
+       state->flush = true;
+       efx->loopback_selftest = NULL;
+       wmb();
+       kfree(state);
 
        return rc;
 }
 
 /**************************************************************************
  *
- * Entry points
+ * Entry point
  *
  *************************************************************************/
 
-/* Online (i.e. non-disruptive) testing
- *
- * This checks interrupt generation, event delivery and PHY presence.
- * The caller should hold the suspend lock
- *
- */
-int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests)
+int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
+                unsigned flags)
 {
+       enum efx_loopback_mode loopback_mode = efx->loopback_mode;
+       int phy_mode = efx->phy_mode;
        struct efx_channel *channel;
-       int rc = 0;
+       int rc_test = 0, rc_reset = 0, rc;
+
+       /* Online (i.e. non-disruptive) testing
+        * This checks interrupt generation, event delivery and PHY presence. */
+
+       {
+               rc = efx_test_phy_alive(efx, tests);
+               if (rc && !rc_test)
+                       rc_test = rc;
 
-       EFX_LOG(efx, "performing online self-tests\n");
+               rc = efx_test_nvram(efx, tests);
+               if (rc && !rc_test)
+                       rc_test = rc;
+       }
+
+       rc = efx_test_interrupts(efx, tests);
+       if (rc && !rc_test)
+               rc_test = rc;
 
-       rc |= efx_test_interrupts(efx, tests);
        efx_for_each_channel(channel, efx) {
-               if (channel->has_interrupt)
-                       rc |= efx_test_eventq_irq(channel, tests);
+               rc = efx_test_eventq_irq(channel, tests);
+               if (rc && !rc_test)
+                       rc_test = rc;
+       }
+
+       if (rc_test)
+               return rc_test;
+
+       if (!(flags & ETH_TEST_FL_OFFLINE)) {
+                       return efx_test_phy(efx, tests, flags);
+       }
+
+       /* Offline (i.e. disruptive) testing
+        * This checks MAC and PHY loopback on the specified port. */
+
+       /* force the carrier state off so the kernel doesn't transmit during
+        * the loopback test, and the watchdog timeout doesn't fire. Also put
+        * falcon into loopback for the register test.
+        */
+       mutex_lock(&efx->mac_lock);
+       efx->port_inhibited = true;
+       if (efx->loopback_modes) {
+               /* We need the 312 clock from the PHY to test the XMAC
+                * registers, so move into XGMII loopback if available */
+               if (efx->loopback_modes & (1 << LOOPBACK_XGMII))
+                       efx->loopback_mode = LOOPBACK_XGMII;
                else
-                       rc |= efx_test_eventq(channel, tests);
+                       efx->loopback_mode = __ffs(efx->loopback_modes);
        }
-       rc |= efx_test_phy(efx, tests);
 
-       if (rc)
-               EFX_ERR(efx, "failed online self-tests\n");
+       __efx_reconfigure_port(efx);
+       mutex_unlock(&efx->mac_lock);
 
-       return rc;
-}
+       {
+               enum reset_type method = RESET_TYPE_INVISIBLE;
 
-/* Offline (i.e. disruptive) testing
- * This checks MAC and PHY loopback on the specified port. The caller
- * should hold the rtnl lock
- */
-int efx_offline_test(struct efx_nic *efx,
-                    struct efx_self_tests *tests, unsigned int loopback_modes)
-{
-       struct efx_selftest_state *state;
-       int rc = 0;
+               /* free up all consumers of SRAM (including all the queues) */
+               efx_reset_down(efx, method);
 
-       EFX_LOG(efx, "performing offline self-tests\n");
+               rc = efx_test_chip(efx, tests);
+               if (rc && !rc_test)
+                       rc_test = rc;
 
-       /* Create a selftest_state structure to hold state for the test */
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (state == NULL) {
-               rc = -ENOMEM;
-               goto out;
-       }
+               /* reset the chip to recover from the register test */
+               rc_reset = efx->type->reset(efx, method);
 
-       /* Set the port loopback_selftest member. From this point on
-        * all received packets will be dropped. Mark the state as
-        * "flushing" so all inflight packets are dropped */
-       BUG_ON(efx->loopback_selftest);
-       state->flush = 1;
-       efx->loopback_selftest = (void *)state;
-       wmb();
+               /* Ensure that the phy is powered and out of loopback
+                * for the bist and loopback tests */
+               efx->phy_mode &= ~PHY_MODE_LOW_POWER;
+               efx->loopback_mode = LOOPBACK_NONE;
+               rc = efx_reset_up(efx, method, rc_reset == 0);
+               if (rc && !rc_reset)
+                       rc_reset = rc;
+
+               if (rc_reset) {
+                       EFX_ERR(efx, "Unable to recover from chip test\n");
+                       efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+                       return rc_reset;
+               }
 
-       /* Test all loopback  modes */
-       rc = efx_test_loopbacks(efx, tests, loopback_modes);
+               rc = efx_test_phy(efx, tests, flags);
+               if (rc && !rc_test)
+                       rc_test = rc;
 
-       /* Tidy up the port test state */
-       efx->loopback_selftest = NULL;
-       wmb();
-       kfree(state);
+               rc = efx_test_loopbacks(efx, tests, efx->loopback_modes, 3);
+               if (rc && !rc_test)
+                       rc_test = rc;
+       }
 
- out:
-       if (rc)
-               EFX_ERR(efx, "failed offline self-tests\n");
+       /* restore the PHY to the previous state */
+       mutex_lock(&efx->mac_lock);
+       efx->phy_mode = phy_mode;
+       efx->port_inhibited = false;
+       efx->loopback_mode = loopback_mode;
+       __efx_reconfigure_port(efx);
+       mutex_unlock(&efx->mac_lock);
 
-       return rc;
+       return rc_test;
 }
 
index 76d4c5aef5f853d26b19f8143fd7cdd37874e6d4..bbf21dab2b9ece1c7134ccda49266e5061e9ecf5 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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_SELFTEST_H
  */
 
 struct efx_loopback_self_tests {
-       int tx_sent[EFX_MAX_TX_QUEUES];
-       int tx_done[EFX_MAX_TX_QUEUES];
+       int tx_sent[EFX_TX_QUEUE_COUNT];
+       int tx_done[EFX_TX_QUEUE_COUNT];
        int rx_good;
        int rx_bad;
 };
 
+#define EFX_MAX_PHY_TESTS 20
+
 /* Efx self test results
  * For fields which are not counters, 1 indicates success and -1
  * indicates failure.
  */
 struct efx_self_tests {
+       /* online tests */
+       int phy_alive;
+       int nvram;
        int interrupt;
        int eventq_dma[EFX_MAX_CHANNELS];
        int eventq_int[EFX_MAX_CHANNELS];
        int eventq_poll[EFX_MAX_CHANNELS];
-       int phy_ok;
-       int loopback_speed;
-       int loopback_full_duplex;
-       struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX];
+       /* offline tests */
+       int memory;
+       int registers;
+       int phy_ext[EFX_MAX_PHY_TESTS];
+       struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
 };
 
 extern void efx_loopback_rx_packet(struct efx_nic *efx,
                                   const char *buf_ptr, int pkt_len);
-extern int efx_online_test(struct efx_nic *efx,
-                          struct efx_self_tests *tests);
-extern int efx_offline_test(struct efx_nic *efx,
-                           struct efx_self_tests *tests,
-                           unsigned int loopback_modes);
+extern int efx_selftest(struct efx_nic *efx,
+                       struct efx_self_tests *tests,
+                       unsigned flags);
 
 #endif /* EFX_SELFTEST_H */
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
deleted file mode 100644 (file)
index e6a5075..0000000
+++ /dev/null
@@ -1,315 +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@solarflare.com>
- *
- * 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
- ****************************************************************************/
-
-/*****************************************************************************
- * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
- * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
- * the PHY
- */
-#include <linux/delay.h>
-#include "efx.h"
-#include "phy.h"
-#include "boards.h"
-#include "falcon.h"
-#include "falcon_hwdefs.h"
-
-/**************************************************************************
- *
- * I2C IO Expander device
- *
- **************************************************************************/
-#define        PCA9539 0x74
-
-#define        P0_IN 0x00
-#define        P0_OUT 0x02
-#define        P0_INVERT 0x04
-#define        P0_CONFIG 0x06
-
-#define        P0_EN_1V0X_LBN 0
-#define        P0_EN_1V0X_WIDTH 1
-#define        P0_EN_1V2_LBN 1
-#define        P0_EN_1V2_WIDTH 1
-#define        P0_EN_2V5_LBN 2
-#define        P0_EN_2V5_WIDTH 1
-#define        P0_EN_3V3X_LBN 3
-#define        P0_EN_3V3X_WIDTH 1
-#define        P0_EN_5V_LBN 4
-#define        P0_EN_5V_WIDTH 1
-#define        P0_SHORTEN_JTAG_LBN 5
-#define        P0_SHORTEN_JTAG_WIDTH 1
-#define        P0_X_TRST_LBN 6
-#define        P0_X_TRST_WIDTH 1
-#define        P0_DSP_RESET_LBN 7
-#define        P0_DSP_RESET_WIDTH 1
-
-#define        P1_IN 0x01
-#define        P1_OUT 0x03
-#define        P1_INVERT 0x05
-#define        P1_CONFIG 0x07
-
-#define        P1_AFE_PWD_LBN 0
-#define        P1_AFE_PWD_WIDTH 1
-#define        P1_DSP_PWD25_LBN 1
-#define        P1_DSP_PWD25_WIDTH 1
-#define        P1_RESERVED_LBN 2
-#define        P1_RESERVED_WIDTH 2
-#define        P1_SPARE_LBN 4
-#define        P1_SPARE_WIDTH 4
-
-
-/**************************************************************************
- *
- * Temperature Sensor
- *
- **************************************************************************/
-#define        MAX6647 0x4e
-
-#define        RLTS    0x00
-#define        RLTE    0x01
-#define        RSL     0x02
-#define        RCL     0x03
-#define        RCRA    0x04
-#define        RLHN    0x05
-#define        RLLI    0x06
-#define        RRHI    0x07
-#define        RRLS    0x08
-#define        WCRW    0x0a
-#define        WLHO    0x0b
-#define        WRHA    0x0c
-#define        WRLN    0x0e
-#define        OSHT    0x0f
-#define        REET    0x10
-#define        RIET    0x11
-#define        RWOE    0x19
-#define        RWOI    0x20
-#define        HYS     0x21
-#define        QUEUE   0x22
-#define        MFID    0xfe
-#define        REVID   0xff
-
-/* Status bits */
-#define MAX6647_BUSY   (1 << 7)        /* ADC is converting */
-#define MAX6647_LHIGH  (1 << 6)        /* Local high temp. alarm */
-#define MAX6647_LLOW   (1 << 5)        /* Local low temp. alarm */
-#define MAX6647_RHIGH  (1 << 4)        /* Remote high temp. alarm */
-#define MAX6647_RLOW   (1 << 3)        /* Remote low temp. alarm */
-#define MAX6647_FAULT  (1 << 2)        /* DXN/DXP short/open circuit */
-#define MAX6647_EOT    (1 << 1)        /* Remote junction overtemp. */
-#define MAX6647_IOT    (1 << 0)        /* Local junction overtemp. */
-
-static const u8 xgphy_max_temperature = 90;
-
-void sfe4001_poweroff(struct efx_nic *efx)
-{
-       struct efx_i2c_interface *i2c = &efx->i2c;
-
-       u8 cfg, out, in;
-
-       EFX_INFO(efx, "%s\n", __func__);
-
-       /* Turn off all power rails */
-       out = 0xff;
-       (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-
-       /* Disable port 1 outputs on IO expander */
-       cfg = 0xff;
-       (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
-
-       /* Disable port 0 outputs on IO expander */
-       cfg = 0xff;
-       (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
-
-       /* Clear any over-temperature alert */
-       (void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
-}
-
-static int sfe4001_check_hw(struct efx_nic *efx)
-{
-       struct efx_i2c_interface *i2c = &efx->i2c;
-       int rc;
-       u8 status;
-
-       /* Check the powered status of the PHY. Lack of power implies that
-        * the MAX6647 has shut down power to it, probably due to a temp.
-        * alarm. Reading the power status rather than the MAX6647 status
-        * directly because the later is read-to-clear and would thus
-        * start to power up the PHY again when polled, causing us to blip
-        * the power undesirably */
-
-       /* If XAUI link is down, check power status. Reading
-        * power requires a I2C byte read, which is too slow
-        * to poll (see SFC bug 7884). */
-       if (falcon_xaui_link_ok(efx))
-               return 0;
-
-       rc = efx_i2c_read(i2c, PCA9539, P1_IN, &status, 1);
-       status &= ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN));
-
-       /* We know we can read from the IO expander because we did
-        * it during power-on. Assume failure now is bad news. */
-       if (rc != 0 || status == 0) {
-               sfe4001_poweroff(efx);
-
-               /* Note that the PHY is pining for the cooling fans */
-               tenxpress_set_state(efx, TENXPRESS_STATUS_OTEMP);
-
-               /* Log the info */
-               if (status == 0) {
-                       EFX_ERR(efx, "%s: Temperature sensor reports "
-                               "alarm! (0x%x) Shutting down PHY.\n",
-                               __func__, status);
-                       rc = -EIO;
-               } else {
-                       EFX_ERR(efx, "%s: Failed to read PHY status!"
-                               " Shutting down PHY.\n",
-                               __func__);
-               }
-       }
-
-       return rc;
-}
-
-/* This board uses an I2C expander to provider power to the PHY, which needs to
- * be turned on before the PHY can be used.
- * Context: Process context, rtnl lock held
- */
-int sfe4001_poweron(struct efx_nic *efx)
-{
-       struct efx_i2c_interface *i2c = &efx->i2c;
-       unsigned int count;
-       int rc;
-       u8 out, in, cfg;
-       efx_dword_t reg;
-
-       /* 10Xpress has fixed-function LED pins, so there is no board-specific
-        * blink code. */
-       efx->board_info.blink = tenxpress_phy_blink;
-
-       /* Ensure that XGXS and XAUI SerDes are held in reset */
-       EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
-                            XX_PWRDNB_EN, 1,
-                            XX_RSTPLLAB_EN, 1,
-                            XX_RESETA_EN, 1,
-                            XX_RESETB_EN, 1,
-                            XX_RSTXGXSRX_EN, 1,
-                            XX_RSTXGXSTX_EN, 1);
-       efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
-       udelay(10);
-
-       efx->board_info.monitor = sfe4001_check_hw;
-       efx->board_info.fini = sfe4001_poweroff;
-
-       /* Set DSP over-temperature alert threshold */
-       EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
-       rc = efx_i2c_write(i2c, MAX6647, WLHO,
-                          &xgphy_max_temperature, 1);
-       if (rc)
-               goto fail1;
-
-       /* Read it back and verify */
-       rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
-       if (rc)
-               goto fail1;
-       if (in != xgphy_max_temperature) {
-               rc = -EFAULT;
-               goto fail1;
-       }
-
-       /* Clear any previous over-temperature alert */
-       rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
-       if (rc)
-               goto fail1;
-
-       /* Enable port 0 and port 1 outputs on IO expander */
-       cfg = 0x00;
-       rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
-       if (rc)
-               goto fail1;
-       cfg = 0xff & ~(1 << P1_SPARE_LBN);
-       rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
-       if (rc)
-               goto fail2;
-
-       /* Turn all power off then wait 1 sec. This ensures PHY is reset */
-       out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
-                      (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
-                      (0 << P0_EN_1V0X_LBN));
-       rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-       if (rc)
-               goto fail3;
-
-       schedule_timeout_uninterruptible(HZ);
-       count = 0;
-       do {
-               /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
-               out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
-                              (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
-                              (1 << P0_X_TRST_LBN));
-
-               rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-               if (rc)
-                       goto fail3;
-               msleep(10);
-
-               /* Turn on 1V power rail */
-               out &= ~(1 << P0_EN_1V0X_LBN);
-               rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-               if (rc)
-                       goto fail3;
-
-               EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
-
-               schedule_timeout_uninterruptible(HZ);
-
-               /* Check DSP is powered */
-               rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
-               if (rc)
-                       goto fail3;
-               if (in & (1 << P1_AFE_PWD_LBN))
-                       goto done;
-
-       } while (++count < 20);
-
-       EFX_INFO(efx, "timed out waiting for power\n");
-       rc = -ETIMEDOUT;
-       goto fail3;
-
-done:
-       EFX_INFO(efx, "PHY is powered on\n");
-       return 0;
-
-fail3:
-       /* Turn off all power rails */
-       out = 0xff;
-       (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-       /* Disable port 1 outputs on IO expander */
-       out = 0xff;
-       (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
-fail2:
-       /* Disable port 0 outputs on IO expander */
-       out = 0xff;
-       (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
-fail1:
-       return rc;
-}
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
new file mode 100644 (file)
index 0000000..b94e80b
--- /dev/null
@@ -0,0 +1,743 @@
+/****************************************************************************
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include "net_driver.h"
+#include "bitfield.h"
+#include "efx.h"
+#include "nic.h"
+#include "mac.h"
+#include "spi.h"
+#include "regs.h"
+#include "io.h"
+#include "phy.h"
+#include "workarounds.h"
+#include "mcdi.h"
+#include "mcdi_pcol.h"
+
+/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */
+
+static void siena_init_wol(struct efx_nic *efx);
+
+
+static void siena_push_irq_moderation(struct efx_channel *channel)
+{
+       efx_dword_t timer_cmd;
+
+       if (channel->irq_moderation)
+               EFX_POPULATE_DWORD_2(timer_cmd,
+                                    FRF_CZ_TC_TIMER_MODE,
+                                    FFE_CZ_TIMER_MODE_INT_HLDOFF,
+                                    FRF_CZ_TC_TIMER_VAL,
+                                    channel->irq_moderation - 1);
+       else
+               EFX_POPULATE_DWORD_2(timer_cmd,
+                                    FRF_CZ_TC_TIMER_MODE,
+                                    FFE_CZ_TIMER_MODE_DIS,
+                                    FRF_CZ_TC_TIMER_VAL, 0);
+       efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0,
+                              channel->channel);
+}
+
+static void siena_push_multicast_hash(struct efx_nic *efx)
+{
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+       efx_mcdi_rpc(efx, MC_CMD_SET_MCAST_HASH,
+                    efx->multicast_hash.byte, sizeof(efx->multicast_hash),
+                    NULL, 0, NULL);
+}
+
+static int siena_mdio_write(struct net_device *net_dev,
+                           int prtad, int devad, u16 addr, u16 value)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       uint32_t status;
+       int rc;
+
+       rc = efx_mcdi_mdio_write(efx, efx->mdio_bus, prtad, devad,
+                                addr, value, &status);
+       if (rc)
+               return rc;
+       if (status != MC_CMD_MDIO_STATUS_GOOD)
+               return -EIO;
+
+       return 0;
+}
+
+static int siena_mdio_read(struct net_device *net_dev,
+                          int prtad, int devad, u16 addr)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+       uint16_t value;
+       uint32_t status;
+       int rc;
+
+       rc = efx_mcdi_mdio_read(efx, efx->mdio_bus, prtad, devad,
+                               addr, &value, &status);
+       if (rc)
+               return rc;
+       if (status != MC_CMD_MDIO_STATUS_GOOD)
+               return -EIO;
+
+       return (int)value;
+}
+
+/* This call is responsible for hooking in the MAC and PHY operations */
+static int siena_probe_port(struct efx_nic *efx)
+{
+       int rc;
+
+       /* Hook in PHY operations table */
+       efx->phy_op = &efx_mcdi_phy_ops;
+
+       /* Set up MDIO structure for PHY */
+       efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+       efx->mdio.mdio_read = siena_mdio_read;
+       efx->mdio.mdio_write = siena_mdio_write;
+
+       /* Fill out MDIO structure, loopback modes, and initial link state */
+       rc = efx->phy_op->probe(efx);
+       if (rc != 0)
+               return rc;
+
+       /* Allocate buffer for stats */
+       rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
+                                 MC_CMD_MAC_NSTATS * sizeof(u64));
+       if (rc)
+               return rc;
+       EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n",
+               (u64)efx->stats_buffer.dma_addr,
+               efx->stats_buffer.addr,
+               (u64)virt_to_phys(efx->stats_buffer.addr));
+
+       efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1);
+
+       return 0;
+}
+
+void siena_remove_port(struct efx_nic *efx)
+{
+       efx->phy_op->remove(efx);
+       efx_nic_free_buffer(efx, &efx->stats_buffer);
+}
+
+static int siena_test_sram(struct efx_nic *efx,
+                          void (*pattern)(unsigned, efx_qword_t *, int, int),
+                          int a, int b)
+{
+       void __iomem *membase = efx->membase + FR_BZ_BUF_FULL_TBL;
+       int finish = efx->sram_lim / 8;
+       efx_qword_t buf1, buf2;
+       efx_oword_t reg;
+       int wptr = 0, rptr = 0;
+
+       /* Move descriptor caches out into space so we can treat all
+        * SRAM as buffer table.  These registers will be restored by
+        * a following reset. */
+       EFX_POPULATE_OWORD_1(reg, FRF_AZ_SRM_RX_DC_BASE_ADR, finish);
+       efx_writeo(efx, &reg, FR_AZ_SRM_RX_DC_CFG);
+       EFX_POPULATE_OWORD_1(reg, FRF_AZ_SRM_TX_DC_BASE_ADR, finish + 64);
+       efx_writeo(efx, &reg, FR_AZ_SRM_TX_DC_CFG);
+
+       while (wptr < finish) {
+               pattern(wptr, &buf1, a, b);
+               efx_sram_writeq(efx, membase, &buf1, wptr);
+               wptr++;
+
+               /* Buffer table writes are not performed synchronously
+                * but go through a 128-entry FIFO, so we must switch
+                * from writing to reading after at most 128 writes.
+                * We choose 125 to make the following calculation
+                * result in a round number. */
+               if ((wptr - rptr) < 125 && wptr < finish)
+                       continue;
+
+               /* The SRAM arbiter will allow 2 writes per 8 cycles
+                * with a cycle time of 8 ns.  Each MMIO access takes
+                * at least one cycle.  So in order to avoid reads
+                * overtaking writes we must wait for at least
+                * 125 * (8 / 2 - 2) * 8 ns = 2 us */
+               udelay(2);
+
+               for (; rptr < wptr; ++rptr) {
+                       pattern(rptr, &buf1, a, b);
+                       efx_sram_readq(efx, membase, &buf2, rptr);
+
+                       if (!memcmp(&buf1, &buf2, sizeof(buf1)))
+                               continue;
+
+                       EFX_ERR(efx, "sram test failed at index 0x%x. "
+                               "wrote "EFX_QWORD_FMT" read "EFX_QWORD_FMT"\n",
+                               rptr, EFX_QWORD_VAL(buf1), EFX_QWORD_VAL(buf2));
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static const struct efx_nic_register_test siena_register_tests[] = {
+       { FR_AZ_ADR_REGION,
+         EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) },
+       { FR_CZ_USR_EV_CFG,
+         EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_RX_CFG,
+         EFX_OWORD32(0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000) },
+       { FR_AZ_TX_CFG,
+         EFX_OWORD32(0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF) },
+       { FR_AZ_TX_RESERVED,
+         EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) },
+       { FR_AZ_SRM_TX_DC_CFG,
+         EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_RX_DC_CFG,
+         EFX_OWORD32(0x00000003, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_AZ_RX_DC_PF_WM,
+         EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_BZ_DP_CTRL,
+         EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_BZ_RX_RSS_TKEY,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) },
+       { FR_CZ_RX_RSS_IPV6_REG1,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) },
+       { FR_CZ_RX_RSS_IPV6_REG2,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) },
+       { FR_CZ_RX_RSS_IPV6_REG3,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) },
+};
+
+static const struct efx_nic_table_test siena_table_tests[] = {
+       { FR_BZ_RX_FILTER_TBL0,
+         FR_BZ_RX_FILTER_TBL0_STEP, FR_BZ_RX_FILTER_TBL0_ROWS,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF) },
+       { FR_CZ_RX_MAC_FILTER_TBL0,
+         FR_CZ_RX_MAC_FILTER_TBL0_STEP, FR_CZ_RX_MAC_FILTER_TBL0_ROWS,
+         EFX_OWORD32(0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000) },
+       { FR_BZ_RX_DESC_PTR_TBL,
+         FR_BZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS,
+         EFX_OWORD32(0xFFFFFFFF, 0x0FFFFFFF, 0x01800000, 0x00000000) },
+       { FR_BZ_TX_DESC_PTR_TBL,
+         FR_BZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS,
+         EFX_OWORD32(0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000) },
+       { FR_BZ_TIMER_TBL,
+         FR_BZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS,
+         EFX_OWORD32(0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000) },
+       { FR_CZ_TX_FILTER_TBL0,
+         FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS,
+         EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF) },
+       { FR_CZ_TX_MAC_FILTER_TBL0,
+         FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS,
+         EFX_OWORD32(0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000) },
+};
+
+static int siena_test_registers(struct efx_nic *efx)
+{
+       return efx_nic_test_registers(efx, siena_register_tests,
+                                     ARRAY_SIZE(siena_register_tests));
+}
+
+static int
+siena_test_tables(struct efx_nic *efx,
+                 void (*pattern)(unsigned, efx_qword_t *, int, int),
+                 int a, int b)
+{
+       int rc, i;
+
+       rc = siena_test_sram(efx, pattern, a, b);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < ARRAY_SIZE(siena_table_tests); i++) {
+               rc = efx_nic_test_table(efx, &siena_table_tests[i],
+                                       pattern, a, b);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+/**************************************************************************
+ *
+ * Device reset
+ *
+ **************************************************************************
+ */
+
+static int siena_reset_hw(struct efx_nic *efx, enum reset_type method)
+{
+       int rc;
+
+       /* Recover from a failed assertion pre-reset */
+       rc = efx_mcdi_handle_assertion(efx);
+       if (rc)
+               return rc;
+
+       if (method == RESET_TYPE_WORLD)
+               return efx_mcdi_reset_mc(efx);
+       else
+               return efx_mcdi_reset_port(efx);
+}
+
+static int siena_probe_nvconfig(struct efx_nic *efx)
+{
+       int rc;
+
+       rc = efx_mcdi_get_board_cfg(efx, efx->mac_address, NULL);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int siena_dimension_resources(struct efx_nic *efx)
+{
+       /* There is a small block of internal SRAM dedicated to the
+        * buffer table and descriptor caches. */
+       size_t sram_size = 72 * 1024 * 64 / 8;
+
+       return efx_nic_dimension_resources(efx, sram_size, 512);
+}
+
+static int siena_probe_nic(struct efx_nic *efx)
+{
+       struct siena_nic_data *nic_data;
+       bool already_attached = 0;
+       int rc;
+
+       /* Allocate storage for hardware specific data */
+       nic_data = kzalloc(sizeof(struct siena_nic_data), GFP_KERNEL);
+       if (!nic_data)
+               return -ENOMEM;
+       efx->nic_data = nic_data;
+
+       if (efx_nic_fpga_ver(efx) != 0) {
+               EFX_ERR(efx, "Siena FPGA not supported\n");
+               rc = -ENODEV;
+               goto fail1;
+       }
+
+       efx_mcdi_init(efx);
+
+       /* Recover from a failed assertion before probing */
+       rc = efx_mcdi_handle_assertion(efx);
+       if (rc)
+               goto fail1;
+
+       rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build);
+       if (rc) {
+               EFX_ERR(efx, "Failed to read MCPU firmware version - "
+                       "rc %d\n", rc);
+               goto fail1; /* MCPU absent? */
+       }
+
+       /* Let the BMC know that the driver is now in charge of link and
+        * filter settings. We must do this before we reset the NIC */
+       rc = efx_mcdi_drv_attach(efx, true, &already_attached);
+       if (rc) {
+               EFX_ERR(efx, "Unable to register driver with MCPU\n");
+               goto fail2;
+       }
+       if (already_attached)
+               /* Not a fatal error */
+               EFX_ERR(efx, "Host already registered with MCPU\n");
+
+       /* Now we can reset the NIC */
+       rc = siena_reset_hw(efx, RESET_TYPE_ALL);
+       if (rc) {
+               EFX_ERR(efx, "failed to reset NIC\n");
+               goto fail3;
+       }
+
+       siena_init_wol(efx);
+
+       /* Allocate memory for INT_KER */
+       rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
+       if (rc)
+               goto fail4;
+       BUG_ON(efx->irq_status.dma_addr & 0x0f);
+
+       EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n",
+               (unsigned long long)efx->irq_status.dma_addr,
+               efx->irq_status.addr,
+               (unsigned long long)virt_to_phys(efx->irq_status.addr));
+
+       /* Read in the non-volatile configuration */
+       rc = siena_probe_nvconfig(efx);
+       if (rc == -EINVAL) {
+               EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n");
+               efx->phy_type = PHY_TYPE_NONE;
+               efx->mdio.prtad = MDIO_PRTAD_NONE;
+       } else if (rc) {
+               goto fail5;
+       }
+
+       rc = siena_dimension_resources(efx);
+       if (rc)
+               goto fail6;
+
+       return 0;
+
+fail6:
+fail5:
+       efx_nic_free_buffer(efx, &efx->irq_status);
+fail4:
+fail3:
+       efx_mcdi_drv_attach(efx, false, NULL);
+fail2:
+fail1:
+       kfree(efx->nic_data);
+       return rc;
+}
+
+/* This call performs hardware-specific global initialisation, such as
+ * defining the descriptor cache sizes and number of RSS channels.
+ * It does not set up any buffers, descriptor rings or event queues.
+ */
+static int siena_init_nic(struct efx_nic *efx)
+{
+       efx_oword_t temp;
+       int rc;
+
+       /* Recover from a failed assertion post-reset */
+       rc = efx_mcdi_handle_assertion(efx);
+       if (rc)
+               return rc;
+
+       efx_nic_check_pcie_link(efx, 8, 2);
+
+       /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
+        * descriptors (which is bad).
+        */
+       efx_reado(efx, &temp, FR_AZ_TX_CFG);
+       EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0);
+       EFX_SET_OWORD_FIELD(temp, FRF_CZ_TX_FILTER_EN_BIT, 1);
+       efx_writeo(efx, &temp, FR_AZ_TX_CFG);
+
+       efx_reado(efx, &temp, FR_AZ_RX_CFG);
+       EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0);
+       EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1);
+       efx_writeo(efx, &temp, FR_AZ_RX_CFG);
+
+       if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0)
+               /* No MCDI operation has been defined to set thresholds */
+               EFX_ERR(efx, "ignoring RX flow control thresholds\n");
+
+       /* Enable event logging */
+       rc = efx_mcdi_log_ctrl(efx, true, false, 0);
+       if (rc)
+               return rc;
+
+       /* Set destination of both TX and RX Flush events */
+       EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
+       efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
+
+       EFX_POPULATE_OWORD_1(temp, FRF_CZ_USREV_DIS, 1);
+       efx_writeo(efx, &temp, FR_CZ_USR_EV_CFG);
+
+       efx_nic_init_common(efx);
+       return 0;
+}
+
+static void siena_remove_nic(struct efx_nic *efx)
+{
+       efx_nic_free_buffer(efx, &efx->irq_status);
+
+       siena_reset_hw(efx, RESET_TYPE_ALL);
+
+       /* Relinquish the device back to the BMC */
+       if (efx_nic_has_mc(efx))
+               efx_mcdi_drv_attach(efx, false, NULL);
+
+       /* Tear down the private nic state, and the driverlink nic params */
+       kfree(efx->nic_data);
+       efx->nic_data = NULL;
+}
+
+#define STATS_GENERATION_INVALID ((u64)(-1))
+
+static int siena_try_update_nic_stats(struct efx_nic *efx)
+{
+       u64 *dma_stats;
+       struct efx_mac_stats *mac_stats;
+       u64 generation_start;
+       u64 generation_end;
+       u64 stat_val;
+
+       mac_stats = &efx->mac_stats;
+       dma_stats = (u64 *)efx->stats_buffer.addr;
+
+       generation_end = dma_stats[MC_CMD_MAC_GENERATION_END];
+       if (generation_end == STATS_GENERATION_INVALID)
+               return 0;
+       rmb();
+
+#define MAC_STAT(M, D) \
+       mac_stats->M = dma_stats[MC_CMD_MAC_ ## D]
+
+       MAC_STAT(tx_bytes, TX_BYTES);
+       MAC_STAT(tx_bad_bytes, TX_BAD_BYTES);
+       mac_stats->tx_good_bytes = (mac_stats->tx_bytes -
+                                   mac_stats->tx_bad_bytes);
+       MAC_STAT(tx_packets, TX_PKTS);
+       MAC_STAT(tx_bad, TX_BAD_FCS_PKTS);
+       MAC_STAT(tx_pause, TX_PAUSE_PKTS);
+       MAC_STAT(tx_control, TX_CONTROL_PKTS);
+       MAC_STAT(tx_unicast, TX_UNICAST_PKTS);
+       MAC_STAT(tx_multicast, TX_MULTICAST_PKTS);
+       MAC_STAT(tx_broadcast, TX_BROADCAST_PKTS);
+       MAC_STAT(tx_lt64, TX_LT64_PKTS);
+       MAC_STAT(tx_64, TX_64_PKTS);
+       MAC_STAT(tx_65_to_127, TX_65_TO_127_PKTS);
+       MAC_STAT(tx_128_to_255, TX_128_TO_255_PKTS);
+       MAC_STAT(tx_256_to_511, TX_256_TO_511_PKTS);
+       MAC_STAT(tx_512_to_1023, TX_512_TO_1023_PKTS);
+       MAC_STAT(tx_1024_to_15xx, TX_1024_TO_15XX_PKTS);
+       MAC_STAT(tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS);
+       MAC_STAT(tx_gtjumbo, TX_GTJUMBO_PKTS);
+       mac_stats->tx_collision = 0;
+       MAC_STAT(tx_single_collision, TX_SINGLE_COLLISION_PKTS);
+       MAC_STAT(tx_multiple_collision, TX_MULTIPLE_COLLISION_PKTS);
+       MAC_STAT(tx_excessive_collision, TX_EXCESSIVE_COLLISION_PKTS);
+       MAC_STAT(tx_deferred, TX_DEFERRED_PKTS);
+       MAC_STAT(tx_late_collision, TX_LATE_COLLISION_PKTS);
+       mac_stats->tx_collision = (mac_stats->tx_single_collision +
+                                  mac_stats->tx_multiple_collision +
+                                  mac_stats->tx_excessive_collision +
+                                  mac_stats->tx_late_collision);
+       MAC_STAT(tx_excessive_deferred, TX_EXCESSIVE_DEFERRED_PKTS);
+       MAC_STAT(tx_non_tcpudp, TX_NON_TCPUDP_PKTS);
+       MAC_STAT(tx_mac_src_error, TX_MAC_SRC_ERR_PKTS);
+       MAC_STAT(tx_ip_src_error, TX_IP_SRC_ERR_PKTS);
+       MAC_STAT(rx_bytes, RX_BYTES);
+       MAC_STAT(rx_bad_bytes, RX_BAD_BYTES);
+       mac_stats->rx_good_bytes = (mac_stats->rx_bytes -
+                                   mac_stats->rx_bad_bytes);
+       MAC_STAT(rx_packets, RX_PKTS);
+       MAC_STAT(rx_good, RX_GOOD_PKTS);
+       mac_stats->rx_bad = mac_stats->rx_packets - mac_stats->rx_good;
+       MAC_STAT(rx_pause, RX_PAUSE_PKTS);
+       MAC_STAT(rx_control, RX_CONTROL_PKTS);
+       MAC_STAT(rx_unicast, RX_UNICAST_PKTS);
+       MAC_STAT(rx_multicast, RX_MULTICAST_PKTS);
+       MAC_STAT(rx_broadcast, RX_BROADCAST_PKTS);
+       MAC_STAT(rx_lt64, RX_UNDERSIZE_PKTS);
+       MAC_STAT(rx_64, RX_64_PKTS);
+       MAC_STAT(rx_65_to_127, RX_65_TO_127_PKTS);
+       MAC_STAT(rx_128_to_255, RX_128_TO_255_PKTS);
+       MAC_STAT(rx_256_to_511, RX_256_TO_511_PKTS);
+       MAC_STAT(rx_512_to_1023, RX_512_TO_1023_PKTS);
+       MAC_STAT(rx_1024_to_15xx, RX_1024_TO_15XX_PKTS);
+       MAC_STAT(rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS);
+       MAC_STAT(rx_gtjumbo, RX_GTJUMBO_PKTS);
+       mac_stats->rx_bad_lt64 = 0;
+       mac_stats->rx_bad_64_to_15xx = 0;
+       mac_stats->rx_bad_15xx_to_jumbo = 0;
+       MAC_STAT(rx_bad_gtjumbo, RX_JABBER_PKTS);
+       MAC_STAT(rx_overflow, RX_OVERFLOW_PKTS);
+       mac_stats->rx_missed = 0;
+       MAC_STAT(rx_false_carrier, RX_FALSE_CARRIER_PKTS);
+       MAC_STAT(rx_symbol_error, RX_SYMBOL_ERROR_PKTS);
+       MAC_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS);
+       MAC_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS);
+       MAC_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS);
+       mac_stats->rx_good_lt64 = 0;
+
+       efx->n_rx_nodesc_drop_cnt = dma_stats[MC_CMD_MAC_RX_NODESC_DROPS];
+
+       stat_val = dma_stats[MC_CMD_MAC_RX_LANES01_CHAR_ERR];
+       mac_stats->rx_char_error_lane0 = (stat_val >>  0) & 0xffffffff;
+       mac_stats->rx_char_error_lane1 = (stat_val >> 32) & 0xffffffff;
+       stat_val = dma_stats[MC_CMD_MAC_RX_LANES23_CHAR_ERR];
+       mac_stats->rx_char_error_lane2 = (stat_val >>  0) & 0xffffffff;
+       mac_stats->rx_char_error_lane3 = (stat_val >> 32) & 0xffffffff;
+       stat_val = dma_stats[MC_CMD_MAC_RX_LANES01_DISP_ERR];
+       mac_stats->rx_disp_error_lane0 = (stat_val >>  0) & 0xffffffff;
+       mac_stats->rx_disp_error_lane1 = (stat_val >> 32) & 0xffffffff;
+       stat_val = dma_stats[MC_CMD_MAC_RX_LANES23_DISP_ERR];
+       mac_stats->rx_disp_error_lane2 = (stat_val >>  0) & 0xffffffff;
+       mac_stats->rx_disp_error_lane3 = (stat_val >> 32) & 0xffffffff;
+       MAC_STAT(rx_match_fault, RX_MATCH_FAULT);
+#undef MAC_STAT
+
+       rmb();
+       generation_start = dma_stats[MC_CMD_MAC_GENERATION_START];
+       if (generation_end != generation_start)
+               return -EAGAIN;
+
+       return 0;
+}
+
+static void siena_update_nic_stats(struct efx_nic *efx)
+{
+       while (siena_try_update_nic_stats(efx) == -EAGAIN)
+               cpu_relax();
+}
+
+static void siena_start_nic_stats(struct efx_nic *efx)
+{
+       u64 *dma_stats = (u64 *)efx->stats_buffer.addr;
+
+       dma_stats[MC_CMD_MAC_GENERATION_END] = STATS_GENERATION_INVALID;
+
+       efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr,
+                          MC_CMD_MAC_NSTATS * sizeof(u64), 1, 0);
+}
+
+static void siena_stop_nic_stats(struct efx_nic *efx)
+{
+       efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0);
+}
+
+void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len)
+{
+       struct siena_nic_data *nic_data = efx->nic_data;
+       snprintf(buf, len, "%u.%u.%u.%u",
+                (unsigned int)(nic_data->fw_version >> 48),
+                (unsigned int)(nic_data->fw_version >> 32 & 0xffff),
+                (unsigned int)(nic_data->fw_version >> 16 & 0xffff),
+                (unsigned int)(nic_data->fw_version & 0xffff));
+}
+
+/**************************************************************************
+ *
+ * Wake on LAN
+ *
+ **************************************************************************
+ */
+
+static void siena_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol)
+{
+       struct siena_nic_data *nic_data = efx->nic_data;
+
+       wol->supported = WAKE_MAGIC;
+       if (nic_data->wol_filter_id != -1)
+               wol->wolopts = WAKE_MAGIC;
+       else
+               wol->wolopts = 0;
+       memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+
+static int siena_set_wol(struct efx_nic *efx, u32 type)
+{
+       struct siena_nic_data *nic_data = efx->nic_data;
+       int rc;
+
+       if (type & ~WAKE_MAGIC)
+               return -EINVAL;
+
+       if (type & WAKE_MAGIC) {
+               if (nic_data->wol_filter_id != -1)
+                       efx_mcdi_wol_filter_remove(efx,
+                                                  nic_data->wol_filter_id);
+               rc = efx_mcdi_wol_filter_set_magic(efx, efx->mac_address,
+                                                  &nic_data->wol_filter_id);
+               if (rc)
+                       goto fail;
+
+               pci_wake_from_d3(efx->pci_dev, true);
+       } else {
+               rc = efx_mcdi_wol_filter_reset(efx);
+               nic_data->wol_filter_id = -1;
+               pci_wake_from_d3(efx->pci_dev, false);
+               if (rc)
+                       goto fail;
+       }
+
+       return 0;
+ fail:
+       EFX_ERR(efx, "%s failed: type=%d rc=%d\n", __func__, type, rc);
+       return rc;
+}
+
+
+static void siena_init_wol(struct efx_nic *efx)
+{
+       struct siena_nic_data *nic_data = efx->nic_data;
+       int rc;
+
+       rc = efx_mcdi_wol_filter_get_magic(efx, &nic_data->wol_filter_id);
+
+       if (rc != 0) {
+               /* If it failed, attempt to get into a synchronised
+                * state with MC by resetting any set WoL filters */
+               efx_mcdi_wol_filter_reset(efx);
+               nic_data->wol_filter_id = -1;
+       } else if (nic_data->wol_filter_id != -1) {
+               pci_wake_from_d3(efx->pci_dev, true);
+       }
+}
+
+
+/**************************************************************************
+ *
+ * Revision-dependent attributes used by efx.c and nic.c
+ *
+ **************************************************************************
+ */
+
+struct efx_nic_type siena_a0_nic_type = {
+       .probe = siena_probe_nic,
+       .remove = siena_remove_nic,
+       .init = siena_init_nic,
+       .fini = efx_port_dummy_op_void,
+       .monitor = NULL,
+       .reset = siena_reset_hw,
+       .probe_port = siena_probe_port,
+       .remove_port = siena_remove_port,
+       .prepare_flush = efx_port_dummy_op_void,
+       .update_stats = siena_update_nic_stats,
+       .start_stats = siena_start_nic_stats,
+       .stop_stats = siena_stop_nic_stats,
+       .set_id_led = efx_mcdi_set_id_led,
+       .push_irq_moderation = siena_push_irq_moderation,
+       .push_multicast_hash = siena_push_multicast_hash,
+       .reconfigure_port = efx_mcdi_phy_reconfigure,
+       .get_wol = siena_get_wol,
+       .set_wol = siena_set_wol,
+       .resume_wol = siena_init_wol,
+       .test_registers = siena_test_registers,
+       .test_memory = siena_test_tables,
+       .test_nvram = efx_mcdi_nvram_test_all,
+       .default_mac_ops = &efx_mcdi_mac_operations,
+
+       .revision = EFX_REV_SIENA_A0,
+       .dl_revision = "siena/a0",
+       .mem_map_size = (FR_CZ_MC_TREG_SMEM +
+                        FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS),
+       .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL,
+       .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL,
+       .buf_tbl_base = FR_BZ_BUF_FULL_TBL,
+       .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL,
+       .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR,
+       .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
+       .rx_buffer_padding = 0,
+       .max_interrupt_mode = EFX_INT_MODE_MSIX,
+       .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
+                                  * interrupt handler only supports 32
+                                  * channels */
+       .resources = {
+               .hdr.type = EFX_DL_FALCON_RESOURCES,
+               .rxq_min = 0, .rxq_lim = 1024,
+               .txq_min = 0, .txq_lim = 1024,
+               .evq_int_min = 0, .evq_int_lim = 64,
+               .evq_timer_min = 64, .evq_timer_lim = 1024,
+       },
+#if !defined(EFX_USE_KCOMPAT) || defined(NETIF_F_IPV6_CSUM)
+       .offload_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM,
+#else
+       .offload_features = NETIF_F_HW_CSUM,
+#endif
+       .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT,
+};
index fd6ef618a741ffe66c7908fbaf5cf3cf84a6bf57..8bf4fce0813a8ee53a38b3e1d0baa82ddffa9e31 100644 (file)
@@ -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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 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_SPI_H
  *
  *************************************************************************/
 
-/*
- * Commands common to all known devices.
- *
- */
-
-/* Write status register */
-#define SPI_WRSR 0x01
-
-/* Write data to memory array */
-#define SPI_WRITE 0x02
-
-/* Read data from memory array */
-#define SPI_READ 0x03
-
-/* Reset write enable latch */
-#define SPI_WRDI 0x04
-
-/* Read status register */
-#define SPI_RDSR 0x05
-
-/* Set write enable latch */
-#define SPI_WREN 0x06
-
-/* SST: Enable write to status register */
-#define SPI_SST_EWSR 0x50
-
-/*
- * Status register bits.  Not all bits are supported on all devices.
- *
- */
-
-/* Write-protect pin enabled */
-#define SPI_STATUS_WPEN 0x80
-
-/* Block protection bit 2 */
-#define SPI_STATUS_BP2 0x10
-
-/* Block protection bit 1 */
-#define SPI_STATUS_BP1 0x08
-
-/* Block protection bit 0 */
-#define SPI_STATUS_BP0 0x04
-
-/* State of the write enable latch */
-#define SPI_STATUS_WEN 0x02
-
-/* Device busy flag */
-#define SPI_STATUS_NRDY 0x01
-
-/**************************************************************************
- *
- * Efx SPI devices
- *
- **************************************************************************
- */
+#define SPI_WRSR 0x01          /* Write status register */
+#define SPI_WRITE 0x02         /* Write data to memory array */
+#define SPI_READ 0x03          /* Read data from memory array */
+#define SPI_WRDI 0x04          /* Reset write enable latch */
+#define SPI_RDSR 0x05          /* Read status register */
+#define SPI_WREN 0x06          /* Set write enable latch */
+#define SPI_SST_EWSR 0x50      /* SST: Enable write to status register */
+
+#define SPI_STATUS_WPEN 0x80   /* Write-protect pin enabled */
+#define SPI_STATUS_BP2 0x10    /* Block protection bit 2 */
+#define SPI_STATUS_BP1 0x08    /* Block protection bit 1 */
+#define SPI_STATUS_BP0 0x04    /* Block protection bit 0 */
+#define SPI_STATUS_WEN 0x02    /* State of the write enable latch */
+#define SPI_STATUS_NRDY 0x01   /* Device busy flag */
 
 /**
  * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
  *     This must be a power of two.
  * @block_size:                Write block size (in bytes).
  *     Write commands are limited to blocks with this size and alignment.
- * @read:              Read function for the device
- * @write:             Write function for the device
  */
 struct efx_spi_device {
        int device_id;
@@ -119,68 +59,36 @@ struct efx_spi_device {
        u8 erase_command;
        unsigned int erase_size;
        unsigned int block_size;
-       int (*read) (const struct efx_spi_device *spi,
-                    struct efx_nic *efx, unsigned int command,
-                    int address, void *data, unsigned int len);
-       int (*write) (const struct efx_spi_device *spi,
-                     struct efx_nic *efx, unsigned int command,
-                     int address, const void *data, unsigned int len);
 };
 
-/* Maximum length for SPI read or write through Falcon */
-#define FALCON_SPI_MAX_LEN 16U
-
-/**
- * efx_spi_write_limit - calculate maximum permitted length for write
- * @spi:               SPI device description
- * @start:             Starting address
- *
- * Return the maximum length for a write starting at the given address
- * in the device.
- *
- * SPI writes must not cross block boundaries.  Devices tend
- * to wrap addresses at block boundaries; e.g. trying to write 5 bytes
- * starting at offset 14 with a block size of 16 might write
- * {14,15,0,1,2} rather than {14,15,16,17,18}.
- */
-static inline unsigned int
-efx_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
-{
-       return min(FALCON_SPI_MAX_LEN,
-                  (spi->block_size - (start & (spi->block_size - 1))));
-}
-
-/**
- * efx_spi_read_limit - calculate maximum permitted length for read
- * @spi:               SPI device description
- * @start:             Starting address
- *
- * Return the maximum length for a read starting at the given address
- * in the device.
- */
-static inline unsigned int
-efx_spi_read_limit(const struct efx_spi_device *spi __attribute__ ((unused)),
-                  unsigned int start __attribute__ ((unused)))
-{
-       return FALCON_SPI_MAX_LEN;
-}
+int falcon_spi_cmd(struct efx_nic *efx,
+                  const struct efx_spi_device *spi, unsigned int command,
+                  int address, const void* in, void *out, size_t len);
+int falcon_spi_wait_write(struct efx_nic *efx,
+                         const struct efx_spi_device *spi);
+int falcon_spi_read(struct efx_nic *efx,
+                   const struct efx_spi_device *spi, loff_t start,
+                   size_t len, size_t *retlen, u8 *buffer);
+int falcon_spi_write(struct efx_nic *efx,
+                    const struct efx_spi_device *spi, loff_t start,
+                    size_t len, size_t *retlen, const u8 *buffer);
 
-/**
- * efx_spi_munge_command - adjust command as necessary for given address
- * @spi:               SPI device description
- * @command:           Normal SPI command
- * @address:           Address for command
- *
- * Some devices with 9-bit addresses (e.g. AT25040A EEPROM) use bit 3
- * of the command byte as address bit A8, rather than having a
- * two-byte address.  This function calculates the appropriate command
- * byte for the device, taking this munging into account.
+/*
+ * SFC4000 flash is partitioned into:
+ *     0-0x400       chip and board config (see falcon_hwdefs.h)
+ *     0x400-0x8000  unused (or may contain VPD if EEPROM not present)
+ *     0x8000-end    boot code (mapped to PCI expansion ROM)
+ * SFC4000 small EEPROM (size < 0x400) is used for VPD only.
+ * SFC4000 large EEPROM (size >= 0x400) is partitioned into:
+ *     0-0x400       chip and board config
+ *     configurable  VPD
+ *     0x800-0x1800  boot config
+ * Aside from the chip and board config, all of these are optional and may
+ * be absent or truncated depending on the devices used.
  */
-static inline u8 efx_spi_munge_command(const struct efx_spi_device *spi,
-                                           const u8 command,
-                                           const unsigned int address)
-{
-       return (command | (((address >> 8) & spi->munge_address) << 3));
-}
+#define FALCON_NVCONFIG_END 0x400U
+#define FALCON_FLASH_BOOTCODE_START 0x8000U
+#define EFX_EEPROM_BOOTCONFIG_START 0x800U
+#define EFX_EEPROM_BOOTCONFIG_END 0x1800U
 
 #endif /* EFX_SPI_H */
index 2cb18f3ca384685ac7b5c9514a2704cc9d984907..c6ab73414d0891c7614d9b2121ac67a2b5c454ea 100644 (file)
@@ -1,82 +1,76 @@
 /****************************************************************************
- * Driver for Solarflare 802.3an compliant PHY
- *           (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@solarflare.com>
+ * 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
- ****************************************************************************/
+ */
 
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include "efx.h"
 #include "debugfs.h"
-#include "gmii.h"
 #include "mdio_10g.h"
-#include "falcon.h"
+#include "nic.h"
 #include "phy.h"
-#include "falcon_hwdefs.h"
-#include "boards.h"
-
-/* We expect these MMDs to be in the package */
-/* AN not here as mdio_check_mmds() requires STAT2 support */
-#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
-                                MDIO_MMDREG_DEVS0_PCS    | \
-                                MDIO_MMDREG_DEVS0_PHYXS)
+#include "regs.h"
+#include "workarounds.h"
+#include "selftest.h"
 
-#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) |   \
-                            (1 << LOOPBACK_PCS) |      \
-                            (1 << LOOPBACK_PMAPMD) |   \
-                            (1 << LOOPBACK_NETWORK))
+/* We expect these MMDs to be in the package.  SFT9001 also has a
+ * clause 22 extension MMD, but since it doesn't have all the generic
+ * MMD registers it is pointless to include it here.
+ */
+#define TENXPRESS_REQUIRED_DEVS (MDIO_DEVS_PMAPMD      | \
+                                MDIO_DEVS_PCS          | \
+                                MDIO_DEVS_PHYXS        | \
+                                MDIO_DEVS_AN)
+
+#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) |     \
+                          (1 << LOOPBACK_PCS) |        \
+                          (1 << LOOPBACK_PMAPMD) |     \
+                          (1 << LOOPBACK_PHYXS_WS))
+
+#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) |      \
+                          (1 << LOOPBACK_PHYXS) |      \
+                          (1 << LOOPBACK_PCS) |        \
+                          (1 << LOOPBACK_PMAPMD) |     \
+                          (1 << LOOPBACK_PHYXS_WS))
 
 /* We complain if we fail to see the link partner as 10G capable this many
  * times in a row (must be > 1 as sampling the autoneg. registers is racy)
  */
 #define MAX_BAD_LP_TRIES       (5)
 
-/* SNR operating margin register */
-#define PMA_PMD_SNR_MARGIN_0   (133)
-#define PMA_PMD_SNR_MARGIN_1   (134)
-#define PMA_PMD_SNR_MARGIN_2   (135)
-#define PMA_PMD_SNR_MARGIN_3   (136)
-
 /* Extended control register */
-#define        PMA_PMD_XCONTROL_REG 0xc000
-#define        PMA_PMD_LNPGA_POWERDOWN_LBN 8
-#define        PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
-#define        PMA_PMD_AFE_POWERDOWN_LBN 9
-#define        PMA_PMD_AFE_POWERDOWN_WIDTH 1
-#define        PMA_PMD_DSP_POWERDOWN_LBN 10
-#define        PMA_PMD_DSP_POWERDOWN_WIDTH 1
-#define        PMA_PMD_PHY_POWERDOWN_LBN 11
-#define        PMA_PMD_PHY_POWERDOWN_WI
+#define PMA_PMD_XCONTROL_REG   49152
+#define PMA_PMD_EXT_GMII_EN_LBN        1
+#define PMA_PMD_EXT_GMII_EN_WIDTH 1
+#define PMA_PMD_EXT_CLK_OUT_LBN        2
+#define PMA_PMD_EXT_CLK_OUT_WIDTH 1
+#define PMA_PMD_LNPGA_POWERDOWN_LBN 8  /* SFX7101 only */
+#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
+#define PMA_PMD_EXT_CLK312_LBN 8       /* SFT9001 only */
+#define PMA_PMD_EXT_CLK312_WIDTH 1
+#define PMA_PMD_EXT_LPOWER_LBN  12
+#define PMA_PMD_EXT_LPOWER_WIDTH 1
+#define PMA_PMD_EXT_ROBUST_LBN 14
+#define PMA_PMD_EXT_ROBUST_WIDTH 1
+#define PMA_PMD_EXT_SSR_LBN    15
+#define PMA_PMD_EXT_SSR_WIDTH  1
 
 /* extended status register */
-#define PMA_PMD_XSTATUS_REG 0xc001
+#define PMA_PMD_XSTATUS_REG    49153
+#define PMA_PMD_XSTAT_MDIX_LBN 14
 #define PMA_PMD_XSTAT_FLP_LBN   (12)
 
-
 /* LED control register */
-#define PMA_PMD_LED_CTRL_REG   (0xc007)
+#define PMA_PMD_LED_CTRL_REG   49159
 #define PMA_PMA_LED_ACTIVITY_LBN       (3)
 
 /* LED function override register */
-#define PMA_PMD_LED_OVERR_REG  (0xc009)
+#define PMA_PMD_LED_OVERR_REG  49161
 /* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
 #define PMA_PMD_LED_LINK_LBN   (0)
 #define PMA_PMD_LED_SPEED_LBN  (2)
 #define        PMA_PMD_LED_ON          (1)
 #define        PMA_PMD_LED_OFF         (2)
 #define PMA_PMD_LED_FLASH      (3)
+#define PMA_PMD_LED_MASK       3
 /* All LEDs under hardware control */
-#define PMA_PMD_LED_FULL_AUTO  (0)
+#define SFT9001_PMA_PMD_LED_DEFAULT 0
 /* Green and Amber under hardware control, Red off */
-#define PMA_PMD_LED_DEFAULT    (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
-
-
-/* Self test (BIST) control register */
-#define PMA_PMD_BIST_CTRL_REG  (0xc014)
-#define PMA_PMD_BIST_BER_LBN   (2)     /* Run BER test */
-#define PMA_PMD_BIST_CONT_LBN  (1)     /* Run continuous BIST until cleared */
-#define PMA_PMD_BIST_SINGLE_LBN        (0)     /* Run 1 BIST iteration (self clears) */
-/* Self test status register */
-#define PMA_PMD_BIST_STAT_REG  (0xc015)
-#define PMA_PMD_BIST_ENX_LBN   (3)
-#define PMA_PMD_BIST_PMA_LBN   (2)
-#define PMA_PMD_BIST_RXD_LBN   (1)
-#define PMA_PMD_BIST_AFE_LBN   (0)
-
-/* Special Software reset register */
-#define PMA_PMD_EXT_CTRL_REG 49152
-#define PMA_PMD_EXT_SSR_LBN 15
-
-#define BIST_MAX_DELAY (1000)
-#define BIST_POLL_DELAY        (10)
-
-static const char *bist_names[] = {
-       [PMA_PMD_BIST_AFE_LBN] = "AFE communication",
-       [PMA_PMD_BIST_RXD_LBN] = "RX data path",
-       [PMA_PMD_BIST_PMA_LBN] = "PMA loopback",
-       [PMA_PMD_BIST_ENX_LBN] = "ENX"
-};
+#define SFX7101_PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
 
 /* Identifier registers: each identifier has 4 part number and 2 revision
  * registers starting at one of these addresses */
@@ -125,571 +93,812 @@ static const char *bist_names[] = {
 #define PMA_PMD_DSP_ID_REG      49180
 #define PMA_PMD_FIRMWARE_ID_REG 49186
 
-/* Misc register defines */
-#define PCS_CLOCK_CTRL_REG 0xd801
+#define PMA_PMD_SPEED_ENABLE_REG 49192
+#define PMA_PMD_100TX_ADV_LBN    1
+#define PMA_PMD_100TX_ADV_WIDTH  1
+#define PMA_PMD_1000T_ADV_LBN    2
+#define PMA_PMD_1000T_ADV_WIDTH  1
+#define PMA_PMD_10000T_ADV_LBN   3
+#define PMA_PMD_10000T_ADV_WIDTH 1
+#define PMA_PMD_SPEED_LBN        4
+#define PMA_PMD_SPEED_WIDTH      4
+
+/* Cable diagnostics - SFT9001 only */
+#define PMA_PMD_CDIAG_CTRL_REG  49213
+#define CDIAG_CTRL_IMMED_LBN    15
+#define CDIAG_CTRL_BRK_LINK_LBN 12
+#define CDIAG_CTRL_IN_PROG_LBN  11
+#define CDIAG_CTRL_LEN_UNIT_LBN 10
+#define CDIAG_CTRL_LEN_METRES   1
+#define PMA_PMD_CDIAG_RES_REG   49174
+#define CDIAG_RES_A_LBN         12
+#define CDIAG_RES_B_LBN         8
+#define CDIAG_RES_C_LBN         4
+#define CDIAG_RES_D_LBN         0
+#define CDIAG_RES_WIDTH         4
+#define CDIAG_RES_OPEN          2
+#define CDIAG_RES_OK            1
+#define CDIAG_RES_INVALID       0
+/* Set of 4 registers for pairs A-D */
+#define PMA_PMD_CDIAG_LEN_REG   49175
+
+/* Serdes control registers - SFT9001 only */
+#define PMA_PMD_CSERDES_CTRL_REG 64258
+/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */
+#define PMA_PMD_CSERDES_DEFAULT        0x000f
+
+/* Misc register defines - SFX7101 only */
+#define PCS_CLOCK_CTRL_REG     55297
 #define PLL312_RST_N_LBN 2
 
-#define PCS_SOFT_RST2_REG 0xd806
+#define PCS_SOFT_RST2_REG      55302
 #define SERDES_RST_N_LBN 13
 #define XGXS_RST_N_LBN 12
 
-#define        PCS_TEST_SELECT_REG 0xd807      /* PRM 10.5.8 */
+#define        PCS_TEST_SELECT_REG     55303   /* PRM 10.5.8 */
 #define        CLK312_EN_LBN 3
 
 /* PHYXS registers */
+#define PHYXS_XCONTROL_REG     49152
+#define PHYXS_RESET_LBN                15
+#define PHYXS_RESET_WIDTH      1
+
 #define PHYXS_TEST1         (49162)
 #define LOOPBACK_NEAR_LBN   (8)
 #define LOOPBACK_NEAR_WIDTH (1)
 
 /* Boot status register */
-#define PCS_BOOT_STATUS_REG    (0xd000)
-#define PCS_BOOT_FATAL_ERR_LBN (0)
-#define PCS_BOOT_PROGRESS_LBN  (1)
-#define PCS_BOOT_PROGRESS_WIDTH        (2)
-#define PCS_BOOT_COMPLETE_LBN  (3)
-
-#define PCS_BOOT_MAX_DELAY     (100)
-#define PCS_BOOT_POLL_DELAY    (10)
+#define PCS_BOOT_STATUS_REG            53248
+#define PCS_BOOT_FATAL_ERROR_LBN       0
+#define PCS_BOOT_PROGRESS_LBN          1
+#define PCS_BOOT_PROGRESS_WIDTH                2
+#define PCS_BOOT_PROGRESS_INIT         0
+#define PCS_BOOT_PROGRESS_WAIT_MDIO    1
+#define PCS_BOOT_PROGRESS_CHECKSUM     2
+#define PCS_BOOT_PROGRESS_JUMP         3
+#define PCS_BOOT_DOWNLOAD_WAIT_LBN     3
+#define PCS_BOOT_CODE_STARTED_LBN      4
+
+/* 100M/1G PHY registers */
+#define GPHY_XCONTROL_REG      49152
+#define GPHY_ISOLATE_LBN       10
+#define GPHY_ISOLATE_WIDTH     1
+#define GPHY_DUPLEX_LBN                8
+#define GPHY_DUPLEX_WIDTH      1
+#define GPHY_LOOPBACK_NEAR_LBN 14
+#define GPHY_LOOPBACK_NEAR_WIDTH 1
+
+#define C22EXT_STATUS_REG       49153
+#define C22EXT_STATUS_LINK_LBN  2
+#define C22EXT_STATUS_LINK_WIDTH 1
+
+#define C22EXT_MSTSLV_CTRL                     49161
+#define C22EXT_MSTSLV_CTRL_ADV_1000_HD_LBN     8
+#define C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN     9
+
+#define C22EXT_MSTSLV_STATUS                   49162
+#define C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN    10
+#define C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN    11
 
 #define TENXPRESS_ID_PN_LEN     (8)
 #define TENXPRESS_ID_REV_LEN    (4)
 #define TENXPRESS_ID_LEN        (TENXPRESS_ID_PN_LEN+1+TENXPRESS_ID_REV_LEN)
 
-static const int bist_max = ARRAY_SIZE(bist_names);
-
 /* Time to wait between powering down the LNPGA and turning off the power
  * rails */
 #define LNPGA_PDOWN_WAIT       (HZ / 5)
 
-
-static int crc_error_reset_threshold = 100;
-module_param(crc_error_reset_threshold, int, 0644);
-MODULE_PARM_DESC(crc_error_reset_threshold,
-                "Max number of CRC errors before XAUI reset");
-
 struct tenxpress_phy_data {
-#ifdef CONFIG_SFC_DEBUGFS
-       char phy_snr[4];
-       char phy_afe_id[TENXPRESS_ID_LEN + 1];
-       char phy_dsp_id[TENXPRESS_ID_LEN + 1];
-       char phy_firmware_id[TENXPRESS_ID_LEN + 1];
-       struct efx_nic *efx;
-#endif
-       enum tenxpress_state state;
        enum efx_loopback_mode loopback_mode;
-       atomic_t bad_crc_count;
-       int phy_powered;
-       int tx_disabled;
+       enum efx_phy_mode phy_mode;
        int bad_lp_tries;
 };
 
-static int tenxpress_state_is(struct efx_nic *efx, int state)
+static ssize_t show_phy_short_reach(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
 {
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       return (phy_data != NULL) && (state == phy_data->state);
-}
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       int reg;
 
-void tenxpress_set_state(struct efx_nic *efx,
-                               enum tenxpress_state state)
-{
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       if (phy_data != NULL)
-               phy_data->state = state;
+       reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR);
+       return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT));
 }
 
-void tenxpress_crc_err(struct efx_nic *efx)
+static ssize_t set_phy_short_reach(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t count)
 {
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       if (phy_data != NULL)
-               atomic_inc(&phy_data->bad_crc_count);
-}
-
-#ifdef CONFIG_SFC_DEBUGFS
-
-/* debugfs entries for this PHY */
-static int tenxpress_ber_read(struct seq_file *file, void *data)
-{
-       struct efx_nic *efx = *(struct efx_nic **)data;
-       int reg, ber;
-
-       reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PCS,
-                                MDIO_PCS_10GBT_STATUS2);
-
-       /* Extract the BER */
-       ber = (reg >> MDIO_PCS_10GBT_STATUS2_BER_LBN) &
-               ((1 << MDIO_PCS_10GBT_STATUS2_BER_WIDTH) - 1);
+       struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev));
+       int rc;
+
+       rtnl_lock();
+       if (efx->state != STATE_RUNNING)
+               rc = -EBUSY;
+       else {
+               efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR,
+                                 MDIO_PMA_10GBT_TXPWR_SHORT,
+                                 count != 0 && *buf != '0');
+               rc = efx_reconfigure_port(efx);
+       }
+       rtnl_unlock();
 
-       return seq_printf(file, "%d", ber);
+       return rc < 0 ? rc : (ssize_t)count;
 }
 
+static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
+                  set_phy_short_reach);
 
-static int tenxpress_snr_read(struct seq_file *file, void *data)
+int sft9001_wait_boot(struct efx_nic *efx)
 {
-       struct tenxpress_phy_data *phy_data = NULL;
-       struct efx_nic *efx;
-       int lane = *(char *) data;
-       int reg, snr;
-
-       EFX_BUG_ON_PARANOID(lane < 0 || lane >= 4);
-       phy_data = container_of(data, struct tenxpress_phy_data, phy_snr[lane]);
-       efx = phy_data->efx;
-
-       reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                MDIO_MMD_PMAPMD, PMA_PMD_SNR_MARGIN_0 + lane);
-
-       /* Convert from SNR margin to SNR to match phychk output */
-       snr = (reg - 0x8000 + 238);
-
-       return seq_printf(file, "%d.%d", snr / 10, snr % 10);
-}
+       unsigned long timeout = jiffies + HZ + 1;
+       int boot_stat;
 
+       for (;;) {
+               boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS,
+                                         PCS_BOOT_STATUS_REG);
+               if (boot_stat >= 0) {
+                       EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
+                       switch (boot_stat &
+                               ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
+                                (3 << PCS_BOOT_PROGRESS_LBN) |
+                                (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
+                                (1 << PCS_BOOT_CODE_STARTED_LBN))) {
+                       case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
+                             (PCS_BOOT_PROGRESS_CHECKSUM <<
+                              PCS_BOOT_PROGRESS_LBN)):
+                       case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
+                             (PCS_BOOT_PROGRESS_INIT <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
+                               return -EINVAL;
+                       case ((PCS_BOOT_PROGRESS_WAIT_MDIO <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
+                               return (efx->phy_mode & PHY_MODE_SPECIAL) ?
+                                       0 : -EIO;
+                       case ((PCS_BOOT_PROGRESS_JUMP <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_CODE_STARTED_LBN)):
+                       case ((PCS_BOOT_PROGRESS_JUMP <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
+                             (1 << PCS_BOOT_CODE_STARTED_LBN)):
+                               return (efx->phy_mode & PHY_MODE_SPECIAL) ?
+                                       -EIO : 0;
+                       default:
+                               if (boot_stat & (1 << PCS_BOOT_FATAL_ERROR_LBN))
+                                       return -EIO;
+                               break;
+                       }
+               }
 
-static struct efx_debugfs_parameter debug_entries[] = {
-       EFX_PER_LANE_PARAMETER("phy_lane", "_snr",
-                              struct tenxpress_phy_data, phy_snr, char,
-                              tenxpress_snr_read),
-       EFX_NAMED_PARAMETER(phy_ber, struct tenxpress_phy_data, efx,
-                           struct efx_nic *, tenxpress_ber_read),
-       EFX_STRING_PARAMETER(struct tenxpress_phy_data, phy_afe_id),
-       EFX_STRING_PARAMETER(struct tenxpress_phy_data, phy_dsp_id),
-       EFX_STRING_PARAMETER(struct tenxpress_phy_data, phy_firmware_id),
-       {NULL}
-};
+               if (time_after_eq(jiffies, timeout))
+                       return -ETIMEDOUT;
 
-static void tenxpress_phy_get_id(struct efx_nic *efx,
-                                char *id_buf, int id_addr)
-{
-       int i, reg;
-       char ch;
-
-       for (i = TENXPRESS_ID_PN_LEN / 2 - 1; i >= 0; --i) {
-               reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                        MDIO_MMD_PMAPMD, id_addr + i);
-               ch = reg & 0xFF;
-               *id_buf++ = ch ? ch : ' ';
-               ch = (reg & 0xFF00) >> 8;
-               *id_buf++ = ch ? ch : ' ';
-       }
-       *id_buf++ = ' ';
-       for (i = TENXPRESS_ID_REV_LEN / 2 - 1; i >= 0; --i) {
-               reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                        MDIO_MMD_PMAPMD,
-                                        id_addr + TENXPRESS_ID_PN_LEN / 2 + i);
-               ch = reg & 0xFF;
-               *id_buf++ = ch ? ch : ' ';
-               ch = (reg & 0xFF00) >> 8;
-               *id_buf++ = ch ? ch : ' ';
+               msleep(50);
        }
 }
 
-static int tenxpress_debugfs_init(struct efx_nic *efx)
+/* Initialise the part post power on reset or software special reset */
+static int tenxpress_init(struct efx_nic *efx)
 {
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       int lane, rc;
-
-       for (lane = 0; lane < 4; lane++)
-               phy_data->phy_snr[lane] = lane;
+       int reg;
 
-       phy_data->efx = efx;
-       rc = efx_extend_debugfs_port(efx, efx->phy_data,
-                                    debug_entries);
-       if (rc < 0)
-               return rc;
+       if (efx->phy_type == PHY_TYPE_SFX7101) {
+               /* Enable 312.5 MHz clock */
+               efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG,
+                              1 << CLK312_EN_LBN);
+       } else {
+               /* Enable 312.5 MHz clock and GMII */
+               reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
+               reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) |
+                       (1 << PMA_PMD_EXT_CLK_OUT_LBN) |
+                       (1 << PMA_PMD_EXT_CLK312_LBN) |
+                       (1 << PMA_PMD_EXT_ROBUST_LBN));
+
+               efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
+               efx_mdio_set_flag(efx, MDIO_MMD_C22EXT,
+                                 GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN,
+                                 false);
+       }
 
-       tenxpress_phy_get_id(efx, phy_data->phy_afe_id,
-                            PMA_PMD_AFE_ID_REG);
-       tenxpress_phy_get_id(efx, phy_data->phy_dsp_id,
-                            PMA_PMD_DSP_ID_REG);
-       tenxpress_phy_get_id(efx, phy_data->phy_firmware_id,
-                            PMA_PMD_FIRMWARE_ID_REG);
+       /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
+       if (efx->phy_type == PHY_TYPE_SFX7101) {
+               efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG,
+                                 1 << PMA_PMA_LED_ACTIVITY_LBN, true);
+               efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG,
+                              SFX7101_PMA_PMD_LED_DEFAULT);
+       }
 
        return 0;
 }
 
-#endif /* CONFIG_SFC_DEBUGFS */
-
-/* Check that the C166 has booted successfully */
-static int tenxpress_phy_check(struct efx_nic *efx)
+static int tenxpress_phy_probe(struct efx_nic *efx)
 {
-       int phy_id = efx->mii.phy_id;
-       int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
-       int boot_stat;
+       struct tenxpress_phy_data *phy_data;
+       int rc;
 
-       /* Wait for the boot to complete (or not) */
-       while (count) {
-               boot_stat = mdio_clause45_read(efx, phy_id,
-                                              MDIO_MMD_PCS,
-                                              PCS_BOOT_STATUS_REG);
-               if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
-                       break;
-               count--;
-               udelay(PCS_BOOT_POLL_DELAY);
+       /* Allocate phy private storage */
+       phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+       if (!phy_data)
+               return -ENOMEM;
+       efx->phy_data = phy_data;
+       phy_data->phy_mode = efx->phy_mode;
+
+       /* Create any special files */
+       if (efx->phy_type == PHY_TYPE_SFT9001B) {
+               rc = device_create_file(&efx->pci_dev->dev,
+                                       &dev_attr_phy_short_reach);
+               if (rc)
+                       goto fail;
        }
 
-       if (!count) {
-               EFX_ERR(efx, "%s: PHY boot timed out. Last status "
-                       "%x\n", __func__,
-                       (boot_stat >> PCS_BOOT_PROGRESS_LBN) &
-                       ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
-               return -ETIMEDOUT;
-       }
+       if (efx->phy_type == PHY_TYPE_SFX7101) {
+               efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+               efx->mdio.mode_support = MDIO_SUPPORTS_C45;
 
-       return 0;
-}
+               efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+               efx->startup_loopback_mode = LOOPBACK_PCS;
 
-static void tenxpress_reset_xaui(struct efx_nic *efx);
+               strlcpy(efx->phy_name, "SFX7101 10GBASE-T",
+                       sizeof(efx->phy_name));
 
-/* Initialise the part post power on reset or software special reset */
-static int tenxpress_init(struct efx_nic *efx)
-{
-       int rc, reg;
+               efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+                                        ADVERTISED_10000baseT_Full);
+       } else {
+               efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS;
+               efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
 
-       /* Turn on the clock  */
-       reg = (1 << CLK312_EN_LBN);
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+               efx->loopback_modes = (SFT9001_LOOPBACKS |
+                                      FALCON_XMAC_LOOPBACKS | 
+                                      FALCON_GMAC_LOOPBACKS);
+               efx->startup_loopback_mode = LOOPBACK_PCS;
 
-       rc = tenxpress_phy_check(efx);
-       if (rc < 0)
-               return rc;
+               strlcpy(efx->phy_name, "SFT9001 100/1000/10GBASE-T",
+                       sizeof(efx->phy_name));
 
-       /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
-       reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
-       reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_LED_CTRL_REG, reg);
+               efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg |
+                                        ADVERTISED_10000baseT_Full |
+                                        ADVERTISED_1000baseT_Full |
+                                        ADVERTISED_100baseT_Full);
+       }
 
-       reg = PMA_PMD_LED_DEFAULT;
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_LED_OVERR_REG, reg);
+       return 0;
 
+fail_devattr:
+       if (efx->phy_type == PHY_TYPE_SFT9001B)
+               device_remove_file(&efx->pci_dev->dev,
+                                  &dev_attr_phy_short_reach);
+fail:
+       kfree(efx->phy_data);
+       efx->phy_data = NULL;
        return rc;
 }
 
 static int tenxpress_phy_init(struct efx_nic *efx)
 {
-       struct tenxpress_phy_data *phy_data;
-       int rc = 0;
-
-       phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
-       efx->phy_data = phy_data;
-       phy_data->phy_powered = efx->phy_powered;
+       int rc;
+
+       falcon_board(efx)->type->init_phy(efx);
+
+       if (!(efx->phy_mode & PHY_MODE_SPECIAL)) {
+               if (efx->phy_type == PHY_TYPE_SFT9001A) {
+                       int reg;
+                       reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
+                                           PMA_PMD_XCONTROL_REG);
+                       reg |= (1 << PMA_PMD_EXT_SSR_LBN);
+                       efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+                                      PMA_PMD_XCONTROL_REG, reg);
+                       mdelay(200);
+               }
 
-       tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
+               rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
+               if (rc < 0)
+                       return rc;
 
-       rc = mdio_clause45_wait_reset_mmds(efx,
-                                          TENXPRESS_REQUIRED_DEVS);
-       if (rc < 0)
-               goto fail;
-
-       rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
-       if (rc < 0)
-               goto fail;
+               rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+               if (rc < 0)
+                       return rc;
+       }
 
        rc = tenxpress_init(efx);
        if (rc < 0)
-               goto fail;
+               return rc;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       rc = tenxpress_debugfs_init(efx);
-       if (rc < 0)
-               goto fail;
-#endif
+       /* Reinitialise flow control settings */
+       efx_link_set_wanted_fc(efx, efx->wanted_fc);
+       efx_mdio_an_reconfigure(efx);
 
        schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
 
-       /* Let XGXS and SerDes out of reset and resets 10XPress */
+       /* Let XGXS and SerDes out of reset */
        falcon_reset_xaui(efx);
 
        return 0;
-
- fail:
-       kfree(efx->phy_data);
-       efx->phy_data = NULL;
-       return rc;
 }
 
+/* Perform a "special software reset" on the PHY. The caller is
+ * responsible for saving and restoring the PHY hardware registers
+ * properly, and masking/unmasking LASI */
 static int tenxpress_special_reset(struct efx_nic *efx)
 {
        int rc, reg;
 
-       EFX_TRACE(efx, "%s\n", __func__);
+       /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
+        * a special software reset can glitch the XGMAC sufficiently for stats
+        * requests to fail. */
+       falcon_stop_nic_stats(efx);
 
        /* Initiate reset */
-       reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG);
+       reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
        reg |= (1 << PMA_PMD_EXT_SSR_LBN);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_EXT_CTRL_REG, reg);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
 
-       msleep(200);
+       mdelay(200);
 
        /* Wait for the blocks to come out of reset */
-       rc = mdio_clause45_wait_reset_mmds(efx,
-                                          TENXPRESS_REQUIRED_DEVS);
+       rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS);
        if (rc < 0)
-               return rc;
+               goto out;
 
        /* Try and reconfigure the device */
        rc = tenxpress_init(efx);
        if (rc < 0)
-               return rc;
+               goto out;
 
-       return 0;
+       /* Wait for the XGXS state machine to churn */
+       mdelay(10);
+out:
+       falcon_start_nic_stats(efx);
+       return rc;
 }
 
-static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
+static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok)
 {
        struct tenxpress_phy_data *pd = efx->phy_data;
+       bool bad_lp;
        int reg;
 
+       if (link_ok) {
+               bad_lp = false;
+       } else {
+               /* Check that AN has started but not completed. */
+               reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1);
+               if (!(reg & MDIO_AN_STAT1_LPABLE))
+                       return; /* LP status is unknown */
+               bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE);
+               if (bad_lp)
+                       pd->bad_lp_tries++;
+       }
+
        /* Nothing to do if all is well and was previously so. */
-       if (!(bad_lp || pd->bad_lp_tries))
+       if (!pd->bad_lp_tries)
                return;
 
-       reg = mdio_clause45_read(efx, efx->mii.phy_id,
-                                MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
-
-       if (bad_lp)
-               pd->bad_lp_tries++;
-       else
-               pd->bad_lp_tries = 0;
-
-       if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
-               pd->bad_lp_tries = 0;   /* Restart count */
-               reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
-               reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
-               EFX_ERR(efx, "This NIC appears to be plugged into"
-                       " a port that is not 10GBASE-T capable.\n"
-                       " This PHY is 10GBASE-T ONLY, so no link can"
-                       " be established.\n");
-       } else {
-               reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
+       /* Use the RX (red) LED as an error indicator once we've seen AN
+        * failure several times in a row, and also log a message. */
+       if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
+               reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
+                                   PMA_PMD_LED_OVERR_REG);
+               reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN);
+               if (!bad_lp) {
+                       reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN;
+               } else {
+                       reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN;
+                       EFX_ERR(efx, "appears to be plugged into a port"
+                               " that is not 10GBASE-T capable. The PHY"
+                               " supports 10GBASE-T ONLY, so no link can"
+                               " be established\n");
+               }
+               efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+                              PMA_PMD_LED_OVERR_REG, reg);
+               pd->bad_lp_tries = bad_lp;
        }
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_LED_OVERR_REG, reg);
 }
 
-/* Check link status and return a boolean OK value. If the link is NOT
- * OK we have a quick rummage round to see if we appear to be plugged
- * into a non-10GBT port and if so warn the user that they won't get
- * link any time soon as we are 10GBT only, unless caller specified
- * not to do this check (it isn't useful in loopback) */
-static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
+static bool sfx7101_link_ok(struct efx_nic *efx)
 {
-       int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
-
-       if (ok) {
-               tenxpress_set_bad_lp(efx, 0);
-       } else if (check_lp) {
-               /* Are we plugged into the wrong sort of link? */
-               int bad_lp = 0;
-               int phy_id = efx->mii.phy_id;
-               int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
-                                                MDIO_AN_STATUS);
-               int xphy_stat = mdio_clause45_read(efx, phy_id,
-                                                  MDIO_MMD_PMAPMD,
-                                                  PMA_PMD_XSTATUS_REG);
-               /* Are we plugged into anything that sends FLPs? If
-                * not we can't distinguish between not being plugged
-                * in and being plugged into a non-AN antique. The FLP
-                * bit has the advantage of not clearing when autoneg
-                * restarts. */
-               if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
-                       tenxpress_set_bad_lp(efx, 0);
-                       return ok;
-               }
+       return efx_mdio_links_ok(efx,
+                                MDIO_DEVS_PMAPMD |
+                                MDIO_DEVS_PCS |
+                                MDIO_DEVS_PHYXS);
+}
 
-               /* If it can do 10GBT it must be XNP capable */
-               bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
-               if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
-                       bad_lp = !(mdio_clause45_read(efx, phy_id,
-                                       MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
-                                       (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
-               }
-               tenxpress_set_bad_lp(efx, bad_lp);
+static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       u32 reg;
+
+       if (efx_phy_mode_disabled(efx->phy_mode))
+               return false;
+       else if (efx->loopback_mode == LOOPBACK_GPHY)
+               return true;
+       else if (efx->loopback_mode)
+               return efx_mdio_links_ok(efx,
+                                        MDIO_DEVS_PMAPMD |
+                                        MDIO_DEVS_PHYXS);
+
+       /* We must use the same definition of link state as LASI,
+        * otherwise we can miss a link state transition
+        */
+       if (ecmd->speed == 10000) {
+               reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
+               return reg & MDIO_PCS_10GBRT_STAT1_BLKLK;
+       } else {
+               reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG);
+               return reg & (1 << C22EXT_STATUS_LINK_LBN);
        }
-       return ok;
 }
 
-static void tenxpress_phyxs_loopback(struct efx_nic *efx)
+static void tenxpress_ext_loopback(struct efx_nic *efx)
 {
-       int phy_id = efx->mii.phy_id;
-       int ctrl1, ctrl2;
+       efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, PHYXS_TEST1,
+                         1 << LOOPBACK_NEAR_LBN,
+                         efx->loopback_mode == LOOPBACK_PHYXS);
+       if (efx->phy_type != PHY_TYPE_SFX7101)
+               efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG,
+                                 1 << GPHY_LOOPBACK_NEAR_LBN,
+                                 efx->loopback_mode == LOOPBACK_GPHY);
+}
 
-       ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
-                                          PHYXS_TEST1);
-       if (efx->loopback_mode == LOOPBACK_PHYXS)
-               ctrl2 |= (1 << LOOPBACK_NEAR_LBN);
+static void tenxpress_low_power(struct efx_nic *efx)
+{
+       if (efx->phy_type == PHY_TYPE_SFX7101)
+               efx_mdio_set_mmds_lpower(
+                       efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER),
+                       TENXPRESS_REQUIRED_DEVS);
        else
-               ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN);
-       if (ctrl1 != ctrl2)
-               mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
-                                   PHYXS_TEST1, ctrl2);
+               efx_mdio_set_flag(
+                       efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG,
+                       1 << PMA_PMD_EXT_LPOWER_LBN,
+                       !!(efx->phy_mode & PHY_MODE_LOW_POWER));
 }
 
-static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+static int tenxpress_phy_reconfigure(struct efx_nic *efx)
 {
        struct tenxpress_phy_data *phy_data = efx->phy_data;
-       int loop_change = LOOPBACK_OUT_OF(phy_data, efx,
-                                         TENXPRESS_LOOPBACKS);
+       bool phy_mode_change, loop_reset;
 
-       if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
-               return;
+       if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) {
+               phy_data->phy_mode = efx->phy_mode;
+               return 0;
+       }
+
+       phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL &&
+                          phy_data->phy_mode != PHY_MODE_NORMAL);
+       loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) ||
+                     LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY));
+
+       if (loop_reset || phy_mode_change) {
+               tenxpress_special_reset(efx);
 
-       /* When coming out of transmit disable, coming out of low power
-        * mode, or moving out of any PHY internal loopback mode,
-        * perform a special software reset */
-       if (((efx->phy_powered && !efx->tx_disabled) &&
-            (!phy_data->phy_powered || phy_data->tx_disabled)) ||
-           loop_change) {
-               (void) tenxpress_special_reset(efx);
-               falcon_reset_xaui(efx);
+               /* Reset XAUI if we were in 10G, and are staying
+                * in 10G. If we're moving into and out of 10G
+                * then xaui will be reset anyway */
+               if (EFX_IS10G(efx))
+                       falcon_reset_xaui(efx);
        }
 
-       mdio_clause45_transmit_disable(efx, efx->tx_disabled);
-       mdio_clause45_phy_reconfigure(efx);
-       tenxpress_phyxs_loopback(efx);
+       tenxpress_low_power(efx);
+       efx_mdio_transmit_disable(efx);
+       efx_mdio_phy_reconfigure(efx);
+       tenxpress_ext_loopback(efx);
+       efx_mdio_an_reconfigure(efx);
 
-       phy_data->tx_disabled = efx->tx_disabled;
        phy_data->loopback_mode = efx->loopback_mode;
-       phy_data->phy_powered = efx->phy_powered;
-       efx->link_up = tenxpress_link_ok(efx, 0);
-       efx->link_options = GM_LPA_10000FULL;
-}
+       phy_data->phy_mode = efx->phy_mode;
 
-static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
-{
-       /* Nothing done here - LASI interrupts aren't reliable so poll  */
+       return 0;
 }
 
+static void
+tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd);
 
-/* Poll PHY for interrupt */
-static int tenxpress_phy_check_hw(struct efx_nic *efx)
+/* Poll for link state changes */
+static bool tenxpress_phy_poll(struct efx_nic *efx)
 {
-       struct tenxpress_phy_data *phy_data = efx->phy_data;
-       int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
-       int link_ok, rc = 0;
+       struct efx_link_state old_state = efx->link_state;
+
+       if (efx->phy_type == PHY_TYPE_SFX7101) {
+               efx->link_state.up = sfx7101_link_ok(efx);
+               efx->link_state.speed = 10000;
+               efx->link_state.fd = true;
+               efx->link_state.fc = efx_mdio_get_pause(efx);
 
-       link_ok = phy_up && tenxpress_link_ok(efx, 1);
+               sfx7101_check_bad_lp(efx, efx->link_state.up);
+       } else {
+               struct ethtool_cmd ecmd;
 
-       if (link_ok != efx->link_up)
-               efx->mac_op->fake_phy_event(efx);
+               /* Check the LASI alarm first */
+               if (efx->loopback_mode == LOOPBACK_NONE &&
+                   !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) &
+                     MDIO_PMA_LASI_LSALARM))
+                       return false;
 
-       /* Nothing to check if we've already shut down the PHY */
-       if (!phy_up)
-               return 0;
+               tenxpress_get_settings(efx, &ecmd);
 
-       if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
-               EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
-               falcon_reset_xaui(efx);
-               atomic_set(&phy_data->bad_crc_count, 0);
+               efx->link_state.up = sft9001_link_ok(efx, &ecmd);
+               efx->link_state.speed = ecmd.speed;
+               efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL);
+               efx->link_state.fc = efx_mdio_get_pause(efx);
        }
 
-       rc = efx->board_info.monitor(efx);
-       if (rc)
-               efx->link_up = 0;
-
-       return rc;
+       return !efx_link_state_equal(&efx->link_state, &old_state);
 }
 
-static void tenxpress_phy_fini(struct efx_nic *efx)
+static void sfx7101_phy_fini(struct efx_nic *efx)
 {
        int reg;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       efx_trim_debugfs_port(efx, debug_entries);
-#endif
        /* Power down the LNPGA */
        reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_XCONTROL_REG, reg);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg);
 
-       /* Waiting here ensures that the board fini, which can turn off the
-        * power to the PHY, won't get run until the LNPGA powerdown has been
-        * given long enough to complete. */
+       /* Waiting here ensures that the board fini, which can turn
+        * off the power to the PHY, won't get run until the LNPGA
+        * powerdown has been given long enough to complete. */
        schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+}
+
+static void tenxpress_phy_remove(struct efx_nic *efx)
+{
+       if (efx->phy_type == PHY_TYPE_SFT9001B)
+               device_remove_file(&efx->pci_dev->dev,
+                                  &dev_attr_phy_short_reach);
 
        kfree(efx->phy_data);
        efx->phy_data = NULL;
 }
 
 
-/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
- * (which probably aren't wired anyway) are left in AUTO mode */
-void tenxpress_phy_blink(struct efx_nic *efx, int blink)
+/* Override the RX, TX and link LEDs */
+void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
 {
        int reg;
 
-       if (blink)
-               reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
-                       (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
-                       (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
-       else
-               reg = PMA_PMD_LED_DEFAULT;
+       switch (mode) {
+       case EFX_LED_OFF:
+               reg = (PMA_PMD_LED_OFF << PMA_PMD_LED_TX_LBN) |
+                       (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) |
+                       (PMA_PMD_LED_OFF << PMA_PMD_LED_LINK_LBN);
+               break;
+       case EFX_LED_ON:
+               reg = (PMA_PMD_LED_ON << PMA_PMD_LED_TX_LBN) |
+                       (PMA_PMD_LED_ON << PMA_PMD_LED_RX_LBN) |
+                       (PMA_PMD_LED_ON << PMA_PMD_LED_LINK_LBN);
+               break;
+       default:
+               if (efx->phy_type == PHY_TYPE_SFX7101)
+                       reg = SFX7101_PMA_PMD_LED_DEFAULT;
+               else
+                       reg = SFT9001_PMA_PMD_LED_DEFAULT;
+               break;
+       }
 
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_LED_OVERR_REG, reg);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg);
 }
 
-static void tenxpress_reset_xaui(struct efx_nic *efx)
+static const char *const sfx7101_test_names[] = {
+       "bist"
+};
+
+static const char *sfx7101_test_name(struct efx_nic *efx, unsigned int index)
 {
-       int phy = efx->mii.phy_id;
-       int clk_ctrl, test_select, soft_rst2;
+       if (index < ARRAY_SIZE(sfx7101_test_names))
+               return sfx7101_test_names[index];
+       return NULL;
+}
 
-       /* Real work is done on clock_ctrl other resets are thought to be
-        * optional but make the reset more reliable
-        */
+static int
+sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
+{
+       int rc;
+
+       if (!(flags & ETH_TEST_FL_OFFLINE))
+               return 0;
+
+       /* BIST is automatically run after a special software reset */
+       rc = tenxpress_special_reset(efx);
+       results[0] = rc ? -1 : 1;
+
+       efx_mdio_an_reconfigure(efx);
 
-       /* Read */
-       clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-                                     PCS_CLOCK_CTRL_REG);
-       test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-                                        PCS_TEST_SELECT_REG);
-       soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-                                      PCS_SOFT_RST2_REG);
-
-       /* Put in reset */
-       test_select &= ~(1 << CLK312_EN_LBN);
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           PCS_TEST_SELECT_REG, test_select);
-
-       soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           PCS_SOFT_RST2_REG, soft_rst2);
-
-       clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           PCS_CLOCK_CTRL_REG, clk_ctrl);
-       udelay(10);
-
-       /* Remove reset */
-       clk_ctrl |= (1 << PLL312_RST_N_LBN);
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           PCS_CLOCK_CTRL_REG, clk_ctrl);
-       udelay(10);
-
-       soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           PCS_SOFT_RST2_REG, soft_rst2);
-       udelay(10);
-
-       test_select |= (1 << CLK312_EN_LBN);
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           PCS_TEST_SELECT_REG, test_select);
-       udelay(10);
+       return rc;
+}
+
+static const char *const sft9001_test_names[] = {
+       "bist",
+       "cable.pairA.status",
+       "cable.pairB.status",
+       "cable.pairC.status",
+       "cable.pairD.status",
+       "cable.pairA.length",
+       "cable.pairB.length",
+       "cable.pairC.length",
+       "cable.pairD.length",
+};
+
+static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index)
+{
+       if (index < ARRAY_SIZE(sft9001_test_names))
+               return sft9001_test_names[index];
+       return NULL;
+}
+
+static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
+{
+       int rc = 0, rc2, i, ctrl_reg, res_reg;
+
+       /* Initialise cable diagnostic results to unknown failure */
+       for (i = 1; i < 9; ++i)
+               results[i] = -1;
+
+       /* Run cable diagnostics; wait up to 5 seconds for them to complete.
+        * A cable fault is not a self-test failure, but a timeout is. */
+       ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) |
+                   (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
+       if (flags & ETH_TEST_FL_OFFLINE) {
+               /* Break the link in order to run full diagnostics.  We
+                * must reset the PHY to resume normal service. */
+               ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN);
+       }
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG,
+                      ctrl_reg);
+       i = 0;
+       while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) &
+              (1 << CDIAG_CTRL_IN_PROG_LBN)) {
+               if (++i == 50) {
+                       rc = -ETIMEDOUT;
+                       goto out;
+               }
+               msleep(100);
+       }
+       res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG);
+       for (i = 0; i < 4; i++) {
+               int pair_res =
+                       (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH))
+                       & ((1 << CDIAG_RES_WIDTH) - 1);
+               int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD,
+                                           PMA_PMD_CDIAG_LEN_REG + i);
+               if (pair_res == CDIAG_RES_OK)
+                       results[1 + i] = 1;
+               else if (pair_res == CDIAG_RES_INVALID)
+                       results[1 + i] = -1;
+               else
+                       results[1 + i] = -pair_res;
+               if (pair_res != CDIAG_RES_INVALID &&
+                   pair_res != CDIAG_RES_OPEN &&
+                   len_reg != 0xffff)
+                       results[5 + i] = len_reg;
+       }
+
+out:
+       if (flags & ETH_TEST_FL_OFFLINE) {
+               /* Reset, running the BIST and then resuming normal service. */
+               rc2 = tenxpress_special_reset(efx);
+               results[0] = rc2 ? -1 : 1;
+               if (!rc)
+                       rc = rc2;
+
+               efx_mdio_an_reconfigure(efx);
+       }
+
+       return rc;
+}
+
+static void
+tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       u32 adv = 0, lpa = 0;
+       int reg;
+
+       if (efx->phy_type != PHY_TYPE_SFX7101) {
+               reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL);
+               if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN))
+                       adv |= ADVERTISED_1000baseT_Full;
+               reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS);
+               if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN))
+                       lpa |= ADVERTISED_1000baseT_Half;
+               if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN))
+                       lpa |= ADVERTISED_1000baseT_Full;
+       }
+       reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
+       if (reg & MDIO_AN_10GBT_CTRL_ADV10G)
+               adv |= ADVERTISED_10000baseT_Full;
+       reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
+       if (reg & MDIO_AN_10GBT_STAT_LP10G)
+               lpa |= ADVERTISED_10000baseT_Full;
+
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_NEED_MDIO45_FLOW_CONTROL_HACKS)
+       /* Old versions of the intree mdio45 layer don't set the pause
+        * capabilities in the ecmd structure properly */
+       {
+               const struct mdio_if_info *mdio = &efx->mdio;
+               u32 reg;
+
+               reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN,
+                                     MDIO_AN_ADVERTISE);
+               if (reg & ADVERTISE_PAUSE_CAP)
+                       adv |= ADVERTISED_Pause;
+               if (reg & ADVERTISE_PAUSE_ASYM)
+                       adv |= ADVERTISED_Asym_Pause;
+       }
+#endif
+
+       mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
+
+       if (efx->phy_type != PHY_TYPE_SFX7101) {
+               ecmd->supported |= (SUPPORTED_100baseT_Full |
+                                   SUPPORTED_1000baseT_Full);
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_ETHTOOL_ETH_TP_MDIX)
+               if (ecmd->speed != SPEED_10000) {
+                       ecmd->eth_tp_mdix =
+                               (efx_mdio_read(efx, MDIO_MMD_PMAPMD,
+                                              PMA_PMD_XSTATUS_REG) &
+                                (1 << PMA_PMD_XSTAT_MDIX_LBN))
+                               ? ETH_TP_MDI_X : ETH_TP_MDI;
+               }
+#endif
+       }
+
+       /* In loopback, the PHY automatically brings up the correct interface,
+        * but doesn't advertise the correct speed. So override it */
+       if (efx->loopback_mode == LOOPBACK_GPHY)
+               ecmd->speed = SPEED_1000;
+       else if (LOOPBACK_EXTERNAL(efx))
+               ecmd->speed = SPEED_10000;
+}
+
+static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       if (!ecmd->autoneg)
+               return -EINVAL;
+
+       return efx_mdio_set_settings(efx, ecmd);
+}
+
+static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising)
+{
+       efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+                         MDIO_AN_10GBT_CTRL_ADV10G,
+                         advertising & ADVERTISED_10000baseT_Full);
 }
 
+static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising)
+{
+       efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL,
+                         1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN,
+                         advertising & ADVERTISED_1000baseT_Full);
+       efx_mdio_set_flag(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+                         MDIO_AN_10GBT_CTRL_ADV10G,
+                         advertising & ADVERTISED_10000baseT_Full);
+}
+
+struct efx_phy_operations falcon_sfx7101_phy_ops = {
+       .probe            = tenxpress_phy_probe,
+       .init             = tenxpress_phy_init,
+       .reconfigure      = tenxpress_phy_reconfigure,
+       .poll             = tenxpress_phy_poll,
+       .fini             = sfx7101_phy_fini,
+       .remove           = tenxpress_phy_remove,
+       .get_settings     = tenxpress_get_settings,
+       .set_settings     = tenxpress_set_settings,
+       .set_npage_adv    = sfx7101_set_npage_adv,
+       .test_alive       = efx_mdio_test_alive,
+       .test_name        = sfx7101_test_name,
+       .run_tests        = sfx7101_run_tests,
+};
 
-struct efx_phy_operations falcon_tenxpress_phy_ops = {
+struct efx_phy_operations falcon_sft9001_phy_ops = {
+       .probe            = tenxpress_phy_probe,
        .init             = tenxpress_phy_init,
        .reconfigure      = tenxpress_phy_reconfigure,
-       .check_hw         = tenxpress_phy_check_hw,
-       .fini             = tenxpress_phy_fini,
-       .clear_interrupt  = tenxpress_phy_clear_interrupt,
-       .reset_xaui       = tenxpress_reset_xaui,
-       .mmds             = TENXPRESS_REQUIRED_DEVS,
-       .loopbacks        = TENXPRESS_LOOPBACKS,
-       .startup_loopback = LOOPBACK_PCS,
+       .poll             = tenxpress_phy_poll,
+       .fini             = efx_port_dummy_op_void,
+       .remove           = tenxpress_phy_remove,
+       .get_settings     = tenxpress_get_settings,
+       .set_settings     = tenxpress_set_settings,
+       .set_npage_adv    = sft9001_set_npage_adv,
+       .test_alive       = efx_mdio_test_alive,
+       .test_name        = sft9001_test_name,
+       .run_tests        = sft9001_run_tests,
 };
index 38ddfeefd550953617d4969b28b52d7793e9f78a..777dbbcb6ccf052cc8ca4c99a1f792c0450c43c7 100644 (file)
@@ -1,56 +1,36 @@
 /****************************************************************************
- * 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * 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/pci.h>
 #include <linux/tcp.h>
 #include <linux/ip.h>
 #include <linux/in.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
 #include <linux/if_ether.h>
 #include <linux/version.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
 #include <linux/highmem.h>
 #endif
 #include "net_driver.h"
-#include "tx.h"
 #include "efx.h"
-#include "falcon.h"
+#include "nic.h"
 #include "workarounds.h"
 
-
 /*
  * TX descriptor ring full threshold
  *
  * The tx_queue descriptor ring fill-level must fall below this value
  * before we restart the netif queue
  */
-#define EFX_NETDEV_TX_THRESHOLD(_tx_queue)     \
-       (_tx_queue->efx->type->txd_ring_mask / 2u)
-
-
+#define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u)
 
 /* We want to be able to nest calls to netif_stop_queue(), since each
  * channel can have an individual stop on the queue.
@@ -70,7 +50,7 @@ void efx_stop_queue(struct efx_nic *efx)
  * We want to be able to nest calls to netif_stop_queue(), since each
  * channel can have an individual stop on the queue.
  */
-inline void efx_wake_queue(struct efx_nic *efx)
+void efx_wake_queue(struct efx_nic *efx)
 {
        local_bh_disable();
        if (atomic_dec_and_lock(&efx->netif_stop_count,
@@ -82,29 +62,87 @@ inline void efx_wake_queue(struct efx_nic *efx)
        local_bh_enable();
 }
 
-static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
-                                     struct efx_tx_buffer *buffer)
+static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
+                              struct efx_tx_buffer *buffer)
 {
        if (buffer->unmap_len) {
                struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+               dma_addr_t unmap_addr = (buffer->dma_addr + buffer->len -
+                                        buffer->unmap_len);
                if (buffer->unmap_single)
-                       pci_unmap_single(pci_dev, buffer->unmap_addr,
-                                        buffer->unmap_len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(pci_dev, unmap_addr, buffer->unmap_len,
+                                        PCI_DMA_TODEVICE);
                else
-                       pci_unmap_page(pci_dev, buffer->unmap_addr,
-                                      buffer->unmap_len, PCI_DMA_TODEVICE);
+                       pci_unmap_page(pci_dev, unmap_addr, buffer->unmap_len,
+                                      PCI_DMA_TODEVICE);
                buffer->unmap_len = 0;
-               buffer->unmap_single = 0;
+               buffer->unmap_single = false;
        }
 
        if (buffer->skb) {
                dev_kfree_skb_any((struct sk_buff *) buffer->skb);
                buffer->skb = NULL;
-               EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
-                         "complete\n", tx_queue->queue, read_ptr);
        }
 }
 
+/**
+ * struct efx_tso_header - a DMA mapped buffer for packet headers
+ * @next: Linked list of free ones.
+ *     The list is protected by the TX queue lock.
+ * @dma_unmap_len: Length to unmap for an oversize buffer, or 0.
+ * @dma_addr: The DMA address of the header below.
+ *
+ * This controls the memory used for a TSO header.  Use TSOH_DATA()
+ * to find the packet header data.  Use TSOH_SIZE() to calculate the
+ * total size required for a given packet header length.  TSO headers
+ * in the free list are exactly %TSOH_STD_SIZE bytes in size.
+ */
+struct efx_tso_header {
+       union {
+               struct efx_tso_header *next;
+               size_t unmap_len;
+       };
+       dma_addr_t dma_addr;
+};
+
+static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
+                              struct sk_buff *skb);
+static void efx_fini_tso(struct efx_tx_queue *tx_queue);
+static void efx_tsoh_heap_free(struct efx_tx_queue *tx_queue,
+                              struct efx_tso_header *tsoh);
+
+static void efx_tsoh_free(struct efx_tx_queue *tx_queue,
+                         struct efx_tx_buffer *buffer)
+{
+       if (buffer->tsoh) {
+               if (likely(!buffer->tsoh->unmap_len)) {
+                       buffer->tsoh->next = tx_queue->tso_headers_free;
+                       tx_queue->tso_headers_free = buffer->tsoh;
+               } else {
+                       efx_tsoh_heap_free(tx_queue, buffer->tsoh);
+               }
+               buffer->tsoh = NULL;
+       }
+}
+
+
+static inline unsigned
+efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
+{
+       /* Depending on the NIC revision, we can use descriptor
+        * lengths up to 8K or 8K-1.  However, since PCI Express
+        * devices must split read requests at 4K boundaries, there is
+        * little benefit from using descriptors that cross those
+        * boundaries and we keep things simple by not doing so.
+        */
+       unsigned len = (~dma_addr & 0xfff) + 1;
+
+       /* Work around hardware bug for unaligned buffers. */
+       if (EFX_WORKAROUND_5391(efx) && (dma_addr & 0xf))
+               len = min_t(unsigned, len, 512 - (dma_addr & 0xf));
+
+       return len;
+}
 
 /*
  * Add a socket buffer to a TX queue
@@ -116,11 +154,13 @@ static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
  * If any DMA mapping fails, any mapped fragments will be unmapped,
  * the queue's insert pointer will be restored to its original value.
  *
+ * This function is split out from efx_hard_start_xmit to allow the
+ * loopback test to direct packets via specific TX queues.
+ *
  * Returns NETDEV_TX_OK or NETDEV_TX_BUSY
  * You must hold netif_tx_lock() to call this function.
  */
-static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
-                                 const struct sk_buff *skb)
+netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
 {
        struct efx_nic *efx = tx_queue->efx;
        struct pci_dev *pci_dev = efx->pci_dev;
@@ -128,31 +168,42 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
        skb_frag_t *fragment;
        struct page *page;
        int page_offset;
-       unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
+       unsigned int len, unmap_len = 0, fill_level, insert_ptr;
        dma_addr_t dma_addr, unmap_addr = 0;
        unsigned int dma_len;
-       unsigned unmap_single;
+       bool unmap_single;
        int q_space, i = 0;
-       int rc = NETDEV_TX_OK;
+       netdev_tx_t rc = NETDEV_TX_OK;
 
        EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
 
+       if (skb_shinfo(skb)->gso_size)
+               return efx_enqueue_skb_tso(tx_queue, skb);
+
        /* Get size of the initial fragment */
        len = skb_headlen(skb);
 
+       /* Pad if necessary */
+       if (EFX_WORKAROUND_15592(efx) && skb->len <= 32) {
+               EFX_BUG_ON_PARANOID(skb->data_len);
+               len = 32 + 1;
+               if (skb_pad(skb, len - skb->len))
+                       return NETDEV_TX_OK;
+       }
+
        fill_level = tx_queue->insert_count - tx_queue->old_read_count;
-       q_space = efx->type->txd_ring_mask - 1 - fill_level;
+       q_space = EFX_TXQ_MASK - 1 - fill_level;
 
        /* Map for DMA.  Use pci_map_single rather than pci_map_page
         * since this is more efficient on machines with sparse
         * memory.
         */
-       unmap_single = 1;
+       unmap_single = true;
        dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
 
        /* Process all fragments */
        while (1) {
-               if (unlikely(pci_dma_mapping_error(dma_addr)))
+               if (unlikely(pci_dma_mapping_error(pci_dev, dma_addr)))
                        goto pci_err;
 
                /* Store fields for marking in the per-fragment final
@@ -178,30 +229,26 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
                                        &tx_queue->read_count;
                                fill_level = (tx_queue->insert_count
                                              - tx_queue->old_read_count);
-                               q_space = (efx->type->txd_ring_mask - 1 -
-                                          fill_level);
+                               q_space = EFX_TXQ_MASK - 1 - fill_level;
                                if (unlikely(q_space-- <= 0))
                                        goto stop;
                                smp_mb();
                                --tx_queue->stopped;
                        }
 
-                       insert_ptr = (tx_queue->insert_count &
-                                     efx->type->txd_ring_mask);
+                       insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
                        buffer = &tx_queue->buffer[insert_ptr];
+                       efx_tsoh_free(tx_queue, buffer);
+                       EFX_BUG_ON_PARANOID(buffer->tsoh);
                        EFX_BUG_ON_PARANOID(buffer->skb);
                        EFX_BUG_ON_PARANOID(buffer->len);
-                       EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+                       EFX_BUG_ON_PARANOID(!buffer->continuation);
                        EFX_BUG_ON_PARANOID(buffer->unmap_len);
 
-                       dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
-                       if (likely(dma_len > len))
+                       dma_len = efx_max_tx_len(efx, dma_addr);
+                       if (likely(dma_len >= len))
                                dma_len = len;
 
-                       misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
-                       if (misalign && dma_len + misalign > 512)
-                               dma_len = 512 - misalign;
-
                        /* Fill out per descriptor fields */
                        buffer->len = dma_len;
                        buffer->dma_addr = dma_addr;
@@ -211,7 +258,6 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
                } while (len);
 
                /* Transfer ownership of the unmapping to the final buffer */
-               buffer->unmap_addr = unmap_addr;
                buffer->unmap_single = unmap_single;
                buffer->unmap_len = unmap_len;
                unmap_len = 0;
@@ -225,17 +271,17 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
                page_offset = fragment->page_offset;
                i++;
                /* Map for DMA */
-               unmap_single = 0;
+               unmap_single = false;
                dma_addr = pci_map_page(pci_dev, page, page_offset, len,
                                        PCI_DMA_TODEVICE);
        }
 
        /* Transfer ownership of the skb to the final buffer */
        buffer->skb = skb;
-       buffer->continuation = 0;
+       buffer->continuation = false;
 
        /* Pass off to hardware */
-       falcon_push_buffers(tx_queue);
+       efx_nic_push_buffers(tx_queue);
 
        return NETDEV_TX_OK;
 
@@ -245,7 +291,7 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
                   skb_shinfo(skb)->nr_frags + 1);
 
        /* Mark the packet as transmitted, and free the SKB ourselves */
-       dev_kfree_skb_any((struct sk_buff *)skb);
+       dev_kfree_skb_any(skb);
        goto unwind;
 
  stop:
@@ -259,16 +305,21 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
        /* Work backwards until we hit the original insert pointer value */
        while (tx_queue->insert_count != tx_queue->write_count) {
                --tx_queue->insert_count;
-               insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+               insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
                buffer = &tx_queue->buffer[insert_ptr];
                efx_dequeue_buffer(tx_queue, buffer);
                buffer->len = 0;
        }
 
        /* Free the fragment we were mid-way through pushing */
-       if (unmap_len)
-               pci_unmap_page(pci_dev, unmap_addr, unmap_len,
-                              PCI_DMA_TODEVICE);
+       if (unmap_len) {
+               if (unmap_single)
+                       pci_unmap_single(pci_dev, unmap_addr, unmap_len,
+                                        PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_page(pci_dev, unmap_addr, unmap_len,
+                                      PCI_DMA_TODEVICE);
+       }
 
        return rc;
 }
@@ -278,15 +329,14 @@ static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
  * This removes packets from the TX queue, up to and including the
  * specified index.
  */
-static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
-                                      unsigned int index)
+static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
+                               unsigned int index)
 {
        struct efx_nic *efx = tx_queue->efx;
        unsigned int stop_index, read_ptr;
-       unsigned int mask = tx_queue->efx->type->txd_ring_mask;
 
-       stop_index = (index + 1) & mask;
-       read_ptr = tx_queue->read_count & mask;
+       stop_index = (index + 1) & EFX_TXQ_MASK;
+       read_ptr = tx_queue->read_count & EFX_TXQ_MASK;
 
        while (read_ptr != stop_index) {
                struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
@@ -299,43 +349,17 @@ static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
                        return;
                }
 
+               EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
+                         "complete\n", tx_queue->queue, read_ptr);
                efx_dequeue_buffer(tx_queue, buffer);
-               buffer->continuation = 1;
+               buffer->continuation = true;
                buffer->len = 0;
 
                ++tx_queue->read_count;
-               read_ptr = tx_queue->read_count & mask;
+               read_ptr = tx_queue->read_count & EFX_TXQ_MASK;
        }
 }
 
-/* Initiate a packet transmission on the specified TX queue.
- * Note that returning anything other than NETDEV_TX_OK will cause the
- * OS to free the skb.
- *
- * This function is split out from efx_hard_start_xmit to allow the
- * loopback test to direct packets via specific TX queues.  It is
- * therefore a non-static inline, so as not to penalise performance
- * for non-loopback transmissions.
- *
- * Context: netif_tx_lock held
- */
-inline int efx_xmit(struct efx_nic *efx,
-                   struct efx_tx_queue *tx_queue, struct sk_buff *skb)
-{
-       int rc;
-
-       /* Map fragments for DMA and add to TX queue */
-       rc = efx_enqueue_skb(tx_queue, skb);
-       if (unlikely(rc != NETDEV_TX_OK))
-               goto out;
-
-       /* Update last TX timer */
-       efx->net_dev->trans_start = jiffies;
-
- out:
-       return rc;
-}
-
 /* Initiate a packet transmission.  We use one channel per CPU
  * (sharing when we have more CPUs than channels).  On Falcon, the TX
  * completion events will be directed back to the CPU that transmitted
@@ -345,15 +369,18 @@ inline int efx_xmit(struct efx_nic *efx,
  * Note that returning anything other than NETDEV_TX_OK will cause the
  * OS to free the skb.
  */
-int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
+                               struct net_device *net_dev)
 {
-       struct efx_nic *efx = net_dev->priv;
+       struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_tx_queue *tx_queue;
        enum efx_veto veto;
-       int rc = NETDEV_TX_OK;
+       int rc;
 
-       /* We have one TX queue. */
-       tx_queue = &efx->tx_queue[0];
+       if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
+               tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM];
+       else
+               tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM];
 
        /* See if driverlink wants to veto the packet. */
        veto = EFX_DL_CALLBACK(efx, tx_packet, skb);
@@ -362,33 +389,41 @@ int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
                        "driverlink %s driver\n", tx_queue->queue,
                        efx->dl_cb_dev.tx_packet->driver->name);
                /* Free the skb; nothing else will do it */
-               dev_kfree_skb_any((struct sk_buff *)skb);
-               goto out;
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
        }
 
-       rc = efx_xmit(efx, tx_queue, skb);
-out:
+       rc = efx_enqueue_skb(tx_queue, skb);
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_NET_DEVICE_TRANS_START)
+       if (likely(rc == NETDEV_TX_OK)) {
+               /* Update last TX timer */
+               efx->net_dev->trans_start = jiffies;
+       }
+#endif
        return rc;
 }
 
+#if defined(EFX_USE_KCOMPAT) && defined(EFX_USE_FASTCALL)
 void fastcall efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
+#else
+void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
+#endif
 {
        unsigned fill_level;
        struct efx_nic *efx = tx_queue->efx;
 
-       EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask);
+       EFX_BUG_ON_PARANOID(index > EFX_TXQ_MASK);
 
-       /* Remove buffers from TX queue */
        efx_dequeue_buffers(tx_queue, index);
 
        /* See if we need to restart the netif queue.  This barrier
         * separates the update of read_count from the test of
         * stopped. */
        smp_mb();
-       if (unlikely(tx_queue->stopped)) {
+       if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) {
                fill_level = tx_queue->insert_count - tx_queue->read_count;
-               if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
-                       EFX_BUG_ON_PARANOID(!NET_DEV_REGISTERED(efx));
+               if (fill_level < EFX_TXQ_THRESHOLD) {
+                       EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
 
                        /* Do this under netif_tx_lock(), to avoid racing
                         * with efx_xmit(). */
@@ -411,37 +446,30 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
        EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
 
        /* Allocate software ring */
-       txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
+       txq_size = EFX_TXQ_SIZE * sizeof(*tx_queue->buffer);
        tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
-       if (!tx_queue->buffer) {
-               rc = -ENOMEM;
-               goto fail1;
-       }
-       for (i = 0; i <= efx->type->txd_ring_mask; ++i)
-               tx_queue->buffer[i].continuation = 1;
+       if (!tx_queue->buffer)
+               return -ENOMEM;
+       for (i = 0; i <= EFX_TXQ_MASK; ++i)
+               tx_queue->buffer[i].continuation = true;
 
        /* Allocate hardware ring */
-       rc = falcon_probe_tx(tx_queue);
+       rc = efx_nic_probe_tx(tx_queue);
        if (rc)
-               goto fail2;
+               goto fail;
 
        return 0;
 
- fail2:
+ fail:
        kfree(tx_queue->buffer);
        tx_queue->buffer = NULL;
- fail1:
-       /* Mark queue as unused */
-       tx_queue->used = 0;
-
        return rc;
 }
 
-int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
+void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
 {
        EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
 
-       /* Initialise fields */
        tx_queue->insert_count = 0;
        tx_queue->write_count = 0;
        tx_queue->read_count = 0;
@@ -449,7 +477,7 @@ int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
        BUG_ON(tx_queue->stopped);
 
        /* Set up TX descriptor ring */
-       return falcon_init_tx(tx_queue);
+       efx_nic_init_tx(tx_queue);
 }
 
 void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
@@ -461,10 +489,9 @@ void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
 
        /* Free any buffers left in the ring */
        while (tx_queue->read_count != tx_queue->write_count) {
-               buffer = &tx_queue->buffer[tx_queue->read_count &
-                                          tx_queue->efx->type->txd_ring_mask];
+               buffer = &tx_queue->buffer[tx_queue->read_count & EFX_TXQ_MASK];
                efx_dequeue_buffer(tx_queue, buffer);
-               buffer->continuation = 1;
+               buffer->continuation = true;
                buffer->len = 0;
 
                ++tx_queue->read_count;
@@ -476,11 +503,13 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
        EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
 
        /* Flush TX queue, remove descriptor ring */
-       falcon_fini_tx(tx_queue);
+       efx_nic_fini_tx(tx_queue);
 
-       /* Release TX buffers */
        efx_release_tx_buffers(tx_queue);
 
+       /* Free up TSO header cache */
+       efx_fini_tso(tx_queue);
+
        /* Release queue's stop on port, if any */
        if (tx_queue->stopped) {
                tx_queue->stopped = 0;
@@ -491,11 +520,683 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
 void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
 {
        EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
-       falcon_remove_tx(tx_queue);
+       efx_nic_remove_tx(tx_queue);
 
        kfree(tx_queue->buffer);
        tx_queue->buffer = NULL;
-       tx_queue->used = 0;
 }
 
 
+/* Efx TCP segmentation acceleration.
+ *
+ * Why?  Because by doing it here in the driver we can go significantly
+ * faster than the GSO.
+ *
+ * Requires TX checksum offload support.
+ */
+
+/* Number of bytes inserted at the start of a TSO header buffer,
+ * similar to NET_IP_ALIGN.
+ */
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#define TSOH_OFFSET    0
+#else
+#define TSOH_OFFSET    NET_IP_ALIGN
+#endif
+
+#define TSOH_BUFFER(tsoh)      ((u8 *)(tsoh + 1) + TSOH_OFFSET)
+
+/* Total size of struct efx_tso_header, buffer and padding */
+#define TSOH_SIZE(hdr_len)                                     \
+       (sizeof(struct efx_tso_header) + TSOH_OFFSET + hdr_len)
+
+/* Size of blocks on free list.  Larger blocks must be allocated from
+ * the heap.
+ */
+#define TSOH_STD_SIZE          128
+
+#define PTR_DIFF(p1, p2)  ((u8 *)(p1) - (u8 *)(p2))
+#define ETH_HDR_LEN(skb)  (skb_network_header(skb) - (skb)->data)
+#define SKB_TCP_OFF(skb)  PTR_DIFF(tcp_hdr(skb), (skb)->data)
+#define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data)
+#define SKB_IPV6_OFF(skb) PTR_DIFF(ipv6_hdr(skb), (skb)->data)
+
+/**
+ * struct tso_state - TSO state for an SKB
+ * @out_len: Remaining length in current segment
+ * @seqnum: Current sequence number
+ * @ipv4_id: Current IPv4 ID, host endian
+ * @packet_space: Remaining space in current packet
+ * @dma_addr: DMA address of current position
+ * @in_len: Remaining length in current SKB fragment
+ * @unmap_len: Length of SKB fragment
+ * @unmap_addr: DMA address of SKB fragment
+ * @unmap_single: DMA single vs page mapping flag
+ * @protocol: Network protocol (after any VLAN header)
+ * @header_len: Number of bytes of header
+ * @full_packet_size: Number of bytes to put in each outgoing segment
+ *
+ * The state used during segmentation.  It is put into this data structure
+ * just to make it easy to pass into inline functions.
+ */
+struct tso_state {
+       /* Output position */
+       unsigned out_len;
+       unsigned seqnum;
+       unsigned ipv4_id;
+       unsigned packet_space;
+
+       /* Input position */
+       dma_addr_t dma_addr;
+       unsigned in_len;
+       unsigned unmap_len;
+       dma_addr_t unmap_addr;
+       bool unmap_single;
+
+       __be16 protocol;
+       unsigned header_len;
+       int full_packet_size;
+};
+
+
+static inline void prefetch_ptr(struct efx_tx_queue *tx_queue)
+{
+       unsigned insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
+       char *ptr;
+
+       ptr = (char *) (tx_queue->buffer + insert_ptr);
+       prefetch(ptr);
+       prefetch(ptr + 0x80);
+
+       ptr = (char *) (((efx_qword_t *)tx_queue->txd.addr) + insert_ptr);
+       prefetch(ptr);
+       prefetch(ptr + 0x80);
+}
+
+/*
+ * Verify that our various assumptions about sk_buffs and the conditions
+ * under which TSO will be attempted hold true.  Return the protocol number.
+ */
+static __be16 efx_tso_check_protocol(struct sk_buff *skb)
+{
+       __be16 protocol = skb->protocol;
+
+       EFX_BUG_ON_PARANOID(((struct ethhdr *)skb->data)->h_proto !=
+                           protocol);
+#if !defined(EFX_USE_KCOMPAT) || defined(EFX_USE_NETDEV_VLAN_FEATURES)
+       if (protocol == htons(ETH_P_8021Q)) {
+               /* Find the encapsulated protocol; reset network header
+                * and transport header based on that. */
+               struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
+               protocol = veh->h_vlan_encapsulated_proto;
+               skb_set_network_header(skb, sizeof(*veh));
+               if (protocol == htons(ETH_P_IP))
+                       skb_set_transport_header(skb, sizeof(*veh) +
+                                                4 * ip_hdr(skb)->ihl);
+               else if (protocol == htons(ETH_P_IPV6))
+                       skb_set_transport_header(skb, sizeof(*veh) +
+                                                sizeof(struct ipv6hdr));
+       }
+#endif
+
+       if (protocol == htons(ETH_P_IP)) {
+               EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP);
+       } else {
+               EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IPV6));
+               EFX_BUG_ON_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP);
+       }
+       EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data)
+                            + (tcp_hdr(skb)->doff << 2u)) >
+                           skb_headlen(skb));
+
+       return protocol;
+}
+
+
+/*
+ * Allocate a page worth of efx_tso_header structures, and string them
+ * into the tx_queue->tso_headers_free linked list. Return 0 or -ENOMEM.
+ */
+static int efx_tsoh_block_alloc(struct efx_tx_queue *tx_queue)
+{
+
+       struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+       struct efx_tso_header *tsoh;
+       dma_addr_t dma_addr;
+       u8 *base_kva, *kva;
+
+       base_kva = pci_alloc_consistent(pci_dev, PAGE_SIZE, &dma_addr);
+       if (base_kva == NULL) {
+               EFX_ERR(tx_queue->efx, "Unable to allocate page for TSO"
+                       " headers\n");
+               return -ENOMEM;
+       }
+
+       /* pci_alloc_consistent() allocates pages. */
+       EFX_BUG_ON_PARANOID(dma_addr & (PAGE_SIZE - 1u));
+
+       for (kva = base_kva; kva < base_kva + PAGE_SIZE; kva += TSOH_STD_SIZE) {
+               tsoh = (struct efx_tso_header *)kva;
+               tsoh->dma_addr = dma_addr + (TSOH_BUFFER(tsoh) - base_kva);
+               tsoh->next = tx_queue->tso_headers_free;
+               tx_queue->tso_headers_free = tsoh;
+       }
+
+       return 0;
+}
+
+
+/* Free up a TSO header, and all others in the same page. */
+static void efx_tsoh_block_free(struct efx_tx_queue *tx_queue,
+                               struct efx_tso_header *tsoh,
+                               struct pci_dev *pci_dev)
+{
+       struct efx_tso_header **p;
+       unsigned long base_kva;
+       dma_addr_t base_dma;
+
+       base_kva = (unsigned long)tsoh & PAGE_MASK;
+       base_dma = tsoh->dma_addr & PAGE_MASK;
+
+       p = &tx_queue->tso_headers_free;
+       while (*p != NULL) {
+               if (((unsigned long)*p & PAGE_MASK) == base_kva)
+                       *p = (*p)->next;
+               else
+                       p = &(*p)->next;
+       }
+
+       pci_free_consistent(pci_dev, PAGE_SIZE, (void *)base_kva, base_dma);
+}
+
+static struct efx_tso_header *
+efx_tsoh_heap_alloc(struct efx_tx_queue *tx_queue, size_t header_len)
+{
+       struct efx_tso_header *tsoh;
+
+       tsoh = kmalloc(TSOH_SIZE(header_len), GFP_ATOMIC | GFP_DMA);
+       if (unlikely(!tsoh))
+               return NULL;
+
+       tsoh->dma_addr = pci_map_single(tx_queue->efx->pci_dev,
+                                       TSOH_BUFFER(tsoh), header_len,
+                                       PCI_DMA_TODEVICE);
+       if (unlikely(pci_dma_mapping_error(tx_queue->efx->pci_dev,
+                                          tsoh->dma_addr))) {
+               kfree(tsoh);
+               return NULL;
+       }
+
+       tsoh->unmap_len = header_len;
+       return tsoh;
+}
+
+static void
+efx_tsoh_heap_free(struct efx_tx_queue *tx_queue, struct efx_tso_header *tsoh)
+{
+       pci_unmap_single(tx_queue->efx->pci_dev,
+                        tsoh->dma_addr, tsoh->unmap_len,
+                        PCI_DMA_TODEVICE);
+       kfree(tsoh);
+}
+
+/**
+ * efx_tx_queue_insert - push descriptors onto the TX queue
+ * @tx_queue:          Efx TX queue
+ * @dma_addr:          DMA address of fragment
+ * @len:               Length of fragment
+ * @final_buffer:      The final buffer inserted into the queue
+ *
+ * Push descriptors onto the TX queue.  Return 0 on success or 1 if
+ * @tx_queue full.
+ */
+static int efx_tx_queue_insert(struct efx_tx_queue *tx_queue,
+                              dma_addr_t dma_addr, unsigned len,
+                              struct efx_tx_buffer **final_buffer)
+{
+       struct efx_tx_buffer *buffer;
+       struct efx_nic *efx = tx_queue->efx;
+       unsigned dma_len, fill_level, insert_ptr;
+       int q_space;
+
+       EFX_BUG_ON_PARANOID(len <= 0);
+
+       fill_level = tx_queue->insert_count - tx_queue->old_read_count;
+       /* -1 as there is no way to represent all descriptors used */
+       q_space = EFX_TXQ_MASK - 1 - fill_level;
+
+       while (1) {
+               if (unlikely(q_space-- <= 0)) {
+                       /* It might be that completions have happened
+                        * since the xmit path last checked.  Update
+                        * the xmit path's copy of read_count.
+                        */
+                       ++tx_queue->stopped;
+                       /* This memory barrier protects the change of
+                        * stopped from the access of read_count. */
+                       smp_mb();
+                       tx_queue->old_read_count =
+                               *(volatile unsigned *)&tx_queue->read_count;
+                       fill_level = (tx_queue->insert_count
+                                     - tx_queue->old_read_count);
+                       q_space = EFX_TXQ_MASK - 1 - fill_level;
+                       if (unlikely(q_space-- <= 0)) {
+                               *final_buffer = NULL;
+                               return 1;
+                       }
+                       smp_mb();
+                       --tx_queue->stopped;
+               }
+
+               insert_ptr = tx_queue->insert_count & EFX_TXQ_MASK;
+               buffer = &tx_queue->buffer[insert_ptr];
+               ++tx_queue->insert_count;
+
+               EFX_BUG_ON_PARANOID(tx_queue->insert_count -
+                                   tx_queue->read_count >
+                                   EFX_TXQ_MASK);
+
+               efx_tsoh_free(tx_queue, buffer);
+               EFX_BUG_ON_PARANOID(buffer->len);
+               EFX_BUG_ON_PARANOID(buffer->unmap_len);
+               EFX_BUG_ON_PARANOID(buffer->skb);
+               EFX_BUG_ON_PARANOID(!buffer->continuation);
+               EFX_BUG_ON_PARANOID(buffer->tsoh);
+
+               buffer->dma_addr = dma_addr;
+
+               dma_len = efx_max_tx_len(efx, dma_addr);
+
+               /* If there is enough space to send then do so */
+               if (dma_len >= len)
+                       break;
+
+               buffer->len = dma_len; /* Don't set the other members */
+               dma_addr += dma_len;
+               len -= dma_len;
+       }
+
+       EFX_BUG_ON_PARANOID(!len);
+       buffer->len = len;
+       *final_buffer = buffer;
+       return 0;
+}
+
+
+/*
+ * Put a TSO header into the TX queue.
+ *
+ * This is special-cased because we know that it is small enough to fit in
+ * a single fragment, and we know it doesn't cross a page boundary.  It
+ * also allows us to not worry about end-of-packet etc.
+ */
+static void efx_tso_put_header(struct efx_tx_queue *tx_queue,
+                              struct efx_tso_header *tsoh, unsigned len)
+{
+       struct efx_tx_buffer *buffer;
+
+       buffer = &tx_queue->buffer[tx_queue->insert_count & EFX_TXQ_MASK];
+       efx_tsoh_free(tx_queue, buffer);
+       EFX_BUG_ON_PARANOID(buffer->len);
+       EFX_BUG_ON_PARANOID(buffer->unmap_len);
+       EFX_BUG_ON_PARANOID(buffer->skb);
+       EFX_BUG_ON_PARANOID(!buffer->continuation);
+       EFX_BUG_ON_PARANOID(buffer->tsoh);
+       buffer->len = len;
+       buffer->dma_addr = tsoh->dma_addr;
+       buffer->tsoh = tsoh;
+
+       ++tx_queue->insert_count;
+}
+
+
+/* Remove descriptors put into a tx_queue. */
+static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
+{
+       struct efx_tx_buffer *buffer;
+       dma_addr_t unmap_addr;
+
+       /* Work backwards until we hit the original insert pointer value */
+       while (tx_queue->insert_count != tx_queue->write_count) {
+               --tx_queue->insert_count;
+               buffer = &tx_queue->buffer[tx_queue->insert_count &
+                                          EFX_TXQ_MASK];
+               efx_tsoh_free(tx_queue, buffer);
+               EFX_BUG_ON_PARANOID(buffer->skb);
+               if (buffer->unmap_len) {
+                       unmap_addr = (buffer->dma_addr + buffer->len -
+                                     buffer->unmap_len);
+                       if (buffer->unmap_single)
+                               pci_unmap_single(tx_queue->efx->pci_dev,
+                                                unmap_addr, buffer->unmap_len,
+                                                PCI_DMA_TODEVICE);
+                       else
+                               pci_unmap_page(tx_queue->efx->pci_dev,
+                                              unmap_addr, buffer->unmap_len,
+                                              PCI_DMA_TODEVICE);
+                       buffer->unmap_len = 0;
+               }
+               buffer->len = 0;
+               buffer->continuation = true;
+       }
+}
+
+
+/* Parse the SKB header and initialise state. */
+static void tso_start(struct tso_state *st, const struct sk_buff *skb)
+{
+       /* All ethernet/IP/TCP headers combined size is TCP header size
+        * plus offset of TCP header relative to start of packet.
+        */
+       st->header_len = ((tcp_hdr(skb)->doff << 2u)
+                         + PTR_DIFF(tcp_hdr(skb), skb->data));
+       st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size;
+
+       if (st->protocol == htons(ETH_P_IP))
+               st->ipv4_id = ntohs(ip_hdr(skb)->id);
+       else
+               st->ipv4_id = 0;
+       st->seqnum = ntohl(tcp_hdr(skb)->seq);
+
+       EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg);
+       EFX_BUG_ON_PARANOID(tcp_hdr(skb)->syn);
+       EFX_BUG_ON_PARANOID(tcp_hdr(skb)->rst);
+
+       st->packet_space = st->full_packet_size;
+       st->out_len = skb->len - st->header_len;
+       st->unmap_len = 0;
+       st->unmap_single = false;
+}
+
+static int tso_get_fragment(struct tso_state *st, struct efx_nic *efx,
+                           skb_frag_t *frag)
+{
+       st->unmap_addr = pci_map_page(efx->pci_dev, frag->page,
+                                     frag->page_offset, frag->size,
+                                     PCI_DMA_TODEVICE);
+       if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) {
+               st->unmap_single = false;
+               st->unmap_len = frag->size;
+               st->in_len = frag->size;
+               st->dma_addr = st->unmap_addr;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+static int tso_get_head_fragment(struct tso_state *st, struct efx_nic *efx,
+                                const struct sk_buff *skb)
+{
+       int hl = st->header_len;
+       int len = skb_headlen(skb) - hl;
+
+       st->unmap_addr = pci_map_single(efx->pci_dev, skb->data + hl,
+                                       len, PCI_DMA_TODEVICE);
+       if (likely(!pci_dma_mapping_error(efx->pci_dev, st->unmap_addr))) {
+               st->unmap_single = true;
+               st->unmap_len = len;
+               st->in_len = len;
+               st->dma_addr = st->unmap_addr;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+
+/**
+ * tso_fill_packet_with_fragment - form descriptors for the current fragment
+ * @tx_queue:          Efx TX queue
+ * @skb:               Socket buffer
+ * @st:                        TSO state
+ *
+ * Form descriptors for the current fragment, until we reach the end
+ * of fragment or end-of-packet.  Return 0 on success, 1 if not enough
+ * space in @tx_queue.
+ */
+static int tso_fill_packet_with_fragment(struct efx_tx_queue *tx_queue,
+                                        const struct sk_buff *skb,
+                                        struct tso_state *st)
+{
+       struct efx_tx_buffer *buffer;
+       int n, end_of_packet, rc;
+
+       if (st->in_len == 0)
+               return 0;
+       if (st->packet_space == 0)
+               return 0;
+
+       EFX_BUG_ON_PARANOID(st->in_len <= 0);
+       EFX_BUG_ON_PARANOID(st->packet_space <= 0);
+
+       n = min(st->in_len, st->packet_space);
+
+       st->packet_space -= n;
+       st->out_len -= n;
+       st->in_len -= n;
+
+       rc = efx_tx_queue_insert(tx_queue, st->dma_addr, n, &buffer);
+       if (likely(rc == 0)) {
+               if (st->out_len == 0)
+                       /* Transfer ownership of the skb */
+                       buffer->skb = skb;
+
+               end_of_packet = st->out_len == 0 || st->packet_space == 0;
+               buffer->continuation = !end_of_packet;
+
+               if (st->in_len == 0) {
+                       /* Transfer ownership of the pci mapping */
+                       buffer->unmap_len = st->unmap_len;
+                       buffer->unmap_single = st->unmap_single;
+                       st->unmap_len = 0;
+               }
+       }
+
+       st->dma_addr += n;
+       return rc;
+}
+
+
+/**
+ * tso_start_new_packet - generate a new header and prepare for the new packet
+ * @tx_queue:          Efx TX queue
+ * @skb:               Socket buffer
+ * @st:                        TSO state
+ *
+ * Generate a new header and prepare for the new packet.  Return 0 on
+ * success, or -1 if failed to alloc header.
+ */
+static int tso_start_new_packet(struct efx_tx_queue *tx_queue,
+                               const struct sk_buff *skb,
+                               struct tso_state *st)
+{
+       struct efx_tso_header *tsoh;
+       struct tcphdr *tsoh_th;
+       unsigned ip_length;
+       u8 *header;
+
+       /* Allocate a DMA-mapped header buffer. */
+       if (likely(TSOH_SIZE(st->header_len) <= TSOH_STD_SIZE)) {
+               if (tx_queue->tso_headers_free == NULL) {
+                       if (efx_tsoh_block_alloc(tx_queue))
+                               return -1;
+               }
+               EFX_BUG_ON_PARANOID(!tx_queue->tso_headers_free);
+               tsoh = tx_queue->tso_headers_free;
+               tx_queue->tso_headers_free = tsoh->next;
+               tsoh->unmap_len = 0;
+       } else {
+               tx_queue->tso_long_headers++;
+               tsoh = efx_tsoh_heap_alloc(tx_queue, st->header_len);
+               if (unlikely(!tsoh))
+                       return -1;
+       }
+
+       header = TSOH_BUFFER(tsoh);
+       tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb));
+
+       /* Copy and update the headers. */
+       memcpy(header, skb->data, st->header_len);
+
+       tsoh_th->seq = htonl(st->seqnum);
+       st->seqnum += skb_shinfo(skb)->gso_size;
+       if (st->out_len > skb_shinfo(skb)->gso_size) {
+               /* This packet will not finish the TSO burst. */
+               ip_length = st->full_packet_size - ETH_HDR_LEN(skb);
+               tsoh_th->fin = 0;
+               tsoh_th->psh = 0;
+       } else {
+               /* This packet will be the last in the TSO burst. */
+               ip_length = st->header_len - ETH_HDR_LEN(skb) + st->out_len;
+               tsoh_th->fin = tcp_hdr(skb)->fin;
+               tsoh_th->psh = tcp_hdr(skb)->psh;
+       }
+
+       if (st->protocol == htons(ETH_P_IP)) {
+               struct iphdr *tsoh_iph =
+                       (struct iphdr *)(header + SKB_IPV4_OFF(skb));
+
+               tsoh_iph->tot_len = htons(ip_length);
+
+               /* Linux leaves suitable gaps in the IP ID space for us to fill. */
+               tsoh_iph->id = htons(st->ipv4_id);
+               st->ipv4_id++;
+       } else {
+               struct ipv6hdr *tsoh_iph =
+                       (struct ipv6hdr *)(header + SKB_IPV6_OFF(skb));
+
+               tsoh_iph->payload_len = htons(ip_length - sizeof(*tsoh_iph));
+       }
+
+       st->packet_space = skb_shinfo(skb)->gso_size;
+       ++tx_queue->tso_packets;
+
+       /* Form a descriptor for this header. */
+       efx_tso_put_header(tx_queue, tsoh, st->header_len);
+
+       return 0;
+}
+
+/**
+ * efx_enqueue_skb_tso - segment and transmit a TSO socket buffer
+ * @tx_queue:          Efx TX queue
+ * @skb:               Socket buffer
+ *
+ * Context: You must hold netif_tx_lock() to call this function.
+ *
+ * Add socket buffer @skb to @tx_queue, doing TSO or return != 0 if
+ * @skb was not enqueued.  In all cases @skb is consumed.  Return
+ * %NETDEV_TX_OK or %NETDEV_TX_BUSY.
+ */
+static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
+                              struct sk_buff *skb)
+{
+       struct efx_nic *efx = tx_queue->efx;
+       int frag_i, rc, rc2 = NETDEV_TX_OK;
+       struct tso_state state;
+
+       prefetch(skb->data);
+
+       /* Find the packet protocol and sanity-check it */
+       state.protocol = efx_tso_check_protocol(skb);
+
+       EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
+
+       tso_start(&state, skb);
+
+       /* Assume that skb header area contains exactly the headers, and
+        * all payload is in the frag list.
+        */
+       if (skb_headlen(skb) == state.header_len) {
+               /* Grab the first payload fragment. */
+               EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags < 1);
+               frag_i = 0;
+               rc = tso_get_fragment(&state, efx,
+                                     skb_shinfo(skb)->frags + frag_i);
+               if (rc)
+                       goto mem_err;
+       } else {
+               rc = tso_get_head_fragment(&state, efx, skb);
+               if (rc)
+                       goto mem_err;
+               frag_i = -1;
+       }
+
+       if (tso_start_new_packet(tx_queue, skb, &state) < 0)
+               goto mem_err;
+
+       prefetch_ptr(tx_queue);
+
+       while (1) {
+               rc = tso_fill_packet_with_fragment(tx_queue, skb, &state);
+               if (unlikely(rc))
+                       goto stop;
+
+               /* Move onto the next fragment? */
+               if (state.in_len == 0) {
+                       if (++frag_i >= skb_shinfo(skb)->nr_frags)
+                               /* End of payload reached. */
+                               break;
+                       rc = tso_get_fragment(&state, efx,
+                                             skb_shinfo(skb)->frags + frag_i);
+                       if (rc)
+                               goto mem_err;
+               }
+
+               /* Start at new packet? */
+               if (state.packet_space == 0 &&
+                   tso_start_new_packet(tx_queue, skb, &state) < 0)
+                       goto mem_err;
+       }
+
+       /* Pass off to hardware */
+       efx_nic_push_buffers(tx_queue);
+
+       tx_queue->tso_bursts++;
+       return NETDEV_TX_OK;
+
+ mem_err:
+       EFX_ERR(efx, "Out of memory for TSO headers, or PCI mapping error\n");
+       dev_kfree_skb_any(skb);
+       goto unwind;
+
+ stop:
+       rc2 = NETDEV_TX_BUSY;
+
+       /* Stop the queue if it wasn't stopped before. */
+       if (tx_queue->stopped == 1)
+               efx_stop_queue(efx);
+
+ unwind:
+       /* Free the DMA mapping we were in the process of writing out */
+       if (state.unmap_len) {
+               if (state.unmap_single)
+                       pci_unmap_single(efx->pci_dev, state.unmap_addr,
+                                        state.unmap_len, PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_page(efx->pci_dev, state.unmap_addr,
+                                      state.unmap_len, PCI_DMA_TODEVICE);
+       }
+
+       efx_enqueue_unwind(tx_queue);
+       return rc2;
+}
+
+
+/*
+ * Free up all TSO datastructures associated with tx_queue. This
+ * routine should be called only once the tx_queue is both empty and
+ * will no longer be used.
+ */
+static void efx_fini_tso(struct efx_tx_queue *tx_queue)
+{
+       unsigned i;
+
+       if (tx_queue->buffer) {
+               for (i = 0; i <= EFX_TXQ_MASK; ++i)
+                       efx_tsoh_free(tx_queue, &tx_queue->buffer[i]);
+       }
+
+       while (tx_queue->tso_headers_free != NULL)
+               efx_tsoh_block_free(tx_queue, tx_queue->tso_headers_free,
+                                   tx_queue->efx->pci_dev);
+}
diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h
deleted file mode 100644 (file)
index ff0c972..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 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@fensystems.co.uk>
- * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_TX_H
-#define EFX_TX_H
-
-#include "net_driver.h"
-
-int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
-void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
-int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
-void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
-
-int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
-void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
-
-#endif /* EFX_TX_H */
index cbc897caacaea4e05ae3827ab9ca408c47b6243c..341a56af28b9a4240e1a41daf6da20580294b76a 100644 (file)
@@ -1,27 +1,12 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * 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
- ****************************************************************************
  */
+
 /*
  * Driver for Transwitch/Mysticom CX4 retimer
  * see www.transwitch.com, part is TXC-43128
 #include <linux/seq_file.h>
 #include "efx.h"
 #include "debugfs.h"
-#include "gmii.h"
 #include "mdio_10g.h"
-#include "xenpack.h"
 #include "phy.h"
-#include "lm87_support.h"
-#include "falcon.h"
+#include "nic.h"
 #include "workarounds.h"
 
 /* We expect these MMDs to be in the package */
-#define TXC_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS |     \
-                          MDIO_MMDREG_DEVS0_PMAPMD |   \
-                          MDIO_MMDREG_DEVS0_PHYXS)
+#define TXC_REQUIRED_DEVS (MDIO_DEVS_PCS |     \
+                          MDIO_DEVS_PMAPMD |   \
+                          MDIO_DEVS_PHYXS)
 
 #define TXC_LOOPBACKS ((1 << LOOPBACK_PCS) |           \
                       (1 << LOOPBACK_PMAPMD) |         \
-                      (1 << LOOPBACK_NETWORK))
+                      (1 << LOOPBACK_PHYXS_WS))
 
 /**************************************************************************
  *
 #define TXC_MTDIABLO_CTRL_PMA_LOOP_LBN (10)
 
 struct txc43128_data {
-#ifdef CONFIG_SFC_DEBUGFS
-       /* BER stats update from check_hw. Note that this is in errors/second,
-        * converting it to errors/bit is left as an exercise for user-space.
-        */
-       unsigned phy_ber_pcs[4];
-       unsigned phy_ber_phyxs[4];
-#endif
        unsigned bug10934_timer;
-       int phy_powered;
-       int tx_disabled;
+       enum efx_phy_mode phy_mode;
        enum efx_loopback_mode loopback_mode;
 };
 
@@ -240,48 +214,32 @@ static void txc_reset_logic(struct efx_nic *efx);
 /* Set the output value of a gpio */
 void txc_set_gpio_val(struct efx_nic *efx, int pin, int on)
 {
-       int outputs;
-
-       outputs = mdio_clause45_read(efx, efx->mii.phy_id,
-                                       MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT);
-
-       outputs = (outputs & ~(1 << pin)) | (on << pin);
-
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                                       MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT,
-                                       outputs);
+       efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT, 1 << pin, on);
 }
 
 /* Set up the GPIO direction register */
 void txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir)
 {
-       int dirs;
+       struct falcon_board *board = falcon_board(efx);
 
-       if (efx->board_info.minor < 3 &&
-                  efx->board_info.major == 0)
+       if (board->minor < 3 && board->major == 0)
                return;
 
-       dirs = mdio_clause45_read(efx, efx->mii.phy_id,
-                           MDIO_MMD_PHYXS, TXC_GPIO_DIR);
-       dirs = (dir & ~(1 << pin)) | (dir << pin);
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           MDIO_MMD_PHYXS, TXC_GPIO_DIR, dirs);
-
+       efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, TXC_GPIO_DIR, 1 << pin, dir);
 }
 
 /* Reset the PMA/PMD MMD. The documentation is explicit that this does a
  * global reset (it's less clear what reset of other MMDs does).*/
 static int txc_reset_phy(struct efx_nic *efx)
 {
-       int rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PMAPMD,
-                                        TXC_MAX_RESET_TIME / TXC_RESET_WAIT,
-                                        TXC_RESET_WAIT);
+       int rc = efx_mdio_reset_mmd(efx, MDIO_MMD_PMAPMD,
+                                   TXC_MAX_RESET_TIME / TXC_RESET_WAIT,
+                                   TXC_RESET_WAIT);
        if (rc < 0)
                goto fail;
 
-       /* Check that all the MMDs we expect are present and responding. We
-        * expect faults on some if the link is down, but not on the PHY XS */
-       rc = mdio_clause45_check_mmds(efx, TXC_REQUIRED_DEVS, 0);
+       /* Check that all the MMDs we expect are present and responding. */
+       rc = efx_mdio_check_mmds(efx, TXC_REQUIRED_DEVS, 0);
        if (rc < 0)
                goto fail;
 
@@ -295,58 +253,52 @@ static int txc_reset_phy(struct efx_nic *efx)
 /* Run a single BIST on one MMD*/
 static int txc_bist_one(struct efx_nic *efx, int mmd, int test)
 {
-       int phy = efx->mii.phy_id;
        int ctrl, bctl;
        int lane;
        int rc = 0;
 
        EFX_INFO(efx, "" TXCNAME ": running BIST on %s MMD\n",
-                mdio_clause45_mmd_name(mmd));
+                efx_mdio_mmd_name(mmd));
 
        /* Set PMA to test into loopback using Mt Diablo reg as per app note */
-       ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
-                                 TXC_MTDIABLO_CTRL);
+       ctrl = efx_mdio_read(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL);
        ctrl |= (1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           TXC_MTDIABLO_CTRL, ctrl);
-
+       efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl);
 
        /* The BIST app. note lists these  as 3 distinct steps. */
        /* Set the BIST type */
        bctl = (test << TXC_BIST_CTRL_TYPE_LBN);
-       mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl);
+       efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
 
        /* Set the BSTEN bit in the BIST Control register to enable */
        bctl |= (1 << TXC_BIST_CTRL_ENAB_LBN);
-       mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl);
+       efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
 
        /* Set the BSTRT bit in the BIST Control register */
-       mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl |
-                           (1 << TXC_BIST_CTRL_STRT_LBN));
+       efx_mdio_write(efx, mmd, TXC_BIST_CTL,
+                      bctl | (1 << TXC_BIST_CTRL_STRT_LBN));
 
        /* Wait. */
        udelay(TXC_BIST_DURATION);
 
        /* Set the BSTOP bit in the BIST Control register */
        bctl |= (1 << TXC_BIST_CTRL_STOP_LBN);
-       mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl);
+       efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl);
 
        /* The STOP bit should go off when things have stopped */
        while (bctl & (1 << TXC_BIST_CTRL_STOP_LBN))
-               bctl = mdio_clause45_read(efx, phy, mmd, TXC_BIST_CTL);
+               bctl = efx_mdio_read(efx, mmd, TXC_BIST_CTL);
 
        /* Check all the error counts are 0 and all the frame counts are
           non-zero */
        for (lane = 0; lane < 4; lane++) {
-               int count = mdio_clause45_read(efx, phy, mmd,
-                                              TXC_BIST_RX0ERRCNT + lane);
+               int count = efx_mdio_read(efx, mmd, TXC_BIST_RX0ERRCNT + lane);
                if (count != 0) {
                        EFX_ERR(efx, ""TXCNAME": BIST error. "
                                "Lane %d had %d errs\n", lane, count);
                        rc = -EIO;
                }
-               count = mdio_clause45_read(efx, phy, mmd,
-                                          TXC_BIST_RX0FRMCNT + lane);
+               count = efx_mdio_read(efx, mmd, TXC_BIST_RX0FRMCNT + lane);
                if (count == 0) {
                        EFX_ERR(efx, ""TXCNAME": BIST error. "
                                "Lane %d got 0 frames\n", lane);
@@ -358,12 +310,11 @@ static int txc_bist_one(struct efx_nic *efx, int mmd, int test)
                EFX_INFO(efx, ""TXCNAME": BIST pass\n");
 
        /* Disable BIST */
-       mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, 0);
+       efx_mdio_write(efx, mmd, TXC_BIST_CTL, 0);
 
        /* Turn off loopback */
        ctrl &= ~(1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
-       mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
-                           TXC_MTDIABLO_CTRL, ctrl);
+       efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl);
 
        return rc;
 }
@@ -378,22 +329,6 @@ static int txc_bist(struct efx_nic *efx)
        return rc;
 }
 
-#ifdef CONFIG_SFC_DEBUGFS
-
-/* debugfs entries for this PHY */
-static struct efx_debugfs_parameter debug_entries[] = {
-       EFX_PER_LANE_PARAMETER("phy_ber_lane", "_pcs",
-                              struct txc43128_data, phy_ber_pcs,
-                              unsigned, efx_debugfs_read_uint),
-       EFX_PER_LANE_PARAMETER("phy_ber_lane", "_phyxs",
-                              struct txc43128_data, phy_ber_phyxs,
-                              unsigned, efx_debugfs_read_uint),
-       EFX_INT_PARAMETER(struct txc43128_data, phy_powered),
-       {NULL}
-};
-
-#endif /* CONFIG_SFC_DEBUGFS */
-
 /* Push the non-configurable defaults into the PHY. This must be
  * done after every full reset */
 static void txc_apply_defaults(struct efx_nic *efx)
@@ -406,111 +341,109 @@ static void txc_apply_defaults(struct efx_nic *efx)
         * saves a picowatt or two */
 
        /* Turn off preemphasis */
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
-                           TXC_ALRGS_ATXPRE0, TXC_ATXPRE_NONE);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
-                           TXC_ALRGS_ATXPRE1, TXC_ATXPRE_NONE);
+       efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0, TXC_ATXPRE_NONE);
+       efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1, TXC_ATXPRE_NONE);
 
        /* Turn down the amplitude */
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
-                           TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
-                           TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH);
+       efx_mdio_write(efx, MDIO_MMD_PHYXS,
+                      TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH);
+       efx_mdio_write(efx, MDIO_MMD_PHYXS,
+                      TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH);
 
        /* Set the line side amplitude and preemphasis to the databook
         * defaults as an erratum causes them to be 0 on at least some
         * PHY rev.s */
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT);
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+                      TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+                      TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+                      TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD,
+                      TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT);
 
        /* Set up the LEDs  */
-       mctrl = mdio_clause45_read(efx, efx->mii.phy_id,
-                                  MDIO_MMD_PHYXS, TXC_MRGS_CTL);
+       mctrl = efx_mdio_read(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL);
 
        /* Set the Green and Red LEDs to their default modes */
        mctrl &= ~((1 << TXC_MCTL_TXLED_LBN) | (1 << TXC_MCTL_RXLED_LBN));
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl);
+       efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl);
 
        /* Databook recommends doing this after configuration changes */
        txc_reset_logic(efx);
 
-       efx->board_info.init_leds(efx);
+       falcon_board(efx)->type->init_phy(efx);
 }
 
-/* Initialisation entry point for this PHY driver */
-static int txc43128_phy_init(struct efx_nic *efx)
+static int txc43128_phy_probe(struct efx_nic *efx)
 {
-       u32 devid;
-       int rc = 0;
        struct txc43128_data *phy_data;
+       int rc;
 
-       devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
-
+       /* Allocate phy private storage */
        phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+       if (!phy_data)
+               return -ENOMEM;
        efx->phy_data = phy_data;
+       phy_data->phy_mode = efx->phy_mode;
 
-       /* This is the default after reset */
-       phy_data->phy_powered = efx->phy_powered;
-       phy_data->tx_disabled = efx->tx_disabled;
+       efx->mdio.mmds = TXC_REQUIRED_DEVS;
+       efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
 
-#ifdef CONFIG_SFC_DEBUGFS
-       rc = efx_extend_debugfs_port(efx, phy_data, debug_entries);
-       if (rc < 0)
-               goto fail1;
-#endif
-       EFX_INFO(efx, ""TXCNAME ": PHY ID reg %x (OUI %x model %x "
-                "revision %x)\n", devid, MDIO_ID_OUI(devid),
-                MDIO_ID_MODEL(devid), MDIO_ID_REV(devid));
+       efx->loopback_modes = TXC_LOOPBACKS | FALCON_XMAC_LOOPBACKS;
+       efx->startup_loopback_mode = LOOPBACK_PMAPMD;
+
+       strlcpy(efx->phy_name, "Mysticom CX4", sizeof(efx->phy_name));
+
+       return 0;
+
+fail:
+       kfree(efx->phy_data);
+       efx->phy_data = NULL;
+
+       return rc;
+}
+
+/* Initialisation entry point for this PHY driver */
+static int txc43128_phy_init(struct efx_nic *efx)
+{
+       u32 devid;
+       int rc;
+
+       devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS);
+       EFX_INFO(efx, ""TXCNAME ": PHY ID reg %x (OUI %06x model %02x "
+                "revision %x)\n", devid, efx_mdio_id_oui(devid),
+                efx_mdio_id_model(devid), efx_mdio_id_rev(devid));
 
        EFX_INFO(efx, ""TXCNAME ": Silicon ID %x\n",
-                mdio_clause45_read(efx, efx->mii.phy_id,
-                                   MDIO_MMD_PHYXS, TXC_GLRGS_SLID) &
-                                       TXC_GLRGS_SLID_MASK);
+                efx_mdio_read(efx, MDIO_MMD_PHYXS, TXC_GLRGS_SLID) &
+                TXC_GLRGS_SLID_MASK);
 
        rc = txc_reset_phy(efx);
        if (rc < 0)
-               goto fail2;
+               return rc;
 
        rc = txc_bist(efx);
        if (rc < 0)
-               goto fail2;
+               return rc;
 
        txc_apply_defaults(efx);
 
        return 0;
-
- fail2:
-#ifdef CONFIG_SFC_DEBUGFS
-       efx_trim_debugfs_port(efx, debug_entries);
-       /* fall-thru */
- fail1:
-#endif
-       kfree(efx->phy_data);
-       efx->phy_data = NULL;
-       return rc;
 }
 
 /* Set the lane power down state in the global registers */
 static void txc_glrgs_lane_power(struct efx_nic *efx, int mmd)
 {
        int pd = (1 << TXC_GLCMD_L01PD_LBN) | (1 << TXC_GLCMD_L23PD_LBN);
-       int ctl = mdio_clause45_read(efx, efx->mii.phy_id,
-                                    mmd, TXC_GLRGS_GLCMD);
+       int ctl = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
 
-       if (efx->phy_powered)
+       if (!(efx->phy_mode & PHY_MODE_LOW_POWER))
                ctl &= ~pd;
        else
                ctl |= pd;
 
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           mmd, TXC_GLRGS_GLCMD, ctl);
+       efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, ctl);
 }
 
 /* Set the lane power down state in the analog control registers */
@@ -522,12 +455,10 @@ static void txc_analog_lane_power(struct efx_nic *efx, int mmd)
        int rxpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN)
                | (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN);
 
-       int txctl = mdio_clause45_read(efx, efx->mii.phy_id,
-                                      mmd, TXC_ALRGS_ATXCTL);
-       int rxctl = mdio_clause45_read(efx, efx->mii.phy_id,
-                                      mmd, TXC_ALRGS_ARXCTL);
+       int txctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ATXCTL);
+       int rxctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ARXCTL);
 
-       if (efx->phy_powered) {
+       if (!(efx->phy_mode & PHY_MODE_LOW_POWER)) {
                txctl &= ~txpd;
                rxctl &= ~rxpd;
        } else {
@@ -535,16 +466,15 @@ static void txc_analog_lane_power(struct efx_nic *efx, int mmd)
                rxctl |= rxpd;
        }
 
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           mmd, TXC_ALRGS_ATXCTL, txctl);
-       mdio_clause45_write(efx, efx->mii.phy_id,
-                           mmd, TXC_ALRGS_ARXCTL, rxctl);
+       efx_mdio_write(efx, mmd, TXC_ALRGS_ATXCTL, txctl);
+       efx_mdio_write(efx, mmd, TXC_ALRGS_ARXCTL, rxctl);
 }
 
 static void txc_set_power(struct efx_nic *efx)
 {
        /* According to the data book, all the MMDs can do low power */
-       mdio_clause45_set_mmds_lpower(efx, !efx->phy_powered,
+       efx_mdio_set_mmds_lpower(efx,
+                                     !!(efx->phy_mode & PHY_MODE_LOW_POWER),
                                      TXC_REQUIRED_DEVS);
 
        /* Global register bank is in PCS, PHY XS. These control the host
@@ -560,14 +490,12 @@ static void txc_set_power(struct efx_nic *efx)
 
 static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd)
 {
-       int portid = efx->mii.phy_id;
-       int val = mdio_clause45_read(efx, portid, mmd, TXC_GLRGS_GLCMD);
+       int val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
        int tries = 50;
        val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
-       mdio_clause45_write(efx, portid, mmd, TXC_GLRGS_GLCMD, val);
+       efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val);
        while (tries--) {
-               val = mdio_clause45_read(efx, portid, mmd,
-                                        TXC_GLRGS_GLCMD);
+               val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
                if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN)))
                        break;
                udelay(1);
@@ -587,76 +515,68 @@ static void txc_reset_logic(struct efx_nic *efx)
        txc_reset_logic_mmd(efx, MDIO_MMD_PCS);
 }
 
-static int txc43128_phy_read_link(struct efx_nic *efx)
+static bool txc43128_phy_read_link(struct efx_nic *efx)
 {
-       return mdio_clause45_links_ok(efx, TXC_REQUIRED_DEVS);
+       return efx_mdio_links_ok(efx, TXC_REQUIRED_DEVS);
 }
 
-static void txc43128_phy_reconfigure(struct efx_nic *efx)
+static int txc43128_phy_reconfigure(struct efx_nic *efx)
 {
        struct txc43128_data *phy_data = efx->phy_data;
-       int power_change = (efx->phy_powered != phy_data->phy_powered);
-       int loop_change = LOOPBACK_CHANGED(phy_data, efx, TXC_LOOPBACKS);
-       int disable_change = (efx->tx_disabled != phy_data->tx_disabled);
+       enum efx_phy_mode mode_change = efx->phy_mode ^ phy_data->phy_mode;
+       bool loop_change = LOOPBACK_CHANGED(phy_data, efx, TXC_LOOPBACKS);
 
-       if (!phy_data->tx_disabled && efx->tx_disabled) {
+       if (efx->phy_mode & mode_change & PHY_MODE_TX_DISABLED) {
                txc_reset_phy(efx);
                txc_apply_defaults(efx);
                falcon_reset_xaui(efx);
-               disable_change = 0;
+               mode_change &= ~PHY_MODE_TX_DISABLED;
        }
 
-       mdio_clause45_transmit_disable(efx, efx->tx_disabled);
-       mdio_clause45_phy_reconfigure(efx);
-       if (power_change)
+       efx_mdio_transmit_disable(efx);
+       efx_mdio_phy_reconfigure(efx);
+       if (mode_change & PHY_MODE_LOW_POWER)
                txc_set_power(efx);
 
        /* The data sheet claims this is required after every reconfiguration
         * (note at end of 7.1), but we mustn't do it when nothing changes as
         * it glitches the link, and reconfigure gets called on link change,
         * so we get an IRQ storm on link up. */
-       if (loop_change || power_change || disable_change)
+       if (loop_change || mode_change)
                txc_reset_logic(efx);
 
-       phy_data->phy_powered = efx->phy_powered;
+       phy_data->phy_mode = efx->phy_mode;
        phy_data->loopback_mode = efx->loopback_mode;
-       phy_data->tx_disabled = efx->tx_disabled;
-       efx->link_up = txc43128_phy_read_link(efx);
-       efx->link_options = GM_LPA_10000FULL;
+
+       return 0;
 }
 
 static void txc43128_phy_fini(struct efx_nic *efx)
 {
-       efx->board_info.blink(efx, 0);
-
        /* Disable link events */
-       xenpack_disable_lasi_irqs(efx);
+       efx_mdio_write(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0);
+}
 
-#ifdef CONFIG_SFC_DEBUGFS
-       /* Remove the extra debug entries and free data */
-       efx_trim_debugfs_port(efx, debug_entries);
-#endif
+static void txc43128_phy_remove(struct efx_nic *efx)
+{
        kfree(efx->phy_data);
        efx->phy_data = NULL;
 }
 
 /* Periodic callback: this exists mainly to poll link status as we currently
  * don't use LASI interrupts. Also update the BER counters and poll the lm87 */
-static int txc43128_phy_check_hw(struct efx_nic *efx)
+static bool txc43128_phy_poll(struct efx_nic *efx)
 {
        struct txc43128_data *data = efx->phy_data;
-#ifdef CONFIG_SFC_DEBUGFS
-       int phy = efx->mii.phy_id;
-       int timer, count, i, mmd;
-#endif
-       int rc = 0;
-       int link_up = txc43128_phy_read_link(efx);
+       bool was_up = efx->link_state.up;
+
+       efx->link_state.up = txc43128_phy_read_link(efx);
+       efx->link_state.speed = 10000;
+       efx->link_state.fd = true;
+       efx->link_state.fc = efx->wanted_fc;
 
-       /* Simulate a PHY event if link state has changed */
-       if (link_up != efx->link_up)
-               efx->mac_op->fake_phy_event(efx);
-       else if (EFX_WORKAROUND_10934(efx)) {
-               if (link_up || (efx->loopback_mode != LOOPBACK_NONE))
+       if (EFX_WORKAROUND_10934(efx)) {
+               if (efx->link_state.up || (efx->loopback_mode != LOOPBACK_NONE))
                        data->bug10934_timer = jiffies;
                else {
                        int delta = jiffies - data->bug10934_timer;
@@ -667,58 +587,52 @@ static int txc43128_phy_check_hw(struct efx_nic *efx)
                }
        }
 
-       rc = efx->board_info.monitor(efx);
-       if (rc) {
-               EFX_ERR(efx, "" TXCNAME
-                       ": sensor alert! Putting PHY into low power.\n");
-               efx->phy_powered = 0;
-               txc_set_power(efx);
-       }
+       return efx->link_state.up != was_up;
+}
 
-#ifdef CONFIG_SFC_DEBUGFS
-       /* There are 2 MMDs with RX BER counters: PCS and PHY XS,
-        * which happen to be consecutively numbered */
-       for (mmd = MDIO_MMD_PCS; mmd <= MDIO_MMD_PHYXS; mmd++) {
-               for (i = 0; i < XAUI_NUM_LANES; i++) {
-                       timer = mdio_clause45_read(efx, phy, mmd,
-                                                  TXC_RXCTL_BERTMR0 +
-                                                  i * BER_REG_SPACING);
-                       count = mdio_clause45_read(efx, phy, mmd,
-                                                  TXC_RXCTL_BERCNT0 +
-                                                  i * BER_REG_SPACING);
-                       /* The BER timer counts down in seconds. If it would
-                        * expire before the next check_hw, update the stats &
-                        * restart the timer (clears the count) */
-                       if (timer * HZ < efx_monitor_interval) {
-                               /* Record count, allowing for the fact that the
-                                * timer may not have reached zero */
-                               unsigned ber = (count * BER_INTERVAL) /
-                                       (BER_INTERVAL - timer * HZ);
-                               if (mmd == MDIO_MMD_PCS)
-                                       data->phy_ber_pcs[i] = ber;
-                               else
-                                       data->phy_ber_phyxs[i] = ber;
-                               /* Reprogram the timer */
-                               mdio_clause45_write(efx, phy, mmd,
-                                                   TXC_RXCTL_BERTMR0 +
-                                                   i * BER_REG_SPACING,
-                                                   BER_INTERVAL / HZ);
-                       }
-               }
-               mmd = (mmd == MDIO_MMD_PCS) ? MDIO_MMD_PHYXS : 0;
-       }
-#endif /* CONFIG_SFC_DEBUGFS */
+static const char *txc43128_test_names[] = {
+       "bist"
+};
+
+static const char *txc43128_test_name(struct efx_nic *efx, unsigned int index)
+{
+       if (index < ARRAY_SIZE(txc43128_test_names))
+               return txc43128_test_names[index];
+       return NULL;
+}
+
+static int txc43128_run_tests(struct efx_nic *efx, int *results, unsigned flags)
+{
+       int rc;
+
+       if (!(flags & ETH_TEST_FL_OFFLINE))
+               return 0;
+
+       rc = txc_reset_phy(efx);
+       if (rc < 0)
+               return rc;
+
+       rc = txc_bist(efx);
+       txc_apply_defaults(efx);
+       results[0] = rc ? -1 : 1;
        return rc;
 }
 
+static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+       mdio45_ethtool_gset(&efx->mdio, ecmd);
+}
+
 struct efx_phy_operations falcon_txc_phy_ops = {
-       .init             = txc43128_phy_init,
-       .reconfigure      = txc43128_phy_reconfigure,
-       .check_hw         = txc43128_phy_check_hw,
-       .fini             = txc43128_phy_fini,
-       .clear_interrupt  = efx_port_dummy_op_void,
-       .reset_xaui       = efx_port_dummy_op_void,
-       .mmds             = TXC_REQUIRED_DEVS,
-       .loopbacks        = TXC_LOOPBACKS,
-       .startup_loopback = LOOPBACK_PMAPMD,
+       .probe          = txc43128_phy_probe,
+       .init           = txc43128_phy_init,
+       .reconfigure    = txc43128_phy_reconfigure,
+       .poll           = txc43128_phy_poll,
+       .fini           = txc43128_phy_fini,
+       .remove         = txc43128_phy_remove,
+       .get_settings   = txc43128_get_settings,
+       .set_settings   = efx_mdio_set_settings,
+       .test_alive     = efx_mdio_test_alive,
+       .run_tests      = txc43128_run_tests,
+       .test_name      = txc43128_test_name,
 };
index 2c07d54c3e4c786274a551e3cebc01a2e78550e4..e4f7817dfcbe92b654221e29c361c662b58a7f06 100644 (file)
@@ -1,26 +1,10 @@
 /****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * 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_WORKAROUNDS_H
  */
 
 #define EFX_WORKAROUND_ALWAYS(efx) 1
-#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
-#define EFX_WORKAROUND_FALCON_B0FPGA(efx) \
-       (FALCON_REV(efx) >= FALCON_REV_B0 && !(efx)->is_asic)
+#define EFX_WORKAROUND_NEVER(efx) 0
+#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1)
+#define EFX_WORKAROUND_FALCON_B(efx) (efx_nic_rev(efx) == EFX_REV_FALCON_B0)
+#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0)
+#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0)
+#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
+#define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \
+                                    (efx)->phy_type == PHY_TYPE_SFT9001B)
 
 /* XAUI resets if link not detected */
 #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
-/* SNAP frames have TOBE_DISC set */
-#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
-/* PHY interrupts can go to the wrong port */
-#define EFX_WORKAROUND_6263 EFX_WORKAROUND_ALWAYS
 /* Reprog PCIe ACK timer to workaround issue in PCIe IP block */
-#define EFX_WORKAROUND_6943 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_6943 EFX_WORKAROUND_FALCON_B
 /* RX PCIe double split performance issue */
 #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
 /* Bit-bashed I2C reads cause performance drop */
-#define EFX_WORKAROUND_7884 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G
 /* Selftests need to be retried */
-#define EFX_WORKAROUND_8909 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_8568 EFX_WORKAROUND_ALWAYS
 /* Queued ACKs aren't flushed before L1 entry */
-#define EFX_WORKAROUND_9096 EFX_WORKAROUND_ALWAYS
-/* TX pkt parser problem with <= 16 byte TXes */
-#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
-/* XGXS and XAUI reset sequencing in SW */
-#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
-/* Low rate CRC errors require XAUI reset */
-#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_9096 EFX_WORKAROUND_FALCON_B
 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
  * or a PCIe error (bug 11028) */
 #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
-/* CX4 retimer fails to bring link up after reset */
-#define EFX_WORKAROUND_10934 EFX_WORKAROUND_ALWAYS
 /* Transmit flow control may get disabled */
-#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
-/* Flush events can take a very long time to appear */
-#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
-/* 10Xpress is sensitive to unstable XAUI sync when going into loopback */
-#define EFX_WORKAROUND_11667 EFX_WORKAROUND_ALWAYS
+#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB
+/* Truncated IPv4 packets can confuse the TX packet parser */
+#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
+/* Legacy ISR read can return zero once */
+#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA
+/* Legacy interrupt storm when interrupt fifo fills */
+#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
 
 /* Spurious parity errors in TSORT buffers */
 #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
-/* No unaligned TX over 512 byte boundaries */
+/* Unaligned read request >512 bytes after aligning may break TSORT */
 #define EFX_WORKAROUND_5391 EFX_WORKAROUND_FALCON_A
 /* iSCSI parsing errors */
 #define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
@@ -80,8 +59,6 @@
 #define EFX_WORKAROUND_5676 EFX_WORKAROUND_FALCON_A
 /* RX_RESET on A1 */
 #define EFX_WORKAROUND_6555 EFX_WORKAROUND_FALCON_A
-/* Spurious duplicate RX events */
-#define EFX_WORKAROUND_7062 EFX_WORKAROUND_FALCON_A
 /* Increase filter depth to avoid RX_RESET */
 #define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
 /* Flushes may never complete */
 /* Leak overlength packets rather than free */
 #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
 
-/* Memory needs clearing at start-of-day */
-#define EFX_WORKAROUND_8202 EFX_WORKAROUND_FALCON_B0FPGA
-/* MAC statistics are transient */
-#define EFX_WORKAROUND_8419 EFX_WORKAROUND_FALCON_B0FPGA
-/* Prefetch watchdog timer may trigger erroneously on busy systems */
-#define EFX_WORKAROUND_9008 EFX_WORKAROUND_FALCON_B0FPGA
+/* Invalid BAR accesses may not be completed, leading to NMI */
+#define EFX_WORKAROUND_11368 EFX_WORKAROUND_FALCON_B
+
+/* Need to send XNP pages for 100BaseT */
+#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001
+/* Don't restart AN in near-side loopback */
+#define EFX_WORKAROUND_15195 EFX_WORKAROUND_SFT9001
 
 #endif /* EFX_WORKAROUNDS_H */
diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h
deleted file mode 100644 (file)
index f1ece94..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006:      Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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_XENPACK_H
-#define EFX_XENPACK_H
-
-/* Exported functions from Xenpack standard PHY control */
-
-#include "mdio_10g.h"
-
-/****************************************************************************/
-/* XENPACK MDIO register extensions */
-#define MDIO_XP_LASI_RX_CTRL   (0x9000)
-#define MDIO_XP_LASI_TX_CTRL   (0x9001)
-#define MDIO_XP_LASI_CTRL      (0x9002)
-#define MDIO_XP_LASI_RX_STAT   (0x9003)
-#define MDIO_XP_LASI_TX_STAT   (0x9004)
-#define MDIO_XP_LASI_STAT      (0x9005)
-
-/* Control/Status bits */
-#define XP_LASI_LS_ALARM       (1 << 0)
-#define XP_LASI_TX_ALARM       (1 << 1)
-#define XP_LASI_RX_ALARM       (1 << 2)
-/* These two are Quake vendor extensions to the standard XENPACK defines */
-#define XP_LASI_LS_INTB                (1 << 3)
-#define XP_LASI_TEST           (1 << 7)
-
-/* Enable LASI interrupts for PHY */
-static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
-{
-       int reg;
-       int phy_id = efx->mii.phy_id;
-       /* Read to clear LASI status register */
-       reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
-                                MDIO_XP_LASI_STAT);
-
-       /* Enable LASI interrupts from PMA/PMD */
-       mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
-                           MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
-}
-
-/* Read the LASI interrupt status to clear the interrupt. */
-static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
-{
-       /* Read to clear link status alarm */
-       return mdio_clause45_read(efx, efx->mii.phy_id,
-                                 MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
-}
-
-/* Turn off LASI interrupts */
-static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
-{
-       /* Turn LASI interrupts off */
-       mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
-                           MDIO_XP_LASI_CTRL, 0);
-}
-
-#endif /* EFX_XENPACK_H */
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
deleted file mode 100644 (file)
index ad5bc61..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare network controllers
- *           (including support for SFE4001 10GBT NIC)
- *
- * Copyright 2006-2008: Solarflare Communications Inc,
- *                      9501 Jeronimo Road, Suite 250,
- *                      Irvine, CA 92618, USA
- *
- * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
- *
- * 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
- ****************************************************************************
- */
-/*
- * Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
- * See www.amcc.com for details (search for qt2032)
- */
-
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include "efx.h"
-#include "gmii.h"
-#include "mdio_10g.h"
-#include "xenpack.h"
-#include "phy.h"
-
-#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS |     \
-                          MDIO_MMDREG_DEVS0_PMAPMD |   \
-                          MDIO_MMDREG_DEVS0_PHYXS)
-
-#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) |           \
-                      (1 << LOOPBACK_PMAPMD) |         \
-                      (1 << LOOPBACK_NETWORK))
-
-/****************************************************************************/
-/* Quake-specific MDIO registers */
-#define MDIO_QUAKE_LED0_REG    (0xD006)
-
-
-void xfp_set_led(struct efx_nic *p, int led, int mode)
-{
-       int addr = MDIO_QUAKE_LED0_REG + led;
-       mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
-                           mode);
-}
-
-struct xfp_phy_data {
-       int phy_powered;
-       int tx_disabled;
-};
-
-
-#define XFP_MAX_RESET_TIME 500
-#define XFP_RESET_WAIT 10
-
-/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
- * a complete soft reset.
- */
-static int xfp_reset_phy(struct efx_nic *efx)
-{
-       int rc;
-
-       rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
-                                    XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
-                                    XFP_RESET_WAIT);
-       if (rc < 0)
-               goto fail;
-
-       /* Wait 250ms for the PHY to complete bootup */
-       msleep(250);
-
-       /* Check that all the MMDs we expect are present and responding. We
-        * expect faults on some if the link is down, but not on the PHY XS */
-       rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
-                                     MDIO_MMDREG_DEVS0_PHYXS);
-       if (rc < 0)
-               goto fail;
-
-       efx->board_info.init_leds(efx);
-
-       return rc;
-
- fail:
-       EFX_ERR(efx, "XFP: reset timed out!\n");
-       return rc;
-}
-
-
-static int xfp_phy_init(struct efx_nic *efx)
-{
-       struct xfp_phy_data *phy_data;
-       u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
-       int rc;
-
-       phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
-       efx->phy_data = (void *) phy_data;
-
-       EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
-                " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
-                MDIO_ID_REV(devid));
-
-       phy_data->phy_powered = efx->phy_powered;
-       phy_data->tx_disabled = efx->tx_disabled;
-
-       rc = xfp_reset_phy(efx);
-
-       EFX_INFO(efx, "XFP: PHY init %s.\n",
-                rc ? "failed" : "successful");
-       if (rc < 0)
-               goto fail;
-
-       return 0;
-
- fail:
-       kfree(efx->phy_data);
-       efx->phy_data = NULL;
-       return rc;
-}
-
-static void xfp_phy_clear_interrupt(struct efx_nic *efx)
-{
-       xenpack_clear_lasi_irqs(efx);
-}
-
-static int xfp_link_ok(struct efx_nic *efx)
-{
-       return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
-}
-
-static int xfp_phy_check_hw(struct efx_nic *efx)
-{
-       int rc = 0;
-       int link_up = xfp_link_ok(efx);
-       /* Simulate a PHY event if link state has changed */
-       if (link_up != efx->link_up)
-               efx->mac_op->fake_phy_event(efx);
-
-       rc = efx->board_info.monitor(efx);
-       if (rc) {
-               EFX_ERR(efx, ": XFP sensor alert! Putting PHY into "
-                       "low power.\n");
-               efx->phy_powered = 0;
-
-               mdio_clause45_set_mmds_lpower(efx, 1, XFP_REQUIRED_DEVS);
-       }
-
-       return rc;
-}
-
-static void xfp_phy_reconfigure(struct efx_nic *efx)
-{
-       struct xfp_phy_data *phy_data = efx->phy_data;
-
-       /* Reset the PHY when moving from transmitter off or powered off,
-        * to transmitter on and powered on */
-       if ((efx->phy_powered && !efx->tx_disabled) &&
-           (!phy_data->phy_powered || phy_data->tx_disabled))
-               xfp_reset_phy(efx);
-
-       mdio_clause45_transmit_disable(efx, efx->tx_disabled);
-       mdio_clause45_set_mmds_lpower(efx, !efx->phy_powered,
-                                     XFP_REQUIRED_DEVS);
-       mdio_clause45_phy_reconfigure(efx);
-
-       phy_data->tx_disabled = efx->tx_disabled;
-       phy_data->phy_powered = efx->phy_powered;
-       efx->link_up = xfp_link_ok(efx);
-       efx->link_options = GM_LPA_10000FULL;
-}
-
-
-static void xfp_phy_fini(struct efx_nic *efx)
-{
-       /* Clobber the LED if it was blinking */
-       efx->board_info.blink(efx, 0);
-
-       /* Free the context block */
-       kfree(efx->phy_data);
-       efx->phy_data = NULL;
-}
-
-struct efx_phy_operations falcon_xfp_phy_ops = {
-       .init             = xfp_phy_init,
-       .reconfigure      = xfp_phy_reconfigure,
-       .check_hw         = xfp_phy_check_hw,
-       .fini             = xfp_phy_fini,
-       .clear_interrupt  = xfp_phy_clear_interrupt,
-       .reset_xaui       = efx_port_dummy_op_void,
-       .mmds             = XFP_REQUIRED_DEVS,
-       .loopbacks        = XFP_LOOPBACKS,
-       .startup_loopback = LOOPBACK_PCS,
-};