4.4-stable review patch.  If anyone has any objections, please let me know.

------------------

[ Upstream commit 44c445c3d1b4eacff23141fa7977c3b2ec3a45c9 ]

This patch fixes a race condition that can result into the interface being
up and carrier on, but with transmits disabled in the hardware.
The bug may show up by repeatedly IFF_DOWN+IFF_UP the interface, which
allows e1000_watchdog() interleave with e1000_down().

    CPU x                           CPU y
    --------------------------------------------------------------------
    e1000_down():
        netif_carrier_off()
                                    e1000_watchdog():
                                        if (carrier == off) {
                                            netif_carrier_on();
                                            enable_hw_transmit();
                                        }
        disable_hw_transmit();
                                    e1000_watchdog():
                                        /* carrier on, do nothing */

Signed-off-by: Vincenzo Maffione <v.maffi...@gmail.com>
Tested-by: Aaron Brown <aaron.f.br...@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirs...@intel.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/net/ethernet/intel/e1000/e1000_main.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c 
b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 2a1d4a9d3c19..1f84f2fa459f 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -521,8 +521,6 @@ void e1000_down(struct e1000_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        u32 rctl, tctl;
 
-       netif_carrier_off(netdev);
-
        /* disable receives in the hardware */
        rctl = er32(RCTL);
        ew32(RCTL, rctl & ~E1000_RCTL_EN);
@@ -538,6 +536,15 @@ void e1000_down(struct e1000_adapter *adapter)
        E1000_WRITE_FLUSH();
        msleep(10);
 
+       /* Set the carrier off after transmits have been disabled in the
+        * hardware, to avoid race conditions with e1000_watchdog() (which
+        * may be running concurrently to us, checking for the carrier
+        * bit to decide whether it should enable transmits again). Such
+        * a race condition would result into transmission being disabled
+        * in the hardware until the next IFF_DOWN+IFF_UP cycle.
+        */
+       netif_carrier_off(netdev);
+
        napi_disable(&adapter->napi);
 
        e1000_irq_disable(adapter);
-- 
2.17.1



Reply via email to