aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-02-02 20:29:28 -0500
committerDavid S. Miller <davem@davemloft.net>2006-02-02 20:29:28 -0500
commit7faa006f94fda56a587242b2a22fa19abf840222 (patch)
treeb1354b391829bc3f1d83fd3121167318f8472147 /drivers/net
parent3f330317ab4973178423aba750d6d0ca5ce0024a (diff)
[TG3]: Flush tg3_reset_task()
Make sure tg3_reset_task() is flushed in the close and suspend paths as noted by Jeff Garzik. In the close path, calling flush_scheduled_work() may cause deadlock if linkwatch_event() is on the workqueue. linkwatch_event() will try to get the rtnl_lock() which is already held by tg3_close(). So instead, we set a flag in tg3_reset_task() and tg3_close() polls the flag until it is cleared. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tg3.c26
-rw-r--r--drivers/net/tg3.h1
2 files changed, 25 insertions, 2 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f2d1dafde087..6fb29ca3fd30 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3482,6 +3482,17 @@ static void tg3_reset_task(void *_data)
3482 struct tg3 *tp = _data; 3482 struct tg3 *tp = _data;
3483 unsigned int restart_timer; 3483 unsigned int restart_timer;
3484 3484
3485 tg3_full_lock(tp, 0);
3486 tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
3487
3488 if (!netif_running(tp->dev)) {
3489 tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
3490 tg3_full_unlock(tp);
3491 return;
3492 }
3493
3494 tg3_full_unlock(tp);
3495
3485 tg3_netif_stop(tp); 3496 tg3_netif_stop(tp);
3486 3497
3487 tg3_full_lock(tp, 1); 3498 tg3_full_lock(tp, 1);
@@ -3494,10 +3505,12 @@ static void tg3_reset_task(void *_data)
3494 3505
3495 tg3_netif_start(tp); 3506 tg3_netif_start(tp);
3496 3507
3497 tg3_full_unlock(tp);
3498
3499 if (restart_timer) 3508 if (restart_timer)
3500 mod_timer(&tp->timer, jiffies + 1); 3509 mod_timer(&tp->timer, jiffies + 1);
3510
3511 tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
3512
3513 tg3_full_unlock(tp);
3501} 3514}
3502 3515
3503static void tg3_tx_timeout(struct net_device *dev) 3516static void tg3_tx_timeout(struct net_device *dev)
@@ -6786,6 +6799,13 @@ static int tg3_close(struct net_device *dev)
6786{ 6799{
6787 struct tg3 *tp = netdev_priv(dev); 6800 struct tg3 *tp = netdev_priv(dev);
6788 6801
6802 /* Calling flush_scheduled_work() may deadlock because
6803 * linkwatch_event() may be on the workqueue and it will try to get
6804 * the rtnl_lock which we are holding.
6805 */
6806 while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
6807 msleep(1);
6808
6789 netif_stop_queue(dev); 6809 netif_stop_queue(dev);
6790 6810
6791 del_timer_sync(&tp->timer); 6811 del_timer_sync(&tp->timer);
@@ -10880,6 +10900,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
10880 if (dev) { 10900 if (dev) {
10881 struct tg3 *tp = netdev_priv(dev); 10901 struct tg3 *tp = netdev_priv(dev);
10882 10902
10903 flush_scheduled_work();
10883 unregister_netdev(dev); 10904 unregister_netdev(dev);
10884 if (tp->regs) { 10905 if (tp->regs) {
10885 iounmap(tp->regs); 10906 iounmap(tp->regs);
@@ -10901,6 +10922,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
10901 if (!netif_running(dev)) 10922 if (!netif_running(dev))
10902 return 0; 10923 return 0;
10903 10924
10925 flush_scheduled_work();
10904 tg3_netif_stop(tp); 10926 tg3_netif_stop(tp);
10905 10927
10906 del_timer_sync(&tp->timer); 10928 del_timer_sync(&tp->timer);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index e8243305f0e8..7f4b7f6ac40d 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2162,6 +2162,7 @@ struct tg3 {
2162#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 2162#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
2163#define TG3_FLAG_10_100_ONLY 0x01000000 2163#define TG3_FLAG_10_100_ONLY 0x01000000
2164#define TG3_FLAG_PAUSE_AUTONEG 0x02000000 2164#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
2165#define TG3_FLAG_IN_RESET_TASK 0x04000000
2165#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 2166#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
2166#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 2167#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
2167#define TG3_FLAG_SPLIT_MODE 0x40000000 2168#define TG3_FLAG_SPLIT_MODE 0x40000000