diff options
author | Felix Fietkau <nbd@openwrt.org> | 2010-07-01 18:09:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-07-02 13:44:38 -0400 |
commit | 347809fc2c99da5b89f1c014f3e5a0f85c04803c (patch) | |
tree | 6bacea4f51a2ab8711deaea1ee4eecc213ff39ca | |
parent | 54bd5006b03ee980f6067b4d61c3605b5a5e1d4a (diff) |
ath9k: fix false positives in the baseband hang check
ath9k_hw_check_alive() occasionally returns false, as the hardware
is still processing data in a specific state. Fix this issue by
repeating the test a few times with longer delay inbetween attempts.
This gets rid of excessive hardware resets that appear frequently on
some AR9132 based devices, but could also happen on AR9280.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Reported-by: Björn Smedman <bjorn.smedman@venatech.se>
Cc: stable@kernel.org
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 27 |
3 files changed, 28 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 72d5e52abb8f..6e486a508edb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -428,6 +428,7 @@ int ath_beaconq_config(struct ath_softc *sc); | |||
428 | 428 | ||
429 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ | 429 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ |
430 | 430 | ||
431 | void ath_hw_check(struct work_struct *work); | ||
431 | void ath_paprd_calibrate(struct work_struct *work); | 432 | void ath_paprd_calibrate(struct work_struct *work); |
432 | void ath_ani_calibrate(unsigned long data); | 433 | void ath_ani_calibrate(unsigned long data); |
433 | 434 | ||
@@ -562,6 +563,7 @@ struct ath_softc { | |||
562 | spinlock_t sc_pm_lock; | 563 | spinlock_t sc_pm_lock; |
563 | struct mutex mutex; | 564 | struct mutex mutex; |
564 | struct work_struct paprd_work; | 565 | struct work_struct paprd_work; |
566 | struct work_struct hw_check_work; | ||
565 | struct completion paprd_complete; | 567 | struct completion paprd_complete; |
566 | 568 | ||
567 | u32 intrstatus; | 569 | u32 intrstatus; |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 8700e3dc53cf..fe730cb16ec2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -718,6 +718,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | |||
718 | goto error_world; | 718 | goto error_world; |
719 | } | 719 | } |
720 | 720 | ||
721 | INIT_WORK(&sc->hw_check_work, ath_hw_check); | ||
721 | INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); | 722 | INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); |
722 | INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); | 723 | INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); |
723 | INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); | 724 | INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index efbf53534ade..4c0831ff6e92 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -515,6 +515,25 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
515 | ath_tx_node_cleanup(sc, an); | 515 | ath_tx_node_cleanup(sc, an); |
516 | } | 516 | } |
517 | 517 | ||
518 | void ath_hw_check(struct work_struct *work) | ||
519 | { | ||
520 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); | ||
521 | int i; | ||
522 | |||
523 | ath9k_ps_wakeup(sc); | ||
524 | |||
525 | for (i = 0; i < 3; i++) { | ||
526 | if (ath9k_hw_check_alive(sc->sc_ah)) | ||
527 | goto out; | ||
528 | |||
529 | msleep(1); | ||
530 | } | ||
531 | ath_reset(sc, false); | ||
532 | |||
533 | out: | ||
534 | ath9k_ps_restore(sc); | ||
535 | } | ||
536 | |||
518 | void ath9k_tasklet(unsigned long data) | 537 | void ath9k_tasklet(unsigned long data) |
519 | { | 538 | { |
520 | struct ath_softc *sc = (struct ath_softc *)data; | 539 | struct ath_softc *sc = (struct ath_softc *)data; |
@@ -526,13 +545,15 @@ void ath9k_tasklet(unsigned long data) | |||
526 | 545 | ||
527 | ath9k_ps_wakeup(sc); | 546 | ath9k_ps_wakeup(sc); |
528 | 547 | ||
529 | if ((status & ATH9K_INT_FATAL) || | 548 | if (status & ATH9K_INT_FATAL) { |
530 | !ath9k_hw_check_alive(ah)) { | ||
531 | ath_reset(sc, false); | 549 | ath_reset(sc, false); |
532 | ath9k_ps_restore(sc); | 550 | ath9k_ps_restore(sc); |
533 | return; | 551 | return; |
534 | } | 552 | } |
535 | 553 | ||
554 | if (!ath9k_hw_check_alive(ah)) | ||
555 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); | ||
556 | |||
536 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 557 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
537 | rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | | 558 | rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | |
538 | ATH9K_INT_RXORN); | 559 | ATH9K_INT_RXORN); |
@@ -1253,6 +1274,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1253 | 1274 | ||
1254 | cancel_delayed_work_sync(&sc->tx_complete_work); | 1275 | cancel_delayed_work_sync(&sc->tx_complete_work); |
1255 | cancel_work_sync(&sc->paprd_work); | 1276 | cancel_work_sync(&sc->paprd_work); |
1277 | cancel_work_sync(&sc->hw_check_work); | ||
1256 | 1278 | ||
1257 | if (!sc->num_sec_wiphy) { | 1279 | if (!sc->num_sec_wiphy) { |
1258 | cancel_delayed_work_sync(&sc->wiphy_work); | 1280 | cancel_delayed_work_sync(&sc->wiphy_work); |
@@ -1976,6 +1998,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | |||
1976 | sc->sc_flags |= SC_OP_SCANNING; | 1998 | sc->sc_flags |= SC_OP_SCANNING; |
1977 | del_timer_sync(&common->ani.timer); | 1999 | del_timer_sync(&common->ani.timer); |
1978 | cancel_work_sync(&sc->paprd_work); | 2000 | cancel_work_sync(&sc->paprd_work); |
2001 | cancel_work_sync(&sc->hw_check_work); | ||
1979 | cancel_delayed_work_sync(&sc->tx_complete_work); | 2002 | cancel_delayed_work_sync(&sc->tx_complete_work); |
1980 | mutex_unlock(&sc->mutex); | 2003 | mutex_unlock(&sc->mutex); |
1981 | } | 2004 | } |