提交 7faa006f 编写于 作者: M Michael Chan 提交者: David S. Miller

[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: NMichael Chan <mchan@broadcom.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 3f330317
...@@ -3482,6 +3482,17 @@ static void tg3_reset_task(void *_data) ...@@ -3482,6 +3482,17 @@ static void tg3_reset_task(void *_data)
struct tg3 *tp = _data; struct tg3 *tp = _data;
unsigned int restart_timer; 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_netif_stop(tp);
tg3_full_lock(tp, 1); tg3_full_lock(tp, 1);
...@@ -3494,10 +3505,12 @@ static void tg3_reset_task(void *_data) ...@@ -3494,10 +3505,12 @@ static void tg3_reset_task(void *_data)
tg3_netif_start(tp); tg3_netif_start(tp);
tg3_full_unlock(tp);
if (restart_timer) if (restart_timer)
mod_timer(&tp->timer, jiffies + 1); 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) static void tg3_tx_timeout(struct net_device *dev)
...@@ -6786,6 +6799,13 @@ static int tg3_close(struct net_device *dev) ...@@ -6786,6 +6799,13 @@ static int tg3_close(struct net_device *dev)
{ {
struct tg3 *tp = netdev_priv(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); netif_stop_queue(dev);
del_timer_sync(&tp->timer); del_timer_sync(&tp->timer);
...@@ -10880,6 +10900,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) ...@@ -10880,6 +10900,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
if (dev) { if (dev) {
struct tg3 *tp = netdev_priv(dev); struct tg3 *tp = netdev_priv(dev);
flush_scheduled_work();
unregister_netdev(dev); unregister_netdev(dev);
if (tp->regs) { if (tp->regs) {
iounmap(tp->regs); iounmap(tp->regs);
...@@ -10901,6 +10922,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) ...@@ -10901,6 +10922,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev)) if (!netif_running(dev))
return 0; return 0;
flush_scheduled_work();
tg3_netif_stop(tp); tg3_netif_stop(tp);
del_timer_sync(&tp->timer); del_timer_sync(&tp->timer);
......
...@@ -2162,6 +2162,7 @@ struct tg3 { ...@@ -2162,6 +2162,7 @@ struct tg3 {
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000
#define TG3_FLAG_IN_RESET_TASK 0x04000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
#define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_SPLIT_MODE 0x40000000
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册