From 9c636baf8518d0f986004b40669b75506459beac Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 5 Jan 2012 17:19:45 +0000 Subject: sfc: Fix some formatting errors reported by checkpatch Fix the following errors and warnings: ERROR: trailing whitespace ERROR: spaces required around that '=' (ctx:VxV) WARNING: please, no space before tabs Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/selftest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 52edd24fcde3..fc62fe2f766f 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -445,7 +445,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue, /* Count the number of tx completions, and decrement the refcnt. Any * skbs not already completed will be free'd when the queue is flushed */ - for (i=0; i < state->packet_count; i++) { + for (i = 0; i < state->packet_count; i++) { skb = state->skbs[i]; if (skb && !skb_shared(skb)) ++tx_done; -- cgit v1.2.3 From 18e83e4cd144e30fb38bf1f714914182c6c8bced Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 5 Jan 2012 19:05:20 +0000 Subject: sfc: Const-qualify static data as appropriate, partly prompted by checkpatch Fix the following warnings: WARNING: struct dev_pm_ops should normally be const WARNING: static const char * array should probably be static const char * const Similarly const-qualify struct i2c_board_info, struct i2c_algo_bit_data, struct efx_ethtool_stat, struct efx_mtd_ops and struct siena_nvram_type_info. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 6 +++--- drivers/net/ethernet/sfc/ethtool.c | 4 ++-- drivers/net/ethernet/sfc/falcon.c | 2 +- drivers/net/ethernet/sfc/falcon_boards.c | 12 ++++++------ drivers/net/ethernet/sfc/mcdi.c | 4 ++-- drivers/net/ethernet/sfc/mtd.c | 8 ++++---- drivers/net/ethernet/sfc/net_driver.h | 4 ++-- drivers/net/ethernet/sfc/selftest.c | 2 +- drivers/net/ethernet/sfc/txc43128_phy.c | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 0539a8d88a23..9ca5dcdf5a86 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -38,7 +38,7 @@ /* Loopback mode names (see LOOPBACK_MODE()) */ const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; -const char *efx_loopback_mode_names[] = { +const char *const efx_loopback_mode_names[] = { [LOOPBACK_NONE] = "NONE", [LOOPBACK_DATA] = "DATAPATH", [LOOPBACK_GMAC] = "GMAC", @@ -69,7 +69,7 @@ const char *efx_loopback_mode_names[] = { }; const unsigned int efx_reset_type_max = RESET_TYPE_MAX; -const char *efx_reset_type_names[] = { +const char *const efx_reset_type_names[] = { [RESET_TYPE_INVISIBLE] = "INVISIBLE", [RESET_TYPE_ALL] = "ALL", [RESET_TYPE_WORLD] = "WORLD", @@ -2660,7 +2660,7 @@ static int efx_pm_suspend(struct device *dev) return rc; } -static struct dev_pm_ops efx_pm_ops = { +static const struct dev_pm_ops efx_pm_ops = { .suspend = efx_pm_suspend, .resume = efx_pm_resume, .freeze = efx_pm_freeze, diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index c090de4e66c3..52c9ee4c8aa3 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -91,7 +91,7 @@ static u64 efx_get_atomic_stat(void *field) EFX_ETHTOOL_STAT(tx_##field, tx_queue, field, \ unsigned int, efx_get_uint_stat) -static struct efx_ethtool_stat efx_ethtool_stats[] = { +static const struct efx_ethtool_stat efx_ethtool_stats[] = { EFX_ETHTOOL_U64_MAC_STAT(tx_bytes), EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes), EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes), @@ -486,7 +486,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_mac_stats *mac_stats = &efx->mac_stats; - struct efx_ethtool_stat *stat; + const struct efx_ethtool_stat *stat; struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct rtnl_link_stats64 temp; diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 8ae1ebd35397..5c7548959dd7 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -89,7 +89,7 @@ static int falcon_getscl(void *data) return EFX_OWORD_FIELD(reg, FRF_AB_GPIO0_IN); } -static struct i2c_algo_bit_data falcon_i2c_bit_operations = { +static const struct i2c_algo_bit_data falcon_i2c_bit_operations = { .setsda = falcon_setsda, .setscl = falcon_setscl, .getsda = falcon_getsda, diff --git a/drivers/net/ethernet/sfc/falcon_boards.c b/drivers/net/ethernet/sfc/falcon_boards.c index 6cc16b8cc6f4..2084cc6ede52 100644 --- a/drivers/net/ethernet/sfc/falcon_boards.c +++ b/drivers/net/ethernet/sfc/falcon_boards.c @@ -87,7 +87,7 @@ static const u8 falcon_lm87_common_regs[] = { 0 }; -static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, +static int efx_init_lm87(struct efx_nic *efx, const struct i2c_board_info *info, const u8 *reg_values) { struct falcon_board *board = falcon_board(efx); @@ -179,7 +179,7 @@ static int efx_check_lm87(struct efx_nic *efx, unsigned mask) #else /* !CONFIG_SENSORS_LM87 */ static inline int -efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, +efx_init_lm87(struct efx_nic *efx, const struct i2c_board_info *info, const u8 *reg_values) { return 0; @@ -442,7 +442,7 @@ static int sfe4001_check_hw(struct efx_nic *efx) return (status < 0) ? -EIO : -ERANGE; } -static struct i2c_board_info sfe4001_hwmon_info = { +static const struct i2c_board_info sfe4001_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), }; @@ -522,7 +522,7 @@ static const u8 sfe4002_lm87_regs[] = { 0 }; -static struct i2c_board_info sfe4002_hwmon_info = { +static const struct i2c_board_info sfe4002_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfe4002_lm87_channel, }; @@ -591,7 +591,7 @@ static const u8 sfn4112f_lm87_regs[] = { 0 }; -static struct i2c_board_info sfn4112f_hwmon_info = { +static const struct i2c_board_info sfn4112f_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfn4112f_lm87_channel, }; @@ -653,7 +653,7 @@ static const u8 sfe4003_lm87_regs[] = { 0 }; -static struct i2c_board_info sfe4003_hwmon_info = { +static const struct i2c_board_info sfe4003_hwmon_info = { I2C_BOARD_INFO("lm87", 0x2e), .platform_data = &sfe4003_lm87_channel, }; diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 81a425397468..b1de400ca24e 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -502,7 +502,7 @@ static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) efx_link_status_changed(efx); } -static const char *sensor_names[] = { +static const char *const sensor_names[] = { [MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor", [MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor", [MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling", @@ -518,7 +518,7 @@ static const char *sensor_names[] = { [MC_CMD_SENSOR_IN_12V0] = "12V supply sensor" }; -static const char *sensor_status_names[] = { +static const char *const sensor_status_names[] = { [MC_CMD_SENSOR_STATE_OK] = "OK", [MC_CMD_SENSOR_STATE_WARNING] = "Warning", [MC_CMD_SENSOR_STATE_FATAL] = "Fatal", diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c index bc9dcd6b30d7..13f61fba731f 100644 --- a/drivers/net/ethernet/sfc/mtd.c +++ b/drivers/net/ethernet/sfc/mtd.c @@ -382,7 +382,7 @@ static int falcon_mtd_sync(struct mtd_info *mtd) return rc; } -static struct efx_mtd_ops falcon_mtd_ops = { +static const struct efx_mtd_ops falcon_mtd_ops = { .read = falcon_mtd_read, .erase = falcon_mtd_erase, .write = falcon_mtd_write, @@ -560,7 +560,7 @@ static int siena_mtd_sync(struct mtd_info *mtd) return rc; } -static struct efx_mtd_ops siena_mtd_ops = { +static const struct efx_mtd_ops siena_mtd_ops = { .read = siena_mtd_read, .erase = siena_mtd_erase, .write = siena_mtd_write, @@ -572,7 +572,7 @@ struct siena_nvram_type_info { const char *name; }; -static struct siena_nvram_type_info siena_nvram_types[] = { +static const struct siena_nvram_type_info siena_nvram_types[] = { [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, @@ -593,7 +593,7 @@ static int siena_mtd_probe_partition(struct efx_nic *efx, unsigned int type) { struct efx_mtd_partition *part = &efx_mtd->part[part_id]; - struct siena_nvram_type_info *info; + const struct siena_nvram_type_info *info; size_t size, erase_size; bool protected; int rc; diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index c49502bab6a3..9353ce801752 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -395,12 +395,12 @@ enum efx_led_mode { #define STRING_TABLE_LOOKUP(val, member) \ ((val) < member ## _max) ? member ## _names[val] : "(invalid)" -extern const char *efx_loopback_mode_names[]; +extern const char *const efx_loopback_mode_names[]; extern const unsigned int efx_loopback_mode_max; #define LOOPBACK_MODE(efx) \ STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode) -extern const char *efx_reset_type_names[]; +extern const char *const efx_reset_type_names[]; extern const unsigned int efx_reset_type_max; #define RESET_TYPE(type) \ STRING_TABLE_LOOKUP(type, efx_reset_type) diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index fc62fe2f766f..17ff9b399957 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -50,7 +50,7 @@ static const char payload_msg[] = /* Interrupt mode names */ static const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX; -static const char *efx_interrupt_mode_names[] = { +static const char *const efx_interrupt_mode_names[] = { [EFX_INT_MODE_MSIX] = "MSI-X", [EFX_INT_MODE_MSI] = "MSI", [EFX_INT_MODE_LEGACY] = "legacy", diff --git a/drivers/net/ethernet/sfc/txc43128_phy.c b/drivers/net/ethernet/sfc/txc43128_phy.c index 7c21b334a75b..29bb3f9941c0 100644 --- a/drivers/net/ethernet/sfc/txc43128_phy.c +++ b/drivers/net/ethernet/sfc/txc43128_phy.c @@ -512,7 +512,7 @@ static bool txc43128_phy_poll(struct efx_nic *efx) return efx->link_state.up != was_up; } -static const char *txc43128_test_names[] = { +static const char *const txc43128_test_names[] = { "bist" }; -- cgit v1.2.3 From 783b6bb66d4289826b3d022ad7b8ac3666951bb6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 5 Jan 2012 19:09:24 +0000 Subject: sfc: Remove unnecessary inclusion of , prompted by checkpatch Fix the warning: WARNING: Use #include instead of There is no need for selftest.c to include the file at all. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/selftest.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 17ff9b399957..5226d9857f30 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "net_driver.h" #include "efx.h" #include "nic.h" -- cgit v1.2.3 From 710b208dc2687fdb3370110d54a67fb2288835eb Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 3 Sep 2011 00:15:00 +0100 Subject: sfc: Merge efx_mac_operations into efx_nic_type No NICs need to switch efx_mac_operations at run-time, and the MAC operations are fairly closely bound to NIC types. Move efx_mac_operations::reconfigure to efx_nic_type::reconfigure_mac and efx_mac_operations::check_fault fo efx_nic_type::check_mac_fault. Change callers to call through efx->type or directly if the NIC type is known. Remove efx_mac_operations::update_stats. The implementations for Falcon used to fetch MAC statistics synchronously and this was used by efx_register_netdev() to clear statistics after running self-tests. However, it now only converts statistics that have already been fetched (and that only for Falcon), and the call from efx_register_netdev() has no effect. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 17 ++++++----------- drivers/net/ethernet/sfc/ethtool.c | 4 ++-- drivers/net/ethernet/sfc/falcon.c | 15 ++++++++------- drivers/net/ethernet/sfc/falcon_xmac.c | 13 +++---------- drivers/net/ethernet/sfc/mac.h | 21 --------------------- drivers/net/ethernet/sfc/mcdi.h | 4 ++++ drivers/net/ethernet/sfc/mcdi_mac.c | 12 ++---------- drivers/net/ethernet/sfc/net_driver.h | 21 ++++----------------- drivers/net/ethernet/sfc/nic.h | 3 +++ drivers/net/ethernet/sfc/selftest.c | 2 +- drivers/net/ethernet/sfc/siena.c | 4 ++-- 11 files changed, 35 insertions(+), 81 deletions(-) delete mode 100644 drivers/net/ethernet/sfc/mac.h (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 8f4cbb642bf2..1d20e01c6aea 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -900,7 +900,7 @@ static void efx_mac_work(struct work_struct *data) mutex_lock(&efx->mac_lock); if (efx->port_enabled) { efx->type->push_multicast_hash(efx); - efx->mac_op->reconfigure(efx); + efx->type->reconfigure_mac(efx); } mutex_unlock(&efx->mac_lock); } @@ -941,7 +941,7 @@ static int efx_init_port(struct efx_nic *efx) /* 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); + efx->type->reconfigure_mac(efx); /* Ensure the PHY advertises the correct flow control settings */ rc = efx->phy_op->reconfigure(efx); @@ -969,7 +969,7 @@ static void efx_start_port(struct efx_nic *efx) /* 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); + efx->type->reconfigure_mac(efx); mutex_unlock(&efx->mac_lock); } @@ -1807,7 +1807,7 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) /* Reconfigure the MAC before enabling the dma queues so that * the RX buffers don't overflow */ net_dev->mtu = new_mtu; - efx->mac_op->reconfigure(efx); + efx->type->reconfigure_mac(efx); mutex_unlock(&efx->mac_lock); efx_init_channels(efx); @@ -1835,7 +1835,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) /* Reconfigure the MAC */ mutex_lock(&efx->mac_lock); - efx->mac_op->reconfigure(efx); + efx->type->reconfigure_mac(efx); mutex_unlock(&efx->mac_lock); return 0; @@ -1949,10 +1949,6 @@ static int efx_register_netdev(struct efx_nic *efx) net_dev->netdev_ops = &efx_netdev_ops; SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); - /* Clear MAC statistics */ - efx->mac_op->update_stats(efx); - memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); - rtnl_lock(); rc = dev_alloc_name(net_dev, net_dev->name); @@ -2069,7 +2065,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) "could not restore PHY settings\n"); } - efx->mac_op->reconfigure(efx); + efx->type->reconfigure_mac(efx); efx_init_channels(efx); efx_restore_filters(efx); @@ -2274,7 +2270,6 @@ static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, efx->net_dev = net_dev; 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); diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 55a25b14d304..1a7f7ba27bea 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -750,7 +750,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, /* Recover by resetting the EM block */ falcon_stop_nic_stats(efx); falcon_drain_tx_fifo(efx); - efx->mac_op->reconfigure(efx); + falcon_reconfigure_xmac(efx); falcon_start_nic_stats(efx); } else { /* Schedule a reset to recover */ @@ -775,7 +775,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, /* 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); + efx->type->reconfigure_mac(efx); out: mutex_unlock(&efx->mac_lock); diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 5c7548959dd7..1a8a316bb538 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -19,7 +19,6 @@ #include "net_driver.h" #include "bitfield.h" #include "efx.h" -#include "mac.h" #include "spi.h" #include "nic.h" #include "regs.h" @@ -613,7 +612,7 @@ static void falcon_stats_complete(struct efx_nic *efx) nic_data->stats_pending = false; if (*nic_data->stats_dma_done == FALCON_STATS_DONE) { rmb(); /* read the done flag before the stats */ - efx->mac_op->update_stats(efx); + falcon_update_stats_xmac(efx); } else { netif_err(efx, hw, efx->net_dev, "timed out waiting for statistics\n"); @@ -670,7 +669,7 @@ static int falcon_reconfigure_port(struct efx_nic *efx) falcon_reset_macs(efx); efx->phy_op->reconfigure(efx); - rc = efx->mac_op->reconfigure(efx); + rc = falcon_reconfigure_xmac(efx); BUG_ON(rc); falcon_start_nic_stats(efx); @@ -1218,7 +1217,7 @@ static void falcon_monitor(struct efx_nic *efx) falcon_deconfigure_mac_wrapper(efx); falcon_reset_macs(efx); - rc = efx->mac_op->reconfigure(efx); + rc = falcon_reconfigure_xmac(efx); BUG_ON(rc); falcon_start_nic_stats(efx); @@ -1676,7 +1675,7 @@ static void falcon_update_nic_stats(struct efx_nic *efx) *nic_data->stats_dma_done == FALCON_STATS_DONE) { nic_data->stats_pending = false; rmb(); /* read the done flag before the stats */ - efx->mac_op->update_stats(efx); + falcon_update_stats_xmac(efx); } } @@ -1769,11 +1768,12 @@ const struct efx_nic_type falcon_a1_nic_type = { .push_irq_moderation = falcon_push_irq_moderation, .push_multicast_hash = falcon_push_multicast_hash, .reconfigure_port = falcon_reconfigure_port, + .reconfigure_mac = falcon_reconfigure_xmac, + .check_mac_fault = falcon_xmac_check_fault, .get_wol = falcon_get_wol, .set_wol = falcon_set_wol, .resume_wol = efx_port_dummy_op_void, .test_nvram = falcon_test_nvram, - .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_A1, .mem_map_size = 0x20000, @@ -1811,12 +1811,13 @@ const struct efx_nic_type falcon_b0_nic_type = { .push_irq_moderation = falcon_push_irq_moderation, .push_multicast_hash = falcon_push_multicast_hash, .reconfigure_port = falcon_reconfigure_port, + .reconfigure_mac = falcon_reconfigure_xmac, + .check_mac_fault = falcon_xmac_check_fault, .get_wol = falcon_get_wol, .set_wol = falcon_set_wol, .resume_wol = efx_port_dummy_op_void, .test_registers = falcon_b0_test_registers, .test_nvram = falcon_test_nvram, - .default_mac_ops = &falcon_xmac_operations, .revision = EFX_REV_FALCON_B0, /* Map everything up to and including the RSS indirection diff --git a/drivers/net/ethernet/sfc/falcon_xmac.c b/drivers/net/ethernet/sfc/falcon_xmac.c index 57434593f07b..6106ef15dee3 100644 --- a/drivers/net/ethernet/sfc/falcon_xmac.c +++ b/drivers/net/ethernet/sfc/falcon_xmac.c @@ -14,7 +14,6 @@ #include "nic.h" #include "regs.h" #include "io.h" -#include "mac.h" #include "mdio_10g.h" #include "workarounds.h" @@ -270,12 +269,12 @@ static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries) return mac_up; } -static bool falcon_xmac_check_fault(struct efx_nic *efx) +bool falcon_xmac_check_fault(struct efx_nic *efx) { return !falcon_xmac_link_ok_retry(efx, 5); } -static int falcon_reconfigure_xmac(struct efx_nic *efx) +int falcon_reconfigure_xmac(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; @@ -290,7 +289,7 @@ static int falcon_reconfigure_xmac(struct efx_nic *efx) return 0; } -static void falcon_update_stats_xmac(struct efx_nic *efx) +void falcon_update_stats_xmac(struct efx_nic *efx) { struct efx_mac_stats *mac_stats = &efx->mac_stats; @@ -361,9 +360,3 @@ void falcon_poll_xmac(struct efx_nic *efx) nic_data->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1); falcon_ack_status_intr(efx); } - -const struct efx_mac_operations falcon_xmac_operations = { - .reconfigure = falcon_reconfigure_xmac, - .update_stats = falcon_update_stats_xmac, - .check_fault = falcon_xmac_check_fault, -}; diff --git a/drivers/net/ethernet/sfc/mac.h b/drivers/net/ethernet/sfc/mac.h deleted file mode 100644 index d6a255d0856b..000000000000 --- a/drivers/net/ethernet/sfc/mac.h +++ /dev/null @@ -1,21 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_MAC_H -#define EFX_MAC_H - -#include "net_driver.h" - -extern const struct efx_mac_operations falcon_xmac_operations; -extern const struct efx_mac_operations efx_mcdi_mac_operations; -extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, - u32 dma_len, int enable, int clear); - -#endif diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index aced2a7856fc..c59667bf64ac 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -126,5 +126,9 @@ extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); +extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, + u32 dma_len, int enable, int clear); +extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx); +extern bool efx_mcdi_mac_check_fault(struct efx_nic *efx); #endif /* EFX_MCDI_H */ diff --git a/drivers/net/ethernet/sfc/mcdi_mac.c b/drivers/net/ethernet/sfc/mcdi_mac.c index 85fe24f86396..4907062b24a2 100644 --- a/drivers/net/ethernet/sfc/mcdi_mac.c +++ b/drivers/net/ethernet/sfc/mcdi_mac.c @@ -9,7 +9,6 @@ #include "net_driver.h" #include "efx.h" -#include "mac.h" #include "mcdi.h" #include "mcdi_pcol.h" @@ -115,7 +114,7 @@ fail: return rc; } -static int efx_mcdi_mac_reconfigure(struct efx_nic *efx) +int efx_mcdi_mac_reconfigure(struct efx_nic *efx) { int rc; @@ -130,16 +129,9 @@ static int efx_mcdi_mac_reconfigure(struct efx_nic *efx) } -static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) +bool efx_mcdi_mac_check_fault(struct efx_nic *efx) { u32 faults; int rc = efx_mcdi_get_mac_faults(efx, &faults); return (rc != 0) || (faults != 0); } - - -const struct efx_mac_operations efx_mcdi_mac_operations = { - .reconfigure = efx_mcdi_mac_reconfigure, - .update_stats = efx_port_dummy_op_void, - .check_fault = efx_mcdi_mac_check_fault, -}; diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index b6040141ef79..aa5a321a1419 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -473,18 +473,6 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left, left->fc == right->fc && left->speed == right->speed; } -/** - * struct efx_mac_operations - Efx MAC operations table - * @reconfigure: Reconfigure MAC. Serialised by the mac_lock - * @update_stats: Update statistics - * @check_fault: Check fault state. True if fault present. - */ -struct efx_mac_operations { - int (*reconfigure) (struct efx_nic *efx); - void (*update_stats) (struct efx_nic *efx); - bool (*check_fault)(struct efx_nic *efx); -}; - /** * struct efx_phy_operations - Efx PHY operations table * @probe: Probe PHY and initialise efx->mdio.mode_support, efx->mdio.mmds, @@ -676,7 +664,6 @@ struct efx_filter_state; * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock * @stats_buffer: DMA buffer for statistics - * @mac_op: MAC interface * @phy_type: PHY type * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) @@ -767,8 +754,6 @@ struct efx_nic { struct efx_buffer stats_buffer; - const struct efx_mac_operations *mac_op; - unsigned int phy_type; const struct efx_phy_operations *phy_op; void *phy_data; @@ -843,12 +828,13 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) * @push_irq_moderation: Apply interrupt moderation value * @push_multicast_hash: Apply multicast hash table * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY + * @reconfigure_mac: Reconfigure MAC only. Serialised by the mac_lock + * @check_mac_fault: Check MAC fault state. True if fault present. * @get_wol: Get WoL configuration from driver state * @set_wol: Push WoL configuration to the NIC * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) * @test_registers: Test read/write functionality of control registers * @test_nvram: Test validity of NVRAM contents - * @default_mac_ops: efx_mac_operations to set at startup * @revision: Hardware architecture revision * @mem_map_size: Memory BAR mapped size * @txd_ptr_tbl_base: TX descriptor ring base address @@ -888,12 +874,13 @@ struct efx_nic_type { void (*push_irq_moderation)(struct efx_channel *channel); void (*push_multicast_hash)(struct efx_nic *efx); int (*reconfigure_port)(struct efx_nic *efx); + int (*reconfigure_mac)(struct efx_nic *efx); + bool (*check_mac_fault)(struct efx_nic *efx); void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); int (*set_wol)(struct efx_nic *efx, u32 type); void (*resume_wol)(struct efx_nic *efx); int (*test_registers)(struct efx_nic *efx); int (*test_nvram)(struct efx_nic *efx); - const struct efx_mac_operations *default_mac_ops; int revision; unsigned int mem_map_size; diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 5fb24d3aa3ca..cfda6ded24fe 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -189,6 +189,9 @@ extern bool efx_nic_event_present(struct efx_channel *channel); /* MAC/PHY */ extern void falcon_drain_tx_fifo(struct efx_nic *efx); extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); +extern bool falcon_xmac_check_fault(struct efx_nic *efx); +extern int falcon_reconfigure_xmac(struct efx_nic *efx); +extern void falcon_update_stats_xmac(struct efx_nic *efx); /* Interrupts and test events */ extern int efx_nic_init_interrupt(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 5226d9857f30..9df2a7942509 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -569,7 +569,7 @@ static int efx_wait_for_link(struct efx_nic *efx) mutex_lock(&efx->mac_lock); link_up = link_state->up; if (link_up) - link_up = !efx->mac_op->check_fault(efx); + link_up = !efx->type->check_mac_fault(efx); mutex_unlock(&efx->mac_lock); if (link_up) { diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 4d5d619feaa6..775b6784cbdb 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -18,7 +18,6 @@ #include "bitfield.h" #include "efx.h" #include "nic.h" -#include "mac.h" #include "spi.h" #include "regs.h" #include "io.h" @@ -631,13 +630,14 @@ const struct efx_nic_type siena_a0_nic_type = { .set_id_led = efx_mcdi_set_id_led, .push_irq_moderation = siena_push_irq_moderation, .push_multicast_hash = siena_push_multicast_hash, + .reconfigure_mac = efx_mcdi_mac_reconfigure, + .check_mac_fault = efx_mcdi_mac_check_fault, .reconfigure_port = efx_mcdi_phy_reconfigure, .get_wol = siena_get_wol, .set_wol = siena_set_wol, .resume_wol = siena_init_wol, .test_registers = siena_test_registers, .test_nvram = efx_mcdi_nvram_test_all, - .default_mac_ops = &efx_mcdi_mac_operations, .revision = EFX_REV_SIENA_A0, .mem_map_size = (FR_CZ_MC_TREG_SMEM + -- cgit v1.2.3 From 5f3f9d6c441faa323444b2f6b092d630fcd7d04c Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 4 Nov 2011 22:29:14 +0000 Subject: sfc: Consistently test DEBUG macro, not EFX_ENABLE_DEBUG The netif_dbg() macro is defined in . If the DEBUG macro is defined, it logs a message at 'debug' level, otherwise it does nothing. In net_driver.h we define DEBUG if EFX_ENABLE_DEBUG is defined, but this is too late for those source files that already got a definition of netif_dbg() by including Get rid of EFX_ENABLE_DEBUG, and only define and test DEBUG. In mtd.c, we do not use DEBUG as a condition flag but are forced to use the DEBUG macro-function from . Undefine DEBUG before including it. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/mtd.c | 1 + drivers/net/ethernet/sfc/net_driver.h | 6 +----- drivers/net/ethernet/sfc/nic.c | 2 +- drivers/net/ethernet/sfc/selftest.c | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/mtd.c b/drivers/net/ethernet/sfc/mtd.c index 7f61cd3812d9..b702862a0924 100644 --- a/drivers/net/ethernet/sfc/mtd.c +++ b/drivers/net/ethernet/sfc/mtd.c @@ -10,6 +10,7 @@ #include #include +#undef DEBUG /* has its own use for DEBUG */ #include #include #include diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index a88e95f58b0a..4cbd997e378b 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -13,10 +13,6 @@ #ifndef EFX_NET_DRIVER_H #define EFX_NET_DRIVER_H -#if defined(EFX_ENABLE_DEBUG) && !defined(DEBUG) -#define DEBUG -#endif - #include #include #include @@ -42,7 +38,7 @@ #define EFX_DRIVER_VERSION "3.1" -#ifdef EFX_ENABLE_DEBUG +#ifdef DEBUG #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) #define EFX_WARN_ON_PARANOID(x) WARN_ON(x) #else diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index b1df2f39c8f0..bf07bd0488cf 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -801,7 +801,7 @@ static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, * error message. FRM_TRUNC indicates RXDP dropped the packet due * to a FIFO overflow. */ -#ifdef EFX_ENABLE_DEBUG +#ifdef DEBUG if (rx_ev_other_err && net_ratelimit()) { netif_dbg(efx, rx_err, efx->net_dev, " RX queue %d unexpected RX event " diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 9df2a7942509..7718287ad0bc 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -315,7 +315,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, return; err: -#ifdef EFX_ENABLE_DEBUG +#ifdef DEBUG if (atomic_read(&state->rx_bad) == 0) { netif_err(efx, drv, efx->net_dev, "received packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, -- cgit v1.2.3 From 0fb53faa2e6fe67a76b8cfc6eb70a88d9d623648 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 4 Nov 2011 23:06:04 +0000 Subject: sfc: Remove dependence on NAPI polling in efx_test_eventq_irq() We cannot safely assume that the NAPI handler will complete within the 20 ms that we allow for the event self-test. The handler may be deferred for longer than this, particularly on realtime kernels. Instead, check whether either an event has been handled or (as in the old failure path) whether an interrupt has been received and an event has been delivered but not yet handled. Use napi_disable() to synchronize with the NAPI handler before checking, since it will clear events before updating eventq_read_ptr. Remove the test result chan.N.eventq.poll, since it is not an error if the NAPI handler does not run during the test. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/ethtool.c | 4 -- drivers/net/ethernet/sfc/selftest.c | 79 +++++++++++++++++++------------------ drivers/net/ethernet/sfc/selftest.h | 1 - 3 files changed, 40 insertions(+), 44 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 1a7f7ba27bea..ba9011678013 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -404,10 +404,6 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, &tests->eventq_int[channel->channel], EFX_CHANNEL_NAME(channel), "eventq.int", NULL); - efx_fill_test(n++, strings, data, - &tests->eventq_poll[channel->channel], - EFX_CHANNEL_NAME(channel), - "eventq.poll", NULL); } efx_fill_test(n++, strings, data, &tests->registers, diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 7718287ad0bc..0f8478924475 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -161,11 +161,8 @@ static int efx_test_eventq_irq(struct efx_channel *channel, struct efx_self_tests *tests) { struct efx_nic *efx = channel->efx; - unsigned int read_ptr, count; - - tests->eventq_dma[channel->channel] = -1; - tests->eventq_int[channel->channel] = -1; - tests->eventq_poll[channel->channel] = -1; + unsigned int read_ptr; + bool napi_ran, dma_seen, int_seen; read_ptr = channel->eventq_read_ptr; channel->efx->last_irq_cpu = -1; @@ -173,44 +170,48 @@ static int efx_test_eventq_irq(struct efx_channel *channel, efx_nic_generate_test_event(channel); - /* Wait for arrival of interrupt */ - count = 0; - do { - schedule_timeout_uninterruptible(HZ / 100); - - if (ACCESS_ONCE(channel->eventq_read_ptr) != read_ptr) - goto eventq_ok; - } while (++count < 2); - - netif_err(efx, drv, efx->net_dev, - "channel %d timed out waiting for event queue\n", - channel->channel); - - /* See if interrupt arrived */ - if (channel->efx->last_irq_cpu >= 0) { - netif_err(efx, drv, efx->net_dev, - "channel %d saw interrupt on CPU%d " - "during event queue test\n", channel->channel, - raw_smp_processor_id()); - tests->eventq_int[channel->channel] = 1; + /* Wait for arrival of interrupt. NAPI processing may or may + * not complete in time, but we can cope in any case. + */ + msleep(10); + napi_disable(&channel->napi_str); + if (channel->eventq_read_ptr != read_ptr) { + napi_ran = true; + dma_seen = true; + int_seen = true; + } else { + napi_ran = false; + dma_seen = efx_nic_event_present(channel); + int_seen = efx->last_irq_cpu >= 0; } + napi_enable(&channel->napi_str); + efx_nic_eventq_read_ack(channel); + + tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1; + tests->eventq_int[channel->channel] = int_seen ? 1 : -1; - /* Check to see if event was received even if interrupt wasn't */ - if (efx_nic_event_present(channel)) { + if (dma_seen && int_seen) { + netif_dbg(efx, drv, efx->net_dev, + "channel %d event queue passed (with%s NAPI)\n", + channel->channel, napi_ran ? "" : "out"); + return 0; + } else { + /* Report failure and whether either interrupt or DMA worked */ netif_err(efx, drv, efx->net_dev, - "channel %d event was generated, but " - "failed to trigger an interrupt\n", channel->channel); - tests->eventq_dma[channel->channel] = 1; + "channel %d timed out waiting for event queue\n", + channel->channel); + if (int_seen) + netif_err(efx, drv, efx->net_dev, + "channel %d saw interrupt " + "during event queue test\n", + channel->channel); + if (dma_seen) + netif_err(efx, drv, efx->net_dev, + "channel %d event was generated, but " + "failed to trigger an interrupt\n", + channel->channel); + return -ETIMEDOUT; } - - return -ETIMEDOUT; - eventq_ok: - netif_dbg(efx, drv, efx->net_dev, "channel %d event queue passed\n", - channel->channel); - tests->eventq_dma[channel->channel] = 1; - tests->eventq_int[channel->channel] = 1; - tests->eventq_poll[channel->channel] = 1; - return 0; } static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, diff --git a/drivers/net/ethernet/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h index dba5456e70f3..87abe2a53846 100644 --- a/drivers/net/ethernet/sfc/selftest.h +++ b/drivers/net/ethernet/sfc/selftest.h @@ -37,7 +37,6 @@ struct efx_self_tests { int interrupt; int eventq_dma[EFX_MAX_CHANNELS]; int eventq_int[EFX_MAX_CHANNELS]; - int eventq_poll[EFX_MAX_CHANNELS]; /* offline tests */ int registers; int phy_ext[EFX_MAX_PHY_TESTS]; -- cgit v1.2.3 From 1646a6f352a6f70fcca828589ed04797aa09d494 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 5 Jan 2012 20:14:10 +0000 Subject: sfc: Clean up test interrupt handling Interrupts are normally generated by the event queues, moderated by timers. However, they may also be triggered by detection of a 'fatal' error condition (e.g. memory parity error) or by the host writing to certain CSR fields as part of a self-test. The IRQ level/index used for these on Falcon rev B0 and Siena is set by the KER_INT_LEVE_SEL field and cached by the driver in efx_nic::fatal_irq_level. Since this value is also relevant to self-tests rename the field to just 'irq_level'. Avoid unnecessary cache traffic by using a per-channel 'last_irq_cpu' field and only writing to the per-controller field when the interrupt matches efx_nic::irq_level. Remove the volatile qualifier and use ACCESS_ONCE in the places we read these fields. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.h | 6 ++++++ drivers/net/ethernet/sfc/falcon.c | 4 ++-- drivers/net/ethernet/sfc/net_driver.h | 15 ++++++++------- drivers/net/ethernet/sfc/nic.c | 27 +++++++++++++-------------- drivers/net/ethernet/sfc/selftest.c | 12 +++++++----- 5 files changed, 36 insertions(+), 28 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index a3541ac6ea01..e0b66d158d79 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -145,6 +145,12 @@ static inline void efx_schedule_channel(struct efx_channel *channel) napi_schedule(&channel->napi_str); } +static inline void efx_schedule_channel_irq(struct efx_channel *channel) +{ + channel->last_irq_cpu = raw_smp_processor_id(); + efx_schedule_channel(channel); +} + 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, u8); diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index b4e91edec0fa..98285115df10 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -189,9 +189,9 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) falcon_irq_ack_a1(efx); if (queues & 1) - efx_schedule_channel(efx_get_channel(efx, 0)); + efx_schedule_channel_irq(efx_get_channel(efx, 0)); if (queues & 2) - efx_schedule_channel(efx_get_channel(efx, 1)); + efx_schedule_channel_irq(efx_get_channel(efx, 1)); return IRQ_HANDLED; } /************************************************************************** diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 8ce4d068bba5..a4cf8cb8180c 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -325,6 +325,7 @@ enum efx_rx_alloc_method { * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer * @last_eventq_read_ptr: Last event queue read pointer value. + * @last_irq_cpu: Last CPU to handle interrupt for this channel * @irq_count: Number of IRQs since last adaptive moderation decision * @irq_mod_score: IRQ moderation score * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors @@ -355,6 +356,7 @@ struct efx_channel { unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; + int last_irq_cpu; unsigned int irq_count; unsigned int irq_mod_score; #ifdef CONFIG_RFS_ACCEL @@ -648,7 +650,7 @@ struct efx_filter_state; * @int_error_expire: Time at which error count will be expired * @irq_status: Interrupt status buffer * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0 - * @fatal_irq_level: IRQ level (bit number) used for serious errors + * @irq_level: IRQ level/index for IRQs not triggered by an event queue * @mtd_list: List of MTDs attached to the NIC * @nic_data: Hardware dependent state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, @@ -679,10 +681,9 @@ struct efx_filter_state; * @loopback_selftest: Offline self-test private state * @monitor_work: Hardware monitor workitem * @biu_lock: BIU (bus interface unit) lock - * @last_irq_cpu: Last CPU to handle interrupt. - * This register is written with the SMP processor ID whenever an - * interrupt is handled. It is used by efx_nic_test_interrupt() - * to verify that an interrupt has occurred. + * @last_irq_cpu: Last CPU to handle a possible test interrupt. This + * field is used by efx_test_interrupts() to verify that an + * interrupt has occurred. * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @mac_stats: MAC statistics. These include all statistics the MACs * can provide. Generic code converts these into a standard @@ -735,7 +736,7 @@ struct efx_nic { struct efx_buffer irq_status; unsigned irq_zero_count; - unsigned fatal_irq_level; + unsigned irq_level; #ifdef CONFIG_SFC_MTD struct list_head mtd_list; @@ -779,7 +780,7 @@ struct efx_nic { struct delayed_work monitor_work ____cacheline_aligned_in_smp; spinlock_t biu_lock; - volatile signed int last_irq_cpu; + int last_irq_cpu; unsigned n_rx_nodesc_drop_cnt; struct efx_mac_stats mac_stats; spinlock_t stats_lock; diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index bf07bd0488cf..de7aa1c8ebda 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -1311,7 +1311,7 @@ static inline void efx_nic_interrupts(struct efx_nic *efx, efx_oword_t int_en_reg_ker; EFX_POPULATE_OWORD_3(int_en_reg_ker, - FRF_AZ_KER_INT_LEVE_SEL, efx->fatal_irq_level, + FRF_AZ_KER_INT_LEVE_SEL, efx->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); @@ -1427,11 +1427,12 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) efx_readd(efx, ®, FR_BZ_INT_ISR0); queues = EFX_EXTRACT_DWORD(reg, 0, 31); - /* Check to see if we have a serious error condition */ - if (queues & (1U << efx->fatal_irq_level)) { + /* Handle non-event-queue sources */ + if (queues & (1U << efx->irq_level)) { syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); if (unlikely(syserr)) return efx_nic_fatal_interrupt(efx); + efx->last_irq_cpu = raw_smp_processor_id(); } if (queues != 0) { @@ -1441,7 +1442,7 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) /* Schedule processing of any interrupting queues */ efx_for_each_channel(channel, efx) { if (queues & 1) - efx_schedule_channel(channel); + efx_schedule_channel_irq(channel); queues >>= 1; } result = IRQ_HANDLED; @@ -1458,18 +1459,16 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) efx_for_each_channel(channel, efx) { event = efx_event(channel, channel->eventq_read_ptr); if (efx_event_present(event)) - efx_schedule_channel(channel); + efx_schedule_channel_irq(channel); else efx_nic_eventq_read_ack(channel); } } - if (result == IRQ_HANDLED) { - efx->last_irq_cpu = raw_smp_processor_id(); + if (result == IRQ_HANDLED) netif_vdbg(efx, intr, efx->net_dev, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); - } return result; } @@ -1488,20 +1487,20 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) efx_oword_t *int_ker = efx->irq_status.addr; int syserr; - efx->last_irq_cpu = raw_smp_processor_id(); netif_vdbg(efx, intr, efx->net_dev, "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 */ - if (channel->channel == efx->fatal_irq_level) { + /* Handle non-event-queue sources */ + if (channel->channel == efx->irq_level) { syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); if (unlikely(syserr)) return efx_nic_fatal_interrupt(efx); + efx->last_irq_cpu = raw_smp_processor_id(); } /* Schedule processing of the channel */ - efx_schedule_channel(channel); + efx_schedule_channel_irq(channel); return IRQ_HANDLED; } @@ -1640,10 +1639,10 @@ void efx_nic_init_common(struct efx_nic *efx) if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) /* Use an interrupt level unused by event queues */ - efx->fatal_irq_level = 0x1f; + efx->irq_level = 0x1f; else /* Use a valid MSI-X vector */ - efx->fatal_irq_level = 0; + efx->irq_level = 0; /* Enable all the genuinely fatal interrupts. (They are still * masked by the overall interrupt mask, controlled by diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 0f8478924475..7def480570c3 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -130,6 +130,8 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) static int efx_test_interrupts(struct efx_nic *efx, struct efx_self_tests *tests) { + int cpu; + netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); tests->interrupt = -1; @@ -142,7 +144,8 @@ static int efx_test_interrupts(struct efx_nic *efx, /* Wait for arrival of test interrupt. */ netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n"); schedule_timeout_uninterruptible(HZ / 10); - if (efx->last_irq_cpu >= 0) + cpu = ACCESS_ONCE(efx->last_irq_cpu); + if (cpu >= 0) goto success; netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n"); @@ -150,8 +153,7 @@ static int efx_test_interrupts(struct efx_nic *efx, success: netif_dbg(efx, drv, efx->net_dev, "%s test interrupt seen on CPU%d\n", - INT_MODE(efx), - efx->last_irq_cpu); + INT_MODE(efx), cpu); tests->interrupt = 1; return 0; } @@ -165,7 +167,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, bool napi_ran, dma_seen, int_seen; read_ptr = channel->eventq_read_ptr; - channel->efx->last_irq_cpu = -1; + channel->last_irq_cpu = -1; smp_wmb(); efx_nic_generate_test_event(channel); @@ -182,7 +184,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, } else { napi_ran = false; dma_seen = efx_nic_event_present(channel); - int_seen = efx->last_irq_cpu >= 0; + int_seen = ACCESS_ONCE(channel->last_irq_cpu) >= 0; } napi_enable(&channel->napi_str); efx_nic_eventq_read_ack(channel); -- cgit v1.2.3 From 73ba7b68e952d98b0885e35402b204a7a675f4a9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 9 Jan 2012 19:47:08 +0000 Subject: sfc: Remove remnants of on-load self-test The out-of-tree version of the sfc driver used to run a self-test on each device before registering it. Although this was never included in-tree, some functions have checks for this special case which is not really possible. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 34 +++++++++++++--------------------- drivers/net/ethernet/sfc/nic.c | 6 ++---- drivers/net/ethernet/sfc/selftest.c | 12 ++++-------- drivers/net/ethernet/sfc/tx.c | 4 +--- 4 files changed, 20 insertions(+), 36 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 9d4ab5e5e1fa..4f412fe22e8c 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -855,10 +855,8 @@ int __efx_reconfigure_port(struct efx_nic *efx) WARN_ON(!mutex_is_locked(&efx->mac_lock)); /* 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); - } + 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; @@ -981,10 +979,8 @@ static void efx_stop_port(struct efx_nic *efx) mutex_unlock(&efx->mac_lock); /* Serialise against efx_set_multicast_list() */ - if (efx_dev_registered(efx)) { - netif_addr_lock_bh(efx->net_dev); - netif_addr_unlock_bh(efx->net_dev); - } + netif_addr_lock_bh(efx->net_dev); + netif_addr_unlock_bh(efx->net_dev); } static void efx_fini_port(struct efx_nic *efx) @@ -1394,14 +1390,14 @@ static void efx_start_all(struct efx_nic *efx) return; if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT)) return; - if (efx_dev_registered(efx) && !netif_running(efx->net_dev)) + if (!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); - if (efx_dev_registered(efx) && netif_device_present(efx->net_dev)) + if (netif_device_present(efx->net_dev)) netif_tx_wake_all_queues(efx->net_dev); efx_for_each_channel(channel, efx) @@ -1492,11 +1488,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)) { - netif_tx_stop_all_queues(efx->net_dev); - netif_tx_lock_bh(efx->net_dev); - netif_tx_unlock_bh(efx->net_dev); - } + netif_tx_stop_all_queues(efx->net_dev); + netif_tx_lock_bh(efx->net_dev); + netif_tx_unlock_bh(efx->net_dev); } static void efx_remove_all(struct efx_nic *efx) @@ -2018,11 +2012,9 @@ static void efx_unregister_netdev(struct efx_nic *efx) efx_release_tx_buffers(tx_queue); } - 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); - unregister_netdev(efx->net_dev); - } + strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type); + unregister_netdev(efx->net_dev); } /************************************************************************** @@ -2438,7 +2430,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) /* NIC initialisation * * This is called at module load (or hotplug insertion, - * theoretically). It sets up PCI mappings, tests and resets the NIC, + * theoretically). It sets up PCI mappings, resets the NIC, * sets up and registers the network devices with the kernel and hooks * the interrupt service routine. It does not prepare the device for * transmission; this is left to the first time one of the network diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index de7aa1c8ebda..cd250f197b38 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -726,11 +726,9 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) tx_queue = efx_channel_get_tx_queue( channel, tx_ev_q_label % EFX_TXQ_TYPES); - if (efx_dev_registered(efx)) - netif_tx_lock(efx->net_dev); + netif_tx_lock(efx->net_dev); efx_notify_tx_desc(tx_queue); - if (efx_dev_registered(efx)) - netif_tx_unlock(efx->net_dev); + netif_tx_unlock(efx->net_dev); } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) && EFX_WORKAROUND_10727(efx)) { efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 7def480570c3..febe2a9e6211 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -397,11 +397,9 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) * interrupt handler. */ smp_wmb(); - if (efx_dev_registered(efx)) - netif_tx_lock_bh(efx->net_dev); + netif_tx_lock_bh(efx->net_dev); rc = efx_enqueue_skb(tx_queue, skb); - if (efx_dev_registered(efx)) - netif_tx_unlock_bh(efx->net_dev); + netif_tx_unlock_bh(efx->net_dev); if (rc != NETDEV_TX_OK) { netif_err(efx, drv, efx->net_dev, @@ -442,8 +440,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue, int tx_done = 0, rx_good, rx_bad; int i, rc = 0; - if (efx_dev_registered(efx)) - netif_tx_lock_bh(efx->net_dev); + netif_tx_lock_bh(efx->net_dev); /* Count the number of tx completions, and decrement the refcnt. Any * skbs not already completed will be free'd when the queue is flushed */ @@ -454,8 +451,7 @@ static int efx_end_loopback(struct efx_tx_queue *tx_queue, dev_kfree_skb_any(skb); } - if (efx_dev_registered(efx)) - netif_tx_unlock_bh(efx->net_dev); + netif_tx_unlock_bh(efx->net_dev); /* Check TX completion and received packet counts */ rx_good = atomic_read(&state->rx_good); diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 72f0fbc73b1a..5cb81fa3fcbd 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -446,10 +446,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) likely(efx->port_enabled) && likely(netif_device_present(efx->net_dev))) { fill_level = tx_queue->insert_count - tx_queue->read_count; - if (fill_level < EFX_TXQ_THRESHOLD(efx)) { - EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); + if (fill_level < EFX_TXQ_THRESHOLD(efx)) netif_tx_wake_queue(tx_queue->core_txq); - } } /* Check whether the hardware queue is now empty */ -- cgit v1.2.3 From 93e5dfa59b0e26a145a8adce5c9edf50bdaef4c7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 28 Feb 2012 20:40:53 +0000 Subject: sfc: Raise self-test timeouts IRQ latency can be ridiculously high for various reasons, so our current timeouts of 100 ms or 10 ms are too short. Change the IRQ and event tests to use polling loops starting with a delay of 1 tick and doubling that if necessary up to a maximum total delay of approximately 1 second. Raise the loopback packet RX timeout to 1 second. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/selftest.c | 65 ++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 19 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index febe2a9e6211..dc330b9d9168 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -25,6 +25,16 @@ #include "selftest.h" #include "workarounds.h" +/* IRQ latency can be enormous because: + * - All IRQs may be disabled on a CPU for a *long* time by e.g. a + * slow serial console or an old IDE driver doing error recovery + * - The PREEMPT_RT patches mostly deal with this, but also allow a + * tasklet or normal task to be given higher priority than our IRQ + * threads + * Try to avoid blaming the hardware for this. + */ +#define IRQ_TIMEOUT HZ + /* * Loopback test packet structure * @@ -77,6 +87,9 @@ struct efx_loopback_state { struct efx_loopback_payload payload; }; +/* How long to wait for all the packets to arrive (in ms) */ +#define LOOPBACK_TIMEOUT_MS 1000 + /************************************************************************** * * MII, NVRAM and register tests @@ -130,6 +143,7 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) static int efx_test_interrupts(struct efx_nic *efx, struct efx_self_tests *tests) { + unsigned long timeout, wait; int cpu; netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); @@ -140,13 +154,18 @@ static int efx_test_interrupts(struct efx_nic *efx, smp_wmb(); efx_nic_generate_interrupt(efx); + timeout = jiffies + IRQ_TIMEOUT; + wait = 1; /* Wait for arrival of test interrupt. */ netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n"); - schedule_timeout_uninterruptible(HZ / 10); - cpu = ACCESS_ONCE(efx->last_irq_cpu); - if (cpu >= 0) - goto success; + do { + schedule_timeout_uninterruptible(wait); + cpu = ACCESS_ONCE(efx->last_irq_cpu); + if (cpu >= 0) + goto success; + wait *= 2; + } while (time_before(jiffies, timeout)); netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n"); return -ETIMEDOUT; @@ -165,29 +184,37 @@ static int efx_test_eventq_irq(struct efx_channel *channel, struct efx_nic *efx = channel->efx; unsigned int read_ptr; bool napi_ran, dma_seen, int_seen; + unsigned long timeout, wait; read_ptr = channel->eventq_read_ptr; channel->last_irq_cpu = -1; smp_wmb(); efx_nic_generate_test_event(channel); + timeout = jiffies + IRQ_TIMEOUT; + wait = 1; /* Wait for arrival of interrupt. NAPI processing may or may * not complete in time, but we can cope in any case. */ - msleep(10); - napi_disable(&channel->napi_str); - if (channel->eventq_read_ptr != read_ptr) { - napi_ran = true; - dma_seen = true; - int_seen = true; - } else { - napi_ran = false; - dma_seen = efx_nic_event_present(channel); - int_seen = ACCESS_ONCE(channel->last_irq_cpu) >= 0; - } - napi_enable(&channel->napi_str); - efx_nic_eventq_read_ack(channel); + do { + schedule_timeout_uninterruptible(wait); + + napi_disable(&channel->napi_str); + if (channel->eventq_read_ptr != read_ptr) { + napi_ran = true; + dma_seen = true; + int_seen = true; + } else { + napi_ran = false; + dma_seen = efx_nic_event_present(channel); + int_seen = ACCESS_ONCE(channel->last_irq_cpu) >= 0; + } + napi_enable(&channel->napi_str); + efx_nic_eventq_read_ack(channel); + + wait *= 2; + } while (!(dma_seen && int_seen) && time_before(jiffies, timeout)); tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1; tests->eventq_int[channel->channel] = int_seen ? 1 : -1; @@ -516,10 +543,10 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, begin_rc = efx_begin_loopback(tx_queue); /* This will normally complete very quickly, but be - * prepared to wait up to 100 ms. */ + * prepared to wait much longer. */ msleep(1); if (!efx_poll_loopback(efx)) { - msleep(100); + msleep(LOOPBACK_TIMEOUT_MS); efx_poll_loopback(efx); } -- cgit v1.2.3 From ed74f48087d1b1cf7cf534dad03bf1584eee783d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 28 Feb 2012 20:40:54 +0000 Subject: sfc: Test all event queues in parallel In case all event queues are broken for some reason, this means it will only take about a second to check them all, rather than up to 32 seconds. This may also speed up testing in the successful case. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/selftest.c | 114 ++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 49 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index dc330b9d9168..e4b4c8a3abc6 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -178,69 +178,88 @@ static int efx_test_interrupts(struct efx_nic *efx, } /* Test generation and receipt of interrupting events */ -static int efx_test_eventq_irq(struct efx_channel *channel, +static int efx_test_eventq_irq(struct efx_nic *efx, struct efx_self_tests *tests) { - struct efx_nic *efx = channel->efx; - unsigned int read_ptr; - bool napi_ran, dma_seen, int_seen; + struct efx_channel *channel; + unsigned int read_ptr[EFX_MAX_CHANNELS]; + unsigned long napi_ran = 0, dma_pend = 0, int_pend = 0; unsigned long timeout, wait; - read_ptr = channel->eventq_read_ptr; - channel->last_irq_cpu = -1; - smp_wmb(); + BUILD_BUG_ON(EFX_MAX_CHANNELS > BITS_PER_LONG); + + efx_for_each_channel(channel, efx) { + read_ptr[channel->channel] = channel->eventq_read_ptr; + set_bit(channel->channel, &dma_pend); + set_bit(channel->channel, &int_pend); + channel->last_irq_cpu = -1; + smp_wmb(); + efx_nic_generate_test_event(channel); + } - efx_nic_generate_test_event(channel); timeout = jiffies + IRQ_TIMEOUT; wait = 1; - /* Wait for arrival of interrupt. NAPI processing may or may + /* Wait for arrival of interrupts. NAPI processing may or may * not complete in time, but we can cope in any case. */ do { schedule_timeout_uninterruptible(wait); - napi_disable(&channel->napi_str); - if (channel->eventq_read_ptr != read_ptr) { - napi_ran = true; - dma_seen = true; - int_seen = true; - } else { - napi_ran = false; - dma_seen = efx_nic_event_present(channel); - int_seen = ACCESS_ONCE(channel->last_irq_cpu) >= 0; + efx_for_each_channel(channel, efx) { + napi_disable(&channel->napi_str); + if (channel->eventq_read_ptr != + read_ptr[channel->channel]) { + set_bit(channel->channel, &napi_ran); + clear_bit(channel->channel, &dma_pend); + clear_bit(channel->channel, &int_pend); + } else { + if (efx_nic_event_present(channel)) + clear_bit(channel->channel, &dma_pend); + if (ACCESS_ONCE(channel->last_irq_cpu) >= 0) + clear_bit(channel->channel, &int_pend); + } + napi_enable(&channel->napi_str); + efx_nic_eventq_read_ack(channel); } - napi_enable(&channel->napi_str); - efx_nic_eventq_read_ack(channel); wait *= 2; - } while (!(dma_seen && int_seen) && time_before(jiffies, timeout)); - - tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1; - tests->eventq_int[channel->channel] = int_seen ? 1 : -1; + } while ((dma_pend || int_pend) && time_before(jiffies, timeout)); - if (dma_seen && int_seen) { - netif_dbg(efx, drv, efx->net_dev, - "channel %d event queue passed (with%s NAPI)\n", - channel->channel, napi_ran ? "" : "out"); - return 0; - } else { - /* Report failure and whether either interrupt or DMA worked */ - netif_err(efx, drv, efx->net_dev, - "channel %d timed out waiting for event queue\n", - channel->channel); - if (int_seen) - netif_err(efx, drv, efx->net_dev, - "channel %d saw interrupt " - "during event queue test\n", - channel->channel); - if (dma_seen) + efx_for_each_channel(channel, efx) { + bool dma_seen = !test_bit(channel->channel, &dma_pend); + bool int_seen = !test_bit(channel->channel, &int_pend); + + tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1; + tests->eventq_int[channel->channel] = int_seen ? 1 : -1; + + if (dma_seen && int_seen) { + netif_dbg(efx, drv, efx->net_dev, + "channel %d event queue passed (with%s NAPI)\n", + channel->channel, + test_bit(channel->channel, &napi_ran) ? + "" : "out"); + } else { + /* Report failure and whether either interrupt or DMA + * worked + */ netif_err(efx, drv, efx->net_dev, - "channel %d event was generated, but " - "failed to trigger an interrupt\n", + "channel %d timed out waiting for event queue\n", channel->channel); - return -ETIMEDOUT; + if (int_seen) + netif_err(efx, drv, efx->net_dev, + "channel %d saw interrupt " + "during event queue test\n", + channel->channel); + if (dma_seen) + netif_err(efx, drv, efx->net_dev, + "channel %d event was generated, but " + "failed to trigger an interrupt\n", + channel->channel); + } } + + return (dma_pend || int_pend) ? -ETIMEDOUT : 0; } static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, @@ -687,7 +706,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, enum efx_loopback_mode loopback_mode = efx->loopback_mode; int phy_mode = efx->phy_mode; enum reset_type reset_method = RESET_TYPE_INVISIBLE; - struct efx_channel *channel; int rc_test = 0, rc_reset = 0, rc; /* Online (i.e. non-disruptive) testing @@ -705,11 +723,9 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, if (rc && !rc_test) rc_test = rc; - efx_for_each_channel(channel, efx) { - rc = efx_test_eventq_irq(channel, tests); - if (rc && !rc_test) - rc_test = rc; - } + rc = efx_test_eventq_irq(efx, tests); + if (rc && !rc_test) + rc_test = rc; if (rc_test) return rc_test; -- cgit v1.2.3 From eee6f6a9e0c83811de77a137989d4a3289e297cc Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 28 Feb 2012 23:37:35 +0000 Subject: sfc: Encapsulate access to efx_{channel,nic}::last_irq_cpu in self-test Cleanup in preparation for doing an event test on ifup. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/nic.c | 8 ++++++-- drivers/net/ethernet/sfc/nic.h | 13 +++++++++++-- drivers/net/ethernet/sfc/selftest.c | 14 ++++---------- 3 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 5da8af5e7501..4c47b7569145 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -1332,8 +1332,10 @@ void efx_nic_remove_eventq(struct efx_channel *channel) } -void efx_nic_generate_test_event(struct efx_channel *channel) +void efx_nic_event_test_start(struct efx_channel *channel) { + channel->last_irq_cpu = -1; + smp_wmb(); efx_magic_event(channel, EFX_CHANNEL_MAGIC_TEST(channel)); } @@ -1382,8 +1384,10 @@ void efx_nic_disable_interrupts(struct efx_nic *efx) * Interrupt must already have been enabled, otherwise nasty things * may happen. */ -void efx_nic_generate_interrupt(struct efx_nic *efx) +void efx_nic_irq_test_start(struct efx_nic *efx) { + efx->last_irq_cpu = -1; + smp_wmb(); efx_nic_interrupts(efx, true, true); } diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index ac12f7f7f35b..e0e8596f4d10 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -301,14 +301,23 @@ extern void falcon_update_stats_xmac(struct efx_nic *efx); /* Interrupts and test events */ extern int efx_nic_init_interrupt(struct efx_nic *efx); extern void efx_nic_enable_interrupts(struct efx_nic *efx); -extern void efx_nic_generate_test_event(struct efx_channel *channel); -extern void efx_nic_generate_interrupt(struct efx_nic *efx); +extern void efx_nic_event_test_start(struct efx_channel *channel); +extern void efx_nic_irq_test_start(struct efx_nic *efx); extern void efx_nic_disable_interrupts(struct efx_nic *efx); extern void efx_nic_fini_interrupt(struct efx_nic *efx); extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); extern void falcon_irq_ack_a1(struct efx_nic *efx); +static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel) +{ + return ACCESS_ONCE(channel->last_irq_cpu); +} +static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx) +{ + return ACCESS_ONCE(efx->last_irq_cpu); +} + /* Global Resources */ extern int efx_nic_flush_queues(struct efx_nic *efx); extern void falcon_start_nic_stats(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index e4b4c8a3abc6..aa4ab53cac57 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -149,11 +149,7 @@ static int efx_test_interrupts(struct efx_nic *efx, netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); tests->interrupt = -1; - /* Reset interrupt flag */ - efx->last_irq_cpu = -1; - smp_wmb(); - - efx_nic_generate_interrupt(efx); + efx_nic_irq_test_start(efx); timeout = jiffies + IRQ_TIMEOUT; wait = 1; @@ -161,7 +157,7 @@ static int efx_test_interrupts(struct efx_nic *efx, netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n"); do { schedule_timeout_uninterruptible(wait); - cpu = ACCESS_ONCE(efx->last_irq_cpu); + cpu = efx_nic_irq_test_irq_cpu(efx); if (cpu >= 0) goto success; wait *= 2; @@ -192,9 +188,7 @@ static int efx_test_eventq_irq(struct efx_nic *efx, read_ptr[channel->channel] = channel->eventq_read_ptr; set_bit(channel->channel, &dma_pend); set_bit(channel->channel, &int_pend); - channel->last_irq_cpu = -1; - smp_wmb(); - efx_nic_generate_test_event(channel); + efx_nic_event_test_start(channel); } timeout = jiffies + IRQ_TIMEOUT; @@ -216,7 +210,7 @@ static int efx_test_eventq_irq(struct efx_nic *efx, } else { if (efx_nic_event_present(channel)) clear_bit(channel->channel, &dma_pend); - if (ACCESS_ONCE(channel->last_irq_cpu) >= 0) + if (efx_nic_event_test_irq_cpu(channel) >= 0) clear_bit(channel->channel, &int_pend); } napi_enable(&channel->napi_str); -- cgit v1.2.3 From dd40781e3a4e9d3177a548c389232ee9496dae8e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 28 Feb 2012 23:40:21 +0000 Subject: sfc: Run event/IRQ self-test asynchronously when interface is brought up Generate a test event on each event queue whenever the interface is brought up, then after 1 second check that we have either handled a test event or handled another IRQ for each event queue. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 6 +++++- drivers/net/ethernet/sfc/efx.h | 2 +- drivers/net/ethernet/sfc/net_driver.h | 6 ++++-- drivers/net/ethernet/sfc/nic.c | 4 ++-- drivers/net/ethernet/sfc/nic.h | 2 +- drivers/net/ethernet/sfc/selftest.c | 35 +++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/selftest.h | 3 +++ 7 files changed, 51 insertions(+), 7 deletions(-) (limited to 'drivers/net/ethernet/sfc/selftest.c') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 00e13ab080e6..7683e53fda1d 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -25,6 +25,7 @@ #include "net_driver.h" #include "efx.h" #include "nic.h" +#include "selftest.h" #include "mcdi.h" #include "workarounds.h" @@ -1564,8 +1565,9 @@ static void efx_start_all(struct efx_nic *efx) * since we're holding the rtnl_lock at this point. */ static void efx_flush_all(struct efx_nic *efx) { - /* Make sure the hardware monitor is stopped */ + /* Make sure the hardware monitor and event self-test are stopped */ cancel_delayed_work_sync(&efx->monitor_work); + efx_selftest_async_cancel(efx); /* Stop scheduled port reconfigurations */ cancel_work_sync(&efx->mac_work); } @@ -1825,6 +1827,7 @@ static int efx_net_open(struct net_device *net_dev) efx_link_status_changed(efx); efx_start_all(efx); + efx_selftest_async_start(efx); return 0; } @@ -2375,6 +2378,7 @@ static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type, #endif INIT_WORK(&efx->reset_work, efx_reset_work); INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); + INIT_DELAYED_WORK(&efx->selftest_work, efx_selftest_async_work); efx->pci_dev = pci_dev; efx->msg_enable = debug; efx->state = STATE_INIT; diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 4debfe07fb88..be8f9158a714 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -148,7 +148,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel) static inline void efx_schedule_channel_irq(struct efx_channel *channel) { - channel->last_irq_cpu = raw_smp_processor_id(); + channel->event_test_cpu = raw_smp_processor_id(); efx_schedule_channel(channel); } diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 0b95505e8968..27fe85fd4ba3 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -325,7 +325,7 @@ enum efx_rx_alloc_method { * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer * @last_eventq_read_ptr: Last event queue read pointer value. - * @last_irq_cpu: Last CPU to handle interrupt for this channel + * @event_test_cpu: Last CPU to handle interrupt or test event for this channel * @irq_count: Number of IRQs since last adaptive moderation decision * @irq_mod_score: IRQ moderation score * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors @@ -356,8 +356,8 @@ struct efx_channel { unsigned int eventq_mask; unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; + int event_test_cpu; - int last_irq_cpu; unsigned int irq_count; unsigned int irq_mod_score; #ifdef CONFIG_RFS_ACCEL @@ -678,6 +678,7 @@ struct vfdi_status; * @irq_status: Interrupt status buffer * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0 * @irq_level: IRQ level/index for IRQs not triggered by an event queue + * @selftest_work: Work item for asynchronous self-test * @mtd_list: List of MTDs attached to the NIC * @nic_data: Hardware dependent state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, @@ -791,6 +792,7 @@ struct efx_nic { struct efx_buffer irq_status; unsigned irq_zero_count; unsigned irq_level; + struct delayed_work selftest_work; #ifdef CONFIG_SFC_MTD struct list_head mtd_list; diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 4c47b7569145..4a9a5beec8fc 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -1083,7 +1083,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) code = _EFX_CHANNEL_MAGIC_CODE(magic); if (magic == EFX_CHANNEL_MAGIC_TEST(channel)) { - /* ignore */ + channel->event_test_cpu = raw_smp_processor_id(); } else if (rx_queue && magic == EFX_CHANNEL_MAGIC_FILL(rx_queue)) { /* The queue must be empty, so we won't receive any rx * events, so efx_process_channel() won't refill the @@ -1334,7 +1334,7 @@ void efx_nic_remove_eventq(struct efx_channel *channel) void efx_nic_event_test_start(struct efx_channel *channel) { - channel->last_irq_cpu = -1; + channel->event_test_cpu = -1; smp_wmb(); efx_magic_event(channel, EFX_CHANNEL_MAGIC_TEST(channel)); } diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index e0e8596f4d10..f46e2cea8ca9 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -311,7 +311,7 @@ extern void falcon_irq_ack_a1(struct efx_nic *efx); static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel) { - return ACCESS_ONCE(channel->last_irq_cpu); + return ACCESS_ONCE(channel->event_test_cpu); } static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx) { diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index aa4ab53cac57..de4c0069f5b2 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -702,6 +702,8 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, enum reset_type reset_method = RESET_TYPE_INVISIBLE; int rc_test = 0, rc_reset = 0, rc; + efx_selftest_async_cancel(efx); + /* Online (i.e. non-disruptive) testing * This checks interrupt generation, event delivery and PHY presence. */ @@ -794,3 +796,36 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, return rc_test; } +void efx_selftest_async_start(struct efx_nic *efx) +{ + struct efx_channel *channel; + + efx_for_each_channel(channel, efx) + efx_nic_event_test_start(channel); + schedule_delayed_work(&efx->selftest_work, IRQ_TIMEOUT); +} + +void efx_selftest_async_cancel(struct efx_nic *efx) +{ + cancel_delayed_work_sync(&efx->selftest_work); +} + +void efx_selftest_async_work(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, + selftest_work.work); + struct efx_channel *channel; + int cpu; + + efx_for_each_channel(channel, efx) { + cpu = efx_nic_event_test_irq_cpu(channel); + if (cpu < 0) + netif_err(efx, ifup, efx->net_dev, + "channel %d failed to trigger an interrupt\n", + channel->channel); + else + netif_dbg(efx, ifup, efx->net_dev, + "channel %d triggered interrupt on CPU %d\n", + channel->channel, cpu); + } +} diff --git a/drivers/net/ethernet/sfc/selftest.h b/drivers/net/ethernet/sfc/selftest.h index 87abe2a53846..aed24b736059 100644 --- a/drivers/net/ethernet/sfc/selftest.h +++ b/drivers/net/ethernet/sfc/selftest.h @@ -48,5 +48,8 @@ extern void efx_loopback_rx_packet(struct efx_nic *efx, extern int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, unsigned flags); +extern void efx_selftest_async_start(struct efx_nic *efx); +extern void efx_selftest_async_cancel(struct efx_nic *efx); +extern void efx_selftest_async_work(struct work_struct *data); #endif /* EFX_SELFTEST_H */ -- cgit v1.2.3