diff options
author | Auke Kok <auke\-jan.h.kok@intel.com> | 2006-09-27 12:54:02 -0700 |
---|---|---|
committer | Auke Kok <juke-jan.h.kok@intel.com> | 2006-09-27 12:54:02 -0700 |
commit | 1314bbf3a3d911218fc153e14873e2e384d08084 (patch) | |
tree | 4b2517261087f6d1374fe84272dcf20cd184f701 /drivers/net | |
parent | 4f5f2317fbb3655edae21de3ada0f1692523eeef (diff) | |
download | talos-op-linux-1314bbf3a3d911218fc153e14873e2e384d08084.tar.gz talos-op-linux-1314bbf3a3d911218fc153e14873e2e384d08084.zip |
e1000: driver state fixes (race fix)
We were plagued by our interrupt handler posting a watchdog event which
could occur when our adapter was going down in case a late packet arrived
just before e1000_down() finished. This caused the watchdog timer to start
after the NIC was down and keep rescheduling it every N seconds. Once
the driver unloaded it would panic.
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/e1000/e1000.h | 3 | ||||
-rw-r--r-- | drivers/net/e1000/e1000_ethtool.c | 6 | ||||
-rw-r--r-- | drivers/net/e1000/e1000_main.c | 28 |
3 files changed, 23 insertions, 14 deletions
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index a9501e7b8ef9..7ecce438d258 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -345,8 +345,9 @@ struct e1000_adapter { }; enum e1000_state_t { - __E1000_DRIVER_TESTING, + __E1000_TESTING, __E1000_RESETTING, + __E1000_DOWN }; #endif /* _E1000_H_ */ diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 5edf8a099ceb..2cc949a34451 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1624,7 +1624,7 @@ e1000_diag_test(struct net_device *netdev, struct e1000_adapter *adapter = netdev_priv(netdev); boolean_t if_running = netif_running(netdev); - set_bit(__E1000_DRIVER_TESTING, &adapter->flags); + set_bit(__E1000_TESTING, &adapter->flags); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* Offline tests */ @@ -1669,7 +1669,7 @@ e1000_diag_test(struct net_device *netdev, adapter->hw.autoneg = autoneg; e1000_reset(adapter); - clear_bit(__E1000_DRIVER_TESTING, &adapter->flags); + clear_bit(__E1000_TESTING, &adapter->flags); if (if_running) dev_open(netdev); } else { @@ -1684,7 +1684,7 @@ e1000_diag_test(struct net_device *netdev, data[2] = 0; data[3] = 0; - clear_bit(__E1000_DRIVER_TESTING, &adapter->flags); + clear_bit(__E1000_TESTING, &adapter->flags); } msleep_interruptible(4 * 1000); } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index e2615782966e..5098dd7df7cd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -476,13 +476,14 @@ e1000_up(struct e1000_adapter *adapter) adapter->tx_queue_len = netdev->tx_queue_len; - mod_timer(&adapter->watchdog_timer, jiffies); - #ifdef CONFIG_E1000_NAPI netif_poll_enable(netdev); #endif e1000_irq_enable(adapter); + clear_bit(__E1000_DOWN, &adapter->flags); + + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); return 0; } @@ -561,6 +562,10 @@ e1000_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; + /* signal that we're down so the interrupt handler does not + * reschedule our watchdog timer */ + set_bit(__E1000_DOWN, &adapter->flags); + e1000_irq_disable(adapter); del_timer_sync(&adapter->tx_fifo_stall_timer); @@ -903,11 +908,6 @@ e1000_probe(struct pci_dev *pdev, INIT_WORK(&adapter->reset_task, (void (*)(void *))e1000_reset_task, netdev); - /* we're going to reset, so assume we have no link for now */ - - netif_carrier_off(netdev); - netif_stop_queue(netdev); - e1000_check_options(adapter); /* Initial Wake on LAN setting @@ -1014,6 +1014,10 @@ e1000_probe(struct pci_dev *pdev, if ((err = register_netdev(netdev))) goto err_register; + /* tell the stack to leave us alone until e1000_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n"); cards_found++; @@ -1200,6 +1204,8 @@ e1000_sw_init(struct e1000_adapter *adapter) atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); + set_bit(__E1000_DOWN, &adapter->flags); + return 0; } @@ -1265,7 +1271,7 @@ e1000_open(struct net_device *netdev) int err; /* disallow open during test */ - if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags)) + if (test_bit(__E1000_TESTING, &adapter->flags)) return -EBUSY; /* allocate transmit descriptors */ @@ -3072,7 +3078,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (unlikely(adapter->hw.mac_type == e1000_82547)) { if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); - mod_timer(&adapter->tx_fifo_stall_timer, jiffies); + mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1); spin_unlock_irqrestore(&tx_ring->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -3468,7 +3474,9 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) rctl = E1000_READ_REG(hw, RCTL); E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); } - mod_timer(&adapter->watchdog_timer, jiffies); + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->flags)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); } #ifdef CONFIG_E1000_NAPI |