Commit 4b988280 authored by Steve Hodgson's avatar Steve Hodgson Committed by David S. Miller

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: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0cc12838
...@@ -676,9 +676,8 @@ static int efx_init_port(struct efx_nic *efx) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment