sfc: Reinitialise the PHY completely in case of a PHY or NIC reset
In particular, set pause advertising bits properly. A PHY reset is not necessary to recover from the register self-test, so use a "invisible" reset there instead. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0cc1283879
commit
4b988280be
|
@ -676,9 +676,8 @@ static int efx_init_port(struct efx_nic *efx)
|
||||||
rc = efx->phy_op->init(efx);
|
rc = efx->phy_op->init(efx);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
efx->phy_op->reconfigure(efx);
|
|
||||||
|
|
||||||
mutex_lock(&efx->mac_lock);
|
mutex_lock(&efx->mac_lock);
|
||||||
|
efx->phy_op->reconfigure(efx);
|
||||||
rc = falcon_switch_mac(efx);
|
rc = falcon_switch_mac(efx);
|
||||||
mutex_unlock(&efx->mac_lock);
|
mutex_unlock(&efx->mac_lock);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1622,7 +1621,8 @@ static void efx_unregister_netdev(struct efx_nic *efx)
|
||||||
|
|
||||||
/* Tears down the entire software state and most of the hardware state
|
/* Tears down the entire software state and most of the hardware state
|
||||||
* before reset. */
|
* before reset. */
|
||||||
void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
void efx_reset_down(struct efx_nic *efx, enum reset_type method,
|
||||||
|
struct ethtool_cmd *ecmd)
|
||||||
{
|
{
|
||||||
EFX_ASSERT_RESET_SERIALISED(efx);
|
EFX_ASSERT_RESET_SERIALISED(efx);
|
||||||
|
|
||||||
|
@ -1639,6 +1639,8 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
||||||
efx->phy_op->get_settings(efx, ecmd);
|
efx->phy_op->get_settings(efx, ecmd);
|
||||||
|
|
||||||
efx_fini_channels(efx);
|
efx_fini_channels(efx);
|
||||||
|
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
|
||||||
|
efx->phy_op->fini(efx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function will always ensure that the locks acquired in
|
/* This function will always ensure that the locks acquired in
|
||||||
|
@ -1646,7 +1648,8 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
|
||||||
* that we were unable to reinitialise the hardware, and the
|
* that we were unable to reinitialise the hardware, and the
|
||||||
* driver should be disabled. If ok is false, then the rx and tx
|
* driver should be disabled. If ok is false, then the rx and tx
|
||||||
* engines are not restarted, pending a RESET_DISABLE. */
|
* engines are not restarted, pending a RESET_DISABLE. */
|
||||||
int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok)
|
int efx_reset_up(struct efx_nic *efx, enum reset_type method,
|
||||||
|
struct ethtool_cmd *ecmd, bool ok)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -1658,6 +1661,15 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok)
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
|
||||||
|
if (ok) {
|
||||||
|
rc = efx->phy_op->init(efx);
|
||||||
|
if (rc)
|
||||||
|
ok = false;
|
||||||
|
} else
|
||||||
|
efx->port_initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
efx_init_channels(efx);
|
efx_init_channels(efx);
|
||||||
|
|
||||||
|
@ -1702,7 +1714,7 @@ static int efx_reset(struct efx_nic *efx)
|
||||||
|
|
||||||
EFX_INFO(efx, "resetting (%d)\n", method);
|
EFX_INFO(efx, "resetting (%d)\n", method);
|
||||||
|
|
||||||
efx_reset_down(efx, &ecmd);
|
efx_reset_down(efx, method, &ecmd);
|
||||||
|
|
||||||
rc = falcon_reset_hw(efx, method);
|
rc = falcon_reset_hw(efx, method);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -1721,10 +1733,10 @@ static int efx_reset(struct efx_nic *efx)
|
||||||
|
|
||||||
/* Leave device stopped if necessary */
|
/* Leave device stopped if necessary */
|
||||||
if (method == RESET_TYPE_DISABLE) {
|
if (method == RESET_TYPE_DISABLE) {
|
||||||
efx_reset_up(efx, &ecmd, false);
|
efx_reset_up(efx, method, &ecmd, false);
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
} else {
|
} else {
|
||||||
rc = efx_reset_up(efx, &ecmd, true);
|
rc = efx_reset_up(efx, method, &ecmd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
out_disable:
|
out_disable:
|
||||||
|
|
|
@ -40,9 +40,10 @@ extern void efx_reconfigure_port(struct efx_nic *efx);
|
||||||
extern void __efx_reconfigure_port(struct efx_nic *efx);
|
extern void __efx_reconfigure_port(struct efx_nic *efx);
|
||||||
|
|
||||||
/* Reset handling */
|
/* Reset handling */
|
||||||
extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd);
|
extern void efx_reset_down(struct efx_nic *efx, enum reset_type method,
|
||||||
extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd,
|
struct ethtool_cmd *ecmd);
|
||||||
bool ok);
|
extern int efx_reset_up(struct efx_nic *efx, enum reset_type method,
|
||||||
|
struct ethtool_cmd *ecmd, bool ok);
|
||||||
|
|
||||||
/* Global */
|
/* Global */
|
||||||
extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
|
extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
|
||||||
|
|
|
@ -665,6 +665,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
|
||||||
{
|
{
|
||||||
enum efx_loopback_mode loopback_mode = efx->loopback_mode;
|
enum efx_loopback_mode loopback_mode = efx->loopback_mode;
|
||||||
int phy_mode = efx->phy_mode;
|
int phy_mode = efx->phy_mode;
|
||||||
|
enum reset_type reset_method = RESET_TYPE_INVISIBLE;
|
||||||
struct ethtool_cmd ecmd;
|
struct ethtool_cmd ecmd;
|
||||||
struct efx_channel *channel;
|
struct efx_channel *channel;
|
||||||
int rc_test = 0, rc_reset = 0, rc;
|
int rc_test = 0, rc_reset = 0, rc;
|
||||||
|
@ -718,21 +719,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
|
||||||
mutex_unlock(&efx->mac_lock);
|
mutex_unlock(&efx->mac_lock);
|
||||||
|
|
||||||
/* free up all consumers of SRAM (including all the queues) */
|
/* free up all consumers of SRAM (including all the queues) */
|
||||||
efx_reset_down(efx, &ecmd);
|
efx_reset_down(efx, reset_method, &ecmd);
|
||||||
|
|
||||||
rc = efx_test_chip(efx, tests);
|
rc = efx_test_chip(efx, tests);
|
||||||
if (rc && !rc_test)
|
if (rc && !rc_test)
|
||||||
rc_test = rc;
|
rc_test = rc;
|
||||||
|
|
||||||
/* reset the chip to recover from the register test */
|
/* reset the chip to recover from the register test */
|
||||||
rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL);
|
rc_reset = falcon_reset_hw(efx, reset_method);
|
||||||
|
|
||||||
/* Ensure that the phy is powered and out of loopback
|
/* Ensure that the phy is powered and out of loopback
|
||||||
* for the bist and loopback tests */
|
* for the bist and loopback tests */
|
||||||
efx->phy_mode &= ~PHY_MODE_LOW_POWER;
|
efx->phy_mode &= ~PHY_MODE_LOW_POWER;
|
||||||
efx->loopback_mode = LOOPBACK_NONE;
|
efx->loopback_mode = LOOPBACK_NONE;
|
||||||
|
|
||||||
rc = efx_reset_up(efx, &ecmd, rc_reset == 0);
|
rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0);
|
||||||
if (rc && !rc_reset)
|
if (rc && !rc_reset)
|
||||||
rc_reset = rc;
|
rc_reset = rc;
|
||||||
|
|
||||||
|
|
|
@ -337,6 +337,7 @@ static int tenxpress_phy_init(struct efx_nic *efx)
|
||||||
rc = tenxpress_init(efx);
|
rc = tenxpress_init(efx);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
mdio_clause45_set_pause(efx);
|
||||||
|
|
||||||
if (efx->phy_type == PHY_TYPE_SFT9001B) {
|
if (efx->phy_type == PHY_TYPE_SFT9001B) {
|
||||||
rc = device_create_file(&efx->pci_dev->dev,
|
rc = device_create_file(&efx->pci_dev->dev,
|
||||||
|
|
Loading…
Reference in New Issue