[NET]: Fix interrupt semaphore corruption in Intel drivers.
authorDavid S. Miller <davem@davemloft.net>
Fri, 18 Jan 2008 12:21:39 +0000 (04:21 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 21 Jan 2008 04:31:39 +0000 (20:31 -0800)
Several of the Intel ethernet drivers keep an atomic counter used to
manage when to actually hit the hardware with a disable or an enable.

The way the net_rx_work() breakout logic works during a pending
napi_disable() is that it simply unschedules the poll even if it
still has work.

This can potentially leave interrupts disabled, but that is OK
because all of the drivers are about to disable interrupts
anyways in all such code paths that do a napi_disable().

Unfortunately, this trips up the semaphore used here in the Intel
drivers.  If you hit this case, when you try to bring the interface
back up it won't enable interrupts.  A reload of the driver module
fixes it of course.

So what we do is make sure all the sequences now go:

napi_disable();
atomic_set(&adapter->irq_sem, 0);
*_irq_disable();

which makes sure the counter is always in the correct state.

Reported by Robert Olsson.

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/netdev.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/ixgbe_main.c

index 0c9a6f7104d2803b4072f5e6bf788df0a98e3aca..76c0fa690cc6adb60e0ab94d1e4cf7cbb6cbb00f 100644 (file)
@@ -632,6 +632,7 @@ e1000_down(struct e1000_adapter *adapter)
 
 #ifdef CONFIG_E1000_NAPI
        napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
 #endif
        e1000_irq_disable(adapter);
 
index 2ab3bfbb8a63380b2505756fdfe301374123b569..9cc5a6b01bc1dcfb73ca17ec11a476e586837951 100644 (file)
@@ -2183,6 +2183,7 @@ void e1000e_down(struct e1000_adapter *adapter)
        msleep(10);
 
        napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
        e1000_irq_disable(adapter);
 
        del_timer_sync(&adapter->watchdog_timer);
index d2fb88d5cda2773675e87de42d3dee6e0789e8f7..4f63839051b05ca2d282e8e62dd0419713d0e124 100644 (file)
@@ -296,6 +296,11 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
 {
        struct net_device *netdev = adapter->netdev;
 
+#ifdef CONFIG_IXGB_NAPI
+       napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
+#endif
+
        ixgb_irq_disable(adapter);
        free_irq(adapter->pdev->irq, netdev);
 
@@ -304,9 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
 
        if(kill_watchdog)
                del_timer_sync(&adapter->watchdog_timer);
-#ifdef CONFIG_IXGB_NAPI
-       napi_disable(&adapter->napi);
-#endif
+
        adapter->link_speed = 0;
        adapter->link_duplex = 0;
        netif_carrier_off(netdev);
index de3f45e4c5ae382b5e7feb9995d07a38e1e47fa9..a4265bc1cebb7162fbbdcbc59ffd2590f292fc9e 100644 (file)
@@ -1409,9 +1409,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_FLUSH(&adapter->hw);
        msleep(10);
 
+       napi_disable(&adapter->napi);
+       atomic_set(&adapter->irq_sem, 0);
+
        ixgbe_irq_disable(adapter);
 
-       napi_disable(&adapter->napi);
        del_timer_sync(&adapter->watchdog_timer);
 
        netif_carrier_off(netdev);