diff options
author | Vincenzo Maffione <v.maffione@gmail.com> | 2017-09-16 18:00:00 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-11-21 09:27:41 +0100 |
commit | 9b574c3d21460550175a8036c0d15a964ae79774 (patch) | |
tree | 74f3023d0fc71e3877aec8522ea82cac5877e618 | |
parent | 5637fad6b1462945ccc8bd9734146c93422590fd (diff) | |
download | linux-stable-9b574c3d21460550175a8036c0d15a964ae79774.tar.gz linux-stable-9b574c3d21460550175a8036c0d15a964ae79774.tar.bz2 linux-stable-9b574c3d21460550175a8036c0d15a964ae79774.zip |
e1000: fix race condition between e1000_down() and e1000_watchdog
[ 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.maffione@gmail.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | drivers/net/ethernet/intel/e1000/e1000_main.c | 11 |
1 files 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); |