aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-07-08 07:40:23 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-08 23:02:59 -0400
commit31a6de34f3daa9b1f412931befd9f82fd4a1b968 (patch)
tree160dd8c66b6f6b082da81252bfe5ac5d17156595
parent6af42d420bcfa0c837911bd5b518fd4a3cfa4fe4 (diff)
net: fec: quiesce packet processing before stopping device in fec_suspend()
fec_suspend() calls fec_stop() to stop the transmit ring while the transmit packet processing is still active. This can lead to the transmit queue being restarted by an intervening packet queued for transmission, or by the tx quirk timer expiring. Fix this by disabling NAPI first, which will ensure that the NAPI handlers are not running. Then, take the transmit lock before detaching the netif device. This ensures that there are no races with the transmit path - and also ensures that the watchdog won't fire. We can then safely stop the ethernet device itself, knowing that the rest of the driver is safely shut down. On resume, we bring the device back up in reverse order - we restart the device, reattach the device (under the tx lock), and then enable the NAPI handlers. We also need to adjust the close function to cope with this new sequence, so that it's possible to cleanly close down the driver after the hardware fails to resume (eg, due to the regulator_enable() or pinctrl calls in the resume path returning an error.) Acked-by: Fugang Duan <B38611@freescale.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 25a9f7fb30da..fc9f6f465e7a 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2211,10 +2211,11 @@ fec_enet_close(struct net_device *ndev)
2211 2211
2212 phy_stop(fep->phy_dev); 2212 phy_stop(fep->phy_dev);
2213 2213
2214 napi_disable(&fep->napi); 2214 if (netif_device_present(ndev)) {
2215 netif_tx_disable(ndev); 2215 napi_disable(&fep->napi);
2216 if (netif_device_present(ndev)) 2216 netif_tx_disable(ndev);
2217 fec_stop(ndev); 2217 fec_stop(ndev);
2218 }
2218 2219
2219 phy_disconnect(fep->phy_dev); 2220 phy_disconnect(fep->phy_dev);
2220 fep->phy_dev = NULL; 2221 fep->phy_dev = NULL;
@@ -2701,8 +2702,11 @@ fec_suspend(struct device *dev)
2701 rtnl_lock(); 2702 rtnl_lock();
2702 if (netif_running(ndev)) { 2703 if (netif_running(ndev)) {
2703 phy_stop(fep->phy_dev); 2704 phy_stop(fep->phy_dev);
2704 fec_stop(ndev); 2705 napi_disable(&fep->napi);
2706 netif_tx_lock_bh(ndev);
2705 netif_device_detach(ndev); 2707 netif_device_detach(ndev);
2708 netif_tx_unlock_bh(ndev);
2709 fec_stop(ndev);
2706 } 2710 }
2707 rtnl_unlock(); 2711 rtnl_unlock();
2708 2712
@@ -2735,12 +2739,10 @@ fec_resume(struct device *dev)
2735 2739
2736 rtnl_lock(); 2740 rtnl_lock();
2737 if (netif_running(ndev)) { 2741 if (netif_running(ndev)) {
2738 napi_disable(&fep->napi);
2739 netif_tx_lock_bh(ndev);
2740 fec_restart(ndev, fep->full_duplex); 2742 fec_restart(ndev, fep->full_duplex);
2743 netif_tx_lock_bh(ndev);
2741 netif_device_attach(ndev); 2744 netif_device_attach(ndev);
2742 netif_tx_unlock_bh(ndev); 2745 netif_tx_unlock_bh(ndev);
2743 netif_device_attach(ndev);
2744 napi_enable(&fep->napi); 2746 napi_enable(&fep->napi);
2745 phy_start(fep->phy_dev); 2747 phy_start(fep->phy_dev);
2746 } 2748 }