xref: /freebsd/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
1 /*-
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
5  * Copyright (c) 2002-2004 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$
20  */
21 #include "opt_ah.h"
22 
23 #include "ah.h"
24 #include "ah_internal.h"
25 #include "ah_desc.h"
26 
27 #include "ar5210/ar5210.h"
28 #include "ar5210/ar5210reg.h"
29 #include "ar5210/ar5210phy.h"
30 #include "ar5210/ar5210desc.h"
31 
32 /*
33  * Set the properties of the tx queue with the parameters
34  * from qInfo.  The queue must previously have been setup
35  * with a call to ar5210SetupTxQueue.
36  */
37 HAL_BOOL
38 ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
39 {
40 	struct ath_hal_5210 *ahp = AH5210(ah);
41 
42 	if (q >= HAL_NUM_TX_QUEUES) {
43 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
44 		    __func__, q);
45 		return AH_FALSE;
46 	}
47 	return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
48 }
49 
50 /*
51  * Return the properties for the specified tx queue.
52  */
53 HAL_BOOL
54 ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
55 {
56 	struct ath_hal_5210 *ahp = AH5210(ah);
57 
58 	if (q >= HAL_NUM_TX_QUEUES) {
59 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
60 		    __func__, q);
61 		return AH_FALSE;
62 	}
63 	return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
64 }
65 
66 /*
67  * Allocate and initialize a tx DCU/QCU combination.
68  */
69 int
70 ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
71 	const HAL_TXQ_INFO *qInfo)
72 {
73 	struct ath_hal_5210 *ahp = AH5210(ah);
74 	HAL_TX_QUEUE_INFO *qi;
75 	int q;
76 
77 	switch (type) {
78 	case HAL_TX_QUEUE_BEACON:
79 		q = 2;
80 		break;
81 	case HAL_TX_QUEUE_CAB:
82 		q = 1;
83 		break;
84 	case HAL_TX_QUEUE_DATA:
85 		q = 0;
86 		break;
87 	default:
88 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
89 		    __func__, type);
90 		return -1;
91 	}
92 
93 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
94 
95 	qi = &ahp->ah_txq[q];
96 	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
97 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
98 		    __func__, q);
99 		return -1;
100 	}
101 	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
102 	qi->tqi_type = type;
103 	if (qInfo == AH_NULL) {
104 		/* by default enable OK+ERR+DESC+URN interrupts */
105 		qi->tqi_qflags =
106 			  HAL_TXQ_TXOKINT_ENABLE
107 			| HAL_TXQ_TXERRINT_ENABLE
108 			| HAL_TXQ_TXDESCINT_ENABLE
109 			| HAL_TXQ_TXURNINT_ENABLE
110 			;
111 		qi->tqi_aifs = INIT_AIFS;
112 		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
113 		qi->tqi_shretry = INIT_SH_RETRY;
114 		qi->tqi_lgretry = INIT_LG_RETRY;
115 	} else
116 		(void) ar5210SetTxQueueProps(ah, q, qInfo);
117 	/* NB: must be followed by ar5210ResetTxQueue */
118 	return q;
119 }
120 
121 /*
122  * Free a tx DCU/QCU combination.
123  */
124 HAL_BOOL
125 ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q)
126 {
127 	struct ath_hal_5210 *ahp = AH5210(ah);
128 	HAL_TX_QUEUE_INFO *qi;
129 
130 	if (q >= HAL_NUM_TX_QUEUES) {
131 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
132 		    __func__, q);
133 		return AH_FALSE;
134 	}
135 	qi = &ahp->ah_txq[q];
136 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
137 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
138 		    __func__, q);
139 		return AH_FALSE;
140 	}
141 
142 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
143 
144 	qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
145 	ahp->ah_txOkInterruptMask &= ~(1 << q);
146 	ahp->ah_txErrInterruptMask &= ~(1 << q);
147 	ahp->ah_txDescInterruptMask &= ~(1 << q);
148 	ahp->ah_txEolInterruptMask &= ~(1 << q);
149 	ahp->ah_txUrnInterruptMask &= ~(1 << q);
150 
151 	return AH_TRUE;
152 #undef N
153 }
154 
155 HAL_BOOL
156 ar5210ResetTxQueue(struct ath_hal *ah, u_int q)
157 {
158 	struct ath_hal_5210 *ahp = AH5210(ah);
159 	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
160 	HAL_TX_QUEUE_INFO *qi;
161 	uint32_t cwMin;
162 
163 	if (q >= HAL_NUM_TX_QUEUES) {
164 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
165 		    __func__, q);
166 		return AH_FALSE;
167 	}
168 	qi = &ahp->ah_txq[q];
169 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
170 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
171 		    __func__, q);
172 		return AH_FALSE;
173 	}
174 
175 	/*
176 	 * Ignore any non-data queue(s).
177 	 */
178 	if (qi->tqi_type != HAL_TX_QUEUE_DATA)
179 		return AH_TRUE;
180 
181 	/* Set turbo mode / base mode parameters on or off */
182 	if (IEEE80211_IS_CHAN_TURBO(chan)) {
183 		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);
184 		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);
185 		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);
186 		OS_REG_WRITE(ah, AR_IFS0,
187 			((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)
188 				<< AR_IFS0_DIFS_S)
189 			| INIT_SIFS_TURBO);
190 		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);
191 		OS_REG_WRITE(ah, AR_PHY(17),
192 			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);
193 		OS_REG_WRITE(ah, AR_PHY_FRCTL,
194 			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
195 			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
196 			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |
197 			0x2020 |
198 			AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);
199 	} else {
200 		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);
201 		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);
202 		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);
203 		OS_REG_WRITE(ah, AR_IFS0,
204 			((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)
205 				<< AR_IFS0_DIFS_S)
206 			| INIT_SIFS);
207 		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);
208 		OS_REG_WRITE(ah, AR_PHY(17),
209 			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);
210 		OS_REG_WRITE(ah, AR_PHY_FRCTL,
211 			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
212 			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
213 			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);
214 	}
215 
216 	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)
217 		cwMin = INIT_CWMIN;
218 	else
219 		cwMin = qi->tqi_cwmin;
220 
221 	/* Set cwmin and retry limit values */
222 	OS_REG_WRITE(ah, AR_RETRY_LMT,
223 		  (cwMin << AR_RETRY_LMT_CW_MIN_S)
224 		 | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)
225 		 | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)
226 		 | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)
227 		 | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)
228 	);
229 
230 	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
231 		ahp->ah_txOkInterruptMask |= 1 << q;
232 	else
233 		ahp->ah_txOkInterruptMask &= ~(1 << q);
234 	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
235 		ahp->ah_txErrInterruptMask |= 1 << q;
236 	else
237 		ahp->ah_txErrInterruptMask &= ~(1 << q);
238 	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
239 		ahp->ah_txDescInterruptMask |= 1 << q;
240 	else
241 		ahp->ah_txDescInterruptMask &= ~(1 << q);
242 	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
243 		ahp->ah_txEolInterruptMask |= 1 << q;
244 	else
245 		ahp->ah_txEolInterruptMask &= ~(1 << q);
246 	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
247 		ahp->ah_txUrnInterruptMask |= 1 << q;
248 	else
249 		ahp->ah_txUrnInterruptMask &= ~(1 << q);
250 
251 	return AH_TRUE;
252 }
253 
254 /*
255  * Get the TXDP for the "main" data queue.  Needs to be extended
256  * for multiple Q functionality
257  */
258 uint32_t
259 ar5210GetTxDP(struct ath_hal *ah, u_int q)
260 {
261 	struct ath_hal_5210 *ahp = AH5210(ah);
262 	HAL_TX_QUEUE_INFO *qi;
263 
264 	HALASSERT(q < HAL_NUM_TX_QUEUES);
265 
266 	qi = &ahp->ah_txq[q];
267 	switch (qi->tqi_type) {
268 	case HAL_TX_QUEUE_DATA:
269 		return OS_REG_READ(ah, AR_TXDP0);
270 	case HAL_TX_QUEUE_INACTIVE:
271 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
272 		    __func__, q);
273 		/* fall thru... */
274 	default:
275 		break;
276 	}
277 	return 0xffffffff;
278 }
279 
280 /*
281  * Set the TxDP for the "main" data queue.
282  */
283 HAL_BOOL
284 ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
285 {
286 	struct ath_hal_5210 *ahp = AH5210(ah);
287 	HAL_TX_QUEUE_INFO *qi;
288 
289 	HALASSERT(q < HAL_NUM_TX_QUEUES);
290 
291 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n",
292 	    __func__, q, txdp);
293 	qi = &ahp->ah_txq[q];
294 	switch (qi->tqi_type) {
295 	case HAL_TX_QUEUE_DATA:
296 #ifdef AH_DEBUG
297 		/*
298 		 * Make sure that TXE is deasserted before setting the
299 		 * TXDP.  If TXE is still asserted, setting TXDP will
300 		 * have no effect.
301 		 */
302 		if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0)
303 			ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n",
304 				__func__, OS_REG_READ(ah, AR_CR));
305 #endif
306 		OS_REG_WRITE(ah, AR_TXDP0, txdp);
307 		break;
308 	case HAL_TX_QUEUE_BEACON:
309 	case HAL_TX_QUEUE_CAB:
310 		OS_REG_WRITE(ah, AR_TXDP1, txdp);
311 		break;
312 	case HAL_TX_QUEUE_INACTIVE:
313 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
314 		    __func__, q);
315 		/* fall thru... */
316 	default:
317 		return AH_FALSE;
318 	}
319 	return AH_TRUE;
320 }
321 
322 /*
323  * Update Tx FIFO trigger level.
324  *
325  * Set bIncTrigLevel to TRUE to increase the trigger level.
326  * Set bIncTrigLevel to FALSE to decrease the trigger level.
327  *
328  * Returns TRUE if the trigger level was updated
329  */
330 HAL_BOOL
331 ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
332 {
333 	uint32_t curTrigLevel;
334 	HAL_INT ints = ar5210GetInterrupts(ah);
335 
336 	/*
337 	 * Disable chip interrupts. This is because halUpdateTxTrigLevel
338 	 * is called from both ISR and non-ISR contexts.
339 	 */
340 	(void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
341 	curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV);
342 	if (bIncTrigLevel){
343 		/* increase the trigger level */
344 		curTrigLevel = curTrigLevel +
345 			((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
346 	} else {
347 		/* decrease the trigger level if not already at the minimum */
348 		if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
349 			/* decrease the trigger level */
350 			curTrigLevel--;
351 		} else {
352 			/* no update to the trigger level */
353 			/* re-enable chip interrupts */
354 			ar5210SetInterrupts(ah, ints);
355 			return AH_FALSE;
356 		}
357 	}
358 	/* Update the trigger level */
359 	OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel);
360 	/* re-enable chip interrupts */
361 	ar5210SetInterrupts(ah, ints);
362 	return AH_TRUE;
363 }
364 
365 /*
366  * Set Transmit Enable bits for the specified queues.
367  */
368 HAL_BOOL
369 ar5210StartTxDma(struct ath_hal *ah, u_int q)
370 {
371 	struct ath_hal_5210 *ahp = AH5210(ah);
372 	HAL_TX_QUEUE_INFO *qi;
373 
374 	HALASSERT(q < HAL_NUM_TX_QUEUES);
375 
376 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
377 	qi = &ahp->ah_txq[q];
378 	switch (qi->tqi_type) {
379 	case HAL_TX_QUEUE_DATA:
380 		OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0);
381 		break;
382 	case HAL_TX_QUEUE_CAB:
383 		OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1);	/* enable altq xmit */
384 		OS_REG_WRITE(ah, AR_BCR,
385 			AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV);
386 		break;
387 	case HAL_TX_QUEUE_BEACON:
388 		/* XXX add CR_BCR_BCMD if IBSS mode */
389 		OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE);
390 		break;
391 	case HAL_TX_QUEUE_INACTIVE:
392 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
393 		    __func__, q);
394 		/* fal thru... */
395 	default:
396 		return AH_FALSE;
397 	}
398 	return AH_TRUE;
399 }
400 
401 uint32_t
402 ar5210NumTxPending(struct ath_hal *ah, u_int q)
403 {
404 	struct ath_hal_5210 *ahp = AH5210(ah);
405 	HAL_TX_QUEUE_INFO *qi;
406 	uint32_t v;
407 
408 	HALASSERT(q < HAL_NUM_TX_QUEUES);
409 
410 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
411 	qi = &ahp->ah_txq[q];
412 	switch (qi->tqi_type) {
413 	case HAL_TX_QUEUE_DATA:
414 		v = OS_REG_READ(ah, AR_CFG);
415 		return MS(v, AR_CFG_TXCNT);
416 	case HAL_TX_QUEUE_INACTIVE:
417 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
418 		    __func__, q);
419 		/* fall thru... */
420 	default:
421 		break;
422 	}
423 	return 0;
424 }
425 
426 /*
427  * Stop transmit on the specified queue
428  */
429 HAL_BOOL
430 ar5210StopTxDma(struct ath_hal *ah, u_int q)
431 {
432 	struct ath_hal_5210 *ahp = AH5210(ah);
433 	HAL_TX_QUEUE_INFO *qi;
434 
435 	HALASSERT(q < HAL_NUM_TX_QUEUES);
436 
437 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
438 	qi = &ahp->ah_txq[q];
439 	switch (qi->tqi_type) {
440 	case HAL_TX_QUEUE_DATA: {
441 		int i;
442 		OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0);
443 		for (i = 0; i < 1000; i++) {
444 			if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0)
445 				break;
446 			OS_DELAY(10);
447 		}
448 		OS_REG_WRITE(ah, AR_CR, 0);
449 		return (i < 1000);
450 	}
451 	case HAL_TX_QUEUE_BEACON:
452 		return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0);
453 	case HAL_TX_QUEUE_INACTIVE:
454 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
455 		    __func__, q);
456 		/* fall thru... */
457 	default:
458 		break;
459 	}
460 	return AH_FALSE;
461 }
462 
463 /*
464  * Descriptor Access Functions
465  */
466 
467 #define	VALID_PKT_TYPES \
468 	((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
469 	 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
470 	 (1<<HAL_PKT_TYPE_BEACON))
471 #define	isValidPktType(_t)	((1<<(_t)) & VALID_PKT_TYPES)
472 #define	VALID_TX_RATES \
473 	((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
474 	 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
475 	 (1<<0x1d)|(1<<0x18)|(1<<0x1c))
476 #define	isValidTxRate(_r)	((1<<(_r)) & VALID_TX_RATES)
477 
478 HAL_BOOL
479 ar5210SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
480 	u_int pktLen,
481 	u_int hdrLen,
482 	HAL_PKT_TYPE type,
483 	u_int txPower,
484 	u_int txRate0, u_int txTries0,
485 	u_int keyIx,
486 	u_int antMode,
487 	u_int flags,
488 	u_int rtsctsRate,
489 	u_int rtsctsDuration,
490         u_int compicvLen,
491 	u_int compivLen,
492 	u_int comp)
493 {
494 	struct ar5210_desc *ads = AR5210DESC(ds);
495 	uint32_t frtype;
496 
497 	(void) txPower;
498 	(void) rtsctsDuration;
499 
500 	HALASSERT(txTries0 != 0);
501 	HALASSERT(isValidPktType(type));
502 	HALASSERT(isValidTxRate(txRate0));
503 
504 	if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP)
505 		frtype = AR_Frm_NoDelay;
506 	else
507 		frtype = type << 26;
508 	ads->ds_ctl0 = (pktLen & AR_FrameLen)
509 		     | (txRate0 << AR_XmitRate_S)
510 		     | ((hdrLen << AR_HdrLen_S) & AR_HdrLen)
511 		     | frtype
512 		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
513 		     | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
514 		     | (antMode ? AR_AntModeXmit : 0)
515 		     ;
516 	if (keyIx != HAL_TXKEYIX_INVALID) {
517 		ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
518 		ads->ds_ctl0 |= AR_EncryptKeyValid;
519 	} else
520 		ads->ds_ctl1 = 0;
521 	if (flags & HAL_TXDESC_RTSENA) {
522 		ads->ds_ctl0 |= AR_RTSCTSEnable;
523 		ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S)
524 		    & AR_RTSDuration;
525 	}
526 	return AH_TRUE;
527 }
528 
529 HAL_BOOL
530 ar5210SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
531 	u_int txRate1, u_int txTries1,
532 	u_int txRate2, u_int txTries2,
533 	u_int txRate3, u_int txTries3)
534 {
535 	(void) ah; (void) ds;
536 	(void) txRate1; (void) txTries1;
537 	(void) txRate2; (void) txTries2;
538 	(void) txRate3; (void) txTries3;
539 	return AH_FALSE;
540 }
541 
542 void
543 ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
544 {
545 	struct ar5210_desc *ads = AR5210DESC(ds);
546 
547 	ads->ds_ctl0 |= AR_TxInterReq;
548 }
549 
550 HAL_BOOL
551 ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
552 	HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
553 	u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
554 	const struct ath_desc *ds0)
555 {
556 	struct ar5210_desc *ads = AR5210DESC(ds);
557 	uint32_t segLen = segLenList[0];
558 
559 	HALASSERT((segLen &~ AR_BufLen) == 0);
560 
561 	ds->ds_data = bufAddrList[0];
562 
563 	if (firstSeg) {
564 		/*
565 		 * First descriptor, don't clobber xmit control data
566 		 * setup by ar5210SetupTxDesc.
567 		 */
568 		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
569 	} else if (lastSeg) {		/* !firstSeg && lastSeg */
570 		/*
571 		 * Last descriptor in a multi-descriptor frame,
572 		 * copy the transmit parameters from the first
573 		 * frame for processing on completion.
574 		 */
575 		ads->ds_ctl0 = AR5210DESC_CONST(ds0)->ds_ctl0;
576 		ads->ds_ctl1 = segLen;
577 	} else {			/* !firstSeg && !lastSeg */
578 		/*
579 		 * Intermediate descriptor in a multi-descriptor frame.
580 		 */
581 		ads->ds_ctl0 = 0;
582 		ads->ds_ctl1 = segLen | AR_More;
583 	}
584 	ads->ds_status0 = ads->ds_status1 = 0;
585 	return AH_TRUE;
586 }
587 
588 /*
589  * Processing of HW TX descriptor.
590  */
591 HAL_STATUS
592 ar5210ProcTxDesc(struct ath_hal *ah,
593 	struct ath_desc *ds, struct ath_tx_status *ts)
594 {
595 	struct ar5210_desc *ads = AR5210DESC(ds);
596 
597 	if ((ads->ds_status1 & AR_Done) == 0)
598 		return HAL_EINPROGRESS;
599 
600 	/* Update software copies of the HW status */
601 	ts->ts_seqnum = ads->ds_status1 & AR_SeqNum;
602 	ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
603 	ts->ts_status = 0;
604 	if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
605 		if (ads->ds_status0 & AR_ExcessiveRetries)
606 			ts->ts_status |= HAL_TXERR_XRETRY;
607 		if (ads->ds_status0 & AR_Filtered)
608 			ts->ts_status |= HAL_TXERR_FILT;
609 		if (ads->ds_status0  & AR_FIFOUnderrun)
610 			ts->ts_status |= HAL_TXERR_FIFO;
611 	}
612 	ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
613 	ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
614 	ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
615 	ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
616 	ts->ts_antenna = 0;		/* NB: don't know */
617 	ts->ts_finaltsi = 0;
618 
619 	return HAL_OK;
620 }
621 
622 /*
623  * Determine which tx queues need interrupt servicing.
624  * STUB.
625  */
626 void
627 ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
628 {
629 	return;
630 }
631 
632 /*
633  * Retrieve the rate table from the given TX completion descriptor
634  */
635 HAL_BOOL
636 ar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
637 {
638 	return AH_FALSE;
639 }
640 
641 /*
642  * Set the TX descriptor link pointer
643  */
644 void
645 ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
646 {
647 	struct ar5210_desc *ads = AR5210DESC(ds);
648 
649 	ads->ds_link = link;
650 }
651 
652 /*
653  * Get the TX descriptor link pointer
654  */
655 void
656 ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
657 {
658 	struct ar5210_desc *ads = AR5210DESC(ds);
659 
660 	*link = ads->ds_link;
661 }
662 
663 /*
664  * Get a pointer to the TX descriptor link pointer
665  */
666 void
667 ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
668 {
669 	struct ar5210_desc *ads = AR5210DESC(ds);
670 
671 	*linkptr = &ads->ds_link;
672 }
673