Merge commit 'kumar/kumar-next' into next
[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 ath9k_channel *chan = ah->ah_curchan;
283         struct ar5416AniState *aniState;
284         enum wireless_mode mode;
285         int32_t rssi;
286
287         if (!DO_ANI(ah))
288                 return;
289
290         aniState = ahp->ah_curani;
291
292         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
293                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
294                                          aniState->noiseImmunityLevel + 1)) {
295                         return;
296                 }
297         }
298
299         if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
300                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
301                                          aniState->spurImmunityLevel + 1)) {
302                         return;
303                 }
304         }
305
306         if (ah->ah_opmode == NL80211_IFTYPE_AP) {
307                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
308                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
309                                              aniState->firstepLevel + 1);
310                 }
311                 return;
312         }
313         rssi = BEACON_RSSI(ahp);
314         if (rssi > aniState->rssiThrHigh) {
315                 if (!aniState->ofdmWeakSigDetectOff) {
316                         if (ath9k_hw_ani_control(ah,
317                                          ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
318                                          false)) {
319                                 ath9k_hw_ani_control(ah,
320                                         ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
321                                 return;
322                         }
323                 }
324                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
325                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
326                                              aniState->firstepLevel + 1);
327                         return;
328                 }
329         } else if (rssi > aniState->rssiThrLow) {
330                 if (aniState->ofdmWeakSigDetectOff)
331                         ath9k_hw_ani_control(ah,
332                                      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
333                                      true);
334                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
335                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
336                                              aniState->firstepLevel + 1);
337                 return;
338         } else {
339                 mode = ath9k_hw_chan2wmode(ah, chan);
340                 if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
341                         if (!aniState->ofdmWeakSigDetectOff)
342                                 ath9k_hw_ani_control(ah,
343                                      ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
344                                      false);
345                         if (aniState->firstepLevel > 0)
346                                 ath9k_hw_ani_control(ah,
347                                              ATH9K_ANI_FIRSTEP_LEVEL, 0);
348                         return;
349                 }
350         }
351 }
352
353 static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
354 {
355         struct ath_hal_5416 *ahp = AH5416(ah);
356         struct ath9k_channel *chan = ah->ah_curchan;
357         struct ar5416AniState *aniState;
358         enum wireless_mode mode;
359         int32_t rssi;
360
361         if (!DO_ANI(ah))
362                 return;
363
364         aniState = ahp->ah_curani;
365         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
366                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
367                                          aniState->noiseImmunityLevel + 1)) {
368                         return;
369                 }
370         }
371         if (ah->ah_opmode == NL80211_IFTYPE_AP) {
372                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
373                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
374                                              aniState->firstepLevel + 1);
375                 }
376                 return;
377         }
378         rssi = BEACON_RSSI(ahp);
379         if (rssi > aniState->rssiThrLow) {
380                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
381                         ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
382                                              aniState->firstepLevel + 1);
383         } else {
384                 mode = ath9k_hw_chan2wmode(ah, chan);
385                 if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
386                         if (aniState->firstepLevel > 0)
387                                 ath9k_hw_ani_control(ah,
388                                              ATH9K_ANI_FIRSTEP_LEVEL, 0);
389                 }
390         }
391 }
392
393 static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
394 {
395         struct ath_hal_5416 *ahp = AH5416(ah);
396         struct ar5416AniState *aniState;
397         int32_t rssi;
398
399         aniState = ahp->ah_curani;
400
401         if (ah->ah_opmode == NL80211_IFTYPE_AP) {
402                 if (aniState->firstepLevel > 0) {
403                         if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
404                                                  aniState->firstepLevel - 1))
405                                 return;
406                 }
407         } else {
408                 rssi = BEACON_RSSI(ahp);
409                 if (rssi > aniState->rssiThrHigh) {
410                         /* XXX: Handle me */
411                 } else if (rssi > aniState->rssiThrLow) {
412                         if (aniState->ofdmWeakSigDetectOff) {
413                                 if (ath9k_hw_ani_control(ah,
414                                          ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
415                                          true) == true)
416                                         return;
417                         }
418                         if (aniState->firstepLevel > 0) {
419                                 if (ath9k_hw_ani_control(ah,
420                                          ATH9K_ANI_FIRSTEP_LEVEL,
421                                          aniState->firstepLevel - 1) == true)
422                                         return;
423                         }
424                 } else {
425                         if (aniState->firstepLevel > 0) {
426                                 if (ath9k_hw_ani_control(ah,
427                                          ATH9K_ANI_FIRSTEP_LEVEL,
428                                          aniState->firstepLevel - 1) == true)
429                                         return;
430                         }
431                 }
432         }
433
434         if (aniState->spurImmunityLevel > 0) {
435                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
436                                          aniState->spurImmunityLevel - 1))
437                         return;
438         }
439
440         if (aniState->noiseImmunityLevel > 0) {
441                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
442                                      aniState->noiseImmunityLevel - 1);
443                 return;
444         }
445 }
446
447 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
448 {
449         struct ath_hal_5416 *ahp = AH5416(ah);
450         struct ar5416AniState *aniState;
451         u32 txFrameCount, rxFrameCount, cycleCount;
452         int32_t listenTime;
453
454         txFrameCount = REG_READ(ah, AR_TFCNT);
455         rxFrameCount = REG_READ(ah, AR_RFCNT);
456         cycleCount = REG_READ(ah, AR_CCCNT);
457
458         aniState = ahp->ah_curani;
459         if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
460
461                 listenTime = 0;
462                 ahp->ah_stats.ast_ani_lzero++;
463         } else {
464                 int32_t ccdelta = cycleCount - aniState->cycleCount;
465                 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
466                 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
467                 listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
468         }
469         aniState->cycleCount = cycleCount;
470         aniState->txFrameCount = txFrameCount;
471         aniState->rxFrameCount = rxFrameCount;
472
473         return listenTime;
474 }
475
476 void ath9k_ani_reset(struct ath_hal *ah)
477 {
478         struct ath_hal_5416 *ahp = AH5416(ah);
479         struct ar5416AniState *aniState;
480         struct ath9k_channel *chan = ah->ah_curchan;
481         int index;
482
483         if (!DO_ANI(ah))
484                 return;
485
486         index = ath9k_hw_get_ani_channel_idx(ah, chan);
487         aniState = &ahp->ah_ani[index];
488         ahp->ah_curani = aniState;
489
490         if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION
491             && ah->ah_opmode != NL80211_IFTYPE_ADHOC) {
492                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
493                         "Reset ANI state opmode %u\n", ah->ah_opmode);
494                 ahp->ah_stats.ast_ani_reset++;
495
496                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
497                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
498                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
499                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
500                                      !ATH9K_ANI_USE_OFDM_WEAK_SIG);
501                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
502                                      ATH9K_ANI_CCK_WEAK_SIG_THR);
503
504                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
505                                      ATH9K_RX_FILTER_PHYERR);
506
507                 if (ah->ah_opmode == NL80211_IFTYPE_AP) {
508                         ahp->ah_curani->ofdmTrigHigh =
509                                 ah->ah_config.ofdm_trig_high;
510                         ahp->ah_curani->ofdmTrigLow =
511                                 ah->ah_config.ofdm_trig_low;
512                         ahp->ah_curani->cckTrigHigh =
513                                 ah->ah_config.cck_trig_high;
514                         ahp->ah_curani->cckTrigLow =
515                                 ah->ah_config.cck_trig_low;
516                 }
517                 ath9k_ani_restart(ah);
518                 return;
519         }
520
521         if (aniState->noiseImmunityLevel != 0)
522                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
523                                      aniState->noiseImmunityLevel);
524         if (aniState->spurImmunityLevel != 0)
525                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
526                                      aniState->spurImmunityLevel);
527         if (aniState->ofdmWeakSigDetectOff)
528                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
529                                      !aniState->ofdmWeakSigDetectOff);
530         if (aniState->cckWeakSigThreshold)
531                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
532                                      aniState->cckWeakSigThreshold);
533         if (aniState->firstepLevel != 0)
534                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
535                                      aniState->firstepLevel);
536         if (ahp->ah_hasHwPhyCounters) {
537                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
538                                      ~ATH9K_RX_FILTER_PHYERR);
539                 ath9k_ani_restart(ah);
540                 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
541                 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
542
543         } else {
544                 ath9k_ani_restart(ah);
545                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
546                                      ATH9K_RX_FILTER_PHYERR);
547         }
548 }
549
550 void ath9k_hw_ani_monitor(struct ath_hal *ah,
551                           const struct ath9k_node_stats *stats,
552                           struct ath9k_channel *chan)
553 {
554         struct ath_hal_5416 *ahp = AH5416(ah);
555         struct ar5416AniState *aniState;
556         int32_t listenTime;
557
558         aniState = ahp->ah_curani;
559         ahp->ah_stats.ast_nodestats = *stats;
560
561         listenTime = ath9k_hw_ani_get_listen_time(ah);
562         if (listenTime < 0) {
563                 ahp->ah_stats.ast_ani_lneg++;
564                 ath9k_ani_restart(ah);
565                 return;
566         }
567
568         aniState->listenTime += listenTime;
569
570         if (ahp->ah_hasHwPhyCounters) {
571                 u32 phyCnt1, phyCnt2;
572                 u32 ofdmPhyErrCnt, cckPhyErrCnt;
573
574                 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
575
576                 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
577                 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
578
579                 if (phyCnt1 < aniState->ofdmPhyErrBase ||
580                     phyCnt2 < aniState->cckPhyErrBase) {
581                         if (phyCnt1 < aniState->ofdmPhyErrBase) {
582                                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
583                                         "phyCnt1 0x%x, resetting "
584                                         "counter value to 0x%x\n",
585                                         phyCnt1,
586                                         aniState->ofdmPhyErrBase);
587                                 REG_WRITE(ah, AR_PHY_ERR_1,
588                                           aniState->ofdmPhyErrBase);
589                                 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
590                                           AR_PHY_ERR_OFDM_TIMING);
591                         }
592                         if (phyCnt2 < aniState->cckPhyErrBase) {
593                                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
594                                         "phyCnt2 0x%x, resetting "
595                                         "counter value to 0x%x\n",
596                                         phyCnt2,
597                                         aniState->cckPhyErrBase);
598                                 REG_WRITE(ah, AR_PHY_ERR_2,
599                                           aniState->cckPhyErrBase);
600                                 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
601                                           AR_PHY_ERR_CCK_TIMING);
602                         }
603                         return;
604                 }
605
606                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
607                 ahp->ah_stats.ast_ani_ofdmerrs +=
608                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
609                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
610
611                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
612                 ahp->ah_stats.ast_ani_cckerrs +=
613                         cckPhyErrCnt - aniState->cckPhyErrCount;
614                 aniState->cckPhyErrCount = cckPhyErrCnt;
615         }
616
617         if (!DO_ANI(ah))
618                 return;
619
620         if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
621                 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
622                     aniState->ofdmTrigLow / 1000 &&
623                     aniState->cckPhyErrCount <= aniState->listenTime *
624                     aniState->cckTrigLow / 1000)
625                         ath9k_hw_ani_lower_immunity(ah);
626                 ath9k_ani_restart(ah);
627         } else if (aniState->listenTime > ahp->ah_aniPeriod) {
628                 if (aniState->ofdmPhyErrCount > aniState->listenTime *
629                     aniState->ofdmTrigHigh / 1000) {
630                         ath9k_hw_ani_ofdm_err_trigger(ah);
631                         ath9k_ani_restart(ah);
632                 } else if (aniState->cckPhyErrCount >
633                            aniState->listenTime * aniState->cckTrigHigh /
634                            1000) {
635                         ath9k_hw_ani_cck_err_trigger(ah);
636                         ath9k_ani_restart(ah);
637                 }
638         }
639 }
640
641 bool ath9k_hw_phycounters(struct ath_hal *ah)
642 {
643         struct ath_hal_5416 *ahp = AH5416(ah);
644
645         return ahp->ah_hasHwPhyCounters ? true : false;
646 }
647
648 void ath9k_enable_mib_counters(struct ath_hal *ah)
649 {
650         struct ath_hal_5416 *ahp = AH5416(ah);
651
652         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
653
654         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
655
656         REG_WRITE(ah, AR_FILT_OFDM, 0);
657         REG_WRITE(ah, AR_FILT_CCK, 0);
658         REG_WRITE(ah, AR_MIBC,
659                   ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
660                   & 0x0f);
661         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
662         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
663 }
664
665 void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
666 {
667         struct ath_hal_5416 *ahp = AH5416(ah);
668
669         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
670
671         REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
672
673         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
674
675         REG_WRITE(ah, AR_FILT_OFDM, 0);
676         REG_WRITE(ah, AR_FILT_CCK, 0);
677 }
678
679 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
680                                   u32 *rxc_pcnt,
681                                   u32 *rxf_pcnt,
682                                   u32 *txf_pcnt)
683 {
684         static u32 cycles, rx_clear, rx_frame, tx_frame;
685         u32 good = 1;
686
687         u32 rc = REG_READ(ah, AR_RCCNT);
688         u32 rf = REG_READ(ah, AR_RFCNT);
689         u32 tf = REG_READ(ah, AR_TFCNT);
690         u32 cc = REG_READ(ah, AR_CCCNT);
691
692         if (cycles == 0 || cycles > cc) {
693                 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
694                         "cycle counter wrap. ExtBusy = 0\n");
695                 good = 0;
696         } else {
697                 u32 cc_d = cc - cycles;
698                 u32 rc_d = rc - rx_clear;
699                 u32 rf_d = rf - rx_frame;
700                 u32 tf_d = tf - tx_frame;
701
702                 if (cc_d != 0) {
703                         *rxc_pcnt = rc_d * 100 / cc_d;
704                         *rxf_pcnt = rf_d * 100 / cc_d;
705                         *txf_pcnt = tf_d * 100 / cc_d;
706                 } else {
707                         good = 0;
708                 }
709         }
710
711         cycles = cc;
712         rx_frame = rf;
713         rx_clear = rc;
714         tx_frame = tf;
715
716         return good;
717 }
718
719 /*
720  * Process a MIB interrupt.  We may potentially be invoked because
721  * any of the MIB counters overflow/trigger so don't assume we're
722  * here because a PHY error counter triggered.
723  */
724 void ath9k_hw_procmibevent(struct ath_hal *ah,
725                            const struct ath9k_node_stats *stats)
726 {
727         struct ath_hal_5416 *ahp = AH5416(ah);
728         u32 phyCnt1, phyCnt2;
729
730         /* Reset these counters regardless */
731         REG_WRITE(ah, AR_FILT_OFDM, 0);
732         REG_WRITE(ah, AR_FILT_CCK, 0);
733         if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
734                 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
735
736         /* Clear the mib counters and save them in the stats */
737         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
738         ahp->ah_stats.ast_nodestats = *stats;
739
740         if (!DO_ANI(ah))
741                 return;
742
743         /* NB: these are not reset-on-read */
744         phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
745         phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
746         if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
747             ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
748                 struct ar5416AniState *aniState = ahp->ah_curani;
749                 u32 ofdmPhyErrCnt, cckPhyErrCnt;
750
751                 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
752                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
753                 ahp->ah_stats.ast_ani_ofdmerrs +=
754                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
755                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
756
757                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
758                 ahp->ah_stats.ast_ani_cckerrs +=
759                         cckPhyErrCnt - aniState->cckPhyErrCount;
760                 aniState->cckPhyErrCount = cckPhyErrCnt;
761
762                 /*
763                  * NB: figure out which counter triggered.  If both
764                  * trigger we'll only deal with one as the processing
765                  * clobbers the error counter so the trigger threshold
766                  * check will never be true.
767                  */
768                 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
769                         ath9k_hw_ani_ofdm_err_trigger(ah);
770                 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
771                         ath9k_hw_ani_cck_err_trigger(ah);
772                 /* NB: always restart to insure the h/w counters are reset */
773                 ath9k_ani_restart(ah);
774         }
775 }
776
777 void ath9k_hw_ani_setup(struct ath_hal *ah)
778 {
779         struct ath_hal_5416 *ahp = AH5416(ah);
780         int i;
781
782         const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
783         const int coarseHigh[] = { -14, -14, -14, -14, -12 };
784         const int coarseLow[] = { -64, -64, -64, -64, -70 };
785         const int firpwr[] = { -78, -78, -78, -78, -80 };
786
787         for (i = 0; i < 5; i++) {
788                 ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
789                 ahp->ah_coarseHigh[i] = coarseHigh[i];
790                 ahp->ah_coarseLow[i] = coarseLow[i];
791                 ahp->ah_firpwr[i] = firpwr[i];
792         }
793 }
794
795 void ath9k_hw_ani_attach(struct ath_hal *ah)
796 {
797         struct ath_hal_5416 *ahp = AH5416(ah);
798         int i;
799
800         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
801
802         ahp->ah_hasHwPhyCounters = 1;
803
804         memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
805         for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
806                 ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
807                 ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
808                 ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
809                 ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
810                 ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
811                 ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
812                 ahp->ah_ani[i].ofdmWeakSigDetectOff =
813                         !ATH9K_ANI_USE_OFDM_WEAK_SIG;
814                 ahp->ah_ani[i].cckWeakSigThreshold =
815                         ATH9K_ANI_CCK_WEAK_SIG_THR;
816                 ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
817                 ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
818                 if (ahp->ah_hasHwPhyCounters) {
819                         ahp->ah_ani[i].ofdmPhyErrBase =
820                                 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
821                         ahp->ah_ani[i].cckPhyErrBase =
822                                 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
823                 }
824         }
825         if (ahp->ah_hasHwPhyCounters) {
826                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
827                         "Setting OfdmErrBase = 0x%08x\n",
828                         ahp->ah_ani[0].ofdmPhyErrBase);
829                 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
830                         ahp->ah_ani[0].cckPhyErrBase);
831
832                 REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
833                 REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
834                 ath9k_enable_mib_counters(ah);
835         }
836         ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
837         if (ah->ah_config.enable_ani)
838                 ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
839 }
840
841 void ath9k_hw_ani_detach(struct ath_hal *ah)
842 {
843         struct ath_hal_5416 *ahp = AH5416(ah);
844
845         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
846
847         if (ahp->ah_hasHwPhyCounters) {
848                 ath9k_hw_disable_mib_counters(ah);
849                 REG_WRITE(ah, AR_PHY_ERR_1, 0);
850                 REG_WRITE(ah, AR_PHY_ERR_2, 0);
851         }
852 }