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