2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
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.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
20 #include "ah_internal.h"
22 //#include "ah_pktlog.h"
24 #include "ar9300/ar9300.h"
25 #include "ar9300/ar9300reg.h"
26 #include "ar9300/ar9300phy.h"
28 extern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits);
29 extern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah);
31 #define HAL_ANI_DEBUG 1
34 * Anti noise immunity support. We track phy errors and react
35 * to excessive errors by adjusting the noise immunity parameters.
38 /******************************************************************************
40 * New Ani Algorithm for Station side only
42 *****************************************************************************/
44 #define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */
45 #define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */
46 #define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */
47 #define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */
48 #define HAL_ANI_USE_OFDM_WEAK_SIG AH_TRUE
49 #define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */
50 #define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3
51 #define HAL_ANI_DEF_FIRSTEP_LVL 2
52 #define HAL_ANI_RSSI_THR_HIGH 40
53 #define HAL_ANI_RSSI_THR_LOW 7
54 #define HAL_ANI_PERIOD 1000
56 #define HAL_NOISE_DETECT_PERIOD 100
57 #define HAL_NOISE_RECOVER_PERIOD 5000
59 #define HAL_SIG_FIRSTEP_SETTING_MIN 0
60 #define HAL_SIG_FIRSTEP_SETTING_MAX 20
61 #define HAL_SIG_SPUR_IMM_SETTING_MIN 0
62 #define HAL_SIG_SPUR_IMM_SETTING_MAX 22
64 #define HAL_EP_RND(x, mul) \
65 ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul))
66 #define BEACON_RSSI(ahp) \
67 HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
68 HAL_RSSI_EP_MULTIPLIER)
72 * level: 0 1 2 3 4 5 6 7 8
73 * firstep_table: lvl 0-8, default 2
75 static const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12};
76 /* cycpwr_thr1_table: lvl 0-7, default 3 */
77 static const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 };
78 /* values here are relative to the INI */
80 typedef struct _HAL_ANI_OFDM_LEVEL_ENTRY {
81 int spur_immunity_level;
83 int ofdm_weak_signal_on;
84 } HAL_ANI_OFDM_LEVEL_ENTRY;
85 static const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = {
87 { 0, 0, 1 }, /* lvl 0 */
88 { 1, 1, 1 }, /* lvl 1 */
89 { 2, 2, 1 }, /* lvl 2 */
90 { 3, 2, 1 }, /* lvl 3 (default) */
91 { 4, 3, 1 }, /* lvl 4 */
92 { 5, 4, 1 }, /* lvl 5 */
93 { 6, 5, 1 }, /* lvl 6 */
94 { 7, 6, 1 }, /* lvl 7 */
95 { 7, 7, 1 }, /* lvl 8 */
96 { 7, 8, 0 } /* lvl 9 */
98 #define HAL_ANI_OFDM_NUM_LEVEL \
99 (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0]))
100 #define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1)
101 #define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */
103 typedef struct _HAL_ANI_CCK_LEVEL_ENTRY {
106 } HAL_ANI_CCK_LEVEL_ENTRY;
108 static const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = {
110 { 0, 1 }, /* lvl 0 */
111 { 1, 1 }, /* lvl 1 */
112 { 2, 1 }, /* lvl 2 (default) */
113 { 3, 1 }, /* lvl 3 */
114 { 4, 0 }, /* lvl 4 */
115 { 5, 0 }, /* lvl 5 */
116 { 6, 0 }, /* lvl 6 */
117 { 7, 0 }, /* lvl 7 (only for high rssi) */
118 { 8, 0 } /* lvl 8 (only for high rssi) */
120 #define HAL_ANI_CCK_NUM_LEVEL \
121 (sizeof(cck_level_table) / sizeof(cck_level_table[0]))
122 #define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1)
123 #define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3)
124 #define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */
127 * register values to turn OFDM weak signal detection OFF
129 static const int m1_thresh_low_off = 127;
130 static const int m2_thresh_low_off = 127;
131 static const int m1_thresh_off = 127;
132 static const int m2_thresh_off = 127;
133 static const int m2_count_thr_off = 31;
134 static const int m2_count_thr_low_off = 63;
135 static const int m1_thresh_low_ext_off = 127;
136 static const int m2_thresh_low_ext_off = 127;
137 static const int m1_thresh_ext_off = 127;
138 static const int m2_thresh_ext_off = 127;
141 ar9300_enable_mib_counters(struct ath_hal *ah)
143 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__);
144 /* Clear the mib counters and save them in the stats */
145 ar9300_update_mib_mac_stats(ah);
147 OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
148 OS_REG_WRITE(ah, AR_FILT_CCK, 0);
149 OS_REG_WRITE(ah, AR_MIBC,
150 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
151 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
152 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
157 ar9300_disable_mib_counters(struct ath_hal *ah)
159 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__);
161 OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
163 /* Clear the mib counters and save them in the stats */
164 ar9300_update_mib_mac_stats(ah);
166 OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
167 OS_REG_WRITE(ah, AR_FILT_CCK, 0);
171 * This routine returns the index into the ani_state array that
172 * corresponds to the channel in *chan. If no match is found and the
173 * array is still not fully utilized, a new entry is created for the
174 * channel. We assume the attach function has already initialized the
175 * ah_ani values and only the channel field needs to be set.
178 ar9300_get_ani_channel_index(struct ath_hal *ah,
179 const struct ieee80211_channel *chan)
181 struct ath_hal_9300 *ahp = AH9300(ah);
184 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) {
185 /* XXX this doesn't distinguish between 20/40 channels */
186 if (ahp->ah_ani[i].c.ic_freq == chan->ic_freq) {
189 if (ahp->ah_ani[i].c.ic_freq == 0) {
190 ahp->ah_ani[i].c.ic_freq = chan->ic_freq;
191 ahp->ah_ani[i].c.ic_flags = chan->ic_flags;
196 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
197 "%s: No more channel states left. Using channel 0\n", __func__);
198 return 0; /* XXX gotta return something valid */
202 * Return the current ANI state of the channel we're on
204 struct ar9300_ani_state *
205 ar9300_ani_get_current_state(struct ath_hal *ah)
207 return AH9300(ah)->ah_curani;
211 * Return the current statistics.
213 struct ar9300_stats *
214 ar9300_ani_get_current_stats(struct ath_hal *ah)
216 return &AH9300(ah)->ah_stats;
220 * Setup ANI handling. Sets all thresholds and levels to default level AND
221 * resets the channel statistics
225 ar9300_ani_attach(struct ath_hal *ah)
227 struct ath_hal_9300 *ahp = AH9300(ah);
230 OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
231 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) {
232 ahp->ah_ani[i].ofdm_trig_high = HAL_ANI_OFDM_TRIG_HIGH;
233 ahp->ah_ani[i].ofdm_trig_low = HAL_ANI_OFDM_TRIG_LOW;
234 ahp->ah_ani[i].cck_trig_high = HAL_ANI_CCK_TRIG_HIGH;
235 ahp->ah_ani[i].cck_trig_low = HAL_ANI_CCK_TRIG_LOW;
236 ahp->ah_ani[i].rssi_thr_high = HAL_ANI_RSSI_THR_HIGH;
237 ahp->ah_ani[i].rssi_thr_low = HAL_ANI_RSSI_THR_LOW;
238 ahp->ah_ani[i].ofdm_noise_immunity_level = HAL_ANI_OFDM_DEF_LEVEL;
239 ahp->ah_ani[i].cck_noise_immunity_level = HAL_ANI_CCK_DEF_LEVEL;
240 ahp->ah_ani[i].ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG;
241 ahp->ah_ani[i].spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL;
242 ahp->ah_ani[i].firstep_level = HAL_ANI_DEF_FIRSTEP_LVL;
243 ahp->ah_ani[i].mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK;
244 ahp->ah_ani[i].ofdms_turn = AH_TRUE;
245 ahp->ah_ani[i].must_restore = AH_FALSE;
249 * Since we expect some ongoing maintenance on the tables,
250 * let's sanity check here.
251 * The default level should not modify INI setting.
253 HALASSERT(firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] == 0);
254 HALASSERT(cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] == 0);
256 ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].fir_step_level ==
257 HAL_ANI_DEF_FIRSTEP_LVL);
259 ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].spur_immunity_level ==
260 HAL_ANI_DEF_SPUR_IMMUNE_LVL);
262 cck_level_table[HAL_ANI_CCK_DEF_LEVEL].fir_step_level ==
263 HAL_ANI_DEF_FIRSTEP_LVL);
265 /* Initialize and enable MIB Counters */
266 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
267 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
268 ar9300_enable_mib_counters(ah);
270 ahp->ah_ani_period = HAL_ANI_PERIOD;
271 if (ah->ah_config.ath_hal_enable_ani) {
272 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
277 * Cleanup any ANI state setup.
280 ar9300_ani_detach(struct ath_hal *ah)
282 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Detaching Ani\n", __func__);
283 ar9300_disable_mib_counters(ah);
284 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
285 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
289 * Initialize the ANI register values with default (ini) values.
290 * This routine is called during a (full) hardware reset after
291 * all the registers are initialised from the INI.
294 ar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode)
296 struct ath_hal_9300 *ahp = AH9300(ah);
297 struct ar9300_ani_state *ani_state;
298 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
302 HALASSERT(chan != AH_NULL);
303 index = ar9300_get_ani_channel_index(ah, chan);
304 ani_state = &ahp->ah_ani[index];
305 ahp->ah_curani = ani_state;
307 HALDEBUG(ah, HAL_DEBUG_ANI,
308 "%s: ver %d.%d opmode %u chan %d Mhz/0x%x macmode %d\n",
309 __func__, AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev,
310 AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, macmode);
312 val = OS_REG_READ(ah, AR_PHY_SFCORR);
313 ani_state->ini_def.m1_thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
314 ani_state->ini_def.m2_thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
315 ani_state->ini_def.m2_count_thr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
317 val = OS_REG_READ(ah, AR_PHY_SFCORR_LOW);
318 ani_state->ini_def.m1_thresh_low =
319 MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
320 ani_state->ini_def.m2_thresh_low =
321 MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
322 ani_state->ini_def.m2_count_thr_low =
323 MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
325 val = OS_REG_READ(ah, AR_PHY_SFCORR_EXT);
326 ani_state->ini_def.m1_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
327 ani_state->ini_def.m2_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
328 ani_state->ini_def.m1_thresh_low_ext =
329 MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
330 ani_state->ini_def.m2_thresh_low_ext =
331 MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
333 ani_state->ini_def.firstep =
334 OS_REG_READ_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP);
335 ani_state->ini_def.firstep_low =
337 ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW);
338 ani_state->ini_def.cycpwr_thr1 =
339 OS_REG_READ_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1);
340 ani_state->ini_def.cycpwr_thr1_ext =
341 OS_REG_READ_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1);
343 /* these levels just got reset to defaults by the INI */
344 ani_state->spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL;
345 ani_state->firstep_level = HAL_ANI_DEF_FIRSTEP_LVL;
346 ani_state->ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG;
347 ani_state->mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK;
349 ani_state->cycle_count = 0;
353 * Set the ANI settings to match an OFDM level.
356 ar9300_ani_set_odfm_noise_immunity_level(struct ath_hal *ah,
357 u_int8_t ofdm_noise_immunity_level)
359 struct ath_hal_9300 *ahp = AH9300(ah);
360 struct ar9300_ani_state *ani_state = ahp->ah_curani;
362 ani_state->rssi = BEACON_RSSI(ahp);
363 HALDEBUG(ah, HAL_DEBUG_ANI,
364 "**** %s: ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", __func__,
365 ani_state->ofdm_noise_immunity_level, ofdm_noise_immunity_level,
366 ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high);
368 ani_state->ofdm_noise_immunity_level = ofdm_noise_immunity_level;
370 if (ani_state->spur_immunity_level !=
371 ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level)
374 ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
375 ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level);
378 if (ani_state->firstep_level !=
379 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level &&
380 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level >=
381 cck_level_table[ani_state->cck_noise_immunity_level].fir_step_level)
384 ah, HAL_ANI_FIRSTEP_LEVEL,
385 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level);
388 if ((AH_PRIVATE(ah)->ah_opmode != HAL_M_STA ||
389 ani_state->rssi <= ani_state->rssi_thr_high))
391 if (ani_state->ofdm_weak_sig_detect_off) {
393 * force on ofdm weak sig detect.
395 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE);
397 } else if (ani_state->ofdm_weak_sig_detect_off ==
398 ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on)
401 ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
402 ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on);
407 * Set the ANI settings to match a CCK level.
410 ar9300_ani_set_cck_noise_immunity_level(struct ath_hal *ah,
411 u_int8_t cck_noise_immunity_level)
413 struct ath_hal_9300 *ahp = AH9300(ah);
414 struct ar9300_ani_state *ani_state = ahp->ah_curani;
417 ani_state->rssi = BEACON_RSSI(ahp);
418 HALDEBUG(ah, HAL_DEBUG_ANI,
419 "**** %s: ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
420 __func__, ani_state->cck_noise_immunity_level, cck_noise_immunity_level,
421 ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high);
423 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA &&
424 ani_state->rssi <= ani_state->rssi_thr_low &&
425 cck_noise_immunity_level > HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI)
427 cck_noise_immunity_level = HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI;
430 ani_state->cck_noise_immunity_level = cck_noise_immunity_level;
432 level = ani_state->ofdm_noise_immunity_level;
433 if (ani_state->firstep_level !=
434 cck_level_table[cck_noise_immunity_level].fir_step_level &&
435 cck_level_table[cck_noise_immunity_level].fir_step_level >=
436 ofdm_level_table[level].fir_step_level)
439 ah, HAL_ANI_FIRSTEP_LEVEL,
440 cck_level_table[cck_noise_immunity_level].fir_step_level);
443 if (ani_state->mrc_cck_off ==
444 cck_level_table[cck_noise_immunity_level].mrc_cck_on)
448 cck_level_table[cck_noise_immunity_level].mrc_cck_on);
453 * Control Adaptive Noise Immunity Parameters
456 ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
458 struct ath_hal_9300 *ahp = AH9300(ah);
459 struct ar9300_ani_state *ani_state = ahp->ah_curani;
460 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
461 int32_t value, value2;
465 if (chan == NULL && cmd != HAL_ANI_MODE) {
466 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
467 "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd);
471 switch (cmd & ahp->ah_ani_function) {
472 case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
474 int m1_thresh_low, m2_thresh_low;
475 int m1_thresh, m2_thresh;
476 int m2_count_thr, m2_count_thr_low;
477 int m1_thresh_low_ext, m2_thresh_low_ext;
478 int m1_thresh_ext, m2_thresh_ext;
480 * is_on == 1 means ofdm weak signal detection is ON
481 * (default, less noise imm)
482 * is_on == 0 means ofdm weak signal detection is OFF
485 is_on = param ? 1 : 0;
488 * make register setting for default (weak sig detect ON)
491 m1_thresh_low = is_on ?
492 ani_state->ini_def.m1_thresh_low : m1_thresh_low_off;
493 m2_thresh_low = is_on ?
494 ani_state->ini_def.m2_thresh_low : m2_thresh_low_off;
496 ani_state->ini_def.m1_thresh : m1_thresh_off;
498 ani_state->ini_def.m2_thresh : m2_thresh_off;
499 m2_count_thr = is_on ?
500 ani_state->ini_def.m2_count_thr : m2_count_thr_off;
501 m2_count_thr_low = is_on ?
502 ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off;
503 m1_thresh_low_ext = is_on ?
504 ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off;
505 m2_thresh_low_ext = is_on ?
506 ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off;
507 m1_thresh_ext = is_on ?
508 ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off;
509 m2_thresh_ext = is_on ?
510 ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off;
511 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
512 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low);
513 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
514 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low);
515 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH,
517 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
519 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
521 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
522 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low);
523 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
524 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext);
525 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
526 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext);
527 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH,
529 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
532 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
533 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
535 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
536 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
538 if (!is_on != ani_state->ofdm_weak_sig_detect_off) {
539 HALDEBUG(ah, HAL_DEBUG_ANI,
540 "%s: ** ch %d: ofdm weak signal: %s=>%s\n",
541 __func__, chan->ic_freq,
542 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
543 is_on ? "on" : "off");
545 ahp->ah_stats.ast_ani_ofdmon++;
547 ahp->ah_stats.ast_ani_ofdmoff++;
549 ani_state->ofdm_weak_sig_detect_off = !is_on;
553 case HAL_ANI_FIRSTEP_LEVEL:
554 if (level >= ARRAY_LENGTH(firstep_table)) {
555 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
556 "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n",
557 __func__, level, (unsigned) ARRAY_LENGTH(firstep_table));
561 * make register setting relative to default
562 * from INI file & cap value
565 firstep_table[level] -
566 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
567 ani_state->ini_def.firstep;
568 if (value < HAL_SIG_FIRSTEP_SETTING_MIN) {
569 value = HAL_SIG_FIRSTEP_SETTING_MIN;
571 if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
572 value = HAL_SIG_FIRSTEP_SETTING_MAX;
574 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
576 * we need to set first step low register too
577 * make register setting relative to default from INI file & cap value
580 firstep_table[level] -
581 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
582 ani_state->ini_def.firstep_low;
583 if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) {
584 value2 = HAL_SIG_FIRSTEP_SETTING_MIN;
586 if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
587 value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
589 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
590 AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
592 if (level != ani_state->firstep_level) {
593 HALDEBUG(ah, HAL_DEBUG_ANI,
594 "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
595 __func__, chan->ic_freq, ani_state->firstep_level, level,
596 HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep);
597 HALDEBUG(ah, HAL_DEBUG_ANI,
598 "%s: ** ch %d: level %d=>%d[def:%d] "
599 "firstep_low[level]=%d ini=%d\n",
600 __func__, chan->ic_freq, ani_state->firstep_level, level,
601 HAL_ANI_DEF_FIRSTEP_LVL, value2,
602 ani_state->ini_def.firstep_low);
603 if (level > ani_state->firstep_level) {
604 ahp->ah_stats.ast_ani_stepup++;
605 } else if (level < ani_state->firstep_level) {
606 ahp->ah_stats.ast_ani_stepdown++;
608 ani_state->firstep_level = level;
611 case HAL_ANI_SPUR_IMMUNITY_LEVEL:
612 if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) {
613 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
614 "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level "
615 "out of range (%u > %u)\n",
616 __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table));
620 * make register setting relative to default from INI file & cap value
623 cycpwr_thr1_table[level] -
624 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
625 ani_state->ini_def.cycpwr_thr1;
626 if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) {
627 value = HAL_SIG_SPUR_IMM_SETTING_MIN;
629 if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
630 value = HAL_SIG_SPUR_IMM_SETTING_MAX;
632 OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);
635 * set AR_PHY_EXT_CCA for extension channel
636 * make register setting relative to default from INI file & cap value
639 cycpwr_thr1_table[level] -
640 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
641 ani_state->ini_def.cycpwr_thr1_ext;
642 if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) {
643 value2 = HAL_SIG_SPUR_IMM_SETTING_MIN;
645 if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
646 value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
648 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);
650 if (level != ani_state->spur_immunity_level) {
651 HALDEBUG(ah, HAL_DEBUG_ANI,
652 "%s: ** ch %d: level %d=>%d[def:%d] "
653 "cycpwr_thr1[level]=%d ini=%d\n",
654 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
655 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value,
656 ani_state->ini_def.cycpwr_thr1);
657 HALDEBUG(ah, HAL_DEBUG_ANI,
658 "%s: ** ch %d: level %d=>%d[def:%d] "
659 "cycpwr_thr1_ext[level]=%d ini=%d\n",
660 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
661 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2,
662 ani_state->ini_def.cycpwr_thr1_ext);
663 if (level > ani_state->spur_immunity_level) {
664 ahp->ah_stats.ast_ani_spurup++;
665 } else if (level < ani_state->spur_immunity_level) {
666 ahp->ah_stats.ast_ani_spurdown++;
668 ani_state->spur_immunity_level = level;
671 case HAL_ANI_MRC_CCK:
673 * is_on == 1 means MRC CCK ON (default, less noise imm)
674 * is_on == 0 means MRC CCK is OFF (more noise imm)
676 is_on = param ? 1 : 0;
677 if (!AR_SREV_POSEIDON(ah)) {
678 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
679 AR_PHY_MRC_CCK_ENABLE, is_on);
680 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
681 AR_PHY_MRC_CCK_MUX_REG, is_on);
683 if (!is_on != ani_state->mrc_cck_off) {
684 HALDEBUG(ah, HAL_DEBUG_ANI,
685 "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq,
686 !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off");
688 ahp->ah_stats.ast_ani_ccklow++;
690 ahp->ah_stats.ast_ani_cckhigh++;
692 ani_state->mrc_cck_off = !is_on;
695 case HAL_ANI_PRESENT:
697 #ifdef AH_PRIVATE_DIAG
700 ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI;
701 /* Turn off HW counters if we have them */
702 ar9300_ani_detach(ah);
703 if (AH_PRIVATE(ah)->ah_curchan == NULL) {
706 /* if we're turning off ANI, reset regs back to INI settings */
707 if (ah->ah_config.ath_hal_enable_ani) {
708 HAL_ANI_CMD savefunc = ahp->ah_ani_function;
709 /* temporarly allow all functions so we can reset */
710 ahp->ah_ani_function = HAL_ANI_ALL;
711 HALDEBUG(ah, HAL_DEBUG_ANI,
712 "%s: disable all ANI functions\n", __func__);
713 ar9300_ani_set_odfm_noise_immunity_level(
714 ah, HAL_ANI_OFDM_DEF_LEVEL);
715 ar9300_ani_set_cck_noise_immunity_level(
716 ah, HAL_ANI_CCK_DEF_LEVEL);
717 ahp->ah_ani_function = savefunc;
719 } else { /* normal/auto mode */
720 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__);
721 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
722 if (AH_PRIVATE(ah)->ah_curchan == NULL) {
725 ar9300_enable_mib_counters(ah);
726 ar9300_ani_reset(ah, AH_FALSE);
727 ani_state = ahp->ah_curani;
729 HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
730 ahp->ah_proc_phy_err);
732 case HAL_ANI_PHYERR_RESET:
733 ahp->ah_stats.ast_ani_ofdmerrs = 0;
734 ahp->ah_stats.ast_ani_cckerrs = 0;
736 #endif /* AH_PRIVATE_DIAG */
739 HALDEBUG(ah, HAL_DEBUG_ANI,
740 "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
741 __func__, cmd, ahp->ah_ani_function);
747 HALDEBUG(ah, HAL_DEBUG_ANI,
748 "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d "
749 "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n",
750 __func__, ani_state->spur_immunity_level,
751 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
752 ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off",
753 ani_state->listen_time, ani_state->cycle_count,
754 ani_state->listen_time, ani_state->ofdm_phy_err_count,
755 ani_state->cck_phy_err_count);
758 #ifndef REMOVE_PKT_LOG
761 struct log_ani log_data;
763 /* Populate the ani log record */
764 log_data.phy_stats_disable = DO_ANI(ah);
765 log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level;
766 log_data.spur_immun_lvl = ani_state->spur_immunity_level;
767 log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off;
768 log_data.cck_weak_thr = ani_state->cck_noise_immunity_level;
769 log_data.fir_lvl = ani_state->firstep_level;
770 log_data.listen_time = ani_state->listen_time;
771 log_data.cycle_count = ani_state->cycle_count;
772 /* express ofdm_phy_err_count as errors/second */
773 log_data.ofdm_phy_err_count = ani_state->listen_time ?
774 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0;
775 /* express cck_phy_err_count as errors/second */
776 log_data.cck_phy_err_count = ani_state->listen_time ?
777 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0;
778 log_data.rssi = ani_state->rssi;
780 /* clear interrupt context flag */
781 ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
789 ar9300_ani_restart(struct ath_hal *ah)
791 struct ath_hal_9300 *ahp = AH9300(ah);
792 struct ar9300_ani_state *ani_state;
798 ani_state = ahp->ah_curani;
800 ani_state->listen_time = 0;
802 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
803 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
804 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
805 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
807 /* Clear the mib counters and save them in the stats */
808 ar9300_update_mib_mac_stats(ah);
810 ani_state->ofdm_phy_err_count = 0;
811 ani_state->cck_phy_err_count = 0;
815 ar9300_ani_ofdm_err_trigger(struct ath_hal *ah)
817 struct ath_hal_9300 *ahp = AH9300(ah);
818 struct ar9300_ani_state *ani_state;
824 ani_state = ahp->ah_curani;
826 if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) {
827 ar9300_ani_set_odfm_noise_immunity_level(
828 ah, ani_state->ofdm_noise_immunity_level + 1);
833 ar9300_ani_cck_err_trigger(struct ath_hal *ah)
835 struct ath_hal_9300 *ahp = AH9300(ah);
836 struct ar9300_ani_state *ani_state;
842 ani_state = ahp->ah_curani;
844 if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) {
845 ar9300_ani_set_cck_noise_immunity_level(
846 ah, ani_state->cck_noise_immunity_level + 1);
851 * Restore the ANI parameters in the HAL and reset the statistics.
852 * This routine should be called for every hardware reset and for
853 * every channel change.
856 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
858 struct ath_hal_9300 *ahp = AH9300(ah);
859 struct ar9300_ani_state *ani_state;
860 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
861 HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
864 HALASSERT(chan != AH_NULL);
871 * we need to re-point to the correct ANI state since the channel
872 * may have changed due to a fast channel change
874 index = ar9300_get_ani_channel_index(ah, chan);
875 ani_state = &ahp->ah_ani[index];
876 HALASSERT(ani_state != AH_NULL);
877 ahp->ah_curani = ani_state;
879 ahp->ah_stats.ast_ani_reset++;
881 ani_state->phy_noise_spur = 0;
883 /* only allow a subset of functions in AP mode */
884 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
885 if (IS_CHAN_2GHZ(ichan)) {
886 ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL |
887 HAL_ANI_FIRSTEP_LEVEL |
890 ahp->ah_ani_function = 0;
893 /* always allow mode (on/off) to be controlled */
894 ahp->ah_ani_function |= HAL_ANI_MODE;
897 (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
898 AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
901 * If we're scanning or in AP mode, the defaults (ini) should be
903 * For an AP we assume the historical levels for this channel are
904 * probably outdated so start from defaults instead.
906 if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL ||
907 ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL)
909 HALDEBUG(ah, HAL_DEBUG_ANI,
910 "%s: Restore defaults: opmode %u chan %d Mhz/0x%x "
911 "is_scanning=%d restore=%d ofdm:%d cck:%d\n",
912 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
913 chan->ic_flags, is_scanning, ani_state->must_restore,
914 ani_state->ofdm_noise_immunity_level,
915 ani_state->cck_noise_immunity_level);
917 * for STA/IBSS, we want to restore the historical values later
918 * (when we're not scanning)
920 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
921 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
923 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
924 HAL_ANI_DEF_SPUR_IMMUNE_LVL);
926 ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL);
927 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
928 HAL_ANI_USE_OFDM_WEAK_SIG);
929 ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK);
930 ani_state->must_restore = AH_TRUE;
932 ar9300_ani_set_odfm_noise_immunity_level(
933 ah, HAL_ANI_OFDM_DEF_LEVEL);
934 ar9300_ani_set_cck_noise_immunity_level(
935 ah, HAL_ANI_CCK_DEF_LEVEL);
940 * restore historical levels for this channel
942 HALDEBUG(ah, HAL_DEBUG_ANI,
943 "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d "
944 "restore=%d ofdm:%d cck:%d\n",
945 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
946 chan->ic_flags, is_scanning, ani_state->must_restore,
947 ani_state->ofdm_noise_immunity_level,
948 ani_state->cck_noise_immunity_level);
949 ar9300_ani_set_odfm_noise_immunity_level(
950 ah, ani_state->ofdm_noise_immunity_level);
951 ar9300_ani_set_cck_noise_immunity_level(
952 ah, ani_state->cck_noise_immunity_level);
953 ani_state->must_restore = AH_FALSE;
956 /* enable phy counters */
957 ar9300_ani_restart(ah);
958 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
959 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
963 * Process a MIB interrupt. We may potentially be invoked because
964 * any of the MIB counters overflow/trigger so don't assume we're
965 * here because a PHY error counter triggered.
968 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
970 struct ath_hal_9300 *ahp = AH9300(ah);
971 u_int32_t phy_cnt1, phy_cnt2;
974 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
977 /* Reset these counters regardless */
978 OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
979 OS_REG_WRITE(ah, AR_FILT_CCK, 0);
980 if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) {
981 OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
984 /* Clear the mib counters and save them in the stats */
985 ar9300_update_mib_mac_stats(ah);
986 ahp->ah_stats.ast_nodestats = *stats;
990 * We must always clear the interrupt cause by resetting
991 * the phy error regs.
993 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
994 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
998 /* NB: these are not reset-on-read */
999 phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
1000 phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
1002 HALDEBUG(ah, HAL_DEBUG_ANI,
1003 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n",
1004 __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2);
1006 if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
1007 ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
1008 /* NB: always restart to insure the h/w counters are reset */
1009 ar9300_ani_restart(ah);
1015 ar9300_ani_lower_immunity(struct ath_hal *ah)
1017 struct ath_hal_9300 *ahp = AH9300(ah);
1018 struct ar9300_ani_state *ani_state = ahp->ah_curani;
1020 if (ani_state->ofdm_noise_immunity_level > 0 &&
1021 (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) {
1023 * lower OFDM noise immunity
1025 ar9300_ani_set_odfm_noise_immunity_level(
1026 ah, ani_state->ofdm_noise_immunity_level - 1);
1029 * only lower either OFDM or CCK errors per turn
1030 * we lower the other one next time
1035 if (ani_state->cck_noise_immunity_level > 0) {
1037 * lower CCK noise immunity
1039 ar9300_ani_set_cck_noise_immunity_level(
1040 ah, ani_state->cck_noise_immunity_level - 1);
1044 /* convert HW counter values to ms using mode specifix clock rate */
1045 //#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000)
1046 #define CLOCK_RATE(_ah) (ath_hal_mac_clks(ah, 1000))
1049 * Return an approximation of the time spent ``listening'' by
1050 * deducting the cycles spent tx'ing and rx'ing from the total
1051 * cycle count since our last call. A return value <0 indicates
1052 * an invalid/inconsistent time.
1055 ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats)
1057 struct ath_hal_9300 *ahp = AH9300(ah);
1058 struct ar9300_ani_state *ani_state;
1059 u_int32_t tx_frame_count, rx_frame_count, cycle_count;
1060 int32_t listen_time;
1062 tx_frame_count = OS_REG_READ(ah, AR_TFCNT);
1063 rx_frame_count = OS_REG_READ(ah, AR_RFCNT);
1064 cycle_count = OS_REG_READ(ah, AR_CCCNT);
1066 ani_state = ahp->ah_curani;
1067 if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) {
1069 * Cycle counter wrap (or initial call); it's not possible
1070 * to accurately calculate a value because the registers
1071 * right shift rather than wrap--so punt and return 0.
1074 ahp->ah_stats.ast_ani_lzero++;
1076 HALDEBUG(ah, HAL_DEBUG_ANI,
1077 "%s: 1st call: ani_state->cycle_count=%d\n",
1078 __func__, ani_state->cycle_count);
1081 int32_t ccdelta = cycle_count - ani_state->cycle_count;
1082 int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count;
1083 int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count;
1084 listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah);
1086 HALDEBUG(ah, HAL_DEBUG_ANI,
1087 "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d "
1089 __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah));
1092 ani_state->cycle_count = cycle_count;
1093 ani_state->tx_frame_count = tx_frame_count;
1094 ani_state->rx_frame_count = rx_frame_count;
1099 * Do periodic processing. This routine is called from a timer
1102 ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
1103 const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
1105 struct ath_hal_9300 *ahp = AH9300(ah);
1106 struct ar9300_ani_state *ani_state;
1107 int32_t listen_time;
1108 u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
1109 u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
1110 HAL_BOOL old_phy_noise_spur;
1112 ani_state = ahp->ah_curani;
1113 ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */
1115 if (ani_state == NULL) {
1116 /* should not happen */
1117 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1118 "%s: can't poll - no ANI not initialized for this channel\n",
1124 * ar9300_ani_ar_poll is never called while scanning but we may have been
1125 * scanning and now just restarted polling. In this case we need to
1126 * restore historical values.
1128 if (ani_state->must_restore) {
1129 HALDEBUG(ah, HAL_DEBUG_ANI,
1130 "%s: must restore - calling ar9300_ani_restart\n", __func__);
1131 ar9300_ani_reset(ah, AH_FALSE);
1135 listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
1136 if (listen_time <= 0) {
1137 ahp->ah_stats.ast_ani_lneg++;
1138 /* restart ANI period if listen_time is invalid */
1139 HALDEBUG(ah, HAL_DEBUG_ANI,
1140 "%s: listen_time=%d - calling ar9300_ani_restart\n",
1141 __func__, listen_time);
1142 ar9300_ani_restart(ah);
1145 /* XXX beware of overflow? */
1146 ani_state->listen_time += listen_time;
1148 /* Clear the mib counters and save them in the stats */
1149 ar9300_update_mib_mac_stats(ah);
1150 /* NB: these are not reset-on-read */
1151 ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
1152 cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);
1156 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
1157 ahp->ah_stats.ast_ani_ofdmerrs +=
1158 ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1159 ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;
1161 ahp->ah_stats.ast_ani_cckerrs +=
1162 cck_phy_err_cnt - ani_state->cck_phy_err_count;
1163 ani_state->cck_phy_err_count = cck_phy_err_cnt;
1166 HALDEBUG(ah, HAL_DEBUG_ANI,
1167 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n",
1168 __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
1169 cck_phy_err_cnt, cck_phy_err_cnt);
1173 * If ani is not enabled, return after we've collected
1181 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
1183 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;
1185 HALDEBUG(ah, HAL_DEBUG_ANI,
1186 "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
1187 __func__, listen_time,
1188 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1189 ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1190 ani_state->ofdms_turn);
1192 if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
1193 old_phy_noise_spur = ani_state->phy_noise_spur;
1194 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1195 cck_phy_err_rate <= ani_state->cck_trig_low) {
1196 if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
1197 ani_state->phy_noise_spur = 0;
1200 ani_state->phy_noise_spur = 1;
1202 if (old_phy_noise_spur != ani_state->phy_noise_spur) {
1203 HALDEBUG(ah, HAL_DEBUG_ANI,
1204 "%s: enviroment change from %d to %d\n",
1205 __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
1209 if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
1211 * Check to see if need to lower immunity if
1212 * 5 ani_periods have passed
1214 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1215 cck_phy_err_rate <= ani_state->cck_trig_low)
1217 HALDEBUG(ah, HAL_DEBUG_ANI,
1218 "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) "
1219 "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
1220 __func__, ani_state->listen_time,
1221 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1222 ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
1223 cck_phy_err_rate, ani_state->cck_trig_low);
1224 ar9300_ani_lower_immunity(ah);
1225 ani_state->ofdms_turn = !ani_state->ofdms_turn;
1227 HALDEBUG(ah, HAL_DEBUG_ANI,
1228 "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
1229 "calling ar9300_ani_restart\n",
1230 __func__, ani_state->listen_time,
1231 ofdm_phy_err_rate, cck_phy_err_rate);
1232 ar9300_ani_restart(ah);
1233 } else if (ani_state->listen_time > ahp->ah_ani_period) {
1234 /* check to see if need to raise immunity */
1235 if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
1236 (cck_phy_err_rate <= ani_state->cck_trig_high ||
1237 ani_state->ofdms_turn))
1239 HALDEBUG(ah, HAL_DEBUG_ANI,
1240 "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
1241 "ar9300_ani_ofdm_err_trigger\n",
1242 __func__, ani_state->listen_time,
1243 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1244 ani_state->ofdm_trig_high);
1245 ar9300_ani_ofdm_err_trigger(ah);
1246 ar9300_ani_restart(ah);
1247 ani_state->ofdms_turn = AH_FALSE;
1248 } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
1249 HALDEBUG(ah, HAL_DEBUG_ANI,
1250 "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
1251 "ar9300_ani_cck_err_trigger\n",
1252 __func__, ani_state->listen_time,
1253 ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1254 ani_state->cck_trig_high);
1255 ar9300_ani_cck_err_trigger(ah);
1256 ar9300_ani_restart(ah);
1257 ani_state->ofdms_turn = AH_TRUE;
1263 * The poll function above calculates short noise spurs, caused by non-80211
1264 * devices, based on OFDM/CCK Phy errs.
1265 * If the noise is short enough, we don't want our ratectrl Algo to stop probing
1266 * higher rates, due to bad PER.
1269 ar9300_is_ani_noise_spur(struct ath_hal *ah)
1271 struct ath_hal_9300 *ahp = AH9300(ah);
1272 struct ar9300_ani_state *ani_state;
1274 ani_state = ahp->ah_curani;
1276 return ani_state->phy_noise_spur;