]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/net/wireless/ath/ath9k/ani.c
ath9k: describe hw initialization better
[linux-2.6.git] / drivers / net / wireless / ath / ath9k / ani.c
1 /*
2  * Copyright (c) 2008-2009 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
17 #include "ath9k.h"
18
19 static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
20                                         struct ath9k_channel *chan)
21 {
22         int i;
23
24         for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
25                 if (ah->ani[i].c &&
26                     ah->ani[i].c->channel == chan->channel)
27                         return i;
28                 if (ah->ani[i].c == NULL) {
29                         ah->ani[i].c = chan;
30                         return i;
31                 }
32         }
33
34         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
35                 "No more channel states left. Using channel 0\n");
36
37         return 0;
38 }
39
40 static bool ath9k_hw_ani_control(struct ath_hw *ah,
41                                  enum ath9k_ani_cmd cmd, int param)
42 {
43         struct ar5416AniState *aniState = ah->curani;
44
45         switch (cmd & ah->ani_function) {
46         case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
47                 u32 level = param;
48
49                 if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
50                         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
51                                 "level out of range (%u > %u)\n",
52                                 level,
53                                 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
54                         return false;
55                 }
56
57                 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
58                               AR_PHY_DESIRED_SZ_TOT_DES,
59                               ah->totalSizeDesired[level]);
60                 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
61                               AR_PHY_AGC_CTL1_COARSE_LOW,
62                               ah->coarse_low[level]);
63                 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
64                               AR_PHY_AGC_CTL1_COARSE_HIGH,
65                               ah->coarse_high[level]);
66                 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
67                               AR_PHY_FIND_SIG_FIRPWR,
68                               ah->firpwr[level]);
69
70                 if (level > aniState->noiseImmunityLevel)
71                         ah->stats.ast_ani_niup++;
72                 else if (level < aniState->noiseImmunityLevel)
73                         ah->stats.ast_ani_nidown++;
74                 aniState->noiseImmunityLevel = level;
75                 break;
76         }
77         case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
78                 const int m1ThreshLow[] = { 127, 50 };
79                 const int m2ThreshLow[] = { 127, 40 };
80                 const int m1Thresh[] = { 127, 0x4d };
81                 const int m2Thresh[] = { 127, 0x40 };
82                 const int m2CountThr[] = { 31, 16 };
83                 const int m2CountThrLow[] = { 63, 48 };
84                 u32 on = param ? 1 : 0;
85
86                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
87                               AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
88                               m1ThreshLow[on]);
89                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
90                               AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
91                               m2ThreshLow[on]);
92                 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
93                               AR_PHY_SFCORR_M1_THRESH,
94                               m1Thresh[on]);
95                 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
96                               AR_PHY_SFCORR_M2_THRESH,
97                               m2Thresh[on]);
98                 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
99                               AR_PHY_SFCORR_M2COUNT_THR,
100                               m2CountThr[on]);
101                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
102                               AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
103                               m2CountThrLow[on]);
104
105                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
106                               AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
107                               m1ThreshLow[on]);
108                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
109                               AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
110                               m2ThreshLow[on]);
111                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
112                               AR_PHY_SFCORR_EXT_M1_THRESH,
113                               m1Thresh[on]);
114                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
115                               AR_PHY_SFCORR_EXT_M2_THRESH,
116                               m2Thresh[on]);
117
118                 if (on)
119                         REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
120                                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
121                 else
122                         REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
123                                     AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
124
125                 if (!on != aniState->ofdmWeakSigDetectOff) {
126                         if (on)
127                                 ah->stats.ast_ani_ofdmon++;
128                         else
129                                 ah->stats.ast_ani_ofdmoff++;
130                         aniState->ofdmWeakSigDetectOff = !on;
131                 }
132                 break;
133         }
134         case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
135                 const int weakSigThrCck[] = { 8, 6 };
136                 u32 high = param ? 1 : 0;
137
138                 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
139                               AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
140                               weakSigThrCck[high]);
141                 if (high != aniState->cckWeakSigThreshold) {
142                         if (high)
143                                 ah->stats.ast_ani_cckhigh++;
144                         else
145                                 ah->stats.ast_ani_ccklow++;
146                         aniState->cckWeakSigThreshold = high;
147                 }
148                 break;
149         }
150         case ATH9K_ANI_FIRSTEP_LEVEL:{
151                 const int firstep[] = { 0, 4, 8 };
152                 u32 level = param;
153
154                 if (level >= ARRAY_SIZE(firstep)) {
155                         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
156                                 "level out of range (%u > %u)\n",
157                                 level,
158                                 (unsigned) ARRAY_SIZE(firstep));
159                         return false;
160                 }
161                 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
162                               AR_PHY_FIND_SIG_FIRSTEP,
163                               firstep[level]);
164                 if (level > aniState->firstepLevel)
165                         ah->stats.ast_ani_stepup++;
166                 else if (level < aniState->firstepLevel)
167                         ah->stats.ast_ani_stepdown++;
168                 aniState->firstepLevel = level;
169                 break;
170         }
171         case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
172                 const int cycpwrThr1[] =
173                         { 2, 4, 6, 8, 10, 12, 14, 16 };
174                 u32 level = param;
175
176                 if (level >= ARRAY_SIZE(cycpwrThr1)) {
177                         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
178                                 "level out of range (%u > %u)\n",
179                                 level,
180                                 (unsigned)
181                                 ARRAY_SIZE(cycpwrThr1));
182                         return false;
183                 }
184                 REG_RMW_FIELD(ah, AR_PHY_TIMING5,
185                               AR_PHY_TIMING5_CYCPWR_THR1,
186                               cycpwrThr1[level]);
187                 if (level > aniState->spurImmunityLevel)
188                         ah->stats.ast_ani_spurup++;
189                 else if (level < aniState->spurImmunityLevel)
190                         ah->stats.ast_ani_spurdown++;
191                 aniState->spurImmunityLevel = level;
192                 break;
193         }
194         case ATH9K_ANI_PRESENT:
195                 break;
196         default:
197                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
198                         "invalid cmd %u\n", cmd);
199                 return false;
200         }
201
202         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
203         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
204                 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
205                 "ofdmWeakSigDetectOff=%d\n",
206                 aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
207                 !aniState->ofdmWeakSigDetectOff);
208         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
209                 "cckWeakSigThreshold=%d, "
210                 "firstepLevel=%d, listenTime=%d\n",
211                 aniState->cckWeakSigThreshold, aniState->firstepLevel,
212                 aniState->listenTime);
213         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
214                 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
215                 aniState->cycleCount, aniState->ofdmPhyErrCount,
216                 aniState->cckPhyErrCount);
217
218         return true;
219 }
220
221 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
222                                      struct ath9k_mib_stats *stats)
223 {
224         stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
225         stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
226         stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
227         stats->rts_good += REG_READ(ah, AR_RTS_OK);
228         stats->beacons += REG_READ(ah, AR_BEACON_CNT);
229 }
230
231 static void ath9k_ani_restart(struct ath_hw *ah)
232 {
233         struct ar5416AniState *aniState;
234
235         if (!DO_ANI(ah))
236                 return;
237
238         aniState = ah->curani;
239
240         aniState->listenTime = 0;
241         if (ah->has_hw_phycounters) {
242                 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
243                         aniState->ofdmPhyErrBase = 0;
244                         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
245                                 "OFDM Trigger is too high for hw counters\n");
246                 } else {
247                         aniState->ofdmPhyErrBase =
248                                 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
249                 }
250                 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
251                         aniState->cckPhyErrBase = 0;
252                         DPRINTF(ah->ah_sc, ATH_DBG_ANI,
253                                 "CCK Trigger is too high for hw counters\n");
254                 } else {
255                         aniState->cckPhyErrBase =
256                                 AR_PHY_COUNTMAX - aniState->cckTrigHigh;
257                 }
258                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
259                         "Writing ofdmbase=%u   cckbase=%u\n",
260                         aniState->ofdmPhyErrBase,
261                         aniState->cckPhyErrBase);
262                 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
263                 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
264                 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
265                 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
266
267                 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
268         }
269         aniState->ofdmPhyErrCount = 0;
270         aniState->cckPhyErrCount = 0;
271 }
272
273 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
274 {
275         struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
276         struct ar5416AniState *aniState;
277         int32_t rssi;
278
279         if (!DO_ANI(ah))
280                 return;
281
282         aniState = ah->curani;
283
284         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
285                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
286                                          aniState->noiseImmunityLevel + 1)) {
287                         return;
288                 }
289         }
290
291         if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
292                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
293                                          aniState->spurImmunityLevel + 1)) {
294                         return;
295                 }
296         }
297
298         if (ah->opmode == NL80211_IFTYPE_AP) {
299                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
300                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
301                                              aniState->firstepLevel + 1);
302                 }
303                 return;
304         }
305         rssi = BEACON_RSSI(ah);
306         if (rssi > aniState->rssiThrHigh) {
307                 if (!aniState->ofdmWeakSigDetectOff) {
308                         if (ath9k_hw_ani_control(ah,
309                                          ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
310                                          false)) {
311                                 ath9k_hw_ani_control(ah,
312                                         ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
313                                 return;
314                         }
315                 }
316                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
317                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
318                                              aniState->firstepLevel + 1);
319                         return;
320                 }
321         } else if (rssi > aniState->rssiThrLow) {
322                 if (aniState->ofdmWeakSigDetectOff)
323                         ath9k_hw_ani_control(ah,
324                                      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
325                                      true);
326                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
327                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
328                                              aniState->firstepLevel + 1);
329                 return;
330         } else {
331                 if (conf->channel->band == IEEE80211_BAND_2GHZ) {
332                         if (!aniState->ofdmWeakSigDetectOff)
333                                 ath9k_hw_ani_control(ah,
334                                      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
335                                      false);
336                         if (aniState->firstepLevel > 0)
337                                 ath9k_hw_ani_control(ah,
338                                              ATH9K_ANI_FIRSTEP_LEVEL, 0);
339                         return;
340                 }
341         }
342 }
343
344 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
345 {
346         struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
347         struct ar5416AniState *aniState;
348         int32_t rssi;
349
350         if (!DO_ANI(ah))
351                 return;
352
353         aniState = ah->curani;
354         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
355                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
356                                          aniState->noiseImmunityLevel + 1)) {
357                         return;
358                 }
359         }
360         if (ah->opmode == NL80211_IFTYPE_AP) {
361                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
362                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
363                                              aniState->firstepLevel + 1);
364                 }
365                 return;
366         }
367         rssi = BEACON_RSSI(ah);
368         if (rssi > aniState->rssiThrLow) {
369                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
370                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
371                                              aniState->firstepLevel + 1);
372         } else {
373                 if (conf->channel->band == IEEE80211_BAND_2GHZ) {
374                         if (aniState->firstepLevel > 0)
375                                 ath9k_hw_ani_control(ah,
376                                              ATH9K_ANI_FIRSTEP_LEVEL, 0);
377                 }
378         }
379 }
380
381 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
382 {
383         struct ar5416AniState *aniState;
384         int32_t rssi;
385
386         aniState = ah->curani;
387
388         if (ah->opmode == NL80211_IFTYPE_AP) {
389                 if (aniState->firstepLevel > 0) {
390                         if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
391                                                  aniState->firstepLevel - 1))
392                                 return;
393                 }
394         } else {
395                 rssi = BEACON_RSSI(ah);
396                 if (rssi > aniState->rssiThrHigh) {
397                         /* XXX: Handle me */
398                 } else if (rssi > aniState->rssiThrLow) {
399                         if (aniState->ofdmWeakSigDetectOff) {
400                                 if (ath9k_hw_ani_control(ah,
401                                          ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
402                                          true) == true)
403                                         return;
404                         }
405                         if (aniState->firstepLevel > 0) {
406                                 if (ath9k_hw_ani_control(ah,
407                                          ATH9K_ANI_FIRSTEP_LEVEL,
408                                          aniState->firstepLevel - 1) == true)
409                                         return;
410                         }
411                 } else {
412                         if (aniState->firstepLevel > 0) {
413                                 if (ath9k_hw_ani_control(ah,
414                                          ATH9K_ANI_FIRSTEP_LEVEL,
415                                          aniState->firstepLevel - 1) == true)
416                                         return;
417                         }
418                 }
419         }
420
421         if (aniState->spurImmunityLevel > 0) {
422                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
423                                          aniState->spurImmunityLevel - 1))
424                         return;
425         }
426
427         if (aniState->noiseImmunityLevel > 0) {
428                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
429                                      aniState->noiseImmunityLevel - 1);
430                 return;
431         }
432 }
433
434 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
435 {
436         struct ar5416AniState *aniState;
437         u32 txFrameCount, rxFrameCount, cycleCount;
438         int32_t listenTime;
439
440         txFrameCount = REG_READ(ah, AR_TFCNT);
441         rxFrameCount = REG_READ(ah, AR_RFCNT);
442         cycleCount = REG_READ(ah, AR_CCCNT);
443
444         aniState = ah->curani;
445         if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
446
447                 listenTime = 0;
448                 ah->stats.ast_ani_lzero++;
449         } else {
450                 int32_t ccdelta = cycleCount - aniState->cycleCount;
451                 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
452                 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
453                 listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
454         }
455         aniState->cycleCount = cycleCount;
456         aniState->txFrameCount = txFrameCount;
457         aniState->rxFrameCount = rxFrameCount;
458
459         return listenTime;
460 }
461
462 void ath9k_ani_reset(struct ath_hw *ah)
463 {
464         struct ar5416AniState *aniState;
465         struct ath9k_channel *chan = ah->curchan;
466         int index;
467
468         if (!DO_ANI(ah))
469                 return;
470
471         index = ath9k_hw_get_ani_channel_idx(ah, chan);
472         aniState = &ah->ani[index];
473         ah->curani = aniState;
474
475         if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
476             && ah->opmode != NL80211_IFTYPE_ADHOC) {
477                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
478                         "Reset ANI state opmode %u\n", ah->opmode);
479                 ah->stats.ast_ani_reset++;
480
481                 if (ah->opmode == NL80211_IFTYPE_AP) {
482                         /*
483                          * ath9k_hw_ani_control() will only process items set on
484                          * ah->ani_function
485                          */
486                         if (IS_CHAN_2GHZ(chan))
487                                 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
488                                                     ATH9K_ANI_FIRSTEP_LEVEL);
489                         else
490                                 ah->ani_function = 0;
491                 }
492
493                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
494                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
495                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
496                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
497                                      !ATH9K_ANI_USE_OFDM_WEAK_SIG);
498                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
499                                      ATH9K_ANI_CCK_WEAK_SIG_THR);
500
501                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
502                                      ATH9K_RX_FILTER_PHYERR);
503
504                 if (ah->opmode == NL80211_IFTYPE_AP) {
505                         ah->curani->ofdmTrigHigh =
506                                 ah->config.ofdm_trig_high;
507                         ah->curani->ofdmTrigLow =
508                                 ah->config.ofdm_trig_low;
509                         ah->curani->cckTrigHigh =
510                                 ah->config.cck_trig_high;
511                         ah->curani->cckTrigLow =
512                                 ah->config.cck_trig_low;
513                 }
514                 ath9k_ani_restart(ah);
515                 return;
516         }
517
518         if (aniState->noiseImmunityLevel != 0)
519                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
520                                      aniState->noiseImmunityLevel);
521         if (aniState->spurImmunityLevel != 0)
522                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
523                                      aniState->spurImmunityLevel);
524         if (aniState->ofdmWeakSigDetectOff)
525                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
526                                      !aniState->ofdmWeakSigDetectOff);
527         if (aniState->cckWeakSigThreshold)
528                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
529                                      aniState->cckWeakSigThreshold);
530         if (aniState->firstepLevel != 0)
531                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
532                                      aniState->firstepLevel);
533         if (ah->has_hw_phycounters) {
534                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
535                                      ~ATH9K_RX_FILTER_PHYERR);
536                 ath9k_ani_restart(ah);
537                 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
538                 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
539
540         } else {
541                 ath9k_ani_restart(ah);
542                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
543                                      ATH9K_RX_FILTER_PHYERR);
544         }
545 }
546
547 void ath9k_hw_ani_monitor(struct ath_hw *ah,
548                           const struct ath9k_node_stats *stats,
549                           struct ath9k_channel *chan)
550 {
551         struct ar5416AniState *aniState;
552         int32_t listenTime;
553
554         if (!DO_ANI(ah))
555                 return;
556
557         aniState = ah->curani;
558         ah->stats.ast_nodestats = *stats;
559
560         listenTime = ath9k_hw_ani_get_listen_time(ah);
561         if (listenTime < 0) {
562                 ah->stats.ast_ani_lneg++;
563                 ath9k_ani_restart(ah);
564                 return;
565         }
566
567         aniState->listenTime += listenTime;
568
569         if (ah->has_hw_phycounters) {
570                 u32 phyCnt1, phyCnt2;
571                 u32 ofdmPhyErrCnt, cckPhyErrCnt;
572
573                 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
574
575                 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
576                 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
577
578                 if (phyCnt1 < aniState->ofdmPhyErrBase ||
579                     phyCnt2 < aniState->cckPhyErrBase) {
580                         if (phyCnt1 < aniState->ofdmPhyErrBase) {
581                                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
582                                         "phyCnt1 0x%x, resetting "
583                                         "counter value to 0x%x\n",
584                                         phyCnt1, aniState->ofdmPhyErrBase);
585                                 REG_WRITE(ah, AR_PHY_ERR_1,
586                                           aniState->ofdmPhyErrBase);
587                                 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
588                                           AR_PHY_ERR_OFDM_TIMING);
589                         }
590                         if (phyCnt2 < aniState->cckPhyErrBase) {
591                                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
592                                         "phyCnt2 0x%x, resetting "
593                                         "counter value to 0x%x\n",
594                                         phyCnt2, aniState->cckPhyErrBase);
595                                 REG_WRITE(ah, AR_PHY_ERR_2,
596                                           aniState->cckPhyErrBase);
597                                 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
598                                           AR_PHY_ERR_CCK_TIMING);
599                         }
600                         return;
601                 }
602
603                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
604                 ah->stats.ast_ani_ofdmerrs +=
605                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
606                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
607
608                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
609                 ah->stats.ast_ani_cckerrs +=
610                         cckPhyErrCnt - aniState->cckPhyErrCount;
611                 aniState->cckPhyErrCount = cckPhyErrCnt;
612         }
613
614         if (aniState->listenTime > 5 * ah->aniperiod) {
615                 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
616                     aniState->ofdmTrigLow / 1000 &&
617                     aniState->cckPhyErrCount <= aniState->listenTime *
618                     aniState->cckTrigLow / 1000)
619                         ath9k_hw_ani_lower_immunity(ah);
620                 ath9k_ani_restart(ah);
621         } else if (aniState->listenTime > ah->aniperiod) {
622                 if (aniState->ofdmPhyErrCount > aniState->listenTime *
623                     aniState->ofdmTrigHigh / 1000) {
624                         ath9k_hw_ani_ofdm_err_trigger(ah);
625                         ath9k_ani_restart(ah);
626                 } else if (aniState->cckPhyErrCount >
627                            aniState->listenTime * aniState->cckTrigHigh /
628                            1000) {
629                         ath9k_hw_ani_cck_err_trigger(ah);
630                         ath9k_ani_restart(ah);
631                 }
632         }
633 }
634
635 bool ath9k_hw_phycounters(struct ath_hw *ah)
636 {
637         return ah->has_hw_phycounters ? true : false;
638 }
639
640 void ath9k_enable_mib_counters(struct ath_hw *ah)
641 {
642         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
643
644         ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
645
646         REG_WRITE(ah, AR_FILT_OFDM, 0);
647         REG_WRITE(ah, AR_FILT_CCK, 0);
648         REG_WRITE(ah, AR_MIBC,
649                   ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
650                   & 0x0f);
651         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
652         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
653 }
654
655 /* Freeze the MIB counters, get the stats and then clear them */
656 void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
657 {
658         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
659         REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
660         ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
661         REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
662         REG_WRITE(ah, AR_FILT_OFDM, 0);
663         REG_WRITE(ah, AR_FILT_CCK, 0);
664 }
665
666 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
667                                   u32 *rxc_pcnt,
668                                   u32 *rxf_pcnt,
669                                   u32 *txf_pcnt)
670 {
671         static u32 cycles, rx_clear, rx_frame, tx_frame;
672         u32 good = 1;
673
674         u32 rc = REG_READ(ah, AR_RCCNT);
675         u32 rf = REG_READ(ah, AR_RFCNT);
676         u32 tf = REG_READ(ah, AR_TFCNT);
677         u32 cc = REG_READ(ah, AR_CCCNT);
678
679         if (cycles == 0 || cycles > cc) {
680                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
681                         "cycle counter wrap. ExtBusy = 0\n");
682                 good = 0;
683         } else {
684                 u32 cc_d = cc - cycles;
685                 u32 rc_d = rc - rx_clear;
686                 u32 rf_d = rf - rx_frame;
687                 u32 tf_d = tf - tx_frame;
688
689                 if (cc_d != 0) {
690                         *rxc_pcnt = rc_d * 100 / cc_d;
691                         *rxf_pcnt = rf_d * 100 / cc_d;
692                         *txf_pcnt = tf_d * 100 / cc_d;
693                 } else {
694                         good = 0;
695                 }
696         }
697
698         cycles = cc;
699         rx_frame = rf;
700         rx_clear = rc;
701         tx_frame = tf;
702
703         return good;
704 }
705
706 /*
707  * Process a MIB interrupt.  We may potentially be invoked because
708  * any of the MIB counters overflow/trigger so don't assume we're
709  * here because a PHY error counter triggered.
710  */
711 void ath9k_hw_procmibevent(struct ath_hw *ah,
712                            const struct ath9k_node_stats *stats)
713 {
714         u32 phyCnt1, phyCnt2;
715
716         /* Reset these counters regardless */
717         REG_WRITE(ah, AR_FILT_OFDM, 0);
718         REG_WRITE(ah, AR_FILT_CCK, 0);
719         if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
720                 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
721
722         /* Clear the mib counters and save them in the stats */
723         ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
724         ah->stats.ast_nodestats = *stats;
725
726         if (!DO_ANI(ah))
727                 return;
728
729         /* NB: these are not reset-on-read */
730         phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
731         phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
732         if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
733             ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
734                 struct ar5416AniState *aniState = ah->curani;
735                 u32 ofdmPhyErrCnt, cckPhyErrCnt;
736
737                 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
738                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
739                 ah->stats.ast_ani_ofdmerrs +=
740                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
741                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
742
743                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
744                 ah->stats.ast_ani_cckerrs +=
745                         cckPhyErrCnt - aniState->cckPhyErrCount;
746                 aniState->cckPhyErrCount = cckPhyErrCnt;
747
748                 /*
749                  * NB: figure out which counter triggered.  If both
750                  * trigger we'll only deal with one as the processing
751                  * clobbers the error counter so the trigger threshold
752                  * check will never be true.
753                  */
754                 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
755                         ath9k_hw_ani_ofdm_err_trigger(ah);
756                 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
757                         ath9k_hw_ani_cck_err_trigger(ah);
758                 /* NB: always restart to insure the h/w counters are reset */
759                 ath9k_ani_restart(ah);
760         }
761 }
762
763 void ath9k_hw_ani_setup(struct ath_hw *ah)
764 {
765         int i;
766
767         const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
768         const int coarseHigh[] = { -14, -14, -14, -14, -12 };
769         const int coarseLow[] = { -64, -64, -64, -64, -70 };
770         const int firpwr[] = { -78, -78, -78, -78, -80 };
771
772         for (i = 0; i < 5; i++) {
773                 ah->totalSizeDesired[i] = totalSizeDesired[i];
774                 ah->coarse_high[i] = coarseHigh[i];
775                 ah->coarse_low[i] = coarseLow[i];
776                 ah->firpwr[i] = firpwr[i];
777         }
778 }
779
780 void ath9k_hw_ani_init(struct ath_hw *ah)
781 {
782         int i;
783
784         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
785
786         ah->has_hw_phycounters = 1;
787
788         memset(ah->ani, 0, sizeof(ah->ani));
789         for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
790                 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
791                 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
792                 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
793                 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
794                 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
795                 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
796                 ah->ani[i].ofdmWeakSigDetectOff =
797                         !ATH9K_ANI_USE_OFDM_WEAK_SIG;
798                 ah->ani[i].cckWeakSigThreshold =
799                         ATH9K_ANI_CCK_WEAK_SIG_THR;
800                 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
801                 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
802                 if (ah->has_hw_phycounters) {
803                         ah->ani[i].ofdmPhyErrBase =
804                                 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
805                         ah->ani[i].cckPhyErrBase =
806                                 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
807                 }
808         }
809         if (ah->has_hw_phycounters) {
810                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
811                         "Setting OfdmErrBase = 0x%08x\n",
812                         ah->ani[0].ofdmPhyErrBase);
813                 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
814                         ah->ani[0].cckPhyErrBase);
815
816                 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
817                 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
818                 ath9k_enable_mib_counters(ah);
819         }
820         ah->aniperiod = ATH9K_ANI_PERIOD;
821         if (ah->config.enable_ani)
822                 ah->proc_phyerr |= HAL_PROCESS_ANI;
823 }
824
825 void ath9k_hw_ani_detach(struct ath_hw *ah)
826 {
827         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
828
829         if (ah->has_hw_phycounters) {
830                 ath9k_hw_disable_mib_counters(ah);
831                 REG_WRITE(ah, AR_PHY_ERR_1, 0);
832                 REG_WRITE(ah, AR_PHY_ERR_2, 0);
833         }
834 }