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