struct tg3 *tp = _data;
unsigned int restart_timer;
+ tg3_full_lock(tp, 0);
+ tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
+
+ if (!netif_running(tp->dev)) {
+ tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+ tg3_full_unlock(tp);
+ return;
+ }
+
+ tg3_full_unlock(tp);
+
tg3_netif_stop(tp);
tg3_full_lock(tp, 1);
tg3_netif_start(tp);
- tg3_full_unlock(tp);
-
if (restart_timer)
mod_timer(&tp->timer, jiffies + 1);
+
+ tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+
+ tg3_full_unlock(tp);
}
static void tg3_tx_timeout(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
+ /* Calling flush_scheduled_work() may deadlock because
+ * linkwatch_event() may be on the workqueue and it will try to get
+ * the rtnl_lock which we are holding.
+ */
+ while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
+ msleep(1);
+
netif_stop_queue(dev);
del_timer_sync(&tp->timer);
if (dev) {
struct tg3 *tp = netdev_priv(dev);
+ flush_scheduled_work();
unregister_netdev(dev);
if (tp->regs) {
iounmap(tp->regs);
if (!netif_running(dev))
return 0;
+ flush_scheduled_work();
tg3_netif_stop(tp);
del_timer_sync(&tp->timer);
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
+#define TG3_FLAG_IN_RESET_TASK 0x04000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
#define TG3_FLAG_SPLIT_MODE 0x40000000