diff options
author | Vivek Natarajan <vnatarajan@atheros.com> | 2011-01-27 04:15:08 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-28 15:44:28 -0500 |
commit | 181fb18daaf88a20175b0da70024563b0b7c0666 (patch) | |
tree | 2b3c3d8ff01e37880027d25c1b67579bba68e797 | |
parent | b141581923ab4904052174e3b4eb17cc3ce8632c (diff) |
ath9k: Fix a PLL hang issue observed with AR9485.
When this PLL hang issue is seen, both Rx and Tx fail to work.
The sqsum_dvc needs to be below 2000 for a good chip. During
this issue the sqsum_dvc value is beyond 80000 and only a
full reset can solve this problem.
Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 23 |
3 files changed, 27 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 73db9576af57..a23e9a884693 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -641,6 +641,7 @@ struct ath_softc { | |||
641 | #endif | 641 | #endif |
642 | struct ath_beacon_config cur_beacon_conf; | 642 | struct ath_beacon_config cur_beacon_conf; |
643 | struct delayed_work tx_complete_work; | 643 | struct delayed_work tx_complete_work; |
644 | struct delayed_work hw_pll_work; | ||
644 | struct ath_btcoex btcoex; | 645 | struct ath_btcoex btcoex; |
645 | 646 | ||
646 | struct ath_descdma txsdma; | 647 | struct ath_descdma txsdma; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 23c016a81bcf..0663a32d81d2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -230,6 +230,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
230 | cancel_work_sync(&sc->paprd_work); | 230 | cancel_work_sync(&sc->paprd_work); |
231 | cancel_work_sync(&sc->hw_check_work); | 231 | cancel_work_sync(&sc->hw_check_work); |
232 | cancel_delayed_work_sync(&sc->tx_complete_work); | 232 | cancel_delayed_work_sync(&sc->tx_complete_work); |
233 | cancel_delayed_work_sync(&sc->hw_pll_work); | ||
233 | 234 | ||
234 | ath9k_ps_wakeup(sc); | 235 | ath9k_ps_wakeup(sc); |
235 | 236 | ||
@@ -290,6 +291,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
290 | if (sc->sc_flags & SC_OP_BEACONS) | 291 | if (sc->sc_flags & SC_OP_BEACONS) |
291 | ath_beacon_config(sc, NULL); | 292 | ath_beacon_config(sc, NULL); |
292 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 293 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); |
294 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); | ||
293 | ath_start_ani(common); | 295 | ath_start_ani(common); |
294 | } | 296 | } |
295 | 297 | ||
@@ -1263,6 +1265,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1263 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | 1265 | cancel_delayed_work_sync(&sc->ath_led_blink_work); |
1264 | 1266 | ||
1265 | cancel_delayed_work_sync(&sc->tx_complete_work); | 1267 | cancel_delayed_work_sync(&sc->tx_complete_work); |
1268 | cancel_delayed_work_sync(&sc->hw_pll_work); | ||
1266 | cancel_work_sync(&sc->paprd_work); | 1269 | cancel_work_sync(&sc->paprd_work); |
1267 | cancel_work_sync(&sc->hw_check_work); | 1270 | cancel_work_sync(&sc->hw_check_work); |
1268 | 1271 | ||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 879365e9b1c9..10a3dbefaa09 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -2091,6 +2091,28 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2091 | } | 2091 | } |
2092 | } | 2092 | } |
2093 | 2093 | ||
2094 | static void ath_hw_pll_work(struct work_struct *work) | ||
2095 | { | ||
2096 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
2097 | hw_pll_work.work); | ||
2098 | static int count; | ||
2099 | |||
2100 | if (AR_SREV_9485(sc->sc_ah)) { | ||
2101 | if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { | ||
2102 | count++; | ||
2103 | |||
2104 | if (count == 3) { | ||
2105 | /* Rx is hung for more than 500ms. Reset it */ | ||
2106 | ath_reset(sc, true); | ||
2107 | count = 0; | ||
2108 | } | ||
2109 | } else | ||
2110 | count = 0; | ||
2111 | |||
2112 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); | ||
2113 | } | ||
2114 | } | ||
2115 | |||
2094 | static void ath_tx_complete_poll_work(struct work_struct *work) | 2116 | static void ath_tx_complete_poll_work(struct work_struct *work) |
2095 | { | 2117 | { |
2096 | struct ath_softc *sc = container_of(work, struct ath_softc, | 2118 | struct ath_softc *sc = container_of(work, struct ath_softc, |
@@ -2312,6 +2334,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) | |||
2312 | } | 2334 | } |
2313 | 2335 | ||
2314 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); | 2336 | INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); |
2337 | INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); | ||
2315 | 2338 | ||
2316 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { | 2339 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { |
2317 | error = ath_tx_edma_init(sc); | 2340 | error = ath_tx_edma_init(sc); |