aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDoug Berger <opendmb@gmail.com>2018-11-01 18:55:37 -0400
committerDavid S. Miller <davem@davemloft.net>2018-11-03 03:03:39 -0400
commit09e805d2570a3a94f13dd9c9ad2bcab23da76e09 (patch)
treea1776791b3260d0e3e1c73708e58fd2bda2058ed /drivers/net
parentc7e86acfcee30794dc99a0759924bf7b9d43f1ca (diff)
net: bcmgenet: protect stop from timeout
A timing hazard exists when the network interface is stopped that allows a watchdog timeout to be processed by a separate core in parallel. This creates the potential for the timeout handler to wake the queues while the driver is shutting down, or access registers after their clocks have been removed. The more common case is that the watchdog timeout will produce a warning message which doesn't lead to a crash. The chances of this are greatly increased by the fact that bcmgenet_netif_stop stops the transmit queues which can easily precipitate a watchdog time- out because of stale trans_start data in the queues. This commit corrects the behavior by ensuring that the watchdog timeout is disabled before enterring bcmgenet_netif_stop. There are currently only two users of the bcmgenet_netif_stop function: close and suspend. The close case already handles the issue by exiting the RUNNING state before invoking the driver close service. The suspend case now performs the netif_device_detach to exit the PRESENT state before the call to bcmgenet_netif_stop rather than after it. These behaviors prevent any future scheduling of the driver timeout service during the window. The netif_tx_stop_all_queues function in bcmgenet_netif_stop is replaced with netif_tx_disable to ensure synchronization with any transmit or timeout threads that may already be executing on other cores. For symmetry, the netif_device_attach call upon resume is moved to after the call to bcmgenet_netif_start. Since it wakes the transmit queues it is not necessary to invoke netif_tx_start_all_queues from bcmgenet_netif_start so it is moved into the driver open service. Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file") Signed-off-by: Doug Berger <opendmb@gmail.com> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 20c1681bb1af..2d6f090bf644 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2855,7 +2855,6 @@ static void bcmgenet_netif_start(struct net_device *dev)
2855 2855
2856 umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true); 2856 umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
2857 2857
2858 netif_tx_start_all_queues(dev);
2859 bcmgenet_enable_tx_napi(priv); 2858 bcmgenet_enable_tx_napi(priv);
2860 2859
2861 /* Monitor link interrupts now */ 2860 /* Monitor link interrupts now */
@@ -2937,6 +2936,8 @@ static int bcmgenet_open(struct net_device *dev)
2937 2936
2938 bcmgenet_netif_start(dev); 2937 bcmgenet_netif_start(dev);
2939 2938
2939 netif_tx_start_all_queues(dev);
2940
2940 return 0; 2941 return 0;
2941 2942
2942err_irq1: 2943err_irq1:
@@ -2958,7 +2959,7 @@ static void bcmgenet_netif_stop(struct net_device *dev)
2958 struct bcmgenet_priv *priv = netdev_priv(dev); 2959 struct bcmgenet_priv *priv = netdev_priv(dev);
2959 2960
2960 bcmgenet_disable_tx_napi(priv); 2961 bcmgenet_disable_tx_napi(priv);
2961 netif_tx_stop_all_queues(dev); 2962 netif_tx_disable(dev);
2962 2963
2963 /* Disable MAC receive */ 2964 /* Disable MAC receive */
2964 umac_enable_set(priv, CMD_RX_EN, false); 2965 umac_enable_set(priv, CMD_RX_EN, false);
@@ -3620,13 +3621,13 @@ static int bcmgenet_suspend(struct device *d)
3620 if (!netif_running(dev)) 3621 if (!netif_running(dev))
3621 return 0; 3622 return 0;
3622 3623
3624 netif_device_detach(dev);
3625
3623 bcmgenet_netif_stop(dev); 3626 bcmgenet_netif_stop(dev);
3624 3627
3625 if (!device_may_wakeup(d)) 3628 if (!device_may_wakeup(d))
3626 phy_suspend(dev->phydev); 3629 phy_suspend(dev->phydev);
3627 3630
3628 netif_device_detach(dev);
3629
3630 /* Prepare the device for Wake-on-LAN and switch to the slow clock */ 3631 /* Prepare the device for Wake-on-LAN and switch to the slow clock */
3631 if (device_may_wakeup(d) && priv->wolopts) { 3632 if (device_may_wakeup(d) && priv->wolopts) {
3632 ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); 3633 ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC);
@@ -3700,8 +3701,6 @@ static int bcmgenet_resume(struct device *d)
3700 /* Always enable ring 16 - descriptor ring */ 3701 /* Always enable ring 16 - descriptor ring */
3701 bcmgenet_enable_dma(priv, dma_ctrl); 3702 bcmgenet_enable_dma(priv, dma_ctrl);
3702 3703
3703 netif_device_attach(dev);
3704
3705 if (!device_may_wakeup(d)) 3704 if (!device_may_wakeup(d))
3706 phy_resume(dev->phydev); 3705 phy_resume(dev->phydev);
3707 3706
@@ -3710,6 +3709,8 @@ static int bcmgenet_resume(struct device *d)
3710 3709
3711 bcmgenet_netif_start(dev); 3710 bcmgenet_netif_start(dev);
3712 3711
3712 netif_device_attach(dev);
3713
3713 return 0; 3714 return 0;
3714 3715
3715out_clk_disable: 3716out_clk_disable: