Skip to content

Commit 5566993

Browse files
Michael Chandavem330
authored andcommitted
tg3: Fix soft lockup when tg3_reset_task() fails.
If tg3_reset_task() fails, the device state is left in an inconsistent state with IFF_RUNNING still set but NAPI state not enabled. A subsequent operation, such as ifdown or AER error can cause it to soft lock up when it tries to disable NAPI state. Fix it by bringing down the device to !IFF_RUNNING state when tg3_reset_task() fails. tg3_reset_task() running from workqueue will now call tg3_close() when the reset fails. We need to modify tg3_reset_task_cancel() slightly to avoid tg3_close() calling cancel_work_sync() to cancel tg3_reset_task(). Otherwise cancel_work_sync() will wait forever for tg3_reset_task() to finish. Reported-by: David Christensen <[email protected]> Reported-by: Baptiste Covolato <[email protected]> Fixes: db21997 ("tg3: Schedule at most one tg3_reset_task run") Signed-off-by: Michael Chan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent af0ae99 commit 5566993

File tree

1 file changed

+13
-4
lines changed
  • drivers/net/ethernet/broadcom

1 file changed

+13
-4
lines changed

drivers/net/ethernet/broadcom/tg3.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7221,8 +7221,8 @@ static inline void tg3_reset_task_schedule(struct tg3 *tp)
72217221

72227222
static inline void tg3_reset_task_cancel(struct tg3 *tp)
72237223
{
7224-
cancel_work_sync(&tp->reset_task);
7225-
tg3_flag_clear(tp, RESET_TASK_PENDING);
7224+
if (test_and_clear_bit(TG3_FLAG_RESET_TASK_PENDING, tp->tg3_flags))
7225+
cancel_work_sync(&tp->reset_task);
72267226
tg3_flag_clear(tp, TX_RECOVERY_PENDING);
72277227
}
72287228

@@ -11209,18 +11209,27 @@ static void tg3_reset_task(struct work_struct *work)
1120911209

1121011210
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
1121111211
err = tg3_init_hw(tp, true);
11212-
if (err)
11212+
if (err) {
11213+
tg3_full_unlock(tp);
11214+
tp->irq_sync = 0;
11215+
tg3_napi_enable(tp);
11216+
/* Clear this flag so that tg3_reset_task_cancel() will not
11217+
* call cancel_work_sync() and wait forever.
11218+
*/
11219+
tg3_flag_clear(tp, RESET_TASK_PENDING);
11220+
dev_close(tp->dev);
1121311221
goto out;
11222+
}
1121411223

1121511224
tg3_netif_start(tp);
1121611225

11217-
out:
1121811226
tg3_full_unlock(tp);
1121911227

1122011228
if (!err)
1122111229
tg3_phy_start(tp);
1122211230

1122311231
tg3_flag_clear(tp, RESET_TASK_PENDING);
11232+
out:
1122411233
rtnl_unlock();
1122511234
}
1122611235

0 commit comments

Comments
 (0)