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