aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-28 22:43:15 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-29 19:46:29 -0500
commiteb9f6744cbfa97674c13263802259b5aa0034594 (patch)
treeae57310bc8fd9b7b21e6d6ca63853bcae002a5c2 /drivers
parent89c758fa47b54d8ce10d2b39ed09de6da0ba4324 (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.c98
-rw-r--r--drivers/net/sfc/efx.h1
-rw-r--r--drivers/net/sfc/ethtool.c30
-rw-r--r--drivers/net/sfc/falcon.c2
-rw-r--r--drivers/net/sfc/net_driver.h3
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
1782fail:
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 */
1795static int efx_reset(struct efx_nic *efx) 1796int 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
1820out:
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
1837out_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
1846out_unlock:
1847 rtnl_unlock();
1848 return rc; 1836 return rc;
1849} 1837}
1850 1838
@@ -1853,9 +1841,19 @@ out_unlock:
1853 */ 1841 */
1854static void efx_reset_work(struct work_struct *data) 1842static 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
1861void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) 1859void 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,
71extern const struct ethtool_ops efx_ethtool_ops; 71extern const struct ethtool_ops efx_ethtool_ops;
72 72
73/* Reset handling */ 73/* Reset handling */
74extern int efx_reset(struct efx_nic *efx, enum reset_type method);
74extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); 75extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
75extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); 76extern 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
757extern 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
757const struct ethtool_ops efx_ethtool_ops = { 786const 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
3310struct efx_nic_type falcon_b0_nic_type = { 3311struct 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 */
884struct efx_nic_type { 886struct 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/**************************************************************************