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 /* 198 * Free a tx DCU/QCU combination. 199 */ 200 HAL_BOOL 201 ar5211ReleaseTxQueue(struct ath_hal *ah, u_int q) 202 { 203 struct ath_hal_5211 *ahp = AH5211(ah); 204 HAL_TX_QUEUE_INFO *qi; 205 206 if (q >= HAL_NUM_TX_QUEUES) { 207 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", 208 __func__, q); 209 return AH_FALSE; 210 } 211 qi = &ahp->ah_txq[q]; 212 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 213 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", 214 __func__, q); 215 return AH_FALSE; 216 } 217 218 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: release queue %u\n", __func__, q); 219 220 qi->tqi_type = HAL_TX_QUEUE_INACTIVE; 221 ahp->ah_txOkInterruptMask &= ~(1 << q); 222 ahp->ah_txErrInterruptMask &= ~(1 << q); 223 ahp->ah_txDescInterruptMask &= ~(1 << q); 224 ahp->ah_txEolInterruptMask &= ~(1 << q); 225 ahp->ah_txUrnInterruptMask &= ~(1 << q); 226 setTxQInterrupts(ah, qi); 227 228 return AH_TRUE; 229 } 230 231 /* 232 * Set the retry, aifs, cwmin/max, readyTime regs for specified queue 233 */ 234 HAL_BOOL 235 ar5211ResetTxQueue(struct ath_hal *ah, u_int q) 236 { 237 struct ath_hal_5211 *ahp = AH5211(ah); 238 const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; 239 HAL_TX_QUEUE_INFO *qi; 240 uint32_t cwMin, chanCwMin, value; 241 242 if (q >= HAL_NUM_TX_QUEUES) { 243 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid queue num %u\n", 244 __func__, q); 245 return AH_FALSE; 246 } 247 qi = &ahp->ah_txq[q]; 248 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 249 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: inactive queue %u\n", 250 __func__, q); 251 return AH_TRUE; /* XXX??? */ 252 } 253 254 if (qi->tqi_cwmin == HAL_TXQ_USEDEFAULT) { 255 /* 256 * Select cwmin according to channel type. 257 * NB: chan can be NULL during attach 258 */ 259 if (chan && IEEE80211_IS_CHAN_B(chan)) 260 chanCwMin = INIT_CWMIN_11B; 261 else 262 chanCwMin = INIT_CWMIN; 263 /* make sure that the CWmin is of the form (2^n - 1) */ 264 for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1) 265 ; 266 } else 267 cwMin = qi->tqi_cwmin; 268 269 /* set cwMin/Max and AIFS values */ 270 OS_REG_WRITE(ah, AR_DLCL_IFS(q), 271 SM(cwMin, AR_D_LCL_IFS_CWMIN) 272 | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) 273 | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); 274 275 /* Set retry limit values */ 276 OS_REG_WRITE(ah, AR_DRETRY_LIMIT(q), 277 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) 278 | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) 279 | SM(qi->tqi_lgretry, AR_D_RETRY_LIMIT_FR_LG) 280 | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) 281 ); 282 283 /* enable early termination on the QCU */ 284 OS_REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); 285 286 if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) { 287 /* Configure DCU to use the global sequence count */ 288 OS_REG_WRITE(ah, AR_DMISC(q), AR5311_D_MISC_SEQ_NUM_CONTROL); 289 } 290 /* multiqueue support */ 291 if (qi->tqi_cbrPeriod) { 292 OS_REG_WRITE(ah, AR_QCBRCFG(q), 293 SM(qi->tqi_cbrPeriod,AR_Q_CBRCFG_CBR_INTERVAL) 294 | SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_CBR_OVF_THRESH)); 295 OS_REG_WRITE(ah, AR_QMISC(q), 296 OS_REG_READ(ah, AR_QMISC(q)) | 297 AR_Q_MISC_FSP_CBR | 298 (qi->tqi_cbrOverflowLimit ? 299 AR_Q_MISC_CBR_EXP_CNTR_LIMIT : 0)); 300 } 301 if (qi->tqi_readyTime) { 302 OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), 303 SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_INT) | 304 AR_Q_RDYTIMECFG_EN); 305 } 306 if (qi->tqi_burstTime) { 307 OS_REG_WRITE(ah, AR_DCHNTIME(q), 308 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | 309 AR_D_CHNTIME_EN); 310 if (qi->tqi_qflags & HAL_TXQ_RDYTIME_EXP_POLICY_ENABLE) { 311 OS_REG_WRITE(ah, AR_QMISC(q), 312 OS_REG_READ(ah, AR_QMISC(q)) | 313 AR_Q_MISC_RDYTIME_EXP_POLICY); 314 } 315 } 316 317 if (qi->tqi_qflags & HAL_TXQ_BACKOFF_DISABLE) { 318 OS_REG_WRITE(ah, AR_DMISC(q), 319 OS_REG_READ(ah, AR_DMISC(q)) | 320 AR_D_MISC_POST_FR_BKOFF_DIS); 321 } 322 if (qi->tqi_qflags & HAL_TXQ_FRAG_BURST_BACKOFF_ENABLE) { 323 OS_REG_WRITE(ah, AR_DMISC(q), 324 OS_REG_READ(ah, AR_DMISC(q)) | 325 AR_D_MISC_FRAG_BKOFF_EN); 326 } 327 switch (qi->tqi_type) { 328 case HAL_TX_QUEUE_BEACON: 329 /* Configure QCU for beacons */ 330 OS_REG_WRITE(ah, AR_QMISC(q), 331 OS_REG_READ(ah, AR_QMISC(q)) 332 | AR_Q_MISC_FSP_DBA_GATED 333 | AR_Q_MISC_BEACON_USE 334 | AR_Q_MISC_CBR_INCR_DIS1); 335 /* Configure DCU for beacons */ 336 value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S) 337 | AR_D_MISC_BEACON_USE | AR_D_MISC_POST_FR_BKOFF_DIS; 338 if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) 339 value |= AR5311_D_MISC_SEQ_NUM_CONTROL; 340 OS_REG_WRITE(ah, AR_DMISC(q), value); 341 break; 342 case HAL_TX_QUEUE_CAB: 343 /* Configure QCU for CAB (Crap After Beacon) frames */ 344 OS_REG_WRITE(ah, AR_QMISC(q), 345 OS_REG_READ(ah, AR_QMISC(q)) 346 | AR_Q_MISC_FSP_DBA_GATED | AR_Q_MISC_CBR_INCR_DIS1 347 | AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY); 348 349 value = (ahp->ah_beaconInterval 350 - (ah->ah_config.ah_sw_beacon_response_time 351 - ah->ah_config.ah_dma_beacon_response_time) 352 - ah->ah_config.ah_additional_swba_backoff) * 1024; 353 OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); 354 355 /* Configure DCU for CAB */ 356 value = (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S); 357 if (AH_PRIVATE(ah)->ah_macVersion < AR_SREV_VERSION_OAHU) 358 value |= AR5311_D_MISC_SEQ_NUM_CONTROL; 359 OS_REG_WRITE(ah, AR_QMISC(q), value); 360 break; 361 default: 362 /* NB: silence compiler */ 363 break; 364 } 365 366 /* 367 * Always update the secondary interrupt mask registers - this 368 * could be a new queue getting enabled in a running system or 369 * hw getting re-initialized during a reset! 370 * 371 * Since we don't differentiate between tx interrupts corresponding 372 * to individual queues - secondary tx mask regs are always unmasked; 373 * tx interrupts are enabled/disabled for all queues collectively 374 * using the primary mask reg 375 */ 376 if (qi->tqi_qflags & HAL_TXQ_TXOKINT_ENABLE) 377 ahp->ah_txOkInterruptMask |= 1 << q; 378 else 379 ahp->ah_txOkInterruptMask &= ~(1 << q); 380 if (qi->tqi_qflags & HAL_TXQ_TXERRINT_ENABLE) 381 ahp->ah_txErrInterruptMask |= 1 << q; 382 else 383 ahp->ah_txErrInterruptMask &= ~(1 << q); 384 if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) 385 ahp->ah_txDescInterruptMask |= 1 << q; 386 else 387 ahp->ah_txDescInterruptMask &= ~(1 << q); 388 if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) 389 ahp->ah_txEolInterruptMask |= 1 << q; 390 else 391 ahp->ah_txEolInterruptMask &= ~(1 << q); 392 if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) 393 ahp->ah_txUrnInterruptMask |= 1 << q; 394 else 395 ahp->ah_txUrnInterruptMask &= ~(1 << q); 396 setTxQInterrupts(ah, qi); 397 398 return AH_TRUE; 399 } 400 401 /* 402 * Get the TXDP for the specified data queue. 403 */ 404 uint32_t 405 ar5211GetTxDP(struct ath_hal *ah, u_int q) 406 { 407 HALASSERT(q < HAL_NUM_TX_QUEUES); 408 return OS_REG_READ(ah, AR_QTXDP(q)); 409 } 410 411 /* 412 * Set the TxDP for the specified tx queue. 413 */ 414 HAL_BOOL 415 ar5211SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp) 416 { 417 HALASSERT(q < HAL_NUM_TX_QUEUES); 418 HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); 419 420 /* 421 * Make sure that TXE is deasserted before setting the TXDP. If TXE 422 * is still asserted, setting TXDP will have no effect. 423 */ 424 HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0); 425 426 OS_REG_WRITE(ah, AR_QTXDP(q), txdp); 427 428 return AH_TRUE; 429 } 430 431 /* 432 * Set Transmit Enable bits for the specified queues. 433 */ 434 HAL_BOOL 435 ar5211StartTxDma(struct ath_hal *ah, u_int q) 436 { 437 HALASSERT(q < HAL_NUM_TX_QUEUES); 438 HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); 439 440 /* Check that queue is not already active */ 441 HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1<<q)) == 0); 442 443 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); 444 445 /* Check to be sure we're not enabling a q that has its TXD bit set. */ 446 HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0); 447 448 OS_REG_WRITE(ah, AR_Q_TXE, 1 << q); 449 return AH_TRUE; 450 } 451 452 /* 453 * Return the number of frames pending on the specified queue. 454 */ 455 uint32_t 456 ar5211NumTxPending(struct ath_hal *ah, u_int q) 457 { 458 uint32_t n; 459 460 HALASSERT(q < HAL_NUM_TX_QUEUES); 461 HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); 462 463 n = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT_M; 464 /* 465 * Pending frame count (PFC) can momentarily go to zero 466 * while TXE remains asserted. In other words a PFC of 467 * zero is not sufficient to say that the queue has stopped. 468 */ 469 if (n == 0 && (OS_REG_READ(ah, AR_Q_TXE) & (1<<q))) 470 n = 1; /* arbitrarily pick 1 */ 471 return n; 472 } 473 474 /* 475 * Stop transmit on the specified queue 476 */ 477 HAL_BOOL 478 ar5211StopTxDma(struct ath_hal *ah, u_int q) 479 { 480 int i; 481 482 HALASSERT(q < HAL_NUM_TX_QUEUES); 483 HALASSERT(AH5211(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); 484 485 OS_REG_WRITE(ah, AR_Q_TXD, 1<<q); 486 for (i = 0; i < 10000; i++) { 487 if (ar5211NumTxPending(ah, q) == 0) 488 break; 489 OS_DELAY(10); 490 } 491 OS_REG_WRITE(ah, AR_Q_TXD, 0); 492 493 return (i < 10000); 494 } 495 496 /* 497 * Descriptor Access Functions 498 */ 499 500 #define VALID_PKT_TYPES \ 501 ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\ 502 (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\ 503 (1<<HAL_PKT_TYPE_BEACON)) 504 #define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES) 505 #define VALID_TX_RATES \ 506 ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\ 507 (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\ 508 (1<<0x1d)|(1<<0x18)|(1<<0x1c)) 509 #define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES) 510 511 HAL_BOOL 512 ar5211SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, 513 u_int pktLen, 514 u_int hdrLen, 515 HAL_PKT_TYPE type, 516 u_int txPower, 517 u_int txRate0, u_int txTries0, 518 u_int keyIx, 519 u_int antMode, 520 u_int flags, 521 u_int rtsctsRate, 522 u_int rtsctsDuration, 523 u_int compicvLen, 524 u_int compivLen, 525 u_int comp) 526 { 527 struct ar5211_desc *ads = AR5211DESC(ds); 528 529 (void) hdrLen; 530 (void) txPower; 531 (void) rtsctsRate; (void) rtsctsDuration; 532 533 HALASSERT(txTries0 != 0); 534 HALASSERT(isValidPktType(type)); 535 HALASSERT(isValidTxRate(txRate0)); 536 /* XXX validate antMode */ 537 538 ads->ds_ctl0 = (pktLen & AR_FrameLen) 539 | (txRate0 << AR_XmitRate_S) 540 | (antMode << AR_AntModeXmit_S) 541 | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) 542 | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) 543 | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0) 544 | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) 545 ; 546 ads->ds_ctl1 = (type << 26) 547 | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) 548 ; 549 550 if (keyIx != HAL_TXKEYIX_INVALID) { 551 ads->ds_ctl1 |= 552 (keyIx << AR_EncryptKeyIdx_S) & AR_EncryptKeyIdx; 553 ads->ds_ctl0 |= AR_EncryptKeyValid; 554 } 555 return AH_TRUE; 556 #undef RATE 557 } 558 559 HAL_BOOL 560 ar5211SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, 561 u_int txRate1, u_int txTries1, 562 u_int txRate2, u_int txTries2, 563 u_int txRate3, u_int txTries3) 564 { 565 (void) ah; (void) ds; 566 (void) txRate1; (void) txTries1; 567 (void) txRate2; (void) txTries2; 568 (void) txRate3; (void) txTries3; 569 return AH_FALSE; 570 } 571 572 void 573 ar5211IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds) 574 { 575 struct ar5211_desc *ads = AR5211DESC(ds); 576 577 ads->ds_ctl0 |= AR_TxInterReq; 578 } 579 580 HAL_BOOL 581 ar5211FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, 582 HAL_DMA_ADDR *bufAddrList, uint32_t *segLenList, u_int qcuId, 583 u_int descId, HAL_BOOL firstSeg, HAL_BOOL lastSeg, 584 const struct ath_desc *ds0) 585 { 586 struct ar5211_desc *ads = AR5211DESC(ds); 587 uint32_t segLen = segLenList[0]; 588 589 ds->ds_data = bufAddrList[0]; 590 591 HALASSERT((segLen &~ AR_BufLen) == 0); 592 593 if (firstSeg) { 594 /* 595 * First descriptor, don't clobber xmit control data 596 * setup by ar5211SetupTxDesc. 597 */ 598 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); 599 } else if (lastSeg) { /* !firstSeg && lastSeg */ 600 /* 601 * Last descriptor in a multi-descriptor frame, 602 * copy the transmit parameters from the first 603 * frame for processing on completion. 604 */ 605 ads->ds_ctl0 = AR5211DESC_CONST(ds0)->ds_ctl0; 606 ads->ds_ctl1 = segLen; 607 } else { /* !firstSeg && !lastSeg */ 608 /* 609 * Intermediate descriptor in a multi-descriptor frame. 610 */ 611 ads->ds_ctl0 = 0; 612 ads->ds_ctl1 = segLen | AR_More; 613 } 614 ads->ds_status0 = ads->ds_status1 = 0; 615 return AH_TRUE; 616 } 617 618 /* 619 * Processing of HW TX descriptor. 620 */ 621 HAL_STATUS 622 ar5211ProcTxDesc(struct ath_hal *ah, 623 struct ath_desc *ds, struct ath_tx_status *ts) 624 { 625 struct ar5211_desc *ads = AR5211DESC(ds); 626 627 if ((ads->ds_status1 & AR_Done) == 0) 628 return HAL_EINPROGRESS; 629 630 /* Update software copies of the HW status */ 631 ts->ts_seqnum = MS(ads->ds_status1, AR_SeqNum); 632 ts->ts_tstamp = MS(ads->ds_status0, AR_SendTimestamp); 633 ts->ts_status = 0; 634 if ((ads->ds_status0 & AR_FrmXmitOK) == 0) { 635 if (ads->ds_status0 & AR_ExcessiveRetries) 636 ts->ts_status |= HAL_TXERR_XRETRY; 637 if (ads->ds_status0 & AR_Filtered) 638 ts->ts_status |= HAL_TXERR_FILT; 639 if (ads->ds_status0 & AR_FIFOUnderrun) 640 ts->ts_status |= HAL_TXERR_FIFO; 641 } 642 ts->ts_rate = MS(ads->ds_ctl0, AR_XmitRate); 643 ts->ts_rssi = MS(ads->ds_status1, AR_AckSigStrength); 644 ts->ts_shortretry = MS(ads->ds_status0, AR_ShortRetryCnt); 645 ts->ts_longretry = MS(ads->ds_status0, AR_LongRetryCnt); 646 ts->ts_virtcol = MS(ads->ds_status0, AR_VirtCollCnt); 647 ts->ts_antenna = 0; /* NB: don't know */ 648 ts->ts_finaltsi = 0; 649 /* 650 * NB: the number of retries is one less than it should be. 651 * Also, 0 retries and 1 retry are both reported as 0 retries. 652 */ 653 if (ts->ts_shortretry > 0) 654 ts->ts_shortretry++; 655 if (ts->ts_longretry > 0) 656 ts->ts_longretry++; 657 658 return HAL_OK; 659 } 660 661 /* 662 * Determine which tx queues need interrupt servicing. 663 * STUB. 664 */ 665 void 666 ar5211GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs) 667 { 668 return; 669 } 670 671 /* 672 * Retrieve the rate table from the given TX completion descriptor 673 */ 674 HAL_BOOL 675 ar5211GetTxCompletionRates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries) 676 { 677 return AH_FALSE; 678 } 679 680 681 void 682 ar5211SetTxDescLink(struct ath_hal *ah, void *ds, uint32_t link) 683 { 684 struct ar5211_desc *ads = AR5211DESC(ds); 685 686 ads->ds_link = link; 687 } 688 689 void 690 ar5211GetTxDescLink(struct ath_hal *ah, void *ds, uint32_t *link) 691 { 692 struct ar5211_desc *ads = AR5211DESC(ds); 693 694 *link = ads->ds_link; 695 } 696 697 void 698 ar5211GetTxDescLinkPtr(struct ath_hal *ah, void *ds, uint32_t **linkptr) 699 { 700 struct ar5211_desc *ads = AR5211DESC(ds); 701 702 *linkptr = &ads->ds_link; 703 } 704