diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-09-02 19:40:25 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-09-14 13:56:20 -0400 |
commit | 236de5149b9cbec3e76aef00a4663a8de7feeebe (patch) | |
tree | 3086a9d4b4bcd0e5a5ccfba94b02545e765f56bc | |
parent | e8cfe9f8c488f5b345ab557148c7af57af4fbe25 (diff) |
ath9k: always call ath_reset from workqueue context
This makes it much easier to add further rework to avoid race conditions
between reset and other work items.
Move other functions to make ath_reset static.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 14 |
5 files changed, 26 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 5d9a9aabe476..b2992d4097c3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -425,6 +425,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); | |||
425 | 425 | ||
426 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ | 426 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ |
427 | 427 | ||
428 | void ath_reset_work(struct work_struct *work); | ||
428 | void ath_hw_check(struct work_struct *work); | 429 | void ath_hw_check(struct work_struct *work); |
429 | void ath_hw_pll_work(struct work_struct *work); | 430 | void ath_hw_pll_work(struct work_struct *work); |
430 | void ath_paprd_calibrate(struct work_struct *work); | 431 | void ath_paprd_calibrate(struct work_struct *work); |
@@ -604,6 +605,7 @@ struct ath_softc { | |||
604 | struct mutex mutex; | 605 | struct mutex mutex; |
605 | struct work_struct paprd_work; | 606 | struct work_struct paprd_work; |
606 | struct work_struct hw_check_work; | 607 | struct work_struct hw_check_work; |
608 | struct work_struct hw_reset_work; | ||
607 | struct completion paprd_complete; | 609 | struct completion paprd_complete; |
608 | 610 | ||
609 | unsigned int hw_busy_count; | 611 | unsigned int hw_busy_count; |
@@ -650,7 +652,6 @@ struct ath_softc { | |||
650 | }; | 652 | }; |
651 | 653 | ||
652 | void ath9k_tasklet(unsigned long data); | 654 | void ath9k_tasklet(unsigned long data); |
653 | int ath_reset(struct ath_softc *sc, bool retry_tx); | ||
654 | int ath_cabq_update(struct ath_softc *); | 655 | int ath_cabq_update(struct ath_softc *); |
655 | 656 | ||
656 | static inline void ath_read_cachesize(struct ath_common *common, int *csz) | 657 | static inline void ath_read_cachesize(struct ath_common *common, int *csz) |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0c757c9f978a..22e8e2580116 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -386,9 +386,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
386 | ath_dbg(common, ATH_DBG_BSTUCK, | 386 | ath_dbg(common, ATH_DBG_BSTUCK, |
387 | "beacon is officially stuck\n"); | 387 | "beacon is officially stuck\n"); |
388 | sc->sc_flags |= SC_OP_TSF_RESET; | 388 | sc->sc_flags |= SC_OP_TSF_RESET; |
389 | spin_lock(&sc->sc_pcu_lock); | 389 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
390 | ath_reset(sc, true); | ||
391 | spin_unlock(&sc->sc_pcu_lock); | ||
392 | } | 390 | } |
393 | 391 | ||
394 | return; | 392 | return; |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 50da6421728b..be302fbdc3dc 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -777,6 +777,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, | |||
777 | goto error_world; | 777 | goto error_world; |
778 | } | 778 | } |
779 | 779 | ||
780 | INIT_WORK(&sc->hw_reset_work, ath_reset_work); | ||
780 | INIT_WORK(&sc->hw_check_work, ath_hw_check); | 781 | INIT_WORK(&sc->hw_check_work, ath_hw_check); |
781 | INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); | 782 | INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); |
782 | INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); | 783 | INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9ff73e007d34..9a6db2964b18 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -236,6 +236,7 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
236 | del_timer_sync(&common->ani.timer); | 236 | del_timer_sync(&common->ani.timer); |
237 | cancel_work_sync(&sc->paprd_work); | 237 | cancel_work_sync(&sc->paprd_work); |
238 | cancel_work_sync(&sc->hw_check_work); | 238 | cancel_work_sync(&sc->hw_check_work); |
239 | cancel_work_sync(&sc->hw_reset_work); | ||
239 | cancel_delayed_work_sync(&sc->tx_complete_work); | 240 | cancel_delayed_work_sync(&sc->tx_complete_work); |
240 | cancel_delayed_work_sync(&sc->hw_pll_work); | 241 | cancel_delayed_work_sync(&sc->hw_pll_work); |
241 | 242 | ||
@@ -608,9 +609,7 @@ void ath9k_tasklet(unsigned long data) | |||
608 | 609 | ||
609 | if ((status & ATH9K_INT_FATAL) || | 610 | if ((status & ATH9K_INT_FATAL) || |
610 | (status & ATH9K_INT_BB_WATCHDOG)) { | 611 | (status & ATH9K_INT_BB_WATCHDOG)) { |
611 | spin_lock(&sc->sc_pcu_lock); | 612 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
612 | ath_reset(sc, true); | ||
613 | spin_unlock(&sc->sc_pcu_lock); | ||
614 | return; | 613 | return; |
615 | } | 614 | } |
616 | 615 | ||
@@ -901,7 +900,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
901 | ath9k_ps_restore(sc); | 900 | ath9k_ps_restore(sc); |
902 | } | 901 | } |
903 | 902 | ||
904 | int ath_reset(struct ath_softc *sc, bool retry_tx) | 903 | static int ath_reset(struct ath_softc *sc, bool retry_tx) |
905 | { | 904 | { |
906 | struct ath_hw *ah = sc->sc_ah; | 905 | struct ath_hw *ah = sc->sc_ah; |
907 | struct ath_common *common = ath9k_hw_common(ah); | 906 | struct ath_common *common = ath9k_hw_common(ah); |
@@ -969,6 +968,15 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
969 | return r; | 968 | return r; |
970 | } | 969 | } |
971 | 970 | ||
971 | void ath_reset_work(struct work_struct *work) | ||
972 | { | ||
973 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); | ||
974 | |||
975 | spin_lock_bh(&sc->sc_pcu_lock); | ||
976 | ath_reset(sc, true); | ||
977 | spin_unlock_bh(&sc->sc_pcu_lock); | ||
978 | } | ||
979 | |||
972 | void ath_hw_check(struct work_struct *work) | 980 | void ath_hw_check(struct work_struct *work) |
973 | { | 981 | { |
974 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); | 982 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); |
@@ -1230,6 +1238,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1230 | cancel_delayed_work_sync(&sc->hw_pll_work); | 1238 | cancel_delayed_work_sync(&sc->hw_pll_work); |
1231 | cancel_work_sync(&sc->paprd_work); | 1239 | cancel_work_sync(&sc->paprd_work); |
1232 | cancel_work_sync(&sc->hw_check_work); | 1240 | cancel_work_sync(&sc->hw_check_work); |
1241 | cancel_work_sync(&sc->hw_reset_work); | ||
1233 | 1242 | ||
1234 | if (sc->sc_flags & SC_OP_INVALID) { | 1243 | if (sc->sc_flags & SC_OP_INVALID) { |
1235 | ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); | 1244 | ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0fb8fb57b5c8..cb37047e71d2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -582,7 +582,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
582 | rcu_read_unlock(); | 582 | rcu_read_unlock(); |
583 | 583 | ||
584 | if (needreset) | 584 | if (needreset) |
585 | ath_reset(sc, false); | 585 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
586 | } | 586 | } |
587 | 587 | ||
588 | static bool ath_lookup_legacy(struct ath_buf *bf) | 588 | static bool ath_lookup_legacy(struct ath_buf *bf) |
@@ -1333,7 +1333,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) | |||
1333 | struct ath_atx_ac *ac, *ac_tmp, *last_ac; | 1333 | struct ath_atx_ac *ac, *ac_tmp, *last_ac; |
1334 | struct ath_atx_tid *tid, *last_tid; | 1334 | struct ath_atx_tid *tid, *last_tid; |
1335 | 1335 | ||
1336 | if (list_empty(&txq->axq_acq) || | 1336 | if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) || |
1337 | txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) | 1337 | txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) |
1338 | return; | 1338 | return; |
1339 | 1339 | ||
@@ -2148,6 +2148,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2148 | 2148 | ||
2149 | spin_lock_bh(&txq->axq_lock); | 2149 | spin_lock_bh(&txq->axq_lock); |
2150 | for (;;) { | 2150 | for (;;) { |
2151 | if (work_pending(&sc->hw_reset_work)) | ||
2152 | break; | ||
2153 | |||
2151 | if (list_empty(&txq->axq_q)) { | 2154 | if (list_empty(&txq->axq_q)) { |
2152 | txq->axq_link = NULL; | 2155 | txq->axq_link = NULL; |
2153 | if (sc->sc_flags & SC_OP_TXAGGR) | 2156 | if (sc->sc_flags & SC_OP_TXAGGR) |
@@ -2235,9 +2238,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work) | |||
2235 | if (needreset) { | 2238 | if (needreset) { |
2236 | ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, | 2239 | ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, |
2237 | "tx hung, resetting the chip\n"); | 2240 | "tx hung, resetting the chip\n"); |
2238 | spin_lock_bh(&sc->sc_pcu_lock); | 2241 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
2239 | ath_reset(sc, true); | ||
2240 | spin_unlock_bh(&sc->sc_pcu_lock); | ||
2241 | } | 2242 | } |
2242 | 2243 | ||
2243 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, | 2244 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, |
@@ -2270,6 +2271,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) | |||
2270 | int status; | 2271 | int status; |
2271 | 2272 | ||
2272 | for (;;) { | 2273 | for (;;) { |
2274 | if (work_pending(&sc->hw_reset_work)) | ||
2275 | break; | ||
2276 | |||
2273 | status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); | 2277 | status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); |
2274 | if (status == -EINPROGRESS) | 2278 | if (status == -EINPROGRESS) |
2275 | break; | 2279 | break; |