ar5210_xmit.c revision 186333
12522Sraf/*
22522Sraf * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
32522Sraf * Copyright (c) 2002-2004 Atheros Communications, Inc.
42522Sraf *
52522Sraf * Permission to use, copy, modify, and/or distribute this software for any
62522Sraf * purpose with or without fee is hereby granted, provided that the above
72522Sraf * copyright notice and this permission notice appear in all copies.
82522Sraf *
92522Sraf * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
102522Sraf * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
112522Sraf * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
122522Sraf * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
132522Sraf * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
142522Sraf * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
152522Sraf * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
162522Sraf *
172522Sraf * $Id: ar5210_xmit.c,v 1.5 2008/11/10 04:08:02 sam Exp $
182522Sraf */
192522Sraf#include "opt_ah.h"
202522Sraf
212522Sraf#include "ah.h"
2212326Sgww@eng.sun.com#include "ah_internal.h"
232522Sraf#include "ah_desc.h"
242522Sraf
258744SAli.Bahrami@Sun.COM#include "ar5210/ar5210.h"
268744SAli.Bahrami@Sun.COM#include "ar5210/ar5210reg.h"
278744SAli.Bahrami@Sun.COM#include "ar5210/ar5210phy.h"
288744SAli.Bahrami@Sun.COM#include "ar5210/ar5210desc.h"
298744SAli.Bahrami@Sun.COM
308744SAli.Bahrami@Sun.COM/*
318744SAli.Bahrami@Sun.COM * Set the properties of the tx queue with the parameters
328744SAli.Bahrami@Sun.COM * from qInfo.  The queue must previously have been setup
338744SAli.Bahrami@Sun.COM * with a call to ar5210SetupTxQueue.
348744SAli.Bahrami@Sun.COM */
358744SAli.Bahrami@Sun.COMHAL_BOOL
368744SAli.Bahrami@Sun.COMar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)
378744SAli.Bahrami@Sun.COM{
388744SAli.Bahrami@Sun.COM	struct ath_hal_5210 *ahp = AH5210(ah);
3912692SAli.Bahrami@Oracle.COM
4012692SAli.Bahrami@Oracle.COM	if (q >= HAL_NUM_TX_QUEUES) {
4112692SAli.Bahrami@Oracle.COM		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
422522Sraf		    __func__, q);
432522Sraf		return AH_FALSE;
442522Sraf	}
452522Sraf	return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);
462522Sraf}
472522Sraf
482522Sraf/*
492522Sraf * Return the properties for the specified tx queue.
502522Sraf */
512522SrafHAL_BOOL
522522Srafar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)
532522Sraf{
542522Sraf	struct ath_hal_5210 *ahp = AH5210(ah);
552522Sraf
562522Sraf	if (q >= HAL_NUM_TX_QUEUES) {
5712692SAli.Bahrami@Oracle.COM		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
582522Sraf		    __func__, q);
592522Sraf		return AH_FALSE;
602522Sraf	}
612522Sraf	return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);
6212692SAli.Bahrami@Oracle.COM}
632522Sraf
642522Sraf/*
652522Sraf * Allocate and initialize a tx DCU/QCU combination.
662522Sraf */
672522Srafint
682522Srafar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,
692522Sraf	const HAL_TXQ_INFO *qInfo)
702522Sraf{
712522Sraf	struct ath_hal_5210 *ahp = AH5210(ah);
7212692SAli.Bahrami@Oracle.COM	HAL_TX_QUEUE_INFO *qi;
732522Sraf	int q;
742522Sraf
752522Sraf	switch (type) {
762522Sraf	case HAL_TX_QUEUE_BEACON:
772522Sraf		q = 2;
782522Sraf		break;
792522Sraf	case HAL_TX_QUEUE_CAB:
802522Sraf		q = 1;
812522Sraf		break;
822522Sraf	case HAL_TX_QUEUE_DATA:
832522Sraf		q = 0;
842522Sraf		break;
852522Sraf	default:
862522Sraf		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",
872522Sraf		    __func__, type);
882522Sraf		return -1;
892522Sraf	}
902522Sraf
912522Sraf	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);
922522Sraf
932522Sraf	qi = &ahp->ah_txq[q];
942522Sraf	if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {
952522Sraf		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",
962522Sraf		    __func__, q);
972522Sraf		return -1;
982522Sraf	}
992522Sraf	OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));
1002522Sraf	qi->tqi_type = type;
1012522Sraf	if (qInfo == AH_NULL) {
1022522Sraf		/* by default enable OK+ERR+DESC+URN interrupts */
1032522Sraf		qi->tqi_qflags =
1042522Sraf			  HAL_TXQ_TXOKINT_ENABLE
1052522Sraf			| HAL_TXQ_TXERRINT_ENABLE
1062522Sraf			| HAL_TXQ_TXDESCINT_ENABLE
1072522Sraf			| HAL_TXQ_TXURNINT_ENABLE
1082522Sraf			;
1092522Sraf		qi->tqi_aifs = INIT_AIFS;
1102522Sraf		qi->tqi_cwmin = HAL_TXQ_USEDEFAULT;	/* NB: do at reset */
1112522Sraf		qi->tqi_shretry = INIT_SH_RETRY;
1122522Sraf		qi->tqi_lgretry = INIT_LG_RETRY;
1132522Sraf	} else
1142522Sraf		(void) ar5210SetTxQueueProps(ah, q, qInfo);
1152522Sraf	/* NB: must be followed by ar5210ResetTxQueue */
11612692SAli.Bahrami@Oracle.COM	return q;
1172522Sraf}
1182522Sraf
1192522Sraf/*
1202522Sraf * Free a tx DCU/QCU combination.
1212522Sraf */
1222522SrafHAL_BOOL
1232522Srafar5210ReleaseTxQueue(struct ath_hal *ah, u_int q)
1242522Sraf{
1252522Sraf	struct ath_hal_5210 *ahp = AH5210(ah);
1262522Sraf	HAL_TX_QUEUE_INFO *qi;
1272522Sraf
1282522Sraf	if (q >= HAL_NUM_TX_QUEUES) {
1292522Sraf		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
1302522Sraf		    __func__, q);
1315012Sgww		return AH_FALSE;
1322522Sraf	}
1332522Sraf	qi = &ahp->ah_txq[q];
1342522Sraf	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
1352522Sraf		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
1362522Sraf		    __func__, q);
1372522Sraf		return AH_FALSE;
1382522Sraf	}
1392522Sraf
1402522Sraf	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);
1412522Sraf
1425344Stz204579	qi->tqi_type = HAL_TX_QUEUE_INACTIVE;
1432522Sraf	ahp->ah_txOkInterruptMask &= ~(1 << q);
1447753STon.Nguyen@Sun.COM	ahp->ah_txErrInterruptMask &= ~(1 << q);
1452522Sraf	ahp->ah_txDescInterruptMask &= ~(1 << q);
1462522Sraf	ahp->ah_txEolInterruptMask &= ~(1 << q);
1472522Sraf	ahp->ah_txUrnInterruptMask &= ~(1 << q);
1486680Sgww
1492522Sraf	return AH_TRUE;
1502522Sraf#undef N
1512522Sraf}
1522522Sraf
1532522SrafHAL_BOOL
1542522Srafar5210ResetTxQueue(struct ath_hal *ah, u_int q)
1552522Sraf{
1562522Sraf	struct ath_hal_5210 *ahp = AH5210(ah);
1572522Sraf	HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan;
1585777Stw21770	HAL_TX_QUEUE_INFO *qi;
1592522Sraf	uint32_t cwMin;
1607496Sgww@eng.sun.com
1612522Sraf	if (q >= HAL_NUM_TX_QUEUES) {
1622522Sraf		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",
1632522Sraf		    __func__, q);
1642522Sraf		return AH_FALSE;
1652522Sraf	}
1662522Sraf	qi = &ahp->ah_txq[q];
1672522Sraf	if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {
1682522Sraf		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
1692522Sraf		    __func__, q);
1702522Sraf		return AH_FALSE;
1712522Sraf	}
1722522Sraf
1732522Sraf	/*
1742522Sraf	 * Ignore any non-data queue(s).
1752522Sraf	 */
1762522Sraf	if (qi->tqi_type != HAL_TX_QUEUE_DATA)
1772522Sraf		return AH_TRUE;
1782522Sraf
1792522Sraf	/* Set turbo mode / base mode parameters on or off */
1802522Sraf	if (IS_CHAN_TURBO(chan)) {
1812522Sraf		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);
1822522Sraf		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);
1832522Sraf		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);
1842522Sraf		OS_REG_WRITE(ah, AR_IFS0,
1852522Sraf			((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)
1862522Sraf				<< AR_IFS0_DIFS_S)
1872522Sraf			| INIT_SIFS_TURBO);
1882522Sraf		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);
1892522Sraf		OS_REG_WRITE(ah, AR_PHY(17),
1902522Sraf			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);
1912522Sraf		OS_REG_WRITE(ah, AR_PHY_FRCTL,
1922522Sraf			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
1932522Sraf			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
1942522Sraf			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |
1952522Sraf			0x2020 |
1962522Sraf			AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);
1972522Sraf	} else {
1982522Sraf		OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);
1992522Sraf		OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);
2002522Sraf		OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);
2012522Sraf		OS_REG_WRITE(ah, AR_IFS0,
2022522Sraf			((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)
2032522Sraf				<< AR_IFS0_DIFS_S)
2042522Sraf			| INIT_SIFS);
2052522Sraf		OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);
2062522Sraf		OS_REG_WRITE(ah, AR_PHY(17),
2072522Sraf			(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);
2082522Sraf		OS_REG_WRITE(ah, AR_PHY_FRCTL,
2092522Sraf			AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |
2102522Sraf			AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |
2112522Sraf			AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);
2122522Sraf	}
2132522Sraf
2142522Sraf	if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)
2152522Sraf		cwMin = INIT_CWMIN;
2162522Sraf	else
2172522Sraf		cwMin = qi->tqi_cwmin;
2182522Sraf
2192522Sraf	/* Set cwmin and retry limit values */
2202522Sraf	OS_REG_WRITE(ah, AR_RETRY_LMT,
2212522Sraf		  (cwMin << AR_RETRY_LMT_CW_MIN_S)
2222522Sraf		 | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)
2232522Sraf		 | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)
2242522Sraf		 | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)
2252522Sraf		 | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)
2262522Sraf	);
2272522Sraf
2282522Sraf	if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)
2292522Sraf		ahp->ah_txOkInterruptMask |= 1 << q;
2302522Sraf	else
2312522Sraf		ahp->ah_txOkInterruptMask &= ~(1 << q);
2322522Sraf	if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)
2332522Sraf		ahp->ah_txErrInterruptMask |= 1 << q;
2342522Sraf	else
2352522Sraf		ahp->ah_txErrInterruptMask &= ~(1 << q);
2362522Sraf	if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)
2372522Sraf		ahp->ah_txDescInterruptMask |= 1 << q;
2382522Sraf	else
2392522Sraf		ahp->ah_txDescInterruptMask &= ~(1 << q);
2402522Sraf	if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)
2412522Sraf		ahp->ah_txEolInterruptMask |= 1 << q;
2422522Sraf	else
2432522Sraf		ahp->ah_txEolInterruptMask &= ~(1 << q);
2442522Sraf	if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)
2452522Sraf		ahp->ah_txUrnInterruptMask |= 1 << q;
2462522Sraf	else
2472522Sraf		ahp->ah_txUrnInterruptMask &= ~(1 << q);
2482522Sraf
2492522Sraf	return AH_TRUE;
2502522Sraf}
2512522Sraf
2522522Sraf/*
2532522Sraf * Get the TXDP for the "main" data queue.  Needs to be extended
2542522Sraf * for multiple Q functionality
2552522Sraf */
2562522Srafuint32_t
2572522Srafar5210GetTxDP(struct ath_hal *ah, u_int q)
2582522Sraf{
2592522Sraf	struct ath_hal_5210 *ahp = AH5210(ah);
2605537Sgww	HAL_TX_QUEUE_INFO *qi;
2612522Sraf
2622522Sraf	HALASSERT(q < HAL_NUM_TX_QUEUES);
2632522Sraf
2642522Sraf	qi = &ahp->ah_txq[q];
2652522Sraf	switch (qi->tqi_type) {
2662522Sraf	case HAL_TX_QUEUE_DATA:
2675012Sgww		return OS_REG_READ(ah, AR_TXDP0);
26811893Sgww@eng.sun.com	case HAL_TX_QUEUE_INACTIVE:
2692522Sraf		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",
2705012Sgww		    __func__, q);
2715012Sgww		/* fall thru... */
2725012Sgww	default:
2735012Sgww		break;
2745012Sgww	}
2755012Sgww	return 0xffffffff;
2765012Sgww}
2772522Sraf
2785012Sgww/*
2792522Sraf * Set the TxDP for the "main" data queue.
2802522Sraf */
2812522SrafHAL_BOOL
2822522Srafar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)
28312326Sgww@eng.sun.com{
2842522Sraf	struct ath_hal_5210 *ahp = AH5210(ah);
2852522Sraf	HAL_TX_QUEUE_INFO *qi;
2862522Sraf
2872522Sraf	HALASSERT(q < HAL_NUM_TX_QUEUES);
2882522Sraf
2892522Sraf	HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n",
29011529SJan.Parcel@Sun.COM	    __func__, q, txdp);
2912522Sraf	qi = &ahp->ah_txq[q];
2922522Sraf	switch (qi->tqi_type) {
29312918SJan.Friedel@Sun.COM	case HAL_TX_QUEUE_DATA:
29412918SJan.Friedel@Sun.COM#ifdef AH_DEBUG
29512918SJan.Friedel@Sun.COM		/*
29612918SJan.Friedel@Sun.COM		 * Make sure that TXE is deasserted before setting the
29712918SJan.Friedel@Sun.COM		 * TXDP.  If TXE is still asserted, setting TXDP will
29812918SJan.Friedel@Sun.COM		 * have no effect.
29912918SJan.Friedel@Sun.COM		 */
30012918SJan.Friedel@Sun.COM		if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0)
30112918SJan.Friedel@Sun.COM			ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n",
30212918SJan.Friedel@Sun.COM				__func__, OS_REG_READ(ah, AR_CR));
30312918SJan.Friedel@Sun.COM#endif
30412918SJan.Friedel@Sun.COM		OS_REG_WRITE(ah, AR_TXDP0, txdp);
30512918SJan.Friedel@Sun.COM		break;
30612918SJan.Friedel@Sun.COM	case HAL_TX_QUEUE_BEACON:
30712918SJan.Friedel@Sun.COM	case HAL_TX_QUEUE_CAB:
30812918SJan.Friedel@Sun.COM		OS_REG_WRITE(ah, AR_TXDP1, txdp);
30912918SJan.Friedel@Sun.COM		break;
31012918SJan.Friedel@Sun.COM	case HAL_TX_QUEUE_INACTIVE:
3112522Sraf		HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",
3122522Sraf		    __func__, q);
3132522Sraf		/* fall thru... */
3142522Sraf	default:
3152522Sraf		return AH_FALSE;
3162522Sraf	}
31712918SJan.Friedel@Sun.COM	return AH_TRUE;
3182522Sraf}
3192522Sraf
3202522Sraf/*
3212522Sraf * Update Tx FIFO trigger level.
3222522Sraf *
3232522Sraf * Set bIncTrigLevel to TRUE to increase the trigger level.
3242522Sraf * Set bIncTrigLevel to FALSE to decrease the trigger level.
3252522Sraf *
3262522Sraf * Returns TRUE if the trigger level was updated
3272522Sraf */
3282522SrafHAL_BOOL
3292522Srafar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)
3302522Sraf{
33112918SJan.Friedel@Sun.COM	uint32_t curTrigLevel;
3322522Sraf	HAL_INT ints = ar5210GetInterrupts(ah);
33312918SJan.Friedel@Sun.COM
33412918SJan.Friedel@Sun.COM	/*
33512918SJan.Friedel@Sun.COM	 * Disable chip interrupts. This is because halUpdateTxTrigLevel
3362522Sraf	 * is called from both ISR and non-ISR contexts.
3372522Sraf	 */
3382522Sraf	(void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);
3392522Sraf	curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV);
3402522Sraf	if (bIncTrigLevel){
3412522Sraf		/* increase the trigger level */
3424292Sab196087		curTrigLevel = curTrigLevel +
3434292Sab196087			((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);
34412692SAli.Bahrami@Oracle.COM	} else {
34512692SAli.Bahrami@Oracle.COM		/* decrease the trigger level if not already at the minimum */
34612692SAli.Bahrami@Oracle.COM		if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {
34712692SAli.Bahrami@Oracle.COM			/* decrease the trigger level */
34812692SAli.Bahrami@Oracle.COM			curTrigLevel--;
3494292Sab196087		} else {
3504292Sab196087			/* no update to the trigger level */
3512522Sraf			/* re-enable chip interrupts */
3522522Sraf			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 */
366HAL_BOOL
367ar5210StartTxDma(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		/* fal thru... */
393	default:
394		return AH_FALSE;
395	}
396	return AH_TRUE;
397}
398
399uint32_t
400ar5210NumTxPending(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 */
427HAL_BOOL
428ar5210StopTxDma(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
476HAL_BOOL
477ar5210SetupTxDesc(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
526HAL_BOOL
527ar5210SetupXTxDesc(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
539void
540ar5210IntrReqTxDesc(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
547HAL_BOOL
548ar5210FillTxDesc(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 */
584HAL_STATUS
585ar5210ProcTxDesc(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 */
619void
620ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)
621{
622	return;
623}
624