ah.c revision 189713
1178354Ssam/* 2178354Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3178354Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4178354Ssam * 5178354Ssam * Permission to use, copy, modify, and/or distribute this software for any 6178354Ssam * purpose with or without fee is hereby granted, provided that the above 7178354Ssam * copyright notice and this permission notice appear in all copies. 8178354Ssam * 9178354Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10178354Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11178354Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12178354Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13178354Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14178354Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15178354Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16178354Ssam * 17178354Ssam * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 189713 2009-03-12 00:09:29Z sam $ 18178354Ssam */ 19178354Ssam#include "opt_ah.h" 20178354Ssam 21178354Ssam#include "ah.h" 22178354Ssam#include "ah_internal.h" 23178354Ssam#include "ah_devid.h" 24178354Ssam 25178354Ssam#include "ar5416/ar5416reg.h" /* NB: includes ar5212reg.h */ 26178354Ssam 27178354Ssam/* linker set of registered chips */ 28178354SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip); 29178354Ssam 30178354Ssam/* 31178354Ssam * Check the set of registered chips to see if any recognize 32178354Ssam * the device as one they can support. 33178354Ssam */ 34178354Ssamconst char* 35178354Ssamath_hal_probe(uint16_t vendorid, uint16_t devid) 36178354Ssam{ 37178354Ssam struct ath_hal_chip * const *pchip; 38178354Ssam 39178354Ssam OS_SET_FOREACH(pchip, ah_chips) { 40178354Ssam const char *name = (*pchip)->probe(vendorid, devid); 41178354Ssam if (name != AH_NULL) 42178354Ssam return name; 43178354Ssam } 44178354Ssam return AH_NULL; 45178354Ssam} 46178354Ssam 47178354Ssam/* 48178354Ssam * Attach detects device chip revisions, initializes the hwLayer 49178354Ssam * function list, reads EEPROM information, 50178354Ssam * selects reset vectors, and performs a short self test. 51178354Ssam * Any failures will return an error that should cause a hardware 52178354Ssam * disable. 53178354Ssam */ 54178354Ssamstruct ath_hal* 55178354Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc, 56178354Ssam HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *error) 57178354Ssam{ 58178354Ssam struct ath_hal_chip * const *pchip; 59178354Ssam 60190391Ssam OS_SET_FOREACH(pchip, ah_chips) { 61190391Ssam struct ath_hal_chip *chip = *pchip; 62190391Ssam struct ath_hal *ah; 63178354Ssam 64178354Ssam /* XXX don't have vendorid, assume atheros one works */ 65178354Ssam if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 66192468Ssam continue; 67178354Ssam ah = chip->attach(devid, sc, st, sh, error); 68192468Ssam if (ah != AH_NULL) { 69178354Ssam /* copy back private state to public area */ 70178354Ssam ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 71178354Ssam ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 72178354Ssam ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 73178354Ssam ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 74178354Ssam ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 75178354Ssam ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 76178354Ssam ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 77178354Ssam return ah; 78178354Ssam } 79178354Ssam } 80178354Ssam return AH_NULL; 81178354Ssam} 82178354Ssam 83178354Ssamconst char * 84178354Ssamath_hal_mac_name(struct ath_hal *ah) 85178354Ssam{ 86178354Ssam switch (ah->ah_macVersion) { 87178354Ssam case AR_SREV_VERSION_CRETE: 88178354Ssam case AR_SREV_VERSION_MAUI_1: 89178354Ssam return "5210"; 90178354Ssam case AR_SREV_VERSION_MAUI_2: 91178354Ssam case AR_SREV_VERSION_OAHU: 92178354Ssam return "5211"; 93178354Ssam case AR_SREV_VERSION_VENICE: 94178354Ssam return "5212"; 95178354Ssam case AR_SREV_VERSION_GRIFFIN: 96178354Ssam return "2413"; 97178354Ssam case AR_SREV_VERSION_CONDOR: 98178354Ssam return "5424"; 99178354Ssam case AR_SREV_VERSION_EAGLE: 100195379Ssam return "5413"; 101195379Ssam case AR_SREV_VERSION_COBRA: 102195379Ssam return "2415"; 103195379Ssam case AR_SREV_2425: 104195379Ssam return "2425"; 105195379Ssam case AR_SREV_2417: 106195379Ssam return "2417"; 107195379Ssam case AR_XSREV_VERSION_OWL_PCI: 108195379Ssam return "5416"; 109195379Ssam case AR_XSREV_VERSION_OWL_PCIE: 110195379Ssam return "5418"; 111195379Ssam case AR_XSREV_VERSION_SOWL: 112195379Ssam return "9160"; 113195379Ssam case AR_XSREV_VERSION_MERLIN: 114195379Ssam return "9280"; 115195379Ssam case AR_XSREV_VERSION_KITE: 116195379Ssam return "9285"; 117195379Ssam } 118195379Ssam return "????"; 119195379Ssam} 120195379Ssam 121195379Ssam/* 122178354Ssam * Return the mask of available modes based on the hardware capabilities. 123178354Ssam */ 124178354Ssamu_int 125178354Ssamath_hal_getwirelessmodes(struct ath_hal*ah) 126178354Ssam{ 127178354Ssam return ath_hal_getWirelessModes(ah); 128178354Ssam} 129178354Ssam 130178354Ssam/* linker set of registered RF backends */ 131178354SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 132178354Ssam 133178354Ssam/* 134178354Ssam * Check the set of registered RF backends to see if 135178354Ssam * any recognize the device as one they can support. 136178354Ssam */ 137178354Ssamstruct ath_hal_rf * 138178354Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 139178354Ssam{ 140178354Ssam struct ath_hal_rf * const *prf; 141178354Ssam 142178354Ssam OS_SET_FOREACH(prf, ah_rfs) { 143178354Ssam struct ath_hal_rf *rf = *prf; 144178354Ssam if (rf->probe(ah)) 145178354Ssam return rf; 146178354Ssam } 147178354Ssam *ecode = HAL_ENOTSUPP; 148178354Ssam return AH_NULL; 149178354Ssam} 150178354Ssam 151178354Ssamconst char * 152178354Ssamath_hal_rf_name(struct ath_hal *ah) 153178354Ssam{ 154178354Ssam switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { 155178354Ssam case 0: /* 5210 */ 156178354Ssam return "5110"; /* NB: made up */ 157178354Ssam case AR_RAD5111_SREV_MAJOR: 158178354Ssam case AR_RAD5111_SREV_PROD: 159178354Ssam return "5111"; 160178354Ssam case AR_RAD2111_SREV_MAJOR: 161178354Ssam return "2111"; 162178354Ssam case AR_RAD5112_SREV_MAJOR: 163178354Ssam case AR_RAD5112_SREV_2_0: 164178354Ssam case AR_RAD5112_SREV_2_1: 165178354Ssam return "5112"; 166178354Ssam case AR_RAD2112_SREV_MAJOR: 167178354Ssam case AR_RAD2112_SREV_2_0: 168178354Ssam case AR_RAD2112_SREV_2_1: 169178354Ssam return "2112"; 170178354Ssam case AR_RAD2413_SREV_MAJOR: 171178354Ssam return "2413"; 172178354Ssam case AR_RAD5413_SREV_MAJOR: 173178354Ssam return "5413"; 174178354Ssam case AR_RAD2316_SREV_MAJOR: 175178354Ssam return "2316"; 176178354Ssam case AR_RAD2317_SREV_MAJOR: 177178354Ssam return "2317"; 178178354Ssam case AR_RAD5424_SREV_MAJOR: 179178354Ssam return "5424"; 180178354Ssam 181178354Ssam case AR_RAD5133_SREV_MAJOR: 182178354Ssam return "5133"; 183178354Ssam case AR_RAD2133_SREV_MAJOR: 184178354Ssam return "2133"; 185178354Ssam case AR_RAD5122_SREV_MAJOR: 186178354Ssam return "5122"; 187178354Ssam case AR_RAD2122_SREV_MAJOR: 188178354Ssam return "2122"; 189178354Ssam } 190178354Ssam return "????"; 191178354Ssam} 192178354Ssam 193178354Ssam/* 194178354Ssam * Poll the register looking for a specific value. 195178354Ssam */ 196178354SsamHAL_BOOL 197178354Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 198178354Ssam{ 199178354Ssam#define AH_TIMEOUT 1000 200178354Ssam int i; 201178354Ssam 202178354Ssam for (i = 0; i < AH_TIMEOUT; i++) { 203178354Ssam if ((OS_REG_READ(ah, reg) & mask) == val) 204178354Ssam return AH_TRUE; 205178354Ssam OS_DELAY(10); 206178354Ssam } 207178354Ssam HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 208178354Ssam "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 209178354Ssam __func__, reg, OS_REG_READ(ah, reg), mask, val); 210178354Ssam return AH_FALSE; 211178354Ssam#undef AH_TIMEOUT 212178354Ssam} 213178354Ssam 214178354Ssam/* 215178354Ssam * Reverse the bits starting at the low bit for a value of 216178354Ssam * bit_count in size 217178354Ssam */ 218178354Ssamuint32_t 219178354Ssamath_hal_reverseBits(uint32_t val, uint32_t n) 220195379Ssam{ 221178354Ssam uint32_t retval; 222195379Ssam int i; 223195379Ssam 224178354Ssam for (i = 0, retval = 0; i < n; i++) { 225178354Ssam retval = (retval << 1) | (val & 1); 226178354Ssam val >>= 1; 227178354Ssam } 228178354Ssam return retval; 229178354Ssam} 230178354Ssam 231178354Ssam/* 232178354Ssam * Compute the time to transmit a frame of length frameLen bytes 233178354Ssam * using the specified rate, phy, and short preamble setting. 234178354Ssam */ 235178354Ssamuint16_t 236178354Ssamath_hal_computetxtime(struct ath_hal *ah, 237178354Ssam const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 238178354Ssam HAL_BOOL shortPreamble) 239178354Ssam{ 240178354Ssam uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 241178354Ssam uint32_t kbps; 242178354Ssam 243178354Ssam kbps = rates->info[rateix].rateKbps; 244178354Ssam /* 245178354Ssam * index can be invalid duting dynamic Turbo transitions. 246178354Ssam * XXX 247178354Ssam */ 248178354Ssam if (kbps == 0) 249178354Ssam return 0; 250178354Ssam switch (rates->info[rateix].phy) { 251178354Ssam case IEEE80211_T_CCK: 252178354Ssam phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 253178354Ssam if (shortPreamble && rates->info[rateix].shortPreamble) 254178354Ssam phyTime >>= 1; 255178354Ssam numBits = frameLen << 3; 256178354Ssam txTime = CCK_SIFS_TIME + phyTime 257190672Ssam + ((numBits * 1000)/kbps); 258178354Ssam break; 259243882Sglebius case IEEE80211_T_OFDM: 260178354Ssam bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 261178354Ssam HALASSERT(bitsPerSymbol != 0); 262178354Ssam 263178354Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 264178354Ssam numSymbols = howmany(numBits, bitsPerSymbol); 265178354Ssam txTime = OFDM_SIFS_TIME 266178354Ssam + OFDM_PREAMBLE_TIME 267178354Ssam + (numSymbols * OFDM_SYMBOL_TIME); 268178354Ssam break; 269178354Ssam case IEEE80211_T_OFDM_HALF: 270178354Ssam bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 271178354Ssam HALASSERT(bitsPerSymbol != 0); 272190672Ssam 273178354Ssam numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 274178354Ssam numSymbols = howmany(numBits, bitsPerSymbol); 275178354Ssam txTime = OFDM_HALF_SIFS_TIME 276178354Ssam + OFDM_HALF_PREAMBLE_TIME 277178354Ssam + (numSymbols * OFDM_HALF_SYMBOL_TIME); 278178354Ssam break; 279178354Ssam case IEEE80211_T_OFDM_QUARTER: 280178354Ssam bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 281178354Ssam HALASSERT(bitsPerSymbol != 0); 282178354Ssam 283178354Ssam numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 284191542Ssam numSymbols = howmany(numBits, bitsPerSymbol); 285191542Ssam txTime = OFDM_QUARTER_SIFS_TIME 286191542Ssam + OFDM_QUARTER_PREAMBLE_TIME 287190672Ssam + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 288190672Ssam break; 289190672Ssam case IEEE80211_T_TURBO: 290190672Ssam /* we still save OFDM rates in kbps - so double them */ 291194461Srpaulo bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; 292190672Ssam HALASSERT(bitsPerSymbol != 0); 293190672Ssam 294190672Ssam numBits = TURBO_PLCP_BITS + (frameLen << 3); 295190672Ssam numSymbols = howmany(numBits, bitsPerSymbol); 296190672Ssam txTime = TURBO_SIFS_TIME 297178354Ssam + TURBO_PREAMBLE_TIME 298178354Ssam + (numSymbols * TURBO_SYMBOL_TIME); 299186658Ssam break; 300178354Ssam default: 301178354Ssam HALDEBUG(ah, HAL_DEBUG_PHYIO, 302178354Ssam "%s: unknown phy %u (rate ix %u)\n", 303178354Ssam __func__, rates->info[rateix].phy, rateix); 304178354Ssam txTime = 0; 305178354Ssam break; 306178354Ssam } 307178354Ssam return txTime; 308178354Ssam} 309178354Ssam 310178354Ssamtypedef enum { 311178354Ssam WIRELESS_MODE_11a = 0, 312178354Ssam WIRELESS_MODE_TURBO = 1, 313178354Ssam WIRELESS_MODE_11b = 2, 314178354Ssam WIRELESS_MODE_11g = 3, 315178354Ssam WIRELESS_MODE_108g = 4, 316178354Ssam 317178354Ssam WIRELESS_MODE_MAX 318178354Ssam} WIRELESS_MODE; 319178354Ssam 320178354Ssamstatic WIRELESS_MODE 321195379Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 322195379Ssam{ 323195379Ssam if (IEEE80211_IS_CHAN_B(chan)) 324195379Ssam return WIRELESS_MODE_11b; 325195379Ssam if (IEEE80211_IS_CHAN_G(chan)) 326195379Ssam return WIRELESS_MODE_11g; 327195379Ssam if (IEEE80211_IS_CHAN_108G(chan)) 328195379Ssam return WIRELESS_MODE_108g; 329195379Ssam if (IEEE80211_IS_CHAN_TURBO(chan)) 330195379Ssam return WIRELESS_MODE_TURBO; 331195379Ssam return WIRELESS_MODE_11a; 332195379Ssam} 333178354Ssam 334178354Ssam/* 335178354Ssam * Convert between microseconds and core system clocks. 336178354Ssam */ 337178354Ssam /* 11a Turbo 11b 11g 108g */ 338178354Ssamstatic const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 339178354Ssam 340178354Ssamu_int 341178354Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 342178354Ssam{ 343178354Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 344178354Ssam u_int clks; 345178354Ssam 346178354Ssam /* NB: ah_curchan may be null when called attach time */ 347178354Ssam if (c != AH_NULL) { 348178354Ssam clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 349178354Ssam if (IEEE80211_IS_CHAN_HT40(c)) 350178354Ssam clks <<= 1; 351178354Ssam } else 352178354Ssam clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 353178354Ssam return clks; 354178354Ssam} 355178354Ssam 356178354Ssamu_int 357178354Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks) 358178354Ssam{ 359178354Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 360178354Ssam u_int usec; 361178354Ssam 362178354Ssam /* NB: ah_curchan may be null when called attach time */ 363178354Ssam if (c != AH_NULL) { 364178354Ssam usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 365178354Ssam if (IEEE80211_IS_CHAN_HT40(c)) 366178354Ssam usec >>= 1; 367178354Ssam } else 368178354Ssam usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 369178354Ssam return usec; 370178354Ssam} 371178354Ssam 372178354Ssam/* 373178354Ssam * Setup a h/w rate table's reverse lookup table and 374178354Ssam * fill in ack durations. This routine is called for 375178354Ssam * each rate table returned through the ah_getRateTable 376178354Ssam * method. The reverse lookup tables are assumed to be 377178354Ssam * initialized to zero (or at least the first entry). 378178354Ssam * We use this as a key that indicates whether or not 379178354Ssam * we've previously setup the reverse lookup table. 380178354Ssam * 381178354Ssam * XXX not reentrant, but shouldn't matter 382178354Ssam */ 383178354Ssamvoid 384178354Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 385178354Ssam{ 386178354Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 387178354Ssam int i; 388178354Ssam 389178354Ssam if (rt->rateCodeToIndex[0] != 0) /* already setup */ 390178354Ssam return; 391178354Ssam for (i = 0; i < N(rt->rateCodeToIndex); i++) 392178354Ssam rt->rateCodeToIndex[i] = (uint8_t) -1; 393178354Ssam for (i = 0; i < rt->rateCount; i++) { 394178354Ssam uint8_t code = rt->info[i].rateCode; 395178354Ssam uint8_t cix = rt->info[i].controlRate; 396178354Ssam 397178354Ssam HALASSERT(code < N(rt->rateCodeToIndex)); 398178354Ssam rt->rateCodeToIndex[code] = i; 399178354Ssam HALASSERT((code | rt->info[i].shortPreamble) < 400178354Ssam N(rt->rateCodeToIndex)); 401178354Ssam rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 402178354Ssam /* 403178354Ssam * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 404178354Ssam * depends on whether they are marked as basic rates; 405178354Ssam * the static tables are setup with an 11b-compatible 406178354Ssam * 2Mb/s rate which will work but is suboptimal 407192468Ssam */ 408178354Ssam rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 409178354Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 410178354Ssam rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 411178354Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 412178354Ssam } 413178354Ssam#undef N 414178354Ssam} 415178354Ssam 416203422SrpauloHAL_STATUS 417178354Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 418178354Ssam uint32_t capability, uint32_t *result) 419178354Ssam{ 420183247Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 421178354Ssam 422178354Ssam switch (type) { 423183247Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 424183247Ssam *result = AH_PRIVATE(ah)->ah_currentRD; 425183247Ssam return HAL_OK; 426183247Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 427183247Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 428178354Ssam return HAL_ENOTSUPP; 429178354Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 430178354Ssam return HAL_ENOTSUPP; 431178354Ssam case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 432178354Ssam return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 433178354Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 434178354Ssam return HAL_ENOTSUPP; 435178354Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 436178354Ssam return HAL_ENOTSUPP; 437178354Ssam case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 438178354Ssam *result = pCap->halKeyCacheSize; 439178354Ssam return HAL_OK; 440178354Ssam case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 441178354Ssam *result = pCap->halTotalQueues; 442178354Ssam return HAL_OK; 443178354Ssam case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 444178354Ssam return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 445178354Ssam case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 446178354Ssam return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 447178354Ssam case HAL_CAP_COMPRESSION: 448178354Ssam return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 449178354Ssam case HAL_CAP_BURST: 450178354Ssam return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 451178354Ssam case HAL_CAP_FASTFRAME: 452178354Ssam return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 453178354Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 454178354Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 455178354Ssam return HAL_OK; 456218958Sbschmidt case HAL_CAP_TXPOW: /* global tx power limit */ 457218958Sbschmidt switch (capability) { 458218958Sbschmidt case 0: /* facility is supported */ 459178354Ssam return HAL_OK; 460178354Ssam case 1: /* current limit */ 461178354Ssam *result = AH_PRIVATE(ah)->ah_powerLimit; 462191547Ssam return HAL_OK; 463191547Ssam case 2: /* current max tx power */ 464178354Ssam *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 465178354Ssam return HAL_OK; 466178354Ssam case 3: /* scale factor */ 467178354Ssam *result = AH_PRIVATE(ah)->ah_tpScale; 468178354Ssam return HAL_OK; 469178354Ssam } 470178354Ssam return HAL_ENOTSUPP; 471178354Ssam case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 472178354Ssam return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 473178354Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 474178354Ssam return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 475178354Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 476178354Ssam return HAL_ENOTSUPP; 477178354Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 478178354Ssam switch (capability) { 479178354Ssam case 0: /* facility is supported */ 480178354Ssam return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 481178354Ssam case 1: /* current setting */ 482178354Ssam return AH_PRIVATE(ah)->ah_rfkillEnabled ? 483178354Ssam HAL_OK : HAL_ENOTSUPP; 484178354Ssam case 2: /* rfsilent config */ 485178354Ssam *result = AH_PRIVATE(ah)->ah_rfsilent; 486178354Ssam return HAL_OK; 487178354Ssam } 488178354Ssam return HAL_ENOTSUPP; 489178354Ssam case HAL_CAP_11D: 490192468Ssam return HAL_OK; 491178354Ssam case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 492178354Ssam return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 493178354Ssam case HAL_CAP_HT: 494178354Ssam return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 495178354Ssam case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 496178354Ssam *result = pCap->halTxChainMask; 497221418Sadrian return HAL_OK; 498178354Ssam case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 499178354Ssam *result = pCap->halRxChainMask; 500178354Ssam return HAL_OK; 501178354Ssam case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 502178354Ssam *result = pCap->halTstampPrecision; 503178354Ssam return HAL_OK; 504178354Ssam default: 505178354Ssam return HAL_EINVAL; 506178354Ssam } 507178354Ssam} 508178354Ssam 509178354SsamHAL_BOOL 510178354Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 511178354Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 512178354Ssam{ 513178354Ssam 514178354Ssam switch (type) { 515178354Ssam case HAL_CAP_TXPOW: 516178354Ssam switch (capability) { 517178354Ssam case 3: 518178354Ssam if (setting <= HAL_TP_SCALE_MIN) { 519178354Ssam AH_PRIVATE(ah)->ah_tpScale = setting; 520178354Ssam return AH_TRUE; 521178354Ssam } 522178354Ssam break; 523178354Ssam } 524178354Ssam break; 525178354Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 526178354Ssam /* 527178354Ssam * NB: allow even if halRfSilentSupport is false 528178354Ssam * in case the EEPROM is misprogrammed. 529178354Ssam */ 530178354Ssam switch (capability) { 531178354Ssam case 1: /* current setting */ 532178354Ssam AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 533178354Ssam return AH_TRUE; 534178354Ssam case 2: /* rfsilent config */ 535178354Ssam /* XXX better done per-chip for validation? */ 536178354Ssam AH_PRIVATE(ah)->ah_rfsilent = setting; 537178354Ssam return AH_TRUE; 538178354Ssam } 539178354Ssam break; 540183247Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 541183247Ssam AH_PRIVATE(ah)->ah_currentRD = setting; 542178354Ssam return AH_TRUE; 543178354Ssam case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 544178354Ssam AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 545183247Ssam return AH_TRUE; 546178354Ssam default: 547178354Ssam break; 548178354Ssam } 549178354Ssam if (status) 550178354Ssam *status = HAL_EINVAL; 551178354Ssam return AH_FALSE; 552178354Ssam} 553178354Ssam 554178354Ssam/* 555178354Ssam * Common support for getDiagState method. 556178354Ssam */ 557178354Ssam 558178354Ssamstatic u_int 559178354Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 560178354Ssam void *dstbuf, int space) 561178354Ssam{ 562178354Ssam uint32_t *dp = dstbuf; 563178354Ssam int i; 564178354Ssam 565178354Ssam for (i = 0; space >= 2*sizeof(uint32_t); i++) { 566178354Ssam u_int r = regs[i].start; 567178354Ssam u_int e = regs[i].end; 568178354Ssam *dp++ = (r<<16) | e; 569178354Ssam space -= sizeof(uint32_t); 570178354Ssam do { 571178354Ssam *dp++ = OS_REG_READ(ah, r); 572178354Ssam r += sizeof(uint32_t); 573178354Ssam space -= sizeof(uint32_t); 574178354Ssam } while (r <= e && space >= sizeof(uint32_t)); 575178354Ssam } 576178354Ssam return (char *) dp - (char *) dstbuf; 577178354Ssam} 578178354Ssam 579178354Ssamstatic void 580178354Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 581178354Ssam{ 582178354Ssam while (space >= sizeof(HAL_REGWRITE)) { 583178354Ssam OS_REG_WRITE(ah, regs->addr, regs->value); 584178354Ssam regs++, space -= sizeof(HAL_REGWRITE); 585178354Ssam } 586178354Ssam} 587178354Ssam 588178354SsamHAL_BOOL 589178354Ssamath_hal_getdiagstate(struct ath_hal *ah, int request, 590178354Ssam const void *args, uint32_t argsize, 591178354Ssam void **result, uint32_t *resultsize) 592178354Ssam{ 593178354Ssam switch (request) { 594178354Ssam case HAL_DIAG_REVS: 595178354Ssam *result = &AH_PRIVATE(ah)->ah_devid; 596178354Ssam *resultsize = sizeof(HAL_REVS); 597178354Ssam return AH_TRUE; 598178354Ssam case HAL_DIAG_REGS: 599178354Ssam *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 600178354Ssam return AH_TRUE; 601178354Ssam case HAL_DIAG_SETREGS: 602178354Ssam ath_hal_setregs(ah, args, argsize); 603178354Ssam *resultsize = 0; 604178354Ssam return AH_TRUE; 605178354Ssam case HAL_DIAG_FATALERR: 606178354Ssam *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 607178354Ssam *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 608178354Ssam return AH_TRUE; 609178354Ssam case HAL_DIAG_EEREAD: 610178354Ssam if (argsize != sizeof(uint16_t)) 611178354Ssam return AH_FALSE; 612178354Ssam if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 613178354Ssam return AH_FALSE; 614178354Ssam *resultsize = sizeof(uint16_t); 615178354Ssam return AH_TRUE; 616178354Ssam#ifdef AH_PRIVATE_DIAG 617178354Ssam case HAL_DIAG_SETKEY: { 618192468Ssam const HAL_DIAG_KEYVAL *dk; 619192468Ssam 620178354Ssam if (argsize != sizeof(HAL_DIAG_KEYVAL)) 621178354Ssam return AH_FALSE; 622178354Ssam dk = (const HAL_DIAG_KEYVAL *)args; 623178354Ssam return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 624178354Ssam &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 625178354Ssam } 626178354Ssam case HAL_DIAG_RESETKEY: 627178354Ssam if (argsize != sizeof(uint16_t)) 628178354Ssam return AH_FALSE; 629178354Ssam return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 630178354Ssam#ifdef AH_SUPPORT_WRITE_EEPROM 631178354Ssam case HAL_DIAG_EEWRITE: { 632178354Ssam const HAL_DIAG_EEVAL *ee; 633178354Ssam if (argsize != sizeof(HAL_DIAG_EEVAL)) 634178354Ssam return AH_FALSE; 635178354Ssam ee = (const HAL_DIAG_EEVAL *)args; 636178354Ssam return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 637178354Ssam } 638178354Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */ 639178354Ssam#endif /* AH_PRIVATE_DIAG */ 640178354Ssam case HAL_DIAG_11NCOMPAT: 641178354Ssam if (argsize == 0) { 642178354Ssam *resultsize = sizeof(uint32_t); 643178354Ssam *((uint32_t *)(*result)) = 644178354Ssam AH_PRIVATE(ah)->ah_11nCompat; 645178354Ssam } else if (argsize == sizeof(uint32_t)) { 646178354Ssam AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 647178354Ssam } else 648178354Ssam return AH_FALSE; 649178354Ssam return AH_TRUE; 650178354Ssam } 651178354Ssam return AH_FALSE; 652178354Ssam} 653178354Ssam 654178354Ssam/* 655178354Ssam * Set the properties of the tx queue with the parameters 656178354Ssam * from qInfo. 657178354Ssam */ 658178354SsamHAL_BOOL 659178354Ssamath_hal_setTxQProps(struct ath_hal *ah, 660178354Ssam HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 661178354Ssam{ 662178354Ssam uint32_t cw; 663178354Ssam 664178354Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 665178354Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 666178354Ssam "%s: inactive queue\n", __func__); 667178354Ssam return AH_FALSE; 668178354Ssam } 669178354Ssam /* XXX validate parameters */ 670178354Ssam qi->tqi_ver = qInfo->tqi_ver; 671178354Ssam qi->tqi_subtype = qInfo->tqi_subtype; 672178354Ssam qi->tqi_qflags = qInfo->tqi_qflags; 673178354Ssam qi->tqi_priority = qInfo->tqi_priority; 674178354Ssam if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 675178354Ssam qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 676178354Ssam else 677178354Ssam qi->tqi_aifs = INIT_AIFS; 678190391Ssam if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 679190391Ssam cw = AH_MIN(qInfo->tqi_cwmin, 1024); 680190391Ssam /* make sure that the CWmin is of the form (2^n - 1) */ 681190391Ssam qi->tqi_cwmin = 1; 682178354Ssam while (qi->tqi_cwmin < cw) 683190391Ssam qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 684178354Ssam } else 685178354Ssam qi->tqi_cwmin = qInfo->tqi_cwmin; 686178354Ssam if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 687178354Ssam cw = AH_MIN(qInfo->tqi_cwmax, 1024); 688178354Ssam /* make sure that the CWmax is of the form (2^n - 1) */ 689178354Ssam qi->tqi_cwmax = 1; 690178354Ssam while (qi->tqi_cwmax < cw) 691178354Ssam qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 692178354Ssam } else 693178354Ssam qi->tqi_cwmax = INIT_CWMAX; 694178354Ssam /* Set retry limit values */ 695178354Ssam if (qInfo->tqi_shretry != 0) 696178354Ssam qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 697178354Ssam else 698178354Ssam qi->tqi_shretry = INIT_SH_RETRY; 699178354Ssam if (qInfo->tqi_lgretry != 0) 700178354Ssam qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 701178354Ssam else 702178354Ssam qi->tqi_lgretry = INIT_LG_RETRY; 703178354Ssam qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 704178354Ssam qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 705178354Ssam qi->tqi_burstTime = qInfo->tqi_burstTime; 706178354Ssam qi->tqi_readyTime = qInfo->tqi_readyTime; 707178354Ssam 708178354Ssam switch (qInfo->tqi_subtype) { 709178354Ssam case HAL_WME_UPSD: 710178354Ssam if (qi->tqi_type == HAL_TX_QUEUE_DATA) 711178354Ssam qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 712178354Ssam break; 713178354Ssam default: 714178354Ssam break; /* NB: silence compiler */ 715178354Ssam } 716178354Ssam return AH_TRUE; 717178354Ssam} 718192468Ssam 719192468SsamHAL_BOOL 720178354Ssamath_hal_getTxQProps(struct ath_hal *ah, 721178354Ssam HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 722178354Ssam{ 723178354Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 724178354Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 725192468Ssam "%s: inactive queue\n", __func__); 726178354Ssam return AH_FALSE; 727178354Ssam } 728178354Ssam 729178354Ssam qInfo->tqi_qflags = qi->tqi_qflags; 730178354Ssam qInfo->tqi_ver = qi->tqi_ver; 731178354Ssam qInfo->tqi_subtype = qi->tqi_subtype; 732178354Ssam qInfo->tqi_qflags = qi->tqi_qflags; 733178354Ssam qInfo->tqi_priority = qi->tqi_priority; 734178354Ssam qInfo->tqi_aifs = qi->tqi_aifs; 735178354Ssam qInfo->tqi_cwmin = qi->tqi_cwmin; 736192765Ssam qInfo->tqi_cwmax = qi->tqi_cwmax; 737192468Ssam qInfo->tqi_shretry = qi->tqi_shretry; 738178354Ssam qInfo->tqi_lgretry = qi->tqi_lgretry; 739178354Ssam qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 740178354Ssam qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 741178354Ssam qInfo->tqi_burstTime = qi->tqi_burstTime; 742178354Ssam qInfo->tqi_readyTime = qi->tqi_readyTime; 743178354Ssam return AH_TRUE; 744178354Ssam} 745192468Ssam 746178354Ssam /* 11a Turbo 11b 11g 108g */ 747178354Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 748178354Ssam 749178354Ssam/* 750178354Ssam * Read the current channel noise floor and return. 751178354Ssam * If nf cal hasn't finished, channel noise floor should be 0 752178354Ssam * and we return a nominal value based on band and frequency. 753178354Ssam * 754178354Ssam * NB: This is a private routine used by per-chip code to 755178354Ssam * implement the ah_getChanNoise method. 756218927Sbschmidt */ 757218927Sbschmidtint16_t 758218958Sbschmidtath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 759218958Sbschmidt{ 760218958Sbschmidt HAL_CHANNEL_INTERNAL *ichan; 761218927Sbschmidt 762218958Sbschmidt ichan = ath_hal_checkchannel(ah, chan); 763218958Sbschmidt if (ichan == AH_NULL) { 764218927Sbschmidt HALDEBUG(ah, HAL_DEBUG_NFCAL, 765218958Sbschmidt "%s: invalid channel %u/0x%x; no mapping\n", 766218958Sbschmidt __func__, chan->ic_freq, chan->ic_flags); 767218958Sbschmidt return 0; 768218958Sbschmidt } 769218927Sbschmidt if (ichan->rawNoiseFloor == 0) { 770218927Sbschmidt WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 771218927Sbschmidt 772218958Sbschmidt HALASSERT(mode < WIRELESS_MODE_MAX); 773218958Sbschmidt return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 774218958Sbschmidt } else 775218927Sbschmidt return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 776218927Sbschmidt} 777218927Sbschmidt 778178354Ssam/* 779218927Sbschmidt * Process all valid raw noise floors into the dBm noise floor values. 780178354Ssam * Though our device has no reference for a dBm noise floor, we perform 781178354Ssam * a relative minimization of NF's based on the lowest NF found across a 782218927Sbschmidt * channel scan. 783218927Sbschmidt */ 784218927Sbschmidtvoid 785218927Sbschmidtath_hal_process_noisefloor(struct ath_hal *ah) 786178354Ssam{ 787218927Sbschmidt HAL_CHANNEL_INTERNAL *c; 788218927Sbschmidt int16_t correct2, correct5; 789218927Sbschmidt int16_t lowest2, lowest5; 790218927Sbschmidt int i; 791178354Ssam 792178354Ssam /* 793218927Sbschmidt * Find the lowest 2GHz and 5GHz noise floor values after adjusting 794178354Ssam * for statistically recorded NF/channel deviation. 795178354Ssam */ 796218927Sbschmidt correct2 = lowest2 = 0; 797178354Ssam correct5 = lowest5 = 0; 798178354Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 799178354Ssam WIRELESS_MODE mode; 800178354Ssam int16_t nf; 801 802 c = &AH_PRIVATE(ah)->ah_channels[i]; 803 if (c->rawNoiseFloor >= 0) 804 continue; 805 /* XXX can't identify proper mode */ 806 mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 807 nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 808 ath_hal_getNfAdjust(ah, c); 809 if (IS_CHAN_5GHZ(c)) { 810 if (nf < lowest5) { 811 lowest5 = nf; 812 correct5 = NOISE_FLOOR[mode] - 813 (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 814 } 815 } else { 816 if (nf < lowest2) { 817 lowest2 = nf; 818 correct2 = NOISE_FLOOR[mode] - 819 (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 820 } 821 } 822 } 823 824 /* Correct the channels to reach the expected NF value */ 825 for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 826 c = &AH_PRIVATE(ah)->ah_channels[i]; 827 if (c->rawNoiseFloor >= 0) 828 continue; 829 /* Apply correction factor */ 830 c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 831 (IS_CHAN_5GHZ(c) ? correct5 : correct2); 832 HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 833 c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 834 } 835} 836 837/* 838 * INI support routines. 839 */ 840 841int 842ath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 843 int col, int regWr) 844{ 845 int r; 846 847 HALASSERT(col < ia->cols); 848 for (r = 0; r < ia->rows; r++) { 849 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 850 HAL_INI_VAL(ia, r, col)); 851 DMA_YIELD(regWr); 852 } 853 return regWr; 854} 855 856void 857ath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 858{ 859 int r; 860 861 HALASSERT(col < ia->cols); 862 for (r = 0; r < ia->rows; r++) 863 data[r] = HAL_INI_VAL(ia, r, col); 864} 865 866int 867ath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 868 const uint32_t data[], int regWr) 869{ 870 int r; 871 872 for (r = 0; r < ia->rows; r++) { 873 OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 874 DMA_YIELD(regWr); 875 } 876 return regWr; 877} 878