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