xref: /freebsd/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c (revision db70ff37a051dfa19f6f3f0f0c5e3571aba91982)
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     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             if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah))
488                 goto skip_ws_det;
489 
490             /*
491              * make register setting for default (weak sig detect ON)
492              * come from INI file
493              */
494             m1_thresh_low    = is_on ?
495                 ani_state->ini_def.m1_thresh_low    : m1_thresh_low_off;
496             m2_thresh_low    = is_on ?
497                 ani_state->ini_def.m2_thresh_low    : m2_thresh_low_off;
498             m1_thresh       = is_on ?
499                 ani_state->ini_def.m1_thresh       : m1_thresh_off;
500             m2_thresh       = is_on ?
501                 ani_state->ini_def.m2_thresh       : m2_thresh_off;
502             m2_count_thr     = is_on ?
503                 ani_state->ini_def.m2_count_thr     : m2_count_thr_off;
504             m2_count_thr_low  = is_on ?
505                 ani_state->ini_def.m2_count_thr_low  : m2_count_thr_low_off;
506             m1_thresh_low_ext = is_on ?
507                 ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off;
508             m2_thresh_low_ext = is_on ?
509                 ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off;
510             m1_thresh_ext    = is_on ?
511                 ani_state->ini_def.m1_thresh_ext    : m1_thresh_ext_off;
512             m2_thresh_ext    = is_on ?
513                 ani_state->ini_def.m2_thresh_ext    : m2_thresh_ext_off;
514             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
515                 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low);
516             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
517                 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low);
518             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH,
519                 m1_thresh);
520             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
521                 m2_thresh);
522             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
523                 m2_count_thr);
524             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
525                 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low);
526             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
527                 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext);
528             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
529                 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext);
530             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH,
531                 m1_thresh_ext);
532             OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
533                 m2_thresh_ext);
534 skip_ws_det:
535             if (is_on) {
536                 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
537                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
538             } else {
539                 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
540                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
541             }
542             if ((!is_on) != ani_state->ofdm_weak_sig_detect_off) {
543                 HALDEBUG(ah, HAL_DEBUG_ANI,
544                     "%s: ** ch %d: ofdm weak signal: %s=>%s\n",
545                     __func__, chan->ic_freq,
546                     !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
547                     is_on ? "on" : "off");
548                 if (is_on) {
549                     ahp->ah_stats.ast_ani_ofdmon++;
550                 } else {
551                     ahp->ah_stats.ast_ani_ofdmoff++;
552                 }
553                 ani_state->ofdm_weak_sig_detect_off = !is_on;
554             }
555             break;
556         }
557     case HAL_ANI_FIRSTEP_LEVEL:
558         if (level >= ARRAY_LENGTH(firstep_table)) {
559             HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
560                 "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n",
561                 __func__, level, (unsigned) ARRAY_LENGTH(firstep_table));
562             return AH_FALSE;
563         }
564         /*
565          * make register setting relative to default
566          * from INI file & cap value
567          */
568         value =
569             firstep_table[level] -
570             firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
571             ani_state->ini_def.firstep;
572         if (value < HAL_SIG_FIRSTEP_SETTING_MIN) {
573             value = HAL_SIG_FIRSTEP_SETTING_MIN;
574         }
575         if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
576             value = HAL_SIG_FIRSTEP_SETTING_MAX;
577         }
578         OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
579         /*
580          * we need to set first step low register too
581          * make register setting relative to default from INI file & cap value
582          */
583         value2 =
584             firstep_table[level] -
585             firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
586             ani_state->ini_def.firstep_low;
587         if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) {
588             value2 = HAL_SIG_FIRSTEP_SETTING_MIN;
589         }
590         if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
591             value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
592         }
593         OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
594             AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
595 
596         if (level != ani_state->firstep_level) {
597             HALDEBUG(ah, HAL_DEBUG_ANI,
598                 "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
599                 __func__, chan->ic_freq, ani_state->firstep_level, level,
600                 HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep);
601             HALDEBUG(ah, HAL_DEBUG_ANI,
602                 "%s: ** ch %d: level %d=>%d[def:%d] "
603                 "firstep_low[level]=%d ini=%d\n",
604                 __func__, chan->ic_freq, ani_state->firstep_level, level,
605                 HAL_ANI_DEF_FIRSTEP_LVL, value2,
606                 ani_state->ini_def.firstep_low);
607             if (level > ani_state->firstep_level) {
608                 ahp->ah_stats.ast_ani_stepup++;
609             } else if (level < ani_state->firstep_level) {
610                 ahp->ah_stats.ast_ani_stepdown++;
611             }
612             ani_state->firstep_level = level;
613         }
614         break;
615     case HAL_ANI_SPUR_IMMUNITY_LEVEL:
616         if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) {
617             HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
618                 "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level "
619                 "out of range (%u > %u)\n",
620                 __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table));
621             return AH_FALSE;
622         }
623         /*
624          * make register setting relative to default from INI file & cap value
625          */
626         value =
627             cycpwr_thr1_table[level] -
628             cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
629             ani_state->ini_def.cycpwr_thr1;
630         if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) {
631             value = HAL_SIG_SPUR_IMM_SETTING_MIN;
632         }
633         if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
634             value = HAL_SIG_SPUR_IMM_SETTING_MAX;
635         }
636         OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);
637 
638         /*
639          * set AR_PHY_EXT_CCA for extension channel
640          * make register setting relative to default from INI file & cap value
641          */
642         value2 =
643             cycpwr_thr1_table[level] -
644             cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
645             ani_state->ini_def.cycpwr_thr1_ext;
646         if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) {
647             value2 = HAL_SIG_SPUR_IMM_SETTING_MIN;
648         }
649         if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
650             value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
651         }
652         OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);
653 
654         if (level != ani_state->spur_immunity_level) {
655             HALDEBUG(ah, HAL_DEBUG_ANI,
656                 "%s: ** ch %d: level %d=>%d[def:%d] "
657                 "cycpwr_thr1[level]=%d ini=%d\n",
658                 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
659                 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value,
660                 ani_state->ini_def.cycpwr_thr1);
661             HALDEBUG(ah, HAL_DEBUG_ANI,
662                 "%s: ** ch %d: level %d=>%d[def:%d] "
663                 "cycpwr_thr1_ext[level]=%d ini=%d\n",
664                 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
665                 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2,
666                 ani_state->ini_def.cycpwr_thr1_ext);
667             if (level > ani_state->spur_immunity_level) {
668                 ahp->ah_stats.ast_ani_spurup++;
669             } else if (level < ani_state->spur_immunity_level) {
670                 ahp->ah_stats.ast_ani_spurdown++;
671             }
672             ani_state->spur_immunity_level = level;
673         }
674         break;
675     case HAL_ANI_MRC_CCK:
676         /*
677          * is_on == 1 means MRC CCK ON (default, less noise imm)
678          * is_on == 0 means MRC CCK is OFF (more noise imm)
679          */
680         is_on = param ? 1 : 0;
681         if (!AR_SREV_POSEIDON(ah)) {
682             OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
683                 AR_PHY_MRC_CCK_ENABLE, is_on);
684             OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
685                 AR_PHY_MRC_CCK_MUX_REG, is_on);
686         }
687         if ((!is_on) != ani_state->mrc_cck_off) {
688             HALDEBUG(ah, HAL_DEBUG_ANI,
689                 "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq,
690                 !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off");
691             if (is_on) {
692                 ahp->ah_stats.ast_ani_ccklow++;
693             } else {
694                 ahp->ah_stats.ast_ani_cckhigh++;
695             }
696             ani_state->mrc_cck_off = !is_on;
697         }
698         break;
699     case HAL_ANI_PRESENT:
700         break;
701 #ifdef AH_PRIVATE_DIAG
702     case HAL_ANI_MODE:
703         if (param == 0) {
704             ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI;
705             /* Turn off HW counters if we have them */
706             ar9300_ani_detach(ah);
707             if (AH_PRIVATE(ah)->ah_curchan == NULL) {
708                 return AH_TRUE;
709             }
710             /* if we're turning off ANI, reset regs back to INI settings */
711             if (ah->ah_config.ath_hal_enable_ani) {
712                 HAL_ANI_CMD savefunc = ahp->ah_ani_function;
713                 /* temporarly allow all functions so we can reset */
714                 ahp->ah_ani_function = HAL_ANI_ALL;
715                 HALDEBUG(ah, HAL_DEBUG_ANI,
716                     "%s: disable all ANI functions\n", __func__);
717                 ar9300_ani_set_odfm_noise_immunity_level(
718                     ah, HAL_ANI_OFDM_DEF_LEVEL);
719                 ar9300_ani_set_cck_noise_immunity_level(
720                     ah, HAL_ANI_CCK_DEF_LEVEL);
721                 ahp->ah_ani_function = savefunc;
722             }
723         } else {            /* normal/auto mode */
724             HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__);
725             ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
726             if (AH_PRIVATE(ah)->ah_curchan == NULL) {
727                 return AH_TRUE;
728             }
729             ar9300_enable_mib_counters(ah);
730             ar9300_ani_reset(ah, AH_FALSE);
731             ani_state = ahp->ah_curani;
732         }
733         HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
734                  ahp->ah_proc_phy_err);
735         break;
736     case HAL_ANI_PHYERR_RESET:
737         ahp->ah_stats.ast_ani_ofdmerrs = 0;
738         ahp->ah_stats.ast_ani_cckerrs = 0;
739         break;
740 #endif /* AH_PRIVATE_DIAG */
741     default:
742 #if HAL_ANI_DEBUG
743         HALDEBUG(ah, HAL_DEBUG_ANI,
744             "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
745             __func__, cmd, ahp->ah_ani_function);
746 #endif
747         return AH_FALSE;
748     }
749 
750 #if HAL_ANI_DEBUG
751     HALDEBUG(ah, HAL_DEBUG_ANI,
752         "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d "
753         "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n",
754         __func__, ani_state->spur_immunity_level,
755         !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
756         ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off",
757         ani_state->listen_time, ani_state->cycle_count,
758         ani_state->listen_time, ani_state->ofdm_phy_err_count,
759         ani_state->cck_phy_err_count);
760 #endif
761 
762 #ifndef REMOVE_PKT_LOG
763     /* do pktlog */
764     {
765         struct log_ani log_data;
766 
767         /* Populate the ani log record */
768         log_data.phy_stats_disable = DO_ANI(ah);
769         log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level;
770         log_data.spur_immun_lvl = ani_state->spur_immunity_level;
771         log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off;
772         log_data.cck_weak_thr = ani_state->cck_noise_immunity_level;
773         log_data.fir_lvl = ani_state->firstep_level;
774         log_data.listen_time = ani_state->listen_time;
775         log_data.cycle_count = ani_state->cycle_count;
776         /* express ofdm_phy_err_count as errors/second */
777         log_data.ofdm_phy_err_count = ani_state->listen_time ?
778             ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0;
779         /* express cck_phy_err_count as errors/second */
780         log_data.cck_phy_err_count =  ani_state->listen_time ?
781             ani_state->cck_phy_err_count * 1000 / ani_state->listen_time  : 0;
782         log_data.rssi = ani_state->rssi;
783 
784         /* clear interrupt context flag */
785         ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
786     }
787 #endif
788 
789     return AH_TRUE;
790 }
791 
792 static void
793 ar9300_ani_restart(struct ath_hal *ah)
794 {
795     struct ath_hal_9300 *ahp = AH9300(ah);
796     struct ar9300_ani_state *ani_state;
797 
798     if (!DO_ANI(ah)) {
799         return;
800     }
801 
802     ani_state = ahp->ah_curani;
803 
804     ani_state->listen_time = 0;
805 
806     OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
807     OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
808     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
809     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
810 
811     /* Clear the mib counters and save them in the stats */
812     ar9300_update_mib_mac_stats(ah);
813 
814     ani_state->ofdm_phy_err_count = 0;
815     ani_state->cck_phy_err_count = 0;
816 }
817 
818 static void
819 ar9300_ani_ofdm_err_trigger(struct ath_hal *ah)
820 {
821     struct ath_hal_9300 *ahp = AH9300(ah);
822     struct ar9300_ani_state *ani_state;
823 
824     if (!DO_ANI(ah)) {
825         return;
826     }
827 
828     ani_state = ahp->ah_curani;
829 
830     if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) {
831         ar9300_ani_set_odfm_noise_immunity_level(
832             ah, ani_state->ofdm_noise_immunity_level + 1);
833     }
834 }
835 
836 static void
837 ar9300_ani_cck_err_trigger(struct ath_hal *ah)
838 {
839     struct ath_hal_9300 *ahp = AH9300(ah);
840     struct ar9300_ani_state *ani_state;
841 
842     if (!DO_ANI(ah)) {
843         return;
844     }
845 
846     ani_state = ahp->ah_curani;
847 
848     if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) {
849         ar9300_ani_set_cck_noise_immunity_level(
850             ah, ani_state->cck_noise_immunity_level + 1);
851     }
852 }
853 
854 /*
855  * Restore the ANI parameters in the HAL and reset the statistics.
856  * This routine should be called for every hardware reset and for
857  * every channel change.
858  */
859 void
860 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
861 {
862     struct ath_hal_9300 *ahp = AH9300(ah);
863     struct ar9300_ani_state *ani_state;
864     const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
865     HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
866     int index;
867 
868     HALASSERT(chan != AH_NULL);
869 
870     if (!DO_ANI(ah)) {
871         return;
872     }
873 
874     /*
875      * we need to re-point to the correct ANI state since the channel
876      * may have changed due to a fast channel change
877     */
878     index = ar9300_get_ani_channel_index(ah, chan);
879     ani_state = &ahp->ah_ani[index];
880     HALASSERT(ani_state != AH_NULL);
881     ahp->ah_curani = ani_state;
882 
883     ahp->ah_stats.ast_ani_reset++;
884 
885     ani_state->phy_noise_spur = 0;
886 
887     /* only allow a subset of functions in AP mode */
888     if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
889         if (IS_CHAN_2GHZ(ichan)) {
890             ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL |
891                                     HAL_ANI_FIRSTEP_LEVEL |
892                                     HAL_ANI_MRC_CCK);
893         } else {
894             ahp->ah_ani_function = 0;
895         }
896     }
897     /* always allow mode (on/off) to be controlled */
898     ahp->ah_ani_function |= HAL_ANI_MODE;
899 
900     if (is_scanning ||
901         (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
902          AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
903     {
904         /*
905          * If we're scanning or in AP mode, the defaults (ini) should be
906          * in place.
907          * For an AP we assume the historical levels for this channel are
908          * probably outdated so start from defaults instead.
909          */
910         if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL ||
911             ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL)
912         {
913             HALDEBUG(ah, HAL_DEBUG_ANI,
914                 "%s: Restore defaults: opmode %u chan %d Mhz/0x%x "
915                 "is_scanning=%d restore=%d ofdm:%d cck:%d\n",
916                 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
917                 chan->ic_flags, is_scanning, ani_state->must_restore,
918                 ani_state->ofdm_noise_immunity_level,
919                 ani_state->cck_noise_immunity_level);
920             /*
921              * for STA/IBSS, we want to restore the historical values later
922              * (when we're not scanning)
923              */
924             if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
925                 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
926             {
927                 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
928                     HAL_ANI_DEF_SPUR_IMMUNE_LVL);
929                 ar9300_ani_control(
930                     ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL);
931                 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
932                     HAL_ANI_USE_OFDM_WEAK_SIG);
933                 ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK);
934                 ani_state->must_restore = AH_TRUE;
935             } else {
936                 ar9300_ani_set_odfm_noise_immunity_level(
937                     ah, HAL_ANI_OFDM_DEF_LEVEL);
938                 ar9300_ani_set_cck_noise_immunity_level(
939                     ah, HAL_ANI_CCK_DEF_LEVEL);
940             }
941         }
942     } else {
943         /*
944          * restore historical levels for this channel
945          */
946         HALDEBUG(ah, HAL_DEBUG_ANI,
947             "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d "
948             "restore=%d ofdm:%d cck:%d\n",
949             __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
950             chan->ic_flags, is_scanning, ani_state->must_restore,
951             ani_state->ofdm_noise_immunity_level,
952             ani_state->cck_noise_immunity_level);
953         ar9300_ani_set_odfm_noise_immunity_level(
954             ah, ani_state->ofdm_noise_immunity_level);
955         ar9300_ani_set_cck_noise_immunity_level(
956             ah, ani_state->cck_noise_immunity_level);
957         ani_state->must_restore = AH_FALSE;
958     }
959 
960     /* enable phy counters */
961     ar9300_ani_restart(ah);
962     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
963     OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
964 }
965 
966 /*
967  * Process a MIB interrupt.  We may potentially be invoked because
968  * any of the MIB counters overflow/trigger so don't assume we're
969  * here because a PHY error counter triggered.
970  */
971 void
972 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
973 {
974     struct ath_hal_9300 *ahp = AH9300(ah);
975     u_int32_t phy_cnt1, phy_cnt2;
976 
977 #if 0
978     HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
979 #endif
980 
981     /* Reset these counters regardless */
982     OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
983     OS_REG_WRITE(ah, AR_FILT_CCK, 0);
984     if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) {
985         OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
986     }
987 
988     /* Clear the mib counters and save them in the stats */
989     ar9300_update_mib_mac_stats(ah);
990     ahp->ah_stats.ast_nodestats = *stats;
991 
992     if (!DO_ANI(ah)) {
993         /*
994          * We must always clear the interrupt cause by resetting
995          * the phy error regs.
996          */
997         OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
998         OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
999         return;
1000     }
1001 
1002     /* NB: these are not reset-on-read */
1003     phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
1004     phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
1005 #if HAL_ANI_DEBUG
1006     HALDEBUG(ah, HAL_DEBUG_ANI,
1007         "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
1008         __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2);
1009 #endif
1010     if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
1011         ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
1012         /* NB: always restart to insure the h/w counters are reset */
1013         ar9300_ani_restart(ah);
1014     }
1015 }
1016 
1017 
1018 static void
1019 ar9300_ani_lower_immunity(struct ath_hal *ah)
1020 {
1021     struct ath_hal_9300 *ahp = AH9300(ah);
1022     struct ar9300_ani_state *ani_state = ahp->ah_curani;
1023 
1024     if (ani_state->ofdm_noise_immunity_level > 0 &&
1025         (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) {
1026         /*
1027          * lower OFDM noise immunity
1028          */
1029         ar9300_ani_set_odfm_noise_immunity_level(
1030             ah, ani_state->ofdm_noise_immunity_level - 1);
1031 
1032         /*
1033          * only lower either OFDM or CCK errors per turn
1034          * we lower the other one next time
1035          */
1036         return;
1037     }
1038 
1039     if (ani_state->cck_noise_immunity_level > 0) {
1040         /*
1041          * lower CCK noise immunity
1042          */
1043         ar9300_ani_set_cck_noise_immunity_level(
1044             ah, ani_state->cck_noise_immunity_level - 1);
1045     }
1046 }
1047 
1048 /* convert HW counter values to ms using mode specifix clock rate */
1049 //#define CLOCK_RATE(_ah)  (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000)
1050 #define CLOCK_RATE(_ah)  (ath_hal_mac_clks(ah, 1000))
1051 
1052 /*
1053  * Return an approximation of the time spent ``listening'' by
1054  * deducting the cycles spent tx'ing and rx'ing from the total
1055  * cycle count since our last call.  A return value <0 indicates
1056  * an invalid/inconsistent time.
1057  */
1058 static int32_t
1059 ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats)
1060 {
1061     struct ath_hal_9300 *ahp = AH9300(ah);
1062     struct ar9300_ani_state *ani_state;
1063     u_int32_t tx_frame_count, rx_frame_count, cycle_count;
1064     u_int32_t rx_busy_count, rx_ext_busy_count;
1065     int32_t listen_time;
1066 
1067     tx_frame_count = OS_REG_READ(ah, AR_TFCNT);
1068     rx_frame_count = OS_REG_READ(ah, AR_RFCNT);
1069     rx_busy_count = OS_REG_READ(ah, AR_RCCNT);
1070     rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT);
1071     cycle_count = OS_REG_READ(ah, AR_CCCNT);
1072 
1073     ani_state = ahp->ah_curani;
1074     if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) {
1075         /*
1076          * Cycle counter wrap (or initial call); it's not possible
1077          * to accurately calculate a value because the registers
1078          * right shift rather than wrap--so punt and return 0.
1079          */
1080         listen_time = 0;
1081         ahp->ah_stats.ast_ani_lzero++;
1082 #if HAL_ANI_DEBUG
1083         HALDEBUG(ah, HAL_DEBUG_ANI,
1084             "%s: 1st call: ani_state->cycle_count=%d\n",
1085             __func__, ani_state->cycle_count);
1086 #endif
1087     } else {
1088         int32_t ccdelta = cycle_count - ani_state->cycle_count;
1089         int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count;
1090         int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count;
1091         int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count;
1092         int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count;
1093         listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah);
1094 //#if HAL_ANI_DEBUG
1095         HALDEBUG(ah, HAL_DEBUG_ANI,
1096             "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d "
1097             "CLOCK_RATE=%d\n",
1098             __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta,
1099             listen_time, CLOCK_RATE(ah));
1100 //#endif
1101             /* Populate as appropriate */
1102             ani_stats->cyclecnt_diff = ccdelta;
1103             ani_stats->rxclr_cnt = rcdelta;
1104             ani_stats->txframecnt_diff = tfdelta;
1105             ani_stats->rxframecnt_diff = rfdelta;
1106             ani_stats->extrxclr_cnt = extrcdelta;
1107             ani_stats->listen_time = listen_time;
1108             ani_stats->valid = AH_TRUE;
1109     }
1110     ani_state->cycle_count = cycle_count;
1111     ani_state->tx_frame_count = tx_frame_count;
1112     ani_state->rx_frame_count = rx_frame_count;
1113     ani_state->rx_busy_count = rx_busy_count;
1114     ani_state->rx_ext_busy_count = rx_ext_busy_count;
1115     return listen_time;
1116 }
1117 
1118 /*
1119  * Do periodic processing.  This routine is called from a timer
1120  */
1121 void
1122 ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
1123                 const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
1124 {
1125     struct ath_hal_9300 *ahp = AH9300(ah);
1126     struct ar9300_ani_state *ani_state;
1127     int32_t listen_time;
1128     u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
1129     u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
1130     HAL_BOOL old_phy_noise_spur;
1131 
1132     ani_state = ahp->ah_curani;
1133     ahp->ah_stats.ast_nodestats = *stats;        /* XXX optimize? */
1134 
1135     if (ani_state == NULL) {
1136         /* should not happen */
1137         HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1138             "%s: can't poll - no ANI not initialized for this channel\n",
1139             __func__);
1140         return;
1141     }
1142 
1143     /*
1144      * ar9300_ani_ar_poll is never called while scanning but we may have been
1145      * scanning and now just restarted polling.  In this case we need to
1146      * restore historical values.
1147      */
1148     if (ani_state->must_restore) {
1149         HALDEBUG(ah, HAL_DEBUG_ANI,
1150             "%s: must restore - calling ar9300_ani_restart\n", __func__);
1151         ar9300_ani_reset(ah, AH_FALSE);
1152         return;
1153     }
1154 
1155     listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
1156     if (listen_time <= 0) {
1157         ahp->ah_stats.ast_ani_lneg++;
1158         /* restart ANI period if listen_time is invalid */
1159         HALDEBUG(ah, HAL_DEBUG_ANI,
1160             "%s: listen_time=%d - calling ar9300_ani_restart\n",
1161             __func__, listen_time);
1162         ar9300_ani_restart(ah);
1163         return;
1164     }
1165     /* XXX beware of overflow? */
1166     ani_state->listen_time += listen_time;
1167 
1168     /* Clear the mib counters and save them in the stats */
1169     ar9300_update_mib_mac_stats(ah);
1170     /* NB: these are not reset-on-read */
1171     ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
1172     cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);
1173 
1174     /* Populate HAL_ANISTATS */
1175     if (ani_stats) {
1176             ani_stats->cckphyerr_cnt =
1177                cck_phy_err_cnt - ani_state->cck_phy_err_count;
1178             ani_stats->ofdmphyerrcnt_diff =
1179               ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1180     }
1181 
1182     /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
1183     ahp->ah_stats.ast_ani_ofdmerrs +=
1184         ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1185     ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;
1186 
1187     ahp->ah_stats.ast_ani_cckerrs +=
1188         cck_phy_err_cnt - ani_state->cck_phy_err_count;
1189     ani_state->cck_phy_err_count = cck_phy_err_cnt;
1190 
1191     /*
1192      * Note - the ANI code is using the aggregate listen time.
1193      * The AR_PHY_CNT1/AR_PHY_CNT2 registers here are also
1194      * free running, not clear-on-read and are free-running.
1195      *
1196      * So, ofdm_phy_err_rate / cck_phy_err_rate are accumulating
1197      * the same as listenTime is accumulating.
1198      */
1199 
1200 #if HAL_ANI_DEBUG
1201     HALDEBUG(ah, HAL_DEBUG_ANI,
1202         "%s: Errors: OFDM=0x%08x-0x0=%d   CCK=0x%08x-0x0=%d\n",
1203         __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
1204         cck_phy_err_cnt, cck_phy_err_cnt);
1205 #endif
1206 
1207     /*
1208      * If ani is not enabled, return after we've collected
1209      * statistics
1210      */
1211     if (!DO_ANI(ah)) {
1212         return;
1213     }
1214 
1215     ofdm_phy_err_rate =
1216         ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
1217     cck_phy_err_rate =
1218         ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;
1219 
1220     HALDEBUG(ah, HAL_DEBUG_ANI,
1221         "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
1222         __func__, listen_time,
1223         ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1224         ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1225         ani_state->ofdms_turn);
1226 
1227     if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
1228         old_phy_noise_spur = ani_state->phy_noise_spur;
1229         if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1230             cck_phy_err_rate <= ani_state->cck_trig_low) {
1231             if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
1232                 ani_state->phy_noise_spur = 0;
1233             }
1234         } else {
1235             ani_state->phy_noise_spur = 1;
1236         }
1237         if (old_phy_noise_spur != ani_state->phy_noise_spur) {
1238             HALDEBUG(ah, HAL_DEBUG_ANI,
1239                      "%s: enviroment change from %d to %d\n",
1240                      __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
1241         }
1242     }
1243 
1244     if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
1245         /*
1246          * Check to see if need to lower immunity if
1247          * 5 ani_periods have passed
1248          */
1249         if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1250             cck_phy_err_rate <= ani_state->cck_trig_low)
1251         {
1252             HALDEBUG(ah, HAL_DEBUG_ANI,
1253                 "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d)  "
1254                 "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
1255                 __func__, ani_state->listen_time,
1256                 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1257                 ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
1258                 cck_phy_err_rate, ani_state->cck_trig_low);
1259             ar9300_ani_lower_immunity(ah);
1260             ani_state->ofdms_turn = !ani_state->ofdms_turn;
1261         }
1262         HALDEBUG(ah, HAL_DEBUG_ANI,
1263             "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
1264             "calling ar9300_ani_restart\n",
1265             __func__, ani_state->listen_time,
1266             ofdm_phy_err_rate, cck_phy_err_rate);
1267         ar9300_ani_restart(ah);
1268      } else if (ani_state->listen_time > ahp->ah_ani_period) {
1269         /* check to see if need to raise immunity */
1270         if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
1271             (cck_phy_err_rate <= ani_state->cck_trig_high ||
1272              ani_state->ofdms_turn))
1273         {
1274             HALDEBUG(ah, HAL_DEBUG_ANI,
1275                 "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
1276                 "ar9300_ani_ofdm_err_trigger\n",
1277                 __func__, ani_state->listen_time,
1278                 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1279                 ani_state->ofdm_trig_high);
1280             ar9300_ani_ofdm_err_trigger(ah);
1281             ar9300_ani_restart(ah);
1282             ani_state->ofdms_turn = AH_FALSE;
1283         } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
1284             HALDEBUG(ah, HAL_DEBUG_ANI,
1285                 "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
1286                 "ar9300_ani_cck_err_trigger\n",
1287                 __func__, ani_state->listen_time,
1288                 ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1289                 ani_state->cck_trig_high);
1290             ar9300_ani_cck_err_trigger(ah);
1291             ar9300_ani_restart(ah);
1292             ani_state->ofdms_turn = AH_TRUE;
1293         }
1294     }
1295 }
1296 
1297 /*
1298  * The poll function above calculates short noise spurs, caused by non-80211
1299  * devices, based on OFDM/CCK Phy errs.
1300  * If the noise is short enough, we don't want our ratectrl Algo to stop probing
1301  * higher rates, due to bad PER.
1302  */
1303 HAL_BOOL
1304 ar9300_is_ani_noise_spur(struct ath_hal *ah)
1305 {
1306     struct ath_hal_9300 *ahp = AH9300(ah);
1307     struct ar9300_ani_state *ani_state;
1308 
1309     ani_state = ahp->ah_curani;
1310 
1311     return ani_state->phy_noise_spur;
1312 }
1313 
1314