netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net] driver: e1000: fix race condition between e1000_down() and e1000_watchdog
@ 2017-09-16 16:00 Vincenzo Maffione
  2017-10-11  1:07 ` Brown, Aaron F
  0 siblings, 1 reply; 2+ messages in thread
From: Vincenzo Maffione @ 2017-09-16 16:00 UTC (permalink / raw)
  To: jeffrey.t.kirsher
  Cc: intel-wired-lan, netdev, linux-kernel, Vincenzo Maffione

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>
---
 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 98375e1e1185..1982f7917a8d 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -520,8 +520,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);
@@ -537,6 +535,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.14.1

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* RE: [PATCH net] driver: e1000: fix race condition between e1000_down() and e1000_watchdog
  2017-09-16 16:00 [PATCH net] driver: e1000: fix race condition between e1000_down() and e1000_watchdog Vincenzo Maffione
@ 2017-10-11  1:07 ` Brown, Aaron F
  0 siblings, 0 replies; 2+ messages in thread
From: Brown, Aaron F @ 2017-10-11  1:07 UTC (permalink / raw)
  To: Vincenzo Maffione, Kirsher, Jeffrey T
  Cc: intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org

> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of Vincenzo Maffione
> Sent: Saturday, September 16, 2017 9:00 AM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>
> Cc: intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org; linux-
> kernel@vger.kernel.org; Vincenzo Maffione <v.maffione@gmail.com>
> Subject: [PATCH net] driver: 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: Vincenzo Maffione <v.maffione@gmail.com>
> ---
>  drivers/net/ethernet/intel/e1000/e1000_main.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)

Tested-by: Aaron Brown <aaron.f.brown@intel.com>

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-10-11  1:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-16 16:00 [PATCH net] driver: e1000: fix race condition between e1000_down() and e1000_watchdog Vincenzo Maffione
2017-10-11  1:07 ` Brown, Aaron F

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).