Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c
48526 views
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1386