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