static int tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return 0; } phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); falcon_reset_xaui(efx); } tenxpress_low_power(efx); efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); efx_mdio_an_reconfigure(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; return 0; }
static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) { int rc = 0, rc2, i, ctrl_reg, res_reg; /* Initialise cable diagnostic results to unknown failure */ for (i = 1; i < 9; ++i) results[i] = -1; /* Run cable diagnostics; wait up to 5 seconds for them to complete. * A cable fault is not a self-test failure, but a timeout is. */ ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) | (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN)); if (flags & ETH_TEST_FL_OFFLINE) { /* Break the link in order to run full diagnostics. We * must reset the PHY to resume normal service. */ ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN); } efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG, ctrl_reg); i = 0; while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) & (1 << CDIAG_CTRL_IN_PROG_LBN)) { if (++i == 50) { rc = -ETIMEDOUT; goto out; } msleep(100); } res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG); for (i = 0; i < 4; i++) { int pair_res = (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) & ((1 << CDIAG_RES_WIDTH) - 1); int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_LEN_REG + i); if (pair_res == CDIAG_RES_OK) results[1 + i] = 1; else if (pair_res == CDIAG_RES_INVALID) results[1 + i] = -1; else results[1 + i] = -pair_res; if (pair_res != CDIAG_RES_INVALID && pair_res != CDIAG_RES_OPEN && len_reg != 0xffff) results[5 + i] = len_reg; } out: if (flags & ETH_TEST_FL_OFFLINE) { /* Reset, running the BIST and then resuming normal service. */ rc2 = tenxpress_special_reset(efx); results[0] = rc2 ? -1 : 1; if (!rc) rc = rc2; efx_mdio_an_reconfigure(efx); } return rc; }
static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; struct ethtool_cmd ecmd; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return; } tenxpress_low_power(efx); phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { int rc; efx->phy_op->get_settings(efx, &ecmd); if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); /* Reset XAUI if we were in 10G, and are staying * in 10G. If we're moving into and out of 10G * then xaui will be reset anyway */ if (EFX_IS10G(efx)) falcon_reset_xaui(efx); } rc = efx->phy_op->set_settings(efx, &ecmd); WARN_ON(rc); } mdio_clause45_transmit_disable(efx); mdio_clause45_phy_reconfigure(efx); tenxpress_ext_loopback(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; if (efx->phy_type == PHY_TYPE_SFX7101) { efx->link_speed = 10000; efx->link_fd = true; efx->link_up = sfx7101_link_ok(efx); } else { efx->phy_op->get_settings(efx, &ecmd); efx->link_speed = ecmd.speed; efx->link_fd = ecmd.duplex == DUPLEX_FULL; efx->link_up = sft9001_link_ok(efx, &ecmd); } efx->link_fc = mdio_clause45_get_pause(efx); }
static int sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) { int rc; if (!(flags & ETH_TEST_FL_OFFLINE)) return 0; /* BIST is automatically run after a special software reset */ rc = tenxpress_special_reset(efx); results[0] = rc ? -1 : 1; return rc; }
static int sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) { int rc; if (!(flags & ETH_TEST_FL_OFFLINE)) return 0; rc = tenxpress_special_reset(efx); results[0] = rc ? -1 : 1; efx_mdio_an_reconfigure(efx); return rc; }
static int tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return 0; } phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); /* Reset XAUI if we were in 10G, and are staying * in 10G. If we're moving into and out of 10G * then xaui will be reset anyway */ if (EFX_IS10G(efx)) falcon_reset_xaui(efx); } tenxpress_low_power(efx); efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); efx_mdio_an_reconfigure(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; return 0; }