aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorVivek Natarajan <vnatarajan@atheros.com>2011-01-27 04:15:08 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-28 15:44:28 -0500
commit181fb18daaf88a20175b0da70024563b0b7c0666 (patch)
tree2b3c3d8ff01e37880027d25c1b67579bba68e797 /drivers/net
parentb141581923ab4904052174e3b4eb17cc3ce8632c (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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c23
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
2094static 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
2094static void ath_tx_complete_poll_work(struct work_struct *work) 2116static 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);