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