1185377Ssam/*
2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2006 Atheros Communications, Inc.
4185377Ssam *
5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any
6185377Ssam * purpose with or without fee is hereby granted, provided that the above
7185377Ssam * copyright notice and this permission notice appear in all copies.
8185377Ssam *
9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16185377Ssam *
17187831Ssam * $FreeBSD$
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam#include "ah_desc.h"
24185377Ssam
25185377Ssam#include "ar5211/ar5211.h"
26185377Ssam#include "ar5211/ar5211reg.h"
27185377Ssam#include "ar5211/ar5211desc.h"
28185377Ssam
29185377Ssam/*
30185377Ssam * Update Tx FIFO trigger level.
31185377Ssam *
32185377Ssam * Set bIncTrigLevel to TRUE to increase the trigger level.
33185377Ssam * Set bIncTrigLevel to FALSE to decrease the trigger level.
34185377Ssam *
35185377Ssam * Returns TRUE if the trigger level was updated
36185377Ssam */
37185377SsamHAL_BOOL
38185377Ssamar5211UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
39185377Ssam{
40185377Ssam	uint32_t curTrigLevel, txcfg;
41185377Ssam	HAL_INT ints = ar5211GetInterrupts(ah);
42185377Ssam
43185377Ssam	/*
44185377Ssam	 * Disable chip interrupts. This is because halUpdateTxTrigLevel
45185377Ssam	 * is called from both ISR and non-ISR contexts.
46185377Ssam	 */
47185377Ssam	ar5211SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
48185377Ssam	txcfg = OS_REG_READ(ah, AR_TXCFG);
49185377Ssam	curTrigLevel = (txcfg & AR_TXCFG_FTRIG_M) >> AR_TXCFG_FTRIG_S;
50185377Ssam	if (bIncTrigLevel){
51185377Ssam		/* increase the trigger level */
52185377Ssam		curTrigLevel = curTrigLevel +
53185377Ssam			((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
54185377Ssam	} else {
55185377Ssam		/* decrease the trigger level if not already at the minimum */
56185377Ssam		if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
57185377Ssam			/* decrease the trigger level */
58185377Ssam			curTrigLevel--;
59185377Ssam		} else {
60185377Ssam			/* no update to the trigger level */
61185377Ssam			/* re-enable chip interrupts */
62185377Ssam			ar5211SetInterrupts(ah, ints);
63185377Ssam			return AH_FALSE;
64185377Ssam		}
65185377Ssam	}
66185377Ssam	/* Update the trigger level */
67185377Ssam	OS_REG_WRITE(ah, AR_TXCFG, (txcfg &~ AR_TXCFG_FTRIG_M) |
68185377Ssam		((curTrigLevel << AR_TXCFG_FTRIG_S) & AR_TXCFG_FTRIG_M));
69185377Ssam	/* re-enable chip interrupts */
70185377Ssam	ar5211SetInterrupts(ah, ints);
71185377Ssam	return AH_TRUE;
72185377Ssam}
73185377Ssam
74185377Ssam/*
75185377Ssam * Set the properties of the tx queue with the parameters
76185377Ssam * from qInfo.  The queue must previously have been setup
77185377Ssam * with a call to ar5211SetupTxQueue.
78185377Ssam */
79185377SsamHAL_BOOL
80185377Ssamar5211SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
81185377Ssam{
82185377Ssam	struct ath_hal_5211 *ahp = AH5211(ah);
83185377Ssam
84185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
85185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
86185377Ssam		    __func__, q);
87185377Ssam		return AH_FALSE;
88185377Ssam	}
89185377Ssam	return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
90185377Ssam}
91185377Ssam
92185377Ssam/*
93185377Ssam * Return the properties for the specified tx queue.
94185377Ssam */
95185377SsamHAL_BOOL
96185377Ssamar5211GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
97185377Ssam{
98185377Ssam	struct ath_hal_5211 *ahp = AH5211(ah);
99185377Ssam
100185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
101185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
102185377Ssam		    __func__, q);
103185377Ssam		return AH_FALSE;
104185377Ssam	}
105185377Ssam	return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
106185377Ssam}
107185377Ssam
108185377Ssam/*
109185377Ssam * Allocate and initialize a tx DCU/QCU combination.
110185377Ssam */
111185377Ssamint
112185377Ssamar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
113185377Ssam	const HAL_TXQ_INFO *qInfo)
114185377Ssam{
115185377Ssam	struct ath_hal_5211 *ahp = AH5211(ah);
116185377Ssam	HAL_TX_QUEUE_INFO *qi;
117185377Ssam	int q;
118185377Ssam
119185377Ssam	switch (type) {
120185377Ssam	case HAL_TX_QUEUE_BEACON:
121185377Ssam		q = 9;
122185377Ssam		break;
123185377Ssam	case HAL_TX_QUEUE_CAB:
124185377Ssam		q = 8;
125185377Ssam		break;
126185377Ssam	case HAL_TX_QUEUE_DATA:
127185377Ssam		q = 0;
128185377Ssam		if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE)
129185377Ssam			return q;
130185377Ssam		break;
131185377Ssam	default:
132185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
133185377Ssam		    __func__, type);
134185377Ssam		return -1;
135185377Ssam	}
136185377Ssam
137185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
138185377Ssam
139185377Ssam	qi = &ahp->ah_txq[q];
140185377Ssam	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
141185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
142185377Ssam		    __func__, q);
143185377Ssam		return -1;
144185377Ssam	}
145185377Ssam	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
146185377Ssam	qi->tqi_type = type;
147185377Ssam	if (qInfo == AH_NULL) {
148185377Ssam		/* by default enable OK+ERR+DESC+URN interrupts */
149185377Ssam		qi->tqi_qflags =
150185377Ssam			  HAL_TXQ_TXOKINT_ENABLE
151185377Ssam			| HAL_TXQ_TXERRINT_ENABLE
152185377Ssam			| HAL_TXQ_TXDESCINT_ENABLE
153185377Ssam			| HAL_TXQ_TXURNINT_ENABLE
154185377Ssam			;
155185377Ssam		qi->tqi_aifs = INIT_AIFS;
156185377Ssam		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
157185377Ssam		qi->tqi_cwmax = INIT_CWMAX;
158185377Ssam		qi->tqi_shretry = INIT_SH_RETRY;
159185377Ssam		qi->tqi_lgretry = INIT_LG_RETRY;
160185377Ssam	} else
161185377Ssam		(void) ar5211SetTxQueueProps(ah, q, qInfo);
162185377Ssam	return q;
163185377Ssam}
164185377Ssam
165185377Ssam/*
166185377Ssam * Update the h/w interrupt registers to reflect a tx q's configuration.
167185377Ssam */
168185377Ssamstatic void
169185377SsamsetTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)
170185377Ssam{
171185377Ssam	struct ath_hal_5211 *ahp = AH5211(ah);
172185377Ssam
173185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
174185377Ssam	    "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__
175185377Ssam		, ahp->ah_txOkInterruptMask
176185377Ssam		, ahp->ah_txErrInterruptMask
177185377Ssam		, ahp->ah_txDescInterruptMask
178185377Ssam		, ahp->ah_txEolInterruptMask
179185377Ssam		, ahp->ah_txUrnInterruptMask
180185377Ssam	);
181185377Ssam
182185377Ssam	OS_REG_WRITE(ah, AR_IMR_S0,
183185377Ssam		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
184185377Ssam		| SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)
185185377Ssam	);
186185377Ssam	OS_REG_WRITE(ah, AR_IMR_S1,
187185377Ssam		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
188185377Ssam		| SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)
189185377Ssam	);
190185377Ssam	OS_REG_RMW_FIELD(ah, AR_IMR_S2,
191185377Ssam		AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
192185377Ssam}
193185377Ssam
194185377Ssam
195185377Ssam/*
196185377Ssam * Free a tx DCU/QCU combination.
197185377Ssam */
198185377SsamHAL_BOOL
199185377Ssamar5211ReleaseTxQueue(struct ath_hal *ah, u_int q)
200185377Ssam{
201185377Ssam	struct ath_hal_5211 *ahp = AH5211(ah);
202185377Ssam	HAL_TX_QUEUE_INFO *qi;
203185377Ssam
204185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
205185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
206185377Ssam		    __func__, q);
207185377Ssam		return AH_FALSE;
208185377Ssam	}
209185377Ssam	qi = &ahp->ah_txq[q];
210185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
211185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
212185377Ssam		    __func__, q);
213185377Ssam		return AH_FALSE;
214185377Ssam	}
215185377Ssam
216185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
217185377Ssam
218185377Ssam	qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
219185377Ssam	ahp->ah_txOkInterruptMask &= ~(1 << q);
220185377Ssam	ahp->ah_txErrInterruptMask &= ~(1 << q);
221185377Ssam	ahp->ah_txDescInterruptMask &= ~(1 << q);
222185377Ssam	ahp->ah_txEolInterruptMask &= ~(1 << q);
223185377Ssam	ahp->ah_txUrnInterruptMask &= ~(1 << q);
224185377Ssam	setTxQInterrupts(ah, qi);
225185377Ssam
226185377Ssam	return AH_TRUE;
227185377Ssam}
228185377Ssam
229185377Ssam/*
230185377Ssam * Set the retry, aifs, cwmin/max, readyTime regs for specified queue
231185377Ssam */
232185377SsamHAL_BOOL
233185377Ssamar5211ResetTxQueue(struct ath_hal *ah, u_int q)
234185377Ssam{
235185377Ssam	struct ath_hal_5211 *ahp = AH5211(ah);
236187831Ssam	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
237185377Ssam	HAL_TX_QUEUE_INFO *qi;
238185377Ssam	uint32_t cwMin, chanCwMin, value;
239185377Ssam
240185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
241185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
242185377Ssam		    __func__, q);
243185377Ssam		return AH_FALSE;
244185377Ssam	}
245185377Ssam	qi = &ahp->ah_txq[q];
246185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
247185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
248185377Ssam		    __func__, q);
249185377Ssam		return AH_TRUE;		/* XXX??? */
250185377Ssam	}
251185377Ssam
252185377Ssam	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) {
253185377Ssam		/*
254185377Ssam		 * Select cwmin according to channel type.
255185377Ssam		 * NB: chan can be NULL during attach
256185377Ssam		 */
257187831Ssam		if (chan && IEEE80211_IS_CHAN_B(chan))
258185377Ssam			chanCwMin = INIT_CWMIN_11B;
259185377Ssam		else
260185377Ssam			chanCwMin = INIT_CWMIN;
261185377Ssam		/* make sure that the CWmin is of the form (2^n - 1) */
262185377Ssam		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1)
263185377Ssam			;
264185377Ssam	} else
265185377Ssam		cwMin = qi->tqi_cwmin;
266185377Ssam
267185377Ssam	/* set cwMin/Max and AIFS values */
268185377Ssam	OS_REG_WRITE(ah, AR_DLCL_IFS(q),
269185377Ssam		  SM(cwMin, AR_D_LCL_IFS_CWMIN)
270185377Ssam		| SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
271185377Ssam		| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
272185377Ssam
273185377Ssam	/* Set retry limit values */
274185377Ssam	OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q),
275185377Ssam		   SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
276185377Ssam		 | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
277185377Ssam		 | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG)
278185377Ssam		 | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
279185377Ssam	);
280185377Ssam
281185377Ssam	/* enable early termination on the QCU */
282185377Ssam	OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
283185377Ssam
284185377Ssam	if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {
285185377Ssam		/* Configure DCU to use the global sequence count */
286185377Ssam		OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL);
287185377Ssam	}
288185377Ssam	/* multiqueue support */
289185377Ssam	if (qi->tqi_cbrPeriod) {
290185377Ssam		OS_REG_WRITE(ah, AR_QCBRCFG(q),
291185377Ssam			  SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL)
292185377Ssam			| SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH));
293185377Ssam		OS_REG_WRITE(ah, AR_QMISC(q),
294185377Ssam			OS_REG_READ(ah, AR_QMISC(q)) |
295185377Ssam			AR_Q_MISC_FSP_CBR |
296185377Ssam			(qi->tqi_cbrOverflowLimit ?
297185377Ssam				AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0));
298185377Ssam	}
299185377Ssam	if (qi->tqi_readyTime) {
300185377Ssam		OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
301185377Ssam			SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) |
302185377Ssam			AR_Q_RDYTIMECFG_EN);
303185377Ssam	}
304185377Ssam	if (qi->tqi_burstTime) {
305185377Ssam		OS_REG_WRITE(ah, AR_DCHNTIME(q),
306185377Ssam			SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
307185377Ssam			AR_D_CHNTIME_EN);
308185377Ssam		if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) {
309185377Ssam			OS_REG_WRITE(ah, AR_QMISC(q),
310185377Ssam			     OS_REG_READ(ah, AR_QMISC(q)) |
311185377Ssam			     AR_Q_MISC_RDYTIME_EXP_POLICY);
312185377Ssam		}
313185377Ssam	}
314185377Ssam
315185377Ssam	if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) {
316185377Ssam		OS_REG_WRITE(ah, AR_DMISC(q),
317185377Ssam			OS_REG_READ(ah, AR_DMISC(q)) |
318185377Ssam			AR_D_MISC_POST_FR_BKOFF_DIS);
319185377Ssam	}
320185377Ssam	if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) {
321185377Ssam		OS_REG_WRITE(ah, AR_DMISC(q),
322185377Ssam			OS_REG_READ(ah, AR_DMISC(q)) |
323185377Ssam			AR_D_MISC_FRAG_BKOFF_EN);
324185377Ssam	}
325185377Ssam	switch (qi->tqi_type) {
326185377Ssam	case HAL_TX_QUEUE_BEACON:
327185377Ssam		/* Configure QCU for beacons */
328185377Ssam		OS_REG_WRITE(ah, AR_QMISC(q),
329185377Ssam			OS_REG_READ(ah, AR_QMISC(q))
330185377Ssam			| AR_Q_MISC_FSP_DBA_GATED
331185377Ssam			| AR_Q_MISC_BEACON_USE
332185377Ssam			| AR_Q_MISC_CBR_INCR_DIS1);
333185377Ssam		/* Configure DCU for beacons */
334185377Ssam		value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
335185377Ssam			| AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS;
336185377Ssam		if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU)
337185377Ssam			value |= AR5311_D_MISC_SEQ_NUM_CONTROL;
338185377Ssam		OS_REG_WRITE(ah, AR_DMISC(q), value);
339185377Ssam		break;
340185377Ssam	case HAL_TX_QUEUE_CAB:
341185377Ssam		/* Configure QCU for CAB (Crap After Beacon) frames */
342185377Ssam		OS_REG_WRITE(ah, AR_QMISC(q),
343185377Ssam			OS_REG_READ(ah, AR_QMISC(q))
344185377Ssam			| AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1
345185377Ssam			| AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY);
346185377Ssam
347185377Ssam		value = (ahp->ah_beaconInterval
348223459Sadrian			- (ah->ah_config.ah_sw_beacon_response_time
349223459Sadrian			        - ah->ah_config.ah_dma_beacon_response_time)
350223459Sadrian			- ah->ah_config.ah_additional_swba_backoff) * 1024;
351185377Ssam		OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN);
352185377Ssam
353185377Ssam		/* Configure DCU for CAB */
354185377Ssam		value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S);
355185377Ssam		if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU)
356185377Ssam			value |= AR5311_D_MISC_SEQ_NUM_CONTROL;
357185377Ssam		OS_REG_WRITE(ah, AR_QMISC(q), value);
358185377Ssam		break;
359185377Ssam	default:
360185377Ssam		/* NB: silence compiler */
361185377Ssam		break;
362185377Ssam	}
363185377Ssam
364185377Ssam	/*
365185377Ssam	 * Always update the secondary interrupt mask registers - this
366185377Ssam	 * could be a new queue getting enabled in a running system or
367185377Ssam	 * hw getting re-initialized during a reset!
368185377Ssam	 *
369185377Ssam	 * Since we don't differentiate between tx interrupts corresponding
370185377Ssam	 * to individual queues - secondary tx mask regs are always unmasked;
371185377Ssam	 * tx interrupts are enabled/disabled for all queues collectively
372185377Ssam	 * using the primary mask reg
373185377Ssam	 */
374185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
375185377Ssam		ahp->ah_txOkInterruptMask |= 1 << q;
376185377Ssam	else
377185377Ssam		ahp->ah_txOkInterruptMask &= ~(1 << q);
378185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
379185377Ssam		ahp->ah_txErrInterruptMask |= 1 << q;
380185377Ssam	else
381185377Ssam		ahp->ah_txErrInterruptMask &= ~(1 << q);
382185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
383185377Ssam		ahp->ah_txDescInterruptMask |= 1 << q;
384185377Ssam	else
385185377Ssam		ahp->ah_txDescInterruptMask &= ~(1 << q);
386185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
387185377Ssam		ahp->ah_txEolInterruptMask |= 1 << q;
388185377Ssam	else
389185377Ssam		ahp->ah_txEolInterruptMask &= ~(1 << q);
390185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
391185377Ssam		ahp->ah_txUrnInterruptMask |= 1 << q;
392185377Ssam	else
393185377Ssam		ahp->ah_txUrnInterruptMask &= ~(1 << q);
394185377Ssam	setTxQInterrupts(ah, qi);
395185377Ssam
396185377Ssam	return AH_TRUE;
397185377Ssam}
398185377Ssam
399185377Ssam/*
400185377Ssam * Get the TXDP for the specified data queue.
401185377Ssam */
402185377Ssamuint32_t
403185377Ssamar5211GetTxDP(struct ath_hal *ah, u_int q)
404185377Ssam{
405185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
406185377Ssam	return OS_REG_READ(ah, AR_QTXDP(q));
407185377Ssam}
408185377Ssam
409185377Ssam/*
410185377Ssam * Set the TxDP for the specified tx queue.
411185377Ssam */
412185377SsamHAL_BOOL
413185377Ssamar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
414185377Ssam{
415185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
416185377Ssam	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
417185377Ssam
418185377Ssam	/*
419185377Ssam	 * Make sure that TXE is deasserted before setting the TXDP.  If TXE
420185377Ssam	 * is still asserted, setting TXDP will have no effect.
421185377Ssam	 */
422185377Ssam	HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0);
423185377Ssam
424185377Ssam	OS_REG_WRITE(ah, AR_QTXDP(q), txdp);
425185377Ssam
426185377Ssam	return AH_TRUE;
427185377Ssam}
428185377Ssam
429185377Ssam/*
430185377Ssam * Set Transmit Enable bits for the specified queues.
431185377Ssam */
432185377SsamHAL_BOOL
433185377Ssamar5211StartTxDma(struct ath_hal *ah, u_int q)
434185377Ssam{
435185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
436185377Ssam	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
437185377Ssam
438185377Ssam	/* Check that queue is not already active */
439185377Ssam	HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<<q)) == 0);
440185377Ssam
441185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
442185377Ssam
443185377Ssam	/* Check to be sure we're not enabling a q that has its TXD bit set. */
444185377Ssam	HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0);
445185377Ssam
446185377Ssam	OS_REG_WRITE(ah, AR_Q_TXE, 1 << q);
447185377Ssam	return AH_TRUE;
448185377Ssam}
449185377Ssam
450185377Ssam/*
451185377Ssam * Return the number of frames pending on the specified queue.
452185377Ssam */
453185377Ssamuint32_t
454185377Ssamar5211NumTxPending(struct ath_hal *ah, u_int q)
455185377Ssam{
456185377Ssam	uint32_t n;
457185377Ssam
458185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
459185377Ssam	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
460185377Ssam
461185377Ssam	n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M;
462185377Ssam	/*
463185377Ssam	 * Pending frame count (PFC) can momentarily go to zero
464185377Ssam	 * while TXE remains asserted.  In other words a PFC of
465185377Ssam	 * zero is not sufficient to say that the queue has stopped.
466185377Ssam	 */
467185377Ssam	if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<<q)))
468185377Ssam		n = 1;			/* arbitrarily pick 1 */
469185377Ssam	return n;
470185377Ssam}
471185377Ssam
472185377Ssam/*
473185377Ssam * Stop transmit on the specified queue
474185377Ssam */
475185377SsamHAL_BOOL
476185377Ssamar5211StopTxDma(struct ath_hal *ah, u_int q)
477185377Ssam{
478185377Ssam	int i;
479185377Ssam
480185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
481185377Ssam	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
482185377Ssam
483185377Ssam	OS_REG_WRITE(ah, AR_Q_TXD, 1<<q);
484185377Ssam	for (i = 0; i < 10000; i++) {
485185377Ssam		if (ar5211NumTxPending(ah, q) == 0)
486185377Ssam			break;
487185377Ssam		OS_DELAY(10);
488185377Ssam	}
489185377Ssam	OS_REG_WRITE(ah, AR_Q_TXD, 0);
490185377Ssam
491185377Ssam	return (i < 10000);
492185377Ssam}
493185377Ssam
494185377Ssam/*
495185377Ssam * Descriptor Access Functions
496185377Ssam */
497185377Ssam
498185377Ssam#define	VALID_PKT_TYPES \
499185377Ssam	((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
500185377Ssam	 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
501185377Ssam	 (1<<HAL_PKT_TYPE_BEACON))
502185377Ssam#define	isValidPktType(_t)	((1<<(_t)) & VALID_PKT_TYPES)
503185377Ssam#define	VALID_TX_RATES \
504185377Ssam	((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
505185377Ssam	 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
506185377Ssam	 (1<<0x1d)|(1<<0x18)|(1<<0x1c))
507185377Ssam#define	isValidTxRate(_r)	((1<<(_r)) & VALID_TX_RATES)
508185377Ssam
509185377SsamHAL_BOOL
510185377Ssamar5211SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
511185377Ssam	u_int pktLen,
512185377Ssam	u_int hdrLen,
513185377Ssam	HAL_PKT_TYPE type,
514185377Ssam	u_int txPower,
515185377Ssam	u_int txRate0, u_int txTries0,
516185377Ssam	u_int keyIx,
517185377Ssam	u_int antMode,
518185377Ssam	u_int flags,
519185377Ssam	u_int rtsctsRate,
520185377Ssam	u_int rtsctsDuration,
521185377Ssam	u_int compicvLen,
522185377Ssam	u_int compivLen,
523185377Ssam	u_int comp)
524185377Ssam{
525185377Ssam	struct ar5211_desc *ads = AR5211DESC(ds);
526185377Ssam
527185377Ssam	(void) hdrLen;
528185377Ssam	(void) txPower;
529185377Ssam	(void) rtsctsRate; (void) rtsctsDuration;
530185377Ssam
531185377Ssam	HALASSERT(txTries0 != 0);
532185377Ssam	HALASSERT(isValidPktType(type));
533185377Ssam	HALASSERT(isValidTxRate(txRate0));
534185377Ssam	/* XXX validate antMode */
535185377Ssam
536185377Ssam	ads->ds_ctl0 = (pktLen & AR_FrameLen)
537185377Ssam		     | (txRate0 << AR_XmitRate_S)
538185377Ssam		     | (antMode << AR_AntModeXmit_S)
539185377Ssam		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
540185377Ssam		     | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
541185377Ssam		     | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0)
542185377Ssam		     | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
543185377Ssam		     ;
544185377Ssam	ads->ds_ctl1 = (type << 26)
545185377Ssam		     | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0)
546185377Ssam		     ;
547185377Ssam
548185377Ssam	if (keyIx != HAL_TXKEYIX_INVALID) {
549185377Ssam		ads->ds_ctl1 |=
550185377Ssam			(keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
551185377Ssam		ads->ds_ctl0 |= AR_EncryptKeyValid;
552185377Ssam	}
553185377Ssam	return AH_TRUE;
554185377Ssam#undef RATE
555185377Ssam}
556185377Ssam
557185377SsamHAL_BOOL
558185377Ssamar5211SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
559185377Ssam	u_int txRate1, u_int txTries1,
560185377Ssam	u_int txRate2, u_int txTries2,
561185377Ssam	u_int txRate3, u_int txTries3)
562185377Ssam{
563185377Ssam	(void) ah; (void) ds;
564185377Ssam	(void) txRate1; (void) txTries1;
565185377Ssam	(void) txRate2; (void) txTries2;
566185377Ssam	(void) txRate3; (void) txTries3;
567185377Ssam	return AH_FALSE;
568185377Ssam}
569185377Ssam
570185377Ssamvoid
571185377Ssamar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
572185377Ssam{
573185377Ssam	struct ar5211_desc *ads = AR5211DESC(ds);
574185377Ssam
575185377Ssam	ads->ds_ctl0 |= AR_TxInterReq;
576185377Ssam}
577185377Ssam
578185377SsamHAL_BOOL
579185377Ssamar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
580239051Sadrian	HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
581239051Sadrian	u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
582185377Ssam	const struct ath_desc *ds0)
583185377Ssam{
584185377Ssam	struct ar5211_desc *ads = AR5211DESC(ds);
585239051Sadrian	uint32_t segLen = segLenList[0];
586185377Ssam
587239051Sadrian	ds->ds_data = bufAddrList[0];
588239051Sadrian
589185377Ssam	HALASSERT((segLen &~ AR_BufLen) == 0);
590185377Ssam
591185377Ssam	if (firstSeg) {
592185377Ssam		/*
593185377Ssam		 * First descriptor, don't clobber xmit control data
594185377Ssam		 * setup by ar5211SetupTxDesc.
595185377Ssam		 */
596185377Ssam		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
597185377Ssam	} else if (lastSeg) {		/* !firstSeg && lastSeg */
598185377Ssam		/*
599185377Ssam		 * Last descriptor in a multi-descriptor frame,
600185377Ssam		 * copy the transmit parameters from the first
601185377Ssam		 * frame for processing on completion.
602185377Ssam		 */
603185377Ssam		ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0;
604185377Ssam		ads->ds_ctl1 = segLen;
605185377Ssam	} else {			/* !firstSeg && !lastSeg */
606185377Ssam		/*
607185377Ssam		 * Intermediate descriptor in a multi-descriptor frame.
608185377Ssam		 */
609185377Ssam		ads->ds_ctl0 = 0;
610185377Ssam		ads->ds_ctl1 = segLen | AR_More;
611185377Ssam	}
612185377Ssam	ads->ds_status0 = ads->ds_status1 = 0;
613185377Ssam	return AH_TRUE;
614185377Ssam}
615185377Ssam
616185377Ssam/*
617185377Ssam * Processing of HW TX descriptor.
618185377Ssam */
619185377SsamHAL_STATUS
620185377Ssamar5211ProcTxDesc(struct ath_hal *ah,
621185377Ssam	struct ath_desc *ds, struct ath_tx_status *ts)
622185377Ssam{
623185377Ssam	struct ar5211_desc *ads = AR5211DESC(ds);
624185377Ssam
625185377Ssam	if ((ads->ds_status1 & AR_Done) == 0)
626185377Ssam		return HAL_EINPROGRESS;
627185377Ssam
628185377Ssam	/* Update software copies of the HW status */
629185377Ssam	ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum);
630185377Ssam	ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
631185377Ssam	ts->ts_status = 0;
632185377Ssam	if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
633185377Ssam		if (ads->ds_status0 & AR_ExcessiveRetries)
634185377Ssam			ts->ts_status |= HAL_TXERR_XRETRY;
635185377Ssam		if (ads->ds_status0 & AR_Filtered)
636185377Ssam			ts->ts_status |= HAL_TXERR_FILT;
637185377Ssam		if (ads->ds_status0 & AR_FIFOUnderrun)
638185377Ssam			ts->ts_status |= HAL_TXERR_FIFO;
639185377Ssam	}
640185377Ssam	ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
641185377Ssam	ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
642185377Ssam	ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
643185377Ssam	ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
644185377Ssam	ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt);
645185377Ssam	ts->ts_antenna = 0;		/* NB: don't know */
646185377Ssam	ts->ts_finaltsi = 0;
647185377Ssam	/*
648185377Ssam	 * NB: the number of retries is one less than it should be.
649185377Ssam	 * Also, 0 retries and 1 retry are both reported as 0 retries.
650185377Ssam	 */
651185377Ssam	if (ts->ts_shortretry > 0)
652185377Ssam		ts->ts_shortretry++;
653185377Ssam	if (ts->ts_longretry > 0)
654185377Ssam		ts->ts_longretry++;
655185377Ssam
656185377Ssam	return HAL_OK;
657185377Ssam}
658185377Ssam
659185377Ssam/*
660185377Ssam * Determine which tx queues need interrupt servicing.
661185377Ssam * STUB.
662185377Ssam */
663185377Ssamvoid
664185377Ssamar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
665185377Ssam{
666185377Ssam	return;
667185377Ssam}
668217621Sadrian
669217621Sadrian/*
670217621Sadrian * Retrieve the rate table from the given TX completion descriptor
671217621Sadrian */
672217621SadrianHAL_BOOL
673217621Sadrianar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
674217621Sadrian{
675217621Sadrian	return AH_FALSE;
676217621Sadrian}
677217621Sadrian
678238607Sadrian
679238607Sadrianvoid
680238607Sadrianar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
681238607Sadrian{
682238607Sadrian	struct ar5211_desc *ads = AR5211DESC(ds);
683238607Sadrian
684238607Sadrian	ads->ds_link = link;
685238607Sadrian}
686238607Sadrian
687238607Sadrianvoid
688238607Sadrianar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
689238607Sadrian{
690238607Sadrian	struct ar5211_desc *ads = AR5211DESC(ds);
691238607Sadrian
692238607Sadrian	*link = ads->ds_link;
693238607Sadrian}
694238607Sadrian
695238607Sadrianvoid
696238607Sadrianar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
697238607Sadrian{
698238607Sadrian	struct ar5211_desc *ads = AR5211DESC(ds);
699238607Sadrian
700238607Sadrian	*linkptr = &ads->ds_link;
701238607Sadrian}
702