diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/alx/main.c')
| -rw-r--r-- | drivers/net/ethernet/atheros/alx/main.c | 131 |
1 files changed, 85 insertions, 46 deletions
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index b9b4edb913c1..ad6d6abd885f 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> + * Copyright (c) 2013, 2021 Johannes Berg <johannes@sipsolutions.net> * * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the @@ -39,7 +39,6 @@ #include <linux/ipv6.h> #include <linux/if_vlan.h> #include <linux/mdio.h> -#include <linux/aer.h> #include <linux/bitops.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -607,7 +606,7 @@ static int alx_set_mac_address(struct net_device *netdev, void *data) if (netdev->addr_assign_type & NET_ADDR_RANDOM) netdev->addr_assign_type ^= NET_ADDR_RANDOM; - memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + eth_hw_addr_set(netdev, addr->sa_data); memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len); alx_set_macaddr(hw, hw->mac_addr); @@ -752,7 +751,7 @@ static int alx_alloc_napis(struct alx_priv *alx) goto err_out; np->alx = alx; - netif_napi_add(alx->dev, &np->napi, alx_poll, 64); + netif_napi_add(alx->dev, &np->napi, alx_poll); alx->qnapi[i] = np; } @@ -902,7 +901,7 @@ static int alx_init_intr(struct alx_priv *alx) int ret; ret = pci_alloc_irq_vectors(alx->hw.pdev, 1, 1, - PCI_IRQ_MSI | PCI_IRQ_LEGACY); + PCI_IRQ_MSI | PCI_IRQ_INTX); if (ret < 0) return ret; @@ -1091,8 +1090,9 @@ static int alx_init_sw(struct alx_priv *alx) ALX_MAC_CTRL_RXFC_EN | ALX_MAC_CTRL_TXFC_EN | 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT; + mutex_init(&alx->mtx); - return err; + return 0; } @@ -1122,6 +1122,8 @@ static void alx_halt(struct alx_priv *alx) { struct alx_hw *hw = &alx->hw; + lockdep_assert_held(&alx->mtx); + alx_netif_stop(alx); hw->link_speed = SPEED_UNKNOWN; hw->duplex = DUPLEX_UNKNOWN; @@ -1147,6 +1149,8 @@ static void alx_configure(struct alx_priv *alx) static void alx_activate(struct alx_priv *alx) { + lockdep_assert_held(&alx->mtx); + /* hardware setting lost, restore it */ alx_reinit_rings(alx); alx_configure(alx); @@ -1161,7 +1165,7 @@ static void alx_activate(struct alx_priv *alx) static void alx_reinit(struct alx_priv *alx) { - ASSERT_RTNL(); + lockdep_assert_held(&alx->mtx); alx_halt(alx); alx_activate(alx); @@ -1172,12 +1176,15 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) struct alx_priv *alx = netdev_priv(netdev); int max_frame = ALX_MAX_FRAME_LEN(mtu); - netdev->mtu = mtu; + WRITE_ONCE(netdev->mtu, mtu); alx->hw.mtu = mtu; alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); netdev_update_features(netdev); - if (netif_running(netdev)) + if (netif_running(netdev)) { + mutex_lock(&alx->mtx); alx_reinit(alx); + mutex_unlock(&alx->mtx); + } return 0; } @@ -1249,8 +1256,14 @@ out_disable_adv_intr: static void __alx_stop(struct alx_priv *alx) { - alx_halt(alx); + lockdep_assert_held(&alx->mtx); + alx_free_irq(alx); + + cancel_work_sync(&alx->link_check_wk); + cancel_work_sync(&alx->reset_wk); + + alx_halt(alx); alx_free_rings(alx); alx_free_napis(alx); } @@ -1280,6 +1293,8 @@ static void alx_check_link(struct alx_priv *alx) int old_speed; int err; + lockdep_assert_held(&alx->mtx); + /* clear PHY internal interrupt status, otherwise the main * interrupt status will be asserted forever */ @@ -1334,12 +1349,24 @@ reset: static int alx_open(struct net_device *netdev) { - return __alx_open(netdev_priv(netdev), false); + struct alx_priv *alx = netdev_priv(netdev); + int ret; + + mutex_lock(&alx->mtx); + ret = __alx_open(alx, false); + mutex_unlock(&alx->mtx); + + return ret; } static int alx_stop(struct net_device *netdev) { - __alx_stop(netdev_priv(netdev)); + struct alx_priv *alx = netdev_priv(netdev); + + mutex_lock(&alx->mtx); + __alx_stop(alx); + mutex_unlock(&alx->mtx); + return 0; } @@ -1349,18 +1376,18 @@ static void alx_link_check(struct work_struct *work) alx = container_of(work, struct alx_priv, link_check_wk); - rtnl_lock(); + mutex_lock(&alx->mtx); alx_check_link(alx); - rtnl_unlock(); + mutex_unlock(&alx->mtx); } static void alx_reset(struct work_struct *work) { struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk); - rtnl_lock(); + mutex_lock(&alx->mtx); alx_reinit(alx); - rtnl_unlock(); + mutex_unlock(&alx->mtx); } static int alx_tpd_req(struct sk_buff *skb) @@ -1676,7 +1703,7 @@ static const struct net_device_ops alx_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = alx_set_mac_address, .ndo_change_mtu = alx_change_mtu, - .ndo_do_ioctl = alx_ioctl, + .ndo_eth_ioctl = alx_ioctl, .ndo_tx_timeout = alx_tx_timeout, .ndo_fix_features = alx_fix_features, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1717,7 +1744,6 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_pci_disable; } - pci_enable_pcie_error_reporting(pdev); pci_set_master(pdev); if (!pdev->pm_cap) { @@ -1767,6 +1793,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_unmap; } + mutex_lock(&alx->mtx); + alx_reset_pcie(hw); phy_configured = alx_phy_configured(hw); @@ -1777,7 +1805,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = alx_reset_mac(hw); if (err) { dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err); - goto out_unmap; + goto out_unlock; } /* setup link to put it in a known good starting state */ @@ -1787,7 +1815,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&pdev->dev, "failed to configure PHY speed/duplex (err=%d)\n", err); - goto out_unmap; + goto out_unlock; } } @@ -1805,7 +1833,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN); - memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN); + eth_hw_addr_set(netdev, hw->mac_addr); memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN); hw->mdio.prtad = 0; @@ -1820,9 +1848,11 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!alx_get_phy_info(hw)) { dev_err(&pdev->dev, "failed to identify PHY\n"); err = -EIO; - goto out_unmap; + goto out_unlock; } + mutex_unlock(&alx->mtx); + INIT_WORK(&alx->link_check_wk, alx_link_check); INIT_WORK(&alx->reset_wk, alx_reset); netif_carrier_off(netdev); @@ -1839,6 +1869,8 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; +out_unlock: + mutex_unlock(&alx->mtx); out_unmap: iounmap(hw->hw_addr); out_free_netdev: @@ -1855,9 +1887,6 @@ static void alx_remove(struct pci_dev *pdev) struct alx_priv *alx = pci_get_drvdata(pdev); struct alx_hw *hw = &alx->hw; - cancel_work_sync(&alx->link_check_wk); - cancel_work_sync(&alx->reset_wk); - /* restore permanent mac address */ alx_set_macaddr(hw, hw->perm_addr); @@ -1865,21 +1894,28 @@ static void alx_remove(struct pci_dev *pdev) iounmap(hw->hw_addr); pci_release_mem_regions(pdev); - pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); + mutex_destroy(&alx->mtx); + free_netdev(alx->dev); } -#ifdef CONFIG_PM_SLEEP static int alx_suspend(struct device *dev) { struct alx_priv *alx = dev_get_drvdata(dev); if (!netif_running(alx->dev)) return 0; + + rtnl_lock(); netif_device_detach(alx->dev); + + mutex_lock(&alx->mtx); __alx_stop(alx); + mutex_unlock(&alx->mtx); + rtnl_unlock(); + return 0; } @@ -1889,25 +1925,28 @@ static int alx_resume(struct device *dev) struct alx_hw *hw = &alx->hw; int err; + rtnl_lock(); + mutex_lock(&alx->mtx); alx_reset_phy(hw); - if (!netif_running(alx->dev)) - return 0; - netif_device_attach(alx->dev); + if (!netif_running(alx->dev)) { + err = 0; + goto unlock; + } - rtnl_lock(); err = __alx_open(alx, true); - rtnl_unlock(); + if (err) + goto unlock; + netif_device_attach(alx->dev); + +unlock: + mutex_unlock(&alx->mtx); + rtnl_unlock(); return err; } -static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); -#define ALX_PM_OPS (&alx_pm_ops) -#else -#define ALX_PM_OPS NULL -#endif - +static DEFINE_SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume); static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) @@ -1918,7 +1957,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, dev_info(&pdev->dev, "pci error detected\n"); - rtnl_lock(); + mutex_lock(&alx->mtx); if (netif_running(netdev)) { netif_device_detach(netdev); @@ -1930,7 +1969,7 @@ static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev, else pci_disable_device(pdev); - rtnl_unlock(); + mutex_unlock(&alx->mtx); return rc; } @@ -1943,7 +1982,7 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) dev_info(&pdev->dev, "pci error slot reset\n"); - rtnl_lock(); + mutex_lock(&alx->mtx); if (pci_enable_device(pdev)) { dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n"); @@ -1956,7 +1995,7 @@ static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev) if (!alx_reset_mac(hw)) rc = PCI_ERS_RESULT_RECOVERED; out: - rtnl_unlock(); + mutex_unlock(&alx->mtx); return rc; } @@ -1968,14 +2007,14 @@ static void alx_pci_error_resume(struct pci_dev *pdev) dev_info(&pdev->dev, "pci error resume\n"); - rtnl_lock(); + mutex_lock(&alx->mtx); if (netif_running(netdev)) { alx_activate(alx); netif_device_attach(netdev); } - rtnl_unlock(); + mutex_unlock(&alx->mtx); } static const struct pci_error_handlers alx_err_handlers = { @@ -2006,13 +2045,13 @@ static struct pci_driver alx_driver = { .probe = alx_probe, .remove = alx_remove, .err_handler = &alx_err_handlers, - .driver.pm = ALX_PM_OPS, + .driver.pm = pm_sleep_ptr(&alx_pm_ops), }; module_pci_driver(alx_driver); MODULE_DEVICE_TABLE(pci, alx_pci_tbl); MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); -MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>"); +MODULE_AUTHOR("Qualcomm Corporation"); MODULE_DESCRIPTION( "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver"); MODULE_LICENSE("GPL"); |
