ah.c revision 188773
1/* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 188773 2009-02-19 04:24:22Z sam $ 18 */ 19#include "opt_ah.h" 20 21#include "ah.h" 22#include "ah_internal.h" 23#include "ah_devid.h" 24 25/* linker set of registered chips */ 26OS_SET_DECLARE(ah_chips, struct ath_hal_chip); 27 28/* 29 * Check the set of registered chips to see if any recognize 30 * the device as one they can support. 31 */ 32const char* 33ath_hal_probe(uint16_t vendorid, uint16_t devid) 34{ 35 struct ath_hal_chip * const *pchip; 36 37 OS_SET_FOREACH(pchip, ah_chips) { 38 const char *name = (*pchip)->probe(vendorid, devid); 39 if (name != AH_NULL) 40 return name; 41 } 42 return AH_NULL; 43} 44 45/* 46 * Attach detects device chip revisions, initializes the hwLayer 47 * function list, reads EEPROM information, 48 * selects reset vectors, and performs a short self test. 49 * Any failures will return an error that should cause a hardware 50 * disable. 51 */ 52struct ath_hal* 53ath_hal_attach(uint16_t devid, HAL_SOFTC sc, 54 HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error) 55{ 56 struct ath_hal_chip * const *pchip; 57 58 OS_SET_FOREACH(pchip, ah_chips) { 59 struct ath_hal_chip *chip = *pchip; 60 struct ath_hal *ah; 61 62 /* XXX don't have vendorid, assume atheros one works */ 63 if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 64 continue; 65 ah = chip->attach(devid, sc, st, sh, error); 66 if (ah != AH_NULL) { 67 /* copy back private state to public area */ 68 ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 69 ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 70 ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 71 ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 72 ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 73 ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 74 ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 75 return ah; 76 } 77 } 78 return AH_NULL; 79} 80 81/* 82 * Return the mask of available modes based on the hardware capabilities. 83 */ 84u_int 85ath_hal_getwirelessmodes(struct ath_hal*ah) 86{ 87 return ath_hal_getWirelessModes(ah); 88} 89 90/* linker set of registered RF backends */ 91OS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 92 93/* 94 * Check the set of registered RF backends to see if 95 * any recognize the device as one they can support. 96 */ 97struct ath_hal_rf * 98ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 99{ 100 struct ath_hal_rf * const *prf; 101 102 OS_SET_FOREACH(prf, ah_rfs) { 103 struct ath_hal_rf *rf = *prf; 104 if (rf->probe(ah)) 105 return rf; 106 } 107 *ecode = HAL_ENOTSUPP; 108 return AH_NULL; 109} 110 111/* 112 * Poll the register looking for a specific value. 113 */ 114HAL_BOOL 115ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 116{ 117#define AH_TIMEOUT 1000 118 int i; 119 120 for (i = 0; i < AH_TIMEOUT; i++) { 121 if ((OS_REG_READ(ah, reg) & mask) == val) 122 return AH_TRUE; 123 OS_DELAY(10); 124 } 125 HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 126 "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 127 __func__, reg, OS_REG_READ(ah, reg), mask, val); 128 return AH_FALSE; 129#undef AH_TIMEOUT 130} 131 132/* 133 * Reverse the bits starting at the low bit for a value of 134 * bit_count in size 135 */ 136uint32_t 137ath_hal_reverseBits(uint32_t val, uint32_t n) 138{ 139 uint32_t retval; 140 int i; 141 142 for (i = 0, retval = 0; i < n; i++) { 143 retval = (retval << 1) | (val & 1); 144 val >>= 1; 145 } 146 return retval; 147} 148 149/* 150 * Compute the time to transmit a frame of length frameLen bytes 151 * using the specified rate, phy, and short preamble setting. 152 */ 153uint16_t 154ath_hal_computetxtime(struct ath_hal *ah, 155 const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 156 HAL_BOOL shortPreamble) 157{ 158 uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 159 uint32_t kbps; 160 161 kbps = rates->info[rateix].rateKbps; 162 /* 163 * index can be invalid duting dynamic Turbo transitions. 164 * XXX 165 */ 166 if (kbps == 0) 167 return 0; 168 switch (rates->info[rateix].phy) { 169 case IEEE80211_T_CCK: 170 phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 171 if (shortPreamble && rates->info[rateix].shortPreamble) 172 phyTime >>= 1; 173 numBits = frameLen << 3; 174 txTime = CCK_SIFS_TIME + phyTime 175 + ((numBits * 1000)/kbps); 176 break; 177 case IEEE80211_T_OFDM: 178 bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 179 HALASSERT(bitsPerSymbol != 0); 180 181 numBits = OFDM_PLCP_BITS + (frameLen << 3); 182 numSymbols = howmany(numBits, bitsPerSymbol); 183 txTime = OFDM_SIFS_TIME 184 + OFDM_PREAMBLE_TIME 185 + (numSymbols * OFDM_SYMBOL_TIME); 186 break; 187 case IEEE80211_T_OFDM_HALF: 188 bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 189 HALASSERT(bitsPerSymbol != 0); 190 191 numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 192 numSymbols = howmany(numBits, bitsPerSymbol); 193 txTime = OFDM_HALF_SIFS_TIME 194 + OFDM_HALF_PREAMBLE_TIME 195 + (numSymbols * OFDM_HALF_SYMBOL_TIME); 196 break; 197 case IEEE80211_T_OFDM_QUARTER: 198 bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 199 HALASSERT(bitsPerSymbol != 0); 200 201 numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 202 numSymbols = howmany(numBits, bitsPerSymbol); 203 txTime = OFDM_QUARTER_SIFS_TIME 204 + OFDM_QUARTER_PREAMBLE_TIME 205 + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 206 break; 207 case IEEE80211_T_TURBO: 208 /* we still save OFDM rates in kbps - so double them */ 209 bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; 210 HALASSERT(bitsPerSymbol != 0); 211 212 numBits = TURBO_PLCP_BITS + (frameLen << 3); 213 numSymbols = howmany(numBits, bitsPerSymbol); 214 txTime = TURBO_SIFS_TIME 215 + TURBO_PREAMBLE_TIME 216 + (numSymbols * TURBO_SYMBOL_TIME); 217 break; 218 default: 219 HALDEBUG(ah, HAL_DEBUG_PHYIO, 220 "%s: unknown phy %u (rate ix %u)\n", 221 __func__, rates->info[rateix].phy, rateix); 222 txTime = 0; 223 break; 224 } 225 return txTime; 226} 227 228typedef enum { 229 WIRELESS_MODE_11a = 0, 230 WIRELESS_MODE_TURBO = 1, 231 WIRELESS_MODE_11b = 2, 232 WIRELESS_MODE_11g = 3, 233 WIRELESS_MODE_108g = 4, 234 235 WIRELESS_MODE_MAX 236} WIRELESS_MODE; 237 238static WIRELESS_MODE 239ath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 240{ 241 if (IEEE80211_IS_CHAN_B(chan)) 242 return WIRELESS_MODE_11b; 243 if (IEEE80211_IS_CHAN_G(chan)) 244 return WIRELESS_MODE_11g; 245 if (IEEE80211_IS_CHAN_108G(chan)) 246 return WIRELESS_MODE_108g; 247 if (IEEE80211_IS_CHAN_TURBO(chan)) 248 return WIRELESS_MODE_TURBO; 249 return WIRELESS_MODE_11a; 250} 251 252/* 253 * Convert between microseconds and core system clocks. 254 */ 255 /* 11a Turbo 11b 11g 108g */ 256static const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 257 258u_int 259ath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 260{ 261 const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 262 u_int clks; 263 264 /* NB: ah_curchan may be null when called attach time */ 265 if (c != AH_NULL) { 266 clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 267 if (IEEE80211_IS_CHAN_HT40(c)) 268 clks <<= 1; 269 else if (IEEE80211_IS_CHAN_HALF(c)) 270 clks >>= 1; 271 else if (IEEE80211_IS_CHAN_QUARTER(c)) 272 clks >>= 2; 273 } else 274 clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 275 return clks; 276} 277 278u_int 279ath_hal_mac_usec(struct ath_hal *ah, u_int clks) 280{ 281 const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 282 u_int usec; 283 284 /* NB: ah_curchan may be null when called attach time */ 285 if (c != AH_NULL) { 286 usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 287 if (IEEE80211_IS_CHAN_HT40(c)) 288 usec >>= 1; 289 else if (IEEE80211_IS_CHAN_HALF(c)) 290 usec <<= 1; 291 else if (IEEE80211_IS_CHAN_QUARTER(c)) 292 usec <<= 2; 293 } else 294 usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 295 return usec; 296} 297 298/* 299 * Setup a h/w rate table's reverse lookup table and 300 * fill in ack durations. This routine is called for 301 * each rate table returned through the ah_getRateTable 302 * method. The reverse lookup tables are assumed to be 303 * initialized to zero (or at least the first entry). 304 * We use this as a key that indicates whether or not 305 * we've previously setup the reverse lookup table. 306 * 307 * XXX not reentrant, but shouldn't matter 308 */ 309void 310ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 311{ 312#define N(a) (sizeof(a)/sizeof(a[0])) 313 int i; 314 315 if (rt->rateCodeToIndex[0] != 0) /* already setup */ 316 return; 317 for (i = 0; i < N(rt->rateCodeToIndex); i++) 318 rt->rateCodeToIndex[i] = (uint8_t) -1; 319 for (i = 0; i < rt->rateCount; i++) { 320 uint8_t code = rt->info[i].rateCode; 321 uint8_t cix = rt->info[i].controlRate; 322 323 HALASSERT(code < N(rt->rateCodeToIndex)); 324 rt->rateCodeToIndex[code] = i; 325 HALASSERT((code | rt->info[i].shortPreamble) < 326 N(rt->rateCodeToIndex)); 327 rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 328 /* 329 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 330 * depends on whether they are marked as basic rates; 331 * the static tables are setup with an 11b-compatible 332 * 2Mb/s rate which will work but is suboptimal 333 */ 334 rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 335 WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 336 rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 337 WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 338 } 339#undef N 340} 341 342HAL_STATUS 343ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 344 uint32_t capability, uint32_t *result) 345{ 346 const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 347 348 switch (type) { 349 case HAL_CAP_REG_DMN: /* regulatory domain */ 350 *result = AH_PRIVATE(ah)->ah_currentRD; 351 return HAL_OK; 352 case HAL_CAP_CIPHER: /* cipher handled in hardware */ 353 case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 354 return HAL_ENOTSUPP; 355 case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 356 return HAL_ENOTSUPP; 357 case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 358 return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 359 case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 360 return HAL_ENOTSUPP; 361 case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 362 return HAL_ENOTSUPP; 363 case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 364 *result = pCap->halKeyCacheSize; 365 return HAL_OK; 366 case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 367 *result = pCap->halTotalQueues; 368 return HAL_OK; 369 case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 370 return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 371 case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 372 return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 373 case HAL_CAP_COMPRESSION: 374 return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 375 case HAL_CAP_BURST: 376 return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 377 case HAL_CAP_FASTFRAME: 378 return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 379 case HAL_CAP_DIAG: /* hardware diagnostic support */ 380 *result = AH_PRIVATE(ah)->ah_diagreg; 381 return HAL_OK; 382 case HAL_CAP_TXPOW: /* global tx power limit */ 383 switch (capability) { 384 case 0: /* facility is supported */ 385 return HAL_OK; 386 case 1: /* current limit */ 387 *result = AH_PRIVATE(ah)->ah_powerLimit; 388 return HAL_OK; 389 case 2: /* current max tx power */ 390 *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 391 return HAL_OK; 392 case 3: /* scale factor */ 393 *result = AH_PRIVATE(ah)->ah_tpScale; 394 return HAL_OK; 395 } 396 return HAL_ENOTSUPP; 397 case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 398 return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 399 case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 400 return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 401 case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 402 return HAL_ENOTSUPP; 403 case HAL_CAP_RFSILENT: /* rfsilent support */ 404 switch (capability) { 405 case 0: /* facility is supported */ 406 return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 407 case 1: /* current setting */ 408 return AH_PRIVATE(ah)->ah_rfkillEnabled ? 409 HAL_OK : HAL_ENOTSUPP; 410 case 2: /* rfsilent config */ 411 *result = AH_PRIVATE(ah)->ah_rfsilent; 412 return HAL_OK; 413 } 414 return HAL_ENOTSUPP; 415 case HAL_CAP_11D: 416 return HAL_OK; 417 case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 418 return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 419 case HAL_CAP_HT: 420 return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 421 case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 422 *result = pCap->halTxChainMask; 423 return HAL_OK; 424 case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 425 *result = pCap->halRxChainMask; 426 return HAL_OK; 427 case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 428 *result = pCap->halTstampPrecision; 429 return HAL_OK; 430 default: 431 return HAL_EINVAL; 432 } 433} 434 435HAL_BOOL 436ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 437 uint32_t capability, uint32_t setting, HAL_STATUS *status) 438{ 439 440 switch (type) { 441 case HAL_CAP_TXPOW: 442 switch (capability) { 443 case 3: 444 if (setting <= HAL_TP_SCALE_MIN) { 445 AH_PRIVATE(ah)->ah_tpScale = setting; 446 return AH_TRUE; 447 } 448 break; 449 } 450 break; 451 case HAL_CAP_RFSILENT: /* rfsilent support */ 452 /* 453 * NB: allow even if halRfSilentSupport is false 454 * in case the EEPROM is misprogrammed. 455 */ 456 switch (capability) { 457 case 1: /* current setting */ 458 AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 459 return AH_TRUE; 460 case 2: /* rfsilent config */ 461 /* XXX better done per-chip for validation? */ 462 AH_PRIVATE(ah)->ah_rfsilent = setting; 463 return AH_TRUE; 464 } 465 break; 466 case HAL_CAP_REG_DMN: /* regulatory domain */ 467 AH_PRIVATE(ah)->ah_currentRD = setting; 468 return AH_TRUE; 469 case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 470 AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 471 return AH_TRUE; 472 default: 473 break; 474 } 475 if (status) 476 *status = HAL_EINVAL; 477 return AH_FALSE; 478} 479 480/* 481 * Common support for getDiagState method. 482 */ 483 484static u_int 485ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 486 void *dstbuf, int space) 487{ 488 uint32_t *dp = dstbuf; 489 int i; 490 491 for (i = 0; space >= 2*sizeof(uint32_t); i++) { 492 u_int r = regs[i].start; 493 u_int e = regs[i].end; 494 *dp++ = (r<<16) | e; 495 space -= sizeof(uint32_t); 496 do { 497 *dp++ = OS_REG_READ(ah, r); 498 r += sizeof(uint32_t); 499 space -= sizeof(uint32_t); 500 } while (r <= e && space >= sizeof(uint32_t)); 501 } 502 return (char *) dp - (char *) dstbuf; 503} 504 505static void 506ath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 507{ 508 while (space >= sizeof(HAL_REGWRITE)) { 509 OS_REG_WRITE(ah, regs->addr, regs->value); 510 regs++, space -= sizeof(HAL_REGWRITE); 511 } 512} 513 514HAL_BOOL 515ath_hal_getdiagstate(struct ath_hal *ah, int request, 516 const void *args, uint32_t argsize, 517 void **result, uint32_t *resultsize) 518{ 519 switch (request) { 520 case HAL_DIAG_REVS: 521 *result = &AH_PRIVATE(ah)->ah_devid; 522 *resultsize = sizeof(HAL_REVS); 523 return AH_TRUE; 524 case HAL_DIAG_REGS: 525 *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 526 return AH_TRUE; 527 case HAL_DIAG_SETREGS: 528 ath_hal_setregs(ah, args, argsize); 529 *resultsize = 0; 530 return AH_TRUE; 531 case HAL_DIAG_FATALERR: 532 *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 533 *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 534 return AH_TRUE; 535 case HAL_DIAG_EEREAD: 536 if (argsize != sizeof(uint16_t)) 537 return AH_FALSE; 538 if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 539 return AH_FALSE; 540 *resultsize = sizeof(uint16_t); 541 return AH_TRUE; 542#ifdef AH_PRIVATE_DIAG 543 case HAL_DIAG_SETKEY: { 544 const HAL_DIAG_KEYVAL *dk; 545 546 if (argsize != sizeof(HAL_DIAG_KEYVAL)) 547 return AH_FALSE; 548 dk = (const HAL_DIAG_KEYVAL *)args; 549 return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 550 &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 551 } 552 case HAL_DIAG_RESETKEY: 553 if (argsize != sizeof(uint16_t)) 554 return AH_FALSE; 555 return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 556#ifdef AH_SUPPORT_WRITE_EEPROM 557 case HAL_DIAG_EEWRITE: { 558 const HAL_DIAG_EEVAL *ee; 559 if (argsize != sizeof(HAL_DIAG_EEVAL)) 560 return AH_FALSE; 561 ee = (const HAL_DIAG_EEVAL *)args; 562 return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 563 } 564#endif /* AH_SUPPORT_WRITE_EEPROM */ 565#endif /* AH_PRIVATE_DIAG */ 566 case HAL_DIAG_11NCOMPAT: 567 if (argsize == 0) { 568 *resultsize = sizeof(uint32_t); 569 *((uint32_t *)(*result)) = 570 AH_PRIVATE(ah)->ah_11nCompat; 571 } else if (argsize == sizeof(uint32_t)) { 572 AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 573 } else 574 return AH_FALSE; 575 return AH_TRUE; 576 } 577 return AH_FALSE; 578} 579 580/* 581 * Set the properties of the tx queue with the parameters 582 * from qInfo. 583 */ 584HAL_BOOL 585ath_hal_setTxQProps(struct ath_hal *ah, 586 HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 587{ 588 uint32_t cw; 589 590 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 591 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 592 "%s: inactive queue\n", __func__); 593 return AH_FALSE; 594 } 595 /* XXX validate parameters */ 596 qi->tqi_ver = qInfo->tqi_ver; 597 qi->tqi_subtype = qInfo->tqi_subtype; 598 qi->tqi_qflags = qInfo->tqi_qflags; 599 qi->tqi_priority = qInfo->tqi_priority; 600 if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 601 qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 602 else 603 qi->tqi_aifs = INIT_AIFS; 604 if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 605 cw = AH_MIN(qInfo->tqi_cwmin, 1024); 606 /* make sure that the CWmin is of the form (2^n - 1) */ 607 qi->tqi_cwmin = 1; 608 while (qi->tqi_cwmin < cw) 609 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 610 } else 611 qi->tqi_cwmin = qInfo->tqi_cwmin; 612 if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 613 cw = AH_MIN(qInfo->tqi_cwmax, 1024); 614 /* make sure that the CWmax is of the form (2^n - 1) */ 615 qi->tqi_cwmax = 1; 616 while (qi->tqi_cwmax < cw) 617 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 618 } else 619 qi->tqi_cwmax = INIT_CWMAX; 620 /* Set retry limit values */ 621 if (qInfo->tqi_shretry != 0) 622 qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 623 else 624 qi->tqi_shretry = INIT_SH_RETRY; 625 if (qInfo->tqi_lgretry != 0) 626 qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 627 else 628 qi->tqi_lgretry = INIT_LG_RETRY; 629 qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 630 qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 631 qi->tqi_burstTime = qInfo->tqi_burstTime; 632 qi->tqi_readyTime = qInfo->tqi_readyTime; 633 634 switch (qInfo->tqi_subtype) { 635 case HAL_WME_UPSD: 636 if (qi->tqi_type == HAL_TX_QUEUE_DATA) 637 qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 638 break; 639 default: 640 break; /* NB: silence compiler */ 641 } 642 return AH_TRUE; 643} 644 645HAL_BOOL 646ath_hal_getTxQProps(struct ath_hal *ah, 647 HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 648{ 649 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 650 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 651 "%s: inactive queue\n", __func__); 652 return AH_FALSE; 653 } 654 655 qInfo->tqi_qflags = qi->tqi_qflags; 656 qInfo->tqi_ver = qi->tqi_ver; 657 qInfo->tqi_subtype = qi->tqi_subtype; 658 qInfo->tqi_qflags = qi->tqi_qflags; 659 qInfo->tqi_priority = qi->tqi_priority; 660 qInfo->tqi_aifs = qi->tqi_aifs; 661 qInfo->tqi_cwmin = qi->tqi_cwmin; 662 qInfo->tqi_cwmax = qi->tqi_cwmax; 663 qInfo->tqi_shretry = qi->tqi_shretry; 664 qInfo->tqi_lgretry = qi->tqi_lgretry; 665 qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 666 qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 667 qInfo->tqi_burstTime = qi->tqi_burstTime; 668 qInfo->tqi_readyTime = qi->tqi_readyTime; 669 return AH_TRUE; 670} 671 672 /* 11a Turbo 11b 11g 108g */ 673static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 674 675/* 676 * Read the current channel noise floor and return. 677 * If nf cal hasn't finished, channel noise floor should be 0 678 * and we return a nominal value based on band and frequency. 679 * 680 * NB: This is a private routine used by per-chip code to 681 * implement the ah_getChanNoise method. 682 */ 683int16_t 684ath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 685{ 686 HAL_CHANNEL_INTERNAL *ichan; 687 688 ichan = ath_hal_checkchannel(ah, chan); 689 if (ichan == AH_NULL) { 690 HALDEBUG(ah, HAL_DEBUG_NFCAL, 691 "%s: invalid channel %u/0x%x; no mapping\n", 692 __func__, chan->ic_freq, chan->ic_flags); 693 return 0; 694 } 695 if (ichan->rawNoiseFloor == 0) { 696 WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 697 698 HALASSERT(mode < WIRELESS_MODE_MAX); 699 return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 700 } else 701 return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 702} 703 704/* 705 * Process all valid raw noise floors into the dBm noise floor values. 706 * Though our device has no reference for a dBm noise floor, we perform 707 * a relative minimization of NF's based on the lowest NF found across a 708 * channel scan. 709 */ 710void 711ath_hal_process_noisefloor(struct ath_hal *ah) 712{ 713 HAL_CHANNEL_INTERNAL *c; 714 int16_t correct2, correct5; 715 int16_t lowest2, lowest5; 716 int i; 717 718 /* 719 * Find the lowest 2GHz and 5GHz noise floor values after adjusting 720 * for statistically recorded NF/channel deviation. 721 */ 722 correct2 = lowest2 = 0; 723 correct5 = lowest5 = 0; 724 for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 725 WIRELESS_MODE mode; 726 int16_t nf; 727 728 c = &AH_PRIVATE(ah)->ah_channels[i]; 729 if (c->rawNoiseFloor >= 0) 730 continue; 731 /* XXX can't identify proper mode */ 732 mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 733 nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 734 ath_hal_getNfAdjust(ah, c); 735 if (IS_CHAN_5GHZ(c)) { 736 if (nf < lowest5) { 737 lowest5 = nf; 738 correct5 = NOISE_FLOOR[mode] - 739 (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 740 } 741 } else { 742 if (nf < lowest2) { 743 lowest2 = nf; 744 correct2 = NOISE_FLOOR[mode] - 745 (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 746 } 747 } 748 } 749 750 /* Correct the channels to reach the expected NF value */ 751 for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 752 c = &AH_PRIVATE(ah)->ah_channels[i]; 753 if (c->rawNoiseFloor >= 0) 754 continue; 755 /* Apply correction factor */ 756 c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 757 (IS_CHAN_5GHZ(c) ? correct5 : correct2); 758 HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 759 c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 760 } 761} 762 763/* 764 * INI support routines. 765 */ 766 767int 768ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 769 int col, int regWr) 770{ 771 int r; 772 773 for (r = 0; r < ia->rows; r++) { 774 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 775 HAL_INI_VAL(ia, r, col)); 776 DMA_YIELD(regWr); 777 } 778 return regWr; 779} 780 781void 782ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 783{ 784 int r; 785 786 for (r = 0; r < ia->rows; r++) 787 data[r] = HAL_INI_VAL(ia, r, col); 788} 789 790int 791ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 792 const uint32_t data[], int regWr) 793{ 794 int r; 795 796 for (r = 0; r < ia->rows; r++) { 797 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 798 DMA_YIELD(regWr); 799 } 800 return regWr; 801} 802