netmap: d_poll -> d_kqfilter
[dragonfly.git] / sys / dev / netif / ath / hal / ath_hal / ar5212 / ar5212_ani.c
1 /*
2  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * $FreeBSD: head/sys/dev/ath/ath_hal/ar5212/ar5212_ani.c 188444 2009-02-10 19:23:25Z sam $
18  */
19 #include "opt_ah.h"
20
21 #include "ah.h"
22 #include "ah_internal.h"
23 #include "ah_desc.h"
24
25 #include "ar5212/ar5212.h"
26 #include "ar5212/ar5212reg.h"
27 #include "ar5212/ar5212phy.h"
28
29 /*
30  * Anti noise immunity support.  We track phy errors and react
31  * to excessive errors by adjusting the noise immunity parameters.
32  */
33
34 #define HAL_EP_RND(x, mul) \
35         ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
36 #define BEACON_RSSI(ahp) \
37         HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
38                 HAL_RSSI_EP_MULTIPLIER)
39
40 /*
41  * ANI processing tunes radio parameters according to PHY errors
42  * and related information.  This is done for for noise and spur
43  * immunity in all operating modes if the device indicates it's
44  * capable at attach time.  In addition, when there is a reference
45  * rssi value (e.g. beacon frames from an ap in station mode)
46  * further tuning is done.
47  *
48  * ANI_ENA indicates whether any ANI processing should be done;
49  * this is specified at attach time.
50  *
51  * ANI_ENA_RSSI indicates whether rssi-based processing should
52  * done, this is enabled based on operating mode and is meaningful
53  * only if ANI_ENA is true.
54  *
55  * ANI parameters are typically controlled only by the hal.  The
56  * AniControl interface however permits manual tuning through the
57  * diagnostic api.
58  */
59 #define ANI_ENA(ah) \
60         (AH5212(ah)->ah_procPhyErr & HAL_ANI_ENA)
61 #define ANI_ENA_RSSI(ah) \
62         (AH5212(ah)->ah_procPhyErr & HAL_RSSI_ANI_ENA)
63
64 #define ah_mibStats     ah_stats.ast_mibstats
65
66 static void
67 enableAniMIBCounters(struct ath_hal *ah, const struct ar5212AniParams *params)
68 {
69         struct ath_hal_5212 *ahp = AH5212(ah);
70
71         HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Enable mib counters: "
72             "OfdmPhyErrBase 0x%x cckPhyErrBase 0x%x\n",
73             __func__, params->ofdmPhyErrBase, params->cckPhyErrBase);
74
75         OS_REG_WRITE(ah, AR_FILTOFDM, 0);
76         OS_REG_WRITE(ah, AR_FILTCCK, 0);
77
78         OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
79         OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
80         OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
81         OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);
82
83         ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save+clear counters*/
84         ar5212EnableMibCounters(ah);                    /* enable everything */
85 }
86
87 static void 
88 disableAniMIBCounters(struct ath_hal *ah)
89 {
90         struct ath_hal_5212 *ahp = AH5212(ah);
91
92         HALDEBUG(ah, HAL_DEBUG_ANI, "Disable MIB counters\n");
93
94         ar5212UpdateMibCounters(ah, &ahp->ah_mibStats); /* save stats */
95         ar5212DisableMibCounters(ah);                   /* disable everything */
96
97         OS_REG_WRITE(ah, AR_PHYCNTMASK1, 0);
98         OS_REG_WRITE(ah, AR_PHYCNTMASK2, 0);
99 }
100
101 /*
102  * Return the current ANI state of the channel we're on
103  */
104 struct ar5212AniState *
105 ar5212AniGetCurrentState(struct ath_hal *ah)
106 {
107         return AH5212(ah)->ah_curani;
108 }
109
110 /*
111  * Return the current statistics.
112  */
113 struct ar5212Stats *
114 ar5212AniGetCurrentStats(struct ath_hal *ah)
115 {
116         struct ath_hal_5212 *ahp = AH5212(ah);
117
118         /* update mib stats so we return current data */
119         /* XXX? side-effects to doing this here? */
120         ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
121         return &ahp->ah_stats;
122 }
123
124 static void
125 setPhyErrBase(struct ath_hal *ah, struct ar5212AniParams *params)
126 {
127         if (params->ofdmTrigHigh >= AR_PHY_COUNTMAX) {
128                 HALDEBUG(ah, HAL_DEBUG_ANY,
129                     "OFDM Trigger %d is too high for hw counters, using max\n",
130                     params->ofdmTrigHigh);
131                 params->ofdmPhyErrBase = 0;
132         } else
133                 params->ofdmPhyErrBase = AR_PHY_COUNTMAX - params->ofdmTrigHigh;
134         if (params->cckTrigHigh >= AR_PHY_COUNTMAX) {
135                 HALDEBUG(ah, HAL_DEBUG_ANY,
136                     "CCK Trigger %d is too high for hw counters, using max\n",
137                     params->cckTrigHigh);
138                 params->cckPhyErrBase = 0;
139         } else
140                 params->cckPhyErrBase = AR_PHY_COUNTMAX - params->cckTrigHigh;
141 }
142
143 /*
144  * Setup ANI handling.  Sets all thresholds and reset the
145  * channel statistics.  Note that ar5212AniReset should be
146  * called by ar5212Reset before anything else happens and
147  * that's where we force initial settings.
148  */
149 void
150 ar5212AniAttach(struct ath_hal *ah, const struct ar5212AniParams *params24,
151         const struct ar5212AniParams *params5, HAL_BOOL enable)
152 {
153         struct ath_hal_5212 *ahp = AH5212(ah);
154
155         ahp->ah_hasHwPhyCounters =
156                 AH_PRIVATE(ah)->ah_caps.halHwPhyCounterSupport;
157
158         if (params24 != AH_NULL) {
159                 OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
160                 setPhyErrBase(ah, &ahp->ah_aniParams24);
161         }
162         if (params5 != AH_NULL) {
163                 OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
164                 setPhyErrBase(ah, &ahp->ah_aniParams5);
165         }
166
167         OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
168         if (ahp->ah_hasHwPhyCounters) {
169                 /* Enable MIB Counters */
170                 enableAniMIBCounters(ah, &ahp->ah_aniParams24 /*XXX*/);
171         }
172         if (enable) {           /* Enable ani now */
173                 HALASSERT(params24 != AH_NULL && params5 != AH_NULL);
174                 ahp->ah_procPhyErr |= HAL_ANI_ENA;
175         } else {
176                 ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
177         }
178 }
179
180 HAL_BOOL
181 ar5212AniSetParams(struct ath_hal *ah, const struct ar5212AniParams *params24,
182         const struct ar5212AniParams *params5)
183 {
184         struct ath_hal_5212 *ahp = AH5212(ah);
185         HAL_BOOL ena = (ahp->ah_procPhyErr & HAL_ANI_ENA) != 0;
186
187         ar5212AniControl(ah, HAL_ANI_MODE, AH_FALSE);
188
189         OS_MEMCPY(&ahp->ah_aniParams24, params24, sizeof(*params24));
190         setPhyErrBase(ah, &ahp->ah_aniParams24);
191         OS_MEMCPY(&ahp->ah_aniParams5, params5, sizeof(*params5));
192         setPhyErrBase(ah, &ahp->ah_aniParams5);
193
194         OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
195         ar5212AniReset(ah, AH_PRIVATE(ah)->ah_curchan,
196             AH_PRIVATE(ah)->ah_opmode, AH_FALSE);
197
198         ar5212AniControl(ah, HAL_ANI_MODE, ena);
199
200         return AH_TRUE;
201 }
202
203 /*
204  * Cleanup any ANI state setup.
205  */
206 void
207 ar5212AniDetach(struct ath_hal *ah)
208 {
209         struct ath_hal_5212 *ahp = AH5212(ah);
210
211         HALDEBUG(ah, HAL_DEBUG_ANI, "Detaching Ani\n");
212         if (ahp->ah_hasHwPhyCounters)
213                 disableAniMIBCounters(ah);
214 }
215
216 /*
217  * Control Adaptive Noise Immunity Parameters
218  */
219 HAL_BOOL
220 ar5212AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
221 {
222         typedef int TABLE[];
223         struct ath_hal_5212 *ahp = AH5212(ah);
224         struct ar5212AniState *aniState = ahp->ah_curani;
225         const struct ar5212AniParams *params = aniState->params;
226
227         OS_MARK(ah, AH_MARK_ANI_CONTROL, cmd);
228
229         switch (cmd) {
230         case HAL_ANI_NOISE_IMMUNITY_LEVEL: {
231                 u_int level = param;
232
233                 if (level > params->maxNoiseImmunityLevel) {
234                         HALDEBUG(ah, HAL_DEBUG_ANY,
235                             "%s: level out of range (%u > %u)\n",
236                             __func__, level, params->maxNoiseImmunityLevel);
237                         return AH_FALSE;
238                 }
239
240                 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
241                     AR_PHY_DESIRED_SZ_TOT_DES, params->totalSizeDesired[level]);
242                 OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
243                     AR_PHY_AGC_CTL1_COARSE_LOW, params->coarseLow[level]);
244                 OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
245                     AR_PHY_AGC_CTL1_COARSE_HIGH, params->coarseHigh[level]);
246                 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
247                     AR_PHY_FIND_SIG_FIRPWR, params->firpwr[level]);
248
249                 if (level > aniState->noiseImmunityLevel)
250                         ahp->ah_stats.ast_ani_niup++;
251                 else if (level < aniState->noiseImmunityLevel)
252                         ahp->ah_stats.ast_ani_nidown++;
253                 aniState->noiseImmunityLevel = level;
254                 break;
255         }
256         case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
257                 static const TABLE m1ThreshLow   = { 127,   50 };
258                 static const TABLE m2ThreshLow   = { 127,   40 };
259                 static const TABLE m1Thresh      = { 127, 0x4d };
260                 static const TABLE m2Thresh      = { 127, 0x40 };
261                 static const TABLE m2CountThr    = {  31,   16 };
262                 static const TABLE m2CountThrLow = {  63,   48 };
263                 u_int on = param ? 1 : 0;
264
265                 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
266                         AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1ThreshLow[on]);
267                 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
268                         AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2ThreshLow[on]);
269                 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
270                         AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
271                 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
272                         AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
273                 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR,
274                         AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
275                 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
276                         AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2CountThrLow[on]);
277
278                 if (on) {
279                         OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
280                                 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
281                         ahp->ah_stats.ast_ani_ofdmon++;
282                 } else {
283                         OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
284                                 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
285                         ahp->ah_stats.ast_ani_ofdmoff++;
286                 }
287                 aniState->ofdmWeakSigDetectOff = !on;
288                 break;
289         }
290         case HAL_ANI_CCK_WEAK_SIGNAL_THR: {
291                 static const TABLE weakSigThrCck = { 8, 6 };
292                 u_int high = param ? 1 : 0;
293
294                 OS_REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
295                     AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, weakSigThrCck[high]);
296                 if (high)
297                         ahp->ah_stats.ast_ani_cckhigh++;
298                 else
299                         ahp->ah_stats.ast_ani_ccklow++;
300                 aniState->cckWeakSigThreshold = high;
301                 break;
302         }
303         case HAL_ANI_FIRSTEP_LEVEL: {
304                 u_int level = param;
305
306                 if (level > params->maxFirstepLevel) {
307                         HALDEBUG(ah, HAL_DEBUG_ANY,
308                             "%s: level out of range (%u > %u)\n",
309                             __func__, level, params->maxFirstepLevel);
310                         return AH_FALSE;
311                 }
312                 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
313                     AR_PHY_FIND_SIG_FIRSTEP, params->firstep[level]);
314                 if (level > aniState->firstepLevel)
315                         ahp->ah_stats.ast_ani_stepup++;
316                 else if (level < aniState->firstepLevel)
317                         ahp->ah_stats.ast_ani_stepdown++;
318                 aniState->firstepLevel = level;
319                 break;
320         }
321         case HAL_ANI_SPUR_IMMUNITY_LEVEL: {
322                 u_int level = param;
323
324                 if (level > params->maxSpurImmunityLevel) {
325                         HALDEBUG(ah, HAL_DEBUG_ANY,
326                             "%s: level out of range (%u > %u)\n",
327                             __func__, level, params->maxSpurImmunityLevel);
328                         return AH_FALSE;
329                 }
330                 OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5,
331                     AR_PHY_TIMING5_CYCPWR_THR1, params->cycPwrThr1[level]);
332                 if (level > aniState->spurImmunityLevel)
333                         ahp->ah_stats.ast_ani_spurup++;
334                 else if (level < aniState->spurImmunityLevel)
335                         ahp->ah_stats.ast_ani_spurdown++;
336                 aniState->spurImmunityLevel = level;
337                 break;
338         }
339         case HAL_ANI_PRESENT:
340                 break;
341         case HAL_ANI_MODE:
342                 if (param == 0) {
343                         ahp->ah_procPhyErr &= ~HAL_ANI_ENA;
344                         /* Turn off HW counters if we have them */
345                         ar5212AniDetach(ah);
346                         ar5212SetRxFilter(ah,
347                                 ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
348                 } else {                        /* normal/auto mode */
349                         /* don't mess with state if already enabled */
350                         if (ahp->ah_procPhyErr & HAL_ANI_ENA)
351                                 break;
352                         if (ahp->ah_hasHwPhyCounters) {
353                                 ar5212SetRxFilter(ah,
354                                         ar5212GetRxFilter(ah) &~ HAL_RX_FILTER_PHYERR);
355                                 /* Enable MIB Counters */
356                                 enableAniMIBCounters(ah,
357                                     ahp->ah_curani != AH_NULL ?
358                                         ahp->ah_curani->params:
359                                         &ahp->ah_aniParams24 /*XXX*/);
360                         } else {
361                                 ar5212SetRxFilter(ah,
362                                         ar5212GetRxFilter(ah) | HAL_RX_FILTER_PHYERR);
363                         }
364                         ahp->ah_procPhyErr |= HAL_ANI_ENA;
365                 }
366                 break;
367 #ifdef AH_PRIVATE_DIAG
368         case HAL_ANI_PHYERR_RESET:
369                 ahp->ah_stats.ast_ani_ofdmerrs = 0;
370                 ahp->ah_stats.ast_ani_cckerrs = 0;
371                 break;
372 #endif /* AH_PRIVATE_DIAG */
373         default:
374                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid cmd %u\n",
375                     __func__, cmd);
376                 return AH_FALSE;
377         }
378         return AH_TRUE;
379 }
380
381 static void
382 ar5212AniOfdmErrTrigger(struct ath_hal *ah)
383 {
384         struct ath_hal_5212 *ahp = AH5212(ah);
385         const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
386         struct ar5212AniState *aniState;
387         const struct ar5212AniParams *params;
388
389         HALASSERT(chan != AH_NULL);
390
391         if (!ANI_ENA(ah))
392                 return;
393
394         aniState = ahp->ah_curani;
395         params = aniState->params;
396         /* First, raise noise immunity level, up to max */
397         if (aniState->noiseImmunityLevel+1 <= params->maxNoiseImmunityLevel) {
398                 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__,
399                     aniState->noiseImmunityLevel + 1);
400                 ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 
401                                  aniState->noiseImmunityLevel + 1);
402                 return;
403         }
404         /* then, raise spur immunity level, up to max */
405         if (aniState->spurImmunityLevel+1 <= params->maxSpurImmunityLevel) {
406                 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise SI to %u\n", __func__,
407                     aniState->spurImmunityLevel + 1);
408                 ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
409                                  aniState->spurImmunityLevel + 1);
410                 return;
411         }
412
413         if (ANI_ENA_RSSI(ah)) {
414                 int32_t rssi = BEACON_RSSI(ahp);
415                 if (rssi > params->rssiThrHigh) {
416                         /*
417                          * Beacon rssi is high, can turn off ofdm
418                          * weak sig detect.
419                          */
420                         if (!aniState->ofdmWeakSigDetectOff) {
421                                 HALDEBUG(ah, HAL_DEBUG_ANI,
422                                     "%s: rssi %d OWSD off\n", __func__, rssi);
423                                 ar5212AniControl(ah,
424                                     HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
425                                     AH_FALSE);
426                                 ar5212AniControl(ah,
427                                     HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
428                                 return;
429                         }
430                         /* 
431                          * If weak sig detect is already off, as last resort,
432                          * raise firstep level 
433                          */
434                         if (aniState->firstepLevel+1 <= params->maxFirstepLevel) {
435                                 HALDEBUG(ah, HAL_DEBUG_ANI,
436                                     "%s: rssi %d raise ST %u\n", __func__, rssi,
437                                     aniState->firstepLevel+1);
438                                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
439                                                  aniState->firstepLevel + 1);
440                                 return;
441                         }
442                 } else if (rssi > params->rssiThrLow) {
443                         /* 
444                          * Beacon rssi in mid range, need ofdm weak signal
445                          * detect, but we can raise firststepLevel.
446                          */
447                         if (aniState->ofdmWeakSigDetectOff) {
448                                 HALDEBUG(ah, HAL_DEBUG_ANI,
449                                     "%s: rssi %d OWSD on\n", __func__, rssi);
450                                 ar5212AniControl(ah,
451                                     HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
452                                     AH_TRUE);
453                         }
454                         if (aniState->firstepLevel+1 <= params->maxFirstepLevel) {
455                                 HALDEBUG(ah, HAL_DEBUG_ANI,
456                                     "%s: rssi %d raise ST %u\n", __func__, rssi,
457                                     aniState->firstepLevel+1);
458                                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
459                                      aniState->firstepLevel + 1);
460                         }
461                         return;
462                 } else {
463                         /* 
464                          * Beacon rssi is low, if in 11b/g mode, turn off ofdm
465                          * weak signal detection and zero firstepLevel to
466                          * maximize CCK sensitivity 
467                          */
468                         if (IEEE80211_IS_CHAN_CCK(chan)) {
469                                 if (!aniState->ofdmWeakSigDetectOff) {
470                                         HALDEBUG(ah, HAL_DEBUG_ANI,
471                                             "%s: rssi %d OWSD off\n",
472                                             __func__, rssi);
473                                         ar5212AniControl(ah,
474                                             HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
475                                             AH_FALSE);
476                                 }
477                                 if (aniState->firstepLevel > 0) {
478                                         HALDEBUG(ah, HAL_DEBUG_ANI,
479                                             "%s: rssi %d zero ST (was %u)\n",
480                                             __func__, rssi,
481                                             aniState->firstepLevel);
482                                         ar5212AniControl(ah,
483                                              HAL_ANI_FIRSTEP_LEVEL, 0);
484                                 }
485                                 return;
486                         }
487                 }
488         }
489 }
490
491 static void
492 ar5212AniCckErrTrigger(struct ath_hal *ah)
493 {
494         struct ath_hal_5212 *ahp = AH5212(ah);
495         const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
496         struct ar5212AniState *aniState;
497         const struct ar5212AniParams *params;
498
499         HALASSERT(chan != AH_NULL);
500
501         if (!ANI_ENA(ah))
502                 return;
503
504         /* first, raise noise immunity level, up to max */
505         aniState = ahp->ah_curani;
506         params = aniState->params;
507         if (aniState->noiseImmunityLevel+1 <= params->maxNoiseImmunityLevel) {
508                 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: raise NI to %u\n", __func__,
509                     aniState->noiseImmunityLevel + 1);
510                 ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
511                                  aniState->noiseImmunityLevel + 1);
512                 return;
513         }
514
515         if (ANI_ENA_RSSI(ah)) {
516                 int32_t rssi = BEACON_RSSI(ahp);
517                 if (rssi >  params->rssiThrLow) {
518                         /*
519                          * Beacon signal in mid and high range,
520                          * raise firstep level.
521                          */
522                         if (aniState->firstepLevel+1 <= params->maxFirstepLevel) {
523                                 HALDEBUG(ah, HAL_DEBUG_ANI,
524                                     "%s: rssi %d raise ST %u\n", __func__, rssi,
525                                     aniState->firstepLevel+1);
526                                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
527                                                  aniState->firstepLevel + 1);
528                         }
529                 } else {
530                         /*
531                          * Beacon rssi is low, zero firstep level to maximize
532                          * CCK sensitivity in 11b/g mode.
533                          */
534                         /* XXX can optimize */
535                         if (IEEE80211_IS_CHAN_B(chan) ||
536                             IEEE80211_IS_CHAN_G(chan)) {
537                                 if (aniState->firstepLevel > 0) {
538                                         HALDEBUG(ah, HAL_DEBUG_ANI,
539                                             "%s: rssi %d zero ST (was %u)\n",
540                                             __func__, rssi,
541                                             aniState->firstepLevel);
542                                         ar5212AniControl(ah,
543                                             HAL_ANI_FIRSTEP_LEVEL, 0);
544                                 }
545                         }
546                 }
547         }
548 }
549
550 static void
551 ar5212AniRestart(struct ath_hal *ah, struct ar5212AniState *aniState)
552 {
553         struct ath_hal_5212 *ahp = AH5212(ah);
554
555         aniState->listenTime = 0;
556         if (ahp->ah_hasHwPhyCounters) {
557                 const struct ar5212AniParams *params = aniState->params;
558                 /*
559                  * NB: these are written on reset based on the
560                  *     ini so we must re-write them!
561                  */
562                 OS_REG_WRITE(ah, AR_PHYCNT1, params->ofdmPhyErrBase);
563                 OS_REG_WRITE(ah, AR_PHYCNT2, params->cckPhyErrBase);
564                 OS_REG_WRITE(ah, AR_PHYCNTMASK1, AR_PHY_ERR_OFDM_TIMING);
565                 OS_REG_WRITE(ah, AR_PHYCNTMASK2, AR_PHY_ERR_CCK_TIMING);
566
567                 /* Clear the mib counters and save them in the stats */
568                 ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
569         }
570         aniState->ofdmPhyErrCount = 0;
571         aniState->cckPhyErrCount = 0;
572 }
573
574 /*
575  * Restore/reset the ANI parameters and reset the statistics.
576  * This routine must be called for every channel change.
577  */
578 void
579 ar5212AniReset(struct ath_hal *ah, const struct ieee80211_channel *chan,
580         HAL_OPMODE opmode, int restore)
581 {
582         struct ath_hal_5212 *ahp = AH5212(ah);
583         HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
584         /* XXX bounds check ic_devdata */
585         struct ar5212AniState *aniState = &ahp->ah_ani[chan->ic_devdata];
586         uint32_t rxfilter;
587
588         if ((ichan->privFlags & CHANNEL_ANI_INIT) == 0) {
589                 OS_MEMZERO(aniState, sizeof(*aniState));
590                 if (IEEE80211_IS_CHAN_2GHZ(chan))
591                         aniState->params = &ahp->ah_aniParams24;
592                 else
593                         aniState->params = &ahp->ah_aniParams5;
594                 ichan->privFlags |= CHANNEL_ANI_INIT;
595                 HALASSERT((ichan->privFlags & CHANNEL_ANI_SETUP) == 0);
596         }
597         ahp->ah_curani = aniState;
598 #if 0
599         ath_hal_printf(ah,"%s: chan %u/0x%x restore %d opmode %u%s\n",
600             __func__, chan->ic_freq, chan->ic_flags, restore, opmode,
601             ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : "");
602 #else
603         HALDEBUG(ah, HAL_DEBUG_ANI, "%s: chan %u/0x%x restore %d opmode %u%s\n",
604             __func__, chan->ic_freq, chan->ic_flags, restore, opmode,
605             ichan->privFlags & CHANNEL_ANI_SETUP ? " setup" : "");
606 #endif
607         OS_MARK(ah, AH_MARK_ANI_RESET, opmode);
608
609         /*
610          * Turn off PHY error frame delivery while we futz with settings.
611          */
612         rxfilter = ar5212GetRxFilter(ah);
613         ar5212SetRxFilter(ah, rxfilter &~ HAL_RX_FILTER_PHYERR);
614         /*
615          * Automatic processing is done only in station mode right now.
616          */
617         if (opmode == HAL_M_STA)
618                 ahp->ah_procPhyErr |= HAL_RSSI_ANI_ENA;
619         else
620                 ahp->ah_procPhyErr &= ~HAL_RSSI_ANI_ENA;
621         /*
622          * Set all ani parameters.  We either set them to initial
623          * values or restore the previous ones for the channel.
624          * XXX if ANI follows hardware, we don't care what mode we're
625          * XXX in, we should keep the ani parameters
626          */
627         if (restore && (ichan->privFlags & CHANNEL_ANI_SETUP)) {
628                 ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
629                                  aniState->noiseImmunityLevel);
630                 ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
631                                  aniState->spurImmunityLevel);
632                 ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
633                                  !aniState->ofdmWeakSigDetectOff);
634                 ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR,
635                                  aniState->cckWeakSigThreshold);
636                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
637                                  aniState->firstepLevel);
638         } else {
639                 ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL, 0);
640                 ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
641                 ar5212AniControl(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
642                         AH_TRUE);
643                 ar5212AniControl(ah, HAL_ANI_CCK_WEAK_SIGNAL_THR, AH_FALSE);
644                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL, 0);
645                 ichan->privFlags |= CHANNEL_ANI_SETUP;
646         }
647         ar5212AniRestart(ah, aniState);
648
649         /* restore RX filter mask */
650         ar5212SetRxFilter(ah, rxfilter);
651 }
652
653 /*
654  * Process a MIB interrupt.  We may potentially be invoked because
655  * any of the MIB counters overflow/trigger so don't assume we're
656  * here because a PHY error counter triggered.
657  */
658 void
659 ar5212ProcessMibIntr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
660 {
661         struct ath_hal_5212 *ahp = AH5212(ah);
662         uint32_t phyCnt1, phyCnt2;
663
664         HALDEBUG(ah, HAL_DEBUG_ANI, "%s: mibc 0x%x phyCnt1 0x%x phyCnt2 0x%x "
665             "filtofdm 0x%x filtcck 0x%x\n",
666             __func__, OS_REG_READ(ah, AR_MIBC),
667             OS_REG_READ(ah, AR_PHYCNT1), OS_REG_READ(ah, AR_PHYCNT2),
668             OS_REG_READ(ah, AR_FILTOFDM), OS_REG_READ(ah, AR_FILTCCK));
669
670         /*
671          * First order of business is to clear whatever caused
672          * the interrupt so we don't keep getting interrupted.
673          * We have the usual mib counters that are reset-on-read
674          * and the additional counters that appeared starting in
675          * Hainan.  We collect the mib counters and explicitly
676          * zero additional counters we are not using.  Anything
677          * else is reset only if it caused the interrupt.
678          */
679         /* NB: these are not reset-on-read */
680         phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1);
681         phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2);
682         /* not used, always reset them in case they are the cause */
683         OS_REG_WRITE(ah, AR_FILTOFDM, 0);
684         OS_REG_WRITE(ah, AR_FILTCCK, 0);
685
686         /* Clear the mib counters and save them in the stats */
687         ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
688         ahp->ah_stats.ast_nodestats = *stats;
689
690         /*
691          * Check for an ani stat hitting the trigger threshold.
692          * When this happens we get a MIB interrupt and the top
693          * 2 bits of the counter register will be 0b11, hence
694          * the mask check of phyCnt?.
695          */
696         if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || 
697             ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
698                 struct ar5212AniState *aniState = ahp->ah_curani;
699                 const struct ar5212AniParams *params = aniState->params;
700                 uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
701
702                 ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
703                 ahp->ah_stats.ast_ani_ofdmerrs +=
704                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
705                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
706
707                 cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
708                 ahp->ah_stats.ast_ani_cckerrs +=
709                         cckPhyErrCnt - aniState->cckPhyErrCount;
710                 aniState->cckPhyErrCount = cckPhyErrCnt;
711
712                 /*
713                  * NB: figure out which counter triggered.  If both
714                  * trigger we'll only deal with one as the processing
715                  * clobbers the error counter so the trigger threshold
716                  * check will never be true.
717                  */
718                 if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh)
719                         ar5212AniOfdmErrTrigger(ah);
720                 if (aniState->cckPhyErrCount > params->cckTrigHigh)
721                         ar5212AniCckErrTrigger(ah);
722                 /* NB: always restart to insure the h/w counters are reset */
723                 ar5212AniRestart(ah, aniState);
724         }
725 }
726
727 void 
728 ar5212AniPhyErrReport(struct ath_hal *ah, const struct ath_rx_status *rs)
729 {
730         struct ath_hal_5212 *ahp = AH5212(ah);
731         struct ar5212AniState *aniState;
732         const struct ar5212AniParams *params;
733
734         HALASSERT(!ahp->ah_hasHwPhyCounters && rs != AH_NULL);
735
736         aniState = ahp->ah_curani;
737         params = aniState->params;
738         if (rs->rs_phyerr == HAL_PHYERR_OFDM_TIMING) {
739                 aniState->ofdmPhyErrCount++;
740                 ahp->ah_stats.ast_ani_ofdmerrs++;
741                 if (aniState->ofdmPhyErrCount > params->ofdmTrigHigh) {
742                         ar5212AniOfdmErrTrigger(ah);
743                         ar5212AniRestart(ah, aniState);
744                 }
745         } else if (rs->rs_phyerr == HAL_PHYERR_CCK_TIMING) {
746                 aniState->cckPhyErrCount++;
747                 ahp->ah_stats.ast_ani_cckerrs++;
748                 if (aniState->cckPhyErrCount > params->cckTrigHigh) {
749                         ar5212AniCckErrTrigger(ah);
750                         ar5212AniRestart(ah, aniState);
751                 }
752         }
753 }
754
755 static void
756 ar5212AniLowerImmunity(struct ath_hal *ah)
757 {
758         struct ath_hal_5212 *ahp = AH5212(ah);
759         struct ar5212AniState *aniState;
760         const struct ar5212AniParams *params;
761         
762         HALASSERT(ANI_ENA(ah));
763
764         aniState = ahp->ah_curani;
765         params = aniState->params;
766         if (ANI_ENA_RSSI(ah)) {
767                 int32_t rssi = BEACON_RSSI(ahp);
768                 if (rssi > params->rssiThrHigh) {
769                         /* 
770                          * Beacon signal is high, leave ofdm weak signal
771                          * detection off or it may oscillate.  Let it fall
772                          * through.
773                          */
774                 } else if (rssi > params->rssiThrLow) {
775                         /*
776                          * Beacon rssi in mid range, turn on ofdm weak signal
777                          * detection or lower firstep level.
778                          */
779                         if (aniState->ofdmWeakSigDetectOff) {
780                                 HALDEBUG(ah, HAL_DEBUG_ANI,
781                                     "%s: rssi %d OWSD on\n", __func__, rssi);
782                                 ar5212AniControl(ah,
783                                     HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
784                                     AH_TRUE);
785                                 return;
786                         }
787                         if (aniState->firstepLevel > 0) {
788                                 HALDEBUG(ah, HAL_DEBUG_ANI,
789                                     "%s: rssi %d lower ST %u\n", __func__, rssi,
790                                     aniState->firstepLevel-1);
791                                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
792                                                  aniState->firstepLevel - 1);
793                                 return;
794                         }
795                 } else {
796                         /*
797                          * Beacon rssi is low, reduce firstep level.
798                          */
799                         if (aniState->firstepLevel > 0) {
800                                 HALDEBUG(ah, HAL_DEBUG_ANI,
801                                     "%s: rssi %d lower ST %u\n", __func__, rssi,
802                                     aniState->firstepLevel-1);
803                                 ar5212AniControl(ah, HAL_ANI_FIRSTEP_LEVEL,
804                                                  aniState->firstepLevel - 1);
805                                 return;
806                         }
807                 }
808         }
809         /* then lower spur immunity level, down to zero */
810         if (aniState->spurImmunityLevel > 0) {
811                 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower SI %u\n",
812                     __func__, aniState->spurImmunityLevel-1);
813                 ar5212AniControl(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
814                                  aniState->spurImmunityLevel - 1);
815                 return;
816         }
817         /* 
818          * if all else fails, lower noise immunity level down to a min value
819          * zero for now
820          */
821         if (aniState->noiseImmunityLevel > 0) {
822                 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: lower NI %u\n",
823                     __func__, aniState->noiseImmunityLevel-1);
824                 ar5212AniControl(ah, HAL_ANI_NOISE_IMMUNITY_LEVEL,
825                                  aniState->noiseImmunityLevel - 1);
826                 return;
827         }
828 }
829
830 #define CLOCK_RATE 44000        /* XXX use mac_usec or similar */
831 /* convert HW counter values to ms using 11g clock rate, goo9d enough
832    for 11a and Turbo */
833
834 /* 
835  * Return an approximation of the time spent ``listening'' by
836  * deducting the cycles spent tx'ing and rx'ing from the total
837  * cycle count since our last call.  A return value <0 indicates
838  * an invalid/inconsistent time.
839  */
840 static int32_t
841 ar5212AniGetListenTime(struct ath_hal *ah)
842 {
843         struct ath_hal_5212 *ahp = AH5212(ah);
844         struct ar5212AniState *aniState;
845         uint32_t txFrameCount, rxFrameCount, cycleCount;
846         int32_t listenTime;
847
848         txFrameCount = OS_REG_READ(ah, AR_TFCNT);
849         rxFrameCount = OS_REG_READ(ah, AR_RFCNT);
850         cycleCount = OS_REG_READ(ah, AR_CCCNT);
851
852         aniState = ahp->ah_curani;
853         if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
854                 /*
855                  * Cycle counter wrap (or initial call); it's not possible
856                  * to accurately calculate a value because the registers
857                  * right shift rather than wrap--so punt and return 0.
858                  */
859                 listenTime = 0;
860                 ahp->ah_stats.ast_ani_lzero++;
861         } else {
862                 int32_t ccdelta = cycleCount - aniState->cycleCount;
863                 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
864                 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
865                 listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
866         }
867         aniState->cycleCount = cycleCount;
868         aniState->txFrameCount = txFrameCount;
869         aniState->rxFrameCount = rxFrameCount;
870         return listenTime;
871 }
872
873 /*
874  * Update ani stats in preparation for listen time processing.
875  */
876 static void
877 updateMIBStats(struct ath_hal *ah, struct ar5212AniState *aniState)
878 {
879         struct ath_hal_5212 *ahp = AH5212(ah);
880         const struct ar5212AniParams *params = aniState->params;
881         uint32_t phyCnt1, phyCnt2;
882         int32_t ofdmPhyErrCnt, cckPhyErrCnt;
883
884         HALASSERT(ahp->ah_hasHwPhyCounters);
885
886         /* Clear the mib counters and save them in the stats */
887         ar5212UpdateMibCounters(ah, &ahp->ah_mibStats);
888
889         /* NB: these are not reset-on-read */
890         phyCnt1 = OS_REG_READ(ah, AR_PHYCNT1);
891         phyCnt2 = OS_REG_READ(ah, AR_PHYCNT2);
892
893         /* NB: these are spec'd to never roll-over */
894         ofdmPhyErrCnt = phyCnt1 - params->ofdmPhyErrBase;
895         if (ofdmPhyErrCnt < 0) {
896                 HALDEBUG(ah, HAL_DEBUG_ANI, "OFDM phyErrCnt %d phyCnt1 0x%x\n",
897                     ofdmPhyErrCnt, phyCnt1);
898                 ofdmPhyErrCnt = AR_PHY_COUNTMAX;
899         }
900         ahp->ah_stats.ast_ani_ofdmerrs +=
901              ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
902         aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
903
904         cckPhyErrCnt = phyCnt2 - params->cckPhyErrBase;
905         if (cckPhyErrCnt < 0) {
906                 HALDEBUG(ah, HAL_DEBUG_ANI, "CCK phyErrCnt %d phyCnt2 0x%x\n",
907                     cckPhyErrCnt, phyCnt2);
908                 cckPhyErrCnt = AR_PHY_COUNTMAX;
909         }
910         ahp->ah_stats.ast_ani_cckerrs +=
911                 cckPhyErrCnt - aniState->cckPhyErrCount;
912         aniState->cckPhyErrCount = cckPhyErrCnt;
913 }
914
915 /*
916  * Do periodic processing.  This routine is called from the
917  * driver's rx interrupt handler after processing frames.
918  */
919 void
920 ar5212AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
921                 const struct ieee80211_channel *chan)
922 {
923         struct ath_hal_5212 *ahp = AH5212(ah);
924         struct ar5212AniState *aniState = ahp->ah_curani;
925         const struct ar5212AniParams *params;
926         int32_t listenTime;
927
928         ahp->ah_stats.ast_nodestats.ns_avgbrssi = stats->ns_avgbrssi;
929
930         /* XXX can aniState be null? */
931         if (aniState == AH_NULL)
932                 return;
933         if (!ANI_ENA(ah))
934                 return;
935
936         listenTime = ar5212AniGetListenTime(ah);
937         if (listenTime < 0) {
938                 ahp->ah_stats.ast_ani_lneg++;
939                 /* restart ANI period if listenTime is invalid */
940                 ar5212AniRestart(ah, aniState);
941         }
942         /* XXX beware of overflow? */
943         aniState->listenTime += listenTime;
944
945         OS_MARK(ah, AH_MARK_ANI_POLL, aniState->listenTime);
946
947         params = aniState->params;
948         if (aniState->listenTime > 5*params->period) {
949                 /* 
950                  * Check to see if need to lower immunity if
951                  * 5 aniPeriods have passed
952                  */
953                 if (ahp->ah_hasHwPhyCounters)
954                         updateMIBStats(ah, aniState);
955                 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
956                     params->ofdmTrigLow/1000 &&
957                     aniState->cckPhyErrCount <= aniState->listenTime *
958                     params->cckTrigLow/1000)
959                         ar5212AniLowerImmunity(ah);
960                 ar5212AniRestart(ah, aniState);
961         } else if (aniState->listenTime > params->period) {
962                 if (ahp->ah_hasHwPhyCounters)
963                         updateMIBStats(ah, aniState);
964                 /* check to see if need to raise immunity */
965                 if (aniState->ofdmPhyErrCount > aniState->listenTime *
966                     params->ofdmTrigHigh / 1000) {
967                         HALDEBUG(ah, HAL_DEBUG_ANI,
968                             "%s: OFDM err %u listenTime %u\n", __func__,
969                             aniState->ofdmPhyErrCount, aniState->listenTime);
970                         ar5212AniOfdmErrTrigger(ah);
971                         ar5212AniRestart(ah, aniState);
972                 } else if (aniState->cckPhyErrCount > aniState->listenTime *
973                            params->cckTrigHigh / 1000) {
974                         HALDEBUG(ah, HAL_DEBUG_ANI,
975                             "%s: CCK err %u listenTime %u\n", __func__,
976                             aniState->cckPhyErrCount, aniState->listenTime);
977                         ar5212AniCckErrTrigger(ah);
978                         ar5212AniRestart(ah, aniState);
979                 }
980         }
981 }