Path: blob/main/sys/dev/ath/ath_hal/ar5210/ar5210_xmit.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2009 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2004 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"22#include "ah_desc.h"2324#include "ar5210/ar5210.h"25#include "ar5210/ar5210reg.h"26#include "ar5210/ar5210phy.h"27#include "ar5210/ar5210desc.h"2829/*30* Set the properties of the tx queue with the parameters31* from qInfo. The queue must previously have been setup32* with a call to ar5210SetupTxQueue.33*/34HAL_BOOL35ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo)36{37struct ath_hal_5210 *ahp = AH5210(ah);3839if (q >= HAL_NUM_TX_QUEUES) {40HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",41__func__, q);42return AH_FALSE;43}44return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo);45}4647/*48* Return the properties for the specified tx queue.49*/50HAL_BOOL51ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo)52{53struct ath_hal_5210 *ahp = AH5210(ah);5455if (q >= HAL_NUM_TX_QUEUES) {56HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",57__func__, q);58return AH_FALSE;59}60return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]);61}6263/*64* Allocate and initialize a tx DCU/QCU combination.65*/66int67ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type,68const HAL_TXQ_INFO *qInfo)69{70struct ath_hal_5210 *ahp = AH5210(ah);71HAL_TX_QUEUE_INFO *qi;72int q;7374switch (type) {75case HAL_TX_QUEUE_BEACON:76q = 2;77break;78case HAL_TX_QUEUE_CAB:79q = 1;80break;81case HAL_TX_QUEUE_DATA:82q = 0;83break;84default:85HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n",86__func__, type);87return -1;88}8990HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);9192qi = &ahp->ah_txq[q];93if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) {94HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n",95__func__, q);96return -1;97}98OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO));99qi->tqi_type = type;100if (qInfo == AH_NULL) {101/* by default enable OK+ERR+DESC+URN interrupts */102qi->tqi_qflags =103HAL_TXQ_TXOKINT_ENABLE104| HAL_TXQ_TXERRINT_ENABLE105| HAL_TXQ_TXDESCINT_ENABLE106| HAL_TXQ_TXURNINT_ENABLE107;108qi->tqi_aifs = INIT_AIFS;109qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */110qi->tqi_shretry = INIT_SH_RETRY;111qi->tqi_lgretry = INIT_LG_RETRY;112} else113(void) ar5210SetTxQueueProps(ah, q, qInfo);114/* NB: must be followed by ar5210ResetTxQueue */115return q;116}117118/*119* Free a tx DCU/QCU combination.120*/121HAL_BOOL122ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q)123{124struct ath_hal_5210 *ahp = AH5210(ah);125HAL_TX_QUEUE_INFO *qi;126127if (q >= HAL_NUM_TX_QUEUES) {128HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",129__func__, q);130return AH_FALSE;131}132qi = &ahp->ah_txq[q];133if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {134HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",135__func__, q);136return AH_FALSE;137}138139HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q);140141qi->tqi_type = HAL_TX_QUEUE_INACTIVE;142ahp->ah_txOkInterruptMask &= ~(1 << q);143ahp->ah_txErrInterruptMask &= ~(1 << q);144ahp->ah_txDescInterruptMask &= ~(1 << q);145ahp->ah_txEolInterruptMask &= ~(1 << q);146ahp->ah_txUrnInterruptMask &= ~(1 << q);147148return AH_TRUE;149#undef N150}151152HAL_BOOL153ar5210ResetTxQueue(struct ath_hal *ah, u_int q)154{155struct ath_hal_5210 *ahp = AH5210(ah);156const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan;157HAL_TX_QUEUE_INFO *qi;158uint32_t cwMin;159160if (q >= HAL_NUM_TX_QUEUES) {161HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n",162__func__, q);163return AH_FALSE;164}165qi = &ahp->ah_txq[q];166if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) {167HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",168__func__, q);169return AH_FALSE;170}171172/*173* Ignore any non-data queue(s).174*/175if (qi->tqi_type != HAL_TX_QUEUE_DATA)176return AH_TRUE;177178/* Set turbo mode / base mode parameters on or off */179if (IEEE80211_IS_CHAN_TURBO(chan)) {180OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO);181OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO);182OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO);183OS_REG_WRITE(ah, AR_IFS0,184((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO)185<< AR_IFS0_DIFS_S)186| INIT_SIFS_TURBO);187OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO);188OS_REG_WRITE(ah, AR_PHY(17),189(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38);190OS_REG_WRITE(ah, AR_PHY_FRCTL,191AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |192AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |193AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR |1940x2020 |195AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT);196} else {197OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME);198OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT);199OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY);200OS_REG_WRITE(ah, AR_IFS0,201((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME)202<< AR_IFS0_DIFS_S)203| INIT_SIFS);204OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL);205OS_REG_WRITE(ah, AR_PHY(17),206(OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C);207OS_REG_WRITE(ah, AR_PHY_FRCTL,208AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR |209AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR |210AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020);211}212213if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT)214cwMin = INIT_CWMIN;215else216cwMin = qi->tqi_cwmin;217218/* Set cwmin and retry limit values */219OS_REG_WRITE(ah, AR_RETRY_LMT,220(cwMin << AR_RETRY_LMT_CW_MIN_S)221| SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY)222| SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY)223| SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY)224| SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY)225);226227if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE)228ahp->ah_txOkInterruptMask |= 1 << q;229else230ahp->ah_txOkInterruptMask &= ~(1 << q);231if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE)232ahp->ah_txErrInterruptMask |= 1 << q;233else234ahp->ah_txErrInterruptMask &= ~(1 << q);235if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE)236ahp->ah_txDescInterruptMask |= 1 << q;237else238ahp->ah_txDescInterruptMask &= ~(1 << q);239if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE)240ahp->ah_txEolInterruptMask |= 1 << q;241else242ahp->ah_txEolInterruptMask &= ~(1 << q);243if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE)244ahp->ah_txUrnInterruptMask |= 1 << q;245else246ahp->ah_txUrnInterruptMask &= ~(1 << q);247248return AH_TRUE;249}250251/*252* Get the TXDP for the "main" data queue. Needs to be extended253* for multiple Q functionality254*/255uint32_t256ar5210GetTxDP(struct ath_hal *ah, u_int q)257{258struct ath_hal_5210 *ahp = AH5210(ah);259HAL_TX_QUEUE_INFO *qi;260261HALASSERT(q < HAL_NUM_TX_QUEUES);262263qi = &ahp->ah_txq[q];264switch (qi->tqi_type) {265case HAL_TX_QUEUE_DATA:266return OS_REG_READ(ah, AR_TXDP0);267case HAL_TX_QUEUE_INACTIVE:268HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",269__func__, q);270/* fall thru... */271default:272break;273}274return 0xffffffff;275}276277/*278* Set the TxDP for the "main" data queue.279*/280HAL_BOOL281ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp)282{283struct ath_hal_5210 *ahp = AH5210(ah);284HAL_TX_QUEUE_INFO *qi;285286HALASSERT(q < HAL_NUM_TX_QUEUES);287288HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n",289__func__, q, txdp);290qi = &ahp->ah_txq[q];291switch (qi->tqi_type) {292case HAL_TX_QUEUE_DATA:293#ifdef AH_DEBUG294/*295* Make sure that TXE is deasserted before setting the296* TXDP. If TXE is still asserted, setting TXDP will297* have no effect.298*/299if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0)300ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n",301__func__, OS_REG_READ(ah, AR_CR));302#endif303OS_REG_WRITE(ah, AR_TXDP0, txdp);304break;305case HAL_TX_QUEUE_BEACON:306case HAL_TX_QUEUE_CAB:307OS_REG_WRITE(ah, AR_TXDP1, txdp);308break;309case HAL_TX_QUEUE_INACTIVE:310HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n",311__func__, q);312/* fall thru... */313default:314return AH_FALSE;315}316return AH_TRUE;317}318319/*320* Update Tx FIFO trigger level.321*322* Set bIncTrigLevel to TRUE to increase the trigger level.323* Set bIncTrigLevel to FALSE to decrease the trigger level.324*325* Returns TRUE if the trigger level was updated326*/327HAL_BOOL328ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel)329{330uint32_t curTrigLevel;331HAL_INT ints = ar5210GetInterrupts(ah);332333/*334* Disable chip interrupts. This is because halUpdateTxTrigLevel335* is called from both ISR and non-ISR contexts.336*/337(void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL);338curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV);339if (bIncTrigLevel){340/* increase the trigger level */341curTrigLevel = curTrigLevel +342((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2);343} else {344/* decrease the trigger level if not already at the minimum */345if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) {346/* decrease the trigger level */347curTrigLevel--;348} else {349/* no update to the trigger level */350/* re-enable chip interrupts */351ar5210SetInterrupts(ah, ints);352return AH_FALSE;353}354}355/* Update the trigger level */356OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel);357/* re-enable chip interrupts */358ar5210SetInterrupts(ah, ints);359return AH_TRUE;360}361362/*363* Set Transmit Enable bits for the specified queues.364*/365HAL_BOOL366ar5210StartTxDma(struct ath_hal *ah, u_int q)367{368struct ath_hal_5210 *ahp = AH5210(ah);369HAL_TX_QUEUE_INFO *qi;370371HALASSERT(q < HAL_NUM_TX_QUEUES);372373HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);374qi = &ahp->ah_txq[q];375switch (qi->tqi_type) {376case HAL_TX_QUEUE_DATA:377OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0);378break;379case HAL_TX_QUEUE_CAB:380OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1); /* enable altq xmit */381OS_REG_WRITE(ah, AR_BCR,382AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV);383break;384case HAL_TX_QUEUE_BEACON:385/* XXX add CR_BCR_BCMD if IBSS mode */386OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE);387break;388case HAL_TX_QUEUE_INACTIVE:389HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",390__func__, q);391/* fal thru... */392default:393return AH_FALSE;394}395return AH_TRUE;396}397398uint32_t399ar5210NumTxPending(struct ath_hal *ah, u_int q)400{401struct ath_hal_5210 *ahp = AH5210(ah);402HAL_TX_QUEUE_INFO *qi;403uint32_t v;404405HALASSERT(q < HAL_NUM_TX_QUEUES);406407HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);408qi = &ahp->ah_txq[q];409switch (qi->tqi_type) {410case HAL_TX_QUEUE_DATA:411v = OS_REG_READ(ah, AR_CFG);412return MS(v, AR_CFG_TXCNT);413case HAL_TX_QUEUE_INACTIVE:414HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",415__func__, q);416/* fall thru... */417default:418break;419}420return 0;421}422423/*424* Stop transmit on the specified queue425*/426HAL_BOOL427ar5210StopTxDma(struct ath_hal *ah, u_int q)428{429struct ath_hal_5210 *ahp = AH5210(ah);430HAL_TX_QUEUE_INFO *qi;431432HALASSERT(q < HAL_NUM_TX_QUEUES);433434HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q);435qi = &ahp->ah_txq[q];436switch (qi->tqi_type) {437case HAL_TX_QUEUE_DATA: {438int i;439OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0);440for (i = 0; i < 1000; i++) {441if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0)442break;443OS_DELAY(10);444}445OS_REG_WRITE(ah, AR_CR, 0);446return (i < 1000);447}448case HAL_TX_QUEUE_BEACON:449return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0);450case HAL_TX_QUEUE_INACTIVE:451HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n",452__func__, q);453/* fall thru... */454default:455break;456}457return AH_FALSE;458}459460/*461* Descriptor Access Functions462*/463464#define VALID_PKT_TYPES \465((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\466(1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\467(1<<HAL_PKT_TYPE_BEACON))468#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)469#define VALID_TX_RATES \470((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\471(1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\472(1<<0x1d)|(1<<0x18)|(1<<0x1c))473#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)474475HAL_BOOL476ar5210SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,477u_int pktLen,478u_int hdrLen,479HAL_PKT_TYPE type,480u_int txPower,481u_int txRate0, u_int txTries0,482u_int keyIx,483u_int antMode,484u_int flags,485u_int rtsctsRate,486u_int rtsctsDuration,487u_int compicvLen,488u_int compivLen,489u_int comp)490{491struct ar5210_desc *ads = AR5210DESC(ds);492uint32_t frtype;493494(void) txPower;495(void) rtsctsDuration;496497HALASSERT(txTries0 != 0);498HALASSERT(isValidPktType(type));499HALASSERT(isValidTxRate(txRate0));500501if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP)502frtype = AR_Frm_NoDelay;503else504frtype = type << 26;505ads->ds_ctl0 = (pktLen & AR_FrameLen)506| (txRate0 << AR_XmitRate_S)507| ((hdrLen << AR_HdrLen_S) & AR_HdrLen)508| frtype509| (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0)510| (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0)511| (antMode ? AR_AntModeXmit : 0)512;513if (keyIx != HAL_TXKEYIX_INVALID) {514ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx;515ads->ds_ctl0 |= AR_EncryptKeyValid;516} else517ads->ds_ctl1 = 0;518if (flags & HAL_TXDESC_RTSENA) {519ads->ds_ctl0 |= AR_RTSCTSEnable;520ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S)521& AR_RTSDuration;522}523return AH_TRUE;524}525526HAL_BOOL527ar5210SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds,528u_int txRate1, u_int txTries1,529u_int txRate2, u_int txTries2,530u_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;536return AH_FALSE;537}538539void540ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds)541{542struct ar5210_desc *ads = AR5210DESC(ds);543544ads->ds_ctl0 |= AR_TxInterReq;545}546547HAL_BOOL548ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds,549HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId,550u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg,551const struct ath_desc *ds0)552{553struct ar5210_desc *ads = AR5210DESC(ds);554uint32_t segLen = segLenList[0];555556HALASSERT((segLen &~ AR_BufLen) == 0);557558ds->ds_data = bufAddrList[0];559560if (firstSeg) {561/*562* First descriptor, don't clobber xmit control data563* setup by ar5210SetupTxDesc.564*/565ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More);566} else if (lastSeg) { /* !firstSeg && lastSeg */567/*568* Last descriptor in a multi-descriptor frame,569* copy the transmit parameters from the first570* frame for processing on completion.571*/572ads->ds_ctl0 = AR5210DESC_CONST(ds0)->ds_ctl0;573ads->ds_ctl1 = segLen;574} else { /* !firstSeg && !lastSeg */575/*576* Intermediate descriptor in a multi-descriptor frame.577*/578ads->ds_ctl0 = 0;579ads->ds_ctl1 = segLen | AR_More;580}581ads->ds_status0 = ads->ds_status1 = 0;582return AH_TRUE;583}584585/*586* Processing of HW TX descriptor.587*/588HAL_STATUS589ar5210ProcTxDesc(struct ath_hal *ah,590struct ath_desc *ds, struct ath_tx_status *ts)591{592struct ar5210_desc *ads = AR5210DESC(ds);593594if ((ads->ds_status1 & AR_Done) == 0)595return HAL_EINPROGRESS;596597/* Update software copies of the HW status */598ts->ts_seqnum = ads->ds_status1 & AR_SeqNum;599ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp);600ts->ts_status = 0;601if ((ads->ds_status0 & AR_FrmXmitOK) == 0) {602if (ads->ds_status0 & AR_ExcessiveRetries)603ts->ts_status |= HAL_TXERR_XRETRY;604if (ads->ds_status0 & AR_Filtered)605ts->ts_status |= HAL_TXERR_FILT;606if (ads->ds_status0 & AR_FIFOUnderrun)607ts->ts_status |= HAL_TXERR_FIFO;608}609ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate);610ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength);611ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt);612ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt);613ts->ts_antenna = 0; /* NB: don't know */614ts->ts_finaltsi = 0;615616return HAL_OK;617}618619/*620* Determine which tx queues need interrupt servicing.621* STUB.622*/623void624ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs)625{626return;627}628629/*630* Retrieve the rate table from the given TX completion descriptor631*/632HAL_BOOL633ar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries)634{635return AH_FALSE;636}637638/*639* Set the TX descriptor link pointer640*/641void642ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link)643{644struct ar5210_desc *ads = AR5210DESC(ds);645646ads->ds_link = link;647}648649/*650* Get the TX descriptor link pointer651*/652void653ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link)654{655struct ar5210_desc *ads = AR5210DESC(ds);656657*link = ads->ds_link;658}659660/*661* Get a pointer to the TX descriptor link pointer662*/663void664ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr)665{666struct ar5210_desc *ads = AR5210DESC(ds);667668*linkptr = &ads->ds_link;669}670671672