ani.c 18.0 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.
 */

17
#include "hw.h"
18
#include "hw-ops.h"
S
Sujith 已提交
19

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

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

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

	return 0;
}

41
static void ath9k_hw_update_mibstats(struct ath_hw *ah,
S
Sujith 已提交
42 43 44 45 46 47 48 49 50
				     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);
}

51
static void ath9k_ani_restart(struct ath_hw *ah)
S
Sujith 已提交
52 53
{
	struct ar5416AniState *aniState;
54
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
55 56 57 58

	if (!DO_ANI(ah))
		return;

59
	aniState = ah->curani;
S
Sujith 已提交
60
	aniState->listenTime = 0;
S
Sujith 已提交
61 62 63

	if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
		aniState->ofdmPhyErrBase = 0;
64 65
		ath_print(common, ATH_DBG_ANI,
			  "OFDM Trigger is too high for hw counters\n");
S
Sujith 已提交
66 67 68 69 70 71
	} else {
		aniState->ofdmPhyErrBase =
			AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
	}
	if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
		aniState->cckPhyErrBase = 0;
72 73
		ath_print(common, ATH_DBG_ANI,
			  "CCK Trigger is too high for hw counters\n");
S
Sujith 已提交
74 75 76
	} else {
		aniState->cckPhyErrBase =
			AR_PHY_COUNTMAX - aniState->cckTrigHigh;
S
Sujith 已提交
77
	}
78 79 80 81
	ath_print(common, ATH_DBG_ANI,
		  "Writing ofdmbase=%u   cckbase=%u\n",
		  aniState->ofdmPhyErrBase,
		  aniState->cckPhyErrBase);
S
Sujith 已提交
82 83 84 85 86 87 88
	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 已提交
89 90 91 92
	aniState->ofdmPhyErrCount = 0;
	aniState->cckPhyErrCount = 0;
}

93
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
S
Sujith 已提交
94
{
95
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
96 97 98 99 100 101
	struct ar5416AniState *aniState;
	int32_t rssi;

	if (!DO_ANI(ah))
		return;

102
	aniState = ah->curani;
S
Sujith 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

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

118
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
119 120 121 122 123 124
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
125
	rssi = BEACON_RSSI(ah);
S
Sujith 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
	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 已提交
151 152
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
S
Sujith 已提交
153 154 155 156 157 158 159 160 161 162 163 164
			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;
		}
	}
}

165
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
S
Sujith 已提交
166
{
167
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
168 169 170 171 172 173
	struct ar5416AniState *aniState;
	int32_t rssi;

	if (!DO_ANI(ah))
		return;

174
	aniState = ah->curani;
S
Sujith 已提交
175 176 177 178 179 180
	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
					 aniState->noiseImmunityLevel + 1)) {
			return;
		}
	}
181
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
182 183 184 185 186 187
		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
					     aniState->firstepLevel + 1);
		}
		return;
	}
188
	rssi = BEACON_RSSI(ah);
S
Sujith 已提交
189 190 191 192 193
	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 已提交
194 195
		if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
		    !conf_is_ht(conf)) {
S
Sujith 已提交
196 197 198 199 200 201 202
			if (aniState->firstepLevel > 0)
				ath9k_hw_ani_control(ah,
					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
		}
	}
}

203
static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
S
Sujith 已提交
204 205 206 207
{
	struct ar5416AniState *aniState;
	int32_t rssi;

208
	aniState = ah->curani;
S
Sujith 已提交
209

210
	if (ah->opmode == NL80211_IFTYPE_AP) {
S
Sujith 已提交
211 212 213 214 215 216
		if (aniState->firstepLevel > 0) {
			if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
						 aniState->firstepLevel - 1))
				return;
		}
	} else {
217
		rssi = BEACON_RSSI(ah);
S
Sujith 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
		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;
	}
}

256
static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
S
Sujith 已提交
257 258 259 260 261 262 263 264 265
{
	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);

266
	aniState = ah->curani;
S
Sujith 已提交
267 268 269
	if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {

		listenTime = 0;
270
		ah->stats.ast_ani_lzero++;
S
Sujith 已提交
271 272 273 274 275 276 277 278 279 280 281 282 283
	} 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;
}

284
void ath9k_ani_reset(struct ath_hw *ah)
S
Sujith 已提交
285 286
{
	struct ar5416AniState *aniState;
287
	struct ath9k_channel *chan = ah->curchan;
288
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
289 290 291 292 293 294
	int index;

	if (!DO_ANI(ah))
		return;

	index = ath9k_hw_get_ani_channel_idx(ah, chan);
295 296
	aniState = &ah->ani[index];
	ah->curani = aniState;
S
Sujith 已提交
297

298 299
	if (DO_ANI(ah) && ah->opmode != NL80211_IFTYPE_STATION
	    && ah->opmode != NL80211_IFTYPE_ADHOC) {
300 301
		ath_print(common, ATH_DBG_ANI,
			  "Reset ANI state opmode %u\n", ah->opmode);
302
		ah->stats.ast_ani_reset++;
S
Sujith 已提交
303

304 305 306 307 308 309 310 311 312 313 314 315
		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 已提交
316 317 318 319 320 321 322 323 324 325 326
		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);

327 328 329 330 331 332 333 334 335
		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 已提交
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
		}
		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 已提交
357 358 359 360 361
	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 已提交
362 363
}

364
void ath9k_hw_ani_monitor(struct ath_hw *ah,
S
Sujith 已提交
365 366 367
			  struct ath9k_channel *chan)
{
	struct ar5416AniState *aniState;
368
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
369
	int32_t listenTime;
S
Sujith 已提交
370 371
	u32 phyCnt1, phyCnt2;
	u32 ofdmPhyErrCnt, cckPhyErrCnt;
S
Sujith 已提交
372

373 374 375
	if (!DO_ANI(ah))
		return;

376
	aniState = ah->curani;
S
Sujith 已提交
377 378 379

	listenTime = ath9k_hw_ani_get_listen_time(ah);
	if (listenTime < 0) {
380
		ah->stats.ast_ani_lneg++;
S
Sujith 已提交
381 382 383 384 385 386
		ath9k_ani_restart(ah);
		return;
	}

	aniState->listenTime += listenTime;

S
Sujith 已提交
387
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
388

S
Sujith 已提交
389 390 391 392 393 394
	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) {
395 396 397 398 399
			ath_print(common, ATH_DBG_ANI,
				  "phyCnt1 0x%x, resetting "
				  "counter value to 0x%x\n",
				  phyCnt1,
				  aniState->ofdmPhyErrBase);
S
Sujith 已提交
400 401 402 403 404 405
			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) {
406 407 408 409 410
			ath_print(common, ATH_DBG_ANI,
				  "phyCnt2 0x%x, resetting "
				  "counter value to 0x%x\n",
				  phyCnt2,
				  aniState->cckPhyErrBase);
S
Sujith 已提交
411 412 413 414
			REG_WRITE(ah, AR_PHY_ERR_2,
				  aniState->cckPhyErrBase);
			REG_WRITE(ah, AR_PHY_ERR_MASK_2,
				  AR_PHY_ERR_CCK_TIMING);
S
Sujith 已提交
415
		}
S
Sujith 已提交
416 417
		return;
	}
S
Sujith 已提交
418

S
Sujith 已提交
419 420 421 422
	ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
	ah->stats.ast_ani_ofdmerrs +=
		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
S
Sujith 已提交
423

S
Sujith 已提交
424 425 426 427
	cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
	ah->stats.ast_ani_cckerrs +=
		cckPhyErrCnt - aniState->cckPhyErrCount;
	aniState->cckPhyErrCount = cckPhyErrCnt;
S
Sujith 已提交
428

429
	if (aniState->listenTime > 5 * ah->aniperiod) {
S
Sujith 已提交
430 431 432 433 434 435
		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);
436
	} else if (aniState->listenTime > ah->aniperiod) {
S
Sujith 已提交
437 438 439 440 441 442 443 444 445 446 447 448
		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);
		}
	}
}
449
EXPORT_SYMBOL(ath9k_hw_ani_monitor);
S
Sujith 已提交
450

451
void ath9k_enable_mib_counters(struct ath_hw *ah)
S
Sujith 已提交
452
{
453 454 455
	struct ath_common *common = ath9k_hw_common(ah);

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

457
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
458 459 460 461 462 463 464 465 466 467

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

468
/* Freeze the MIB counters, get the stats and then clear them */
469
void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
S
Sujith 已提交
470
{
471 472 473 474
	struct ath_common *common = ath9k_hw_common(ah);

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

475
	REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
476
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
477
	REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
S
Sujith 已提交
478 479 480 481
	REG_WRITE(ah, AR_FILT_OFDM, 0);
	REG_WRITE(ah, AR_FILT_CCK, 0);
}

482
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
S
Sujith 已提交
483 484 485 486
				  u32 *rxc_pcnt,
				  u32 *rxf_pcnt,
				  u32 *txf_pcnt)
{
487
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
488 489 490 491 492 493 494 495 496
	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) {
497 498
		ath_print(common, ATH_DBG_ANI,
			  "cycle counter wrap. ExtBusy = 0\n");
S
Sujith 已提交
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
		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.
 */
528
void ath9k_hw_procmibevent(struct ath_hw *ah)
S
Sujith 已提交
529 530 531 532 533 534 535 536 537 538
{
	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 */
539
	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
S
Sujith 已提交
540 541 542 543 544 545 546 547 548

	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)) {
549
		struct ar5416AniState *aniState = ah->curani;
S
Sujith 已提交
550 551 552 553
		u32 ofdmPhyErrCnt, cckPhyErrCnt;

		/* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
		ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
554
		ah->stats.ast_ani_ofdmerrs +=
S
Sujith 已提交
555 556 557 558
			ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
		aniState->ofdmPhyErrCount = ofdmPhyErrCnt;

		cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
559
		ah->stats.ast_ani_cckerrs +=
S
Sujith 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
			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);
	}
}
577
EXPORT_SYMBOL(ath9k_hw_procmibevent);
S
Sujith 已提交
578

579
void ath9k_hw_ani_setup(struct ath_hw *ah)
S
Sujith 已提交
580 581 582 583 584 585 586 587 588
{
	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++) {
589 590 591 592
		ah->totalSizeDesired[i] = totalSizeDesired[i];
		ah->coarse_high[i] = coarseHigh[i];
		ah->coarse_low[i] = coarseLow[i];
		ah->firpwr[i] = firpwr[i];
S
Sujith 已提交
593 594 595
	}
}

596
void ath9k_hw_ani_init(struct ath_hw *ah)
S
Sujith 已提交
597
{
598
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
599 600
	int i;

601
	ath_print(common, ATH_DBG_ANI, "Initialize ANI\n");
602 603 604 605 606 607 608 609 610 611

	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 已提交
612
			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
613
		ah->ani[i].cckWeakSigThreshold =
S
Sujith 已提交
614
			ATH9K_ANI_CCK_WEAK_SIG_THR;
615 616
		ah->ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
		ah->ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
S
Sujith 已提交
617 618 619 620
		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 已提交
621
	}
S
Sujith 已提交
622

623 624 625 626 627
	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 已提交
628 629 630 631 632

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

633 634 635
	ah->aniperiod = ATH9K_ANI_PERIOD;
	if (ah->config.enable_ani)
		ah->proc_phyerr |= HAL_PROCESS_ANI;
S
Sujith 已提交
636 637
}

638
void ath9k_hw_ani_disable(struct ath_hw *ah)
S
Sujith 已提交
639
{
640
	ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
S
Sujith 已提交
641

S
Sujith 已提交
642 643 644
	ath9k_hw_disable_mib_counters(ah);
	REG_WRITE(ah, AR_PHY_ERR_1, 0);
	REG_WRITE(ah, AR_PHY_ERR_2, 0);
S
Sujith 已提交
645
}