ah.c revision 222157
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 222157 2011-05-21 09:23:18Z adrian $ 18 */ 19#include "opt_ah.h" 20 21#include "ah.h" 22#include "ah_internal.h" 23#include "ah_devid.h" 24#include "ah_eeprom.h" /* for 5ghz fast clock flag */ 25 26#include "ar5416/ar5416reg.h" /* NB: includes ar5212reg.h */ 27 28/* linker set of registered chips */ 29OS_SET_DECLARE(ah_chips, struct ath_hal_chip); 30 31/* 32 * Check the set of registered chips to see if any recognize 33 * the device as one they can support. 34 */ 35const char* 36ath_hal_probe(uint16_t vendorid, uint16_t devid) 37{ 38 struct ath_hal_chip * const *pchip; 39 40 OS_SET_FOREACH(pchip, ah_chips) { 41 const char *name = (*pchip)->probe(vendorid, devid); 42 if (name != AH_NULL) 43 return name; 44 } 45 return AH_NULL; 46} 47 48/* 49 * Attach detects device chip revisions, initializes the hwLayer 50 * function list, reads EEPROM information, 51 * selects reset vectors, and performs a short self test. 52 * Any failures will return an error that should cause a hardware 53 * disable. 54 */ 55struct ath_hal* 56ath_hal_attach(uint16_t devid, HAL_SOFTC sc, 57 HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error) 58{ 59 struct ath_hal_chip * const *pchip; 60 61 OS_SET_FOREACH(pchip, ah_chips) { 62 struct ath_hal_chip *chip = *pchip; 63 struct ath_hal *ah; 64 65 /* XXX don't have vendorid, assume atheros one works */ 66 if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 67 continue; 68 ah = chip->attach(devid, sc, st, sh, eepromdata, error); 69 if (ah != AH_NULL) { 70 /* copy back private state to public area */ 71 ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 72 ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 73 ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 74 ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 75 ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 76 ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 77 ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 78 return ah; 79 } 80 } 81 return AH_NULL; 82} 83 84const char * 85ath_hal_mac_name(struct ath_hal *ah) 86{ 87 switch (ah->ah_macVersion) { 88 case AR_SREV_VERSION_CRETE: 89 case AR_SREV_VERSION_MAUI_1: 90 return "5210"; 91 case AR_SREV_VERSION_MAUI_2: 92 case AR_SREV_VERSION_OAHU: 93 return "5211"; 94 case AR_SREV_VERSION_VENICE: 95 return "5212"; 96 case AR_SREV_VERSION_GRIFFIN: 97 return "2413"; 98 case AR_SREV_VERSION_CONDOR: 99 return "5424"; 100 case AR_SREV_VERSION_EAGLE: 101 return "5413"; 102 case AR_SREV_VERSION_COBRA: 103 return "2415"; 104 case AR_SREV_2425: 105 return "2425"; 106 case AR_SREV_2417: 107 return "2417"; 108 case AR_XSREV_VERSION_OWL_PCI: 109 return "5416"; 110 case AR_XSREV_VERSION_OWL_PCIE: 111 return "5418"; 112 case AR_XSREV_VERSION_HOWL: 113 return "9130"; 114 case AR_XSREV_VERSION_SOWL: 115 return "9160"; 116 case AR_XSREV_VERSION_MERLIN: 117 return "9280"; 118 case AR_XSREV_VERSION_KITE: 119 return "9285"; 120 } 121 return "????"; 122} 123 124/* 125 * Return the mask of available modes based on the hardware capabilities. 126 */ 127u_int 128ath_hal_getwirelessmodes(struct ath_hal*ah) 129{ 130 return ath_hal_getWirelessModes(ah); 131} 132 133/* linker set of registered RF backends */ 134OS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 135 136/* 137 * Check the set of registered RF backends to see if 138 * any recognize the device as one they can support. 139 */ 140struct ath_hal_rf * 141ath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 142{ 143 struct ath_hal_rf * const *prf; 144 145 OS_SET_FOREACH(prf, ah_rfs) { 146 struct ath_hal_rf *rf = *prf; 147 if (rf->probe(ah)) 148 return rf; 149 } 150 *ecode = HAL_ENOTSUPP; 151 return AH_NULL; 152} 153 154const char * 155ath_hal_rf_name(struct ath_hal *ah) 156{ 157 switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { 158 case 0: /* 5210 */ 159 return "5110"; /* NB: made up */ 160 case AR_RAD5111_SREV_MAJOR: 161 case AR_RAD5111_SREV_PROD: 162 return "5111"; 163 case AR_RAD2111_SREV_MAJOR: 164 return "2111"; 165 case AR_RAD5112_SREV_MAJOR: 166 case AR_RAD5112_SREV_2_0: 167 case AR_RAD5112_SREV_2_1: 168 return "5112"; 169 case AR_RAD2112_SREV_MAJOR: 170 case AR_RAD2112_SREV_2_0: 171 case AR_RAD2112_SREV_2_1: 172 return "2112"; 173 case AR_RAD2413_SREV_MAJOR: 174 return "2413"; 175 case AR_RAD5413_SREV_MAJOR: 176 return "5413"; 177 case AR_RAD2316_SREV_MAJOR: 178 return "2316"; 179 case AR_RAD2317_SREV_MAJOR: 180 return "2317"; 181 case AR_RAD5424_SREV_MAJOR: 182 return "5424"; 183 184 case AR_RAD5133_SREV_MAJOR: 185 return "5133"; 186 case AR_RAD2133_SREV_MAJOR: 187 return "2133"; 188 case AR_RAD5122_SREV_MAJOR: 189 return "5122"; 190 case AR_RAD2122_SREV_MAJOR: 191 return "2122"; 192 } 193 return "????"; 194} 195 196/* 197 * Poll the register looking for a specific value. 198 */ 199HAL_BOOL 200ath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 201{ 202#define AH_TIMEOUT 1000 203 return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT); 204#undef AH_TIMEOUT 205} 206 207HAL_BOOL 208ath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout) 209{ 210 int i; 211 212 for (i = 0; i < timeout; i++) { 213 if ((OS_REG_READ(ah, reg) & mask) == val) 214 return AH_TRUE; 215 OS_DELAY(10); 216 } 217 HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 218 "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 219 __func__, reg, OS_REG_READ(ah, reg), mask, val); 220 return AH_FALSE; 221} 222 223/* 224 * Reverse the bits starting at the low bit for a value of 225 * bit_count in size 226 */ 227uint32_t 228ath_hal_reverseBits(uint32_t val, uint32_t n) 229{ 230 uint32_t retval; 231 int i; 232 233 for (i = 0, retval = 0; i < n; i++) { 234 retval = (retval << 1) | (val & 1); 235 val >>= 1; 236 } 237 return retval; 238} 239 240/* 802.11n related timing definitions */ 241 242#define OFDM_PLCP_BITS 22 243#define HT_L_STF 8 244#define HT_L_LTF 8 245#define HT_L_SIG 4 246#define HT_SIG 8 247#define HT_STF 4 248#define HT_LTF(n) ((n) * 4) 249 250#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 251#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 252#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 253 254/* 255 * Calculate the duration of a packet whether it is 11n or legacy. 256 */ 257uint32_t 258ath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen, 259 uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble) 260{ 261 uint8_t rc; 262 int numStreams; 263 264 rc = rates->info[rateix].rateCode; 265 266 /* Legacy rate? Return the old way */ 267 if (! IS_HT_RATE(rc)) 268 return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble); 269 270 /* 11n frame - extract out the number of spatial streams */ 271 numStreams = HT_RC_2_STREAMS(rc); 272 KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix)); 273 274 return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble); 275} 276 277/* 278 * Calculate the transmit duration of an 11n frame. 279 * This only works for MCS0->MCS15. 280 */ 281uint32_t 282ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40, 283 HAL_BOOL isShortGI) 284{ 285 static const uint16_t ht20_bps[16] = { 286 26, 52, 78, 104, 156, 208, 234, 260, 287 52, 104, 156, 208, 312, 416, 468, 520 288 }; 289 static const uint16_t ht40_bps[16] = { 290 54, 108, 162, 216, 324, 432, 486, 540, 291 108, 216, 324, 432, 648, 864, 972, 1080, 292 }; 293 uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 294 295 KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 296 KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate)); 297 298 if (isht40) 299 bitsPerSymbol = ht40_bps[rate & 0xf]; 300 else 301 bitsPerSymbol = ht20_bps[rate & 0xf]; 302 numBits = OFDM_PLCP_BITS + (frameLen << 3); 303 numSymbols = howmany(numBits, bitsPerSymbol); 304 if (isShortGI) 305 txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 306 else 307 txTime = numSymbols * 4; /* 4us */ 308 return txTime + HT_L_STF + HT_L_LTF + 309 HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 310} 311 312/* 313 * Compute the time to transmit a frame of length frameLen bytes 314 * using the specified rate, phy, and short preamble setting. 315 */ 316uint16_t 317ath_hal_computetxtime(struct ath_hal *ah, 318 const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 319 HAL_BOOL shortPreamble) 320{ 321 uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 322 uint32_t kbps; 323 324 /* Warn if this function is called for 11n rates; it should not be! */ 325 if (IS_HT_RATE(rates->info[rateix].rateCode)) 326 ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n", 327 __func__, rateix, rates->info[rateix].rateCode); 328 329 kbps = rates->info[rateix].rateKbps; 330 /* 331 * index can be invalid duting dynamic Turbo transitions. 332 * XXX 333 */ 334 if (kbps == 0) 335 return 0; 336 switch (rates->info[rateix].phy) { 337 case IEEE80211_T_CCK: 338 phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 339 if (shortPreamble && rates->info[rateix].shortPreamble) 340 phyTime >>= 1; 341 numBits = frameLen << 3; 342 txTime = CCK_SIFS_TIME + phyTime 343 + ((numBits * 1000)/kbps); 344 break; 345 case IEEE80211_T_OFDM: 346 bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 347 HALASSERT(bitsPerSymbol != 0); 348 349 numBits = OFDM_PLCP_BITS + (frameLen << 3); 350 numSymbols = howmany(numBits, bitsPerSymbol); 351 txTime = OFDM_SIFS_TIME 352 + OFDM_PREAMBLE_TIME 353 + (numSymbols * OFDM_SYMBOL_TIME); 354 break; 355 case IEEE80211_T_OFDM_HALF: 356 bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 357 HALASSERT(bitsPerSymbol != 0); 358 359 numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 360 numSymbols = howmany(numBits, bitsPerSymbol); 361 txTime = OFDM_HALF_SIFS_TIME 362 + OFDM_HALF_PREAMBLE_TIME 363 + (numSymbols * OFDM_HALF_SYMBOL_TIME); 364 break; 365 case IEEE80211_T_OFDM_QUARTER: 366 bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 367 HALASSERT(bitsPerSymbol != 0); 368 369 numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 370 numSymbols = howmany(numBits, bitsPerSymbol); 371 txTime = OFDM_QUARTER_SIFS_TIME 372 + OFDM_QUARTER_PREAMBLE_TIME 373 + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 374 break; 375 case IEEE80211_T_TURBO: 376 bitsPerSymbol = (kbps * TURBO_SYMBOL_TIME) / 1000; 377 HALASSERT(bitsPerSymbol != 0); 378 379 numBits = TURBO_PLCP_BITS + (frameLen << 3); 380 numSymbols = howmany(numBits, bitsPerSymbol); 381 txTime = TURBO_SIFS_TIME 382 + TURBO_PREAMBLE_TIME 383 + (numSymbols * TURBO_SYMBOL_TIME); 384 break; 385 default: 386 HALDEBUG(ah, HAL_DEBUG_PHYIO, 387 "%s: unknown phy %u (rate ix %u)\n", 388 __func__, rates->info[rateix].phy, rateix); 389 txTime = 0; 390 break; 391 } 392 return txTime; 393} 394 395typedef enum { 396 WIRELESS_MODE_11a = 0, 397 WIRELESS_MODE_TURBO = 1, 398 WIRELESS_MODE_11b = 2, 399 WIRELESS_MODE_11g = 3, 400 WIRELESS_MODE_108g = 4, 401 402 WIRELESS_MODE_MAX 403} WIRELESS_MODE; 404 405static WIRELESS_MODE 406ath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 407{ 408 if (IEEE80211_IS_CHAN_B(chan)) 409 return WIRELESS_MODE_11b; 410 if (IEEE80211_IS_CHAN_G(chan)) 411 return WIRELESS_MODE_11g; 412 if (IEEE80211_IS_CHAN_108G(chan)) 413 return WIRELESS_MODE_108g; 414 if (IEEE80211_IS_CHAN_TURBO(chan)) 415 return WIRELESS_MODE_TURBO; 416 return WIRELESS_MODE_11a; 417} 418 419/* 420 * Convert between microseconds and core system clocks. 421 */ 422 /* 11a Turbo 11b 11g 108g */ 423static const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 424 425#define CLOCK_FAST_RATE_5GHZ_OFDM 44 426 427u_int 428ath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 429{ 430 const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 431 u_int clks; 432 433 /* NB: ah_curchan may be null when called attach time */ 434 /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 435 if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 436 clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM; 437 if (IEEE80211_IS_CHAN_HT40(c)) 438 clks <<= 1; 439 } else if (c != AH_NULL) { 440 clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 441 if (IEEE80211_IS_CHAN_HT40(c)) 442 clks <<= 1; 443 } else 444 clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 445 return clks; 446} 447 448u_int 449ath_hal_mac_usec(struct ath_hal *ah, u_int clks) 450{ 451 const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 452 u_int usec; 453 454 /* NB: ah_curchan may be null when called attach time */ 455 /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 456 if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 457 usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM; 458 if (IEEE80211_IS_CHAN_HT40(c)) 459 usec >>= 1; 460 } else if (c != AH_NULL) { 461 usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 462 if (IEEE80211_IS_CHAN_HT40(c)) 463 usec >>= 1; 464 } else 465 usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 466 return usec; 467} 468 469/* 470 * Setup a h/w rate table's reverse lookup table and 471 * fill in ack durations. This routine is called for 472 * each rate table returned through the ah_getRateTable 473 * method. The reverse lookup tables are assumed to be 474 * initialized to zero (or at least the first entry). 475 * We use this as a key that indicates whether or not 476 * we've previously setup the reverse lookup table. 477 * 478 * XXX not reentrant, but shouldn't matter 479 */ 480void 481ath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 482{ 483#define N(a) (sizeof(a)/sizeof(a[0])) 484 int i; 485 486 if (rt->rateCodeToIndex[0] != 0) /* already setup */ 487 return; 488 for (i = 0; i < N(rt->rateCodeToIndex); i++) 489 rt->rateCodeToIndex[i] = (uint8_t) -1; 490 for (i = 0; i < rt->rateCount; i++) { 491 uint8_t code = rt->info[i].rateCode; 492 uint8_t cix = rt->info[i].controlRate; 493 494 HALASSERT(code < N(rt->rateCodeToIndex)); 495 rt->rateCodeToIndex[code] = i; 496 HALASSERT((code | rt->info[i].shortPreamble) < 497 N(rt->rateCodeToIndex)); 498 rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 499 /* 500 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 501 * depends on whether they are marked as basic rates; 502 * the static tables are setup with an 11b-compatible 503 * 2Mb/s rate which will work but is suboptimal 504 */ 505 rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 506 WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 507 rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 508 WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 509 } 510#undef N 511} 512 513HAL_STATUS 514ath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 515 uint32_t capability, uint32_t *result) 516{ 517 const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 518 519 switch (type) { 520 case HAL_CAP_REG_DMN: /* regulatory domain */ 521 *result = AH_PRIVATE(ah)->ah_currentRD; 522 return HAL_OK; 523 case HAL_CAP_CIPHER: /* cipher handled in hardware */ 524 case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 525 return HAL_ENOTSUPP; 526 case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 527 return HAL_ENOTSUPP; 528 case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 529 return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 530 case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 531 return HAL_ENOTSUPP; 532 case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 533 return HAL_ENOTSUPP; 534 case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 535 *result = pCap->halKeyCacheSize; 536 return HAL_OK; 537 case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 538 *result = pCap->halTotalQueues; 539 return HAL_OK; 540 case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 541 return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 542 case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 543 return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 544 case HAL_CAP_COMPRESSION: 545 return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 546 case HAL_CAP_BURST: 547 return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 548 case HAL_CAP_FASTFRAME: 549 return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 550 case HAL_CAP_DIAG: /* hardware diagnostic support */ 551 *result = AH_PRIVATE(ah)->ah_diagreg; 552 return HAL_OK; 553 case HAL_CAP_TXPOW: /* global tx power limit */ 554 switch (capability) { 555 case 0: /* facility is supported */ 556 return HAL_OK; 557 case 1: /* current limit */ 558 *result = AH_PRIVATE(ah)->ah_powerLimit; 559 return HAL_OK; 560 case 2: /* current max tx power */ 561 *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 562 return HAL_OK; 563 case 3: /* scale factor */ 564 *result = AH_PRIVATE(ah)->ah_tpScale; 565 return HAL_OK; 566 } 567 return HAL_ENOTSUPP; 568 case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 569 return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 570 case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 571 return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 572 case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 573 return HAL_ENOTSUPP; 574 case HAL_CAP_RFSILENT: /* rfsilent support */ 575 switch (capability) { 576 case 0: /* facility is supported */ 577 return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 578 case 1: /* current setting */ 579 return AH_PRIVATE(ah)->ah_rfkillEnabled ? 580 HAL_OK : HAL_ENOTSUPP; 581 case 2: /* rfsilent config */ 582 *result = AH_PRIVATE(ah)->ah_rfsilent; 583 return HAL_OK; 584 } 585 return HAL_ENOTSUPP; 586 case HAL_CAP_11D: 587 return HAL_OK; 588 589 case HAL_CAP_HT: 590 return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 591 case HAL_CAP_GTXTO: 592 return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP; 593 case HAL_CAP_FAST_CC: 594 return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP; 595 case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 596 *result = pCap->halTxChainMask; 597 return HAL_OK; 598 case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 599 *result = pCap->halRxChainMask; 600 return HAL_OK; 601 case HAL_CAP_NUM_GPIO_PINS: 602 *result = pCap->halNumGpioPins; 603 return HAL_OK; 604 case HAL_CAP_CST: 605 return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP; 606 case HAL_CAP_RTS_AGGR_LIMIT: 607 *result = pCap->halRtsAggrLimit; 608 return HAL_OK; 609 case HAL_CAP_4ADDR_AGGR: 610 return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP; 611 case HAL_CAP_AUTO_SLEEP: 612 return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP; 613 case HAL_CAP_MBSSID_AGGR_SUPPORT: 614 return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP; 615 case HAL_CAP_SPLIT_4KB_TRANS: /* hardware handles descriptors straddling 4k page boundary */ 616 return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP; 617 case HAL_CAP_REG_FLAG: 618 *result = AH_PRIVATE(ah)->ah_currentRDext; 619 return HAL_OK; 620 case HAL_CAP_BT_COEX: 621 return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP; 622 case HAL_CAP_HT20_SGI: 623 return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP; 624 case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 625 *result = pCap->halTstampPrecision; 626 return HAL_OK; 627 628 /* FreeBSD-specific entries for now */ 629 case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 630 return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 631 case HAL_CAP_INTRMASK: /* mask of supported interrupts */ 632 *result = pCap->halIntrMask; 633 return HAL_OK; 634 case HAL_CAP_BSSIDMATCH: /* hardware has disable bssid match */ 635 return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP; 636 case HAL_CAP_STREAMS: /* number of 11n spatial streams */ 637 switch (capability) { 638 case 0: /* TX */ 639 *result = pCap->halTxStreams; 640 return HAL_OK; 641 case 1: /* RX */ 642 *result = pCap->halRxStreams; 643 return HAL_OK; 644 default: 645 return HAL_ENOTSUPP; 646 } 647 case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ 648 return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; 649 default: 650 return HAL_EINVAL; 651 } 652} 653 654HAL_BOOL 655ath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 656 uint32_t capability, uint32_t setting, HAL_STATUS *status) 657{ 658 659 switch (type) { 660 case HAL_CAP_TXPOW: 661 switch (capability) { 662 case 3: 663 if (setting <= HAL_TP_SCALE_MIN) { 664 AH_PRIVATE(ah)->ah_tpScale = setting; 665 return AH_TRUE; 666 } 667 break; 668 } 669 break; 670 case HAL_CAP_RFSILENT: /* rfsilent support */ 671 /* 672 * NB: allow even if halRfSilentSupport is false 673 * in case the EEPROM is misprogrammed. 674 */ 675 switch (capability) { 676 case 1: /* current setting */ 677 AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 678 return AH_TRUE; 679 case 2: /* rfsilent config */ 680 /* XXX better done per-chip for validation? */ 681 AH_PRIVATE(ah)->ah_rfsilent = setting; 682 return AH_TRUE; 683 } 684 break; 685 case HAL_CAP_REG_DMN: /* regulatory domain */ 686 AH_PRIVATE(ah)->ah_currentRD = setting; 687 return AH_TRUE; 688 case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 689 AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 690 return AH_TRUE; 691 default: 692 break; 693 } 694 if (status) 695 *status = HAL_EINVAL; 696 return AH_FALSE; 697} 698 699/* 700 * Common support for getDiagState method. 701 */ 702 703static u_int 704ath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 705 void *dstbuf, int space) 706{ 707 uint32_t *dp = dstbuf; 708 int i; 709 710 for (i = 0; space >= 2*sizeof(uint32_t); i++) { 711 u_int r = regs[i].start; 712 u_int e = regs[i].end; 713 *dp++ = (r<<16) | e; 714 space -= sizeof(uint32_t); 715 do { 716 *dp++ = OS_REG_READ(ah, r); 717 r += sizeof(uint32_t); 718 space -= sizeof(uint32_t); 719 } while (r <= e && space >= sizeof(uint32_t)); 720 } 721 return (char *) dp - (char *) dstbuf; 722} 723 724static void 725ath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 726{ 727 while (space >= sizeof(HAL_REGWRITE)) { 728 OS_REG_WRITE(ah, regs->addr, regs->value); 729 regs++, space -= sizeof(HAL_REGWRITE); 730 } 731} 732 733HAL_BOOL 734ath_hal_getdiagstate(struct ath_hal *ah, int request, 735 const void *args, uint32_t argsize, 736 void **result, uint32_t *resultsize) 737{ 738 switch (request) { 739 case HAL_DIAG_REVS: 740 *result = &AH_PRIVATE(ah)->ah_devid; 741 *resultsize = sizeof(HAL_REVS); 742 return AH_TRUE; 743 case HAL_DIAG_REGS: 744 *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 745 return AH_TRUE; 746 case HAL_DIAG_SETREGS: 747 ath_hal_setregs(ah, args, argsize); 748 *resultsize = 0; 749 return AH_TRUE; 750 case HAL_DIAG_FATALERR: 751 *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 752 *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 753 return AH_TRUE; 754 case HAL_DIAG_EEREAD: 755 if (argsize != sizeof(uint16_t)) 756 return AH_FALSE; 757 if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 758 return AH_FALSE; 759 *resultsize = sizeof(uint16_t); 760 return AH_TRUE; 761#ifdef AH_PRIVATE_DIAG 762 case HAL_DIAG_SETKEY: { 763 const HAL_DIAG_KEYVAL *dk; 764 765 if (argsize != sizeof(HAL_DIAG_KEYVAL)) 766 return AH_FALSE; 767 dk = (const HAL_DIAG_KEYVAL *)args; 768 return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 769 &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 770 } 771 case HAL_DIAG_RESETKEY: 772 if (argsize != sizeof(uint16_t)) 773 return AH_FALSE; 774 return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 775#ifdef AH_SUPPORT_WRITE_EEPROM 776 case HAL_DIAG_EEWRITE: { 777 const HAL_DIAG_EEVAL *ee; 778 if (argsize != sizeof(HAL_DIAG_EEVAL)) 779 return AH_FALSE; 780 ee = (const HAL_DIAG_EEVAL *)args; 781 return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 782 } 783#endif /* AH_SUPPORT_WRITE_EEPROM */ 784#endif /* AH_PRIVATE_DIAG */ 785 case HAL_DIAG_11NCOMPAT: 786 if (argsize == 0) { 787 *resultsize = sizeof(uint32_t); 788 *((uint32_t *)(*result)) = 789 AH_PRIVATE(ah)->ah_11nCompat; 790 } else if (argsize == sizeof(uint32_t)) { 791 AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 792 } else 793 return AH_FALSE; 794 return AH_TRUE; 795 } 796 return AH_FALSE; 797} 798 799/* 800 * Set the properties of the tx queue with the parameters 801 * from qInfo. 802 */ 803HAL_BOOL 804ath_hal_setTxQProps(struct ath_hal *ah, 805 HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 806{ 807 uint32_t cw; 808 809 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 810 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 811 "%s: inactive queue\n", __func__); 812 return AH_FALSE; 813 } 814 /* XXX validate parameters */ 815 qi->tqi_ver = qInfo->tqi_ver; 816 qi->tqi_subtype = qInfo->tqi_subtype; 817 qi->tqi_qflags = qInfo->tqi_qflags; 818 qi->tqi_priority = qInfo->tqi_priority; 819 if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 820 qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 821 else 822 qi->tqi_aifs = INIT_AIFS; 823 if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 824 cw = AH_MIN(qInfo->tqi_cwmin, 1024); 825 /* make sure that the CWmin is of the form (2^n - 1) */ 826 qi->tqi_cwmin = 1; 827 while (qi->tqi_cwmin < cw) 828 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 829 } else 830 qi->tqi_cwmin = qInfo->tqi_cwmin; 831 if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 832 cw = AH_MIN(qInfo->tqi_cwmax, 1024); 833 /* make sure that the CWmax is of the form (2^n - 1) */ 834 qi->tqi_cwmax = 1; 835 while (qi->tqi_cwmax < cw) 836 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 837 } else 838 qi->tqi_cwmax = INIT_CWMAX; 839 /* Set retry limit values */ 840 if (qInfo->tqi_shretry != 0) 841 qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 842 else 843 qi->tqi_shretry = INIT_SH_RETRY; 844 if (qInfo->tqi_lgretry != 0) 845 qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 846 else 847 qi->tqi_lgretry = INIT_LG_RETRY; 848 qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 849 qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 850 qi->tqi_burstTime = qInfo->tqi_burstTime; 851 qi->tqi_readyTime = qInfo->tqi_readyTime; 852 853 switch (qInfo->tqi_subtype) { 854 case HAL_WME_UPSD: 855 if (qi->tqi_type == HAL_TX_QUEUE_DATA) 856 qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 857 break; 858 default: 859 break; /* NB: silence compiler */ 860 } 861 return AH_TRUE; 862} 863 864HAL_BOOL 865ath_hal_getTxQProps(struct ath_hal *ah, 866 HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 867{ 868 if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 869 HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 870 "%s: inactive queue\n", __func__); 871 return AH_FALSE; 872 } 873 874 qInfo->tqi_qflags = qi->tqi_qflags; 875 qInfo->tqi_ver = qi->tqi_ver; 876 qInfo->tqi_subtype = qi->tqi_subtype; 877 qInfo->tqi_qflags = qi->tqi_qflags; 878 qInfo->tqi_priority = qi->tqi_priority; 879 qInfo->tqi_aifs = qi->tqi_aifs; 880 qInfo->tqi_cwmin = qi->tqi_cwmin; 881 qInfo->tqi_cwmax = qi->tqi_cwmax; 882 qInfo->tqi_shretry = qi->tqi_shretry; 883 qInfo->tqi_lgretry = qi->tqi_lgretry; 884 qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 885 qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 886 qInfo->tqi_burstTime = qi->tqi_burstTime; 887 qInfo->tqi_readyTime = qi->tqi_readyTime; 888 return AH_TRUE; 889} 890 891 /* 11a Turbo 11b 11g 108g */ 892static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 893 894/* 895 * Read the current channel noise floor and return. 896 * If nf cal hasn't finished, channel noise floor should be 0 897 * and we return a nominal value based on band and frequency. 898 * 899 * NB: This is a private routine used by per-chip code to 900 * implement the ah_getChanNoise method. 901 */ 902int16_t 903ath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 904{ 905 HAL_CHANNEL_INTERNAL *ichan; 906 907 ichan = ath_hal_checkchannel(ah, chan); 908 if (ichan == AH_NULL) { 909 HALDEBUG(ah, HAL_DEBUG_NFCAL, 910 "%s: invalid channel %u/0x%x; no mapping\n", 911 __func__, chan->ic_freq, chan->ic_flags); 912 return 0; 913 } 914 if (ichan->rawNoiseFloor == 0) { 915 WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 916 917 HALASSERT(mode < WIRELESS_MODE_MAX); 918 return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 919 } else 920 return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 921} 922 923/* 924 * Fetch the current setup of ctl/ext noise floor values. 925 * 926 * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply 927 * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust(). 928 * 929 * The caller must supply ctl/ext NF arrays which are at least 930 * AH_MIMO_MAX_CHAINS entries long. 931 */ 932int 933ath_hal_get_mimo_chan_noise(struct ath_hal *ah, 934 const struct ieee80211_channel *chan, int16_t *nf_ctl, 935 int16_t *nf_ext) 936{ 937#ifdef AH_SUPPORT_AR5416 938 HAL_CHANNEL_INTERNAL *ichan; 939 int i; 940 941 ichan = ath_hal_checkchannel(ah, chan); 942 if (ichan == AH_NULL) { 943 HALDEBUG(ah, HAL_DEBUG_NFCAL, 944 "%s: invalid channel %u/0x%x; no mapping\n", 945 __func__, chan->ic_freq, chan->ic_flags); 946 for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 947 nf_ctl[i] = nf_ext[i] = 0; 948 } 949 return 0; 950 } 951 952 /* Return 0 if there's no valid MIMO values (yet) */ 953 if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) { 954 for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 955 nf_ctl[i] = nf_ext[i] = 0; 956 } 957 return 0; 958 } 959 if (ichan->rawNoiseFloor == 0) { 960 WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 961 HALASSERT(mode < WIRELESS_MODE_MAX); 962 /* 963 * See the comment below - this could cause issues for 964 * stations which have a very low RSSI, below the 965 * 'normalised' NF values in NOISE_FLOOR[]. 966 */ 967 for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 968 nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] + 969 ath_hal_getNfAdjust(ah, ichan); 970 } 971 return 1; 972 } else { 973 /* 974 * The value returned here from a MIMO radio is presumed to be 975 * "good enough" as a NF calculation. As RSSI values are calculated 976 * against this, an adjusted NF may be higher than the RSSI value 977 * returned from a vary weak station, resulting in an obscenely 978 * high signal strength calculation being returned. 979 * 980 * This should be re-evaluated at a later date, along with any 981 * signal strength calculations which are made. Quite likely the 982 * RSSI values will need to be adjusted to ensure the calculations 983 * don't "wrap" when RSSI is less than the "adjusted" NF value. 984 * ("Adjust" here is via ichan->noiseFloorAdjust.) 985 */ 986 for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 987 nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan); 988 nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan); 989 } 990 return 1; 991 } 992#else 993 return 0; 994#endif /* AH_SUPPORT_AR5416 */ 995} 996 997/* 998 * Process all valid raw noise floors into the dBm noise floor values. 999 * Though our device has no reference for a dBm noise floor, we perform 1000 * a relative minimization of NF's based on the lowest NF found across a 1001 * channel scan. 1002 */ 1003void 1004ath_hal_process_noisefloor(struct ath_hal *ah) 1005{ 1006 HAL_CHANNEL_INTERNAL *c; 1007 int16_t correct2, correct5; 1008 int16_t lowest2, lowest5; 1009 int i; 1010 1011 /* 1012 * Find the lowest 2GHz and 5GHz noise floor values after adjusting 1013 * for statistically recorded NF/channel deviation. 1014 */ 1015 correct2 = lowest2 = 0; 1016 correct5 = lowest5 = 0; 1017 for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1018 WIRELESS_MODE mode; 1019 int16_t nf; 1020 1021 c = &AH_PRIVATE(ah)->ah_channels[i]; 1022 if (c->rawNoiseFloor >= 0) 1023 continue; 1024 /* XXX can't identify proper mode */ 1025 mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 1026 nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 1027 ath_hal_getNfAdjust(ah, c); 1028 if (IS_CHAN_5GHZ(c)) { 1029 if (nf < lowest5) { 1030 lowest5 = nf; 1031 correct5 = NOISE_FLOOR[mode] - 1032 (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1033 } 1034 } else { 1035 if (nf < lowest2) { 1036 lowest2 = nf; 1037 correct2 = NOISE_FLOOR[mode] - 1038 (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1039 } 1040 } 1041 } 1042 1043 /* Correct the channels to reach the expected NF value */ 1044 for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1045 c = &AH_PRIVATE(ah)->ah_channels[i]; 1046 if (c->rawNoiseFloor >= 0) 1047 continue; 1048 /* Apply correction factor */ 1049 c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 1050 (IS_CHAN_5GHZ(c) ? correct5 : correct2); 1051 HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 1052 c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 1053 } 1054} 1055 1056/* 1057 * INI support routines. 1058 */ 1059 1060int 1061ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1062 int col, int regWr) 1063{ 1064 int r; 1065 1066 HALASSERT(col < ia->cols); 1067 for (r = 0; r < ia->rows; r++) { 1068 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 1069 HAL_INI_VAL(ia, r, col)); 1070 1071 /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ 1072 if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900) 1073 OS_DELAY(100); 1074 1075 DMA_YIELD(regWr); 1076 } 1077 return regWr; 1078} 1079 1080void 1081ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 1082{ 1083 int r; 1084 1085 HALASSERT(col < ia->cols); 1086 for (r = 0; r < ia->rows; r++) 1087 data[r] = HAL_INI_VAL(ia, r, col); 1088} 1089 1090int 1091ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1092 const uint32_t data[], int regWr) 1093{ 1094 int r; 1095 1096 for (r = 0; r < ia->rows; r++) { 1097 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 1098 DMA_YIELD(regWr); 1099 } 1100 return regWr; 1101} 1102 1103/* 1104 * These are EEPROM board related routines which should likely live in 1105 * a helper library of some sort. 1106 */ 1107 1108/************************************************************** 1109 * ath_ee_getLowerUppderIndex 1110 * 1111 * Return indices surrounding the value in sorted integer lists. 1112 * Requirement: the input list must be monotonically increasing 1113 * and populated up to the list size 1114 * Returns: match is set if an index in the array matches exactly 1115 * or a the target is before or after the range of the array. 1116 */ 1117HAL_BOOL 1118ath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize, 1119 uint16_t *indexL, uint16_t *indexR) 1120{ 1121 uint16_t i; 1122 1123 /* 1124 * Check first and last elements for beyond ordered array cases. 1125 */ 1126 if (target <= pList[0]) { 1127 *indexL = *indexR = 0; 1128 return AH_TRUE; 1129 } 1130 if (target >= pList[listSize-1]) { 1131 *indexL = *indexR = (uint16_t)(listSize - 1); 1132 return AH_TRUE; 1133 } 1134 1135 /* look for value being near or between 2 values in list */ 1136 for (i = 0; i < listSize - 1; i++) { 1137 /* 1138 * If value is close to the current value of the list 1139 * then target is not between values, it is one of the values 1140 */ 1141 if (pList[i] == target) { 1142 *indexL = *indexR = i; 1143 return AH_TRUE; 1144 } 1145 /* 1146 * Look for value being between current value and next value 1147 * if so return these 2 values 1148 */ 1149 if (target < pList[i + 1]) { 1150 *indexL = i; 1151 *indexR = (uint16_t)(i + 1); 1152 return AH_FALSE; 1153 } 1154 } 1155 HALASSERT(0); 1156 *indexL = *indexR = 0; 1157 return AH_FALSE; 1158} 1159 1160/************************************************************** 1161 * ath_ee_FillVpdTable 1162 * 1163 * Fill the Vpdlist for indices Pmax-Pmin 1164 * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4 1165 */ 1166HAL_BOOL 1167ath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList, 1168 uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList) 1169{ 1170 uint16_t i, k; 1171 uint8_t currPwr = pwrMin; 1172 uint16_t idxL, idxR; 1173 1174 HALASSERT(pwrMax > pwrMin); 1175 for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 1176 ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts, 1177 &(idxL), &(idxR)); 1178 if (idxR < 1) 1179 idxR = 1; /* extrapolate below */ 1180 if (idxL == numIntercepts - 1) 1181 idxL = (uint16_t)(numIntercepts - 2); /* extrapolate above */ 1182 if (pPwrList[idxL] == pPwrList[idxR]) 1183 k = pVpdList[idxL]; 1184 else 1185 k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 1186 (pPwrList[idxR] - pPwrList[idxL]) ); 1187 HALASSERT(k < 256); 1188 pRetVpdList[i] = (uint8_t)k; 1189 currPwr += 2; /* half dB steps */ 1190 } 1191 1192 return AH_TRUE; 1193} 1194 1195/************************************************************************** 1196 * ath_ee_interpolate 1197 * 1198 * Returns signed interpolated or the scaled up interpolated value 1199 */ 1200int16_t 1201ath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 1202 int16_t targetLeft, int16_t targetRight) 1203{ 1204 int16_t rv; 1205 1206 if (srcRight == srcLeft) { 1207 rv = targetLeft; 1208 } else { 1209 rv = (int16_t)( ((target - srcLeft) * targetRight + 1210 (srcRight - target) * targetLeft) / (srcRight - srcLeft) ); 1211 } 1212 return rv; 1213} 1214