diff options
Diffstat (limited to 'drivers/net/sfc/selftest.c')
-rw-r--r-- | drivers/net/sfc/selftest.c | 145 |
1 files changed, 76 insertions, 69 deletions
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 362956e3fe1..dba0d64d50c 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -26,7 +26,6 @@ #include "selftest.h" #include "boards.h" #include "workarounds.h" -#include "mac.h" #include "spi.h" #include "falcon_io.h" #include "mdio_10g.h" @@ -105,9 +104,11 @@ static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) goto out; } - rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); - if (rc) - goto out; + if (EFX_IS10G(efx)) { + rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + if (rc) + goto out; + } out: mutex_unlock(&efx->mac_lock); @@ -246,17 +247,20 @@ static int efx_test_eventq_irq(struct efx_channel *channel, return 0; } -static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) +static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned flags) { int rc; - if (!efx->phy_op->test) + if (!efx->phy_op->run_tests) return 0; + EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || + efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); + mutex_lock(&efx->mac_lock); - rc = efx->phy_op->test(efx); + rc = efx->phy_op->run_tests(efx, tests->phy, flags); mutex_unlock(&efx->mac_lock); - tests->phy = rc ? -1 : 1; return rc; } @@ -563,8 +567,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, return 0; } -static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, - struct efx_self_tests *tests, +static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { enum efx_loopback_mode mode; @@ -593,12 +596,14 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, efx->loopback_mode = mode; efx_reconfigure_port(efx); - /* Wait for the PHY to signal the link is up */ + /* Wait for the PHY to signal the link is up. Interrupts + * are enabled for PHY's using LASI, otherwise we poll() + * quickly */ count = 0; do { struct efx_channel *channel = &efx->channel[0]; - falcon_check_xmac(efx); + efx->phy_op->poll(efx); schedule_timeout_uninterruptible(HZ / 10); if (channel->work_pending) efx_process_channel_now(channel); @@ -606,13 +611,12 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, flush_workqueue(efx->workqueue); rmb(); - /* efx->link_up can be 1 even if the XAUI link is down, - * (bug5762). Usually, it's not worth bothering with the - * difference, but for selftests, we need that extra - * guarantee that the link is really, really, up. - */ + /* We need both the phy and xaui links to be ok. + * rather than relying on the falcon_xmac irq/poll + * regime, just poll xaui directly */ link_up = efx->link_up; - if (!falcon_xaui_link_ok(efx)) + if (link_up && EFX_IS10G(efx) && + !falcon_xaui_link_ok(efx)) link_up = false; } while ((++count < 20) && !link_up); @@ -652,47 +656,48 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, /************************************************************************** * - * Entry points + * Entry point * *************************************************************************/ -/* Online (i.e. non-disruptive) testing - * This checks interrupt generation, event delivery and PHY presence. */ -int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) +int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned flags) { + enum efx_loopback_mode loopback_mode = efx->loopback_mode; + int phy_mode = efx->phy_mode; + struct ethtool_cmd ecmd; struct efx_channel *channel; - int rc, rc2 = 0; + int rc_test = 0, rc_reset = 0, rc; + + /* Online (i.e. non-disruptive) testing + * This checks interrupt generation, event delivery and PHY presence. */ rc = efx_test_mii(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; rc = efx_test_nvram(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; rc = efx_test_interrupts(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; efx_for_each_channel(channel, efx) { rc = efx_test_eventq_irq(channel, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; } - return rc2; -} + if (rc_test) + return rc_test; -/* Offline (i.e. disruptive) testing - * This checks MAC and PHY loopback on the specified port. */ -int efx_offline_test(struct efx_nic *efx, - struct efx_self_tests *tests, unsigned int loopback_modes) -{ - enum efx_loopback_mode loopback_mode = efx->loopback_mode; - int phy_mode = efx->phy_mode; - struct ethtool_cmd ecmd, ecmd_test; - int rc, rc2 = 0; + if (!(flags & ETH_TEST_FL_OFFLINE)) + return efx_test_phy(efx, tests, flags); + + /* Offline (i.e. disruptive) testing + * This checks MAC and PHY loopback on the specified port. */ /* force the carrier state off so the kernel doesn't transmit during * the loopback test, and the watchdog timeout doesn't fire. Also put @@ -700,8 +705,15 @@ int efx_offline_test(struct efx_nic *efx, */ mutex_lock(&efx->mac_lock); efx->port_inhibited = true; - if (efx->loopback_modes) - efx->loopback_mode = __ffs(efx->loopback_modes); + if (efx->loopback_modes) { + /* We need the 312 clock from the PHY to test the XMAC + * registers, so move into XGMII loopback if available */ + if (efx->loopback_modes & (1 << LOOPBACK_XGMII)) + efx->loopback_mode = LOOPBACK_XGMII; + else + efx->loopback_mode = __ffs(efx->loopback_modes); + } + __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); @@ -709,39 +721,34 @@ int efx_offline_test(struct efx_nic *efx, efx_reset_down(efx, &ecmd); rc = efx_test_chip(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; /* reset the chip to recover from the register test */ - rc = falcon_reset_hw(efx, RESET_TYPE_ALL); - - /* Modify the saved ecmd so that when efx_reset_up() restores the phy - * state, AN is disabled, and the phy is powered, and out of loopback */ - memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); - if (ecmd_test.autoneg == AUTONEG_ENABLE) { - ecmd_test.autoneg = AUTONEG_DISABLE; - ecmd_test.duplex = DUPLEX_FULL; - ecmd_test.speed = SPEED_10000; - } + rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL); + + /* Ensure that the phy is powered and out of loopback + * for the bist and loopback tests */ + efx->phy_mode &= ~PHY_MODE_LOW_POWER; efx->loopback_mode = LOOPBACK_NONE; - rc = efx_reset_up(efx, &ecmd_test, rc == 0); - if (rc) { + rc = efx_reset_up(efx, &ecmd, rc_reset == 0); + if (rc && !rc_reset) + rc_reset = rc; + + if (rc_reset) { EFX_ERR(efx, "Unable to recover from chip test\n"); efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; + return rc_reset; } - tests->loopback_speed = ecmd_test.speed; - tests->loopback_full_duplex = ecmd_test.duplex; - - rc = efx_test_phy(efx, tests); - if (rc && !rc2) - rc2 = rc; + rc = efx_test_phy(efx, tests, flags); + if (rc && !rc_test) + rc_test = rc; - rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); - if (rc && !rc2) - rc2 = rc; + rc = efx_test_loopbacks(efx, tests, efx->loopback_modes); + if (rc && !rc_test) + rc_test = rc; /* restore the PHY to the previous state */ efx->loopback_mode = loopback_mode; @@ -749,6 +756,6 @@ int efx_offline_test(struct efx_nic *efx, efx->port_inhibited = false; efx_ethtool_set_settings(efx->net_dev, &ecmd); - return rc2; + return rc_test; } |