ar5416_xmit.c revision 185406
1263508Sdim/* 2218885Sdim * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3218885Sdim * Copyright (c) 2002-2008 Atheros Communications, Inc. 4218885Sdim * 5218885Sdim * Permission to use, copy, modify, and/or distribute this software for any 6218885Sdim * purpose with or without fee is hereby granted, provided that the above 7218885Sdim * copyright notice and this permission notice appear in all copies. 8218885Sdim * 9218885Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10263508Sdim * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11218885Sdim * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12218885Sdim * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13218885Sdim * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14218885Sdim * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15263508Sdim * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16263508Sdim * 17218885Sdim * $Id: ar5416_xmit.c,v 1.9 2008/11/27 22:30:08 sam Exp $ 18218885Sdim */ 19263508Sdim#include "opt_ah.h" 20218885Sdim 21263508Sdim#include "ah.h" 22263508Sdim#include "ah_desc.h" 23263508Sdim#include "ah_internal.h" 24263508Sdim 25218885Sdim#include "ar5416/ar5416.h" 26263508Sdim#include "ar5416/ar5416reg.h" 27218885Sdim#include "ar5416/ar5416phy.h" 28263508Sdim#include "ar5416/ar5416desc.h" 29263508Sdim 30263508Sdim/* 31263508Sdim * Stop transmit on the specified queue 32263508Sdim */ 33218885SdimHAL_BOOL 34263508Sdimar5416StopTxDma(struct ath_hal *ah, u_int q) 35263508Sdim{ 36263508Sdim#define STOP_DMA_TIMEOUT 4000 /* us */ 37218885Sdim#define STOP_DMA_ITER 100 /* us */ 38263508Sdim u_int i; 39218885Sdim 40263508Sdim HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); 41263508Sdim 42218885Sdim HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); 43263508Sdim 44263508Sdim OS_REG_WRITE(ah, AR_Q_TXD, 1 << q); 45263508Sdim for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) { 46263508Sdim if (ar5212NumTxPending(ah, q) == 0) 47263508Sdim break; 48218885Sdim OS_DELAY(STOP_DMA_ITER); 49263508Sdim } 50263508Sdim#ifdef AH_DEBUG 51263508Sdim if (i == 0) { 52218885Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 53263508Sdim "%s: queue %u DMA did not stop in 400 msec\n", __func__, q); 54263508Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 55263508Sdim "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n", __func__, 56218885Sdim OS_REG_READ(ah, AR_QSTS(q)), OS_REG_READ(ah, AR_Q_TXE), 57263508Sdim OS_REG_READ(ah, AR_Q_TXD), OS_REG_READ(ah, AR_QCBRCFG(q))); 58263508Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 59218885Sdim "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n", 60263508Sdim __func__, OS_REG_READ(ah, AR_QMISC(q)), 61263508Sdim OS_REG_READ(ah, AR_QRDYTIMECFG(q)), 62263508Sdim OS_REG_READ(ah, AR_Q_RDYTIMESHDN)); 63263508Sdim } 64218885Sdim#endif /* AH_DEBUG */ 65263508Sdim 66263508Sdim /* ar5416 and up can kill packets at the PCU level */ 67263508Sdim if (ar5212NumTxPending(ah, q)) { 68234353Sdim uint32_t j; 69263508Sdim 70263508Sdim HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 71263508Sdim "%s: Num of pending TX Frames %d on Q %d\n", 72263508Sdim __func__, ar5212NumTxPending(ah, q), q); 73263508Sdim 74263508Sdim /* Kill last PCU Tx Frame */ 75218885Sdim /* TODO - save off and restore current values of Q1/Q2? */ 76263508Sdim for (j = 0; j < 2; j++) { 77218885Sdim uint32_t tsfLow = OS_REG_READ(ah, AR_TSF_L32); 78263508Sdim OS_REG_WRITE(ah, AR_QUIET2, 79218885Sdim SM(10, AR_QUIET2_QUIET_DUR)); 80263508Sdim OS_REG_WRITE(ah, AR_QUIET_PERIOD, 100); 81263508Sdim OS_REG_WRITE(ah, AR_NEXT_QUIET, tsfLow >> 10); 82263508Sdim OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 83263508Sdim 84263508Sdim if ((OS_REG_READ(ah, AR_TSF_L32)>>10) == (tsfLow>>10)) 85263508Sdim break; 86263508Sdim 87263508Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 88263508Sdim "%s: TSF moved while trying to set quiet time " 89218885Sdim "TSF: 0x%08x\n", __func__, tsfLow); 90263508Sdim HALASSERT(j < 1); /* TSF shouldn't count twice or reg access is taking forever */ 91263508Sdim } 92218885Sdim 93263508Sdim OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); 94263508Sdim 95263508Sdim /* Allow the quiet mechanism to do its work */ 96218885Sdim OS_DELAY(200); 97263508Sdim OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 98263508Sdim 99263508Sdim /* Verify the transmit q is empty */ 100263508Sdim for (i = STOP_DMA_TIMEOUT/STOP_DMA_ITER; i != 0; i--) { 101263508Sdim if (ar5212NumTxPending(ah, q) == 0) 102263508Sdim break; 103263508Sdim OS_DELAY(STOP_DMA_ITER); 104263508Sdim } 105218885Sdim if (i == 0) { 106263508Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 107218885Sdim "%s: Failed to stop Tx DMA in %d msec after killing" 108263508Sdim " last frame\n", __func__, STOP_DMA_TIMEOUT / 1000); 109263508Sdim } 110263508Sdim OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); 111263508Sdim } 112263508Sdim 113263508Sdim OS_REG_WRITE(ah, AR_Q_TXD, 0); 114263508Sdim return (i != 0); 115263508Sdim#undef STOP_DMA_ITER 116263508Sdim#undef STOP_DMA_TIMEOUT 117263508Sdim} 118263508Sdim 119263508Sdim#define VALID_KEY_TYPES \ 120263508Sdim ((1 << HAL_KEY_TYPE_CLEAR) | (1 << HAL_KEY_TYPE_WEP)|\ 121263508Sdim (1 << HAL_KEY_TYPE_AES) | (1 << HAL_KEY_TYPE_TKIP)) 122263508Sdim#define isValidKeyType(_t) ((1 << (_t)) & VALID_KEY_TYPES) 123263508Sdim 124263508Sdim#define set11nTries(_series, _index) \ 125263508Sdim (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) 126263508Sdim 127263508Sdim#define set11nRate(_series, _index) \ 128263508Sdim (SM((_series)[_index].Rate, AR_XmitRate##_index)) 129263508Sdim 130263508Sdim#define set11nPktDurRTSCTS(_series, _index) \ 131263508Sdim (SM((_series)[_index].PktDuration, AR_PacketDur##_index) |\ 132218885Sdim ((_series)[_index].RateFlags & HAL_RATESERIES_RTS_CTS ?\ 133263508Sdim AR_RTSCTSQual##_index : 0)) 134263508Sdim 135218885Sdim#define set11nRateFlags(_series, _index) \ 136263508Sdim ((_series)[_index].RateFlags & HAL_RATESERIES_2040 ? AR_2040_##_index : 0) \ 137263508Sdim |((_series)[_index].RateFlags & HAL_RATESERIES_HALFGI ? AR_GI##_index : 0) \ 138263508Sdim |SM((_series)[_index].ChSel, AR_ChainSel##_index) 139218885Sdim 140263508Sdim/* 141218885Sdim * Descriptor Access Functions 142263508Sdim */ 143263508Sdim 144263508Sdim#define VALID_PKT_TYPES \ 145263508Sdim ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\ 146263508Sdim (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\ 147263508Sdim (1<<HAL_PKT_TYPE_BEACON)|(1<<HAL_PKT_TYPE_AMPDU)) 148263508Sdim#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES) 149263508Sdim#define VALID_TX_RATES \ 150263508Sdim ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\ 151263508Sdim (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\ 152263508Sdim (1<<0x1d)|(1<<0x18)|(1<<0x1c)) 153263508Sdim#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES) 154263508Sdim 155263508SdimHAL_BOOL 156218885Sdimar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, 157263508Sdim u_int pktLen, 158263508Sdim u_int hdrLen, 159218885Sdim HAL_PKT_TYPE type, 160263508Sdim u_int txPower, 161263508Sdim u_int txRate0, u_int txTries0, 162263508Sdim u_int keyIx, 163263508Sdim u_int antMode, 164263508Sdim u_int flags, 165263508Sdim u_int rtsctsRate, 166263508Sdim u_int rtsctsDuration, 167263508Sdim u_int compicvLen, 168263508Sdim u_int compivLen, 169263508Sdim u_int comp) 170263508Sdim{ 171263508Sdim#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA) 172218885Sdim struct ar5416_desc *ads = AR5416DESC(ds); 173218885Sdim struct ath_hal_5416 *ahp = AH5416(ah); 174263508Sdim 175263508Sdim (void) hdrLen; 176263508Sdim 177263508Sdim HALASSERT(txTries0 != 0); 178263508Sdim HALASSERT(isValidPktType(type)); 179263508Sdim HALASSERT(isValidTxRate(txRate0)); 180263508Sdim HALASSERT((flags & RTSCTS) != RTSCTS); 181263508Sdim /* XXX validate antMode */ 182263508Sdim 183218885Sdim txPower = (txPower + AH5212(ah)->ah_txPowerIndexOffset); 184218885Sdim if (txPower > 63) 185263508Sdim txPower = 63; 186263508Sdim 187263508Sdim ads->ds_ctl0 = (pktLen & AR_FrameLen) 188263508Sdim | (txPower << AR_XmitPower_S) 189263508Sdim | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) 190263508Sdim | (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) 191263508Sdim | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0) 192263508Sdim ; 193218885Sdim ads->ds_ctl1 = (type << AR_FrameType_S) 194263508Sdim | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) 195263508Sdim ; 196263508Sdim ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0) 197263508Sdim | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEn : 0) 198263508Sdim ; 199263508Sdim ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S) 200263508Sdim ; 201263508Sdim ads->ds_ctl4 = 0; 202263508Sdim ads->ds_ctl5 = 0; 203263508Sdim ads->ds_ctl6 = 0; 204263508Sdim ads->ds_ctl7 = SM(ahp->ah_tx_chainmask, AR_ChainSel0) 205263508Sdim | SM(ahp->ah_tx_chainmask, AR_ChainSel1) 206263508Sdim | SM(ahp->ah_tx_chainmask, AR_ChainSel2) 207263508Sdim | SM(ahp->ah_tx_chainmask, AR_ChainSel3) 208263508Sdim ; 209263508Sdim ads->ds_ctl8 = 0; 210263508Sdim ads->ds_ctl9 = (txPower << 24); /* XXX? */ 211263508Sdim ads->ds_ctl10 = (txPower << 24); /* XXX? */ 212218885Sdim ads->ds_ctl11 = (txPower << 24); /* XXX? */ 213218885Sdim if (keyIx != HAL_TXKEYIX_INVALID) { 214263508Sdim /* XXX validate key index */ 215263508Sdim ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); 216263508Sdim ads->ds_ctl0 |= AR_DestIdxValid; 217218885Sdim ads->ds_ctl6 |= SM(ahp->ah_keytype[keyIx], AR_EncrType); 218263508Sdim } 219263508Sdim if (flags & RTSCTS) { 220263508Sdim if (!isValidTxRate(rtsctsRate)) { 221218885Sdim HALDEBUG(ah, HAL_DEBUG_ANY, 222263508Sdim "%s: invalid rts/cts rate 0x%x\n", 223263508Sdim __func__, rtsctsRate); 224263508Sdim return AH_FALSE; 225218885Sdim } 226263508Sdim /* XXX validate rtsctsDuration */ 227263508Sdim ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0) 228263508Sdim | (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0) 229263508Sdim ; 230218885Sdim ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur); 231263508Sdim ads->ds_ctl7 |= (rtsctsRate << AR_RTSCTSRate_S); 232263508Sdim } 233263508Sdim return AH_TRUE; 234218885Sdim#undef RTSCTS 235263508Sdim} 236263508Sdim 237263508SdimHAL_BOOL 238263508Sdimar5416SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, 239218885Sdim u_int txRate1, u_int txTries1, 240263508Sdim u_int txRate2, u_int txTries2, 241218885Sdim u_int txRate3, u_int txTries3) 242218885Sdim{ 243263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 244263508Sdim 245263508Sdim if (txTries1) { 246263508Sdim HALASSERT(isValidTxRate(txRate1)); 247263508Sdim ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1); 248263508Sdim ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S); 249263508Sdim } 250218885Sdim if (txTries2) { 251218885Sdim HALASSERT(isValidTxRate(txRate2)); 252263508Sdim ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2); 253263508Sdim ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S); 254263508Sdim } 255263508Sdim if (txTries3) { 256218885Sdim HALASSERT(isValidTxRate(txRate3)); 257263508Sdim ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3); 258263508Sdim ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S); 259263508Sdim } 260218885Sdim return AH_TRUE; 261218885Sdim} 262263508Sdim 263263508SdimHAL_BOOL 264263508Sdimar5416FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, 265218885Sdim u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, 266263508Sdim const struct ath_desc *ds0) 267263508Sdim{ 268263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 269218885Sdim 270263508Sdim HALASSERT((segLen &~ AR_BufLen) == 0); 271263508Sdim 272263508Sdim if (firstSeg) { 273218885Sdim /* 274263508Sdim * First descriptor, don't clobber xmit control data 275263508Sdim * setup by ar5212SetupTxDesc. 276263508Sdim */ 277263508Sdim ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); 278263508Sdim } else if (lastSeg) { /* !firstSeg && lastSeg */ 279263508Sdim /* 280263508Sdim * Last descriptor in a multi-descriptor frame, 281263508Sdim * copy the multi-rate transmit parameters from 282218885Sdim * the first frame for processing on completion. 283218885Sdim */ 284263508Sdim ads->ds_ctl0 = 0; 285263508Sdim ads->ds_ctl1 = segLen; 286263508Sdim#ifdef AH_NEED_DESC_SWAP 287218885Sdim ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2); 288263508Sdim ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3); 289263508Sdim#else 290263508Sdim ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; 291218885Sdim ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; 292263508Sdim#endif 293263508Sdim } else { /* !firstSeg && !lastSeg */ 294263508Sdim /* 295263508Sdim * Intermediate descriptor in a multi-descriptor frame. 296263508Sdim */ 297263508Sdim ads->ds_ctl0 = 0; 298263508Sdim ads->ds_ctl1 = segLen | AR_TxMore; 299263508Sdim ads->ds_ctl2 = 0; 300218885Sdim ads->ds_ctl3 = 0; 301263508Sdim } 302218885Sdim /* XXX only on last descriptor? */ 303218885Sdim OS_MEMZERO(ads->u.tx.status, sizeof(ads->u.tx.status)); 304263508Sdim return AH_TRUE; 305263508Sdim} 306263508Sdim 307263508Sdim#if 0 308263508Sdim 309263508SdimHAL_BOOL 310218885Sdimar5416ChainTxDesc(struct ath_hal *ah, struct ath_desc *ds, 311263508Sdim u_int pktLen, 312263508Sdim u_int hdrLen, 313263508Sdim HAL_PKT_TYPE type, 314263508Sdim u_int keyIx, 315263508Sdim HAL_CIPHER cipher, 316218885Sdim uint8_t delims, 317263508Sdim u_int segLen, 318263508Sdim HAL_BOOL firstSeg, 319218885Sdim HAL_BOOL lastSeg) 320263508Sdim{ 321218885Sdim struct ar5416_desc *ads = AR5416DESC(ds); 322218885Sdim uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); 323263508Sdim 324263508Sdim int isaggr = 0; 325263508Sdim 326263508Sdim (void) hdrLen; 327218885Sdim (void) ah; 328263508Sdim 329263508Sdim HALASSERT((segLen &~ AR_BufLen) == 0); 330263508Sdim 331263508Sdim HALASSERT(isValidPktType(type)); 332263508Sdim if (type == HAL_PKT_TYPE_AMPDU) { 333218885Sdim type = HAL_PKT_TYPE_NORMAL; 334263508Sdim isaggr = 1; 335263508Sdim } 336263508Sdim 337263508Sdim if (!firstSeg) { 338263508Sdim ath_hal_memzero(ds->ds_hw, AR5416_DESC_TX_CTL_SZ); 339218885Sdim } 340263508Sdim 341263508Sdim ads->ds_ctl0 = (pktLen & AR_FrameLen); 342218885Sdim ads->ds_ctl1 = (type << AR_FrameType_S) 343263508Sdim | (isaggr ? (AR_IsAggr | AR_MoreAggr) : 0); 344218885Sdim ads->ds_ctl2 = 0; 345218885Sdim ads->ds_ctl3 = 0; 346263508Sdim if (keyIx != HAL_TXKEYIX_INVALID) { 347263508Sdim /* XXX validate key index */ 348263508Sdim ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); 349218885Sdim ads->ds_ctl0 |= AR_DestIdxValid; 350263508Sdim } 351263508Sdim 352263508Sdim ads->ds_ctl6 = SM(keyType[cipher], AR_EncrType); 353263508Sdim if (isaggr) { 354263508Sdim ads->ds_ctl6 |= SM(delims, AR_PadDelim); 355263508Sdim } 356263508Sdim 357263508Sdim if (firstSeg) { 358263508Sdim ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); 359263508Sdim } else if (lastSeg) { /* !firstSeg && lastSeg */ 360263508Sdim ads->ds_ctl0 = 0; 361263508Sdim ads->ds_ctl1 |= segLen; 362263508Sdim } else { /* !firstSeg && !lastSeg */ 363263508Sdim /* 364263508Sdim * Intermediate descriptor in a multi-descriptor frame. 365263508Sdim */ 366263508Sdim ads->ds_ctl0 = 0; 367263508Sdim ads->ds_ctl1 |= segLen | AR_TxMore; 368263508Sdim } 369263508Sdim ds_txstatus[0] = ds_txstatus[1] = 0; 370263508Sdim ds_txstatus[9] &= ~AR_TxDone; 371263508Sdim 372263508Sdim return AH_TRUE; 373263508Sdim} 374263508Sdim 375263508SdimHAL_BOOL 376263508Sdimar5416SetupFirstTxDesc(struct ath_hal *ah, struct ath_desc *ds, 377263508Sdim u_int aggrLen, u_int flags, u_int txPower, 378263508Sdim u_int txRate0, u_int txTries0, u_int antMode, 379263508Sdim u_int rtsctsRate, u_int rtsctsDuration) 380263508Sdim{ 381263508Sdim#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA) 382263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 383263508Sdim struct ath_hal_5212 *ahp = AH5212(ah); 384218885Sdim 385218885Sdim HALASSERT(txTries0 != 0); 386263508Sdim HALASSERT(isValidTxRate(txRate0)); 387263508Sdim HALASSERT((flags & RTSCTS) != RTSCTS); 388263508Sdim /* XXX validate antMode */ 389263508Sdim 390263508Sdim txPower = (txPower + ahp->ah_txPowerIndexOffset ); 391263508Sdim if(txPower > 63) txPower=63; 392263508Sdim 393263508Sdim ads->ds_ctl0 |= (txPower << AR_XmitPower_S) 394263508Sdim | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) 395263508Sdim | (flags & HAL_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) 396263508Sdim | (flags & HAL_TXDESC_INTREQ ? AR_TxIntrReq : 0); 397263508Sdim ads->ds_ctl1 |= (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0); 398263508Sdim ads->ds_ctl2 |= SM(txTries0, AR_XmitDataTries0); 399263508Sdim ads->ds_ctl3 |= (txRate0 << AR_XmitRate0_S); 400263508Sdim ads->ds_ctl7 = SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel0) 401263508Sdim | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel1) 402263508Sdim | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel2) 403263508Sdim | SM(AH5416(ah)->ah_tx_chainmask, AR_ChainSel3); 404263508Sdim 405263508Sdim /* NB: no V1 WAR */ 406263508Sdim ads->ds_ctl8 = 0; 407263508Sdim ads->ds_ctl9 = (txPower << 24); 408263508Sdim ads->ds_ctl10 = (txPower << 24); 409263508Sdim ads->ds_ctl11 = (txPower << 24); 410263508Sdim 411263508Sdim ads->ds_ctl6 &= ~(0xffff); 412263508Sdim ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); 413263508Sdim 414218885Sdim if (flags & RTSCTS) { 415218885Sdim /* XXX validate rtsctsDuration */ 416263508Sdim ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0) 417263508Sdim | (flags & HAL_TXDESC_RTSENA ? AR_RTSEnable : 0); 418263508Sdim ads->ds_ctl2 |= SM(rtsctsDuration, AR_BurstDur); 419263508Sdim } 420263508Sdim 421263508Sdim return AH_TRUE; 422263508Sdim#undef RTSCTS 423263508Sdim} 424263508Sdim 425263508SdimHAL_BOOL 426263508Sdimar5416SetupLastTxDesc(struct ath_hal *ah, struct ath_desc *ds, 427263508Sdim const struct ath_desc *ds0) 428263508Sdim{ 429263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 430263508Sdim 431263508Sdim ads->ds_ctl1 &= ~AR_MoreAggr; 432263508Sdim ads->ds_ctl6 &= ~AR_PadDelim; 433263508Sdim 434218885Sdim /* hack to copy rate info to last desc for later processing */ 435218885Sdim#ifdef AH_NEED_DESC_SWAP 436263508Sdim ads->ds_ctl2 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl2); 437263508Sdim ads->ds_ctl3 = __bswap32(AR5416DESC_CONST(ds0)->ds_ctl3); 438263508Sdim#else 439218885Sdim ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; 440263508Sdim ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; 441263508Sdim#endif 442263508Sdim 443218885Sdim return AH_TRUE; 444263508Sdim} 445218885Sdim#endif /* 0 */ 446263508Sdim 447263508Sdim#ifdef AH_NEED_DESC_SWAP 448263508Sdim/* Swap transmit descriptor */ 449263508Sdimstatic __inline void 450263508Sdimar5416SwapTxDesc(struct ath_desc *ds) 451263508Sdim{ 452263508Sdim ds->ds_data = __bswap32(ds->ds_data); 453263508Sdim ds->ds_ctl0 = __bswap32(ds->ds_ctl0); 454263508Sdim ds->ds_ctl1 = __bswap32(ds->ds_ctl1); 455263508Sdim ds->ds_hw[0] = __bswap32(ds->ds_hw[0]); 456218885Sdim ds->ds_hw[1] = __bswap32(ds->ds_hw[1]); 457218885Sdim ds->ds_hw[2] = __bswap32(ds->ds_hw[2]); 458263508Sdim ds->ds_hw[3] = __bswap32(ds->ds_hw[3]); 459263508Sdim} 460263508Sdim#endif 461263508Sdim 462218885Sdim/* 463263508Sdim * Processing of HW TX descriptor. 464263508Sdim */ 465218885SdimHAL_STATUS 466263508Sdimar5416ProcTxDesc(struct ath_hal *ah, 467263508Sdim struct ath_desc *ds, struct ath_tx_status *ts) 468263508Sdim{ 469218885Sdim struct ar5416_desc *ads = AR5416DESC(ds); 470263508Sdim uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); 471263508Sdim 472263508Sdim#ifdef AH_NEED_DESC_SWAP 473218885Sdim if ((ds_txstatus[9] & __bswap32(AR_TxDone)) == 0) 474263508Sdim return HAL_EINPROGRESS; 475263508Sdim ar5416SwapTxDesc(ds); 476218885Sdim#else 477263508Sdim if ((ds_txstatus[9] & AR_TxDone) == 0) 478263508Sdim return HAL_EINPROGRESS; 479218885Sdim#endif 480218885Sdim 481263508Sdim /* Update software copies of the HW status */ 482263508Sdim ts->ts_seqnum = MS(ds_txstatus[9], AR_SeqNum); 483263508Sdim ts->ts_tstamp = AR_SendTimestamp(ds_txstatus); 484263508Sdim 485263508Sdim ts->ts_status = 0; 486263508Sdim if (ds_txstatus[1] & AR_ExcessiveRetries) 487263508Sdim ts->ts_status |= HAL_TXERR_XRETRY; 488263508Sdim if (ds_txstatus[1] & AR_Filtered) 489263508Sdim ts->ts_status |= HAL_TXERR_FILT; 490218885Sdim if (ds_txstatus[1] & AR_FIFOUnderrun) 491218885Sdim ts->ts_status |= HAL_TXERR_FIFO; 492263508Sdim if (ds_txstatus[9] & AR_TxOpExceeded) 493263508Sdim ts->ts_status |= HAL_TXERR_XTXOP; 494263508Sdim if (ds_txstatus[1] & AR_TxTimerExpired) 495263508Sdim ts->ts_status |= HAL_TXERR_TIMER_EXPIRED; 496263508Sdim 497263508Sdim ts->ts_flags = 0; 498263508Sdim if (ds_txstatus[0] & AR_TxBaStatus) { 499218885Sdim ts->ts_flags |= HAL_TX_BA; 500263508Sdim ts->ts_ba_low = AR_BaBitmapLow(ds_txstatus); 501263508Sdim ts->ts_ba_high = AR_BaBitmapHigh(ds_txstatus); 502263508Sdim } 503263508Sdim if (ds->ds_ctl1 & AR_IsAggr) 504263508Sdim ts->ts_flags |= HAL_TX_AGGR; 505263508Sdim if (ds_txstatus[1] & AR_DescCfgErr) 506263508Sdim ts->ts_flags |= HAL_TX_DESC_CFG_ERR; 507218885Sdim if (ds_txstatus[1] & AR_TxDataUnderrun) 508263508Sdim ts->ts_flags |= HAL_TX_DATA_UNDERRUN; 509263508Sdim if (ds_txstatus[1] & AR_TxDelimUnderrun) 510263508Sdim ts->ts_flags |= HAL_TX_DELIM_UNDERRUN; 511263508Sdim 512263508Sdim /* 513263508Sdim * Extract the transmit rate used and mark the rate as 514263508Sdim * ``alternate'' if it wasn't the series 0 rate. 515263508Sdim */ 516218885Sdim ts->ts_finaltsi = MS(ds_txstatus[9], AR_FinalTxIdx); 517218885Sdim switch (ts->ts_finaltsi) { 518218885Sdim case 0: 519263508Sdim ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate0); 520218885Sdim break; 521218885Sdim case 1: 522218885Sdim ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate1) | 523263508Sdim HAL_TXSTAT_ALTRATE; 524263508Sdim break; 525263508Sdim case 2: 526263508Sdim ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate2) | 527263508Sdim HAL_TXSTAT_ALTRATE; 528263508Sdim break; 529263508Sdim case 3: 530263508Sdim ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate3) | 531263508Sdim HAL_TXSTAT_ALTRATE; 532263508Sdim break; 533263508Sdim } 534263508Sdim 535263508Sdim ts->ts_rssi = MS(ds_txstatus[5], AR_TxRSSICombined); 536218885Sdim ts->ts_rssi_ctl[0] = MS(ds_txstatus[0], AR_TxRSSIAnt00); 537263508Sdim ts->ts_rssi_ctl[1] = MS(ds_txstatus[0], AR_TxRSSIAnt01); 538263508Sdim ts->ts_rssi_ctl[2] = MS(ds_txstatus[0], AR_TxRSSIAnt02); 539263508Sdim ts->ts_rssi_ext[0] = MS(ds_txstatus[5], AR_TxRSSIAnt10); 540263508Sdim ts->ts_rssi_ext[1] = MS(ds_txstatus[5], AR_TxRSSIAnt11); 541263508Sdim ts->ts_rssi_ext[2] = MS(ds_txstatus[5], AR_TxRSSIAnt12); 542263508Sdim ts->ts_evm0 = AR_TxEVM0(ds_txstatus); 543263508Sdim ts->ts_evm1 = AR_TxEVM1(ds_txstatus); 544263508Sdim ts->ts_evm2 = AR_TxEVM2(ds_txstatus); 545263508Sdim 546218885Sdim ts->ts_shortretry = MS(ds_txstatus[1], AR_RTSFailCnt); 547263508Sdim ts->ts_longretry = MS(ds_txstatus[1], AR_DataFailCnt); 548263508Sdim /* 549263508Sdim * The retry count has the number of un-acked tries for the 550263508Sdim * final series used. When doing multi-rate retry we must 551263508Sdim * fixup the retry count by adding in the try counts for 552263508Sdim * each series that was fully-processed. Beware that this 553263508Sdim * takes values from the try counts in the final descriptor. 554263508Sdim * These are not required by the hardware. We assume they 555263508Sdim * are placed there by the driver as otherwise we have no 556263508Sdim * access and the driver can't do the calculation because it 557263508Sdim * doesn't know the descriptor format. 558263508Sdim */ 559263508Sdim switch (ts->ts_finaltsi) { 560263508Sdim case 3: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries2); 561218885Sdim case 2: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries1); 562218885Sdim case 1: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries0); 563263508Sdim } 564263508Sdim 565263508Sdim /* 566263508Sdim * These fields are not used. Zero these to preserve compatability 567263508Sdim * with existing drivers. 568263508Sdim */ 569263508Sdim ts->ts_virtcol = MS(ads->ds_ctl1, AR_VirtRetryCnt); 570218885Sdim ts->ts_antenna = 0; /* We don't switch antennas on Owl*/ 571263508Sdim 572263508Sdim /* handle tx trigger level changes internally */ 573263508Sdim if ((ts->ts_status & HAL_TXERR_FIFO) || 574218885Sdim (ts->ts_flags & (HAL_TX_DATA_UNDERRUN | HAL_TX_DELIM_UNDERRUN))) 575263508Sdim ar5212UpdateTxTrigLevel(ah, AH_TRUE); 576263508Sdim 577263508Sdim return HAL_OK; 578263508Sdim} 579263508Sdim 580263508Sdim#if 0 581263508SdimHAL_BOOL 582263508Sdimar5416SetGlobalTxTimeout(struct ath_hal *ah, u_int tu) 583218885Sdim{ 584218885Sdim struct ath_hal_5416 *ahp = AH5416(ah); 585263508Sdim 586263508Sdim if (tu > 0xFFFF) { 587218885Sdim HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad global tx timeout %u\n", 588263508Sdim __func__, tu); 589263508Sdim /* restore default handling */ 590263508Sdim ahp->ah_globaltxtimeout = (u_int) -1; 591263508Sdim return AH_FALSE; 592263508Sdim } 593263508Sdim OS_REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu); 594263508Sdim ahp->ah_globaltxtimeout = tu; 595263508Sdim return AH_TRUE; 596263508Sdim} 597263508Sdim 598263508Sdimu_int 599263508Sdimar5416GetGlobalTxTimeout(struct ath_hal *ah) 600263508Sdim{ 601263508Sdim return MS(OS_REG_READ(ah, AR_GTXTO), AR_GTXTO_TIMEOUT_LIMIT); 602263508Sdim} 603263508Sdim 604218885Sdimvoid 605263508Sdimar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds, 606263508Sdim u_int durUpdateEn, u_int rtsctsRate, 607263508Sdim HAL_11N_RATE_SERIES series[], u_int nseries) 608263508Sdim{ 609263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 610263508Sdim 611263508Sdim HALASSERT(nseries == 4); 612263508Sdim (void)nseries; 613263508Sdim 614218885Sdim 615218885Sdim ads->ds_ctl2 = set11nTries(series, 0) 616263508Sdim | set11nTries(series, 1) 617263508Sdim | set11nTries(series, 2) 618263508Sdim | set11nTries(series, 3) 619263508Sdim | (durUpdateEn ? AR_DurUpdateEn : 0); 620263508Sdim 621263508Sdim ads->ds_ctl3 = set11nRate(series, 0) 622263508Sdim | set11nRate(series, 1) 623263508Sdim | set11nRate(series, 2) 624263508Sdim | set11nRate(series, 3); 625263508Sdim 626263508Sdim ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) 627263508Sdim | set11nPktDurRTSCTS(series, 1); 628263508Sdim 629263508Sdim ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) 630263508Sdim | set11nPktDurRTSCTS(series, 3); 631263508Sdim 632263508Sdim ads->ds_ctl7 = set11nRateFlags(series, 0) 633263508Sdim | set11nRateFlags(series, 1) 634263508Sdim | set11nRateFlags(series, 2) 635263508Sdim | set11nRateFlags(series, 3) 636263508Sdim | SM(rtsctsRate, AR_RTSCTSRate); 637263508Sdim 638263508Sdim /* 639263508Sdim * Enable RTSCTS if any of the series is flagged for RTSCTS, 640263508Sdim * but only if CTS is not enabled. 641263508Sdim */ 642263508Sdim /* 643263508Sdim * FIXME : the entire RTS/CTS handling should be moved to this 644263508Sdim * function (by passing the global RTS/CTS flags to this function). 645263508Sdim * currently it is split between this function and the 646263508Sdim * setupFiirstDescriptor. with this current implementation there 647263508Sdim * is an implicit assumption that setupFirstDescriptor is called 648263508Sdim * before this function. 649263508Sdim */ 650263508Sdim if (((series[0].RateFlags & HAL_RATESERIES_RTS_CTS) || 651263508Sdim (series[1].RateFlags & HAL_RATESERIES_RTS_CTS) || 652263508Sdim (series[2].RateFlags & HAL_RATESERIES_RTS_CTS) || 653263508Sdim (series[3].RateFlags & HAL_RATESERIES_RTS_CTS) ) && 654263508Sdim (ads->ds_ctl0 & AR_CTSEnable) == 0) { 655263508Sdim ads->ds_ctl0 |= AR_RTSEnable; 656263508Sdim ads->ds_ctl0 &= ~AR_CTSEnable; 657263508Sdim } 658263508Sdim} 659263508Sdim 660263508Sdimvoid 661263508Sdimar5416Set11nAggrMiddle(struct ath_hal *ah, struct ath_desc *ds, u_int numDelims) 662263508Sdim{ 663263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 664263508Sdim uint32_t *ds_txstatus = AR5416_DS_TXSTATUS(ah,ads); 665263508Sdim 666263508Sdim ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); 667263508Sdim 668263508Sdim ads->ds_ctl6 &= ~AR_PadDelim; 669218885Sdim ads->ds_ctl6 |= SM(numDelims, AR_PadDelim); 670263508Sdim ads->ds_ctl6 &= ~AR_AggrLen; 671263508Sdim 672263508Sdim /* 673218885Sdim * Clear the TxDone status here, may need to change 674218885Sdim * func name to reflect this 675263508Sdim */ 676263508Sdim ds_txstatus[9] &= ~AR_TxDone; 677263508Sdim} 678263508Sdim 679263508Sdimvoid 680263508Sdimar5416Clr11nAggr(struct ath_hal *ah, struct ath_desc *ds) 681263508Sdim{ 682263508Sdim struct ar5416_desc *ads = AR5416DESC(ds); 683263508Sdim 684263508Sdim ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); 685218885Sdim ads->ds_ctl6 &= ~AR_PadDelim; 686263508Sdim ads->ds_ctl6 &= ~AR_AggrLen; 687263508Sdim} 688263508Sdim 689263508Sdimvoid 690263508Sdimar5416Set11nBurstDuration(struct ath_hal *ah, struct ath_desc *ds, 691263508Sdim u_int burstDuration) 692218885Sdim{ 693218885Sdim struct ar5416_desc *ads = AR5416DESC(ds); 694263508Sdim 695263508Sdim ads->ds_ctl2 &= ~AR_BurstDur; 696263508Sdim ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); 697263508Sdim} 698263508Sdim#endif 699263508Sdim