mac.c 26.6 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 void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
S
Sujith 已提交
20 21 22
					struct ath9k_tx_queue_info *qi)
{
	DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
S
Sujith 已提交
23
		"tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
24 25 26
		ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
		ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
		ah->txurn_interrupt_mask);
S
Sujith 已提交
27 28

	REG_WRITE(ah, AR_IMR_S0,
29 30
		  SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
		  | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
S
Sujith 已提交
31
	REG_WRITE(ah, AR_IMR_S1,
32 33
		  SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
		  | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
S
Sujith 已提交
34
	REG_RMW_FIELD(ah, AR_IMR_S2,
35
		      AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask);
S
Sujith 已提交
36 37
}

38
u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
S
Sujith 已提交
39 40 41 42
{
	return REG_READ(ah, AR_QTXDP(q));
}

43
bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
S
Sujith 已提交
44 45 46 47 48 49
{
	REG_WRITE(ah, AR_QTXDP(q), txdp);

	return true;
}

50
bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
S
Sujith 已提交
51
{
S
Sujith 已提交
52
	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Enable TXE on queue: %u\n", q);
S
Sujith 已提交
53 54 55 56 57 58

	REG_WRITE(ah, AR_Q_TXE, 1 << q);

	return true;
}

59
u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
S
Sujith 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72
{
	u32 npend;

	npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
	if (npend == 0) {

		if (REG_READ(ah, AR_Q_TXE) & (1 << q))
			npend = 1;
	}

	return npend;
}

73
bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
S
Sujith 已提交
74 75 76 77
{
	u32 txcfg, curLevel, newLevel;
	enum ath9k_int omask;

78
	if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD)
S
Sujith 已提交
79 80
		return false;

81
	omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
S
Sujith 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

	txcfg = REG_READ(ah, AR_TXCFG);
	curLevel = MS(txcfg, AR_FTRIG);
	newLevel = curLevel;
	if (bIncTrigLevel) {
		if (curLevel < MAX_TX_FIFO_THRESHOLD)
			newLevel++;
	} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
		newLevel--;
	if (newLevel != curLevel)
		REG_WRITE(ah, AR_TXCFG,
			  (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));

	ath9k_hw_set_interrupts(ah, omask);

97
	ah->tx_trig_level = newLevel;
S
Sujith 已提交
98 99 100 101

	return newLevel != curLevel;
}

102
bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
S
Sujith 已提交
103
{
S
Sujith 已提交
104 105 106
#define ATH9K_TX_STOP_DMA_TIMEOUT	4000    /* usec */
#define ATH9K_TIME_QUANTUM		100     /* usec */

107
	struct ath9k_hw_capabilities *pCap = &ah->caps;
S
Sujith 已提交
108
	struct ath9k_tx_queue_info *qi;
S
Sujith 已提交
109
	u32 tsfLow, j, wait;
S
Sujith 已提交
110 111 112
	u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;

	if (q >= pCap->total_queues) {
S
Sujith 已提交
113 114
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
			"invalid queue: %u\n", q);
S
Sujith 已提交
115 116 117
		return false;
	}

118
	qi = &ah->txq[q];
S
Sujith 已提交
119
	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
S
Sujith 已提交
120 121
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Stopping TX DMA, "
			"inactive queue: %u\n", q);
S
Sujith 已提交
122 123
		return false;
	}
S
Sujith 已提交
124 125 126

	REG_WRITE(ah, AR_Q_TXD, 1 << q);

S
Sujith 已提交
127
	for (wait = wait_time; wait != 0; wait--) {
S
Sujith 已提交
128 129
		if (ath9k_hw_numtxpending(ah, q) == 0)
			break;
S
Sujith 已提交
130
		udelay(ATH9K_TIME_QUANTUM);
S
Sujith 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
	}

	if (ath9k_hw_numtxpending(ah, q)) {
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
			"%s: Num of pending TX Frames %d on Q %d\n",
			__func__, ath9k_hw_numtxpending(ah, q), q);

		for (j = 0; j < 2; j++) {
			tsfLow = REG_READ(ah, AR_TSF_L32);
			REG_WRITE(ah, AR_QUIET2,
				  SM(10, AR_QUIET2_QUIET_DUR));
			REG_WRITE(ah, AR_QUIET_PERIOD, 100);
			REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
			REG_SET_BIT(ah, AR_TIMER_MODE,
				       AR_QUIET_TIMER_EN);

			if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
				break;

			DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
S
Sujith 已提交
151
				"TSF has moved while trying to set "
S
Sujith 已提交
152
				"quiet time TSF: 0x%08x\n", tsfLow);
S
Sujith 已提交
153 154 155 156 157 158 159
		}

		REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);

		udelay(200);
		REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);

S
Sujith 已提交
160
		wait = wait_time;
S
Sujith 已提交
161 162
		while (ath9k_hw_numtxpending(ah, q)) {
			if ((--wait) == 0) {
S
Sujith 已提交
163 164
				DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
					"Failed to stop TX DMA in 100 "
S
Sujith 已提交
165
					"msec after killing last frame\n");
S
Sujith 已提交
166 167
				break;
			}
S
Sujith 已提交
168
			udelay(ATH9K_TIME_QUANTUM);
S
Sujith 已提交
169 170 171 172 173 174 175
		}

		REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
	}

	REG_WRITE(ah, AR_Q_TXD, 0);
	return wait != 0;
S
Sujith 已提交
176 177 178

#undef ATH9K_TX_STOP_DMA_TIMEOUT
#undef ATH9K_TIME_QUANTUM
S
Sujith 已提交
179 180
}

181
bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
			 u32 segLen, bool firstSeg,
			 bool lastSeg, const struct ath_desc *ds0)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	if (firstSeg) {
		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
	} else if (lastSeg) {
		ads->ds_ctl0 = 0;
		ads->ds_ctl1 = segLen;
		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
	} else {
		ads->ds_ctl0 = 0;
		ads->ds_ctl1 = segLen | AR_TxMore;
		ads->ds_ctl2 = 0;
		ads->ds_ctl3 = 0;
	}
	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;

	return true;
}

209
void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
S
Sujith 已提交
210 211 212 213 214 215 216 217 218 219
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
}

220
int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
S
Sujith 已提交
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	if ((ads->ds_txstatus9 & AR_TxDone) == 0)
		return -EINPROGRESS;

	ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
	ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
	ds->ds_txstat.ts_status = 0;
	ds->ds_txstat.ts_flags = 0;

	if (ads->ds_txstatus1 & AR_ExcessiveRetries)
		ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
	if (ads->ds_txstatus1 & AR_Filtered)
		ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
236
	if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
S
Sujith 已提交
237
		ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
238 239
		ath9k_hw_updatetxtriglevel(ah, true);
	}
S
Sujith 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
	if (ads->ds_txstatus9 & AR_TxOpExceeded)
		ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
	if (ads->ds_txstatus1 & AR_TxTimerExpired)
		ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;

	if (ads->ds_txstatus1 & AR_DescCfgErr)
		ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
	if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
		ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
		ath9k_hw_updatetxtriglevel(ah, true);
	}
	if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
		ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
		ath9k_hw_updatetxtriglevel(ah, true);
	}
	if (ads->ds_txstatus0 & AR_TxBaStatus) {
		ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
		ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
		ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
	}

	ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
	switch (ds->ds_txstat.ts_rateindex) {
	case 0:
		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
		break;
	case 1:
		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
		break;
	case 2:
		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
		break;
	case 3:
		ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
		break;
	}

	ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
	ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
	ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
	ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
	ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
	ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
	ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
	ds->ds_txstat.evm0 = ads->AR_TxEVM0;
	ds->ds_txstat.evm1 = ads->AR_TxEVM1;
	ds->ds_txstat.evm2 = ads->AR_TxEVM2;
	ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
	ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
	ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
290
	ds->ds_txstat.ts_antenna = 0;
S
Sujith 已提交
291 292 293 294

	return 0;
}

295
void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
296 297 298 299 300
			    u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
			    u32 keyIx, enum ath9k_key_type keyType, u32 flags)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

301
	txPower += ah->txpower_indexoffset;
S
Sujith 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
	if (txPower > 63)
		txPower = 63;

	ads->ds_ctl0 = (pktLen & AR_FrameLen)
		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
		| SM(txPower, AR_XmitPower)
		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
		| (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);

	ads->ds_ctl1 =
		(keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
		| SM(type, AR_FrameType)
		| (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
		| (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
		| (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);

	ads->ds_ctl6 = SM(keyType, AR_EncrType);

	if (AR_SREV_9285(ah)) {
		ads->ds_ctl8 = 0;
		ads->ds_ctl9 = 0;
		ads->ds_ctl10 = 0;
		ads->ds_ctl11 = 0;
	}
}

330
void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
				  struct ath_desc *lastds,
				  u32 durUpdateEn, u32 rtsctsRate,
				  u32 rtsctsDuration,
				  struct ath9k_11n_rate_series series[],
				  u32 nseries, u32 flags)
{
	struct ar5416_desc *ads = AR5416DESC(ds);
	struct ar5416_desc *last_ads = AR5416DESC(lastds);
	u32 ds_ctl0;

	if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
		ds_ctl0 = ads->ds_ctl0;

		if (flags & ATH9K_TXDESC_RTSENA) {
			ds_ctl0 &= ~AR_CTSEnable;
			ds_ctl0 |= AR_RTSEnable;
		} else {
			ds_ctl0 &= ~AR_RTSEnable;
			ds_ctl0 |= AR_CTSEnable;
		}

		ads->ds_ctl0 = ds_ctl0;
	} else {
		ads->ds_ctl0 =
			(ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
	}

	ads->ds_ctl2 = set11nTries(series, 0)
		| set11nTries(series, 1)
		| set11nTries(series, 2)
		| set11nTries(series, 3)
		| (durUpdateEn ? AR_DurUpdateEna : 0)
		| SM(0, AR_BurstDur);

	ads->ds_ctl3 = set11nRate(series, 0)
		| set11nRate(series, 1)
		| set11nRate(series, 2)
		| set11nRate(series, 3);

	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
		| set11nPktDurRTSCTS(series, 1);

	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
		| set11nPktDurRTSCTS(series, 3);

	ads->ds_ctl7 = set11nRateFlags(series, 0)
		| set11nRateFlags(series, 1)
		| set11nRateFlags(series, 2)
		| set11nRateFlags(series, 3)
		| SM(rtsctsRate, AR_RTSCTSRate);
	last_ads->ds_ctl2 = ads->ds_ctl2;
	last_ads->ds_ctl3 = ads->ds_ctl3;
}

385
void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
386 387 388 389 390 391 392 393 394
				u32 aggrLen)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
	ads->ds_ctl6 &= ~AR_AggrLen;
	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
}

395
void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
396 397 398 399 400 401 402 403 404 405 406 407 408
				 u32 numDelims)
{
	struct ar5416_desc *ads = AR5416DESC(ds);
	unsigned int ctl6;

	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);

	ctl6 = ads->ds_ctl6;
	ctl6 &= ~AR_PadDelim;
	ctl6 |= SM(numDelims, AR_PadDelim);
	ads->ds_ctl6 = ctl6;
}

409
void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
S
Sujith 已提交
410 411 412 413 414 415 416 417
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	ads->ds_ctl1 |= AR_IsAggr;
	ads->ds_ctl1 &= ~AR_MoreAggr;
	ads->ds_ctl6 &= ~AR_PadDelim;
}

418
void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
S
Sujith 已提交
419 420 421 422 423 424
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
}

425
void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
426 427 428 429 430 431 432 433
				   u32 burstDuration)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	ads->ds_ctl2 &= ~AR_BurstDur;
	ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
}

434
void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
435 436 437 438 439 440 441 442 443 444
				     u32 vmf)
{
	struct ar5416_desc *ads = AR5416DESC(ds);

	if (vmf)
		ads->ds_ctl0 |= AR_VirtMoreFrag;
	else
		ads->ds_ctl0 &= ~AR_VirtMoreFrag;
}

445
void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
S
Sujith 已提交
446
{
447 448
	*txqs &= ah->intr_txqs;
	ah->intr_txqs &= ~(*txqs);
S
Sujith 已提交
449 450
}

451
bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
S
Sujith 已提交
452 453 454
			    const struct ath9k_tx_queue_info *qinfo)
{
	u32 cw;
455
	struct ath9k_hw_capabilities *pCap = &ah->caps;
S
Sujith 已提交
456 457 458
	struct ath9k_tx_queue_info *qi;

	if (q >= pCap->total_queues) {
S
Sujith 已提交
459 460
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
			"invalid queue: %u\n", q);
S
Sujith 已提交
461 462 463
		return false;
	}

464
	qi = &ah->txq[q];
S
Sujith 已提交
465
	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
S
Sujith 已提交
466 467
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set TXQ properties, "
			"inactive queue: %u\n", q);
S
Sujith 已提交
468 469 470
		return false;
	}

S
Sujith 已提交
471
	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
S
Sujith 已提交
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520

	qi->tqi_ver = qinfo->tqi_ver;
	qi->tqi_subtype = qinfo->tqi_subtype;
	qi->tqi_qflags = qinfo->tqi_qflags;
	qi->tqi_priority = qinfo->tqi_priority;
	if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
		qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
	else
		qi->tqi_aifs = INIT_AIFS;
	if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
		cw = min(qinfo->tqi_cwmin, 1024U);
		qi->tqi_cwmin = 1;
		while (qi->tqi_cwmin < cw)
			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
	} else
		qi->tqi_cwmin = qinfo->tqi_cwmin;
	if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
		cw = min(qinfo->tqi_cwmax, 1024U);
		qi->tqi_cwmax = 1;
		while (qi->tqi_cwmax < cw)
			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
	} else
		qi->tqi_cwmax = INIT_CWMAX;

	if (qinfo->tqi_shretry != 0)
		qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
	else
		qi->tqi_shretry = INIT_SH_RETRY;
	if (qinfo->tqi_lgretry != 0)
		qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
	else
		qi->tqi_lgretry = INIT_LG_RETRY;
	qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
	qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
	qi->tqi_burstTime = qinfo->tqi_burstTime;
	qi->tqi_readyTime = qinfo->tqi_readyTime;

	switch (qinfo->tqi_subtype) {
	case ATH9K_WME_UPSD:
		if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
			qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
		break;
	default:
		break;
	}

	return true;
}

521
bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
S
Sujith 已提交
522 523
			    struct ath9k_tx_queue_info *qinfo)
{
524
	struct ath9k_hw_capabilities *pCap = &ah->caps;
S
Sujith 已提交
525 526 527
	struct ath9k_tx_queue_info *qi;

	if (q >= pCap->total_queues) {
S
Sujith 已提交
528 529
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
			"invalid queue: %u\n", q);
S
Sujith 已提交
530 531 532
		return false;
	}

533
	qi = &ah->txq[q];
S
Sujith 已提交
534
	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
S
Sujith 已提交
535 536
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Get TXQ properties, "
			"inactive queue: %u\n", q);
S
Sujith 已提交
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
		return false;
	}

	qinfo->tqi_qflags = qi->tqi_qflags;
	qinfo->tqi_ver = qi->tqi_ver;
	qinfo->tqi_subtype = qi->tqi_subtype;
	qinfo->tqi_qflags = qi->tqi_qflags;
	qinfo->tqi_priority = qi->tqi_priority;
	qinfo->tqi_aifs = qi->tqi_aifs;
	qinfo->tqi_cwmin = qi->tqi_cwmin;
	qinfo->tqi_cwmax = qi->tqi_cwmax;
	qinfo->tqi_shretry = qi->tqi_shretry;
	qinfo->tqi_lgretry = qi->tqi_lgretry;
	qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
	qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
	qinfo->tqi_burstTime = qi->tqi_burstTime;
	qinfo->tqi_readyTime = qi->tqi_readyTime;

	return true;
}

558
int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
S
Sujith 已提交
559 560 561
			  const struct ath9k_tx_queue_info *qinfo)
{
	struct ath9k_tx_queue_info *qi;
562
	struct ath9k_hw_capabilities *pCap = &ah->caps;
S
Sujith 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
	int q;

	switch (type) {
	case ATH9K_TX_QUEUE_BEACON:
		q = pCap->total_queues - 1;
		break;
	case ATH9K_TX_QUEUE_CAB:
		q = pCap->total_queues - 2;
		break;
	case ATH9K_TX_QUEUE_PSPOLL:
		q = 1;
		break;
	case ATH9K_TX_QUEUE_UAPSD:
		q = pCap->total_queues - 3;
		break;
	case ATH9K_TX_QUEUE_DATA:
		for (q = 0; q < pCap->total_queues; q++)
580
			if (ah->txq[q].tqi_type ==
S
Sujith 已提交
581 582 583
			    ATH9K_TX_QUEUE_INACTIVE)
				break;
		if (q == pCap->total_queues) {
S
Sujith 已提交
584 585
			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
				"No available TX queue\n");
S
Sujith 已提交
586 587 588 589
			return -1;
		}
		break;
	default:
S
Sujith 已提交
590 591
		DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Invalid TX queue type: %u\n",
			type);
S
Sujith 已提交
592 593 594
		return -1;
	}

S
Sujith 已提交
595
	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
S
Sujith 已提交
596

597
	qi = &ah->txq[q];
S
Sujith 已提交
598
	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
S
Sujith 已提交
599 600
		DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
			"TX queue: %u already active\n", q);
S
Sujith 已提交
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
		return -1;
	}
	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
	qi->tqi_type = type;
	if (qinfo == NULL) {
		qi->tqi_qflags =
			TXQ_FLAG_TXOKINT_ENABLE
			| TXQ_FLAG_TXERRINT_ENABLE
			| TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
		qi->tqi_aifs = INIT_AIFS;
		qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
		qi->tqi_cwmax = INIT_CWMAX;
		qi->tqi_shretry = INIT_SH_RETRY;
		qi->tqi_lgretry = INIT_LG_RETRY;
		qi->tqi_physCompBuf = 0;
	} else {
		qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
		(void) ath9k_hw_set_txq_props(ah, q, qinfo);
	}

	return q;
}

624
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
S
Sujith 已提交
625
{
626
	struct ath9k_hw_capabilities *pCap = &ah->caps;
S
Sujith 已提交
627 628 629
	struct ath9k_tx_queue_info *qi;

	if (q >= pCap->total_queues) {
S
Sujith 已提交
630 631
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
			"invalid queue: %u\n", q);
S
Sujith 已提交
632 633
		return false;
	}
634
	qi = &ah->txq[q];
S
Sujith 已提交
635
	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
S
Sujith 已提交
636 637
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TXQ, "
			"inactive queue: %u\n", q);
S
Sujith 已提交
638 639 640
		return false;
	}

S
Sujith 已提交
641
	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
S
Sujith 已提交
642 643

	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
644 645 646 647 648
	ah->txok_interrupt_mask &= ~(1 << q);
	ah->txerr_interrupt_mask &= ~(1 << q);
	ah->txdesc_interrupt_mask &= ~(1 << q);
	ah->txeol_interrupt_mask &= ~(1 << q);
	ah->txurn_interrupt_mask &= ~(1 << q);
S
Sujith 已提交
649 650 651 652 653
	ath9k_hw_set_txq_interrupts(ah, qi);

	return true;
}

654
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
S
Sujith 已提交
655
{
656 657
	struct ath9k_hw_capabilities *pCap = &ah->caps;
	struct ath9k_channel *chan = ah->curchan;
S
Sujith 已提交
658 659 660 661
	struct ath9k_tx_queue_info *qi;
	u32 cwMin, chanCwMin, value;

	if (q >= pCap->total_queues) {
S
Sujith 已提交
662 663
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
			"invalid queue: %u\n", q);
S
Sujith 已提交
664 665 666
		return false;
	}

667
	qi = &ah->txq[q];
S
Sujith 已提交
668
	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
S
Sujith 已提交
669 670
		DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TXQ, "
			"inactive queue: %u\n", q);
S
Sujith 已提交
671 672 673
		return true;
	}

S
Sujith 已提交
674
	DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
S
Sujith 已提交
675 676 677 678 679 680 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 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755

	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
		if (chan && IS_CHAN_B(chan))
			chanCwMin = INIT_CWMIN_11B;
		else
			chanCwMin = INIT_CWMIN;

		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
	} else
		cwMin = qi->tqi_cwmin;

	REG_WRITE(ah, AR_DLCL_IFS(q),
		  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
		  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
		  SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));

	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
		  SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
		  SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));

	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
	REG_WRITE(ah, AR_DMISC(q),
		  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);

	if (qi->tqi_cbrPeriod) {
		REG_WRITE(ah, AR_QCBRCFG(q),
			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
			  SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
		REG_WRITE(ah, AR_QMISC(q),
			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
			  (qi->tqi_cbrOverflowLimit ?
			   AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
	}
	if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
		REG_WRITE(ah, AR_QRDYTIMECFG(q),
			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
			  AR_Q_RDYTIMECFG_EN);
	}

	REG_WRITE(ah, AR_DCHNTIME(q),
		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));

	if (qi->tqi_burstTime
	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
		REG_WRITE(ah, AR_QMISC(q),
			  REG_READ(ah, AR_QMISC(q)) |
			  AR_Q_MISC_RDYTIME_EXP_POLICY);

	}

	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
		REG_WRITE(ah, AR_DMISC(q),
			  REG_READ(ah, AR_DMISC(q)) |
			  AR_D_MISC_POST_FR_BKOFF_DIS);
	}
	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
		REG_WRITE(ah, AR_DMISC(q),
			  REG_READ(ah, AR_DMISC(q)) |
			  AR_D_MISC_FRAG_BKOFF_EN);
	}
	switch (qi->tqi_type) {
	case ATH9K_TX_QUEUE_BEACON:
		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
			  | AR_Q_MISC_FSP_DBA_GATED
			  | AR_Q_MISC_BEACON_USE
			  | AR_Q_MISC_CBR_INCR_DIS1);

		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
			  | AR_D_MISC_BEACON_USE
			  | AR_D_MISC_POST_FR_BKOFF_DIS);
		break;
	case ATH9K_TX_QUEUE_CAB:
		REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
			  | AR_Q_MISC_FSP_DBA_GATED
			  | AR_Q_MISC_CBR_INCR_DIS1
			  | AR_Q_MISC_CBR_INCR_DIS0);
		value = (qi->tqi_readyTime -
756 757 758
			 (ah->config.sw_beacon_response_time -
			  ah->config.dma_beacon_response_time) -
			 ah->config.additional_swba_backoff) * 1024;
S
Sujith 已提交
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
		REG_WRITE(ah, AR_QRDYTIMECFG(q),
			  value | AR_Q_RDYTIMECFG_EN);
		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
			  | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
			     AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
		break;
	case ATH9K_TX_QUEUE_PSPOLL:
		REG_WRITE(ah, AR_QMISC(q),
			  REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
		break;
	case ATH9K_TX_QUEUE_UAPSD:
		REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
			  AR_D_MISC_POST_FR_BKOFF_DIS);
		break;
	default:
		break;
	}

	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
		REG_WRITE(ah, AR_DMISC(q),
			  REG_READ(ah, AR_DMISC(q)) |
			  SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
			     AR_D_MISC_ARB_LOCKOUT_CNTRL) |
			  AR_D_MISC_POST_FR_BKOFF_DIS);
	}

	if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
786
		ah->txok_interrupt_mask |= 1 << q;
S
Sujith 已提交
787
	else
788
		ah->txok_interrupt_mask &= ~(1 << q);
S
Sujith 已提交
789
	if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
790
		ah->txerr_interrupt_mask |= 1 << q;
S
Sujith 已提交
791
	else
792
		ah->txerr_interrupt_mask &= ~(1 << q);
S
Sujith 已提交
793
	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
794
		ah->txdesc_interrupt_mask |= 1 << q;
S
Sujith 已提交
795
	else
796
		ah->txdesc_interrupt_mask &= ~(1 << q);
S
Sujith 已提交
797
	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
798
		ah->txeol_interrupt_mask |= 1 << q;
S
Sujith 已提交
799
	else
800
		ah->txeol_interrupt_mask &= ~(1 << q);
S
Sujith 已提交
801
	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
802
		ah->txurn_interrupt_mask |= 1 << q;
S
Sujith 已提交
803
	else
804
		ah->txurn_interrupt_mask &= ~(1 << q);
S
Sujith 已提交
805 806 807 808 809
	ath9k_hw_set_txq_interrupts(ah, qi);

	return true;
}

810
int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
			u32 pa, struct ath_desc *nds, u64 tsf)
{
	struct ar5416_desc ads;
	struct ar5416_desc *adsp = AR5416DESC(ds);
	u32 phyerr;

	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
		return -EINPROGRESS;

	ads.u.rx = adsp->u.rx;

	ds->ds_rxstat.rs_status = 0;
	ds->ds_rxstat.rs_flags = 0;

	ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
	ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;

	ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
	ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
	ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
	ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
	ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
	ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
	ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
		ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
	else
		ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;

	ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
	ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;

	ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
	ds->ds_rxstat.rs_moreaggr =
		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
	ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
	ds->ds_rxstat.rs_flags =
		(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
	ds->ds_rxstat.rs_flags |=
		(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;

	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
		ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
		ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;

	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
		if (ads.ds_rxstatus8 & AR_CRCErr)
			ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
		else if (ads.ds_rxstatus8 & AR_PHYErr) {
			ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
			ds->ds_rxstat.rs_phyerr = phyerr;
		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
			ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
		else if (ads.ds_rxstatus8 & AR_MichaelErr)
			ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
	}

	return 0;
}

875
bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
S
Sujith 已提交
876 877 878
			  u32 size, u32 flags)
{
	struct ar5416_desc *ads = AR5416DESC(ds);
879
	struct ath9k_hw_capabilities *pCap = &ah->caps;
S
Sujith 已提交
880 881 882 883 884 885 886 887 888 889 890 891

	ads->ds_ctl1 = size & AR_BufLen;
	if (flags & ATH9K_RXDESC_INTREQ)
		ads->ds_ctl1 |= AR_RxIntrReq;

	ads->ds_rxstatus8 &= ~AR_RxDone;
	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
		memset(&(ads->u), 0, sizeof(ads->u));

	return true;
}

892
bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
S
Sujith 已提交
893 894 895 896 897 898 899
{
	u32 reg;

	if (set) {
		REG_SET_BIT(ah, AR_DIAG_SW,
			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));

S
Sujith 已提交
900 901
		if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
				   0, AH_WAIT_TIMEOUT)) {
S
Sujith 已提交
902 903 904 905 906 907
			REG_CLR_BIT(ah, AR_DIAG_SW,
				    (AR_DIAG_RX_DIS |
				     AR_DIAG_RX_ABORT));

			reg = REG_READ(ah, AR_OBS_BUS_1);
			DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
S
Sujith 已提交
908
				"RX failed to go idle in 10 ms RXSM=0x%x\n", reg);
S
Sujith 已提交
909 910 911 912 913 914 915 916 917 918 919

			return false;
		}
	} else {
		REG_CLR_BIT(ah, AR_DIAG_SW,
			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
	}

	return true;
}

920
void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
S
Sujith 已提交
921 922 923 924
{
	REG_WRITE(ah, AR_RXDP, rxdp);
}

925
void ath9k_hw_rxena(struct ath_hw *ah)
S
Sujith 已提交
926 927 928 929
{
	REG_WRITE(ah, AR_CR, AR_CR_RXE);
}

930
void ath9k_hw_startpcureceive(struct ath_hw *ah)
S
Sujith 已提交
931 932 933 934
{
	ath9k_enable_mib_counters(ah);

	ath9k_ani_reset(ah);
935

936
	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
S
Sujith 已提交
937 938
}

939
void ath9k_hw_stoppcurecv(struct ath_hw *ah)
S
Sujith 已提交
940 941 942 943 944 945
{
	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);

	ath9k_hw_disable_mib_counters(ah);
}

946
bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
S
Sujith 已提交
947
{
S
Sujith 已提交
948 949 950 951 952
#define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
#define AH_RX_TIME_QUANTUM     100     /* usec */

	int i;

S
Sujith 已提交
953 954
	REG_WRITE(ah, AR_CR, AR_CR_RXD);

S
Sujith 已提交
955 956 957 958 959 960 961 962
	/* Wait for rx enable bit to go low */
	for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
		if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
			break;
		udelay(AH_TIME_QUANTUM);
	}

	if (i == 0) {
S
Sujith 已提交
963 964
		DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
			"DMA failed to stop in %d ms "
S
Sujith 已提交
965 966 967 968
			"AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
			AH_RX_STOP_DMA_TIMEOUT / 1000,
			REG_READ(ah, AR_CR),
			REG_READ(ah, AR_DIAG_SW));
S
Sujith 已提交
969 970 971 972
		return false;
	} else {
		return true;
	}
S
Sujith 已提交
973 974 975

#undef AH_RX_TIME_QUANTUM
#undef AH_RX_STOP_DMA_TIMEOUT
S
Sujith 已提交
976
}