sfc: Disable VF queues during register self-test

Currently VF queues and drivers may remain active during this test.
This could cause memory corruption or spurious test failures.
Therefore we reset the port/function before running these tests on
Siena.

On Falcon this doesn't work: we have to do some additional
initialisation before some blocks will work again.  So refactor the
reset/register-test sequence into an efx_nic_type method so
efx_selftest() doesn't have to consider such quirks.

In the process, fix another minor bug: Siena does not have an
'invisible' reset and the self-test currently fails to push the PHY
configuration after resetting.  Passing RESET_TYPE_ALL to
efx_reset_{down,up}() fixes this.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
Ben Hutchings 2012-07-04 03:58:33 +01:00
Родитель 0f1e54ae52
Коммит d4f2cecce1
5 изменённых файлов: 76 добавлений и 60 удалений

Просмотреть файл

@ -25,9 +25,12 @@
#include "io.h"
#include "phy.h"
#include "workarounds.h"
#include "selftest.h"
/* Hardware control for SFC4000 (aka Falcon). */
static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
static const unsigned int
/* "Large" EEPROM device: Atmel AT25640 or similar
* 8 KB, 16-bit address, 32 B write block */
@ -1034,10 +1037,34 @@ static const struct efx_nic_register_test falcon_b0_register_tests[] = {
EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) },
};
static int falcon_b0_test_registers(struct efx_nic *efx)
static int
falcon_b0_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
{
return efx_nic_test_registers(efx, falcon_b0_register_tests,
ARRAY_SIZE(falcon_b0_register_tests));
enum reset_type reset_method = RESET_TYPE_INVISIBLE;
int rc, rc2;
mutex_lock(&efx->mac_lock);
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);
efx_reset_down(efx, reset_method);
tests->registers =
efx_nic_test_registers(efx, falcon_b0_register_tests,
ARRAY_SIZE(falcon_b0_register_tests))
? -1 : 1;
rc = falcon_reset_hw(efx, reset_method);
rc2 = efx_reset_up(efx, reset_method, rc == 0);
return rc ? rc : rc2;
}
/**************************************************************************
@ -1818,7 +1845,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
.get_wol = falcon_get_wol,
.set_wol = falcon_set_wol,
.resume_wol = efx_port_dummy_op_void,
.test_registers = falcon_b0_test_registers,
.test_chip = falcon_b0_test_chip,
.test_nvram = falcon_test_nvram,
.revision = EFX_REV_FALCON_B0,

Просмотреть файл

@ -68,6 +68,8 @@
#define EFX_TXQ_TYPES 4
#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS)
struct efx_self_tests;
/**
* struct efx_special_buffer - An Efx special buffer
* @addr: CPU base address of the buffer
@ -901,7 +903,8 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* @get_wol: Get WoL configuration from driver state
* @set_wol: Push WoL configuration to the NIC
* @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
* @test_registers: Test read/write functionality of control registers
* @test_chip: Test registers. Should use efx_nic_test_registers(), and is
* expected to reset the NIC.
* @test_nvram: Test validity of NVRAM contents
* @revision: Hardware architecture revision
* @mem_map_size: Memory BAR mapped size
@ -946,7 +949,7 @@ struct efx_nic_type {
void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
int (*set_wol)(struct efx_nic *efx, u32 type);
void (*resume_wol)(struct efx_nic *efx);
int (*test_registers)(struct efx_nic *efx);
int (*test_chip)(struct efx_nic *efx, struct efx_self_tests *tests);
int (*test_nvram)(struct efx_nic *efx);
int revision;

Просмотреть файл

@ -124,9 +124,6 @@ int efx_nic_test_registers(struct efx_nic *efx,
unsigned address = 0, i, j;
efx_oword_t mask, imask, original, reg, buf;
/* Falcon should be in loopback to isolate the XMAC from the PHY */
WARN_ON(!LOOPBACK_INTERNAL(efx));
for (i = 0; i < n_regs; ++i) {
address = regs[i].address;
mask = imask = regs[i].mask;

Просмотреть файл

@ -120,19 +120,6 @@ static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests)
return rc;
}
static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
{
int rc = 0;
/* Test register access */
if (efx->type->test_registers) {
rc = efx->type->test_registers(efx);
tests->registers = rc ? -1 : 1;
}
return rc;
}
/**************************************************************************
*
* Interrupt and event queue testing
@ -699,8 +686,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
{
enum efx_loopback_mode loopback_mode = efx->loopback_mode;
int phy_mode = efx->phy_mode;
enum reset_type reset_method = RESET_TYPE_INVISIBLE;
int rc_test = 0, rc_reset = 0, rc;
int rc_test = 0, rc_reset, rc;
efx_selftest_async_cancel(efx);
@ -737,44 +723,26 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
*/
netif_device_detach(efx->net_dev);
mutex_lock(&efx->mac_lock);
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);
if (efx->type->test_chip) {
rc_reset = efx->type->test_chip(efx, tests);
if (rc_reset) {
netif_err(efx, hw, efx->net_dev,
"Unable to recover from chip test\n");
efx_schedule_reset(efx, RESET_TYPE_DISABLE);
return rc_reset;
}
if ((tests->registers < 0) && !rc_test)
rc_test = -EIO;
}
__efx_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
/* free up all consumers of SRAM (including all the queues) */
efx_reset_down(efx, reset_method);
rc = efx_test_chip(efx, tests);
if (rc && !rc_test)
rc_test = rc;
/* reset the chip to recover from the register test */
rc_reset = efx->type->reset(efx, reset_method);
/* Ensure that the phy is powered and out of loopback
* for the bist and loopback tests */
mutex_lock(&efx->mac_lock);
efx->phy_mode &= ~PHY_MODE_LOW_POWER;
efx->loopback_mode = LOOPBACK_NONE;
rc = efx_reset_up(efx, reset_method, rc_reset == 0);
if (rc && !rc_reset)
rc_reset = rc;
if (rc_reset) {
netif_err(efx, drv, efx->net_dev,
"Unable to recover from chip test\n");
efx_schedule_reset(efx, RESET_TYPE_DISABLE);
return rc_reset;
}
__efx_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
rc = efx_test_phy(efx, tests, flags);
if (rc && !rc_test)

Просмотреть файл

@ -25,10 +25,12 @@
#include "workarounds.h"
#include "mcdi.h"
#include "mcdi_pcol.h"
#include "selftest.h"
/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */
static void siena_init_wol(struct efx_nic *efx);
static int siena_reset_hw(struct efx_nic *efx, enum reset_type method);
static void siena_push_irq_moderation(struct efx_channel *channel)
@ -154,10 +156,29 @@ static const struct efx_nic_register_test siena_register_tests[] = {
EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) },
};
static int siena_test_registers(struct efx_nic *efx)
static int siena_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
{
return efx_nic_test_registers(efx, siena_register_tests,
ARRAY_SIZE(siena_register_tests));
enum reset_type reset_method = reset_method;
int rc, rc2;
efx_reset_down(efx, reset_method);
/* Reset the chip immediately so that it is completely
* quiescent regardless of what any VF driver does.
*/
rc = siena_reset_hw(efx, reset_method);
if (rc)
goto out;
tests->registers =
efx_nic_test_registers(efx, siena_register_tests,
ARRAY_SIZE(siena_register_tests))
? -1 : 1;
rc = siena_reset_hw(efx, reset_method);
out:
rc2 = efx_reset_up(efx, reset_method, rc == 0);
return rc ? rc : rc2;
}
/**************************************************************************
@ -649,7 +670,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.get_wol = siena_get_wol,
.set_wol = siena_set_wol,
.resume_wol = siena_init_wol,
.test_registers = siena_test_registers,
.test_chip = siena_test_chip,
.test_nvram = efx_mcdi_nvram_test_all,
.revision = EFX_REV_SIENA_A0,