1 /*- 2 * SPDX-License-Identifier: ISC 3 * 4 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 5 * Copyright (c) 2002-2004 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 "ar5210/ar5210.h" 28 #include "ar5210/ar5210reg.h" 29 #include "ar5210/ar5210phy.h" 30 #include "ar5210/ar5210desc.h" 31 32 /* 33 * Set the properties of the tx queue with the parameters 34 * from qInfo. The queue must previously have been setup 35 * with a call to ar5210SetupTxQueue. 36 */ 37 HAL_BOOL 38 ar5210SetTxQueueProps(struct ath_hal *ah, int q, const HAL_TXQ_INFO *qInfo) 39 { 40 struct ath_hal_5210 *ahp = AH5210(ah); 41 42 if (q >= HAL_NUM_TX_QUEUES) { 43 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", 44 __func__, q); 45 return AH_FALSE; 46 } 47 return ath_hal_setTxQProps(ah, &ahp->ah_txq[q], qInfo); 48 } 49 50 /* 51 * Return the properties for the specified tx queue. 52 */ 53 HAL_BOOL 54 ar5210GetTxQueueProps(struct ath_hal *ah, int q, HAL_TXQ_INFO *qInfo) 55 { 56 struct ath_hal_5210 *ahp = AH5210(ah); 57 58 if (q >= HAL_NUM_TX_QUEUES) { 59 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", 60 __func__, q); 61 return AH_FALSE; 62 } 63 return ath_hal_getTxQProps(ah, qInfo, &ahp->ah_txq[q]); 64 } 65 66 /* 67 * Allocate and initialize a tx DCU/QCU combination. 68 */ 69 int 70 ar5210SetupTxQueue(struct ath_hal *ah, HAL_TX_QUEUE type, 71 const HAL_TXQ_INFO *qInfo) 72 { 73 struct ath_hal_5210 *ahp = AH5210(ah); 74 HAL_TX_QUEUE_INFO *qi; 75 int q; 76 77 switch (type) { 78 case HAL_TX_QUEUE_BEACON: 79 q = 2; 80 break; 81 case HAL_TX_QUEUE_CAB: 82 q = 1; 83 break; 84 case HAL_TX_QUEUE_DATA: 85 q = 0; 86 break; 87 default: 88 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad tx queue type %u\n", 89 __func__, type); 90 return -1; 91 } 92 93 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); 94 95 qi = &ahp->ah_txq[q]; 96 if (qi->tqi_type != HAL_TX_QUEUE_INACTIVE) { 97 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: tx queue %u already active\n", 98 __func__, q); 99 return -1; 100 } 101 OS_MEMZERO(qi, sizeof(HAL_TX_QUEUE_INFO)); 102 qi->tqi_type = type; 103 if (qInfo == AH_NULL) { 104 /* by default enable OK+ERR+DESC+URN interrupts */ 105 qi->tqi_qflags = 106 HAL_TXQ_TXOKINT_ENABLE 107 | HAL_TXQ_TXERRINT_ENABLE 108 | HAL_TXQ_TXDESCINT_ENABLE 109 | HAL_TXQ_TXURNINT_ENABLE 110 ; 111 qi->tqi_aifs = INIT_AIFS; 112 qi->tqi_cwmin = HAL_TXQ_USEDEFAULT; /* NB: do at reset */ 113 qi->tqi_shretry = INIT_SH_RETRY; 114 qi->tqi_lgretry = INIT_LG_RETRY; 115 } else 116 (void) ar5210SetTxQueueProps(ah, q, qInfo); 117 /* NB: must be followed by ar5210ResetTxQueue */ 118 return q; 119 } 120 121 /* 122 * Free a tx DCU/QCU combination. 123 */ 124 HAL_BOOL 125 ar5210ReleaseTxQueue(struct ath_hal *ah, u_int q) 126 { 127 struct ath_hal_5210 *ahp = AH5210(ah); 128 HAL_TX_QUEUE_INFO *qi; 129 130 if (q >= HAL_NUM_TX_QUEUES) { 131 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", 132 __func__, q); 133 return AH_FALSE; 134 } 135 qi = &ahp->ah_txq[q]; 136 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 137 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", 138 __func__, q); 139 return AH_FALSE; 140 } 141 142 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q); 143 144 qi->tqi_type = HAL_TX_QUEUE_INACTIVE; 145 ahp->ah_txOkInterruptMask &= ~(1 << q); 146 ahp->ah_txErrInterruptMask &= ~(1 << q); 147 ahp->ah_txDescInterruptMask &= ~(1 << q); 148 ahp->ah_txEolInterruptMask &= ~(1 << q); 149 ahp->ah_txUrnInterruptMask &= ~(1 << q); 150 151 return AH_TRUE; 152 #undef N 153 } 154 155 HAL_BOOL 156 ar5210ResetTxQueue(struct ath_hal *ah, u_int q) 157 { 158 struct ath_hal_5210 *ahp = AH5210(ah); 159 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 160 HAL_TX_QUEUE_INFO *qi; 161 uint32_t cwMin; 162 163 if (q >= HAL_NUM_TX_QUEUES) { 164 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", 165 __func__, q); 166 return AH_FALSE; 167 } 168 qi = &ahp->ah_txq[q]; 169 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 170 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", 171 __func__, q); 172 return AH_FALSE; 173 } 174 175 /* 176 * Ignore any non-data queue(s). 177 */ 178 if (qi->tqi_type != HAL_TX_QUEUE_DATA) 179 return AH_TRUE; 180 181 /* Set turbo mode / base mode parameters on or off */ 182 if (IEEE80211_IS_CHAN_TURBO(chan)) { 183 OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME_TURBO); 184 OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT_TURBO); 185 OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY_TURBO); 186 OS_REG_WRITE(ah, AR_IFS0, 187 ((INIT_SIFS_TURBO + qi->tqi_aifs * INIT_SLOT_TIME_TURBO) 188 << AR_IFS0_DIFS_S) 189 | INIT_SIFS_TURBO); 190 OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL_TURBO); 191 OS_REG_WRITE(ah, AR_PHY(17), 192 (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x38); 193 OS_REG_WRITE(ah, AR_PHY_FRCTL, 194 AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | 195 AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | 196 AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 197 0x2020 | 198 AR_PHY_TURBO_MODE | AR_PHY_TURBO_SHORT); 199 } else { 200 OS_REG_WRITE(ah, AR_SLOT_TIME, INIT_SLOT_TIME); 201 OS_REG_WRITE(ah, AR_TIME_OUT, INIT_ACK_CTS_TIMEOUT); 202 OS_REG_WRITE(ah, AR_USEC, INIT_TRANSMIT_LATENCY); 203 OS_REG_WRITE(ah, AR_IFS0, 204 ((INIT_SIFS + qi->tqi_aifs * INIT_SLOT_TIME) 205 << AR_IFS0_DIFS_S) 206 | INIT_SIFS); 207 OS_REG_WRITE(ah, AR_IFS1, INIT_PROTO_TIME_CNTRL); 208 OS_REG_WRITE(ah, AR_PHY(17), 209 (OS_REG_READ(ah, AR_PHY(17)) & ~0x7F) | 0x1C); 210 OS_REG_WRITE(ah, AR_PHY_FRCTL, 211 AR_PHY_SERVICE_ERR | AR_PHY_TXURN_ERR | 212 AR_PHY_ILLLEN_ERR | AR_PHY_ILLRATE_ERR | 213 AR_PHY_PARITY_ERR | AR_PHY_TIMING_ERR | 0x1020); 214 } 215 216 if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) 217 cwMin = INIT_CWMIN; 218 else 219 cwMin = qi->tqi_cwmin; 220 221 /* Set cwmin and retry limit values */ 222 OS_REG_WRITE(ah, AR_RETRY_LMT, 223 (cwMin << AR_RETRY_LMT_CW_MIN_S) 224 | SM(INIT_SLG_RETRY, AR_RETRY_LMT_SLG_RETRY) 225 | SM(INIT_SSH_RETRY, AR_RETRY_LMT_SSH_RETRY) 226 | SM(qi->tqi_lgretry, AR_RETRY_LMT_LG_RETRY) 227 | SM(qi->tqi_shretry, AR_RETRY_LMT_SH_RETRY) 228 ); 229 230 if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) 231 ahp->ah_txOkInterruptMask |= 1 << q; 232 else 233 ahp->ah_txOkInterruptMask &= ~(1 << q); 234 if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) 235 ahp->ah_txErrInterruptMask |= 1 << q; 236 else 237 ahp->ah_txErrInterruptMask &= ~(1 << q); 238 if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) 239 ahp->ah_txDescInterruptMask |= 1 << q; 240 else 241 ahp->ah_txDescInterruptMask &= ~(1 << q); 242 if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) 243 ahp->ah_txEolInterruptMask |= 1 << q; 244 else 245 ahp->ah_txEolInterruptMask &= ~(1 << q); 246 if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) 247 ahp->ah_txUrnInterruptMask |= 1 << q; 248 else 249 ahp->ah_txUrnInterruptMask &= ~(1 << q); 250 251 return AH_TRUE; 252 } 253 254 /* 255 * Get the TXDP for the "main" data queue. Needs to be extended 256 * for multiple Q functionality 257 */ 258 uint32_t 259 ar5210GetTxDP(struct ath_hal *ah, u_int q) 260 { 261 struct ath_hal_5210 *ahp = AH5210(ah); 262 HAL_TX_QUEUE_INFO *qi; 263 264 HALASSERT(q < HAL_NUM_TX_QUEUES); 265 266 qi = &ahp->ah_txq[q]; 267 switch (qi->tqi_type) { 268 case HAL_TX_QUEUE_DATA: 269 return OS_REG_READ(ah, AR_TXDP0); 270 case HAL_TX_QUEUE_INACTIVE: 271 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", 272 __func__, q); 273 /* fall thru... */ 274 default: 275 break; 276 } 277 return 0xffffffff; 278 } 279 280 /* 281 * Set the TxDP for the "main" data queue. 282 */ 283 HAL_BOOL 284 ar5210SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) 285 { 286 struct ath_hal_5210 *ahp = AH5210(ah); 287 HAL_TX_QUEUE_INFO *qi; 288 289 HALASSERT(q < HAL_NUM_TX_QUEUES); 290 291 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u 0x%x\n", 292 __func__, q, txdp); 293 qi = &ahp->ah_txq[q]; 294 switch (qi->tqi_type) { 295 case HAL_TX_QUEUE_DATA: 296 #ifdef AH_DEBUG 297 /* 298 * Make sure that TXE is deasserted before setting the 299 * TXDP. If TXE is still asserted, setting TXDP will 300 * have no effect. 301 */ 302 if (OS_REG_READ(ah, AR_CR) & AR_CR_TXE0) 303 ath_hal_printf(ah, "%s: TXE asserted; AR_CR=0x%x\n", 304 __func__, OS_REG_READ(ah, AR_CR)); 305 #endif 306 OS_REG_WRITE(ah, AR_TXDP0, txdp); 307 break; 308 case HAL_TX_QUEUE_BEACON: 309 case HAL_TX_QUEUE_CAB: 310 OS_REG_WRITE(ah, AR_TXDP1, txdp); 311 break; 312 case HAL_TX_QUEUE_INACTIVE: 313 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", 314 __func__, q); 315 /* fall thru... */ 316 default: 317 return AH_FALSE; 318 } 319 return AH_TRUE; 320 } 321 322 /* 323 * Update Tx FIFO trigger level. 324 * 325 * Set bIncTrigLevel to TRUE to increase the trigger level. 326 * Set bIncTrigLevel to FALSE to decrease the trigger level. 327 * 328 * Returns TRUE if the trigger level was updated 329 */ 330 HAL_BOOL 331 ar5210UpdateTxTrigLevel(struct ath_hal *ah, HAL_BOOL bIncTrigLevel) 332 { 333 uint32_t curTrigLevel; 334 HAL_INT ints = ar5210GetInterrupts(ah); 335 336 /* 337 * Disable chip interrupts. This is because halUpdateTxTrigLevel 338 * is called from both ISR and non-ISR contexts. 339 */ 340 (void) ar5210SetInterrupts(ah, ints &~ HAL_INT_GLOBAL); 341 curTrigLevel = OS_REG_READ(ah, AR_TRIG_LEV); 342 if (bIncTrigLevel){ 343 /* increase the trigger level */ 344 curTrigLevel = curTrigLevel + 345 ((MAX_TX_FIFO_THRESHOLD - curTrigLevel) / 2); 346 } else { 347 /* decrease the trigger level if not already at the minimum */ 348 if (curTrigLevel > MIN_TX_FIFO_THRESHOLD) { 349 /* decrease the trigger level */ 350 curTrigLevel--; 351 } else { 352 /* no update to the trigger level */ 353 /* re-enable chip interrupts */ 354 ar5210SetInterrupts(ah, ints); 355 return AH_FALSE; 356 } 357 } 358 /* Update the trigger level */ 359 OS_REG_WRITE(ah, AR_TRIG_LEV, curTrigLevel); 360 /* re-enable chip interrupts */ 361 ar5210SetInterrupts(ah, ints); 362 return AH_TRUE; 363 } 364 365 /* 366 * Set Transmit Enable bits for the specified queues. 367 */ 368 HAL_BOOL 369 ar5210StartTxDma(struct ath_hal *ah, u_int q) 370 { 371 struct ath_hal_5210 *ahp = AH5210(ah); 372 HAL_TX_QUEUE_INFO *qi; 373 374 HALASSERT(q < HAL_NUM_TX_QUEUES); 375 376 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); 377 qi = &ahp->ah_txq[q]; 378 switch (qi->tqi_type) { 379 case HAL_TX_QUEUE_DATA: 380 OS_REG_WRITE(ah, AR_CR, AR_CR_TXE0); 381 break; 382 case HAL_TX_QUEUE_CAB: 383 OS_REG_WRITE(ah, AR_CR, AR_CR_TXE1); /* enable altq xmit */ 384 OS_REG_WRITE(ah, AR_BCR, 385 AR_BCR_TQ1V | AR_BCR_BDMAE | AR_BCR_TQ1FV); 386 break; 387 case HAL_TX_QUEUE_BEACON: 388 /* XXX add CR_BCR_BCMD if IBSS mode */ 389 OS_REG_WRITE(ah, AR_BCR, AR_BCR_TQ1V | AR_BCR_BDMAE); 390 break; 391 case HAL_TX_QUEUE_INACTIVE: 392 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", 393 __func__, q); 394 /* fal thru... */ 395 default: 396 return AH_FALSE; 397 } 398 return AH_TRUE; 399 } 400 401 uint32_t 402 ar5210NumTxPending(struct ath_hal *ah, u_int q) 403 { 404 struct ath_hal_5210 *ahp = AH5210(ah); 405 HAL_TX_QUEUE_INFO *qi; 406 uint32_t v; 407 408 HALASSERT(q < HAL_NUM_TX_QUEUES); 409 410 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); 411 qi = &ahp->ah_txq[q]; 412 switch (qi->tqi_type) { 413 case HAL_TX_QUEUE_DATA: 414 v = OS_REG_READ(ah, AR_CFG); 415 return MS(v, AR_CFG_TXCNT); 416 case HAL_TX_QUEUE_INACTIVE: 417 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", 418 __func__, q); 419 /* fall thru... */ 420 default: 421 break; 422 } 423 return 0; 424 } 425 426 /* 427 * Stop transmit on the specified queue 428 */ 429 HAL_BOOL 430 ar5210StopTxDma(struct ath_hal *ah, u_int q) 431 { 432 struct ath_hal_5210 *ahp = AH5210(ah); 433 HAL_TX_QUEUE_INFO *qi; 434 435 HALASSERT(q < HAL_NUM_TX_QUEUES); 436 437 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); 438 qi = &ahp->ah_txq[q]; 439 switch (qi->tqi_type) { 440 case HAL_TX_QUEUE_DATA: { 441 int i; 442 OS_REG_WRITE(ah, AR_CR, AR_CR_TXD0); 443 for (i = 0; i < 1000; i++) { 444 if ((OS_REG_READ(ah, AR_CFG) & AR_CFG_TXCNT) == 0) 445 break; 446 OS_DELAY(10); 447 } 448 OS_REG_WRITE(ah, AR_CR, 0); 449 return (i < 1000); 450 } 451 case HAL_TX_QUEUE_BEACON: 452 return ath_hal_wait(ah, AR_BSR, AR_BSR_TXQ1F, 0); 453 case HAL_TX_QUEUE_INACTIVE: 454 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: inactive queue %u\n", 455 __func__, q); 456 /* fall thru... */ 457 default: 458 break; 459 } 460 return AH_FALSE; 461 } 462 463 /* 464 * Descriptor Access Functions 465 */ 466 467 #define VALID_PKT_TYPES \ 468 ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\ 469 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\ 470 (1<<HAL_PKT_TYPE_BEACON)) 471 #define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES) 472 #define VALID_TX_RATES \ 473 ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\ 474 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\ 475 (1<<0x1d)|(1<<0x18)|(1<<0x1c)) 476 #define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES) 477 478 HAL_BOOL 479 ar5210SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, 480 u_int pktLen, 481 u_int hdrLen, 482 HAL_PKT_TYPE type, 483 u_int txPower, 484 u_int txRate0, u_int txTries0, 485 u_int keyIx, 486 u_int antMode, 487 u_int flags, 488 u_int rtsctsRate, 489 u_int rtsctsDuration, 490 u_int compicvLen, 491 u_int compivLen, 492 u_int comp) 493 { 494 struct ar5210_desc *ads = AR5210DESC(ds); 495 uint32_t frtype; 496 497 (void) txPower; 498 (void) rtsctsDuration; 499 500 HALASSERT(txTries0 != 0); 501 HALASSERT(isValidPktType(type)); 502 HALASSERT(isValidTxRate(txRate0)); 503 504 if (type == HAL_PKT_TYPE_BEACON || type == HAL_PKT_TYPE_PROBE_RESP) 505 frtype = AR_Frm_NoDelay; 506 else 507 frtype = type << 26; 508 ads->ds_ctl0 = (pktLen & AR_FrameLen) 509 | (txRate0 << AR_XmitRate_S) 510 | ((hdrLen << AR_HdrLen_S) & AR_HdrLen) 511 | frtype 512 | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) 513 | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) 514 | (antMode ? AR_AntModeXmit : 0) 515 ; 516 if (keyIx != HAL_TXKEYIX_INVALID) { 517 ads->ds_ctl1 = (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx; 518 ads->ds_ctl0 |= AR_EncryptKeyValid; 519 } else 520 ads->ds_ctl1 = 0; 521 if (flags & HAL_TXDESC_RTSENA) { 522 ads->ds_ctl0 |= AR_RTSCTSEnable; 523 ads->ds_ctl1 |= (rtsctsDuration << AR_RTSDuration_S) 524 & AR_RTSDuration; 525 } 526 return AH_TRUE; 527 } 528 529 HAL_BOOL 530 ar5210SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, 531 u_int txRate1, u_int txTries1, 532 u_int txRate2, u_int txTries2, 533 u_int txRate3, u_int txTries3) 534 { 535 (void) ah; (void) ds; 536 (void) txRate1; (void) txTries1; 537 (void) txRate2; (void) txTries2; 538 (void) txRate3; (void) txTries3; 539 return AH_FALSE; 540 } 541 542 void 543 ar5210IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) 544 { 545 struct ar5210_desc *ads = AR5210DESC(ds); 546 547 ads->ds_ctl0 |= AR_TxInterReq; 548 } 549 550 HAL_BOOL 551 ar5210FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, 552 HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int descId, 553 u_int qcuId, HAL_BOOL firstSeg, HAL_BOOL lastSeg, 554 const struct ath_desc *ds0) 555 { 556 struct ar5210_desc *ads = AR5210DESC(ds); 557 uint32_t segLen = segLenList[0]; 558 559 HALASSERT((segLen &~ AR_BufLen) == 0); 560 561 ds->ds_data = bufAddrList[0]; 562 563 if (firstSeg) { 564 /* 565 * First descriptor, don't clobber xmit control data 566 * setup by ar5210SetupTxDesc. 567 */ 568 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); 569 } else if (lastSeg) { /* !firstSeg && lastSeg */ 570 /* 571 * Last descriptor in a multi-descriptor frame, 572 * copy the transmit parameters from the first 573 * frame for processing on completion. 574 */ 575 ads->ds_ctl0 = AR5210DESC_CONST(ds0)->ds_ctl0; 576 ads->ds_ctl1 = segLen; 577 } else { /* !firstSeg && !lastSeg */ 578 /* 579 * Intermediate descriptor in a multi-descriptor frame. 580 */ 581 ads->ds_ctl0 = 0; 582 ads->ds_ctl1 = segLen | AR_More; 583 } 584 ads->ds_status0 = ads->ds_status1 = 0; 585 return AH_TRUE; 586 } 587 588 /* 589 * Processing of HW TX descriptor. 590 */ 591 HAL_STATUS 592 ar5210ProcTxDesc(struct ath_hal *ah, 593 struct ath_desc *ds, struct ath_tx_status *ts) 594 { 595 struct ar5210_desc *ads = AR5210DESC(ds); 596 597 if ((ads->ds_status1 & AR_Done) == 0) 598 return HAL_EINPROGRESS; 599 600 /* Update software copies of the HW status */ 601 ts->ts_seqnum = ads->ds_status1 & AR_SeqNum; 602 ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp); 603 ts->ts_status = 0; 604 if ((ads->ds_status0 & AR_FrmXmitOK) == 0) { 605 if (ads->ds_status0 & AR_ExcessiveRetries) 606 ts->ts_status |= HAL_TXERR_XRETRY; 607 if (ads->ds_status0 & AR_Filtered) 608 ts->ts_status |= HAL_TXERR_FILT; 609 if (ads->ds_status0 & AR_FIFOUnderrun) 610 ts->ts_status |= HAL_TXERR_FIFO; 611 } 612 ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate); 613 ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength); 614 ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt); 615 ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt); 616 ts->ts_antenna = 0; /* NB: don't know */ 617 ts->ts_finaltsi = 0; 618 619 return HAL_OK; 620 } 621 622 /* 623 * Determine which tx queues need interrupt servicing. 624 * STUB. 625 */ 626 void 627 ar5210GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) 628 { 629 return; 630 } 631 632 /* 633 * Retrieve the rate table from the given TX completion descriptor 634 */ 635 HAL_BOOL 636 ar5210GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries) 637 { 638 return AH_FALSE; 639 } 640 641 /* 642 * Set the TX descriptor link pointer 643 */ 644 void 645 ar5210SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link) 646 { 647 struct ar5210_desc *ads = AR5210DESC(ds); 648 649 ads->ds_link = link; 650 } 651 652 /* 653 * Get the TX descriptor link pointer 654 */ 655 void 656 ar5210GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link) 657 { 658 struct ar5210_desc *ads = AR5210DESC(ds); 659 660 *link = ads->ds_link; 661 } 662 663 /* 664 * Get a pointer to the TX descriptor link pointer 665 */ 666 void 667 ar5210GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr) 668 { 669 struct ar5210_desc *ads = AR5210DESC(ds); 670 671 *linkptr = &ads->ds_link; 672 } 673