aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-07-01 18:09:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-07-02 13:44:38 -0400
commit347809fc2c99da5b89f1c014f3e5a0f85c04803c (patch)
tree6bacea4f51a2ab8711deaea1ee4eecc213ff39ca
parent54bd5006b03ee980f6067b4d61c3605b5a5e1d4a (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.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c27
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
431void ath_hw_check(struct work_struct *work);
431void ath_paprd_calibrate(struct work_struct *work); 432void ath_paprd_calibrate(struct work_struct *work);
432void ath_ani_calibrate(unsigned long data); 433void 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
518void 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
533out:
534 ath9k_ps_restore(sc);
535}
536
518void ath9k_tasklet(unsigned long data) 537void 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}