ani.c 23.1 KB
Newer Older
S
Sujith 已提交
1
/*
2
 * Copyright (c) 2008-2009 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.
 */

S
Sujith 已提交
17
#include "ath9k.h"
S
Sujith 已提交
18

19
static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
S
Sujith 已提交
20 21 22 23
					struct ath9k_channel *chan)
{
	int i;

24 25 26
	for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
		if (ah->ani[i].c &&
		    ah->ani[i].c->channel == chan->channel)
S
Sujith 已提交
27
			return i;
28 29
		if (ah->ani[i].c == NULL) {
			ah->ani[i].c = chan;
S
Sujith 已提交
30 31 32 33
			return i;
		}
	}

34 35
	ath_print(ath9k_hw_common(ah), ATH_DBG_ANI,
		  "No more channel states left. Using channel 0\n");
S
Sujith 已提交
36 37 38 39

	return 0;
}

40
static bool ath9k_hw_ani_control(struct ath_hw *ah,
S
Sujith 已提交
41 42
				 enum ath9k_ani_cmd cmd, int param)
{
43
	struct ar5416AniState *aniState = ah->curani;
44
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
45

46
	switch (cmd & ah->ani_function) {
S
Sujith 已提交
47 48 49
	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
		u32 level = param;

50
		if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
51 52 53 54
			ath_print(common, ATH_DBG_ANI,
				  "level out of range (%u > %u)\n",
				  level,
				  (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
S
Sujith 已提交
55 56 57 58 59
			return false;
		}

		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
			      AR_PHY_DESIRED_SZ_TOT_DES,
60
			      ah->totalSizeDesired[level]);
S
Sujith 已提交
61 62
		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
			      AR_PHY_AGC_CTL1_COARSE_LOW,
63
			      ah->coarse_low[level]);
S
Sujith 已提交
64 65
		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
			      AR_PHY_AGC_CTL1_COARSE_HIGH,
66
			      ah->coarse_high[level]);
S
Sujith 已提交
67 68
		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
			      AR_PHY_FIND_SIG_FIRPWR,
69
			      ah->firpwr[level]);
S
Sujith 已提交
70 71

		if (level > aniState->noiseImmunityLevel)
72
			ah->stats.ast_ani_niup++;
S
Sujith 已提交
73
		else if (level < aniState->noiseImmunityLevel)
74
			ah->stats.ast_ani_nidown++;
S
Sujith 已提交
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
		aniState->noiseImmunityLevel = level;
		break;
	}
	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
		const int m1ThreshLow[] = { 127, 50 };
		const int m2ThreshLow[] = { 127, 40 };
		const int m1Thresh[] = { 127, 0x4d };
		const int m2Thresh[] = { 127, 0x40 };
		const int m2CountThr[] = { 31, 16 };
		const int m2CountThrLow[] = { 63, 48 };
		u32 on = param ? 1 : 0;

		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
			      m1ThreshLow[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
			      m2ThreshLow[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
			      AR_PHY_SFCORR_M1_THRESH,
			      m1Thresh[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
			      AR_PHY_SFCORR_M2_THRESH,
			      m2Thresh[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
			      AR_PHY_SFCORR_M2COUNT_THR,
			      m2CountThr[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
			      m2CountThrLow[on]);

		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
			      m1ThreshLow[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
			      m2ThreshLow[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
			      AR_PHY_SFCORR_EXT_M1_THRESH,
			      m1Thresh[on]);
		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
			      AR_PHY_SFCORR_EXT_M2_THRESH,
			      m2Thresh[on]);

		if (on)
			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
		else
			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);

		if (!on != aniState->ofdmWeakSigDetectOff) {
			if (on)
128
				ah->stats.ast_ani_ofdmon++;
S
Sujith 已提交
129
			else
130
				ah->stats.ast_ani_ofdmoff++;
S
Sujith 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143
			aniState->ofdmWeakSigDetectOff = !on;
		}
		break;
	}
	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
		const int weakSigThrCck[] = { 8, 6 };
		u32 high = param ? 1 : 0;

		REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
			      AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
			      weakSigThrCck[high]);
		if (high != aniState->cckWeakSigThreshold) {
			if (high)
144
				ah->stats.ast_ani_cckhigh++;
S
Sujith 已提交
145
			else
146
				ah->stats.ast_ani_ccklow++;
S
Sujith 已提交
147 148 149 150 151 152 153 154 155
			aniState->cckWeakSigThreshold = high;
		}
		break;
	}
	case ATH9K_ANI_FIRSTEP_LEVEL:{
		const int firstep[] = { 0, 4, 8 };
		u32 level = param;

		if (level >= ARRAY_SIZE(firstep)) {
156 157 158 159
			ath_print(common, ATH_DBG_ANI,
				  "level out of range (%u > %u)\n",
				  level,
				  (unsigned) ARRAY_SIZE(firstep));
S
Sujith 已提交
160 161 162 163 164 165
			return false;
		}
		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
			      AR_PHY_FIND_SIG_FIRSTEP,
			      firstep[level]);
		if (level > aniState->firstepLevel)
166
			ah->stats.ast_ani_stepup++;
S
Sujith 已提交
167
		else if (level < aniState->firstepLevel)
168
			ah->stats.ast_ani_stepdown++;
S
Sujith 已提交
169 170 171 172 173 174 175 176 177
		aniState->firstepLevel = level;
		break;
	}
	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
		const int cycpwrThr1[] =
			{ 2, 4, 6, 8, 10, 12, 14, 16 };
		u32 level = param;

		if (level >= ARRAY_SIZE(cycpwrThr1)) {
178 179 180 181
			ath_print(common, ATH_DBG_ANI,
				  "level out of range (%u > %u)\n",
				  level,
				  (unsigned) ARRAY_SIZE(cycpwrThr1));
S
Sujith 已提交
182 183 184 185 186 187
			return false;
		}
		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
			      AR_PHY_TIMING5_CYCPWR_THR1,
			      cycpwrThr1[level]);
		if (level > aniState->spurImmunityLevel)
188
			ah->stats.ast_ani_spurup++;
S
Sujith 已提交
189
		else if (level < aniState->spurImmunityLevel)
190
			ah->stats.ast_ani_spurdown++;
S
Sujith 已提交
191 192 193 194 195 196
		aniState->spurImmunityLevel = level;
		break;
	}
	case ATH9K_ANI_PRESENT:
		break;
	default:
197 198
		ath_print(common, ATH_DBG_ANI,
			  "invalid cmd %u\n", cmd);
S
Sujith 已提交
199 200 201
		return false;
	}

202 203 204 205 206 207 208 209 210 211 212 213 214 215
	ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
	ath_print(common, ATH_DBG_ANI,
		  "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
		  "ofdmWeakSigDetectOff=%d\n",
		  aniState->noiseImmunityLevel,
		  aniState->spurImmunityLevel,
		  !aniState->ofdmWeakSigDetectOff);
	ath_print(common, ATH_DBG_ANI,
		  "cckWeakSigThreshold=%d, "
		  "firstepLevel=%d, listenTime=%d\n",
		  aniState->cckWeakSigThreshold,
		  aniState->firstepLevel,
		  aniState->listenTime);
	ath_print(common, ATH_DBG_ANI,
S
Sujith 已提交
216
		"cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
217 218
		aniState->cycleCount,
		aniState->ofdmPhyErrCount,
S
Sujith 已提交
219 220 221 222 223
		aniState->cckPhyErrCount);

	return true;
}

224
static void ath9k_hw_update_mibstats(struct ath_hw *ah,
S
Sujith 已提交
225 226 227 228 229 230 231 232 233
				     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);
}

234
static void ath9k_ani_restart(struct ath_hw *ah)
S
Sujith 已提交
235 236
{
	struct ar5416AniState *aniState;
237
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
238 239 240 241

	if (!DO_ANI(ah))
		return;

242
	aniState = ah->curani;
S
Sujith 已提交
243
	aniState->listenTime = 0;
S
Sujith 已提交
244 245 246

	if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
		aniState->ofdmPhyErrBase = 0;
247 248
		ath_print(common, ATH_DBG_ANI,
			  "OFDM Trigger is too high for hw counters\n");
S
Sujith 已提交
249 250 251 252 253 254
	} else {
		aniState->ofdmPhyErrBase =
			AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
	}
	if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
		aniState->cckPhyErrBase = 0;
255 256
		ath_print(common, ATH_DBG_ANI,
			  "CCK Trigger is too high for hw counters\n");
S
Sujith 已提交
257 258 259
	} else {
		aniState->cckPhyErrBase =
			AR_PHY_COUNTMAX - aniState->cckTrigHigh;
S
Sujith 已提交
260
	}
261 262 263 264
	ath_print(common, ATH_DBG_ANI,
		  "Writing ofdmbase=%u   cckbase=%u\n",
		  aniState->ofdmPhyErrBase,
		  aniState->cckPhyErrBase);
S
Sujith 已提交
265 266 267 268 269 270 271
	REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
	REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
	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);

	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);

S
Sujith 已提交
272 273 274 275
	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}

276
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
S
Sujith 已提交
277
{
278
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
279 280 281 282 283 284
	struct ar5416AniState *aniState;
	int32_t rssi;

	if (!DO_ANI(ah))
		return;

285
	aniState = ah->curani;
S
Sujith 已提交
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300

	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;
		}
	}

301
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
302 303 304 305 306 307
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
308
	rssi = BEACON_RSSI(ah);
S
Sujith 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
	if (rssi > aniState->rssiThrHigh) {
		if (!aniState->ofdmWeakSigDetectOff) {
			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) {
		if (aniState->ofdmWeakSigDetectOff)
			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 已提交
334 335
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
S
Sujith 已提交
336 337 338 339 340 341 342 343 344 345 346 347
			if (!aniState->ofdmWeakSigDetectOff)
				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;
		}
	}
}

348
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
S
Sujith 已提交
349
{
350
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
351 352 353 354 355 356
	struct ar5416AniState *aniState;
	int32_t rssi;

	if (!DO_ANI(ah))
		return;

357
	aniState = ah->curani;
S
Sujith 已提交
358 359 360 361 362 363
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
					 aniState->noiseImmunityLevel + 1)) {
			return;
		}
	}
364
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
365 366 367 368 369 370
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
371
	rssi = BEACON_RSSI(ah);
S
Sujith 已提交
372 373 374 375 376
	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 已提交
377 378
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
S
Sujith 已提交
379 380 381 382 383 384 385
			if (aniState->firstepLevel > 0)
				ath9k_hw_ani_control(ah,
					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
		}
	}
}

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

391
	aniState = ah->curani;
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 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
		if (rssi > aniState->rssiThrHigh) {
			/* XXX: Handle me */
		} else if (rssi > aniState->rssiThrLow) {
			if (aniState->ofdmWeakSigDetectOff) {
				if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
					 true) == true)
					return;
			}
			if (aniState->firstepLevel > 0) {
				if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel - 1) == true)
					return;
			}
		} else {
			if (aniState->firstepLevel > 0) {
				if (ath9k_hw_ani_control(ah,
					 ATH9K_ANI_FIRSTEP_LEVEL,
					 aniState->firstepLevel - 1) == true)
					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
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
S
Sujith 已提交
440 441 442 443 444 445 446 447 448
{
	struct ar5416AniState *aniState;
	u32 txFrameCount, rxFrameCount, cycleCount;
	int32_t listenTime;

	txFrameCount = REG_READ(ah, AR_TFCNT);
	rxFrameCount = REG_READ(ah, AR_RFCNT);
	cycleCount = REG_READ(ah, AR_CCCNT);

449
	aniState = ah->curani;
S
Sujith 已提交
450 451 452
	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {

		listenTime = 0;
453
		ah->stats.ast_ani_lzero++;
S
Sujith 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466
	} else {
		int32_t ccdelta = cycleCount - aniState->cycleCount;
		int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
		int32_t tfdelta = txFrameCount - aniState->txFrameCount;
		listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
	}
	aniState->cycleCount = cycleCount;
	aniState->txFrameCount = txFrameCount;
	aniState->rxFrameCount = rxFrameCount;

	return listenTime;
}

467
void ath9k_ani_reset(struct ath_hw *ah)
S
Sujith 已提交
468 469
{
	struct ar5416AniState *aniState;
470
	struct ath9k_channel *chan = ah->curchan;
471
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
472 473 474 475 476 477
	int index;

	if (!DO_ANI(ah))
		return;

	index = ath9k_hw_get_ani_channel_idx(ah, chan);
478 479
	aniState = &ah->ani[index];
	ah->curani = aniState;
S
Sujith 已提交
480

481 482
	if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
	    && ah->opmode != NL80211_IFTYPE_ADHOC) {
483 484
		ath_print(common, ATH_DBG_ANI,
			  "Reset ANI state opmode %u\n", ah->opmode);
485
		ah->stats.ast_ani_reset++;
S
Sujith 已提交
486

487 488 489 490 491 492 493 494 495 496 497 498
		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 已提交
499 500 501 502 503 504 505 506 507 508 509
		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);

		ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
				     ATH9K_RX_FILTER_PHYERR);

510 511 512 513 514 515 516 517 518
		if (ah->opmode == NL80211_IFTYPE_AP) {
			ah->curani->ofdmTrigHigh =
				ah->config.ofdm_trig_high;
			ah->curani->ofdmTrigLow =
				ah->config.ofdm_trig_low;
			ah->curani->cckTrigHigh =
				ah->config.cck_trig_high;
			ah->curani->cckTrigLow =
				ah->config.cck_trig_low;
S
Sujith 已提交
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
		}
		ath9k_ani_restart(ah);
		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);
	if (aniState->ofdmWeakSigDetectOff)
		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
				     !aniState->ofdmWeakSigDetectOff);
	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);

S
Sujith 已提交
540 541 542 543 544
	ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
			     ~ATH9K_RX_FILTER_PHYERR);
	ath9k_ani_restart(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);
S
Sujith 已提交
545 546
}

547
void ath9k_hw_ani_monitor(struct ath_hw *ah,
S
Sujith 已提交
548 549 550
			  struct ath9k_channel *chan)
{
	struct ar5416AniState *aniState;
551
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
552
	int32_t listenTime;
S
Sujith 已提交
553 554
	u32 phyCnt1, phyCnt2;
	u32 ofdmPhyErrCnt, cckPhyErrCnt;
S
Sujith 已提交
555

556 557 558
	if (!DO_ANI(ah))
		return;

559
	aniState = ah->curani;
S
Sujith 已提交
560 561 562

	listenTime = ath9k_hw_ani_get_listen_time(ah);
	if (listenTime < 0) {
563
		ah->stats.ast_ani_lneg++;
S
Sujith 已提交
564 565 566 567 568 569
		ath9k_ani_restart(ah);
		return;
	}

	aniState->listenTime += listenTime;

S
Sujith 已提交
570
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
571

S
Sujith 已提交
572 573 574 575 576 577
	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);

	if (phyCnt1 < aniState->ofdmPhyErrBase ||
	    phyCnt2 < aniState->cckPhyErrBase) {
		if (phyCnt1 < aniState->ofdmPhyErrBase) {
578 579 580 581 582
			ath_print(common, ATH_DBG_ANI,
				  "phyCnt1 0x%x, resetting "
				  "counter value to 0x%x\n",
				  phyCnt1,
				  aniState->ofdmPhyErrBase);
S
Sujith 已提交
583 584 585 586 587 588
			REG_WRITE(ah, AR_PHY_ERR_1,
				  aniState->ofdmPhyErrBase);
			REG_WRITE(ah, AR_PHY_ERR_MASK_1,
				  AR_PHY_ERR_OFDM_TIMING);
		}
		if (phyCnt2 < aniState->cckPhyErrBase) {
589 590 591 592 593
			ath_print(common, ATH_DBG_ANI,
				  "phyCnt2 0x%x, resetting "
				  "counter value to 0x%x\n",
				  phyCnt2,
				  aniState->cckPhyErrBase);
S
Sujith 已提交
594 595 596 597
			REG_WRITE(ah, AR_PHY_ERR_2,
				  aniState->cckPhyErrBase);
			REG_WRITE(ah, AR_PHY_ERR_MASK_2,
				  AR_PHY_ERR_CCK_TIMING);
S
Sujith 已提交
598
		}
S
Sujith 已提交
599 600
		return;
	}
S
Sujith 已提交
601

S
Sujith 已提交
602 603 604 605
	ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
	ah->stats.ast_ani_ofdmerrs +=
		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
S
Sujith 已提交
606

S
Sujith 已提交
607 608 609 610
	cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
	ah->stats.ast_ani_cckerrs +=
		cckPhyErrCnt - aniState->cckPhyErrCount;
	aniState->cckPhyErrCount = cckPhyErrCnt;
S
Sujith 已提交
611

612
	if (aniState->listenTime > 5 * ah->aniperiod) {
S
Sujith 已提交
613 614 615 616 617 618
		if (aniState->ofdmPhyErrCount <= aniState->listenTime *
		    aniState->ofdmTrigLow / 1000 &&
		    aniState->cckPhyErrCount <= aniState->listenTime *
		    aniState->cckTrigLow / 1000)
			ath9k_hw_ani_lower_immunity(ah);
		ath9k_ani_restart(ah);
619
	} else if (aniState->listenTime > ah->aniperiod) {
S
Sujith 已提交
620 621 622 623 624 625 626 627 628 629 630 631 632
		if (aniState->ofdmPhyErrCount > aniState->listenTime *
		    aniState->ofdmTrigHigh / 1000) {
			ath9k_hw_ani_ofdm_err_trigger(ah);
			ath9k_ani_restart(ah);
		} else if (aniState->cckPhyErrCount >
			   aniState->listenTime * aniState->cckTrigHigh /
			   1000) {
			ath9k_hw_ani_cck_err_trigger(ah);
			ath9k_ani_restart(ah);
		}
	}
}

633
void ath9k_enable_mib_counters(struct ath_hw *ah)
S
Sujith 已提交
634
{
635 636 637
	struct ath_common *common = ath9k_hw_common(ah);

	ath_print(common, ATH_DBG_ANI, "Enable MIB counters\n");
S
Sujith 已提交
638

639
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
640 641 642 643 644 645 646 647 648 649

	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);
}

650
/* Freeze the MIB counters, get the stats and then clear them */
651
void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
S
Sujith 已提交
652
{
653 654 655 656
	struct ath_common *common = ath9k_hw_common(ah);

	ath_print(common, ATH_DBG_ANI, "Disable MIB counters\n");

657
	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
658
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
659
	REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
S
Sujith 已提交
660 661 662 663
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
}

664
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
S
Sujith 已提交
665 666 667 668
				  u32 *rxc_pcnt,
				  u32 *rxf_pcnt,
				  u32 *txf_pcnt)
{
669
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
670 671 672 673 674 675 676 677 678
	static u32 cycles, rx_clear, rx_frame, tx_frame;
	u32 good = 1;

	u32 rc = REG_READ(ah, AR_RCCNT);
	u32 rf = REG_READ(ah, AR_RFCNT);
	u32 tf = REG_READ(ah, AR_TFCNT);
	u32 cc = REG_READ(ah, AR_CCCNT);

	if (cycles == 0 || cycles > cc) {
679 680
		ath_print(common, ATH_DBG_ANI,
			  "cycle counter wrap. ExtBusy = 0\n");
S
Sujith 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
		good = 0;
	} else {
		u32 cc_d = cc - cycles;
		u32 rc_d = rc - rx_clear;
		u32 rf_d = rf - rx_frame;
		u32 tf_d = tf - tx_frame;

		if (cc_d != 0) {
			*rxc_pcnt = rc_d * 100 / cc_d;
			*rxf_pcnt = rf_d * 100 / cc_d;
			*txf_pcnt = tf_d * 100 / cc_d;
		} else {
			good = 0;
		}
	}

	cycles = cc;
	rx_frame = rf;
	rx_clear = rc;
	tx_frame = tf;

	return good;
}

/*
 * 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.
 */
710
void ath9k_hw_procmibevent(struct ath_hw *ah)
S
Sujith 已提交
711 712 713 714 715 716 717 718 719 720
{
	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 */
721
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
722 723 724 725 726 727 728 729 730

	if (!DO_ANI(ah))
		return;

	/* 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)) {
731
		struct ar5416AniState *aniState = ah->curani;
S
Sujith 已提交
732 733 734 735
		u32 ofdmPhyErrCnt, cckPhyErrCnt;

		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
736
		ah->stats.ast_ani_ofdmerrs +=
S
Sujith 已提交
737 738 739 740
			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;

		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
741
		ah->stats.ast_ani_cckerrs +=
S
Sujith 已提交
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
			cckPhyErrCnt - aniState->cckPhyErrCount;
		aniState->cckPhyErrCount = cckPhyErrCnt;

		/*
		 * NB: figure out which counter triggered.  If both
		 * trigger we'll only deal with one as the processing
		 * clobbers the error counter so the trigger threshold
		 * check will never be true.
		 */
		if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
			ath9k_hw_ani_ofdm_err_trigger(ah);
		if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
			ath9k_hw_ani_cck_err_trigger(ah);
		/* NB: always restart to insure the h/w counters are reset */
		ath9k_ani_restart(ah);
	}
}

760
void ath9k_hw_ani_setup(struct ath_hw *ah)
S
Sujith 已提交
761 762 763 764 765 766 767 768 769
{
	int i;

	const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
	const int coarseHigh[] = { -14, -14, -14, -14, -12 };
	const int coarseLow[] = { -64, -64, -64, -64, -70 };
	const int firpwr[] = { -78, -78, -78, -78, -80 };

	for (i = 0; i < 5; i++) {
770 771 772 773
		ah->totalSizeDesired[i] = totalSizeDesired[i];
		ah->coarse_high[i] = coarseHigh[i];
		ah->coarse_low[i] = coarseLow[i];
		ah->firpwr[i] = firpwr[i];
S
Sujith 已提交
774 775 776
	}
}

777
void ath9k_hw_ani_init(struct ath_hw *ah)
S
Sujith 已提交
778
{
779
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
780 781
	int i;

782
	ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
783 784 785 786 787 788 789 790 791 792

	memset(ah->ani, 0, sizeof(ah->ani));
	for (i = 0; i < ARRAY_SIZE(ah->ani); i++) {
		ah->ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
		ah->ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
		ah->ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
		ah->ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
		ah->ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
		ah->ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
		ah->ani[i].ofdmWeakSigDetectOff =
S
Sujith 已提交
793
			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
794
		ah->ani[i].cckWeakSigThreshold =
S
Sujith 已提交
795
			ATH9K_ANI_CCK_WEAK_SIG_THR;
796 797
		ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
		ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
S
Sujith 已提交
798 799 800 801
		ah->ani[i].ofdmPhyErrBase =
			AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
		ah->ani[i].cckPhyErrBase =
			AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
S
Sujith 已提交
802
	}
S
Sujith 已提交
803

804 805 806 807 808
	ath_print(common, ATH_DBG_ANI,
		  "Setting OfdmErrBase = 0x%08x\n",
		  ah->ani[0].ofdmPhyErrBase);
	ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
		  ah->ani[0].cckPhyErrBase);
S
Sujith 已提交
809 810 811 812 813

	REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
	REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
	ath9k_enable_mib_counters(ah);

814 815 816
	ah->aniperiod = ATH9K_ANI_PERIOD;
	if (ah->config.enable_ani)
		ah->proc_phyerr |= HAL_PROCESS_ANI;
S
Sujith 已提交
817 818
}

819
void ath9k_hw_ani_disable(struct ath_hw *ah)
S
Sujith 已提交
820
{
821
	ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
S
Sujith 已提交
822

S
Sujith 已提交
823 824 825
	ath9k_hw_disable_mib_counters(ah);
	REG_WRITE(ah, AR_PHY_ERR_1, 0);
	REG_WRITE(ah, AR_PHY_ERR_2, 0);
S
Sujith 已提交
826
}