diff options
author | Rajkumar Manoharan <rmanohar@qca.qualcomm.com> | 2012-07-17 15:46:42 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-07-17 23:11:40 +0400 |
commit | 124b979baeb2d7a0593be8d392f43725578478c1 (patch) | |
tree | 3b6f3d1d1915f3dba8f2405a8e79f1bf7958b22e /drivers/net/wireless/ath/ath9k/link.c | |
parent | 6dcc344469d60a1f0d72cc638967e8c83c6e166e (diff) | |
download | linux-124b979baeb2d7a0593be8d392f43725578478c1.tar.xz |
ath9k: Fix race in reset-work usage
Using work_pending() to defer certain operations when
a HW-reset work has been queued is racy since the check
would return false when the work item is actually in
execution. Use SC_OP_HW_RESET instead to fix this race.
Also, unify the reset debug statistics maintenance.
Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/link.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/link.c | 13 |
1 files changed, 6 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 42fc0a374c61..d4549e9aac5c 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -50,8 +50,7 @@ void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, "tx hung, resetting the chip\n"); - RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, RESET_TYPE_TX_HANG); return; } @@ -69,6 +68,7 @@ void ath_hw_check(struct work_struct *work) unsigned long flags; int busy; u8 is_alive, nbeacon = 1; + enum ath_reset_type type; ath9k_ps_wakeup(sc); is_alive = ath9k_hw_check_alive(sc->sc_ah); @@ -78,7 +78,7 @@ void ath_hw_check(struct work_struct *work) else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { ath_dbg(common, RESET, "DCU stuck is detected. Schedule chip reset\n"); - RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG); + type = RESET_TYPE_MAC_HANG; goto sched_reset; } @@ -90,7 +90,7 @@ void ath_hw_check(struct work_struct *work) busy, sc->hw_busy_count + 1); if (busy >= 99) { if (++sc->hw_busy_count >= 3) { - RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); + type = RESET_TYPE_BB_HANG; goto sched_reset; } } else if (busy >= 0) { @@ -102,7 +102,7 @@ void ath_hw_check(struct work_struct *work) goto out; sched_reset: - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, type); out: ath9k_ps_restore(sc); } @@ -119,8 +119,7 @@ static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) count++; if (count == 3) { ath_dbg(common, RESET, "PLL WAR, resetting the chip\n"); - RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, RESET_TYPE_PLL_HANG); count = 0; return true; } |