diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/alx')
-rw-r--r-- | drivers/net/ethernet/atheros/alx/alx.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/atheros/alx/ethtool.c | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/atheros/alx/main.c | 120 |
3 files changed, 101 insertions, 42 deletions
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h index 9d0e74f6b089..693006c5a498 100644 --- a/drivers/net/ethernet/atheros/alx/alx.h +++ b/drivers/net/ethernet/atheros/alx/alx.h @@ -137,6 +137,8 @@ struct alx_priv { /* protects hw.stats */ spinlock_t stats_lock; + + struct mutex mtx; }; extern const struct ethtool_ops alx_ethtool_ops; diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c index 2f4eabf652e8..b716adacd815 100644 --- a/drivers/net/ethernet/atheros/alx/ethtool.c +++ b/drivers/net/ethernet/atheros/alx/ethtool.c @@ -163,8 +163,10 @@ static int alx_get_link_ksettings(struct net_device *netdev, } } + mutex_lock(&alx->mtx); cmd->base.speed = hw->link_speed; cmd->base.duplex = hw->duplex; + mutex_unlock(&alx->mtx); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); @@ -181,8 +183,7 @@ static int alx_set_link_ksettings(struct net_device *netdev, struct alx_hw *hw = &alx->hw; u32 adv_cfg; u32 advertising; - - ASSERT_RTNL(); + int ret; ethtool_convert_link_mode_to_legacy_u32(&advertising, cmd->link_modes.advertising); @@ -200,7 +201,12 @@ static int alx_set_link_ksettings(struct net_device *netdev, } hw->adv_cfg = adv_cfg; - return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl); + + mutex_lock(&alx->mtx); + ret = alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl); + mutex_unlock(&alx->mtx); + + return ret; } static void alx_get_pauseparam(struct net_device *netdev, @@ -209,10 +215,12 @@ static void alx_get_pauseparam(struct net_device *netdev, struct alx_priv *alx = netdev_priv(netdev); struct alx_hw *hw = &alx->hw; + mutex_lock(&alx->mtx); pause->autoneg = !!(hw->flowctrl & ALX_FC_ANEG && hw->adv_cfg & ADVERTISED_Autoneg); pause->tx_pause = !!(hw->flowctrl & ALX_FC_TX); pause->rx_pause = !!(hw->flowctrl & ALX_FC_RX); + mutex_unlock(&alx->mtx); } @@ -232,7 +240,7 @@ static int alx_set_pauseparam(struct net_device *netdev, if (pause->autoneg) fc |= ALX_FC_ANEG; - ASSERT_RTNL(); + mutex_lock(&alx->mtx); /* restart auto-neg for auto-mode */ if (hw->adv_cfg & ADVERTISED_Autoneg) { @@ -245,8 +253,10 @@ static int alx_set_pauseparam(struct net_device *netdev, if (reconfig_phy) { err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc); - if (err) + if (err) { + mutex_unlock(&alx->mtx); return err; + } } /* flow control on mac */ @@ -254,6 +264,7 @@ static int alx_set_pauseparam(struct net_device *netdev, alx_cfg_mac_flowcontrol(hw, fc); hw->flowctrl = fc; + mutex_unlock(&alx->mtx); return 0; } diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 1dcbc486eca9..d30d11872719 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 @@ -607,7 +607,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 +752,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; } @@ -1091,8 +1091,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 +1123,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 +1150,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 +1166,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); @@ -1176,8 +1181,11 @@ static int alx_change_mtu(struct net_device *netdev, int 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 +1257,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 +1294,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 +1350,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 +1377,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) @@ -1416,10 +1444,7 @@ static int alx_tso(struct sk_buff *skb, struct alx_txd *first) 0, IPPROTO_TCP, 0); first->word1 |= 1 << TPD_IPV4_SHIFT; } else if (skb_is_gso_v6(skb)) { - ipv6_hdr(skb)->payload_len = 0; - tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); + tcp_v6_gso_csum_prep(skb); /* LSOv2: the first TPD only provides the packet length */ first->adrl.l.pkt_len = skb->len; first->word1 |= 1 << TPD_LSO_V2_SHIFT; @@ -1679,7 +1704,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 @@ -1770,6 +1795,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); @@ -1780,7 +1807,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 */ @@ -1790,7 +1817,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; } } @@ -1808,7 +1835,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; @@ -1823,9 +1850,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); @@ -1842,12 +1871,15 @@ 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: free_netdev(netdev); out_pci_release: pci_release_mem_regions(pdev); + pci_disable_pcie_error_reporting(pdev); out_pci_disable: pci_disable_device(pdev); return err; @@ -1858,9 +1890,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); @@ -1871,6 +1900,8 @@ static void alx_remove(struct pci_dev *pdev) pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); + mutex_destroy(&alx->mtx); + free_netdev(alx->dev); } @@ -1881,8 +1912,15 @@ static int alx_suspend(struct device *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; } @@ -1892,16 +1930,24 @@ 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; } @@ -1921,7 +1967,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); @@ -1933,7 +1979,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; } @@ -1946,7 +1992,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"); @@ -1959,7 +2005,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; } @@ -1971,14 +2017,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 = { @@ -2015,7 +2061,7 @@ static struct pci_driver alx_driver = { 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"); |