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