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
BEACON_RSSI(zdev_t * dev)55 s32_t BEACON_RSSI(zdev_t* dev)
56 {
57 s32_t rssi;
58
59 zmw_get_wlan_dev(dev);
60
61 struct zsHpPriv *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
zfHpAniAttach(zdev_t * dev)73 void zfHpAniAttach(zdev_t* dev)
74 {
75 #define N(a) (sizeof(a) / sizeof(a[0]))
76 u32_t i;
77
78 zmw_get_wlan_dev(dev);
79
80 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
81
82 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
83 const int coarseHigh[] = { -14, -14, -14, -14, -12 };
84 const int coarseLow[] = { -64, -64, -64, -64, -70 };
85 const int firpwr[] = { -78, -78, -78, -78, -80 };
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 */
zfHpAniControl(zdev_t * dev,ZM_HAL_ANI_CMD cmd,int param)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
143 zmw_get_wlan_dev(dev);
144
145 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
146
147 struct zsAniState *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
zfHpAniRestart(zdev_t * dev)346 void zfHpAniRestart(zdev_t* dev)
347 {
348 struct zsAniState *aniState;
349
350 zmw_get_wlan_dev(dev);
351
352 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
353
354 aniState = HpPriv->curani;
355
356 aniState->listenTime = 0;
357 if (HpPriv->hasHwPhyCounters)
358 {
359 //if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX)
360 //{
361 // aniState->ofdmPhyErrBase = 0;
362 // zm_debug_msg0("OFDM Trigger is too high for hw counters");
363 //}
364 //else
365 // aniState->ofdmPhyErrBase = AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
366 //if (aniState->cckTrigHigh > AR_PHY_COUNTMAX)
367 //{
368 // aniState->cckPhyErrBase = 0;
369 // zm_debug_msg0("CCK Trigger is too high for hw counters");
370 //}
371 //else
372 // aniState->cckPhyErrBase = AR_PHY_COUNTMAX - aniState->cckTrigHigh;
373 //zm_debug_msg2("Writing ofdmbase = 0x", aniState->ofdmPhyErrBase);
374 //zm_debug_msg2("Writing cckbase = 0x", aniState->cckPhyErrBase);
375 //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
376 //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
377 //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
378 //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
379 aniState->ofdmPhyErrBase = 0;
380 aniState->cckPhyErrBase = 0;
381 }
382 aniState->ofdmPhyErrCount = 0;
383 aniState->cckPhyErrCount = 0;
384 }
385
zfHpAniOfdmErrTrigger(zdev_t * dev)386 void zfHpAniOfdmErrTrigger(zdev_t* dev)
387 {
388 struct zsAniState *aniState;
389 s32_t rssi;
390
391 zmw_get_wlan_dev(dev);
392
393 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
394
395 //HALASSERT(chan != NULL);
396
397 if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0)
398 return;
399
400 aniState = HpPriv->curani;
401 /* First, raise noise immunity level, up to max */
402 if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX)
403 {
404 zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1);
405 return;
406 }
407 /* then, raise spur immunity level, up to max */
408 if (aniState->spurImmunityLevel < ZM_HAL_SPUR_IMMUNE_MAX)
409 {
410 zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1);
411 return;
412 }
413 rssi = BEACON_RSSI(dev);
414 if (rssi > aniState->rssiThrHigh)
415 {
416 /*
417 * Beacon rssi is high, can turn off ofdm weak sig detect.
418 */
419 if (!aniState->ofdmWeakSigDetectOff)
420 {
421 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE);
422 zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, 0);
423 return;
424 }
425 /*
426 * If weak sig detect is already off, as last resort, raise
427 * first step level
428 */
429 if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX)
430 {
431 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1);
432 return;
433 }
434 }
435 else if (rssi > aniState->rssiThrLow)
436 {
437 /*
438 * Beacon rssi in mid range, need ofdm weak signal detect,
439 * but we can raise firststepLevel
440 */
441 if (aniState->ofdmWeakSigDetectOff)
442 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE);
443 if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX)
444 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1);
445 return;
446 }
447 else
448 {
449 /*
450 * Beacon rssi is low, if in 11b/g mode, turn off ofdm
451 * weak sign detction and zero firstepLevel to maximize
452 * CCK sensitivity
453 */
454 if (wd->frequency < 3000)
455 {
456 if (!aniState->ofdmWeakSigDetectOff)
457 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, FALSE);
458 if (aniState->firstepLevel > 0)
459 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0);
460 return;
461 }
462 }
463 }
464
zfHpAniCckErrTrigger(zdev_t * dev)465 void zfHpAniCckErrTrigger(zdev_t* dev)
466 {
467 struct zsAniState *aniState;
468 s32_t rssi;
469
470 zmw_get_wlan_dev(dev);
471
472 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
473
474 //HALASSERT(chan != NULL);
475
476 if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0)
477 return;
478
479 /* first, raise noise immunity level, up to max */
480 aniState = HpPriv->curani;
481 if (aniState->noiseImmunityLevel < ZM_HAL_NOISE_IMMUNE_MAX)
482 {
483 zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL,
484 aniState->noiseImmunityLevel + 1);
485 return;
486 }
487 rssi = BEACON_RSSI(dev);
488 if (rssi > aniState->rssiThrLow)
489 {
490 /*
491 * Beacon signal in mid and high range, raise firsteplevel.
492 */
493 if (aniState->firstepLevel < ZM_HAL_FIRST_STEP_MAX)
494 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1);
495 }
496 else
497 {
498 /*
499 * Beacon rssi is low, zero firstepLevel to maximize
500 * CCK sensitivity.
501 */
502 if (wd->frequency < 3000)
503 {
504 if (aniState->firstepLevel > 0)
505 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, 0);
506 }
507 }
508 }
509
zfHpAniLowerImmunity(zdev_t * dev)510 void zfHpAniLowerImmunity(zdev_t* dev)
511 {
512 struct zsAniState *aniState;
513 s32_t rssi;
514
515 zmw_get_wlan_dev(dev);
516
517 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
518
519 aniState = HpPriv->curani;
520
521 rssi = BEACON_RSSI(dev);
522 if (rssi > aniState->rssiThrHigh)
523 {
524 /*
525 * Beacon signal is high, leave ofdm weak signal detection off
526 * or it may oscillate. Let it fall through.
527 */
528 }
529 else if (rssi > aniState->rssiThrLow)
530 {
531 /*
532 * Beacon rssi in mid range, turn on ofdm weak signal
533 * detection or lower first step level.
534 */
535 if (aniState->ofdmWeakSigDetectOff)
536 {
537 zfHpAniControl(dev, ZM_HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, TRUE);
538 return;
539 }
540 if (aniState->firstepLevel > 0)
541 {
542 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1);
543 return;
544 }
545 }
546 else
547 {
548 /*
549 * Beacon rssi is low, reduce first step level.
550 */
551 if (aniState->firstepLevel > 0)
552 {
553 zfHpAniControl(dev, ZM_HAL_ANI_FIRSTEP_LEVEL, aniState->firstepLevel - 1);
554 return;
555 }
556 }
557 /* then lower spur immunity level, down to zero */
558 if (aniState->spurImmunityLevel > 0)
559 {
560 zfHpAniControl(dev, ZM_HAL_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel - 1);
561 return;
562 }
563 /*
564 * if all else fails, lower noise immunity level down to a min value
565 * zero for now
566 */
567 if (aniState->noiseImmunityLevel > 0)
568 {
569 zfHpAniControl(dev, ZM_HAL_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel - 1);
570 return;
571 }
572 }
573
574 #define CLOCK_RATE 44000 /* XXX use mac_usec or similar */
575 /* convert HW counter values to ms using 11g clock rate, goo9d enough
576 for 11a and Turbo */
577
578 /*
579 * Return an approximation of the time spent ``listening'' by
580 * deducting the cycles spent tx'ing and rx'ing from the total
581 * cycle count since our last call. A return value <0 indicates
582 * an invalid/inconsistent time.
583 */
zfHpAniGetListenTime(zdev_t * dev)584 s32_t zfHpAniGetListenTime(zdev_t* dev)
585 {
586 struct zsAniState *aniState;
587 u32_t txFrameCount, rxFrameCount, cycleCount;
588 s32_t listenTime;
589
590 zmw_get_wlan_dev(dev);
591
592 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
593
594 txFrameCount = 0;//OS_REG_READ(ah, AR_TFCNT);
595 rxFrameCount = 0;//OS_REG_READ(ah, AR_RFCNT);
596 cycleCount = 0;//OS_REG_READ(ah, AR_CCCNT);
597
598 aniState = HpPriv->curani;
599 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount)
600 {
601 /*
602 * Cycle counter wrap (or initial call); it's not possible
603 * to accurately calculate a value because the registers
604 * right shift rather than wrap--so punt and return 0.
605 */
606 listenTime = 0;
607 HpPriv->stats.ast_ani_lzero++;
608 }
609 else
610 {
611 s32_t ccdelta = cycleCount - aniState->cycleCount;
612 s32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
613 s32_t tfdelta = txFrameCount - aniState->txFrameCount;
614 listenTime = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE;
615 }
616 aniState->cycleCount = cycleCount;
617 aniState->txFrameCount = txFrameCount;
618 aniState->rxFrameCount = rxFrameCount;
619 return listenTime;
620 }
621
622 /*
623 * Do periodic processing. This routine is called from the
624 * driver's rx interrupt handler after processing frames.
625 */
zfHpAniArPoll(zdev_t * dev,u32_t listenTime,u32_t phyCnt1,u32_t phyCnt2)626 void zfHpAniArPoll(zdev_t* dev, u32_t listenTime, u32_t phyCnt1, u32_t phyCnt2)
627 {
628 struct zsAniState *aniState;
629 //s32_t listenTime;
630
631 zmw_get_wlan_dev(dev);
632
633 struct zsHpPriv *HpPriv = (struct zsHpPriv*)wd->hpPrivate;
634
635 /*
636 * Since we're called from end of rx tasklet, we also check for
637 * AR processing now
638 */
639
640 aniState = HpPriv->curani;
641 //HpPriv->stats.ast_nodestats = *stats; /* XXX optimize? */
642
643 //listenTime = zfHpAniGetListenTime(dev);
644 //if (listenTime < 0)
645 //{
646 // HpPriv->stats.ast_ani_lneg++;
647 // /* restart ANI period if listenTime is invalid */
648 // zfHpAniRestart(dev);
649 // return;
650 //}
651 /* XXX beware of overflow? */
652 aniState->listenTime += listenTime;
653
654 if (HpPriv->hasHwPhyCounters)
655 {
656 //u32_t phyCnt1, phyCnt2;
657 u32_t ofdmPhyErrCnt, cckPhyErrCnt;
658
659 /* NB: these are not reset-on-read */
660 //phyCnt1 = 0;//OS_REG_READ(ah, AR_PHY_ERR_1);
661 //phyCnt2 = 0;//OS_REG_READ(ah, AR_PHY_ERR_2);
662 /* XXX sometimes zero, why? */
663 //if (phyCnt1 < aniState->ofdmPhyErrBase ||
664 // phyCnt2 < aniState->cckPhyErrBase)
665 //{
666 // if (phyCnt1 < aniState->ofdmPhyErrBase)
667 // {
668 // zm_debug_msg2("phyCnt1 = 0x", phyCnt1);
669 // zm_debug_msg2("resetting counter value to 0x", aniState->ofdmPhyErrBase);
670 // //OS_REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
671 // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
672 // }
673 // if (phyCnt2 < aniState->cckPhyErrBase)
674 // {
675 // zm_debug_msg2("phyCnt2 = 0x", phyCnt2);
676 // zm_debug_msg2("resetting counter value to 0x", aniState->cckPhyErrBase);
677 // //OS_REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
678 // //OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
679 // }
680 // return; /* XXX */
681 //}
682 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
683 //ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
684 //HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
685 //aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
686 ofdmPhyErrCnt = phyCnt1;
687 HpPriv->stats.ast_ani_ofdmerrs += ofdmPhyErrCnt;
688 aniState->ofdmPhyErrCount += ofdmPhyErrCnt;
689
690 //cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
691 //HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt - aniState->cckPhyErrCount;
692 //aniState->cckPhyErrCount = cckPhyErrCnt;
693 cckPhyErrCnt = phyCnt2;
694 HpPriv->stats.ast_ani_cckerrs += cckPhyErrCnt;
695 aniState->cckPhyErrCount += cckPhyErrCnt;
696 }
697 /*
698 * If ani is not enabled, return after we've collected
699 * statistics
700 */
701 if ((HpPriv->procPhyErr & ZM_HAL_PROCESS_ANI) == 0)
702 return;
703 if (aniState->listenTime > 5 * HpPriv->aniPeriod)
704 {
705 /*
706 * Check to see if need to lower immunity if
707 * 5 aniPeriods have passed
708 */
709 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
710 aniState->ofdmTrigLow/1000 &&
711 aniState->cckPhyErrCount <= aniState->listenTime *
712 aniState->cckTrigLow/1000)
713 zfHpAniLowerImmunity(dev);
714 zfHpAniRestart(dev);
715 }
716 else if (aniState->listenTime > HpPriv->aniPeriod)
717 {
718 /* check to see if need to raise immunity */
719 if (aniState->ofdmPhyErrCount > aniState->listenTime *
720 aniState->ofdmTrigHigh / 1000)
721 {
722 zfHpAniOfdmErrTrigger(dev);
723 zfHpAniRestart(dev);
724 }
725 else if (aniState->cckPhyErrCount > aniState->listenTime *
726 aniState->cckTrigHigh / 1000)
727 {
728 zfHpAniCckErrTrigger(dev);
729 zfHpAniRestart(dev);
730 }
731 }
732 }
733