Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / net / ath / ath9k / ath9k_ani.c
1 /*
2  * Copyright (c) 2008-2011 Atheros Communications Inc.
3  *
4  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
5  * Original from Linux kernel 3.0.1
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19
20 #include "hw.h"
21 #include "hw-ops.h"
22
23 struct ani_ofdm_level_entry {
24         int spur_immunity_level;
25         int fir_step_level;
26         int ofdm_weak_signal_on;
27 };
28
29 /* values here are relative to the INI */
30
31 /*
32  * Legend:
33  *
34  * SI: Spur immunity
35  * FS: FIR Step
36  * WS: OFDM / CCK Weak Signal detection
37  * MRC-CCK: Maximal Ratio Combining for CCK
38  */
39
40 static const struct ani_ofdm_level_entry ofdm_level_table[] = {
41         /* SI  FS  WS */
42         {  0,  0,  1  }, /* lvl 0 */
43         {  1,  1,  1  }, /* lvl 1 */
44         {  2,  2,  1  }, /* lvl 2 */
45         {  3,  2,  1  }, /* lvl 3  (default) */
46         {  4,  3,  1  }, /* lvl 4 */
47         {  5,  4,  1  }, /* lvl 5 */
48         {  6,  5,  1  }, /* lvl 6 */
49         {  7,  6,  1  }, /* lvl 7 */
50         {  7,  7,  1  }, /* lvl 8 */
51         {  7,  8,  0  }  /* lvl 9 */
52 };
53 #define ATH9K_ANI_OFDM_NUM_LEVEL \
54         ARRAY_SIZE(ofdm_level_table)
55 #define ATH9K_ANI_OFDM_MAX_LEVEL \
56         (ATH9K_ANI_OFDM_NUM_LEVEL-1)
57 #define ATH9K_ANI_OFDM_DEF_LEVEL \
58         3 /* default level - matches the INI settings */
59
60 /*
61  * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
62  * With OFDM for single stream you just add up all antenna inputs, you're
63  * only interested in what you get after FFT. Signal aligment is also not
64  * required for OFDM because any phase difference adds up in the frequency
65  * domain.
66  *
67  * MRC requires extra work for use with CCK. You need to align the antenna
68  * signals from the different antenna before you can add the signals together.
69  * You need aligment of signals as CCK is in time domain, so addition can cancel
70  * your signal completely if phase is 180 degrees (think of adding sine waves).
71  * You also need to remove noise before the addition and this is where ANI
72  * MRC CCK comes into play. One of the antenna inputs may be stronger but
73  * lower SNR, so just adding after alignment can be dangerous.
74  *
75  * Regardless of alignment in time, the antenna signals add constructively after
76  * FFT and improve your reception. For more information:
77  *
78  * http://en.wikipedia.org/wiki/Maximal-ratio_combining
79  */
80
81 struct ani_cck_level_entry {
82         int fir_step_level;
83         int mrc_cck_on;
84 };
85
86 static const struct ani_cck_level_entry cck_level_table[] = {
87         /* FS  MRC-CCK  */
88         {  0,  1  }, /* lvl 0 */
89         {  1,  1  }, /* lvl 1 */
90         {  2,  1  }, /* lvl 2  (default) */
91         {  3,  1  }, /* lvl 3 */
92         {  4,  0  }, /* lvl 4 */
93         {  5,  0  }, /* lvl 5 */
94         {  6,  0  }, /* lvl 6 */
95         {  7,  0  }, /* lvl 7 (only for high rssi) */
96         {  8,  0  }  /* lvl 8 (only for high rssi) */
97 };
98
99 #define ATH9K_ANI_CCK_NUM_LEVEL \
100         ARRAY_SIZE(cck_level_table)
101 #define ATH9K_ANI_CCK_MAX_LEVEL \
102         (ATH9K_ANI_CCK_NUM_LEVEL-1)
103 #define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
104         (ATH9K_ANI_CCK_NUM_LEVEL-3)
105 #define ATH9K_ANI_CCK_DEF_LEVEL \
106         2 /* default level - matches the INI settings */
107
108 static int use_new_ani(struct ath_hw *ah)
109 {
110         return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
111 }
112
113 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
114                                      struct ath9k_mib_stats *stats)
115 {
116         stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
117         stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
118         stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
119         stats->rts_good += REG_READ(ah, AR_RTS_OK);
120         stats->beacons += REG_READ(ah, AR_BEACON_CNT);
121 }
122
123 static void ath9k_ani_restart(struct ath_hw *ah)
124 {
125         struct ar5416AniState *aniState;
126         u32 ofdm_base = 0, cck_base = 0;
127
128         if (!DO_ANI(ah))
129                 return;
130
131         aniState = &ah->curchan->ani;
132         aniState->listenTime = 0;
133
134         if (!use_new_ani(ah)) {
135                 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
136                 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
137         }
138
139         DBG2("ath9k: "
140                 "Writing ofdmbase=%d   cckbase=%d\n", ofdm_base, cck_base);
141
142         ENABLE_REGWRITE_BUFFER(ah);
143
144         REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
145         REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
146         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
147         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
148
149         REGWRITE_BUFFER_FLUSH(ah);
150
151         ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
152
153         aniState->ofdmPhyErrCount = 0;
154         aniState->cckPhyErrCount = 0;
155 }
156
157 static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
158 {
159         struct ar5416AniState *aniState;
160         int32_t rssi;
161
162         aniState = &ah->curchan->ani;
163
164         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
165                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
166                                          aniState->noiseImmunityLevel + 1)) {
167                         return;
168                 }
169         }
170
171         if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
172                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
173                                          aniState->spurImmunityLevel + 1)) {
174                         return;
175                 }
176         }
177
178         rssi = BEACON_RSSI(ah);
179         if (rssi > aniState->rssiThrHigh) {
180                 if (!aniState->ofdmWeakSigDetectOff) {
181                         if (ath9k_hw_ani_control(ah,
182                                          ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
183                                          0)) {
184                                 ath9k_hw_ani_control(ah,
185                                         ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
186                                 return;
187                         }
188                 }
189                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
190                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
191                                              aniState->firstepLevel + 1);
192                         return;
193                 }
194         } else if (rssi > aniState->rssiThrLow) {
195                 if (aniState->ofdmWeakSigDetectOff)
196                         ath9k_hw_ani_control(ah,
197                                      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
198                                      1);
199                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
200                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
201                                              aniState->firstepLevel + 1);
202                 return;
203         } else {
204                 if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
205                         if (!aniState->ofdmWeakSigDetectOff)
206                                 ath9k_hw_ani_control(ah,
207                                      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
208                                      0);
209                         if (aniState->firstepLevel > 0)
210                                 ath9k_hw_ani_control(ah,
211                                              ATH9K_ANI_FIRSTEP_LEVEL, 0);
212                         return;
213                 }
214         }
215 }
216
217 static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
218 {
219         struct ar5416AniState *aniState;
220         int32_t rssi;
221
222         aniState = &ah->curchan->ani;
223         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
224                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
225                                          aniState->noiseImmunityLevel + 1)) {
226                         return;
227                 }
228         }
229         rssi = BEACON_RSSI(ah);
230         if (rssi > aniState->rssiThrLow) {
231                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
232                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
233                                              aniState->firstepLevel + 1);
234         } else {
235                 if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
236                         if (aniState->firstepLevel > 0)
237                                 ath9k_hw_ani_control(ah,
238                                              ATH9K_ANI_FIRSTEP_LEVEL, 0);
239                 }
240         }
241 }
242
243 /* Adjust the OFDM Noise Immunity Level */
244 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
245 {
246         struct ar5416AniState *aniState = &ah->curchan->ani;
247         const struct ani_ofdm_level_entry *entry_ofdm;
248         const struct ani_cck_level_entry *entry_cck;
249
250         aniState->noiseFloor = BEACON_RSSI(ah);
251
252         DBG2("ath9k: "
253                 "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
254                 aniState->ofdmNoiseImmunityLevel,
255                 immunityLevel, aniState->noiseFloor,
256                 aniState->rssiThrLow, aniState->rssiThrHigh);
257
258         aniState->ofdmNoiseImmunityLevel = immunityLevel;
259
260         entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
261         entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
262
263         if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
264                 ath9k_hw_ani_control(ah,
265                                      ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
266                                      entry_ofdm->spur_immunity_level);
267
268         if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
269             entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
270                 ath9k_hw_ani_control(ah,
271                                      ATH9K_ANI_FIRSTEP_LEVEL,
272                                      entry_ofdm->fir_step_level);
273 }
274
275 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
276 {
277         struct ar5416AniState *aniState;
278
279         if (!DO_ANI(ah))
280                 return;
281
282         if (!use_new_ani(ah)) {
283                 ath9k_hw_ani_ofdm_err_trigger_old(ah);
284                 return;
285         }
286
287         aniState = &ah->curchan->ani;
288
289         if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
290                 ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
291 }
292
293 /*
294  * Set the ANI settings to match an CCK level.
295  */
296 static void ath9k_hw_set_cck_nil(struct ath_hw *ah, uint8_t immunityLevel)
297 {
298         struct ar5416AniState *aniState = &ah->curchan->ani;
299         const struct ani_ofdm_level_entry *entry_ofdm;
300         const struct ani_cck_level_entry *entry_cck;
301
302         aniState->noiseFloor = BEACON_RSSI(ah);
303         DBG2("ath9k: "
304                 "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
305                 aniState->cckNoiseImmunityLevel, immunityLevel,
306                 aniState->noiseFloor, aniState->rssiThrLow,
307                 aniState->rssiThrHigh);
308
309         if (aniState->noiseFloor <= (unsigned int)aniState->rssiThrLow &&
310             immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
311                 immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
312
313         aniState->cckNoiseImmunityLevel = immunityLevel;
314
315         entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
316         entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
317
318         if (aniState->firstepLevel != entry_cck->fir_step_level &&
319             entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
320                 ath9k_hw_ani_control(ah,
321                                      ATH9K_ANI_FIRSTEP_LEVEL,
322                                      entry_cck->fir_step_level);
323
324         /* Skip MRC CCK for pre AR9003 families */
325         if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
326                 return;
327
328         if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
329                 ath9k_hw_ani_control(ah,
330                                      ATH9K_ANI_MRC_CCK,
331                                      entry_cck->mrc_cck_on);
332 }
333
334 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
335 {
336         struct ar5416AniState *aniState;
337
338         if (!DO_ANI(ah))
339                 return;
340
341         if (!use_new_ani(ah)) {
342                 ath9k_hw_ani_cck_err_trigger_old(ah);
343                 return;
344         }
345
346         aniState = &ah->curchan->ani;
347
348         if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
349                 ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
350 }
351
352 static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
353 {
354         struct ar5416AniState *aniState;
355         int32_t rssi;
356
357         aniState = &ah->curchan->ani;
358
359         rssi = BEACON_RSSI(ah);
360         if (rssi > aniState->rssiThrHigh) {
361                 /* XXX: Handle me */
362         } else if (rssi > aniState->rssiThrLow) {
363                 if (aniState->ofdmWeakSigDetectOff) {
364                         if (ath9k_hw_ani_control(ah,
365                                  ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
366                                  1) == 1)
367                                 return;
368                 }
369                 if (aniState->firstepLevel > 0) {
370                         if (ath9k_hw_ani_control(ah,
371                                  ATH9K_ANI_FIRSTEP_LEVEL,
372                                  aniState->firstepLevel - 1) == 1)
373                                 return;
374                 }
375         } else {
376                 if (aniState->firstepLevel > 0) {
377                         if (ath9k_hw_ani_control(ah,
378                                  ATH9K_ANI_FIRSTEP_LEVEL,
379                                  aniState->firstepLevel - 1) == 1)
380                                 return;
381                 }
382         }
383
384         if (aniState->spurImmunityLevel > 0) {
385                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
386                                          aniState->spurImmunityLevel - 1))
387                         return;
388         }
389
390         if (aniState->noiseImmunityLevel > 0) {
391                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
392                                      aniState->noiseImmunityLevel - 1);
393                 return;
394         }
395 }
396
397 /*
398  * only lower either OFDM or CCK errors per turn
399  * we lower the other one next time
400  */
401 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
402 {
403         struct ar5416AniState *aniState;
404
405         aniState = &ah->curchan->ani;
406
407         if (!use_new_ani(ah)) {
408                 ath9k_hw_ani_lower_immunity_old(ah);
409                 return;
410         }
411
412         /* lower OFDM noise immunity */
413         if (aniState->ofdmNoiseImmunityLevel > 0 &&
414             (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
415                 ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
416                 return;
417         }
418
419         /* lower CCK noise immunity */
420         if (aniState->cckNoiseImmunityLevel > 0)
421                 ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
422 }
423
424 static void ath9k_ani_reset_old(struct ath_hw *ah)
425 {
426         struct ar5416AniState *aniState;
427
428         if (!DO_ANI(ah))
429                 return;
430
431         aniState = &ah->curchan->ani;
432
433         if (aniState->noiseImmunityLevel != 0)
434                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
435                                      aniState->noiseImmunityLevel);
436         if (aniState->spurImmunityLevel != 0)
437                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
438                                      aniState->spurImmunityLevel);
439         if (aniState->ofdmWeakSigDetectOff)
440                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
441                                      !aniState->ofdmWeakSigDetectOff);
442         if (aniState->cckWeakSigThreshold)
443                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
444                                      aniState->cckWeakSigThreshold);
445         if (aniState->firstepLevel != 0)
446                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
447                                      aniState->firstepLevel);
448
449         ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
450                              ~ATH9K_RX_FILTER_PHYERR);
451         ath9k_ani_restart(ah);
452
453         ENABLE_REGWRITE_BUFFER(ah);
454
455         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
456         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
457
458         REGWRITE_BUFFER_FLUSH(ah);
459 }
460
461 /*
462  * Restore the ANI parameters in the HAL and reset the statistics.
463  * This routine should be called for every hardware reset and for
464  * every channel change.
465  */
466 void ath9k_ani_reset(struct ath_hw *ah, int is_scanning)
467 {
468         struct ar5416AniState *aniState = &ah->curchan->ani;
469         struct ath9k_channel *chan = ah->curchan;
470
471         if (!DO_ANI(ah))
472                 return;
473
474         if (!use_new_ani(ah))
475                 return ath9k_ani_reset_old(ah);
476
477         ah->stats.ast_ani_reset++;
478
479         /* always allow mode (on/off) to be controlled */
480         ah->ani_function |= ATH9K_ANI_MODE;
481
482         if (is_scanning) {
483                 /*
484                  * If we're scanning or in AP mode, the defaults (ini)
485                  * should be in place. For an AP we assume the historical
486                  * levels for this channel are probably outdated so start
487                  * from defaults instead.
488                  */
489                 if (aniState->ofdmNoiseImmunityLevel !=
490                     ATH9K_ANI_OFDM_DEF_LEVEL ||
491                     aniState->cckNoiseImmunityLevel !=
492                     ATH9K_ANI_CCK_DEF_LEVEL) {
493                         DBG("ath9k: "
494                                 "Restore defaults: chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
495                                 chan->channel,
496                                 chan->channelFlags,
497                                 is_scanning,
498                                 aniState->ofdmNoiseImmunityLevel,
499                                 aniState->cckNoiseImmunityLevel);
500
501                         ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
502                         ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
503                 }
504         } else {
505                 /*
506                  * restore historical levels for this channel
507                  */
508                 DBG2("ath9k: "
509                         "Restore history: chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
510                         chan->channel,
511                         chan->channelFlags,
512                         is_scanning,
513                         aniState->ofdmNoiseImmunityLevel,
514                         aniState->cckNoiseImmunityLevel);
515
516                         ath9k_hw_set_ofdm_nil(ah,
517                                               aniState->ofdmNoiseImmunityLevel);
518                         ath9k_hw_set_cck_nil(ah,
519                                              aniState->cckNoiseImmunityLevel);
520         }
521
522         /*
523          * enable phy counters if hw supports or if not, enable phy
524          * interrupts (so we can count each one)
525          */
526         ath9k_ani_restart(ah);
527
528         ENABLE_REGWRITE_BUFFER(ah);
529
530         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
531         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
532
533         REGWRITE_BUFFER_FLUSH(ah);
534 }
535
536 static int ath9k_hw_ani_read_counters(struct ath_hw *ah)
537 {
538         struct ath_common *common = ath9k_hw_common(ah);
539         struct ar5416AniState *aniState = &ah->curchan->ani;
540         u32 ofdm_base = 0;
541         u32 cck_base = 0;
542         u32 ofdmPhyErrCnt, cckPhyErrCnt;
543         u32 phyCnt1, phyCnt2;
544         int32_t listenTime;
545
546         ath_hw_cycle_counters_update(common);
547         listenTime = ath_hw_get_listen_time(common);
548
549         if (listenTime <= 0) {
550                 ah->stats.ast_ani_lneg++;
551                 ath9k_ani_restart(ah);
552                 return 0;
553         }
554
555         if (!use_new_ani(ah)) {
556                 ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
557                 cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
558         }
559
560         aniState->listenTime += listenTime;
561
562         phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
563         phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
564
565         if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
566                 if (phyCnt1 < ofdm_base) {
567                         DBG2("ath9k: "
568                                 "phyCnt1 0x%x, resetting counter value to 0x%x\n",
569                                 phyCnt1, ofdm_base);
570                         REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
571                         REG_WRITE(ah, AR_PHY_ERR_MASK_1,
572                                   AR_PHY_ERR_OFDM_TIMING);
573                 }
574                 if (phyCnt2 < cck_base) {
575                         DBG2("ath9k: "
576                                 "phyCnt2 0x%x, resetting counter value to 0x%x\n",
577                                 phyCnt2, cck_base);
578                         REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
579                         REG_WRITE(ah, AR_PHY_ERR_MASK_2,
580                                   AR_PHY_ERR_CCK_TIMING);
581                 }
582                 return 0;
583         }
584
585         ofdmPhyErrCnt = phyCnt1 - ofdm_base;
586         ah->stats.ast_ani_ofdmerrs +=
587                 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
588         aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
589
590         cckPhyErrCnt = phyCnt2 - cck_base;
591         ah->stats.ast_ani_cckerrs +=
592                 cckPhyErrCnt - aniState->cckPhyErrCount;
593         aniState->cckPhyErrCount = cckPhyErrCnt;
594         return 1;
595 }
596
597 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan __unused)
598 {
599         struct ar5416AniState *aniState;
600         u32 ofdmPhyErrRate, cckPhyErrRate;
601
602         if (!DO_ANI(ah))
603                 return;
604
605         aniState = &ah->curchan->ani;
606         if (!aniState)
607                 return;
608
609         if (!ath9k_hw_ani_read_counters(ah))
610                 return;
611
612         ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
613                          aniState->listenTime;
614         cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
615                          aniState->listenTime;
616
617         DBG2("ath9k: "
618                 "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
619                 aniState->listenTime,
620                 aniState->ofdmNoiseImmunityLevel,
621                 ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
622                 cckPhyErrRate, aniState->ofdmsTurn);
623
624         if (aniState->listenTime > 5 * ah->aniperiod) {
625                 if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
626                     cckPhyErrRate <= ah->config.cck_trig_low) {
627                         ath9k_hw_ani_lower_immunity(ah);
628                         aniState->ofdmsTurn = !aniState->ofdmsTurn;
629                 }
630                 ath9k_ani_restart(ah);
631         } else if (aniState->listenTime > ah->aniperiod) {
632                 /* check to see if need to raise immunity */
633                 if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
634                     (cckPhyErrRate <= ah->config.cck_trig_high ||
635                      aniState->ofdmsTurn)) {
636                         ath9k_hw_ani_ofdm_err_trigger(ah);
637                         ath9k_ani_restart(ah);
638                         aniState->ofdmsTurn = 0;
639                 } else if (cckPhyErrRate > ah->config.cck_trig_high) {
640                         ath9k_hw_ani_cck_err_trigger(ah);
641                         ath9k_ani_restart(ah);
642                         aniState->ofdmsTurn = 1;
643                 }
644         }
645 }
646
647 void ath9k_hw_ani_setup(struct ath_hw *ah)
648 {
649         int i;
650
651         static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
652         static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
653         static const int coarseLow[] = { -64, -64, -64, -64, -70 };
654         static const int firpwr[] = { -78, -78, -78, -78, -80 };
655
656         for (i = 0; i < 5; i++) {
657                 ah->totalSizeDesired[i] = totalSizeDesired[i];
658                 ah->coarse_high[i] = coarseHigh[i];
659                 ah->coarse_low[i] = coarseLow[i];
660                 ah->firpwr[i] = firpwr[i];
661         }
662 }
663
664 void ath9k_hw_ani_init(struct ath_hw *ah)
665 {
666         unsigned int i;
667
668         DBG2("ath9k: Initialize ANI\n");
669
670         if (use_new_ani(ah)) {
671                 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
672                 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
673
674                 ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
675                 ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
676         } else {
677                 ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
678                 ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
679
680                 ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
681                 ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
682         }
683
684         for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
685                 struct ath9k_channel *chan = &ah->channels[i];
686                 struct ar5416AniState *ani = &chan->ani;
687
688                 if (use_new_ani(ah)) {
689                         ani->spurImmunityLevel =
690                                 ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
691
692                         ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
693
694                         if (AR_SREV_9300_20_OR_LATER(ah))
695                                 ani->mrcCCKOff =
696                                         !ATH9K_ANI_ENABLE_MRC_CCK;
697                         else
698                                 ani->mrcCCKOff = 1;
699
700                         ani->ofdmsTurn = 1;
701                 } else {
702                         ani->spurImmunityLevel =
703                                 ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
704                         ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
705
706                         ani->cckWeakSigThreshold =
707                                 ATH9K_ANI_CCK_WEAK_SIG_THR;
708                 }
709
710                 ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
711                 ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
712                 ani->ofdmWeakSigDetectOff =
713                         !ATH9K_ANI_USE_OFDM_WEAK_SIG;
714                 ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
715         }
716
717         /*
718          * since we expect some ongoing maintenance on the tables, let's sanity
719          * check here default level should not modify INI setting.
720          */
721         if (use_new_ani(ah)) {
722                 ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
723                 ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
724         } else {
725                 ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
726                 ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
727         }
728
729         if (ah->config.enable_ani)
730                 ah->proc_phyerr |= HAL_PROCESS_ANI;
731
732         ath9k_ani_restart(ah);
733 }