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