forked from Minki/linux
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_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 */
|
||||
#define PMA_PMD_CSERDES_CTRL_REG 64258
|
||||
/* 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);
|
||||
}
|
||||
|
||||
static const char *const tenxpress_test_names[] = {
|
||||
static const char *const sfx7101_test_names[] = {
|
||||
"bist"
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
@ -672,6 +691,86 @@ tenxpress_run_tests(struct efx_nic *efx, int *results, unsigned flags)
|
||||
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)
|
||||
{
|
||||
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,
|
||||
.get_settings = sfx7101_get_settings,
|
||||
.set_settings = mdio_clause45_set_settings,
|
||||
.num_tests = ARRAY_SIZE(tenxpress_test_names),
|
||||
.test_names = tenxpress_test_names,
|
||||
.run_tests = tenxpress_run_tests,
|
||||
.num_tests = ARRAY_SIZE(sfx7101_test_names),
|
||||
.test_names = sfx7101_test_names,
|
||||
.run_tests = sfx7101_run_tests,
|
||||
.mmds = TENXPRESS_REQUIRED_DEVS,
|
||||
.loopbacks = SFX7101_LOOPBACKS,
|
||||
};
|
||||
@ -801,9 +900,9 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
|
||||
.get_settings = sft9001_get_settings,
|
||||
.set_settings = sft9001_set_settings,
|
||||
.set_xnp_advertise = sft9001_set_xnp_advertise,
|
||||
.num_tests = ARRAY_SIZE(tenxpress_test_names),
|
||||
.test_names = tenxpress_test_names,
|
||||
.run_tests = tenxpress_run_tests,
|
||||
.num_tests = ARRAY_SIZE(sft9001_test_names),
|
||||
.test_names = sft9001_test_names,
|
||||
.run_tests = sft9001_run_tests,
|
||||
.mmds = TENXPRESS_REQUIRED_DEVS,
|
||||
.loopbacks = SFT9001_LOOPBACKS,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user