xref: /freebsd/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c (revision 95ee2897)
16e778a7eSPedro F. Giffuni /*-
26e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
36e778a7eSPedro F. Giffuni  *
459efa8b5SSam Leffler  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
514779705SSam Leffler  * Copyright (c) 2002-2004 Atheros Communications, Inc.
614779705SSam Leffler  *
714779705SSam Leffler  * Permission to use, copy, modify, and/or distribute this software for any
814779705SSam Leffler  * purpose with or without fee is hereby granted, provided that the above
914779705SSam Leffler  * copyright notice and this permission notice appear in all copies.
1014779705SSam Leffler  *
1114779705SSam Leffler  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1214779705SSam Leffler  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1314779705SSam Leffler  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1414779705SSam Leffler  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1514779705SSam Leffler  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1614779705SSam Leffler  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1714779705SSam Leffler  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1814779705SSam Leffler  */
1914779705SSam Leffler #include "opt_ah.h"
2014779705SSam Leffler 
2114779705SSam Leffler #include "ah.h"
2214779705SSam Leffler #include "ah_internal.h"
2314779705SSam Leffler #include "ah_desc.h"
2414779705SSam Leffler 
2514779705SSam Leffler #include "ar5210/ar5210.h"
2614779705SSam Leffler #include "ar5210/ar5210reg.h"
2714779705SSam Leffler #include "ar5210/ar5210phy.h"
2814779705SSam Leffler #include "ar5210/ar5210desc.h"
2914779705SSam Leffler 
3014779705SSam Leffler /*
3114779705SSam Leffler  * Set the properties of the tx queue with the parameters
3214779705SSam Leffler  * from qInfo.  The queue must previously have been setup
3314779705SSam Leffler  * with a call to ar5210SetupTxQueue.
3414779705SSam Leffler  */
3514779705SSam Leffler HAL_BOOL
ar5210SetTxQueueProps(struct ath_hal * ah,int q,const HAL_TXQ_INFO * qInfo)3614779705SSam Leffler ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
3714779705SSam Leffler {
3814779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
3914779705SSam Leffler 
4014779705SSam Leffler 	if (q >= HAL_NUM_TX_QUEUES) {
4114779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
4214779705SSam Leffler 		    __func__, q);
4314779705SSam Leffler 		return AH_FALSE;
4414779705SSam Leffler 	}
4514779705SSam Leffler 	return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
4614779705SSam Leffler }
4714779705SSam Leffler 
4814779705SSam Leffler /*
4914779705SSam Leffler  * Return the properties for the specified tx queue.
5014779705SSam Leffler  */
5114779705SSam Leffler HAL_BOOL
ar5210GetTxQueueProps(struct ath_hal * ah,int q,HAL_TXQ_INFO * qInfo)5214779705SSam Leffler ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
5314779705SSam Leffler {
5414779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
5514779705SSam Leffler 
5614779705SSam Leffler 	if (q >= HAL_NUM_TX_QUEUES) {
5714779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
5814779705SSam Leffler 		    __func__, q);
5914779705SSam Leffler 		return AH_FALSE;
6014779705SSam Leffler 	}
6114779705SSam Leffler 	return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
6214779705SSam Leffler }
6314779705SSam Leffler 
6414779705SSam Leffler /*
6514779705SSam Leffler  * Allocate and initialize a tx DCU/QCU combination.
6614779705SSam Leffler  */
6714779705SSam Leffler int
ar5210SetupTxQueue(struct ath_hal * ah,HAL_TX_QUEUE type,const HAL_TXQ_INFO * qInfo)6814779705SSam Leffler ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
6914779705SSam Leffler 	const HAL_TXQ_INFO *qInfo)
7014779705SSam Leffler {
7114779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
7214779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
7314779705SSam Leffler 	int q;
7414779705SSam Leffler 
7514779705SSam Leffler 	switch (type) {
7614779705SSam Leffler 	case HAL_TX_QUEUE_BEACON:
7714779705SSam Leffler 		q = 2;
7814779705SSam Leffler 		break;
7914779705SSam Leffler 	case HAL_TX_QUEUE_CAB:
8014779705SSam Leffler 		q = 1;
8114779705SSam Leffler 		break;
8214779705SSam Leffler 	case HAL_TX_QUEUE_DATA:
8314779705SSam Leffler 		q = 0;
8414779705SSam Leffler 		break;
8514779705SSam Leffler 	default:
8614779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
8714779705SSam Leffler 		    __func__, type);
8814779705SSam Leffler 		return -1;
8914779705SSam Leffler 	}
9014779705SSam Leffler 
9114779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
9214779705SSam Leffler 
9314779705SSam Leffler 	qi = &ahp->ah_txq[q];
9414779705SSam Leffler 	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
9514779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
9614779705SSam Leffler 		    __func__, q);
9714779705SSam Leffler 		return -1;
9814779705SSam Leffler 	}
9914779705SSam Leffler 	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
10014779705SSam Leffler 	qi->tqi_type = type;
10114779705SSam Leffler 	if (qInfo == AH_NULL) {
10214779705SSam Leffler 		/* by default enable OK+ERR+DESC+URN interrupts */
10314779705SSam Leffler 		qi->tqi_qflags =
10414779705SSam Leffler 			  HAL_TXQ_TXOKINT_ENABLE
10514779705SSam Leffler 			| HAL_TXQ_TXERRINT_ENABLE
10614779705SSam Leffler 			| HAL_TXQ_TXDESCINT_ENABLE
10714779705SSam Leffler 			| HAL_TXQ_TXURNINT_ENABLE
10814779705SSam Leffler 			;
10914779705SSam Leffler 		qi->tqi_aifs = INIT_AIFS;
11014779705SSam Leffler 		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
11114779705SSam Leffler 		qi->tqi_shretry = INIT_SH_RETRY;
11214779705SSam Leffler 		qi->tqi_lgretry = INIT_LG_RETRY;
11314779705SSam Leffler 	} else
11414779705SSam Leffler 		(void) ar5210SetTxQueueProps(ah, q, qInfo);
11514779705SSam Leffler 	/* NB: must be followed by ar5210ResetTxQueue */
11614779705SSam Leffler 	return q;
11714779705SSam Leffler }
11814779705SSam Leffler 
11914779705SSam Leffler /*
12014779705SSam Leffler  * Free a tx DCU/QCU combination.
12114779705SSam Leffler  */
12214779705SSam Leffler HAL_BOOL
ar5210ReleaseTxQueue(struct ath_hal * ah,u_int q)12314779705SSam Leffler ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q)
12414779705SSam Leffler {
12514779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
12614779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
12714779705SSam Leffler 
12814779705SSam Leffler 	if (q >= HAL_NUM_TX_QUEUES) {
12914779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
13014779705SSam Leffler 		    __func__, q);
13114779705SSam Leffler 		return AH_FALSE;
13214779705SSam Leffler 	}
13314779705SSam Leffler 	qi = &ahp->ah_txq[q];
13414779705SSam Leffler 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
13514779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
13614779705SSam Leffler 		    __func__, q);
13714779705SSam Leffler 		return AH_FALSE;
13814779705SSam Leffler 	}
13914779705SSam Leffler 
14014779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
14114779705SSam Leffler 
14214779705SSam Leffler 	qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
14314779705SSam Leffler 	ahp->ah_txOkInterruptMask &= ~(1 << q);
14414779705SSam Leffler 	ahp->ah_txErrInterruptMask &= ~(1 << q);
14514779705SSam Leffler 	ahp->ah_txDescInterruptMask &= ~(1 << q);
14614779705SSam Leffler 	ahp->ah_txEolInterruptMask &= ~(1 << q);
14714779705SSam Leffler 	ahp->ah_txUrnInterruptMask &= ~(1 << q);
14814779705SSam Leffler 
14914779705SSam Leffler 	return AH_TRUE;
15014779705SSam Leffler #undef N
15114779705SSam Leffler }
15214779705SSam Leffler 
15314779705SSam Leffler HAL_BOOL
ar5210ResetTxQueue(struct ath_hal * ah,u_int q)15414779705SSam Leffler ar5210ResetTxQueue(struct ath_hal *ah, u_int q)
15514779705SSam Leffler {
15614779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
15759efa8b5SSam Leffler 	const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;
15814779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
15914779705SSam Leffler 	uint32_t cwMin;
16014779705SSam Leffler 
16114779705SSam Leffler 	if (q >= HAL_NUM_TX_QUEUES) {
16214779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
16314779705SSam Leffler 		    __func__, q);
16414779705SSam Leffler 		return AH_FALSE;
16514779705SSam Leffler 	}
16614779705SSam Leffler 	qi = &ahp->ah_txq[q];
16714779705SSam Leffler 	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
16814779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
16914779705SSam Leffler 		    __func__, q);
17014779705SSam Leffler 		return AH_FALSE;
17114779705SSam Leffler 	}
17214779705SSam Leffler 
17314779705SSam Leffler 	/*
17414779705SSam Leffler 	 * Ignore any non-data queue(s).
17514779705SSam Leffler 	 */
17614779705SSam Leffler 	if (qi->tqi_type != HAL_TX_QUEUE_DATA)
17714779705SSam Leffler 		return AH_TRUE;
17814779705SSam Leffler 
17914779705SSam Leffler 	/* Set turbo mode / base mode parameters on or off */
18059efa8b5SSam Leffler 	if (IEEE80211_IS_CHAN_TURBO(chan)) {
18114779705SSam Leffler 		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);
18214779705SSam Leffler 		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);
18314779705SSam Leffler 		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);
18414779705SSam Leffler 		OS_REG_WRITE(ah, AR_IFS0,
18514779705SSam Leffler 			((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)
18614779705SSam Leffler 				<< AR_IFS0_DIFS_S)
18714779705SSam Leffler 			| INIT_SIFS_TURBO);
18814779705SSam Leffler 		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);
18914779705SSam Leffler 		OS_REG_WRITE(ah, AR_PHY(17),
19014779705SSam Leffler 			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);
19114779705SSam Leffler 		OS_REG_WRITE(ah, AR_PHY_FRCTL,
19214779705SSam Leffler 			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
19314779705SSam Leffler 			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
19414779705SSam Leffler 			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |
19514779705SSam Leffler 			0x2020 |
19614779705SSam Leffler 			AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);
19714779705SSam Leffler 	} else {
19814779705SSam Leffler 		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);
19914779705SSam Leffler 		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);
20014779705SSam Leffler 		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);
20114779705SSam Leffler 		OS_REG_WRITE(ah, AR_IFS0,
20214779705SSam Leffler 			((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)
20314779705SSam Leffler 				<< AR_IFS0_DIFS_S)
20414779705SSam Leffler 			| INIT_SIFS);
20514779705SSam Leffler 		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);
20614779705SSam Leffler 		OS_REG_WRITE(ah, AR_PHY(17),
20714779705SSam Leffler 			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);
20814779705SSam Leffler 		OS_REG_WRITE(ah, AR_PHY_FRCTL,
20914779705SSam Leffler 			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
21014779705SSam Leffler 			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
21114779705SSam Leffler 			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);
21214779705SSam Leffler 	}
21314779705SSam Leffler 
21414779705SSam Leffler 	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)
21514779705SSam Leffler 		cwMin = INIT_CWMIN;
21614779705SSam Leffler 	else
21714779705SSam Leffler 		cwMin = qi->tqi_cwmin;
21814779705SSam Leffler 
21914779705SSam Leffler 	/* Set cwmin and retry limit values */
22014779705SSam Leffler 	OS_REG_WRITE(ah, AR_RETRY_LMT,
22114779705SSam Leffler 		  (cwMin << AR_RETRY_LMT_CW_MIN_S)
22214779705SSam Leffler 		 | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)
22314779705SSam Leffler 		 | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)
22414779705SSam Leffler 		 | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)
22514779705SSam Leffler 		 | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)
22614779705SSam Leffler 	);
22714779705SSam Leffler 
22814779705SSam Leffler 	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
22914779705SSam Leffler 		ahp->ah_txOkInterruptMask |= 1 << q;
23014779705SSam Leffler 	else
23114779705SSam Leffler 		ahp->ah_txOkInterruptMask &= ~(1 << q);
23214779705SSam Leffler 	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
23314779705SSam Leffler 		ahp->ah_txErrInterruptMask |= 1 << q;
23414779705SSam Leffler 	else
23514779705SSam Leffler 		ahp->ah_txErrInterruptMask &= ~(1 << q);
23614779705SSam Leffler 	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
23714779705SSam Leffler 		ahp->ah_txDescInterruptMask |= 1 << q;
23814779705SSam Leffler 	else
23914779705SSam Leffler 		ahp->ah_txDescInterruptMask &= ~(1 << q);
24014779705SSam Leffler 	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
24114779705SSam Leffler 		ahp->ah_txEolInterruptMask |= 1 << q;
24214779705SSam Leffler 	else
24314779705SSam Leffler 		ahp->ah_txEolInterruptMask &= ~(1 << q);
24414779705SSam Leffler 	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
24514779705SSam Leffler 		ahp->ah_txUrnInterruptMask |= 1 << q;
24614779705SSam Leffler 	else
24714779705SSam Leffler 		ahp->ah_txUrnInterruptMask &= ~(1 << q);
24814779705SSam Leffler 
24914779705SSam Leffler 	return AH_TRUE;
25014779705SSam Leffler }
25114779705SSam Leffler 
25214779705SSam Leffler /*
25314779705SSam Leffler  * Get the TXDP for the "main" data queue.  Needs to be extended
25414779705SSam Leffler  * for multiple Q functionality
25514779705SSam Leffler  */
25614779705SSam Leffler uint32_t
ar5210GetTxDP(struct ath_hal * ah,u_int q)25714779705SSam Leffler ar5210GetTxDP(struct ath_hal *ah, u_int q)
25814779705SSam Leffler {
25914779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
26014779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
26114779705SSam Leffler 
26214779705SSam Leffler 	HALASSERT(q < HAL_NUM_TX_QUEUES);
26314779705SSam Leffler 
26414779705SSam Leffler 	qi = &ahp->ah_txq[q];
26514779705SSam Leffler 	switch (qi->tqi_type) {
26614779705SSam Leffler 	case HAL_TX_QUEUE_DATA:
26714779705SSam Leffler 		return OS_REG_READ(ah, AR_TXDP0);
26814779705SSam Leffler 	case HAL_TX_QUEUE_INACTIVE:
26914779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
27014779705SSam Leffler 		    __func__, q);
27114779705SSam Leffler 		/* fall thru... */
27214779705SSam Leffler 	default:
27314779705SSam Leffler 		break;
27414779705SSam Leffler 	}
27514779705SSam Leffler 	return 0xffffffff;
27614779705SSam Leffler }
27714779705SSam Leffler 
27814779705SSam Leffler /*
27914779705SSam Leffler  * Set the TxDP for the "main" data queue.
28014779705SSam Leffler  */
28114779705SSam Leffler HAL_BOOL
ar5210SetTxDP(struct ath_hal * ah,u_int q,uint32_t txdp)28214779705SSam Leffler ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
28314779705SSam Leffler {
28414779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
28514779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
28614779705SSam Leffler 
28714779705SSam Leffler 	HALASSERT(q < HAL_NUM_TX_QUEUES);
28814779705SSam Leffler 
28914779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n",
29014779705SSam Leffler 	    __func__, q, txdp);
29114779705SSam Leffler 	qi = &ahp->ah_txq[q];
29214779705SSam Leffler 	switch (qi->tqi_type) {
29314779705SSam Leffler 	case HAL_TX_QUEUE_DATA:
29414779705SSam Leffler #ifdef AH_DEBUG
29514779705SSam Leffler 		/*
29614779705SSam Leffler 		 * Make sure that TXE is deasserted before setting the
29714779705SSam Leffler 		 * TXDP.  If TXE is still asserted, setting TXDP will
29814779705SSam Leffler 		 * have no effect.
29914779705SSam Leffler 		 */
30014779705SSam Leffler 		if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0)
30114779705SSam Leffler 			ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n",
30214779705SSam Leffler 				__func__, OS_REG_READ(ah, AR_CR));
30314779705SSam Leffler #endif
30414779705SSam Leffler 		OS_REG_WRITE(ah, AR_TXDP0, txdp);
30514779705SSam Leffler 		break;
30614779705SSam Leffler 	case HAL_TX_QUEUE_BEACON:
30714779705SSam Leffler 	case HAL_TX_QUEUE_CAB:
30814779705SSam Leffler 		OS_REG_WRITE(ah, AR_TXDP1, txdp);
30914779705SSam Leffler 		break;
31014779705SSam Leffler 	case HAL_TX_QUEUE_INACTIVE:
31114779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
31214779705SSam Leffler 		    __func__, q);
31314779705SSam Leffler 		/* fall thru... */
31414779705SSam Leffler 	default:
31514779705SSam Leffler 		return AH_FALSE;
31614779705SSam Leffler 	}
31714779705SSam Leffler 	return AH_TRUE;
31814779705SSam Leffler }
31914779705SSam Leffler 
32014779705SSam Leffler /*
32114779705SSam Leffler  * Update Tx FIFO trigger level.
32214779705SSam Leffler  *
32314779705SSam Leffler  * Set bIncTrigLevel to TRUE to increase the trigger level.
32414779705SSam Leffler  * Set bIncTrigLevel to FALSE to decrease the trigger level.
32514779705SSam Leffler  *
32614779705SSam Leffler  * Returns TRUE if the trigger level was updated
32714779705SSam Leffler  */
32814779705SSam Leffler HAL_BOOL
ar5210UpdateTxTrigLevel(struct ath_hal * ah,HAL_BOOL bIncTrigLevel)32914779705SSam Leffler ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
33014779705SSam Leffler {
33114779705SSam Leffler 	uint32_t curTrigLevel;
33214779705SSam Leffler 	HAL_INT ints = ar5210GetInterrupts(ah);
33314779705SSam Leffler 
33414779705SSam Leffler 	/*
33514779705SSam Leffler 	 * Disable chip interrupts. This is because halUpdateTxTrigLevel
33614779705SSam Leffler 	 * is called from both ISR and non-ISR contexts.
33714779705SSam Leffler 	 */
33814779705SSam Leffler 	(void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
33914779705SSam Leffler 	curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV);
34014779705SSam Leffler 	if (bIncTrigLevel){
34114779705SSam Leffler 		/* increase the trigger level */
34214779705SSam Leffler 		curTrigLevel = curTrigLevel +
34314779705SSam Leffler 			((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
34414779705SSam Leffler 	} else {
34514779705SSam Leffler 		/* decrease the trigger level if not already at the minimum */
34614779705SSam Leffler 		if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
34714779705SSam Leffler 			/* decrease the trigger level */
34814779705SSam Leffler 			curTrigLevel--;
34914779705SSam Leffler 		} else {
35014779705SSam Leffler 			/* no update to the trigger level */
35114779705SSam Leffler 			/* re-enable chip interrupts */
35214779705SSam Leffler 			ar5210SetInterrupts(ah, ints);
35314779705SSam Leffler 			return AH_FALSE;
35414779705SSam Leffler 		}
35514779705SSam Leffler 	}
35614779705SSam Leffler 	/* Update the trigger level */
35714779705SSam Leffler 	OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel);
35814779705SSam Leffler 	/* re-enable chip interrupts */
35914779705SSam Leffler 	ar5210SetInterrupts(ah, ints);
36014779705SSam Leffler 	return AH_TRUE;
36114779705SSam Leffler }
36214779705SSam Leffler 
36314779705SSam Leffler /*
36414779705SSam Leffler  * Set Transmit Enable bits for the specified queues.
36514779705SSam Leffler  */
36614779705SSam Leffler HAL_BOOL
ar5210StartTxDma(struct ath_hal * ah,u_int q)36714779705SSam Leffler ar5210StartTxDma(struct ath_hal *ah, u_int q)
36814779705SSam Leffler {
36914779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
37014779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
37114779705SSam Leffler 
37214779705SSam Leffler 	HALASSERT(q < HAL_NUM_TX_QUEUES);
37314779705SSam Leffler 
37414779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
37514779705SSam Leffler 	qi = &ahp->ah_txq[q];
37614779705SSam Leffler 	switch (qi->tqi_type) {
37714779705SSam Leffler 	case HAL_TX_QUEUE_DATA:
37814779705SSam Leffler 		OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0);
37914779705SSam Leffler 		break;
38014779705SSam Leffler 	case HAL_TX_QUEUE_CAB:
38114779705SSam Leffler 		OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1);	/* enable altq xmit */
38214779705SSam Leffler 		OS_REG_WRITE(ah, AR_BCR,
38314779705SSam Leffler 			AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV);
38414779705SSam Leffler 		break;
38514779705SSam Leffler 	case HAL_TX_QUEUE_BEACON:
38614779705SSam Leffler 		/* XXX add CR_BCR_BCMD if IBSS mode */
38714779705SSam Leffler 		OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE);
38814779705SSam Leffler 		break;
38914779705SSam Leffler 	case HAL_TX_QUEUE_INACTIVE:
39014779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
39114779705SSam Leffler 		    __func__, q);
39214779705SSam Leffler 		/* fal thru... */
39314779705SSam Leffler 	default:
39414779705SSam Leffler 		return AH_FALSE;
39514779705SSam Leffler 	}
39614779705SSam Leffler 	return AH_TRUE;
39714779705SSam Leffler }
39814779705SSam Leffler 
39914779705SSam Leffler uint32_t
ar5210NumTxPending(struct ath_hal * ah,u_int q)40014779705SSam Leffler ar5210NumTxPending(struct ath_hal *ah, u_int q)
40114779705SSam Leffler {
40214779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
40314779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
40414779705SSam Leffler 	uint32_t v;
40514779705SSam Leffler 
40614779705SSam Leffler 	HALASSERT(q < HAL_NUM_TX_QUEUES);
40714779705SSam Leffler 
40814779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
40914779705SSam Leffler 	qi = &ahp->ah_txq[q];
41014779705SSam Leffler 	switch (qi->tqi_type) {
41114779705SSam Leffler 	case HAL_TX_QUEUE_DATA:
41214779705SSam Leffler 		v = OS_REG_READ(ah, AR_CFG);
41314779705SSam Leffler 		return MS(v, AR_CFG_TXCNT);
41414779705SSam Leffler 	case HAL_TX_QUEUE_INACTIVE:
41514779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
41614779705SSam Leffler 		    __func__, q);
41714779705SSam Leffler 		/* fall thru... */
41814779705SSam Leffler 	default:
41914779705SSam Leffler 		break;
42014779705SSam Leffler 	}
42114779705SSam Leffler 	return 0;
42214779705SSam Leffler }
42314779705SSam Leffler 
42414779705SSam Leffler /*
42514779705SSam Leffler  * Stop transmit on the specified queue
42614779705SSam Leffler  */
42714779705SSam Leffler HAL_BOOL
ar5210StopTxDma(struct ath_hal * ah,u_int q)42814779705SSam Leffler ar5210StopTxDma(struct ath_hal *ah, u_int q)
42914779705SSam Leffler {
43014779705SSam Leffler 	struct ath_hal_5210 *ahp = AH5210(ah);
43114779705SSam Leffler 	HAL_TX_QUEUE_INFO *qi;
43214779705SSam Leffler 
43314779705SSam Leffler 	HALASSERT(q < HAL_NUM_TX_QUEUES);
43414779705SSam Leffler 
43514779705SSam Leffler 	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
43614779705SSam Leffler 	qi = &ahp->ah_txq[q];
43714779705SSam Leffler 	switch (qi->tqi_type) {
43814779705SSam Leffler 	case HAL_TX_QUEUE_DATA: {
43914779705SSam Leffler 		int i;
44014779705SSam Leffler 		OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0);
44114779705SSam Leffler 		for (i = 0; i < 1000; i++) {
44214779705SSam Leffler 			if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0)
44314779705SSam Leffler 				break;
44414779705SSam Leffler 			OS_DELAY(10);
44514779705SSam Leffler 		}
44614779705SSam Leffler 		OS_REG_WRITE(ah, AR_CR, 0);
44714779705SSam Leffler 		return (i < 1000);
44814779705SSam Leffler 	}
44914779705SSam Leffler 	case HAL_TX_QUEUE_BEACON:
45014779705SSam Leffler 		return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0);
45114779705SSam Leffler 	case HAL_TX_QUEUE_INACTIVE:
45214779705SSam Leffler 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
45314779705SSam Leffler 		    __func__, q);
45414779705SSam Leffler 		/* fall thru... */
45514779705SSam Leffler 	default:
45614779705SSam Leffler 		break;
45714779705SSam Leffler 	}
45814779705SSam Leffler 	return AH_FALSE;
45914779705SSam Leffler }
46014779705SSam Leffler 
46114779705SSam Leffler /*
46214779705SSam Leffler  * Descriptor Access Functions
46314779705SSam Leffler  */
46414779705SSam Leffler 
46514779705SSam Leffler #define	VALID_PKT_TYPES \
46614779705SSam Leffler 	((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\
46714779705SSam Leffler 	 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\
46814779705SSam Leffler 	 (1<<HAL_PKT_TYPE_BEACON))
46914779705SSam Leffler #define	isValidPktType(_t)	((1<<(_t)) & VALID_PKT_TYPES)
47014779705SSam Leffler #define	VALID_TX_RATES \
47114779705SSam Leffler 	((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\
47214779705SSam Leffler 	 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\
47314779705SSam Leffler 	 (1<<0x1d)|(1<<0x18)|(1<<0x1c))
47414779705SSam Leffler #define	isValidTxRate(_r)	((1<<(_r)) & VALID_TX_RATES)
47514779705SSam Leffler 
47614779705SSam Leffler HAL_BOOL
ar5210SetupTxDesc(struct ath_hal * ah,struct ath_desc * ds,u_int pktLen,u_int hdrLen,HAL_PKT_TYPE type,u_int txPower,u_int txRate0,u_int txTries0,u_int keyIx,u_int antMode,u_int flags,u_int rtsctsRate,u_int rtsctsDuration,u_int compicvLen,u_int compivLen,u_int comp)47714779705SSam Leffler ar5210SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
47814779705SSam Leffler 	u_int pktLen,
47914779705SSam Leffler 	u_int hdrLen,
48014779705SSam Leffler 	HAL_PKT_TYPE type,
48114779705SSam Leffler 	u_int txPower,
48214779705SSam Leffler 	u_int txRate0, u_int txTries0,
48314779705SSam Leffler 	u_int keyIx,
48414779705SSam Leffler 	u_int antMode,
48514779705SSam Leffler 	u_int flags,
48614779705SSam Leffler 	u_int rtsctsRate,
48714779705SSam Leffler 	u_int rtsctsDuration,
48814779705SSam Leffler         u_int compicvLen,
48914779705SSam Leffler 	u_int compivLen,
49014779705SSam Leffler 	u_int comp)
49114779705SSam Leffler {
49214779705SSam Leffler 	struct ar5210_desc *ads = AR5210DESC(ds);
49314779705SSam Leffler 	uint32_t frtype;
49414779705SSam Leffler 
49514779705SSam Leffler 	(void) txPower;
49614779705SSam Leffler 	(void) rtsctsDuration;
49714779705SSam Leffler 
49814779705SSam Leffler 	HALASSERT(txTries0 != 0);
49914779705SSam Leffler 	HALASSERT(isValidPktType(type));
50014779705SSam Leffler 	HALASSERT(isValidTxRate(txRate0));
50114779705SSam Leffler 
50214779705SSam Leffler 	if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP)
50314779705SSam Leffler 		frtype = AR_Frm_NoDelay;
50414779705SSam Leffler 	else
50514779705SSam Leffler 		frtype = type << 26;
50614779705SSam Leffler 	ads->ds_ctl0 = (pktLen & AR_FrameLen)
50714779705SSam Leffler 		     | (txRate0 << AR_XmitRate_S)
50814779705SSam Leffler 		     | ((hdrLen << AR_HdrLen_S) & AR_HdrLen)
50914779705SSam Leffler 		     | frtype
51014779705SSam Leffler 		     | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)
51114779705SSam Leffler 		     | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)
51214779705SSam Leffler 		     | (antMode ? AR_AntModeXmit : 0)
51314779705SSam Leffler 		     ;
51414779705SSam Leffler 	if (keyIx != HAL_TXKEYIX_INVALID) {
51514779705SSam Leffler 		ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;
51614779705SSam Leffler 		ads->ds_ctl0 |= AR_EncryptKeyValid;
51714779705SSam Leffler 	} else
51814779705SSam Leffler 		ads->ds_ctl1 = 0;
51914779705SSam Leffler 	if (flags & HAL_TXDESC_RTSENA) {
52014779705SSam Leffler 		ads->ds_ctl0 |= AR_RTSCTSEnable;
521875d039eSAdrian Chadd 		ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S)
522875d039eSAdrian Chadd 		    & AR_RTSDuration;
52314779705SSam Leffler 	}
52414779705SSam Leffler 	return AH_TRUE;
52514779705SSam Leffler }
52614779705SSam Leffler 
52714779705SSam Leffler HAL_BOOL
ar5210SetupXTxDesc(struct ath_hal * ah,struct ath_desc * ds,u_int txRate1,u_int txTries1,u_int txRate2,u_int txTries2,u_int txRate3,u_int txTries3)52814779705SSam Leffler ar5210SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,
52914779705SSam Leffler 	u_int txRate1, u_int txTries1,
53014779705SSam Leffler 	u_int txRate2, u_int txTries2,
53114779705SSam Leffler 	u_int txRate3, u_int txTries3)
53214779705SSam Leffler {
53314779705SSam Leffler 	(void) ah; (void) ds;
53414779705SSam Leffler 	(void) txRate1; (void) txTries1;
53514779705SSam Leffler 	(void) txRate2; (void) txTries2;
53614779705SSam Leffler 	(void) txRate3; (void) txTries3;
53714779705SSam Leffler 	return AH_FALSE;
53814779705SSam Leffler }
53914779705SSam Leffler 
54014779705SSam Leffler void
ar5210IntrReqTxDesc(struct ath_hal * ah,struct ath_desc * ds)54114779705SSam Leffler ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)
54214779705SSam Leffler {
54314779705SSam Leffler 	struct ar5210_desc *ads = AR5210DESC(ds);
54414779705SSam Leffler 
54514779705SSam Leffler 	ads->ds_ctl0 |= AR_TxInterReq;
54614779705SSam Leffler }
54714779705SSam Leffler 
54814779705SSam Leffler HAL_BOOL
ar5210FillTxDesc(struct ath_hal * ah,struct ath_desc * ds,HAL_DMA_ADDR * bufAddrList,uint32_t * segLenList,u_int descId,u_int qcuId,HAL_BOOL firstSeg,HAL_BOOL lastSeg,const struct ath_desc * ds0)54914779705SSam Leffler ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,
55046634305SAdrian Chadd 	HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,
55146634305SAdrian Chadd 	u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,
55214779705SSam Leffler 	const struct ath_desc *ds0)
55314779705SSam Leffler {
55414779705SSam Leffler 	struct ar5210_desc *ads = AR5210DESC(ds);
55546634305SAdrian Chadd 	uint32_t segLen = segLenList[0];
55614779705SSam Leffler 
55714779705SSam Leffler 	HALASSERT((segLen &~ AR_BufLen) == 0);
55814779705SSam Leffler 
55946634305SAdrian Chadd 	ds->ds_data = bufAddrList[0];
56046634305SAdrian Chadd 
56114779705SSam Leffler 	if (firstSeg) {
56214779705SSam Leffler 		/*
56314779705SSam Leffler 		 * First descriptor, don't clobber xmit control data
56414779705SSam Leffler 		 * setup by ar5210SetupTxDesc.
56514779705SSam Leffler 		 */
56614779705SSam Leffler 		ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);
56714779705SSam Leffler 	} else if (lastSeg) {		/* !firstSeg && lastSeg */
56814779705SSam Leffler 		/*
56914779705SSam Leffler 		 * Last descriptor in a multi-descriptor frame,
57014779705SSam Leffler 		 * copy the transmit parameters from the first
57114779705SSam Leffler 		 * frame for processing on completion.
57214779705SSam Leffler 		 */
57314779705SSam Leffler 		ads->ds_ctl0 = AR5210DESC_CONST(ds0)->ds_ctl0;
57414779705SSam Leffler 		ads->ds_ctl1 = segLen;
57514779705SSam Leffler 	} else {			/* !firstSeg && !lastSeg */
57614779705SSam Leffler 		/*
57714779705SSam Leffler 		 * Intermediate descriptor in a multi-descriptor frame.
57814779705SSam Leffler 		 */
57914779705SSam Leffler 		ads->ds_ctl0 = 0;
58014779705SSam Leffler 		ads->ds_ctl1 = segLen | AR_More;
58114779705SSam Leffler 	}
58214779705SSam Leffler 	ads->ds_status0 = ads->ds_status1 = 0;
58314779705SSam Leffler 	return AH_TRUE;
58414779705SSam Leffler }
58514779705SSam Leffler 
58614779705SSam Leffler /*
58714779705SSam Leffler  * Processing of HW TX descriptor.
58814779705SSam Leffler  */
58914779705SSam Leffler HAL_STATUS
ar5210ProcTxDesc(struct ath_hal * ah,struct ath_desc * ds,struct ath_tx_status * ts)59014779705SSam Leffler ar5210ProcTxDesc(struct ath_hal *ah,
59114779705SSam Leffler 	struct ath_desc *ds, struct ath_tx_status *ts)
59214779705SSam Leffler {
59314779705SSam Leffler 	struct ar5210_desc *ads = AR5210DESC(ds);
59414779705SSam Leffler 
59514779705SSam Leffler 	if ((ads->ds_status1 & AR_Done) == 0)
59614779705SSam Leffler 		return HAL_EINPROGRESS;
59714779705SSam Leffler 
59814779705SSam Leffler 	/* Update software copies of the HW status */
59914779705SSam Leffler 	ts->ts_seqnum = ads->ds_status1 & AR_SeqNum;
60014779705SSam Leffler 	ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);
60114779705SSam Leffler 	ts->ts_status = 0;
60214779705SSam Leffler 	if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {
60314779705SSam Leffler 		if (ads->ds_status0 & AR_ExcessiveRetries)
60414779705SSam Leffler 			ts->ts_status |= HAL_TXERR_XRETRY;
60514779705SSam Leffler 		if (ads->ds_status0 & AR_Filtered)
60614779705SSam Leffler 			ts->ts_status |= HAL_TXERR_FILT;
60714779705SSam Leffler 		if (ads->ds_status0  & AR_FIFOUnderrun)
60814779705SSam Leffler 			ts->ts_status |= HAL_TXERR_FIFO;
60914779705SSam Leffler 	}
61014779705SSam Leffler 	ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);
61114779705SSam Leffler 	ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);
61214779705SSam Leffler 	ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);
61314779705SSam Leffler 	ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);
61414779705SSam Leffler 	ts->ts_antenna = 0;		/* NB: don't know */
61514779705SSam Leffler 	ts->ts_finaltsi = 0;
61614779705SSam Leffler 
61714779705SSam Leffler 	return HAL_OK;
61814779705SSam Leffler }
61914779705SSam Leffler 
62014779705SSam Leffler /*
62114779705SSam Leffler  * Determine which tx queues need interrupt servicing.
62214779705SSam Leffler  * STUB.
62314779705SSam Leffler  */
62414779705SSam Leffler void
ar5210GetTxIntrQueue(struct ath_hal * ah,uint32_t * txqs)62514779705SSam Leffler ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
62614779705SSam Leffler {
62714779705SSam Leffler 	return;
62814779705SSam Leffler }
6299ea46744SAdrian Chadd 
6309ea46744SAdrian Chadd /*
6319ea46744SAdrian Chadd  * Retrieve the rate table from the given TX completion descriptor
6329ea46744SAdrian Chadd  */
6339ea46744SAdrian Chadd HAL_BOOL
ar5210GetTxCompletionRates(struct ath_hal * ah,const struct ath_desc * ds0,int * rates,int * tries)6349ea46744SAdrian Chadd ar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)
6359ea46744SAdrian Chadd {
6369ea46744SAdrian Chadd 	return AH_FALSE;
6379ea46744SAdrian Chadd }
638ad3e6dcdSAdrian Chadd 
639ad3e6dcdSAdrian Chadd /*
640ad3e6dcdSAdrian Chadd  * Set the TX descriptor link pointer
641ad3e6dcdSAdrian Chadd  */
642ad3e6dcdSAdrian Chadd void
ar5210SetTxDescLink(struct ath_hal * ah,void * ds,uint32_t link)643ad3e6dcdSAdrian Chadd ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)
644ad3e6dcdSAdrian Chadd {
645ad3e6dcdSAdrian Chadd 	struct ar5210_desc *ads = AR5210DESC(ds);
646ad3e6dcdSAdrian Chadd 
647ad3e6dcdSAdrian Chadd 	ads->ds_link = link;
648ad3e6dcdSAdrian Chadd }
649ad3e6dcdSAdrian Chadd 
650ad3e6dcdSAdrian Chadd /*
651ad3e6dcdSAdrian Chadd  * Get the TX descriptor link pointer
652ad3e6dcdSAdrian Chadd  */
653ad3e6dcdSAdrian Chadd void
ar5210GetTxDescLink(struct ath_hal * ah,void * ds,uint32_t * link)654ad3e6dcdSAdrian Chadd ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)
655ad3e6dcdSAdrian Chadd {
656ad3e6dcdSAdrian Chadd 	struct ar5210_desc *ads = AR5210DESC(ds);
657ad3e6dcdSAdrian Chadd 
658ad3e6dcdSAdrian Chadd 	*link = ads->ds_link;
659ad3e6dcdSAdrian Chadd }
660ad3e6dcdSAdrian Chadd 
661ad3e6dcdSAdrian Chadd /*
662ad3e6dcdSAdrian Chadd  * Get a pointer to the TX descriptor link pointer
663ad3e6dcdSAdrian Chadd  */
664ad3e6dcdSAdrian Chadd void
ar5210GetTxDescLinkPtr(struct ath_hal * ah,void * ds,uint32_t ** linkptr)665ad3e6dcdSAdrian Chadd ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)
666ad3e6dcdSAdrian Chadd {
667ad3e6dcdSAdrian Chadd 	struct ar5210_desc *ads = AR5210DESC(ds);
668ad3e6dcdSAdrian Chadd 
669ad3e6dcdSAdrian Chadd 	*linkptr = &ads->ds_link;
670ad3e6dcdSAdrian Chadd }
671