From 3ad2f3fbb961429d2aa627465ae4829758bc7e07 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Feb 2010 08:01:28 +0800 Subject: tree-wide: Assorted spelling fixes In particular, several occurances of funny versions of 'success', 'unknown', 'therefore', 'acknowledge', 'argument', 'achieve', 'address', 'beginning', 'desirable', 'separate' and 'necessary' are fixed. Signed-off-by: Daniel Mack Cc: Joe Perches Cc: Junio C Hamano Signed-off-by: Jiri Kosina --- drivers/net/sfc/regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h index 89d606fe9248..18a3be428348 100644 --- a/drivers/net/sfc/regs.h +++ b/drivers/net/sfc/regs.h @@ -95,7 +95,7 @@ #define FRF_AA_INT_ACK_KER_FIELD_LBN 0 #define FRF_AA_INT_ACK_KER_FIELD_WIDTH 32 -/* INT_ISR0_REG: Function 0 Interrupt Acknowlege Status register */ +/* INT_ISR0_REG: Function 0 Interrupt Acknowledge Status register */ #define FR_BZ_INT_ISR0 0x00000090 #define FRF_BZ_INT_ISR_REG_LBN 0 #define FRF_BZ_INT_ISR_REG_WIDTH 64 -- cgit v1.2.3 From 5a0e3ad6af8660be21ca98a971cd00f331318c05 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 24 Mar 2010 17:04:11 +0900 Subject: include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo Guess-its-ok-by: Christoph Lameter Cc: Ingo Molnar Cc: Lee Schermerhorn --- drivers/net/sfc/efx.c | 1 + drivers/net/sfc/falcon.c | 1 + drivers/net/sfc/mcdi_phy.c | 1 + drivers/net/sfc/mtd.c | 1 + drivers/net/sfc/qt202x_phy.c | 1 + drivers/net/sfc/rx.c | 1 + drivers/net/sfc/selftest.c | 1 + drivers/net/sfc/siena.c | 1 + drivers/net/sfc/tenxpress.c | 1 + drivers/net/sfc/tx.c | 1 + 10 files changed, 10 insertions(+) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 88f2fb193abe..6486657c47b8 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "net_driver.h" #include "efx.h" #include "mdio_10g.h" diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 1b8d83657aaa..d294d66fd600 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "net_driver.h" #include "bitfield.h" #include "efx.h" diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 34c22fa986e2..2f2354696663 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -11,6 +11,7 @@ * Driver for PHY related operations via MCDI. */ +#include #include "efx.h" #include "phy.h" #include "mcdi.h" diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 407bbaddfea6..f3ac7f30b5e7 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define EFX_DRIVER_NAME "sfc_mtd" diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 1bee62c83001..e077bef08a50 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -10,6 +10,7 @@ * Driver for AMCC QT202x SFP+ and XFP adapters; see www.amcc.com for details */ +#include #include #include #include "efx.h" diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index a97c923b560c..e308818b9f55 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index cf0139a7d9a4..0106b1d9aae2 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "net_driver.h" #include "efx.h" diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 1619fb5a64f5..38dcc42c4f79 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "net_driver.h" #include "bitfield.h" #include "efx.h" diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index 10db071bd837..f21efe7bd316 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "efx.h" #include "mdio_10g.h" #include "nic.h" diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index a8b70ef6d817..be0e110a1f73 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 22bedad3ce112d5ca1eaf043d4990fa2ed698c87 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Apr 2010 21:22:57 +0000 Subject: net: convert multicast list to list_head Converts the list and the core manipulating with it to be the same as uc_list. +uses two functions for adding/removing mc address (normal and "global" variant) instead of a function parameter. +removes dev_mcast.c completely. +exposes netdev_hw_addr_list_* macros along with __hw_addr_* functions for manipulation with lists on a sandbox (used in bonding and 80211 drivers) Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 88f2fb193abe..e07b82b266d9 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1602,7 +1602,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) static void efx_set_multicast_list(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - struct dev_mc_list *mc_list; + struct netdev_hw_addr *ha; union efx_multicast_hash *mc_hash = &efx->multicast_hash; u32 crc; int bit; @@ -1614,8 +1614,8 @@ static void efx_set_multicast_list(struct net_device *net_dev) memset(mc_hash, 0xff, sizeof(*mc_hash)); } else { memset(mc_hash, 0x00, sizeof(*mc_hash)); - netdev_for_each_mc_addr(mc_list, net_dev) { - crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr); + netdev_for_each_mc_addr(ha, net_dev) { + crc = ether_crc_le(ETH_ALEN, ha->addr); bit = crc & (EFX_MCAST_HASH_ENTRIES - 1); set_bit_le(bit, mc_hash->byte); } -- cgit v1.2.3 From aabc5649078310094cbffb430fcbf9c25b6268f9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:00:35 +0000 Subject: sfc: Wait at most 10ms for the MC to finish reading out MAC statistics The original code would wait indefinitely if MAC stats DMA failed. Signed-off-by: Ben Hutchings Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/sfc/siena.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 38dcc42c4f79..e0c46f59d1f8 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -456,8 +456,17 @@ static int siena_try_update_nic_stats(struct efx_nic *efx) static void siena_update_nic_stats(struct efx_nic *efx) { - while (siena_try_update_nic_stats(efx) == -EAGAIN) - cpu_relax(); + int retry; + + /* If we're unlucky enough to read statistics wduring the DMA, wait + * up to 10ms for it to finish (typically takes <500us) */ + for (retry = 0; retry < 100; ++retry) { + if (siena_try_update_nic_stats(efx) == 0) + return; + udelay(100); + } + + /* Use the old values instead */ } static void siena_start_nic_stats(struct efx_nic *efx) -- cgit v1.2.3 From f49a4589e9e25ef525da449b1ce5597cb659bbb5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:01:33 +0000 Subject: sfc: Always close net device at the end of a disabling reset This fixes a regression introduced by commit eb9f6744cbfa97674c13263802259b5aa0034594 "sfc: Implement ethtool reset operation". Signed-off-by: Ben Hutchings Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 6486657c47b8..649a264d6a81 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1861,6 +1861,7 @@ out: } if (disabled) { + dev_close(efx->net_dev); EFX_ERR(efx, "has been disabled\n"); efx->state = STATE_DISABLED; } else { @@ -1884,8 +1885,7 @@ static void efx_reset_work(struct work_struct *data) } rtnl_lock(); - if (efx_reset(efx, efx->reset_pending)) - dev_close(efx->net_dev); + (void)efx_reset(efx, efx->reset_pending); rtnl_unlock(); } -- cgit v1.2.3 From e41c11ee0cc602bcde68916be85fb97d1a484324 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:01:50 +0000 Subject: sfc: Change falcon_probe_board() to fail for unsupported boards The driver needs specific PHY and board support code for each SFC4000 board; there is no point trying to continue if it is missing. Currently unsupported boards can trigger an 'oops'. Signed-off-by: Ben Hutchings Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/sfc/falcon.c | 4 +++- drivers/net/sfc/falcon_boards.c | 13 +++---------- drivers/net/sfc/nic.h | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d294d66fd600..08278e7302b3 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1320,7 +1320,9 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); - falcon_probe_board(efx, board_rev); + rc = falcon_probe_board(efx, board_rev); + if (rc) + goto fail2; kfree(nvconfig); return 0; diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index 5712fddd72f2..c7a933a3292e 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -728,15 +728,7 @@ static const struct falcon_board_type board_types[] = { }, }; -static const struct falcon_board_type falcon_dummy_board = { - .init = efx_port_dummy_op_int, - .init_phy = efx_port_dummy_op_void, - .fini = efx_port_dummy_op_void, - .set_id_led = efx_port_dummy_op_set_id_led, - .monitor = efx_port_dummy_op_int, -}; - -void falcon_probe_board(struct efx_nic *efx, u16 revision_info) +int falcon_probe_board(struct efx_nic *efx, u16 revision_info) { struct falcon_board *board = falcon_board(efx); u8 type_id = FALCON_BOARD_TYPE(revision_info); @@ -754,8 +746,9 @@ void falcon_probe_board(struct efx_nic *efx, u16 revision_info) (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) ? board->type->ref_model : board->type->gen_type, 'A' + board->major, board->minor); + return 0; } else { EFX_ERR(efx, "unknown board type %d\n", type_id); - board->type = &falcon_dummy_board; + return -ENODEV; } } diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 9351c0331a47..3166bafdfbef 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -156,7 +156,7 @@ extern struct efx_nic_type siena_a0_nic_type; ************************************************************************** */ -extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); +extern int falcon_probe_board(struct efx_nic *efx, u16 revision_info); /* TX data path */ extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); -- cgit v1.2.3 From b17424b0b29f94561e73ab9be34037746b378089 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:25:22 +0000 Subject: sfc: Ignore parity errors in the other port's SRAM Siena has a separate SRAM bank for each port. On single-port boards these can be merged together, so each port has an interrupt flag for parity errors in the other port's SRAM. Currently we do not enable such merging and should mask this interrupt source. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/nic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index b06f8e348307..664fd6ceed55 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1563,6 +1563,8 @@ void efx_nic_init_common(struct efx_nic *efx) FRF_AZ_ILL_ADR_INT_KER_EN, 1, FRF_AZ_RBUF_OWN_INT_KER_EN, 1, FRF_AZ_TBUF_OWN_INT_KER_EN, 1); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + EFX_SET_OWORD_FIELD(temp, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 1); EFX_INVERT_OWORD(temp); efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); -- cgit v1.2.3 From 00bbb4a5344a5f81cf5d48e781e5c0df3e588d17 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:27:14 +0000 Subject: sfc: Consistently report short MCDI responses as EIO In some cases failing functions were returning 0 which is obviously wrong. In other cases they were returning inappropriate error codes. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi.c | 22 ++++++++++++++-------- drivers/net/sfc/mcdi_phy.c | 6 +++--- 2 files changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index c48669c77414..1344afac4673 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -613,7 +613,7 @@ int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build) } if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) { - rc = -EMSGSIZE; + rc = -EIO; goto fail; } @@ -647,8 +647,10 @@ int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; - if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) + if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) { + rc = -EIO; goto fail; + } if (was_attached != NULL) *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); @@ -676,7 +678,7 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, goto fail; if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LEN) { - rc = -EMSGSIZE; + rc = -EIO; goto fail; } @@ -738,8 +740,10 @@ int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; - if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) + if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) { + rc = -EIO; goto fail; + } *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES); return 0; @@ -765,8 +769,10 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; - if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) + if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) { + rc = -EIO; goto fail; + } *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE); *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE); @@ -968,7 +974,7 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx) if (rc) return rc; if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) - return -EINVAL; + return -EIO; /* Print out any recorded assertion state */ flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS); @@ -1086,7 +1092,7 @@ int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, goto fail; if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) { - rc = -EMSGSIZE; + rc = -EIO; goto fail; } @@ -1121,7 +1127,7 @@ int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) goto fail; if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { - rc = -EMSGSIZE; + rc = -EIO; goto fail; } diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 2f2354696663..5d344874f294 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -48,7 +48,7 @@ efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg) goto fail; if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { - rc = -EMSGSIZE; + rc = -EIO; goto fail; } @@ -111,7 +111,7 @@ static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes) goto fail; if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) { - rc = -EMSGSIZE; + rc = -EIO; goto fail; } @@ -587,7 +587,7 @@ static int efx_mcdi_phy_test_alive(struct efx_nic *efx) return rc; if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN) - return -EMSGSIZE; + return -EIO; if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK) return -EINVAL; -- cgit v1.2.3 From 6369545945b90daa1a73fca174da9194c398417c Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:27:36 +0000 Subject: sfc: Handle serious errors in exactly one interrupt handler 'Fatal' errors set an interrupt flag associated with a specific event queue; only read the syndrome vector if we see that queue's flag set (legacy interrupts) or in the interrupt handler for that queue (MSI). Do not ignore an interrupt if the fatal error flag is set but specific error flags are all zero. Even if we don't schedule a reset, we must respect the queue mask and rearm the appropriate event queues. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/falcon.c | 13 ++++++++----- drivers/net/sfc/net_driver.h | 2 ++ drivers/net/sfc/nic.c | 35 +++++++++++++++++++---------------- 3 files changed, 29 insertions(+), 21 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d294d66fd600..d09ad1b1cd8b 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -175,16 +175,19 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); - /* Check to see if we have a serious error condition */ - syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); - if (unlikely(syserr)) - return efx_nic_fatal_interrupt(efx); - /* Determine interrupting queues, clear interrupt status * register and acknowledge the device interrupt. */ BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS); queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); + + /* Check to see if we have a serious error condition */ + if (queues & (1U << efx->fatal_irq_level)) { + syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) + return efx_nic_fatal_interrupt(efx); + } + EFX_ZERO_OWORD(*int_ker); wmb(); /* Ensure the vector is cleared before interrupt ack */ falcon_irq_ack_a1(efx); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index cb018e272097..70aea3af9ae7 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -672,6 +672,7 @@ union efx_multicast_hash { * This register is written with the SMP processor ID whenever an * interrupt is handled. It is used by efx_nic_test_interrupt() * to verify that an interrupt has occurred. + * @fatal_irq_level: IRQ level (bit number) used for serious errors * @spi_flash: SPI flash device * This field will be %NULL if no flash device is present (or for Siena). * @spi_eeprom: SPI EEPROM device @@ -756,6 +757,7 @@ struct efx_nic { struct efx_buffer irq_status; volatile signed int last_irq_cpu; unsigned long irq_zero_count; + unsigned fatal_irq_level; struct efx_spi_device *spi_flash; struct efx_spi_device *spi_eeprom; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 664fd6ceed55..23738f80835b 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1229,15 +1229,9 @@ static inline void efx_nic_interrupts(struct efx_nic *efx, bool enabled, bool force) { efx_oword_t int_en_reg_ker; - unsigned int level = 0; - - if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) - /* Set the level always even if we're generating a test - * interrupt, because our legacy interrupt handler is safe */ - level = 0x1f; EFX_POPULATE_OWORD_3(int_en_reg_ker, - FRF_AZ_KER_INT_LEVE_SEL, level, + FRF_AZ_KER_INT_LEVE_SEL, efx->fatal_irq_level, FRF_AZ_KER_INT_KER, force, FRF_AZ_DRV_INT_EN_KER, enabled); efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); @@ -1291,8 +1285,6 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), EFX_OWORD_VAL(fatal_intr), error ? "disabling bus mastering" : "no recognised error"); - if (error == 0) - goto out; /* If this is a memory parity error dump which blocks are offending */ mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); @@ -1324,7 +1316,7 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) "NIC will be disabled\n"); efx_schedule_reset(efx, RESET_TYPE_DISABLE); } -out: + return IRQ_HANDLED; } @@ -1346,9 +1338,11 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) queues = EFX_EXTRACT_DWORD(reg, 0, 31); /* Check to see if we have a serious error condition */ - syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); - if (unlikely(syserr)) - return efx_nic_fatal_interrupt(efx); + if (queues & (1U << efx->fatal_irq_level)) { + syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) + return efx_nic_fatal_interrupt(efx); + } if (queues != 0) { if (EFX_WORKAROUND_15783(efx)) @@ -1413,9 +1407,11 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); /* Check to see if we have a serious error condition */ - syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); - if (unlikely(syserr)) - return efx_nic_fatal_interrupt(efx); + if (channel->channel == efx->fatal_irq_level) { + syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) + return efx_nic_fatal_interrupt(efx); + } /* Schedule processing of the channel */ efx_schedule_channel(channel); @@ -1553,6 +1549,13 @@ void efx_nic_init_common(struct efx_nic *efx) FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER); + if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) + /* Use an interrupt level unused by event queues */ + efx->fatal_irq_level = 0x1f; + else + /* Use a valid MSI-X vector */ + efx->fatal_irq_level = 0; + /* Enable all the genuinely fatal interrupts. (They are still * masked by the overall interrupt mask, controlled by * falcon_interrupts()). -- cgit v1.2.3 From ef524f2e74b39cdf8d42b9d999c43b5144ed66c9 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:27:54 +0000 Subject: sfc: Stop masking out XGMII faults over reconfigures The aim of this code was to avoid a spurious XGMII fault over a MAC reconfigure. It's less relevant now that the PHY reconfigure isn't called from the MAC reconfigure. After applying this patch, our link stress test passed 48 hours of testing without ever resetting the PHY. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/falcon_xmac.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 8ccab2c67a20..3d65abf85b97 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -85,14 +85,14 @@ int falcon_reset_xaui(struct efx_nic *efx) return -ETIMEDOUT; } -static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) +static void falcon_ack_status_intr(struct efx_nic *efx) { efx_oword_t reg; if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) return; - /* We expect xgmii faults if the wireside link is up */ + /* We expect xgmii faults if the wireside link is down */ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up) return; @@ -101,14 +101,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) if (efx->xmac_poll_required) return; - /* Flush the ISR */ - if (enable) - efx_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); - - EFX_POPULATE_OWORD_2(reg, - FRF_AB_XM_MSK_RMTFLT, !enable, - FRF_AB_XM_MSK_LCLFLT, !enable); - efx_writeo(efx, ®, FR_AB_XM_MGT_INT_MASK); + efx_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); } static bool falcon_xgxs_link_ok(struct efx_nic *efx) @@ -283,15 +276,13 @@ static bool falcon_xmac_check_fault(struct efx_nic *efx) static int falcon_reconfigure_xmac(struct efx_nic *efx) { - falcon_mask_status_intr(efx, false); - falcon_reconfigure_xgxs_core(efx); falcon_reconfigure_xmac_core(efx); falcon_reconfigure_mac_wrapper(efx); efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5); - falcon_mask_status_intr(efx, true); + falcon_ack_status_intr(efx); return 0; } @@ -362,9 +353,8 @@ void falcon_poll_xmac(struct efx_nic *efx) !efx->xmac_poll_required) return; - falcon_mask_status_intr(efx, false); efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1); - falcon_mask_status_intr(efx, true); + falcon_ack_status_intr(efx); } struct efx_mac_operations falcon_xmac_operations = { -- cgit v1.2.3 From b7b40eeb0f76e73503a7e5a98d1353c2e42d9a18 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:28:10 +0000 Subject: sfc: Reconfigure the XAUI serdes after an EM reset Fix a regression introduced in d3245b28ef2a45ec4e115062a38100bd06229289 "sfc: Refactor link configuration". Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/falcon.c | 3 +++ drivers/net/sfc/falcon_xmac.c | 2 +- drivers/net/sfc/nic.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d09ad1b1cd8b..f7df24dce38a 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -507,6 +507,9 @@ static void falcon_reset_macs(struct efx_nic *efx) /* Ensure the correct MAC is selected before statistics * are re-enabled by the caller */ efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); + + /* This can run even when the GMAC is selected */ + falcon_setup_xaui(efx); } void falcon_drain_tx_fifo(struct efx_nic *efx) diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 3d65abf85b97..c84a2ce2ccbb 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -26,7 +26,7 @@ *************************************************************************/ /* Configure the XAUI driver that is an output from Falcon */ -static void falcon_setup_xaui(struct efx_nic *efx) +void falcon_setup_xaui(struct efx_nic *efx) { efx_oword_t sdctl, txdrv; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 9351c0331a47..7e3bec8561b8 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -203,6 +203,7 @@ extern void falcon_irq_ack_a1(struct efx_nic *efx); extern int efx_nic_flush_queues(struct efx_nic *efx); extern void falcon_start_nic_stats(struct efx_nic *efx); extern void falcon_stop_nic_stats(struct efx_nic *efx); +extern void falcon_setup_xaui(struct efx_nic *efx); extern int falcon_reset_xaui(struct efx_nic *efx); extern void efx_nic_init_common(struct efx_nic *efx); -- cgit v1.2.3 From 41b7e4c3268d9d2056b9c94cceb386649f7b185b Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:28:27 +0000 Subject: sfc: Extend the legacy interrupt workarounds Siena has two problems with legacy interrupts: 1. There is no synchronisation between the ISR read completion, and the interrupt deassert message. 2. A downstream read at the "wrong" moment can return 0, and suppress generating the next interrupt. Falcon should suffer from both of these, and it appears it does. Enable EFX_WORKAROUND_15783 on Falcon as well. Also, when we see queues == 0, ensure we always schedule or rearm every event queue. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/nic.c | 23 +++++++++-------------- drivers/net/sfc/workarounds.h | 2 +- 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 23738f80835b..b61674cb0c19 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1356,33 +1356,28 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) } result = IRQ_HANDLED; - } else if (EFX_WORKAROUND_15783(efx) && - efx->irq_zero_count++ == 0) { + } else if (EFX_WORKAROUND_15783(efx)) { efx_qword_t *event; - /* Ensure we rearm all event queues */ + /* We can't return IRQ_HANDLED more than once on seeing ISR=0 + * because this might be a shared interrupt. */ + if (efx->irq_zero_count++ == 0) + result = IRQ_HANDLED; + + /* Ensure we schedule or rearm all event queues */ efx_for_each_channel(channel, efx) { event = efx_event(channel, channel->eventq_read_ptr); if (efx_event_present(event)) efx_schedule_channel(channel); + else + efx_nic_eventq_read_ack(channel); } - - result = IRQ_HANDLED; } if (result == IRQ_HANDLED) { efx->last_irq_cpu = raw_smp_processor_id(); EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); - } else if (EFX_WORKAROUND_15783(efx)) { - /* We can't return IRQ_HANDLED more than once on seeing ISR0=0 - * because this might be a shared interrupt, but we do need to - * check the channel every time and preemptively rearm it if - * it's idle. */ - efx_for_each_channel(channel, efx) { - if (!channel->work_pending) - efx_nic_eventq_read_ack(channel); - } } return result; diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index acd9c734e483..518f7fc91473 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -37,7 +37,7 @@ /* Truncated IPv4 packets can confuse the TX packet parser */ #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB /* Legacy ISR read can return zero once */ -#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA +#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS /* Legacy interrupt storm when interrupt fifo fills */ #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA -- cgit v1.2.3 From b548a988a9d08f2b06f6810b1a4cde6f632bd307 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:28:36 +0000 Subject: sfc: Log specific message for failure of NVRAM self-test Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 1344afac4673..93cc3c1b9450 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -932,20 +932,26 @@ int efx_mcdi_nvram_test_all(struct efx_nic *efx) rc = efx_mcdi_nvram_types(efx, &nvram_types); if (rc) - return rc; + goto fail1; type = 0; while (nvram_types != 0) { if (nvram_types & 1) { rc = efx_mcdi_nvram_test(efx, type); if (rc) - return rc; + goto fail2; } type++; nvram_types >>= 1; } return 0; + +fail2: + EFX_ERR(efx, "%s: failed type=%u\n", __func__, type); +fail1: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; } static int efx_mcdi_read_assertion(struct efx_nic *efx) -- cgit v1.2.3 From 97e1eaa0e943439208a692b00dce4a8a3006760f Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:28:52 +0000 Subject: sfc: Read MEM_STAT for SRM_PERR as well as MEM_PERR errors Parity errors in different blocks of SRAM may set one of two different interrupt flags. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/nic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index b61674cb0c19..4105f9099c7c 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1287,7 +1287,8 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) error ? "disabling bus mastering" : "no recognised error"); /* If this is a memory parity error dump which blocks are offending */ - mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); + mem_perr = (EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER) || + EFX_OWORD_FIELD(fatal_intr, FRF_AZ_SRM_PERR_INT_KER)); if (mem_perr) { efx_oword_t reg; efx_reado(efx, ®, FR_AZ_MEM_STAT); -- cgit v1.2.3 From d614cfbc2f6f631e4dba72f945f185ea45ff3f78 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:29:02 +0000 Subject: sfc: Enable IPv6 RSS using random key for Toeplitz hash Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/nic.h | 2 ++ drivers/net/sfc/siena.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 7e3bec8561b8..5825f37b51bd 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -135,12 +135,14 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) * @fw_build: Firmware build number * @mcdi: Management-Controller-to-Driver Interface * @wol_filter_id: Wake-on-LAN packet filter id + * @ipv6_rss_key: Toeplitz hash key for IPv6 RSS */ struct siena_nic_data { u64 fw_version; u32 fw_build; struct efx_mcdi_iface mcdi; int wol_filter_id; + u8 ipv6_rss_key[40]; }; extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 38dcc42c4f79..7bf93faff3ab 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "net_driver.h" #include "bitfield.h" #include "efx.h" @@ -274,6 +275,9 @@ static int siena_probe_nic(struct efx_nic *efx) goto fail5; } + get_random_bytes(&nic_data->ipv6_rss_key, + sizeof(nic_data->ipv6_rss_key)); + return 0; fail5: @@ -293,6 +297,7 @@ fail1: */ static int siena_init_nic(struct efx_nic *efx) { + struct siena_nic_data *nic_data = efx->nic_data; efx_oword_t temp; int rc; @@ -319,6 +324,20 @@ static int siena_init_nic(struct efx_nic *efx) EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1); efx_writeo(efx, &temp, FR_AZ_RX_CFG); + /* Enable IPv6 RSS */ + BUILD_BUG_ON(sizeof(nic_data->ipv6_rss_key) != + 2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 || + FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0); + memcpy(&temp, nic_data->ipv6_rss_key, sizeof(temp)); + efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1); + memcpy(&temp, nic_data->ipv6_rss_key + sizeof(temp), sizeof(temp)); + efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2); + EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1, + FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1); + memcpy(&temp, nic_data->ipv6_rss_key + 2 * sizeof(temp), + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); + efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); + if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0) /* No MCDI operation has been defined to set thresholds */ EFX_ERR(efx, "ignoring RX flow control thresholds\n"); -- cgit v1.2.3 From fbcfe8e1525e6f2f633329147cdbb9ab7029f58a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:29:14 +0000 Subject: sfc: Update MCDI protocol definitions Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi_pcol.h | 71 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 16 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h index bd59302695b3..90359e644006 100644 --- a/drivers/net/sfc/mcdi_pcol.h +++ b/drivers/net/sfc/mcdi_pcol.h @@ -863,7 +863,7 @@ * bist output. The driver should only consume the BIST output * after validating OUTLEN and PHY_CFG.PHY_TYPE. * - * If a driver can't succesfully parse the BIST output, it should + * If a driver can't successfully parse the BIST output, it should * still respect the pass/Fail in OUT.RESULT * * Locks required: PHY_LOCK if doing a PHY BIST @@ -872,7 +872,7 @@ #define MC_CMD_POLL_BIST 0x26 #define MC_CMD_POLL_BIST_IN_LEN 0 #define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN -#define MC_CMD_POLL_BIST_OUT_SFT9001_LEN 40 +#define MC_CMD_POLL_BIST_OUT_SFT9001_LEN 36 #define MC_CMD_POLL_BIST_OUT_MRSFP_LEN 8 #define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0 #define MC_CMD_POLL_BIST_RUNNING 1 @@ -882,15 +882,14 @@ /* Generic: */ #define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4 /* SFT9001-specific: */ -/* (offset 4 unused?) */ -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A_OFST 8 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 12 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 16 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 20 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 24 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 28 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 32 -#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 36 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A_OFST 4 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 8 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 12 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 16 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 20 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 24 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 28 +#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 32 #define MC_CMD_POLL_BIST_SFT9001_PAIR_OK 1 #define MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN 2 #define MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT 3 @@ -1054,9 +1053,13 @@ /* MC_CMD_PHY_STATS: * Get generic PHY statistics * - * This call returns the statistics for a generic PHY, by direct DMA - * into host memory, in a sparse array (indexed by the enumerate). - * Each value is represented by a 32bit number. + * This call returns the statistics for a generic PHY in a sparse + * array (indexed by the enumerate). Each value is represented by + * a 32bit number. + * + * If the DMA_ADDR is 0, then no DMA is performed, and the statistics + * may be read directly out of shared memory. If DMA_ADDR != 0, then + * the statistics are dmad to that (page-aligned location) * * Locks required: None * Returns: 0, ETIME @@ -1066,7 +1069,8 @@ #define MC_CMD_PHY_STATS_IN_LEN 8 #define MC_CMD_PHY_STATS_IN_DMA_ADDR_LO_OFST 0 #define MC_CMD_PHY_STATS_IN_DMA_ADDR_HI_OFST 4 -#define MC_CMD_PHY_STATS_OUT_LEN 0 +#define MC_CMD_PHY_STATS_OUT_DMA_LEN 0 +#define MC_CMD_PHY_STATS_OUT_NO_DMA_LEN (MC_CMD_PHY_NSTATS * 4) /* Unified MAC statistics enumeration */ #define MC_CMD_MAC_GENERATION_START 0 @@ -1158,11 +1162,13 @@ #define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1 -/* Fields only relevent when PERIODIC_CHANGE is set */ +/* Remaining PERIOD* fields only relevent when PERIODIC_CHANGE is set */ #define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3 #define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_WIDTH 1 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT_LBN 5 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT_WIDTH 1 #define MC_CMD_MAC_STATS_CMD_PERIOD_MS_LBN 16 #define MC_CMD_MAC_STATS_CMD_PERIOD_MS_WIDTH 16 #define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12 @@ -1729,6 +1735,39 @@ #define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_OUTPUTS_OFST 4 /* output bits */ #define MC_CMD_MRSFP_TWEAK_OUT_IOEXP_DIRECTION_OFST 8 /* dirs: 0=out, 1=in */ +/* MC_CMD_TEST_HACK: (debug (unsurprisingly)) + * Change bits of network port state for test purposes in ways that would never be + * useful in normal operation and so need a special command to change. */ +#define MC_CMD_TEST_HACK 0x2f +#define MC_CMD_TEST_HACK_IN_LEN 8 +#define MC_CMD_TEST_HACK_IN_TXPAD_OFST 0 +#define MC_CMD_TEST_HACK_IN_TXPAD_AUTO 0 /* Let the MC manage things */ +#define MC_CMD_TEST_HACK_IN_TXPAD_ON 1 /* Force on */ +#define MC_CMD_TEST_HACK_IN_TXPAD_OFF 2 /* Force on */ +#define MC_CMD_TEST_HACK_IN_IPG_OFST 4 /* Takes a value in bits */ +#define MC_CMD_TEST_HACK_IN_IPG_AUTO 0 /* The MC picks the value */ +#define MC_CMD_TEST_HACK_OUT_LEN 0 + +/* MC_CMD_SENSOR_SET_LIMS: (debug) (mostly) adjust the sensor limits. This + * is a warranty-voiding operation. + * + * IN: sensor identifier (one of the enumeration starting with MC_CMD_SENSOR_CONTROLLER_TEMP + * followed by 4 32-bit values: min(warning) max(warning), min(fatal), max(fatal). Which + * of these limits are meaningful and what their interpretation is is sensor-specific. + * + * OUT: nothing + * + * Returns: ENOENT if the sensor specified does not exist, EINVAL if the limits are + * out of range. + */ +#define MC_CMD_SENSOR_SET_LIMS 0x4e +#define MC_CMD_SENSOR_SET_LIMS_IN_LEN 20 +#define MC_CMD_SENSOR_SET_LIMS_IN_SENSOR_OFST 0 +#define MC_CMD_SENSOR_SET_LIMS_IN_LOW0_OFST 4 +#define MC_CMD_SENSOR_SET_LIMS_IN_HI0_OFST 8 +#define MC_CMD_SENSOR_SET_LIMS_IN_LOW1_OFST 12 +#define MC_CMD_SENSOR_SET_LIMS_IN_HI1_OFST 16 + /* Do NOT add new commands beyond 0x4f as part of 3.0 : 0x50 - 0x7f will be * used for post-3.0 extensions. If you run out of space, look for gaps or * commands that are unused in the existing range. */ -- cgit v1.2.3 From 3a595102d4298a357d70aaf1d47ae86d92708ea9 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:29:32 +0000 Subject: sfc: Set PERIODIC_NOEVENT flag for MC_CMD_MAC_STATS When set, an event is not sent whenever periodic MAC statistics are raised. This avoids unnecessary wake-ups. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi_mac.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c index 06d24a1e412a..39182631ac92 100644 --- a/drivers/net/sfc/mcdi_mac.c +++ b/drivers/net/sfc/mcdi_mac.c @@ -80,7 +80,7 @@ int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, u8 inbuf[MC_CMD_MAC_STATS_IN_LEN]; int rc; efx_dword_t *cmd_ptr; - int period = 1000; + int period = enable ? 1000 : 0; u32 addr_hi; u32 addr_lo; @@ -92,21 +92,14 @@ int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo); MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi); cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD); - if (enable) - EFX_POPULATE_DWORD_6(*cmd_ptr, - MC_CMD_MAC_STATS_CMD_DMA, 1, - MC_CMD_MAC_STATS_CMD_CLEAR, clear, - MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, - MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 1, - MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0, - MC_CMD_MAC_STATS_CMD_PERIOD_MS, period); - else - EFX_POPULATE_DWORD_5(*cmd_ptr, - MC_CMD_MAC_STATS_CMD_DMA, 0, - MC_CMD_MAC_STATS_CMD_CLEAR, clear, - MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, - MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 0, - MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0); + EFX_POPULATE_DWORD_7(*cmd_ptr, + MC_CMD_MAC_STATS_CMD_DMA, !!enable, + MC_CMD_MAC_STATS_CMD_CLEAR, clear, + MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, + MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, !!enable, + MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0, + MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT, 1, + MC_CMD_MAC_STATS_CMD_PERIOD_MS, period); MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len); rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf), -- cgit v1.2.3 From fa236e18047ec178b07fdf3f24f286eef1797842 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:29:42 +0000 Subject: sfc: Break NAPI processing after one ring-full of TX completions Currently TX completions do not count towards the NAPI budget. This means a continuous stream of TX completions can cause the polling function to loop indefinitely with scheduling disabled. To avoid this, follow the common practice of reporting the budget spent after processing one ring-full of TX completions. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 18 +++++++++--------- drivers/net/sfc/nic.c | 39 ++++++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 24 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 1ad61b7bba40..5e3f944fdd95 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -225,17 +225,17 @@ static void efx_fini_channels(struct efx_nic *efx); * never be concurrently called more than once on the same channel, * though different channels may be being processed concurrently. */ -static int efx_process_channel(struct efx_channel *channel, int rx_quota) +static int efx_process_channel(struct efx_channel *channel, int budget) { struct efx_nic *efx = channel->efx; - int rx_packets; + int spent; if (unlikely(efx->reset_pending != RESET_TYPE_NONE || !channel->enabled)) return 0; - rx_packets = efx_nic_process_eventq(channel, rx_quota); - if (rx_packets == 0) + spent = efx_nic_process_eventq(channel, budget); + if (spent == 0) return 0; /* Deliver last RX packet. */ @@ -249,7 +249,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota) efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]); - return rx_packets; + return spent; } /* Mark channel as finished processing @@ -278,14 +278,14 @@ static int efx_poll(struct napi_struct *napi, int budget) { struct efx_channel *channel = container_of(napi, struct efx_channel, napi_str); - int rx_packets; + int spent; EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n", channel->channel, raw_smp_processor_id()); - rx_packets = efx_process_channel(channel, budget); + spent = efx_process_channel(channel, budget); - if (rx_packets < budget) { + if (spent < budget) { struct efx_nic *efx = channel->efx; if (channel->used_flags & EFX_USED_BY_RX && @@ -318,7 +318,7 @@ static int efx_poll(struct napi_struct *napi, int budget) efx_channel_processed(channel); } - return rx_packets; + return spent; } /* Process the eventq of the specified channel immediately on this CPU diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 4105f9099c7c..f3226bbf9831 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -654,22 +654,23 @@ void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) * The NIC batches TX completion events; the message we receive is of * the form "complete all TX events up to this index". */ -static void +static int efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) { unsigned int tx_ev_desc_ptr; unsigned int tx_ev_q_label; struct efx_tx_queue *tx_queue; struct efx_nic *efx = channel->efx; + int tx_packets = 0; if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) { /* Transmit completion */ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR); tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); tx_queue = &efx->tx_queue[tx_ev_q_label]; - channel->irq_mod_score += - (tx_ev_desc_ptr - tx_queue->read_count) & - EFX_TXQ_MASK; + tx_packets = ((tx_ev_desc_ptr - tx_queue->read_count) & + EFX_TXQ_MASK); + channel->irq_mod_score += tx_packets; efx_xmit_done(tx_queue, tx_ev_desc_ptr); } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { /* Rewrite the FIFO write pointer */ @@ -689,6 +690,8 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) EFX_QWORD_FMT"\n", channel->channel, EFX_QWORD_VAL(*event)); } + + return tx_packets; } /* Detect errors included in the rx_evt_pkt_ok bit. */ @@ -947,16 +950,17 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) } } -int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) +int efx_nic_process_eventq(struct efx_channel *channel, int budget) { unsigned int read_ptr; efx_qword_t event, *p_event; int ev_code; - int rx_packets = 0; + int tx_packets = 0; + int spent = 0; read_ptr = channel->eventq_read_ptr; - do { + for (;;) { p_event = efx_event(channel, read_ptr); event = *p_event; @@ -970,15 +974,23 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) /* Clear this event by marking it all ones */ EFX_SET_QWORD(*p_event); + /* Increment read pointer */ + read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; + ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); switch (ev_code) { case FSE_AZ_EV_CODE_RX_EV: efx_handle_rx_event(channel, &event); - ++rx_packets; + if (++spent == budget) + goto out; break; case FSE_AZ_EV_CODE_TX_EV: - efx_handle_tx_event(channel, &event); + tx_packets += efx_handle_tx_event(channel, &event); + if (tx_packets >= EFX_TXQ_SIZE) { + spent = budget; + goto out; + } break; case FSE_AZ_EV_CODE_DRV_GEN_EV: channel->eventq_magic = EFX_QWORD_FIELD( @@ -1001,14 +1013,11 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) " (data " EFX_QWORD_FMT ")\n", channel->channel, ev_code, EFX_QWORD_VAL(event)); } + } - /* Increment read pointer */ - read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; - - } while (rx_packets < rx_quota); - +out: channel->eventq_read_ptr = read_ptr; - return rx_packets; + return spent; } -- cgit v1.2.3 From 3d07df11c4be368681c0b8228c3d80eeb1fcfabd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:29:50 +0000 Subject: sfc: Add necessary parentheses to macro definitions in net_driver.h Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/net_driver.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 70aea3af9ae7..bdea03c54e07 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -926,8 +926,8 @@ struct efx_nic_type { /* Iterate over all used channels */ #define efx_for_each_channel(_channel, _efx) \ - for (_channel = &_efx->channel[0]; \ - _channel < &_efx->channel[EFX_MAX_CHANNELS]; \ + for (_channel = &((_efx)->channel[0]); \ + _channel < &((_efx)->channel[EFX_MAX_CHANNELS]); \ _channel++) \ if (!_channel->used_flags) \ continue; \ @@ -935,31 +935,31 @@ struct efx_nic_type { /* Iterate over all used TX queues */ #define efx_for_each_tx_queue(_tx_queue, _efx) \ - for (_tx_queue = &_efx->tx_queue[0]; \ - _tx_queue < &_efx->tx_queue[EFX_TX_QUEUE_COUNT]; \ + for (_tx_queue = &((_efx)->tx_queue[0]); \ + _tx_queue < &((_efx)->tx_queue[EFX_TX_QUEUE_COUNT]); \ _tx_queue++) /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ - for (_tx_queue = &_channel->efx->tx_queue[0]; \ - _tx_queue < &_channel->efx->tx_queue[EFX_TX_QUEUE_COUNT]; \ + for (_tx_queue = &((_channel)->efx->tx_queue[0]); \ + _tx_queue < &((_channel)->efx->tx_queue[EFX_TX_QUEUE_COUNT]); \ _tx_queue++) \ - if (_tx_queue->channel != _channel) \ + if (_tx_queue->channel != (_channel)) \ continue; \ else /* Iterate over all used RX queues */ #define efx_for_each_rx_queue(_rx_queue, _efx) \ - for (_rx_queue = &_efx->rx_queue[0]; \ - _rx_queue < &_efx->rx_queue[_efx->n_rx_queues]; \ + for (_rx_queue = &((_efx)->rx_queue[0]); \ + _rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_queues]); \ _rx_queue++) /* Iterate over all RX queues belonging to a channel */ #define efx_for_each_channel_rx_queue(_rx_queue, _channel) \ - for (_rx_queue = &_channel->efx->rx_queue[_channel->channel]; \ + for (_rx_queue = &((_channel)->efx->rx_queue[(_channel)->channel]); \ _rx_queue; \ _rx_queue = NULL) \ - if (_rx_queue->channel != _channel) \ + if (_rx_queue->channel != (_channel)) \ continue; \ else -- cgit v1.2.3 From c28884c57400de326ba4c1ff9608f1d425bdd0fd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:30:00 +0000 Subject: sfc: Clean up efx_nic::irq_zero_count There is no need for this to be unsigned long; make it unsigned int. It does need a line in kernel-doc, so add that. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/net_driver.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index bdea03c54e07..d68331c7fb5d 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -672,6 +672,7 @@ union efx_multicast_hash { * This register is written with the SMP processor ID whenever an * interrupt is handled. It is used by efx_nic_test_interrupt() * to verify that an interrupt has occurred. + * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0 * @fatal_irq_level: IRQ level (bit number) used for serious errors * @spi_flash: SPI flash device * This field will be %NULL if no flash device is present (or for Siena). @@ -756,7 +757,7 @@ struct efx_nic { struct efx_buffer irq_status; volatile signed int last_irq_cpu; - unsigned long irq_zero_count; + unsigned irq_zero_count; unsigned fatal_irq_level; struct efx_spi_device *spi_flash; -- cgit v1.2.3 From affaf485ca628cb7d7f57ae5e2b8c710c58b11aa Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Wed, 28 Apr 2010 09:30:22 +0000 Subject: sfc: Add Siena PHY BIST and cable diagnostic support Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/mcdi_phy.c | 146 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index 5d344874f294..6032c0e1f1f8 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -17,6 +17,8 @@ #include "mcdi.h" #include "mcdi_pcol.h" #include "mdio_10g.h" +#include "nic.h" +#include "selftest.h" struct efx_mcdi_phy_cfg { u32 flags; @@ -594,6 +596,146 @@ static int efx_mcdi_phy_test_alive(struct efx_nic *efx) return 0; } +static const char *const mcdi_sft9001_cable_diag_names[] = { + "cable.pairA.length", + "cable.pairB.length", + "cable.pairC.length", + "cable.pairD.length", + "cable.pairA.status", + "cable.pairB.status", + "cable.pairC.status", + "cable.pairD.status", +}; + +static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode, + int *results) +{ + unsigned int retry, i, count = 0; + size_t outlen; + u32 status; + u8 *buf, *ptr; + int rc; + + buf = kzalloc(0x100, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0); + MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode); + rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN, + NULL, 0, NULL); + if (rc) + goto out; + + /* Wait up to 10s for BIST to finish */ + for (retry = 0; retry < 100; ++retry) { + BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0); + rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0, + buf, 0x100, &outlen); + if (rc) + goto out; + + status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT); + if (status != MC_CMD_POLL_BIST_RUNNING) + goto finished; + + msleep(100); + } + + rc = -ETIMEDOUT; + goto out; + +finished: + results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1; + + /* SFT9001 specific cable diagnostics output */ + if (efx->phy_type == PHY_TYPE_SFT9001B && + (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT || + bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) { + ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); + if (status == MC_CMD_POLL_BIST_PASSED && + outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) { + for (i = 0; i < 8; i++) { + results[count + i] = + EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i], + EFX_DWORD_0); + } + } + count += 8; + } + rc = count; + +out: + kfree(buf); + + return rc; +} + +static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results, + unsigned flags) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + u32 mode; + int rc; + + if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) { + rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results); + if (rc < 0) + return rc; + + results += rc; + } + + /* If we support both LONG and SHORT, then run each in response to + * break or not. Otherwise, run the one we support */ + mode = 0; + if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN)) { + if ((flags & ETH_TEST_FL_OFFLINE) && + (phy_cfg->flags & + (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) + mode = MC_CMD_PHY_BIST_CABLE_LONG; + else + mode = MC_CMD_PHY_BIST_CABLE_SHORT; + } else if (phy_cfg->flags & + (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN)) + mode = MC_CMD_PHY_BIST_CABLE_LONG; + + if (mode != 0) { + rc = efx_mcdi_bist(efx, mode, results); + if (rc < 0) + return rc; + results += rc; + } + + return 0; +} + +const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + + if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) { + if (index == 0) + return "bist"; + --index; + } + + if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN) | + (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) { + if (index == 0) + return "cable"; + --index; + + if (efx->phy_type == PHY_TYPE_SFT9001B) { + if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names)) + return mcdi_sft9001_cable_diag_names[index]; + index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names); + } + } + + return NULL; +} + struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, @@ -604,6 +746,6 @@ struct efx_phy_operations efx_mcdi_phy_ops = { .get_settings = efx_mcdi_phy_get_settings, .set_settings = efx_mcdi_phy_set_settings, .test_alive = efx_mcdi_phy_test_alive, - .run_tests = NULL, - .test_name = NULL, + .run_tests = efx_mcdi_phy_run_tests, + .test_name = efx_mcdi_phy_test_name, }; -- cgit v1.2.3 From 5298c37f4d1f0360082be9d9e3a236b9cc114a03 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:30:30 +0000 Subject: sfc: Test only the first pair of TX queues This makes no immediate difference, but we definitely do not want to test all TX queues once we allocate a pair of TX queues to each channel. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/ethtool.c | 2 +- drivers/net/sfc/selftest.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index d9f9c02a928e..cbe9319f8322 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -304,7 +304,7 @@ static int efx_fill_loopback_test(struct efx_nic *efx, { struct efx_tx_queue *tx_queue; - efx_for_each_tx_queue(tx_queue, efx) { + efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) { efx_fill_test(test_index++, strings, data, &lb_tests->tx_sent[tx_queue->queue], EFX_TX_QUEUE_NAME(tx_queue), diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 0106b1d9aae2..3a16e0612267 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -616,8 +616,8 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, goto out; } - /* Test every TX queue */ - efx_for_each_tx_queue(tx_queue, efx) { + /* Test both types of TX queue */ + efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) { state->offload_csum = (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM); rc = efx_test_loopback(tx_queue, -- cgit v1.2.3 From a4900ac9f7d10ad062e54dd03125e3619e0ac17a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2010 09:30:43 +0000 Subject: sfc: Create multiple TX queues Create a core TX queue and 2 hardware TX queues for each channel. If separate_tx_channels is set, create equal numbers of RX and TX channels instead. Rewrite the channel and queue iteration macros accordingly. Eliminate efx_channel::used_flags as redundant. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 113 +++++++++++++++++++++++-------------------- drivers/net/sfc/efx.h | 4 +- drivers/net/sfc/ethtool.c | 4 +- drivers/net/sfc/net_driver.h | 61 +++++++++++------------ drivers/net/sfc/nic.c | 12 ++--- drivers/net/sfc/selftest.c | 4 +- drivers/net/sfc/selftest.h | 4 +- drivers/net/sfc/tx.c | 61 ++++++++++++++--------- 8 files changed, 140 insertions(+), 123 deletions(-) (limited to 'drivers/net/sfc') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 5e3f944fdd95..bc75ef683c9f 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -288,7 +288,7 @@ static int efx_poll(struct napi_struct *napi, int budget) if (spent < budget) { struct efx_nic *efx = channel->efx; - if (channel->used_flags & EFX_USED_BY_RX && + if (channel->channel < efx->n_rx_channels && efx->irq_rx_adaptive && unlikely(++channel->irq_count == 1000)) { if (unlikely(channel->irq_mod_score < @@ -333,7 +333,6 @@ void efx_process_channel_now(struct efx_channel *channel) { struct efx_nic *efx = channel->efx; - BUG_ON(!channel->used_flags); BUG_ON(!channel->enabled); /* Disable interrupts and wait for ISRs to complete */ @@ -446,12 +445,12 @@ static void efx_set_channel_names(struct efx_nic *efx) efx_for_each_channel(channel, efx) { number = channel->channel; - if (efx->n_channels > efx->n_rx_queues) { - if (channel->channel < efx->n_rx_queues) { + if (efx->n_channels > efx->n_rx_channels) { + if (channel->channel < efx->n_rx_channels) { type = "-rx"; } else { type = "-tx"; - number -= efx->n_rx_queues; + number -= efx->n_rx_channels; } } snprintf(channel->name, sizeof(channel->name), @@ -585,8 +584,6 @@ static void efx_remove_channel(struct efx_channel *channel) efx_for_each_channel_tx_queue(tx_queue, channel) efx_remove_tx_queue(tx_queue); efx_remove_eventq(channel); - - channel->used_flags = 0; } void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) @@ -956,10 +953,9 @@ static void efx_fini_io(struct efx_nic *efx) pci_disable_device(efx->pci_dev); } -/* Get number of RX queues wanted. Return number of online CPU - * packages in the expectation that an IRQ balancer will spread - * interrupts across them. */ -static int efx_wanted_rx_queues(void) +/* Get number of channels wanted. Each channel will have its own IRQ, + * 1 RX queue and/or 2 TX queues. */ +static int efx_wanted_channels(void) { cpumask_var_t core_mask; int count; @@ -995,34 +991,39 @@ static void efx_probe_interrupts(struct efx_nic *efx) if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { struct msix_entry xentries[EFX_MAX_CHANNELS]; - int wanted_ints; - int rx_queues; + int n_channels; - /* We want one RX queue and interrupt per CPU package - * (or as specified by the rss_cpus module parameter). - * We will need one channel per interrupt. - */ - rx_queues = rss_cpus ? rss_cpus : efx_wanted_rx_queues(); - wanted_ints = rx_queues + (separate_tx_channels ? 1 : 0); - wanted_ints = min(wanted_ints, max_channels); + n_channels = efx_wanted_channels(); + if (separate_tx_channels) + n_channels *= 2; + n_channels = min(n_channels, max_channels); - for (i = 0; i < wanted_ints; i++) + for (i = 0; i < n_channels; i++) xentries[i].entry = i; - rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints); + rc = pci_enable_msix(efx->pci_dev, xentries, n_channels); if (rc > 0) { EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors" - " available (%d < %d).\n", rc, wanted_ints); + " available (%d < %d).\n", rc, n_channels); EFX_ERR(efx, "WARNING: Performance may be reduced.\n"); - EFX_BUG_ON_PARANOID(rc >= wanted_ints); - wanted_ints = rc; + EFX_BUG_ON_PARANOID(rc >= n_channels); + n_channels = rc; rc = pci_enable_msix(efx->pci_dev, xentries, - wanted_ints); + n_channels); } if (rc == 0) { - efx->n_rx_queues = min(rx_queues, wanted_ints); - efx->n_channels = wanted_ints; - for (i = 0; i < wanted_ints; i++) + efx->n_channels = n_channels; + if (separate_tx_channels) { + efx->n_tx_channels = + max(efx->n_channels / 2, 1U); + efx->n_rx_channels = + max(efx->n_channels - + efx->n_tx_channels, 1U); + } else { + efx->n_tx_channels = efx->n_channels; + efx->n_rx_channels = efx->n_channels; + } + for (i = 0; i < n_channels; i++) efx->channel[i].irq = xentries[i].vector; } else { /* Fall back to single channel MSI */ @@ -1033,8 +1034,9 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Try single interrupt MSI */ if (efx->interrupt_mode == EFX_INT_MODE_MSI) { - efx->n_rx_queues = 1; efx->n_channels = 1; + efx->n_rx_channels = 1; + efx->n_tx_channels = 1; rc = pci_enable_msi(efx->pci_dev); if (rc == 0) { efx->channel[0].irq = efx->pci_dev->irq; @@ -1046,8 +1048,9 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Assume legacy interrupts */ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { - efx->n_rx_queues = 1; efx->n_channels = 1 + (separate_tx_channels ? 1 : 0); + efx->n_rx_channels = 1; + efx->n_tx_channels = 1; efx->legacy_irq = efx->pci_dev->irq; } } @@ -1068,21 +1071,24 @@ static void efx_remove_interrupts(struct efx_nic *efx) static void efx_set_channels(struct efx_nic *efx) { + struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + unsigned tx_channel_offset = + separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; - 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_channel(channel, efx) { + if (channel->channel - tx_channel_offset < efx->n_tx_channels) { + channel->tx_queue = &efx->tx_queue[ + (channel->channel - tx_channel_offset) * + EFX_TXQ_TYPES]; + efx_for_each_channel_tx_queue(tx_queue, channel) + tx_queue->channel = channel; + } } - efx_for_each_rx_queue(rx_queue, efx) { + 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; - } } static int efx_probe_nic(struct efx_nic *efx) @@ -1096,11 +1102,12 @@ static int efx_probe_nic(struct efx_nic *efx) if (rc) return rc; - /* Determine the number of channels and RX queues by trying to hook + /* Determine the number of channels and queues by trying to hook * in MSI-X interrupts. */ efx_probe_interrupts(efx); efx_set_channels(efx); + efx->net_dev->real_num_tx_queues = efx->n_tx_channels; /* Initialise the interrupt moderation settings */ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true); @@ -1187,11 +1194,12 @@ static void efx_start_all(struct efx_nic *efx) /* 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); - if (efx_dev_registered(efx)) - efx_wake_queue(efx); - efx_for_each_channel(channel, efx) + efx_for_each_channel(channel, efx) { + if (efx_dev_registered(efx)) + efx_wake_queue(channel); efx_start_channel(channel); + } efx_nic_enable_interrupts(efx); @@ -1282,7 +1290,9 @@ static void efx_stop_all(struct efx_nic *efx) /* Stop the kernel transmit interface late, so the watchdog * timer isn't ticking over the flush */ if (efx_dev_registered(efx)) { - efx_stop_queue(efx); + struct efx_channel *channel; + efx_for_each_channel(channel, efx) + efx_stop_queue(channel); netif_tx_lock_bh(efx->net_dev); netif_tx_unlock_bh(efx->net_dev); } @@ -1537,9 +1547,8 @@ static void efx_watchdog(struct net_device *net_dev) { 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_ERR(efx, "TX stuck with port_enabled=%d: resetting channels\n", + efx->port_enabled); efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); } @@ -2014,22 +2023,22 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->net_dev = net_dev; efx->rx_checksum_enabled = true; - spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); efx->mac_op = type->default_mac_ops; efx->phy_op = &efx_dummy_phy_operations; efx->mdio.dev = net_dev; 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->work_pending = false; + spin_lock_init(&channel->tx_stop_lock); + atomic_set(&channel->tx_stop_count, 1); } - for (i = 0; i < EFX_TX_QUEUE_COUNT; i++) { + for (i = 0; i < EFX_MAX_TX_QUEUES; i++) { tx_queue = &efx->tx_queue[i]; tx_queue->efx = efx; tx_queue->queue = i; @@ -2201,7 +2210,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, int i, rc; /* Allocate and initialise a struct net_device and struct efx_nic */ - net_dev = alloc_etherdev(sizeof(*efx)); + net_dev = alloc_etherdev_mq(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES); if (!net_dev) return -ENOMEM; net_dev->features |= (type->offload_features | NETIF_F_SG | diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 7eff0a615cb3..ffd708c5304a 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -35,8 +35,8 @@ 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); extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); -extern void efx_stop_queue(struct efx_nic *efx); -extern void efx_wake_queue(struct efx_nic *efx); +extern void efx_stop_queue(struct efx_channel *channel); +extern void efx_wake_queue(struct efx_channel *channel); #define EFX_TXQ_SIZE 1024 #define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1) diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index cbe9319f8322..22026bfbc4c1 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -647,7 +647,7 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, efx_for_each_tx_queue(tx_queue, efx) { channel = tx_queue->channel; if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) { - if (channel->used_flags != EFX_USED_BY_RX_TX) + if (channel->channel < efx->n_rx_channels) coalesce->tx_coalesce_usecs_irq = channel->irq_moderation; else @@ -690,7 +690,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, /* If the channel is shared only allow RX parameters to be set */ efx_for_each_tx_queue(tx_queue, efx) { - if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) && + if ((tx_queue->channel->channel < efx->n_rx_channels) && tx_usecs) { EFX_ERR(efx, "Channel is shared. " "Only RX coalescing may be set\n"); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index d68331c7fb5d..2e6fd89f2a72 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -85,9 +85,13 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0) #define EFX_MAX_CHANNELS 32 #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS -#define EFX_TX_QUEUE_OFFLOAD_CSUM 0 -#define EFX_TX_QUEUE_NO_CSUM 1 -#define EFX_TX_QUEUE_COUNT 2 +/* Checksum generation is a per-queue option in hardware, so each + * queue visible to the networking core is backed by two hardware TX + * queues. */ +#define EFX_MAX_CORE_TX_QUEUES EFX_MAX_CHANNELS +#define EFX_TXQ_TYPE_OFFLOAD 1 +#define EFX_TXQ_TYPES 2 +#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CORE_TX_QUEUES) /** * struct efx_special_buffer - An Efx special buffer @@ -187,7 +191,7 @@ struct efx_tx_buffer { struct efx_tx_queue { /* Members which don't change on the fast path */ struct efx_nic *efx ____cacheline_aligned_in_smp; - int queue; + unsigned queue; struct efx_channel *channel; struct efx_nic *nic; struct efx_tx_buffer *buffer; @@ -306,11 +310,6 @@ struct efx_buffer { }; -/* Flags for channel->used_flags */ -#define EFX_USED_BY_RX 1 -#define EFX_USED_BY_TX 2 -#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX) - enum efx_rx_alloc_method { RX_ALLOC_METHOD_AUTO = 0, RX_ALLOC_METHOD_SKB = 1, @@ -327,7 +326,6 @@ enum efx_rx_alloc_method { * @efx: Associated Efx NIC * @channel: Channel instance number * @name: Name for channel and IRQ - * @used_flags: Channel is used by net driver * @enabled: Channel enabled indicator * @irq: IRQ number (MSI and MSI-X only) * @irq_moderation: IRQ moderation value (in hardware ticks) @@ -352,12 +350,14 @@ enum efx_rx_alloc_method { * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors * @n_rx_overlength: Count of RX_OVERLENGTH errors * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun + * @tx_queue: Pointer to first TX queue, or %NULL if not used for TX + * @tx_stop_count: Core TX queue stop count + * @tx_stop_lock: Core TX queue stop lock */ struct efx_channel { struct efx_nic *efx; int channel; char name[IFNAMSIZ + 6]; - int used_flags; bool enabled; int irq; unsigned int irq_moderation; @@ -389,6 +389,9 @@ struct efx_channel { struct efx_rx_buffer *rx_pkt; bool rx_pkt_csummed; + struct efx_tx_queue *tx_queue; + atomic_t tx_stop_count; + spinlock_t tx_stop_lock; }; enum efx_led_mode { @@ -661,8 +664,9 @@ union efx_multicast_hash { * @rx_queue: RX DMA queues * @channel: Channels * @next_buffer_table: First available buffer table id - * @n_rx_queues: Number of RX queues * @n_channels: Number of channels in use + * @n_rx_channels: Number of channels used for RX (= number of RX queues) + * @n_tx_channels: Number of channels used for TX * @rx_buffer_len: RX buffer length * @rx_buffer_order: Order (log2) of number of pages for each RX buffer * @int_error_count: Number of internal errors seen recently @@ -693,8 +697,6 @@ union efx_multicast_hash { * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock * @rx_checksum_enabled: RX checksumming enabled - * @netif_stop_count: Port stop count - * @netif_stop_lock: Port stop lock * @mac_stats: MAC statistics. These include all statistics the MACs * can provide. Generic code converts these into a standard * &struct net_device_stats. @@ -742,13 +744,14 @@ struct efx_nic { enum nic_state state; enum reset_type reset_pending; - struct efx_tx_queue tx_queue[EFX_TX_QUEUE_COUNT]; + struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES]; struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES]; struct efx_channel channel[EFX_MAX_CHANNELS]; unsigned next_buffer_table; - int n_rx_queues; - int n_channels; + unsigned n_channels; + unsigned n_rx_channels; + unsigned n_tx_channels; unsigned int rx_buffer_len; unsigned int rx_buffer_order; @@ -780,9 +783,6 @@ struct efx_nic { struct net_device *net_dev; bool rx_checksum_enabled; - atomic_t netif_stop_count; - spinlock_t netif_stop_lock; - struct efx_mac_stats mac_stats; struct efx_buffer stats_buffer; spinlock_t stats_lock; @@ -928,31 +928,26 @@ struct efx_nic_type { /* Iterate over all used channels */ #define efx_for_each_channel(_channel, _efx) \ for (_channel = &((_efx)->channel[0]); \ - _channel < &((_efx)->channel[EFX_MAX_CHANNELS]); \ - _channel++) \ - if (!_channel->used_flags) \ - continue; \ - else + _channel < &((_efx)->channel[(efx)->n_channels]); \ + _channel++) /* Iterate over all used TX queues */ #define efx_for_each_tx_queue(_tx_queue, _efx) \ for (_tx_queue = &((_efx)->tx_queue[0]); \ - _tx_queue < &((_efx)->tx_queue[EFX_TX_QUEUE_COUNT]); \ + _tx_queue < &((_efx)->tx_queue[EFX_TXQ_TYPES * \ + (_efx)->n_tx_channels]); \ _tx_queue++) /* Iterate over all TX queues belonging to a channel */ #define efx_for_each_channel_tx_queue(_tx_queue, _channel) \ - for (_tx_queue = &((_channel)->efx->tx_queue[0]); \ - _tx_queue < &((_channel)->efx->tx_queue[EFX_TX_QUEUE_COUNT]); \ - _tx_queue++) \ - if (_tx_queue->channel != (_channel)) \ - continue; \ - else + for (_tx_queue = (_channel)->tx_queue; \ + _tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \ + _tx_queue++) /* Iterate over all used RX queues */ #define efx_for_each_rx_queue(_rx_queue, _efx) \ for (_rx_queue = &((_efx)->rx_queue[0]); \ - _rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_queues]); \ + _rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_channels]); \ _rx_queue++) /* Iterate over all RX queues belonging to a channel */ diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index f3226bbf9831..5d3aaec58556 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -418,7 +418,7 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) FRF_BZ_TX_NON_IP_DROP_DIS, 1); if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { - int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; + int csum = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD; EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, !csum); @@ -431,10 +431,10 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue) efx_oword_t reg; /* Only 128 bits in this register */ - BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); + BUILD_BUG_ON(EFX_MAX_TX_QUEUES > 128); efx_reado(efx, ®, FR_AA_TX_CHKSM_CFG); - if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) + if (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD) clear_bit_le(tx_queue->queue, (void *)®); else set_bit_le(tx_queue->queue, (void *)®); @@ -1132,7 +1132,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) { ev_queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); - if (ev_queue < EFX_TX_QUEUE_COUNT) { + if (ev_queue < EFX_TXQ_TYPES * efx->n_tx_channels) { tx_queue = efx->tx_queue + ev_queue; tx_queue->flushed = FLUSH_DONE; } @@ -1142,7 +1142,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); ev_failed = EFX_QWORD_FIELD( *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); - if (ev_queue < efx->n_rx_queues) { + if (ev_queue < efx->n_rx_channels) { rx_queue = efx->rx_queue + ev_queue; rx_queue->flushed = ev_failed ? FLUSH_FAILED : FLUSH_DONE; @@ -1441,7 +1441,7 @@ static void efx_setup_rss_indir_table(struct efx_nic *efx) offset < FR_BZ_RX_INDIRECTION_TBL + 0x800; offset += 0x10) { EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, - i % efx->n_rx_queues); + i % efx->n_rx_channels); efx_writed(efx, &dword, offset); i++; } diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 3a16e0612267..371e86cc090f 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -618,8 +618,8 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, /* Test both types of TX queue */ efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) { - state->offload_csum = (tx_queue->queue == - EFX_TX_QUEUE_OFFLOAD_CSUM); + state->offload_csum = (tx_queue->queue & + EFX_TXQ_TYPE_OFFLOAD); rc = efx_test_loopback(tx_queue, &tests->loopback[mode]); if (rc) diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index 643bef72b99d..aed495a4dad7 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -18,8 +18,8 @@ */ struct efx_loopback_self_tests { - int tx_sent[EFX_TX_QUEUE_COUNT]; - int tx_done[EFX_TX_QUEUE_COUNT]; + int tx_sent[EFX_TXQ_TYPES]; + int tx_done[EFX_TXQ_TYPES]; int rx_good; int rx_bad; }; diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index be0e110a1f73..6bb12a87ef2d 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -30,32 +30,46 @@ */ #define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u) -/* We want to be able to nest calls to netif_stop_queue(), since each - * channel can have an individual stop on the queue. - */ -void efx_stop_queue(struct efx_nic *efx) +/* We need to be able to nest calls to netif_tx_stop_queue(), partly + * because of the 2 hardware queues associated with each core queue, + * but also so that we can inhibit TX for reasons other than a full + * hardware queue. */ +void efx_stop_queue(struct efx_channel *channel) { - spin_lock_bh(&efx->netif_stop_lock); + struct efx_nic *efx = channel->efx; + + if (!channel->tx_queue) + return; + + spin_lock_bh(&channel->tx_stop_lock); EFX_TRACE(efx, "stop TX queue\n"); - atomic_inc(&efx->netif_stop_count); - netif_stop_queue(efx->net_dev); + atomic_inc(&channel->tx_stop_count); + netif_tx_stop_queue( + netdev_get_tx_queue( + efx->net_dev, + channel->tx_queue->queue / EFX_TXQ_TYPES)); - spin_unlock_bh(&efx->netif_stop_lock); + spin_unlock_bh(&channel->tx_stop_lock); } -/* Wake netif's TX queue - * We want to be able to nest calls to netif_stop_queue(), since each - * channel can have an individual stop on the queue. - */ -void efx_wake_queue(struct efx_nic *efx) +/* Decrement core TX queue stop count and wake it if the count is 0 */ +void efx_wake_queue(struct efx_channel *channel) { + struct efx_nic *efx = channel->efx; + + if (!channel->tx_queue) + return; + local_bh_disable(); - if (atomic_dec_and_lock(&efx->netif_stop_count, - &efx->netif_stop_lock)) { + if (atomic_dec_and_lock(&channel->tx_stop_count, + &channel->tx_stop_lock)) { EFX_TRACE(efx, "waking TX queue\n"); - netif_wake_queue(efx->net_dev); - spin_unlock(&efx->netif_stop_lock); + netif_tx_wake_queue( + netdev_get_tx_queue( + efx->net_dev, + channel->tx_queue->queue / EFX_TXQ_TYPES)); + spin_unlock(&channel->tx_stop_lock); } local_bh_enable(); } @@ -298,7 +312,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) rc = NETDEV_TX_BUSY; if (tx_queue->stopped == 1) - efx_stop_queue(efx); + efx_stop_queue(tx_queue->channel); unwind: /* Work backwards until we hit the original insert pointer value */ @@ -374,10 +388,9 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, if (unlikely(efx->port_inhibited)) return NETDEV_TX_BUSY; + tx_queue = &efx->tx_queue[EFX_TXQ_TYPES * skb_get_queue_mapping(skb)]; if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) - tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM]; - else - tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM]; + tx_queue += EFX_TXQ_TYPE_OFFLOAD; return efx_enqueue_skb(tx_queue, skb); } @@ -405,7 +418,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) netif_tx_lock(efx->net_dev); if (tx_queue->stopped) { tx_queue->stopped = 0; - efx_wake_queue(efx); + efx_wake_queue(tx_queue->channel); } netif_tx_unlock(efx->net_dev); } @@ -488,7 +501,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) /* Release queue's stop on port, if any */ if (tx_queue->stopped) { tx_queue->stopped = 0; - efx_wake_queue(tx_queue->efx); + efx_wake_queue(tx_queue->channel); } } @@ -1120,7 +1133,7 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, /* Stop the queue if it wasn't stopped before. */ if (tx_queue->stopped == 1) - efx_stop_queue(efx); + efx_stop_queue(tx_queue->channel); unwind: /* Free the DMA mapping we were in the process of writing out */ -- cgit v1.2.3