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