sfc: SFT9001: Add cable diagnostics
The SFT9001 firmware implements cable diagnostics; run those and include their results in a self-test. In case of a cable fault, do not fail the self-test as a whole; only faults in the NIC should cause that. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1796721a5a
commit
307505e9a4
|
@ -106,6 +106,25 @@
|
||||||
#define PMA_PMD_SPEED_LBN 4
|
#define PMA_PMD_SPEED_LBN 4
|
||||||
#define PMA_PMD_SPEED_WIDTH 4
|
#define PMA_PMD_SPEED_WIDTH 4
|
||||||
|
|
||||||
|
/* Cable diagnostics - SFT9001 only */
|
||||||
|
#define PMA_PMD_CDIAG_CTRL_REG 49213
|
||||||
|
#define CDIAG_CTRL_IMMED_LBN 15
|
||||||
|
#define CDIAG_CTRL_BRK_LINK_LBN 12
|
||||||
|
#define CDIAG_CTRL_IN_PROG_LBN 11
|
||||||
|
#define CDIAG_CTRL_LEN_UNIT_LBN 10
|
||||||
|
#define CDIAG_CTRL_LEN_METRES 1
|
||||||
|
#define PMA_PMD_CDIAG_RES_REG 49174
|
||||||
|
#define CDIAG_RES_A_LBN 12
|
||||||
|
#define CDIAG_RES_B_LBN 8
|
||||||
|
#define CDIAG_RES_C_LBN 4
|
||||||
|
#define CDIAG_RES_D_LBN 0
|
||||||
|
#define CDIAG_RES_WIDTH 4
|
||||||
|
#define CDIAG_RES_OPEN 2
|
||||||
|
#define CDIAG_RES_OK 1
|
||||||
|
#define CDIAG_RES_INVALID 0
|
||||||
|
/* Set of 4 registers for pairs A-D */
|
||||||
|
#define PMA_PMD_CDIAG_LEN_REG 49175
|
||||||
|
|
||||||
/* Serdes control registers - SFT9001 only */
|
/* Serdes control registers - SFT9001 only */
|
||||||
#define PMA_PMD_CSERDES_CTRL_REG 64258
|
#define PMA_PMD_CSERDES_CTRL_REG 64258
|
||||||
/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */
|
/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */
|
||||||
|
@ -654,12 +673,12 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink)
|
||||||
PMA_PMD_LED_OVERR_REG, reg);
|
PMA_PMD_LED_OVERR_REG, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *const tenxpress_test_names[] = {
|
static const char *const sfx7101_test_names[] = {
|
||||||
"bist"
|
"bist"
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tenxpress_run_tests(struct efx_nic *efx, int *results, unsigned flags)
|
sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -672,6 +691,86 @@ tenxpress_run_tests(struct efx_nic *efx, int *results, unsigned flags)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *const sft9001_test_names[] = {
|
||||||
|
"bist",
|
||||||
|
"cable.pairA.status",
|
||||||
|
"cable.pairB.status",
|
||||||
|
"cable.pairC.status",
|
||||||
|
"cable.pairD.status",
|
||||||
|
"cable.pairA.length",
|
||||||
|
"cable.pairB.length",
|
||||||
|
"cable.pairC.length",
|
||||||
|
"cable.pairD.length",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
|
||||||
|
{
|
||||||
|
struct ethtool_cmd ecmd;
|
||||||
|
int phy_id = efx->mii.phy_id;
|
||||||
|
int rc = 0, rc2, i, res_reg;
|
||||||
|
|
||||||
|
if (!(flags & ETH_TEST_FL_OFFLINE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
efx->phy_op->get_settings(efx, &ecmd);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||||
|
PMA_PMD_CDIAG_CTRL_REG,
|
||||||
|
(1 << CDIAG_CTRL_IMMED_LBN) |
|
||||||
|
(1 << CDIAG_CTRL_BRK_LINK_LBN) |
|
||||||
|
(CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
|
||||||
|
i = 0;
|
||||||
|
while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
|
||||||
|
PMA_PMD_CDIAG_CTRL_REG) &
|
||||||
|
(1 << CDIAG_CTRL_IN_PROG_LBN)) {
|
||||||
|
if (++i == 50) {
|
||||||
|
rc = -ETIMEDOUT;
|
||||||
|
goto reset;
|
||||||
|
}
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
res_reg = mdio_clause45_read(efx, efx->mii.phy_id, 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 = mdio_clause45_read(efx, efx->mii.phy_id,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We must reset to exit cable diagnostic mode. The BIST will
|
||||||
|
* also run when we do this. */
|
||||||
|
reset:
|
||||||
|
rc2 = tenxpress_special_reset(efx);
|
||||||
|
results[0] = rc2 ? -1 : 1;
|
||||||
|
if (!rc)
|
||||||
|
rc = rc2;
|
||||||
|
|
||||||
|
rc2 = efx->phy_op->set_settings(efx, &ecmd);
|
||||||
|
if (!rc)
|
||||||
|
rc = rc2;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx)
|
static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx)
|
||||||
{
|
{
|
||||||
int phy = efx->mii.phy_id;
|
int phy = efx->mii.phy_id;
|
||||||
|
@ -784,9 +883,9 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
|
||||||
.clear_interrupt = efx_port_dummy_op_void,
|
.clear_interrupt = efx_port_dummy_op_void,
|
||||||
.get_settings = sfx7101_get_settings,
|
.get_settings = sfx7101_get_settings,
|
||||||
.set_settings = mdio_clause45_set_settings,
|
.set_settings = mdio_clause45_set_settings,
|
||||||
.num_tests = ARRAY_SIZE(tenxpress_test_names),
|
.num_tests = ARRAY_SIZE(sfx7101_test_names),
|
||||||
.test_names = tenxpress_test_names,
|
.test_names = sfx7101_test_names,
|
||||||
.run_tests = tenxpress_run_tests,
|
.run_tests = sfx7101_run_tests,
|
||||||
.mmds = TENXPRESS_REQUIRED_DEVS,
|
.mmds = TENXPRESS_REQUIRED_DEVS,
|
||||||
.loopbacks = SFX7101_LOOPBACKS,
|
.loopbacks = SFX7101_LOOPBACKS,
|
||||||
};
|
};
|
||||||
|
@ -801,9 +900,9 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
|
||||||
.get_settings = sft9001_get_settings,
|
.get_settings = sft9001_get_settings,
|
||||||
.set_settings = sft9001_set_settings,
|
.set_settings = sft9001_set_settings,
|
||||||
.set_xnp_advertise = sft9001_set_xnp_advertise,
|
.set_xnp_advertise = sft9001_set_xnp_advertise,
|
||||||
.num_tests = ARRAY_SIZE(tenxpress_test_names),
|
.num_tests = ARRAY_SIZE(sft9001_test_names),
|
||||||
.test_names = tenxpress_test_names,
|
.test_names = sft9001_test_names,
|
||||||
.run_tests = tenxpress_run_tests,
|
.run_tests = sft9001_run_tests,
|
||||||
.mmds = TENXPRESS_REQUIRED_DEVS,
|
.mmds = TENXPRESS_REQUIRED_DEVS,
|
||||||
.loopbacks = SFT9001_LOOPBACKS,
|
.loopbacks = SFT9001_LOOPBACKS,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue