1/*-
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
5 * Copyright (c) 2002-2006 Atheros Communications, Inc.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * $FreeBSD: releng/12.0/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c 326695 2017-12-08 15:57:29Z pfg $
20 */
21#include "opt_ah.h"
22
23#include "ah.h"
24#include "ah_internal.h"
25#include "ah_desc.h"
26
27#include "ar5211/ar5211.h"
28#include "ar5211/ar5211reg.h"
29#include "ar5211/ar5211desc.h"
30
31/*
32 * Update Tx FIFO trigger level.
33 *
34 * Set bIncTrigLevel to TRUE to increase the trigger level.
35 * Set bIncTrigLevel to FALSE to decrease the trigger level.
36 *
37 * Returns TRUE if the trigger level was updated
38 */
39HAL_BOOL
40ar5211UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
41{
42	uint32_t curTrigLevel, txcfg;
43	HAL_INT ints = ar5211GetInterrupts(ah);
44
45	/*
46	 * Disable chip interrupts. This is because halUpdateTxTrigLevel
47	 * is called from both ISR and non-ISR contexts.
48	 */
49	ar5211SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
50	txcfg = OS_REG_READ(ah, AR_TXCFG);
51	curTrigLevel = (txcfg & AR_TXCFG_FTRIG_M) >> AR_TXCFG_FTRIG_S;
52	if (bIncTrigLevel){
53		/* increase the trigger level */
54		curTrigLevel = curTrigLevel +
55			((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
56	} else {
57		/* decrease the trigger level if not already at the minimum */
58		if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
59			/* decrease the trigger level */
60			curTrigLevel--;
61		} else {
62			/* no update to the trigger level */
63			/* re-enable chip interrupts */
64			ar5211SetInterrupts(ah, ints);
65			return AH_FALSE;
66		}
67	}
68	/* Update the trigger level */
69	OS_REG_WRITE(ah, AR_TXCFG, (txcfg &~ AR_TXCFG_FTRIG_M) |
70		((curTrigLevel << AR_TXCFG_FTRIG_S) & AR_TXCFG_FTRIG_M));
71	/* re-enable chip interrupts */
72	ar5211SetInterrupts(ah, ints);
73	return AH_TRUE;
74}
75
76/*
77 * Set the properties of the tx queue with the parameters
78 * from qInfo.  The queue must previously have been setup
79 * with a call to ar5211SetupTxQueue.
80 */
81HAL_BOOL
82ar5211SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
83{
84	struct ath_hal_5211 *ahp = AH5211(ah);
85
86	if (q >= HAL_NUM_TX_QUEUES) {
87		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
88		    __func__, q);
89		return AH_FALSE;
90	}
91	return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
92}
93
94/*
95 * Return the properties for the specified tx queue.
96 */
97HAL_BOOL
98ar5211GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
99{
100	struct ath_hal_5211 *ahp = AH5211(ah);
101
102	if (q >= HAL_NUM_TX_QUEUES) {
103		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
104		    __func__, q);
105		return AH_FALSE;
106	}
107	return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
108}
109
110/*
111 * Allocate and initialize a tx DCU/QCU combination.
112 */
113int
114ar5211SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
115	const HAL_TXQ_INFO *qInfo)
116{
117	struct ath_hal_5211 *ahp = AH5211(ah);
118	HAL_TX_QUEUE_INFO *qi;
119	int q;
120
121	switch (type) {
122	case HAL_TX_QUEUE_BEACON:
123		q = 9;
124		break;
125	case HAL_TX_QUEUE_CAB:
126		q = 8;
127		break;
128	case HAL_TX_QUEUE_DATA:
129		q = 0;
130		if (ahp->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE)
131			return q;
132		break;
133	default:
134		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
135		    __func__, type);
136		return -1;
137	}
138
139	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
140
141	qi = &ahp->ah_txq[q];
142	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
143		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
144		    __func__, q);
145		return -1;
146	}
147	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
148	qi->tqi_type = type;
149	if (qInfo == AH_NULL) {
150		/* by default enable OK+ERR+DESC+URN interrupts */
151		qi->tqi_qflags =
152			  HAL_TXQ_TXOKINT_ENABLE
153			| HAL_TXQ_TXERRINT_ENABLE
154			| HAL_TXQ_TXDESCINT_ENABLE
155			| HAL_TXQ_TXURNINT_ENABLE
156			;
157		qi->tqi_aifs = INIT_AIFS;
158		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
159		qi->tqi_cwmax = INIT_CWMAX;
160		qi->tqi_shretry = INIT_SH_RETRY;
161		qi->tqi_lgretry = INIT_LG_RETRY;
162	} else
163		(void) ar5211SetTxQueueProps(ah, q, qInfo);
164	return q;
165}
166
167/*
168 * Update the h/w interrupt registers to reflect a tx q's configuration.
169 */
170static void
171setTxQInterrupts(struct ath_hal *ah, HAL_TX_QUEUE_INFO *qi)
172{
173	struct ath_hal_5211 *ahp = AH5211(ah);
174
175	HALDEBUG(ah, HAL_DEBUG_TXQUEUE,
176	    "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", __func__
177		, ahp->ah_txOkInterruptMask
178		, ahp->ah_txErrInterruptMask
179		, ahp->ah_txDescInterruptMask
180		, ahp->ah_txEolInterruptMask
181		, ahp->ah_txUrnInterruptMask
182	);
183
184	OS_REG_WRITE(ah, AR_IMR_S0,
185		  SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
186		| SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)
187	);
188	OS_REG_WRITE(ah, AR_IMR_S1,
189		  SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
190		| SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)
191	);
192	OS_REG_RMW_FIELD(ah, AR_IMR_S2,
193		AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
194}
195
196/*
197 * Free a tx DCU/QCU combination.
198 */
199HAL_BOOL
200ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q)
201{
202	struct ath_hal_5211 *ahp = AH5211(ah);
203	HAL_TX_QUEUE_INFO *qi;
204
205	if (q >= HAL_NUM_TX_QUEUES) {
206		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
207		    __func__, q);
208		return AH_FALSE;
209	}
210	qi = &ahp->ah_txq[q];
211	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
212		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
213		    __func__, q);
214		return AH_FALSE;
215	}
216
217	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
218
219	qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
220	ahp->ah_txOkInterruptMask &= ~(1 << q);
221	ahp->ah_txErrInterruptMask &= ~(1 << q);
222	ahp->ah_txDescInterruptMask &= ~(1 << q);
223	ahp->ah_txEolInterruptMask &= ~(1 << q);
224	ahp->ah_txUrnInterruptMask &= ~(1 << q);
225	setTxQInterrupts(ah, qi);
226
227	return AH_TRUE;
228}
229
230/*
231 * Set the retry, aifs, cwmin/max, readyTime regs for specified queue
232 */
233HAL_BOOL
234ar5211ResetTxQueue(struct ath_hal *ah, u_int q)
235{
236	struct ath_hal_5211 *ahp = AH5211(ah);
237	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
238	HAL_TX_QUEUE_INFO *qi;
239	uint32_t cwMin, chanCwMin, value;
240
241	if (q >= HAL_NUM_TX_QUEUES) {
242		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
243		    __func__, q);
244		return AH_FALSE;
245	}
246	qi = &ahp->ah_txq[q];
247	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
248		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
249		    __func__, q);
250		return AH_TRUE;		/* XXX??? */
251	}
252
253	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) {
254		/*
255		 * Select cwmin according to channel type.
256		 * NB: chan can be NULL during attach
257		 */
258		if (chan && IEEE80211_IS_CHAN_B(chan))
259			chanCwMin = INIT_CWMIN_11B;
260		else
261			chanCwMin = INIT_CWMIN;
262		/* make sure that the CWmin is of the form (2^n - 1) */
263		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1)
264			;
265	} else
266		cwMin = qi->tqi_cwmin;
267
268	/* set cwMin/Max and AIFS values */
269	OS_REG_WRITE(ah, AR_DLCL_IFS(q),
270		  SM(cwMin, AR_D_LCL_IFS_CWMIN)
271		| SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
272		| SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
273
274	/* Set retry limit values */
275	OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q),
276		   SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
277		 | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
278		 | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG)
279		 | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
280	);
281
282	/* enable early termination on the QCU */
283	OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
284
285	if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) {
286		/* Configure DCU to use the global sequence count */
287		OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL);
288	}
289	/* multiqueue support */
290	if (qi->tqi_cbrPeriod) {
291		OS_REG_WRITE(ah, AR_QCBRCFG(q),
292			  SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL)
293			| SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH));
294		OS_REG_WRITE(ah, AR_QMISC(q),
295			OS_REG_READ(ah, AR_QMISC(q)) |
296			AR_Q_MISC_FSP_CBR |
297			(qi->tqi_cbrOverflowLimit ?
298				AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0));
299	}
300	if (qi->tqi_readyTime) {
301		OS_REG_WRITE(ah, AR_QRDYTIMECFG(q),
302			SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) |
303			AR_Q_RDYTIMECFG_EN);
304	}
305	if (qi->tqi_burstTime) {
306		OS_REG_WRITE(ah, AR_DCHNTIME(q),
307			SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
308			AR_D_CHNTIME_EN);
309		if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) {
310			OS_REG_WRITE(ah, AR_QMISC(q),
311			     OS_REG_READ(ah, AR_QMISC(q)) |
312			     AR_Q_MISC_RDYTIME_EXP_POLICY);
313		}
314	}
315
316	if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) {
317		OS_REG_WRITE(ah, AR_DMISC(q),
318			OS_REG_READ(ah, AR_DMISC(q)) |
319			AR_D_MISC_POST_FR_BKOFF_DIS);
320	}
321	if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) {
322		OS_REG_WRITE(ah, AR_DMISC(q),
323			OS_REG_READ(ah, AR_DMISC(q)) |
324			AR_D_MISC_FRAG_BKOFF_EN);
325	}
326	switch (qi->tqi_type) {
327	case HAL_TX_QUEUE_BEACON:
328		/* Configure QCU for beacons */
329		OS_REG_WRITE(ah, AR_QMISC(q),
330			OS_REG_READ(ah, AR_QMISC(q))
331			| AR_Q_MISC_FSP_DBA_GATED
332			| AR_Q_MISC_BEACON_USE
333			| AR_Q_MISC_CBR_INCR_DIS1);
334		/* Configure DCU for beacons */
335		value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
336			| AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS;
337		if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU)
338			value |= AR5311_D_MISC_SEQ_NUM_CONTROL;
339		OS_REG_WRITE(ah, AR_DMISC(q), value);
340		break;
341	case HAL_TX_QUEUE_CAB:
342		/* Configure QCU for CAB (Crap After Beacon) frames */
343		OS_REG_WRITE(ah, AR_QMISC(q),
344			OS_REG_READ(ah, AR_QMISC(q))
345			| AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1
346			| AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY);
347
348		value = (ahp->ah_beaconInterval
349			- (ah->ah_config.ah_sw_beacon_response_time
350			        - ah->ah_config.ah_dma_beacon_response_time)
351			- ah->ah_config.ah_additional_swba_backoff) * 1024;
352		OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN);
353
354		/* Configure DCU for CAB */
355		value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S);
356		if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU)
357			value |= AR5311_D_MISC_SEQ_NUM_CONTROL;
358		OS_REG_WRITE(ah, AR_QMISC(q), value);
359		break;
360	default:
361		/* NB: silence compiler */
362		break;
363	}
364
365	/*
366	 * Always update the secondary interrupt mask registers - this
367	 * could be a new queue getting enabled in a running system or
368	 * hw getting re-initialized during a reset!
369	 *
370	 * Since we don't differentiate between tx interrupts corresponding
371	 * to individual queues - secondary tx mask regs are always unmasked;
372	 * tx interrupts are enabled/disabled for all queues collectively
373	 * using the primary mask reg
374	 */
375	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
376		ahp->ah_txOkInterruptMask |= 1 << q;
377	else
378		ahp->ah_txOkInterruptMask &= ~(1 << q);
379	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
380		ahp->ah_txErrInterruptMask |= 1 << q;
381	else
382		ahp->ah_txErrInterruptMask &= ~(1 << q);
383	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
384		ahp->ah_txDescInterruptMask |= 1 << q;
385	else
386		ahp->ah_txDescInterruptMask &= ~(1 << q);
387	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
388		ahp->ah_txEolInterruptMask |= 1 << q;
389	else
390		ahp->ah_txEolInterruptMask &= ~(1 << q);
391	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
392		ahp->ah_txUrnInterruptMask |= 1 << q;
393	else
394		ahp->ah_txUrnInterruptMask &= ~(1 << q);
395	setTxQInterrupts(ah, qi);
396
397	return AH_TRUE;
398}
399
400/*
401 * Get the TXDP for the specified data queue.
402 */
403uint32_t
404ar5211GetTxDP(struct ath_hal *ah, u_int q)
405{
406	HALASSERT(q < HAL_NUM_TX_QUEUES);
407	return OS_REG_READ(ah, AR_QTXDP(q));
408}
409
410/*
411 * Set the TxDP for the specified tx queue.
412 */
413HAL_BOOL
414ar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
415{
416	HALASSERT(q < HAL_NUM_TX_QUEUES);
417	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
418
419	/*
420	 * Make sure that TXE is deasserted before setting the TXDP.  If TXE
421	 * is still asserted, setting TXDP will have no effect.
422	 */
423	HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0);
424
425	OS_REG_WRITE(ah, AR_QTXDP(q), txdp);
426
427	return AH_TRUE;
428}
429
430/*
431 * Set Transmit Enable bits for the specified queues.
432 */
433HAL_BOOL
434ar5211StartTxDma(struct ath_hal *ah, u_int q)
435{
436	HALASSERT(q < HAL_NUM_TX_QUEUES);
437	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
438
439	/* Check that queue is not already active */
440	HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<<q)) == 0);
441
442	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
443
444	/* Check to be sure we're not enabling a q that has its TXD bit set. */
445	HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0);
446
447	OS_REG_WRITE(ah, AR_Q_TXE, 1 << q);
448	return AH_TRUE;
449}
450
451/*
452 * Return the number of frames pending on the specified queue.
453 */
454uint32_t
455ar5211NumTxPending(struct ath_hal *ah, u_int q)
456{
457	uint32_t n;
458
459	HALASSERT(q < HAL_NUM_TX_QUEUES);
460	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
461
462	n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M;
463	/*
464	 * Pending frame count (PFC) can momentarily go to zero
465	 * while TXE remains asserted.  In other words a PFC of
466	 * zero is not sufficient to say that the queue has stopped.
467	 */
468	if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<<q)))
469		n = 1;			/* arbitrarily pick 1 */
470	return n;
471}
472
473/*
474 * Stop transmit on the specified queue
475 */
476HAL_BOOL
477ar5211StopTxDma(struct ath_hal *ah, u_int q)
478{
479	int i;
480
481	HALASSERT(q < HAL_NUM_TX_QUEUES);
482	HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE);
483
484	OS_REG_WRITE(ah, AR_Q_TXD, 1<<q);
485	for (i = 0; i < 10000; i++) {
486		if (ar5211NumTxPending(ah, q) == 0)
487			break;
488		OS_DELAY(10);
489	}
490	OS_REG_WRITE(ah, AR_Q_TXD, 0);
491
492	return (i < 10000);
493}
494
495/*
496 * Descriptor Access Functions
497 */
498
499#define	VALID_PKT_TYPES \
500	((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
501	 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
502	 (1<<HAL_PKT_TYPE_BEACON))
503#define	isValidPktType(_t)	((1<<(_t)) & VALID_PKT_TYPES)
504#define	VALID_TX_RATES \
505	((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
506	 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
507	 (1<<0x1d)|(1<<0x18)|(1<<0x1c))
508#define	isValidTxRate(_r)	((1<<(_r)) & VALID_TX_RATES)
509
510HAL_BOOL
511ar5211SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
512	u_int pktLen,
513	u_int hdrLen,
514	HAL_PKT_TYPE type,
515	u_int txPower,
516	u_int txRate0, u_int txTries0,
517	u_int keyIx,
518	u_int antMode,
519	u_int flags,
520	u_int rtsctsRate,
521	u_int rtsctsDuration,
522	u_int compicvLen,
523	u_int compivLen,
524	u_int comp)
525{
526	struct ar5211_desc *ads = AR5211DESC(ds);
527
528	(void) hdrLen;
529	(void) txPower;
530	(void) rtsctsRate; (void) rtsctsDuration;
531
532	HALASSERT(txTries0 != 0);
533	HALASSERT(isValidPktType(type));
534	HALASSERT(isValidTxRate(txRate0));
535	/* XXX validate antMode */
536
537	ads->ds_ctl0 = (pktLen & AR_FrameLen)
538		     | (txRate0 << AR_XmitRate_S)
539		     | (antMode << AR_AntModeXmit_S)
540		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
541		     | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
542		     | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0)
543		     | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
544		     ;
545	ads->ds_ctl1 = (type << 26)
546		     | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0)
547		     ;
548
549	if (keyIx != HAL_TXKEYIX_INVALID) {
550		ads->ds_ctl1 |=
551			(keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
552		ads->ds_ctl0 |= AR_EncryptKeyValid;
553	}
554	return AH_TRUE;
555#undef RATE
556}
557
558HAL_BOOL
559ar5211SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
560	u_int txRate1, u_int txTries1,
561	u_int txRate2, u_int txTries2,
562	u_int txRate3, u_int txTries3)
563{
564	(void) ah; (void) ds;
565	(void) txRate1; (void) txTries1;
566	(void) txRate2; (void) txTries2;
567	(void) txRate3; (void) txTries3;
568	return AH_FALSE;
569}
570
571void
572ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
573{
574	struct ar5211_desc *ads = AR5211DESC(ds);
575
576	ads->ds_ctl0 |= AR_TxInterReq;
577}
578
579HAL_BOOL
580ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
581	HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId,
582	u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
583	const struct ath_desc *ds0)
584{
585	struct ar5211_desc *ads = AR5211DESC(ds);
586	uint32_t segLen = segLenList[0];
587
588	ds->ds_data = bufAddrList[0];
589
590	HALASSERT((segLen &~ AR_BufLen) == 0);
591
592	if (firstSeg) {
593		/*
594		 * First descriptor, don't clobber xmit control data
595		 * setup by ar5211SetupTxDesc.
596		 */
597		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
598	} else if (lastSeg) {		/* !firstSeg && lastSeg */
599		/*
600		 * Last descriptor in a multi-descriptor frame,
601		 * copy the transmit parameters from the first
602		 * frame for processing on completion.
603		 */
604		ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0;
605		ads->ds_ctl1 = segLen;
606	} else {			/* !firstSeg && !lastSeg */
607		/*
608		 * Intermediate descriptor in a multi-descriptor frame.
609		 */
610		ads->ds_ctl0 = 0;
611		ads->ds_ctl1 = segLen | AR_More;
612	}
613	ads->ds_status0 = ads->ds_status1 = 0;
614	return AH_TRUE;
615}
616
617/*
618 * Processing of HW TX descriptor.
619 */
620HAL_STATUS
621ar5211ProcTxDesc(struct ath_hal *ah,
622	struct ath_desc *ds, struct ath_tx_status *ts)
623{
624	struct ar5211_desc *ads = AR5211DESC(ds);
625
626	if ((ads->ds_status1 & AR_Done) == 0)
627		return HAL_EINPROGRESS;
628
629	/* Update software copies of the HW status */
630	ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum);
631	ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
632	ts->ts_status = 0;
633	if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
634		if (ads->ds_status0 & AR_ExcessiveRetries)
635			ts->ts_status |= HAL_TXERR_XRETRY;
636		if (ads->ds_status0 & AR_Filtered)
637			ts->ts_status |= HAL_TXERR_FILT;
638		if (ads->ds_status0 & AR_FIFOUnderrun)
639			ts->ts_status |= HAL_TXERR_FIFO;
640	}
641	ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
642	ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
643	ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
644	ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
645	ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt);
646	ts->ts_antenna = 0;		/* NB: don't know */
647	ts->ts_finaltsi = 0;
648	/*
649	 * NB: the number of retries is one less than it should be.
650	 * Also, 0 retries and 1 retry are both reported as 0 retries.
651	 */
652	if (ts->ts_shortretry > 0)
653		ts->ts_shortretry++;
654	if (ts->ts_longretry > 0)
655		ts->ts_longretry++;
656
657	return HAL_OK;
658}
659
660/*
661 * Determine which tx queues need interrupt servicing.
662 * STUB.
663 */
664void
665ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
666{
667	return;
668}
669
670/*
671 * Retrieve the rate table from the given TX completion descriptor
672 */
673HAL_BOOL
674ar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
675{
676	return AH_FALSE;
677}
678
679void
680ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
681{
682	struct ar5211_desc *ads = AR5211DESC(ds);
683
684	ads->ds_link = link;
685}
686
687void
688ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
689{
690	struct ar5211_desc *ads = AR5211DESC(ds);
691
692	*link = ads->ds_link;
693}
694
695void
696ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
697{
698	struct ar5211_desc *ads = AR5211DESC(ds);
699
700	*linkptr = &ads->ds_link;
701}
702