diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-07-01 21:41:40 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-07-01 21:41:40 +0000 |
commit | 7d977508b0fb947e23d5092ec31daf5c2e35592e (patch) | |
tree | ec37bdc1de885430066a33d6d435a7fe1ec1609a | |
parent | c500f2eeb22154292f6df5f2132e94d9d32e566f (diff) |
ath9k: fix false positives in the baseband hang check by repeating the test a few times before pronouncing the hardware dead and resetting it
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22038 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r-- | package/mac80211/patches/540-ath9k_hang_check.patch | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/package/mac80211/patches/540-ath9k_hang_check.patch b/package/mac80211/patches/540-ath9k_hang_check.patch new file mode 100644 index 0000000000..85e03bc98c --- /dev/null +++ b/package/mac80211/patches/540-ath9k_hang_check.patch @@ -0,0 +1,90 @@ +--- 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 + + #define ATH_PAPRD_TIMEOUT 100 /* msecs */ + ++void ath_hw_check(struct work_struct *work); + void ath_paprd_calibrate(struct work_struct *work); + void ath_ani_calibrate(unsigned long data); + +@@ -563,6 +564,7 @@ struct ath_softc { + spinlock_t sc_pm_lock; + struct mutex mutex; + struct work_struct paprd_work; ++ struct work_struct hw_check_work; + struct completion paprd_complete; + + u32 intrstatus; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -516,6 +516,25 @@ static void ath_node_detach(struct ath_s + ath_tx_node_cleanup(sc, an); + } + ++void ath_hw_check(struct work_struct *work) ++{ ++ struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); ++ int i; ++ ++ ath9k_ps_wakeup(sc); ++ ++ for (i = 0; i < 3; i++) { ++ if (ath9k_hw_check_alive(sc->sc_ah)) ++ goto out; ++ ++ msleep(1); ++ } ++ ath_reset(sc, false); ++ ++out: ++ ath9k_ps_restore(sc); ++} ++ + void ath9k_tasklet(unsigned long data) + { + struct ath_softc *sc = (struct ath_softc *)data; +@@ -527,13 +546,15 @@ void ath9k_tasklet(unsigned long data) + + ath9k_ps_wakeup(sc); + +- if ((status & ATH9K_INT_FATAL) || +- !ath9k_hw_check_alive(ah)) { ++ if (status & ATH9K_INT_FATAL) { + ath_reset(sc, false); + ath9k_ps_restore(sc); + return; + } + ++ if (!ath9k_hw_check_alive(ah)) ++ ieee80211_queue_work(sc->hw, &sc->hw_check_work); ++ + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | + ATH9K_INT_RXORN); +@@ -1254,6 +1275,7 @@ static void ath9k_stop(struct ieee80211_ + + cancel_delayed_work_sync(&sc->tx_complete_work); + cancel_work_sync(&sc->paprd_work); ++ cancel_work_sync(&sc->hw_check_work); + + if (!sc->num_sec_wiphy) { + cancel_delayed_work_sync(&sc->wiphy_work); +@@ -1977,6 +1999,7 @@ static void ath9k_sw_scan_start(struct i + sc->sc_flags |= SC_OP_SCANNING; + del_timer_sync(&common->ani.timer); + cancel_work_sync(&sc->paprd_work); ++ cancel_work_sync(&sc->hw_check_work); + cancel_delayed_work_sync(&sc->tx_complete_work); + mutex_unlock(&sc->mutex); + } +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -751,6 +751,7 @@ int ath9k_init_device(u16 devid, struct + goto error_world; + } + ++ INIT_WORK(&sc->hw_check_work, ath_hw_check); + INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); + INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); |