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