0afecd8c2de4e1ff509988eca98ae0f32fe4b06b
[safe/jmp/linux-2.6] / drivers / staging / otus / hal / hpani.c
1 /*
2  * Copyright (c) 2007-2008 Atheros Communications 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
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include "../80211core/cprecomp.h"
17 #include "hpani.h"
18 #include "hpusb.h"
19
20
21 extern u16_t zfDelayWriteInternalReg(zdev_t* dev, u32_t addr, u32_t val);
22 extern u16_t zfFlushDelayWrite(zdev_t* dev);
23
24 /*
25  * Anti noise immunity support.  We track phy errors and react
26  * to excessive errors by adjusting the noise immunity parameters.
27  */
28
29 /******************************************************************************
30  *
31  * New Ani Algorithm for Station side only
32  *
33  *****************************************************************************/
34
35 #define ZM_HAL_NOISE_IMMUNE_MAX     4   /* Max noise immunity level */
36 #define ZM_HAL_SPUR_IMMUNE_MAX      7   /* Max spur immunity level */
37 #define ZM_HAL_FIRST_STEP_MAX       2   /* Max first step level */
38
39 #define ZM_HAL_ANI_OFDM_TRIG_HIGH       500
40 #define ZM_HAL_ANI_OFDM_TRIG_LOW        200
41 #define ZM_HAL_ANI_CCK_TRIG_HIGH        200
42 #define ZM_HAL_ANI_CCK_TRIG_LOW         100
43 #define ZM_HAL_ANI_NOISE_IMMUNE_LVL     4
44 #define ZM_HAL_ANI_USE_OFDM_WEAK_SIG    TRUE
45 #define ZM_HAL_ANI_CCK_WEAK_SIG_THR     FALSE
46 #define ZM_HAL_ANI_SPUR_IMMUNE_LVL      7
47 #define ZM_HAL_ANI_FIRSTEP_LVL          0
48 #define ZM_HAL_ANI_RSSI_THR_HIGH        40
49 #define ZM_HAL_ANI_RSSI_THR_LOW         7
50 #define ZM_HAL_ANI_PERIOD               100
51
52 #define ZM_HAL_EP_RND(x, mul) \
53     ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
54
55 s32_t BEACON_RSSI(zdev_t* dev)
56 {
57     s32_t rssi;
58     struct zsHpPriv *HpPriv;
59
60     zmw_get_wlan_dev(dev);
61     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
62
63     rssi = ZM_HAL_EP_RND(HpPriv->stats.ast_nodestats.ns_avgbrssi, ZM_HAL_RSSI_EP_MULTIPLIER);
64
65     return rssi;
66 }
67
68 /*
69  * Setup ANI handling.  Sets all thresholds and levels to default level AND
70  * resets the channel statistics
71  */
72
73 void zfHpAniAttach(zdev_t* dev)
74 {
75 #define N(a)     (sizeof(a) / sizeof(a[0]))
76     u32_t i;
77     struct zsHpPriv *HpPriv;
78
79     const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
80     const int coarseHigh[]       = { -14, -14, -14, -14, -12 };
81     const int coarseLow[]        = { -64, -64, -64, -64, -70 };
82     const int firpwr[]           = { -78, -78, -78, -78, -80 };
83
84     zmw_get_wlan_dev(dev);
85     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
86
87     for (i = 0; i < 5; i++)
88     {
89         HpPriv->totalSizeDesired[i] = totalSizeDesired[i];
90         HpPriv->coarseHigh[i] = coarseHigh[i];
91         HpPriv->coarseLow[i] = coarseLow[i];
92         HpPriv->firpwr[i] = firpwr[i];
93     }
94
95     /* owl has phy counters */
96     HpPriv->hasHwPhyCounters = 1;
97
98     memset((char *)&HpPriv->ani, 0, sizeof(HpPriv->ani));
99     for (i = 0; i < N(wd->regulationTable.allowChannel); i++)
100     {
101         /* New ANI stuff */
102         HpPriv->ani[i].ofdmTrigHigh = ZM_HAL_ANI_OFDM_TRIG_HIGH;
103         HpPriv->ani[i].ofdmTrigLow = ZM_HAL_ANI_OFDM_TRIG_LOW;
104         HpPriv->ani[i].cckTrigHigh = ZM_HAL_ANI_CCK_TRIG_HIGH;
105         HpPriv->ani[i].cckTrigLow = ZM_HAL_ANI_CCK_TRIG_LOW;
106         HpPriv->ani[i].rssiThrHigh = ZM_HAL_ANI_RSSI_THR_HIGH;
107         HpPriv->ani[i].rssiThrLow = ZM_HAL_ANI_RSSI_THR_LOW;
108         HpPriv->ani[i].ofdmWeakSigDetectOff = !ZM_HAL_ANI_USE_OFDM_WEAK_SIG;
109         HpPriv->ani[i].cckWeakSigThreshold = ZM_HAL_ANI_CCK_WEAK_SIG_THR;
110         HpPriv->ani[i].spurImmunityLevel = ZM_HAL_ANI_SPUR_IMMUNE_LVL;
111         HpPriv->ani[i].firstepLevel = ZM_HAL_ANI_FIRSTEP_LVL;
112         if (HpPriv->hasHwPhyCounters)
113         {
114             HpPriv->ani[i].ofdmPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_OFDM_TRIG_HIGH;
115             HpPriv->ani[i].cckPhyErrBase = 0;//AR_PHY_COUNTMAX - ZM_HAL_ANI_CCK_TRIG_HIGH;
116         }
117     }
118     if (HpPriv->hasHwPhyCounters)
119     {
120         //zm_debug_msg2("Setting OfdmErrBase = 0x", HpPriv->ani[0].ofdmPhyErrBase);
121         //zm_debug_msg2("Setting cckErrBase = 0x", HpPriv->ani[0].cckPhyErrBase);
122         //OS_REG_WRITE(ah, AR_PHY_ERR_1, HpPriv->ani[0].ofdmPhyErrBase);
123         //OS_REG_WRITE(ah, AR_PHY_ERR_2, HpPriv->ani[0].cckPhyErrBase);
124     }
125     HpPriv->aniPeriod = ZM_HAL_ANI_PERIOD;
126     //if (ath_hal_enableANI)
127     HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI;
128
129     HpPriv->stats.ast_nodestats.ns_avgbrssi = ZM_RSSI_DUMMY_MARKER;
130     HpPriv->stats.ast_nodestats.ns_avgrssi = ZM_RSSI_DUMMY_MARKER;
131     HpPriv->stats.ast_nodestats.ns_avgtxrssi = ZM_RSSI_DUMMY_MARKER;
132 #undef N
133 }
134
135 /*
136  * Control Adaptive Noise Immunity Parameters
137  */
138 u8_t zfHpAniControl(zdev_t* dev, ZM_HAL_ANI_CMD cmd, int param)
139 {
140 #define N(a) (sizeof(a)/sizeof(a[0]))
141     typedef s32_t TABLE[];
142     struct zsHpPriv *HpPriv;
143     struct zsAniState *aniState;
144
145     zmw_get_wlan_dev(dev);
146     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
147     aniState = HpPriv->curani;
148
149     switch (cmd)
150     {
151     case ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL:
152     {
153         u32_t level = param;
154
155         if (level >= N(HpPriv->totalSizeDesired))
156         {
157           zm_debug_msg1("level out of range, desired level : ", level);
158           zm_debug_msg1("max level : ", N(HpPriv->totalSizeDesired));
159           return FALSE;
160         }
161
162         zfDelayWriteInternalReg(dev, AR_PHY_DESIRED_SZ,
163                 (HpPriv->regPHYDesiredSZ & ~AR_PHY_DESIRED_SZ_TOT_DES)
164                 | ((HpPriv->totalSizeDesired[level] << AR_PHY_DESIRED_SZ_TOT_DES_S)
165                 & AR_PHY_DESIRED_SZ_TOT_DES));
166         zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1,
167                 (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_LOW)
168                 | ((HpPriv->coarseLow[level] << AR_PHY_AGC_CTL1_COARSE_LOW_S)
169                 & AR_PHY_AGC_CTL1_COARSE_LOW));
170         zfDelayWriteInternalReg(dev, AR_PHY_AGC_CTL1,
171                 (HpPriv->regPHYAgcCtl1 & ~AR_PHY_AGC_CTL1_COARSE_HIGH)
172                 | ((HpPriv->coarseHigh[level] << AR_PHY_AGC_CTL1_COARSE_HIGH_S)
173                 & AR_PHY_AGC_CTL1_COARSE_HIGH));
174         zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG,
175                 (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRPWR)
176                 | ((HpPriv->firpwr[level] << AR_PHY_FIND_SIG_FIRPWR_S)
177                 & AR_PHY_FIND_SIG_FIRPWR));
178         zfFlushDelayWrite(dev);
179
180         if (level > aniState->noiseImmunityLevel)
181             HpPriv->stats.ast_ani_niup++;
182         else if (level < aniState->noiseImmunityLevel)
183             HpPriv->stats.ast_ani_nidown++;
184         aniState->noiseImmunityLevel = (u8_t)level;
185         break;
186     }
187     case ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
188     {
189         const TABLE m1ThreshLow   = { 127,   50 };
190         const TABLE m2ThreshLow   = { 127,   40 };
191         const TABLE m1Thresh      = { 127, 0x4d };
192         const TABLE m2Thresh      = { 127, 0x40 };
193         const TABLE m2CountThr    = {  31,   16 };
194         const TABLE m2CountThrLow = {  63,   48 };
195         u32_t on = param ? 1 : 0;
196
197         zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW,
198                 (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M1_THRESH_LOW)
199                 | ((m1ThreshLow[on] << AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S)
200                 & AR_PHY_SFCORR_LOW_M1_THRESH_LOW));
201         zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW,
202                 (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2_THRESH_LOW)
203                 | ((m2ThreshLow[on] << AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S)
204                 & AR_PHY_SFCORR_LOW_M2_THRESH_LOW));
205         zfDelayWriteInternalReg(dev, AR_PHY_SFCORR,
206                 (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M1_THRESH)
207                 | ((m1Thresh[on] << AR_PHY_SFCORR_M1_THRESH_S)
208                 & AR_PHY_SFCORR_M1_THRESH));
209         zfDelayWriteInternalReg(dev, AR_PHY_SFCORR,
210                 (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2_THRESH)
211                 | ((m2Thresh[on] << AR_PHY_SFCORR_M2_THRESH_S)
212                 & AR_PHY_SFCORR_M2_THRESH));
213         zfDelayWriteInternalReg(dev, AR_PHY_SFCORR,
214                 (HpPriv->regPHYSfcorr & ~AR_PHY_SFCORR_M2COUNT_THR)
215                 | ((m2CountThr[on] << AR_PHY_SFCORR_M2COUNT_THR_S)
216                 & AR_PHY_SFCORR_M2COUNT_THR));
217         zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW,
218                 (HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW)
219                 | ((m2CountThrLow[on] << AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S)
220                 & AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW));
221
222         if (on)
223         {
224             zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW,
225                     HpPriv->regPHYSfcorrLow | AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
226         }
227         else
228         {
229             zfDelayWriteInternalReg(dev, AR_PHY_SFCORR_LOW,
230                     HpPriv->regPHYSfcorrLow & ~AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
231         }
232         zfFlushDelayWrite(dev);
233         if (!on != aniState->ofdmWeakSigDetectOff)
234         {
235             if (on)
236                 HpPriv->stats.ast_ani_ofdmon++;
237             else
238                 HpPriv->stats.ast_ani_ofdmoff++;
239             aniState->ofdmWeakSigDetectOff = !on;
240         }
241         break;
242     }
243     case ZM_HAL_ANI_CCK_WEAK_SIGNAL_THR:
244     {
245         const TABLE weakSigThrCck = { 8, 6 };
246         u32_t high = param ? 1 : 0;
247
248         zfDelayWriteInternalReg(dev, AR_PHY_CCK_DETECT,
249                 (HpPriv->regPHYCckDetect & ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK)
250                 | ((weakSigThrCck[high] << AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S)
251                 & AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK));
252         zfFlushDelayWrite(dev);
253         if (high != aniState->cckWeakSigThreshold)
254         {
255             if (high)
256                 HpPriv->stats.ast_ani_cckhigh++;
257             else
258                 HpPriv->stats.ast_ani_ccklow++;
259             aniState->cckWeakSigThreshold = (u8_t)high;
260         }
261         break;
262     }
263     case ZM_HAL_ANI_FIRSTEP_LEVEL:
264     {
265         const TABLE firstep = { 0, 4, 8 };
266         u32_t level = param;
267
268         if (level >= N(firstep))
269         {
270             zm_debug_msg1("level out of range, desired level : ", level);
271             zm_debug_msg1("max level : ", N(firstep));
272             return FALSE;
273         }
274         zfDelayWriteInternalReg(dev, AR_PHY_FIND_SIG,
275                 (HpPriv->regPHYFindSig & ~AR_PHY_FIND_SIG_FIRSTEP)
276                 | ((firstep[level] << AR_PHY_FIND_SIG_FIRSTEP_S)
277                 & AR_PHY_FIND_SIG_FIRSTEP));
278         zfFlushDelayWrite(dev);
279         if (level > aniState->firstepLevel)
280             HpPriv->stats.ast_ani_stepup++;
281         else if (level < aniState->firstepLevel)
282             HpPriv->stats.ast_ani_stepdown++;
283         aniState->firstepLevel = (u8_t)level;
284         break;
285     }
286     case ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL:
287     {
288         const TABLE cycpwrThr1 = { 2, 4, 6, 8, 10, 12, 14, 16 };
289         u32_t level = param;
290
291         if (level >= N(cycpwrThr1))
292         {
293             zm_debug_msg1("level out of range, desired level : ", level);
294             zm_debug_msg1("max level : ", N(cycpwrThr1));
295             return FALSE;
296         }
297         zfDelayWriteInternalReg(dev, AR_PHY_TIMING5,
298                 (HpPriv->regPHYTiming5 & ~AR_PHY_TIMING5_CYCPWR_THR1)
299                 | ((cycpwrThr1[level] << AR_PHY_TIMING5_CYCPWR_THR1_S)
300                 & AR_PHY_TIMING5_CYCPWR_THR1));
301         zfFlushDelayWrite(dev);
302         if (level > aniState->spurImmunityLevel)
303             HpPriv->stats.ast_ani_spurup++;
304         else if (level < aniState->spurImmunityLevel)
305             HpPriv->stats.ast_ani_spurdown++;
306         aniState->spurImmunityLevel = (u8_t)level;
307         break;
308     }
309     case ZM_HAL_ANI_PRESENT:
310         break;
311 #ifdef AH_PRIVATE_DIAG
312     case ZM_HAL_ANI_MODE:
313         if (param == 0)
314         {
315             HpPriv->procPhyErr &= ~ZM_HAL_PROCESS_ANI;
316             /* Turn off HW counters if we have them */
317             zfHpAniDetach(dev);
318             //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR);
319         }
320         else
321         {           /* normal/auto mode */
322             HpPriv->procPhyErr |= ZM_HAL_PROCESS_ANI;
323             if (HpPriv->hasHwPhyCounters)
324             {
325                 //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) &~ HAL_RX_FILTER_PHYERR);
326             }
327             else
328             {
329                 //zfHpSetRxFilter(dev, zfHpGetRxFilter(dev) | HAL_RX_FILTER_PHYERR);
330             }
331         }
332         break;
333     case ZM_HAL_ANI_PHYERR_RESET:
334         HpPriv->stats.ast_ani_ofdmerrs = 0;
335         HpPriv->stats.ast_ani_cckerrs = 0;
336         break;
337 #endif /* AH_PRIVATE_DIAG */
338     default:
339         zm_debug_msg1("invalid cmd ", cmd);
340         return FALSE;
341     }
342     return TRUE;
343 #undef  N
344 }
345
346 void zfHpAniRestart(zdev_t* dev)
347 {
348     struct zsAniState *aniState;
349     struct zsHpPriv *HpPriv;
350
351     zmw_get_wlan_dev(dev);
352     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
353     aniState = HpPriv->curani;
354
355     aniState->listenTime = 0;
356     if (HpPriv->hasHwPhyCounters)
357     {
358         //if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX)
359         //{
360         //    aniState->ofdmPhyErrBase = 0;
361         //    zm_debug_msg0("OFDM Trigger is too high for hw counters");
362         //}
363         //else
364         //    aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
365         //if (aniState->cckTrigHigh > AR_PHY_COUNTMAX)
366         //{
367         //    aniState->cckPhyErrBase = 0;
368         //    zm_debug_msg0("CCK Trigger is too high for hw counters");
369         //}
370         //else
371         //    aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh;
372         //zm_debug_msg2("Writing ofdmbase = 0x", aniState->ofdmPhyErrBase);
373         //zm_debug_msg2("Writing cckbase = 0x", aniState->cckPhyErrBase);
374         //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
375         //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
376         //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
377         //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
378         aniState->ofdmPhyErrBase = 0;
379         aniState->cckPhyErrBase = 0;
380     }
381     aniState->ofdmPhyErrCount = 0;
382     aniState->cckPhyErrCount = 0;
383 }
384
385 void zfHpAniOfdmErrTrigger(zdev_t* dev)
386 {
387     struct zsAniState *aniState;
388     s32_t rssi;
389     struct zsHpPriv *HpPriv;
390
391     zmw_get_wlan_dev(dev);
392     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
393
394     //HALASSERT(chan != NULL);
395
396     if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0)
397         return;
398
399     aniState = HpPriv->curani;
400     /* First, raise noise immunity level, up to max */
401     if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX)
402     {
403         zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1);
404         return;
405     }
406     /* then, raise spur immunity level, up to max */
407     if (aniState->spurImmunityLevel < ZM_HAL_SPUR_IMMUNE_MAX)
408     {
409         zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1);
410         return;
411     }
412     rssi = BEACON_RSSI(dev);
413     if (rssi > aniState->rssiThrHigh)
414     {
415         /*
416          * Beacon rssi is high, can turn off ofdm weak sig detect.
417          */
418         if (!aniState->ofdmWeakSigDetectOff)
419         {
420             zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE);
421             zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
422             return;
423         }
424         /*
425          * If weak sig detect is already off, as last resort, raise
426          * first step level
427          */
428         if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX)
429         {
430             zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1);
431             return;
432         }
433     }
434     else if (rssi > aniState->rssiThrLow)
435     {
436         /*
437          * Beacon rssi in mid range, need ofdm weak signal detect,
438          * but we can raise firststepLevel
439          */
440         if (aniState->ofdmWeakSigDetectOff)
441             zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE);
442         if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX)
443             zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1);
444         return;
445     }
446     else
447     {
448         /*
449          * Beacon rssi is low, if in 11b/g mode, turn off ofdm
450          * weak sign detction and zero firstepLevel to maximize
451          * CCK sensitivity
452          */
453         if (wd->frequency < 3000)
454         {
455             if (!aniState->ofdmWeakSigDetectOff)
456                 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE);
457             if (aniState->firstepLevel > 0)
458                 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0);
459             return;
460         }
461     }
462 }
463
464 void zfHpAniCckErrTrigger(zdev_t* dev)
465 {
466     struct zsAniState *aniState;
467     s32_t rssi;
468     struct zsHpPriv *HpPriv;
469
470     zmw_get_wlan_dev(dev);
471     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
472
473     //HALASSERT(chan != NULL);
474
475     if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0)
476         return;
477
478     /* first, raise noise immunity level, up to max */
479     aniState = HpPriv->curani;
480     if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX)
481     {
482         zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL,
483                  aniState->noiseImmunityLevel + 1);
484         return;
485     }
486     rssi = BEACON_RSSI(dev);
487     if (rssi >  aniState->rssiThrLow)
488     {
489         /*
490          * Beacon signal in mid and high range, raise firsteplevel.
491          */
492         if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX)
493             zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1);
494     }
495     else
496     {
497         /*
498          * Beacon rssi is low, zero firstepLevel to maximize
499          * CCK sensitivity.
500          */
501         if (wd->frequency < 3000)
502         {
503             if (aniState->firstepLevel > 0)
504                 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0);
505         }
506     }
507 }
508
509 void zfHpAniLowerImmunity(zdev_t* dev)
510 {
511     struct zsAniState *aniState;
512     s32_t rssi;
513     struct zsHpPriv *HpPriv;
514
515     zmw_get_wlan_dev(dev);
516     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
517     aniState = HpPriv->curani;
518
519     rssi = BEACON_RSSI(dev);
520     if (rssi > aniState->rssiThrHigh)
521     {
522         /*
523          * Beacon signal is high, leave ofdm weak signal detection off
524          * or it may oscillate. Let it fall through.
525          */
526     }
527     else if (rssi > aniState->rssiThrLow)
528     {
529         /*
530          * Beacon rssi in mid range, turn on ofdm weak signal
531          * detection or lower first step level.
532          */
533         if (aniState->ofdmWeakSigDetectOff)
534         {
535             zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE);
536             return;
537         }
538         if (aniState->firstepLevel > 0)
539         {
540             zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1);
541             return;
542         }
543     }
544     else
545     {
546         /*
547          * Beacon rssi is low, reduce first step level.
548          */
549         if (aniState->firstepLevel > 0)
550         {
551             zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1);
552             return;
553         }
554     }
555     /* then lower spur immunity level, down to zero */
556     if (aniState->spurImmunityLevel > 0)
557     {
558         zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel - 1);
559         return;
560     }
561     /*
562      * if all else fails, lower noise immunity level down to a min value
563      * zero for now
564      */
565     if (aniState->noiseImmunityLevel > 0)
566     {
567         zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel - 1);
568         return;
569     }
570 }
571
572 #define CLOCK_RATE 44000    /* XXX use mac_usec or similar */
573 /* convert HW counter values to ms using 11g clock rate, goo9d enough
574    for 11a and Turbo */
575
576 /*
577  * Return an approximation of the time spent ``listening'' by
578  * deducting the cycles spent tx'ing and rx'ing from the total
579  * cycle count since our last call.  A return value <0 indicates
580  * an invalid/inconsistent time.
581  */
582 s32_t zfHpAniGetListenTime(zdev_t* dev)
583 {
584     struct zsAniState *aniState;
585     u32_t txFrameCount, rxFrameCount, cycleCount;
586     s32_t listenTime;
587     struct zsHpPriv *HpPriv;
588
589     zmw_get_wlan_dev(dev);
590     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
591
592     txFrameCount = 0;//OS_REG_READ(ah, AR_TFCNT);
593     rxFrameCount = 0;//OS_REG_READ(ah, AR_RFCNT);
594     cycleCount = 0;//OS_REG_READ(ah, AR_CCCNT);
595
596     aniState = HpPriv->curani;
597     if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount)
598     {
599         /*
600          * Cycle counter wrap (or initial call); it's not possible
601          * to accurately calculate a value because the registers
602          * right shift rather than wrap--so punt and return 0.
603          */
604         listenTime = 0;
605         HpPriv->stats.ast_ani_lzero++;
606     }
607     else
608     {
609         s32_t ccdelta = cycleCount - aniState->cycleCount;
610         s32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
611         s32_t tfdelta = txFrameCount - aniState->txFrameCount;
612         listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
613     }
614     aniState->cycleCount = cycleCount;
615     aniState->txFrameCount = txFrameCount;
616     aniState->rxFrameCount = rxFrameCount;
617     return listenTime;
618 }
619
620 /*
621  * Do periodic processing.  This routine is called from the
622  * driver's rx interrupt handler after processing frames.
623  */
624 void zfHpAniArPoll(zdev_t* dev, u32_t listenTime, u32_t phyCnt1, u32_t phyCnt2)
625 {
626     struct zsAniState *aniState;
627     //s32_t listenTime;
628     struct zsHpPriv *HpPriv;
629
630     zmw_get_wlan_dev(dev);
631     HpPriv = (struct zsHpPriv*)wd->hpPrivate;
632
633     /*
634      * Since we're called from end of rx tasklet, we also check for
635      * AR processing now
636      */
637
638     aniState = HpPriv->curani;
639     //HpPriv->stats.ast_nodestats = *stats;       /* XXX optimize? */
640
641     //listenTime = zfHpAniGetListenTime(dev);
642     //if (listenTime < 0)
643     //{
644     //    HpPriv->stats.ast_ani_lneg++;
645     //    /* restart ANI period if listenTime is invalid */
646     //    zfHpAniRestart(dev);
647     //    return;
648     //}
649     /* XXX beware of overflow? */
650     aniState->listenTime += listenTime;
651
652     if (HpPriv->hasHwPhyCounters)
653     {
654         //u32_t phyCnt1, phyCnt2;
655         u32_t ofdmPhyErrCnt, cckPhyErrCnt;
656
657         /* NB: these are not reset-on-read */
658         //phyCnt1 = 0;//OS_REG_READ(ah, AR_PHY_ERR_1);
659         //phyCnt2 = 0;//OS_REG_READ(ah, AR_PHY_ERR_2);
660         /* XXX sometimes zero, why? */
661         //if (phyCnt1 < aniState->ofdmPhyErrBase ||
662         //    phyCnt2 < aniState->cckPhyErrBase)
663         //{
664         //    if (phyCnt1 < aniState->ofdmPhyErrBase)
665         //    {
666         //        zm_debug_msg2("phyCnt1 = 0x", phyCnt1);
667         //        zm_debug_msg2("resetting counter value to 0x", aniState->ofdmPhyErrBase);
668         //        //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
669         //        //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
670         //    }
671         //    if (phyCnt2 < aniState->cckPhyErrBase)
672         //    {
673         //        zm_debug_msg2("phyCnt2 = 0x", phyCnt2);
674         //        zm_debug_msg2("resetting counter value to 0x", aniState->cckPhyErrBase);
675         //        //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
676         //        //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
677         //    }
678         //    return;     /* XXX */
679         //}
680         /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
681         //ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
682         //HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
683         //aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
684         ofdmPhyErrCnt = phyCnt1;
685         HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt;
686         aniState->ofdmPhyErrCount += ofdmPhyErrCnt;
687
688         //cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
689         //HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount;
690         //aniState->cckPhyErrCount = cckPhyErrCnt;
691         cckPhyErrCnt = phyCnt2;
692         HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt;
693         aniState->cckPhyErrCount += cckPhyErrCnt;
694     }
695     /*
696      * If ani is not enabled, return after we've collected
697      * statistics
698      */
699     if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0)
700         return;
701     if (aniState->listenTime > 5 * HpPriv->aniPeriod)
702     {
703         /*
704          * Check to see if need to lower immunity if
705          * 5 aniPeriods have passed
706          */
707         if (aniState->ofdmPhyErrCount <= aniState->listenTime *
708              aniState->ofdmTrigLow/1000 &&
709             aniState->cckPhyErrCount <= aniState->listenTime *
710              aniState->cckTrigLow/1000)
711             zfHpAniLowerImmunity(dev);
712         zfHpAniRestart(dev);
713     }
714     else if (aniState->listenTime > HpPriv->aniPeriod)
715     {
716         /* check to see if need to raise immunity */
717         if (aniState->ofdmPhyErrCount > aniState->listenTime *
718             aniState->ofdmTrigHigh / 1000)
719         {
720             zfHpAniOfdmErrTrigger(dev);
721             zfHpAniRestart(dev);
722         }
723         else if (aniState->cckPhyErrCount > aniState->listenTime *
724                aniState->cckTrigHigh / 1000)
725         {
726             zfHpAniCckErrTrigger(dev);
727             zfHpAniRestart(dev);
728         }
729     }
730 }