summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-01-18 13:21:39 +0100
committerDavid S. Miller <davem@davemloft.net>2008-01-21 05:31:39 +0100
commit49d85c502ec5e6d5998c1a04394c5b24e8f7d32d (patch)
tree1ee90204956315e148e7fe37d0bafbca8e557d9e
parent[IPV4] fib_trie: fix duplicated route issue (diff)
downloadlinux-49d85c502ec5e6d5998c1a04394c5b24e8f7d32d.tar.xz
linux-49d85c502ec5e6d5998c1a04394c5b24e8f7d32d.zip
[NET]: Fix interrupt semaphore corruption in Intel drivers.
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>
-rw-r--r--drivers/net/e1000/e1000_main.c1
-rw-r--r--drivers/net/e1000e/netdev.c1
-rw-r--r--drivers/net/ixgb/ixgb_main.c9
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c4
4 files changed, 11 insertions, 4 deletions
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 0c9a6f7104d2..76c0fa690cc6 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -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);
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 2ab3bfbb8a63..9cc5a6b01bc1 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -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);
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index d2fb88d5cda2..4f63839051b0 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -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);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index de3f45e4c5ae..a4265bc1cebb 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -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);