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, 58217624Sadrian HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *error) 59185377Ssam{ 60186018Ssam struct ath_hal_chip * const *pchip; 61185377Ssam 62185417Ssam OS_SET_FOREACH(pchip, ah_chips) { 63185406Ssam struct ath_hal_chip *chip = *pchip; 64185406Ssam struct ath_hal *ah; 65185406Ssam 66185406Ssam /* XXX don't have vendorid, assume atheros one works */ 67185406Ssam if (chip->probe(ATHEROS_VENDOR_ID, devid) == AH_NULL) 68185406Ssam continue; 69217624Sadrian ah = chip->attach(devid, sc, st, sh, eepromdata, error); 70185406Ssam if (ah != AH_NULL) { 71185406Ssam /* copy back private state to public area */ 72185406Ssam ah->ah_devid = AH_PRIVATE(ah)->ah_devid; 73185406Ssam ah->ah_subvendorid = AH_PRIVATE(ah)->ah_subvendorid; 74185406Ssam ah->ah_macVersion = AH_PRIVATE(ah)->ah_macVersion; 75185406Ssam ah->ah_macRev = AH_PRIVATE(ah)->ah_macRev; 76185406Ssam ah->ah_phyRev = AH_PRIVATE(ah)->ah_phyRev; 77185406Ssam ah->ah_analog5GhzRev = AH_PRIVATE(ah)->ah_analog5GhzRev; 78185406Ssam ah->ah_analog2GhzRev = AH_PRIVATE(ah)->ah_analog2GhzRev; 79185406Ssam return ah; 80185406Ssam } 81185377Ssam } 82185406Ssam return AH_NULL; 83185406Ssam} 84185406Ssam 85188968Ssamconst char * 86188968Ssamath_hal_mac_name(struct ath_hal *ah) 87188968Ssam{ 88188968Ssam switch (ah->ah_macVersion) { 89188968Ssam case AR_SREV_VERSION_CRETE: 90188968Ssam case AR_SREV_VERSION_MAUI_1: 91188968Ssam return "5210"; 92188968Ssam case AR_SREV_VERSION_MAUI_2: 93188968Ssam case AR_SREV_VERSION_OAHU: 94188968Ssam return "5211"; 95188968Ssam case AR_SREV_VERSION_VENICE: 96188968Ssam return "5212"; 97188968Ssam case AR_SREV_VERSION_GRIFFIN: 98188968Ssam return "2413"; 99188968Ssam case AR_SREV_VERSION_CONDOR: 100188968Ssam return "5424"; 101188968Ssam case AR_SREV_VERSION_EAGLE: 102188968Ssam return "5413"; 103188968Ssam case AR_SREV_VERSION_COBRA: 104188968Ssam return "2415"; 105239603Sadrian case AR_SREV_2425: /* Swan */ 106188968Ssam return "2425"; 107239603Sadrian case AR_SREV_2417: /* Nala */ 108188968Ssam return "2417"; 109188968Ssam case AR_XSREV_VERSION_OWL_PCI: 110188968Ssam return "5416"; 111188968Ssam case AR_XSREV_VERSION_OWL_PCIE: 112188968Ssam return "5418"; 113221163Sadrian case AR_XSREV_VERSION_HOWL: 114221163Sadrian return "9130"; 115188968Ssam case AR_XSREV_VERSION_SOWL: 116188968Ssam return "9160"; 117188968Ssam case AR_XSREV_VERSION_MERLIN: 118227372Sadrian if (AH_PRIVATE(ah)->ah_ispcie) 119227372Sadrian return "9280"; 120227372Sadrian return "9220"; 121188968Ssam case AR_XSREV_VERSION_KITE: 122188968Ssam return "9285"; 123222305Sadrian case AR_XSREV_VERSION_KIWI: 124227372Sadrian if (AH_PRIVATE(ah)->ah_ispcie) 125227372Sadrian return "9287"; 126227372Sadrian return "9227"; 127239604Sadrian case AR_SREV_VERSION_AR9380: 128239604Sadrian if (ah->ah_macRev >= AR_SREV_REVISION_AR9580_10) 129239604Sadrian return "9580"; 130239604Sadrian return "9380"; 131239604Sadrian case AR_SREV_VERSION_AR9460: 132239604Sadrian return "9460"; 133239604Sadrian case AR_SREV_VERSION_AR9330: 134239604Sadrian return "9330"; 135239604Sadrian case AR_SREV_VERSION_AR9340: 136239604Sadrian return "9340"; 137239604Sadrian case AR_SREV_VERSION_QCA9550: 138239604Sadrian /* XXX should say QCA, not AR */ 139239604Sadrian return "9550"; 140239604Sadrian case AR_SREV_VERSION_AR9485: 141239604Sadrian return "9485"; 142250166Sadrian case AR_SREV_VERSION_QCA9565: 143250166Sadrian /* XXX should say QCA, not AR */ 144250166Sadrian return "9565"; 145188968Ssam } 146188968Ssam return "????"; 147188968Ssam} 148188968Ssam 149187831Ssam/* 150187831Ssam * Return the mask of available modes based on the hardware capabilities. 151187831Ssam */ 152187831Ssamu_int 153187831Ssamath_hal_getwirelessmodes(struct ath_hal*ah) 154187831Ssam{ 155187831Ssam return ath_hal_getWirelessModes(ah); 156187831Ssam} 157187831Ssam 158185406Ssam/* linker set of registered RF backends */ 159185406SsamOS_SET_DECLARE(ah_rfs, struct ath_hal_rf); 160185406Ssam 161185406Ssam/* 162185406Ssam * Check the set of registered RF backends to see if 163185406Ssam * any recognize the device as one they can support. 164185406Ssam */ 165185406Ssamstruct ath_hal_rf * 166185406Ssamath_hal_rfprobe(struct ath_hal *ah, HAL_STATUS *ecode) 167185406Ssam{ 168186018Ssam struct ath_hal_rf * const *prf; 169185406Ssam 170185417Ssam OS_SET_FOREACH(prf, ah_rfs) { 171185406Ssam struct ath_hal_rf *rf = *prf; 172185406Ssam if (rf->probe(ah)) 173185406Ssam return rf; 174185377Ssam } 175185406Ssam *ecode = HAL_ENOTSUPP; 176185406Ssam return AH_NULL; 177185377Ssam} 178185377Ssam 179188968Ssamconst char * 180188968Ssamath_hal_rf_name(struct ath_hal *ah) 181188968Ssam{ 182188968Ssam switch (ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { 183188968Ssam case 0: /* 5210 */ 184188968Ssam return "5110"; /* NB: made up */ 185188968Ssam case AR_RAD5111_SREV_MAJOR: 186188968Ssam case AR_RAD5111_SREV_PROD: 187188968Ssam return "5111"; 188188968Ssam case AR_RAD2111_SREV_MAJOR: 189188968Ssam return "2111"; 190188968Ssam case AR_RAD5112_SREV_MAJOR: 191188968Ssam case AR_RAD5112_SREV_2_0: 192188968Ssam case AR_RAD5112_SREV_2_1: 193188968Ssam return "5112"; 194188968Ssam case AR_RAD2112_SREV_MAJOR: 195188968Ssam case AR_RAD2112_SREV_2_0: 196188968Ssam case AR_RAD2112_SREV_2_1: 197188968Ssam return "2112"; 198188968Ssam case AR_RAD2413_SREV_MAJOR: 199188968Ssam return "2413"; 200188968Ssam case AR_RAD5413_SREV_MAJOR: 201188968Ssam return "5413"; 202188968Ssam case AR_RAD2316_SREV_MAJOR: 203188968Ssam return "2316"; 204188968Ssam case AR_RAD2317_SREV_MAJOR: 205188968Ssam return "2317"; 206188968Ssam case AR_RAD5424_SREV_MAJOR: 207188968Ssam return "5424"; 208188968Ssam 209188968Ssam case AR_RAD5133_SREV_MAJOR: 210188968Ssam return "5133"; 211188968Ssam case AR_RAD2133_SREV_MAJOR: 212188968Ssam return "2133"; 213188968Ssam case AR_RAD5122_SREV_MAJOR: 214188968Ssam return "5122"; 215188968Ssam case AR_RAD2122_SREV_MAJOR: 216188968Ssam return "2122"; 217188968Ssam } 218188968Ssam return "????"; 219188968Ssam} 220188968Ssam 221185377Ssam/* 222185377Ssam * Poll the register looking for a specific value. 223185377Ssam */ 224185377SsamHAL_BOOL 225185377Ssamath_hal_wait(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val) 226185377Ssam{ 227185377Ssam#define AH_TIMEOUT 1000 228217622Sadrian return ath_hal_waitfor(ah, reg, mask, val, AH_TIMEOUT); 229217622Sadrian#undef AH_TIMEOUT 230217622Sadrian} 231217622Sadrian 232217622SadrianHAL_BOOL 233217622Sadrianath_hal_waitfor(struct ath_hal *ah, u_int reg, uint32_t mask, uint32_t val, uint32_t timeout) 234217622Sadrian{ 235185377Ssam int i; 236185377Ssam 237217622Sadrian for (i = 0; i < timeout; i++) { 238185377Ssam if ((OS_REG_READ(ah, reg) & mask) == val) 239185377Ssam return AH_TRUE; 240185377Ssam OS_DELAY(10); 241185377Ssam } 242185377Ssam HALDEBUG(ah, HAL_DEBUG_REGIO | HAL_DEBUG_PHYIO, 243185377Ssam "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", 244185377Ssam __func__, reg, OS_REG_READ(ah, reg), mask, val); 245185377Ssam return AH_FALSE; 246185377Ssam} 247185377Ssam 248185377Ssam/* 249185377Ssam * Reverse the bits starting at the low bit for a value of 250185377Ssam * bit_count in size 251185377Ssam */ 252185377Ssamuint32_t 253185377Ssamath_hal_reverseBits(uint32_t val, uint32_t n) 254185377Ssam{ 255185377Ssam uint32_t retval; 256185377Ssam int i; 257185377Ssam 258185377Ssam for (i = 0, retval = 0; i < n; i++) { 259185377Ssam retval = (retval << 1) | (val & 1); 260185377Ssam val >>= 1; 261185377Ssam } 262185377Ssam return retval; 263185377Ssam} 264185377Ssam 265218011Sadrian/* 802.11n related timing definitions */ 266218011Sadrian 267218011Sadrian#define OFDM_PLCP_BITS 22 268218011Sadrian#define HT_L_STF 8 269218011Sadrian#define HT_L_LTF 8 270218011Sadrian#define HT_L_SIG 4 271218011Sadrian#define HT_SIG 8 272218011Sadrian#define HT_STF 4 273218011Sadrian#define HT_LTF(n) ((n) * 4) 274218011Sadrian 275218011Sadrian#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 276218011Sadrian#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 277218011Sadrian#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 278218011Sadrian 279185377Ssam/* 280218011Sadrian * Calculate the duration of a packet whether it is 11n or legacy. 281218011Sadrian */ 282218011Sadrianuint32_t 283218011Sadrianath_hal_pkt_txtime(struct ath_hal *ah, const HAL_RATE_TABLE *rates, uint32_t frameLen, 284218011Sadrian uint16_t rateix, HAL_BOOL isht40, HAL_BOOL shortPreamble) 285218011Sadrian{ 286218011Sadrian uint8_t rc; 287218011Sadrian int numStreams; 288218011Sadrian 289218011Sadrian rc = rates->info[rateix].rateCode; 290218011Sadrian 291218011Sadrian /* Legacy rate? Return the old way */ 292218011Sadrian if (! IS_HT_RATE(rc)) 293218011Sadrian return ath_hal_computetxtime(ah, rates, frameLen, rateix, shortPreamble); 294218011Sadrian 295218011Sadrian /* 11n frame - extract out the number of spatial streams */ 296218011Sadrian numStreams = HT_RC_2_STREAMS(rc); 297239287Sadrian KASSERT(numStreams > 0 && numStreams <= 4, 298239287Sadrian ("number of spatial streams needs to be 1..3: MCS rate 0x%x!", 299239287Sadrian rateix)); 300218011Sadrian 301218011Sadrian return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble); 302218011Sadrian} 303218011Sadrian 304239287Sadrianstatic const uint16_t ht20_bps[32] = { 305239287Sadrian 26, 52, 78, 104, 156, 208, 234, 260, 306239287Sadrian 52, 104, 156, 208, 312, 416, 468, 520, 307239287Sadrian 78, 156, 234, 312, 468, 624, 702, 780, 308239287Sadrian 104, 208, 312, 416, 624, 832, 936, 1040 309239287Sadrian}; 310239287Sadrianstatic const uint16_t ht40_bps[32] = { 311239287Sadrian 54, 108, 162, 216, 324, 432, 486, 540, 312239287Sadrian 108, 216, 324, 432, 648, 864, 972, 1080, 313239287Sadrian 162, 324, 486, 648, 972, 1296, 1458, 1620, 314239287Sadrian 216, 432, 648, 864, 1296, 1728, 1944, 2160 315239287Sadrian}; 316239287Sadrian 317218011Sadrian/* 318218011Sadrian * Calculate the transmit duration of an 11n frame. 319218011Sadrian */ 320218011Sadrianuint32_t 321239287Sadrianath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, 322239287Sadrian HAL_BOOL isht40, HAL_BOOL isShortGI) 323218011Sadrian{ 324218011Sadrian uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 325218011Sadrian 326218011Sadrian KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 327239287Sadrian KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate)); 328218011Sadrian 329218011Sadrian if (isht40) 330250824Sadrian bitsPerSymbol = ht40_bps[rate & 0x1f]; 331218011Sadrian else 332250824Sadrian bitsPerSymbol = ht20_bps[rate & 0x1f]; 333218011Sadrian numBits = OFDM_PLCP_BITS + (frameLen << 3); 334218011Sadrian numSymbols = howmany(numBits, bitsPerSymbol); 335218011Sadrian if (isShortGI) 336218011Sadrian txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 337218011Sadrian else 338218011Sadrian txTime = numSymbols * 4; /* 4us */ 339218011Sadrian return txTime + HT_L_STF + HT_L_LTF + 340218011Sadrian HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 341218011Sadrian} 342218011Sadrian 343218011Sadrian/* 344185377Ssam * Compute the time to transmit a frame of length frameLen bytes 345185377Ssam * using the specified rate, phy, and short preamble setting. 346185377Ssam */ 347185377Ssamuint16_t 348185377Ssamath_hal_computetxtime(struct ath_hal *ah, 349185377Ssam const HAL_RATE_TABLE *rates, uint32_t frameLen, uint16_t rateix, 350185377Ssam HAL_BOOL shortPreamble) 351185377Ssam{ 352185377Ssam uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 353185377Ssam uint32_t kbps; 354185377Ssam 355218923Sadrian /* Warn if this function is called for 11n rates; it should not be! */ 356218923Sadrian if (IS_HT_RATE(rates->info[rateix].rateCode)) 357218923Sadrian ath_hal_printf(ah, "%s: MCS rate? (index %d; hwrate 0x%x)\n", 358218923Sadrian __func__, rateix, rates->info[rateix].rateCode); 359218923Sadrian 360185377Ssam kbps = rates->info[rateix].rateKbps; 361185377Ssam /* 362185377Ssam * index can be invalid duting dynamic Turbo transitions. 363187831Ssam * XXX 364185377Ssam */ 365187831Ssam if (kbps == 0) 366187831Ssam return 0; 367185377Ssam switch (rates->info[rateix].phy) { 368185377Ssam case IEEE80211_T_CCK: 369185377Ssam phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 370185377Ssam if (shortPreamble && rates->info[rateix].shortPreamble) 371185377Ssam phyTime >>= 1; 372185377Ssam numBits = frameLen << 3; 373185377Ssam txTime = CCK_SIFS_TIME + phyTime 374185377Ssam + ((numBits * 1000)/kbps); 375185377Ssam break; 376185377Ssam case IEEE80211_T_OFDM: 377188773Ssam bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 378188773Ssam HALASSERT(bitsPerSymbol != 0); 379185377Ssam 380188773Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 381188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 382188773Ssam txTime = OFDM_SIFS_TIME 383188773Ssam + OFDM_PREAMBLE_TIME 384188773Ssam + (numSymbols * OFDM_SYMBOL_TIME); 385188773Ssam break; 386188773Ssam case IEEE80211_T_OFDM_HALF: 387188773Ssam bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 388188773Ssam HALASSERT(bitsPerSymbol != 0); 389185377Ssam 390188773Ssam numBits = OFDM_HALF_PLCP_BITS + (frameLen << 3); 391188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 392188773Ssam txTime = OFDM_HALF_SIFS_TIME 393188773Ssam + OFDM_HALF_PREAMBLE_TIME 394188773Ssam + (numSymbols * OFDM_HALF_SYMBOL_TIME); 395188773Ssam break; 396188773Ssam case IEEE80211_T_OFDM_QUARTER: 397188773Ssam bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 398188773Ssam HALASSERT(bitsPerSymbol != 0); 399185377Ssam 400188773Ssam numBits = OFDM_QUARTER_PLCP_BITS + (frameLen << 3); 401188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 402188773Ssam txTime = OFDM_QUARTER_SIFS_TIME 403188773Ssam + OFDM_QUARTER_PREAMBLE_TIME 404188773Ssam + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 405185377Ssam break; 406185377Ssam case IEEE80211_T_TURBO: 407191022Ssam bitsPerSymbol = (kbps * TURBO_SYMBOL_TIME) / 1000; 408185377Ssam HALASSERT(bitsPerSymbol != 0); 409185377Ssam 410188773Ssam numBits = TURBO_PLCP_BITS + (frameLen << 3); 411188773Ssam numSymbols = howmany(numBits, bitsPerSymbol); 412188773Ssam txTime = TURBO_SIFS_TIME 413188773Ssam + TURBO_PREAMBLE_TIME 414188773Ssam + (numSymbols * TURBO_SYMBOL_TIME); 415185377Ssam break; 416185377Ssam default: 417185377Ssam HALDEBUG(ah, HAL_DEBUG_PHYIO, 418185377Ssam "%s: unknown phy %u (rate ix %u)\n", 419185377Ssam __func__, rates->info[rateix].phy, rateix); 420185377Ssam txTime = 0; 421185377Ssam break; 422185377Ssam } 423185377Ssam return txTime; 424185377Ssam} 425185377Ssam 426239634Sadrianint 427239634Sadrianath_hal_get_curmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 428239634Sadrian{ 429239634Sadrian /* 430239634Sadrian * Pick a default mode at bootup. A channel change is inevitable. 431239634Sadrian */ 432239634Sadrian if (!chan) 433239634Sadrian return HAL_MODE_11NG_HT20; 434239634Sadrian 435239634Sadrian if (IEEE80211_IS_CHAN_TURBO(chan)) 436239634Sadrian return HAL_MODE_TURBO; 437239634Sadrian 438239634Sadrian /* check for NA_HT before plain A, since IS_CHAN_A includes NA_HT */ 439239634Sadrian if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan)) 440239634Sadrian return HAL_MODE_11NA_HT20; 441239634Sadrian if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan)) 442239634Sadrian return HAL_MODE_11NA_HT40PLUS; 443239634Sadrian if (IEEE80211_IS_CHAN_5GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan)) 444239634Sadrian return HAL_MODE_11NA_HT40MINUS; 445239634Sadrian if (IEEE80211_IS_CHAN_A(chan)) 446239634Sadrian return HAL_MODE_11A; 447239634Sadrian 448239634Sadrian /* check for NG_HT before plain G, since IS_CHAN_G includes NG_HT */ 449239634Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT20(chan)) 450239634Sadrian return HAL_MODE_11NG_HT20; 451239634Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40U(chan)) 452239634Sadrian return HAL_MODE_11NG_HT40PLUS; 453239634Sadrian if (IEEE80211_IS_CHAN_2GHZ(chan) && IEEE80211_IS_CHAN_HT40D(chan)) 454239634Sadrian return HAL_MODE_11NG_HT40MINUS; 455239634Sadrian 456239634Sadrian /* 457239634Sadrian * XXX For FreeBSD, will this work correctly given the DYN 458239634Sadrian * chan mode (OFDM+CCK dynamic) ? We have pure-G versions DYN-BG.. 459239634Sadrian */ 460239634Sadrian if (IEEE80211_IS_CHAN_G(chan)) 461239634Sadrian return HAL_MODE_11G; 462239634Sadrian if (IEEE80211_IS_CHAN_B(chan)) 463239634Sadrian return HAL_MODE_11B; 464239634Sadrian 465239634Sadrian HALASSERT(0); 466239634Sadrian return HAL_MODE_11NG_HT20; 467239634Sadrian} 468239634Sadrian 469239634Sadrian 470185377Ssamtypedef enum { 471185377Ssam WIRELESS_MODE_11a = 0, 472185377Ssam WIRELESS_MODE_TURBO = 1, 473185377Ssam WIRELESS_MODE_11b = 2, 474185377Ssam WIRELESS_MODE_11g = 3, 475185377Ssam WIRELESS_MODE_108g = 4, 476185377Ssam 477185377Ssam WIRELESS_MODE_MAX 478185377Ssam} WIRELESS_MODE; 479185377Ssam 480185377Ssamstatic WIRELESS_MODE 481187831Ssamath_hal_chan2wmode(struct ath_hal *ah, const struct ieee80211_channel *chan) 482185377Ssam{ 483187831Ssam if (IEEE80211_IS_CHAN_B(chan)) 484185377Ssam return WIRELESS_MODE_11b; 485187831Ssam if (IEEE80211_IS_CHAN_G(chan)) 486185377Ssam return WIRELESS_MODE_11g; 487187831Ssam if (IEEE80211_IS_CHAN_108G(chan)) 488185377Ssam return WIRELESS_MODE_108g; 489187831Ssam if (IEEE80211_IS_CHAN_TURBO(chan)) 490185377Ssam return WIRELESS_MODE_TURBO; 491185377Ssam return WIRELESS_MODE_11a; 492185377Ssam} 493185377Ssam 494185377Ssam/* 495185377Ssam * Convert between microseconds and core system clocks. 496185377Ssam */ 497185377Ssam /* 11a Turbo 11b 11g 108g */ 498185377Ssamstatic const uint8_t CLOCK_RATE[] = { 40, 80, 22, 44, 88 }; 499185377Ssam 500220298Sadrian#define CLOCK_FAST_RATE_5GHZ_OFDM 44 501220298Sadrian 502185377Ssamu_int 503185377Ssamath_hal_mac_clks(struct ath_hal *ah, u_int usecs) 504185377Ssam{ 505187831Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 506185377Ssam u_int clks; 507185377Ssam 508185377Ssam /* NB: ah_curchan may be null when called attach time */ 509220298Sadrian /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 510220298Sadrian if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 511220298Sadrian clks = usecs * CLOCK_FAST_RATE_5GHZ_OFDM; 512220298Sadrian if (IEEE80211_IS_CHAN_HT40(c)) 513220298Sadrian clks <<= 1; 514220298Sadrian } else if (c != AH_NULL) { 515185377Ssam clks = usecs * CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 516187831Ssam if (IEEE80211_IS_CHAN_HT40(c)) 517185377Ssam clks <<= 1; 518185377Ssam } else 519185377Ssam clks = usecs * CLOCK_RATE[WIRELESS_MODE_11b]; 520240444Sadrian 521240444Sadrian /* Compensate for half/quarter rate */ 522240444Sadrian if (c != AH_NULL && IEEE80211_IS_CHAN_HALF(c)) 523240444Sadrian clks = clks / 2; 524240444Sadrian else if (c != AH_NULL && IEEE80211_IS_CHAN_QUARTER(c)) 525240444Sadrian clks = clks / 4; 526240444Sadrian 527185377Ssam return clks; 528185377Ssam} 529185377Ssam 530185377Ssamu_int 531185377Ssamath_hal_mac_usec(struct ath_hal *ah, u_int clks) 532185377Ssam{ 533187831Ssam const struct ieee80211_channel *c = AH_PRIVATE(ah)->ah_curchan; 534185377Ssam u_int usec; 535185377Ssam 536185377Ssam /* NB: ah_curchan may be null when called attach time */ 537220298Sadrian /* XXX merlin and later specific workaround - 5ghz fast clock is 44 */ 538220298Sadrian if (c != AH_NULL && IS_5GHZ_FAST_CLOCK_EN(ah, c)) { 539220298Sadrian usec = clks / CLOCK_FAST_RATE_5GHZ_OFDM; 540220298Sadrian if (IEEE80211_IS_CHAN_HT40(c)) 541220298Sadrian usec >>= 1; 542220298Sadrian } else if (c != AH_NULL) { 543185377Ssam usec = clks / CLOCK_RATE[ath_hal_chan2wmode(ah, c)]; 544187831Ssam if (IEEE80211_IS_CHAN_HT40(c)) 545185377Ssam usec >>= 1; 546185377Ssam } else 547185377Ssam usec = clks / CLOCK_RATE[WIRELESS_MODE_11b]; 548185377Ssam return usec; 549185377Ssam} 550185377Ssam 551185377Ssam/* 552185377Ssam * Setup a h/w rate table's reverse lookup table and 553185377Ssam * fill in ack durations. This routine is called for 554185377Ssam * each rate table returned through the ah_getRateTable 555185377Ssam * method. The reverse lookup tables are assumed to be 556185377Ssam * initialized to zero (or at least the first entry). 557185377Ssam * We use this as a key that indicates whether or not 558185377Ssam * we've previously setup the reverse lookup table. 559185377Ssam * 560185377Ssam * XXX not reentrant, but shouldn't matter 561185377Ssam */ 562185377Ssamvoid 563185377Ssamath_hal_setupratetable(struct ath_hal *ah, HAL_RATE_TABLE *rt) 564185377Ssam{ 565185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 566185377Ssam int i; 567185377Ssam 568185377Ssam if (rt->rateCodeToIndex[0] != 0) /* already setup */ 569185377Ssam return; 570185377Ssam for (i = 0; i < N(rt->rateCodeToIndex); i++) 571185377Ssam rt->rateCodeToIndex[i] = (uint8_t) -1; 572185377Ssam for (i = 0; i < rt->rateCount; i++) { 573185377Ssam uint8_t code = rt->info[i].rateCode; 574185377Ssam uint8_t cix = rt->info[i].controlRate; 575185377Ssam 576185377Ssam HALASSERT(code < N(rt->rateCodeToIndex)); 577185377Ssam rt->rateCodeToIndex[code] = i; 578185377Ssam HALASSERT((code | rt->info[i].shortPreamble) < 579185377Ssam N(rt->rateCodeToIndex)); 580185377Ssam rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; 581185377Ssam /* 582185377Ssam * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 583185377Ssam * depends on whether they are marked as basic rates; 584185377Ssam * the static tables are setup with an 11b-compatible 585185377Ssam * 2Mb/s rate which will work but is suboptimal 586185377Ssam */ 587185377Ssam rt->info[i].lpAckDuration = ath_hal_computetxtime(ah, rt, 588185377Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_FALSE); 589185377Ssam rt->info[i].spAckDuration = ath_hal_computetxtime(ah, rt, 590185377Ssam WLAN_CTRL_FRAME_SIZE, cix, AH_TRUE); 591185377Ssam } 592185377Ssam#undef N 593185377Ssam} 594185377Ssam 595185377SsamHAL_STATUS 596185377Ssamath_hal_getcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 597185377Ssam uint32_t capability, uint32_t *result) 598185377Ssam{ 599185377Ssam const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 600185377Ssam 601185377Ssam switch (type) { 602185377Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 603185377Ssam *result = AH_PRIVATE(ah)->ah_currentRD; 604185377Ssam return HAL_OK; 605224716Sadrian case HAL_CAP_DFS_DMN: /* DFS Domain */ 606224716Sadrian *result = AH_PRIVATE(ah)->ah_dfsDomain; 607224716Sadrian return HAL_OK; 608185377Ssam case HAL_CAP_CIPHER: /* cipher handled in hardware */ 609185377Ssam case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 610185377Ssam return HAL_ENOTSUPP; 611185377Ssam case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 612185377Ssam return HAL_ENOTSUPP; 613185377Ssam case HAL_CAP_PHYCOUNTERS: /* hardware PHY error counters */ 614185377Ssam return pCap->halHwPhyCounterSupport ? HAL_OK : HAL_ENXIO; 615185377Ssam case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC when WMM is turned on */ 616185377Ssam return HAL_ENOTSUPP; 617185377Ssam case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 618185377Ssam return HAL_ENOTSUPP; 619185377Ssam case HAL_CAP_KEYCACHE_SIZE: /* hardware key cache size */ 620185377Ssam *result = pCap->halKeyCacheSize; 621185377Ssam return HAL_OK; 622185377Ssam case HAL_CAP_NUM_TXQUEUES: /* number of hardware tx queues */ 623185377Ssam *result = pCap->halTotalQueues; 624185377Ssam return HAL_OK; 625185377Ssam case HAL_CAP_VEOL: /* hardware supports virtual EOL */ 626185377Ssam return pCap->halVEOLSupport ? HAL_OK : HAL_ENOTSUPP; 627185377Ssam case HAL_CAP_PSPOLL: /* hardware PS-Poll support works */ 628185377Ssam return pCap->halPSPollBroken ? HAL_ENOTSUPP : HAL_OK; 629185377Ssam case HAL_CAP_COMPRESSION: 630185377Ssam return pCap->halCompressSupport ? HAL_OK : HAL_ENOTSUPP; 631185377Ssam case HAL_CAP_BURST: 632185377Ssam return pCap->halBurstSupport ? HAL_OK : HAL_ENOTSUPP; 633185377Ssam case HAL_CAP_FASTFRAME: 634185377Ssam return pCap->halFastFramesSupport ? HAL_OK : HAL_ENOTSUPP; 635185377Ssam case HAL_CAP_DIAG: /* hardware diagnostic support */ 636185377Ssam *result = AH_PRIVATE(ah)->ah_diagreg; 637185377Ssam return HAL_OK; 638185377Ssam case HAL_CAP_TXPOW: /* global tx power limit */ 639185377Ssam switch (capability) { 640185377Ssam case 0: /* facility is supported */ 641185377Ssam return HAL_OK; 642185377Ssam case 1: /* current limit */ 643185377Ssam *result = AH_PRIVATE(ah)->ah_powerLimit; 644185377Ssam return HAL_OK; 645185377Ssam case 2: /* current max tx power */ 646185377Ssam *result = AH_PRIVATE(ah)->ah_maxPowerLevel; 647185377Ssam return HAL_OK; 648185377Ssam case 3: /* scale factor */ 649185377Ssam *result = AH_PRIVATE(ah)->ah_tpScale; 650185377Ssam return HAL_OK; 651185377Ssam } 652185377Ssam return HAL_ENOTSUPP; 653185377Ssam case HAL_CAP_BSSIDMASK: /* hardware supports bssid mask */ 654185377Ssam return pCap->halBssIdMaskSupport ? HAL_OK : HAL_ENOTSUPP; 655185377Ssam case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 656185377Ssam return pCap->halMcastKeySrchSupport ? HAL_OK : HAL_ENOTSUPP; 657185377Ssam case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 658185377Ssam return HAL_ENOTSUPP; 659185377Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 660185377Ssam switch (capability) { 661185377Ssam case 0: /* facility is supported */ 662185377Ssam return pCap->halRfSilentSupport ? HAL_OK : HAL_ENOTSUPP; 663185377Ssam case 1: /* current setting */ 664185377Ssam return AH_PRIVATE(ah)->ah_rfkillEnabled ? 665185377Ssam HAL_OK : HAL_ENOTSUPP; 666185377Ssam case 2: /* rfsilent config */ 667185377Ssam *result = AH_PRIVATE(ah)->ah_rfsilent; 668185377Ssam return HAL_OK; 669185377Ssam } 670185377Ssam return HAL_ENOTSUPP; 671185377Ssam case HAL_CAP_11D: 672185377Ssam return HAL_OK; 673221603Sadrian 674185377Ssam case HAL_CAP_HT: 675185377Ssam return pCap->halHTSupport ? HAL_OK : HAL_ENOTSUPP; 676221603Sadrian case HAL_CAP_GTXTO: 677221603Sadrian return pCap->halGTTSupport ? HAL_OK : HAL_ENOTSUPP; 678221603Sadrian case HAL_CAP_FAST_CC: 679221603Sadrian return pCap->halFastCCSupport ? HAL_OK : HAL_ENOTSUPP; 680185377Ssam case HAL_CAP_TX_CHAINMASK: /* mask of TX chains supported */ 681185377Ssam *result = pCap->halTxChainMask; 682185377Ssam return HAL_OK; 683185377Ssam case HAL_CAP_RX_CHAINMASK: /* mask of RX chains supported */ 684185377Ssam *result = pCap->halRxChainMask; 685185377Ssam return HAL_OK; 686221603Sadrian case HAL_CAP_NUM_GPIO_PINS: 687221603Sadrian *result = pCap->halNumGpioPins; 688221603Sadrian return HAL_OK; 689221603Sadrian case HAL_CAP_CST: 690221603Sadrian return pCap->halCSTSupport ? HAL_OK : HAL_ENOTSUPP; 691221603Sadrian case HAL_CAP_RTS_AGGR_LIMIT: 692221603Sadrian *result = pCap->halRtsAggrLimit; 693221603Sadrian return HAL_OK; 694221603Sadrian case HAL_CAP_4ADDR_AGGR: 695221603Sadrian return pCap->hal4AddrAggrSupport ? HAL_OK : HAL_ENOTSUPP; 696222584Sadrian case HAL_CAP_EXT_CHAN_DFS: 697222584Sadrian return pCap->halExtChanDfsSupport ? HAL_OK : HAL_ENOTSUPP; 698247366Sadrian case HAL_CAP_RX_STBC: 699247366Sadrian return pCap->halRxStbcSupport ? HAL_OK : HAL_ENOTSUPP; 700247366Sadrian case HAL_CAP_TX_STBC: 701247366Sadrian return pCap->halTxStbcSupport ? HAL_OK : HAL_ENOTSUPP; 702238333Sadrian case HAL_CAP_COMBINED_RADAR_RSSI: 703238333Sadrian return pCap->halUseCombinedRadarRssi ? HAL_OK : HAL_ENOTSUPP; 704238333Sadrian case HAL_CAP_AUTO_SLEEP: 705238333Sadrian return pCap->halAutoSleepSupport ? HAL_OK : HAL_ENOTSUPP; 706238333Sadrian case HAL_CAP_MBSSID_AGGR_SUPPORT: 707238333Sadrian return pCap->halMbssidAggrSupport ? HAL_OK : HAL_ENOTSUPP; 708238333Sadrian case HAL_CAP_SPLIT_4KB_TRANS: /* hardware handles descriptors straddling 4k page boundary */ 709238333Sadrian return pCap->hal4kbSplitTransSupport ? HAL_OK : HAL_ENOTSUPP; 710238333Sadrian case HAL_CAP_REG_FLAG: 711238333Sadrian *result = AH_PRIVATE(ah)->ah_currentRDext; 712238333Sadrian return HAL_OK; 713238333Sadrian case HAL_CAP_ENHANCED_DMA_SUPPORT: 714238333Sadrian return pCap->halEnhancedDmaSupport ? HAL_OK : HAL_ENOTSUPP; 715238280Sadrian case HAL_CAP_NUM_TXMAPS: 716238280Sadrian *result = pCap->halNumTxMaps; 717238280Sadrian return HAL_OK; 718238280Sadrian case HAL_CAP_TXDESCLEN: 719238280Sadrian *result = pCap->halTxDescLen; 720238280Sadrian return HAL_OK; 721238280Sadrian case HAL_CAP_TXSTATUSLEN: 722238280Sadrian *result = pCap->halTxStatusLen; 723238280Sadrian return HAL_OK; 724238280Sadrian case HAL_CAP_RXSTATUSLEN: 725238280Sadrian *result = pCap->halRxStatusLen; 726238280Sadrian return HAL_OK; 727238280Sadrian case HAL_CAP_RXFIFODEPTH: 728238280Sadrian switch (capability) { 729238280Sadrian case HAL_RX_QUEUE_HP: 730238280Sadrian *result = pCap->halRxHpFifoDepth; 731238280Sadrian return HAL_OK; 732238280Sadrian case HAL_RX_QUEUE_LP: 733238280Sadrian *result = pCap->halRxLpFifoDepth; 734238280Sadrian return HAL_OK; 735238280Sadrian default: 736238280Sadrian return HAL_ENOTSUPP; 737238280Sadrian } 738238280Sadrian case HAL_CAP_RXBUFSIZE: 739238280Sadrian case HAL_CAP_NUM_MR_RETRIES: 740238858Sadrian *result = pCap->halNumMRRetries; 741238858Sadrian return HAL_OK; 742221603Sadrian case HAL_CAP_BT_COEX: 743221603Sadrian return pCap->halBtCoexSupport ? HAL_OK : HAL_ENOTSUPP; 744244854Sadrian case HAL_CAP_SPECTRAL_SCAN: 745244854Sadrian return pCap->halSpectralScanSupport ? HAL_OK : HAL_ENOTSUPP; 746221603Sadrian case HAL_CAP_HT20_SGI: 747221603Sadrian return pCap->halHTSGI20Support ? HAL_OK : HAL_ENOTSUPP; 748185377Ssam case HAL_CAP_RXTSTAMP_PREC: /* rx desc tstamp precision (bits) */ 749185377Ssam *result = pCap->halTstampPrecision; 750185377Ssam return HAL_OK; 751251360Sadrian case HAL_CAP_ANT_DIV_COMB: /* AR9285/AR9485 LNA diversity */ 752251360Sadrian return pCap->halAntDivCombSupport ? HAL_OK : HAL_ENOTSUPP; 753251360Sadrian 754222584Sadrian case HAL_CAP_ENHANCED_DFS_SUPPORT: 755222584Sadrian return pCap->halEnhancedDfsSupport ? HAL_OK : HAL_ENOTSUPP; 756221603Sadrian 757221603Sadrian /* FreeBSD-specific entries for now */ 758221603Sadrian case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 759221603Sadrian return AH_PRIVATE(ah)->ah_rxornIsFatal ? HAL_OK : HAL_ENOTSUPP; 760192396Ssam case HAL_CAP_INTRMASK: /* mask of supported interrupts */ 761192396Ssam *result = pCap->halIntrMask; 762192396Ssam return HAL_OK; 763195114Ssam case HAL_CAP_BSSIDMATCH: /* hardware has disable bssid match */ 764195114Ssam return pCap->halBssidMatchSupport ? HAL_OK : HAL_ENOTSUPP; 765218150Sadrian case HAL_CAP_STREAMS: /* number of 11n spatial streams */ 766218150Sadrian switch (capability) { 767218150Sadrian case 0: /* TX */ 768218150Sadrian *result = pCap->halTxStreams; 769218150Sadrian return HAL_OK; 770218150Sadrian case 1: /* RX */ 771218150Sadrian *result = pCap->halRxStreams; 772218150Sadrian return HAL_OK; 773218150Sadrian default: 774218150Sadrian return HAL_ENOTSUPP; 775218150Sadrian } 776220324Sadrian case HAL_CAP_RXDESC_SELFLINK: /* hardware supports self-linked final RX descriptors correctly */ 777220324Sadrian return pCap->halHasRxSelfLinkedTail ? HAL_OK : HAL_ENOTSUPP; 778225444Sadrian case HAL_CAP_LONG_RXDESC_TSF: /* 32 bit TSF in RX descriptor? */ 779225444Sadrian return pCap->halHasLongRxDescTsf ? HAL_OK : HAL_ENOTSUPP; 780226488Sadrian case HAL_CAP_BB_READ_WAR: /* Baseband read WAR */ 781226488Sadrian return pCap->halHasBBReadWar? HAL_OK : HAL_ENOTSUPP; 782227410Sadrian case HAL_CAP_SERIALISE_WAR: /* PCI register serialisation */ 783227410Sadrian return pCap->halSerialiseRegWar ? HAL_OK : HAL_ENOTSUPP; 784239630Sadrian case HAL_CAP_MFP: /* Management frame protection setting */ 785239630Sadrian *result = pCap->halMfpSupport; 786239630Sadrian return HAL_OK; 787251400Sadrian case HAL_CAP_RX_LNA_MIXING: /* Hardware uses an RX LNA mixer to map 2 antennas to a 1 stream receiver */ 788251400Sadrian return pCap->halRxUsingLnaMixing ? HAL_OK : HAL_ENOTSUPP; 789185377Ssam default: 790185377Ssam return HAL_EINVAL; 791185377Ssam } 792185377Ssam} 793185377Ssam 794185377SsamHAL_BOOL 795185377Ssamath_hal_setcapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 796185377Ssam uint32_t capability, uint32_t setting, HAL_STATUS *status) 797185377Ssam{ 798185377Ssam 799185377Ssam switch (type) { 800185377Ssam case HAL_CAP_TXPOW: 801185377Ssam switch (capability) { 802185377Ssam case 3: 803185377Ssam if (setting <= HAL_TP_SCALE_MIN) { 804185377Ssam AH_PRIVATE(ah)->ah_tpScale = setting; 805185377Ssam return AH_TRUE; 806185377Ssam } 807185377Ssam break; 808185377Ssam } 809185377Ssam break; 810185377Ssam case HAL_CAP_RFSILENT: /* rfsilent support */ 811185377Ssam /* 812185377Ssam * NB: allow even if halRfSilentSupport is false 813185377Ssam * in case the EEPROM is misprogrammed. 814185377Ssam */ 815185377Ssam switch (capability) { 816185377Ssam case 1: /* current setting */ 817185377Ssam AH_PRIVATE(ah)->ah_rfkillEnabled = (setting != 0); 818185377Ssam return AH_TRUE; 819185377Ssam case 2: /* rfsilent config */ 820185377Ssam /* XXX better done per-chip for validation? */ 821185377Ssam AH_PRIVATE(ah)->ah_rfsilent = setting; 822185377Ssam return AH_TRUE; 823185377Ssam } 824185377Ssam break; 825185377Ssam case HAL_CAP_REG_DMN: /* regulatory domain */ 826185377Ssam AH_PRIVATE(ah)->ah_currentRD = setting; 827185377Ssam return AH_TRUE; 828185377Ssam case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 829185377Ssam AH_PRIVATE(ah)->ah_rxornIsFatal = setting; 830185377Ssam return AH_TRUE; 831185377Ssam default: 832185377Ssam break; 833185377Ssam } 834185377Ssam if (status) 835185377Ssam *status = HAL_EINVAL; 836185377Ssam return AH_FALSE; 837185377Ssam} 838185377Ssam 839185377Ssam/* 840185377Ssam * Common support for getDiagState method. 841185377Ssam */ 842185377Ssam 843185377Ssamstatic u_int 844185377Ssamath_hal_getregdump(struct ath_hal *ah, const HAL_REGRANGE *regs, 845185377Ssam void *dstbuf, int space) 846185377Ssam{ 847185377Ssam uint32_t *dp = dstbuf; 848185377Ssam int i; 849185377Ssam 850185377Ssam for (i = 0; space >= 2*sizeof(uint32_t); i++) { 851185377Ssam u_int r = regs[i].start; 852185377Ssam u_int e = regs[i].end; 853185377Ssam *dp++ = (r<<16) | e; 854185377Ssam space -= sizeof(uint32_t); 855185377Ssam do { 856185377Ssam *dp++ = OS_REG_READ(ah, r); 857185377Ssam r += sizeof(uint32_t); 858185377Ssam space -= sizeof(uint32_t); 859185377Ssam } while (r <= e && space >= sizeof(uint32_t)); 860185377Ssam } 861185377Ssam return (char *) dp - (char *) dstbuf; 862185377Ssam} 863188771Ssam 864188771Ssamstatic void 865188771Ssamath_hal_setregs(struct ath_hal *ah, const HAL_REGWRITE *regs, int space) 866188771Ssam{ 867188771Ssam while (space >= sizeof(HAL_REGWRITE)) { 868188771Ssam OS_REG_WRITE(ah, regs->addr, regs->value); 869188771Ssam regs++, space -= sizeof(HAL_REGWRITE); 870188771Ssam } 871188771Ssam} 872185377Ssam 873185377SsamHAL_BOOL 874185377Ssamath_hal_getdiagstate(struct ath_hal *ah, int request, 875185377Ssam const void *args, uint32_t argsize, 876185377Ssam void **result, uint32_t *resultsize) 877185377Ssam{ 878185377Ssam switch (request) { 879185377Ssam case HAL_DIAG_REVS: 880185377Ssam *result = &AH_PRIVATE(ah)->ah_devid; 881185377Ssam *resultsize = sizeof(HAL_REVS); 882185377Ssam return AH_TRUE; 883185377Ssam case HAL_DIAG_REGS: 884185377Ssam *resultsize = ath_hal_getregdump(ah, args, *result,*resultsize); 885185377Ssam return AH_TRUE; 886188771Ssam case HAL_DIAG_SETREGS: 887188771Ssam ath_hal_setregs(ah, args, argsize); 888188771Ssam *resultsize = 0; 889188771Ssam return AH_TRUE; 890185377Ssam case HAL_DIAG_FATALERR: 891185377Ssam *result = &AH_PRIVATE(ah)->ah_fatalState[0]; 892185377Ssam *resultsize = sizeof(AH_PRIVATE(ah)->ah_fatalState); 893185377Ssam return AH_TRUE; 894185377Ssam case HAL_DIAG_EEREAD: 895185377Ssam if (argsize != sizeof(uint16_t)) 896185377Ssam return AH_FALSE; 897185377Ssam if (!ath_hal_eepromRead(ah, *(const uint16_t *)args, *result)) 898185377Ssam return AH_FALSE; 899185377Ssam *resultsize = sizeof(uint16_t); 900185377Ssam return AH_TRUE; 901185377Ssam#ifdef AH_PRIVATE_DIAG 902185377Ssam case HAL_DIAG_SETKEY: { 903185377Ssam const HAL_DIAG_KEYVAL *dk; 904185377Ssam 905185377Ssam if (argsize != sizeof(HAL_DIAG_KEYVAL)) 906185377Ssam return AH_FALSE; 907185377Ssam dk = (const HAL_DIAG_KEYVAL *)args; 908185377Ssam return ah->ah_setKeyCacheEntry(ah, dk->dk_keyix, 909185377Ssam &dk->dk_keyval, dk->dk_mac, dk->dk_xor); 910185377Ssam } 911185377Ssam case HAL_DIAG_RESETKEY: 912185377Ssam if (argsize != sizeof(uint16_t)) 913185377Ssam return AH_FALSE; 914185377Ssam return ah->ah_resetKeyCacheEntry(ah, *(const uint16_t *)args); 915185380Ssam#ifdef AH_SUPPORT_WRITE_EEPROM 916185380Ssam case HAL_DIAG_EEWRITE: { 917185380Ssam const HAL_DIAG_EEVAL *ee; 918185380Ssam if (argsize != sizeof(HAL_DIAG_EEVAL)) 919185380Ssam return AH_FALSE; 920185380Ssam ee = (const HAL_DIAG_EEVAL *)args; 921185380Ssam return ath_hal_eepromWrite(ah, ee->ee_off, ee->ee_data); 922185380Ssam } 923185380Ssam#endif /* AH_SUPPORT_WRITE_EEPROM */ 924185377Ssam#endif /* AH_PRIVATE_DIAG */ 925185377Ssam case HAL_DIAG_11NCOMPAT: 926185377Ssam if (argsize == 0) { 927185377Ssam *resultsize = sizeof(uint32_t); 928185377Ssam *((uint32_t *)(*result)) = 929185377Ssam AH_PRIVATE(ah)->ah_11nCompat; 930185377Ssam } else if (argsize == sizeof(uint32_t)) { 931185377Ssam AH_PRIVATE(ah)->ah_11nCompat = *(const uint32_t *)args; 932185377Ssam } else 933185377Ssam return AH_FALSE; 934185377Ssam return AH_TRUE; 935185377Ssam } 936185377Ssam return AH_FALSE; 937185377Ssam} 938185377Ssam 939185377Ssam/* 940185377Ssam * Set the properties of the tx queue with the parameters 941185377Ssam * from qInfo. 942185377Ssam */ 943185377SsamHAL_BOOL 944185377Ssamath_hal_setTxQProps(struct ath_hal *ah, 945185377Ssam HAL_TX_QUEUE_INFO *qi, const HAL_TXQ_INFO *qInfo) 946185377Ssam{ 947185377Ssam uint32_t cw; 948185377Ssam 949185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 950185377Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 951185377Ssam "%s: inactive queue\n", __func__); 952185377Ssam return AH_FALSE; 953185377Ssam } 954185377Ssam /* XXX validate parameters */ 955185377Ssam qi->tqi_ver = qInfo->tqi_ver; 956185377Ssam qi->tqi_subtype = qInfo->tqi_subtype; 957185377Ssam qi->tqi_qflags = qInfo->tqi_qflags; 958185377Ssam qi->tqi_priority = qInfo->tqi_priority; 959185377Ssam if (qInfo->tqi_aifs != HAL_TXQ_USEDEFAULT) 960185377Ssam qi->tqi_aifs = AH_MIN(qInfo->tqi_aifs, 255); 961185377Ssam else 962185377Ssam qi->tqi_aifs = INIT_AIFS; 963185377Ssam if (qInfo->tqi_cwmin != HAL_TXQ_USEDEFAULT) { 964185377Ssam cw = AH_MIN(qInfo->tqi_cwmin, 1024); 965185377Ssam /* make sure that the CWmin is of the form (2^n - 1) */ 966185377Ssam qi->tqi_cwmin = 1; 967185377Ssam while (qi->tqi_cwmin < cw) 968185377Ssam qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; 969185377Ssam } else 970185377Ssam qi->tqi_cwmin = qInfo->tqi_cwmin; 971185377Ssam if (qInfo->tqi_cwmax != HAL_TXQ_USEDEFAULT) { 972185377Ssam cw = AH_MIN(qInfo->tqi_cwmax, 1024); 973185377Ssam /* make sure that the CWmax is of the form (2^n - 1) */ 974185377Ssam qi->tqi_cwmax = 1; 975185377Ssam while (qi->tqi_cwmax < cw) 976185377Ssam qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; 977185377Ssam } else 978185377Ssam qi->tqi_cwmax = INIT_CWMAX; 979185377Ssam /* Set retry limit values */ 980185377Ssam if (qInfo->tqi_shretry != 0) 981185377Ssam qi->tqi_shretry = AH_MIN(qInfo->tqi_shretry, 15); 982185377Ssam else 983185377Ssam qi->tqi_shretry = INIT_SH_RETRY; 984185377Ssam if (qInfo->tqi_lgretry != 0) 985185377Ssam qi->tqi_lgretry = AH_MIN(qInfo->tqi_lgretry, 15); 986185377Ssam else 987185377Ssam qi->tqi_lgretry = INIT_LG_RETRY; 988185377Ssam qi->tqi_cbrPeriod = qInfo->tqi_cbrPeriod; 989185377Ssam qi->tqi_cbrOverflowLimit = qInfo->tqi_cbrOverflowLimit; 990185377Ssam qi->tqi_burstTime = qInfo->tqi_burstTime; 991185377Ssam qi->tqi_readyTime = qInfo->tqi_readyTime; 992185377Ssam 993185377Ssam switch (qInfo->tqi_subtype) { 994185377Ssam case HAL_WME_UPSD: 995185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_DATA) 996185377Ssam qi->tqi_intFlags = HAL_TXQ_USE_LOCKOUT_BKOFF_DIS; 997185377Ssam break; 998185377Ssam default: 999185377Ssam break; /* NB: silence compiler */ 1000185377Ssam } 1001185377Ssam return AH_TRUE; 1002185377Ssam} 1003185377Ssam 1004185377SsamHAL_BOOL 1005185377Ssamath_hal_getTxQProps(struct ath_hal *ah, 1006185377Ssam HAL_TXQ_INFO *qInfo, const HAL_TX_QUEUE_INFO *qi) 1007185377Ssam{ 1008185377Ssam if (qi->tqi_type == HAL_TX_QUEUE_INACTIVE) { 1009185377Ssam HALDEBUG(ah, HAL_DEBUG_TXQUEUE, 1010185377Ssam "%s: inactive queue\n", __func__); 1011185377Ssam return AH_FALSE; 1012185377Ssam } 1013185377Ssam 1014185377Ssam qInfo->tqi_qflags = qi->tqi_qflags; 1015185377Ssam qInfo->tqi_ver = qi->tqi_ver; 1016185377Ssam qInfo->tqi_subtype = qi->tqi_subtype; 1017185377Ssam qInfo->tqi_qflags = qi->tqi_qflags; 1018185377Ssam qInfo->tqi_priority = qi->tqi_priority; 1019185377Ssam qInfo->tqi_aifs = qi->tqi_aifs; 1020185377Ssam qInfo->tqi_cwmin = qi->tqi_cwmin; 1021185377Ssam qInfo->tqi_cwmax = qi->tqi_cwmax; 1022185377Ssam qInfo->tqi_shretry = qi->tqi_shretry; 1023185377Ssam qInfo->tqi_lgretry = qi->tqi_lgretry; 1024185377Ssam qInfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; 1025185377Ssam qInfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; 1026185377Ssam qInfo->tqi_burstTime = qi->tqi_burstTime; 1027185377Ssam qInfo->tqi_readyTime = qi->tqi_readyTime; 1028185377Ssam return AH_TRUE; 1029185377Ssam} 1030185377Ssam 1031185377Ssam /* 11a Turbo 11b 11g 108g */ 1032185377Ssamstatic const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93 }; 1033185377Ssam 1034185377Ssam/* 1035185377Ssam * Read the current channel noise floor and return. 1036185377Ssam * If nf cal hasn't finished, channel noise floor should be 0 1037185377Ssam * and we return a nominal value based on band and frequency. 1038185377Ssam * 1039185377Ssam * NB: This is a private routine used by per-chip code to 1040185377Ssam * implement the ah_getChanNoise method. 1041185377Ssam */ 1042185377Ssamint16_t 1043187831Ssamath_hal_getChanNoise(struct ath_hal *ah, const struct ieee80211_channel *chan) 1044185377Ssam{ 1045185377Ssam HAL_CHANNEL_INTERNAL *ichan; 1046185377Ssam 1047185377Ssam ichan = ath_hal_checkchannel(ah, chan); 1048185377Ssam if (ichan == AH_NULL) { 1049185377Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, 1050185377Ssam "%s: invalid channel %u/0x%x; no mapping\n", 1051187831Ssam __func__, chan->ic_freq, chan->ic_flags); 1052185377Ssam return 0; 1053185377Ssam } 1054185377Ssam if (ichan->rawNoiseFloor == 0) { 1055185377Ssam WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 1056185377Ssam 1057185377Ssam HALASSERT(mode < WIRELESS_MODE_MAX); 1058185377Ssam return NOISE_FLOOR[mode] + ath_hal_getNfAdjust(ah, ichan); 1059185377Ssam } else 1060185377Ssam return ichan->rawNoiseFloor + ichan->noiseFloorAdjust; 1061185377Ssam} 1062185377Ssam 1063185377Ssam/* 1064220443Sadrian * Fetch the current setup of ctl/ext noise floor values. 1065220443Sadrian * 1066220443Sadrian * If the CHANNEL_MIMO_NF_VALID flag isn't set, the array is simply 1067220443Sadrian * populated with values from NOISE_FLOOR[] + ath_hal_getNfAdjust(). 1068220443Sadrian * 1069220443Sadrian * The caller must supply ctl/ext NF arrays which are at least 1070240623Sadrian * AH_MAX_CHAINS entries long. 1071220443Sadrian */ 1072220443Sadrianint 1073220443Sadrianath_hal_get_mimo_chan_noise(struct ath_hal *ah, 1074220444Sadrian const struct ieee80211_channel *chan, int16_t *nf_ctl, 1075220444Sadrian int16_t *nf_ext) 1076220443Sadrian{ 1077221019Sadrian#ifdef AH_SUPPORT_AR5416 1078220443Sadrian HAL_CHANNEL_INTERNAL *ichan; 1079220443Sadrian int i; 1080220443Sadrian 1081220443Sadrian ichan = ath_hal_checkchannel(ah, chan); 1082220443Sadrian if (ichan == AH_NULL) { 1083220443Sadrian HALDEBUG(ah, HAL_DEBUG_NFCAL, 1084220443Sadrian "%s: invalid channel %u/0x%x; no mapping\n", 1085220443Sadrian __func__, chan->ic_freq, chan->ic_flags); 1086240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1087220443Sadrian nf_ctl[i] = nf_ext[i] = 0; 1088220443Sadrian } 1089220443Sadrian return 0; 1090220443Sadrian } 1091220443Sadrian 1092220443Sadrian /* Return 0 if there's no valid MIMO values (yet) */ 1093220443Sadrian if (! (ichan->privFlags & CHANNEL_MIMO_NF_VALID)) { 1094240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1095220443Sadrian nf_ctl[i] = nf_ext[i] = 0; 1096220443Sadrian } 1097220443Sadrian return 0; 1098220443Sadrian } 1099220443Sadrian if (ichan->rawNoiseFloor == 0) { 1100220443Sadrian WIRELESS_MODE mode = ath_hal_chan2wmode(ah, chan); 1101220443Sadrian HALASSERT(mode < WIRELESS_MODE_MAX); 1102220443Sadrian /* 1103220443Sadrian * See the comment below - this could cause issues for 1104220443Sadrian * stations which have a very low RSSI, below the 1105220443Sadrian * 'normalised' NF values in NOISE_FLOOR[]. 1106220443Sadrian */ 1107240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1108220443Sadrian nf_ctl[i] = nf_ext[i] = NOISE_FLOOR[mode] + 1109220443Sadrian ath_hal_getNfAdjust(ah, ichan); 1110220443Sadrian } 1111220443Sadrian return 1; 1112220443Sadrian } else { 1113220443Sadrian /* 1114220443Sadrian * The value returned here from a MIMO radio is presumed to be 1115220443Sadrian * "good enough" as a NF calculation. As RSSI values are calculated 1116220443Sadrian * against this, an adjusted NF may be higher than the RSSI value 1117220443Sadrian * returned from a vary weak station, resulting in an obscenely 1118220443Sadrian * high signal strength calculation being returned. 1119220443Sadrian * 1120220443Sadrian * This should be re-evaluated at a later date, along with any 1121220443Sadrian * signal strength calculations which are made. Quite likely the 1122220443Sadrian * RSSI values will need to be adjusted to ensure the calculations 1123220443Sadrian * don't "wrap" when RSSI is less than the "adjusted" NF value. 1124220443Sadrian * ("Adjust" here is via ichan->noiseFloorAdjust.) 1125220443Sadrian */ 1126240623Sadrian for (i = 0; i < AH_MAX_CHAINS; i++) { 1127220443Sadrian nf_ctl[i] = ichan->noiseFloorCtl[i] + ath_hal_getNfAdjust(ah, ichan); 1128220443Sadrian nf_ext[i] = ichan->noiseFloorExt[i] + ath_hal_getNfAdjust(ah, ichan); 1129220443Sadrian } 1130220443Sadrian return 1; 1131220443Sadrian } 1132221019Sadrian#else 1133221019Sadrian return 0; 1134221019Sadrian#endif /* AH_SUPPORT_AR5416 */ 1135220443Sadrian} 1136220443Sadrian 1137220443Sadrian/* 1138185377Ssam * Process all valid raw noise floors into the dBm noise floor values. 1139185377Ssam * Though our device has no reference for a dBm noise floor, we perform 1140185377Ssam * a relative minimization of NF's based on the lowest NF found across a 1141185377Ssam * channel scan. 1142185377Ssam */ 1143185377Ssamvoid 1144185377Ssamath_hal_process_noisefloor(struct ath_hal *ah) 1145185377Ssam{ 1146185377Ssam HAL_CHANNEL_INTERNAL *c; 1147185377Ssam int16_t correct2, correct5; 1148185377Ssam int16_t lowest2, lowest5; 1149185377Ssam int i; 1150185377Ssam 1151185377Ssam /* 1152185377Ssam * Find the lowest 2GHz and 5GHz noise floor values after adjusting 1153185377Ssam * for statistically recorded NF/channel deviation. 1154185377Ssam */ 1155185377Ssam correct2 = lowest2 = 0; 1156185377Ssam correct5 = lowest5 = 0; 1157185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1158185377Ssam WIRELESS_MODE mode; 1159185377Ssam int16_t nf; 1160185377Ssam 1161185377Ssam c = &AH_PRIVATE(ah)->ah_channels[i]; 1162185377Ssam if (c->rawNoiseFloor >= 0) 1163185377Ssam continue; 1164187831Ssam /* XXX can't identify proper mode */ 1165187831Ssam mode = IS_CHAN_5GHZ(c) ? WIRELESS_MODE_11a : WIRELESS_MODE_11g; 1166185377Ssam nf = c->rawNoiseFloor + NOISE_FLOOR[mode] + 1167185377Ssam ath_hal_getNfAdjust(ah, c); 1168185377Ssam if (IS_CHAN_5GHZ(c)) { 1169185377Ssam if (nf < lowest5) { 1170185377Ssam lowest5 = nf; 1171185377Ssam correct5 = NOISE_FLOOR[mode] - 1172185377Ssam (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1173185377Ssam } 1174185377Ssam } else { 1175185377Ssam if (nf < lowest2) { 1176185377Ssam lowest2 = nf; 1177185377Ssam correct2 = NOISE_FLOOR[mode] - 1178185377Ssam (c->rawNoiseFloor + ath_hal_getNfAdjust(ah, c)); 1179185377Ssam } 1180185377Ssam } 1181185377Ssam } 1182185377Ssam 1183185377Ssam /* Correct the channels to reach the expected NF value */ 1184185377Ssam for (i = 0; i < AH_PRIVATE(ah)->ah_nchan; i++) { 1185185377Ssam c = &AH_PRIVATE(ah)->ah_channels[i]; 1186185377Ssam if (c->rawNoiseFloor >= 0) 1187185377Ssam continue; 1188185377Ssam /* Apply correction factor */ 1189185377Ssam c->noiseFloorAdjust = ath_hal_getNfAdjust(ah, c) + 1190185377Ssam (IS_CHAN_5GHZ(c) ? correct5 : correct2); 1191187831Ssam HALDEBUG(ah, HAL_DEBUG_NFCAL, "%u raw nf %d adjust %d\n", 1192187831Ssam c->channel, c->rawNoiseFloor, c->noiseFloorAdjust); 1193185377Ssam } 1194185377Ssam} 1195185377Ssam 1196185377Ssam/* 1197185377Ssam * INI support routines. 1198185377Ssam */ 1199185377Ssam 1200185377Ssamint 1201185377Ssamath_hal_ini_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1202185377Ssam int col, int regWr) 1203185377Ssam{ 1204185377Ssam int r; 1205185377Ssam 1206189713Ssam HALASSERT(col < ia->cols); 1207185377Ssam for (r = 0; r < ia->rows; r++) { 1208185377Ssam OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), 1209185377Ssam HAL_INI_VAL(ia, r, col)); 1210217921Sadrian 1211217921Sadrian /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ 1212222157Sadrian if (HAL_INI_VAL(ia, r, 0) >= 0x7800 && HAL_INI_VAL(ia, r, 0) < 0x7900) 1213217921Sadrian OS_DELAY(100); 1214217921Sadrian 1215185377Ssam DMA_YIELD(regWr); 1216185377Ssam } 1217185377Ssam return regWr; 1218185377Ssam} 1219185377Ssam 1220185377Ssamvoid 1221185377Ssamath_hal_ini_bank_setup(uint32_t data[], const HAL_INI_ARRAY *ia, int col) 1222185377Ssam{ 1223185377Ssam int r; 1224185377Ssam 1225189713Ssam HALASSERT(col < ia->cols); 1226185377Ssam for (r = 0; r < ia->rows; r++) 1227185377Ssam data[r] = HAL_INI_VAL(ia, r, col); 1228185377Ssam} 1229185377Ssam 1230185377Ssamint 1231185377Ssamath_hal_ini_bank_write(struct ath_hal *ah, const HAL_INI_ARRAY *ia, 1232185377Ssam const uint32_t data[], int regWr) 1233185377Ssam{ 1234185377Ssam int r; 1235185377Ssam 1236185377Ssam for (r = 0; r < ia->rows; r++) { 1237185377Ssam OS_REG_WRITE(ah, HAL_INI_VAL(ia, r, 0), data[r]); 1238185377Ssam DMA_YIELD(regWr); 1239185377Ssam } 1240185377Ssam return regWr; 1241185377Ssam} 1242219586Sadrian 1243219586Sadrian/* 1244219586Sadrian * These are EEPROM board related routines which should likely live in 1245219586Sadrian * a helper library of some sort. 1246219586Sadrian */ 1247219586Sadrian 1248219586Sadrian/************************************************************** 1249219586Sadrian * ath_ee_getLowerUppderIndex 1250219586Sadrian * 1251219586Sadrian * Return indices surrounding the value in sorted integer lists. 1252219586Sadrian * Requirement: the input list must be monotonically increasing 1253219586Sadrian * and populated up to the list size 1254219586Sadrian * Returns: match is set if an index in the array matches exactly 1255219586Sadrian * or a the target is before or after the range of the array. 1256219586Sadrian */ 1257219586SadrianHAL_BOOL 1258219586Sadrianath_ee_getLowerUpperIndex(uint8_t target, uint8_t *pList, uint16_t listSize, 1259219586Sadrian uint16_t *indexL, uint16_t *indexR) 1260219586Sadrian{ 1261219586Sadrian uint16_t i; 1262219586Sadrian 1263219586Sadrian /* 1264219586Sadrian * Check first and last elements for beyond ordered array cases. 1265219586Sadrian */ 1266219586Sadrian if (target <= pList[0]) { 1267219586Sadrian *indexL = *indexR = 0; 1268219586Sadrian return AH_TRUE; 1269219586Sadrian } 1270219586Sadrian if (target >= pList[listSize-1]) { 1271219586Sadrian *indexL = *indexR = (uint16_t)(listSize - 1); 1272219586Sadrian return AH_TRUE; 1273219586Sadrian } 1274219586Sadrian 1275219586Sadrian /* look for value being near or between 2 values in list */ 1276219586Sadrian for (i = 0; i < listSize - 1; i++) { 1277219586Sadrian /* 1278219586Sadrian * If value is close to the current value of the list 1279219586Sadrian * then target is not between values, it is one of the values 1280219586Sadrian */ 1281219586Sadrian if (pList[i] == target) { 1282219586Sadrian *indexL = *indexR = i; 1283219586Sadrian return AH_TRUE; 1284219586Sadrian } 1285219586Sadrian /* 1286219586Sadrian * Look for value being between current value and next value 1287219586Sadrian * if so return these 2 values 1288219586Sadrian */ 1289219586Sadrian if (target < pList[i + 1]) { 1290219586Sadrian *indexL = i; 1291219586Sadrian *indexR = (uint16_t)(i + 1); 1292219586Sadrian return AH_FALSE; 1293219586Sadrian } 1294219586Sadrian } 1295219586Sadrian HALASSERT(0); 1296219586Sadrian *indexL = *indexR = 0; 1297219586Sadrian return AH_FALSE; 1298219586Sadrian} 1299219586Sadrian 1300219586Sadrian/************************************************************** 1301219586Sadrian * ath_ee_FillVpdTable 1302219586Sadrian * 1303219586Sadrian * Fill the Vpdlist for indices Pmax-Pmin 1304219586Sadrian * Note: pwrMin, pwrMax and Vpdlist are all in dBm * 4 1305219586Sadrian */ 1306219586SadrianHAL_BOOL 1307219586Sadrianath_ee_FillVpdTable(uint8_t pwrMin, uint8_t pwrMax, uint8_t *pPwrList, 1308219586Sadrian uint8_t *pVpdList, uint16_t numIntercepts, uint8_t *pRetVpdList) 1309219586Sadrian{ 1310219586Sadrian uint16_t i, k; 1311219586Sadrian uint8_t currPwr = pwrMin; 1312219586Sadrian uint16_t idxL, idxR; 1313219586Sadrian 1314219586Sadrian HALASSERT(pwrMax > pwrMin); 1315219586Sadrian for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 1316219586Sadrian ath_ee_getLowerUpperIndex(currPwr, pPwrList, numIntercepts, 1317219586Sadrian &(idxL), &(idxR)); 1318219586Sadrian if (idxR < 1) 1319219586Sadrian idxR = 1; /* extrapolate below */ 1320219586Sadrian if (idxL == numIntercepts - 1) 1321219586Sadrian idxL = (uint16_t)(numIntercepts - 2); /* extrapolate above */ 1322219586Sadrian if (pPwrList[idxL] == pPwrList[idxR]) 1323219586Sadrian k = pVpdList[idxL]; 1324219586Sadrian else 1325219586Sadrian k = (uint16_t)( ((currPwr - pPwrList[idxL]) * pVpdList[idxR] + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 1326219586Sadrian (pPwrList[idxR] - pPwrList[idxL]) ); 1327219586Sadrian HALASSERT(k < 256); 1328219586Sadrian pRetVpdList[i] = (uint8_t)k; 1329219586Sadrian currPwr += 2; /* half dB steps */ 1330219586Sadrian } 1331219586Sadrian 1332219586Sadrian return AH_TRUE; 1333219586Sadrian} 1334219586Sadrian 1335219586Sadrian/************************************************************************** 1336219586Sadrian * ath_ee_interpolate 1337219586Sadrian * 1338219586Sadrian * Returns signed interpolated or the scaled up interpolated value 1339219586Sadrian */ 1340219586Sadrianint16_t 1341219586Sadrianath_ee_interpolate(uint16_t target, uint16_t srcLeft, uint16_t srcRight, 1342219586Sadrian int16_t targetLeft, int16_t targetRight) 1343219586Sadrian{ 1344219586Sadrian int16_t rv; 1345219586Sadrian 1346219586Sadrian if (srcRight == srcLeft) { 1347219586Sadrian rv = targetLeft; 1348219586Sadrian } else { 1349219586Sadrian rv = (int16_t)( ((target - srcLeft) * targetRight + 1350219586Sadrian (srcRight - target) * targetLeft) / (srcRight - srcLeft) ); 1351219586Sadrian } 1352219586Sadrian return rv; 1353219586Sadrian} 1354225444Sadrian 1355225444Sadrian/* 1356225444Sadrian * Adjust the TSF. 1357225444Sadrian */ 1358225444Sadrianvoid 1359225444Sadrianath_hal_adjusttsf(struct ath_hal *ah, int32_t tsfdelta) 1360225444Sadrian{ 1361225444Sadrian /* XXX handle wrap/overflow */ 1362225444Sadrian OS_REG_WRITE(ah, AR_TSF_L32, OS_REG_READ(ah, AR_TSF_L32) + tsfdelta); 1363225444Sadrian} 1364225444Sadrian 1365225444Sadrian/* 1366225444Sadrian * Enable or disable CCA. 1367225444Sadrian */ 1368225444Sadrianvoid 1369225444Sadrianath_hal_setcca(struct ath_hal *ah, int ena) 1370225444Sadrian{ 1371225444Sadrian /* 1372225444Sadrian * NB: fill me in; this is not provided by default because disabling 1373225444Sadrian * CCA in most locales violates regulatory. 1374225444Sadrian */ 1375225444Sadrian} 1376225444Sadrian 1377225444Sadrian/* 1378225444Sadrian * Get CCA setting. 1379225444Sadrian */ 1380225444Sadrianint 1381225444Sadrianath_hal_getcca(struct ath_hal *ah) 1382225444Sadrian{ 1383225444Sadrian u_int32_t diag; 1384225444Sadrian if (ath_hal_getcapability(ah, HAL_CAP_DIAG, 0, &diag) != HAL_OK) 1385225444Sadrian return 1; 1386225444Sadrian return ((diag & 0x500000) == 0); 1387225444Sadrian} 1388230147Sadrian 1389230147Sadrian/* 1390230147Sadrian * This routine is only needed when supporting EEPROM-in-RAM setups 1391230147Sadrian * (eg embedded SoCs and on-board PCI/PCIe devices.) 1392230147Sadrian */ 1393230147Sadrian/* NB: This is in 16 bit words; not bytes */ 1394230147Sadrian/* XXX This doesn't belong here! */ 1395230147Sadrian#define ATH_DATA_EEPROM_SIZE 2048 1396230147Sadrian 1397230147SadrianHAL_BOOL 1398230147Sadrianath_hal_EepromDataRead(struct ath_hal *ah, u_int off, uint16_t *data) 1399230147Sadrian{ 1400230147Sadrian if (ah->ah_eepromdata == AH_NULL) { 1401230147Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, "%s: no eeprom data!\n", __func__); 1402230147Sadrian return AH_FALSE; 1403230147Sadrian } 1404230147Sadrian if (off > ATH_DATA_EEPROM_SIZE) { 1405230147Sadrian HALDEBUG(ah, HAL_DEBUG_ANY, "%s: offset %x > %x\n", 1406230147Sadrian __func__, off, ATH_DATA_EEPROM_SIZE); 1407230147Sadrian return AH_FALSE; 1408230147Sadrian } 1409230147Sadrian (*data) = ah->ah_eepromdata[off]; 1410230147Sadrian return AH_TRUE; 1411230147Sadrian} 1412252236Sadrian 1413252236Sadrian/* 1414252236Sadrian * Do a 2GHz specific MHz->IEEE based on the hardware 1415252236Sadrian * frequency. 1416252236Sadrian * 1417252236Sadrian * This is the unmapped frequency which is programmed into the hardware. 1418252236Sadrian */ 1419252236Sadrianint 1420252236Sadrianath_hal_mhz2ieee_2ghz(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) 1421252236Sadrian{ 1422252236Sadrian 1423252236Sadrian if (ichan->channel == 2484) 1424252236Sadrian return 14; 1425252236Sadrian if (ichan->channel < 2484) 1426252236Sadrian return ((int) ichan->channel - 2407) / 5; 1427252236Sadrian else 1428252236Sadrian return 15 + ((ichan->channel - 2512) / 20); 1429252236Sadrian} 1430