1185377Ssam/*
2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2004 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 "ar5210/ar5210.h"
26185377Ssam#include "ar5210/ar5210reg.h"
27185377Ssam#include "ar5210/ar5210phy.h"
28185377Ssam#include "ar5210/ar5210desc.h"
29185377Ssam
30185377Ssam/*
31185377Ssam * Set the properties of the tx queue with the parameters
32185377Ssam * from qInfo.  The queue must previously have been setup
33185377Ssam * with a call to ar5210SetupTxQueue.
34185377Ssam */
35185377SsamHAL_BOOL
36185377Ssamar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
37185377Ssam{
38185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
39185377Ssam
40185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
41185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
42185377Ssam		    __func__, q);
43185377Ssam		return AH_FALSE;
44185377Ssam	}
45185377Ssam	return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
46185377Ssam}
47185377Ssam
48185377Ssam/*
49185377Ssam * Return the properties for the specified tx queue.
50185377Ssam */
51185377SsamHAL_BOOL
52185377Ssamar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
53185377Ssam{
54185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
55185377Ssam
56185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
57185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
58185377Ssam		    __func__, q);
59185377Ssam		return AH_FALSE;
60185377Ssam	}
61185377Ssam	return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
62185377Ssam}
63185377Ssam
64185377Ssam/*
65185377Ssam * Allocate and initialize a tx DCU/QCU combination.
66185377Ssam */
67185377Ssamint
68185377Ssamar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
69185377Ssam	const HAL_TXQ_INFO *qInfo)
70185377Ssam{
71185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
72185377Ssam	HAL_TX_QUEUE_INFO *qi;
73185377Ssam	int q;
74185377Ssam
75185377Ssam	switch (type) {
76185377Ssam	case HAL_TX_QUEUE_BEACON:
77185377Ssam		q = 2;
78185377Ssam		break;
79185377Ssam	case HAL_TX_QUEUE_CAB:
80185377Ssam		q = 1;
81185377Ssam		break;
82185377Ssam	case HAL_TX_QUEUE_DATA:
83185377Ssam		q = 0;
84185377Ssam		break;
85185377Ssam	default:
86185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
87185377Ssam		    __func__, type);
88185377Ssam		return -1;
89185377Ssam	}
90185377Ssam
91185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
92185377Ssam
93185377Ssam	qi = &ahp->ah_txq[q];
94185377Ssam	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
95185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
96185377Ssam		    __func__, q);
97185377Ssam		return -1;
98185377Ssam	}
99185377Ssam	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
100185377Ssam	qi->tqi_type = type;
101185377Ssam	if (qInfo == AH_NULL) {
102185377Ssam		/* by default enable OK+ERR+DESC+URN interrupts */
103185377Ssam		qi->tqi_qflags =
104185377Ssam			  HAL_TXQ_TXOKINT_ENABLE
105185377Ssam			| HAL_TXQ_TXERRINT_ENABLE
106185377Ssam			| HAL_TXQ_TXDESCINT_ENABLE
107185377Ssam			| HAL_TXQ_TXURNINT_ENABLE
108185377Ssam			;
109185377Ssam		qi->tqi_aifs = INIT_AIFS;
110185377Ssam		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
111185377Ssam		qi->tqi_shretry = INIT_SH_RETRY;
112185377Ssam		qi->tqi_lgretry = INIT_LG_RETRY;
113185377Ssam	} else
114185377Ssam		(void) ar5210SetTxQueueProps(ah, q, qInfo);
115185377Ssam	/* NB: must be followed by ar5210ResetTxQueue */
116185377Ssam	return q;
117185377Ssam}
118185377Ssam
119185377Ssam/*
120185377Ssam * Free a tx DCU/QCU combination.
121185377Ssam */
122185377SsamHAL_BOOL
123185377Ssamar5210ReleaseTxQueue(struct ath_hal *ah, u_int q)
124185377Ssam{
125185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
126185377Ssam	HAL_TX_QUEUE_INFO *qi;
127185377Ssam
128185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
129185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
130185377Ssam		    __func__, q);
131185377Ssam		return AH_FALSE;
132185377Ssam	}
133185377Ssam	qi = &ahp->ah_txq[q];
134185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
135185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
136185377Ssam		    __func__, q);
137185377Ssam		return AH_FALSE;
138185377Ssam	}
139185377Ssam
140185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
141185377Ssam
142185377Ssam	qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
143185377Ssam	ahp->ah_txOkInterruptMask &= ~(1 << q);
144185377Ssam	ahp->ah_txErrInterruptMask &= ~(1 << q);
145185377Ssam	ahp->ah_txDescInterruptMask &= ~(1 << q);
146185377Ssam	ahp->ah_txEolInterruptMask &= ~(1 << q);
147185377Ssam	ahp->ah_txUrnInterruptMask &= ~(1 << q);
148185377Ssam
149185377Ssam	return AH_TRUE;
150185377Ssam#undef N
151185377Ssam}
152185377Ssam
153185377SsamHAL_BOOL
154185377Ssamar5210ResetTxQueue(struct ath_hal *ah, u_int q)
155185377Ssam{
156185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
157187831Ssam	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
158185377Ssam	HAL_TX_QUEUE_INFO *qi;
159185377Ssam	uint32_t cwMin;
160185377Ssam
161185377Ssam	if (q >= HAL_NUM_TX_QUEUES) {
162185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
163185377Ssam		    __func__, q);
164185377Ssam		return AH_FALSE;
165185377Ssam	}
166185377Ssam	qi = &ahp->ah_txq[q];
167185377Ssam	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
168185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
169185377Ssam		    __func__, q);
170185377Ssam		return AH_FALSE;
171185377Ssam	}
172185377Ssam
173185377Ssam	/*
174185377Ssam	 * Ignore any non-data queue(s).
175185377Ssam	 */
176185377Ssam	if (qi->tqi_type != HAL_TX_QUEUE_DATA)
177185377Ssam		return AH_TRUE;
178185377Ssam
179185377Ssam	/* Set turbo mode / base mode parameters on or off */
180187831Ssam	if (IEEE80211_IS_CHAN_TURBO(chan)) {
181185377Ssam		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);
182185377Ssam		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);
183185377Ssam		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);
184185377Ssam		OS_REG_WRITE(ah, AR_IFS0,
185185377Ssam			((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)
186185377Ssam				<< AR_IFS0_DIFS_S)
187185377Ssam			| INIT_SIFS_TURBO);
188185377Ssam		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);
189185377Ssam		OS_REG_WRITE(ah, AR_PHY(17),
190185377Ssam			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);
191185377Ssam		OS_REG_WRITE(ah, AR_PHY_FRCTL,
192185377Ssam			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
193185377Ssam			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
194185377Ssam			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |
195185377Ssam			0x2020 |
196185377Ssam			AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);
197185377Ssam	} else {
198185377Ssam		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);
199185377Ssam		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);
200185377Ssam		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);
201185377Ssam		OS_REG_WRITE(ah, AR_IFS0,
202185377Ssam			((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)
203185377Ssam				<< AR_IFS0_DIFS_S)
204185377Ssam			| INIT_SIFS);
205185377Ssam		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);
206185377Ssam		OS_REG_WRITE(ah, AR_PHY(17),
207185377Ssam			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);
208185377Ssam		OS_REG_WRITE(ah, AR_PHY_FRCTL,
209185377Ssam			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
210185377Ssam			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
211185377Ssam			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);
212185377Ssam	}
213185377Ssam
214185377Ssam	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)
215185377Ssam		cwMin = INIT_CWMIN;
216185377Ssam	else
217185377Ssam		cwMin = qi->tqi_cwmin;
218185377Ssam
219185377Ssam	/* Set cwmin and retry limit values */
220185377Ssam	OS_REG_WRITE(ah, AR_RETRY_LMT,
221185377Ssam		  (cwMin << AR_RETRY_LMT_CW_MIN_S)
222185377Ssam		 | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)
223185377Ssam		 | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)
224185377Ssam		 | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)
225185377Ssam		 | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)
226185377Ssam	);
227185377Ssam
228185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
229185377Ssam		ahp->ah_txOkInterruptMask |= 1 << q;
230185377Ssam	else
231185377Ssam		ahp->ah_txOkInterruptMask &= ~(1 << q);
232185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
233185377Ssam		ahp->ah_txErrInterruptMask |= 1 << q;
234185377Ssam	else
235185377Ssam		ahp->ah_txErrInterruptMask &= ~(1 << q);
236185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
237185377Ssam		ahp->ah_txDescInterruptMask |= 1 << q;
238185377Ssam	else
239185377Ssam		ahp->ah_txDescInterruptMask &= ~(1 << q);
240185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
241185377Ssam		ahp->ah_txEolInterruptMask |= 1 << q;
242185377Ssam	else
243185377Ssam		ahp->ah_txEolInterruptMask &= ~(1 << q);
244185377Ssam	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
245185377Ssam		ahp->ah_txUrnInterruptMask |= 1 << q;
246185377Ssam	else
247185377Ssam		ahp->ah_txUrnInterruptMask &= ~(1 << q);
248185377Ssam
249185377Ssam	return AH_TRUE;
250185377Ssam}
251185377Ssam
252185377Ssam/*
253185377Ssam * Get the TXDP for the "main" data queue.  Needs to be extended
254185377Ssam * for multiple Q functionality
255185377Ssam */
256185377Ssamuint32_t
257185377Ssamar5210GetTxDP(struct ath_hal *ah, u_int q)
258185377Ssam{
259185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
260185377Ssam	HAL_TX_QUEUE_INFO *qi;
261185377Ssam
262185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
263185377Ssam
264185377Ssam	qi = &ahp->ah_txq[q];
265185377Ssam	switch (qi->tqi_type) {
266185377Ssam	case HAL_TX_QUEUE_DATA:
267185377Ssam		return OS_REG_READ(ah, AR_TXDP0);
268185377Ssam	case HAL_TX_QUEUE_INACTIVE:
269185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
270185377Ssam		    __func__, q);
271185377Ssam		/* fall thru... */
272185377Ssam	default:
273185377Ssam		break;
274185377Ssam	}
275185377Ssam	return 0xffffffff;
276185377Ssam}
277185377Ssam
278185377Ssam/*
279185377Ssam * Set the TxDP for the "main" data queue.
280185377Ssam */
281185377SsamHAL_BOOL
282185377Ssamar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
283185377Ssam{
284185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
285185377Ssam	HAL_TX_QUEUE_INFO *qi;
286185377Ssam
287185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
288185377Ssam
289185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n",
290185377Ssam	    __func__, q, txdp);
291185377Ssam	qi = &ahp->ah_txq[q];
292185377Ssam	switch (qi->tqi_type) {
293185377Ssam	case HAL_TX_QUEUE_DATA:
294185377Ssam#ifdef AH_DEBUG
295185377Ssam		/*
296185377Ssam		 * Make sure that TXE is deasserted before setting the
297185377Ssam		 * TXDP.  If TXE is still asserted, setting TXDP will
298185377Ssam		 * have no effect.
299185377Ssam		 */
300185377Ssam		if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0)
301185377Ssam			ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n",
302185377Ssam				__func__, OS_REG_READ(ah, AR_CR));
303185377Ssam#endif
304185377Ssam		OS_REG_WRITE(ah, AR_TXDP0, txdp);
305185377Ssam		break;
306185377Ssam	case HAL_TX_QUEUE_BEACON:
307185377Ssam	case HAL_TX_QUEUE_CAB:
308185377Ssam		OS_REG_WRITE(ah, AR_TXDP1, txdp);
309185377Ssam		break;
310185377Ssam	case HAL_TX_QUEUE_INACTIVE:
311185377Ssam		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
312185377Ssam		    __func__, q);
313185377Ssam		/* fall thru... */
314185377Ssam	default:
315185377Ssam		return AH_FALSE;
316185377Ssam	}
317185377Ssam	return AH_TRUE;
318185377Ssam}
319185377Ssam
320185377Ssam/*
321185377Ssam * Update Tx FIFO trigger level.
322185377Ssam *
323185377Ssam * Set bIncTrigLevel to TRUE to increase the trigger level.
324185377Ssam * Set bIncTrigLevel to FALSE to decrease the trigger level.
325185377Ssam *
326185377Ssam * Returns TRUE if the trigger level was updated
327185377Ssam */
328185377SsamHAL_BOOL
329185377Ssamar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
330185377Ssam{
331185377Ssam	uint32_t curTrigLevel;
332185377Ssam	HAL_INT ints = ar5210GetInterrupts(ah);
333185377Ssam
334185377Ssam	/*
335185377Ssam	 * Disable chip interrupts. This is because halUpdateTxTrigLevel
336185377Ssam	 * is called from both ISR and non-ISR contexts.
337185377Ssam	 */
338185377Ssam	(void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
339185377Ssam	curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV);
340185377Ssam	if (bIncTrigLevel){
341185377Ssam		/* increase the trigger level */
342185377Ssam		curTrigLevel = curTrigLevel +
343185377Ssam			((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
344185377Ssam	} else {
345185377Ssam		/* decrease the trigger level if not already at the minimum */
346185377Ssam		if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
347185377Ssam			/* decrease the trigger level */
348185377Ssam			curTrigLevel--;
349185377Ssam		} else {
350185377Ssam			/* no update to the trigger level */
351185377Ssam			/* re-enable chip interrupts */
352185377Ssam			ar5210SetInterrupts(ah, ints);
353185377Ssam			return AH_FALSE;
354185377Ssam		}
355185377Ssam	}
356185377Ssam	/* Update the trigger level */
357185377Ssam	OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel);
358185377Ssam	/* re-enable chip interrupts */
359185377Ssam	ar5210SetInterrupts(ah, ints);
360185377Ssam	return AH_TRUE;
361185377Ssam}
362185377Ssam
363185377Ssam/*
364185377Ssam * Set Transmit Enable bits for the specified queues.
365185377Ssam */
366185377SsamHAL_BOOL
367185377Ssamar5210StartTxDma(struct ath_hal *ah, u_int q)
368185377Ssam{
369185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
370185377Ssam	HAL_TX_QUEUE_INFO *qi;
371185377Ssam
372185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
373185377Ssam
374185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
375185377Ssam	qi = &ahp->ah_txq[q];
376185377Ssam	switch (qi->tqi_type) {
377185377Ssam	case HAL_TX_QUEUE_DATA:
378185377Ssam		OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0);
379185377Ssam		break;
380185377Ssam	case HAL_TX_QUEUE_CAB:
381185377Ssam		OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1);	/* enable altq xmit */
382185377Ssam		OS_REG_WRITE(ah, AR_BCR,
383185377Ssam			AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV);
384185377Ssam		break;
385185377Ssam	case HAL_TX_QUEUE_BEACON:
386185377Ssam		/* XXX add CR_BCR_BCMD if IBSS mode */
387185377Ssam		OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE);
388185377Ssam		break;
389185377Ssam	case HAL_TX_QUEUE_INACTIVE:
390185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
391185377Ssam		    __func__, q);
392185377Ssam		/* fal thru... */
393185377Ssam	default:
394185377Ssam		return AH_FALSE;
395185377Ssam	}
396185377Ssam	return AH_TRUE;
397185377Ssam}
398185377Ssam
399185377Ssamuint32_t
400185377Ssamar5210NumTxPending(struct ath_hal *ah, u_int q)
401185377Ssam{
402185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
403185377Ssam	HAL_TX_QUEUE_INFO *qi;
404185377Ssam	uint32_t v;
405185377Ssam
406185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
407185377Ssam
408185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
409185377Ssam	qi = &ahp->ah_txq[q];
410185377Ssam	switch (qi->tqi_type) {
411185377Ssam	case HAL_TX_QUEUE_DATA:
412185377Ssam		v = OS_REG_READ(ah, AR_CFG);
413185377Ssam		return MS(v, AR_CFG_TXCNT);
414185377Ssam	case HAL_TX_QUEUE_INACTIVE:
415185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
416185377Ssam		    __func__, q);
417185377Ssam		/* fall thru... */
418185377Ssam	default:
419185377Ssam		break;
420185377Ssam	}
421185377Ssam	return 0;
422185377Ssam}
423185377Ssam
424185377Ssam/*
425185377Ssam * Stop transmit on the specified queue
426185377Ssam */
427185377SsamHAL_BOOL
428185377Ssamar5210StopTxDma(struct ath_hal *ah, u_int q)
429185377Ssam{
430185377Ssam	struct ath_hal_5210 *ahp = AH5210(ah);
431185377Ssam	HAL_TX_QUEUE_INFO *qi;
432185377Ssam
433185377Ssam	HALASSERT(q < HAL_NUM_TX_QUEUES);
434185377Ssam
435185377Ssam	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
436185377Ssam	qi = &ahp->ah_txq[q];
437185377Ssam	switch (qi->tqi_type) {
438185377Ssam	case HAL_TX_QUEUE_DATA: {
439185377Ssam		int i;
440185377Ssam		OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0);
441185377Ssam		for (i = 0; i < 1000; i++) {
442185377Ssam			if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0)
443185377Ssam				break;
444185377Ssam			OS_DELAY(10);
445185377Ssam		}
446185377Ssam		OS_REG_WRITE(ah, AR_CR, 0);
447185377Ssam		return (i < 1000);
448185377Ssam	}
449185377Ssam	case HAL_TX_QUEUE_BEACON:
450185377Ssam		return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0);
451185377Ssam	case HAL_TX_QUEUE_INACTIVE:
452185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
453185377Ssam		    __func__, q);
454185377Ssam		/* fall thru... */
455185377Ssam	default:
456185377Ssam		break;
457185377Ssam	}
458185377Ssam	return AH_FALSE;
459185377Ssam}
460185377Ssam
461185377Ssam/*
462185377Ssam * Descriptor Access Functions
463185377Ssam */
464185377Ssam
465185377Ssam#define	VALID_PKT_TYPES \
466185377Ssam	((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
467185377Ssam	 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
468185377Ssam	 (1<<HAL_PKT_TYPE_BEACON))
469185377Ssam#define	isValidPktType(_t)	((1<<(_t)) & VALID_PKT_TYPES)
470185377Ssam#define	VALID_TX_RATES \
471185377Ssam	((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
472185377Ssam	 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
473185377Ssam	 (1<<0x1d)|(1<<0x18)|(1<<0x1c))
474185377Ssam#define	isValidTxRate(_r)	((1<<(_r)) & VALID_TX_RATES)
475185377Ssam
476185377SsamHAL_BOOL
477185377Ssamar5210SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
478185377Ssam	u_int pktLen,
479185377Ssam	u_int hdrLen,
480185377Ssam	HAL_PKT_TYPE type,
481185377Ssam	u_int txPower,
482185377Ssam	u_int txRate0, u_int txTries0,
483185377Ssam	u_int keyIx,
484185377Ssam	u_int antMode,
485185377Ssam	u_int flags,
486185377Ssam	u_int rtsctsRate,
487185377Ssam	u_int rtsctsDuration,
488185377Ssam        u_int compicvLen,
489185377Ssam	u_int compivLen,
490185377Ssam	u_int comp)
491185377Ssam{
492185377Ssam	struct ar5210_desc *ads = AR5210DESC(ds);
493185377Ssam	uint32_t frtype;
494185377Ssam
495185377Ssam	(void) txPower;
496185377Ssam	(void) rtsctsDuration;
497185377Ssam
498185377Ssam	HALASSERT(txTries0 != 0);
499185377Ssam	HALASSERT(isValidPktType(type));
500185377Ssam	HALASSERT(isValidTxRate(txRate0));
501185377Ssam
502185377Ssam	if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP)
503185377Ssam		frtype = AR_Frm_NoDelay;
504185377Ssam	else
505185377Ssam		frtype = type << 26;
506185377Ssam	ads->ds_ctl0 = (pktLen & AR_FrameLen)
507185377Ssam		     | (txRate0 << AR_XmitRate_S)
508185377Ssam		     | ((hdrLen << AR_HdrLen_S) & AR_HdrLen)
509185377Ssam		     | frtype
510185377Ssam		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
511185377Ssam		     | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
512185377Ssam		     | (antMode ? AR_AntModeXmit : 0)
513185377Ssam		     ;
514185377Ssam	if (keyIx != HAL_TXKEYIX_INVALID) {
515185377Ssam		ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
516185377Ssam		ads->ds_ctl0 |= AR_EncryptKeyValid;
517185377Ssam	} else
518185377Ssam		ads->ds_ctl1 = 0;
519185377Ssam	if (flags & HAL_TXDESC_RTSENA) {
520185377Ssam		ads->ds_ctl0 |= AR_RTSCTSEnable;
521243174Sadrian		ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S)
522243174Sadrian		    & AR_RTSDuration;
523185377Ssam	}
524185377Ssam	return AH_TRUE;
525185377Ssam}
526185377Ssam
527185377SsamHAL_BOOL
528185377Ssamar5210SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
529185377Ssam	u_int txRate1, u_int txTries1,
530185377Ssam	u_int txRate2, u_int txTries2,
531185377Ssam	u_int txRate3, u_int txTries3)
532185377Ssam{
533185377Ssam	(void) ah; (void) ds;
534185377Ssam	(void) txRate1; (void) txTries1;
535185377Ssam	(void) txRate2; (void) txTries2;
536185377Ssam	(void) txRate3; (void) txTries3;
537185377Ssam	return AH_FALSE;
538185377Ssam}
539185377Ssam
540185377Ssamvoid
541185377Ssamar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
542185377Ssam{
543185377Ssam	struct ar5210_desc *ads = AR5210DESC(ds);
544185377Ssam
545185377Ssam	ads->ds_ctl0 |= AR_TxInterReq;
546185377Ssam}
547185377Ssam
548185377SsamHAL_BOOL
549185377Ssamar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
550239051Sadrian	HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
551239051Sadrian	u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
552185377Ssam	const struct ath_desc *ds0)
553185377Ssam{
554185377Ssam	struct ar5210_desc *ads = AR5210DESC(ds);
555239051Sadrian	uint32_t segLen = segLenList[0];
556185377Ssam
557185377Ssam	HALASSERT((segLen &~ AR_BufLen) == 0);
558185377Ssam
559239051Sadrian	ds->ds_data = bufAddrList[0];
560239051Sadrian
561185377Ssam	if (firstSeg) {
562185377Ssam		/*
563185377Ssam		 * First descriptor, don't clobber xmit control data
564185377Ssam		 * setup by ar5210SetupTxDesc.
565185377Ssam		 */
566185377Ssam		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
567185377Ssam	} else if (lastSeg) {		/* !firstSeg && lastSeg */
568185377Ssam		/*
569185377Ssam		 * Last descriptor in a multi-descriptor frame,
570185377Ssam		 * copy the transmit parameters from the first
571185377Ssam		 * frame for processing on completion.
572185377Ssam		 */
573185377Ssam		ads->ds_ctl0 = AR5210DESC_CONST(ds0)->ds_ctl0;
574185377Ssam		ads->ds_ctl1 = segLen;
575185377Ssam	} else {			/* !firstSeg && !lastSeg */
576185377Ssam		/*
577185377Ssam		 * Intermediate descriptor in a multi-descriptor frame.
578185377Ssam		 */
579185377Ssam		ads->ds_ctl0 = 0;
580185377Ssam		ads->ds_ctl1 = segLen | AR_More;
581185377Ssam	}
582185377Ssam	ads->ds_status0 = ads->ds_status1 = 0;
583185377Ssam	return AH_TRUE;
584185377Ssam}
585185377Ssam
586185377Ssam/*
587185377Ssam * Processing of HW TX descriptor.
588185377Ssam */
589185377SsamHAL_STATUS
590185377Ssamar5210ProcTxDesc(struct ath_hal *ah,
591185377Ssam	struct ath_desc *ds, struct ath_tx_status *ts)
592185377Ssam{
593185377Ssam	struct ar5210_desc *ads = AR5210DESC(ds);
594185377Ssam
595185377Ssam	if ((ads->ds_status1 & AR_Done) == 0)
596185377Ssam		return HAL_EINPROGRESS;
597185377Ssam
598185377Ssam	/* Update software copies of the HW status */
599185377Ssam	ts->ts_seqnum = ads->ds_status1 & AR_SeqNum;
600185377Ssam	ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
601185377Ssam	ts->ts_status = 0;
602185377Ssam	if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
603185377Ssam		if (ads->ds_status0 & AR_ExcessiveRetries)
604185377Ssam			ts->ts_status |= HAL_TXERR_XRETRY;
605185377Ssam		if (ads->ds_status0 & AR_Filtered)
606185377Ssam			ts->ts_status |= HAL_TXERR_FILT;
607185377Ssam		if (ads->ds_status0  & AR_FIFOUnderrun)
608185377Ssam			ts->ts_status |= HAL_TXERR_FIFO;
609185377Ssam	}
610185377Ssam	ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
611185377Ssam	ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
612185377Ssam	ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
613185377Ssam	ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
614185377Ssam	ts->ts_antenna = 0;		/* NB: don't know */
615185377Ssam	ts->ts_finaltsi = 0;
616185377Ssam
617185377Ssam	return HAL_OK;
618185377Ssam}
619185377Ssam
620185377Ssam/*
621185377Ssam * Determine which tx queues need interrupt servicing.
622185377Ssam * STUB.
623185377Ssam */
624185377Ssamvoid
625185377Ssamar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
626185377Ssam{
627185377Ssam	return;
628185377Ssam}
629217621Sadrian
630217621Sadrian/*
631217621Sadrian * Retrieve the rate table from the given TX completion descriptor
632217621Sadrian */
633217621SadrianHAL_BOOL
634217621Sadrianar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
635217621Sadrian{
636217621Sadrian	return AH_FALSE;
637217621Sadrian}
638238607Sadrian
639238607Sadrian/*
640238607Sadrian * Set the TX descriptor link pointer
641238607Sadrian */
642238607Sadrianvoid
643238607Sadrianar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
644238607Sadrian{
645238607Sadrian	struct ar5210_desc *ads = AR5210DESC(ds);
646238607Sadrian
647238607Sadrian	ads->ds_link = link;
648238607Sadrian}
649238607Sadrian
650238607Sadrian/*
651238607Sadrian * Get the TX descriptor link pointer
652238607Sadrian */
653238607Sadrianvoid
654238607Sadrianar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
655238607Sadrian{
656238607Sadrian	struct ar5210_desc *ads = AR5210DESC(ds);
657238607Sadrian
658238607Sadrian	*link = ads->ds_link;
659238607Sadrian}
660238607Sadrian
661238607Sadrian/*
662238607Sadrian * Get a pointer to the TX descriptor link pointer
663238607Sadrian */
664238607Sadrianvoid
665238607Sadrianar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
666238607Sadrian{
667238607Sadrian	struct ar5210_desc *ads = AR5210DESC(ds);
668238607Sadrian
669238607Sadrian	*linkptr = &ads->ds_link;
670238607Sadrian}
671