diff options
author | Steve Hodgson <shodgson@solarflare.com> | 2009-01-29 12:50:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-30 17:06:30 -0500 |
commit | 4b988280be13a1b4c17f51cc66948aef467e7601 (patch) | |
tree | b8a0bd4e96520461caeaeeea2f91aa64d6c32bdd /drivers | |
parent | 0cc128387969753ae037401eb49e4bbb474186ea (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sfc/efx.c | 26 | ||||
-rw-r--r-- | drivers/net/sfc/efx.h | 7 | ||||
-rw-r--r-- | drivers/net/sfc/selftest.c | 7 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 1 |
4 files changed, 28 insertions, 13 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 7673fd92eaf5..b0e53087bda0 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -676,9 +676,8 @@ static int efx_init_port(struct efx_nic *efx) | |||
676 | rc = efx->phy_op->init(efx); | 676 | rc = efx->phy_op->init(efx); |
677 | if (rc) | 677 | if (rc) |
678 | return rc; | 678 | return rc; |
679 | efx->phy_op->reconfigure(efx); | ||
680 | |||
681 | mutex_lock(&efx->mac_lock); | 679 | mutex_lock(&efx->mac_lock); |
680 | efx->phy_op->reconfigure(efx); | ||
682 | rc = falcon_switch_mac(efx); | 681 | rc = falcon_switch_mac(efx); |
683 | mutex_unlock(&efx->mac_lock); | 682 | mutex_unlock(&efx->mac_lock); |
684 | if (rc) | 683 | if (rc) |
@@ -1622,7 +1621,8 @@ static void efx_unregister_netdev(struct efx_nic *efx) | |||
1622 | 1621 | ||
1623 | /* Tears down the entire software state and most of the hardware state | 1622 | /* Tears down the entire software state and most of the hardware state |
1624 | * before reset. */ | 1623 | * before reset. */ |
1625 | void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) | 1624 | void efx_reset_down(struct efx_nic *efx, enum reset_type method, |
1625 | struct ethtool_cmd *ecmd) | ||
1626 | { | 1626 | { |
1627 | EFX_ASSERT_RESET_SERIALISED(efx); | 1627 | EFX_ASSERT_RESET_SERIALISED(efx); |
1628 | 1628 | ||
@@ -1639,6 +1639,8 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) | |||
1639 | efx->phy_op->get_settings(efx, ecmd); | 1639 | efx->phy_op->get_settings(efx, ecmd); |
1640 | 1640 | ||
1641 | efx_fini_channels(efx); | 1641 | efx_fini_channels(efx); |
1642 | if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) | ||
1643 | efx->phy_op->fini(efx); | ||
1642 | } | 1644 | } |
1643 | 1645 | ||
1644 | /* This function will always ensure that the locks acquired in | 1646 | /* 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 | * that we were unable to reinitialise the hardware, and the | 1648 | * that we were unable to reinitialise the hardware, and the |
1647 | * driver should be disabled. If ok is false, then the rx and tx | 1649 | * driver should be disabled. If ok is false, then the rx and tx |
1648 | * engines are not restarted, pending a RESET_DISABLE. */ | 1650 | * engines are not restarted, pending a RESET_DISABLE. */ |
1649 | int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) | 1651 | int efx_reset_up(struct efx_nic *efx, enum reset_type method, |
1652 | struct ethtool_cmd *ecmd, bool ok) | ||
1650 | { | 1653 | { |
1651 | int rc; | 1654 | int rc; |
1652 | 1655 | ||
@@ -1658,6 +1661,15 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) | |||
1658 | ok = false; | 1661 | ok = false; |
1659 | } | 1662 | } |
1660 | 1663 | ||
1664 | if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { | ||
1665 | if (ok) { | ||
1666 | rc = efx->phy_op->init(efx); | ||
1667 | if (rc) | ||
1668 | ok = false; | ||
1669 | } else | ||
1670 | efx->port_initialized = false; | ||
1671 | } | ||
1672 | |||
1661 | if (ok) { | 1673 | if (ok) { |
1662 | efx_init_channels(efx); | 1674 | efx_init_channels(efx); |
1663 | 1675 | ||
@@ -1702,7 +1714,7 @@ static int efx_reset(struct efx_nic *efx) | |||
1702 | 1714 | ||
1703 | EFX_INFO(efx, "resetting (%d)\n", method); | 1715 | EFX_INFO(efx, "resetting (%d)\n", method); |
1704 | 1716 | ||
1705 | efx_reset_down(efx, &ecmd); | 1717 | efx_reset_down(efx, method, &ecmd); |
1706 | 1718 | ||
1707 | rc = falcon_reset_hw(efx, method); | 1719 | rc = falcon_reset_hw(efx, method); |
1708 | if (rc) { | 1720 | if (rc) { |
@@ -1721,10 +1733,10 @@ static int efx_reset(struct efx_nic *efx) | |||
1721 | 1733 | ||
1722 | /* Leave device stopped if necessary */ | 1734 | /* Leave device stopped if necessary */ |
1723 | if (method == RESET_TYPE_DISABLE) { | 1735 | if (method == RESET_TYPE_DISABLE) { |
1724 | efx_reset_up(efx, &ecmd, false); | 1736 | efx_reset_up(efx, method, &ecmd, false); |
1725 | rc = -EIO; | 1737 | rc = -EIO; |
1726 | } else { | 1738 | } else { |
1727 | rc = efx_reset_up(efx, &ecmd, true); | 1739 | rc = efx_reset_up(efx, method, &ecmd, true); |
1728 | } | 1740 | } |
1729 | 1741 | ||
1730 | out_disable: | 1742 | out_disable: |
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 0dd7a532c78a..ac201587a163 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h | |||
@@ -40,9 +40,10 @@ extern void efx_reconfigure_port(struct efx_nic *efx); | |||
40 | extern void __efx_reconfigure_port(struct efx_nic *efx); | 40 | extern void __efx_reconfigure_port(struct efx_nic *efx); |
41 | 41 | ||
42 | /* Reset handling */ | 42 | /* Reset handling */ |
43 | extern void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd); | 43 | extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, |
44 | extern int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, | 44 | struct ethtool_cmd *ecmd); |
45 | bool ok); | 45 | extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, |
46 | struct ethtool_cmd *ecmd, bool ok); | ||
46 | 47 | ||
47 | /* Global */ | 48 | /* Global */ |
48 | extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); | 49 | extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); |
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index dba0d64d50cd..0a598084c513 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c | |||
@@ -665,6 +665,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, | |||
665 | { | 665 | { |
666 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; | 666 | enum efx_loopback_mode loopback_mode = efx->loopback_mode; |
667 | int phy_mode = efx->phy_mode; | 667 | int phy_mode = efx->phy_mode; |
668 | enum reset_type reset_method = RESET_TYPE_INVISIBLE; | ||
668 | struct ethtool_cmd ecmd; | 669 | struct ethtool_cmd ecmd; |
669 | struct efx_channel *channel; | 670 | struct efx_channel *channel; |
670 | int rc_test = 0, rc_reset = 0, rc; | 671 | 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 | mutex_unlock(&efx->mac_lock); | 719 | mutex_unlock(&efx->mac_lock); |
719 | 720 | ||
720 | /* free up all consumers of SRAM (including all the queues) */ | 721 | /* free up all consumers of SRAM (including all the queues) */ |
721 | efx_reset_down(efx, &ecmd); | 722 | efx_reset_down(efx, reset_method, &ecmd); |
722 | 723 | ||
723 | rc = efx_test_chip(efx, tests); | 724 | rc = efx_test_chip(efx, tests); |
724 | if (rc && !rc_test) | 725 | if (rc && !rc_test) |
725 | rc_test = rc; | 726 | rc_test = rc; |
726 | 727 | ||
727 | /* reset the chip to recover from the register test */ | 728 | /* reset the chip to recover from the register test */ |
728 | rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL); | 729 | rc_reset = falcon_reset_hw(efx, reset_method); |
729 | 730 | ||
730 | /* Ensure that the phy is powered and out of loopback | 731 | /* Ensure that the phy is powered and out of loopback |
731 | * for the bist and loopback tests */ | 732 | * for the bist and loopback tests */ |
732 | efx->phy_mode &= ~PHY_MODE_LOW_POWER; | 733 | efx->phy_mode &= ~PHY_MODE_LOW_POWER; |
733 | efx->loopback_mode = LOOPBACK_NONE; | 734 | efx->loopback_mode = LOOPBACK_NONE; |
734 | 735 | ||
735 | rc = efx_reset_up(efx, &ecmd, rc_reset == 0); | 736 | rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); |
736 | if (rc && !rc_reset) | 737 | if (rc && !rc_reset) |
737 | rc_reset = rc; | 738 | rc_reset = rc; |
738 | 739 | ||
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index bc2833f9cbe4..c9584619322a 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -337,6 +337,7 @@ static int tenxpress_phy_init(struct efx_nic *efx) | |||
337 | rc = tenxpress_init(efx); | 337 | rc = tenxpress_init(efx); |
338 | if (rc < 0) | 338 | if (rc < 0) |
339 | goto fail; | 339 | goto fail; |
340 | mdio_clause45_set_pause(efx); | ||
340 | 341 | ||
341 | if (efx->phy_type == PHY_TYPE_SFT9001B) { | 342 | if (efx->phy_type == PHY_TYPE_SFT9001B) { |
342 | rc = device_create_file(&efx->pci_dev->dev, | 343 | rc = device_create_file(&efx->pci_dev->dev, |