blob: aad259b4c1979c01f698a8354bb6c6d8374fb2c0 [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
Sujith394cf0a2009-02-09 13:26:54 +053017#include "ath9k.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
34 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
35 "No more channel states left. Using channel 0\n");
36
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;
Sujithf1dc5602008-10-29 10:16:30 +053044
Sujith2660b812009-02-09 13:27:26 +053045 switch (cmd & ah->ani_function) {
Sujithf1dc5602008-10-29 10:16:30 +053046 case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
47 u32 level = param;
48
Sujith2660b812009-02-09 13:27:26 +053049 if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
Sujithf1dc5602008-10-29 10:16:30 +053050 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +053051 "level out of range (%u > %u)\n",
52 level,
Sujith2660b812009-02-09 13:27:26 +053053 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
Sujithf1dc5602008-10-29 10:16:30 +053054 return false;
55 }
56
57 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
58 AR_PHY_DESIRED_SZ_TOT_DES,
Sujith2660b812009-02-09 13:27:26 +053059 ah->totalSizeDesired[level]);
Sujithf1dc5602008-10-29 10:16:30 +053060 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
61 AR_PHY_AGC_CTL1_COARSE_LOW,
Sujith2660b812009-02-09 13:27:26 +053062 ah->coarse_low[level]);
Sujithf1dc5602008-10-29 10:16:30 +053063 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
64 AR_PHY_AGC_CTL1_COARSE_HIGH,
Sujith2660b812009-02-09 13:27:26 +053065 ah->coarse_high[level]);
Sujithf1dc5602008-10-29 10:16:30 +053066 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
67 AR_PHY_FIND_SIG_FIRPWR,
Sujith2660b812009-02-09 13:27:26 +053068 ah->firpwr[level]);
Sujithf1dc5602008-10-29 10:16:30 +053069
70 if (level > aniState->noiseImmunityLevel)
Sujith2660b812009-02-09 13:27:26 +053071 ah->stats.ast_ani_niup++;
Sujithf1dc5602008-10-29 10:16:30 +053072 else if (level < aniState->noiseImmunityLevel)
Sujith2660b812009-02-09 13:27:26 +053073 ah->stats.ast_ani_nidown++;
Sujithf1dc5602008-10-29 10:16:30 +053074 aniState->noiseImmunityLevel = level;
75 break;
76 }
77 case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
78 const int m1ThreshLow[] = { 127, 50 };
79 const int m2ThreshLow[] = { 127, 40 };
80 const int m1Thresh[] = { 127, 0x4d };
81 const int m2Thresh[] = { 127, 0x40 };
82 const int m2CountThr[] = { 31, 16 };
83 const int m2CountThrLow[] = { 63, 48 };
84 u32 on = param ? 1 : 0;
85
86 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
87 AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
88 m1ThreshLow[on]);
89 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
90 AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
91 m2ThreshLow[on]);
92 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
93 AR_PHY_SFCORR_M1_THRESH,
94 m1Thresh[on]);
95 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
96 AR_PHY_SFCORR_M2_THRESH,
97 m2Thresh[on]);
98 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
99 AR_PHY_SFCORR_M2COUNT_THR,
100 m2CountThr[on]);
101 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
102 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
103 m2CountThrLow[on]);
104
105 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
106 AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
107 m1ThreshLow[on]);
108 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
109 AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
110 m2ThreshLow[on]);
111 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
112 AR_PHY_SFCORR_EXT_M1_THRESH,
113 m1Thresh[on]);
114 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
115 AR_PHY_SFCORR_EXT_M2_THRESH,
116 m2Thresh[on]);
117
118 if (on)
119 REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
120 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
121 else
122 REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
123 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
124
125 if (!on != aniState->ofdmWeakSigDetectOff) {
126 if (on)
Sujith2660b812009-02-09 13:27:26 +0530127 ah->stats.ast_ani_ofdmon++;
Sujithf1dc5602008-10-29 10:16:30 +0530128 else
Sujith2660b812009-02-09 13:27:26 +0530129 ah->stats.ast_ani_ofdmoff++;
Sujithf1dc5602008-10-29 10:16:30 +0530130 aniState->ofdmWeakSigDetectOff = !on;
131 }
132 break;
133 }
134 case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
135 const int weakSigThrCck[] = { 8, 6 };
136 u32 high = param ? 1 : 0;
137
138 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
139 AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
140 weakSigThrCck[high]);
141 if (high != aniState->cckWeakSigThreshold) {
142 if (high)
Sujith2660b812009-02-09 13:27:26 +0530143 ah->stats.ast_ani_cckhigh++;
Sujithf1dc5602008-10-29 10:16:30 +0530144 else
Sujith2660b812009-02-09 13:27:26 +0530145 ah->stats.ast_ani_ccklow++;
Sujithf1dc5602008-10-29 10:16:30 +0530146 aniState->cckWeakSigThreshold = high;
147 }
148 break;
149 }
150 case ATH9K_ANI_FIRSTEP_LEVEL:{
151 const int firstep[] = { 0, 4, 8 };
152 u32 level = param;
153
154 if (level >= ARRAY_SIZE(firstep)) {
155 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530156 "level out of range (%u > %u)\n",
157 level,
Sujithf1dc5602008-10-29 10:16:30 +0530158 (unsigned) ARRAY_SIZE(firstep));
159 return false;
160 }
161 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
162 AR_PHY_FIND_SIG_FIRSTEP,
163 firstep[level]);
164 if (level > aniState->firstepLevel)
Sujith2660b812009-02-09 13:27:26 +0530165 ah->stats.ast_ani_stepup++;
Sujithf1dc5602008-10-29 10:16:30 +0530166 else if (level < aniState->firstepLevel)
Sujith2660b812009-02-09 13:27:26 +0530167 ah->stats.ast_ani_stepdown++;
Sujithf1dc5602008-10-29 10:16:30 +0530168 aniState->firstepLevel = level;
169 break;
170 }
171 case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
172 const int cycpwrThr1[] =
173 { 2, 4, 6, 8, 10, 12, 14, 16 };
174 u32 level = param;
175
176 if (level >= ARRAY_SIZE(cycpwrThr1)) {
177 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530178 "level out of range (%u > %u)\n",
179 level,
Sujithf1dc5602008-10-29 10:16:30 +0530180 (unsigned)
181 ARRAY_SIZE(cycpwrThr1));
182 return false;
183 }
184 REG_RMW_FIELD(ah, AR_PHY_TIMING5,
185 AR_PHY_TIMING5_CYCPWR_THR1,
186 cycpwrThr1[level]);
187 if (level > aniState->spurImmunityLevel)
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:
197 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530198 "invalid cmd %u\n", cmd);
Sujithf1dc5602008-10-29 10:16:30 +0530199 return false;
200 }
201
Sujith04bd4632008-11-28 22:18:05 +0530202 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n");
Sujithf1dc5602008-10-29 10:16:30 +0530203 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
204 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
205 "ofdmWeakSigDetectOff=%d\n",
206 aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
207 !aniState->ofdmWeakSigDetectOff);
208 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
209 "cckWeakSigThreshold=%d, "
210 "firstepLevel=%d, listenTime=%d\n",
211 aniState->cckWeakSigThreshold, aniState->firstepLevel,
212 aniState->listenTime);
213 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
214 "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
215 aniState->cycleCount, aniState->ofdmPhyErrCount,
216 aniState->cckPhyErrCount);
217
218 return true;
219}
220
Sujithcbe61d82009-02-09 13:27:12 +0530221static void ath9k_hw_update_mibstats(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530222 struct ath9k_mib_stats *stats)
223{
224 stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
225 stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
226 stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
227 stats->rts_good += REG_READ(ah, AR_RTS_OK);
228 stats->beacons += REG_READ(ah, AR_BEACON_CNT);
229}
230
Sujithcbe61d82009-02-09 13:27:12 +0530231static void ath9k_ani_restart(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530232{
Sujithf1dc5602008-10-29 10:16:30 +0530233 struct ar5416AniState *aniState;
234
235 if (!DO_ANI(ah))
236 return;
237
Sujith2660b812009-02-09 13:27:26 +0530238 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530239
240 aniState->listenTime = 0;
Sujith2660b812009-02-09 13:27:26 +0530241 if (ah->has_hw_phycounters) {
Sujithf1dc5602008-10-29 10:16:30 +0530242 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
243 aniState->ofdmPhyErrBase = 0;
244 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
245 "OFDM Trigger is too high for hw counters\n");
246 } else {
247 aniState->ofdmPhyErrBase =
248 AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
249 }
250 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
251 aniState->cckPhyErrBase = 0;
252 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
253 "CCK Trigger is too high for hw counters\n");
254 } else {
255 aniState->cckPhyErrBase =
256 AR_PHY_COUNTMAX - aniState->cckTrigHigh;
257 }
258 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530259 "Writing ofdmbase=%u cckbase=%u\n",
260 aniState->ofdmPhyErrBase,
Sujithf1dc5602008-10-29 10:16:30 +0530261 aniState->cckPhyErrBase);
262 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
263 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
264 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
265 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
266
Sujithcbe61d82009-02-09 13:27:12 +0530267 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujithf1dc5602008-10-29 10:16:30 +0530268 }
269 aniState->ofdmPhyErrCount = 0;
270 aniState->cckPhyErrCount = 0;
271}
272
Sujithcbe61d82009-02-09 13:27:12 +0530273static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530274{
Luis R. Rodriguez38b33702008-12-23 15:58:46 -0800275 struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
Sujithf1dc5602008-10-29 10:16:30 +0530276 struct ar5416AniState *aniState;
Sujithf1dc5602008-10-29 10:16:30 +0530277 int32_t rssi;
278
279 if (!DO_ANI(ah))
280 return;
281
Sujith2660b812009-02-09 13:27:26 +0530282 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530283
284 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
285 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
286 aniState->noiseImmunityLevel + 1)) {
287 return;
288 }
289 }
290
291 if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
292 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
293 aniState->spurImmunityLevel + 1)) {
294 return;
295 }
296 }
297
Sujith2660b812009-02-09 13:27:26 +0530298 if (ah->opmode == NL80211_IFTYPE_AP) {
Sujithf1dc5602008-10-29 10:16:30 +0530299 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
300 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
301 aniState->firstepLevel + 1);
302 }
303 return;
304 }
Sujithcbe61d82009-02-09 13:27:12 +0530305 rssi = BEACON_RSSI(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530306 if (rssi > aniState->rssiThrHigh) {
307 if (!aniState->ofdmWeakSigDetectOff) {
308 if (ath9k_hw_ani_control(ah,
309 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
310 false)) {
311 ath9k_hw_ani_control(ah,
312 ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
313 return;
314 }
315 }
316 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
317 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
318 aniState->firstepLevel + 1);
319 return;
320 }
321 } else if (rssi > aniState->rssiThrLow) {
322 if (aniState->ofdmWeakSigDetectOff)
323 ath9k_hw_ani_control(ah,
324 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
325 true);
326 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
327 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
328 aniState->firstepLevel + 1);
329 return;
330 } else {
Luis R. Rodriguez38b33702008-12-23 15:58:46 -0800331 if (conf->channel->band == IEEE80211_BAND_2GHZ) {
Sujithf1dc5602008-10-29 10:16:30 +0530332 if (!aniState->ofdmWeakSigDetectOff)
333 ath9k_hw_ani_control(ah,
334 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
335 false);
336 if (aniState->firstepLevel > 0)
337 ath9k_hw_ani_control(ah,
338 ATH9K_ANI_FIRSTEP_LEVEL, 0);
339 return;
340 }
341 }
342}
343
Sujithcbe61d82009-02-09 13:27:12 +0530344static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530345{
Luis R. Rodriguez38b33702008-12-23 15:58:46 -0800346 struct ieee80211_conf *conf = &ah->ah_sc->hw->conf;
Sujithf1dc5602008-10-29 10:16:30 +0530347 struct ar5416AniState *aniState;
Sujithf1dc5602008-10-29 10:16:30 +0530348 int32_t rssi;
349
350 if (!DO_ANI(ah))
351 return;
352
Sujith2660b812009-02-09 13:27:26 +0530353 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530354 if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
355 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
356 aniState->noiseImmunityLevel + 1)) {
357 return;
358 }
359 }
Sujith2660b812009-02-09 13:27:26 +0530360 if (ah->opmode == NL80211_IFTYPE_AP) {
Sujithf1dc5602008-10-29 10:16:30 +0530361 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
362 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
363 aniState->firstepLevel + 1);
364 }
365 return;
366 }
Sujithcbe61d82009-02-09 13:27:12 +0530367 rssi = BEACON_RSSI(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530368 if (rssi > aniState->rssiThrLow) {
369 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
370 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
371 aniState->firstepLevel + 1);
372 } else {
Luis R. Rodriguez38b33702008-12-23 15:58:46 -0800373 if (conf->channel->band == IEEE80211_BAND_2GHZ) {
Sujithf1dc5602008-10-29 10:16:30 +0530374 if (aniState->firstepLevel > 0)
375 ath9k_hw_ani_control(ah,
376 ATH9K_ANI_FIRSTEP_LEVEL, 0);
377 }
378 }
379}
380
Sujithcbe61d82009-02-09 13:27:12 +0530381static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530382{
Sujithf1dc5602008-10-29 10:16:30 +0530383 struct ar5416AniState *aniState;
384 int32_t rssi;
385
Sujith2660b812009-02-09 13:27:26 +0530386 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530387
Sujith2660b812009-02-09 13:27:26 +0530388 if (ah->opmode == NL80211_IFTYPE_AP) {
Sujithf1dc5602008-10-29 10:16:30 +0530389 if (aniState->firstepLevel > 0) {
390 if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
391 aniState->firstepLevel - 1))
392 return;
393 }
394 } else {
Sujithcbe61d82009-02-09 13:27:12 +0530395 rssi = BEACON_RSSI(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530396 if (rssi > aniState->rssiThrHigh) {
397 /* XXX: Handle me */
398 } else if (rssi > aniState->rssiThrLow) {
399 if (aniState->ofdmWeakSigDetectOff) {
400 if (ath9k_hw_ani_control(ah,
401 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
402 true) == true)
403 return;
404 }
405 if (aniState->firstepLevel > 0) {
406 if (ath9k_hw_ani_control(ah,
407 ATH9K_ANI_FIRSTEP_LEVEL,
408 aniState->firstepLevel - 1) == true)
409 return;
410 }
411 } else {
412 if (aniState->firstepLevel > 0) {
413 if (ath9k_hw_ani_control(ah,
414 ATH9K_ANI_FIRSTEP_LEVEL,
415 aniState->firstepLevel - 1) == true)
416 return;
417 }
418 }
419 }
420
421 if (aniState->spurImmunityLevel > 0) {
422 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
423 aniState->spurImmunityLevel - 1))
424 return;
425 }
426
427 if (aniState->noiseImmunityLevel > 0) {
428 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
429 aniState->noiseImmunityLevel - 1);
430 return;
431 }
432}
433
Sujithcbe61d82009-02-09 13:27:12 +0530434static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530435{
Sujithf1dc5602008-10-29 10:16:30 +0530436 struct ar5416AniState *aniState;
437 u32 txFrameCount, rxFrameCount, cycleCount;
438 int32_t listenTime;
439
440 txFrameCount = REG_READ(ah, AR_TFCNT);
441 rxFrameCount = REG_READ(ah, AR_RFCNT);
442 cycleCount = REG_READ(ah, AR_CCCNT);
443
Sujith2660b812009-02-09 13:27:26 +0530444 aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530445 if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
446
447 listenTime = 0;
Sujith2660b812009-02-09 13:27:26 +0530448 ah->stats.ast_ani_lzero++;
Sujithf1dc5602008-10-29 10:16:30 +0530449 } else {
450 int32_t ccdelta = cycleCount - aniState->cycleCount;
451 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
452 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
453 listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
454 }
455 aniState->cycleCount = cycleCount;
456 aniState->txFrameCount = txFrameCount;
457 aniState->rxFrameCount = rxFrameCount;
458
459 return listenTime;
460}
461
Sujithcbe61d82009-02-09 13:27:12 +0530462void ath9k_ani_reset(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530463{
Sujithf1dc5602008-10-29 10:16:30 +0530464 struct ar5416AniState *aniState;
Sujith2660b812009-02-09 13:27:26 +0530465 struct ath9k_channel *chan = ah->curchan;
Sujithf1dc5602008-10-29 10:16:30 +0530466 int index;
467
468 if (!DO_ANI(ah))
469 return;
470
471 index = ath9k_hw_get_ani_channel_idx(ah, chan);
Sujith2660b812009-02-09 13:27:26 +0530472 aniState = &ah->ani[index];
473 ah->curani = aniState;
Sujithf1dc5602008-10-29 10:16:30 +0530474
Sujith2660b812009-02-09 13:27:26 +0530475 if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
476 && ah->opmode != NL80211_IFTYPE_ADHOC) {
Sujithf1dc5602008-10-29 10:16:30 +0530477 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith2660b812009-02-09 13:27:26 +0530478 "Reset ANI state opmode %u\n", ah->opmode);
479 ah->stats.ast_ani_reset++;
Sujithf1dc5602008-10-29 10:16:30 +0530480
Luis R. Rodriguezc66284f2009-07-16 10:17:35 -0700481 if (ah->opmode == NL80211_IFTYPE_AP) {
482 /*
483 * ath9k_hw_ani_control() will only process items set on
484 * ah->ani_function
485 */
486 if (IS_CHAN_2GHZ(chan))
487 ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
488 ATH9K_ANI_FIRSTEP_LEVEL);
489 else
490 ah->ani_function = 0;
491 }
492
Sujithf1dc5602008-10-29 10:16:30 +0530493 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
494 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
495 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
496 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
497 !ATH9K_ANI_USE_OFDM_WEAK_SIG);
498 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
499 ATH9K_ANI_CCK_WEAK_SIG_THR);
500
501 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
502 ATH9K_RX_FILTER_PHYERR);
503
Sujith2660b812009-02-09 13:27:26 +0530504 if (ah->opmode == NL80211_IFTYPE_AP) {
505 ah->curani->ofdmTrigHigh =
506 ah->config.ofdm_trig_high;
507 ah->curani->ofdmTrigLow =
508 ah->config.ofdm_trig_low;
509 ah->curani->cckTrigHigh =
510 ah->config.cck_trig_high;
511 ah->curani->cckTrigLow =
512 ah->config.cck_trig_low;
Sujithf1dc5602008-10-29 10:16:30 +0530513 }
514 ath9k_ani_restart(ah);
515 return;
516 }
517
518 if (aniState->noiseImmunityLevel != 0)
519 ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
520 aniState->noiseImmunityLevel);
521 if (aniState->spurImmunityLevel != 0)
522 ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
523 aniState->spurImmunityLevel);
524 if (aniState->ofdmWeakSigDetectOff)
525 ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
526 !aniState->ofdmWeakSigDetectOff);
527 if (aniState->cckWeakSigThreshold)
528 ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
529 aniState->cckWeakSigThreshold);
530 if (aniState->firstepLevel != 0)
531 ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
532 aniState->firstepLevel);
Sujith2660b812009-02-09 13:27:26 +0530533 if (ah->has_hw_phycounters) {
Sujithf1dc5602008-10-29 10:16:30 +0530534 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
535 ~ATH9K_RX_FILTER_PHYERR);
536 ath9k_ani_restart(ah);
537 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
538 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
539
540 } else {
541 ath9k_ani_restart(ah);
542 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
543 ATH9K_RX_FILTER_PHYERR);
544 }
545}
546
Sujithcbe61d82009-02-09 13:27:12 +0530547void ath9k_hw_ani_monitor(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530548 const struct ath9k_node_stats *stats,
549 struct ath9k_channel *chan)
550{
Sujithf1dc5602008-10-29 10:16:30 +0530551 struct ar5416AniState *aniState;
552 int32_t listenTime;
553
Gabor Juhos99506882009-01-14 20:17:11 +0100554 if (!DO_ANI(ah))
555 return;
556
Sujith2660b812009-02-09 13:27:26 +0530557 aniState = ah->curani;
558 ah->stats.ast_nodestats = *stats;
Sujithf1dc5602008-10-29 10:16:30 +0530559
560 listenTime = ath9k_hw_ani_get_listen_time(ah);
561 if (listenTime < 0) {
Sujith2660b812009-02-09 13:27:26 +0530562 ah->stats.ast_ani_lneg++;
Sujithf1dc5602008-10-29 10:16:30 +0530563 ath9k_ani_restart(ah);
564 return;
565 }
566
567 aniState->listenTime += listenTime;
568
Sujith2660b812009-02-09 13:27:26 +0530569 if (ah->has_hw_phycounters) {
Sujithf1dc5602008-10-29 10:16:30 +0530570 u32 phyCnt1, phyCnt2;
571 u32 ofdmPhyErrCnt, cckPhyErrCnt;
572
Sujithcbe61d82009-02-09 13:27:12 +0530573 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujithf1dc5602008-10-29 10:16:30 +0530574
575 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
576 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
577
578 if (phyCnt1 < aniState->ofdmPhyErrBase ||
579 phyCnt2 < aniState->cckPhyErrBase) {
580 if (phyCnt1 < aniState->ofdmPhyErrBase) {
581 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530582 "phyCnt1 0x%x, resetting "
Sujithf1dc5602008-10-29 10:16:30 +0530583 "counter value to 0x%x\n",
Sujithd8baa932009-03-30 15:28:25 +0530584 phyCnt1, aniState->ofdmPhyErrBase);
Sujithf1dc5602008-10-29 10:16:30 +0530585 REG_WRITE(ah, AR_PHY_ERR_1,
586 aniState->ofdmPhyErrBase);
587 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
588 AR_PHY_ERR_OFDM_TIMING);
589 }
590 if (phyCnt2 < aniState->cckPhyErrBase) {
591 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530592 "phyCnt2 0x%x, resetting "
Sujithf1dc5602008-10-29 10:16:30 +0530593 "counter value to 0x%x\n",
Sujithd8baa932009-03-30 15:28:25 +0530594 phyCnt2, aniState->cckPhyErrBase);
Sujithf1dc5602008-10-29 10:16:30 +0530595 REG_WRITE(ah, AR_PHY_ERR_2,
596 aniState->cckPhyErrBase);
597 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
598 AR_PHY_ERR_CCK_TIMING);
599 }
600 return;
601 }
602
603 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
Sujith2660b812009-02-09 13:27:26 +0530604 ah->stats.ast_ani_ofdmerrs +=
Sujithf1dc5602008-10-29 10:16:30 +0530605 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
606 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
607
608 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
Sujith2660b812009-02-09 13:27:26 +0530609 ah->stats.ast_ani_cckerrs +=
Sujithf1dc5602008-10-29 10:16:30 +0530610 cckPhyErrCnt - aniState->cckPhyErrCount;
611 aniState->cckPhyErrCount = cckPhyErrCnt;
612 }
613
Sujith2660b812009-02-09 13:27:26 +0530614 if (aniState->listenTime > 5 * ah->aniperiod) {
Sujithf1dc5602008-10-29 10:16:30 +0530615 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
616 aniState->ofdmTrigLow / 1000 &&
617 aniState->cckPhyErrCount <= aniState->listenTime *
618 aniState->cckTrigLow / 1000)
619 ath9k_hw_ani_lower_immunity(ah);
620 ath9k_ani_restart(ah);
Sujith2660b812009-02-09 13:27:26 +0530621 } else if (aniState->listenTime > ah->aniperiod) {
Sujithf1dc5602008-10-29 10:16:30 +0530622 if (aniState->ofdmPhyErrCount > aniState->listenTime *
623 aniState->ofdmTrigHigh / 1000) {
624 ath9k_hw_ani_ofdm_err_trigger(ah);
625 ath9k_ani_restart(ah);
626 } else if (aniState->cckPhyErrCount >
627 aniState->listenTime * aniState->cckTrigHigh /
628 1000) {
629 ath9k_hw_ani_cck_err_trigger(ah);
630 ath9k_ani_restart(ah);
631 }
632 }
633}
634
Sujithcbe61d82009-02-09 13:27:12 +0530635bool ath9k_hw_phycounters(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530636{
Sujith2660b812009-02-09 13:27:26 +0530637 return ah->has_hw_phycounters ? true : false;
Sujithf1dc5602008-10-29 10:16:30 +0530638}
639
Sujithcbe61d82009-02-09 13:27:12 +0530640void ath9k_enable_mib_counters(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530641{
Sujithf1dc5602008-10-29 10:16:30 +0530642 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
643
Sujithcbe61d82009-02-09 13:27:12 +0530644 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujithf1dc5602008-10-29 10:16:30 +0530645
646 REG_WRITE(ah, AR_FILT_OFDM, 0);
647 REG_WRITE(ah, AR_FILT_CCK, 0);
648 REG_WRITE(ah, AR_MIBC,
649 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
650 & 0x0f);
651 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
652 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
653}
654
Sujith0fd06c92009-02-12 10:06:51 +0530655/* Freeze the MIB counters, get the stats and then clear them */
Sujithcbe61d82009-02-09 13:27:12 +0530656void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530657{
Sujithf1dc5602008-10-29 10:16:30 +0530658 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
Sujith0fd06c92009-02-12 10:06:51 +0530659 REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
Sujithcbe61d82009-02-09 13:27:12 +0530660 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujith0fd06c92009-02-12 10:06:51 +0530661 REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
Sujithf1dc5602008-10-29 10:16:30 +0530662 REG_WRITE(ah, AR_FILT_OFDM, 0);
663 REG_WRITE(ah, AR_FILT_CCK, 0);
664}
665
Sujithcbe61d82009-02-09 13:27:12 +0530666u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530667 u32 *rxc_pcnt,
668 u32 *rxf_pcnt,
669 u32 *txf_pcnt)
670{
671 static u32 cycles, rx_clear, rx_frame, tx_frame;
672 u32 good = 1;
673
674 u32 rc = REG_READ(ah, AR_RCCNT);
675 u32 rf = REG_READ(ah, AR_RFCNT);
676 u32 tf = REG_READ(ah, AR_TFCNT);
677 u32 cc = REG_READ(ah, AR_CCCNT);
678
679 if (cycles == 0 || cycles > cc) {
Sujithd8baa932009-03-30 15:28:25 +0530680 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
Sujith04bd4632008-11-28 22:18:05 +0530681 "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 */
Sujithcbe61d82009-02-09 13:27:12 +0530711void ath9k_hw_procmibevent(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530712 const struct ath9k_node_stats *stats)
713{
Sujithf1dc5602008-10-29 10:16:30 +0530714 u32 phyCnt1, phyCnt2;
715
716 /* Reset these counters regardless */
717 REG_WRITE(ah, AR_FILT_OFDM, 0);
718 REG_WRITE(ah, AR_FILT_CCK, 0);
719 if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
720 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
721
722 /* Clear the mib counters and save them in the stats */
Sujithcbe61d82009-02-09 13:27:12 +0530723 ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
Sujith2660b812009-02-09 13:27:26 +0530724 ah->stats.ast_nodestats = *stats;
Sujithf1dc5602008-10-29 10:16:30 +0530725
726 if (!DO_ANI(ah))
727 return;
728
729 /* NB: these are not reset-on-read */
730 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
731 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
732 if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
733 ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
Sujith2660b812009-02-09 13:27:26 +0530734 struct ar5416AniState *aniState = ah->curani;
Sujithf1dc5602008-10-29 10:16:30 +0530735 u32 ofdmPhyErrCnt, cckPhyErrCnt;
736
737 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
738 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
Sujith2660b812009-02-09 13:27:26 +0530739 ah->stats.ast_ani_ofdmerrs +=
Sujithf1dc5602008-10-29 10:16:30 +0530740 ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
741 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
742
743 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
Sujith2660b812009-02-09 13:27:26 +0530744 ah->stats.ast_ani_cckerrs +=
Sujithf1dc5602008-10-29 10:16:30 +0530745 cckPhyErrCnt - aniState->cckPhyErrCount;
746 aniState->cckPhyErrCount = cckPhyErrCnt;
747
748 /*
749 * NB: figure out which counter triggered. If both
750 * trigger we'll only deal with one as the processing
751 * clobbers the error counter so the trigger threshold
752 * check will never be true.
753 */
754 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
755 ath9k_hw_ani_ofdm_err_trigger(ah);
756 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
757 ath9k_hw_ani_cck_err_trigger(ah);
758 /* NB: always restart to insure the h/w counters are reset */
759 ath9k_ani_restart(ah);
760 }
761}
762
Sujithcbe61d82009-02-09 13:27:12 +0530763void ath9k_hw_ani_setup(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530764{
Sujithf1dc5602008-10-29 10:16:30 +0530765 int i;
766
767 const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
768 const int coarseHigh[] = { -14, -14, -14, -14, -12 };
769 const int coarseLow[] = { -64, -64, -64, -64, -70 };
770 const int firpwr[] = { -78, -78, -78, -78, -80 };
771
772 for (i = 0; i < 5; i++) {
Sujith2660b812009-02-09 13:27:26 +0530773 ah->totalSizeDesired[i] = totalSizeDesired[i];
774 ah->coarse_high[i] = coarseHigh[i];
775 ah->coarse_low[i] = coarseLow[i];
776 ah->firpwr[i] = firpwr[i];
Sujithf1dc5602008-10-29 10:16:30 +0530777 }
778}
779
Sujithcbe61d82009-02-09 13:27:12 +0530780void ath9k_hw_ani_attach(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530781{
Sujithf1dc5602008-10-29 10:16:30 +0530782 int i;
783
784 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
785
Sujith2660b812009-02-09 13:27:26 +0530786 ah->has_hw_phycounters = 1;
Sujithf1dc5602008-10-29 10:16:30 +0530787
Sujith2660b812009-02-09 13:27:26 +0530788 memset(ah->ani, 0, sizeof(ah->ani));
789 for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
790 ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
791 ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
792 ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
793 ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
794 ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
795 ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
796 ah->ani[i].ofdmWeakSigDetectOff =
Sujithf1dc5602008-10-29 10:16:30 +0530797 !ATH9K_ANI_USE_OFDM_WEAK_SIG;
Sujith2660b812009-02-09 13:27:26 +0530798 ah->ani[i].cckWeakSigThreshold =
Sujithf1dc5602008-10-29 10:16:30 +0530799 ATH9K_ANI_CCK_WEAK_SIG_THR;
Sujith2660b812009-02-09 13:27:26 +0530800 ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
801 ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
802 if (ah->has_hw_phycounters) {
803 ah->ani[i].ofdmPhyErrBase =
Sujithf1dc5602008-10-29 10:16:30 +0530804 AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
Sujith2660b812009-02-09 13:27:26 +0530805 ah->ani[i].cckPhyErrBase =
Sujithf1dc5602008-10-29 10:16:30 +0530806 AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
807 }
808 }
Sujith2660b812009-02-09 13:27:26 +0530809 if (ah->has_hw_phycounters) {
Sujithf1dc5602008-10-29 10:16:30 +0530810 DPRINTF(ah->ah_sc, ATH_DBG_ANI,
811 "Setting OfdmErrBase = 0x%08x\n",
Sujith2660b812009-02-09 13:27:26 +0530812 ah->ani[0].ofdmPhyErrBase);
Sujithf1dc5602008-10-29 10:16:30 +0530813 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
Sujith2660b812009-02-09 13:27:26 +0530814 ah->ani[0].cckPhyErrBase);
Sujithf1dc5602008-10-29 10:16:30 +0530815
Sujith2660b812009-02-09 13:27:26 +0530816 REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
817 REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
Sujithf1dc5602008-10-29 10:16:30 +0530818 ath9k_enable_mib_counters(ah);
819 }
Sujith2660b812009-02-09 13:27:26 +0530820 ah->aniperiod = ATH9K_ANI_PERIOD;
821 if (ah->config.enable_ani)
822 ah->proc_phyerr |= HAL_PROCESS_ANI;
Sujithf1dc5602008-10-29 10:16:30 +0530823}
824
Sujithcbe61d82009-02-09 13:27:12 +0530825void ath9k_hw_ani_detach(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530826{
Sujithf1dc5602008-10-29 10:16:30 +0530827 DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
828
Sujith2660b812009-02-09 13:27:26 +0530829 if (ah->has_hw_phycounters) {
Sujithf1dc5602008-10-29 10:16:30 +0530830 ath9k_hw_disable_mib_counters(ah);
831 REG_WRITE(ah, AR_PHY_ERR_1, 0);
832 REG_WRITE(ah, AR_PHY_ERR_2, 0);
833 }
834}