Commit eb9f6744cbfa97674c13263802259b5aa0034594

Authored by Ben Hutchings
Committed by David S. Miller
1 parent 89c758fa47

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>

Showing 5 changed files with 84 additions and 50 deletions Side-by-side Diff

drivers/net/sfc/efx.c
... ... @@ -1754,59 +1754,50 @@
1754 1754 rc = efx->type->init(efx);
1755 1755 if (rc) {
1756 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 1763 if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) {
1761   - if (ok) {
1762   - rc = efx->phy_op->init(efx);
1763   - if (rc)
1764   - ok = false;
1765   - if (efx->phy_op->reconfigure(efx))
1766   - EFX_ERR(efx, "could not restore PHY settings\n");
1767   - }
1768   - if (!ok)
1769   - efx->port_initialized = false;
  1764 + rc = efx->phy_op->init(efx);
  1765 + if (rc)
  1766 + goto fail;
  1767 + if (efx->phy_op->reconfigure(efx))
  1768 + EFX_ERR(efx, "could not restore PHY settings\n");
1770 1769 }
1771 1770  
1772   - if (ok) {
1773   - efx->mac_op->reconfigure(efx);
  1771 + efx->mac_op->reconfigure(efx);
1774 1772  
1775   - efx_init_channels(efx);
1776   - }
  1773 + efx_init_channels(efx);
1777 1774  
1778 1775 mutex_unlock(&efx->spi_lock);
1779 1776 mutex_unlock(&efx->mac_lock);
1780 1777  
1781   - if (ok)
1782   - efx_start_all(efx);
  1778 + efx_start_all(efx);
  1779 +
  1780 + return 0;
  1781 +
  1782 +fail:
  1783 + efx->port_initialized = false;
  1784 +
  1785 + mutex_unlock(&efx->spi_lock);
  1786 + mutex_unlock(&efx->mac_lock);
  1787 +
1783 1788 return rc;
1784 1789 }
1785 1790  
1786   -/* Reset the NIC as transparently as possible. Do not reset the PHY
1787   - * Note that the reset may fail, in which case the card will be left
1788   - * in a most-probably-unusable state.
  1791 +/* Reset the NIC using the specified method. Note that the reset may
  1792 + * fail, in which case the card will be left in an unusable state.
1789 1793 *
1790   - * This function will sleep. You cannot reset from within an atomic
1791   - * state; use efx_schedule_reset() instead.
1792   - *
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 = 0;
  1798 + int rc, rc2;
  1799 + bool disabled;
1799 1800  
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   -
1810 1801 EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
1811 1802  
1812 1803 efx_reset_down(efx, method);
... ... @@ -1814,7 +1805,7 @@
1814 1805 rc = efx->type->reset(efx, method);
1815 1806 if (rc) {
1816 1807 EFX_ERR(efx, "failed to reset hardware\n");
1817   - goto out_disable;
  1808 + goto out;
1818 1809 }
1819 1810  
1820 1811 /* Allow resets to be rescheduled. */
1821 1812  
1822 1813  
1823 1814  
1824 1815  
... ... @@ -1826,25 +1817,22 @@
1826 1817 * can respond to requests. */
1827 1818 pci_set_master(efx->pci_dev);
1828 1819  
  1820 +out:
1829 1821 /* Leave device stopped if necessary */
1830   - if (method == RESET_TYPE_DISABLE) {
1831   - efx_reset_up(efx, method, false);
1832   - rc = -EIO;
1833   - } else {
1834   - rc = efx_reset_up(efx, method, true);
  1822 + disabled = rc || method == RESET_TYPE_DISABLE;
  1823 + rc2 = efx_reset_up(efx, method, !disabled);
  1824 + if (rc2) {
  1825 + disabled = true;
  1826 + if (!rc)
  1827 + rc = rc2;
1835 1828 }
1836 1829  
1837   -out_disable:
1838   - if (rc) {
  1830 + if (disabled) {
1839 1831 EFX_ERR(efx, "has been disabled\n");
1840 1832 efx->state = STATE_DISABLED;
1841   - dev_close(efx->net_dev);
1842 1833 } else {
1843 1834 EFX_LOG(efx, "reset complete\n");
1844 1835 }
1845   -
1846   -out_unlock:
1847   - rtnl_unlock();
1848 1836 return rc;
1849 1837 }
1850 1838  
1851 1839  
... ... @@ -1853,9 +1841,19 @@
1853 1841 */
1854 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 1859 void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
drivers/net/sfc/efx.h
... ... @@ -71,6 +71,7 @@
71 71 extern const struct ethtool_ops efx_ethtool_ops;
72 72  
73 73 /* Reset handling */
  74 +extern int efx_reset(struct efx_nic *efx, enum reset_type method);
74 75 extern void efx_reset_down(struct efx_nic *efx, enum reset_type method);
75 76 extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok);
76 77  
drivers/net/sfc/ethtool.c
... ... @@ -754,6 +754,35 @@
754 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 786 const struct ethtool_ops efx_ethtool_ops = {
758 787 .get_settings = efx_ethtool_get_settings,
759 788 .set_settings = efx_ethtool_set_settings,
... ... @@ -784,5 +813,6 @@
784 813 .get_ethtool_stats = efx_ethtool_get_stats,
785 814 .get_wol = efx_ethtool_get_wol,
786 815 .set_wol = efx_ethtool_set_wol,
  816 + .reset = efx_ethtool_reset,
787 817 };
drivers/net/sfc/falcon.c
... ... @@ -3305,6 +3305,7 @@
3305 3305 .phys_addr_channels = 4,
3306 3306 .tx_dc_base = 0x130000,
3307 3307 .rx_dc_base = 0x100000,
  3308 + .reset_world_flags = ETH_RESET_IRQ,
3308 3309 };
3309 3310  
3310 3311 struct efx_nic_type falcon_b0_nic_type = {
... ... @@ -3348,5 +3349,6 @@
3348 3349 * channels */
3349 3350 .tx_dc_base = 0x130000,
3350 3351 .rx_dc_base = 0x100000,
  3352 + .reset_world_flags = ETH_RESET_IRQ,
3351 3353 };
drivers/net/sfc/net_driver.h
... ... @@ -880,6 +880,8 @@
880 880 * descriptors
881 881 * @tx_dc_base: Base address in SRAM of TX queue descriptor caches
882 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 886 struct efx_nic_type {
885 887 int (*probe)(struct efx_nic *efx);
... ... @@ -915,6 +917,7 @@
915 917 unsigned int phys_addr_channels;
916 918 unsigned int tx_dc_base;
917 919 unsigned int rx_dc_base;
  920 + u32 reset_world_flags;
918 921 };
919 922  
920 923 /**************************************************************************