ah.c revision 220444
1185377Ssam/* 2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17186018Ssam * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 220444 2011-04-08 08:49:50Z adrian $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam#include "ah_devid.h" 24220298Sadrian#include "ah_eeprom.h" /* for 5ghz fast clock flag */ 25185377Ssam 26188968Ssam#include "ar5416/ar5416reg.h" /* NB: includes ar5212reg.h */ 27188968Ssam 28185406Ssam/* linker set of registered chips */ 29185406SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip); 30185406Ssam 31185406Ssam/* 32185406Ssam * Check the set of registered chips to see if any recognize 33185406Ssam * the device as one they can support. 34185406Ssam */ 35185406Ssamconst char* 36185406Ssamath_hal_probe(uint16_t vendorid, uint16_t devid) 37185377Ssam{ 38186018Ssam struct ath_hal_chip * const *pchip; 39185377Ssam 40185417Ssam OS_SET_FOREACH(pchip, ah_chips) { 41185406Ssam const char *name = (*pchip)->probe(vendorid, devid); 42185406Ssam if (name != AH_NULL) 43185406Ssam return name; 44185377Ssam } 45185377Ssam return AH_NULL; 46185377Ssam} 47185377Ssam 48185377Ssam/* 49185377Ssam * Attach detects device chip revisions, initializes the hwLayer 50185377Ssam * function list, reads EEPROM information, 51185377Ssam * selects reset vectors, and performs a short self test. 52185377Ssam * Any failures will return an error that should cause a hardware 53185377Ssam * disable. 54185377Ssam */ 55185377Ssamstruct ath_hal* 56185377Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc, 57217624Sadrian HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error) 58185377Ssam{ 59186018Ssam struct ath_hal_chip * const *pchip; 60185377Ssam 61185417Ssam OS_SET_FOREACH(pchip, ah_chips) { 62185406Ssam struct ath_hal_chip *chip = *pchip; 63185406Ssam struct ath_hal *ah; 64185406Ssam 65185406Ssam /* XXX don't have vendorid, assume atheros one works */ 66185406Ssam if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 67185406Ssam continue; 68217624Sadrian ah = chip->attach(devid, sc, st, sh, eepromdata, error); 69185406Ssam if (ah != AH_NULL) { 70185406Ssam /* copy back private state to public area */ 71185406Ssam ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 72185406Ssam ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 73185406Ssam ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 74185406Ssam ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 75185406Ssam ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 76185406Ssam ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 77185406Ssam ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 78185406Ssam return ah; 79185406Ssam } 80185377Ssam } 81185406Ssam return AH_NULL; 82185406Ssam} 83185406Ssam 84188968Ssamconst char * 85188968Ssamath_hal_mac_name(struct ath_hal *ah) 86188968Ssam{ 87188968Ssam switch (ah->ah_macVersion) { 88188968Ssam case AR_SREV_VERSION_CRETE: 89188968Ssam case AR_SREV_VERSION_MAUI_1: 90188968Ssam return "5210"; 91188968Ssam case AR_SREV_VERSION_MAUI_2: 92188968Ssam case AR_SREV_VERSION_OAHU: 93188968Ssam return "5211"; 94188968Ssam case AR_SREV_VERSION_VENICE: 95188968Ssam return "5212"; 96188968Ssam case AR_SREV_VERSION_GRIFFIN: 97188968Ssam return "2413"; 98188968Ssam case AR_SREV_VERSION_CONDOR: 99188968Ssam return "5424"; 100188968Ssam case AR_SREV_VERSION_EAGLE: 101188968Ssam return "5413"; 102188968Ssam case AR_SREV_VERSION_COBRA: 103188968Ssam return "2415"; 104188968Ssam case AR_SREV_2425: 105188968Ssam return "2425"; 106188968Ssam case AR_SREV_2417: 107188968Ssam return "2417"; 108188968Ssam case AR_XSREV_VERSION_OWL_PCI: 109188968Ssam return "5416"; 110188968Ssam case AR_XSREV_VERSION_OWL_PCIE: 111188968Ssam return "5418"; 112188968Ssam case AR_XSREV_VERSION_SOWL: 113188968Ssam return "9160"; 114188968Ssam case AR_XSREV_VERSION_MERLIN: 115188968Ssam return "9280"; 116188968Ssam case AR_XSREV_VERSION_KITE: 117188968Ssam return "9285"; 118188968Ssam } 119188968Ssam return "????"; 120188968Ssam} 121188968Ssam 122187831Ssam/* 123187831Ssam * Return the mask of available modes based on the hardware capabilities. 124187831Ssam */ 125187831Ssamu_int 126187831Ssamath_hal_getwirelessmodes(struct ath_hal*ah) 127187831Ssam{ 128187831Ssam return ath_hal_getWirelessModes(ah); 129187831Ssam} 130187831Ssam 131185406Ssam/* linker set of registered RF backends */ 132185406SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 133185406Ssam 134185406Ssam/* 135185406Ssam * Check the set of registered RF backends to see if 136185406Ssam * any recognize the device as one they can support. 137185406Ssam */ 138185406Ssamstruct ath_hal_rf * 139185406Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 140185406Ssam{ 141186018Ssam struct ath_hal_rf * const *prf; 142185406Ssam 143185417Ssam OS_SET_FOREACH(prf, ah_rfs) { 144185406Ssam struct ath_hal_rf *rf = *prf; 145185406Ssam if (rf->probe(ah)) 146185406Ssam return rf; 147185377Ssam } 148185406Ssam *ecode = HAL_ENOTSUPP; 149185406Ssam return AH_NULL; 150185377Ssam} 151185377Ssam 152188968Ssamconst char * 153188968Ssamath_hal_rf_name(struct ath_hal *ah) 154188968Ssam{ 155188968Ssam switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { 156188968Ssam case 0: /* 5210 */ 157188968Ssam return "5110"; /* NB: made up */ 158188968Ssam case AR_RAD5111_SREV_MAJOR: 159188968Ssam case AR_RAD5111_SREV_PROD: 160188968Ssam return "5111"; 161188968Ssam case AR_RAD2111_SREV_MAJOR: 162188968Ssam return "2111"; 163188968Ssam case AR_RAD5112_SREV_MAJOR: 164188968Ssam case AR_RAD5112_SREV_2_0: 165188968Ssam case AR_RAD5112_SREV_2_1: 166188968Ssam return "5112"; 167188968Ssam case AR_RAD2112_SREV_MAJOR: 168188968Ssam case AR_RAD2112_SREV_2_0: 169188968Ssam case AR_RAD2112_SREV_2_1: 170188968Ssam return "2112"; 171188968Ssam case AR_RAD2413_SREV_MAJOR: 172188968Ssam return "2413"; 173188968Ssam case AR_RAD5413_SREV_MAJOR: 174188968Ssam return "5413"; 175188968Ssam case AR_RAD2316_SREV_MAJOR: 176188968Ssam return "2316"; 177188968Ssam case AR_RAD2317_SREV_MAJOR: 178188968Ssam return "2317"; 179188968Ssam case AR_RAD5424_SREV_MAJOR: 180188968Ssam return "5424"; 181188968Ssam 182188968Ssam case AR_RAD5133_SREV_MAJOR: 183188968Ssam return "5133"; 184188968Ssam case AR_RAD2133_SREV_MAJOR: 185188968Ssam return "2133"; 186188968Ssam case AR_RAD5122_SREV_MAJOR: 187188968Ssam return "5122"; 188188968Ssam case AR_RAD2122_SREV_MAJOR: 189188968Ssam return "2122"; 190188968Ssam } 191188968Ssam return "????"; 192188968Ssam} 193188968Ssam 194185377Ssam/* 195185377Ssam * Poll the register looking for a specific value. 196185377Ssam */ 197185377SsamHAL_BOOL 198185377Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 199185377Ssam{ 200185377Ssam#define AH_TIMEOUT 1000 201217622Sadrian return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT); 202217622Sadrian#undef AH_TIMEOUT 203217622Sadrian} 204217622Sadrian 205217622SadrianHAL_BOOL 206217622Sadrianath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout) 207217622Sadrian{ 208185377Ssam int i; 209185377Ssam 210217622Sadrian for (i = 0; i < timeout; i++) { 211185377Ssam if ((OS_REG_READ(ah, reg) & mask) == val) 212185377Ssam return AH_TRUE; 213185377Ssam OS_DELAY(10); 214185377Ssam } 215185377Ssam HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 216185377Ssam "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 217185377Ssam __func__, reg, OS_REG_READ(ah, reg), mask, val); 218185377Ssam return AH_FALSE; 219185377Ssam} 220185377Ssam 221185377Ssam/* 222185377Ssam * Reverse the bits starting at the low bit for a value of 223185377Ssam * bit_count in size 224185377Ssam */ 225185377Ssamuint32_t 226185377Ssamath_hal_reverseBits(uint32_t val, uint32_t n) 227185377Ssam{ 228185377Ssam uint32_t retval; 229185377Ssam int i; 230185377Ssam 231185377Ssam for (i = 0, retval = 0; i < n; i++) { 232185377Ssam retval = (retval << 1) | (val & 1); 233185377Ssam val >>= 1; 234185377Ssam } 235185377Ssam return retval; 236185377Ssam} 237185377Ssam 238218011Sadrian/* 802.11n related timing definitions */ 239218011Sadrian 240218011Sadrian#define OFDM_PLCP_BITS 22 241218011Sadrian#define HT_L_STF 8 242218011Sadrian#define HT_L_LTF 8 243218011Sadrian#define HT_L_SIG 4 244218011Sadrian#define HT_SIG 8 245218011Sadrian#define HT_STF 4 246218011Sadrian#define HT_LTF(n) ((n) * 4) 247218011Sadrian 248218011Sadrian#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 249218011Sadrian#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 250218011Sadrian#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 251218011Sadrian 252185377Ssam/* 253218011Sadrian * Calculate the duration of a packet whether it is 11n or legacy. 254218011Sadrian */ 255218011Sadrianuint32_t 256218011Sadrianath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen, 257218011Sadrian uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble) 258218011Sadrian{ 259218011Sadrian uint8_t rc; 260218011Sadrian int numStreams; 261218011Sadrian 262218011Sadrian rc = rates->info[rateix].rateCode; 263218011Sadrian 264218011Sadrian /* Legacy rate? Return the old way */ 265218011Sadrian if (! IS_HT_RATE(rc)) 266218011Sadrian return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble); 267218011Sadrian 268218011Sadrian /* 11n frame - extract out the number of spatial streams */ 269218011Sadrian numStreams = HT_RC_2_STREAMS(rc); 270218011Sadrian KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix)); 271218011Sadrian 272218011Sadrian return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble); 273218011Sadrian} 274218011Sadrian 275218011Sadrian/* 276218011Sadrian * Calculate the transmit duration of an 11n frame. 277218011Sadrian * This only works for MCS0->MCS15. 278218011Sadrian */ 279218011Sadrianuint32_t 280218011Sadrianath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40, 281218011Sadrian HAL_BOOL isShortGI) 282218011Sadrian{ 283218011Sadrian static const uint16_t ht20_bps[16] = { 284218011Sadrian 26, 52, 78, 104, 156, 208, 234, 260, 285218011Sadrian 52, 104, 156, 208, 312, 416, 468, 520 286218011Sadrian }; 287218011Sadrian static const uint16_t ht40_bps[16] = { 288218011Sadrian 54, 108, 162, 216, 324, 432, 486, 540, 289218011Sadrian 108, 216, 324, 432, 648, 864, 972, 1080, 290218011Sadrian }; 291218011Sadrian uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 292218011Sadrian 293218011Sadrian KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 294218011Sadrian KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate)); 295218011Sadrian 296218011Sadrian if (isht40) 297218011Sadrian bitsPerSymbol = ht40_bps[rate & 0xf]; 298218011Sadrian else 299218011Sadrian bitsPerSymbol = ht20_bps[rate & 0xf]; 300218011Sadrian numBits = OFDM_PLCP_BITS + (frameLen << 3); 301218011Sadrian numSymbols = howmany(numBits, bitsPerSymbol); 302218011Sadrian if (isShortGI) 303218011Sadrian txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 304218011Sadrian else 305218011Sadrian txTime = numSymbols * 4; /* 4us */ 306218011Sadrian return txTime + HT_L_STF + HT_L_LTF + 307218011Sadrian HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 308218011Sadrian} 309218011Sadrian 310218011Sadrian/* 311185377Ssam * Compute the time to transmit a frame of length frameLen bytes 312185377Ssam * using the specified rate, phy, and short preamble setting. 313185377Ssam */ 314185377Ssamuint16_t 315185377Ssamath_hal_computetxtime(struct ath_hal *ah, 316185377Ssam const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 317185377Ssam HAL_BOOL shortPreamble) 318185377Ssam{ 319185377Ssam uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 320185377Ssam uint32_t kbps; 321185377Ssam 322218923Sadrian /* Warn if this function is called for 11n rates; it should not be! */ 323218923Sadrian if (IS_HT_RATE(rates->info[rateix].rateCode)) 324218923Sadrian ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n", 325218923Sadrian __func__, rateix, rates->info[rateix].rateCode); 326218923Sadrian 327185377Ssam kbps = rates->info[rateix].rateKbps; 328185377Ssam /* 329185377Ssam * index can be invalid duting dynamic Turbo transitions. 330187831Ssam * XXX 331185377Ssam */ 332187831Ssam if (kbps == 0) 333187831Ssam return 0; 334185377Ssam switch (rates->info[rateix].phy) { 335185377Ssam case IEEE80211_T_CCK: 336185377Ssam phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 337185377Ssam if (shortPreamble && rates->info[rateix].shortPreamble) 338185377Ssam phyTime >>= 1; 339185377Ssam numBits = frameLen << 3; 340185377Ssam txTime = CCK_SIFS_TIME + phyTime 341185377Ssam + ((numBits * 1000)/kbps); 342185377Ssam break; 343185377Ssam case IEEE80211_T_OFDM: 344188773Ssam bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 345188773Ssam HALASSERT(bitsPerSymbol != 0); 346185377Ssam 347188773Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 348188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 349188773Ssam txTime = OFDM_SIFS_TIME 350188773Ssam + OFDM_PREAMBLE_TIME 351188773Ssam + (numSymbols * OFDM_SYMBOL_TIME); 352188773Ssam break; 353188773Ssam case IEEE80211_T_OFDM_HALF: 354188773Ssam bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 355188773Ssam HALASSERT(bitsPerSymbol != 0); 356185377Ssam 357188773Ssam numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 358188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 359188773Ssam txTime = OFDM_HALF_SIFS_TIME 360188773Ssam + OFDM_HALF_PREAMBLE_TIME 361188773Ssam + (numSymbols * OFDM_HALF_SYMBOL_TIME); 362188773Ssam break; 363188773Ssam case IEEE80211_T_OFDM_QUARTER: 364188773Ssam bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 365188773Ssam HALASSERT(bitsPerSymbol != 0); 366185377Ssam 367188773Ssam numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 368188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 369188773Ssam txTime = OFDM_QUARTER_SIFS_TIME 370188773Ssam + OFDM_QUARTER_PREAMBLE_TIME 371188773Ssam + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 372185377Ssam break; 373185377Ssam case IEEE80211_T_TURBO: 374191022Ssam bitsPerSymbol = (kbps * TURBO_SYMBOL_TIME) / 1000; 375185377Ssam HALASSERT(bitsPerSymbol != 0); 376185377Ssam 377188773Ssam numBits = TURBO_PLCP_BITS + (frameLen << 3); 378188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 379188773Ssam txTime = TURBO_SIFS_TIME 380188773Ssam + TURBO_PREAMBLE_TIME 381188773Ssam + (numSymbols * TURBO_SYMBOL_TIME); 382185377Ssam break; 383185377Ssam default: 384185377Ssam HALDEBUG(ah, HAL_DEBUG_PHYIO, 385185377Ssam "%s: unknown phy %u (rate ix %u)\n", 386185377Ssam __func__, rates->info[rateix].phy, rateix); 387185377Ssam txTime = 0; 388185377Ssam break; 389185377Ssam } 390185377Ssam return txTime; 391185377Ssam} 392185377Ssam 393185377Ssamtypedef enum { 394185377Ssam WIRELESS_MODE_11a = 0, 395185377Ssam WIRELESS_MODE_TURBO = 1, 396185377Ssam WIRELESS_MODE_11b = 2, 397185377Ssam WIRELESS_MODE_11g = 3, 398185377Ssam WIRELESS_MODE_108g = 4, 399185377Ssam 400185377Ssam WIRELESS_MODE_MAX 401185377Ssam} WIRELESS_MODE; 402185377Ssam 403185377Ssamstatic WIRELESS_MODE 404187831Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 405185377Ssam{ 406187831Ssam if (IEEE80211_IS_CHAN_B(chan)) 407185377Ssam return WIRELESS_MODE_11b; 408187831Ssam if (IEEE80211_IS_CHAN_G(chan)) 409185377Ssam return WIRELESS_MODE_11g; 410187831Ssam if (IEEE80211_IS_CHAN_108G(chan)) 411185377Ssam return WIRELESS_MODE_108g; 412187831Ssam if (IEEE80211_IS_CHAN_TURBO(chan)) 413185377Ssam return WIRELESS_MODE_TURBO; 414185377Ssam return WIRELESS_MODE_11a; 415185377Ssam} 416185377Ssam 417185377Ssam/* 418185377Ssam * Convert between microseconds and core system clocks. 419185377Ssam */ 420185377Ssam /* 11a Turbo 11b 11g 108g */ 421185377Ssamstatic const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 422185377Ssam 423220298Sadrian#define CLOCK_FAST_RATE_5GHZ_OFDM 44 424220298Sadrian 425185377Ssamu_int 426185377Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 427185377Ssam{ 428187831Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 429185377Ssam u_int clks; 430185377Ssam 431185377Ssam /* NB: ah_curchan may be null when called attach time */ 432220298Sadrian /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 433220298Sadrian if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 434220298Sadrian clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM; 435220298Sadrian if (IEEE80211_IS_CHAN_HT40(c)) 436220298Sadrian clks <<= 1; 437220298Sadrian } else if (c != AH_NULL) { 438185377Ssam clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 439187831Ssam if (IEEE80211_IS_CHAN_HT40(c)) 440185377Ssam clks <<= 1; 441185377Ssam } else 442185377Ssam clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 443185377Ssam return clks; 444185377Ssam} 445185377Ssam 446185377Ssamu_int 447185377Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks) 448185377Ssam{ 449187831Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 450185377Ssam u_int usec; 451185377Ssam 452185377Ssam /* NB: ah_curchan may be null when called attach time */ 453220298Sadrian /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 454220298Sadrian if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 455220298Sadrian usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM; 456220298Sadrian if (IEEE80211_IS_CHAN_HT40(c)) 457220298Sadrian usec >>= 1; 458220298Sadrian } else if (c != AH_NULL) { 459185377Ssam usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 460187831Ssam if (IEEE80211_IS_CHAN_HT40(c)) 461185377Ssam usec >>= 1; 462185377Ssam } else 463185377Ssam usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 464185377Ssam return usec; 465185377Ssam} 466185377Ssam 467185377Ssam/* 468185377Ssam * Setup a h/w rate table's reverse lookup table and 469185377Ssam * fill in ack durations. This routine is called for 470185377Ssam * each rate table returned through the ah_getRateTable 471185377Ssam * method. The reverse lookup tables are assumed to be 472185377Ssam * initialized to zero (or at least the first entry). 473185377Ssam * We use this as a key that indicates whether or not 474185377Ssam * we've previously setup the reverse lookup table. 475185377Ssam * 476185377Ssam * XXX not reentrant, but shouldn't matter 477185377Ssam */ 478185377Ssamvoid 479185377Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 480185377Ssam{ 481185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 482185377Ssam int i; 483185377Ssam 484185377Ssam if (rt->rateCodeToIndex[0] != 0) /* already setup */ 485185377Ssam return; 486185377Ssam for (i = 0; i < N(rt->rateCodeToIndex); i++) 487185377Ssam rt->rateCodeToIndex[i] = (uint8_t) -1; 488185377Ssam for (i = 0; i < rt->rateCount; i++) { 489185377Ssam uint8_t code = rt->info[i].rateCode; 490185377Ssam uint8_t cix = rt->info[i].controlRate; 491185377Ssam 492185377Ssam HALASSERT(code < N(rt->rateCodeToIndex)); 493185377Ssam rt->rateCodeToIndex[code] = i; 494185377Ssam HALASSERT((code | rt->info[i].shortPreamble) < 495185377Ssam N(rt->rateCodeToIndex)); 496185377Ssam rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 497185377Ssam /* 498185377Ssam * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 499185377Ssam * depends on whether they are marked as basic rates; 500185377Ssam * the static tables are setup with an 11b-compatible 501185377Ssam * 2Mb/s rate which will work but is suboptimal 502185377Ssam */ 503185377Ssam rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 504185377Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 505185377Ssam rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 506185377Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 507185377Ssam } 508185377Ssam#undef N 509185377Ssam} 510185377Ssam 511185377SsamHAL_STATUS 512185377Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 513185377Ssam uint32_t capability, uint32_t *result) 514185377Ssam{ 515185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 516185377Ssam 517185377Ssam switch (type) { 518185377Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 519185377Ssam *result = AH_PRIVATE(ah)->ah_currentRD; 520185377Ssam return HAL_OK; 521185377Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 522185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 523185377Ssam return HAL_ENOTSUPP; 524185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 525185377Ssam return HAL_ENOTSUPP; 526185377Ssam case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 527185377Ssam return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 528185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 529185377Ssam return HAL_ENOTSUPP; 530185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 531185377Ssam return HAL_ENOTSUPP; 532185377Ssam case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 533185377Ssam *result = pCap->halKeyCacheSize; 534185377Ssam return HAL_OK; 535185377Ssam case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 536185377Ssam *result = pCap->halTotalQueues; 537185377Ssam return HAL_OK; 538185377Ssam case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 539185377Ssam return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 540185377Ssam case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 541185377Ssam return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 542185377Ssam case HAL_CAP_COMPRESSION: 543185377Ssam return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 544185377Ssam case HAL_CAP_BURST: 545185377Ssam return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 546185377Ssam case HAL_CAP_FASTFRAME: 547185377Ssam return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 548185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 549185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 550185377Ssam return HAL_OK; 551185377Ssam case HAL_CAP_TXPOW: /* global tx power limit */ 552185377Ssam switch (capability) { 553185377Ssam case 0: /* facility is supported */ 554185377Ssam return HAL_OK; 555185377Ssam case 1: /* current limit */ 556185377Ssam *result = AH_PRIVATE(ah)->ah_powerLimit; 557185377Ssam return HAL_OK; 558185377Ssam case 2: /* current max tx power */ 559185377Ssam *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 560185377Ssam return HAL_OK; 561185377Ssam case 3: /* scale factor */ 562185377Ssam *result = AH_PRIVATE(ah)->ah_tpScale; 563185377Ssam return HAL_OK; 564185377Ssam } 565185377Ssam return HAL_ENOTSUPP; 566185377Ssam case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 567185377Ssam return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 568185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 569185377Ssam return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 570185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 571185377Ssam return HAL_ENOTSUPP; 572185377Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 573185377Ssam switch (capability) { 574185377Ssam case 0: /* facility is supported */ 575185377Ssam return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 576185377Ssam case 1: /* current setting */ 577185377Ssam return AH_PRIVATE(ah)->ah_rfkillEnabled ? 578185377Ssam HAL_OK : HAL_ENOTSUPP; 579185377Ssam case 2: /* rfsilent config */ 580185377Ssam *result = AH_PRIVATE(ah)->ah_rfsilent; 581185377Ssam return HAL_OK; 582185377Ssam } 583185377Ssam return HAL_ENOTSUPP; 584185377Ssam case HAL_CAP_11D: 585185377Ssam return HAL_OK; 586185377Ssam case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 587185377Ssam return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 588185377Ssam case HAL_CAP_HT: 589185377Ssam return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 590185377Ssam case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 591185377Ssam *result = pCap->halTxChainMask; 592185377Ssam return HAL_OK; 593185377Ssam case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 594185377Ssam *result = pCap->halRxChainMask; 595185377Ssam return HAL_OK; 596185377Ssam case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 597185377Ssam *result = pCap->halTstampPrecision; 598185377Ssam return HAL_OK; 599192396Ssam case HAL_CAP_INTRMASK: /* mask of supported interrupts */ 600192396Ssam *result = pCap->halIntrMask; 601192396Ssam return HAL_OK; 602195114Ssam case HAL_CAP_BSSIDMATCH: /* hardware has disable bssid match */ 603195114Ssam return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP; 604218150Sadrian case HAL_CAP_STREAMS: /* number of 11n spatial streams */ 605218150Sadrian switch (capability) { 606218150Sadrian case 0: /* TX */ 607218150Sadrian *result = pCap->halTxStreams; 608218150Sadrian return HAL_OK; 609218150Sadrian case 1: /* RX */ 610218150Sadrian *result = pCap->halRxStreams; 611218150Sadrian return HAL_OK; 612218150Sadrian default: 613218150Sadrian return HAL_ENOTSUPP; 614218150Sadrian } 615220027Sadrian case HAL_CAP_SPLIT_4KB_TRANS: /* hardware handles descriptors straddling 4k page boundary */ 616218490Sadrian return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP; 617220027Sadrian case HAL_CAP_HAS_PSPOLL: /* hardware has ps-poll support */ 618220027Sadrian return pCap->halHasPsPollSupport ? HAL_OK : HAL_ENOTSUPP; 619220324Sadrian case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ 620220324Sadrian return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; 621185377Ssam default: 622185377Ssam return HAL_EINVAL; 623185377Ssam } 624185377Ssam} 625185377Ssam 626185377SsamHAL_BOOL 627185377Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 628185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 629185377Ssam{ 630185377Ssam 631185377Ssam switch (type) { 632185377Ssam case HAL_CAP_TXPOW: 633185377Ssam switch (capability) { 634185377Ssam case 3: 635185377Ssam if (setting <= HAL_TP_SCALE_MIN) { 636185377Ssam AH_PRIVATE(ah)->ah_tpScale = setting; 637185377Ssam return AH_TRUE; 638185377Ssam } 639185377Ssam break; 640185377Ssam } 641185377Ssam break; 642185377Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 643185377Ssam /* 644185377Ssam * NB: allow even if halRfSilentSupport is false 645185377Ssam * in case the EEPROM is misprogrammed. 646185377Ssam */ 647185377Ssam switch (capability) { 648185377Ssam case 1: /* current setting */ 649185377Ssam AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 650185377Ssam return AH_TRUE; 651185377Ssam case 2: /* rfsilent config */ 652185377Ssam /* XXX better done per-chip for validation? */ 653185377Ssam AH_PRIVATE(ah)->ah_rfsilent = setting; 654185377Ssam return AH_TRUE; 655185377Ssam } 656185377Ssam break; 657185377Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 658185377Ssam AH_PRIVATE(ah)->ah_currentRD = setting; 659185377Ssam return AH_TRUE; 660185377Ssam case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 661185377Ssam AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 662185377Ssam return AH_TRUE; 663185377Ssam default: 664185377Ssam break; 665185377Ssam } 666185377Ssam if (status) 667185377Ssam *status = HAL_EINVAL; 668185377Ssam return AH_FALSE; 669185377Ssam} 670185377Ssam 671185377Ssam/* 672185377Ssam * Common support for getDiagState method. 673185377Ssam */ 674185377Ssam 675185377Ssamstatic u_int 676185377Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 677185377Ssam void *dstbuf, int space) 678185377Ssam{ 679185377Ssam uint32_t *dp = dstbuf; 680185377Ssam int i; 681185377Ssam 682185377Ssam for (i = 0; space >= 2*sizeof(uint32_t); i++) { 683185377Ssam u_int r = regs[i].start; 684185377Ssam u_int e = regs[i].end; 685185377Ssam *dp++ = (r<<16) | e; 686185377Ssam space -= sizeof(uint32_t); 687185377Ssam do { 688185377Ssam *dp++ = OS_REG_READ(ah, r); 689185377Ssam r += sizeof(uint32_t); 690185377Ssam space -= sizeof(uint32_t); 691185377Ssam } while (r <= e && space >= sizeof(uint32_t)); 692185377Ssam } 693185377Ssam return (char *) dp - (char *) dstbuf; 694185377Ssam} 695188771Ssam 696188771Ssamstatic void 697188771Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 698188771Ssam{ 699188771Ssam while (space >= sizeof(HAL_REGWRITE)) { 700188771Ssam OS_REG_WRITE(ah, regs->addr, regs->value); 701188771Ssam regs++, space -= sizeof(HAL_REGWRITE); 702188771Ssam } 703188771Ssam} 704185377Ssam 705185377SsamHAL_BOOL 706185377Ssamath_hal_getdiagstate(struct ath_hal *ah, int request, 707185377Ssam const void *args, uint32_t argsize, 708185377Ssam void **result, uint32_t *resultsize) 709185377Ssam{ 710185377Ssam switch (request) { 711185377Ssam case HAL_DIAG_REVS: 712185377Ssam *result = &AH_PRIVATE(ah)->ah_devid; 713185377Ssam *resultsize = sizeof(HAL_REVS); 714185377Ssam return AH_TRUE; 715185377Ssam case HAL_DIAG_REGS: 716185377Ssam *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 717185377Ssam return AH_TRUE; 718188771Ssam case HAL_DIAG_SETREGS: 719188771Ssam ath_hal_setregs(ah, args, argsize); 720188771Ssam *resultsize = 0; 721188771Ssam return AH_TRUE; 722185377Ssam case HAL_DIAG_FATALERR: 723185377Ssam *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 724185377Ssam *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 725185377Ssam return AH_TRUE; 726185377Ssam case HAL_DIAG_EEREAD: 727185377Ssam if (argsize != sizeof(uint16_t)) 728185377Ssam return AH_FALSE; 729185377Ssam if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 730185377Ssam return AH_FALSE; 731185377Ssam *resultsize = sizeof(uint16_t); 732185377Ssam return AH_TRUE; 733185377Ssam#ifdef AH_PRIVATE_DIAG 734185377Ssam case HAL_DIAG_SETKEY: { 735185377Ssam const HAL_DIAG_KEYVAL *dk; 736185377Ssam 737185377Ssam if (argsize != sizeof(HAL_DIAG_KEYVAL)) 738185377Ssam return AH_FALSE; 739185377Ssam dk = (const HAL_DIAG_KEYVAL *)args; 740185377Ssam return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 741185377Ssam &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 742185377Ssam } 743185377Ssam case HAL_DIAG_RESETKEY: 744185377Ssam if (argsize != sizeof(uint16_t)) 745185377Ssam return AH_FALSE; 746185377Ssam return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 747185380Ssam#ifdef AH_SUPPORT_WRITE_EEPROM 748185380Ssam case HAL_DIAG_EEWRITE: { 749185380Ssam const HAL_DIAG_EEVAL *ee; 750185380Ssam if (argsize != sizeof(HAL_DIAG_EEVAL)) 751185380Ssam return AH_FALSE; 752185380Ssam ee = (const HAL_DIAG_EEVAL *)args; 753185380Ssam return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 754185380Ssam } 755185380Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */ 756185377Ssam#endif /* AH_PRIVATE_DIAG */ 757185377Ssam case HAL_DIAG_11NCOMPAT: 758185377Ssam if (argsize == 0) { 759185377Ssam *resultsize = sizeof(uint32_t); 760185377Ssam *((uint32_t *)(*result)) = 761185377Ssam AH_PRIVATE(ah)->ah_11nCompat; 762185377Ssam } else if (argsize == sizeof(uint32_t)) { 763185377Ssam AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 764185377Ssam } else 765185377Ssam return AH_FALSE; 766185377Ssam return AH_TRUE; 767185377Ssam } 768185377Ssam return AH_FALSE; 769185377Ssam} 770185377Ssam 771185377Ssam/* 772185377Ssam * Set the properties of the tx queue with the parameters 773185377Ssam * from qInfo. 774185377Ssam */ 775185377SsamHAL_BOOL 776185377Ssamath_hal_setTxQProps(struct ath_hal *ah, 777185377Ssam HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 778185377Ssam{ 779185377Ssam uint32_t cw; 780185377Ssam 781185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 782185377Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 783185377Ssam "%s: inactive queue\n", __func__); 784185377Ssam return AH_FALSE; 785185377Ssam } 786185377Ssam /* XXX validate parameters */ 787185377Ssam qi->tqi_ver = qInfo->tqi_ver; 788185377Ssam qi->tqi_subtype = qInfo->tqi_subtype; 789185377Ssam qi->tqi_qflags = qInfo->tqi_qflags; 790185377Ssam qi->tqi_priority = qInfo->tqi_priority; 791185377Ssam if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 792185377Ssam qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 793185377Ssam else 794185377Ssam qi->tqi_aifs = INIT_AIFS; 795185377Ssam if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 796185377Ssam cw = AH_MIN(qInfo->tqi_cwmin, 1024); 797185377Ssam /* make sure that the CWmin is of the form (2^n - 1) */ 798185377Ssam qi->tqi_cwmin = 1; 799185377Ssam while (qi->tqi_cwmin < cw) 800185377Ssam qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 801185377Ssam } else 802185377Ssam qi->tqi_cwmin = qInfo->tqi_cwmin; 803185377Ssam if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 804185377Ssam cw = AH_MIN(qInfo->tqi_cwmax, 1024); 805185377Ssam /* make sure that the CWmax is of the form (2^n - 1) */ 806185377Ssam qi->tqi_cwmax = 1; 807185377Ssam while (qi->tqi_cwmax < cw) 808185377Ssam qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 809185377Ssam } else 810185377Ssam qi->tqi_cwmax = INIT_CWMAX; 811185377Ssam /* Set retry limit values */ 812185377Ssam if (qInfo->tqi_shretry != 0) 813185377Ssam qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 814185377Ssam else 815185377Ssam qi->tqi_shretry = INIT_SH_RETRY; 816185377Ssam if (qInfo->tqi_lgretry != 0) 817185377Ssam qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 818185377Ssam else 819185377Ssam qi->tqi_lgretry = INIT_LG_RETRY; 820185377Ssam qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 821185377Ssam qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 822185377Ssam qi->tqi_burstTime = qInfo->tqi_burstTime; 823185377Ssam qi->tqi_readyTime = qInfo->tqi_readyTime; 824185377Ssam 825185377Ssam switch (qInfo->tqi_subtype) { 826185377Ssam case HAL_WME_UPSD: 827185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_DATA) 828185377Ssam qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 829185377Ssam break; 830185377Ssam default: 831185377Ssam break; /* NB: silence compiler */ 832185377Ssam } 833185377Ssam return AH_TRUE; 834185377Ssam} 835185377Ssam 836185377SsamHAL_BOOL 837185377Ssamath_hal_getTxQProps(struct ath_hal *ah, 838185377Ssam HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 839185377Ssam{ 840185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 841185377Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 842185377Ssam "%s: inactive queue\n", __func__); 843185377Ssam return AH_FALSE; 844185377Ssam } 845185377Ssam 846185377Ssam qInfo->tqi_qflags = qi->tqi_qflags; 847185377Ssam qInfo->tqi_ver = qi->tqi_ver; 848185377Ssam qInfo->tqi_subtype = qi->tqi_subtype; 849185377Ssam qInfo->tqi_qflags = qi->tqi_qflags; 850185377Ssam qInfo->tqi_priority = qi->tqi_priority; 851185377Ssam qInfo->tqi_aifs = qi->tqi_aifs; 852185377Ssam qInfo->tqi_cwmin = qi->tqi_cwmin; 853185377Ssam qInfo->tqi_cwmax = qi->tqi_cwmax; 854185377Ssam qInfo->tqi_shretry = qi->tqi_shretry; 855185377Ssam qInfo->tqi_lgretry = qi->tqi_lgretry; 856185377Ssam qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 857185377Ssam qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 858185377Ssam qInfo->tqi_burstTime = qi->tqi_burstTime; 859185377Ssam qInfo->tqi_readyTime = qi->tqi_readyTime; 860185377Ssam return AH_TRUE; 861185377Ssam} 862185377Ssam 863185377Ssam /* 11a Turbo 11b 11g 108g */ 864185377Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 865185377Ssam 866185377Ssam/* 867185377Ssam * Read the current channel noise floor and return. 868185377Ssam * If nf cal hasn't finished, channel noise floor should be 0 869185377Ssam * and we return a nominal value based on band and frequency. 870185377Ssam * 871185377Ssam * NB: This is a private routine used by per-chip code to 872185377Ssam * implement the ah_getChanNoise method. 873185377Ssam */ 874185377Ssamint16_t 875187831Ssamath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 876185377Ssam{ 877185377Ssam HAL_CHANNEL_INTERNAL *ichan; 878185377Ssam 879185377Ssam ichan = ath_hal_checkchannel(ah, chan); 880185377Ssam if (ichan == AH_NULL) { 881185377Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 882185377Ssam "%s: invalid channel %u/0x%x; no mapping\n", 883187831Ssam __func__, chan->ic_freq, chan->ic_flags); 884185377Ssam return 0; 885185377Ssam } 886185377Ssam if (ichan->rawNoiseFloor == 0) { 887185377Ssam WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 888185377Ssam 889185377Ssam HALASSERT(mode < WIRELESS_MODE_MAX); 890185377Ssam return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 891185377Ssam } else 892185377Ssam return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 893185377Ssam} 894185377Ssam 895185377Ssam/* 896220443Sadrian * Fetch the current setup of ctl/ext noise floor values. 897220443Sadrian * 898220443Sadrian * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply 899220443Sadrian * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust(). 900220443Sadrian * 901220443Sadrian * The caller must supply ctl/ext NF arrays which are at least 902220443Sadrian * AH_MIMO_MAX_CHAINS entries long. 903220443Sadrian */ 904220443Sadrianint 905220443Sadrianath_hal_get_mimo_chan_noise(struct ath_hal *ah, 906220444Sadrian const struct ieee80211_channel *chan, int16_t *nf_ctl, 907220444Sadrian int16_t *nf_ext) 908220443Sadrian{ 909220443Sadrian HAL_CHANNEL_INTERNAL *ichan; 910220443Sadrian int i; 911220443Sadrian 912220443Sadrian ichan = ath_hal_checkchannel(ah, chan); 913220443Sadrian if (ichan == AH_NULL) { 914220443Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 915220443Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 916220443Sadrian __func__, chan->ic_freq, chan->ic_flags); 917220443Sadrian for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 918220443Sadrian nf_ctl[i] = nf_ext[i] = 0; 919220443Sadrian } 920220443Sadrian return 0; 921220443Sadrian } 922220443Sadrian 923220443Sadrian /* Return 0 if there's no valid MIMO values (yet) */ 924220443Sadrian if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) { 925220443Sadrian for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 926220443Sadrian nf_ctl[i] = nf_ext[i] = 0; 927220443Sadrian } 928220443Sadrian return 0; 929220443Sadrian } 930220443Sadrian if (ichan->rawNoiseFloor == 0) { 931220443Sadrian WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 932220443Sadrian HALASSERT(mode < WIRELESS_MODE_MAX); 933220443Sadrian /* 934220443Sadrian * See the comment below - this could cause issues for 935220443Sadrian * stations which have a very low RSSI, below the 936220443Sadrian * 'normalised' NF values in NOISE_FLOOR[]. 937220443Sadrian */ 938220443Sadrian for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 939220443Sadrian nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] + 940220443Sadrian ath_hal_getNfAdjust(ah, ichan); 941220443Sadrian } 942220443Sadrian return 1; 943220443Sadrian } else { 944220443Sadrian /* 945220443Sadrian * The value returned here from a MIMO radio is presumed to be 946220443Sadrian * "good enough" as a NF calculation. As RSSI values are calculated 947220443Sadrian * against this, an adjusted NF may be higher than the RSSI value 948220443Sadrian * returned from a vary weak station, resulting in an obscenely 949220443Sadrian * high signal strength calculation being returned. 950220443Sadrian * 951220443Sadrian * This should be re-evaluated at a later date, along with any 952220443Sadrian * signal strength calculations which are made. Quite likely the 953220443Sadrian * RSSI values will need to be adjusted to ensure the calculations 954220443Sadrian * don't "wrap" when RSSI is less than the "adjusted" NF value. 955220443Sadrian * ("Adjust" here is via ichan->noiseFloorAdjust.) 956220443Sadrian */ 957220443Sadrian for (i = 0; i < AH_MIMO_MAX_CHAINS; i++) { 958220443Sadrian nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan); 959220443Sadrian nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan); 960220443Sadrian } 961220443Sadrian return 1; 962220443Sadrian } 963220443Sadrian} 964220443Sadrian 965220443Sadrian/* 966185377Ssam * Process all valid raw noise floors into the dBm noise floor values. 967185377Ssam * Though our device has no reference for a dBm noise floor, we perform 968185377Ssam * a relative minimization of NF's based on the lowest NF found across a 969185377Ssam * channel scan. 970185377Ssam */ 971185377Ssamvoid 972185377Ssamath_hal_process_noisefloor(struct ath_hal *ah) 973185377Ssam{ 974185377Ssam HAL_CHANNEL_INTERNAL *c; 975185377Ssam int16_t correct2, correct5; 976185377Ssam int16_t lowest2, lowest5; 977185377Ssam int i; 978185377Ssam 979185377Ssam /* 980185377Ssam * Find the lowest 2GHz and 5GHz noise floor values after adjusting 981185377Ssam * for statistically recorded NF/channel deviation. 982185377Ssam */ 983185377Ssam correct2 = lowest2 = 0; 984185377Ssam correct5 = lowest5 = 0; 985185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 986185377Ssam WIRELESS_MODE mode; 987185377Ssam int16_t nf; 988185377Ssam 989185377Ssam c = &AH_PRIVATE(ah)->ah_channels[i]; 990185377Ssam if (c->rawNoiseFloor >= 0) 991185377Ssam continue; 992187831Ssam /* XXX can't identify proper mode */ 993187831Ssam mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 994185377Ssam nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 995185377Ssam ath_hal_getNfAdjust(ah, c); 996185377Ssam if (IS_CHAN_5GHZ(c)) { 997185377Ssam if (nf < lowest5) { 998185377Ssam lowest5 = nf; 999185377Ssam correct5 = NOISE_FLOOR[mode] - 1000185377Ssam (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1001185377Ssam } 1002185377Ssam } else { 1003185377Ssam if (nf < lowest2) { 1004185377Ssam lowest2 = nf; 1005185377Ssam correct2 = NOISE_FLOOR[mode] - 1006185377Ssam (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1007185377Ssam } 1008185377Ssam } 1009185377Ssam } 1010185377Ssam 1011185377Ssam /* Correct the channels to reach the expected NF value */ 1012185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1013185377Ssam c = &AH_PRIVATE(ah)->ah_channels[i]; 1014185377Ssam if (c->rawNoiseFloor >= 0) 1015185377Ssam continue; 1016185377Ssam /* Apply correction factor */ 1017185377Ssam c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 1018185377Ssam (IS_CHAN_5GHZ(c) ? correct5 : correct2); 1019187831Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 1020187831Ssam c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 1021185377Ssam } 1022185377Ssam} 1023185377Ssam 1024185377Ssam/* 1025185377Ssam * INI support routines. 1026185377Ssam */ 1027185377Ssam 1028185377Ssamint 1029185377Ssamath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1030185377Ssam int col, int regWr) 1031185377Ssam{ 1032185377Ssam int r; 1033185377Ssam 1034189713Ssam HALASSERT(col < ia->cols); 1035185377Ssam for (r = 0; r < ia->rows; r++) { 1036185377Ssam OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 1037185377Ssam HAL_INI_VAL(ia, r, col)); 1038217921Sadrian 1039217921Sadrian /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ 1040217921Sadrian if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x78a0) 1041217921Sadrian OS_DELAY(100); 1042217921Sadrian 1043185377Ssam DMA_YIELD(regWr); 1044185377Ssam } 1045185377Ssam return regWr; 1046185377Ssam} 1047185377Ssam 1048185377Ssamvoid 1049185377Ssamath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 1050185377Ssam{ 1051185377Ssam int r; 1052185377Ssam 1053189713Ssam HALASSERT(col < ia->cols); 1054185377Ssam for (r = 0; r < ia->rows; r++) 1055185377Ssam data[r] = HAL_INI_VAL(ia, r, col); 1056185377Ssam} 1057185377Ssam 1058185377Ssamint 1059185377Ssamath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1060185377Ssam const uint32_t data[], int regWr) 1061185377Ssam{ 1062185377Ssam int r; 1063185377Ssam 1064185377Ssam for (r = 0; r < ia->rows; r++) { 1065185377Ssam OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 1066185377Ssam DMA_YIELD(regWr); 1067185377Ssam } 1068185377Ssam return regWr; 1069185377Ssam} 1070219586Sadrian 1071219586Sadrian/* 1072219586Sadrian * These are EEPROM board related routines which should likely live in 1073219586Sadrian * a helper library of some sort. 1074219586Sadrian */ 1075219586Sadrian 1076219586Sadrian/************************************************************** 1077219586Sadrian * ath_ee_getLowerUppderIndex 1078219586Sadrian * 1079219586Sadrian * Return indices surrounding the value in sorted integer lists. 1080219586Sadrian * Requirement: the input list must be monotonically increasing 1081219586Sadrian * and populated up to the list size 1082219586Sadrian * Returns: match is set if an index in the array matches exactly 1083219586Sadrian * or a the target is before or after the range of the array. 1084219586Sadrian */ 1085219586SadrianHAL_BOOL 1086219586Sadrianath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize, 1087219586Sadrian uint16_t *indexL, uint16_t *indexR) 1088219586Sadrian{ 1089219586Sadrian uint16_t i; 1090219586Sadrian 1091219586Sadrian /* 1092219586Sadrian * Check first and last elements for beyond ordered array cases. 1093219586Sadrian */ 1094219586Sadrian if (target <= pList[0]) { 1095219586Sadrian *indexL = *indexR = 0; 1096219586Sadrian return AH_TRUE; 1097219586Sadrian } 1098219586Sadrian if (target >= pList[listSize-1]) { 1099219586Sadrian *indexL = *indexR = (uint16_t)(listSize - 1); 1100219586Sadrian return AH_TRUE; 1101219586Sadrian } 1102219586Sadrian 1103219586Sadrian /* look for value being near or between 2 values in list */ 1104219586Sadrian for (i = 0; i < listSize - 1; i++) { 1105219586Sadrian /* 1106219586Sadrian * If value is close to the current value of the list 1107219586Sadrian * then target is not between values, it is one of the values 1108219586Sadrian */ 1109219586Sadrian if (pList[i] == target) { 1110219586Sadrian *indexL = *indexR = i; 1111219586Sadrian return AH_TRUE; 1112219586Sadrian } 1113219586Sadrian /* 1114219586Sadrian * Look for value being between current value and next value 1115219586Sadrian * if so return these 2 values 1116219586Sadrian */ 1117219586Sadrian if (target < pList[i + 1]) { 1118219586Sadrian *indexL = i; 1119219586Sadrian *indexR = (uint16_t)(i + 1); 1120219586Sadrian return AH_FALSE; 1121219586Sadrian } 1122219586Sadrian } 1123219586Sadrian HALASSERT(0); 1124219586Sadrian *indexL = *indexR = 0; 1125219586Sadrian return AH_FALSE; 1126219586Sadrian} 1127219586Sadrian 1128219586Sadrian/************************************************************** 1129219586Sadrian * ath_ee_FillVpdTable 1130219586Sadrian * 1131219586Sadrian * Fill the Vpdlist for indices Pmax-Pmin 1132219586Sadrian * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4 1133219586Sadrian */ 1134219586SadrianHAL_BOOL 1135219586Sadrianath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList, 1136219586Sadrian uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList) 1137219586Sadrian{ 1138219586Sadrian uint16_t i, k; 1139219586Sadrian uint8_t currPwr = pwrMin; 1140219586Sadrian uint16_t idxL, idxR; 1141219586Sadrian 1142219586Sadrian HALASSERT(pwrMax > pwrMin); 1143219586Sadrian for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 1144219586Sadrian ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts, 1145219586Sadrian &(idxL), &(idxR)); 1146219586Sadrian if (idxR < 1) 1147219586Sadrian idxR = 1; /* extrapolate below */ 1148219586Sadrian if (idxL == numIntercepts - 1) 1149219586Sadrian idxL = (uint16_t)(numIntercepts - 2); /* extrapolate above */ 1150219586Sadrian if (pPwrList[idxL] == pPwrList[idxR]) 1151219586Sadrian k = pVpdList[idxL]; 1152219586Sadrian else 1153219586Sadrian k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 1154219586Sadrian (pPwrList[idxR] - pPwrList[idxL]) ); 1155219586Sadrian HALASSERT(k < 256); 1156219586Sadrian pRetVpdList[i] = (uint8_t)k; 1157219586Sadrian currPwr += 2; /* half dB steps */ 1158219586Sadrian } 1159219586Sadrian 1160219586Sadrian return AH_TRUE; 1161219586Sadrian} 1162219586Sadrian 1163219586Sadrian/************************************************************************** 1164219586Sadrian * ath_ee_interpolate 1165219586Sadrian * 1166219586Sadrian * Returns signed interpolated or the scaled up interpolated value 1167219586Sadrian */ 1168219586Sadrianint16_t 1169219586Sadrianath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 1170219586Sadrian int16_t targetLeft, int16_t targetRight) 1171219586Sadrian{ 1172219586Sadrian int16_t rv; 1173219586Sadrian 1174219586Sadrian if (srcRight == srcLeft) { 1175219586Sadrian rv = targetLeft; 1176219586Sadrian } else { 1177219586Sadrian rv = (int16_t)( ((target - srcLeft) * targetRight + 1178219586Sadrian (srcRight - target) * targetLeft) / (srcRight - srcLeft) ); 1179219586Sadrian } 1180219586Sadrian return rv; 1181219586Sadrian} 1182