diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2012-06-04 10:53:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-06-06 15:20:30 -0400 |
commit | af68abadac378f7a4a44fe766383e7b88c7f9c3b (patch) | |
tree | bad7c43d612dfc187dda5be0bf2c4be4c252d1de | |
parent | ef1b6cd9a1ba06a3daf9a03aa8f25d52d1f2c31a (diff) |
ath9k: Fix work handling
* Currently, there is no synchronization between the reset
work and the tx-poll work. Fix this and make sure that we
bail out properly if a reset work is in progress.
* Cleanup the PLL WAR and enable it for AR9340 too and
use a helper for restarting work/timers after a reset.
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.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/link.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 22 |
3 files changed, 37 insertions, 19 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index d804416092ce..2faa181d8fcf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -431,6 +431,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); | |||
431 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ | 431 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ |
432 | 432 | ||
433 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ | 433 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ |
434 | #define ATH_PLL_WORK_INTERVAL 100 | ||
434 | 435 | ||
435 | void ath_tx_complete_poll_work(struct work_struct *work); | 436 | void ath_tx_complete_poll_work(struct work_struct *work); |
436 | void ath_reset_work(struct work_struct *work); | 437 | void ath_reset_work(struct work_struct *work); |
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 7368b9630b99..89b38a9ab7c5 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c | |||
@@ -52,6 +52,7 @@ void ath_tx_complete_poll_work(struct work_struct *work) | |||
52 | "tx hung, resetting the chip\n"); | 52 | "tx hung, resetting the chip\n"); |
53 | RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); | 53 | RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); |
54 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | 54 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
55 | return; | ||
55 | } | 56 | } |
56 | 57 | ||
57 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, | 58 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, |
@@ -107,9 +108,9 @@ out: | |||
107 | } | 108 | } |
108 | 109 | ||
109 | /* | 110 | /* |
110 | * PLL-WAR for AR9485. | 111 | * PLL-WAR for AR9485/AR9340 |
111 | */ | 112 | */ |
112 | static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) | 113 | static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) |
113 | { | 114 | { |
114 | static int count; | 115 | static int count; |
115 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 116 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
@@ -117,29 +118,33 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) | |||
117 | if (pll_sqsum >= 0x40000) { | 118 | if (pll_sqsum >= 0x40000) { |
118 | count++; | 119 | count++; |
119 | if (count == 3) { | 120 | if (count == 3) { |
120 | /* Rx is hung for more than 500ms. Reset it */ | 121 | ath_dbg(common, RESET, "PLL WAR, resetting the chip\n"); |
121 | ath_dbg(common, RESET, "Possible RX hang, resetting\n"); | ||
122 | RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); | 122 | RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); |
123 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | 123 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); |
124 | count = 0; | 124 | count = 0; |
125 | return true; | ||
125 | } | 126 | } |
126 | } else | 127 | } else { |
127 | count = 0; | 128 | count = 0; |
129 | } | ||
130 | |||
131 | return false; | ||
128 | } | 132 | } |
129 | 133 | ||
130 | void ath_hw_pll_work(struct work_struct *work) | 134 | void ath_hw_pll_work(struct work_struct *work) |
131 | { | 135 | { |
136 | u32 pll_sqsum; | ||
132 | struct ath_softc *sc = container_of(work, struct ath_softc, | 137 | struct ath_softc *sc = container_of(work, struct ath_softc, |
133 | hw_pll_work.work); | 138 | hw_pll_work.work); |
134 | u32 pll_sqsum; | ||
135 | 139 | ||
136 | if (AR_SREV_9485(sc->sc_ah)) { | 140 | ath9k_ps_wakeup(sc); |
137 | ath9k_ps_wakeup(sc); | 141 | pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); |
138 | pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); | 142 | ath9k_ps_restore(sc); |
139 | ath9k_ps_restore(sc); | 143 | if (ath_hw_pll_rx_hang_check(sc, pll_sqsum)) |
140 | ath_hw_pll_rx_hang_check(sc, pll_sqsum); | 144 | return; |
141 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); | 145 | |
142 | } | 146 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, |
147 | msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); | ||
143 | } | 148 | } |
144 | 149 | ||
145 | /* | 150 | /* |
@@ -293,7 +298,7 @@ void ath_paprd_calibrate(struct work_struct *work) | |||
293 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { | 298 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { |
294 | ath_dbg(common, CALIBRATE, | 299 | ath_dbg(common, CALIBRATE, |
295 | "PAPRD create curve failed on chain %d\n", | 300 | "PAPRD create curve failed on chain %d\n", |
296 | chain); | 301 | chain); |
297 | break; | 302 | break; |
298 | } | 303 | } |
299 | 304 | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 304769a3e179..b228aff481e1 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -158,6 +158,22 @@ static void ath_cancel_work(struct ath_softc *sc) | |||
158 | cancel_work_sync(&sc->hw_reset_work); | 158 | cancel_work_sync(&sc->hw_reset_work); |
159 | } | 159 | } |
160 | 160 | ||
161 | static void ath_restart_work(struct ath_softc *sc) | ||
162 | { | ||
163 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
164 | |||
165 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | ||
166 | |||
167 | if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah)) | ||
168 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, | ||
169 | msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); | ||
170 | |||
171 | ath_start_rx_poll(sc, 3); | ||
172 | |||
173 | if (!common->disable_ani) | ||
174 | ath_start_ani(common); | ||
175 | } | ||
176 | |||
161 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | 177 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) |
162 | { | 178 | { |
163 | struct ath_hw *ah = sc->sc_ah; | 179 | struct ath_hw *ah = sc->sc_ah; |
@@ -209,11 +225,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
209 | if (sc->sc_flags & SC_OP_BEACONS) | 225 | if (sc->sc_flags & SC_OP_BEACONS) |
210 | ath_set_beacon(sc); | 226 | ath_set_beacon(sc); |
211 | 227 | ||
212 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 228 | ath_restart_work(sc); |
213 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); | ||
214 | ath_start_rx_poll(sc, 3); | ||
215 | if (!common->disable_ani) | ||
216 | ath_start_ani(common); | ||
217 | } | 229 | } |
218 | 230 | ||
219 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { | 231 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { |