diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2012-06-04 10:53:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-06-06 15:20:30 -0400 |
commit | ef1b6cd9a1ba06a3daf9a03aa8f25d52d1f2c31a (patch) | |
tree | b7257ad0dcbfee66cd02f496238c755e6e281088 /drivers/net | |
parent | 6995fb805ed5de852a7d49413730980bc7173e82 (diff) |
ath9k: Group link monitoring logic
Add link.c and move all the link/connection monitoring
code to it.
Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/link.c | 497 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 431 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 46 |
5 files changed, 511 insertions, 479 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 3f0b84723789..4d60fa84cbb4 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -3,7 +3,8 @@ ath9k-y += beacon.o \ | |||
3 | init.o \ | 3 | init.o \ |
4 | main.o \ | 4 | main.o \ |
5 | recv.o \ | 5 | recv.o \ |
6 | xmit.o | 6 | xmit.o \ |
7 | link.o | ||
7 | 8 | ||
8 | ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o | 9 | ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o |
9 | ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o | 10 | ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ce10d1a9e493..d804416092ce 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -326,6 +326,9 @@ int ath_rx_init(struct ath_softc *sc, int nbufs); | |||
326 | void ath_rx_cleanup(struct ath_softc *sc); | 326 | void ath_rx_cleanup(struct ath_softc *sc); |
327 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); | 327 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); |
328 | struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); | 328 | struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); |
329 | void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq); | ||
330 | void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq); | ||
331 | void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq); | ||
329 | void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); | 332 | void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); |
330 | bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); | 333 | bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); |
331 | void ath_draintxq(struct ath_softc *sc, | 334 | void ath_draintxq(struct ath_softc *sc, |
@@ -415,9 +418,9 @@ int ath_beaconq_config(struct ath_softc *sc); | |||
415 | void ath_set_beacon(struct ath_softc *sc); | 418 | void ath_set_beacon(struct ath_softc *sc); |
416 | void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); | 419 | void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); |
417 | 420 | ||
418 | /*******/ | 421 | /*******************/ |
419 | /* ANI */ | 422 | /* Link Monitoring */ |
420 | /*******/ | 423 | /*******************/ |
421 | 424 | ||
422 | #define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ | 425 | #define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ |
423 | #define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ | 426 | #define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ |
@@ -429,6 +432,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); | |||
429 | 432 | ||
430 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ | 433 | #define ATH_PAPRD_TIMEOUT 100 /* msecs */ |
431 | 434 | ||
435 | void ath_tx_complete_poll_work(struct work_struct *work); | ||
432 | void ath_reset_work(struct work_struct *work); | 436 | void ath_reset_work(struct work_struct *work); |
433 | void ath_hw_check(struct work_struct *work); | 437 | void ath_hw_check(struct work_struct *work); |
434 | void ath_hw_pll_work(struct work_struct *work); | 438 | void ath_hw_pll_work(struct work_struct *work); |
@@ -437,6 +441,8 @@ void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon); | |||
437 | void ath_paprd_calibrate(struct work_struct *work); | 441 | void ath_paprd_calibrate(struct work_struct *work); |
438 | void ath_ani_calibrate(unsigned long data); | 442 | void ath_ani_calibrate(unsigned long data); |
439 | void ath_start_ani(struct ath_common *common); | 443 | void ath_start_ani(struct ath_common *common); |
444 | int ath_update_survey_stats(struct ath_softc *sc); | ||
445 | void ath_update_survey_nf(struct ath_softc *sc, int channel); | ||
440 | 446 | ||
441 | /**********/ | 447 | /**********/ |
442 | /* BTCOEX */ | 448 | /* BTCOEX */ |
@@ -741,5 +747,4 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | |||
741 | struct ieee80211_vif *vif, | 747 | struct ieee80211_vif *vif, |
742 | struct ath9k_vif_iter_data *iter_data); | 748 | struct ath9k_vif_iter_data *iter_data); |
743 | 749 | ||
744 | |||
745 | #endif /* ATH9K_H */ | 750 | #endif /* ATH9K_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c new file mode 100644 index 000000000000..7368b9630b99 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/link.c | |||
@@ -0,0 +1,497 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Qualcomm Atheros, Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | /* | ||
20 | * TX polling - checks if the TX engine is stuck somewhere | ||
21 | * and issues a chip reset if so. | ||
22 | */ | ||
23 | void ath_tx_complete_poll_work(struct work_struct *work) | ||
24 | { | ||
25 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
26 | tx_complete_work.work); | ||
27 | struct ath_txq *txq; | ||
28 | int i; | ||
29 | bool needreset = false; | ||
30 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
31 | sc->tx_complete_poll_work_seen++; | ||
32 | #endif | ||
33 | |||
34 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
35 | if (ATH_TXQ_SETUP(sc, i)) { | ||
36 | txq = &sc->tx.txq[i]; | ||
37 | ath_txq_lock(sc, txq); | ||
38 | if (txq->axq_depth) { | ||
39 | if (txq->axq_tx_inprogress) { | ||
40 | needreset = true; | ||
41 | ath_txq_unlock(sc, txq); | ||
42 | break; | ||
43 | } else { | ||
44 | txq->axq_tx_inprogress = true; | ||
45 | } | ||
46 | } | ||
47 | ath_txq_unlock_complete(sc, txq); | ||
48 | } | ||
49 | |||
50 | if (needreset) { | ||
51 | ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, | ||
52 | "tx hung, resetting the chip\n"); | ||
53 | RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); | ||
54 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
55 | } | ||
56 | |||
57 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, | ||
58 | msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * Checks if the BB/MAC is hung. | ||
63 | */ | ||
64 | void ath_hw_check(struct work_struct *work) | ||
65 | { | ||
66 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); | ||
67 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
68 | unsigned long flags; | ||
69 | int busy; | ||
70 | u8 is_alive, nbeacon = 1; | ||
71 | |||
72 | ath9k_ps_wakeup(sc); | ||
73 | is_alive = ath9k_hw_check_alive(sc->sc_ah); | ||
74 | |||
75 | if (is_alive && !AR_SREV_9300(sc->sc_ah)) | ||
76 | goto out; | ||
77 | else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { | ||
78 | ath_dbg(common, RESET, | ||
79 | "DCU stuck is detected. Schedule chip reset\n"); | ||
80 | RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG); | ||
81 | goto sched_reset; | ||
82 | } | ||
83 | |||
84 | spin_lock_irqsave(&common->cc_lock, flags); | ||
85 | busy = ath_update_survey_stats(sc); | ||
86 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
87 | |||
88 | ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", | ||
89 | busy, sc->hw_busy_count + 1); | ||
90 | if (busy >= 99) { | ||
91 | if (++sc->hw_busy_count >= 3) { | ||
92 | RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); | ||
93 | goto sched_reset; | ||
94 | } | ||
95 | } else if (busy >= 0) { | ||
96 | sc->hw_busy_count = 0; | ||
97 | nbeacon = 3; | ||
98 | } | ||
99 | |||
100 | ath_start_rx_poll(sc, nbeacon); | ||
101 | goto out; | ||
102 | |||
103 | sched_reset: | ||
104 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
105 | out: | ||
106 | ath9k_ps_restore(sc); | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * PLL-WAR for AR9485. | ||
111 | */ | ||
112 | static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) | ||
113 | { | ||
114 | static int count; | ||
115 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
116 | |||
117 | if (pll_sqsum >= 0x40000) { | ||
118 | count++; | ||
119 | if (count == 3) { | ||
120 | /* Rx is hung for more than 500ms. Reset it */ | ||
121 | ath_dbg(common, RESET, "Possible RX hang, resetting\n"); | ||
122 | RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); | ||
123 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
124 | count = 0; | ||
125 | } | ||
126 | } else | ||
127 | count = 0; | ||
128 | } | ||
129 | |||
130 | void ath_hw_pll_work(struct work_struct *work) | ||
131 | { | ||
132 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
133 | hw_pll_work.work); | ||
134 | u32 pll_sqsum; | ||
135 | |||
136 | if (AR_SREV_9485(sc->sc_ah)) { | ||
137 | ath9k_ps_wakeup(sc); | ||
138 | pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); | ||
139 | ath9k_ps_restore(sc); | ||
140 | ath_hw_pll_rx_hang_check(sc, pll_sqsum); | ||
141 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * RX Polling - monitors baseband hangs. | ||
147 | */ | ||
148 | void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon) | ||
149 | { | ||
150 | if (!AR_SREV_9300(sc->sc_ah)) | ||
151 | return; | ||
152 | |||
153 | if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) | ||
154 | return; | ||
155 | |||
156 | mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies | ||
157 | (nbeacon * sc->cur_beacon_conf.beacon_interval)); | ||
158 | } | ||
159 | |||
160 | void ath_rx_poll(unsigned long data) | ||
161 | { | ||
162 | struct ath_softc *sc = (struct ath_softc *)data; | ||
163 | |||
164 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * PA Pre-distortion. | ||
169 | */ | ||
170 | static void ath_paprd_activate(struct ath_softc *sc) | ||
171 | { | ||
172 | struct ath_hw *ah = sc->sc_ah; | ||
173 | struct ath9k_hw_cal_data *caldata = ah->caldata; | ||
174 | int chain; | ||
175 | |||
176 | if (!caldata || !caldata->paprd_done) | ||
177 | return; | ||
178 | |||
179 | ath9k_ps_wakeup(sc); | ||
180 | ar9003_paprd_enable(ah, false); | ||
181 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | ||
182 | if (!(ah->txchainmask & BIT(chain))) | ||
183 | continue; | ||
184 | |||
185 | ar9003_paprd_populate_single_table(ah, caldata, chain); | ||
186 | } | ||
187 | |||
188 | ar9003_paprd_enable(ah, true); | ||
189 | ath9k_ps_restore(sc); | ||
190 | } | ||
191 | |||
192 | static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain) | ||
193 | { | ||
194 | struct ieee80211_hw *hw = sc->hw; | ||
195 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
196 | struct ath_hw *ah = sc->sc_ah; | ||
197 | struct ath_common *common = ath9k_hw_common(ah); | ||
198 | struct ath_tx_control txctl; | ||
199 | int time_left; | ||
200 | |||
201 | memset(&txctl, 0, sizeof(txctl)); | ||
202 | txctl.txq = sc->tx.txq_map[WME_AC_BE]; | ||
203 | |||
204 | memset(tx_info, 0, sizeof(*tx_info)); | ||
205 | tx_info->band = hw->conf.channel->band; | ||
206 | tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
207 | tx_info->control.rates[0].idx = 0; | ||
208 | tx_info->control.rates[0].count = 1; | ||
209 | tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | ||
210 | tx_info->control.rates[1].idx = -1; | ||
211 | |||
212 | init_completion(&sc->paprd_complete); | ||
213 | txctl.paprd = BIT(chain); | ||
214 | |||
215 | if (ath_tx_start(hw, skb, &txctl) != 0) { | ||
216 | ath_dbg(common, CALIBRATE, "PAPRD TX failed\n"); | ||
217 | dev_kfree_skb_any(skb); | ||
218 | return false; | ||
219 | } | ||
220 | |||
221 | time_left = wait_for_completion_timeout(&sc->paprd_complete, | ||
222 | msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); | ||
223 | |||
224 | if (!time_left) | ||
225 | ath_dbg(common, CALIBRATE, | ||
226 | "Timeout waiting for paprd training on TX chain %d\n", | ||
227 | chain); | ||
228 | |||
229 | return !!time_left; | ||
230 | } | ||
231 | |||
232 | void ath_paprd_calibrate(struct work_struct *work) | ||
233 | { | ||
234 | struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work); | ||
235 | struct ieee80211_hw *hw = sc->hw; | ||
236 | struct ath_hw *ah = sc->sc_ah; | ||
237 | struct ieee80211_hdr *hdr; | ||
238 | struct sk_buff *skb = NULL; | ||
239 | struct ath9k_hw_cal_data *caldata = ah->caldata; | ||
240 | struct ath_common *common = ath9k_hw_common(ah); | ||
241 | int ftype; | ||
242 | int chain_ok = 0; | ||
243 | int chain; | ||
244 | int len = 1800; | ||
245 | |||
246 | if (!caldata) | ||
247 | return; | ||
248 | |||
249 | ath9k_ps_wakeup(sc); | ||
250 | |||
251 | if (ar9003_paprd_init_table(ah) < 0) | ||
252 | goto fail_paprd; | ||
253 | |||
254 | skb = alloc_skb(len, GFP_KERNEL); | ||
255 | if (!skb) | ||
256 | goto fail_paprd; | ||
257 | |||
258 | skb_put(skb, len); | ||
259 | memset(skb->data, 0, len); | ||
260 | hdr = (struct ieee80211_hdr *)skb->data; | ||
261 | ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC; | ||
262 | hdr->frame_control = cpu_to_le16(ftype); | ||
263 | hdr->duration_id = cpu_to_le16(10); | ||
264 | memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); | ||
265 | memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); | ||
266 | memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); | ||
267 | |||
268 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | ||
269 | if (!(ah->txchainmask & BIT(chain))) | ||
270 | continue; | ||
271 | |||
272 | chain_ok = 0; | ||
273 | |||
274 | ath_dbg(common, CALIBRATE, | ||
275 | "Sending PAPRD frame for thermal measurement on chain %d\n", | ||
276 | chain); | ||
277 | if (!ath_paprd_send_frame(sc, skb, chain)) | ||
278 | goto fail_paprd; | ||
279 | |||
280 | ar9003_paprd_setup_gain_table(ah, chain); | ||
281 | |||
282 | ath_dbg(common, CALIBRATE, | ||
283 | "Sending PAPRD training frame on chain %d\n", chain); | ||
284 | if (!ath_paprd_send_frame(sc, skb, chain)) | ||
285 | goto fail_paprd; | ||
286 | |||
287 | if (!ar9003_paprd_is_done(ah)) { | ||
288 | ath_dbg(common, CALIBRATE, | ||
289 | "PAPRD not yet done on chain %d\n", chain); | ||
290 | break; | ||
291 | } | ||
292 | |||
293 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { | ||
294 | ath_dbg(common, CALIBRATE, | ||
295 | "PAPRD create curve failed on chain %d\n", | ||
296 | chain); | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | chain_ok = 1; | ||
301 | } | ||
302 | kfree_skb(skb); | ||
303 | |||
304 | if (chain_ok) { | ||
305 | caldata->paprd_done = true; | ||
306 | ath_paprd_activate(sc); | ||
307 | } | ||
308 | |||
309 | fail_paprd: | ||
310 | ath9k_ps_restore(sc); | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * ANI performs periodic noise floor calibration | ||
315 | * that is used to adjust and optimize the chip performance. This | ||
316 | * takes environmental changes (location, temperature) into account. | ||
317 | * When the task is complete, it reschedules itself depending on the | ||
318 | * appropriate interval that was calculated. | ||
319 | */ | ||
320 | void ath_ani_calibrate(unsigned long data) | ||
321 | { | ||
322 | struct ath_softc *sc = (struct ath_softc *)data; | ||
323 | struct ath_hw *ah = sc->sc_ah; | ||
324 | struct ath_common *common = ath9k_hw_common(ah); | ||
325 | bool longcal = false; | ||
326 | bool shortcal = false; | ||
327 | bool aniflag = false; | ||
328 | unsigned int timestamp = jiffies_to_msecs(jiffies); | ||
329 | u32 cal_interval, short_cal_interval, long_cal_interval; | ||
330 | unsigned long flags; | ||
331 | |||
332 | if (ah->caldata && ah->caldata->nfcal_interference) | ||
333 | long_cal_interval = ATH_LONG_CALINTERVAL_INT; | ||
334 | else | ||
335 | long_cal_interval = ATH_LONG_CALINTERVAL; | ||
336 | |||
337 | short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? | ||
338 | ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; | ||
339 | |||
340 | /* Only calibrate if awake */ | ||
341 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) | ||
342 | goto set_timer; | ||
343 | |||
344 | ath9k_ps_wakeup(sc); | ||
345 | |||
346 | /* Long calibration runs independently of short calibration. */ | ||
347 | if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { | ||
348 | longcal = true; | ||
349 | common->ani.longcal_timer = timestamp; | ||
350 | } | ||
351 | |||
352 | /* Short calibration applies only while caldone is false */ | ||
353 | if (!common->ani.caldone) { | ||
354 | if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { | ||
355 | shortcal = true; | ||
356 | common->ani.shortcal_timer = timestamp; | ||
357 | common->ani.resetcal_timer = timestamp; | ||
358 | } | ||
359 | } else { | ||
360 | if ((timestamp - common->ani.resetcal_timer) >= | ||
361 | ATH_RESTART_CALINTERVAL) { | ||
362 | common->ani.caldone = ath9k_hw_reset_calvalid(ah); | ||
363 | if (common->ani.caldone) | ||
364 | common->ani.resetcal_timer = timestamp; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | /* Verify whether we must check ANI */ | ||
369 | if (sc->sc_ah->config.enable_ani | ||
370 | && (timestamp - common->ani.checkani_timer) >= | ||
371 | ah->config.ani_poll_interval) { | ||
372 | aniflag = true; | ||
373 | common->ani.checkani_timer = timestamp; | ||
374 | } | ||
375 | |||
376 | /* Call ANI routine if necessary */ | ||
377 | if (aniflag) { | ||
378 | spin_lock_irqsave(&common->cc_lock, flags); | ||
379 | ath9k_hw_ani_monitor(ah, ah->curchan); | ||
380 | ath_update_survey_stats(sc); | ||
381 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
382 | } | ||
383 | |||
384 | /* Perform calibration if necessary */ | ||
385 | if (longcal || shortcal) { | ||
386 | common->ani.caldone = | ||
387 | ath9k_hw_calibrate(ah, ah->curchan, | ||
388 | ah->rxchainmask, longcal); | ||
389 | } | ||
390 | |||
391 | ath_dbg(common, ANI, | ||
392 | "Calibration @%lu finished: %s %s %s, caldone: %s\n", | ||
393 | jiffies, | ||
394 | longcal ? "long" : "", shortcal ? "short" : "", | ||
395 | aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); | ||
396 | |||
397 | ath9k_ps_restore(sc); | ||
398 | |||
399 | set_timer: | ||
400 | /* | ||
401 | * Set timer interval based on previous results. | ||
402 | * The interval must be the shortest necessary to satisfy ANI, | ||
403 | * short calibration and long calibration. | ||
404 | */ | ||
405 | ath9k_debug_samp_bb_mac(sc); | ||
406 | cal_interval = ATH_LONG_CALINTERVAL; | ||
407 | if (sc->sc_ah->config.enable_ani) | ||
408 | cal_interval = min(cal_interval, | ||
409 | (u32)ah->config.ani_poll_interval); | ||
410 | if (!common->ani.caldone) | ||
411 | cal_interval = min(cal_interval, (u32)short_cal_interval); | ||
412 | |||
413 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | ||
414 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) { | ||
415 | if (!ah->caldata->paprd_done) | ||
416 | ieee80211_queue_work(sc->hw, &sc->paprd_work); | ||
417 | else if (!ah->paprd_table_write_done) | ||
418 | ath_paprd_activate(sc); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | void ath_start_ani(struct ath_common *common) | ||
423 | { | ||
424 | struct ath_hw *ah = common->ah; | ||
425 | unsigned long timestamp = jiffies_to_msecs(jiffies); | ||
426 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
427 | |||
428 | if (!(sc->sc_flags & SC_OP_ANI_RUN)) | ||
429 | return; | ||
430 | |||
431 | if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) | ||
432 | return; | ||
433 | |||
434 | common->ani.longcal_timer = timestamp; | ||
435 | common->ani.shortcal_timer = timestamp; | ||
436 | common->ani.checkani_timer = timestamp; | ||
437 | |||
438 | mod_timer(&common->ani.timer, | ||
439 | jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval)); | ||
440 | } | ||
441 | |||
442 | void ath_update_survey_nf(struct ath_softc *sc, int channel) | ||
443 | { | ||
444 | struct ath_hw *ah = sc->sc_ah; | ||
445 | struct ath9k_channel *chan = &ah->channels[channel]; | ||
446 | struct survey_info *survey = &sc->survey[channel]; | ||
447 | |||
448 | if (chan->noisefloor) { | ||
449 | survey->filled |= SURVEY_INFO_NOISE_DBM; | ||
450 | survey->noise = ath9k_hw_getchan_noise(ah, chan); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * Updates the survey statistics and returns the busy time since last | ||
456 | * update in %, if the measurement duration was long enough for the | ||
457 | * result to be useful, -1 otherwise. | ||
458 | */ | ||
459 | int ath_update_survey_stats(struct ath_softc *sc) | ||
460 | { | ||
461 | struct ath_hw *ah = sc->sc_ah; | ||
462 | struct ath_common *common = ath9k_hw_common(ah); | ||
463 | int pos = ah->curchan - &ah->channels[0]; | ||
464 | struct survey_info *survey = &sc->survey[pos]; | ||
465 | struct ath_cycle_counters *cc = &common->cc_survey; | ||
466 | unsigned int div = common->clockrate * 1000; | ||
467 | int ret = 0; | ||
468 | |||
469 | if (!ah->curchan) | ||
470 | return -1; | ||
471 | |||
472 | if (ah->power_mode == ATH9K_PM_AWAKE) | ||
473 | ath_hw_cycle_counters_update(common); | ||
474 | |||
475 | if (cc->cycles > 0) { | ||
476 | survey->filled |= SURVEY_INFO_CHANNEL_TIME | | ||
477 | SURVEY_INFO_CHANNEL_TIME_BUSY | | ||
478 | SURVEY_INFO_CHANNEL_TIME_RX | | ||
479 | SURVEY_INFO_CHANNEL_TIME_TX; | ||
480 | survey->channel_time += cc->cycles / div; | ||
481 | survey->channel_time_busy += cc->rx_busy / div; | ||
482 | survey->channel_time_rx += cc->rx_frame / div; | ||
483 | survey->channel_time_tx += cc->tx_frame / div; | ||
484 | } | ||
485 | |||
486 | if (cc->cycles < div) | ||
487 | return -1; | ||
488 | |||
489 | if (cc->cycles > 0) | ||
490 | ret = cc->rx_busy * 100 / cc->cycles; | ||
491 | |||
492 | memset(cc, 0, sizeof(*cc)); | ||
493 | |||
494 | ath_update_survey_nf(sc, pos); | ||
495 | |||
496 | return ret; | ||
497 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 623b04f63fe4..304769a3e179 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -144,84 +144,6 @@ void ath9k_ps_restore(struct ath_softc *sc) | |||
144 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | 144 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
145 | } | 145 | } |
146 | 146 | ||
147 | void ath_start_ani(struct ath_common *common) | ||
148 | { | ||
149 | struct ath_hw *ah = common->ah; | ||
150 | unsigned long timestamp = jiffies_to_msecs(jiffies); | ||
151 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
152 | |||
153 | if (!(sc->sc_flags & SC_OP_ANI_RUN)) | ||
154 | return; | ||
155 | |||
156 | if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) | ||
157 | return; | ||
158 | |||
159 | common->ani.longcal_timer = timestamp; | ||
160 | common->ani.shortcal_timer = timestamp; | ||
161 | common->ani.checkani_timer = timestamp; | ||
162 | |||
163 | mod_timer(&common->ani.timer, | ||
164 | jiffies + | ||
165 | msecs_to_jiffies((u32)ah->config.ani_poll_interval)); | ||
166 | } | ||
167 | |||
168 | static void ath_update_survey_nf(struct ath_softc *sc, int channel) | ||
169 | { | ||
170 | struct ath_hw *ah = sc->sc_ah; | ||
171 | struct ath9k_channel *chan = &ah->channels[channel]; | ||
172 | struct survey_info *survey = &sc->survey[channel]; | ||
173 | |||
174 | if (chan->noisefloor) { | ||
175 | survey->filled |= SURVEY_INFO_NOISE_DBM; | ||
176 | survey->noise = ath9k_hw_getchan_noise(ah, chan); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Updates the survey statistics and returns the busy time since last | ||
182 | * update in %, if the measurement duration was long enough for the | ||
183 | * result to be useful, -1 otherwise. | ||
184 | */ | ||
185 | static int ath_update_survey_stats(struct ath_softc *sc) | ||
186 | { | ||
187 | struct ath_hw *ah = sc->sc_ah; | ||
188 | struct ath_common *common = ath9k_hw_common(ah); | ||
189 | int pos = ah->curchan - &ah->channels[0]; | ||
190 | struct survey_info *survey = &sc->survey[pos]; | ||
191 | struct ath_cycle_counters *cc = &common->cc_survey; | ||
192 | unsigned int div = common->clockrate * 1000; | ||
193 | int ret = 0; | ||
194 | |||
195 | if (!ah->curchan) | ||
196 | return -1; | ||
197 | |||
198 | if (ah->power_mode == ATH9K_PM_AWAKE) | ||
199 | ath_hw_cycle_counters_update(common); | ||
200 | |||
201 | if (cc->cycles > 0) { | ||
202 | survey->filled |= SURVEY_INFO_CHANNEL_TIME | | ||
203 | SURVEY_INFO_CHANNEL_TIME_BUSY | | ||
204 | SURVEY_INFO_CHANNEL_TIME_RX | | ||
205 | SURVEY_INFO_CHANNEL_TIME_TX; | ||
206 | survey->channel_time += cc->cycles / div; | ||
207 | survey->channel_time_busy += cc->rx_busy / div; | ||
208 | survey->channel_time_rx += cc->rx_frame / div; | ||
209 | survey->channel_time_tx += cc->tx_frame / div; | ||
210 | } | ||
211 | |||
212 | if (cc->cycles < div) | ||
213 | return -1; | ||
214 | |||
215 | if (cc->cycles > 0) | ||
216 | ret = cc->rx_busy * 100 / cc->cycles; | ||
217 | |||
218 | memset(cc, 0, sizeof(*cc)); | ||
219 | |||
220 | ath_update_survey_nf(sc, pos); | ||
221 | |||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static void __ath_cancel_work(struct ath_softc *sc) | 147 | static void __ath_cancel_work(struct ath_softc *sc) |
226 | { | 148 | { |
227 | cancel_work_sync(&sc->paprd_work); | 149 | cancel_work_sync(&sc->paprd_work); |
@@ -380,258 +302,6 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
380 | return r; | 302 | return r; |
381 | } | 303 | } |
382 | 304 | ||
383 | static void ath_paprd_activate(struct ath_softc *sc) | ||
384 | { | ||
385 | struct ath_hw *ah = sc->sc_ah; | ||
386 | struct ath9k_hw_cal_data *caldata = ah->caldata; | ||
387 | int chain; | ||
388 | |||
389 | if (!caldata || !caldata->paprd_done) | ||
390 | return; | ||
391 | |||
392 | ath9k_ps_wakeup(sc); | ||
393 | ar9003_paprd_enable(ah, false); | ||
394 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | ||
395 | if (!(ah->txchainmask & BIT(chain))) | ||
396 | continue; | ||
397 | |||
398 | ar9003_paprd_populate_single_table(ah, caldata, chain); | ||
399 | } | ||
400 | |||
401 | ar9003_paprd_enable(ah, true); | ||
402 | ath9k_ps_restore(sc); | ||
403 | } | ||
404 | |||
405 | static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int chain) | ||
406 | { | ||
407 | struct ieee80211_hw *hw = sc->hw; | ||
408 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
409 | struct ath_hw *ah = sc->sc_ah; | ||
410 | struct ath_common *common = ath9k_hw_common(ah); | ||
411 | struct ath_tx_control txctl; | ||
412 | int time_left; | ||
413 | |||
414 | memset(&txctl, 0, sizeof(txctl)); | ||
415 | txctl.txq = sc->tx.txq_map[WME_AC_BE]; | ||
416 | |||
417 | memset(tx_info, 0, sizeof(*tx_info)); | ||
418 | tx_info->band = hw->conf.channel->band; | ||
419 | tx_info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
420 | tx_info->control.rates[0].idx = 0; | ||
421 | tx_info->control.rates[0].count = 1; | ||
422 | tx_info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | ||
423 | tx_info->control.rates[1].idx = -1; | ||
424 | |||
425 | init_completion(&sc->paprd_complete); | ||
426 | txctl.paprd = BIT(chain); | ||
427 | |||
428 | if (ath_tx_start(hw, skb, &txctl) != 0) { | ||
429 | ath_dbg(common, CALIBRATE, "PAPRD TX failed\n"); | ||
430 | dev_kfree_skb_any(skb); | ||
431 | return false; | ||
432 | } | ||
433 | |||
434 | time_left = wait_for_completion_timeout(&sc->paprd_complete, | ||
435 | msecs_to_jiffies(ATH_PAPRD_TIMEOUT)); | ||
436 | |||
437 | if (!time_left) | ||
438 | ath_dbg(common, CALIBRATE, | ||
439 | "Timeout waiting for paprd training on TX chain %d\n", | ||
440 | chain); | ||
441 | |||
442 | return !!time_left; | ||
443 | } | ||
444 | |||
445 | void ath_paprd_calibrate(struct work_struct *work) | ||
446 | { | ||
447 | struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work); | ||
448 | struct ieee80211_hw *hw = sc->hw; | ||
449 | struct ath_hw *ah = sc->sc_ah; | ||
450 | struct ieee80211_hdr *hdr; | ||
451 | struct sk_buff *skb = NULL; | ||
452 | struct ath9k_hw_cal_data *caldata = ah->caldata; | ||
453 | struct ath_common *common = ath9k_hw_common(ah); | ||
454 | int ftype; | ||
455 | int chain_ok = 0; | ||
456 | int chain; | ||
457 | int len = 1800; | ||
458 | |||
459 | if (!caldata) | ||
460 | return; | ||
461 | |||
462 | ath9k_ps_wakeup(sc); | ||
463 | |||
464 | if (ar9003_paprd_init_table(ah) < 0) | ||
465 | goto fail_paprd; | ||
466 | |||
467 | skb = alloc_skb(len, GFP_KERNEL); | ||
468 | if (!skb) | ||
469 | goto fail_paprd; | ||
470 | |||
471 | skb_put(skb, len); | ||
472 | memset(skb->data, 0, len); | ||
473 | hdr = (struct ieee80211_hdr *)skb->data; | ||
474 | ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC; | ||
475 | hdr->frame_control = cpu_to_le16(ftype); | ||
476 | hdr->duration_id = cpu_to_le16(10); | ||
477 | memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); | ||
478 | memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); | ||
479 | memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); | ||
480 | |||
481 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | ||
482 | if (!(ah->txchainmask & BIT(chain))) | ||
483 | continue; | ||
484 | |||
485 | chain_ok = 0; | ||
486 | |||
487 | ath_dbg(common, CALIBRATE, | ||
488 | "Sending PAPRD frame for thermal measurement on chain %d\n", | ||
489 | chain); | ||
490 | if (!ath_paprd_send_frame(sc, skb, chain)) | ||
491 | goto fail_paprd; | ||
492 | |||
493 | ar9003_paprd_setup_gain_table(ah, chain); | ||
494 | |||
495 | ath_dbg(common, CALIBRATE, | ||
496 | "Sending PAPRD training frame on chain %d\n", chain); | ||
497 | if (!ath_paprd_send_frame(sc, skb, chain)) | ||
498 | goto fail_paprd; | ||
499 | |||
500 | if (!ar9003_paprd_is_done(ah)) { | ||
501 | ath_dbg(common, CALIBRATE, | ||
502 | "PAPRD not yet done on chain %d\n", chain); | ||
503 | break; | ||
504 | } | ||
505 | |||
506 | if (ar9003_paprd_create_curve(ah, caldata, chain)) { | ||
507 | ath_dbg(common, CALIBRATE, | ||
508 | "PAPRD create curve failed on chain %d\n", | ||
509 | chain); | ||
510 | break; | ||
511 | } | ||
512 | |||
513 | chain_ok = 1; | ||
514 | } | ||
515 | kfree_skb(skb); | ||
516 | |||
517 | if (chain_ok) { | ||
518 | caldata->paprd_done = true; | ||
519 | ath_paprd_activate(sc); | ||
520 | } | ||
521 | |||
522 | fail_paprd: | ||
523 | ath9k_ps_restore(sc); | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * This routine performs the periodic noise floor calibration function | ||
528 | * that is used to adjust and optimize the chip performance. This | ||
529 | * takes environmental changes (location, temperature) into account. | ||
530 | * When the task is complete, it reschedules itself depending on the | ||
531 | * appropriate interval that was calculated. | ||
532 | */ | ||
533 | void ath_ani_calibrate(unsigned long data) | ||
534 | { | ||
535 | struct ath_softc *sc = (struct ath_softc *)data; | ||
536 | struct ath_hw *ah = sc->sc_ah; | ||
537 | struct ath_common *common = ath9k_hw_common(ah); | ||
538 | bool longcal = false; | ||
539 | bool shortcal = false; | ||
540 | bool aniflag = false; | ||
541 | unsigned int timestamp = jiffies_to_msecs(jiffies); | ||
542 | u32 cal_interval, short_cal_interval, long_cal_interval; | ||
543 | unsigned long flags; | ||
544 | |||
545 | if (ah->caldata && ah->caldata->nfcal_interference) | ||
546 | long_cal_interval = ATH_LONG_CALINTERVAL_INT; | ||
547 | else | ||
548 | long_cal_interval = ATH_LONG_CALINTERVAL; | ||
549 | |||
550 | short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? | ||
551 | ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; | ||
552 | |||
553 | /* Only calibrate if awake */ | ||
554 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) | ||
555 | goto set_timer; | ||
556 | |||
557 | ath9k_ps_wakeup(sc); | ||
558 | |||
559 | /* Long calibration runs independently of short calibration. */ | ||
560 | if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) { | ||
561 | longcal = true; | ||
562 | common->ani.longcal_timer = timestamp; | ||
563 | } | ||
564 | |||
565 | /* Short calibration applies only while caldone is false */ | ||
566 | if (!common->ani.caldone) { | ||
567 | if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { | ||
568 | shortcal = true; | ||
569 | common->ani.shortcal_timer = timestamp; | ||
570 | common->ani.resetcal_timer = timestamp; | ||
571 | } | ||
572 | } else { | ||
573 | if ((timestamp - common->ani.resetcal_timer) >= | ||
574 | ATH_RESTART_CALINTERVAL) { | ||
575 | common->ani.caldone = ath9k_hw_reset_calvalid(ah); | ||
576 | if (common->ani.caldone) | ||
577 | common->ani.resetcal_timer = timestamp; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | /* Verify whether we must check ANI */ | ||
582 | if (sc->sc_ah->config.enable_ani | ||
583 | && (timestamp - common->ani.checkani_timer) >= | ||
584 | ah->config.ani_poll_interval) { | ||
585 | aniflag = true; | ||
586 | common->ani.checkani_timer = timestamp; | ||
587 | } | ||
588 | |||
589 | /* Call ANI routine if necessary */ | ||
590 | if (aniflag) { | ||
591 | spin_lock_irqsave(&common->cc_lock, flags); | ||
592 | ath9k_hw_ani_monitor(ah, ah->curchan); | ||
593 | ath_update_survey_stats(sc); | ||
594 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
595 | } | ||
596 | |||
597 | /* Perform calibration if necessary */ | ||
598 | if (longcal || shortcal) { | ||
599 | common->ani.caldone = | ||
600 | ath9k_hw_calibrate(ah, ah->curchan, | ||
601 | ah->rxchainmask, longcal); | ||
602 | } | ||
603 | |||
604 | ath_dbg(common, ANI, | ||
605 | "Calibration @%lu finished: %s %s %s, caldone: %s\n", | ||
606 | jiffies, | ||
607 | longcal ? "long" : "", shortcal ? "short" : "", | ||
608 | aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); | ||
609 | |||
610 | ath9k_ps_restore(sc); | ||
611 | |||
612 | set_timer: | ||
613 | /* | ||
614 | * Set timer interval based on previous results. | ||
615 | * The interval must be the shortest necessary to satisfy ANI, | ||
616 | * short calibration and long calibration. | ||
617 | */ | ||
618 | ath9k_debug_samp_bb_mac(sc); | ||
619 | cal_interval = ATH_LONG_CALINTERVAL; | ||
620 | if (sc->sc_ah->config.enable_ani) | ||
621 | cal_interval = min(cal_interval, | ||
622 | (u32)ah->config.ani_poll_interval); | ||
623 | if (!common->ani.caldone) | ||
624 | cal_interval = min(cal_interval, (u32)short_cal_interval); | ||
625 | |||
626 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | ||
627 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->caldata) { | ||
628 | if (!ah->caldata->paprd_done) | ||
629 | ieee80211_queue_work(sc->hw, &sc->paprd_work); | ||
630 | else if (!ah->paprd_table_write_done) | ||
631 | ath_paprd_activate(sc); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, | 305 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, |
636 | struct ieee80211_vif *vif) | 306 | struct ieee80211_vif *vif) |
637 | { | 307 | { |
@@ -669,7 +339,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
669 | ath_tx_node_cleanup(sc, an); | 339 | ath_tx_node_cleanup(sc, an); |
670 | } | 340 | } |
671 | 341 | ||
672 | |||
673 | void ath9k_tasklet(unsigned long data) | 342 | void ath9k_tasklet(unsigned long data) |
674 | { | 343 | { |
675 | struct ath_softc *sc = (struct ath_softc *)data; | 344 | struct ath_softc *sc = (struct ath_softc *)data; |
@@ -903,87 +572,6 @@ void ath_reset_work(struct work_struct *work) | |||
903 | ath_reset(sc, true); | 572 | ath_reset(sc, true); |
904 | } | 573 | } |
905 | 574 | ||
906 | void ath_hw_check(struct work_struct *work) | ||
907 | { | ||
908 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); | ||
909 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
910 | unsigned long flags; | ||
911 | int busy; | ||
912 | u8 is_alive, nbeacon = 1; | ||
913 | |||
914 | ath9k_ps_wakeup(sc); | ||
915 | is_alive = ath9k_hw_check_alive(sc->sc_ah); | ||
916 | |||
917 | if (is_alive && !AR_SREV_9300(sc->sc_ah)) | ||
918 | goto out; | ||
919 | else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { | ||
920 | ath_dbg(common, RESET, | ||
921 | "DCU stuck is detected. Schedule chip reset\n"); | ||
922 | RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG); | ||
923 | goto sched_reset; | ||
924 | } | ||
925 | |||
926 | spin_lock_irqsave(&common->cc_lock, flags); | ||
927 | busy = ath_update_survey_stats(sc); | ||
928 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
929 | |||
930 | ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", | ||
931 | busy, sc->hw_busy_count + 1); | ||
932 | if (busy >= 99) { | ||
933 | if (++sc->hw_busy_count >= 3) { | ||
934 | RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); | ||
935 | goto sched_reset; | ||
936 | } | ||
937 | } else if (busy >= 0) { | ||
938 | sc->hw_busy_count = 0; | ||
939 | nbeacon = 3; | ||
940 | } | ||
941 | |||
942 | ath_start_rx_poll(sc, nbeacon); | ||
943 | goto out; | ||
944 | |||
945 | sched_reset: | ||
946 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
947 | out: | ||
948 | ath9k_ps_restore(sc); | ||
949 | } | ||
950 | |||
951 | static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) | ||
952 | { | ||
953 | static int count; | ||
954 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
955 | |||
956 | if (pll_sqsum >= 0x40000) { | ||
957 | count++; | ||
958 | if (count == 3) { | ||
959 | /* Rx is hung for more than 500ms. Reset it */ | ||
960 | ath_dbg(common, RESET, "Possible RX hang, resetting\n"); | ||
961 | RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); | ||
962 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
963 | count = 0; | ||
964 | } | ||
965 | } else | ||
966 | count = 0; | ||
967 | } | ||
968 | |||
969 | void ath_hw_pll_work(struct work_struct *work) | ||
970 | { | ||
971 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
972 | hw_pll_work.work); | ||
973 | u32 pll_sqsum; | ||
974 | |||
975 | if (AR_SREV_9485(sc->sc_ah)) { | ||
976 | |||
977 | ath9k_ps_wakeup(sc); | ||
978 | pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); | ||
979 | ath9k_ps_restore(sc); | ||
980 | |||
981 | ath_hw_pll_rx_hang_check(sc, pll_sqsum); | ||
982 | |||
983 | ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); | ||
984 | } | ||
985 | } | ||
986 | |||
987 | /**********************/ | 575 | /**********************/ |
988 | /* mac80211 callbacks */ | 576 | /* mac80211 callbacks */ |
989 | /**********************/ | 577 | /**********************/ |
@@ -1389,25 +977,6 @@ static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, | |||
1389 | } | 977 | } |
1390 | } | 978 | } |
1391 | 979 | ||
1392 | void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon) | ||
1393 | { | ||
1394 | if (!AR_SREV_9300(sc->sc_ah)) | ||
1395 | return; | ||
1396 | |||
1397 | if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) | ||
1398 | return; | ||
1399 | |||
1400 | mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies | ||
1401 | (nbeacon * sc->cur_beacon_conf.beacon_interval)); | ||
1402 | } | ||
1403 | |||
1404 | void ath_rx_poll(unsigned long data) | ||
1405 | { | ||
1406 | struct ath_softc *sc = (struct ath_softc *)data; | ||
1407 | |||
1408 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); | ||
1409 | } | ||
1410 | |||
1411 | static int ath9k_add_interface(struct ieee80211_hw *hw, | 980 | static int ath9k_add_interface(struct ieee80211_hw *hw, |
1412 | struct ieee80211_vif *vif) | 981 | struct ieee80211_vif *vif) |
1413 | { | 982 | { |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d59dd01d6cde..6619a39b8c27 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -105,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = { | |||
105 | /* Aggregation logic */ | 105 | /* Aggregation logic */ |
106 | /*********************/ | 106 | /*********************/ |
107 | 107 | ||
108 | static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) | 108 | void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) |
109 | __acquires(&txq->axq_lock) | 109 | __acquires(&txq->axq_lock) |
110 | { | 110 | { |
111 | spin_lock_bh(&txq->axq_lock); | 111 | spin_lock_bh(&txq->axq_lock); |
112 | } | 112 | } |
113 | 113 | ||
114 | static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) | 114 | void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq) |
115 | __releases(&txq->axq_lock) | 115 | __releases(&txq->axq_lock) |
116 | { | 116 | { |
117 | spin_unlock_bh(&txq->axq_lock); | 117 | spin_unlock_bh(&txq->axq_lock); |
118 | } | 118 | } |
119 | 119 | ||
120 | static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) | 120 | void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) |
121 | __releases(&txq->axq_lock) | 121 | __releases(&txq->axq_lock) |
122 | { | 122 | { |
123 | struct sk_buff_head q; | 123 | struct sk_buff_head q; |
@@ -2231,46 +2231,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2231 | ath_txq_unlock_complete(sc, txq); | 2231 | ath_txq_unlock_complete(sc, txq); |
2232 | } | 2232 | } |
2233 | 2233 | ||
2234 | static void ath_tx_complete_poll_work(struct work_struct *work) | ||
2235 | { | ||
2236 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
2237 | tx_complete_work.work); | ||
2238 | struct ath_txq *txq; | ||
2239 | int i; | ||
2240 | bool needreset = false; | ||
2241 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
2242 | sc->tx_complete_poll_work_seen++; | ||
2243 | #endif | ||
2244 | |||
2245 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
2246 | if (ATH_TXQ_SETUP(sc, i)) { | ||
2247 | txq = &sc->tx.txq[i]; | ||
2248 | ath_txq_lock(sc, txq); | ||
2249 | if (txq->axq_depth) { | ||
2250 | if (txq->axq_tx_inprogress) { | ||
2251 | needreset = true; | ||
2252 | ath_txq_unlock(sc, txq); | ||
2253 | break; | ||
2254 | } else { | ||
2255 | txq->axq_tx_inprogress = true; | ||
2256 | } | ||
2257 | } | ||
2258 | ath_txq_unlock_complete(sc, txq); | ||
2259 | } | ||
2260 | |||
2261 | if (needreset) { | ||
2262 | ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, | ||
2263 | "tx hung, resetting the chip\n"); | ||
2264 | RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); | ||
2265 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
2266 | } | ||
2267 | |||
2268 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, | ||
2269 | msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT)); | ||
2270 | } | ||
2271 | |||
2272 | |||
2273 | |||
2274 | void ath_tx_tasklet(struct ath_softc *sc) | 2234 | void ath_tx_tasklet(struct ath_softc *sc) |
2275 | { | 2235 | { |
2276 | struct ath_hw *ah = sc->sc_ah; | 2236 | struct ath_hw *ah = sc->sc_ah; |