sfc: Add support for multiple PHY self-tests
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
2ef3068e6c
commit
1796721a5a
|
@ -345,7 +345,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
|
||||||
u64 *data)
|
u64 *data)
|
||||||
{
|
{
|
||||||
struct efx_channel *channel;
|
struct efx_channel *channel;
|
||||||
unsigned int n = 0;
|
unsigned int n = 0, i;
|
||||||
enum efx_loopback_mode mode;
|
enum efx_loopback_mode mode;
|
||||||
|
|
||||||
efx_fill_test(n++, strings, data, &tests->mii,
|
efx_fill_test(n++, strings, data, &tests->mii,
|
||||||
|
@ -373,8 +373,10 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
|
||||||
|
|
||||||
efx_fill_test(n++, strings, data, &tests->registers,
|
efx_fill_test(n++, strings, data, &tests->registers,
|
||||||
"core", 0, "registers", NULL);
|
"core", 0, "registers", NULL);
|
||||||
efx_fill_test(n++, strings, data, &tests->phy,
|
|
||||||
"phy", 0, "bist", NULL);
|
for (i = 0; i < efx->phy_op->num_tests; i++)
|
||||||
|
efx_fill_test(n++, strings, data, &tests->phy[i],
|
||||||
|
"phy", 0, efx->phy_op->test_names[i], NULL);
|
||||||
|
|
||||||
/* Loopback tests */
|
/* Loopback tests */
|
||||||
for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
|
for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
|
||||||
|
|
|
@ -568,6 +568,10 @@ struct efx_mac_operations {
|
||||||
* @set_settings: Set ethtool settings. Serialised by the mac_lock.
|
* @set_settings: Set ethtool settings. Serialised by the mac_lock.
|
||||||
* @set_xnp_advertise: Set abilities advertised in Extended Next Page
|
* @set_xnp_advertise: Set abilities advertised in Extended Next Page
|
||||||
* (only needed where AN bit is set in mmds)
|
* (only needed where AN bit is set in mmds)
|
||||||
|
* @num_tests: Number of PHY-specific tests/results
|
||||||
|
* @test_names: Names of the tests/results
|
||||||
|
* @run_tests: Run tests and record results as appropriate.
|
||||||
|
* Flags are the ethtool tests flags.
|
||||||
* @mmds: MMD presence mask
|
* @mmds: MMD presence mask
|
||||||
* @loopbacks: Supported loopback modes mask
|
* @loopbacks: Supported loopback modes mask
|
||||||
*/
|
*/
|
||||||
|
@ -578,12 +582,14 @@ struct efx_phy_operations {
|
||||||
void (*reconfigure) (struct efx_nic *efx);
|
void (*reconfigure) (struct efx_nic *efx);
|
||||||
void (*clear_interrupt) (struct efx_nic *efx);
|
void (*clear_interrupt) (struct efx_nic *efx);
|
||||||
void (*poll) (struct efx_nic *efx);
|
void (*poll) (struct efx_nic *efx);
|
||||||
int (*test) (struct efx_nic *efx);
|
|
||||||
void (*get_settings) (struct efx_nic *efx,
|
void (*get_settings) (struct efx_nic *efx,
|
||||||
struct ethtool_cmd *ecmd);
|
struct ethtool_cmd *ecmd);
|
||||||
int (*set_settings) (struct efx_nic *efx,
|
int (*set_settings) (struct efx_nic *efx,
|
||||||
struct ethtool_cmd *ecmd);
|
struct ethtool_cmd *ecmd);
|
||||||
bool (*set_xnp_advertise) (struct efx_nic *efx, u32);
|
bool (*set_xnp_advertise) (struct efx_nic *efx, u32);
|
||||||
|
u32 num_tests;
|
||||||
|
const char *const *test_names;
|
||||||
|
int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags);
|
||||||
int mmds;
|
int mmds;
|
||||||
unsigned loopbacks;
|
unsigned loopbacks;
|
||||||
};
|
};
|
||||||
|
|
|
@ -247,17 +247,20 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
|
||||||
return 0;
|
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;
|
int rc;
|
||||||
|
|
||||||
if (!efx->phy_op->test)
|
if (!efx->phy_op->run_tests)
|
||||||
return 0;
|
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);
|
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);
|
mutex_unlock(&efx->mac_lock);
|
||||||
tests->phy = rc ? -1 : 1;
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -691,7 +694,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
|
||||||
return rc_test;
|
return rc_test;
|
||||||
|
|
||||||
if (!(flags & ETH_TEST_FL_OFFLINE))
|
if (!(flags & ETH_TEST_FL_OFFLINE))
|
||||||
return 0;
|
return efx_test_phy(efx, tests, flags);
|
||||||
|
|
||||||
/* Offline (i.e. disruptive) testing
|
/* Offline (i.e. disruptive) testing
|
||||||
* This checks MAC and PHY loopback on the specified port. */
|
* This checks MAC and PHY loopback on the specified port. */
|
||||||
|
@ -739,7 +742,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
|
||||||
return rc_reset;
|
return rc_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = efx_test_phy(efx, tests);
|
rc = efx_test_phy(efx, tests, flags);
|
||||||
if (rc && !rc_test)
|
if (rc && !rc_test)
|
||||||
rc_test = rc;
|
rc_test = rc;
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ struct efx_loopback_self_tests {
|
||||||
int rx_bad;
|
int rx_bad;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define EFX_MAX_PHY_TESTS 20
|
||||||
|
|
||||||
/* Efx self test results
|
/* Efx self test results
|
||||||
* For fields which are not counters, 1 indicates success and -1
|
* For fields which are not counters, 1 indicates success and -1
|
||||||
* indicates failure.
|
* indicates failure.
|
||||||
|
@ -38,7 +40,7 @@ struct efx_self_tests {
|
||||||
int eventq_poll[EFX_MAX_CHANNELS];
|
int eventq_poll[EFX_MAX_CHANNELS];
|
||||||
/* offline tests */
|
/* offline tests */
|
||||||
int registers;
|
int registers;
|
||||||
int phy;
|
int phy[EFX_MAX_PHY_TESTS];
|
||||||
struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
|
struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -654,10 +654,22 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink)
|
||||||
PMA_PMD_LED_OVERR_REG, reg);
|
PMA_PMD_LED_OVERR_REG, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tenxpress_phy_test(struct efx_nic *efx)
|
static const char *const tenxpress_test_names[] = {
|
||||||
|
"bist"
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
tenxpress_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 */
|
/* BIST is automatically run after a special software reset */
|
||||||
return tenxpress_special_reset(efx);
|
rc = tenxpress_special_reset(efx);
|
||||||
|
results[0] = rc ? -1 : 1;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx)
|
static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx)
|
||||||
|
@ -770,9 +782,11 @@ struct efx_phy_operations falcon_sfx7101_phy_ops = {
|
||||||
.poll = tenxpress_phy_poll,
|
.poll = tenxpress_phy_poll,
|
||||||
.fini = tenxpress_phy_fini,
|
.fini = tenxpress_phy_fini,
|
||||||
.clear_interrupt = efx_port_dummy_op_void,
|
.clear_interrupt = efx_port_dummy_op_void,
|
||||||
.test = tenxpress_phy_test,
|
|
||||||
.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),
|
||||||
|
.test_names = tenxpress_test_names,
|
||||||
|
.run_tests = tenxpress_run_tests,
|
||||||
.mmds = TENXPRESS_REQUIRED_DEVS,
|
.mmds = TENXPRESS_REQUIRED_DEVS,
|
||||||
.loopbacks = SFX7101_LOOPBACKS,
|
.loopbacks = SFX7101_LOOPBACKS,
|
||||||
};
|
};
|
||||||
|
@ -784,10 +798,12 @@ struct efx_phy_operations falcon_sft9001_phy_ops = {
|
||||||
.poll = tenxpress_phy_poll,
|
.poll = tenxpress_phy_poll,
|
||||||
.fini = tenxpress_phy_fini,
|
.fini = tenxpress_phy_fini,
|
||||||
.clear_interrupt = efx_port_dummy_op_void,
|
.clear_interrupt = efx_port_dummy_op_void,
|
||||||
.test = tenxpress_phy_test,
|
|
||||||
.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),
|
||||||
|
.test_names = tenxpress_test_names,
|
||||||
|
.run_tests = tenxpress_run_tests,
|
||||||
.mmds = TENXPRESS_REQUIRED_DEVS,
|
.mmds = TENXPRESS_REQUIRED_DEVS,
|
||||||
.loopbacks = SFT9001_LOOPBACKS,
|
.loopbacks = SFT9001_LOOPBACKS,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue