]>
Commit | Line | Data |
---|---|---|
f1dc5600 | 1 | /* |
e36b27af | 2 | * Copyright (c) 2008-2010 Atheros Communications Inc. |
f1dc5600 S |
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 | ||
cfe8cba9 | 17 | #include "hw.h" |
c16fcb49 | 18 | #include "hw-ops.h" |
f1dc5600 | 19 | |
e36b27af LR |
20 | struct ani_ofdm_level_entry { |
21 | int spur_immunity_level; | |
22 | int fir_step_level; | |
23 | int ofdm_weak_signal_on; | |
24 | }; | |
25 | ||
26 | /* values here are relative to the INI */ | |
27 | ||
28 | /* | |
29 | * Legend: | |
30 | * | |
31 | * SI: Spur immunity | |
32 | * FS: FIR Step | |
33 | * WS: OFDM / CCK Weak Signal detection | |
34 | * MRC-CCK: Maximal Ratio Combining for CCK | |
35 | */ | |
36 | ||
37 | static const struct ani_ofdm_level_entry ofdm_level_table[] = { | |
38 | /* SI FS WS */ | |
39 | { 0, 0, 1 }, /* lvl 0 */ | |
40 | { 1, 1, 1 }, /* lvl 1 */ | |
41 | { 2, 2, 1 }, /* lvl 2 */ | |
42 | { 3, 2, 1 }, /* lvl 3 (default) */ | |
43 | { 4, 3, 1 }, /* lvl 4 */ | |
44 | { 5, 4, 1 }, /* lvl 5 */ | |
45 | { 6, 5, 1 }, /* lvl 6 */ | |
46 | { 7, 6, 1 }, /* lvl 7 */ | |
47 | { 7, 7, 1 }, /* lvl 8 */ | |
48 | { 7, 8, 0 } /* lvl 9 */ | |
49 | }; | |
50 | #define ATH9K_ANI_OFDM_NUM_LEVEL \ | |
51 | (sizeof(ofdm_level_table)/sizeof(ofdm_level_table[0])) | |
52 | #define ATH9K_ANI_OFDM_MAX_LEVEL \ | |
53 | (ATH9K_ANI_OFDM_NUM_LEVEL-1) | |
54 | #define ATH9K_ANI_OFDM_DEF_LEVEL \ | |
55 | 3 /* default level - matches the INI settings */ | |
56 | ||
57 | /* | |
58 | * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm. | |
59 | * With OFDM for single stream you just add up all antenna inputs, you're | |
60 | * only interested in what you get after FFT. Signal aligment is also not | |
61 | * required for OFDM because any phase difference adds up in the frequency | |
62 | * domain. | |
63 | * | |
64 | * MRC requires extra work for use with CCK. You need to align the antenna | |
65 | * signals from the different antenna before you can add the signals together. | |
66 | * You need aligment of signals as CCK is in time domain, so addition can cancel | |
67 | * your signal completely if phase is 180 degrees (think of adding sine waves). | |
68 | * You also need to remove noise before the addition and this is where ANI | |
69 | * MRC CCK comes into play. One of the antenna inputs may be stronger but | |
70 | * lower SNR, so just adding after alignment can be dangerous. | |
71 | * | |
72 | * Regardless of alignment in time, the antenna signals add constructively after | |
73 | * FFT and improve your reception. For more information: | |
74 | * | |
75 | * http://en.wikipedia.org/wiki/Maximal-ratio_combining | |
76 | */ | |
77 | ||
78 | struct ani_cck_level_entry { | |
79 | int fir_step_level; | |
80 | int mrc_cck_on; | |
81 | }; | |
82 | ||
83 | static const struct ani_cck_level_entry cck_level_table[] = { | |
84 | /* FS MRC-CCK */ | |
85 | { 0, 1 }, /* lvl 0 */ | |
86 | { 1, 1 }, /* lvl 1 */ | |
87 | { 2, 1 }, /* lvl 2 (default) */ | |
88 | { 3, 1 }, /* lvl 3 */ | |
89 | { 4, 0 }, /* lvl 4 */ | |
90 | { 5, 0 }, /* lvl 5 */ | |
91 | { 6, 0 }, /* lvl 6 */ | |
92 | { 7, 0 }, /* lvl 7 (only for high rssi) */ | |
93 | { 8, 0 } /* lvl 8 (only for high rssi) */ | |
94 | }; | |
95 | ||
96 | #define ATH9K_ANI_CCK_NUM_LEVEL \ | |
97 | (sizeof(cck_level_table)/sizeof(cck_level_table[0])) | |
98 | #define ATH9K_ANI_CCK_MAX_LEVEL \ | |
99 | (ATH9K_ANI_CCK_NUM_LEVEL-1) | |
100 | #define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \ | |
101 | (ATH9K_ANI_CCK_NUM_LEVEL-3) | |
102 | #define ATH9K_ANI_CCK_DEF_LEVEL \ | |
103 | 2 /* default level - matches the INI settings */ | |
104 | ||
ac0bb767 | 105 | /* Private to ani.c */ |
e36b27af | 106 | static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) |
ac0bb767 LR |
107 | { |
108 | ath9k_hw_private_ops(ah)->ani_lower_immunity(ah); | |
109 | } | |
110 | ||
e36b27af LR |
111 | int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, |
112 | struct ath9k_channel *chan) | |
f1dc5600 | 113 | { |
f1dc5600 S |
114 | int i; |
115 | ||
2660b81a S |
116 | for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { |
117 | if (ah->ani[i].c && | |
118 | ah->ani[i].c->channel == chan->channel) | |
f1dc5600 | 119 | return i; |
2660b81a S |
120 | if (ah->ani[i].c == NULL) { |
121 | ah->ani[i].c = chan; | |
f1dc5600 S |
122 | return i; |
123 | } | |
124 | } | |
125 | ||
c46917bb LR |
126 | ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, |
127 | "No more channel states left. Using channel 0\n"); | |
f1dc5600 S |
128 | |
129 | return 0; | |
130 | } | |
131 | ||
cbe61d8a | 132 | static void ath9k_hw_update_mibstats(struct ath_hw *ah, |
f1dc5600 S |
133 | struct ath9k_mib_stats *stats) |
134 | { | |
135 | stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); | |
136 | stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); | |
137 | stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); | |
138 | stats->rts_good += REG_READ(ah, AR_RTS_OK); | |
139 | stats->beacons += REG_READ(ah, AR_BEACON_CNT); | |
140 | } | |
141 | ||
e36b27af | 142 | static void ath9k_ani_restart_old(struct ath_hw *ah) |
f1dc5600 | 143 | { |
f1dc5600 | 144 | struct ar5416AniState *aniState; |
c46917bb | 145 | struct ath_common *common = ath9k_hw_common(ah); |
f1dc5600 S |
146 | |
147 | if (!DO_ANI(ah)) | |
148 | return; | |
149 | ||
2660b81a | 150 | aniState = ah->curani; |
f1dc5600 | 151 | aniState->listenTime = 0; |
1aa8e847 S |
152 | |
153 | if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { | |
154 | aniState->ofdmPhyErrBase = 0; | |
c46917bb LR |
155 | ath_print(common, ATH_DBG_ANI, |
156 | "OFDM Trigger is too high for hw counters\n"); | |
1aa8e847 S |
157 | } else { |
158 | aniState->ofdmPhyErrBase = | |
159 | AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; | |
160 | } | |
161 | if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { | |
162 | aniState->cckPhyErrBase = 0; | |
c46917bb LR |
163 | ath_print(common, ATH_DBG_ANI, |
164 | "CCK Trigger is too high for hw counters\n"); | |
1aa8e847 S |
165 | } else { |
166 | aniState->cckPhyErrBase = | |
167 | AR_PHY_COUNTMAX - aniState->cckTrigHigh; | |
f1dc5600 | 168 | } |
c46917bb LR |
169 | ath_print(common, ATH_DBG_ANI, |
170 | "Writing ofdmbase=%u cckbase=%u\n", | |
171 | aniState->ofdmPhyErrBase, | |
172 | aniState->cckPhyErrBase); | |
7d0d0df0 S |
173 | |
174 | ENABLE_REGWRITE_BUFFER(ah); | |
175 | ||
1aa8e847 S |
176 | REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); |
177 | REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); | |
178 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | |
179 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | |
180 | ||
7d0d0df0 S |
181 | REGWRITE_BUFFER_FLUSH(ah); |
182 | DISABLE_REGWRITE_BUFFER(ah); | |
183 | ||
1aa8e847 S |
184 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
185 | ||
f1dc5600 S |
186 | aniState->ofdmPhyErrCount = 0; |
187 | aniState->cckPhyErrCount = 0; | |
188 | } | |
189 | ||
e36b27af LR |
190 | static void ath9k_ani_restart_new(struct ath_hw *ah) |
191 | { | |
192 | struct ar5416AniState *aniState; | |
193 | struct ath_common *common = ath9k_hw_common(ah); | |
194 | ||
195 | if (!DO_ANI(ah)) | |
196 | return; | |
197 | ||
198 | aniState = ah->curani; | |
199 | aniState->listenTime = 0; | |
200 | ||
201 | aniState->ofdmPhyErrBase = 0; | |
202 | aniState->cckPhyErrBase = 0; | |
203 | ||
204 | ath_print(common, ATH_DBG_ANI, | |
205 | "Writing ofdmbase=%08x cckbase=%08x\n", | |
206 | aniState->ofdmPhyErrBase, | |
207 | aniState->cckPhyErrBase); | |
208 | ||
209 | ENABLE_REGWRITE_BUFFER(ah); | |
210 | ||
211 | REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); | |
212 | REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); | |
213 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | |
214 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | |
215 | ||
216 | REGWRITE_BUFFER_FLUSH(ah); | |
217 | DISABLE_REGWRITE_BUFFER(ah); | |
218 | ||
219 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | |
220 | ||
221 | aniState->ofdmPhyErrCount = 0; | |
222 | aniState->cckPhyErrCount = 0; | |
223 | } | |
224 | ||
225 | static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah) | |
f1dc5600 | 226 | { |
b002a4a9 | 227 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; |
f1dc5600 | 228 | struct ar5416AniState *aniState; |
f1dc5600 S |
229 | int32_t rssi; |
230 | ||
231 | if (!DO_ANI(ah)) | |
232 | return; | |
233 | ||
2660b81a | 234 | aniState = ah->curani; |
f1dc5600 S |
235 | |
236 | if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { | |
237 | if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, | |
238 | aniState->noiseImmunityLevel + 1)) { | |
239 | return; | |
240 | } | |
241 | } | |
242 | ||
243 | if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { | |
244 | if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, | |
245 | aniState->spurImmunityLevel + 1)) { | |
246 | return; | |
247 | } | |
248 | } | |
249 | ||
2660b81a | 250 | if (ah->opmode == NL80211_IFTYPE_AP) { |
f1dc5600 S |
251 | if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { |
252 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
253 | aniState->firstepLevel + 1); | |
254 | } | |
255 | return; | |
256 | } | |
cbe61d8a | 257 | rssi = BEACON_RSSI(ah); |
f1dc5600 S |
258 | if (rssi > aniState->rssiThrHigh) { |
259 | if (!aniState->ofdmWeakSigDetectOff) { | |
260 | if (ath9k_hw_ani_control(ah, | |
261 | ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
262 | false)) { | |
263 | ath9k_hw_ani_control(ah, | |
264 | ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); | |
265 | return; | |
266 | } | |
267 | } | |
268 | if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { | |
269 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
270 | aniState->firstepLevel + 1); | |
271 | return; | |
272 | } | |
273 | } else if (rssi > aniState->rssiThrLow) { | |
274 | if (aniState->ofdmWeakSigDetectOff) | |
275 | ath9k_hw_ani_control(ah, | |
276 | ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
277 | true); | |
278 | if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) | |
279 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
280 | aniState->firstepLevel + 1); | |
281 | return; | |
282 | } else { | |
d37b7da3 S |
283 | if ((conf->channel->band == IEEE80211_BAND_2GHZ) && |
284 | !conf_is_ht(conf)) { | |
f1dc5600 S |
285 | if (!aniState->ofdmWeakSigDetectOff) |
286 | ath9k_hw_ani_control(ah, | |
287 | ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
288 | false); | |
289 | if (aniState->firstepLevel > 0) | |
290 | ath9k_hw_ani_control(ah, | |
291 | ATH9K_ANI_FIRSTEP_LEVEL, 0); | |
292 | return; | |
293 | } | |
294 | } | |
295 | } | |
296 | ||
e36b27af | 297 | static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) |
f1dc5600 | 298 | { |
b002a4a9 | 299 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; |
f1dc5600 | 300 | struct ar5416AniState *aniState; |
f1dc5600 S |
301 | int32_t rssi; |
302 | ||
303 | if (!DO_ANI(ah)) | |
304 | return; | |
305 | ||
2660b81a | 306 | aniState = ah->curani; |
f1dc5600 S |
307 | if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { |
308 | if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, | |
309 | aniState->noiseImmunityLevel + 1)) { | |
310 | return; | |
311 | } | |
312 | } | |
2660b81a | 313 | if (ah->opmode == NL80211_IFTYPE_AP) { |
f1dc5600 S |
314 | if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { |
315 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
316 | aniState->firstepLevel + 1); | |
317 | } | |
318 | return; | |
319 | } | |
cbe61d8a | 320 | rssi = BEACON_RSSI(ah); |
f1dc5600 S |
321 | if (rssi > aniState->rssiThrLow) { |
322 | if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) | |
323 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
324 | aniState->firstepLevel + 1); | |
325 | } else { | |
d37b7da3 S |
326 | if ((conf->channel->band == IEEE80211_BAND_2GHZ) && |
327 | !conf_is_ht(conf)) { | |
f1dc5600 S |
328 | if (aniState->firstepLevel > 0) |
329 | ath9k_hw_ani_control(ah, | |
330 | ATH9K_ANI_FIRSTEP_LEVEL, 0); | |
331 | } | |
332 | } | |
333 | } | |
334 | ||
e36b27af LR |
335 | /* Adjust the OFDM Noise Immunity Level */ |
336 | static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) | |
337 | { | |
338 | struct ar5416AniState *aniState = ah->curani; | |
339 | struct ath_common *common = ath9k_hw_common(ah); | |
340 | const struct ani_ofdm_level_entry *entry_ofdm; | |
341 | const struct ani_cck_level_entry *entry_cck; | |
342 | ||
343 | aniState->noiseFloor = BEACON_RSSI(ah); | |
344 | ||
345 | ath_print(common, ATH_DBG_ANI, | |
346 | "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", | |
347 | aniState->ofdmNoiseImmunityLevel, | |
348 | immunityLevel, aniState->noiseFloor, | |
349 | aniState->rssiThrLow, aniState->rssiThrHigh); | |
350 | ||
351 | aniState->ofdmNoiseImmunityLevel = immunityLevel; | |
352 | ||
353 | entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; | |
354 | entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; | |
355 | ||
356 | if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level) | |
357 | ath9k_hw_ani_control(ah, | |
358 | ATH9K_ANI_SPUR_IMMUNITY_LEVEL, | |
359 | entry_ofdm->spur_immunity_level); | |
360 | ||
361 | if (aniState->firstepLevel != entry_ofdm->fir_step_level && | |
362 | entry_ofdm->fir_step_level >= entry_cck->fir_step_level) | |
363 | ath9k_hw_ani_control(ah, | |
364 | ATH9K_ANI_FIRSTEP_LEVEL, | |
365 | entry_ofdm->fir_step_level); | |
366 | ||
367 | if ((ah->opmode != NL80211_IFTYPE_STATION && | |
368 | ah->opmode != NL80211_IFTYPE_ADHOC) || | |
369 | aniState->noiseFloor <= aniState->rssiThrHigh) { | |
370 | if (aniState->ofdmWeakSigDetectOff) | |
371 | /* force on ofdm weak sig detect */ | |
372 | ath9k_hw_ani_control(ah, | |
373 | ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
374 | true); | |
375 | else if (aniState->ofdmWeakSigDetectOff == | |
376 | entry_ofdm->ofdm_weak_signal_on) | |
377 | ath9k_hw_ani_control(ah, | |
378 | ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
379 | entry_ofdm->ofdm_weak_signal_on); | |
380 | } | |
381 | } | |
382 | ||
383 | static void ath9k_hw_ani_ofdm_err_trigger_new(struct ath_hw *ah) | |
384 | { | |
385 | struct ar5416AniState *aniState; | |
386 | ||
387 | if (!DO_ANI(ah)) | |
388 | return; | |
389 | ||
390 | aniState = ah->curani; | |
391 | ||
392 | if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) | |
393 | ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1); | |
394 | } | |
395 | ||
396 | /* | |
397 | * Set the ANI settings to match an CCK level. | |
398 | */ | |
399 | static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) | |
400 | { | |
401 | struct ar5416AniState *aniState = ah->curani; | |
402 | struct ath_common *common = ath9k_hw_common(ah); | |
403 | const struct ani_ofdm_level_entry *entry_ofdm; | |
404 | const struct ani_cck_level_entry *entry_cck; | |
405 | ||
406 | aniState->noiseFloor = BEACON_RSSI(ah); | |
407 | ath_print(common, ATH_DBG_ANI, | |
408 | "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", | |
409 | aniState->cckNoiseImmunityLevel, immunityLevel, | |
410 | aniState->noiseFloor, aniState->rssiThrLow, | |
411 | aniState->rssiThrHigh); | |
412 | ||
413 | if ((ah->opmode == NL80211_IFTYPE_STATION || | |
414 | ah->opmode == NL80211_IFTYPE_ADHOC) && | |
415 | aniState->noiseFloor <= aniState->rssiThrLow && | |
416 | immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) | |
417 | immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; | |
418 | ||
419 | aniState->cckNoiseImmunityLevel = immunityLevel; | |
420 | ||
421 | entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; | |
422 | entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; | |
423 | ||
424 | if (aniState->firstepLevel != entry_cck->fir_step_level && | |
425 | entry_cck->fir_step_level >= entry_ofdm->fir_step_level) | |
426 | ath9k_hw_ani_control(ah, | |
427 | ATH9K_ANI_FIRSTEP_LEVEL, | |
428 | entry_cck->fir_step_level); | |
429 | ||
430 | /* Skip MRC CCK for pre AR9003 families */ | |
431 | if (!AR_SREV_9300_20_OR_LATER(ah)) | |
432 | return; | |
433 | ||
434 | if (aniState->mrcCCKOff == entry_cck->mrc_cck_on) | |
435 | ath9k_hw_ani_control(ah, | |
436 | ATH9K_ANI_MRC_CCK, | |
437 | entry_cck->mrc_cck_on); | |
438 | } | |
439 | ||
440 | static void ath9k_hw_ani_cck_err_trigger_new(struct ath_hw *ah) | |
441 | { | |
442 | struct ar5416AniState *aniState; | |
443 | ||
444 | if (!DO_ANI(ah)) | |
445 | return; | |
446 | ||
447 | aniState = ah->curani; | |
448 | ||
449 | if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) | |
450 | ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1); | |
451 | } | |
452 | ||
ac0bb767 | 453 | static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) |
f1dc5600 | 454 | { |
f1dc5600 S |
455 | struct ar5416AniState *aniState; |
456 | int32_t rssi; | |
457 | ||
2660b81a | 458 | aniState = ah->curani; |
f1dc5600 | 459 | |
2660b81a | 460 | if (ah->opmode == NL80211_IFTYPE_AP) { |
f1dc5600 S |
461 | if (aniState->firstepLevel > 0) { |
462 | if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
463 | aniState->firstepLevel - 1)) | |
464 | return; | |
465 | } | |
466 | } else { | |
cbe61d8a | 467 | rssi = BEACON_RSSI(ah); |
f1dc5600 S |
468 | if (rssi > aniState->rssiThrHigh) { |
469 | /* XXX: Handle me */ | |
470 | } else if (rssi > aniState->rssiThrLow) { | |
471 | if (aniState->ofdmWeakSigDetectOff) { | |
472 | if (ath9k_hw_ani_control(ah, | |
473 | ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
474 | true) == true) | |
475 | return; | |
476 | } | |
477 | if (aniState->firstepLevel > 0) { | |
478 | if (ath9k_hw_ani_control(ah, | |
479 | ATH9K_ANI_FIRSTEP_LEVEL, | |
480 | aniState->firstepLevel - 1) == true) | |
481 | return; | |
482 | } | |
483 | } else { | |
484 | if (aniState->firstepLevel > 0) { | |
485 | if (ath9k_hw_ani_control(ah, | |
486 | ATH9K_ANI_FIRSTEP_LEVEL, | |
487 | aniState->firstepLevel - 1) == true) | |
488 | return; | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | if (aniState->spurImmunityLevel > 0) { | |
494 | if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, | |
495 | aniState->spurImmunityLevel - 1)) | |
496 | return; | |
497 | } | |
498 | ||
499 | if (aniState->noiseImmunityLevel > 0) { | |
500 | ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, | |
501 | aniState->noiseImmunityLevel - 1); | |
502 | return; | |
503 | } | |
504 | } | |
505 | ||
e36b27af LR |
506 | /* |
507 | * only lower either OFDM or CCK errors per turn | |
508 | * we lower the other one next time | |
509 | */ | |
510 | static void ath9k_hw_ani_lower_immunity_new(struct ath_hw *ah) | |
511 | { | |
512 | struct ar5416AniState *aniState; | |
513 | ||
514 | aniState = ah->curani; | |
515 | ||
516 | /* lower OFDM noise immunity */ | |
517 | if (aniState->ofdmNoiseImmunityLevel > 0 && | |
518 | (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) { | |
519 | ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1); | |
520 | return; | |
521 | } | |
522 | ||
523 | /* lower CCK noise immunity */ | |
524 | if (aniState->cckNoiseImmunityLevel > 0) | |
525 | ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); | |
526 | } | |
527 | ||
37e5bf65 LR |
528 | static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah) |
529 | { | |
530 | struct ath9k_channel *chan = ah->curchan; | |
531 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; | |
532 | u8 clockrate; /* in MHz */ | |
533 | ||
534 | if (!ah->curchan) /* should really check for CCK instead */ | |
535 | clockrate = ATH9K_CLOCK_RATE_CCK; | |
536 | else if (conf->channel->band == IEEE80211_BAND_2GHZ) | |
537 | clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM; | |
538 | else if (IS_CHAN_A_FAST_CLOCK(ah, chan)) | |
539 | clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM; | |
540 | else | |
541 | clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM; | |
542 | ||
543 | if (conf_is_ht40(conf)) | |
544 | return clockrate * 2; | |
545 | ||
918df629 | 546 | return clockrate; |
37e5bf65 LR |
547 | } |
548 | ||
cbe61d8a | 549 | static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah) |
f1dc5600 | 550 | { |
f1dc5600 | 551 | struct ar5416AniState *aniState; |
e36b27af | 552 | struct ath_common *common = ath9k_hw_common(ah); |
f1dc5600 S |
553 | u32 txFrameCount, rxFrameCount, cycleCount; |
554 | int32_t listenTime; | |
555 | ||
556 | txFrameCount = REG_READ(ah, AR_TFCNT); | |
557 | rxFrameCount = REG_READ(ah, AR_RFCNT); | |
558 | cycleCount = REG_READ(ah, AR_CCCNT); | |
559 | ||
2660b81a | 560 | aniState = ah->curani; |
f1dc5600 | 561 | if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { |
f1dc5600 | 562 | listenTime = 0; |
2660b81a | 563 | ah->stats.ast_ani_lzero++; |
e36b27af LR |
564 | ath_print(common, ATH_DBG_ANI, |
565 | "1st call: aniState->cycleCount=%d\n", | |
566 | aniState->cycleCount); | |
f1dc5600 S |
567 | } else { |
568 | int32_t ccdelta = cycleCount - aniState->cycleCount; | |
569 | int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; | |
570 | int32_t tfdelta = txFrameCount - aniState->txFrameCount; | |
e36b27af | 571 | int32_t clock_rate; |
37e5bf65 LR |
572 | |
573 | /* | |
574 | * convert HW counter values to ms using mode | |
575 | * specifix clock rate | |
576 | */ | |
577 | clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;; | |
578 | ||
579 | listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate; | |
e36b27af LR |
580 | |
581 | ath_print(common, ATH_DBG_ANI, | |
582 | "cyclecount=%d, rfcount=%d, " | |
583 | "tfcount=%d, listenTime=%d CLOCK_RATE=%d\n", | |
584 | ccdelta, rfdelta, tfdelta, listenTime, clock_rate); | |
f1dc5600 | 585 | } |
e36b27af | 586 | |
f1dc5600 S |
587 | aniState->cycleCount = cycleCount; |
588 | aniState->txFrameCount = txFrameCount; | |
589 | aniState->rxFrameCount = rxFrameCount; | |
590 | ||
591 | return listenTime; | |
592 | } | |
593 | ||
40346b66 | 594 | static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) |
f1dc5600 | 595 | { |
f1dc5600 | 596 | struct ar5416AniState *aniState; |
2660b81a | 597 | struct ath9k_channel *chan = ah->curchan; |
c46917bb | 598 | struct ath_common *common = ath9k_hw_common(ah); |
f1dc5600 S |
599 | int index; |
600 | ||
601 | if (!DO_ANI(ah)) | |
602 | return; | |
603 | ||
604 | index = ath9k_hw_get_ani_channel_idx(ah, chan); | |
2660b81a S |
605 | aniState = &ah->ani[index]; |
606 | ah->curani = aniState; | |
f1dc5600 | 607 | |
2660b81a S |
608 | if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION |
609 | && ah->opmode != NL80211_IFTYPE_ADHOC) { | |
c46917bb LR |
610 | ath_print(common, ATH_DBG_ANI, |
611 | "Reset ANI state opmode %u\n", ah->opmode); | |
2660b81a | 612 | ah->stats.ast_ani_reset++; |
f1dc5600 | 613 | |
c66284f2 LR |
614 | if (ah->opmode == NL80211_IFTYPE_AP) { |
615 | /* | |
616 | * ath9k_hw_ani_control() will only process items set on | |
617 | * ah->ani_function | |
618 | */ | |
619 | if (IS_CHAN_2GHZ(chan)) | |
620 | ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | | |
621 | ATH9K_ANI_FIRSTEP_LEVEL); | |
622 | else | |
623 | ah->ani_function = 0; | |
624 | } | |
625 | ||
f1dc5600 S |
626 | ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); |
627 | ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); | |
628 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); | |
629 | ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
630 | !ATH9K_ANI_USE_OFDM_WEAK_SIG); | |
631 | ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, | |
632 | ATH9K_ANI_CCK_WEAK_SIG_THR); | |
633 | ||
634 | ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | | |
635 | ATH9K_RX_FILTER_PHYERR); | |
636 | ||
2660b81a S |
637 | if (ah->opmode == NL80211_IFTYPE_AP) { |
638 | ah->curani->ofdmTrigHigh = | |
639 | ah->config.ofdm_trig_high; | |
640 | ah->curani->ofdmTrigLow = | |
641 | ah->config.ofdm_trig_low; | |
642 | ah->curani->cckTrigHigh = | |
643 | ah->config.cck_trig_high; | |
644 | ah->curani->cckTrigLow = | |
645 | ah->config.cck_trig_low; | |
f1dc5600 | 646 | } |
e36b27af | 647 | ath9k_ani_restart_old(ah); |
f1dc5600 S |
648 | return; |
649 | } | |
650 | ||
651 | if (aniState->noiseImmunityLevel != 0) | |
652 | ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, | |
653 | aniState->noiseImmunityLevel); | |
654 | if (aniState->spurImmunityLevel != 0) | |
655 | ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, | |
656 | aniState->spurImmunityLevel); | |
657 | if (aniState->ofdmWeakSigDetectOff) | |
658 | ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, | |
659 | !aniState->ofdmWeakSigDetectOff); | |
660 | if (aniState->cckWeakSigThreshold) | |
661 | ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, | |
662 | aniState->cckWeakSigThreshold); | |
663 | if (aniState->firstepLevel != 0) | |
664 | ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, | |
665 | aniState->firstepLevel); | |
f1dc5600 | 666 | |
1aa8e847 S |
667 | ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & |
668 | ~ATH9K_RX_FILTER_PHYERR); | |
e36b27af LR |
669 | ath9k_ani_restart_old(ah); |
670 | ||
671 | ENABLE_REGWRITE_BUFFER(ah); | |
672 | ||
673 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | |
674 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | |
675 | ||
676 | REGWRITE_BUFFER_FLUSH(ah); | |
677 | DISABLE_REGWRITE_BUFFER(ah); | |
678 | } | |
679 | ||
680 | /* | |
681 | * Restore the ANI parameters in the HAL and reset the statistics. | |
682 | * This routine should be called for every hardware reset and for | |
683 | * every channel change. | |
684 | */ | |
685 | static void ath9k_ani_reset_new(struct ath_hw *ah, bool is_scanning) | |
686 | { | |
687 | struct ar5416AniState *aniState = ah->curani; | |
688 | struct ath9k_channel *chan = ah->curchan; | |
689 | struct ath_common *common = ath9k_hw_common(ah); | |
690 | ||
691 | if (!DO_ANI(ah)) | |
692 | return; | |
693 | ||
694 | BUG_ON(aniState == NULL); | |
695 | ah->stats.ast_ani_reset++; | |
696 | ||
697 | /* only allow a subset of functions in AP mode */ | |
698 | if (ah->opmode == NL80211_IFTYPE_AP) { | |
699 | if (IS_CHAN_2GHZ(chan)) { | |
700 | ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | | |
701 | ATH9K_ANI_FIRSTEP_LEVEL); | |
702 | if (AR_SREV_9300_20_OR_LATER(ah)) | |
703 | ah->ani_function |= ATH9K_ANI_MRC_CCK; | |
704 | } else | |
705 | ah->ani_function = 0; | |
706 | } | |
707 | ||
708 | /* always allow mode (on/off) to be controlled */ | |
709 | ah->ani_function |= ATH9K_ANI_MODE; | |
710 | ||
711 | if (is_scanning || | |
712 | (ah->opmode != NL80211_IFTYPE_STATION && | |
713 | ah->opmode != NL80211_IFTYPE_ADHOC)) { | |
714 | /* | |
715 | * If we're scanning or in AP mode, the defaults (ini) | |
716 | * should be in place. For an AP we assume the historical | |
717 | * levels for this channel are probably outdated so start | |
718 | * from defaults instead. | |
719 | */ | |
720 | if (aniState->ofdmNoiseImmunityLevel != | |
721 | ATH9K_ANI_OFDM_DEF_LEVEL || | |
722 | aniState->cckNoiseImmunityLevel != | |
723 | ATH9K_ANI_CCK_DEF_LEVEL) { | |
724 | ath_print(common, ATH_DBG_ANI, | |
725 | "Restore defaults: opmode %u " | |
726 | "chan %d Mhz/0x%x is_scanning=%d " | |
727 | "ofdm:%d cck:%d\n", | |
728 | ah->opmode, | |
729 | chan->channel, | |
730 | chan->channelFlags, | |
731 | is_scanning, | |
732 | aniState->ofdmNoiseImmunityLevel, | |
733 | aniState->cckNoiseImmunityLevel); | |
734 | ||
735 | ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); | |
736 | ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); | |
737 | } | |
738 | } else { | |
739 | /* | |
740 | * restore historical levels for this channel | |
741 | */ | |
742 | ath_print(common, ATH_DBG_ANI, | |
743 | "Restore history: opmode %u " | |
744 | "chan %d Mhz/0x%x is_scanning=%d " | |
745 | "ofdm:%d cck:%d\n", | |
746 | ah->opmode, | |
747 | chan->channel, | |
748 | chan->channelFlags, | |
749 | is_scanning, | |
750 | aniState->ofdmNoiseImmunityLevel, | |
751 | aniState->cckNoiseImmunityLevel); | |
752 | ||
753 | ath9k_hw_set_ofdm_nil(ah, | |
754 | aniState->ofdmNoiseImmunityLevel); | |
755 | ath9k_hw_set_cck_nil(ah, | |
756 | aniState->cckNoiseImmunityLevel); | |
757 | } | |
758 | ||
759 | /* | |
760 | * enable phy counters if hw supports or if not, enable phy | |
761 | * interrupts (so we can count each one) | |
762 | */ | |
763 | ath9k_ani_restart_new(ah); | |
7d0d0df0 S |
764 | |
765 | ENABLE_REGWRITE_BUFFER(ah); | |
766 | ||
1aa8e847 S |
767 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); |
768 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | |
7d0d0df0 S |
769 | |
770 | REGWRITE_BUFFER_FLUSH(ah); | |
771 | DISABLE_REGWRITE_BUFFER(ah); | |
f1dc5600 S |
772 | } |
773 | ||
ac0bb767 LR |
774 | static void ath9k_hw_ani_monitor_old(struct ath_hw *ah, |
775 | struct ath9k_channel *chan) | |
f1dc5600 | 776 | { |
f1dc5600 | 777 | struct ar5416AniState *aniState; |
c46917bb | 778 | struct ath_common *common = ath9k_hw_common(ah); |
f1dc5600 | 779 | int32_t listenTime; |
1aa8e847 S |
780 | u32 phyCnt1, phyCnt2; |
781 | u32 ofdmPhyErrCnt, cckPhyErrCnt; | |
f1dc5600 | 782 | |
99506882 GJ |
783 | if (!DO_ANI(ah)) |
784 | return; | |
785 | ||
2660b81a | 786 | aniState = ah->curani; |
f1dc5600 S |
787 | |
788 | listenTime = ath9k_hw_ani_get_listen_time(ah); | |
789 | if (listenTime < 0) { | |
2660b81a | 790 | ah->stats.ast_ani_lneg++; |
e36b27af | 791 | ath9k_ani_restart_old(ah); |
f1dc5600 S |
792 | return; |
793 | } | |
794 | ||
795 | aniState->listenTime += listenTime; | |
796 | ||
1aa8e847 | 797 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
f1dc5600 | 798 | |
1aa8e847 S |
799 | phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); |
800 | phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); | |
801 | ||
802 | if (phyCnt1 < aniState->ofdmPhyErrBase || | |
803 | phyCnt2 < aniState->cckPhyErrBase) { | |
804 | if (phyCnt1 < aniState->ofdmPhyErrBase) { | |
c46917bb LR |
805 | ath_print(common, ATH_DBG_ANI, |
806 | "phyCnt1 0x%x, resetting " | |
807 | "counter value to 0x%x\n", | |
808 | phyCnt1, | |
809 | aniState->ofdmPhyErrBase); | |
1aa8e847 S |
810 | REG_WRITE(ah, AR_PHY_ERR_1, |
811 | aniState->ofdmPhyErrBase); | |
812 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, | |
813 | AR_PHY_ERR_OFDM_TIMING); | |
814 | } | |
815 | if (phyCnt2 < aniState->cckPhyErrBase) { | |
c46917bb LR |
816 | ath_print(common, ATH_DBG_ANI, |
817 | "phyCnt2 0x%x, resetting " | |
818 | "counter value to 0x%x\n", | |
819 | phyCnt2, | |
820 | aniState->cckPhyErrBase); | |
1aa8e847 S |
821 | REG_WRITE(ah, AR_PHY_ERR_2, |
822 | aniState->cckPhyErrBase); | |
823 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, | |
824 | AR_PHY_ERR_CCK_TIMING); | |
f1dc5600 | 825 | } |
1aa8e847 S |
826 | return; |
827 | } | |
f1dc5600 | 828 | |
1aa8e847 S |
829 | ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; |
830 | ah->stats.ast_ani_ofdmerrs += | |
831 | ofdmPhyErrCnt - aniState->ofdmPhyErrCount; | |
832 | aniState->ofdmPhyErrCount = ofdmPhyErrCnt; | |
f1dc5600 | 833 | |
1aa8e847 S |
834 | cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; |
835 | ah->stats.ast_ani_cckerrs += | |
836 | cckPhyErrCnt - aniState->cckPhyErrCount; | |
837 | aniState->cckPhyErrCount = cckPhyErrCnt; | |
f1dc5600 | 838 | |
2660b81a | 839 | if (aniState->listenTime > 5 * ah->aniperiod) { |
f1dc5600 S |
840 | if (aniState->ofdmPhyErrCount <= aniState->listenTime * |
841 | aniState->ofdmTrigLow / 1000 && | |
842 | aniState->cckPhyErrCount <= aniState->listenTime * | |
843 | aniState->cckTrigLow / 1000) | |
844 | ath9k_hw_ani_lower_immunity(ah); | |
e36b27af | 845 | ath9k_ani_restart_old(ah); |
2660b81a | 846 | } else if (aniState->listenTime > ah->aniperiod) { |
f1dc5600 S |
847 | if (aniState->ofdmPhyErrCount > aniState->listenTime * |
848 | aniState->ofdmTrigHigh / 1000) { | |
e36b27af LR |
849 | ath9k_hw_ani_ofdm_err_trigger_old(ah); |
850 | ath9k_ani_restart_old(ah); | |
f1dc5600 S |
851 | } else if (aniState->cckPhyErrCount > |
852 | aniState->listenTime * aniState->cckTrigHigh / | |
853 | 1000) { | |
e36b27af LR |
854 | ath9k_hw_ani_cck_err_trigger_old(ah); |
855 | ath9k_ani_restart_old(ah); | |
856 | } | |
857 | } | |
858 | } | |
859 | ||
860 | static void ath9k_hw_ani_monitor_new(struct ath_hw *ah, | |
861 | struct ath9k_channel *chan) | |
862 | { | |
863 | struct ar5416AniState *aniState; | |
864 | struct ath_common *common = ath9k_hw_common(ah); | |
865 | int32_t listenTime; | |
866 | u32 phyCnt1, phyCnt2; | |
867 | u32 ofdmPhyErrCnt, cckPhyErrCnt; | |
868 | u32 ofdmPhyErrRate, cckPhyErrRate; | |
869 | ||
870 | if (!DO_ANI(ah)) | |
871 | return; | |
872 | ||
873 | aniState = ah->curani; | |
874 | if (WARN_ON(!aniState)) | |
875 | return; | |
876 | ||
877 | listenTime = ath9k_hw_ani_get_listen_time(ah); | |
878 | if (listenTime <= 0) { | |
879 | ah->stats.ast_ani_lneg++; | |
880 | /* restart ANI period if listenTime is invalid */ | |
881 | ath_print(common, ATH_DBG_ANI, | |
882 | "listenTime=%d - on new ani monitor\n", | |
883 | listenTime); | |
884 | ath9k_ani_restart_new(ah); | |
885 | return; | |
886 | } | |
887 | ||
888 | aniState->listenTime += listenTime; | |
889 | ||
890 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | |
891 | ||
892 | phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); | |
893 | phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); | |
894 | ||
895 | if (phyCnt1 < aniState->ofdmPhyErrBase || | |
896 | phyCnt2 < aniState->cckPhyErrBase) { | |
897 | if (phyCnt1 < aniState->ofdmPhyErrBase) { | |
898 | ath_print(common, ATH_DBG_ANI, | |
899 | "phyCnt1 0x%x, resetting " | |
900 | "counter value to 0x%x\n", | |
901 | phyCnt1, | |
902 | aniState->ofdmPhyErrBase); | |
903 | REG_WRITE(ah, AR_PHY_ERR_1, | |
904 | aniState->ofdmPhyErrBase); | |
905 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, | |
906 | AR_PHY_ERR_OFDM_TIMING); | |
907 | } | |
908 | if (phyCnt2 < aniState->cckPhyErrBase) { | |
909 | ath_print(common, ATH_DBG_ANI, | |
910 | "phyCnt2 0x%x, resetting " | |
911 | "counter value to 0x%x\n", | |
912 | phyCnt2, | |
913 | aniState->cckPhyErrBase); | |
914 | REG_WRITE(ah, AR_PHY_ERR_2, | |
915 | aniState->cckPhyErrBase); | |
916 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, | |
917 | AR_PHY_ERR_CCK_TIMING); | |
918 | } | |
919 | return; | |
920 | } | |
921 | ||
922 | ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; | |
923 | ah->stats.ast_ani_ofdmerrs += | |
924 | ofdmPhyErrCnt - aniState->ofdmPhyErrCount; | |
925 | aniState->ofdmPhyErrCount = ofdmPhyErrCnt; | |
926 | ||
927 | cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; | |
928 | ah->stats.ast_ani_cckerrs += | |
929 | cckPhyErrCnt - aniState->cckPhyErrCount; | |
930 | aniState->cckPhyErrCount = cckPhyErrCnt; | |
931 | ||
932 | ath_print(common, ATH_DBG_ANI, | |
933 | "Errors: OFDM=0x%08x-0x%08x=%d " | |
934 | "CCK=0x%08x-0x%08x=%d\n", | |
935 | phyCnt1, | |
936 | aniState->ofdmPhyErrBase, | |
937 | ofdmPhyErrCnt, | |
938 | phyCnt2, | |
939 | aniState->cckPhyErrBase, | |
940 | cckPhyErrCnt); | |
941 | ||
942 | ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 / | |
943 | aniState->listenTime; | |
944 | cckPhyErrRate = aniState->cckPhyErrCount * 1000 / | |
945 | aniState->listenTime; | |
946 | ||
947 | ath_print(common, ATH_DBG_ANI, | |
948 | "listenTime=%d OFDM:%d errs=%d/s CCK:%d " | |
949 | "errs=%d/s ofdm_turn=%d\n", | |
950 | listenTime, aniState->ofdmNoiseImmunityLevel, | |
951 | ofdmPhyErrRate, aniState->cckNoiseImmunityLevel, | |
952 | cckPhyErrRate, aniState->ofdmsTurn); | |
953 | ||
954 | if (aniState->listenTime > 5 * ah->aniperiod) { | |
955 | if (ofdmPhyErrRate <= aniState->ofdmTrigLow && | |
956 | cckPhyErrRate <= aniState->cckTrigLow) { | |
957 | ath_print(common, ATH_DBG_ANI, | |
958 | "1. listenTime=%d OFDM:%d errs=%d/s(<%d) " | |
959 | "CCK:%d errs=%d/s(<%d) -> " | |
960 | "ath9k_hw_ani_lower_immunity()\n", | |
961 | aniState->listenTime, | |
962 | aniState->ofdmNoiseImmunityLevel, | |
963 | ofdmPhyErrRate, | |
964 | aniState->ofdmTrigLow, | |
965 | aniState->cckNoiseImmunityLevel, | |
966 | cckPhyErrRate, | |
967 | aniState->cckTrigLow); | |
968 | ath9k_hw_ani_lower_immunity(ah); | |
969 | aniState->ofdmsTurn = !aniState->ofdmsTurn; | |
970 | } | |
971 | ath_print(common, ATH_DBG_ANI, | |
972 | "1 listenTime=%d ofdm=%d/s cck=%d/s - " | |
973 | "calling ath9k_ani_restart_new()\n", | |
974 | aniState->listenTime, ofdmPhyErrRate, cckPhyErrRate); | |
975 | ath9k_ani_restart_new(ah); | |
976 | } else if (aniState->listenTime > ah->aniperiod) { | |
977 | /* check to see if need to raise immunity */ | |
978 | if (ofdmPhyErrRate > aniState->ofdmTrigHigh && | |
979 | (cckPhyErrRate <= aniState->cckTrigHigh || | |
980 | aniState->ofdmsTurn)) { | |
981 | ath_print(common, ATH_DBG_ANI, | |
982 | "2 listenTime=%d OFDM:%d errs=%d/s(>%d) -> " | |
983 | "ath9k_hw_ani_ofdm_err_trigger_new()\n", | |
984 | aniState->listenTime, | |
985 | aniState->ofdmNoiseImmunityLevel, | |
986 | ofdmPhyErrRate, | |
987 | aniState->ofdmTrigHigh); | |
988 | ath9k_hw_ani_ofdm_err_trigger_new(ah); | |
989 | ath9k_ani_restart_new(ah); | |
990 | aniState->ofdmsTurn = false; | |
991 | } else if (cckPhyErrRate > aniState->cckTrigHigh) { | |
992 | ath_print(common, ATH_DBG_ANI, | |
993 | "3 listenTime=%d CCK:%d errs=%d/s(>%d) -> " | |
994 | "ath9k_hw_ani_cck_err_trigger_new()\n", | |
995 | aniState->listenTime, | |
996 | aniState->cckNoiseImmunityLevel, | |
997 | cckPhyErrRate, | |
998 | aniState->cckTrigHigh); | |
999 | ath9k_hw_ani_cck_err_trigger_new(ah); | |
1000 | ath9k_ani_restart_new(ah); | |
1001 | aniState->ofdmsTurn = true; | |
f1dc5600 S |
1002 | } |
1003 | } | |
1004 | } | |
1005 | ||
cbe61d8a | 1006 | void ath9k_enable_mib_counters(struct ath_hw *ah) |
f1dc5600 | 1007 | { |
c46917bb LR |
1008 | struct ath_common *common = ath9k_hw_common(ah); |
1009 | ||
1010 | ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n"); | |
f1dc5600 | 1011 | |
cbe61d8a | 1012 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
f1dc5600 | 1013 | |
7d0d0df0 S |
1014 | ENABLE_REGWRITE_BUFFER(ah); |
1015 | ||
f1dc5600 S |
1016 | REG_WRITE(ah, AR_FILT_OFDM, 0); |
1017 | REG_WRITE(ah, AR_FILT_CCK, 0); | |
1018 | REG_WRITE(ah, AR_MIBC, | |
1019 | ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) | |
1020 | & 0x0f); | |
1021 | REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); | |
1022 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | |
7d0d0df0 S |
1023 | |
1024 | REGWRITE_BUFFER_FLUSH(ah); | |
1025 | DISABLE_REGWRITE_BUFFER(ah); | |
f1dc5600 S |
1026 | } |
1027 | ||
0fd06c90 | 1028 | /* Freeze the MIB counters, get the stats and then clear them */ |
cbe61d8a | 1029 | void ath9k_hw_disable_mib_counters(struct ath_hw *ah) |
f1dc5600 | 1030 | { |
c46917bb LR |
1031 | struct ath_common *common = ath9k_hw_common(ah); |
1032 | ||
1033 | ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n"); | |
1034 | ||
0fd06c90 | 1035 | REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); |
cbe61d8a | 1036 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
0fd06c90 | 1037 | REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); |
f1dc5600 S |
1038 | REG_WRITE(ah, AR_FILT_OFDM, 0); |
1039 | REG_WRITE(ah, AR_FILT_CCK, 0); | |
1040 | } | |
21d5130b | 1041 | EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); |
f1dc5600 | 1042 | |
cbe61d8a | 1043 | u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, |
f1dc5600 S |
1044 | u32 *rxc_pcnt, |
1045 | u32 *rxf_pcnt, | |
1046 | u32 *txf_pcnt) | |
1047 | { | |
c46917bb | 1048 | struct ath_common *common = ath9k_hw_common(ah); |
f1dc5600 S |
1049 | static u32 cycles, rx_clear, rx_frame, tx_frame; |
1050 | u32 good = 1; | |
1051 | ||
1052 | u32 rc = REG_READ(ah, AR_RCCNT); | |
1053 | u32 rf = REG_READ(ah, AR_RFCNT); | |
1054 | u32 tf = REG_READ(ah, AR_TFCNT); | |
1055 | u32 cc = REG_READ(ah, AR_CCCNT); | |
1056 | ||
1057 | if (cycles == 0 || cycles > cc) { | |
c46917bb LR |
1058 | ath_print(common, ATH_DBG_ANI, |
1059 | "cycle counter wrap. ExtBusy = 0\n"); | |
f1dc5600 S |
1060 | good = 0; |
1061 | } else { | |
1062 | u32 cc_d = cc - cycles; | |
1063 | u32 rc_d = rc - rx_clear; | |
1064 | u32 rf_d = rf - rx_frame; | |
1065 | u32 tf_d = tf - tx_frame; | |
1066 | ||
1067 | if (cc_d != 0) { | |
1068 | *rxc_pcnt = rc_d * 100 / cc_d; | |
1069 | *rxf_pcnt = rf_d * 100 / cc_d; | |
1070 | *txf_pcnt = tf_d * 100 / cc_d; | |
1071 | } else { | |
1072 | good = 0; | |
1073 | } | |
1074 | } | |
1075 | ||
1076 | cycles = cc; | |
1077 | rx_frame = rf; | |
1078 | rx_clear = rc; | |
1079 | tx_frame = tf; | |
1080 | ||
1081 | return good; | |
1082 | } | |
1083 | ||
1084 | /* | |
1085 | * Process a MIB interrupt. We may potentially be invoked because | |
1086 | * any of the MIB counters overflow/trigger so don't assume we're | |
1087 | * here because a PHY error counter triggered. | |
1088 | */ | |
ac0bb767 | 1089 | static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah) |
f1dc5600 | 1090 | { |
f1dc5600 S |
1091 | u32 phyCnt1, phyCnt2; |
1092 | ||
1093 | /* Reset these counters regardless */ | |
1094 | REG_WRITE(ah, AR_FILT_OFDM, 0); | |
1095 | REG_WRITE(ah, AR_FILT_CCK, 0); | |
1096 | if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) | |
1097 | REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); | |
1098 | ||
1099 | /* Clear the mib counters and save them in the stats */ | |
cbe61d8a | 1100 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
f1dc5600 | 1101 | |
6e97f0fb LR |
1102 | if (!DO_ANI(ah)) { |
1103 | /* | |
1104 | * We must always clear the interrupt cause by | |
1105 | * resetting the phy error regs. | |
1106 | */ | |
1107 | REG_WRITE(ah, AR_PHY_ERR_1, 0); | |
1108 | REG_WRITE(ah, AR_PHY_ERR_2, 0); | |
f1dc5600 | 1109 | return; |
6e97f0fb | 1110 | } |
f1dc5600 S |
1111 | |
1112 | /* NB: these are not reset-on-read */ | |
1113 | phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); | |
1114 | phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); | |
1115 | if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || | |
1116 | ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { | |
2660b81a | 1117 | struct ar5416AniState *aniState = ah->curani; |
f1dc5600 S |
1118 | u32 ofdmPhyErrCnt, cckPhyErrCnt; |
1119 | ||
1120 | /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ | |
1121 | ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; | |
2660b81a | 1122 | ah->stats.ast_ani_ofdmerrs += |
f1dc5600 S |
1123 | ofdmPhyErrCnt - aniState->ofdmPhyErrCount; |
1124 | aniState->ofdmPhyErrCount = ofdmPhyErrCnt; | |
1125 | ||
1126 | cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; | |
2660b81a | 1127 | ah->stats.ast_ani_cckerrs += |
f1dc5600 S |
1128 | cckPhyErrCnt - aniState->cckPhyErrCount; |
1129 | aniState->cckPhyErrCount = cckPhyErrCnt; | |
1130 | ||
1131 | /* | |
1132 | * NB: figure out which counter triggered. If both | |
1133 | * trigger we'll only deal with one as the processing | |
1134 | * clobbers the error counter so the trigger threshold | |
1135 | * check will never be true. | |
1136 | */ | |
1137 | if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) | |
e36b27af | 1138 | ath9k_hw_ani_ofdm_err_trigger_new(ah); |
f1dc5600 | 1139 | if (aniState->cckPhyErrCount > aniState->cckTrigHigh) |
e36b27af | 1140 | ath9k_hw_ani_cck_err_trigger_old(ah); |
f1dc5600 | 1141 | /* NB: always restart to insure the h/w counters are reset */ |
e36b27af | 1142 | ath9k_ani_restart_old(ah); |
f1dc5600 S |
1143 | } |
1144 | } | |
1145 | ||
e36b27af LR |
1146 | /* |
1147 | * Process a MIB interrupt. We may potentially be invoked because | |
1148 | * any of the MIB counters overflow/trigger so don't assume we're | |
1149 | * here because a PHY error counter triggered. | |
1150 | */ | |
1151 | static void ath9k_hw_proc_mib_event_new(struct ath_hw *ah) | |
1152 | { | |
1153 | u32 phyCnt1, phyCnt2; | |
1154 | ||
1155 | /* Reset these counters regardless */ | |
1156 | REG_WRITE(ah, AR_FILT_OFDM, 0); | |
1157 | REG_WRITE(ah, AR_FILT_CCK, 0); | |
1158 | if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) | |
1159 | REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); | |
1160 | ||
1161 | /* Clear the mib counters and save them in the stats */ | |
1162 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | |
1163 | ||
1164 | if (!DO_ANI(ah)) { | |
1165 | /* | |
1166 | * We must always clear the interrupt cause by | |
1167 | * resetting the phy error regs. | |
1168 | */ | |
1169 | REG_WRITE(ah, AR_PHY_ERR_1, 0); | |
1170 | REG_WRITE(ah, AR_PHY_ERR_2, 0); | |
1171 | return; | |
1172 | } | |
1173 | ||
1174 | /* NB: these are not reset-on-read */ | |
1175 | phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); | |
1176 | phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); | |
1177 | ||
1178 | /* NB: always restart to insure the h/w counters are reset */ | |
1179 | if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || | |
1180 | ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) | |
1181 | ath9k_ani_restart_new(ah); | |
1182 | } | |
1183 | ||
cbe61d8a | 1184 | void ath9k_hw_ani_setup(struct ath_hw *ah) |
f1dc5600 | 1185 | { |
f1dc5600 S |
1186 | int i; |
1187 | ||
1188 | const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; | |
1189 | const int coarseHigh[] = { -14, -14, -14, -14, -12 }; | |
1190 | const int coarseLow[] = { -64, -64, -64, -64, -70 }; | |
1191 | const int firpwr[] = { -78, -78, -78, -78, -80 }; | |
1192 | ||
1193 | for (i = 0; i < 5; i++) { | |
2660b81a S |
1194 | ah->totalSizeDesired[i] = totalSizeDesired[i]; |
1195 | ah->coarse_high[i] = coarseHigh[i]; | |
1196 | ah->coarse_low[i] = coarseLow[i]; | |
1197 | ah->firpwr[i] = firpwr[i]; | |
f1dc5600 S |
1198 | } |
1199 | } | |
1200 | ||
f637cfd6 | 1201 | void ath9k_hw_ani_init(struct ath_hw *ah) |
f1dc5600 | 1202 | { |
c46917bb | 1203 | struct ath_common *common = ath9k_hw_common(ah); |
f1dc5600 S |
1204 | int i; |
1205 | ||
c46917bb | 1206 | ath_print(common, ATH_DBG_ANI, "Initialize ANI\n"); |
2660b81a S |
1207 | |
1208 | memset(ah->ani, 0, sizeof(ah->ani)); | |
1209 | for (i = 0; i < ARRAY_SIZE(ah->ani); i++) { | |
e36b27af LR |
1210 | if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) { |
1211 | ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; | |
1212 | ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_NEW; | |
1213 | ||
1214 | ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_NEW; | |
1215 | ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_NEW; | |
1216 | ||
1217 | ah->ani[i].spurImmunityLevel = | |
1218 | ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; | |
1219 | ||
1220 | ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; | |
1221 | ||
1222 | ah->ani[i].ofdmPhyErrBase = 0; | |
1223 | ah->ani[i].cckPhyErrBase = 0; | |
1224 | ||
1225 | if (AR_SREV_9300_20_OR_LATER(ah)) | |
1226 | ah->ani[i].mrcCCKOff = | |
1227 | !ATH9K_ANI_ENABLE_MRC_CCK; | |
1228 | else | |
1229 | ah->ani[i].mrcCCKOff = true; | |
1230 | ||
1231 | ah->ani[i].ofdmsTurn = true; | |
1232 | } else { | |
1233 | ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; | |
1234 | ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW_OLD; | |
1235 | ||
1236 | ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH_OLD; | |
1237 | ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW_OLD; | |
1238 | ||
1239 | ah->ani[i].spurImmunityLevel = | |
1240 | ATH9K_ANI_SPUR_IMMUNE_LVL_OLD; | |
1241 | ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; | |
1242 | ||
1243 | ah->ani[i].ofdmPhyErrBase = | |
1244 | AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH_OLD; | |
1245 | ah->ani[i].cckPhyErrBase = | |
1246 | AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH_OLD; | |
1247 | ah->ani[i].cckWeakSigThreshold = | |
1248 | ATH9K_ANI_CCK_WEAK_SIG_THR; | |
1249 | } | |
1250 | ||
2660b81a S |
1251 | ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; |
1252 | ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; | |
1253 | ah->ani[i].ofdmWeakSigDetectOff = | |
f1dc5600 | 1254 | !ATH9K_ANI_USE_OFDM_WEAK_SIG; |
e36b27af LR |
1255 | ah->ani[i].cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; |
1256 | } | |
1257 | ||
1258 | /* | |
1259 | * since we expect some ongoing maintenance on the tables, let's sanity | |
1260 | * check here default level should not modify INI setting. | |
1261 | */ | |
1262 | if (AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani) { | |
1263 | const struct ani_ofdm_level_entry *entry_ofdm; | |
1264 | const struct ani_cck_level_entry *entry_cck; | |
1265 | ||
1266 | entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL]; | |
1267 | entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL]; | |
1268 | ||
1269 | ah->aniperiod = ATH9K_ANI_PERIOD_NEW; | |
1270 | ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; | |
1271 | } else { | |
1272 | ah->aniperiod = ATH9K_ANI_PERIOD_OLD; | |
1273 | ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD; | |
f1dc5600 | 1274 | } |
1aa8e847 | 1275 | |
c46917bb LR |
1276 | ath_print(common, ATH_DBG_ANI, |
1277 | "Setting OfdmErrBase = 0x%08x\n", | |
1278 | ah->ani[0].ofdmPhyErrBase); | |
1279 | ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", | |
1280 | ah->ani[0].cckPhyErrBase); | |
1aa8e847 | 1281 | |
7d0d0df0 S |
1282 | ENABLE_REGWRITE_BUFFER(ah); |
1283 | ||
1aa8e847 S |
1284 | REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase); |
1285 | REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase); | |
7d0d0df0 S |
1286 | |
1287 | REGWRITE_BUFFER_FLUSH(ah); | |
1288 | DISABLE_REGWRITE_BUFFER(ah); | |
1289 | ||
1aa8e847 S |
1290 | ath9k_enable_mib_counters(ah); |
1291 | ||
2660b81a S |
1292 | if (ah->config.enable_ani) |
1293 | ah->proc_phyerr |= HAL_PROCESS_ANI; | |
f1dc5600 | 1294 | } |
ac0bb767 LR |
1295 | |
1296 | void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah) | |
1297 | { | |
1298 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); | |
1299 | struct ath_hw_ops *ops = ath9k_hw_ops(ah); | |
1300 | ||
1301 | priv_ops->ani_reset = ath9k_ani_reset_old; | |
1302 | priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old; | |
1303 | ||
1304 | ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old; | |
1305 | ops->ani_monitor = ath9k_hw_ani_monitor_old; | |
e36b27af LR |
1306 | |
1307 | ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v1\n"); | |
1308 | } | |
1309 | ||
1310 | void ath9k_hw_attach_ani_ops_new(struct ath_hw *ah) | |
1311 | { | |
1312 | struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); | |
1313 | struct ath_hw_ops *ops = ath9k_hw_ops(ah); | |
1314 | ||
1315 | priv_ops->ani_reset = ath9k_ani_reset_new; | |
1316 | priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_new; | |
1317 | ||
1318 | ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_new; | |
1319 | ops->ani_monitor = ath9k_hw_ani_monitor_new; | |
1320 | ||
1321 | ath_print(ath9k_hw_common(ah), ATH_DBG_ANY, "Using ANI v2\n"); | |
ac0bb767 | 1322 | } |