blob: 2a0cd64c2bfbc64830a8a71bf714972302ebc2dc [file] [log] [blame]
Sujithf1dc5602008-10-29 10:16:30 +05301/*
Sujithcee075a2009-03-13 09:07:23 +05302 * Copyright (c) 2008-2009 Atheros Communications Inc.
Sujithf1dc5602008-10-29 10:16:30 +05303 *
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
Luis R. Rodriguezcfe8cba2009-09-13 23:39:31 -070017#include "hw.h"
Sujithf1dc5602008-10-29 10:16:30 +053018
Sujithcbe61d82009-02-09 13:27:12 +053019static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +053020 struct ath9k_channel *chan)
21{
Sujithf1dc5602008-10-29 10:16:30 +053022 int i;
23
Sujith2660b812009-02-09 13:27:26 +053024 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
25 if (ah->ani[i].c &&
26 ah->ani[i].c->channel == chan->channel)
Sujithf1dc5602008-10-29 10:16:30 +053027 return i;
Sujith2660b812009-02-09 13:27:26 +053028 if (ah->ani[i].c == NULL) {
29 ah->ani[i].c = chan;
Sujithf1dc5602008-10-29 10:16:30 +053030 return i;
31 }
32 }
33
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070034 ath_print(ath9k_hw_common(ah), ATH_DBG_ANI,
35 "No more channel states left. Using channel 0\n");
Sujithf1dc5602008-10-29 10:16:30 +053036
37 return 0;
38}
39
Sujithcbe61d82009-02-09 13:27:12 +053040static bool ath9k_hw_ani_control(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +053041 enum ath9k_ani_cmd cmd, int param)
42{
Sujith2660b812009-02-09 13:27:26 +053043 struct ar5416AniState *aniState = ah->curani;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070044 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +053045
Sujith2660b812009-02-09 13:27:26 +053046 switch (cmd & ah->ani_function) {
Sujithf1dc5602008-10-29 10:16:30 +053047 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
48 u32 level = param;
49
Sujith2660b812009-02-09 13:27:26 +053050 if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070051 ath_print(common, ATH_DBG_ANI,
52 "level out of range (%u > %u)\n",
53 level,
54 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
Sujithf1dc5602008-10-29 10:16:30 +053055 return false;
56 }
57
58 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
59 AR_PHY_DESIRED_SZ_TOT_DES,
Sujith2660b812009-02-09 13:27:26 +053060 ah->totalSizeDesired[level]);
Sujithf1dc5602008-10-29 10:16:30 +053061 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
62 AR_PHY_AGC_CTL1_COARSE_LOW,
Sujith2660b812009-02-09 13:27:26 +053063 ah->coarse_low[level]);
Sujithf1dc5602008-10-29 10:16:30 +053064 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
65 AR_PHY_AGC_CTL1_COARSE_HIGH,
Sujith2660b812009-02-09 13:27:26 +053066 ah->coarse_high[level]);
Sujithf1dc5602008-10-29 10:16:30 +053067 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
68 AR_PHY_FIND_SIG_FIRPWR,
Sujith2660b812009-02-09 13:27:26 +053069 ah->firpwr[level]);
Sujithf1dc5602008-10-29 10:16:30 +053070
71 if (level > aniState->noiseImmunityLevel)
Sujith2660b812009-02-09 13:27:26 +053072 ah->stats.ast_ani_niup++;
Sujithf1dc5602008-10-29 10:16:30 +053073 else if (level < aniState->noiseImmunityLevel)
Sujith2660b812009-02-09 13:27:26 +053074 ah->stats.ast_ani_nidown++;
Sujithf1dc5602008-10-29 10:16:30 +053075 aniState->noiseImmunityLevel = level;
76 break;
77 }
78 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
79 const int m1ThreshLow[] = { 127, 50 };
80 const int m2ThreshLow[] = { 127, 40 };
81 const int m1Thresh[] = { 127, 0x4d };
82 const int m2Thresh[] = { 127, 0x40 };
83 const int m2CountThr[] = { 31, 16 };
84 const int m2CountThrLow[] = { 63, 48 };
85 u32 on = param ? 1 : 0;
86
87 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
88 AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
89 m1ThreshLow[on]);
90 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
91 AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
92 m2ThreshLow[on]);
93 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
94 AR_PHY_SFCORR_M1_THRESH,
95 m1Thresh[on]);
96 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
97 AR_PHY_SFCORR_M2_THRESH,
98 m2Thresh[on]);
99 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
100 AR_PHY_SFCORR_M2COUNT_THR,
101 m2CountThr[on]);
102 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
103 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
104 m2CountThrLow[on]);
105
106 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
107 AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
108 m1ThreshLow[on]);
109 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
110 AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
111 m2ThreshLow[on]);
112 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
113 AR_PHY_SFCORR_EXT_M1_THRESH,
114 m1Thresh[on]);
115 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
116 AR_PHY_SFCORR_EXT_M2_THRESH,
117 m2Thresh[on]);
118
119 if (on)
120 REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
121 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
122 else
123 REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
124 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
125
126 if (!on != aniState->ofdmWeakSigDetectOff) {
127 if (on)
Sujith2660b812009-02-09 13:27:26 +0530128 ah->stats.ast_ani_ofdmon++;
Sujithf1dc5602008-10-29 10:16:30 +0530129 else
Sujith2660b812009-02-09 13:27:26 +0530130 ah->stats.ast_ani_ofdmoff++;
Sujithf1dc5602008-10-29 10:16:30 +0530131 aniState->ofdmWeakSigDetectOff = !on;
132 }
133 break;
134 }
135 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
136 const int weakSigThrCck[] = { 8, 6 };
137 u32 high = param ? 1 : 0;
138
139 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
140 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
141 weakSigThrCck[high]);
142 if (high != aniState->cckWeakSigThreshold) {
143 if (high)
Sujith2660b812009-02-09 13:27:26 +0530144 ah->stats.ast_ani_cckhigh++;
Sujithf1dc5602008-10-29 10:16:30 +0530145 else
Sujith2660b812009-02-09 13:27:26 +0530146 ah->stats.ast_ani_ccklow++;
Sujithf1dc5602008-10-29 10:16:30 +0530147 aniState->cckWeakSigThreshold = high;
148 }
149 break;
150 }
151 case ATH9K_ANI_FIRSTEP_LEVEL:{
152 const int firstep[] = { 0, 4, 8 };
153 u32 level = param;
154
155 if (level >= ARRAY_SIZE(firstep)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700156 ath_print(common, ATH_DBG_ANI,
157 "level out of range (%u > %u)\n",
158 level,
159 (unsigned) ARRAY_SIZE(firstep));
Sujithf1dc5602008-10-29 10:16:30 +0530160 return false;
161 }
162 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
163 AR_PHY_FIND_SIG_FIRSTEP,
164 firstep[level]);
165 if (level > aniState->firstepLevel)
Sujith2660b812009-02-09 13:27:26 +0530166 ah->stats.ast_ani_stepup++;
Sujithf1dc5602008-10-29 10:16:30 +0530167 else if (level < aniState->firstepLevel)
Sujith2660b812009-02-09 13:27:26 +0530168 ah->stats.ast_ani_stepdown++;
Sujithf1dc5602008-10-29 10:16:30 +0530169 aniState->firstepLevel = level;
170 break;
171 }
172 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
173 const int cycpwrThr1[] =
174 { 2, 4, 6, 8, 10, 12, 14, 16 };
175 u32 level = param;
176
177 if (level >= ARRAY_SIZE(cycpwrThr1)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700178 ath_print(common, ATH_DBG_ANI,
179 "level out of range (%u > %u)\n",
180 level,
181 (unsigned) ARRAY_SIZE(cycpwrThr1));
Sujithf1dc5602008-10-29 10:16:30 +0530182 return false;
183 }
184 REG_RMW_FIELD(ah, AR_PHY_TIMING5,
185 AR_PHY_TIMING5_CYCPWR_THR1,
186 cycpwrThr1[level]);
187 if (level > aniState->spurImmunityLevel)
Sujith2660b812009-02-09 13:27:26 +0530188 ah->stats.ast_ani_spurup++;
Sujithf1dc5602008-10-29 10:16:30 +0530189 else if (level < aniState->spurImmunityLevel)
Sujith2660b812009-02-09 13:27:26 +0530190 ah->stats.ast_ani_spurdown++;
Sujithf1dc5602008-10-29 10:16:30 +0530191 aniState->spurImmunityLevel = level;
192 break;
193 }
194 case ATH9K_ANI_PRESENT:
195 break;
196 default:
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700197 ath_print(common, ATH_DBG_ANI,
198 "invalid cmd %u\n", cmd);
Sujithf1dc5602008-10-29 10:16:30 +0530199 return false;
200 }
201
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700202 ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
203 ath_print(common, ATH_DBG_ANI,
204 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
205 "ofdmWeakSigDetectOff=%d\n",
206 aniState->noiseImmunityLevel,
207 aniState->spurImmunityLevel,
208 !aniState->ofdmWeakSigDetectOff);
209 ath_print(common, ATH_DBG_ANI,
210 "cckWeakSigThreshold=%d, "
211 "firstepLevel=%d, listenTime=%d\n",
212 aniState->cckWeakSigThreshold,
213 aniState->firstepLevel,
214 aniState->listenTime);
215 ath_print(common, ATH_DBG_ANI,
Sujithf1dc5602008-10-29 10:16:30 +0530216 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700217 aniState->cycleCount,
218 aniState->ofdmPhyErrCount,
Sujithf1dc5602008-10-29 10:16:30 +0530219 aniState->cckPhyErrCount);
220
221 return true;
222}
223
Sujithcbe61d82009-02-09 13:27:12 +0530224static void ath9k_hw_update_mibstats(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530225 struct ath9k_mib_stats *stats)
226{
227 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
228 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
229 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
230 stats->rts_good += REG_READ(ah, AR_RTS_OK);
231 stats->beacons += REG_READ(ah, AR_BEACON_CNT);
232}
233
Sujithcbe61d82009-02-09 13:27:12 +0530234static void ath9k_ani_restart(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530235{
Sujithf1dc5602008-10-29 10:16:30 +0530236 struct ar5416AniState *aniState;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700237 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530238
239 if (!DO_ANI(ah))
240 return;
241
Sujith2660b812009-02-09 13:27:26 +0530242 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530243 aniState->listenTime = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530244
Sujith1aa8e842009-08-13 09:34:25 +0530245 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
246 aniState->ofdmPhyErrBase = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700247 ath_print(common, ATH_DBG_ANI,
248 "OFDM Trigger is too high for hw counters\n");
Sujith1aa8e842009-08-13 09:34:25 +0530249 } else {
250 aniState->ofdmPhyErrBase =
251 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
Sujithf1dc5602008-10-29 10:16:30 +0530252 }
Sujith1aa8e842009-08-13 09:34:25 +0530253 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
254 aniState->cckPhyErrBase = 0;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700255 ath_print(common, ATH_DBG_ANI,
256 "CCK Trigger is too high for hw counters\n");
Sujith1aa8e842009-08-13 09:34:25 +0530257 } else {
258 aniState->cckPhyErrBase =
259 AR_PHY_COUNTMAX - aniState->cckTrigHigh;
260 }
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700261 ath_print(common, ATH_DBG_ANI,
262 "Writing ofdmbase=%u cckbase=%u\n",
263 aniState->ofdmPhyErrBase,
264 aniState->cckPhyErrBase);
Sujith1aa8e842009-08-13 09:34:25 +0530265 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
266 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
267 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
268 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
269
270 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
271
Sujithf1dc5602008-10-29 10:16:30 +0530272 aniState->ofdmPhyErrCount = 0;
273 aniState->cckPhyErrCount = 0;
274}
275
Sujithcbe61d82009-02-09 13:27:12 +0530276static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530277{
Luis R. Rodriguezb002a4a2009-09-13 00:03:27 -0700278 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
Sujithf1dc5602008-10-29 10:16:30 +0530279 struct ar5416AniState *aniState;
Sujithf1dc5602008-10-29 10:16:30 +0530280 int32_t rssi;
281
282 if (!DO_ANI(ah))
283 return;
284
Sujith2660b812009-02-09 13:27:26 +0530285 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530286
287 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
288 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
289 aniState->noiseImmunityLevel + 1)) {
290 return;
291 }
292 }
293
294 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
295 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
296 aniState->spurImmunityLevel + 1)) {
297 return;
298 }
299 }
300
Sujith2660b812009-02-09 13:27:26 +0530301 if (ah->opmode == NL80211_IFTYPE_AP) {
Sujithf1dc5602008-10-29 10:16:30 +0530302 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
303 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
304 aniState->firstepLevel + 1);
305 }
306 return;
307 }
Sujithcbe61d82009-02-09 13:27:12 +0530308 rssi = BEACON_RSSI(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530309 if (rssi > aniState->rssiThrHigh) {
310 if (!aniState->ofdmWeakSigDetectOff) {
311 if (ath9k_hw_ani_control(ah,
312 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
313 false)) {
314 ath9k_hw_ani_control(ah,
315 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
316 return;
317 }
318 }
319 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
320 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
321 aniState->firstepLevel + 1);
322 return;
323 }
324 } else if (rssi > aniState->rssiThrLow) {
325 if (aniState->ofdmWeakSigDetectOff)
326 ath9k_hw_ani_control(ah,
327 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
328 true);
329 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
330 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
331 aniState->firstepLevel + 1);
332 return;
333 } else {
Sujithd37b7da2009-09-11 08:30:03 +0530334 if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
335 !conf_is_ht(conf)) {
Sujithf1dc5602008-10-29 10:16:30 +0530336 if (!aniState->ofdmWeakSigDetectOff)
337 ath9k_hw_ani_control(ah,
338 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
339 false);
340 if (aniState->firstepLevel > 0)
341 ath9k_hw_ani_control(ah,
342 ATH9K_ANI_FIRSTEP_LEVEL, 0);
343 return;
344 }
345 }
346}
347
Sujithcbe61d82009-02-09 13:27:12 +0530348static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530349{
Luis R. Rodriguezb002a4a2009-09-13 00:03:27 -0700350 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
Sujithf1dc5602008-10-29 10:16:30 +0530351 struct ar5416AniState *aniState;
Sujithf1dc5602008-10-29 10:16:30 +0530352 int32_t rssi;
353
354 if (!DO_ANI(ah))
355 return;
356
Sujith2660b812009-02-09 13:27:26 +0530357 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530358 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
359 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
360 aniState->noiseImmunityLevel + 1)) {
361 return;
362 }
363 }
Sujith2660b812009-02-09 13:27:26 +0530364 if (ah->opmode == NL80211_IFTYPE_AP) {
Sujithf1dc5602008-10-29 10:16:30 +0530365 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
366 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
367 aniState->firstepLevel + 1);
368 }
369 return;
370 }
Sujithcbe61d82009-02-09 13:27:12 +0530371 rssi = BEACON_RSSI(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530372 if (rssi > aniState->rssiThrLow) {
373 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
374 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
375 aniState->firstepLevel + 1);
376 } else {
Sujithd37b7da2009-09-11 08:30:03 +0530377 if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
378 !conf_is_ht(conf)) {
Sujithf1dc5602008-10-29 10:16:30 +0530379 if (aniState->firstepLevel > 0)
380 ath9k_hw_ani_control(ah,
381 ATH9K_ANI_FIRSTEP_LEVEL, 0);
382 }
383 }
384}
385
Sujithcbe61d82009-02-09 13:27:12 +0530386static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530387{
Sujithf1dc5602008-10-29 10:16:30 +0530388 struct ar5416AniState *aniState;
389 int32_t rssi;
390
Sujith2660b812009-02-09 13:27:26 +0530391 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530392
Sujith2660b812009-02-09 13:27:26 +0530393 if (ah->opmode == NL80211_IFTYPE_AP) {
Sujithf1dc5602008-10-29 10:16:30 +0530394 if (aniState->firstepLevel > 0) {
395 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
396 aniState->firstepLevel - 1))
397 return;
398 }
399 } else {
Sujithcbe61d82009-02-09 13:27:12 +0530400 rssi = BEACON_RSSI(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530401 if (rssi > aniState->rssiThrHigh) {
402 /* XXX: Handle me */
403 } else if (rssi > aniState->rssiThrLow) {
404 if (aniState->ofdmWeakSigDetectOff) {
405 if (ath9k_hw_ani_control(ah,
406 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
407 true) == true)
408 return;
409 }
410 if (aniState->firstepLevel > 0) {
411 if (ath9k_hw_ani_control(ah,
412 ATH9K_ANI_FIRSTEP_LEVEL,
413 aniState->firstepLevel - 1) == true)
414 return;
415 }
416 } else {
417 if (aniState->firstepLevel > 0) {
418 if (ath9k_hw_ani_control(ah,
419 ATH9K_ANI_FIRSTEP_LEVEL,
420 aniState->firstepLevel - 1) == true)
421 return;
422 }
423 }
424 }
425
426 if (aniState->spurImmunityLevel > 0) {
427 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
428 aniState->spurImmunityLevel - 1))
429 return;
430 }
431
432 if (aniState->noiseImmunityLevel > 0) {
433 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
434 aniState->noiseImmunityLevel - 1);
435 return;
436 }
437}
438
Sujithcbe61d82009-02-09 13:27:12 +0530439static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530440{
Sujithf1dc5602008-10-29 10:16:30 +0530441 struct ar5416AniState *aniState;
442 u32 txFrameCount, rxFrameCount, cycleCount;
443 int32_t listenTime;
444
445 txFrameCount = REG_READ(ah, AR_TFCNT);
446 rxFrameCount = REG_READ(ah, AR_RFCNT);
447 cycleCount = REG_READ(ah, AR_CCCNT);
448
Sujith2660b812009-02-09 13:27:26 +0530449 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530450 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
451
452 listenTime = 0;
Sujith2660b812009-02-09 13:27:26 +0530453 ah->stats.ast_ani_lzero++;
Sujithf1dc5602008-10-29 10:16:30 +0530454 } else {
455 int32_t ccdelta = cycleCount - aniState->cycleCount;
456 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
457 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
458 listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
459 }
460 aniState->cycleCount = cycleCount;
461 aniState->txFrameCount = txFrameCount;
462 aniState->rxFrameCount = rxFrameCount;
463
464 return listenTime;
465}
466
Sujithcbe61d82009-02-09 13:27:12 +0530467void ath9k_ani_reset(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530468{
Sujithf1dc5602008-10-29 10:16:30 +0530469 struct ar5416AniState *aniState;
Sujith2660b812009-02-09 13:27:26 +0530470 struct ath9k_channel *chan = ah->curchan;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700471 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530472 int index;
473
474 if (!DO_ANI(ah))
475 return;
476
477 index = ath9k_hw_get_ani_channel_idx(ah, chan);
Sujith2660b812009-02-09 13:27:26 +0530478 aniState = &ah->ani[index];
479 ah->curani = aniState;
Sujithf1dc5602008-10-29 10:16:30 +0530480
Sujith2660b812009-02-09 13:27:26 +0530481 if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
482 && ah->opmode != NL80211_IFTYPE_ADHOC) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700483 ath_print(common, ATH_DBG_ANI,
484 "Reset ANI state opmode %u\n", ah->opmode);
Sujith2660b812009-02-09 13:27:26 +0530485 ah->stats.ast_ani_reset++;
Sujithf1dc5602008-10-29 10:16:30 +0530486
Luis R. Rodriguezc66284f2009-07-16 10:17:35 -0700487 if (ah->opmode == NL80211_IFTYPE_AP) {
488 /*
489 * ath9k_hw_ani_control() will only process items set on
490 * ah->ani_function
491 */
492 if (IS_CHAN_2GHZ(chan))
493 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
494 ATH9K_ANI_FIRSTEP_LEVEL);
495 else
496 ah->ani_function = 0;
497 }
498
Sujithf1dc5602008-10-29 10:16:30 +0530499 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
500 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
501 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
502 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
503 !ATH9K_ANI_USE_OFDM_WEAK_SIG);
504 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
505 ATH9K_ANI_CCK_WEAK_SIG_THR);
506
507 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
508 ATH9K_RX_FILTER_PHYERR);
509
Sujith2660b812009-02-09 13:27:26 +0530510 if (ah->opmode == NL80211_IFTYPE_AP) {
511 ah->curani->ofdmTrigHigh =
512 ah->config.ofdm_trig_high;
513 ah->curani->ofdmTrigLow =
514 ah->config.ofdm_trig_low;
515 ah->curani->cckTrigHigh =
516 ah->config.cck_trig_high;
517 ah->curani->cckTrigLow =
518 ah->config.cck_trig_low;
Sujithf1dc5602008-10-29 10:16:30 +0530519 }
520 ath9k_ani_restart(ah);
521 return;
522 }
523
524 if (aniState->noiseImmunityLevel != 0)
525 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
526 aniState->noiseImmunityLevel);
527 if (aniState->spurImmunityLevel != 0)
528 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
529 aniState->spurImmunityLevel);
530 if (aniState->ofdmWeakSigDetectOff)
531 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
532 !aniState->ofdmWeakSigDetectOff);
533 if (aniState->cckWeakSigThreshold)
534 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
535 aniState->cckWeakSigThreshold);
536 if (aniState->firstepLevel != 0)
537 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
538 aniState->firstepLevel);
Sujithf1dc5602008-10-29 10:16:30 +0530539
Sujith1aa8e842009-08-13 09:34:25 +0530540 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
541 ~ATH9K_RX_FILTER_PHYERR);
542 ath9k_ani_restart(ah);
543 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
544 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
Sujithf1dc5602008-10-29 10:16:30 +0530545}
546
Sujithcbe61d82009-02-09 13:27:12 +0530547void ath9k_hw_ani_monitor(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530548 struct ath9k_channel *chan)
549{
Sujithf1dc5602008-10-29 10:16:30 +0530550 struct ar5416AniState *aniState;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700551 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530552 int32_t listenTime;
Sujith1aa8e842009-08-13 09:34:25 +0530553 u32 phyCnt1, phyCnt2;
554 u32 ofdmPhyErrCnt, cckPhyErrCnt;
Sujithf1dc5602008-10-29 10:16:30 +0530555
Gabor Juhos99506882009-01-14 20:17:11 +0100556 if (!DO_ANI(ah))
557 return;
558
Sujith2660b812009-02-09 13:27:26 +0530559 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530560
561 listenTime = ath9k_hw_ani_get_listen_time(ah);
562 if (listenTime < 0) {
Sujith2660b812009-02-09 13:27:26 +0530563 ah->stats.ast_ani_lneg++;
Sujithf1dc5602008-10-29 10:16:30 +0530564 ath9k_ani_restart(ah);
565 return;
566 }
567
568 aniState->listenTime += listenTime;
569
Sujith1aa8e842009-08-13 09:34:25 +0530570 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujithf1dc5602008-10-29 10:16:30 +0530571
Sujith1aa8e842009-08-13 09:34:25 +0530572 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
573 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
Sujithf1dc5602008-10-29 10:16:30 +0530574
Sujith1aa8e842009-08-13 09:34:25 +0530575 if (phyCnt1 < aniState->ofdmPhyErrBase ||
576 phyCnt2 < aniState->cckPhyErrBase) {
577 if (phyCnt1 < aniState->ofdmPhyErrBase) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700578 ath_print(common, ATH_DBG_ANI,
579 "phyCnt1 0x%x, resetting "
580 "counter value to 0x%x\n",
581 phyCnt1,
582 aniState->ofdmPhyErrBase);
Sujith1aa8e842009-08-13 09:34:25 +0530583 REG_WRITE(ah, AR_PHY_ERR_1,
584 aniState->ofdmPhyErrBase);
585 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
586 AR_PHY_ERR_OFDM_TIMING);
Sujithf1dc5602008-10-29 10:16:30 +0530587 }
Sujith1aa8e842009-08-13 09:34:25 +0530588 if (phyCnt2 < aniState->cckPhyErrBase) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700589 ath_print(common, ATH_DBG_ANI,
590 "phyCnt2 0x%x, resetting "
591 "counter value to 0x%x\n",
592 phyCnt2,
593 aniState->cckPhyErrBase);
Sujith1aa8e842009-08-13 09:34:25 +0530594 REG_WRITE(ah, AR_PHY_ERR_2,
595 aniState->cckPhyErrBase);
596 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
597 AR_PHY_ERR_CCK_TIMING);
598 }
599 return;
Sujithf1dc5602008-10-29 10:16:30 +0530600 }
601
Sujith1aa8e842009-08-13 09:34:25 +0530602 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
603 ah->stats.ast_ani_ofdmerrs +=
604 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
605 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
606
607 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
608 ah->stats.ast_ani_cckerrs +=
609 cckPhyErrCnt - aniState->cckPhyErrCount;
610 aniState->cckPhyErrCount = cckPhyErrCnt;
611
Sujith2660b812009-02-09 13:27:26 +0530612 if (aniState->listenTime > 5 * ah->aniperiod) {
Sujithf1dc5602008-10-29 10:16:30 +0530613 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
614 aniState->ofdmTrigLow / 1000 &&
615 aniState->cckPhyErrCount <= aniState->listenTime *
616 aniState->cckTrigLow / 1000)
617 ath9k_hw_ani_lower_immunity(ah);
618 ath9k_ani_restart(ah);
Sujith2660b812009-02-09 13:27:26 +0530619 } else if (aniState->listenTime > ah->aniperiod) {
Sujithf1dc5602008-10-29 10:16:30 +0530620 if (aniState->ofdmPhyErrCount > aniState->listenTime *
621 aniState->ofdmTrigHigh / 1000) {
622 ath9k_hw_ani_ofdm_err_trigger(ah);
623 ath9k_ani_restart(ah);
624 } else if (aniState->cckPhyErrCount >
625 aniState->listenTime * aniState->cckTrigHigh /
626 1000) {
627 ath9k_hw_ani_cck_err_trigger(ah);
628 ath9k_ani_restart(ah);
629 }
630 }
631}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400632EXPORT_SYMBOL(ath9k_hw_ani_monitor);
Sujithf1dc5602008-10-29 10:16:30 +0530633
Sujithcbe61d82009-02-09 13:27:12 +0530634void ath9k_enable_mib_counters(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530635{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700636 struct ath_common *common = ath9k_hw_common(ah);
637
638 ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n");
Sujithf1dc5602008-10-29 10:16:30 +0530639
Sujithcbe61d82009-02-09 13:27:12 +0530640 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujithf1dc5602008-10-29 10:16:30 +0530641
642 REG_WRITE(ah, AR_FILT_OFDM, 0);
643 REG_WRITE(ah, AR_FILT_CCK, 0);
644 REG_WRITE(ah, AR_MIBC,
645 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
646 & 0x0f);
647 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
648 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
649}
650
Sujith0fd06c92009-02-12 10:06:51 +0530651/* Freeze the MIB counters, get the stats and then clear them */
Sujithcbe61d82009-02-09 13:27:12 +0530652void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530653{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700654 struct ath_common *common = ath9k_hw_common(ah);
655
656 ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n");
657
Sujith0fd06c92009-02-12 10:06:51 +0530658 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
Sujithcbe61d82009-02-09 13:27:12 +0530659 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujith0fd06c92009-02-12 10:06:51 +0530660 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
Sujithf1dc5602008-10-29 10:16:30 +0530661 REG_WRITE(ah, AR_FILT_OFDM, 0);
662 REG_WRITE(ah, AR_FILT_CCK, 0);
663}
664
Sujithcbe61d82009-02-09 13:27:12 +0530665u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530666 u32 *rxc_pcnt,
667 u32 *rxf_pcnt,
668 u32 *txf_pcnt)
669{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700670 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530671 static u32 cycles, rx_clear, rx_frame, tx_frame;
672 u32 good = 1;
673
674 u32 rc = REG_READ(ah, AR_RCCNT);
675 u32 rf = REG_READ(ah, AR_RFCNT);
676 u32 tf = REG_READ(ah, AR_TFCNT);
677 u32 cc = REG_READ(ah, AR_CCCNT);
678
679 if (cycles == 0 || cycles > cc) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700680 ath_print(common, ATH_DBG_ANI,
681 "cycle counter wrap. ExtBusy = 0\n");
Sujithf1dc5602008-10-29 10:16:30 +0530682 good = 0;
683 } else {
684 u32 cc_d = cc - cycles;
685 u32 rc_d = rc - rx_clear;
686 u32 rf_d = rf - rx_frame;
687 u32 tf_d = tf - tx_frame;
688
689 if (cc_d != 0) {
690 *rxc_pcnt = rc_d * 100 / cc_d;
691 *rxf_pcnt = rf_d * 100 / cc_d;
692 *txf_pcnt = tf_d * 100 / cc_d;
693 } else {
694 good = 0;
695 }
696 }
697
698 cycles = cc;
699 rx_frame = rf;
700 rx_clear = rc;
701 tx_frame = tf;
702
703 return good;
704}
705
706/*
707 * Process a MIB interrupt. We may potentially be invoked because
708 * any of the MIB counters overflow/trigger so don't assume we're
709 * here because a PHY error counter triggered.
710 */
Vasanthakumar Thiagarajan22e66a42009-08-19 16:23:40 +0530711void ath9k_hw_procmibevent(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530712{
Sujithf1dc5602008-10-29 10:16:30 +0530713 u32 phyCnt1, phyCnt2;
714
715 /* Reset these counters regardless */
716 REG_WRITE(ah, AR_FILT_OFDM, 0);
717 REG_WRITE(ah, AR_FILT_CCK, 0);
718 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
719 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
720
721 /* Clear the mib counters and save them in the stats */
Sujithcbe61d82009-02-09 13:27:12 +0530722 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujithf1dc5602008-10-29 10:16:30 +0530723
724 if (!DO_ANI(ah))
725 return;
726
727 /* NB: these are not reset-on-read */
728 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
729 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
730 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
731 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
Sujith2660b812009-02-09 13:27:26 +0530732 struct ar5416AniState *aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530733 u32 ofdmPhyErrCnt, cckPhyErrCnt;
734
735 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
736 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
Sujith2660b812009-02-09 13:27:26 +0530737 ah->stats.ast_ani_ofdmerrs +=
Sujithf1dc5602008-10-29 10:16:30 +0530738 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
739 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
740
741 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
Sujith2660b812009-02-09 13:27:26 +0530742 ah->stats.ast_ani_cckerrs +=
Sujithf1dc5602008-10-29 10:16:30 +0530743 cckPhyErrCnt - aniState->cckPhyErrCount;
744 aniState->cckPhyErrCount = cckPhyErrCnt;
745
746 /*
747 * NB: figure out which counter triggered. If both
748 * trigger we'll only deal with one as the processing
749 * clobbers the error counter so the trigger threshold
750 * check will never be true.
751 */
752 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
753 ath9k_hw_ani_ofdm_err_trigger(ah);
754 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
755 ath9k_hw_ani_cck_err_trigger(ah);
756 /* NB: always restart to insure the h/w counters are reset */
757 ath9k_ani_restart(ah);
758 }
759}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400760EXPORT_SYMBOL(ath9k_hw_procmibevent);
Sujithf1dc5602008-10-29 10:16:30 +0530761
Sujithcbe61d82009-02-09 13:27:12 +0530762void ath9k_hw_ani_setup(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530763{
Sujithf1dc5602008-10-29 10:16:30 +0530764 int i;
765
766 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
767 const int coarseHigh[] = { -14, -14, -14, -14, -12 };
768 const int coarseLow[] = { -64, -64, -64, -64, -70 };
769 const int firpwr[] = { -78, -78, -78, -78, -80 };
770
771 for (i = 0; i < 5; i++) {
Sujith2660b812009-02-09 13:27:26 +0530772 ah->totalSizeDesired[i] = totalSizeDesired[i];
773 ah->coarse_high[i] = coarseHigh[i];
774 ah->coarse_low[i] = coarseLow[i];
775 ah->firpwr[i] = firpwr[i];
Sujithf1dc5602008-10-29 10:16:30 +0530776 }
777}
778
Luis R. Rodriguezf637cfd2009-08-03 12:24:46 -0700779void ath9k_hw_ani_init(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530780{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700781 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530782 int i;
783
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700784 ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
Sujithf1dc5602008-10-29 10:16:30 +0530785
Sujith2660b812009-02-09 13:27:26 +0530786 memset(ah->ani, 0, sizeof(ah->ani));
787 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
788 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
789 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
790 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
791 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
792 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
793 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
794 ah->ani[i].ofdmWeakSigDetectOff =
Sujithf1dc5602008-10-29 10:16:30 +0530795 !ATH9K_ANI_USE_OFDM_WEAK_SIG;
Sujith2660b812009-02-09 13:27:26 +0530796 ah->ani[i].cckWeakSigThreshold =
Sujithf1dc5602008-10-29 10:16:30 +0530797 ATH9K_ANI_CCK_WEAK_SIG_THR;
Sujith2660b812009-02-09 13:27:26 +0530798 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
799 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
Sujith1aa8e842009-08-13 09:34:25 +0530800 ah->ani[i].ofdmPhyErrBase =
801 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
802 ah->ani[i].cckPhyErrBase =
803 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
Sujithf1dc5602008-10-29 10:16:30 +0530804 }
Sujithf1dc5602008-10-29 10:16:30 +0530805
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700806 ath_print(common, ATH_DBG_ANI,
807 "Setting OfdmErrBase = 0x%08x\n",
808 ah->ani[0].ofdmPhyErrBase);
809 ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
810 ah->ani[0].cckPhyErrBase);
Sujith1aa8e842009-08-13 09:34:25 +0530811
812 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
813 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
814 ath9k_enable_mib_counters(ah);
815
Sujith2660b812009-02-09 13:27:26 +0530816 ah->aniperiod = ATH9K_ANI_PERIOD;
817 if (ah->config.enable_ani)
818 ah->proc_phyerr |= HAL_PROCESS_ANI;
Sujithf1dc5602008-10-29 10:16:30 +0530819}
820
Luis R. Rodrigueze70c0cf2009-08-03 12:24:51 -0700821void ath9k_hw_ani_disable(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530822{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700823 ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
Sujithf1dc5602008-10-29 10:16:30 +0530824
Sujith1aa8e842009-08-13 09:34:25 +0530825 ath9k_hw_disable_mib_counters(ah);
826 REG_WRITE(ah, AR_PHY_ERR_1, 0);
827 REG_WRITE(ah, AR_PHY_ERR_2, 0);
Sujithf1dc5602008-10-29 10:16:30 +0530828}