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$ 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 */ 27239604Sadrian#include "ar9003/ar9300_devid.h" 28188968Ssam 29185406Ssam/* linker set of registered chips */ 30185406SsamOS_SET_DECLARE(ah_chips, struct ath_hal_chip); 31185406Ssam 32185406Ssam/* 33185406Ssam * Check the set of registered chips to see if any recognize 34185406Ssam * the device as one they can support. 35185406Ssam */ 36185406Ssamconst char* 37185406Ssamath_hal_probe(uint16_t vendorid, uint16_t devid) 38185377Ssam{ 39186018Ssam struct ath_hal_chip * const *pchip; 40185377Ssam 41185417Ssam OS_SET_FOREACH(pchip, ah_chips) { 42185406Ssam const char *name = (*pchip)->probe(vendorid, devid); 43185406Ssam if (name != AH_NULL) 44185406Ssam return name; 45185377Ssam } 46185377Ssam return AH_NULL; 47185377Ssam} 48185377Ssam 49185377Ssam/* 50185377Ssam * Attach detects device chip revisions, initializes the hwLayer 51185377Ssam * function list, reads EEPROM information, 52185377Ssam * selects reset vectors, and performs a short self test. 53185377Ssam * Any failures will return an error that should cause a hardware 54185377Ssam * disable. 55185377Ssam */ 56185377Ssamstruct ath_hal* 57185377Ssamath_hal_attach(uint16_t devid, HAL_SOFTC sc, 58272292Sadrian HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, 59272292Sadrian HAL_OPS_CONFIG *ah_config, 60272292Sadrian HAL_STATUS *error) 61185377Ssam{ 62186018Ssam struct ath_hal_chip * const *pchip; 63185377Ssam 64185417Ssam OS_SET_FOREACH(pchip, ah_chips) { 65185406Ssam struct ath_hal_chip *chip = *pchip; 66185406Ssam struct ath_hal *ah; 67185406Ssam 68185406Ssam /* XXX don't have vendorid, assume atheros one works */ 69185406Ssam if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 70185406Ssam continue; 71272292Sadrian ah = chip->attach(devid, sc, st, sh, eepromdata, ah_config, 72272292Sadrian error); 73185406Ssam if (ah != AH_NULL) { 74185406Ssam /* copy back private state to public area */ 75185406Ssam ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 76185406Ssam ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 77185406Ssam ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 78185406Ssam ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 79185406Ssam ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 80185406Ssam ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 81185406Ssam ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 82185406Ssam return ah; 83185406Ssam } 84185377Ssam } 85185406Ssam return AH_NULL; 86185406Ssam} 87185406Ssam 88188968Ssamconst char * 89188968Ssamath_hal_mac_name(struct ath_hal *ah) 90188968Ssam{ 91188968Ssam switch (ah->ah_macVersion) { 92188968Ssam case AR_SREV_VERSION_CRETE: 93188968Ssam case AR_SREV_VERSION_MAUI_1: 94296176Sadrian return "AR5210"; 95188968Ssam case AR_SREV_VERSION_MAUI_2: 96188968Ssam case AR_SREV_VERSION_OAHU: 97296176Sadrian return "AR5211"; 98188968Ssam case AR_SREV_VERSION_VENICE: 99296176Sadrian return "AR5212"; 100188968Ssam case AR_SREV_VERSION_GRIFFIN: 101296176Sadrian return "AR2413"; 102188968Ssam case AR_SREV_VERSION_CONDOR: 103296176Sadrian return "AR5424"; 104188968Ssam case AR_SREV_VERSION_EAGLE: 105296176Sadrian return "AR5413"; 106188968Ssam case AR_SREV_VERSION_COBRA: 107296176Sadrian return "AR2415"; 108239603Sadrian case AR_SREV_2425: /* Swan */ 109296176Sadrian return "AR2425"; 110239603Sadrian case AR_SREV_2417: /* Nala */ 111296176Sadrian return "AR2417"; 112188968Ssam case AR_XSREV_VERSION_OWL_PCI: 113296176Sadrian return "AR5416"; 114188968Ssam case AR_XSREV_VERSION_OWL_PCIE: 115296176Sadrian return "AR5418"; 116221163Sadrian case AR_XSREV_VERSION_HOWL: 117296176Sadrian return "AR9130"; 118188968Ssam case AR_XSREV_VERSION_SOWL: 119296176Sadrian return "AR9160"; 120188968Ssam case AR_XSREV_VERSION_MERLIN: 121227372Sadrian if (AH_PRIVATE(ah)->ah_ispcie) 122296176Sadrian return "AR9280"; 123296176Sadrian return "AR9220"; 124188968Ssam case AR_XSREV_VERSION_KITE: 125296176Sadrian return "AR9285"; 126222305Sadrian case AR_XSREV_VERSION_KIWI: 127227372Sadrian if (AH_PRIVATE(ah)->ah_ispcie) 128296176Sadrian return "AR9287"; 129296176Sadrian return "AR9227"; 130239604Sadrian case AR_SREV_VERSION_AR9380: 131239604Sadrian if (ah->ah_macRev >= AR_SREV_REVISION_AR9580_10) 132296176Sadrian return "AR9580"; 133296176Sadrian return "AR9380"; 134239604Sadrian case AR_SREV_VERSION_AR9460: 135296176Sadrian return "AR9460"; 136239604Sadrian case AR_SREV_VERSION_AR9330: 137296176Sadrian return "AR9330"; 138239604Sadrian case AR_SREV_VERSION_AR9340: 139296176Sadrian return "AR9340"; 140239604Sadrian case AR_SREV_VERSION_QCA9550: 141296176Sadrian return "QCA9550"; 142239604Sadrian case AR_SREV_VERSION_AR9485: 143296176Sadrian return "AR9485"; 144250166Sadrian case AR_SREV_VERSION_QCA9565: 145296176Sadrian return "QCA9565"; 146291418Sadrian case AR_SREV_VERSION_QCA9530: 147296176Sadrian return "QCA9530"; 148188968Ssam } 149188968Ssam return "????"; 150188968Ssam} 151188968Ssam 152187831Ssam/* 153187831Ssam * Return the mask of available modes based on the hardware capabilities. 154187831Ssam */ 155187831Ssamu_int 156187831Ssamath_hal_getwirelessmodes(struct ath_hal*ah) 157187831Ssam{ 158187831Ssam return ath_hal_getWirelessModes(ah); 159187831Ssam} 160187831Ssam 161185406Ssam/* linker set of registered RF backends */ 162185406SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 163185406Ssam 164185406Ssam/* 165185406Ssam * Check the set of registered RF backends to see if 166185406Ssam * any recognize the device as one they can support. 167185406Ssam */ 168185406Ssamstruct ath_hal_rf * 169185406Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 170185406Ssam{ 171186018Ssam struct ath_hal_rf * const *prf; 172185406Ssam 173185417Ssam OS_SET_FOREACH(prf, ah_rfs) { 174185406Ssam struct ath_hal_rf *rf = *prf; 175185406Ssam if (rf->probe(ah)) 176185406Ssam return rf; 177185377Ssam } 178185406Ssam *ecode = HAL_ENOTSUPP; 179185406Ssam return AH_NULL; 180185377Ssam} 181185377Ssam 182188968Ssamconst char * 183188968Ssamath_hal_rf_name(struct ath_hal *ah) 184188968Ssam{ 185188968Ssam switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { 186188968Ssam case 0: /* 5210 */ 187188968Ssam return "5110"; /* NB: made up */ 188188968Ssam case AR_RAD5111_SREV_MAJOR: 189188968Ssam case AR_RAD5111_SREV_PROD: 190188968Ssam return "5111"; 191188968Ssam case AR_RAD2111_SREV_MAJOR: 192188968Ssam return "2111"; 193188968Ssam case AR_RAD5112_SREV_MAJOR: 194188968Ssam case AR_RAD5112_SREV_2_0: 195188968Ssam case AR_RAD5112_SREV_2_1: 196188968Ssam return "5112"; 197188968Ssam case AR_RAD2112_SREV_MAJOR: 198188968Ssam case AR_RAD2112_SREV_2_0: 199188968Ssam case AR_RAD2112_SREV_2_1: 200188968Ssam return "2112"; 201188968Ssam case AR_RAD2413_SREV_MAJOR: 202188968Ssam return "2413"; 203188968Ssam case AR_RAD5413_SREV_MAJOR: 204188968Ssam return "5413"; 205188968Ssam case AR_RAD2316_SREV_MAJOR: 206188968Ssam return "2316"; 207188968Ssam case AR_RAD2317_SREV_MAJOR: 208188968Ssam return "2317"; 209188968Ssam case AR_RAD5424_SREV_MAJOR: 210188968Ssam return "5424"; 211188968Ssam 212188968Ssam case AR_RAD5133_SREV_MAJOR: 213188968Ssam return "5133"; 214188968Ssam case AR_RAD2133_SREV_MAJOR: 215188968Ssam return "2133"; 216188968Ssam case AR_RAD5122_SREV_MAJOR: 217188968Ssam return "5122"; 218188968Ssam case AR_RAD2122_SREV_MAJOR: 219188968Ssam return "2122"; 220188968Ssam } 221188968Ssam return "????"; 222188968Ssam} 223188968Ssam 224185377Ssam/* 225185377Ssam * Poll the register looking for a specific value. 226185377Ssam */ 227185377SsamHAL_BOOL 228185377Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 229185377Ssam{ 230185377Ssam#define AH_TIMEOUT 1000 231217622Sadrian return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT); 232217622Sadrian#undef AH_TIMEOUT 233217622Sadrian} 234217622Sadrian 235217622SadrianHAL_BOOL 236217622Sadrianath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout) 237217622Sadrian{ 238185377Ssam int i; 239185377Ssam 240217622Sadrian for (i = 0; i < timeout; i++) { 241185377Ssam if ((OS_REG_READ(ah, reg) & mask) == val) 242185377Ssam return AH_TRUE; 243185377Ssam OS_DELAY(10); 244185377Ssam } 245185377Ssam HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 246185377Ssam "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 247185377Ssam __func__, reg, OS_REG_READ(ah, reg), mask, val); 248185377Ssam return AH_FALSE; 249185377Ssam} 250185377Ssam 251185377Ssam/* 252185377Ssam * Reverse the bits starting at the low bit for a value of 253185377Ssam * bit_count in size 254185377Ssam */ 255185377Ssamuint32_t 256185377Ssamath_hal_reverseBits(uint32_t val, uint32_t n) 257185377Ssam{ 258185377Ssam uint32_t retval; 259185377Ssam int i; 260185377Ssam 261185377Ssam for (i = 0, retval = 0; i < n; i++) { 262185377Ssam retval = (retval << 1) | (val & 1); 263185377Ssam val >>= 1; 264185377Ssam } 265185377Ssam return retval; 266185377Ssam} 267185377Ssam 268218011Sadrian/* 802.11n related timing definitions */ 269218011Sadrian 270218011Sadrian#define OFDM_PLCP_BITS 22 271218011Sadrian#define HT_L_STF 8 272218011Sadrian#define HT_L_LTF 8 273218011Sadrian#define HT_L_SIG 4 274218011Sadrian#define HT_SIG 8 275218011Sadrian#define HT_STF 4 276218011Sadrian#define HT_LTF(n) ((n) * 4) 277218011Sadrian 278218011Sadrian#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 279218011Sadrian#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 280218011Sadrian#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 281218011Sadrian 282185377Ssam/* 283218011Sadrian * Calculate the duration of a packet whether it is 11n or legacy. 284218011Sadrian */ 285218011Sadrianuint32_t 286218011Sadrianath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen, 287218011Sadrian uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble) 288218011Sadrian{ 289218011Sadrian uint8_t rc; 290218011Sadrian int numStreams; 291218011Sadrian 292218011Sadrian rc = rates->info[rateix].rateCode; 293218011Sadrian 294218011Sadrian /* Legacy rate? Return the old way */ 295218011Sadrian if (! IS_HT_RATE(rc)) 296218011Sadrian return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble); 297218011Sadrian 298218011Sadrian /* 11n frame - extract out the number of spatial streams */ 299218011Sadrian numStreams = HT_RC_2_STREAMS(rc); 300239287Sadrian KASSERT(numStreams > 0 && numStreams <= 4, 301239287Sadrian ("number of spatial streams needs to be 1..3: MCS rate 0x%x!", 302239287Sadrian rateix)); 303218011Sadrian 304218011Sadrian return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble); 305218011Sadrian} 306218011Sadrian 307239287Sadrianstatic const uint16_t ht20_bps[32] = { 308239287Sadrian 26, 52, 78, 104, 156, 208, 234, 260, 309239287Sadrian 52, 104, 156, 208, 312, 416, 468, 520, 310239287Sadrian 78, 156, 234, 312, 468, 624, 702, 780, 311239287Sadrian 104, 208, 312, 416, 624, 832, 936, 1040 312239287Sadrian}; 313239287Sadrianstatic const uint16_t ht40_bps[32] = { 314239287Sadrian 54, 108, 162, 216, 324, 432, 486, 540, 315239287Sadrian 108, 216, 324, 432, 648, 864, 972, 1080, 316239287Sadrian 162, 324, 486, 648, 972, 1296, 1458, 1620, 317239287Sadrian 216, 432, 648, 864, 1296, 1728, 1944, 2160 318239287Sadrian}; 319239287Sadrian 320218011Sadrian/* 321218011Sadrian * Calculate the transmit duration of an 11n frame. 322218011Sadrian */ 323218011Sadrianuint32_t 324239287Sadrianath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, 325239287Sadrian HAL_BOOL isht40, HAL_BOOL isShortGI) 326218011Sadrian{ 327218011Sadrian uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 328218011Sadrian 329218011Sadrian KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 330239287Sadrian KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate)); 331218011Sadrian 332218011Sadrian if (isht40) 333250824Sadrian bitsPerSymbol = ht40_bps[rate & 0x1f]; 334218011Sadrian else 335250824Sadrian bitsPerSymbol = ht20_bps[rate & 0x1f]; 336218011Sadrian numBits = OFDM_PLCP_BITS + (frameLen << 3); 337218011Sadrian numSymbols = howmany(numBits, bitsPerSymbol); 338218011Sadrian if (isShortGI) 339218011Sadrian txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 340218011Sadrian else 341218011Sadrian txTime = numSymbols * 4; /* 4us */ 342218011Sadrian return txTime + HT_L_STF + HT_L_LTF + 343218011Sadrian HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 344218011Sadrian} 345218011Sadrian 346218011Sadrian/* 347185377Ssam * Compute the time to transmit a frame of length frameLen bytes 348185377Ssam * using the specified rate, phy, and short preamble setting. 349185377Ssam */ 350185377Ssamuint16_t 351185377Ssamath_hal_computetxtime(struct ath_hal *ah, 352185377Ssam const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 353185377Ssam HAL_BOOL shortPreamble) 354185377Ssam{ 355185377Ssam uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 356185377Ssam uint32_t kbps; 357185377Ssam 358218923Sadrian /* Warn if this function is called for 11n rates; it should not be! */ 359218923Sadrian if (IS_HT_RATE(rates->info[rateix].rateCode)) 360218923Sadrian ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n", 361218923Sadrian __func__, rateix, rates->info[rateix].rateCode); 362218923Sadrian 363185377Ssam kbps = rates->info[rateix].rateKbps; 364185377Ssam /* 365298939Spfg * index can be invalid during dynamic Turbo transitions. 366187831Ssam * XXX 367185377Ssam */ 368187831Ssam if (kbps == 0) 369187831Ssam return 0; 370185377Ssam switch (rates->info[rateix].phy) { 371185377Ssam case IEEE80211_T_CCK: 372185377Ssam phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 373185377Ssam if (shortPreamble && rates->info[rateix].shortPreamble) 374185377Ssam phyTime >>= 1; 375185377Ssam numBits = frameLen << 3; 376185377Ssam txTime = CCK_SIFS_TIME + phyTime 377185377Ssam + ((numBits * 1000)/kbps); 378185377Ssam break; 379185377Ssam case IEEE80211_T_OFDM: 380188773Ssam bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 381188773Ssam HALASSERT(bitsPerSymbol != 0); 382185377Ssam 383188773Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 384188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 385188773Ssam txTime = OFDM_SIFS_TIME 386188773Ssam + OFDM_PREAMBLE_TIME 387188773Ssam + (numSymbols * OFDM_SYMBOL_TIME); 388188773Ssam break; 389188773Ssam case IEEE80211_T_OFDM_HALF: 390188773Ssam bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 391188773Ssam HALASSERT(bitsPerSymbol != 0); 392185377Ssam 393188773Ssam numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 394188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 395188773Ssam txTime = OFDM_HALF_SIFS_TIME 396188773Ssam + OFDM_HALF_PREAMBLE_TIME 397188773Ssam + (numSymbols * OFDM_HALF_SYMBOL_TIME); 398188773Ssam break; 399188773Ssam case IEEE80211_T_OFDM_QUARTER: 400188773Ssam bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 401188773Ssam HALASSERT(bitsPerSymbol != 0); 402185377Ssam 403188773Ssam numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 404188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 405188773Ssam txTime = OFDM_QUARTER_SIFS_TIME 406188773Ssam + OFDM_QUARTER_PREAMBLE_TIME 407188773Ssam + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 408185377Ssam break; 409185377Ssam case IEEE80211_T_TURBO: 410191022Ssam bitsPerSymbol = (kbps * TURBO_SYMBOL_TIME) / 1000; 411185377Ssam HALASSERT(bitsPerSymbol != 0); 412185377Ssam 413188773Ssam numBits = TURBO_PLCP_BITS + (frameLen << 3); 414188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 415188773Ssam txTime = TURBO_SIFS_TIME 416188773Ssam + TURBO_PREAMBLE_TIME 417188773Ssam + (numSymbols * TURBO_SYMBOL_TIME); 418185377Ssam break; 419185377Ssam default: 420185377Ssam HALDEBUG(ah, HAL_DEBUG_PHYIO, 421185377Ssam "%s: unknown phy %u (rate ix %u)\n", 422185377Ssam __func__, rates->info[rateix].phy, rateix); 423185377Ssam txTime = 0; 424185377Ssam break; 425185377Ssam } 426185377Ssam return txTime; 427185377Ssam} 428185377Ssam 429239634Sadrianint 430239634Sadrianath_hal_get_curmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 431239634Sadrian{ 432239634Sadrian /* 433239634Sadrian * Pick a default mode at bootup. A channel change is inevitable. 434239634Sadrian */ 435239634Sadrian if (!chan) 436239634Sadrian return HAL_MODE_11NG_HT20; 437239634Sadrian 438239634Sadrian if (IEEE80211_IS_CHAN_TURBO(chan)) 439239634Sadrian return HAL_MODE_TURBO; 440239634Sadrian 441239634Sadrian /* check for NA_HT before plain A, since IS_CHAN_A includes NA_HT */ 442239634Sadrian if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan)) 443239634Sadrian return HAL_MODE_11NA_HT20; 444239634Sadrian if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan)) 445239634Sadrian return HAL_MODE_11NA_HT40PLUS; 446239634Sadrian if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan)) 447239634Sadrian return HAL_MODE_11NA_HT40MINUS; 448239634Sadrian if (IEEE80211_IS_CHAN_A(chan)) 449239634Sadrian return HAL_MODE_11A; 450239634Sadrian 451239634Sadrian /* check for NG_HT before plain G, since IS_CHAN_G includes NG_HT */ 452239634Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan)) 453239634Sadrian return HAL_MODE_11NG_HT20; 454239634Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan)) 455239634Sadrian return HAL_MODE_11NG_HT40PLUS; 456239634Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan)) 457239634Sadrian return HAL_MODE_11NG_HT40MINUS; 458239634Sadrian 459239634Sadrian /* 460239634Sadrian * XXX For FreeBSD, will this work correctly given the DYN 461239634Sadrian * chan mode (OFDM+CCK dynamic) ? We have pure-G versions DYN-BG.. 462239634Sadrian */ 463239634Sadrian if (IEEE80211_IS_CHAN_G(chan)) 464239634Sadrian return HAL_MODE_11G; 465239634Sadrian if (IEEE80211_IS_CHAN_B(chan)) 466239634Sadrian return HAL_MODE_11B; 467239634Sadrian 468239634Sadrian HALASSERT(0); 469239634Sadrian return HAL_MODE_11NG_HT20; 470239634Sadrian} 471239634Sadrian 472239634Sadrian 473185377Ssamtypedef enum { 474185377Ssam WIRELESS_MODE_11a = 0, 475185377Ssam WIRELESS_MODE_TURBO = 1, 476185377Ssam WIRELESS_MODE_11b = 2, 477185377Ssam WIRELESS_MODE_11g = 3, 478185377Ssam WIRELESS_MODE_108g = 4, 479185377Ssam 480185377Ssam WIRELESS_MODE_MAX 481185377Ssam} WIRELESS_MODE; 482185377Ssam 483185377Ssamstatic WIRELESS_MODE 484187831Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 485185377Ssam{ 486187831Ssam if (IEEE80211_IS_CHAN_B(chan)) 487185377Ssam return WIRELESS_MODE_11b; 488187831Ssam if (IEEE80211_IS_CHAN_G(chan)) 489185377Ssam return WIRELESS_MODE_11g; 490187831Ssam if (IEEE80211_IS_CHAN_108G(chan)) 491185377Ssam return WIRELESS_MODE_108g; 492187831Ssam if (IEEE80211_IS_CHAN_TURBO(chan)) 493185377Ssam return WIRELESS_MODE_TURBO; 494185377Ssam return WIRELESS_MODE_11a; 495185377Ssam} 496185377Ssam 497185377Ssam/* 498185377Ssam * Convert between microseconds and core system clocks. 499185377Ssam */ 500185377Ssam /* 11a Turbo 11b 11g 108g */ 501185377Ssamstatic const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 502185377Ssam 503220298Sadrian#define CLOCK_FAST_RATE_5GHZ_OFDM 44 504220298Sadrian 505185377Ssamu_int 506185377Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 507185377Ssam{ 508187831Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 509185377Ssam u_int clks; 510185377Ssam 511185377Ssam /* NB: ah_curchan may be null when called attach time */ 512220298Sadrian /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 513220298Sadrian if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 514220298Sadrian clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM; 515220298Sadrian if (IEEE80211_IS_CHAN_HT40(c)) 516220298Sadrian clks <<= 1; 517220298Sadrian } else if (c != AH_NULL) { 518185377Ssam clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 519187831Ssam if (IEEE80211_IS_CHAN_HT40(c)) 520185377Ssam clks <<= 1; 521185377Ssam } else 522185377Ssam clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 523240444Sadrian 524240444Sadrian /* Compensate for half/quarter rate */ 525240444Sadrian if (c != AH_NULL && IEEE80211_IS_CHAN_HALF(c)) 526240444Sadrian clks = clks / 2; 527240444Sadrian else if (c != AH_NULL && IEEE80211_IS_CHAN_QUARTER(c)) 528240444Sadrian clks = clks / 4; 529240444Sadrian 530185377Ssam return clks; 531185377Ssam} 532185377Ssam 533185377Ssamu_int 534185377Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks) 535185377Ssam{ 536187831Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 537185377Ssam u_int usec; 538185377Ssam 539185377Ssam /* NB: ah_curchan may be null when called attach time */ 540220298Sadrian /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 541220298Sadrian if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 542220298Sadrian usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM; 543220298Sadrian if (IEEE80211_IS_CHAN_HT40(c)) 544220298Sadrian usec >>= 1; 545220298Sadrian } else if (c != AH_NULL) { 546185377Ssam usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 547187831Ssam if (IEEE80211_IS_CHAN_HT40(c)) 548185377Ssam usec >>= 1; 549185377Ssam } else 550185377Ssam usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 551185377Ssam return usec; 552185377Ssam} 553185377Ssam 554185377Ssam/* 555185377Ssam * Setup a h/w rate table's reverse lookup table and 556185377Ssam * fill in ack durations. This routine is called for 557185377Ssam * each rate table returned through the ah_getRateTable 558185377Ssam * method. The reverse lookup tables are assumed to be 559185377Ssam * initialized to zero (or at least the first entry). 560185377Ssam * We use this as a key that indicates whether or not 561185377Ssam * we've previously setup the reverse lookup table. 562185377Ssam * 563185377Ssam * XXX not reentrant, but shouldn't matter 564185377Ssam */ 565185377Ssamvoid 566185377Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 567185377Ssam{ 568185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 569185377Ssam int i; 570185377Ssam 571185377Ssam if (rt->rateCodeToIndex[0] != 0) /* already setup */ 572185377Ssam return; 573185377Ssam for (i = 0; i < N(rt->rateCodeToIndex); i++) 574185377Ssam rt->rateCodeToIndex[i] = (uint8_t) -1; 575185377Ssam for (i = 0; i < rt->rateCount; i++) { 576185377Ssam uint8_t code = rt->info[i].rateCode; 577185377Ssam uint8_t cix = rt->info[i].controlRate; 578185377Ssam 579185377Ssam HALASSERT(code < N(rt->rateCodeToIndex)); 580185377Ssam rt->rateCodeToIndex[code] = i; 581185377Ssam HALASSERT((code | rt->info[i].shortPreamble) < 582185377Ssam N(rt->rateCodeToIndex)); 583185377Ssam rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 584185377Ssam /* 585185377Ssam * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 586185377Ssam * depends on whether they are marked as basic rates; 587185377Ssam * the static tables are setup with an 11b-compatible 588185377Ssam * 2Mb/s rate which will work but is suboptimal 589185377Ssam */ 590185377Ssam rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 591185377Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 592185377Ssam rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 593185377Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 594185377Ssam } 595185377Ssam#undef N 596185377Ssam} 597185377Ssam 598185377SsamHAL_STATUS 599185377Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 600185377Ssam uint32_t capability, uint32_t *result) 601185377Ssam{ 602185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 603185377Ssam 604185377Ssam switch (type) { 605185377Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 606185377Ssam *result = AH_PRIVATE(ah)->ah_currentRD; 607185377Ssam return HAL_OK; 608224716Sadrian case HAL_CAP_DFS_DMN: /* DFS Domain */ 609224716Sadrian *result = AH_PRIVATE(ah)->ah_dfsDomain; 610224716Sadrian return HAL_OK; 611185377Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 612185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 613185377Ssam return HAL_ENOTSUPP; 614185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 615185377Ssam return HAL_ENOTSUPP; 616185377Ssam case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 617185377Ssam return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 618185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 619185377Ssam return HAL_ENOTSUPP; 620185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 621185377Ssam return HAL_ENOTSUPP; 622185377Ssam case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 623185377Ssam *result = pCap->halKeyCacheSize; 624185377Ssam return HAL_OK; 625185377Ssam case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 626185377Ssam *result = pCap->halTotalQueues; 627185377Ssam return HAL_OK; 628185377Ssam case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 629185377Ssam return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 630185377Ssam case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 631185377Ssam return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 632185377Ssam case HAL_CAP_COMPRESSION: 633185377Ssam return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 634185377Ssam case HAL_CAP_BURST: 635185377Ssam return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 636185377Ssam case HAL_CAP_FASTFRAME: 637185377Ssam return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 638185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 639185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 640185377Ssam return HAL_OK; 641185377Ssam case HAL_CAP_TXPOW: /* global tx power limit */ 642185377Ssam switch (capability) { 643185377Ssam case 0: /* facility is supported */ 644185377Ssam return HAL_OK; 645185377Ssam case 1: /* current limit */ 646185377Ssam *result = AH_PRIVATE(ah)->ah_powerLimit; 647185377Ssam return HAL_OK; 648185377Ssam case 2: /* current max tx power */ 649185377Ssam *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 650185377Ssam return HAL_OK; 651185377Ssam case 3: /* scale factor */ 652185377Ssam *result = AH_PRIVATE(ah)->ah_tpScale; 653185377Ssam return HAL_OK; 654185377Ssam } 655185377Ssam return HAL_ENOTSUPP; 656185377Ssam case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 657185377Ssam return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 658185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 659185377Ssam return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 660185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 661185377Ssam return HAL_ENOTSUPP; 662185377Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 663185377Ssam switch (capability) { 664185377Ssam case 0: /* facility is supported */ 665185377Ssam return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 666185377Ssam case 1: /* current setting */ 667185377Ssam return AH_PRIVATE(ah)->ah_rfkillEnabled ? 668185377Ssam HAL_OK : HAL_ENOTSUPP; 669185377Ssam case 2: /* rfsilent config */ 670185377Ssam *result = AH_PRIVATE(ah)->ah_rfsilent; 671185377Ssam return HAL_OK; 672185377Ssam } 673185377Ssam return HAL_ENOTSUPP; 674185377Ssam case HAL_CAP_11D: 675185377Ssam return HAL_OK; 676221603Sadrian 677185377Ssam case HAL_CAP_HT: 678185377Ssam return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 679221603Sadrian case HAL_CAP_GTXTO: 680221603Sadrian return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP; 681221603Sadrian case HAL_CAP_FAST_CC: 682221603Sadrian return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP; 683185377Ssam case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 684185377Ssam *result = pCap->halTxChainMask; 685185377Ssam return HAL_OK; 686185377Ssam case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 687185377Ssam *result = pCap->halRxChainMask; 688185377Ssam return HAL_OK; 689221603Sadrian case HAL_CAP_NUM_GPIO_PINS: 690221603Sadrian *result = pCap->halNumGpioPins; 691221603Sadrian return HAL_OK; 692221603Sadrian case HAL_CAP_CST: 693221603Sadrian return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP; 694221603Sadrian case HAL_CAP_RTS_AGGR_LIMIT: 695221603Sadrian *result = pCap->halRtsAggrLimit; 696221603Sadrian return HAL_OK; 697221603Sadrian case HAL_CAP_4ADDR_AGGR: 698221603Sadrian return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP; 699222584Sadrian case HAL_CAP_EXT_CHAN_DFS: 700222584Sadrian return pCap->halExtChanDfsSupport ? HAL_OK : HAL_ENOTSUPP; 701247366Sadrian case HAL_CAP_RX_STBC: 702247366Sadrian return pCap->halRxStbcSupport ? HAL_OK : HAL_ENOTSUPP; 703247366Sadrian case HAL_CAP_TX_STBC: 704247366Sadrian return pCap->halTxStbcSupport ? HAL_OK : HAL_ENOTSUPP; 705238333Sadrian case HAL_CAP_COMBINED_RADAR_RSSI: 706238333Sadrian return pCap->halUseCombinedRadarRssi ? HAL_OK : HAL_ENOTSUPP; 707238333Sadrian case HAL_CAP_AUTO_SLEEP: 708238333Sadrian return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP; 709238333Sadrian case HAL_CAP_MBSSID_AGGR_SUPPORT: 710238333Sadrian return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP; 711238333Sadrian case HAL_CAP_SPLIT_4KB_TRANS: /* hardware handles descriptors straddling 4k page boundary */ 712238333Sadrian return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP; 713238333Sadrian case HAL_CAP_REG_FLAG: 714238333Sadrian *result = AH_PRIVATE(ah)->ah_currentRDext; 715238333Sadrian return HAL_OK; 716238333Sadrian case HAL_CAP_ENHANCED_DMA_SUPPORT: 717238333Sadrian return pCap->halEnhancedDmaSupport ? HAL_OK : HAL_ENOTSUPP; 718238280Sadrian case HAL_CAP_NUM_TXMAPS: 719238280Sadrian *result = pCap->halNumTxMaps; 720238280Sadrian return HAL_OK; 721238280Sadrian case HAL_CAP_TXDESCLEN: 722238280Sadrian *result = pCap->halTxDescLen; 723238280Sadrian return HAL_OK; 724238280Sadrian case HAL_CAP_TXSTATUSLEN: 725238280Sadrian *result = pCap->halTxStatusLen; 726238280Sadrian return HAL_OK; 727238280Sadrian case HAL_CAP_RXSTATUSLEN: 728238280Sadrian *result = pCap->halRxStatusLen; 729238280Sadrian return HAL_OK; 730238280Sadrian case HAL_CAP_RXFIFODEPTH: 731238280Sadrian switch (capability) { 732238280Sadrian case HAL_RX_QUEUE_HP: 733238280Sadrian *result = pCap->halRxHpFifoDepth; 734238280Sadrian return HAL_OK; 735238280Sadrian case HAL_RX_QUEUE_LP: 736238280Sadrian *result = pCap->halRxLpFifoDepth; 737238280Sadrian return HAL_OK; 738238280Sadrian default: 739238280Sadrian return HAL_ENOTSUPP; 740238280Sadrian } 741238280Sadrian case HAL_CAP_RXBUFSIZE: 742238280Sadrian case HAL_CAP_NUM_MR_RETRIES: 743238858Sadrian *result = pCap->halNumMRRetries; 744238858Sadrian return HAL_OK; 745221603Sadrian case HAL_CAP_BT_COEX: 746221603Sadrian return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP; 747244854Sadrian case HAL_CAP_SPECTRAL_SCAN: 748244854Sadrian return pCap->halSpectralScanSupport ? HAL_OK : HAL_ENOTSUPP; 749221603Sadrian case HAL_CAP_HT20_SGI: 750221603Sadrian return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP; 751185377Ssam case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 752185377Ssam *result = pCap->halTstampPrecision; 753185377Ssam return HAL_OK; 754251360Sadrian case HAL_CAP_ANT_DIV_COMB: /* AR9285/AR9485 LNA diversity */ 755251360Sadrian return pCap->halAntDivCombSupport ? HAL_OK : HAL_ENOTSUPP; 756251360Sadrian 757222584Sadrian case HAL_CAP_ENHANCED_DFS_SUPPORT: 758222584Sadrian return pCap->halEnhancedDfsSupport ? HAL_OK : HAL_ENOTSUPP; 759221603Sadrian 760221603Sadrian /* FreeBSD-specific entries for now */ 761221603Sadrian case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 762221603Sadrian return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 763192396Ssam case HAL_CAP_INTRMASK: /* mask of supported interrupts */ 764192396Ssam *result = pCap->halIntrMask; 765192396Ssam return HAL_OK; 766195114Ssam case HAL_CAP_BSSIDMATCH: /* hardware has disable bssid match */ 767195114Ssam return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP; 768218150Sadrian case HAL_CAP_STREAMS: /* number of 11n spatial streams */ 769218150Sadrian switch (capability) { 770218150Sadrian case 0: /* TX */ 771218150Sadrian *result = pCap->halTxStreams; 772218150Sadrian return HAL_OK; 773218150Sadrian case 1: /* RX */ 774218150Sadrian *result = pCap->halRxStreams; 775218150Sadrian return HAL_OK; 776218150Sadrian default: 777218150Sadrian return HAL_ENOTSUPP; 778218150Sadrian } 779220324Sadrian case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ 780220324Sadrian return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; 781225444Sadrian case HAL_CAP_LONG_RXDESC_TSF: /* 32 bit TSF in RX descriptor? */ 782225444Sadrian return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP; 783226488Sadrian case HAL_CAP_BB_READ_WAR: /* Baseband read WAR */ 784226488Sadrian return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP; 785227410Sadrian case HAL_CAP_SERIALISE_WAR: /* PCI register serialisation */ 786227410Sadrian return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP; 787239630Sadrian case HAL_CAP_MFP: /* Management frame protection setting */ 788239630Sadrian *result = pCap->halMfpSupport; 789239630Sadrian return HAL_OK; 790251400Sadrian case HAL_CAP_RX_LNA_MIXING: /* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */ 791251400Sadrian return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP; 792265032Sadrian case HAL_CAP_DO_MYBEACON: /* Hardware supports filtering my-beacons */ 793265032Sadrian return pCap->halRxDoMyBeacon ? HAL_OK : HAL_ENOTSUPP; 794185377Ssam default: 795185377Ssam return HAL_EINVAL; 796185377Ssam } 797185377Ssam} 798185377Ssam 799185377SsamHAL_BOOL 800185377Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 801185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 802185377Ssam{ 803185377Ssam 804185377Ssam switch (type) { 805185377Ssam case HAL_CAP_TXPOW: 806185377Ssam switch (capability) { 807185377Ssam case 3: 808185377Ssam if (setting <= HAL_TP_SCALE_MIN) { 809185377Ssam AH_PRIVATE(ah)->ah_tpScale = setting; 810185377Ssam return AH_TRUE; 811185377Ssam } 812185377Ssam break; 813185377Ssam } 814185377Ssam break; 815185377Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 816185377Ssam /* 817185377Ssam * NB: allow even if halRfSilentSupport is false 818185377Ssam * in case the EEPROM is misprogrammed. 819185377Ssam */ 820185377Ssam switch (capability) { 821185377Ssam case 1: /* current setting */ 822185377Ssam AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 823185377Ssam return AH_TRUE; 824185377Ssam case 2: /* rfsilent config */ 825185377Ssam /* XXX better done per-chip for validation? */ 826185377Ssam AH_PRIVATE(ah)->ah_rfsilent = setting; 827185377Ssam return AH_TRUE; 828185377Ssam } 829185377Ssam break; 830185377Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 831185377Ssam AH_PRIVATE(ah)->ah_currentRD = setting; 832185377Ssam return AH_TRUE; 833185377Ssam case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 834185377Ssam AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 835185377Ssam return AH_TRUE; 836185377Ssam default: 837185377Ssam break; 838185377Ssam } 839185377Ssam if (status) 840185377Ssam *status = HAL_EINVAL; 841185377Ssam return AH_FALSE; 842185377Ssam} 843185377Ssam 844185377Ssam/* 845185377Ssam * Common support for getDiagState method. 846185377Ssam */ 847185377Ssam 848185377Ssamstatic u_int 849185377Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 850185377Ssam void *dstbuf, int space) 851185377Ssam{ 852185377Ssam uint32_t *dp = dstbuf; 853185377Ssam int i; 854185377Ssam 855185377Ssam for (i = 0; space >= 2*sizeof(uint32_t); i++) { 856269760Sadrian uint32_t r = regs[i].start; 857269760Sadrian uint32_t e = regs[i].end; 858269760Sadrian *dp++ = r; 859269760Sadrian *dp++ = e; 860269760Sadrian space -= 2*sizeof(uint32_t); 861185377Ssam do { 862185377Ssam *dp++ = OS_REG_READ(ah, r); 863185377Ssam r += sizeof(uint32_t); 864185377Ssam space -= sizeof(uint32_t); 865185377Ssam } while (r <= e && space >= sizeof(uint32_t)); 866185377Ssam } 867185377Ssam return (char *) dp - (char *) dstbuf; 868185377Ssam} 869188771Ssam 870188771Ssamstatic void 871188771Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 872188771Ssam{ 873188771Ssam while (space >= sizeof(HAL_REGWRITE)) { 874188771Ssam OS_REG_WRITE(ah, regs->addr, regs->value); 875188771Ssam regs++, space -= sizeof(HAL_REGWRITE); 876188771Ssam } 877188771Ssam} 878185377Ssam 879185377SsamHAL_BOOL 880185377Ssamath_hal_getdiagstate(struct ath_hal *ah, int request, 881185377Ssam const void *args, uint32_t argsize, 882185377Ssam void **result, uint32_t *resultsize) 883185377Ssam{ 884280828Sadrian 885185377Ssam switch (request) { 886185377Ssam case HAL_DIAG_REVS: 887185377Ssam *result = &AH_PRIVATE(ah)->ah_devid; 888185377Ssam *resultsize = sizeof(HAL_REVS); 889185377Ssam return AH_TRUE; 890185377Ssam case HAL_DIAG_REGS: 891185377Ssam *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 892185377Ssam return AH_TRUE; 893188771Ssam case HAL_DIAG_SETREGS: 894188771Ssam ath_hal_setregs(ah, args, argsize); 895188771Ssam *resultsize = 0; 896188771Ssam return AH_TRUE; 897185377Ssam case HAL_DIAG_FATALERR: 898185377Ssam *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 899185377Ssam *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 900185377Ssam return AH_TRUE; 901185377Ssam case HAL_DIAG_EEREAD: 902185377Ssam if (argsize != sizeof(uint16_t)) 903185377Ssam return AH_FALSE; 904185377Ssam if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 905185377Ssam return AH_FALSE; 906185377Ssam *resultsize = sizeof(uint16_t); 907185377Ssam return AH_TRUE; 908185377Ssam#ifdef AH_PRIVATE_DIAG 909185377Ssam case HAL_DIAG_SETKEY: { 910185377Ssam const HAL_DIAG_KEYVAL *dk; 911185377Ssam 912185377Ssam if (argsize != sizeof(HAL_DIAG_KEYVAL)) 913185377Ssam return AH_FALSE; 914185377Ssam dk = (const HAL_DIAG_KEYVAL *)args; 915185377Ssam return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 916185377Ssam &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 917185377Ssam } 918185377Ssam case HAL_DIAG_RESETKEY: 919185377Ssam if (argsize != sizeof(uint16_t)) 920185377Ssam return AH_FALSE; 921185377Ssam return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 922185380Ssam#ifdef AH_SUPPORT_WRITE_EEPROM 923185380Ssam case HAL_DIAG_EEWRITE: { 924185380Ssam const HAL_DIAG_EEVAL *ee; 925185380Ssam if (argsize != sizeof(HAL_DIAG_EEVAL)) 926185380Ssam return AH_FALSE; 927185380Ssam ee = (const HAL_DIAG_EEVAL *)args; 928185380Ssam return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 929185380Ssam } 930185380Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */ 931185377Ssam#endif /* AH_PRIVATE_DIAG */ 932185377Ssam case HAL_DIAG_11NCOMPAT: 933185377Ssam if (argsize == 0) { 934185377Ssam *resultsize = sizeof(uint32_t); 935185377Ssam *((uint32_t *)(*result)) = 936185377Ssam AH_PRIVATE(ah)->ah_11nCompat; 937185377Ssam } else if (argsize == sizeof(uint32_t)) { 938185377Ssam AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 939185377Ssam } else 940185377Ssam return AH_FALSE; 941185377Ssam return AH_TRUE; 942280828Sadrian case HAL_DIAG_CHANSURVEY: 943280828Sadrian *result = &AH_PRIVATE(ah)->ah_chansurvey; 944280828Sadrian *resultsize = sizeof(HAL_CHANNEL_SURVEY); 945280828Sadrian return AH_TRUE; 946185377Ssam } 947185377Ssam return AH_FALSE; 948185377Ssam} 949185377Ssam 950185377Ssam/* 951185377Ssam * Set the properties of the tx queue with the parameters 952185377Ssam * from qInfo. 953185377Ssam */ 954185377SsamHAL_BOOL 955185377Ssamath_hal_setTxQProps(struct ath_hal *ah, 956185377Ssam HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 957185377Ssam{ 958185377Ssam uint32_t cw; 959185377Ssam 960185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 961185377Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 962185377Ssam "%s: inactive queue\n", __func__); 963185377Ssam return AH_FALSE; 964185377Ssam } 965185377Ssam /* XXX validate parameters */ 966185377Ssam qi->tqi_ver = qInfo->tqi_ver; 967185377Ssam qi->tqi_subtype = qInfo->tqi_subtype; 968185377Ssam qi->tqi_qflags = qInfo->tqi_qflags; 969185377Ssam qi->tqi_priority = qInfo->tqi_priority; 970185377Ssam if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 971185377Ssam qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 972185377Ssam else 973185377Ssam qi->tqi_aifs = INIT_AIFS; 974185377Ssam if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 975185377Ssam cw = AH_MIN(qInfo->tqi_cwmin, 1024); 976185377Ssam /* make sure that the CWmin is of the form (2^n - 1) */ 977185377Ssam qi->tqi_cwmin = 1; 978185377Ssam while (qi->tqi_cwmin < cw) 979185377Ssam qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 980185377Ssam } else 981185377Ssam qi->tqi_cwmin = qInfo->tqi_cwmin; 982185377Ssam if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 983185377Ssam cw = AH_MIN(qInfo->tqi_cwmax, 1024); 984185377Ssam /* make sure that the CWmax is of the form (2^n - 1) */ 985185377Ssam qi->tqi_cwmax = 1; 986185377Ssam while (qi->tqi_cwmax < cw) 987185377Ssam qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 988185377Ssam } else 989185377Ssam qi->tqi_cwmax = INIT_CWMAX; 990185377Ssam /* Set retry limit values */ 991185377Ssam if (qInfo->tqi_shretry != 0) 992185377Ssam qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 993185377Ssam else 994185377Ssam qi->tqi_shretry = INIT_SH_RETRY; 995185377Ssam if (qInfo->tqi_lgretry != 0) 996185377Ssam qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 997185377Ssam else 998185377Ssam qi->tqi_lgretry = INIT_LG_RETRY; 999185377Ssam qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 1000185377Ssam qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 1001185377Ssam qi->tqi_burstTime = qInfo->tqi_burstTime; 1002185377Ssam qi->tqi_readyTime = qInfo->tqi_readyTime; 1003185377Ssam 1004185377Ssam switch (qInfo->tqi_subtype) { 1005185377Ssam case HAL_WME_UPSD: 1006185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_DATA) 1007185377Ssam qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 1008185377Ssam break; 1009185377Ssam default: 1010185377Ssam break; /* NB: silence compiler */ 1011185377Ssam } 1012185377Ssam return AH_TRUE; 1013185377Ssam} 1014185377Ssam 1015185377SsamHAL_BOOL 1016185377Ssamath_hal_getTxQProps(struct ath_hal *ah, 1017185377Ssam HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 1018185377Ssam{ 1019185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 1020185377Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 1021185377Ssam "%s: inactive queue\n", __func__); 1022185377Ssam return AH_FALSE; 1023185377Ssam } 1024185377Ssam 1025185377Ssam qInfo->tqi_qflags = qi->tqi_qflags; 1026185377Ssam qInfo->tqi_ver = qi->tqi_ver; 1027185377Ssam qInfo->tqi_subtype = qi->tqi_subtype; 1028185377Ssam qInfo->tqi_qflags = qi->tqi_qflags; 1029185377Ssam qInfo->tqi_priority = qi->tqi_priority; 1030185377Ssam qInfo->tqi_aifs = qi->tqi_aifs; 1031185377Ssam qInfo->tqi_cwmin = qi->tqi_cwmin; 1032185377Ssam qInfo->tqi_cwmax = qi->tqi_cwmax; 1033185377Ssam qInfo->tqi_shretry = qi->tqi_shretry; 1034185377Ssam qInfo->tqi_lgretry = qi->tqi_lgretry; 1035185377Ssam qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 1036185377Ssam qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 1037185377Ssam qInfo->tqi_burstTime = qi->tqi_burstTime; 1038185377Ssam qInfo->tqi_readyTime = qi->tqi_readyTime; 1039185377Ssam return AH_TRUE; 1040185377Ssam} 1041185377Ssam 1042185377Ssam /* 11a Turbo 11b 11g 108g */ 1043185377Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 1044185377Ssam 1045185377Ssam/* 1046185377Ssam * Read the current channel noise floor and return. 1047185377Ssam * If nf cal hasn't finished, channel noise floor should be 0 1048185377Ssam * and we return a nominal value based on band and frequency. 1049185377Ssam * 1050185377Ssam * NB: This is a private routine used by per-chip code to 1051185377Ssam * implement the ah_getChanNoise method. 1052185377Ssam */ 1053185377Ssamint16_t 1054187831Ssamath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 1055185377Ssam{ 1056185377Ssam HAL_CHANNEL_INTERNAL *ichan; 1057185377Ssam 1058185377Ssam ichan = ath_hal_checkchannel(ah, chan); 1059185377Ssam if (ichan == AH_NULL) { 1060185377Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 1061185377Ssam "%s: invalid channel %u/0x%x; no mapping\n", 1062187831Ssam __func__, chan->ic_freq, chan->ic_flags); 1063185377Ssam return 0; 1064185377Ssam } 1065185377Ssam if (ichan->rawNoiseFloor == 0) { 1066185377Ssam WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 1067185377Ssam 1068185377Ssam HALASSERT(mode < WIRELESS_MODE_MAX); 1069185377Ssam return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 1070185377Ssam } else 1071185377Ssam return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 1072185377Ssam} 1073185377Ssam 1074185377Ssam/* 1075220443Sadrian * Fetch the current setup of ctl/ext noise floor values. 1076220443Sadrian * 1077220443Sadrian * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply 1078220443Sadrian * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust(). 1079220443Sadrian * 1080220443Sadrian * The caller must supply ctl/ext NF arrays which are at least 1081240623Sadrian * AH_MAX_CHAINS entries long. 1082220443Sadrian */ 1083220443Sadrianint 1084220443Sadrianath_hal_get_mimo_chan_noise(struct ath_hal *ah, 1085220444Sadrian const struct ieee80211_channel *chan, int16_t *nf_ctl, 1086220444Sadrian int16_t *nf_ext) 1087220443Sadrian{ 1088221019Sadrian#ifdef AH_SUPPORT_AR5416 1089220443Sadrian HAL_CHANNEL_INTERNAL *ichan; 1090220443Sadrian int i; 1091220443Sadrian 1092220443Sadrian ichan = ath_hal_checkchannel(ah, chan); 1093220443Sadrian if (ichan == AH_NULL) { 1094220443Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 1095220443Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 1096220443Sadrian __func__, chan->ic_freq, chan->ic_flags); 1097240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1098220443Sadrian nf_ctl[i] = nf_ext[i] = 0; 1099220443Sadrian } 1100220443Sadrian return 0; 1101220443Sadrian } 1102220443Sadrian 1103220443Sadrian /* Return 0 if there's no valid MIMO values (yet) */ 1104220443Sadrian if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) { 1105240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1106220443Sadrian nf_ctl[i] = nf_ext[i] = 0; 1107220443Sadrian } 1108220443Sadrian return 0; 1109220443Sadrian } 1110220443Sadrian if (ichan->rawNoiseFloor == 0) { 1111220443Sadrian WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 1112220443Sadrian HALASSERT(mode < WIRELESS_MODE_MAX); 1113220443Sadrian /* 1114220443Sadrian * See the comment below - this could cause issues for 1115220443Sadrian * stations which have a very low RSSI, below the 1116220443Sadrian * 'normalised' NF values in NOISE_FLOOR[]. 1117220443Sadrian */ 1118240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1119220443Sadrian nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] + 1120220443Sadrian ath_hal_getNfAdjust(ah, ichan); 1121220443Sadrian } 1122220443Sadrian return 1; 1123220443Sadrian } else { 1124220443Sadrian /* 1125220443Sadrian * The value returned here from a MIMO radio is presumed to be 1126220443Sadrian * "good enough" as a NF calculation. As RSSI values are calculated 1127220443Sadrian * against this, an adjusted NF may be higher than the RSSI value 1128220443Sadrian * returned from a vary weak station, resulting in an obscenely 1129220443Sadrian * high signal strength calculation being returned. 1130220443Sadrian * 1131220443Sadrian * This should be re-evaluated at a later date, along with any 1132220443Sadrian * signal strength calculations which are made. Quite likely the 1133220443Sadrian * RSSI values will need to be adjusted to ensure the calculations 1134220443Sadrian * don't "wrap" when RSSI is less than the "adjusted" NF value. 1135220443Sadrian * ("Adjust" here is via ichan->noiseFloorAdjust.) 1136220443Sadrian */ 1137240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1138220443Sadrian nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan); 1139220443Sadrian nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan); 1140220443Sadrian } 1141220443Sadrian return 1; 1142220443Sadrian } 1143221019Sadrian#else 1144221019Sadrian return 0; 1145221019Sadrian#endif /* AH_SUPPORT_AR5416 */ 1146220443Sadrian} 1147220443Sadrian 1148220443Sadrian/* 1149185377Ssam * Process all valid raw noise floors into the dBm noise floor values. 1150185377Ssam * Though our device has no reference for a dBm noise floor, we perform 1151185377Ssam * a relative minimization of NF's based on the lowest NF found across a 1152185377Ssam * channel scan. 1153185377Ssam */ 1154185377Ssamvoid 1155185377Ssamath_hal_process_noisefloor(struct ath_hal *ah) 1156185377Ssam{ 1157185377Ssam HAL_CHANNEL_INTERNAL *c; 1158185377Ssam int16_t correct2, correct5; 1159185377Ssam int16_t lowest2, lowest5; 1160185377Ssam int i; 1161185377Ssam 1162185377Ssam /* 1163185377Ssam * Find the lowest 2GHz and 5GHz noise floor values after adjusting 1164185377Ssam * for statistically recorded NF/channel deviation. 1165185377Ssam */ 1166185377Ssam correct2 = lowest2 = 0; 1167185377Ssam correct5 = lowest5 = 0; 1168185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1169185377Ssam WIRELESS_MODE mode; 1170185377Ssam int16_t nf; 1171185377Ssam 1172185377Ssam c = &AH_PRIVATE(ah)->ah_channels[i]; 1173185377Ssam if (c->rawNoiseFloor >= 0) 1174185377Ssam continue; 1175187831Ssam /* XXX can't identify proper mode */ 1176187831Ssam mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 1177185377Ssam nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 1178185377Ssam ath_hal_getNfAdjust(ah, c); 1179185377Ssam if (IS_CHAN_5GHZ(c)) { 1180185377Ssam if (nf < lowest5) { 1181185377Ssam lowest5 = nf; 1182185377Ssam correct5 = NOISE_FLOOR[mode] - 1183185377Ssam (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1184185377Ssam } 1185185377Ssam } else { 1186185377Ssam if (nf < lowest2) { 1187185377Ssam lowest2 = nf; 1188185377Ssam correct2 = NOISE_FLOOR[mode] - 1189185377Ssam (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1190185377Ssam } 1191185377Ssam } 1192185377Ssam } 1193185377Ssam 1194185377Ssam /* Correct the channels to reach the expected NF value */ 1195185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1196185377Ssam c = &AH_PRIVATE(ah)->ah_channels[i]; 1197185377Ssam if (c->rawNoiseFloor >= 0) 1198185377Ssam continue; 1199185377Ssam /* Apply correction factor */ 1200185377Ssam c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 1201185377Ssam (IS_CHAN_5GHZ(c) ? correct5 : correct2); 1202187831Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 1203187831Ssam c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 1204185377Ssam } 1205185377Ssam} 1206185377Ssam 1207185377Ssam/* 1208185377Ssam * INI support routines. 1209185377Ssam */ 1210185377Ssam 1211185377Ssamint 1212185377Ssamath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1213185377Ssam int col, int regWr) 1214185377Ssam{ 1215185377Ssam int r; 1216185377Ssam 1217189713Ssam HALASSERT(col < ia->cols); 1218185377Ssam for (r = 0; r < ia->rows; r++) { 1219185377Ssam OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 1220185377Ssam HAL_INI_VAL(ia, r, col)); 1221217921Sadrian 1222217921Sadrian /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ 1223222157Sadrian if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900) 1224217921Sadrian OS_DELAY(100); 1225217921Sadrian 1226185377Ssam DMA_YIELD(regWr); 1227185377Ssam } 1228185377Ssam return regWr; 1229185377Ssam} 1230185377Ssam 1231185377Ssamvoid 1232185377Ssamath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 1233185377Ssam{ 1234185377Ssam int r; 1235185377Ssam 1236189713Ssam HALASSERT(col < ia->cols); 1237185377Ssam for (r = 0; r < ia->rows; r++) 1238185377Ssam data[r] = HAL_INI_VAL(ia, r, col); 1239185377Ssam} 1240185377Ssam 1241185377Ssamint 1242185377Ssamath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1243185377Ssam const uint32_t data[], int regWr) 1244185377Ssam{ 1245185377Ssam int r; 1246185377Ssam 1247185377Ssam for (r = 0; r < ia->rows; r++) { 1248185377Ssam OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 1249185377Ssam DMA_YIELD(regWr); 1250185377Ssam } 1251185377Ssam return regWr; 1252185377Ssam} 1253219586Sadrian 1254219586Sadrian/* 1255219586Sadrian * These are EEPROM board related routines which should likely live in 1256219586Sadrian * a helper library of some sort. 1257219586Sadrian */ 1258219586Sadrian 1259219586Sadrian/************************************************************** 1260219586Sadrian * ath_ee_getLowerUppderIndex 1261219586Sadrian * 1262219586Sadrian * Return indices surrounding the value in sorted integer lists. 1263219586Sadrian * Requirement: the input list must be monotonically increasing 1264219586Sadrian * and populated up to the list size 1265219586Sadrian * Returns: match is set if an index in the array matches exactly 1266219586Sadrian * or a the target is before or after the range of the array. 1267219586Sadrian */ 1268219586SadrianHAL_BOOL 1269219586Sadrianath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize, 1270219586Sadrian uint16_t *indexL, uint16_t *indexR) 1271219586Sadrian{ 1272219586Sadrian uint16_t i; 1273219586Sadrian 1274219586Sadrian /* 1275219586Sadrian * Check first and last elements for beyond ordered array cases. 1276219586Sadrian */ 1277219586Sadrian if (target <= pList[0]) { 1278219586Sadrian *indexL = *indexR = 0; 1279219586Sadrian return AH_TRUE; 1280219586Sadrian } 1281219586Sadrian if (target >= pList[listSize-1]) { 1282219586Sadrian *indexL = *indexR = (uint16_t)(listSize - 1); 1283219586Sadrian return AH_TRUE; 1284219586Sadrian } 1285219586Sadrian 1286219586Sadrian /* look for value being near or between 2 values in list */ 1287219586Sadrian for (i = 0; i < listSize - 1; i++) { 1288219586Sadrian /* 1289219586Sadrian * If value is close to the current value of the list 1290219586Sadrian * then target is not between values, it is one of the values 1291219586Sadrian */ 1292219586Sadrian if (pList[i] == target) { 1293219586Sadrian *indexL = *indexR = i; 1294219586Sadrian return AH_TRUE; 1295219586Sadrian } 1296219586Sadrian /* 1297219586Sadrian * Look for value being between current value and next value 1298219586Sadrian * if so return these 2 values 1299219586Sadrian */ 1300219586Sadrian if (target < pList[i + 1]) { 1301219586Sadrian *indexL = i; 1302219586Sadrian *indexR = (uint16_t)(i + 1); 1303219586Sadrian return AH_FALSE; 1304219586Sadrian } 1305219586Sadrian } 1306219586Sadrian HALASSERT(0); 1307219586Sadrian *indexL = *indexR = 0; 1308219586Sadrian return AH_FALSE; 1309219586Sadrian} 1310219586Sadrian 1311219586Sadrian/************************************************************** 1312219586Sadrian * ath_ee_FillVpdTable 1313219586Sadrian * 1314219586Sadrian * Fill the Vpdlist for indices Pmax-Pmin 1315219586Sadrian * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4 1316219586Sadrian */ 1317219586SadrianHAL_BOOL 1318219586Sadrianath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList, 1319219586Sadrian uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList) 1320219586Sadrian{ 1321219586Sadrian uint16_t i, k; 1322219586Sadrian uint8_t currPwr = pwrMin; 1323219586Sadrian uint16_t idxL, idxR; 1324219586Sadrian 1325219586Sadrian HALASSERT(pwrMax > pwrMin); 1326219586Sadrian for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 1327219586Sadrian ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts, 1328219586Sadrian &(idxL), &(idxR)); 1329219586Sadrian if (idxR < 1) 1330219586Sadrian idxR = 1; /* extrapolate below */ 1331219586Sadrian if (idxL == numIntercepts - 1) 1332219586Sadrian idxL = (uint16_t)(numIntercepts - 2); /* extrapolate above */ 1333219586Sadrian if (pPwrList[idxL] == pPwrList[idxR]) 1334219586Sadrian k = pVpdList[idxL]; 1335219586Sadrian else 1336219586Sadrian k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 1337219586Sadrian (pPwrList[idxR] - pPwrList[idxL]) ); 1338219586Sadrian HALASSERT(k < 256); 1339219586Sadrian pRetVpdList[i] = (uint8_t)k; 1340219586Sadrian currPwr += 2; /* half dB steps */ 1341219586Sadrian } 1342219586Sadrian 1343219586Sadrian return AH_TRUE; 1344219586Sadrian} 1345219586Sadrian 1346219586Sadrian/************************************************************************** 1347219586Sadrian * ath_ee_interpolate 1348219586Sadrian * 1349219586Sadrian * Returns signed interpolated or the scaled up interpolated value 1350219586Sadrian */ 1351219586Sadrianint16_t 1352219586Sadrianath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 1353219586Sadrian int16_t targetLeft, int16_t targetRight) 1354219586Sadrian{ 1355219586Sadrian int16_t rv; 1356219586Sadrian 1357219586Sadrian if (srcRight == srcLeft) { 1358219586Sadrian rv = targetLeft; 1359219586Sadrian } else { 1360219586Sadrian rv = (int16_t)( ((target - srcLeft) * targetRight + 1361219586Sadrian (srcRight - target) * targetLeft) / (srcRight - srcLeft) ); 1362219586Sadrian } 1363219586Sadrian return rv; 1364219586Sadrian} 1365225444Sadrian 1366225444Sadrian/* 1367225444Sadrian * Adjust the TSF. 1368225444Sadrian */ 1369225444Sadrianvoid 1370225444Sadrianath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) 1371225444Sadrian{ 1372225444Sadrian /* XXX handle wrap/overflow */ 1373225444Sadrian OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); 1374225444Sadrian} 1375225444Sadrian 1376225444Sadrian/* 1377225444Sadrian * Enable or disable CCA. 1378225444Sadrian */ 1379225444Sadrianvoid 1380225444Sadrianath_hal_setcca(struct ath_hal *ah, int ena) 1381225444Sadrian{ 1382225444Sadrian /* 1383225444Sadrian * NB: fill me in; this is not provided by default because disabling 1384225444Sadrian * CCA in most locales violates regulatory. 1385225444Sadrian */ 1386225444Sadrian} 1387225444Sadrian 1388225444Sadrian/* 1389225444Sadrian * Get CCA setting. 1390225444Sadrian */ 1391225444Sadrianint 1392225444Sadrianath_hal_getcca(struct ath_hal *ah) 1393225444Sadrian{ 1394225444Sadrian u_int32_t diag; 1395225444Sadrian if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) 1396225444Sadrian return 1; 1397225444Sadrian return ((diag & 0x500000) == 0); 1398225444Sadrian} 1399230147Sadrian 1400230147Sadrian/* 1401230147Sadrian * This routine is only needed when supporting EEPROM-in-RAM setups 1402230147Sadrian * (eg embedded SoCs and on-board PCI/PCIe devices.) 1403230147Sadrian */ 1404230147Sadrian/* NB: This is in 16 bit words; not bytes */ 1405230147Sadrian/* XXX This doesn't belong here! */ 1406230147Sadrian#define ATH_DATA_EEPROM_SIZE 2048 1407230147Sadrian 1408230147SadrianHAL_BOOL 1409230147Sadrianath_hal_EepromDataRead(struct ath_hal *ah, u_int off, uint16_t *data) 1410230147Sadrian{ 1411230147Sadrian if (ah->ah_eepromdata == AH_NULL) { 1412230147Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__); 1413230147Sadrian return AH_FALSE; 1414230147Sadrian } 1415230147Sadrian if (off > ATH_DATA_EEPROM_SIZE) { 1416230147Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset %x > %x\n", 1417230147Sadrian __func__, off, ATH_DATA_EEPROM_SIZE); 1418230147Sadrian return AH_FALSE; 1419230147Sadrian } 1420230147Sadrian (*data) = ah->ah_eepromdata[off]; 1421230147Sadrian return AH_TRUE; 1422230147Sadrian} 1423252236Sadrian 1424252236Sadrian/* 1425252236Sadrian * Do a 2GHz specific MHz->IEEE based on the hardware 1426252236Sadrian * frequency. 1427252236Sadrian * 1428252236Sadrian * This is the unmapped frequency which is programmed into the hardware. 1429252236Sadrian */ 1430252236Sadrianint 1431291469Sadrianath_hal_mhz2ieee_2ghz(struct ath_hal *ah, int freq) 1432252236Sadrian{ 1433252236Sadrian 1434291469Sadrian if (freq == 2484) 1435252236Sadrian return 14; 1436291469Sadrian if (freq < 2484) 1437291469Sadrian return ((int) freq - 2407) / 5; 1438252236Sadrian else 1439291469Sadrian return 15 + ((freq - 2512) / 20); 1440252236Sadrian} 1441280828Sadrian 1442280828Sadrian/* 1443280828Sadrian * Clear the current survey data. 1444280828Sadrian * 1445280828Sadrian * This should be done during a channel change. 1446280828Sadrian */ 1447280828Sadrianvoid 1448280828Sadrianath_hal_survey_clear(struct ath_hal *ah) 1449280828Sadrian{ 1450280828Sadrian 1451280828Sadrian OS_MEMZERO(&AH_PRIVATE(ah)->ah_chansurvey, 1452280828Sadrian sizeof(AH_PRIVATE(ah)->ah_chansurvey)); 1453280828Sadrian} 1454280828Sadrian 1455280828Sadrian/* 1456280828Sadrian * Add a sample to the channel survey. 1457280828Sadrian */ 1458280828Sadrianvoid 1459280828Sadrianath_hal_survey_add_sample(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hs) 1460280828Sadrian{ 1461280828Sadrian HAL_CHANNEL_SURVEY *cs; 1462280828Sadrian 1463280828Sadrian cs = &AH_PRIVATE(ah)->ah_chansurvey; 1464280828Sadrian 1465280828Sadrian OS_MEMCPY(&cs->samples[cs->cur_sample], hs, sizeof(*hs)); 1466280828Sadrian cs->samples[cs->cur_sample].seq_num = cs->cur_seq; 1467280828Sadrian cs->cur_sample = (cs->cur_sample + 1) % CHANNEL_SURVEY_SAMPLE_COUNT; 1468280828Sadrian cs->cur_seq++; 1469280828Sadrian} 1470