Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44c445c3 authored by Vincenzo Maffione's avatar Vincenzo Maffione Committed by Jeff Kirsher
Browse files

e1000: fix race condition between e1000_down() and e1000_watchdog



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: default avatarVincenzo Maffione <v.maffione@gmail.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent 78e0ea67
Loading
Loading
Loading
Loading
+9 −2
Original line number Original line Diff line number Diff line
@@ -520,8 +520,6 @@ void e1000_down(struct e1000_adapter *adapter)
	struct net_device *netdev = adapter->netdev;
	struct net_device *netdev = adapter->netdev;
	u32 rctl, tctl;
	u32 rctl, tctl;


	netif_carrier_off(netdev);

	/* disable receives in the hardware */
	/* disable receives in the hardware */
	rctl = er32(RCTL);
	rctl = er32(RCTL);
	ew32(RCTL, rctl & ~E1000_RCTL_EN);
	ew32(RCTL, rctl & ~E1000_RCTL_EN);
@@ -537,6 +535,15 @@ void e1000_down(struct e1000_adapter *adapter)
	E1000_WRITE_FLUSH();
	E1000_WRITE_FLUSH();
	msleep(10);
	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);
	napi_disable(&adapter->napi);


	e1000_irq_disable(adapter);
	e1000_irq_disable(adapter);