1 /*
2 * Copyright (c) 2013 Qualcomm Atheros, 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 WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "opt_ah.h"
18
19 #include "ah.h"
20 #include "ah_internal.h"
21 #include "ah_desc.h"
22 //#include "ah_pktlog.h"
23
24 #include "ar9300/ar9300.h"
25 #include "ar9300/ar9300reg.h"
26 #include "ar9300/ar9300phy.h"
27
28 extern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits);
29 extern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah);
30
31 #define HAL_ANI_DEBUG 1
32
33 /*
34 * Anti noise immunity support. We track phy errors and react
35 * to excessive errors by adjusting the noise immunity parameters.
36 */
37
38 /******************************************************************************
39 *
40 * New Ani Algorithm for Station side only
41 *
42 *****************************************************************************/
43
44 #define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */
45 #define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */
46 #define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */
47 #define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */
48 #define HAL_ANI_USE_OFDM_WEAK_SIG AH_TRUE
49 #define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */
50 #define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3
51 #define HAL_ANI_DEF_FIRSTEP_LVL 2
52 #define HAL_ANI_RSSI_THR_HIGH 40
53 #define HAL_ANI_RSSI_THR_LOW 7
54 #define HAL_ANI_PERIOD 1000
55
56 #define HAL_NOISE_DETECT_PERIOD 100
57 #define HAL_NOISE_RECOVER_PERIOD 5000
58
59 #define HAL_SIG_FIRSTEP_SETTING_MIN 0
60 #define HAL_SIG_FIRSTEP_SETTING_MAX 20
61 #define HAL_SIG_SPUR_IMM_SETTING_MIN 0
62 #define HAL_SIG_SPUR_IMM_SETTING_MAX 22
63
64 #define HAL_EP_RND(x, mul) \
65 ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul))
66 #define BEACON_RSSI(ahp) \
67 HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
68 HAL_RSSI_EP_MULTIPLIER)
69
70 typedef int TABLE[];
71 /*
72 * level: 0 1 2 3 4 5 6 7 8
73 * firstep_table: lvl 0-8, default 2
74 */
75 static const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12};
76 /* cycpwr_thr1_table: lvl 0-7, default 3 */
77 static const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 };
78 /* values here are relative to the INI */
79
80 typedef struct _HAL_ANI_OFDM_LEVEL_ENTRY {
81 int spur_immunity_level;
82 int fir_step_level;
83 int ofdm_weak_signal_on;
84 } HAL_ANI_OFDM_LEVEL_ENTRY;
85 static const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = {
86 /* SI FS WS */
87 { 0, 0, 1 }, /* lvl 0 */
88 { 1, 1, 1 }, /* lvl 1 */
89 { 2, 2, 1 }, /* lvl 2 */
90 { 3, 2, 1 }, /* lvl 3 (default) */
91 { 4, 3, 1 }, /* lvl 4 */
92 { 5, 4, 1 }, /* lvl 5 */
93 { 6, 5, 1 }, /* lvl 6 */
94 { 7, 6, 1 }, /* lvl 7 */
95 { 7, 7, 1 }, /* lvl 8 */
96 { 7, 8, 0 } /* lvl 9 */
97 };
98 #define HAL_ANI_OFDM_NUM_LEVEL \
99 (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0]))
100 #define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1)
101 #define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */
102
103 typedef struct _HAL_ANI_CCK_LEVEL_ENTRY {
104 int fir_step_level;
105 int mrc_cck_on;
106 } HAL_ANI_CCK_LEVEL_ENTRY;
107
108 static const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = {
109 /* FS MRC-CCK */
110 { 0, 1 }, /* lvl 0 */
111 { 1, 1 }, /* lvl 1 */
112 { 2, 1 }, /* lvl 2 (default) */
113 { 3, 1 }, /* lvl 3 */
114 { 4, 0 }, /* lvl 4 */
115 { 5, 0 }, /* lvl 5 */
116 { 6, 0 }, /* lvl 6 */
117 { 7, 0 }, /* lvl 7 (only for high rssi) */
118 { 8, 0 } /* lvl 8 (only for high rssi) */
119 };
120 #define HAL_ANI_CCK_NUM_LEVEL \
121 (sizeof(cck_level_table) / sizeof(cck_level_table[0]))
122 #define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1)
123 #define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3)
124 #define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */
125
126 /*
127 * register values to turn OFDM weak signal detection OFF
128 */
129 static const int m1_thresh_low_off = 127;
130 static const int m2_thresh_low_off = 127;
131 static const int m1_thresh_off = 127;
132 static const int m2_thresh_off = 127;
133 static const int m2_count_thr_off = 31;
134 static const int m2_count_thr_low_off = 63;
135 static const int m1_thresh_low_ext_off = 127;
136 static const int m2_thresh_low_ext_off = 127;
137 static const int m1_thresh_ext_off = 127;
138 static const int m2_thresh_ext_off = 127;
139
140 void
ar9300_enable_mib_counters(struct ath_hal * ah)141 ar9300_enable_mib_counters(struct ath_hal *ah)
142 {
143 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__);
144 /* Clear the mib counters and save them in the stats */
145 ar9300_update_mib_mac_stats(ah);
146
147 OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
148 OS_REG_WRITE(ah, AR_FILT_CCK, 0);
149 OS_REG_WRITE(ah, AR_MIBC,
150 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
151 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
152 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
153
154 }
155
156 void
ar9300_disable_mib_counters(struct ath_hal * ah)157 ar9300_disable_mib_counters(struct ath_hal *ah)
158 {
159 HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__);
160
161 OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
162
163 /* Clear the mib counters and save them in the stats */
164 ar9300_update_mib_mac_stats(ah);
165
166 OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
167 OS_REG_WRITE(ah, AR_FILT_CCK, 0);
168 }
169
170 /*
171 * This routine returns the index into the ani_state array that
172 * corresponds to the channel in *chan. If no match is found and the
173 * array is still not fully utilized, a new entry is created for the
174 * channel. We assume the attach function has already initialized the
175 * ah_ani values and only the channel field needs to be set.
176 */
177 static int
ar9300_get_ani_channel_index(struct ath_hal * ah,const struct ieee80211_channel * chan)178 ar9300_get_ani_channel_index(struct ath_hal *ah,
179 const struct ieee80211_channel *chan)
180 {
181 struct ath_hal_9300 *ahp = AH9300(ah);
182 int i;
183
184 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) {
185 /* XXX this doesn't distinguish between 20/40 channels */
186 if (ahp->ah_ani[i].c.ic_freq == chan->ic_freq) {
187 return i;
188 }
189 if (ahp->ah_ani[i].c.ic_freq == 0) {
190 ahp->ah_ani[i].c.ic_freq = chan->ic_freq;
191 ahp->ah_ani[i].c.ic_flags = chan->ic_flags;
192 return i;
193 }
194 }
195 /* XXX statistic */
196 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
197 "%s: No more channel states left. Using channel 0\n", __func__);
198 return 0; /* XXX gotta return something valid */
199 }
200
201 /*
202 * Return the current ANI state of the channel we're on
203 */
204 struct ar9300_ani_state *
ar9300_ani_get_current_state(struct ath_hal * ah)205 ar9300_ani_get_current_state(struct ath_hal *ah)
206 {
207 return AH9300(ah)->ah_curani;
208 }
209
210 /*
211 * Return the current statistics.
212 */
213 HAL_ANI_STATS *
ar9300_ani_get_current_stats(struct ath_hal * ah)214 ar9300_ani_get_current_stats(struct ath_hal *ah)
215 {
216 return &AH9300(ah)->ah_stats;
217 }
218
219 /*
220 * Setup ANI handling. Sets all thresholds and levels to default level AND
221 * resets the channel statistics
222 */
223
224 void
ar9300_ani_attach(struct ath_hal * ah)225 ar9300_ani_attach(struct ath_hal *ah)
226 {
227 struct ath_hal_9300 *ahp = AH9300(ah);
228 int i;
229
230 OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani));
231 for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) {
232 ahp->ah_ani[i].ofdm_trig_high = HAL_ANI_OFDM_TRIG_HIGH;
233 ahp->ah_ani[i].ofdm_trig_low = HAL_ANI_OFDM_TRIG_LOW;
234 ahp->ah_ani[i].cck_trig_high = HAL_ANI_CCK_TRIG_HIGH;
235 ahp->ah_ani[i].cck_trig_low = HAL_ANI_CCK_TRIG_LOW;
236 ahp->ah_ani[i].rssi_thr_high = HAL_ANI_RSSI_THR_HIGH;
237 ahp->ah_ani[i].rssi_thr_low = HAL_ANI_RSSI_THR_LOW;
238 ahp->ah_ani[i].ofdm_noise_immunity_level = HAL_ANI_OFDM_DEF_LEVEL;
239 ahp->ah_ani[i].cck_noise_immunity_level = HAL_ANI_CCK_DEF_LEVEL;
240 ahp->ah_ani[i].ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG;
241 ahp->ah_ani[i].spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL;
242 ahp->ah_ani[i].firstep_level = HAL_ANI_DEF_FIRSTEP_LVL;
243 ahp->ah_ani[i].mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK;
244 ahp->ah_ani[i].ofdms_turn = AH_TRUE;
245 ahp->ah_ani[i].must_restore = AH_FALSE;
246 }
247
248 /*
249 * Since we expect some ongoing maintenance on the tables,
250 * let's sanity check here.
251 * The default level should not modify INI setting.
252 */
253 HALASSERT(firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] == 0);
254 HALASSERT(cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] == 0);
255 HALASSERT(
256 ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].fir_step_level ==
257 HAL_ANI_DEF_FIRSTEP_LVL);
258 HALASSERT(
259 ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].spur_immunity_level ==
260 HAL_ANI_DEF_SPUR_IMMUNE_LVL);
261 HALASSERT(
262 cck_level_table[HAL_ANI_CCK_DEF_LEVEL].fir_step_level ==
263 HAL_ANI_DEF_FIRSTEP_LVL);
264
265 /* Initialize and enable MIB Counters */
266 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
267 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
268 ar9300_enable_mib_counters(ah);
269
270 ahp->ah_ani_period = HAL_ANI_PERIOD;
271 if (ah->ah_config.ath_hal_enable_ani) {
272 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
273 }
274 }
275
276 /*
277 * Cleanup any ANI state setup.
278 */
279 void
ar9300_ani_detach(struct ath_hal * ah)280 ar9300_ani_detach(struct ath_hal *ah)
281 {
282 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Detaching Ani\n", __func__);
283 ar9300_disable_mib_counters(ah);
284 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
285 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
286 }
287
288 /*
289 * Initialize the ANI register values with default (ini) values.
290 * This routine is called during a (full) hardware reset after
291 * all the registers are initialised from the INI.
292 */
293 void
ar9300_ani_init_defaults(struct ath_hal * ah,HAL_HT_MACMODE macmode)294 ar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode)
295 {
296 struct ath_hal_9300 *ahp = AH9300(ah);
297 struct ar9300_ani_state *ani_state;
298 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
299 int index;
300 u_int32_t val;
301
302 HALASSERT(chan != AH_NULL);
303 index = ar9300_get_ani_channel_index(ah, chan);
304 ani_state = &ahp->ah_ani[index];
305 ahp->ah_curani = ani_state;
306
307 HALDEBUG(ah, HAL_DEBUG_ANI,
308 "%s: ver %d.%d opmode %u chan %d Mhz/0x%x macmode %d\n",
309 __func__, AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev,
310 AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, macmode);
311
312 val = OS_REG_READ(ah, AR_PHY_SFCORR);
313 ani_state->ini_def.m1_thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
314 ani_state->ini_def.m2_thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
315 ani_state->ini_def.m2_count_thr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
316
317 val = OS_REG_READ(ah, AR_PHY_SFCORR_LOW);
318 ani_state->ini_def.m1_thresh_low =
319 MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
320 ani_state->ini_def.m2_thresh_low =
321 MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
322 ani_state->ini_def.m2_count_thr_low =
323 MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
324
325 val = OS_REG_READ(ah, AR_PHY_SFCORR_EXT);
326 ani_state->ini_def.m1_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
327 ani_state->ini_def.m2_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
328 ani_state->ini_def.m1_thresh_low_ext =
329 MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
330 ani_state->ini_def.m2_thresh_low_ext =
331 MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
332
333 ani_state->ini_def.firstep =
334 OS_REG_READ_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP);
335 ani_state->ini_def.firstep_low =
336 OS_REG_READ_FIELD(
337 ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW);
338 ani_state->ini_def.cycpwr_thr1 =
339 OS_REG_READ_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1);
340 ani_state->ini_def.cycpwr_thr1_ext =
341 OS_REG_READ_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1);
342
343 /* these levels just got reset to defaults by the INI */
344 ani_state->spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL;
345 ani_state->firstep_level = HAL_ANI_DEF_FIRSTEP_LVL;
346 ani_state->ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG;
347 ani_state->mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK;
348
349 ani_state->cycle_count = 0;
350 }
351
352 /*
353 * Set the ANI settings to match an OFDM level.
354 */
355 static void
ar9300_ani_set_odfm_noise_immunity_level(struct ath_hal * ah,u_int8_t ofdm_noise_immunity_level)356 ar9300_ani_set_odfm_noise_immunity_level(struct ath_hal *ah,
357 u_int8_t ofdm_noise_immunity_level)
358 {
359 struct ath_hal_9300 *ahp = AH9300(ah);
360 struct ar9300_ani_state *ani_state = ahp->ah_curani;
361
362 ani_state->rssi = BEACON_RSSI(ahp);
363 HALDEBUG(ah, HAL_DEBUG_ANI,
364 "**** %s: ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", __func__,
365 ani_state->ofdm_noise_immunity_level, ofdm_noise_immunity_level,
366 ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high);
367
368 ani_state->ofdm_noise_immunity_level = ofdm_noise_immunity_level;
369
370 if (ani_state->spur_immunity_level !=
371 ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level)
372 {
373 ar9300_ani_control(
374 ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
375 ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level);
376 }
377
378 if (ani_state->firstep_level !=
379 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level &&
380 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level >=
381 cck_level_table[ani_state->cck_noise_immunity_level].fir_step_level)
382 {
383 ar9300_ani_control(
384 ah, HAL_ANI_FIRSTEP_LEVEL,
385 ofdm_level_table[ofdm_noise_immunity_level].fir_step_level);
386 }
387
388 if ((AH_PRIVATE(ah)->ah_opmode != HAL_M_STA ||
389 ani_state->rssi <= ani_state->rssi_thr_high))
390 {
391 if (ani_state->ofdm_weak_sig_detect_off) {
392 /*
393 * force on ofdm weak sig detect.
394 */
395 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE);
396 }
397 } else if (ani_state->ofdm_weak_sig_detect_off ==
398 ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on)
399 {
400 ar9300_ani_control(
401 ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
402 ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on);
403 }
404 }
405
406 /*
407 * Set the ANI settings to match a CCK level.
408 */
409 static void
ar9300_ani_set_cck_noise_immunity_level(struct ath_hal * ah,u_int8_t cck_noise_immunity_level)410 ar9300_ani_set_cck_noise_immunity_level(struct ath_hal *ah,
411 u_int8_t cck_noise_immunity_level)
412 {
413 struct ath_hal_9300 *ahp = AH9300(ah);
414 struct ar9300_ani_state *ani_state = ahp->ah_curani;
415 int level;
416
417 ani_state->rssi = BEACON_RSSI(ahp);
418 HALDEBUG(ah, HAL_DEBUG_ANI,
419 "**** %s: ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
420 __func__, ani_state->cck_noise_immunity_level, cck_noise_immunity_level,
421 ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high);
422
423 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA &&
424 ani_state->rssi <= ani_state->rssi_thr_low &&
425 cck_noise_immunity_level > HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI)
426 {
427 cck_noise_immunity_level = HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI;
428 }
429
430 ani_state->cck_noise_immunity_level = cck_noise_immunity_level;
431
432 level = ani_state->ofdm_noise_immunity_level;
433 if (ani_state->firstep_level !=
434 cck_level_table[cck_noise_immunity_level].fir_step_level &&
435 cck_level_table[cck_noise_immunity_level].fir_step_level >=
436 ofdm_level_table[level].fir_step_level)
437 {
438 ar9300_ani_control(
439 ah, HAL_ANI_FIRSTEP_LEVEL,
440 cck_level_table[cck_noise_immunity_level].fir_step_level);
441 }
442
443 if (ani_state->mrc_cck_off ==
444 cck_level_table[cck_noise_immunity_level].mrc_cck_on)
445 {
446 ar9300_ani_control(
447 ah, HAL_ANI_MRC_CCK,
448 cck_level_table[cck_noise_immunity_level].mrc_cck_on);
449 }
450 }
451
452 /*
453 * Control Adaptive Noise Immunity Parameters
454 */
455 HAL_BOOL
ar9300_ani_control(struct ath_hal * ah,HAL_ANI_CMD cmd,int param)456 ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param)
457 {
458 struct ath_hal_9300 *ahp = AH9300(ah);
459 struct ar9300_ani_state *ani_state = ahp->ah_curani;
460 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
461 int32_t value, value2;
462 u_int level = param;
463 u_int is_on;
464
465 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: cmd=%d, param=%d, chan=%p, funcmask=0x%08x\n",
466 __func__,
467 cmd,
468 param,
469 chan,
470 ahp->ah_ani_function);
471
472
473 if (chan == NULL && cmd != HAL_ANI_MODE) {
474 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
475 "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd);
476 return AH_FALSE;
477 }
478
479 /*
480 * These two control the top-level cck/ofdm immunity levels and will
481 * program the rest of the values.
482 */
483 if (cmd == HAL_ANI_NOISE_IMMUNITY_LEVEL) {
484 if (param > HAL_ANI_OFDM_NUM_LEVEL)
485 return AH_FALSE;
486 ar9300_ani_set_odfm_noise_immunity_level(ah, param);
487 return AH_TRUE;
488 }
489
490 if (cmd == HAL_ANI_CCK_NOISE_IMMUNITY_LEVEL) {
491 if (param > HAL_ANI_CCK_NUM_LEVEL)
492 return AH_FALSE;
493 ar9300_ani_set_cck_noise_immunity_level(ah, param);
494 return AH_TRUE;
495 }
496
497 /*
498 * Check to see if this command is available in the
499 * current operating mode.
500 */
501 if (((1 << cmd) & ahp->ah_ani_function) == 0) {
502 HALDEBUG(ah, HAL_DEBUG_ANI,
503 "%s: early check: invalid cmd 0x%02x (allowed=0x%02x)\n",
504 __func__, cmd, ahp->ah_ani_function);
505 return AH_FALSE;
506 }
507
508 /*
509 * The rest of these program in the requested parameter values
510 * into the PHY.
511 */
512 switch (cmd) {
513
514 case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
515 {
516 int m1_thresh_low, m2_thresh_low;
517 int m1_thresh, m2_thresh;
518 int m2_count_thr, m2_count_thr_low;
519 int m1_thresh_low_ext, m2_thresh_low_ext;
520 int m1_thresh_ext, m2_thresh_ext;
521 /*
522 * is_on == 1 means ofdm weak signal detection is ON
523 * (default, less noise imm)
524 * is_on == 0 means ofdm weak signal detection is OFF
525 * (more noise imm)
526 */
527 is_on = param ? 1 : 0;
528
529 if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah))
530 goto skip_ws_det;
531
532 /*
533 * make register setting for default (weak sig detect ON)
534 * come from INI file
535 */
536 m1_thresh_low = is_on ?
537 ani_state->ini_def.m1_thresh_low : m1_thresh_low_off;
538 m2_thresh_low = is_on ?
539 ani_state->ini_def.m2_thresh_low : m2_thresh_low_off;
540 m1_thresh = is_on ?
541 ani_state->ini_def.m1_thresh : m1_thresh_off;
542 m2_thresh = is_on ?
543 ani_state->ini_def.m2_thresh : m2_thresh_off;
544 m2_count_thr = is_on ?
545 ani_state->ini_def.m2_count_thr : m2_count_thr_off;
546 m2_count_thr_low = is_on ?
547 ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off;
548 m1_thresh_low_ext = is_on ?
549 ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off;
550 m2_thresh_low_ext = is_on ?
551 ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off;
552 m1_thresh_ext = is_on ?
553 ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off;
554 m2_thresh_ext = is_on ?
555 ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off;
556 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
557 AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low);
558 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
559 AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low);
560 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH,
561 m1_thresh);
562 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH,
563 m2_thresh);
564 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR,
565 m2_count_thr);
566 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
567 AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low);
568 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
569 AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext);
570 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
571 AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext);
572 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH,
573 m1_thresh_ext);
574 OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH,
575 m2_thresh_ext);
576 skip_ws_det:
577 if (is_on) {
578 OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
579 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
580 } else {
581 OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
582 AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
583 }
584 if ((!is_on) != ani_state->ofdm_weak_sig_detect_off) {
585 HALDEBUG(ah, HAL_DEBUG_ANI,
586 "%s: ** ch %d: ofdm weak signal: %s=>%s\n",
587 __func__, chan->ic_freq,
588 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
589 is_on ? "on" : "off");
590 if (is_on) {
591 ahp->ah_stats.ast_ani_ofdmon++;
592 } else {
593 ahp->ah_stats.ast_ani_ofdmoff++;
594 }
595 ani_state->ofdm_weak_sig_detect_off = !is_on;
596 }
597 break;
598 }
599 case HAL_ANI_FIRSTEP_LEVEL:
600 if (level >= ARRAY_LENGTH(firstep_table)) {
601 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
602 "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n",
603 __func__, level, (unsigned) ARRAY_LENGTH(firstep_table));
604 return AH_FALSE;
605 }
606 /*
607 * make register setting relative to default
608 * from INI file & cap value
609 */
610 value =
611 firstep_table[level] -
612 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
613 ani_state->ini_def.firstep;
614 if (value < HAL_SIG_FIRSTEP_SETTING_MIN) {
615 value = HAL_SIG_FIRSTEP_SETTING_MIN;
616 }
617 if (value > HAL_SIG_FIRSTEP_SETTING_MAX) {
618 value = HAL_SIG_FIRSTEP_SETTING_MAX;
619 }
620 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value);
621 /*
622 * we need to set first step low register too
623 * make register setting relative to default from INI file & cap value
624 */
625 value2 =
626 firstep_table[level] -
627 firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] +
628 ani_state->ini_def.firstep_low;
629 if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) {
630 value2 = HAL_SIG_FIRSTEP_SETTING_MIN;
631 }
632 if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) {
633 value2 = HAL_SIG_FIRSTEP_SETTING_MAX;
634 }
635 OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
636 AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
637
638 if (level != ani_state->firstep_level) {
639 HALDEBUG(ah, HAL_DEBUG_ANI,
640 "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
641 __func__, chan->ic_freq, ani_state->firstep_level, level,
642 HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep);
643 HALDEBUG(ah, HAL_DEBUG_ANI,
644 "%s: ** ch %d: level %d=>%d[def:%d] "
645 "firstep_low[level]=%d ini=%d\n",
646 __func__, chan->ic_freq, ani_state->firstep_level, level,
647 HAL_ANI_DEF_FIRSTEP_LVL, value2,
648 ani_state->ini_def.firstep_low);
649 if (level > ani_state->firstep_level) {
650 ahp->ah_stats.ast_ani_stepup++;
651 } else if (level < ani_state->firstep_level) {
652 ahp->ah_stats.ast_ani_stepdown++;
653 }
654 ani_state->firstep_level = level;
655 }
656 break;
657 case HAL_ANI_SPUR_IMMUNITY_LEVEL:
658 if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) {
659 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
660 "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level "
661 "out of range (%u > %u)\n",
662 __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table));
663 return AH_FALSE;
664 }
665 /*
666 * make register setting relative to default from INI file & cap value
667 */
668 value =
669 cycpwr_thr1_table[level] -
670 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
671 ani_state->ini_def.cycpwr_thr1;
672 if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) {
673 value = HAL_SIG_SPUR_IMM_SETTING_MIN;
674 }
675 if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) {
676 value = HAL_SIG_SPUR_IMM_SETTING_MAX;
677 }
678 OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value);
679
680 /*
681 * set AR_PHY_EXT_CCA for extension channel
682 * make register setting relative to default from INI file & cap value
683 */
684 value2 =
685 cycpwr_thr1_table[level] -
686 cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] +
687 ani_state->ini_def.cycpwr_thr1_ext;
688 if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) {
689 value2 = HAL_SIG_SPUR_IMM_SETTING_MIN;
690 }
691 if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) {
692 value2 = HAL_SIG_SPUR_IMM_SETTING_MAX;
693 }
694 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2);
695
696 if (level != ani_state->spur_immunity_level) {
697 HALDEBUG(ah, HAL_DEBUG_ANI,
698 "%s: ** ch %d: level %d=>%d[def:%d] "
699 "cycpwr_thr1[level]=%d ini=%d\n",
700 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
701 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value,
702 ani_state->ini_def.cycpwr_thr1);
703 HALDEBUG(ah, HAL_DEBUG_ANI,
704 "%s: ** ch %d: level %d=>%d[def:%d] "
705 "cycpwr_thr1_ext[level]=%d ini=%d\n",
706 __func__, chan->ic_freq, ani_state->spur_immunity_level, level,
707 HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2,
708 ani_state->ini_def.cycpwr_thr1_ext);
709 if (level > ani_state->spur_immunity_level) {
710 ahp->ah_stats.ast_ani_spurup++;
711 } else if (level < ani_state->spur_immunity_level) {
712 ahp->ah_stats.ast_ani_spurdown++;
713 }
714 ani_state->spur_immunity_level = level;
715 }
716 break;
717 case HAL_ANI_MRC_CCK:
718 /*
719 * is_on == 1 means MRC CCK ON (default, less noise imm)
720 * is_on == 0 means MRC CCK is OFF (more noise imm)
721 */
722 is_on = param ? 1 : 0;
723 if (!AR_SREV_POSEIDON(ah)) {
724 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
725 AR_PHY_MRC_CCK_ENABLE, is_on);
726 OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
727 AR_PHY_MRC_CCK_MUX_REG, is_on);
728 }
729 if ((!is_on) != ani_state->mrc_cck_off) {
730 HALDEBUG(ah, HAL_DEBUG_ANI,
731 "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq,
732 !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off");
733 if (is_on) {
734 ahp->ah_stats.ast_ani_ccklow++;
735 } else {
736 ahp->ah_stats.ast_ani_cckhigh++;
737 }
738 ani_state->mrc_cck_off = !is_on;
739 }
740 break;
741 case HAL_ANI_PRESENT:
742 break;
743 #ifdef AH_PRIVATE_DIAG
744 case HAL_ANI_MODE:
745 if (param == 0) {
746 ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI;
747 /* Turn off HW counters if we have them */
748 ar9300_ani_detach(ah);
749 if (AH_PRIVATE(ah)->ah_curchan == NULL) {
750 return AH_TRUE;
751 }
752 /* if we're turning off ANI, reset regs back to INI settings */
753 if (ah->ah_config.ath_hal_enable_ani) {
754 HAL_ANI_CMD savefunc = ahp->ah_ani_function;
755 /* temporarly allow all functions so we can reset */
756 ahp->ah_ani_function = HAL_ANI_ALL;
757 HALDEBUG(ah, HAL_DEBUG_ANI,
758 "%s: disable all ANI functions\n", __func__);
759 ar9300_ani_set_odfm_noise_immunity_level(
760 ah, HAL_ANI_OFDM_DEF_LEVEL);
761 ar9300_ani_set_cck_noise_immunity_level(
762 ah, HAL_ANI_CCK_DEF_LEVEL);
763 ahp->ah_ani_function = savefunc;
764 }
765 } else { /* normal/auto mode */
766 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__);
767 ahp->ah_proc_phy_err |= HAL_PROCESS_ANI;
768 if (AH_PRIVATE(ah)->ah_curchan == NULL) {
769 return AH_TRUE;
770 }
771 ar9300_enable_mib_counters(ah);
772 ar9300_ani_reset(ah, AH_FALSE);
773 ani_state = ahp->ah_curani;
774 }
775 HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n",
776 ahp->ah_proc_phy_err);
777 break;
778 case HAL_ANI_PHYERR_RESET:
779 ahp->ah_stats.ast_ani_ofdmerrs = 0;
780 ahp->ah_stats.ast_ani_cckerrs = 0;
781 break;
782 #endif /* AH_PRIVATE_DIAG */
783 default:
784 #if HAL_ANI_DEBUG
785 HALDEBUG(ah, HAL_DEBUG_ANI,
786 "%s: invalid cmd 0x%02x (allowed=0x%02x)\n",
787 __func__, cmd, ahp->ah_ani_function);
788 #endif
789 return AH_FALSE;
790 }
791
792 #if HAL_ANI_DEBUG
793 HALDEBUG(ah, HAL_DEBUG_ANI,
794 "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d "
795 "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n",
796 __func__, ani_state->spur_immunity_level,
797 !ani_state->ofdm_weak_sig_detect_off ? "on" : "off",
798 ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off",
799 ani_state->listen_time, ani_state->cycle_count,
800 ani_state->listen_time, ani_state->ofdm_phy_err_count,
801 ani_state->cck_phy_err_count);
802 #endif
803
804 #ifndef REMOVE_PKT_LOG
805 /* do pktlog */
806 {
807 struct log_ani log_data;
808
809 /* Populate the ani log record */
810 log_data.phy_stats_disable = DO_ANI(ah);
811 log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level;
812 log_data.spur_immun_lvl = ani_state->spur_immunity_level;
813 log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off;
814 log_data.cck_weak_thr = ani_state->cck_noise_immunity_level;
815 log_data.fir_lvl = ani_state->firstep_level;
816 log_data.listen_time = ani_state->listen_time;
817 log_data.cycle_count = ani_state->cycle_count;
818 /* express ofdm_phy_err_count as errors/second */
819 log_data.ofdm_phy_err_count = ani_state->listen_time ?
820 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0;
821 /* express cck_phy_err_count as errors/second */
822 log_data.cck_phy_err_count = ani_state->listen_time ?
823 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0;
824 log_data.rssi = ani_state->rssi;
825
826 /* clear interrupt context flag */
827 ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0);
828 }
829 #endif
830
831 return AH_TRUE;
832 }
833
834 static void
ar9300_ani_restart(struct ath_hal * ah)835 ar9300_ani_restart(struct ath_hal *ah)
836 {
837 struct ath_hal_9300 *ahp = AH9300(ah);
838 struct ar9300_ani_state *ani_state;
839
840 if (!DO_ANI(ah)) {
841 return;
842 }
843
844 ani_state = ahp->ah_curani;
845
846 ani_state->listen_time = 0;
847
848 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
849 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
850 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
851 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
852
853 /* Clear the mib counters and save them in the stats */
854 ar9300_update_mib_mac_stats(ah);
855
856 ani_state->ofdm_phy_err_count = 0;
857 ani_state->cck_phy_err_count = 0;
858 }
859
860 static void
ar9300_ani_ofdm_err_trigger(struct ath_hal * ah)861 ar9300_ani_ofdm_err_trigger(struct ath_hal *ah)
862 {
863 struct ath_hal_9300 *ahp = AH9300(ah);
864 struct ar9300_ani_state *ani_state;
865
866 if (!DO_ANI(ah)) {
867 return;
868 }
869
870 ani_state = ahp->ah_curani;
871
872 if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) {
873 ar9300_ani_set_odfm_noise_immunity_level(
874 ah, ani_state->ofdm_noise_immunity_level + 1);
875 }
876 }
877
878 static void
ar9300_ani_cck_err_trigger(struct ath_hal * ah)879 ar9300_ani_cck_err_trigger(struct ath_hal *ah)
880 {
881 struct ath_hal_9300 *ahp = AH9300(ah);
882 struct ar9300_ani_state *ani_state;
883
884 if (!DO_ANI(ah)) {
885 return;
886 }
887
888 ani_state = ahp->ah_curani;
889
890 if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) {
891 ar9300_ani_set_cck_noise_immunity_level(
892 ah, ani_state->cck_noise_immunity_level + 1);
893 }
894 }
895
896 /*
897 * Restore the ANI parameters in the HAL and reset the statistics.
898 * This routine should be called for every hardware reset and for
899 * every channel change.
900 */
901 void
ar9300_ani_reset(struct ath_hal * ah,HAL_BOOL is_scanning)902 ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning)
903 {
904 struct ath_hal_9300 *ahp = AH9300(ah);
905 struct ar9300_ani_state *ani_state;
906 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
907 HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan);
908 int index;
909
910 HALASSERT(chan != AH_NULL);
911
912 if (!DO_ANI(ah)) {
913 return;
914 }
915
916 /*
917 * we need to re-point to the correct ANI state since the channel
918 * may have changed due to a fast channel change
919 */
920 index = ar9300_get_ani_channel_index(ah, chan);
921 ani_state = &ahp->ah_ani[index];
922 HALASSERT(ani_state != AH_NULL);
923 ahp->ah_curani = ani_state;
924
925 ahp->ah_stats.ast_ani_reset++;
926
927 ani_state->phy_noise_spur = 0;
928
929 /* only allow a subset of functions in AP mode */
930 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) {
931 if (IS_CHAN_2GHZ(ichan)) {
932 ahp->ah_ani_function = (1 << HAL_ANI_SPUR_IMMUNITY_LEVEL) |
933 (1 << HAL_ANI_FIRSTEP_LEVEL) |
934 (1 << HAL_ANI_MRC_CCK);
935 } else {
936 ahp->ah_ani_function = 0;
937 }
938 } else {
939 ahp->ah_ani_function = HAL_ANI_ALL;
940 }
941
942 /* always allow mode (on/off) to be controlled */
943 ahp->ah_ani_function |= HAL_ANI_MODE;
944
945 if (is_scanning ||
946 (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA &&
947 AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS))
948 {
949 /*
950 * If we're scanning or in AP mode, the defaults (ini) should be
951 * in place.
952 * For an AP we assume the historical levels for this channel are
953 * probably outdated so start from defaults instead.
954 */
955 if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL ||
956 ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL)
957 {
958 HALDEBUG(ah, HAL_DEBUG_ANI,
959 "%s: Restore defaults: opmode %u chan %d Mhz/0x%x "
960 "is_scanning=%d restore=%d ofdm:%d cck:%d\n",
961 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
962 chan->ic_flags, is_scanning, ani_state->must_restore,
963 ani_state->ofdm_noise_immunity_level,
964 ani_state->cck_noise_immunity_level);
965 /*
966 * for STA/IBSS, we want to restore the historical values later
967 * (when we're not scanning)
968 */
969 if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA ||
970 AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS)
971 {
972 ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL,
973 HAL_ANI_DEF_SPUR_IMMUNE_LVL);
974 ar9300_ani_control(
975 ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL);
976 ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION,
977 HAL_ANI_USE_OFDM_WEAK_SIG);
978 ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK);
979 ani_state->must_restore = AH_TRUE;
980 } else {
981 ar9300_ani_set_odfm_noise_immunity_level(
982 ah, HAL_ANI_OFDM_DEF_LEVEL);
983 ar9300_ani_set_cck_noise_immunity_level(
984 ah, HAL_ANI_CCK_DEF_LEVEL);
985 }
986 }
987 } else {
988 /*
989 * restore historical levels for this channel
990 */
991 HALDEBUG(ah, HAL_DEBUG_ANI,
992 "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d "
993 "restore=%d ofdm:%d cck:%d\n",
994 __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq,
995 chan->ic_flags, is_scanning, ani_state->must_restore,
996 ani_state->ofdm_noise_immunity_level,
997 ani_state->cck_noise_immunity_level);
998 ar9300_ani_set_odfm_noise_immunity_level(
999 ah, ani_state->ofdm_noise_immunity_level);
1000 ar9300_ani_set_cck_noise_immunity_level(
1001 ah, ani_state->cck_noise_immunity_level);
1002 ani_state->must_restore = AH_FALSE;
1003 }
1004
1005 /* enable phy counters */
1006 ar9300_ani_restart(ah);
1007 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
1008 OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
1009 }
1010
1011 /*
1012 * Process a MIB interrupt. We may potentially be invoked because
1013 * any of the MIB counters overflow/trigger so don't assume we're
1014 * here because a PHY error counter triggered.
1015 */
1016 void
ar9300_process_mib_intr(struct ath_hal * ah,const HAL_NODE_STATS * stats)1017 ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats)
1018 {
1019 struct ath_hal_9300 *ahp = AH9300(ah);
1020 u_int32_t phy_cnt1, phy_cnt2;
1021
1022 #if 0
1023 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__);
1024 #endif
1025
1026 /* Reset these counters regardless */
1027 OS_REG_WRITE(ah, AR_FILT_OFDM, 0);
1028 OS_REG_WRITE(ah, AR_FILT_CCK, 0);
1029 if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) {
1030 OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
1031 }
1032
1033 /* Clear the mib counters and save them in the stats */
1034 ar9300_update_mib_mac_stats(ah);
1035 ahp->ah_stats.ast_nodestats = *stats;
1036
1037 if (!DO_ANI(ah)) {
1038 /*
1039 * We must always clear the interrupt cause by resetting
1040 * the phy error regs.
1041 */
1042 OS_REG_WRITE(ah, AR_PHY_ERR_1, 0);
1043 OS_REG_WRITE(ah, AR_PHY_ERR_2, 0);
1044 return;
1045 }
1046
1047 /* NB: these are not reset-on-read */
1048 phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1);
1049 phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2);
1050 #if HAL_ANI_DEBUG
1051 HALDEBUG(ah, HAL_DEBUG_ANI,
1052 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n",
1053 __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2);
1054 #endif
1055 if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
1056 ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
1057 /* NB: always restart to insure the h/w counters are reset */
1058 ar9300_ani_restart(ah);
1059 }
1060 }
1061
1062
1063 static void
ar9300_ani_lower_immunity(struct ath_hal * ah)1064 ar9300_ani_lower_immunity(struct ath_hal *ah)
1065 {
1066 struct ath_hal_9300 *ahp = AH9300(ah);
1067 struct ar9300_ani_state *ani_state = ahp->ah_curani;
1068
1069 if (ani_state->ofdm_noise_immunity_level > 0 &&
1070 (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) {
1071 /*
1072 * lower OFDM noise immunity
1073 */
1074 ar9300_ani_set_odfm_noise_immunity_level(
1075 ah, ani_state->ofdm_noise_immunity_level - 1);
1076
1077 /*
1078 * only lower either OFDM or CCK errors per turn
1079 * we lower the other one next time
1080 */
1081 return;
1082 }
1083
1084 if (ani_state->cck_noise_immunity_level > 0) {
1085 /*
1086 * lower CCK noise immunity
1087 */
1088 ar9300_ani_set_cck_noise_immunity_level(
1089 ah, ani_state->cck_noise_immunity_level - 1);
1090 }
1091 }
1092
1093 /* convert HW counter values to ms using mode specifix clock rate */
1094 //#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000)
1095 #define CLOCK_RATE(_ah) (ath_hal_mac_clks(ah, 1000))
1096
1097 /*
1098 * Return an approximation of the time spent ``listening'' by
1099 * deducting the cycles spent tx'ing and rx'ing from the total
1100 * cycle count since our last call. A return value <0 indicates
1101 * an invalid/inconsistent time.
1102 */
1103 static int32_t
ar9300_ani_get_listen_time(struct ath_hal * ah,HAL_ANISTATS * ani_stats)1104 ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats)
1105 {
1106 struct ath_hal_9300 *ahp = AH9300(ah);
1107 struct ar9300_ani_state *ani_state;
1108 u_int32_t tx_frame_count, rx_frame_count, cycle_count;
1109 u_int32_t rx_busy_count, rx_ext_busy_count;
1110 int32_t listen_time;
1111
1112 tx_frame_count = OS_REG_READ(ah, AR_TFCNT);
1113 rx_frame_count = OS_REG_READ(ah, AR_RFCNT);
1114 rx_busy_count = OS_REG_READ(ah, AR_RCCNT);
1115 rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT);
1116 cycle_count = OS_REG_READ(ah, AR_CCCNT);
1117
1118 ani_state = ahp->ah_curani;
1119 if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) {
1120 /*
1121 * Cycle counter wrap (or initial call); it's not possible
1122 * to accurately calculate a value because the registers
1123 * right shift rather than wrap--so punt and return 0.
1124 */
1125 listen_time = 0;
1126 ahp->ah_stats.ast_ani_lzero++;
1127 #if HAL_ANI_DEBUG
1128 HALDEBUG(ah, HAL_DEBUG_ANI,
1129 "%s: 1st call: ani_state->cycle_count=%d\n",
1130 __func__, ani_state->cycle_count);
1131 #endif
1132 } else {
1133 int32_t ccdelta = cycle_count - ani_state->cycle_count;
1134 int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count;
1135 int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count;
1136 int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count;
1137 int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count;
1138 listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah);
1139 //#if HAL_ANI_DEBUG
1140 HALDEBUG(ah, HAL_DEBUG_ANI,
1141 "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d "
1142 "CLOCK_RATE=%d\n",
1143 __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta,
1144 listen_time, CLOCK_RATE(ah));
1145 //#endif
1146 /* Populate as appropriate */
1147 ani_stats->cyclecnt_diff = ccdelta;
1148 ani_stats->rxclr_cnt = rcdelta;
1149 ani_stats->txframecnt_diff = tfdelta;
1150 ani_stats->rxframecnt_diff = rfdelta;
1151 ani_stats->extrxclr_cnt = extrcdelta;
1152 ani_stats->listen_time = listen_time;
1153 ani_stats->valid = AH_TRUE;
1154 }
1155 ani_state->cycle_count = cycle_count;
1156 ani_state->tx_frame_count = tx_frame_count;
1157 ani_state->rx_frame_count = rx_frame_count;
1158 ani_state->rx_busy_count = rx_busy_count;
1159 ani_state->rx_ext_busy_count = rx_ext_busy_count;
1160 return listen_time;
1161 }
1162
1163 /*
1164 * Do periodic processing. This routine is called from a timer
1165 */
1166 void
ar9300_ani_ar_poll(struct ath_hal * ah,const HAL_NODE_STATS * stats,const struct ieee80211_channel * chan,HAL_ANISTATS * ani_stats)1167 ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats,
1168 const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats)
1169 {
1170 struct ath_hal_9300 *ahp = AH9300(ah);
1171 struct ar9300_ani_state *ani_state;
1172 int32_t listen_time;
1173 u_int32_t ofdm_phy_err_rate, cck_phy_err_rate;
1174 u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt;
1175 HAL_BOOL old_phy_noise_spur;
1176
1177 ani_state = ahp->ah_curani;
1178 ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */
1179
1180 if (ani_state == NULL) {
1181 /* should not happen */
1182 HALDEBUG(ah, HAL_DEBUG_UNMASKABLE,
1183 "%s: can't poll - no ANI not initialized for this channel\n",
1184 __func__);
1185 return;
1186 }
1187
1188 /*
1189 * ar9300_ani_ar_poll is never called while scanning but we may have been
1190 * scanning and now just restarted polling. In this case we need to
1191 * restore historical values.
1192 */
1193 if (ani_state->must_restore) {
1194 HALDEBUG(ah, HAL_DEBUG_ANI,
1195 "%s: must restore - calling ar9300_ani_restart\n", __func__);
1196 ar9300_ani_reset(ah, AH_FALSE);
1197 return;
1198 }
1199
1200 listen_time = ar9300_ani_get_listen_time(ah, ani_stats);
1201 if (listen_time <= 0) {
1202 ahp->ah_stats.ast_ani_lneg++;
1203 /* restart ANI period if listen_time is invalid */
1204 HALDEBUG(ah, HAL_DEBUG_ANI,
1205 "%s: listen_time=%d - calling ar9300_ani_restart\n",
1206 __func__, listen_time);
1207 ar9300_ani_restart(ah);
1208 return;
1209 }
1210 /* XXX beware of overflow? */
1211 ani_state->listen_time += listen_time;
1212
1213 /* Clear the mib counters and save them in the stats */
1214 ar9300_update_mib_mac_stats(ah);
1215 /* NB: these are not reset-on-read */
1216 ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1);
1217 cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2);
1218
1219 /* Populate HAL_ANISTATS */
1220 /* XXX TODO: are these correct? */
1221 if (ani_stats) {
1222 ani_stats->cckphyerr_cnt =
1223 cck_phy_err_cnt - ani_state->cck_phy_err_count;
1224 ani_stats->ofdmphyerrcnt_diff =
1225 ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1226 }
1227
1228 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
1229 ahp->ah_stats.ast_ani_ofdmerrs +=
1230 ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count;
1231 ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt;
1232
1233 ahp->ah_stats.ast_ani_cckerrs +=
1234 cck_phy_err_cnt - ani_state->cck_phy_err_count;
1235 ani_state->cck_phy_err_count = cck_phy_err_cnt;
1236
1237 /*
1238 * Note - the ANI code is using the aggregate listen time.
1239 * The AR_PHY_CNT1/AR_PHY_CNT2 registers here are also
1240 * free running, not clear-on-read and are free-running.
1241 *
1242 * So, ofdm_phy_err_rate / cck_phy_err_rate are accumulating
1243 * the same as listenTime is accumulating.
1244 */
1245
1246 #if HAL_ANI_DEBUG
1247 HALDEBUG(ah, HAL_DEBUG_ANI,
1248 "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n",
1249 __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt,
1250 cck_phy_err_cnt, cck_phy_err_cnt);
1251 #endif
1252
1253 /*
1254 * If ani is not enabled, return after we've collected
1255 * statistics
1256 */
1257 if (!DO_ANI(ah)) {
1258 return;
1259 }
1260
1261 /*
1262 * Calculate the OFDM/CCK phy error rate over the listen time interval.
1263 * This is used in subsequent math to see if the OFDM/CCK phy error rate
1264 * is above or below the threshold checks.
1265 */
1266
1267 ofdm_phy_err_rate =
1268 ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time;
1269 cck_phy_err_rate =
1270 ani_state->cck_phy_err_count * 1000 / ani_state->listen_time;
1271
1272 HALDEBUG(ah, HAL_DEBUG_ANI,
1273 "%s: listen_time=%d (total: %d) OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
1274 __func__, listen_time,
1275 ani_state->listen_time,
1276 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1277 ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1278 ani_state->ofdms_turn);
1279
1280 /*
1281 * Check for temporary noise spurs. This is intended to be used by
1282 * rate control to check if we should try higher packet rates or not.
1283 * If the noise period is short enough then we shouldn't avoid trying
1284 * higher rates but if the noise is high/sustained then it's likely
1285 * not a great idea to try the higher MCS rates.
1286 */
1287 if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) {
1288 old_phy_noise_spur = ani_state->phy_noise_spur;
1289 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1290 cck_phy_err_rate <= ani_state->cck_trig_low) {
1291 if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) {
1292 ani_state->phy_noise_spur = 0;
1293 }
1294 } else {
1295 ani_state->phy_noise_spur = 1;
1296 }
1297 if (old_phy_noise_spur != ani_state->phy_noise_spur) {
1298 HALDEBUG(ah, HAL_DEBUG_ANI,
1299 "%s: environment change from %d to %d\n",
1300 __func__, old_phy_noise_spur, ani_state->phy_noise_spur);
1301 }
1302 }
1303
1304 if (ani_state->listen_time > 5 * ahp->ah_ani_period) {
1305 /*
1306 * Check to see if need to lower immunity if
1307 * 5 ani_periods have passed
1308 */
1309 if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low &&
1310 cck_phy_err_rate <= ani_state->cck_trig_low)
1311 {
1312 HALDEBUG(ah, HAL_DEBUG_ANI,
1313 "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) "
1314 "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n",
1315 __func__, ani_state->listen_time,
1316 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1317 ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level,
1318 cck_phy_err_rate, ani_state->cck_trig_low);
1319 ar9300_ani_lower_immunity(ah);
1320 ani_state->ofdms_turn = !ani_state->ofdms_turn;
1321 }
1322 /*
1323 * Force an ANI restart regardless of whether the lower immunity
1324 * level was met.
1325 */
1326 HALDEBUG(ah, HAL_DEBUG_ANI,
1327 "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - "
1328 "calling ar9300_ani_restart\n",
1329 __func__, ani_state->listen_time,
1330 ofdm_phy_err_rate, cck_phy_err_rate);
1331 ar9300_ani_restart(ah);
1332 } else if (ani_state->listen_time > ahp->ah_ani_period) {
1333 /* check to see if need to raise immunity */
1334 if (ofdm_phy_err_rate > ani_state->ofdm_trig_high &&
1335 (cck_phy_err_rate <= ani_state->cck_trig_high ||
1336 ani_state->ofdms_turn))
1337 {
1338 HALDEBUG(ah, HAL_DEBUG_ANI,
1339 "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> "
1340 "ar9300_ani_ofdm_err_trigger\n",
1341 __func__, ani_state->listen_time,
1342 ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate,
1343 ani_state->ofdm_trig_high);
1344 ar9300_ani_ofdm_err_trigger(ah);
1345 ar9300_ani_restart(ah);
1346 ani_state->ofdms_turn = AH_FALSE;
1347 } else if (cck_phy_err_rate > ani_state->cck_trig_high) {
1348 HALDEBUG(ah, HAL_DEBUG_ANI,
1349 "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> "
1350 "ar9300_ani_cck_err_trigger\n",
1351 __func__, ani_state->listen_time,
1352 ani_state->cck_noise_immunity_level, cck_phy_err_rate,
1353 ani_state->cck_trig_high);
1354 ar9300_ani_cck_err_trigger(ah);
1355 ar9300_ani_restart(ah);
1356 ani_state->ofdms_turn = AH_TRUE;
1357 }
1358 }
1359
1360 /*
1361 * Note that currently this poll function doesn't reset the listen
1362 * time after it accumulates a second worth of error samples.
1363 * It will continue to accumulate samples until a counter overflows,
1364 * or a raise threshold is met, or 5 seconds passes.
1365 */
1366 }
1367
1368 /*
1369 * The poll function above calculates short noise spurs, caused by non-80211
1370 * devices, based on OFDM/CCK Phy errs.
1371 * If the noise is short enough, we don't want our ratectrl Algo to stop probing
1372 * higher rates, due to bad PER.
1373 */
1374 HAL_BOOL
ar9300_is_ani_noise_spur(struct ath_hal * ah)1375 ar9300_is_ani_noise_spur(struct ath_hal *ah)
1376 {
1377 struct ath_hal_9300 *ahp = AH9300(ah);
1378 struct ar9300_ani_state *ani_state;
1379
1380 ani_state = ahp->ah_curani;
1381
1382 return ani_state->phy_noise_spur;
1383 }
1384
1385