diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2011-11-04 05:15:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-04 17:31:48 -0400 |
commit | 5b1906241905d9bd1abe920854b3d43c2b9c85e1 (patch) | |
tree | d259390621daa923977f00fb43415a09da565cd5 /drivers/net/ethernet/broadcom/tg3.c | |
parent | db21997379906fe7657d360674e1106d80b020a4 (diff) |
tg3: Eliminate timer race with reset_task
During shutdown, it is impossible to reliably disable the timer and
reset_task threads. Each thread can schedule the other, which leads to
shutdown code that chases its tail.
To fix the problem, this patch removes the ability of tg3_reset_task to
schedule a new timer thread. To support this change, tg3_timer no
longer terminates itself, but rather goes into a polling mode.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Reviewed-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/tg3.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 14 |
1 files changed, 2 insertions, 12 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index d4a85b795344..cc7349fd7fcd 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
@@ -6352,7 +6352,6 @@ static void tg3_reset_task(struct work_struct *work) | |||
6352 | { | 6352 | { |
6353 | struct tg3 *tp = container_of(work, struct tg3, reset_task); | 6353 | struct tg3 *tp = container_of(work, struct tg3, reset_task); |
6354 | int err; | 6354 | int err; |
6355 | unsigned int restart_timer; | ||
6356 | 6355 | ||
6357 | tg3_full_lock(tp, 0); | 6356 | tg3_full_lock(tp, 0); |
6358 | 6357 | ||
@@ -6370,9 +6369,6 @@ static void tg3_reset_task(struct work_struct *work) | |||
6370 | 6369 | ||
6371 | tg3_full_lock(tp, 1); | 6370 | tg3_full_lock(tp, 1); |
6372 | 6371 | ||
6373 | restart_timer = tg3_flag(tp, RESTART_TIMER); | ||
6374 | tg3_flag_clear(tp, RESTART_TIMER); | ||
6375 | |||
6376 | if (tg3_flag(tp, TX_RECOVERY_PENDING)) { | 6372 | if (tg3_flag(tp, TX_RECOVERY_PENDING)) { |
6377 | tp->write32_tx_mbox = tg3_write32_tx_mbox; | 6373 | tp->write32_tx_mbox = tg3_write32_tx_mbox; |
6378 | tp->write32_rx_mbox = tg3_write_flush_reg32; | 6374 | tp->write32_rx_mbox = tg3_write_flush_reg32; |
@@ -6387,9 +6383,6 @@ static void tg3_reset_task(struct work_struct *work) | |||
6387 | 6383 | ||
6388 | tg3_netif_start(tp); | 6384 | tg3_netif_start(tp); |
6389 | 6385 | ||
6390 | if (restart_timer) | ||
6391 | mod_timer(&tp->timer, jiffies + 1); | ||
6392 | |||
6393 | out: | 6386 | out: |
6394 | tg3_full_unlock(tp); | 6387 | tg3_full_unlock(tp); |
6395 | 6388 | ||
@@ -9218,7 +9211,7 @@ static void tg3_timer(unsigned long __opaque) | |||
9218 | { | 9211 | { |
9219 | struct tg3 *tp = (struct tg3 *) __opaque; | 9212 | struct tg3 *tp = (struct tg3 *) __opaque; |
9220 | 9213 | ||
9221 | if (tp->irq_sync) | 9214 | if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING)) |
9222 | goto restart_timer; | 9215 | goto restart_timer; |
9223 | 9216 | ||
9224 | spin_lock(&tp->lock); | 9217 | spin_lock(&tp->lock); |
@@ -9241,10 +9234,9 @@ static void tg3_timer(unsigned long __opaque) | |||
9241 | } | 9234 | } |
9242 | 9235 | ||
9243 | if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { | 9236 | if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { |
9244 | tg3_flag_set(tp, RESTART_TIMER); | ||
9245 | spin_unlock(&tp->lock); | 9237 | spin_unlock(&tp->lock); |
9246 | tg3_reset_task_schedule(tp); | 9238 | tg3_reset_task_schedule(tp); |
9247 | return; | 9239 | goto restart_timer; |
9248 | } | 9240 | } |
9249 | } | 9241 | } |
9250 | 9242 | ||
@@ -15847,12 +15839,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, | |||
15847 | tg3_netif_stop(tp); | 15839 | tg3_netif_stop(tp); |
15848 | 15840 | ||
15849 | del_timer_sync(&tp->timer); | 15841 | del_timer_sync(&tp->timer); |
15850 | tg3_flag_clear(tp, RESTART_TIMER); | ||
15851 | 15842 | ||
15852 | /* Want to make sure that the reset task doesn't run */ | 15843 | /* Want to make sure that the reset task doesn't run */ |
15853 | tg3_reset_task_cancel(tp); | 15844 | tg3_reset_task_cancel(tp); |
15854 | tg3_flag_clear(tp, TX_RECOVERY_PENDING); | 15845 | tg3_flag_clear(tp, TX_RECOVERY_PENDING); |
15855 | tg3_flag_clear(tp, RESTART_TIMER); | ||
15856 | 15846 | ||
15857 | netif_device_detach(netdev); | 15847 | netif_device_detach(netdev); |
15858 | 15848 | ||