ani.c 25.8 KB
Newer Older
S
Sujith 已提交
1
/*
2
 * Copyright (c) 2008-2011 Atheros Communications Inc.
S
Sujith 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

17
#include <linux/kernel.h>
18
#include <linux/export.h>
19
#include "hw.h"
20
#include "hw-ops.h"
S
Sujith 已提交
21

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
struct ani_ofdm_level_entry {
	int spur_immunity_level;
	int fir_step_level;
	int ofdm_weak_signal_on;
};

/* values here are relative to the INI */

/*
 * Legend:
 *
 * SI: Spur immunity
 * FS: FIR Step
 * WS: OFDM / CCK Weak Signal detection
 * MRC-CCK: Maximal Ratio Combining for CCK
 */

static const struct ani_ofdm_level_entry ofdm_level_table[] = {
	/* SI  FS  WS */
	{  0,  0,  1  }, /* lvl 0 */
	{  1,  1,  1  }, /* lvl 1 */
	{  2,  2,  1  }, /* lvl 2 */
	{  3,  2,  1  }, /* lvl 3  (default) */
	{  4,  3,  1  }, /* lvl 4 */
	{  5,  4,  1  }, /* lvl 5 */
	{  6,  5,  1  }, /* lvl 6 */
	{  7,  6,  1  }, /* lvl 7 */
49 50
	{  7,  6,  0  }, /* lvl 8 */
	{  7,  7,  0  }  /* lvl 9 */
51 52
};
#define ATH9K_ANI_OFDM_NUM_LEVEL \
53
	ARRAY_SIZE(ofdm_level_table)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
#define ATH9K_ANI_OFDM_MAX_LEVEL \
	(ATH9K_ANI_OFDM_NUM_LEVEL-1)
#define ATH9K_ANI_OFDM_DEF_LEVEL \
	3 /* default level - matches the INI settings */

/*
 * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
 * With OFDM for single stream you just add up all antenna inputs, you're
 * only interested in what you get after FFT. Signal aligment is also not
 * required for OFDM because any phase difference adds up in the frequency
 * domain.
 *
 * MRC requires extra work for use with CCK. You need to align the antenna
 * signals from the different antenna before you can add the signals together.
 * You need aligment of signals as CCK is in time domain, so addition can cancel
 * your signal completely if phase is 180 degrees (think of adding sine waves).
 * You also need to remove noise before the addition and this is where ANI
 * MRC CCK comes into play. One of the antenna inputs may be stronger but
 * lower SNR, so just adding after alignment can be dangerous.
 *
 * Regardless of alignment in time, the antenna signals add constructively after
 * FFT and improve your reception. For more information:
 *
 * http://en.wikipedia.org/wiki/Maximal-ratio_combining
 */

struct ani_cck_level_entry {
	int fir_step_level;
	int mrc_cck_on;
};

static const struct ani_cck_level_entry cck_level_table[] = {
	/* FS  MRC-CCK  */
	{  0,  1  }, /* lvl 0 */
	{  1,  1  }, /* lvl 1 */
	{  2,  1  }, /* lvl 2  (default) */
	{  3,  1  }, /* lvl 3 */
	{  4,  0  }, /* lvl 4 */
	{  5,  0  }, /* lvl 5 */
	{  6,  0  }, /* lvl 6 */
94 95
	{  6,  0  }, /* lvl 7 (only for high rssi) */
	{  7,  0  }  /* lvl 8 (only for high rssi) */
96 97 98
};

#define ATH9K_ANI_CCK_NUM_LEVEL \
99
	ARRAY_SIZE(cck_level_table)
100 101 102 103 104 105 106
#define ATH9K_ANI_CCK_MAX_LEVEL \
	(ATH9K_ANI_CCK_NUM_LEVEL-1)
#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
	(ATH9K_ANI_CCK_NUM_LEVEL-3)
#define ATH9K_ANI_CCK_DEF_LEVEL \
	2 /* default level - matches the INI settings */

107 108 109 110 111
static bool use_new_ani(struct ath_hw *ah)
{
	return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
}

112
static void ath9k_hw_update_mibstats(struct ath_hw *ah,
S
Sujith 已提交
113 114 115 116 117 118 119 120 121
				     struct ath9k_mib_stats *stats)
{
	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
	stats->rts_good += REG_READ(ah, AR_RTS_OK);
	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
}

122
static void ath9k_ani_restart(struct ath_hw *ah)
S
Sujith 已提交
123 124
{
	struct ar5416AniState *aniState;
125
	struct ath_common *common = ath9k_hw_common(ah);
126
	u32 ofdm_base = 0, cck_base = 0;
S
Sujith 已提交
127 128 129 130

	if (!DO_ANI(ah))
		return;

131
	aniState = &ah->curchan->ani;
S
Sujith 已提交
132
	aniState->listenTime = 0;
S
Sujith 已提交
133

134 135 136
	if (!use_new_ani(ah)) {
		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
S
Sujith 已提交
137
	}
138

139 140
	ath_dbg(common, ANI, "Writing ofdmbase=%u   cckbase=%u\n",
		ofdm_base, cck_base);
141 142 143

	ENABLE_REGWRITE_BUFFER(ah);

144 145
	REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
	REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
146 147 148 149 150 151 152 153 154 155 156 157
	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);

	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}

static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
S
Sujith 已提交
158
{
159
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
160 161 162
	struct ar5416AniState *aniState;
	int32_t rssi;

163
	aniState = &ah->curchan->ani;
S
Sujith 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178

	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
					 aniState->noiseImmunityLevel + 1)) {
			return;
		}
	}

	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
					 aniState->spurImmunityLevel + 1)) {
			return;
		}
	}

179
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
180 181 182 183 184 185
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
186
	rssi = BEACON_RSSI(ah);
S
Sujith 已提交
187
	if (rssi > aniState->rssiThrHigh) {
188
		if (aniState->ofdmWeakSigDetect) {
S
Sujith 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202
			if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
					 false)) {
				ath9k_hw_ani_control(ah,
					ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
				return;
			}
		}
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
			return;
		}
	} else if (rssi > aniState->rssiThrLow) {
203
		if (!aniState->ofdmWeakSigDetect)
S
Sujith 已提交
204 205 206 207 208 209 210 211
			ath9k_hw_ani_control(ah,
				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				     true);
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		return;
	} else {
S
Sujith 已提交
212 213
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
214
			if (aniState->ofdmWeakSigDetect)
S
Sujith 已提交
215 216 217 218 219 220 221 222 223 224 225
				ath9k_hw_ani_control(ah,
				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				     false);
			if (aniState->firstepLevel > 0)
				ath9k_hw_ani_control(ah,
					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
			return;
		}
	}
}

226
static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
S
Sujith 已提交
227
{
228
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
229 230 231
	struct ar5416AniState *aniState;
	int32_t rssi;

232
	aniState = &ah->curchan->ani;
S
Sujith 已提交
233 234 235 236 237 238
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
					 aniState->noiseImmunityLevel + 1)) {
			return;
		}
	}
239
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
240 241 242 243 244 245
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
246
	rssi = BEACON_RSSI(ah);
S
Sujith 已提交
247 248 249 250 251
	if (rssi > aniState->rssiThrLow) {
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
	} else {
S
Sujith 已提交
252 253
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
S
Sujith 已提交
254 255 256 257 258 259 260
			if (aniState->firstepLevel > 0)
				ath9k_hw_ani_control(ah,
					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
		}
	}
}

261 262 263
/* Adjust the OFDM Noise Immunity Level */
static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
{
264
	struct ar5416AniState *aniState = &ah->curchan->ani;
265 266 267
	struct ath_common *common = ath9k_hw_common(ah);
	const struct ani_ofdm_level_entry *entry_ofdm;
	const struct ani_cck_level_entry *entry_cck;
268
	bool weak_sig;
269

270
	ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
J
Joe Perches 已提交
271
		aniState->ofdmNoiseImmunityLevel,
272
		immunityLevel, BEACON_RSSI(ah),
J
Joe Perches 已提交
273
		aniState->rssiThrLow, aniState->rssiThrHigh);
274

275
	if (aniState->update_ani)
276 277 278
		aniState->ofdmNoiseImmunityLevel =
			(immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ?
			immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL;
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293

	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];

	if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
		ath9k_hw_ani_control(ah,
				     ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
				     entry_ofdm->spur_immunity_level);

	if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
	    entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
		ath9k_hw_ani_control(ah,
				     ATH9K_ANI_FIRSTEP_LEVEL,
				     entry_ofdm->fir_step_level);

294 295 296 297 298
	weak_sig = entry_ofdm->ofdm_weak_signal_on;
	if (ah->opmode == NL80211_IFTYPE_STATION &&
	    BEACON_RSSI(ah) <= aniState->rssiThrHigh)
		weak_sig = true;

299
	if (aniState->ofdmWeakSigDetect != weak_sig)
300 301 302 303 304
			ath9k_hw_ani_control(ah,
				ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				entry_ofdm->ofdm_weak_signal_on);
}

305
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
306 307 308 309 310 311
{
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah))
		return;

312 313 314 315 316
	if (!use_new_ani(ah)) {
		ath9k_hw_ani_ofdm_err_trigger_old(ah);
		return;
	}

317
	aniState = &ah->curchan->ani;
318 319 320 321 322 323 324 325 326 327

	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
}

/*
 * Set the ANI settings to match an CCK level.
 */
static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
{
328
	struct ar5416AniState *aniState = &ah->curchan->ani;
329 330 331 332
	struct ath_common *common = ath9k_hw_common(ah);
	const struct ani_ofdm_level_entry *entry_ofdm;
	const struct ani_cck_level_entry *entry_cck;

333
	ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
J
Joe Perches 已提交
334
		aniState->cckNoiseImmunityLevel, immunityLevel,
335
		BEACON_RSSI(ah), aniState->rssiThrLow,
J
Joe Perches 已提交
336
		aniState->rssiThrHigh);
337 338 339

	if ((ah->opmode == NL80211_IFTYPE_STATION ||
	     ah->opmode == NL80211_IFTYPE_ADHOC) &&
340
	    BEACON_RSSI(ah) <= aniState->rssiThrLow &&
341 342 343
	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
		immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;

344
	if (aniState->update_ani)
345 346 347
		aniState->cckNoiseImmunityLevel =
			(immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ?
			immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL;
348 349 350 351 352 353 354 355 356 357 358

	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];

	if (aniState->firstepLevel != entry_cck->fir_step_level &&
	    entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
		ath9k_hw_ani_control(ah,
				     ATH9K_ANI_FIRSTEP_LEVEL,
				     entry_cck->fir_step_level);

	/* Skip MRC CCK for pre AR9003 families */
359
	if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
360 361 362 363 364 365 366 367
		return;

	if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
		ath9k_hw_ani_control(ah,
				     ATH9K_ANI_MRC_CCK,
				     entry_cck->mrc_cck_on);
}

368
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
369 370 371 372 373 374
{
	struct ar5416AniState *aniState;

	if (!DO_ANI(ah))
		return;

375 376 377 378 379
	if (!use_new_ani(ah)) {
		ath9k_hw_ani_cck_err_trigger_old(ah);
		return;
	}

380
	aniState = &ah->curchan->ani;
381 382 383 384 385

	if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
}

386
static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
S
Sujith 已提交
387 388 389 390
{
	struct ar5416AniState *aniState;
	int32_t rssi;

391
	aniState = &ah->curchan->ani;
S
Sujith 已提交
392

393
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
394 395 396 397 398 399
		if (aniState->firstepLevel > 0) {
			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
						 aniState->firstepLevel - 1))
				return;
		}
	} else {
400
		rssi = BEACON_RSSI(ah);
S
Sujith 已提交
401 402 403
		if (rssi > aniState->rssiThrHigh) {
			/* XXX: Handle me */
		} else if (rssi > aniState->rssiThrLow) {
404
			if (!aniState->ofdmWeakSigDetect) {
S
Sujith 已提交
405 406
				if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
407
					 true))
S
Sujith 已提交
408 409 410 411 412
					return;
			}
			if (aniState->firstepLevel > 0) {
				if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_FIRSTEP_LEVEL,
413
					 aniState->firstepLevel - 1))
S
Sujith 已提交
414 415 416 417 418 419
					return;
			}
		} else {
			if (aniState->firstepLevel > 0) {
				if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_FIRSTEP_LEVEL,
420
					 aniState->firstepLevel - 1))
S
Sujith 已提交
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
					return;
			}
		}
	}

	if (aniState->spurImmunityLevel > 0) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
					 aniState->spurImmunityLevel - 1))
			return;
	}

	if (aniState->noiseImmunityLevel > 0) {
		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
				     aniState->noiseImmunityLevel - 1);
		return;
	}
}

439 440 441 442
/*
 * only lower either OFDM or CCK errors per turn
 * we lower the other one next time
 */
443
static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
444 445 446
{
	struct ar5416AniState *aniState;

447
	aniState = &ah->curchan->ani;
448

449 450 451 452 453
	if (!use_new_ani(ah)) {
		ath9k_hw_ani_lower_immunity_old(ah);
		return;
	}

454 455 456 457 458 459 460 461 462 463 464 465
	/* lower OFDM noise immunity */
	if (aniState->ofdmNoiseImmunityLevel > 0 &&
	    (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
		return;
	}

	/* lower CCK noise immunity */
	if (aniState->cckNoiseImmunityLevel > 0)
		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
}

466
static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
S
Sujith 已提交
467 468
{
	struct ar5416AniState *aniState;
469
	struct ath9k_channel *chan = ah->curchan;
470
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
471 472 473 474

	if (!DO_ANI(ah))
		return;

475
	aniState = &ah->curchan->ani;
S
Sujith 已提交
476

477
	if (ah->opmode != NL80211_IFTYPE_STATION
478
	    && ah->opmode != NL80211_IFTYPE_ADHOC) {
479
		ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode);
480
		ah->stats.ast_ani_reset++;
S
Sujith 已提交
481

482 483 484 485 486 487 488 489 490 491 492 493
		if (ah->opmode == NL80211_IFTYPE_AP) {
			/*
			 * ath9k_hw_ani_control() will only process items set on
			 * ah->ani_function
			 */
			if (IS_CHAN_2GHZ(chan))
				ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
						    ATH9K_ANI_FIRSTEP_LEVEL);
			else
				ah->ani_function = 0;
		}

S
Sujith 已提交
494 495 496 497 498 499 500 501
		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
				     ATH9K_ANI_CCK_WEAK_SIG_THR);

502
		ath9k_ani_restart(ah);
S
Sujith 已提交
503 504 505 506 507 508 509 510 511
		return;
	}

	if (aniState->noiseImmunityLevel != 0)
		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
				     aniState->noiseImmunityLevel);
	if (aniState->spurImmunityLevel != 0)
		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
				     aniState->spurImmunityLevel);
512
	if (!aniState->ofdmWeakSigDetect)
S
Sujith 已提交
513
		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
514
				     aniState->ofdmWeakSigDetect);
S
Sujith 已提交
515 516 517 518 519 520 521
	if (aniState->cckWeakSigThreshold)
		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
				     aniState->cckWeakSigThreshold);
	if (aniState->firstepLevel != 0)
		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
				     aniState->firstepLevel);

522
	ath9k_ani_restart(ah);
523 524 525 526 527 528 529 530 531 532 533 534 535 536

	ENABLE_REGWRITE_BUFFER(ah);

	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);

	REGWRITE_BUFFER_FLUSH(ah);
}

/*
 * Restore the ANI parameters in the HAL and reset the statistics.
 * This routine should be called for every hardware reset and for
 * every channel change.
 */
537
void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
538
{
539
	struct ar5416AniState *aniState = &ah->curchan->ani;
540 541 542 543 544 545
	struct ath9k_channel *chan = ah->curchan;
	struct ath_common *common = ath9k_hw_common(ah);

	if (!DO_ANI(ah))
		return;

546 547 548
	if (!use_new_ani(ah))
		return ath9k_ani_reset_old(ah, is_scanning);

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
	BUG_ON(aniState == NULL);
	ah->stats.ast_ani_reset++;

	/* only allow a subset of functions in AP mode */
	if (ah->opmode == NL80211_IFTYPE_AP) {
		if (IS_CHAN_2GHZ(chan)) {
			ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
					    ATH9K_ANI_FIRSTEP_LEVEL);
			if (AR_SREV_9300_20_OR_LATER(ah))
				ah->ani_function |= ATH9K_ANI_MRC_CCK;
		} else
			ah->ani_function = 0;
	}

	/* always allow mode (on/off) to be controlled */
	ah->ani_function |= ATH9K_ANI_MODE;

	if (is_scanning ||
	    (ah->opmode != NL80211_IFTYPE_STATION &&
	     ah->opmode != NL80211_IFTYPE_ADHOC)) {
		/*
		 * If we're scanning or in AP mode, the defaults (ini)
		 * should be in place. For an AP we assume the historical
		 * levels for this channel are probably outdated so start
		 * from defaults instead.
		 */
		if (aniState->ofdmNoiseImmunityLevel !=
		    ATH9K_ANI_OFDM_DEF_LEVEL ||
		    aniState->cckNoiseImmunityLevel !=
		    ATH9K_ANI_CCK_DEF_LEVEL) {
579
			ath_dbg(common, ANI,
J
Joe Perches 已提交
580 581 582 583 584 585 586
				"Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
				ah->opmode,
				chan->channel,
				chan->channelFlags,
				is_scanning,
				aniState->ofdmNoiseImmunityLevel,
				aniState->cckNoiseImmunityLevel);
587

588
			aniState->update_ani = false;
589 590 591 592 593 594 595
			ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
			ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
		}
	} else {
		/*
		 * restore historical levels for this channel
		 */
596
		ath_dbg(common, ANI,
J
Joe Perches 已提交
597 598 599 600 601 602 603
			"Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
			ah->opmode,
			chan->channel,
			chan->channelFlags,
			is_scanning,
			aniState->ofdmNoiseImmunityLevel,
			aniState->cckNoiseImmunityLevel);
604

605
			aniState->update_ani = true;
606 607 608 609 610 611 612 613 614 615
			ath9k_hw_set_ofdm_nil(ah,
					      aniState->ofdmNoiseImmunityLevel);
			ath9k_hw_set_cck_nil(ah,
					     aniState->cckNoiseImmunityLevel);
	}

	/*
	 * enable phy counters if hw supports or if not, enable phy
	 * interrupts (so we can count each one)
	 */
616
	ath9k_ani_restart(ah);
S
Sujith 已提交
617 618 619

	ENABLE_REGWRITE_BUFFER(ah);

S
Sujith 已提交
620 621
	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
S
Sujith 已提交
622 623

	REGWRITE_BUFFER_FLUSH(ah);
S
Sujith 已提交
624 625
}

626
static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
S
Sujith 已提交
627
{
628
	struct ath_common *common = ath9k_hw_common(ah);
629 630 631
	struct ar5416AniState *aniState = &ah->curchan->ani;
	u32 ofdm_base = 0;
	u32 cck_base = 0;
S
Sujith 已提交
632
	u32 ofdmPhyErrCnt, cckPhyErrCnt;
633 634
	u32 phyCnt1, phyCnt2;
	int32_t listenTime;
S
Sujith 已提交
635

636 637 638
	ath_hw_cycle_counters_update(common);
	listenTime = ath_hw_get_listen_time(common);

639
	if (listenTime <= 0) {
640
		ah->stats.ast_ani_lneg_or_lzero++;
641
		ath9k_ani_restart(ah);
642
		return false;
S
Sujith 已提交
643 644
	}

645 646 647 648 649
	if (!use_new_ani(ah)) {
		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
	}

S
Sujith 已提交
650 651
	aniState->listenTime += listenTime;

S
Sujith 已提交
652
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
653

S
Sujith 已提交
654 655 656
	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);

657
	if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
658
		if (phyCnt1 < ofdm_base) {
659
			ath_dbg(common, ANI,
J
Joe Perches 已提交
660 661
				"phyCnt1 0x%x, resetting counter value to 0x%x\n",
				phyCnt1, ofdm_base);
662
			REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
S
Sujith 已提交
663 664 665
			REG_WRITE(ah, AR_PHY_ERR_MASK_1,
				  AR_PHY_ERR_OFDM_TIMING);
		}
666
		if (phyCnt2 < cck_base) {
667
			ath_dbg(common, ANI,
J
Joe Perches 已提交
668 669
				"phyCnt2 0x%x, resetting counter value to 0x%x\n",
				phyCnt2, cck_base);
670
			REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
S
Sujith 已提交
671 672
			REG_WRITE(ah, AR_PHY_ERR_MASK_2,
				  AR_PHY_ERR_CCK_TIMING);
S
Sujith 已提交
673
		}
674
		return false;
S
Sujith 已提交
675
	}
S
Sujith 已提交
676

677
	ofdmPhyErrCnt = phyCnt1 - ofdm_base;
S
Sujith 已提交
678 679 680
	ah->stats.ast_ani_ofdmerrs +=
		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
S
Sujith 已提交
681

682
	cckPhyErrCnt = phyCnt2 - cck_base;
S
Sujith 已提交
683 684 685
	ah->stats.ast_ani_cckerrs +=
		cckPhyErrCnt - aniState->cckPhyErrCount;
	aniState->cckPhyErrCount = cckPhyErrCnt;
686
	return true;
687 688
}

689
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
690 691 692 693 694 695 696 697
{
	struct ar5416AniState *aniState;
	struct ath_common *common = ath9k_hw_common(ah);
	u32 ofdmPhyErrRate, cckPhyErrRate;

	if (!DO_ANI(ah))
		return;

698
	aniState = &ah->curchan->ani;
699 700 701
	if (WARN_ON(!aniState))
		return;

702 703
	if (!ath9k_hw_ani_read_counters(ah))
		return;
704 705 706 707 708 709

	ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
			 aniState->listenTime;
	cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
			 aniState->listenTime;

710
	ath_dbg(common, ANI,
J
Joe Perches 已提交
711 712 713 714 715
		"listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
		aniState->listenTime,
		aniState->ofdmNoiseImmunityLevel,
		ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
		cckPhyErrRate, aniState->ofdmsTurn);
716

717 718 719 720 721 722 723 724
	if (aniState->listenTime > ah->aniperiod) {
		if (cckPhyErrRate < ah->config.cck_trig_low &&
		    ((ofdmPhyErrRate < ah->config.ofdm_trig_low &&
		      aniState->ofdmNoiseImmunityLevel <
		      ATH9K_ANI_OFDM_DEF_LEVEL) ||
		     (ofdmPhyErrRate < ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI &&
		      aniState->ofdmNoiseImmunityLevel >=
		      ATH9K_ANI_OFDM_DEF_LEVEL))) {
725 726
			ath9k_hw_ani_lower_immunity(ah);
			aniState->ofdmsTurn = !aniState->ofdmsTurn;
727 728 729 730 731 732 733
		} else if ((ofdmPhyErrRate > ah->config.ofdm_trig_high &&
			    aniState->ofdmNoiseImmunityLevel >=
			    ATH9K_ANI_OFDM_DEF_LEVEL) ||
			   (ofdmPhyErrRate >
			    ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI &&
			    aniState->ofdmNoiseImmunityLevel <
			    ATH9K_ANI_OFDM_DEF_LEVEL)) {
734
			ath9k_hw_ani_ofdm_err_trigger(ah);
735
			aniState->ofdmsTurn = false;
736
		} else if (cckPhyErrRate > ah->config.cck_trig_high) {
737
			ath9k_hw_ani_cck_err_trigger(ah);
738
			aniState->ofdmsTurn = true;
S
Sujith 已提交
739
		}
740
		ath9k_ani_restart(ah);
S
Sujith 已提交
741 742
	}
}
743
EXPORT_SYMBOL(ath9k_hw_ani_monitor);
S
Sujith 已提交
744

745
void ath9k_enable_mib_counters(struct ath_hw *ah)
S
Sujith 已提交
746
{
747 748
	struct ath_common *common = ath9k_hw_common(ah);

749
	ath_dbg(common, ANI, "Enable MIB counters\n");
S
Sujith 已提交
750

751
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
752

S
Sujith 已提交
753 754
	ENABLE_REGWRITE_BUFFER(ah);

S
Sujith 已提交
755 756 757 758 759 760 761
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
	REG_WRITE(ah, AR_MIBC,
		  ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
		  & 0x0f);
	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
S
Sujith 已提交
762 763

	REGWRITE_BUFFER_FLUSH(ah);
S
Sujith 已提交
764 765
}

766
/* Freeze the MIB counters, get the stats and then clear them */
767
void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
S
Sujith 已提交
768
{
769 770
	struct ath_common *common = ath9k_hw_common(ah);

771
	ath_dbg(common, ANI, "Disable MIB counters\n");
772

773
	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
774
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
775
	REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
S
Sujith 已提交
776 777 778
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
}
S
Sujith 已提交
779
EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
S
Sujith 已提交
780 781 782 783 784 785

/*
 * Process a MIB interrupt.  We may potentially be invoked because
 * any of the MIB counters overflow/trigger so don't assume we're
 * here because a PHY error counter triggered.
 */
786
void ath9k_hw_proc_mib_event(struct ath_hw *ah)
S
Sujith 已提交
787 788 789 790 791 792 793 794 795 796
{
	u32 phyCnt1, phyCnt2;

	/* Reset these counters regardless */
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
	if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
		REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);

	/* Clear the mib counters and save them in the stats */
797
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
798

799 800 801 802 803 804 805
	if (!DO_ANI(ah)) {
		/*
		 * We must always clear the interrupt cause by
		 * resetting the phy error regs.
		 */
		REG_WRITE(ah, AR_PHY_ERR_1, 0);
		REG_WRITE(ah, AR_PHY_ERR_2, 0);
S
Sujith 已提交
806
		return;
807
	}
S
Sujith 已提交
808 809 810 811 812 813 814

	/* NB: these are not reset-on-read */
	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
	if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
	    ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {

815 816
		if (!use_new_ani(ah))
			ath9k_hw_ani_read_counters(ah);
S
Sujith 已提交
817 818

		/* NB: always restart to insure the h/w counters are reset */
819
		ath9k_ani_restart(ah);
S
Sujith 已提交
820 821
	}
}
822
EXPORT_SYMBOL(ath9k_hw_proc_mib_event);
823

824
void ath9k_hw_ani_setup(struct ath_hw *ah)
S
Sujith 已提交
825 826 827
{
	int i;

J
Joe Perches 已提交
828 829 830 831
	static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
	static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
	static const int coarseLow[] = { -64, -64, -64, -64, -70 };
	static const int firpwr[] = { -78, -78, -78, -78, -80 };
S
Sujith 已提交
832 833

	for (i = 0; i < 5; i++) {
834 835 836 837
		ah->totalSizeDesired[i] = totalSizeDesired[i];
		ah->coarse_high[i] = coarseHigh[i];
		ah->coarse_low[i] = coarseLow[i];
		ah->firpwr[i] = firpwr[i];
S
Sujith 已提交
838 839 840
	}
}

841
void ath9k_hw_ani_init(struct ath_hw *ah)
S
Sujith 已提交
842
{
843
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
844 845
	int i;

846
	ath_dbg(common, ANI, "Initialize ANI\n");
847

848 849 850
	if (use_new_ani(ah)) {
		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
851

852 853 854 855 856
		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
	} else {
		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
857

858 859 860
		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
	}
861

862 863 864 865 866 867 868
	for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
		struct ath9k_channel *chan = &ah->channels[i];
		struct ar5416AniState *ani = &chan->ani;

		if (use_new_ani(ah)) {
			ani->spurImmunityLevel =
				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
869

870
			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
871 872

			if (AR_SREV_9300_20_OR_LATER(ah))
873
				ani->mrcCCKOff =
874 875
					!ATH9K_ANI_ENABLE_MRC_CCK;
			else
876
				ani->mrcCCKOff = true;
877

878
			ani->ofdmsTurn = true;
879
		} else {
880
			ani->spurImmunityLevel =
881
				ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
882
			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
883

884
			ani->cckWeakSigThreshold =
885 886 887
				ATH9K_ANI_CCK_WEAK_SIG_THR;
		}

888 889
		ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
		ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
890
		ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
891
		ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
892 893
		ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
		ani->update_ani = false;
894 895 896 897 898 899
	}

	/*
	 * since we expect some ongoing maintenance on the tables, let's sanity
	 * check here default level should not modify INI setting.
	 */
900
	if (use_new_ani(ah)) {
901 902 903 904 905
		ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
	} else {
		ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
S
Sujith 已提交
906
	}
S
Sujith 已提交
907

908 909
	if (ah->config.enable_ani)
		ah->proc_phyerr |= HAL_PROCESS_ANI;
910 911 912

	ath9k_ani_restart(ah);
	ath9k_enable_mib_counters(ah);
S
Sujith 已提交
913
}