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