netdevice: safe convert to netdev_priv() #part-4
[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                                 "%s: level out of range (%u > %u)\n",
57                                 __func__, 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                                 "%s: level out of range (%u > %u)\n",
162                                 __func__, 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                                 "%s: level out of range (%u > %u)\n",
184                                 __func__, 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                         "%s: invalid cmd %u\n", __func__, cmd);
204                 return false;
205         }
206
207         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
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                         "%s: Writing ofdmbase=%u   cckbase=%u\n",
266                         __func__, 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 == ATH9K_M_HOSTAP) {
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 == ATH9K_M_HOSTAP) {
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 == ATH9K_M_HOSTAP) {
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 != ATH9K_M_STA
491             && ah->ah_opmode != ATH9K_M_IBSS) {
492                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
493                         "%s: Reset ANI state opmode %u\n", __func__,
494                         ah->ah_opmode);
495                 ahp->ah_stats.ast_ani_reset++;
496
497                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
498                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
499                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
500                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
501                                      !ATH9K_ANI_USE_OFDM_WEAK_SIG);
502                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
503                                      ATH9K_ANI_CCK_WEAK_SIG_THR);
504
505                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
506                                      ATH9K_RX_FILTER_PHYERR);
507
508                 if (ah->ah_opmode == ATH9K_M_HOSTAP) {
509                         ahp->ah_curani->ofdmTrigHigh =
510                                 ah->ah_config.ofdm_trig_high;
511                         ahp->ah_curani->ofdmTrigLow =
512                                 ah->ah_config.ofdm_trig_low;
513                         ahp->ah_curani->cckTrigHigh =
514                                 ah->ah_config.cck_trig_high;
515                         ahp->ah_curani->cckTrigLow =
516                                 ah->ah_config.cck_trig_low;
517                 }
518                 ath9k_ani_restart(ah);
519                 return;
520         }
521
522         if (aniState->noiseImmunityLevel != 0)
523                 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
524                                      aniState->noiseImmunityLevel);
525         if (aniState->spurImmunityLevel != 0)
526                 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
527                                      aniState->spurImmunityLevel);
528         if (aniState->ofdmWeakSigDetectOff)
529                 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
530                                      !aniState->ofdmWeakSigDetectOff);
531         if (aniState->cckWeakSigThreshold)
532                 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
533                                      aniState->cckWeakSigThreshold);
534         if (aniState->firstepLevel != 0)
535                 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
536                                      aniState->firstepLevel);
537         if (ahp->ah_hasHwPhyCounters) {
538                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
539                                      ~ATH9K_RX_FILTER_PHYERR);
540                 ath9k_ani_restart(ah);
541                 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
542                 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
543
544         } else {
545                 ath9k_ani_restart(ah);
546                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
547                                      ATH9K_RX_FILTER_PHYERR);
548         }
549 }
550
551 void ath9k_hw_ani_monitor(struct ath_hal *ah,
552                           const struct ath9k_node_stats *stats,
553                           struct ath9k_channel *chan)
554 {
555         struct ath_hal_5416 *ahp = AH5416(ah);
556         struct ar5416AniState *aniState;
557         int32_t listenTime;
558
559         aniState = ahp->ah_curani;
560         ahp->ah_stats.ast_nodestats = *stats;
561
562         listenTime = ath9k_hw_ani_get_listen_time(ah);
563         if (listenTime < 0) {
564                 ahp->ah_stats.ast_ani_lneg++;
565                 ath9k_ani_restart(ah);
566                 return;
567         }
568
569         aniState->listenTime += listenTime;
570
571         if (ahp->ah_hasHwPhyCounters) {
572                 u32 phyCnt1, phyCnt2;
573                 u32 ofdmPhyErrCnt, cckPhyErrCnt;
574
575                 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
576
577                 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
578                 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
579
580                 if (phyCnt1 < aniState->ofdmPhyErrBase ||
581                     phyCnt2 < aniState->cckPhyErrBase) {
582                         if (phyCnt1 < aniState->ofdmPhyErrBase) {
583                                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
584                                         "%s: phyCnt1 0x%x, resetting "
585                                         "counter value to 0x%x\n",
586                                         __func__, phyCnt1,
587                                         aniState->ofdmPhyErrBase);
588                                 REG_WRITE(ah, AR_PHY_ERR_1,
589                                           aniState->ofdmPhyErrBase);
590                                 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
591                                           AR_PHY_ERR_OFDM_TIMING);
592                         }
593                         if (phyCnt2 < aniState->cckPhyErrBase) {
594                                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
595                                         "%s: phyCnt2 0x%x, resetting "
596                                         "counter value to 0x%x\n",
597                                         __func__, phyCnt2,
598                                         aniState->cckPhyErrBase);
599                                 REG_WRITE(ah, AR_PHY_ERR_2,
600                                           aniState->cckPhyErrBase);
601                                 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
602                                           AR_PHY_ERR_CCK_TIMING);
603                         }
604                         return;
605                 }
606
607                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
608                 ahp->ah_stats.ast_ani_ofdmerrs +=
609                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
610                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
611
612                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
613                 ahp->ah_stats.ast_ani_cckerrs +=
614                         cckPhyErrCnt - aniState->cckPhyErrCount;
615                 aniState->cckPhyErrCount = cckPhyErrCnt;
616         }
617
618         if (!DO_ANI(ah))
619                 return;
620
621         if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
622                 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
623                     aniState->ofdmTrigLow / 1000 &&
624                     aniState->cckPhyErrCount <= aniState->listenTime *
625                     aniState->cckTrigLow / 1000)
626                         ath9k_hw_ani_lower_immunity(ah);
627                 ath9k_ani_restart(ah);
628         } else if (aniState->listenTime > ahp->ah_aniPeriod) {
629                 if (aniState->ofdmPhyErrCount > aniState->listenTime *
630                     aniState->ofdmTrigHigh / 1000) {
631                         ath9k_hw_ani_ofdm_err_trigger(ah);
632                         ath9k_ani_restart(ah);
633                 } else if (aniState->cckPhyErrCount >
634                            aniState->listenTime * aniState->cckTrigHigh /
635                            1000) {
636                         ath9k_hw_ani_cck_err_trigger(ah);
637                         ath9k_ani_restart(ah);
638                 }
639         }
640 }
641
642 bool ath9k_hw_phycounters(struct ath_hal *ah)
643 {
644         struct ath_hal_5416 *ahp = AH5416(ah);
645
646         return ahp->ah_hasHwPhyCounters ? true : false;
647 }
648
649 void ath9k_enable_mib_counters(struct ath_hal *ah)
650 {
651         struct ath_hal_5416 *ahp = AH5416(ah);
652
653         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
654
655         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
656
657         REG_WRITE(ah, AR_FILT_OFDM, 0);
658         REG_WRITE(ah, AR_FILT_CCK, 0);
659         REG_WRITE(ah, AR_MIBC,
660                   ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
661                   & 0x0f);
662         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
663         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
664 }
665
666 void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
667 {
668         struct ath_hal_5416 *ahp = AH5416(ah);
669
670         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
671
672         REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
673
674         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
675
676         REG_WRITE(ah, AR_FILT_OFDM, 0);
677         REG_WRITE(ah, AR_FILT_CCK, 0);
678 }
679
680 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
681                                   u32 *rxc_pcnt,
682                                   u32 *rxf_pcnt,
683                                   u32 *txf_pcnt)
684 {
685         static u32 cycles, rx_clear, rx_frame, tx_frame;
686         u32 good = 1;
687
688         u32 rc = REG_READ(ah, AR_RCCNT);
689         u32 rf = REG_READ(ah, AR_RFCNT);
690         u32 tf = REG_READ(ah, AR_TFCNT);
691         u32 cc = REG_READ(ah, AR_CCCNT);
692
693         if (cycles == 0 || cycles > cc) {
694                 DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
695                         "%s: cycle counter wrap. ExtBusy = 0\n",
696                         __func__);
697                 good = 0;
698         } else {
699                 u32 cc_d = cc - cycles;
700                 u32 rc_d = rc - rx_clear;
701                 u32 rf_d = rf - rx_frame;
702                 u32 tf_d = tf - tx_frame;
703
704                 if (cc_d != 0) {
705                         *rxc_pcnt = rc_d * 100 / cc_d;
706                         *rxf_pcnt = rf_d * 100 / cc_d;
707                         *txf_pcnt = tf_d * 100 / cc_d;
708                 } else {
709                         good = 0;
710                 }
711         }
712
713         cycles = cc;
714         rx_frame = rf;
715         rx_clear = rc;
716         tx_frame = tf;
717
718         return good;
719 }
720
721 /*
722  * Process a MIB interrupt.  We may potentially be invoked because
723  * any of the MIB counters overflow/trigger so don't assume we're
724  * here because a PHY error counter triggered.
725  */
726 void ath9k_hw_procmibevent(struct ath_hal *ah,
727                            const struct ath9k_node_stats *stats)
728 {
729         struct ath_hal_5416 *ahp = AH5416(ah);
730         u32 phyCnt1, phyCnt2;
731
732         /* Reset these counters regardless */
733         REG_WRITE(ah, AR_FILT_OFDM, 0);
734         REG_WRITE(ah, AR_FILT_CCK, 0);
735         if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
736                 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
737
738         /* Clear the mib counters and save them in the stats */
739         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
740         ahp->ah_stats.ast_nodestats = *stats;
741
742         if (!DO_ANI(ah))
743                 return;
744
745         /* NB: these are not reset-on-read */
746         phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
747         phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
748         if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
749             ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
750                 struct ar5416AniState *aniState = ahp->ah_curani;
751                 u32 ofdmPhyErrCnt, cckPhyErrCnt;
752
753                 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
754                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
755                 ahp->ah_stats.ast_ani_ofdmerrs +=
756                         ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
757                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
758
759                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
760                 ahp->ah_stats.ast_ani_cckerrs +=
761                         cckPhyErrCnt - aniState->cckPhyErrCount;
762                 aniState->cckPhyErrCount = cckPhyErrCnt;
763
764                 /*
765                  * NB: figure out which counter triggered.  If both
766                  * trigger we'll only deal with one as the processing
767                  * clobbers the error counter so the trigger threshold
768                  * check will never be true.
769                  */
770                 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
771                         ath9k_hw_ani_ofdm_err_trigger(ah);
772                 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
773                         ath9k_hw_ani_cck_err_trigger(ah);
774                 /* NB: always restart to insure the h/w counters are reset */
775                 ath9k_ani_restart(ah);
776         }
777 }
778
779 void ath9k_hw_ani_setup(struct ath_hal *ah)
780 {
781         struct ath_hal_5416 *ahp = AH5416(ah);
782         int i;
783
784         const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
785         const int coarseHigh[] = { -14, -14, -14, -14, -12 };
786         const int coarseLow[] = { -64, -64, -64, -64, -70 };
787         const int firpwr[] = { -78, -78, -78, -78, -80 };
788
789         for (i = 0; i < 5; i++) {
790                 ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
791                 ahp->ah_coarseHigh[i] = coarseHigh[i];
792                 ahp->ah_coarseLow[i] = coarseLow[i];
793                 ahp->ah_firpwr[i] = firpwr[i];
794         }
795 }
796
797 void ath9k_hw_ani_attach(struct ath_hal *ah)
798 {
799         struct ath_hal_5416 *ahp = AH5416(ah);
800         int i;
801
802         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
803
804         ahp->ah_hasHwPhyCounters = 1;
805
806         memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
807         for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
808                 ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
809                 ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
810                 ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
811                 ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
812                 ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
813                 ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
814                 ahp->ah_ani[i].ofdmWeakSigDetectOff =
815                         !ATH9K_ANI_USE_OFDM_WEAK_SIG;
816                 ahp->ah_ani[i].cckWeakSigThreshold =
817                         ATH9K_ANI_CCK_WEAK_SIG_THR;
818                 ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
819                 ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
820                 if (ahp->ah_hasHwPhyCounters) {
821                         ahp->ah_ani[i].ofdmPhyErrBase =
822                                 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
823                         ahp->ah_ani[i].cckPhyErrBase =
824                                 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
825                 }
826         }
827         if (ahp->ah_hasHwPhyCounters) {
828                 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
829                         "Setting OfdmErrBase = 0x%08x\n",
830                         ahp->ah_ani[0].ofdmPhyErrBase);
831                 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
832                         ahp->ah_ani[0].cckPhyErrBase);
833
834                 REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
835                 REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
836                 ath9k_enable_mib_counters(ah);
837         }
838         ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
839         if (ah->ah_config.enable_ani)
840                 ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
841 }
842
843 void ath9k_hw_ani_detach(struct ath_hal *ah)
844 {
845         struct ath_hal_5416 *ahp = AH5416(ah);
846
847         DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
848
849         if (ahp->ah_hasHwPhyCounters) {
850                 ath9k_hw_disable_mib_counters(ah);
851                 REG_WRITE(ah, AR_PHY_ERR_1, 0);
852                 REG_WRITE(ah, AR_PHY_ERR_2, 0);
853         }
854 }