diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-28 22:43:15 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-29 19:46:29 -0500 |
commit | eb9f6744cbfa97674c13263802259b5aa0034594 (patch) | |
tree | ae57310bc8fd9b7b21e6d6ca63853bcae002a5c2 /drivers | |
parent | 89c758fa47b54d8ce10d2b39ed09de6da0ba4324 (diff) |
sfc: Implement ethtool reset operation
Refactor efx_reset_down() and efx_reset_up() accordingly.
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 | 98 | ||||
-rw-r--r-- | drivers/net/sfc/efx.h | 1 | ||||
-rw-r--r-- | drivers/net/sfc/ethtool.c | 30 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 2 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 3 |
5 files changed, 84 insertions, 50 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b016719d8f67..4b7168fc546a 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c | |||
@@ -1754,58 +1754,49 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) | |||
1754 | rc = efx->type->init(efx); | 1754 | rc = efx->type->init(efx); |
1755 | if (rc) { | 1755 | if (rc) { |
1756 | EFX_ERR(efx, "failed to initialise NIC\n"); | 1756 | EFX_ERR(efx, "failed to initialise NIC\n"); |
1757 | ok = false; | 1757 | goto fail; |
1758 | } | 1758 | } |
1759 | 1759 | ||
1760 | if (!ok) | ||
1761 | goto fail; | ||
1762 | |||
1760 | if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { | 1763 | if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { |
1761 | if (ok) { | 1764 | rc = efx->phy_op->init(efx); |
1762 | rc = efx->phy_op->init(efx); | 1765 | if (rc) |
1763 | if (rc) | 1766 | goto fail; |
1764 | ok = false; | 1767 | if (efx->phy_op->reconfigure(efx)) |
1765 | if (efx->phy_op->reconfigure(efx)) | 1768 | EFX_ERR(efx, "could not restore PHY settings\n"); |
1766 | EFX_ERR(efx, "could not restore PHY settings\n"); | ||
1767 | } | ||
1768 | if (!ok) | ||
1769 | efx->port_initialized = false; | ||
1770 | } | 1769 | } |
1771 | 1770 | ||
1772 | if (ok) { | 1771 | efx->mac_op->reconfigure(efx); |
1773 | efx->mac_op->reconfigure(efx); | ||
1774 | 1772 | ||
1775 | efx_init_channels(efx); | 1773 | efx_init_channels(efx); |
1776 | } | 1774 | |
1775 | mutex_unlock(&efx->spi_lock); | ||
1776 | mutex_unlock(&efx->mac_lock); | ||
1777 | |||
1778 | efx_start_all(efx); | ||
1779 | |||
1780 | return 0; | ||
1781 | |||
1782 | fail: | ||
1783 | efx->port_initialized = false; | ||
1777 | 1784 | ||
1778 | mutex_unlock(&efx->spi_lock); | 1785 | mutex_unlock(&efx->spi_lock); |
1779 | mutex_unlock(&efx->mac_lock); | 1786 | mutex_unlock(&efx->mac_lock); |
1780 | 1787 | ||
1781 | if (ok) | ||
1782 | efx_start_all(efx); | ||
1783 | return rc; | 1788 | return rc; |
1784 | } | 1789 | } |
1785 | 1790 | ||
1786 | /* Reset the NIC as transparently as possible. Do not reset the PHY | 1791 | /* Reset the NIC using the specified method. Note that the reset may |
1787 | * Note that the reset may fail, in which case the card will be left | 1792 | * fail, in which case the card will be left in an unusable state. |
1788 | * in a most-probably-unusable state. | ||
1789 | * | ||
1790 | * This function will sleep. You cannot reset from within an atomic | ||
1791 | * state; use efx_schedule_reset() instead. | ||
1792 | * | 1793 | * |
1793 | * Grabs the rtnl_lock. | 1794 | * Caller must hold the rtnl_lock. |
1794 | */ | 1795 | */ |
1795 | static int efx_reset(struct efx_nic *efx) | 1796 | int efx_reset(struct efx_nic *efx, enum reset_type method) |
1796 | { | 1797 | { |
1797 | enum reset_type method = efx->reset_pending; | 1798 | int rc, rc2; |
1798 | int rc = 0; | 1799 | bool disabled; |
1799 | |||
1800 | /* Serialise with kernel interfaces */ | ||
1801 | rtnl_lock(); | ||
1802 | |||
1803 | /* If we're not RUNNING then don't reset. Leave the reset_pending | ||
1804 | * flag set so that efx_pci_probe_main will be retried */ | ||
1805 | if (efx->state != STATE_RUNNING) { | ||
1806 | EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); | ||
1807 | goto out_unlock; | ||
1808 | } | ||
1809 | 1800 | ||
1810 | EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); | 1801 | EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); |
1811 | 1802 | ||
@@ -1814,7 +1805,7 @@ static int efx_reset(struct efx_nic *efx) | |||
1814 | rc = efx->type->reset(efx, method); | 1805 | rc = efx->type->reset(efx, method); |
1815 | if (rc) { | 1806 | if (rc) { |
1816 | EFX_ERR(efx, "failed to reset hardware\n"); | 1807 | EFX_ERR(efx, "failed to reset hardware\n"); |
1817 | goto out_disable; | 1808 | goto out; |
1818 | } | 1809 | } |
1819 | 1810 | ||
1820 | /* Allow resets to be rescheduled. */ | 1811 | /* Allow resets to be rescheduled. */ |
@@ -1826,25 +1817,22 @@ static int efx_reset(struct efx_nic *efx) | |||
1826 | * can respond to requests. */ | 1817 | * can respond to requests. */ |
1827 | pci_set_master(efx->pci_dev); | 1818 | pci_set_master(efx->pci_dev); |
1828 | 1819 | ||
1820 | out: | ||
1829 | /* Leave device stopped if necessary */ | 1821 | /* Leave device stopped if necessary */ |
1830 | if (method == RESET_TYPE_DISABLE) { | 1822 | disabled = rc || method == RESET_TYPE_DISABLE; |
1831 | efx_reset_up(efx, method, false); | 1823 | rc2 = efx_reset_up(efx, method, !disabled); |
1832 | rc = -EIO; | 1824 | if (rc2) { |
1833 | } else { | 1825 | disabled = true; |
1834 | rc = efx_reset_up(efx, method, true); | 1826 | if (!rc) |
1827 | rc = rc2; | ||
1835 | } | 1828 | } |
1836 | 1829 | ||
1837 | out_disable: | 1830 | if (disabled) { |
1838 | if (rc) { | ||
1839 | EFX_ERR(efx, "has been disabled\n"); | 1831 | EFX_ERR(efx, "has been disabled\n"); |
1840 | efx->state = STATE_DISABLED; | 1832 | efx->state = STATE_DISABLED; |
1841 | dev_close(efx->net_dev); | ||
1842 | } else { | 1833 | } else { |
1843 | EFX_LOG(efx, "reset complete\n"); | 1834 | EFX_LOG(efx, "reset complete\n"); |
1844 | } | 1835 | } |
1845 | |||
1846 | out_unlock: | ||
1847 | rtnl_unlock(); | ||
1848 | return rc; | 1836 | return rc; |
1849 | } | 1837 | } |
1850 | 1838 | ||
@@ -1853,9 +1841,19 @@ out_unlock: | |||
1853 | */ | 1841 | */ |
1854 | static void efx_reset_work(struct work_struct *data) | 1842 | static void efx_reset_work(struct work_struct *data) |
1855 | { | 1843 | { |
1856 | struct efx_nic *nic = container_of(data, struct efx_nic, reset_work); | 1844 | struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); |
1857 | 1845 | ||
1858 | efx_reset(nic); | 1846 | /* If we're not RUNNING then don't reset. Leave the reset_pending |
1847 | * flag set so that efx_pci_probe_main will be retried */ | ||
1848 | if (efx->state != STATE_RUNNING) { | ||
1849 | EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); | ||
1850 | return; | ||
1851 | } | ||
1852 | |||
1853 | rtnl_lock(); | ||
1854 | if (efx_reset(efx, efx->reset_pending)) | ||
1855 | dev_close(efx->net_dev); | ||
1856 | rtnl_unlock(); | ||
1859 | } | 1857 | } |
1860 | 1858 | ||
1861 | void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) | 1859 | void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) |
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index c78500321586..fa40c7b66d7b 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h | |||
@@ -71,6 +71,7 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev, | |||
71 | extern const struct ethtool_ops efx_ethtool_ops; | 71 | extern const struct ethtool_ops efx_ethtool_ops; |
72 | 72 | ||
73 | /* Reset handling */ | 73 | /* Reset handling */ |
74 | extern int efx_reset(struct efx_nic *efx, enum reset_type method); | ||
74 | extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); | 75 | extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); |
75 | extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); | 76 | extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); |
76 | 77 | ||
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index b4c6ea1b9c07..29aa83c2a0d0 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -754,6 +754,35 @@ static int efx_ethtool_set_wol(struct net_device *net_dev, | |||
754 | return efx->type->set_wol(efx, wol->wolopts); | 754 | return efx->type->set_wol(efx, wol->wolopts); |
755 | } | 755 | } |
756 | 756 | ||
757 | extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) | ||
758 | { | ||
759 | struct efx_nic *efx = netdev_priv(net_dev); | ||
760 | enum reset_type method; | ||
761 | enum { | ||
762 | ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | | ||
763 | ETH_RESET_OFFLOAD | ETH_RESET_MAC) | ||
764 | }; | ||
765 | |||
766 | /* Check for minimal reset flags */ | ||
767 | if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE) | ||
768 | return -EINVAL; | ||
769 | *flags ^= ETH_RESET_EFX_INVISIBLE; | ||
770 | method = RESET_TYPE_INVISIBLE; | ||
771 | |||
772 | if (*flags & ETH_RESET_PHY) { | ||
773 | *flags ^= ETH_RESET_PHY; | ||
774 | method = RESET_TYPE_ALL; | ||
775 | } | ||
776 | |||
777 | if ((*flags & efx->type->reset_world_flags) == | ||
778 | efx->type->reset_world_flags) { | ||
779 | *flags ^= efx->type->reset_world_flags; | ||
780 | method = RESET_TYPE_WORLD; | ||
781 | } | ||
782 | |||
783 | return efx_reset(efx, method); | ||
784 | } | ||
785 | |||
757 | const struct ethtool_ops efx_ethtool_ops = { | 786 | const struct ethtool_ops efx_ethtool_ops = { |
758 | .get_settings = efx_ethtool_get_settings, | 787 | .get_settings = efx_ethtool_get_settings, |
759 | .set_settings = efx_ethtool_set_settings, | 788 | .set_settings = efx_ethtool_set_settings, |
@@ -784,4 +813,5 @@ const struct ethtool_ops efx_ethtool_ops = { | |||
784 | .get_ethtool_stats = efx_ethtool_get_stats, | 813 | .get_ethtool_stats = efx_ethtool_get_stats, |
785 | .get_wol = efx_ethtool_get_wol, | 814 | .get_wol = efx_ethtool_get_wol, |
786 | .set_wol = efx_ethtool_set_wol, | 815 | .set_wol = efx_ethtool_set_wol, |
816 | .reset = efx_ethtool_reset, | ||
787 | }; | 817 | }; |
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 8f2c58305538..6a96c699e15b 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -3305,6 +3305,7 @@ struct efx_nic_type falcon_a1_nic_type = { | |||
3305 | .phys_addr_channels = 4, | 3305 | .phys_addr_channels = 4, |
3306 | .tx_dc_base = 0x130000, | 3306 | .tx_dc_base = 0x130000, |
3307 | .rx_dc_base = 0x100000, | 3307 | .rx_dc_base = 0x100000, |
3308 | .reset_world_flags = ETH_RESET_IRQ, | ||
3308 | }; | 3309 | }; |
3309 | 3310 | ||
3310 | struct efx_nic_type falcon_b0_nic_type = { | 3311 | struct efx_nic_type falcon_b0_nic_type = { |
@@ -3348,5 +3349,6 @@ struct efx_nic_type falcon_b0_nic_type = { | |||
3348 | * channels */ | 3349 | * channels */ |
3349 | .tx_dc_base = 0x130000, | 3350 | .tx_dc_base = 0x130000, |
3350 | .rx_dc_base = 0x100000, | 3351 | .rx_dc_base = 0x100000, |
3352 | .reset_world_flags = ETH_RESET_IRQ, | ||
3351 | }; | 3353 | }; |
3352 | 3354 | ||
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index a9fde82aeeae..58bf761d7317 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -880,6 +880,8 @@ static inline const char *efx_dev_name(struct efx_nic *efx) | |||
880 | * descriptors | 880 | * descriptors |
881 | * @tx_dc_base: Base address in SRAM of TX queue descriptor caches | 881 | * @tx_dc_base: Base address in SRAM of TX queue descriptor caches |
882 | * @rx_dc_base: Base address in SRAM of RX queue descriptor caches | 882 | * @rx_dc_base: Base address in SRAM of RX queue descriptor caches |
883 | * @reset_world_flags: Flags for additional components covered by | ||
884 | * reset method RESET_TYPE_WORLD | ||
883 | */ | 885 | */ |
884 | struct efx_nic_type { | 886 | struct efx_nic_type { |
885 | int (*probe)(struct efx_nic *efx); | 887 | int (*probe)(struct efx_nic *efx); |
@@ -915,6 +917,7 @@ struct efx_nic_type { | |||
915 | unsigned int phys_addr_channels; | 917 | unsigned int phys_addr_channels; |
916 | unsigned int tx_dc_base; | 918 | unsigned int tx_dc_base; |
917 | unsigned int rx_dc_base; | 919 | unsigned int rx_dc_base; |
920 | u32 reset_world_flags; | ||
918 | }; | 921 | }; |
919 | 922 | ||
920 | /************************************************************************** | 923 | /************************************************************************** |