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