Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[deliverable/linux.git] / drivers / net / wireless / ath / ath9k / ani.c
1 /*
2 * Copyright (c) 2008-2009 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "ath9k.h"
18
19 static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
20 struct ath9k_channel *chan)
21 {
22 int i;
23
24 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
25 if (ah->ani[i].c &&
26 ah->ani[i].c->channel == chan->channel)
27 return i;
28 if (ah->ani[i].c == NULL) {
29 ah->ani[i].c = chan;
30 return i;
31 }
32 }
33
34 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
35 "No more channel states left. Using channel 0\n");
36
37 return 0;
38 }
39
40 static bool ath9k_hw_ani_control(struct ath_hw *ah,
41 enum ath9k_ani_cmd cmd, int param)
42 {
43 struct ar5416AniState *aniState = ah->curani;
44
45 switch (cmd & ah->ani_function) {
46 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
47 u32 level = param;
48
49 if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
50 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
51 "level out of range (%u > %u)\n",
52 level,
53 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
54 return false;
55 }
56
57 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
58 AR_PHY_DESIRED_SZ_TOT_DES,
59 ah->totalSizeDesired[level]);
60 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
61 AR_PHY_AGC_CTL1_COARSE_LOW,
62 ah->coarse_low[level]);
63 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
64 AR_PHY_AGC_CTL1_COARSE_HIGH,
65 ah->coarse_high[level]);
66 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
67 AR_PHY_FIND_SIG_FIRPWR,
68 ah->firpwr[level]);
69
70 if (level > aniState->noiseImmunityLevel)
71 ah->stats.ast_ani_niup++;
72 else if (level < aniState->noiseImmunityLevel)
73 ah->stats.ast_ani_nidown++;
74 aniState->noiseImmunityLevel = level;
75 break;
76 }
77 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
78 const int m1ThreshLow[] = { 127, 50 };
79 const int m2ThreshLow[] = { 127, 40 };
80 const int m1Thresh[] = { 127, 0x4d };
81 const int m2Thresh[] = { 127, 0x40 };
82 const int m2CountThr[] = { 31, 16 };
83 const int m2CountThrLow[] = { 63, 48 };
84 u32 on = param ? 1 : 0;
85
86 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
87 AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
88 m1ThreshLow[on]);
89 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
90 AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
91 m2ThreshLow[on]);
92 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
93 AR_PHY_SFCORR_M1_THRESH,
94 m1Thresh[on]);
95 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
96 AR_PHY_SFCORR_M2_THRESH,
97 m2Thresh[on]);
98 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
99 AR_PHY_SFCORR_M2COUNT_THR,
100 m2CountThr[on]);
101 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
102 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
103 m2CountThrLow[on]);
104
105 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
106 AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
107 m1ThreshLow[on]);
108 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
109 AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
110 m2ThreshLow[on]);
111 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
112 AR_PHY_SFCORR_EXT_M1_THRESH,
113 m1Thresh[on]);
114 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
115 AR_PHY_SFCORR_EXT_M2_THRESH,
116 m2Thresh[on]);
117
118 if (on)
119 REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
120 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
121 else
122 REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
123 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
124
125 if (!on != aniState->ofdmWeakSigDetectOff) {
126 if (on)
127 ah->stats.ast_ani_ofdmon++;
128 else
129 ah->stats.ast_ani_ofdmoff++;
130 aniState->ofdmWeakSigDetectOff = !on;
131 }
132 break;
133 }
134 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
135 const int weakSigThrCck[] = { 8, 6 };
136 u32 high = param ? 1 : 0;
137
138 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
139 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
140 weakSigThrCck[high]);
141 if (high != aniState->cckWeakSigThreshold) {
142 if (high)
143 ah->stats.ast_ani_cckhigh++;
144 else
145 ah->stats.ast_ani_ccklow++;
146 aniState->cckWeakSigThreshold = high;
147 }
148 break;
149 }
150 case ATH9K_ANI_FIRSTEP_LEVEL:{
151 const int firstep[] = { 0, 4, 8 };
152 u32 level = param;
153
154 if (level >= ARRAY_SIZE(firstep)) {
155 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
156 "level out of range (%u > %u)\n",
157 level,
158 (unsigned) ARRAY_SIZE(firstep));
159 return false;
160 }
161 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
162 AR_PHY_FIND_SIG_FIRSTEP,
163 firstep[level]);
164 if (level > aniState->firstepLevel)
165 ah->stats.ast_ani_stepup++;
166 else if (level < aniState->firstepLevel)
167 ah->stats.ast_ani_stepdown++;
168 aniState->firstepLevel = level;
169 break;
170 }
171 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
172 const int cycpwrThr1[] =
173 { 2, 4, 6, 8, 10, 12, 14, 16 };
174 u32 level = param;
175
176 if (level >= ARRAY_SIZE(cycpwrThr1)) {
177 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
178 "level out of range (%u > %u)\n",
179 level,
180 (unsigned)
181 ARRAY_SIZE(cycpwrThr1));
182 return false;
183 }
184 REG_RMW_FIELD(ah, AR_PHY_TIMING5,
185 AR_PHY_TIMING5_CYCPWR_THR1,
186 cycpwrThr1[level]);
187 if (level > aniState->spurImmunityLevel)
188 ah->stats.ast_ani_spurup++;
189 else if (level < aniState->spurImmunityLevel)
190 ah->stats.ast_ani_spurdown++;
191 aniState->spurImmunityLevel = level;
192 break;
193 }
194 case ATH9K_ANI_PRESENT:
195 break;
196 default:
197 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
198 "invalid cmd %u\n", cmd);
199 return false;
200 }
201
202 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
203 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
204 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
205 "ofdmWeakSigDetectOff=%d\n",
206 aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
207 !aniState->ofdmWeakSigDetectOff);
208 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
209 "cckWeakSigThreshold=%d, "
210 "firstepLevel=%d, listenTime=%d\n",
211 aniState->cckWeakSigThreshold, aniState->firstepLevel,
212 aniState->listenTime);
213 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
214 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
215 aniState->cycleCount, aniState->ofdmPhyErrCount,
216 aniState->cckPhyErrCount);
217
218 return true;
219 }
220
221 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
222 struct ath9k_mib_stats *stats)
223 {
224 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
225 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
226 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
227 stats->rts_good += REG_READ(ah, AR_RTS_OK);
228 stats->beacons += REG_READ(ah, AR_BEACON_CNT);
229 }
230
231 static void ath9k_ani_restart(struct ath_hw *ah)
232 {
233 struct ar5416AniState *aniState;
234
235 if (!DO_ANI(ah))
236 return;
237
238 aniState = ah->curani;
239 aniState->listenTime = 0;
240
241 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
242 aniState->ofdmPhyErrBase = 0;
243 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
244 "OFDM Trigger is too high for hw counters\n");
245 } else {
246 aniState->ofdmPhyErrBase =
247 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
248 }
249 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
250 aniState->cckPhyErrBase = 0;
251 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
252 "CCK Trigger is too high for hw counters\n");
253 } else {
254 aniState->cckPhyErrBase =
255 AR_PHY_COUNTMAX - aniState->cckTrigHigh;
256 }
257 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
258 "Writing ofdmbase=%u cckbase=%u\n",
259 aniState->ofdmPhyErrBase,
260 aniState->cckPhyErrBase);
261 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
262 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
263 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
264 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
265
266 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
267
268 aniState->ofdmPhyErrCount = 0;
269 aniState->cckPhyErrCount = 0;
270 }
271
272 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
273 {
274 struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
275 struct ar5416AniState *aniState;
276 int32_t rssi;
277
278 if (!DO_ANI(ah))
279 return;
280
281 aniState = ah->curani;
282
283 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
284 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
285 aniState->noiseImmunityLevel + 1)) {
286 return;
287 }
288 }
289
290 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
291 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
292 aniState->spurImmunityLevel + 1)) {
293 return;
294 }
295 }
296
297 if (ah->opmode == NL80211_IFTYPE_AP) {
298 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
299 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
300 aniState->firstepLevel + 1);
301 }
302 return;
303 }
304 rssi = BEACON_RSSI(ah);
305 if (rssi > aniState->rssiThrHigh) {
306 if (!aniState->ofdmWeakSigDetectOff) {
307 if (ath9k_hw_ani_control(ah,
308 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
309 false)) {
310 ath9k_hw_ani_control(ah,
311 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
312 return;
313 }
314 }
315 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
316 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
317 aniState->firstepLevel + 1);
318 return;
319 }
320 } else if (rssi > aniState->rssiThrLow) {
321 if (aniState->ofdmWeakSigDetectOff)
322 ath9k_hw_ani_control(ah,
323 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
324 true);
325 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
326 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
327 aniState->firstepLevel + 1);
328 return;
329 } else {
330 if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
331 !conf_is_ht(conf)) {
332 if (!aniState->ofdmWeakSigDetectOff)
333 ath9k_hw_ani_control(ah,
334 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
335 false);
336 if (aniState->firstepLevel > 0)
337 ath9k_hw_ani_control(ah,
338 ATH9K_ANI_FIRSTEP_LEVEL, 0);
339 return;
340 }
341 }
342 }
343
344 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
345 {
346 struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
347 struct ar5416AniState *aniState;
348 int32_t rssi;
349
350 if (!DO_ANI(ah))
351 return;
352
353 aniState = ah->curani;
354 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
355 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
356 aniState->noiseImmunityLevel + 1)) {
357 return;
358 }
359 }
360 if (ah->opmode == NL80211_IFTYPE_AP) {
361 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
362 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
363 aniState->firstepLevel + 1);
364 }
365 return;
366 }
367 rssi = BEACON_RSSI(ah);
368 if (rssi > aniState->rssiThrLow) {
369 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
370 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
371 aniState->firstepLevel + 1);
372 } else {
373 if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
374 !conf_is_ht(conf)) {
375 if (aniState->firstepLevel > 0)
376 ath9k_hw_ani_control(ah,
377 ATH9K_ANI_FIRSTEP_LEVEL, 0);
378 }
379 }
380 }
381
382 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
383 {
384 struct ar5416AniState *aniState;
385 int32_t rssi;
386
387 aniState = ah->curani;
388
389 if (ah->opmode == NL80211_IFTYPE_AP) {
390 if (aniState->firstepLevel > 0) {
391 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
392 aniState->firstepLevel - 1))
393 return;
394 }
395 } else {
396 rssi = BEACON_RSSI(ah);
397 if (rssi > aniState->rssiThrHigh) {
398 /* XXX: Handle me */
399 } else if (rssi > aniState->rssiThrLow) {
400 if (aniState->ofdmWeakSigDetectOff) {
401 if (ath9k_hw_ani_control(ah,
402 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
403 true) == true)
404 return;
405 }
406 if (aniState->firstepLevel > 0) {
407 if (ath9k_hw_ani_control(ah,
408 ATH9K_ANI_FIRSTEP_LEVEL,
409 aniState->firstepLevel - 1) == true)
410 return;
411 }
412 } else {
413 if (aniState->firstepLevel > 0) {
414 if (ath9k_hw_ani_control(ah,
415 ATH9K_ANI_FIRSTEP_LEVEL,
416 aniState->firstepLevel - 1) == true)
417 return;
418 }
419 }
420 }
421
422 if (aniState->spurImmunityLevel > 0) {
423 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
424 aniState->spurImmunityLevel - 1))
425 return;
426 }
427
428 if (aniState->noiseImmunityLevel > 0) {
429 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
430 aniState->noiseImmunityLevel - 1);
431 return;
432 }
433 }
434
435 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
436 {
437 struct ar5416AniState *aniState;
438 u32 txFrameCount, rxFrameCount, cycleCount;
439 int32_t listenTime;
440
441 txFrameCount = REG_READ(ah, AR_TFCNT);
442 rxFrameCount = REG_READ(ah, AR_RFCNT);
443 cycleCount = REG_READ(ah, AR_CCCNT);
444
445 aniState = ah->curani;
446 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
447
448 listenTime = 0;
449 ah->stats.ast_ani_lzero++;
450 } else {
451 int32_t ccdelta = cycleCount - aniState->cycleCount;
452 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
453 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
454 listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
455 }
456 aniState->cycleCount = cycleCount;
457 aniState->txFrameCount = txFrameCount;
458 aniState->rxFrameCount = rxFrameCount;
459
460 return listenTime;
461 }
462
463 void ath9k_ani_reset(struct ath_hw *ah)
464 {
465 struct ar5416AniState *aniState;
466 struct ath9k_channel *chan = ah->curchan;
467 int index;
468
469 if (!DO_ANI(ah))
470 return;
471
472 index = ath9k_hw_get_ani_channel_idx(ah, chan);
473 aniState = &ah->ani[index];
474 ah->curani = aniState;
475
476 if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
477 && ah->opmode != NL80211_IFTYPE_ADHOC) {
478 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
479 "Reset ANI state opmode %u\n", ah->opmode);
480 ah->stats.ast_ani_reset++;
481
482 if (ah->opmode == NL80211_IFTYPE_AP) {
483 /*
484 * ath9k_hw_ani_control() will only process items set on
485 * ah->ani_function
486 */
487 if (IS_CHAN_2GHZ(chan))
488 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
489 ATH9K_ANI_FIRSTEP_LEVEL);
490 else
491 ah->ani_function = 0;
492 }
493
494 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
495 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
496 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
497 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
498 !ATH9K_ANI_USE_OFDM_WEAK_SIG);
499 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
500 ATH9K_ANI_CCK_WEAK_SIG_THR);
501
502 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
503 ATH9K_RX_FILTER_PHYERR);
504
505 if (ah->opmode == NL80211_IFTYPE_AP) {
506 ah->curani->ofdmTrigHigh =
507 ah->config.ofdm_trig_high;
508 ah->curani->ofdmTrigLow =
509 ah->config.ofdm_trig_low;
510 ah->curani->cckTrigHigh =
511 ah->config.cck_trig_high;
512 ah->curani->cckTrigLow =
513 ah->config.cck_trig_low;
514 }
515 ath9k_ani_restart(ah);
516 return;
517 }
518
519 if (aniState->noiseImmunityLevel != 0)
520 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
521 aniState->noiseImmunityLevel);
522 if (aniState->spurImmunityLevel != 0)
523 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
524 aniState->spurImmunityLevel);
525 if (aniState->ofdmWeakSigDetectOff)
526 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
527 !aniState->ofdmWeakSigDetectOff);
528 if (aniState->cckWeakSigThreshold)
529 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
530 aniState->cckWeakSigThreshold);
531 if (aniState->firstepLevel != 0)
532 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
533 aniState->firstepLevel);
534
535 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
536 ~ATH9K_RX_FILTER_PHYERR);
537 ath9k_ani_restart(ah);
538 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
539 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
540 }
541
542 void ath9k_hw_ani_monitor(struct ath_hw *ah,
543 struct ath9k_channel *chan)
544 {
545 struct ar5416AniState *aniState;
546 int32_t listenTime;
547 u32 phyCnt1, phyCnt2;
548 u32 ofdmPhyErrCnt, cckPhyErrCnt;
549
550 if (!DO_ANI(ah))
551 return;
552
553 aniState = ah->curani;
554
555 listenTime = ath9k_hw_ani_get_listen_time(ah);
556 if (listenTime < 0) {
557 ah->stats.ast_ani_lneg++;
558 ath9k_ani_restart(ah);
559 return;
560 }
561
562 aniState->listenTime += listenTime;
563
564 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
565
566 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
567 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
568
569 if (phyCnt1 < aniState->ofdmPhyErrBase ||
570 phyCnt2 < aniState->cckPhyErrBase) {
571 if (phyCnt1 < aniState->ofdmPhyErrBase) {
572 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
573 "phyCnt1 0x%x, resetting "
574 "counter value to 0x%x\n",
575 phyCnt1, aniState->ofdmPhyErrBase);
576 REG_WRITE(ah, AR_PHY_ERR_1,
577 aniState->ofdmPhyErrBase);
578 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
579 AR_PHY_ERR_OFDM_TIMING);
580 }
581 if (phyCnt2 < aniState->cckPhyErrBase) {
582 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
583 "phyCnt2 0x%x, resetting "
584 "counter value to 0x%x\n",
585 phyCnt2, aniState->cckPhyErrBase);
586 REG_WRITE(ah, AR_PHY_ERR_2,
587 aniState->cckPhyErrBase);
588 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
589 AR_PHY_ERR_CCK_TIMING);
590 }
591 return;
592 }
593
594 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
595 ah->stats.ast_ani_ofdmerrs +=
596 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
597 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
598
599 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
600 ah->stats.ast_ani_cckerrs +=
601 cckPhyErrCnt - aniState->cckPhyErrCount;
602 aniState->cckPhyErrCount = cckPhyErrCnt;
603
604 if (aniState->listenTime > 5 * ah->aniperiod) {
605 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
606 aniState->ofdmTrigLow / 1000 &&
607 aniState->cckPhyErrCount <= aniState->listenTime *
608 aniState->cckTrigLow / 1000)
609 ath9k_hw_ani_lower_immunity(ah);
610 ath9k_ani_restart(ah);
611 } else if (aniState->listenTime > ah->aniperiod) {
612 if (aniState->ofdmPhyErrCount > aniState->listenTime *
613 aniState->ofdmTrigHigh / 1000) {
614 ath9k_hw_ani_ofdm_err_trigger(ah);
615 ath9k_ani_restart(ah);
616 } else if (aniState->cckPhyErrCount >
617 aniState->listenTime * aniState->cckTrigHigh /
618 1000) {
619 ath9k_hw_ani_cck_err_trigger(ah);
620 ath9k_ani_restart(ah);
621 }
622 }
623 }
624
625 void ath9k_enable_mib_counters(struct ath_hw *ah)
626 {
627 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
628
629 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
630
631 REG_WRITE(ah, AR_FILT_OFDM, 0);
632 REG_WRITE(ah, AR_FILT_CCK, 0);
633 REG_WRITE(ah, AR_MIBC,
634 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
635 & 0x0f);
636 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
637 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
638 }
639
640 /* Freeze the MIB counters, get the stats and then clear them */
641 void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
642 {
643 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
644 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
645 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
646 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
647 REG_WRITE(ah, AR_FILT_OFDM, 0);
648 REG_WRITE(ah, AR_FILT_CCK, 0);
649 }
650
651 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
652 u32 *rxc_pcnt,
653 u32 *rxf_pcnt,
654 u32 *txf_pcnt)
655 {
656 static u32 cycles, rx_clear, rx_frame, tx_frame;
657 u32 good = 1;
658
659 u32 rc = REG_READ(ah, AR_RCCNT);
660 u32 rf = REG_READ(ah, AR_RFCNT);
661 u32 tf = REG_READ(ah, AR_TFCNT);
662 u32 cc = REG_READ(ah, AR_CCCNT);
663
664 if (cycles == 0 || cycles > cc) {
665 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
666 "cycle counter wrap. ExtBusy = 0\n");
667 good = 0;
668 } else {
669 u32 cc_d = cc - cycles;
670 u32 rc_d = rc - rx_clear;
671 u32 rf_d = rf - rx_frame;
672 u32 tf_d = tf - tx_frame;
673
674 if (cc_d != 0) {
675 *rxc_pcnt = rc_d * 100 / cc_d;
676 *rxf_pcnt = rf_d * 100 / cc_d;
677 *txf_pcnt = tf_d * 100 / cc_d;
678 } else {
679 good = 0;
680 }
681 }
682
683 cycles = cc;
684 rx_frame = rf;
685 rx_clear = rc;
686 tx_frame = tf;
687
688 return good;
689 }
690
691 /*
692 * Process a MIB interrupt. We may potentially be invoked because
693 * any of the MIB counters overflow/trigger so don't assume we're
694 * here because a PHY error counter triggered.
695 */
696 void ath9k_hw_procmibevent(struct ath_hw *ah)
697 {
698 u32 phyCnt1, phyCnt2;
699
700 /* Reset these counters regardless */
701 REG_WRITE(ah, AR_FILT_OFDM, 0);
702 REG_WRITE(ah, AR_FILT_CCK, 0);
703 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
704 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
705
706 /* Clear the mib counters and save them in the stats */
707 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
708
709 if (!DO_ANI(ah))
710 return;
711
712 /* NB: these are not reset-on-read */
713 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
714 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
715 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
716 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
717 struct ar5416AniState *aniState = ah->curani;
718 u32 ofdmPhyErrCnt, cckPhyErrCnt;
719
720 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
721 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
722 ah->stats.ast_ani_ofdmerrs +=
723 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
724 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
725
726 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
727 ah->stats.ast_ani_cckerrs +=
728 cckPhyErrCnt - aniState->cckPhyErrCount;
729 aniState->cckPhyErrCount = cckPhyErrCnt;
730
731 /*
732 * NB: figure out which counter triggered. If both
733 * trigger we'll only deal with one as the processing
734 * clobbers the error counter so the trigger threshold
735 * check will never be true.
736 */
737 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
738 ath9k_hw_ani_ofdm_err_trigger(ah);
739 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
740 ath9k_hw_ani_cck_err_trigger(ah);
741 /* NB: always restart to insure the h/w counters are reset */
742 ath9k_ani_restart(ah);
743 }
744 }
745
746 void ath9k_hw_ani_setup(struct ath_hw *ah)
747 {
748 int i;
749
750 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
751 const int coarseHigh[] = { -14, -14, -14, -14, -12 };
752 const int coarseLow[] = { -64, -64, -64, -64, -70 };
753 const int firpwr[] = { -78, -78, -78, -78, -80 };
754
755 for (i = 0; i < 5; i++) {
756 ah->totalSizeDesired[i] = totalSizeDesired[i];
757 ah->coarse_high[i] = coarseHigh[i];
758 ah->coarse_low[i] = coarseLow[i];
759 ah->firpwr[i] = firpwr[i];
760 }
761 }
762
763 void ath9k_hw_ani_init(struct ath_hw *ah)
764 {
765 int i;
766
767 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Initialize ANI\n");
768
769 memset(ah->ani, 0, sizeof(ah->ani));
770 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
771 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
772 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
773 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
774 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
775 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
776 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
777 ah->ani[i].ofdmWeakSigDetectOff =
778 !ATH9K_ANI_USE_OFDM_WEAK_SIG;
779 ah->ani[i].cckWeakSigThreshold =
780 ATH9K_ANI_CCK_WEAK_SIG_THR;
781 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
782 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
783 ah->ani[i].ofdmPhyErrBase =
784 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
785 ah->ani[i].cckPhyErrBase =
786 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
787 }
788
789 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
790 "Setting OfdmErrBase = 0x%08x\n",
791 ah->ani[0].ofdmPhyErrBase);
792 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
793 ah->ani[0].cckPhyErrBase);
794
795 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
796 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
797 ath9k_enable_mib_counters(ah);
798
799 ah->aniperiod = ATH9K_ANI_PERIOD;
800 if (ah->config.enable_ani)
801 ah->proc_phyerr |= HAL_PROCESS_ANI;
802 }
803
804 void ath9k_hw_ani_disable(struct ath_hw *ah)
805 {
806 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling ANI\n");
807
808 ath9k_hw_disable_mib_counters(ah);
809 REG_WRITE(ah, AR_PHY_ERR_1, 0);
810 REG_WRITE(ah, AR_PHY_ERR_2, 0);
811 }
This page took 0.051497 seconds and 5 git commands to generate.