xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c (revision 95eb4b873b6a8b527c5bd78d7191975dfca38998)
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, 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 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.
15  */
16 
17 #include "opt_ah.h"
18 
19 #include "ah.h"
20 #include "ah_internal.h"
21 #include "ah_desc.h"
22 //#include "ah_pktlog.h"
23 
24 #include "ar9300/ar9300.h"
25 #include "ar9300/ar9300reg.h"
26 #include "ar9300/ar9300phy.h"
27 
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);
30 
31 #define HAL_ANI_DEBUG 1
32 
33 /*
34  * Anti noise immunity support.  We track phy errors and react
35  * to excessive errors by adjusting the noise immunity parameters.
36  */
37 
38 /******************************************************************************
39  *
40  * New Ani Algorithm for Station side only
41  *
42  *****************************************************************************/
43 
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
55 
56 #define HAL_NOISE_DETECT_PERIOD     100
57 #define HAL_NOISE_RECOVER_PERIOD    5000
58 
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
63 
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)
69 
70 typedef int TABLE[];
71 /*
72  *                            level:    0   1   2   3   4   5   6   7   8
73  * firstep_table:    lvl 0-8, default 2
74  */
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 */
79 
80 typedef struct _HAL_ANI_OFDM_LEVEL_ENTRY {
81     int spur_immunity_level;
82     int fir_step_level;
83     int ofdm_weak_signal_on;
84 } HAL_ANI_OFDM_LEVEL_ENTRY;
85 static const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = {
86 /*     SI  FS  WS */
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 */
97 };
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 */
102 
103 typedef struct _HAL_ANI_CCK_LEVEL_ENTRY {
104     int fir_step_level;
105     int mrc_cck_on;
106 } HAL_ANI_CCK_LEVEL_ENTRY;
107 
108 static const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = {
109 /*     FS  MRC-CCK */
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) */
119 };
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 */
125 
126 /*
127  * register values to turn OFDM weak signal detection OFF
128  */
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;
139 
140 void
141 ar9300_enable_mib_counters(struct ath_hal *ah)
142 {
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);
146 
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);
153 
154 }
155 
156 void
157 ar9300_disable_mib_counters(struct ath_hal *ah)
158 {
159     HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__);
160 
161     OS_REG_WRITE(ah, AR_MIBC,  AR_MIBC_FMC | AR_MIBC_CMC);
162 
163     /* Clear the mib counters and save them in the stats */
164     ar9300_update_mib_mac_stats(ah);
165 
166     OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
167     OS_REG_WRITE(ah, AR_FILT_CCK, 0);
168 }
169 
170 /*
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.
176  */
177 static int
178 ar9300_get_ani_channel_index(struct ath_hal *ah,
179   const struct ieee80211_channel *chan)
180 {
181     struct ath_hal_9300 *ahp = AH9300(ah);
182     int i;
183 
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) {
187             return i;
188         }
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;
192             return i;
193         }
194     }
195     /* XXX statistic */
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 */
199 }
200 
201 /*
202  * Return the current ANI state of the channel we're on
203  */
204 struct ar9300_ani_state *
205 ar9300_ani_get_current_state(struct ath_hal *ah)
206 {
207     return AH9300(ah)->ah_curani;
208 }
209 
210 /*
211  * Return the current statistics.
212  */
213 HAL_ANI_STATS *
214 ar9300_ani_get_current_stats(struct ath_hal *ah)
215 {
216     return &AH9300(ah)->ah_stats;
217 }
218 
219 /*
220  * Setup ANI handling.  Sets all thresholds and levels to default level AND
221  * resets the channel statistics
222  */
223 
224 void
225 ar9300_ani_attach(struct ath_hal *ah)
226 {
227     struct ath_hal_9300 *ahp = AH9300(ah);
228     int i;
229 
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;
246     }
247 
248     /*
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.
252      */
253     HALASSERT(firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] == 0);
254     HALASSERT(cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] == 0);
255     HALASSERT(
256         ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].fir_step_level ==
257         HAL_ANI_DEF_FIRSTEP_LVL);
258     HALASSERT(
259         ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].spur_immunity_level ==
260         HAL_ANI_DEF_SPUR_IMMUNE_LVL);
261     HALASSERT(
262         cck_level_table[HAL_ANI_CCK_DEF_LEVEL].fir_step_level ==
263         HAL_ANI_DEF_FIRSTEP_LVL);
264 
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);
269 
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;
273     }
274 }
275 
276 /*
277  * Cleanup any ANI state setup.
278  */
279 void
280 ar9300_ani_detach(struct ath_hal *ah)
281 {
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);
286 }
287 
288 /*
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.
292  */
293 void
294 ar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode)
295 {
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;
299     int index;
300     u_int32_t val;
301 
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;
306 
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);
311 
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);
316 
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);
324 
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);
332 
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 =
336         OS_REG_READ_FIELD(
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);
342 
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;
348 
349     ani_state->cycle_count = 0;
350 }
351 
352 /*
353  * Set the ANI settings to match an OFDM level.
354  */
355 static void
356 ar9300_ani_set_odfm_noise_immunity_level(struct ath_hal *ah,
357                                    u_int8_t ofdm_noise_immunity_level)
358 {
359     struct ath_hal_9300 *ahp = AH9300(ah);
360     struct ar9300_ani_state *ani_state = ahp->ah_curani;
361 
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);
367 
368     ani_state->ofdm_noise_immunity_level = ofdm_noise_immunity_level;
369 
370     if (ani_state->spur_immunity_level !=
371         ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level)
372     {
373         ar9300_ani_control(
374             ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
375             ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level);
376     }
377 
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)
382     {
383         ar9300_ani_control(
384             ah, HAL_ANI_FIRSTEP_LEVEL,
385             ofdm_level_table[ofdm_noise_immunity_level].fir_step_level);
386     }
387 
388     if ((AH_PRIVATE(ah)->ah_opmode != HAL_M_STA ||
389         ani_state->rssi <= ani_state->rssi_thr_high))
390     {
391         if (ani_state->ofdm_weak_sig_detect_off) {
392             /*
393              * force on ofdm weak sig detect.
394              */
395             ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE);
396         }
397     } else if (ani_state->ofdm_weak_sig_detect_off ==
398                ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on)
399     {
400         ar9300_ani_control(
401             ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
402             ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on);
403     }
404 }
405 
406 /*
407  * Set the ANI settings to match a CCK level.
408  */
409 static void
410 ar9300_ani_set_cck_noise_immunity_level(struct ath_hal *ah,
411                                   u_int8_t cck_noise_immunity_level)
412 {
413     struct ath_hal_9300 *ahp = AH9300(ah);
414     struct ar9300_ani_state *ani_state = ahp->ah_curani;
415     int level;
416 
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);
422 
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)
426     {
427         cck_noise_immunity_level = HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI;
428     }
429 
430     ani_state->cck_noise_immunity_level = cck_noise_immunity_level;
431 
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)
437     {
438         ar9300_ani_control(
439             ah, HAL_ANI_FIRSTEP_LEVEL,
440             cck_level_table[cck_noise_immunity_level].fir_step_level);
441     }
442 
443     if (ani_state->mrc_cck_off ==
444         cck_level_table[cck_noise_immunity_level].mrc_cck_on)
445     {
446         ar9300_ani_control(
447             ah, HAL_ANI_MRC_CCK,
448             cck_level_table[cck_noise_immunity_level].mrc_cck_on);
449     }
450 }
451 
452 /*
453  * Control Adaptive Noise Immunity Parameters
454  */
455 HAL_BOOL
456 ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
457 {
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;
462     u_int level = param;
463     u_int is_on;
464 
465     HALDEBUG(ah, HAL_DEBUG_ANI, "%s: cmd=%d, param=%d, chan=%p, funcmask=0x%08x\n",
466       __func__,
467       cmd,
468       param,
469       chan,
470       ahp->ah_ani_function);
471 
472 
473     if (chan == NULL && cmd != HAL_ANI_MODE) {
474         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
475             "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd);
476         return AH_FALSE;
477     }
478 
479     /*
480      * These two control the top-level cck/ofdm immunity levels and will
481      * program the rest of the values.
482      */
483     if (cmd == HAL_ANI_NOISE_IMMUNITY_LEVEL) {
484         if (param > HAL_ANI_OFDM_NUM_LEVEL)
485           return AH_FALSE;
486         ar9300_ani_set_odfm_noise_immunity_level(ah, param);
487         return AH_TRUE;
488     }
489 
490     if (cmd == HAL_ANI_CCK_NOISE_IMMUNITY_LEVEL) {
491         if (param > HAL_ANI_CCK_NUM_LEVEL)
492           return AH_FALSE;
493         ar9300_ani_set_cck_noise_immunity_level(ah, param);
494         return AH_TRUE;
495     }
496 
497     /*
498      * Check to see if this command is available in the
499      * current operating mode.
500      */
501     if (((1 << cmd) & ahp->ah_ani_function) == 0) {
502         HALDEBUG(ah, HAL_DEBUG_ANI,
503             "%s: early check: invalid cmd 0x%02x (allowed=0x%02x)\n",
504             __func__, cmd, ahp->ah_ani_function);
505         return AH_FALSE;
506     }
507 
508     /*
509      * The rest of these program in the requested parameter values
510      * into the PHY.
511      */
512     switch (cmd) {
513 
514     case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
515         {
516             int m1_thresh_low, m2_thresh_low;
517             int m1_thresh, m2_thresh;
518             int m2_count_thr, m2_count_thr_low;
519             int m1_thresh_low_ext, m2_thresh_low_ext;
520             int m1_thresh_ext, m2_thresh_ext;
521             /*
522              * is_on == 1 means ofdm weak signal detection is ON
523              * (default, less noise imm)
524              * is_on == 0 means ofdm weak signal detection is OFF
525              * (more noise imm)
526              */
527             is_on = param ? 1 : 0;
528 
529             if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah))
530                 goto skip_ws_det;
531 
532             /*
533              * make register setting for default (weak sig detect ON)
534              * come from INI file
535              */
536             m1_thresh_low    = is_on ?
537                 ani_state->ini_def.m1_thresh_low    : m1_thresh_low_off;
538             m2_thresh_low    = is_on ?
539                 ani_state->ini_def.m2_thresh_low    : m2_thresh_low_off;
540             m1_thresh       = is_on ?
541                 ani_state->ini_def.m1_thresh       : m1_thresh_off;
542             m2_thresh       = is_on ?
543                 ani_state->ini_def.m2_thresh       : m2_thresh_off;
544             m2_count_thr     = is_on ?
545                 ani_state->ini_def.m2_count_thr     : m2_count_thr_off;
546             m2_count_thr_low  = is_on ?
547                 ani_state->ini_def.m2_count_thr_low  : m2_count_thr_low_off;
548             m1_thresh_low_ext = is_on ?
549                 ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off;
550             m2_thresh_low_ext = is_on ?
551                 ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off;
552             m1_thresh_ext    = is_on ?
553                 ani_state->ini_def.m1_thresh_ext    : m1_thresh_ext_off;
554             m2_thresh_ext    = is_on ?
555                 ani_state->ini_def.m2_thresh_ext    : m2_thresh_ext_off;
556             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
557                 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low);
558             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
559                 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low);
560             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH,
561                 m1_thresh);
562             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
563                 m2_thresh);
564             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
565                 m2_count_thr);
566             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
567                 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low);
568             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
569                 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext);
570             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
571                 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext);
572             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH,
573                 m1_thresh_ext);
574             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
575                 m2_thresh_ext);
576 skip_ws_det:
577             if (is_on) {
578                 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
579                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
580             } else {
581                 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
582                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
583             }
584             if ((!is_on) != ani_state->ofdm_weak_sig_detect_off) {
585                 HALDEBUG(ah, HAL_DEBUG_ANI,
586                     "%s: ** ch %d: ofdm weak signal: %s=>%s\n",
587                     __func__, chan->ic_freq,
588                     !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
589                     is_on ? "on" : "off");
590                 if (is_on) {
591                     ahp->ah_stats.ast_ani_ofdmon++;
592                 } else {
593                     ahp->ah_stats.ast_ani_ofdmoff++;
594                 }
595                 ani_state->ofdm_weak_sig_detect_off = !is_on;
596             }
597             break;
598         }
599     case HAL_ANI_FIRSTEP_LEVEL:
600         if (level >= ARRAY_LENGTH(firstep_table)) {
601             HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
602                 "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n",
603                 __func__, level, (unsigned) ARRAY_LENGTH(firstep_table));
604             return AH_FALSE;
605         }
606         /*
607          * make register setting relative to default
608          * from INI file & cap value
609          */
610         value =
611             firstep_table[level] -
612             firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
613             ani_state->ini_def.firstep;
614         if (value < HAL_SIG_FIRSTEP_SETTING_MIN) {
615             value = HAL_SIG_FIRSTEP_SETTING_MIN;
616         }
617         if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
618             value = HAL_SIG_FIRSTEP_SETTING_MAX;
619         }
620         OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
621         /*
622          * we need to set first step low register too
623          * make register setting relative to default from INI file & cap value
624          */
625         value2 =
626             firstep_table[level] -
627             firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
628             ani_state->ini_def.firstep_low;
629         if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) {
630             value2 = HAL_SIG_FIRSTEP_SETTING_MIN;
631         }
632         if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
633             value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
634         }
635         OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
636             AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
637 
638         if (level != ani_state->firstep_level) {
639             HALDEBUG(ah, HAL_DEBUG_ANI,
640                 "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
641                 __func__, chan->ic_freq, ani_state->firstep_level, level,
642                 HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep);
643             HALDEBUG(ah, HAL_DEBUG_ANI,
644                 "%s: ** ch %d: level %d=>%d[def:%d] "
645                 "firstep_low[level]=%d ini=%d\n",
646                 __func__, chan->ic_freq, ani_state->firstep_level, level,
647                 HAL_ANI_DEF_FIRSTEP_LVL, value2,
648                 ani_state->ini_def.firstep_low);
649             if (level > ani_state->firstep_level) {
650                 ahp->ah_stats.ast_ani_stepup++;
651             } else if (level < ani_state->firstep_level) {
652                 ahp->ah_stats.ast_ani_stepdown++;
653             }
654             ani_state->firstep_level = level;
655         }
656         break;
657     case HAL_ANI_SPUR_IMMUNITY_LEVEL:
658         if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) {
659             HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
660                 "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level "
661                 "out of range (%u > %u)\n",
662                 __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table));
663             return AH_FALSE;
664         }
665         /*
666          * make register setting relative to default from INI file & cap value
667          */
668         value =
669             cycpwr_thr1_table[level] -
670             cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
671             ani_state->ini_def.cycpwr_thr1;
672         if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) {
673             value = HAL_SIG_SPUR_IMM_SETTING_MIN;
674         }
675         if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
676             value = HAL_SIG_SPUR_IMM_SETTING_MAX;
677         }
678         OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);
679 
680         /*
681          * set AR_PHY_EXT_CCA for extension channel
682          * make register setting relative to default from INI file & cap value
683          */
684         value2 =
685             cycpwr_thr1_table[level] -
686             cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
687             ani_state->ini_def.cycpwr_thr1_ext;
688         if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) {
689             value2 = HAL_SIG_SPUR_IMM_SETTING_MIN;
690         }
691         if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
692             value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
693         }
694         OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);
695 
696         if (level != ani_state->spur_immunity_level) {
697             HALDEBUG(ah, HAL_DEBUG_ANI,
698                 "%s: ** ch %d: level %d=>%d[def:%d] "
699                 "cycpwr_thr1[level]=%d ini=%d\n",
700                 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
701                 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value,
702                 ani_state->ini_def.cycpwr_thr1);
703             HALDEBUG(ah, HAL_DEBUG_ANI,
704                 "%s: ** ch %d: level %d=>%d[def:%d] "
705                 "cycpwr_thr1_ext[level]=%d ini=%d\n",
706                 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
707                 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2,
708                 ani_state->ini_def.cycpwr_thr1_ext);
709             if (level > ani_state->spur_immunity_level) {
710                 ahp->ah_stats.ast_ani_spurup++;
711             } else if (level < ani_state->spur_immunity_level) {
712                 ahp->ah_stats.ast_ani_spurdown++;
713             }
714             ani_state->spur_immunity_level = level;
715         }
716         break;
717     case HAL_ANI_MRC_CCK:
718         /*
719          * is_on == 1 means MRC CCK ON (default, less noise imm)
720          * is_on == 0 means MRC CCK is OFF (more noise imm)
721          */
722         is_on = param ? 1 : 0;
723         if (!AR_SREV_POSEIDON(ah)) {
724             OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
725                 AR_PHY_MRC_CCK_ENABLE, is_on);
726             OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
727                 AR_PHY_MRC_CCK_MUX_REG, is_on);
728         }
729         if ((!is_on) != ani_state->mrc_cck_off) {
730             HALDEBUG(ah, HAL_DEBUG_ANI,
731                 "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq,
732                 !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off");
733             if (is_on) {
734                 ahp->ah_stats.ast_ani_ccklow++;
735             } else {
736                 ahp->ah_stats.ast_ani_cckhigh++;
737             }
738             ani_state->mrc_cck_off = !is_on;
739         }
740         break;
741     case HAL_ANI_PRESENT:
742         break;
743 #ifdef AH_PRIVATE_DIAG
744     case HAL_ANI_MODE:
745         if (param == 0) {
746             ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI;
747             /* Turn off HW counters if we have them */
748             ar9300_ani_detach(ah);
749             if (AH_PRIVATE(ah)->ah_curchan == NULL) {
750                 return AH_TRUE;
751             }
752             /* if we're turning off ANI, reset regs back to INI settings */
753             if (ah->ah_config.ath_hal_enable_ani) {
754                 HAL_ANI_CMD savefunc = ahp->ah_ani_function;
755                 /* temporarly allow all functions so we can reset */
756                 ahp->ah_ani_function = HAL_ANI_ALL;
757                 HALDEBUG(ah, HAL_DEBUG_ANI,
758                     "%s: disable all ANI functions\n", __func__);
759                 ar9300_ani_set_odfm_noise_immunity_level(
760                     ah, HAL_ANI_OFDM_DEF_LEVEL);
761                 ar9300_ani_set_cck_noise_immunity_level(
762                     ah, HAL_ANI_CCK_DEF_LEVEL);
763                 ahp->ah_ani_function = savefunc;
764             }
765         } else {            /* normal/auto mode */
766             HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__);
767             ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
768             if (AH_PRIVATE(ah)->ah_curchan == NULL) {
769                 return AH_TRUE;
770             }
771             ar9300_enable_mib_counters(ah);
772             ar9300_ani_reset(ah, AH_FALSE);
773             ani_state = ahp->ah_curani;
774         }
775         HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
776                  ahp->ah_proc_phy_err);
777         break;
778     case HAL_ANI_PHYERR_RESET:
779         ahp->ah_stats.ast_ani_ofdmerrs = 0;
780         ahp->ah_stats.ast_ani_cckerrs = 0;
781         break;
782 #endif /* AH_PRIVATE_DIAG */
783     default:
784 #if HAL_ANI_DEBUG
785         HALDEBUG(ah, HAL_DEBUG_ANI,
786             "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
787             __func__, cmd, ahp->ah_ani_function);
788 #endif
789         return AH_FALSE;
790     }
791 
792 #if HAL_ANI_DEBUG
793     HALDEBUG(ah, HAL_DEBUG_ANI,
794         "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d "
795         "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n",
796         __func__, ani_state->spur_immunity_level,
797         !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
798         ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off",
799         ani_state->listen_time, ani_state->cycle_count,
800         ani_state->listen_time, ani_state->ofdm_phy_err_count,
801         ani_state->cck_phy_err_count);
802 #endif
803 
804 #ifndef REMOVE_PKT_LOG
805     /* do pktlog */
806     {
807         struct log_ani log_data;
808 
809         /* Populate the ani log record */
810         log_data.phy_stats_disable = DO_ANI(ah);
811         log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level;
812         log_data.spur_immun_lvl = ani_state->spur_immunity_level;
813         log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off;
814         log_data.cck_weak_thr = ani_state->cck_noise_immunity_level;
815         log_data.fir_lvl = ani_state->firstep_level;
816         log_data.listen_time = ani_state->listen_time;
817         log_data.cycle_count = ani_state->cycle_count;
818         /* express ofdm_phy_err_count as errors/second */
819         log_data.ofdm_phy_err_count = ani_state->listen_time ?
820             ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0;
821         /* express cck_phy_err_count as errors/second */
822         log_data.cck_phy_err_count =  ani_state->listen_time ?
823             ani_state->cck_phy_err_count * 1000 / ani_state->listen_time  : 0;
824         log_data.rssi = ani_state->rssi;
825 
826         /* clear interrupt context flag */
827         ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
828     }
829 #endif
830 
831     return AH_TRUE;
832 }
833 
834 static void
835 ar9300_ani_restart(struct ath_hal *ah)
836 {
837     struct ath_hal_9300 *ahp = AH9300(ah);
838     struct ar9300_ani_state *ani_state;
839 
840     if (!DO_ANI(ah)) {
841         return;
842     }
843 
844     ani_state = ahp->ah_curani;
845 
846     ani_state->listen_time = 0;
847 
848     OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
849     OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
850     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
851     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
852 
853     /* Clear the mib counters and save them in the stats */
854     ar9300_update_mib_mac_stats(ah);
855 
856     ani_state->ofdm_phy_err_count = 0;
857     ani_state->cck_phy_err_count = 0;
858 }
859 
860 static void
861 ar9300_ani_ofdm_err_trigger(struct ath_hal *ah)
862 {
863     struct ath_hal_9300 *ahp = AH9300(ah);
864     struct ar9300_ani_state *ani_state;
865 
866     if (!DO_ANI(ah)) {
867         return;
868     }
869 
870     ani_state = ahp->ah_curani;
871 
872     if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) {
873         ar9300_ani_set_odfm_noise_immunity_level(
874             ah, ani_state->ofdm_noise_immunity_level + 1);
875     }
876 }
877 
878 static void
879 ar9300_ani_cck_err_trigger(struct ath_hal *ah)
880 {
881     struct ath_hal_9300 *ahp = AH9300(ah);
882     struct ar9300_ani_state *ani_state;
883 
884     if (!DO_ANI(ah)) {
885         return;
886     }
887 
888     ani_state = ahp->ah_curani;
889 
890     if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) {
891         ar9300_ani_set_cck_noise_immunity_level(
892             ah, ani_state->cck_noise_immunity_level + 1);
893     }
894 }
895 
896 /*
897  * Restore the ANI parameters in the HAL and reset the statistics.
898  * This routine should be called for every hardware reset and for
899  * every channel change.
900  */
901 void
902 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
903 {
904     struct ath_hal_9300 *ahp = AH9300(ah);
905     struct ar9300_ani_state *ani_state;
906     const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
907     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
908     int index;
909 
910     HALASSERT(chan != AH_NULL);
911 
912     if (!DO_ANI(ah)) {
913         return;
914     }
915 
916     /*
917      * we need to re-point to the correct ANI state since the channel
918      * may have changed due to a fast channel change
919     */
920     index = ar9300_get_ani_channel_index(ah, chan);
921     ani_state = &ahp->ah_ani[index];
922     HALASSERT(ani_state != AH_NULL);
923     ahp->ah_curani = ani_state;
924 
925     ahp->ah_stats.ast_ani_reset++;
926 
927     ani_state->phy_noise_spur = 0;
928 
929     /* only allow a subset of functions in AP mode */
930     if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
931         if (IS_CHAN_2GHZ(ichan)) {
932             ahp->ah_ani_function = (1 << HAL_ANI_SPUR_IMMUNITY_LEVEL) |
933                                    (1 << HAL_ANI_FIRSTEP_LEVEL) |
934                                    (1 << HAL_ANI_MRC_CCK);
935         } else {
936             ahp->ah_ani_function = 0;
937         }
938     } else {
939       ahp->ah_ani_function = HAL_ANI_ALL;
940     }
941 
942     /* always allow mode (on/off) to be controlled */
943     ahp->ah_ani_function |= HAL_ANI_MODE;
944 
945     if (is_scanning ||
946         (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
947          AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
948     {
949         /*
950          * If we're scanning or in AP mode, the defaults (ini) should be
951          * in place.
952          * For an AP we assume the historical levels for this channel are
953          * probably outdated so start from defaults instead.
954          */
955         if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL ||
956             ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL)
957         {
958             HALDEBUG(ah, HAL_DEBUG_ANI,
959                 "%s: Restore defaults: opmode %u chan %d Mhz/0x%x "
960                 "is_scanning=%d restore=%d ofdm:%d cck:%d\n",
961                 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
962                 chan->ic_flags, is_scanning, ani_state->must_restore,
963                 ani_state->ofdm_noise_immunity_level,
964                 ani_state->cck_noise_immunity_level);
965             /*
966              * for STA/IBSS, we want to restore the historical values later
967              * (when we're not scanning)
968              */
969             if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
970                 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
971             {
972                 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
973                     HAL_ANI_DEF_SPUR_IMMUNE_LVL);
974                 ar9300_ani_control(
975                     ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL);
976                 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
977                     HAL_ANI_USE_OFDM_WEAK_SIG);
978                 ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK);
979                 ani_state->must_restore = AH_TRUE;
980             } else {
981                 ar9300_ani_set_odfm_noise_immunity_level(
982                     ah, HAL_ANI_OFDM_DEF_LEVEL);
983                 ar9300_ani_set_cck_noise_immunity_level(
984                     ah, HAL_ANI_CCK_DEF_LEVEL);
985             }
986         }
987     } else {
988         /*
989          * restore historical levels for this channel
990          */
991         HALDEBUG(ah, HAL_DEBUG_ANI,
992             "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d "
993             "restore=%d ofdm:%d cck:%d\n",
994             __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
995             chan->ic_flags, is_scanning, ani_state->must_restore,
996             ani_state->ofdm_noise_immunity_level,
997             ani_state->cck_noise_immunity_level);
998         ar9300_ani_set_odfm_noise_immunity_level(
999             ah, ani_state->ofdm_noise_immunity_level);
1000         ar9300_ani_set_cck_noise_immunity_level(
1001             ah, ani_state->cck_noise_immunity_level);
1002         ani_state->must_restore = AH_FALSE;
1003     }
1004 
1005     /* enable phy counters */
1006     ar9300_ani_restart(ah);
1007     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
1008     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
1009 }
1010 
1011 /*
1012  * Process a MIB interrupt.  We may potentially be invoked because
1013  * any of the MIB counters overflow/trigger so don't assume we're
1014  * here because a PHY error counter triggered.
1015  */
1016 void
1017 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
1018 {
1019     struct ath_hal_9300 *ahp = AH9300(ah);
1020     u_int32_t phy_cnt1, phy_cnt2;
1021 
1022 #if 0
1023     HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
1024 #endif
1025 
1026     /* Reset these counters regardless */
1027     OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
1028     OS_REG_WRITE(ah, AR_FILT_CCK, 0);
1029     if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) {
1030         OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
1031     }
1032 
1033     /* Clear the mib counters and save them in the stats */
1034     ar9300_update_mib_mac_stats(ah);
1035     ahp->ah_stats.ast_nodestats = *stats;
1036 
1037     if (!DO_ANI(ah)) {
1038         /*
1039          * We must always clear the interrupt cause by resetting
1040          * the phy error regs.
1041          */
1042         OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
1043         OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
1044         return;
1045     }
1046 
1047     /* NB: these are not reset-on-read */
1048     phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
1049     phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
1050 #if HAL_ANI_DEBUG
1051     HALDEBUG(ah, HAL_DEBUG_ANI,
1052         "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
1053         __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2);
1054 #endif
1055     if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
1056         ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
1057         /* NB: always restart to insure the h/w counters are reset */
1058         ar9300_ani_restart(ah);
1059     }
1060 }
1061 
1062 
1063 static void
1064 ar9300_ani_lower_immunity(struct ath_hal *ah)
1065 {
1066     struct ath_hal_9300 *ahp = AH9300(ah);
1067     struct ar9300_ani_state *ani_state = ahp->ah_curani;
1068 
1069     if (ani_state->ofdm_noise_immunity_level > 0 &&
1070         (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) {
1071         /*
1072          * lower OFDM noise immunity
1073          */
1074         ar9300_ani_set_odfm_noise_immunity_level(
1075             ah, ani_state->ofdm_noise_immunity_level - 1);
1076 
1077         /*
1078          * only lower either OFDM or CCK errors per turn
1079          * we lower the other one next time
1080          */
1081         return;
1082     }
1083 
1084     if (ani_state->cck_noise_immunity_level > 0) {
1085         /*
1086          * lower CCK noise immunity
1087          */
1088         ar9300_ani_set_cck_noise_immunity_level(
1089             ah, ani_state->cck_noise_immunity_level - 1);
1090     }
1091 }
1092 
1093 /* convert HW counter values to ms using mode specifix clock rate */
1094 //#define CLOCK_RATE(_ah)  (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000)
1095 #define CLOCK_RATE(_ah)  (ath_hal_mac_clks(ah, 1000))
1096 
1097 /*
1098  * Return an approximation of the time spent ``listening'' by
1099  * deducting the cycles spent tx'ing and rx'ing from the total
1100  * cycle count since our last call.  A return value <0 indicates
1101  * an invalid/inconsistent time.
1102  */
1103 static int32_t
1104 ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats)
1105 {
1106     struct ath_hal_9300 *ahp = AH9300(ah);
1107     struct ar9300_ani_state *ani_state;
1108     u_int32_t tx_frame_count, rx_frame_count, cycle_count;
1109     u_int32_t rx_busy_count, rx_ext_busy_count;
1110     int32_t listen_time;
1111 
1112     tx_frame_count = OS_REG_READ(ah, AR_TFCNT);
1113     rx_frame_count = OS_REG_READ(ah, AR_RFCNT);
1114     rx_busy_count = OS_REG_READ(ah, AR_RCCNT);
1115     rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT);
1116     cycle_count = OS_REG_READ(ah, AR_CCCNT);
1117 
1118     ani_state = ahp->ah_curani;
1119     if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) {
1120         /*
1121          * Cycle counter wrap (or initial call); it's not possible
1122          * to accurately calculate a value because the registers
1123          * right shift rather than wrap--so punt and return 0.
1124          */
1125         listen_time = 0;
1126         ahp->ah_stats.ast_ani_lzero++;
1127 #if HAL_ANI_DEBUG
1128         HALDEBUG(ah, HAL_DEBUG_ANI,
1129             "%s: 1st call: ani_state->cycle_count=%d\n",
1130             __func__, ani_state->cycle_count);
1131 #endif
1132     } else {
1133         int32_t ccdelta = cycle_count - ani_state->cycle_count;
1134         int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count;
1135         int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count;
1136         int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count;
1137         int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count;
1138         listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah);
1139 //#if HAL_ANI_DEBUG
1140         HALDEBUG(ah, HAL_DEBUG_ANI,
1141             "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d "
1142             "CLOCK_RATE=%d\n",
1143             __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta,
1144             listen_time, CLOCK_RATE(ah));
1145 //#endif
1146             /* Populate as appropriate */
1147             ani_stats->cyclecnt_diff = ccdelta;
1148             ani_stats->rxclr_cnt = rcdelta;
1149             ani_stats->txframecnt_diff = tfdelta;
1150             ani_stats->rxframecnt_diff = rfdelta;
1151             ani_stats->extrxclr_cnt = extrcdelta;
1152             ani_stats->listen_time = listen_time;
1153             ani_stats->valid = AH_TRUE;
1154     }
1155     ani_state->cycle_count = cycle_count;
1156     ani_state->tx_frame_count = tx_frame_count;
1157     ani_state->rx_frame_count = rx_frame_count;
1158     ani_state->rx_busy_count = rx_busy_count;
1159     ani_state->rx_ext_busy_count = rx_ext_busy_count;
1160     return listen_time;
1161 }
1162 
1163 /*
1164  * Do periodic processing.  This routine is called from a timer
1165  */
1166 void
1167 ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
1168                 const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
1169 {
1170     struct ath_hal_9300 *ahp = AH9300(ah);
1171     struct ar9300_ani_state *ani_state;
1172     int32_t listen_time;
1173     u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
1174     u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
1175     HAL_BOOL old_phy_noise_spur;
1176 
1177     ani_state = ahp->ah_curani;
1178     ahp->ah_stats.ast_nodestats = *stats;        /* XXX optimize? */
1179 
1180     if (ani_state == NULL) {
1181         /* should not happen */
1182         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1183             "%s: can't poll - no ANI not initialized for this channel\n",
1184             __func__);
1185         return;
1186     }
1187 
1188     /*
1189      * ar9300_ani_ar_poll is never called while scanning but we may have been
1190      * scanning and now just restarted polling.  In this case we need to
1191      * restore historical values.
1192      */
1193     if (ani_state->must_restore) {
1194         HALDEBUG(ah, HAL_DEBUG_ANI,
1195             "%s: must restore - calling ar9300_ani_restart\n", __func__);
1196         ar9300_ani_reset(ah, AH_FALSE);
1197         return;
1198     }
1199 
1200     listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
1201     if (listen_time <= 0) {
1202         ahp->ah_stats.ast_ani_lneg++;
1203         /* restart ANI period if listen_time is invalid */
1204         HALDEBUG(ah, HAL_DEBUG_ANI,
1205             "%s: listen_time=%d - calling ar9300_ani_restart\n",
1206             __func__, listen_time);
1207         ar9300_ani_restart(ah);
1208         return;
1209     }
1210     /* XXX beware of overflow? */
1211     ani_state->listen_time += listen_time;
1212 
1213     /* Clear the mib counters and save them in the stats */
1214     ar9300_update_mib_mac_stats(ah);
1215     /* NB: these are not reset-on-read */
1216     ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
1217     cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);
1218 
1219     /* Populate HAL_ANISTATS */
1220     /* XXX TODO: are these correct? */
1221     if (ani_stats) {
1222             ani_stats->cckphyerr_cnt =
1223                cck_phy_err_cnt - ani_state->cck_phy_err_count;
1224             ani_stats->ofdmphyerrcnt_diff =
1225               ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1226     }
1227 
1228     /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
1229     ahp->ah_stats.ast_ani_ofdmerrs +=
1230         ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1231     ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;
1232 
1233     ahp->ah_stats.ast_ani_cckerrs +=
1234         cck_phy_err_cnt - ani_state->cck_phy_err_count;
1235     ani_state->cck_phy_err_count = cck_phy_err_cnt;
1236 
1237     /*
1238      * Note - the ANI code is using the aggregate listen time.
1239      * The AR_PHY_CNT1/AR_PHY_CNT2 registers here are also
1240      * free running, not clear-on-read and are free-running.
1241      *
1242      * So, ofdm_phy_err_rate / cck_phy_err_rate are accumulating
1243      * the same as listenTime is accumulating.
1244      */
1245 
1246 #if HAL_ANI_DEBUG
1247     HALDEBUG(ah, HAL_DEBUG_ANI,
1248         "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
1249         __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
1250         cck_phy_err_cnt, cck_phy_err_cnt);
1251 #endif
1252 
1253     /*
1254      * If ani is not enabled, return after we've collected
1255      * statistics
1256      */
1257     if (!DO_ANI(ah)) {
1258         return;
1259     }
1260 
1261     /*
1262      * Calculate the OFDM/CCK phy error rate over the listen time interval.
1263      * This is used in subsequent math to see if the OFDM/CCK phy error rate
1264      * is above or below the threshold checks.
1265      */
1266 
1267     ofdm_phy_err_rate =
1268         ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
1269     cck_phy_err_rate =
1270         ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;
1271 
1272     HALDEBUG(ah, HAL_DEBUG_ANI,
1273         "%s: listen_time=%d (total: %d) OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
1274         __func__, listen_time,
1275         ani_state->listen_time,
1276         ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1277         ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1278         ani_state->ofdms_turn);
1279 
1280     /*
1281      * Check for temporary noise spurs.  This is intended to be used by
1282      * rate control to check if we should try higher packet rates or not.
1283      * If the noise period is short enough then we shouldn't avoid trying
1284      * higher rates but if the noise is high/sustained then it's likely
1285      * not a great idea to try the higher MCS rates.
1286      */
1287     if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
1288         old_phy_noise_spur = ani_state->phy_noise_spur;
1289         if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1290             cck_phy_err_rate <= ani_state->cck_trig_low) {
1291             if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
1292                 ani_state->phy_noise_spur = 0;
1293             }
1294         } else {
1295             ani_state->phy_noise_spur = 1;
1296         }
1297         if (old_phy_noise_spur != ani_state->phy_noise_spur) {
1298             HALDEBUG(ah, HAL_DEBUG_ANI,
1299                      "%s: environment change from %d to %d\n",
1300                      __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
1301         }
1302     }
1303 
1304     if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
1305         /*
1306          * Check to see if need to lower immunity if
1307          * 5 ani_periods have passed
1308          */
1309         if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1310             cck_phy_err_rate <= ani_state->cck_trig_low)
1311         {
1312             HALDEBUG(ah, HAL_DEBUG_ANI,
1313                 "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d)  "
1314                 "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
1315                 __func__, ani_state->listen_time,
1316                 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1317                 ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
1318                 cck_phy_err_rate, ani_state->cck_trig_low);
1319             ar9300_ani_lower_immunity(ah);
1320             ani_state->ofdms_turn = !ani_state->ofdms_turn;
1321         }
1322         /*
1323          * Force an ANI restart regardless of whether the lower immunity
1324          * level was met.
1325          */
1326         HALDEBUG(ah, HAL_DEBUG_ANI,
1327             "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
1328             "calling ar9300_ani_restart\n",
1329             __func__, ani_state->listen_time,
1330             ofdm_phy_err_rate, cck_phy_err_rate);
1331         ar9300_ani_restart(ah);
1332      } else if (ani_state->listen_time > ahp->ah_ani_period) {
1333         /* check to see if need to raise immunity */
1334         if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
1335             (cck_phy_err_rate <= ani_state->cck_trig_high ||
1336              ani_state->ofdms_turn))
1337         {
1338             HALDEBUG(ah, HAL_DEBUG_ANI,
1339                 "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
1340                 "ar9300_ani_ofdm_err_trigger\n",
1341                 __func__, ani_state->listen_time,
1342                 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1343                 ani_state->ofdm_trig_high);
1344             ar9300_ani_ofdm_err_trigger(ah);
1345             ar9300_ani_restart(ah);
1346             ani_state->ofdms_turn = AH_FALSE;
1347         } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
1348             HALDEBUG(ah, HAL_DEBUG_ANI,
1349                 "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
1350                 "ar9300_ani_cck_err_trigger\n",
1351                 __func__, ani_state->listen_time,
1352                 ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1353                 ani_state->cck_trig_high);
1354             ar9300_ani_cck_err_trigger(ah);
1355             ar9300_ani_restart(ah);
1356             ani_state->ofdms_turn = AH_TRUE;
1357         }
1358     }
1359 
1360     /*
1361      * Note that currently this poll function doesn't reset the listen
1362      * time after it accumulates a second worth of error samples.
1363      * It will continue to accumulate samples until a counter overflows,
1364      * or a raise threshold is met, or 5 seconds passes.
1365      */
1366 }
1367 
1368 /*
1369  * The poll function above calculates short noise spurs, caused by non-80211
1370  * devices, based on OFDM/CCK Phy errs.
1371  * If the noise is short enough, we don't want our ratectrl Algo to stop probing
1372  * higher rates, due to bad PER.
1373  */
1374 HAL_BOOL
1375 ar9300_is_ani_noise_spur(struct ath_hal *ah)
1376 {
1377     struct ath_hal_9300 *ahp = AH9300(ah);
1378     struct ar9300_ani_state *ani_state;
1379 
1380     ani_state = ahp->ah_curani;
1381 
1382     return ani_state->phy_noise_spur;
1383 }
1384 
1385