Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4f2cecc authored by Ben Hutchings's avatar Ben Hutchings
Browse files

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: default avatarBen Hutchings <bhutchings@solarflare.com>
parent 0f1e54ae
Loading
Loading
Loading
Loading
+31 −4
Original line number Diff line number Diff line
@@ -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,
+5 −2
Original line number Diff line number Diff line
@@ -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;
+0 −3
Original line number Diff line number Diff line
@@ -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;
+15 −47
Original line number Diff line number Diff line
@@ -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;
		}

	__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);
		if ((tests->registers < 0) && !rc_test)
			rc_test = -EIO;
	}

	/* 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 −4
Original line number Diff line number Diff line
@@ -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,