ah.c revision 218490
1193323Sed/* 2193323Sed * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3193323Sed * Copyright (c) 2002-2008 Atheros Communications, Inc. 4193323Sed * 5193323Sed * Permission to use, copy, modify, and/or distribute this software for any 6193323Sed * purpose with or without fee is hereby granted, provided that the above 7193323Sed * copyright notice and this permission notice appear in all copies. 8193323Sed * 9193323Sed * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10193323Sed * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11193323Sed * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12193323Sed * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13193323Sed * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14193323Sed * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15193323Sed * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16193323Sed * 17193323Sed * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 218490 2011-02-09 16:37:29Z adrian $ 18193323Sed */ 19193323Sed#include "opt_ah.h" 20193323Sed 21193323Sed#include "ah.h" 22193323Sed#include "ah_internal.h" 23193323Sed#include "ah_devid.h" 24198090Srdivacky 25251662Sdim#include "ar5416/ar5416reg.h" /* NB: includes ar5212reg.h */ 26249423Sdim 27249423Sdim/* linker set of registered chips */ 28193323SedOS_SET_DECLARE(ah_chips, struct ath_hal_chip); 29193323Sed 30193323Sed/* 31193323Sed * Check the set of registered chips to see if any recognize 32193323Sed * the device as one they can support. 33193323Sed */ 34193323Sedconst char* 35212904Sdimath_hal_probe(uint16_t vendorid, uint16_t devid) 36193323Sed{ 37193323Sed struct ath_hal_chip * const *pchip; 38193323Sed 39193323Sed OS_SET_FOREACH(pchip, ah_chips) { 40193323Sed const char *name = (*pchip)->probe(vendorid, devid); 41193323Sed if (name != AH_NULL) 42193323Sed return name; 43193323Sed } 44234353Sdim return AH_NULL; 45243830Sdim} 46193323Sed 47193323Sed/* 48193323Sed * Attach detects device chip revisions, initializes the hwLayer 49193323Sed * function list, reads EEPROM information, 50193323Sed * selects reset vectors, and performs a short self test. 51193323Sed * Any failures will return an error that should cause a hardware 52243830Sdim * disable. 53193323Sed */ 54193323Sedstruct ath_hal* 55193323Sedath_hal_attach(uint16_t devid, HAL_SOFTC sc, 56193323Sed HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error) 57193323Sed{ 58193323Sed struct ath_hal_chip * const *pchip; 59193323Sed 60193323Sed OS_SET_FOREACH(pchip, ah_chips) { 61226633Sdim struct ath_hal_chip *chip = *pchip; 62226633Sdim struct ath_hal *ah; 63226633Sdim 64226633Sdim /* XXX don't have vendorid, assume atheros one works */ 65226633Sdim if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 66226633Sdim continue; 67226633Sdim ah = chip->attach(devid, sc, st, sh, eepromdata, error); 68226633Sdim if (ah != AH_NULL) { 69193323Sed /* copy back private state to public area */ 70226633Sdim ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 71221345Sdim ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 72221345Sdim ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 73221345Sdim ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 74221345Sdim ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 75221345Sdim ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 76221345Sdim ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 77193323Sed return ah; 78193323Sed } 79193323Sed } 80193323Sed return AH_NULL; 81193323Sed} 82193323Sed 83193323Sedconst char * 84198090Srdivackyath_hal_mac_name(struct ath_hal *ah) 85234353Sdim{ 86234353Sdim switch (ah->ah_macVersion) { 87234353Sdim case AR_SREV_VERSION_CRETE: 88234353Sdim case AR_SREV_VERSION_MAUI_1: 89193323Sed return "5210"; 90193323Sed case AR_SREV_VERSION_MAUI_2: 91193323Sed case AR_SREV_VERSION_OAHU: 92193323Sed return "5211"; 93193323Sed case AR_SREV_VERSION_VENICE: 94193323Sed return "5212"; 95193323Sed case AR_SREV_VERSION_GRIFFIN: 96193323Sed return "2413"; 97234353Sdim case AR_SREV_VERSION_CONDOR: 98193323Sed return "5424"; 99193323Sed case AR_SREV_VERSION_EAGLE: 100193323Sed return "5413"; 101234353Sdim case AR_SREV_VERSION_COBRA: 102234353Sdim return "2415"; 103234353Sdim case AR_SREV_2425: 104234353Sdim return "2425"; 105193323Sed case AR_SREV_2417: 106193323Sed return "2417"; 107193323Sed case AR_XSREV_VERSION_OWL_PCI: 108234353Sdim return "5416"; 109234353Sdim case AR_XSREV_VERSION_OWL_PCIE: 110234353Sdim return "5418"; 111193323Sed case AR_XSREV_VERSION_SOWL: 112193323Sed return "9160"; 113193323Sed case AR_XSREV_VERSION_MERLIN: 114193323Sed return "9280"; 115193323Sed case AR_XSREV_VERSION_KITE: 116193323Sed return "9285"; 117193323Sed } 118193323Sed return "????"; 119193323Sed} 120193323Sed 121193323Sed/* 122193323Sed * Return the mask of available modes based on the hardware capabilities. 123193323Sed */ 124193323Sedu_int 125193323Sedath_hal_getwirelessmodes(struct ath_hal*ah) 126193323Sed{ 127193323Sed return ath_hal_getWirelessModes(ah); 128193323Sed} 129234353Sdim 130234353Sdim/* linker set of registered RF backends */ 131234353SdimOS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 132234353Sdim 133193323Sed/* 134193323Sed * Check the set of registered RF backends to see if 135193323Sed * any recognize the device as one they can support. 136234353Sdim */ 137234353Sdimstruct ath_hal_rf * 138234353Sdimath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 139193323Sed{ 140193323Sed struct ath_hal_rf * const *prf; 141251662Sdim 142251662Sdim OS_SET_FOREACH(prf, ah_rfs) { 143251662Sdim struct ath_hal_rf *rf = *prf; 144251662Sdim if (rf->probe(ah)) 145251662Sdim return rf; 146251662Sdim } 147251662Sdim *ecode = HAL_ENOTSUPP; 148251662Sdim return AH_NULL; 149251662Sdim} 150251662Sdim 151251662Sdimconst char * 152251662Sdimath_hal_rf_name(struct ath_hal *ah) 153251662Sdim{ 154251662Sdim switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { 155193323Sed case 0: /* 5210 */ 156251662Sdim return "5110"; /* NB: made up */ 157251662Sdim case AR_RAD5111_SREV_MAJOR: 158193323Sed case AR_RAD5111_SREV_PROD: 159193323Sed return "5111"; 160193323Sed case AR_RAD2111_SREV_MAJOR: 161193323Sed return "2111"; 162193323Sed case AR_RAD5112_SREV_MAJOR: 163193323Sed case AR_RAD5112_SREV_2_0: 164193323Sed case AR_RAD5112_SREV_2_1: 165193323Sed return "5112"; 166193323Sed case AR_RAD2112_SREV_MAJOR: 167193323Sed case AR_RAD2112_SREV_2_0: 168193323Sed case AR_RAD2112_SREV_2_1: 169193323Sed return "2112"; 170198090Srdivacky case AR_RAD2413_SREV_MAJOR: 171198090Srdivacky return "2413"; 172193323Sed case AR_RAD5413_SREV_MAJOR: 173193323Sed return "5413"; 174193323Sed case AR_RAD2316_SREV_MAJOR: 175193323Sed return "2316"; 176193323Sed case AR_RAD2317_SREV_MAJOR: 177193323Sed return "2317"; 178193323Sed case AR_RAD5424_SREV_MAJOR: 179193323Sed return "5424"; 180193323Sed 181234353Sdim case AR_RAD5133_SREV_MAJOR: 182234353Sdim return "5133"; 183234353Sdim case AR_RAD2133_SREV_MAJOR: 184234353Sdim return "2133"; 185234353Sdim case AR_RAD5122_SREV_MAJOR: 186234353Sdim return "5122"; 187234353Sdim case AR_RAD2122_SREV_MAJOR: 188234353Sdim return "2122"; 189234353Sdim } 190193323Sed return "????"; 191193323Sed} 192193323Sed 193251662Sdim/* 194193323Sed * Poll the register looking for a specific value. 195251662Sdim */ 196251662SdimHAL_BOOL 197251662Sdimath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 198251662Sdim{ 199193323Sed#define AH_TIMEOUT 1000 200198090Srdivacky return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT); 201234353Sdim#undef AH_TIMEOUT 202193323Sed} 203193323Sed 204234353SdimHAL_BOOL 205193323Sedath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout) 206193323Sed{ 207193323Sed int i; 208234353Sdim 209193323Sed for (i = 0; i < timeout; i++) { 210193323Sed if ((OS_REG_READ(ah, reg) & mask) == val) 211234353Sdim return AH_TRUE; 212193323Sed OS_DELAY(10); 213193323Sed } 214234353Sdim HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 215193323Sed "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 216193323Sed __func__, reg, OS_REG_READ(ah, reg), mask, val); 217193323Sed return AH_FALSE; 218193323Sed} 219193323Sed 220193323Sed/* 221193323Sed * Reverse the bits starting at the low bit for a value of 222193323Sed * bit_count in size 223193323Sed */ 224193323Seduint32_t 225193323Sedath_hal_reverseBits(uint32_t val, uint32_t n) 226193323Sed{ 227193323Sed uint32_t retval; 228198090Srdivacky int i; 229234353Sdim 230193323Sed for (i = 0, retval = 0; i < n; i++) { 231234353Sdim retval = (retval << 1) | (val & 1); 232234353Sdim val >>= 1; 233234353Sdim } 234234353Sdim return retval; 235193323Sed} 236251662Sdim 237193323Sed/* 802.11n related timing definitions */ 238239462Sdim 239234353Sdim#define OFDM_PLCP_BITS 22 240239462Sdim#define HT_L_STF 8 241239462Sdim#define HT_L_LTF 8 242239462Sdim#define HT_L_SIG 4 243251662Sdim#define HT_SIG 8 244193323Sed#define HT_STF 4 245193323Sed#define HT_LTF(n) ((n) * 4) 246198090Srdivacky 247193323Sed#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 248193323Sed#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 249193323Sed#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 250193323Sed 251193323Sed/* 252193323Sed * Calculate the duration of a packet whether it is 11n or legacy. 253193323Sed */ 254193323Seduint32_t 255193323Sedath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen, 256193323Sed uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble) 257193323Sed{ 258193323Sed uint8_t rc; 259193323Sed int numStreams; 260193323Sed 261193323Sed rc = rates->info[rateix].rateCode; 262221345Sdim 263221345Sdim /* Legacy rate? Return the old way */ 264198090Srdivacky if (! IS_HT_RATE(rc)) 265193323Sed return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble); 266198090Srdivacky 267193323Sed /* 11n frame - extract out the number of spatial streams */ 268198090Srdivacky numStreams = HT_RC_2_STREAMS(rc); 269198090Srdivacky KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix)); 270193323Sed 271193323Sed return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble); 272198090Srdivacky} 273193323Sed 274193323Sed/* 275193323Sed * Calculate the transmit duration of an 11n frame. 276193323Sed * This only works for MCS0->MCS15. 277193323Sed */ 278193323Seduint32_t 279193323Sedath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40, 280193323Sed HAL_BOOL isShortGI) 281193323Sed{ 282193323Sed static const uint16_t ht20_bps[16] = { 283193323Sed 26, 52, 78, 104, 156, 208, 234, 260, 284193323Sed 52, 104, 156, 208, 312, 416, 468, 520 285204642Srdivacky }; 286193323Sed static const uint16_t ht40_bps[16] = { 287193323Sed 54, 108, 162, 216, 324, 432, 486, 540, 288193323Sed 108, 216, 324, 432, 648, 864, 972, 1080, 289193323Sed }; 290193323Sed uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 291193323Sed 292204642Srdivacky KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 293193323Sed KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate)); 294193323Sed 295193323Sed if (isht40) 296193323Sed bitsPerSymbol = ht40_bps[rate & 0xf]; 297193323Sed else 298193323Sed bitsPerSymbol = ht20_bps[rate & 0xf]; 299193323Sed numBits = OFDM_PLCP_BITS + (frameLen << 3); 300193323Sed numSymbols = howmany(numBits, bitsPerSymbol); 301193323Sed if (isShortGI) 302193323Sed txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 303193323Sed else 304193323Sed txTime = numSymbols * 4; /* 4us */ 305193323Sed return txTime + HT_L_STF + HT_L_LTF + 306193323Sed HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 307193323Sed} 308193323Sed 309193323Sed/* 310193323Sed * Compute the time to transmit a frame of length frameLen bytes 311193323Sed * using the specified rate, phy, and short preamble setting. 312193323Sed */ 313193323Seduint16_t 314193323Sedath_hal_computetxtime(struct ath_hal *ah, 315193323Sed const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 316193323Sed HAL_BOOL shortPreamble) 317193323Sed{ 318193323Sed uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 319193323Sed uint32_t kbps; 320193323Sed 321193323Sed kbps = rates->info[rateix].rateKbps; 322193323Sed /* 323193323Sed * index can be invalid duting dynamic Turbo transitions. 324193323Sed * XXX 325193323Sed */ 326193323Sed if (kbps == 0) 327193323Sed return 0; 328193323Sed switch (rates->info[rateix].phy) { 329193323Sed case IEEE80211_T_CCK: 330193323Sed phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 331193323Sed if (shortPreamble && rates->info[rateix].shortPreamble) 332193323Sed phyTime >>= 1; 333193323Sed numBits = frameLen << 3; 334193323Sed txTime = CCK_SIFS_TIME + phyTime 335251662Sdim + ((numBits * 1000)/kbps); 336251662Sdim break; 337251662Sdim case IEEE80211_T_OFDM: 338251662Sdim bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 339251662Sdim HALASSERT(bitsPerSymbol != 0); 340193323Sed 341251662Sdim numBits = OFDM_PLCP_BITS + (frameLen << 3); 342251662Sdim numSymbols = howmany(numBits, bitsPerSymbol); 343251662Sdim txTime = OFDM_SIFS_TIME 344251662Sdim + OFDM_PREAMBLE_TIME 345251662Sdim + (numSymbols * OFDM_SYMBOL_TIME); 346193323Sed break; 347221345Sdim case IEEE80211_T_OFDM_HALF: 348221345Sdim bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 349221345Sdim HALASSERT(bitsPerSymbol != 0); 350221345Sdim 351221345Sdim numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 352221345Sdim numSymbols = howmany(numBits, bitsPerSymbol); 353263508Sdim txTime = OFDM_HALF_SIFS_TIME 354234353Sdim + OFDM_HALF_PREAMBLE_TIME 355234353Sdim + (numSymbols * OFDM_HALF_SYMBOL_TIME); 356221345Sdim break; 357221345Sdim case IEEE80211_T_OFDM_QUARTER: 358221345Sdim bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 359221345Sdim HALASSERT(bitsPerSymbol != 0); 360221345Sdim 361221345Sdim numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 362221345Sdim numSymbols = howmany(numBits, bitsPerSymbol); 363221345Sdim txTime = OFDM_QUARTER_SIFS_TIME 364221345Sdim + OFDM_QUARTER_PREAMBLE_TIME 365221345Sdim + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 366221345Sdim break; 367221345Sdim case IEEE80211_T_TURBO: 368221345Sdim bitsPerSymbol = (kbps * TURBO_SYMBOL_TIME) / 1000; 369234353Sdim HALASSERT(bitsPerSymbol != 0); 370221345Sdim 371221345Sdim numBits = TURBO_PLCP_BITS + (frameLen << 3); 372221345Sdim numSymbols = howmany(numBits, bitsPerSymbol); 373221345Sdim txTime = TURBO_SIFS_TIME 374221345Sdim + TURBO_PREAMBLE_TIME 375221345Sdim + (numSymbols * TURBO_SYMBOL_TIME); 376221345Sdim break; 377221345Sdim default: 378221345Sdim HALDEBUG(ah, HAL_DEBUG_PHYIO, 379221345Sdim "%s: unknown phy %u (rate ix %u)\n", 380221345Sdim __func__, rates->info[rateix].phy, rateix); 381221345Sdim txTime = 0; 382221345Sdim break; 383221345Sdim } 384221345Sdim return txTime; 385221345Sdim} 386221345Sdim 387221345Sdimtypedef enum { 388221345Sdim WIRELESS_MODE_11a = 0, 389221345Sdim WIRELESS_MODE_TURBO = 1, 390221345Sdim WIRELESS_MODE_11b = 2, 391221345Sdim WIRELESS_MODE_11g = 3, 392221345Sdim WIRELESS_MODE_108g = 4, 393221345Sdim 394221345Sdim WIRELESS_MODE_MAX 395221345Sdim} WIRELESS_MODE; 396221345Sdim 397221345Sdimstatic WIRELESS_MODE 398221345Sdimath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 399221345Sdim{ 400221345Sdim if (IEEE80211_IS_CHAN_B(chan)) 401221345Sdim return WIRELESS_MODE_11b; 402221345Sdim if (IEEE80211_IS_CHAN_G(chan)) 403221345Sdim return WIRELESS_MODE_11g; 404221345Sdim if (IEEE80211_IS_CHAN_108G(chan)) 405221345Sdim return WIRELESS_MODE_108g; 406221345Sdim if (IEEE80211_IS_CHAN_TURBO(chan)) 407221345Sdim return WIRELESS_MODE_TURBO; 408221345Sdim return WIRELESS_MODE_11a; 409221345Sdim} 410221345Sdim 411221345Sdim/* 412221345Sdim * Convert between microseconds and core system clocks. 413221345Sdim */ 414221345Sdim /* 11a Turbo 11b 11g 108g */ 415221345Sdimstatic const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 416221345Sdim 417221345Sdimu_int 418221345Sdimath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 419221345Sdim{ 420221345Sdim const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 421221345Sdim u_int clks; 422221345Sdim 423221345Sdim /* NB: ah_curchan may be null when called attach time */ 424221345Sdim if (c != AH_NULL) { 425221345Sdim clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 426221345Sdim if (IEEE80211_IS_CHAN_HT40(c)) 427221345Sdim clks <<= 1; 428221345Sdim } else 429221345Sdim clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 430221345Sdim return clks; 431221345Sdim} 432221345Sdim 433221345Sdimu_int 434221345Sdimath_hal_mac_usec(struct ath_hal *ah, u_int clks) 435221345Sdim{ 436221345Sdim const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 437221345Sdim u_int usec; 438221345Sdim 439221345Sdim /* NB: ah_curchan may be null when called attach time */ 440221345Sdim if (c != AH_NULL) { 441221345Sdim usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 442221345Sdim if (IEEE80211_IS_CHAN_HT40(c)) 443221345Sdim usec >>= 1; 444221345Sdim } else 445221345Sdim usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 446234353Sdim return usec; 447234353Sdim} 448221345Sdim 449221345Sdim/* 450221345Sdim * Setup a h/w rate table's reverse lookup table and 451221345Sdim * fill in ack durations. This routine is called for 452221345Sdim * each rate table returned through the ah_getRateTable 453221345Sdim * method. The reverse lookup tables are assumed to be 454221345Sdim * initialized to zero (or at least the first entry). 455221345Sdim * We use this as a key that indicates whether or not 456221345Sdim * we've previously setup the reverse lookup table. 457221345Sdim * 458221345Sdim * XXX not reentrant, but shouldn't matter 459221345Sdim */ 460221345Sdimvoid 461221345Sdimath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 462221345Sdim{ 463234353Sdim#define N(a) (sizeof(a)/sizeof(a[0])) 464234353Sdim int i; 465221345Sdim 466221345Sdim if (rt->rateCodeToIndex[0] != 0) /* already setup */ 467221345Sdim return; 468193323Sed for (i = 0; i < N(rt->rateCodeToIndex); i++) 469193323Sed rt->rateCodeToIndex[i] = (uint8_t) -1; 470193323Sed for (i = 0; i < rt->rateCount; i++) { 471193323Sed uint8_t code = rt->info[i].rateCode; 472193323Sed uint8_t cix = rt->info[i].controlRate; 473193323Sed 474193323Sed HALASSERT(code < N(rt->rateCodeToIndex)); 475193323Sed rt->rateCodeToIndex[code] = i; 476193323Sed HALASSERT((code | rt->info[i].shortPreamble) < 477193323Sed N(rt->rateCodeToIndex)); 478193323Sed rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 479193323Sed /* 480193323Sed * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 481193323Sed * depends on whether they are marked as basic rates; 482193323Sed * the static tables are setup with an 11b-compatible 483193323Sed * 2Mb/s rate which will work but is suboptimal 484193323Sed */ 485193323Sed rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 486193323Sed WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 487193323Sed rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 488193323Sed WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 489193323Sed } 490193323Sed#undef N 491193323Sed} 492193323Sed 493193323SedHAL_STATUS 494193323Sedath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 495193323Sed uint32_t capability, uint32_t *result) 496193323Sed{ 497193323Sed const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 498193323Sed 499193323Sed switch (type) { 500193323Sed case HAL_CAP_REG_DMN: /* regulatory domain */ 501193323Sed *result = AH_PRIVATE(ah)->ah_currentRD; 502193323Sed return HAL_OK; 503249423Sdim case HAL_CAP_CIPHER: /* cipher handled in hardware */ 504193323Sed case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 505193323Sed return HAL_ENOTSUPP; 506193323Sed case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 507193323Sed return HAL_ENOTSUPP; 508193323Sed case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 509193323Sed return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 510193323Sed case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 511193323Sed return HAL_ENOTSUPP; 512193323Sed case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 513193323Sed return HAL_ENOTSUPP; 514193323Sed case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 515193323Sed *result = pCap->halKeyCacheSize; 516193323Sed return HAL_OK; 517193323Sed case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 518193323Sed *result = pCap->halTotalQueues; 519193323Sed return HAL_OK; 520193323Sed case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 521193323Sed return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 522193323Sed case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 523193323Sed return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 524193323Sed case HAL_CAP_COMPRESSION: 525193323Sed return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 526193323Sed case HAL_CAP_BURST: 527193323Sed return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 528193323Sed case HAL_CAP_FASTFRAME: 529193323Sed return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 530193323Sed case HAL_CAP_DIAG: /* hardware diagnostic support */ 531221345Sdim *result = AH_PRIVATE(ah)->ah_diagreg; 532221345Sdim return HAL_OK; 533221345Sdim case HAL_CAP_TXPOW: /* global tx power limit */ 534221345Sdim switch (capability) { 535221345Sdim case 0: /* facility is supported */ 536221345Sdim return HAL_OK; 537221345Sdim case 1: /* current limit */ 538221345Sdim *result = AH_PRIVATE(ah)->ah_powerLimit; 539221345Sdim return HAL_OK; 540221345Sdim case 2: /* current max tx power */ 541193323Sed *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 542193323Sed return HAL_OK; 543193323Sed case 3: /* scale factor */ 544193323Sed *result = AH_PRIVATE(ah)->ah_tpScale; 545193323Sed return HAL_OK; 546193323Sed } 547193323Sed return HAL_ENOTSUPP; 548193323Sed case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 549193323Sed return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 550193323Sed case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 551193323Sed return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 552193323Sed case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 553193323Sed return HAL_ENOTSUPP; 554193323Sed case HAL_CAP_RFSILENT: /* rfsilent support */ 555193323Sed switch (capability) { 556193323Sed case 0: /* facility is supported */ 557221345Sdim return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 558221345Sdim case 1: /* current setting */ 559193323Sed return AH_PRIVATE(ah)->ah_rfkillEnabled ? 560193323Sed HAL_OK : HAL_ENOTSUPP; 561193323Sed case 2: /* rfsilent config */ 562193323Sed *result = AH_PRIVATE(ah)->ah_rfsilent; 563193323Sed return HAL_OK; 564221345Sdim } 565221345Sdim return HAL_ENOTSUPP; 566221345Sdim case HAL_CAP_11D: 567221345Sdim return HAL_OK; 568221345Sdim case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 569221345Sdim return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 570221345Sdim case HAL_CAP_HT: 571221345Sdim return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 572221345Sdim case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 573221345Sdim *result = pCap->halTxChainMask; 574221345Sdim return HAL_OK; 575221345Sdim case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 576221345Sdim *result = pCap->halRxChainMask; 577221345Sdim return HAL_OK; 578221345Sdim case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 579193323Sed *result = pCap->halTstampPrecision; 580193323Sed return HAL_OK; 581193323Sed case HAL_CAP_INTRMASK: /* mask of supported interrupts */ 582193323Sed *result = pCap->halIntrMask; 583193323Sed return HAL_OK; 584193323Sed case HAL_CAP_BSSIDMATCH: /* hardware has disable bssid match */ 585193323Sed return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP; 586198090Srdivacky case HAL_CAP_STREAMS: /* number of 11n spatial streams */ 587193323Sed switch (capability) { 588193323Sed case 0: /* TX */ 589193323Sed *result = pCap->halTxStreams; 590193323Sed return HAL_OK; 591193323Sed case 1: /* RX */ 592193323Sed *result = pCap->halRxStreams; 593193323Sed return HAL_OK; 594193323Sed default: 595193323Sed return HAL_ENOTSUPP; 596193323Sed } 597193323Sed case HAP_CAP_SPLIT_4KB_TRANS: /* hardware handles descriptors straddling 4k page boundary */ 598193323Sed return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP; 599193323Sed default: 600193323Sed return HAL_EINVAL; 601193323Sed } 602193323Sed} 603193323Sed 604193323SedHAL_BOOL 605193323Sedath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 606193323Sed uint32_t capability, uint32_t setting, HAL_STATUS *status) 607193323Sed{ 608193323Sed 609193323Sed switch (type) { 610193323Sed case HAL_CAP_TXPOW: 611193323Sed switch (capability) { 612193323Sed case 3: 613193323Sed if (setting <= HAL_TP_SCALE_MIN) { 614193323Sed AH_PRIVATE(ah)->ah_tpScale = setting; 615193323Sed return AH_TRUE; 616193323Sed } 617193323Sed break; 618193323Sed } 619193323Sed break; 620193323Sed case HAL_CAP_RFSILENT: /* rfsilent support */ 621193323Sed /* 622193323Sed * NB: allow even if halRfSilentSupport is false 623193323Sed * in case the EEPROM is misprogrammed. 624193323Sed */ 625193323Sed switch (capability) { 626204642Srdivacky case 1: /* current setting */ 627193323Sed AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 628193323Sed return AH_TRUE; 629193323Sed case 2: /* rfsilent config */ 630193323Sed /* XXX better done per-chip for validation? */ 631193323Sed AH_PRIVATE(ah)->ah_rfsilent = setting; 632221345Sdim return AH_TRUE; 633212904Sdim } 634212904Sdim break; 635221345Sdim case HAL_CAP_REG_DMN: /* regulatory domain */ 636221345Sdim AH_PRIVATE(ah)->ah_currentRD = setting; 637212904Sdim return AH_TRUE; 638212904Sdim case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 639193323Sed AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 640193323Sed return AH_TRUE; 641193323Sed default: 642193323Sed break; 643193323Sed } 644212904Sdim if (status) 645193323Sed *status = HAL_EINVAL; 646212904Sdim return AH_FALSE; 647193323Sed} 648193323Sed 649221345Sdim/* 650221345Sdim * Common support for getDiagState method. 651221345Sdim */ 652221345Sdim 653221345Sdimstatic u_int 654193323Sedath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 655198090Srdivacky void *dstbuf, int space) 656198090Srdivacky{ 657193323Sed uint32_t *dp = dstbuf; 658193323Sed int i; 659193323Sed 660193323Sed for (i = 0; space >= 2*sizeof(uint32_t); i++) { 661193323Sed u_int r = regs[i].start; 662249423Sdim u_int e = regs[i].end; 663212904Sdim *dp++ = (r<<16) | e; 664221345Sdim space -= sizeof(uint32_t); 665193323Sed do { 666193323Sed *dp++ = OS_REG_READ(ah, r); 667193323Sed r += sizeof(uint32_t); 668198090Srdivacky space -= sizeof(uint32_t); 669193323Sed } while (r <= e && space >= sizeof(uint32_t)); 670193323Sed } 671193323Sed return (char *) dp - (char *) dstbuf; 672193323Sed} 673193323Sed 674193323Sedstatic void 675193323Sedath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 676212904Sdim{ 677212904Sdim while (space >= sizeof(HAL_REGWRITE)) { 678193323Sed OS_REG_WRITE(ah, regs->addr, regs->value); 679193323Sed regs++, space -= sizeof(HAL_REGWRITE); 680193323Sed } 681193323Sed} 682193323Sed 683193323SedHAL_BOOL 684193323Sedath_hal_getdiagstate(struct ath_hal *ah, int request, 685193323Sed const void *args, uint32_t argsize, 686193323Sed void **result, uint32_t *resultsize) 687193323Sed{ 688193323Sed switch (request) { 689193323Sed case HAL_DIAG_REVS: 690193323Sed *result = &AH_PRIVATE(ah)->ah_devid; 691193323Sed *resultsize = sizeof(HAL_REVS); 692193323Sed return AH_TRUE; 693199481Srdivacky case HAL_DIAG_REGS: 694199481Srdivacky *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 695193323Sed return AH_TRUE; 696193323Sed case HAL_DIAG_SETREGS: 697193323Sed ath_hal_setregs(ah, args, argsize); 698193323Sed *resultsize = 0; 699193323Sed return AH_TRUE; 700193323Sed case HAL_DIAG_FATALERR: 701198090Srdivacky *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 702193323Sed *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 703193323Sed return AH_TRUE; 704193323Sed case HAL_DIAG_EEREAD: 705193323Sed if (argsize != sizeof(uint16_t)) 706193323Sed return AH_FALSE; 707193323Sed if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 708193323Sed return AH_FALSE; 709193323Sed *resultsize = sizeof(uint16_t); 710193323Sed return AH_TRUE; 711193323Sed#ifdef AH_PRIVATE_DIAG 712193323Sed case HAL_DIAG_SETKEY: { 713221345Sdim const HAL_DIAG_KEYVAL *dk; 714221345Sdim 715221345Sdim if (argsize != sizeof(HAL_DIAG_KEYVAL)) 716221345Sdim return AH_FALSE; 717193323Sed dk = (const HAL_DIAG_KEYVAL *)args; 718193323Sed return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 719193323Sed &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 720193323Sed } 721193323Sed case HAL_DIAG_RESETKEY: 722221345Sdim if (argsize != sizeof(uint16_t)) 723221345Sdim return AH_FALSE; 724221345Sdim return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 725221345Sdim#ifdef AH_SUPPORT_WRITE_EEPROM 726193323Sed case HAL_DIAG_EEWRITE: { 727193323Sed const HAL_DIAG_EEVAL *ee; 728193323Sed if (argsize != sizeof(HAL_DIAG_EEVAL)) 729193323Sed return AH_FALSE; 730193323Sed ee = (const HAL_DIAG_EEVAL *)args; 731193323Sed return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 732199481Srdivacky } 733199481Srdivacky#endif /* AH_SUPPORT_WRITE_EEPROM */ 734193323Sed#endif /* AH_PRIVATE_DIAG */ 735221345Sdim case HAL_DIAG_11NCOMPAT: 736193323Sed if (argsize == 0) { 737193323Sed *resultsize = sizeof(uint32_t); 738193323Sed *((uint32_t *)(*result)) = 739193323Sed AH_PRIVATE(ah)->ah_11nCompat; 740193323Sed } else if (argsize == sizeof(uint32_t)) { 741193323Sed AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 742193323Sed } else 743193323Sed return AH_FALSE; 744193323Sed return AH_TRUE; 745194612Sed } 746193323Sed return AH_FALSE; 747198090Srdivacky} 748193323Sed 749193323Sed/* 750193323Sed * Set the properties of the tx queue with the parameters 751193323Sed * from qInfo. 752193323Sed */ 753193323SedHAL_BOOL 754193323Sedath_hal_setTxQProps(struct ath_hal *ah, 755193323Sed HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 756193323Sed{ 757193323Sed uint32_t cw; 758193323Sed 759193323Sed if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 760193323Sed HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 761221345Sdim "%s: inactive queue\n", __func__); 762221345Sdim return AH_FALSE; 763221345Sdim } 764193323Sed /* XXX validate parameters */ 765193323Sed qi->tqi_ver = qInfo->tqi_ver; 766193323Sed qi->tqi_subtype = qInfo->tqi_subtype; 767193323Sed qi->tqi_qflags = qInfo->tqi_qflags; 768193323Sed qi->tqi_priority = qInfo->tqi_priority; 769193323Sed if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 770193323Sed qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 771193323Sed else 772193323Sed qi->tqi_aifs = INIT_AIFS; 773193323Sed if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 774193323Sed cw = AH_MIN(qInfo->tqi_cwmin, 1024); 775193323Sed /* make sure that the CWmin is of the form (2^n - 1) */ 776198090Srdivacky qi->tqi_cwmin = 1; 777193323Sed while (qi->tqi_cwmin < cw) 778193323Sed qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 779193323Sed } else 780193323Sed qi->tqi_cwmin = qInfo->tqi_cwmin; 781193323Sed if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 782193323Sed cw = AH_MIN(qInfo->tqi_cwmax, 1024); 783193323Sed /* make sure that the CWmax is of the form (2^n - 1) */ 784193323Sed qi->tqi_cwmax = 1; 785221345Sdim while (qi->tqi_cwmax < cw) 786221345Sdim qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 787221345Sdim } else 788193323Sed qi->tqi_cwmax = INIT_CWMAX; 789193323Sed /* Set retry limit values */ 790193323Sed if (qInfo->tqi_shretry != 0) 791193323Sed qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 792193323Sed else 793193323Sed qi->tqi_shretry = INIT_SH_RETRY; 794193323Sed if (qInfo->tqi_lgretry != 0) 795193323Sed qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 796193323Sed else 797193323Sed qi->tqi_lgretry = INIT_LG_RETRY; 798193323Sed qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 799193323Sed qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 800193323Sed qi->tqi_burstTime = qInfo->tqi_burstTime; 801198090Srdivacky qi->tqi_readyTime = qInfo->tqi_readyTime; 802193323Sed 803193323Sed switch (qInfo->tqi_subtype) { 804193323Sed case HAL_WME_UPSD: 805193323Sed if (qi->tqi_type == HAL_TX_QUEUE_DATA) 806221345Sdim qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 807221345Sdim break; 808221345Sdim default: 809193323Sed break; /* NB: silence compiler */ 810193323Sed } 811193323Sed return AH_TRUE; 812193323Sed} 813193323Sed 814193323SedHAL_BOOL 815193323Sedath_hal_getTxQProps(struct ath_hal *ah, 816193323Sed HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 817193323Sed{ 818193323Sed if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 819193323Sed HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 820193323Sed "%s: inactive queue\n", __func__); 821193323Sed return AH_FALSE; 822193323Sed } 823198090Srdivacky 824193323Sed qInfo->tqi_qflags = qi->tqi_qflags; 825193323Sed qInfo->tqi_ver = qi->tqi_ver; 826193323Sed qInfo->tqi_subtype = qi->tqi_subtype; 827193323Sed qInfo->tqi_qflags = qi->tqi_qflags; 828221345Sdim qInfo->tqi_priority = qi->tqi_priority; 829221345Sdim qInfo->tqi_aifs = qi->tqi_aifs; 830221345Sdim qInfo->tqi_cwmin = qi->tqi_cwmin; 831193323Sed qInfo->tqi_cwmax = qi->tqi_cwmax; 832193323Sed qInfo->tqi_shretry = qi->tqi_shretry; 833193323Sed qInfo->tqi_lgretry = qi->tqi_lgretry; 834193323Sed qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 835193323Sed qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 836193323Sed qInfo->tqi_burstTime = qi->tqi_burstTime; 837193323Sed qInfo->tqi_readyTime = qi->tqi_readyTime; 838226633Sdim return AH_TRUE; 839226633Sdim} 840226633Sdim 841226633Sdim /* 11a Turbo 11b 11g 108g */ 842226633Sdimstatic const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 843226633Sdim 844226633Sdim/* 845226633Sdim * Read the current channel noise floor and return. 846226633Sdim * If nf cal hasn't finished, channel noise floor should be 0 847226633Sdim * and we return a nominal value based on band and frequency. 848226633Sdim * 849226633Sdim * NB: This is a private routine used by per-chip code to 850226633Sdim * implement the ah_getChanNoise method. 851226633Sdim */ 852226633Sdimint16_t 853226633Sdimath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 854226633Sdim{ 855226633Sdim HAL_CHANNEL_INTERNAL *ichan; 856226633Sdim 857226633Sdim ichan = ath_hal_checkchannel(ah, chan); 858226633Sdim if (ichan == AH_NULL) { 859226633Sdim HALDEBUG(ah, HAL_DEBUG_NFCAL, 860193323Sed "%s: invalid channel %u/0x%x; no mapping\n", 861193323Sed __func__, chan->ic_freq, chan->ic_flags); 862193323Sed return 0; 863193323Sed } 864193323Sed if (ichan->rawNoiseFloor == 0) { 865193323Sed WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 866198090Srdivacky 867193323Sed HALASSERT(mode < WIRELESS_MODE_MAX); 868193323Sed return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 869193323Sed } else 870193323Sed return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 871221345Sdim} 872221345Sdim 873221345Sdim/* 874193323Sed * Process all valid raw noise floors into the dBm noise floor values. 875193323Sed * Though our device has no reference for a dBm noise floor, we perform 876193323Sed * a relative minimization of NF's based on the lowest NF found across a 877193323Sed * channel scan. 878193323Sed */ 879193323Sedvoid 880193323Sedath_hal_process_noisefloor(struct ath_hal *ah) 881193323Sed{ 882193323Sed HAL_CHANNEL_INTERNAL *c; 883193323Sed int16_t correct2, correct5; 884193323Sed int16_t lowest2, lowest5; 885193323Sed int i; 886193323Sed 887198090Srdivacky /* 888193323Sed * Find the lowest 2GHz and 5GHz noise floor values after adjusting 889193323Sed * for statistically recorded NF/channel deviation. 890193323Sed */ 891193323Sed correct2 = lowest2 = 0; 892221345Sdim correct5 = lowest5 = 0; 893221345Sdim for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 894221345Sdim WIRELESS_MODE mode; 895193323Sed int16_t nf; 896193323Sed 897193323Sed c = &AH_PRIVATE(ah)->ah_channels[i]; 898193323Sed if (c->rawNoiseFloor >= 0) 899193323Sed continue; 900193323Sed /* XXX can't identify proper mode */ 901193323Sed mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 902193323Sed nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 903193323Sed ath_hal_getNfAdjust(ah, c); 904193323Sed if (IS_CHAN_5GHZ(c)) { 905193323Sed if (nf < lowest5) { 906193323Sed lowest5 = nf; 907193323Sed correct5 = NOISE_FLOOR[mode] - 908198113Srdivacky (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 909198090Srdivacky } 910193323Sed } else { 911193323Sed if (nf < lowest2) { 912193323Sed lowest2 = nf; 913193323Sed correct2 = NOISE_FLOOR[mode] - 914193323Sed (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 915193323Sed } 916221345Sdim } 917221345Sdim } 918221345Sdim 919193323Sed /* Correct the channels to reach the expected NF value */ 920193323Sed for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 921193323Sed c = &AH_PRIVATE(ah)->ah_channels[i]; 922193323Sed if (c->rawNoiseFloor >= 0) 923193323Sed continue; 924193323Sed /* Apply correction factor */ 925193323Sed c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 926193323Sed (IS_CHAN_5GHZ(c) ? correct5 : correct2); 927193323Sed HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 928193323Sed c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 929193323Sed } 930193323Sed} 931193323Sed 932198113Srdivacky/* 933193323Sed * INI support routines. 934193323Sed */ 935193323Sed 936193323Sedint 937193323Sedath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 938193323Sed int col, int regWr) 939193323Sed{ 940221345Sdim int r; 941221345Sdim 942221345Sdim HALASSERT(col < ia->cols); 943193323Sed for (r = 0; r < ia->rows; r++) { 944193323Sed OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 945193323Sed HAL_INI_VAL(ia, r, col)); 946193323Sed 947193323Sed /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ 948193323Sed if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x78a0) 949221345Sdim OS_DELAY(100); 950221345Sdim 951221345Sdim DMA_YIELD(regWr); 952221345Sdim } 953221345Sdim return regWr; 954221345Sdim} 955221345Sdim 956221345Sdimvoid 957221345Sdimath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 958221345Sdim{ 959221345Sdim int r; 960221345Sdim 961221345Sdim HALASSERT(col < ia->cols); 962221345Sdim for (r = 0; r < ia->rows; r++) 963221345Sdim data[r] = HAL_INI_VAL(ia, r, col); 964221345Sdim} 965221345Sdim 966221345Sdimint 967221345Sdimath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 968221345Sdim const uint32_t data[], int regWr) 969221345Sdim{ 970221345Sdim int r; 971221345Sdim 972221345Sdim for (r = 0; r < ia->rows; r++) { 973221345Sdim OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 974221345Sdim 975221345Sdim /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ 976221345Sdim /* XXX verify whether any analog radio bank writes will hit up this */ 977221345Sdim /* XXX since this is a merlin work-around; and merlin doesn't use radio banks */ 978221345Sdim if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x78a0) 979221345Sdim OS_DELAY(100); 980221345Sdim DMA_YIELD(regWr); 981221345Sdim } 982221345Sdim return regWr; 983221345Sdim} 984221345Sdim