xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
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 struct ar9300_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     if (chan == NULL && cmd != HAL_ANI_MODE) {
466         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
467             "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd);
468         return AH_FALSE;
469     }
470 
471     switch (cmd & ahp->ah_ani_function) {
472     case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
473         {
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;
479             /*
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
483              * (more noise imm)
484              */
485             is_on = param ? 1 : 0;
486 
487             /*
488              * make register setting for default (weak sig detect ON)
489              * come from INI file
490              */
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;
495             m1_thresh       = is_on ?
496                 ani_state->ini_def.m1_thresh       : m1_thresh_off;
497             m2_thresh       = is_on ?
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,
516                 m1_thresh);
517             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
518                 m2_thresh);
519             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
520                 m2_count_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,
528                 m1_thresh_ext);
529             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
530                 m2_thresh_ext);
531             if (is_on) {
532                 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
533                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
534             } else {
535                 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
536                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
537             }
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");
544                 if (is_on) {
545                     ahp->ah_stats.ast_ani_ofdmon++;
546                 } else {
547                     ahp->ah_stats.ast_ani_ofdmoff++;
548                 }
549                 ani_state->ofdm_weak_sig_detect_off = !is_on;
550             }
551             break;
552         }
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));
558             return AH_FALSE;
559         }
560         /*
561          * make register setting relative to default
562          * from INI file & cap value
563          */
564         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;
570         }
571         if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
572             value = HAL_SIG_FIRSTEP_SETTING_MAX;
573         }
574         OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
575         /*
576          * we need to set first step low register too
577          * make register setting relative to default from INI file & cap value
578          */
579         value2 =
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;
585         }
586         if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
587             value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
588         }
589         OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
590             AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
591 
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++;
607             }
608             ani_state->firstep_level = level;
609         }
610         break;
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));
617             return AH_FALSE;
618         }
619         /*
620          * make register setting relative to default from INI file & cap value
621          */
622         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;
628         }
629         if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
630             value = HAL_SIG_SPUR_IMM_SETTING_MAX;
631         }
632         OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);
633 
634         /*
635          * set AR_PHY_EXT_CCA for extension channel
636          * make register setting relative to default from INI file & cap value
637          */
638         value2 =
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;
644         }
645         if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
646             value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
647         }
648         OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);
649 
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++;
667             }
668             ani_state->spur_immunity_level = level;
669         }
670         break;
671     case HAL_ANI_MRC_CCK:
672         /*
673          * is_on == 1 means MRC CCK ON (default, less noise imm)
674          * is_on == 0 means MRC CCK is OFF (more noise imm)
675          */
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);
682         }
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");
687             if (is_on) {
688                 ahp->ah_stats.ast_ani_ccklow++;
689             } else {
690                 ahp->ah_stats.ast_ani_cckhigh++;
691             }
692             ani_state->mrc_cck_off = !is_on;
693         }
694         break;
695     case HAL_ANI_PRESENT:
696         break;
697 #ifdef AH_PRIVATE_DIAG
698     case HAL_ANI_MODE:
699         if (param == 0) {
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) {
704                 return AH_TRUE;
705             }
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;
718             }
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) {
723                 return AH_TRUE;
724             }
725             ar9300_enable_mib_counters(ah);
726             ar9300_ani_reset(ah, AH_FALSE);
727             ani_state = ahp->ah_curani;
728         }
729         HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
730                  ahp->ah_proc_phy_err);
731         break;
732     case HAL_ANI_PHYERR_RESET:
733         ahp->ah_stats.ast_ani_ofdmerrs = 0;
734         ahp->ah_stats.ast_ani_cckerrs = 0;
735         break;
736 #endif /* AH_PRIVATE_DIAG */
737     default:
738 #if HAL_ANI_DEBUG
739         HALDEBUG(ah, HAL_DEBUG_ANI,
740             "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
741             __func__, cmd, ahp->ah_ani_function);
742 #endif
743         return AH_FALSE;
744     }
745 
746 #if HAL_ANI_DEBUG
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);
756 #endif
757 
758 #ifndef REMOVE_PKT_LOG
759     /* do pktlog */
760     {
761         struct log_ani log_data;
762 
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;
779 
780         /* clear interrupt context flag */
781         ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
782     }
783 #endif
784 
785     return AH_TRUE;
786 }
787 
788 static void
789 ar9300_ani_restart(struct ath_hal *ah)
790 {
791     struct ath_hal_9300 *ahp = AH9300(ah);
792     struct ar9300_ani_state *ani_state;
793 
794     if (!DO_ANI(ah)) {
795         return;
796     }
797 
798     ani_state = ahp->ah_curani;
799 
800     ani_state->listen_time = 0;
801 
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);
806 
807     /* Clear the mib counters and save them in the stats */
808     ar9300_update_mib_mac_stats(ah);
809 
810     ani_state->ofdm_phy_err_count = 0;
811     ani_state->cck_phy_err_count = 0;
812 }
813 
814 static void
815 ar9300_ani_ofdm_err_trigger(struct ath_hal *ah)
816 {
817     struct ath_hal_9300 *ahp = AH9300(ah);
818     struct ar9300_ani_state *ani_state;
819 
820     if (!DO_ANI(ah)) {
821         return;
822     }
823 
824     ani_state = ahp->ah_curani;
825 
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);
829     }
830 }
831 
832 static void
833 ar9300_ani_cck_err_trigger(struct ath_hal *ah)
834 {
835     struct ath_hal_9300 *ahp = AH9300(ah);
836     struct ar9300_ani_state *ani_state;
837 
838     if (!DO_ANI(ah)) {
839         return;
840     }
841 
842     ani_state = ahp->ah_curani;
843 
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);
847     }
848 }
849 
850 /*
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.
854  */
855 void
856 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
857 {
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);
862     int index;
863 
864     HALASSERT(chan != AH_NULL);
865 
866     if (!DO_ANI(ah)) {
867         return;
868     }
869 
870     /*
871      * we need to re-point to the correct ANI state since the channel
872      * may have changed due to a fast channel change
873     */
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;
878 
879     ahp->ah_stats.ast_ani_reset++;
880 
881     ani_state->phy_noise_spur = 0;
882 
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 |
888                                     HAL_ANI_MRC_CCK);
889         } else {
890             ahp->ah_ani_function = 0;
891         }
892     }
893     /* always allow mode (on/off) to be controlled */
894     ahp->ah_ani_function |= HAL_ANI_MODE;
895 
896     if (is_scanning ||
897         (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
898          AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
899     {
900         /*
901          * If we're scanning or in AP mode, the defaults (ini) should be
902          * in place.
903          * For an AP we assume the historical levels for this channel are
904          * probably outdated so start from defaults instead.
905          */
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)
908         {
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);
916             /*
917              * for STA/IBSS, we want to restore the historical values later
918              * (when we're not scanning)
919              */
920             if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
921                 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
922             {
923                 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
924                     HAL_ANI_DEF_SPUR_IMMUNE_LVL);
925                 ar9300_ani_control(
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;
931             } else {
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);
936             }
937         }
938     } else {
939         /*
940          * restore historical levels for this channel
941          */
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;
954     }
955 
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);
960 }
961 
962 /*
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.
966  */
967 void
968 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
969 {
970     struct ath_hal_9300 *ahp = AH9300(ah);
971     u_int32_t phy_cnt1, phy_cnt2;
972 
973 #if 0
974     HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
975 #endif
976 
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);
982     }
983 
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;
987 
988     if (!DO_ANI(ah)) {
989         /*
990          * We must always clear the interrupt cause by resetting
991          * the phy error regs.
992          */
993         OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
994         OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
995         return;
996     }
997 
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);
1001 #if HAL_ANI_DEBUG
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);
1005 #endif
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);
1010     }
1011 }
1012 
1013 
1014 static void
1015 ar9300_ani_lower_immunity(struct ath_hal *ah)
1016 {
1017     struct ath_hal_9300 *ahp = AH9300(ah);
1018     struct ar9300_ani_state *ani_state = ahp->ah_curani;
1019 
1020     if (ani_state->ofdm_noise_immunity_level > 0 &&
1021         (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) {
1022         /*
1023          * lower OFDM noise immunity
1024          */
1025         ar9300_ani_set_odfm_noise_immunity_level(
1026             ah, ani_state->ofdm_noise_immunity_level - 1);
1027 
1028         /*
1029          * only lower either OFDM or CCK errors per turn
1030          * we lower the other one next time
1031          */
1032         return;
1033     }
1034 
1035     if (ani_state->cck_noise_immunity_level > 0) {
1036         /*
1037          * lower CCK noise immunity
1038          */
1039         ar9300_ani_set_cck_noise_immunity_level(
1040             ah, ani_state->cck_noise_immunity_level - 1);
1041     }
1042 }
1043 
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))
1047 
1048 /*
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.
1053  */
1054 static int32_t
1055 ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats)
1056 {
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;
1061 
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);
1065 
1066     ani_state = ahp->ah_curani;
1067     if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) {
1068         /*
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.
1072          */
1073         listen_time = 0;
1074         ahp->ah_stats.ast_ani_lzero++;
1075 #if HAL_ANI_DEBUG
1076         HALDEBUG(ah, HAL_DEBUG_ANI,
1077             "%s: 1st call: ani_state->cycle_count=%d\n",
1078             __func__, ani_state->cycle_count);
1079 #endif
1080     } else {
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);
1085 #if HAL_ANI_DEBUG
1086         HALDEBUG(ah, HAL_DEBUG_ANI,
1087             "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d "
1088             "CLOCK_RATE=%d\n",
1089             __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah));
1090 #endif
1091     }
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;
1095     return listen_time;
1096 }
1097 
1098 /*
1099  * Do periodic processing.  This routine is called from a timer
1100  */
1101 void
1102 ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
1103                 const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
1104 {
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;
1111 
1112     ani_state = ahp->ah_curani;
1113     ahp->ah_stats.ast_nodestats = *stats;        /* XXX optimize? */
1114 
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",
1119             __func__);
1120         return;
1121     }
1122 
1123     /*
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.
1127      */
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);
1132         return;
1133     }
1134 
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);
1143         return;
1144     }
1145     /* XXX beware of overflow? */
1146     ani_state->listen_time += listen_time;
1147 
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);
1153 
1154 
1155 
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;
1160 
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;
1164 
1165 #if HAL_ANI_DEBUG
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);
1170 #endif
1171 
1172     /*
1173      * If ani is not enabled, return after we've collected
1174      * statistics
1175      */
1176     if (!DO_ANI(ah)) {
1177         return;
1178     }
1179 
1180     ofdm_phy_err_rate =
1181         ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
1182     cck_phy_err_rate =
1183         ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;
1184 
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);
1191 
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;
1198             }
1199         } else {
1200             ani_state->phy_noise_spur = 1;
1201         }
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);
1206         }
1207     }
1208 
1209     if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
1210         /*
1211          * Check to see if need to lower immunity if
1212          * 5 ani_periods have passed
1213          */
1214         if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1215             cck_phy_err_rate <= ani_state->cck_trig_low)
1216         {
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;
1226         }
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))
1238         {
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;
1258         }
1259     }
1260 }
1261 
1262 /*
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.
1267  */
1268 HAL_BOOL
1269 ar9300_is_ani_noise_spur(struct ath_hal *ah)
1270 {
1271     struct ath_hal_9300 *ahp = AH9300(ah);
1272     struct ar9300_ani_state *ani_state;
1273 
1274     ani_state = ahp->ah_curani;
1275 
1276     return ani_state->phy_noise_spur;
1277 }
1278 
1279