ar5212_misc.c revision 185380
1/* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $Id: ar5212_misc.c,v 1.12 2008/11/27 22:30:00 sam Exp $ 18 */ 19#include "opt_ah.h" 20 21#ifdef AH_SUPPORT_AR5212 22 23#include "ah.h" 24#include "ah_internal.h" 25#include "ah_devid.h" 26#ifdef AH_DEBUG 27#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 28#endif 29 30#include "ar5212/ar5212.h" 31#include "ar5212/ar5212reg.h" 32#include "ar5212/ar5212phy.h" 33#ifdef AH_SUPPORT_AR5311 34#include "ar5212/ar5311reg.h" 35#endif 36 37#include "ah_eeprom_v3.h" 38 39#define AR_NUM_GPIO 6 /* 6 GPIO pins */ 40#define AR_GPIOD_MASK 0x0000002F /* GPIO data reg r/w mask */ 41 42extern void ar5212SetRateDurationTable(struct ath_hal *, HAL_CHANNEL *); 43 44void 45ar5212GetMacAddress(struct ath_hal *ah, uint8_t *mac) 46{ 47 struct ath_hal_5212 *ahp = AH5212(ah); 48 49 OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 50} 51 52HAL_BOOL 53ar5212SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 54{ 55 struct ath_hal_5212 *ahp = AH5212(ah); 56 57 OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 58 return AH_TRUE; 59} 60 61void 62ar5212GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 63{ 64 struct ath_hal_5212 *ahp = AH5212(ah); 65 66 OS_MEMCPY(mask, ahp->ah_bssidmask, IEEE80211_ADDR_LEN); 67} 68 69HAL_BOOL 70ar5212SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 71{ 72 struct ath_hal_5212 *ahp = AH5212(ah); 73 74 /* save it since it must be rewritten on reset */ 75 OS_MEMCPY(ahp->ah_bssidmask, mask, IEEE80211_ADDR_LEN); 76 77 OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssidmask)); 78 OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssidmask + 4)); 79 return AH_TRUE; 80} 81 82/* 83 * Attempt to change the cards operating regulatory domain to the given value 84 */ 85HAL_BOOL 86ar5212SetRegulatoryDomain(struct ath_hal *ah, 87 uint16_t regDomain, HAL_STATUS *status) 88{ 89 HAL_STATUS ecode; 90 91 if (AH_PRIVATE(ah)->ah_currentRD == regDomain) { 92 ecode = HAL_EINVAL; 93 goto bad; 94 } 95 if (ath_hal_eepromGetFlag(ah, AR_EEP_WRITEPROTECT)) { 96 ecode = HAL_EEWRITE; 97 goto bad; 98 } 99#ifdef AH_SUPPORT_WRITE_REGDOMAIN 100 if (ath_hal_eepromWrite(ah, AR_EEPROM_REG_DOMAIN, regDomain)) { 101 HALDEBUG(ah, HAL_DEBUG_ANY, 102 "%s: set regulatory domain to %u (0x%x)\n", 103 __func__, regDomain, regDomain); 104 AH_PRIVATE(ah)->ah_currentRD = regDomain; 105 return AH_TRUE; 106 } 107#endif 108 ecode = HAL_EIO; 109bad: 110 if (status) 111 *status = ecode; 112 return AH_FALSE; 113} 114 115/* 116 * Return the wireless modes (a,b,g,t) supported by hardware. 117 * 118 * This value is what is actually supported by the hardware 119 * and is unaffected by regulatory/country code settings. 120 */ 121u_int 122ar5212GetWirelessModes(struct ath_hal *ah) 123{ 124 u_int mode = 0; 125 126 if (ath_hal_eepromGetFlag(ah, AR_EEP_AMODE)) { 127 mode = HAL_MODE_11A; 128 if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO5DISABLE)) 129 mode |= HAL_MODE_TURBO | HAL_MODE_108A; 130 if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 131 mode |= HAL_MODE_11A_HALF_RATE; 132 if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 133 mode |= HAL_MODE_11A_QUARTER_RATE; 134 } 135 if (ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) 136 mode |= HAL_MODE_11B; 137 if (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) && 138 AH_PRIVATE(ah)->ah_subvendorid != AR_SUBVENDOR_ID_NOG) { 139 mode |= HAL_MODE_11G; 140 if (!ath_hal_eepromGetFlag(ah, AR_EEP_TURBO2DISABLE)) 141 mode |= HAL_MODE_108G; 142 if (AH_PRIVATE(ah)->ah_caps.halChanHalfRate) 143 mode |= HAL_MODE_11G_HALF_RATE; 144 if (AH_PRIVATE(ah)->ah_caps.halChanQuarterRate) 145 mode |= HAL_MODE_11G_QUARTER_RATE; 146 } 147 return mode; 148} 149 150/* 151 * Set the interrupt and GPIO values so the ISR can disable RF 152 * on a switch signal. Assumes GPIO port and interrupt polarity 153 * are set prior to call. 154 */ 155void 156ar5212EnableRfKill(struct ath_hal *ah) 157{ 158 uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 159 int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 160 int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 161 162 /* 163 * Configure the desired GPIO port for input 164 * and enable baseband rf silence. 165 */ 166 ath_hal_gpioCfgInput(ah, select); 167 OS_REG_SET_BIT(ah, AR_PHY(0), 0x00002000); 168 /* 169 * If radio disable switch connection to GPIO bit x is enabled 170 * program GPIO interrupt. 171 * If rfkill bit on eeprom is 1, setupeeprommap routine has already 172 * verified that it is a later version of eeprom, it has a place for 173 * rfkill bit and it is set to 1, indicating that GPIO bit x hardware 174 * connection is present. 175 */ 176 ath_hal_gpioSetIntr(ah, select, 177 (ath_hal_gpioGet(ah, select) == polarity ? !polarity : polarity)); 178} 179 180/* 181 * Change the LED blinking pattern to correspond to the connectivity 182 */ 183void 184ar5212SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 185{ 186 static const uint32_t ledbits[8] = { 187 AR_PCICFG_LEDCTL_NONE, /* HAL_LED_INIT */ 188 AR_PCICFG_LEDCTL_PEND, /* HAL_LED_SCAN */ 189 AR_PCICFG_LEDCTL_PEND, /* HAL_LED_AUTH */ 190 AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_ASSOC*/ 191 AR_PCICFG_LEDCTL_ASSOC, /* HAL_LED_RUN */ 192 AR_PCICFG_LEDCTL_NONE, 193 AR_PCICFG_LEDCTL_NONE, 194 AR_PCICFG_LEDCTL_NONE, 195 }; 196 uint32_t bits; 197 198 bits = OS_REG_READ(ah, AR_PCICFG); 199 if (IS_2417(ah)) { 200 /* 201 * Enable LED for Nala. There is a bit marked reserved 202 * that must be set and we also turn on the power led. 203 * Because we mark s/w LED control setting the control 204 * status bits below is meangless (the driver must flash 205 * the LED(s) using the GPIO lines). 206 */ 207 bits = (bits &~ AR_PCICFG_LEDMODE) 208 | SM(AR_PCICFG_LEDMODE_POWON, AR_PCICFG_LEDMODE) 209#if 0 210 | SM(AR_PCICFG_LEDMODE_NETON, AR_PCICFG_LEDMODE) 211#endif 212 | 0x08000000; 213 } 214 bits = (bits &~ AR_PCICFG_LEDCTL) 215 | SM(ledbits[state & 0x7], AR_PCICFG_LEDCTL); 216 OS_REG_WRITE(ah, AR_PCICFG, bits); 217} 218 219/* 220 * Change association related fields programmed into the hardware. 221 * Writing a valid BSSID to the hardware effectively enables the hardware 222 * to synchronize its TSF to the correct beacons and receive frames coming 223 * from that BSSID. It is called by the SME JOIN operation. 224 */ 225void 226ar5212WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 227{ 228 struct ath_hal_5212 *ahp = AH5212(ah); 229 230 /* XXX save bssid for possible re-use on reset */ 231 OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 232 OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 233 OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 234 ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 235} 236 237/* 238 * Get the current hardware tsf for stamlme 239 */ 240uint64_t 241ar5212GetTsf64(struct ath_hal *ah) 242{ 243 uint32_t low1, low2, u32; 244 245 /* sync multi-word read */ 246 low1 = OS_REG_READ(ah, AR_TSF_L32); 247 u32 = OS_REG_READ(ah, AR_TSF_U32); 248 low2 = OS_REG_READ(ah, AR_TSF_L32); 249 if (low2 < low1) { /* roll over */ 250 /* 251 * If we are not preempted this will work. If we are 252 * then we re-reading AR_TSF_U32 does no good as the 253 * low bits will be meaningless. Likewise reading 254 * L32, U32, U32, then comparing the last two reads 255 * to check for rollover doesn't help if preempted--so 256 * we take this approach as it costs one less PCI read 257 * which can be noticeable when doing things like 258 * timestamping packets in monitor mode. 259 */ 260 u32++; 261 } 262 return (((uint64_t) u32) << 32) | ((uint64_t) low2); 263} 264 265/* 266 * Get the current hardware tsf for stamlme 267 */ 268uint32_t 269ar5212GetTsf32(struct ath_hal *ah) 270{ 271 return OS_REG_READ(ah, AR_TSF_L32); 272} 273 274/* 275 * Reset the current hardware tsf for stamlme. 276 */ 277void 278ar5212ResetTsf(struct ath_hal *ah) 279{ 280 281 uint32_t val = OS_REG_READ(ah, AR_BEACON); 282 283 OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 284 /* 285 * When resetting the TSF, write twice to the 286 * corresponding register; each write to the RESET_TSF bit toggles 287 * the internal signal to cause a reset of the TSF - but if the signal 288 * is left high, it will reset the TSF on the next chip reset also! 289 * writing the bit an even number of times fixes this issue 290 */ 291 OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 292} 293 294/* 295 * Set or clear hardware basic rate bit 296 * Set hardware basic rate set if basic rate is found 297 * and basic rate is equal or less than 2Mbps 298 */ 299void 300ar5212SetBasicRate(struct ath_hal *ah, HAL_RATE_SET *rs) 301{ 302 HAL_CHANNEL_INTERNAL *chan = AH_PRIVATE(ah)->ah_curchan; 303 uint32_t reg; 304 uint8_t xset; 305 int i; 306 307 if (chan == AH_NULL || !IS_CHAN_CCK(chan)) 308 return; 309 xset = 0; 310 for (i = 0; i < rs->rs_count; i++) { 311 uint8_t rset = rs->rs_rates[i]; 312 /* Basic rate defined? */ 313 if ((rset & 0x80) && (rset &= 0x7f) >= xset) 314 xset = rset; 315 } 316 /* 317 * Set the h/w bit to reflect whether or not the basic 318 * rate is found to be equal or less than 2Mbps. 319 */ 320 reg = OS_REG_READ(ah, AR_STA_ID1); 321 if (xset && xset/2 <= 2) 322 OS_REG_WRITE(ah, AR_STA_ID1, reg | AR_STA_ID1_BASE_RATE_11B); 323 else 324 OS_REG_WRITE(ah, AR_STA_ID1, reg &~ AR_STA_ID1_BASE_RATE_11B); 325} 326 327/* 328 * Grab a semi-random value from hardware registers - may not 329 * change often 330 */ 331uint32_t 332ar5212GetRandomSeed(struct ath_hal *ah) 333{ 334 uint32_t nf; 335 336 nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; 337 if (nf & 0x100) 338 nf = 0 - ((nf ^ 0x1ff) + 1); 339 return (OS_REG_READ(ah, AR_TSF_U32) ^ 340 OS_REG_READ(ah, AR_TSF_L32) ^ nf); 341} 342 343/* 344 * Detect if our card is present 345 */ 346HAL_BOOL 347ar5212DetectCardPresent(struct ath_hal *ah) 348{ 349 uint16_t macVersion, macRev; 350 uint32_t v; 351 352 /* 353 * Read the Silicon Revision register and compare that 354 * to what we read at attach time. If the same, we say 355 * a card/device is present. 356 */ 357 v = OS_REG_READ(ah, AR_SREV) & AR_SREV_ID; 358 macVersion = v >> AR_SREV_ID_S; 359 macRev = v & AR_SREV_REVISION; 360 return (AH_PRIVATE(ah)->ah_macVersion == macVersion && 361 AH_PRIVATE(ah)->ah_macRev == macRev); 362} 363 364void 365ar5212EnableMibCounters(struct ath_hal *ah) 366{ 367 /* NB: this just resets the mib counter machinery */ 368 OS_REG_WRITE(ah, AR_MIBC, 369 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); 370} 371 372void 373ar5212DisableMibCounters(struct ath_hal *ah) 374{ 375 OS_REG_WRITE(ah, AR_MIBC, AR_MIBC | AR_MIBC_CMC); 376} 377 378/* 379 * Update MIB Counters 380 */ 381void 382ar5212UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS* stats) 383{ 384 stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 385 stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 386 stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 387 stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 388 stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 389} 390 391/* 392 * Detect if the HW supports spreading a CCK signal on channel 14 393 */ 394HAL_BOOL 395ar5212IsJapanChannelSpreadSupported(struct ath_hal *ah) 396{ 397 return AH_TRUE; 398} 399 400/* 401 * Get the rssi of frame curently being received. 402 */ 403uint32_t 404ar5212GetCurRssi(struct ath_hal *ah) 405{ 406 return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 407} 408 409u_int 410ar5212GetDefAntenna(struct ath_hal *ah) 411{ 412 return (OS_REG_READ(ah, AR_DEF_ANTENNA) & 0x7); 413} 414 415void 416ar5212SetDefAntenna(struct ath_hal *ah, u_int antenna) 417{ 418 OS_REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); 419} 420 421HAL_ANT_SETTING 422ar5212GetAntennaSwitch(struct ath_hal *ah) 423{ 424 return AH5212(ah)->ah_antControl; 425} 426 427HAL_BOOL 428ar5212SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING setting) 429{ 430 struct ath_hal_5212 *ahp = AH5212(ah); 431 const HAL_CHANNEL_INTERNAL *ichan = AH_PRIVATE(ah)->ah_curchan; 432 433 if (!ahp->ah_phyPowerOn || ichan == AH_NULL) { 434 /* PHY powered off, just stash settings */ 435 ahp->ah_antControl = setting; 436 ahp->ah_diversity = (setting == HAL_ANT_VARIABLE); 437 return AH_TRUE; 438 } 439 return ar5212SetAntennaSwitchInternal(ah, setting, ichan); 440} 441 442HAL_BOOL 443ar5212IsSleepAfterBeaconBroken(struct ath_hal *ah) 444{ 445 return AH_TRUE; 446} 447 448HAL_BOOL 449ar5212SetSifsTime(struct ath_hal *ah, u_int us) 450{ 451 struct ath_hal_5212 *ahp = AH5212(ah); 452 453 if (us > ath_hal_mac_usec(ah, 0xffff)) { 454 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 455 __func__, us); 456 ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 457 return AH_FALSE; 458 } else { 459 /* convert to system clocks */ 460 OS_REG_WRITE(ah, AR_D_GBL_IFS_SIFS, ath_hal_mac_clks(ah, us)); 461 ahp->ah_slottime = us; 462 return AH_TRUE; 463 } 464} 465 466u_int 467ar5212GetSifsTime(struct ath_hal *ah) 468{ 469 u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SIFS) & 0xffff; 470 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 471} 472 473HAL_BOOL 474ar5212SetSlotTime(struct ath_hal *ah, u_int us) 475{ 476 struct ath_hal_5212 *ahp = AH5212(ah); 477 478 if (us < HAL_SLOT_TIME_6 || us > ath_hal_mac_usec(ah, 0xffff)) { 479 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 480 __func__, us); 481 ahp->ah_slottime = (u_int) -1; /* restore default handling */ 482 return AH_FALSE; 483 } else { 484 /* convert to system clocks */ 485 OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath_hal_mac_clks(ah, us)); 486 ahp->ah_slottime = us; 487 return AH_TRUE; 488 } 489} 490 491u_int 492ar5212GetSlotTime(struct ath_hal *ah) 493{ 494 u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; 495 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 496} 497 498HAL_BOOL 499ar5212SetAckTimeout(struct ath_hal *ah, u_int us) 500{ 501 struct ath_hal_5212 *ahp = AH5212(ah); 502 503 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 504 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 505 __func__, us); 506 ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 507 return AH_FALSE; 508 } else { 509 /* convert to system clocks */ 510 OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 511 AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 512 ahp->ah_acktimeout = us; 513 return AH_TRUE; 514 } 515} 516 517u_int 518ar5212GetAckTimeout(struct ath_hal *ah) 519{ 520 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 521 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 522} 523 524u_int 525ar5212GetAckCTSRate(struct ath_hal *ah) 526{ 527 return ((AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 528} 529 530HAL_BOOL 531ar5212SetAckCTSRate(struct ath_hal *ah, u_int high) 532{ 533 struct ath_hal_5212 *ahp = AH5212(ah); 534 535 if (high) { 536 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 537 ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 538 } else { 539 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 540 ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 541 } 542 return AH_TRUE; 543} 544 545HAL_BOOL 546ar5212SetCTSTimeout(struct ath_hal *ah, u_int us) 547{ 548 struct ath_hal_5212 *ahp = AH5212(ah); 549 550 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 551 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 552 __func__, us); 553 ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 554 return AH_FALSE; 555 } else { 556 /* convert to system clocks */ 557 OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 558 AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 559 ahp->ah_ctstimeout = us; 560 return AH_TRUE; 561 } 562} 563 564u_int 565ar5212GetCTSTimeout(struct ath_hal *ah) 566{ 567 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 568 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 569} 570 571/* Setup decompression for given key index */ 572HAL_BOOL 573ar5212SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 574{ 575 struct ath_hal_5212 *ahp = AH5212(ah); 576 577 if (keyidx >= HAL_DECOMP_MASK_SIZE) 578 return HAL_EINVAL; 579 OS_REG_WRITE(ah, AR_DCM_A, keyidx); 580 OS_REG_WRITE(ah, AR_DCM_D, en ? AR_DCM_D_EN : 0); 581 ahp->ah_decompMask[keyidx] = en; 582 583 return AH_TRUE; 584} 585 586/* Setup coverage class */ 587void 588ar5212SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 589{ 590 uint32_t slot, timeout, eifs; 591 u_int clkRate; 592 593 AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 594 595 if (now) { 596 if (AH_PRIVATE(ah)->ah_coverageClass == 0) 597 return; 598 599 /* Don't apply coverage class to non A channels */ 600 if (!IS_CHAN_A(AH_PRIVATE(ah)->ah_curchan)) 601 return; 602 603 /* Get core clock rate */ 604 clkRate = ath_hal_mac_clks(ah, 1); 605 606 /* Compute EIFS */ 607 slot = coverageclass * 3 * clkRate; 608 eifs = coverageclass * 6 * clkRate; 609 if (IS_CHAN_HALF_RATE(AH_PRIVATE(ah)->ah_curchan)) { 610 slot += IFS_SLOT_HALF_RATE; 611 eifs += IFS_EIFS_HALF_RATE; 612 } else if (IS_CHAN_QUARTER_RATE(AH_PRIVATE(ah)->ah_curchan)) { 613 slot += IFS_SLOT_QUARTER_RATE; 614 eifs += IFS_EIFS_QUARTER_RATE; 615 } else { /* full rate */ 616 slot += IFS_SLOT_FULL_RATE; 617 eifs += IFS_EIFS_FULL_RATE; 618 } 619 620 /* 621 * Add additional time for air propagation for ACK and CTS 622 * timeouts. This value is in core clocks. 623 */ 624 timeout = ACK_CTS_TIMEOUT_11A + (coverageclass * 3 * clkRate); 625 626 /* 627 * Write the values: slot, eifs, ack/cts timeouts. 628 */ 629 OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); 630 OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); 631 OS_REG_WRITE(ah, AR_TIME_OUT, 632 SM(timeout, AR_TIME_OUT_CTS) 633 | SM(timeout, AR_TIME_OUT_ACK)); 634 } 635} 636 637void 638ar5212SetPCUConfig(struct ath_hal *ah) 639{ 640 ar5212SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); 641} 642 643/* 644 * Return whether an external 32KHz crystal should be used 645 * to reduce power consumption when sleeping. We do so if 646 * the crystal is present (obtained from EEPROM) and if we 647 * are not running as an AP and are configured to use it. 648 */ 649HAL_BOOL 650ar5212Use32KHzclock(struct ath_hal *ah, HAL_OPMODE opmode) 651{ 652 if (opmode != HAL_M_HOSTAP) { 653 struct ath_hal_5212 *ahp = AH5212(ah); 654 return ath_hal_eepromGetFlag(ah, AR_EEP_32KHZCRYSTAL) && 655 (ahp->ah_enable32kHzClock == USE_32KHZ || 656 ahp->ah_enable32kHzClock == AUTO_32KHZ); 657 } else 658 return AH_FALSE; 659} 660 661/* 662 * If 32KHz clock exists, use it to lower power consumption during sleep 663 * 664 * Note: If clock is set to 32 KHz, delays on accessing certain 665 * baseband registers (27-31, 124-127) are required. 666 */ 667void 668ar5212SetupClock(struct ath_hal *ah, HAL_OPMODE opmode) 669{ 670 if (ar5212Use32KHzclock(ah, opmode)) { 671 /* 672 * Enable clocks to be turned OFF in BB during sleep 673 * and also enable turning OFF 32MHz/40MHz Refclk 674 * from A2. 675 */ 676 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 677 OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 678 IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 679 OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 1); 680 OS_REG_WRITE(ah, AR_TSF_PARM, 61); /* 32 KHz TSF incr */ 681 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 1); 682 683 if (IS_2413(ah) || IS_5413(ah) || IS_2417(ah)) { 684 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x26); 685 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0d); 686 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x07); 687 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x3f); 688 /* # Set sleep clock rate to 32 KHz. */ 689 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x2); 690 } else { 691 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x0a); 692 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0c); 693 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x03); 694 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0x20); 695 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x3); 696 } 697 } else { 698 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0x0); 699 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 700 701 OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32MHz TSF inc */ 702 703 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 704 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 705 706 if (IS_2417(ah)) 707 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0a); 708 else if (IS_HB63(ah)) 709 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x32); 710 else 711 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 712 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 713 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 714 OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 715 IS_RAD5112_ANY(ah) || IS_5413(ah) || IS_2417(ah) ? 0x14 : 0x18); 716 OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 717 IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 718 } 719} 720 721/* 722 * If 32KHz clock exists, turn it off and turn back on the 32Mhz 723 */ 724void 725ar5212RestoreClock(struct ath_hal *ah, HAL_OPMODE opmode) 726{ 727 if (ar5212Use32KHzclock(ah, opmode)) { 728 /* # Set sleep clock rate back to 32 MHz. */ 729 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_RATE_IND, 0); 730 OS_REG_RMW_FIELD(ah, AR_PCICFG, AR_PCICFG_SCLK_SEL, 0); 731 732 OS_REG_WRITE(ah, AR_TSF_PARM, 1); /* 32 MHz TSF incr */ 733 OS_REG_RMW_FIELD(ah, AR_USEC, AR_USEC_USEC32, 734 IS_RAD5112_ANY(ah) || IS_5413(ah) ? 39 : 31); 735 736 /* 737 * Restore BB registers to power-on defaults 738 */ 739 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_CONTROL, 0x1f); 740 OS_REG_WRITE(ah, AR_PHY_SLEEP_CTR_LIMIT, 0x7f); 741 OS_REG_WRITE(ah, AR_PHY_SLEEP_SCAL, 0x0e); 742 OS_REG_WRITE(ah, AR_PHY_M_SLEEP, 0x0c); 743 OS_REG_WRITE(ah, AR_PHY_REFCLKDLY, 0xff); 744 OS_REG_WRITE(ah, AR_PHY_REFCLKPD, 745 IS_RAD5112_ANY(ah) || IS_5413(ah) ? 0x14 : 0x18); 746 } 747} 748 749/* 750 * Adjust NF based on statistical values for 5GHz frequencies. 751 * Default method: this may be overridden by the rf backend. 752 */ 753int16_t 754ar5212GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) 755{ 756 static const struct { 757 uint16_t freqLow; 758 int16_t adjust; 759 } adjustDef[] = { 760 { 5790, 11 }, /* NB: ordered high -> low */ 761 { 5730, 10 }, 762 { 5690, 9 }, 763 { 5660, 8 }, 764 { 5610, 7 }, 765 { 5530, 5 }, 766 { 5450, 4 }, 767 { 5379, 2 }, 768 { 5209, 0 }, 769 { 3000, 1 }, 770 { 0, 0 }, 771 }; 772 int i; 773 774 for (i = 0; c->channel <= adjustDef[i].freqLow; i++) 775 ; 776 return adjustDef[i].adjust; 777} 778 779HAL_STATUS 780ar5212GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 781 uint32_t capability, uint32_t *result) 782{ 783#define MACVERSION(ah) AH_PRIVATE(ah)->ah_macVersion 784 struct ath_hal_5212 *ahp = AH5212(ah); 785 const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 786 const struct ar5212AniState *ani; 787 788 switch (type) { 789 case HAL_CAP_CIPHER: /* cipher handled in hardware */ 790 switch (capability) { 791 case HAL_CIPHER_AES_CCM: 792 return pCap->halCipherAesCcmSupport ? 793 HAL_OK : HAL_ENOTSUPP; 794 case HAL_CIPHER_AES_OCB: 795 case HAL_CIPHER_TKIP: 796 case HAL_CIPHER_WEP: 797 case HAL_CIPHER_MIC: 798 case HAL_CIPHER_CLR: 799 return HAL_OK; 800 default: 801 return HAL_ENOTSUPP; 802 } 803 case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 804 switch (capability) { 805 case 0: /* hardware capability */ 806 return HAL_OK; 807 case 1: 808 return (ahp->ah_staId1Defaults & 809 AR_STA_ID1_CRPT_MIC_ENABLE) ? HAL_OK : HAL_ENXIO; 810 } 811 case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 812 switch (capability) { 813 case 0: /* hardware capability */ 814 return pCap->halTkipMicTxRxKeySupport ? 815 HAL_ENXIO : HAL_OK; 816 case 1: /* current setting */ 817 return (ahp->ah_miscMode & 818 AR_MISC_MODE_MIC_NEW_LOC_ENABLE) ? HAL_ENXIO : HAL_OK; 819 } 820 return HAL_EINVAL; 821 case HAL_CAP_WME_TKIPMIC: /* hardware can do TKIP MIC w/ WMM */ 822 /* XXX move to capability bit */ 823 return MACVERSION(ah) > AR_SREV_VERSION_VENICE || 824 (MACVERSION(ah) == AR_SREV_VERSION_VENICE && 825 AH_PRIVATE(ah)->ah_macRev >= 8) ? HAL_OK : HAL_ENOTSUPP; 826 case HAL_CAP_DIVERSITY: /* hardware supports fast diversity */ 827 switch (capability) { 828 case 0: /* hardware capability */ 829 return HAL_OK; 830 case 1: /* current setting */ 831 return ahp->ah_diversity ? HAL_OK : HAL_ENXIO; 832 } 833 return HAL_EINVAL; 834 case HAL_CAP_DIAG: 835 *result = AH_PRIVATE(ah)->ah_diagreg; 836 return HAL_OK; 837 case HAL_CAP_TPC: 838 switch (capability) { 839 case 0: /* hardware capability */ 840 return HAL_OK; 841 case 1: 842 return ahp->ah_tpcEnabled ? HAL_OK : HAL_ENXIO; 843 } 844 return HAL_OK; 845 case HAL_CAP_PHYDIAG: /* radar pulse detection capability */ 846 switch (capability) { 847 case HAL_CAP_RADAR: 848 return ath_hal_eepromGetFlag(ah, AR_EEP_AMODE) ? 849 HAL_OK: HAL_ENXIO; 850 case HAL_CAP_AR: 851 return (ath_hal_eepromGetFlag(ah, AR_EEP_GMODE) || 852 ath_hal_eepromGetFlag(ah, AR_EEP_BMODE)) ? 853 HAL_OK: HAL_ENXIO; 854 } 855 return HAL_ENXIO; 856 case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 857 switch (capability) { 858 case 0: /* hardware capability */ 859 return HAL_OK; 860 case 1: 861 return (ahp->ah_staId1Defaults & 862 AR_STA_ID1_MCAST_KSRCH) ? HAL_OK : HAL_ENXIO; 863 } 864 return HAL_EINVAL; 865 case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 866 switch (capability) { 867 case 0: /* hardware capability */ 868 return pCap->halTsfAddSupport ? HAL_OK : HAL_ENOTSUPP; 869 case 1: 870 return (ahp->ah_miscMode & AR_MISC_MODE_TX_ADD_TSF) ? 871 HAL_OK : HAL_ENXIO; 872 } 873 return HAL_EINVAL; 874 case HAL_CAP_TPC_ACK: 875 *result = MS(ahp->ah_macTPC, AR_TPC_ACK); 876 return HAL_OK; 877 case HAL_CAP_TPC_CTS: 878 *result = MS(ahp->ah_macTPC, AR_TPC_CTS); 879 return HAL_OK; 880 case HAL_CAP_INTMIT: /* interference mitigation */ 881 switch (capability) { 882 case 0: /* hardware capability */ 883 return HAL_OK; 884 case 1: 885 return (ahp->ah_procPhyErr & HAL_ANI_ENA) ? 886 HAL_OK : HAL_ENXIO; 887 case 2: /* HAL_ANI_NOISE_IMMUNITY_LEVEL */ 888 case 3: /* HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION */ 889 case 4: /* HAL_ANI_CCK_WEAK_SIGNAL_THR */ 890 case 5: /* HAL_ANI_FIRSTEP_LEVEL */ 891 case 6: /* HAL_ANI_SPUR_IMMUNITY_LEVEL */ 892 ani = ar5212AniGetCurrentState(ah); 893 if (ani == AH_NULL) 894 return HAL_ENXIO; 895 switch (capability) { 896 case 2: *result = ani->noiseImmunityLevel; break; 897 case 3: *result = !ani->ofdmWeakSigDetectOff; break; 898 case 4: *result = ani->cckWeakSigThreshold; break; 899 case 5: *result = ani->firstepLevel; break; 900 case 6: *result = ani->spurImmunityLevel; break; 901 } 902 return HAL_OK; 903 } 904 return HAL_EINVAL; 905 default: 906 return ath_hal_getcapability(ah, type, capability, result); 907 } 908#undef MACVERSION 909} 910 911HAL_BOOL 912ar5212SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 913 uint32_t capability, uint32_t setting, HAL_STATUS *status) 914{ 915#define N(a) (sizeof(a)/sizeof(a[0])) 916 struct ath_hal_5212 *ahp = AH5212(ah); 917 const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 918 uint32_t v; 919 920 switch (type) { 921 case HAL_CAP_TKIP_MIC: /* handle TKIP MIC in hardware */ 922 if (setting) 923 ahp->ah_staId1Defaults |= AR_STA_ID1_CRPT_MIC_ENABLE; 924 else 925 ahp->ah_staId1Defaults &= ~AR_STA_ID1_CRPT_MIC_ENABLE; 926 return AH_TRUE; 927 case HAL_CAP_TKIP_SPLIT: /* hardware TKIP uses split keys */ 928 if (!pCap->halTkipMicTxRxKeySupport) 929 return AH_FALSE; 930 /* NB: true =>'s use split key cache layout */ 931 if (setting) 932 ahp->ah_miscMode &= ~AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 933 else 934 ahp->ah_miscMode |= AR_MISC_MODE_MIC_NEW_LOC_ENABLE; 935 /* NB: write here so keys can be setup w/o a reset */ 936 OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); 937 return AH_TRUE; 938 case HAL_CAP_DIVERSITY: 939 if (ahp->ah_phyPowerOn) { 940 v = OS_REG_READ(ah, AR_PHY_CCK_DETECT); 941 if (setting) 942 v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 943 else 944 v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 945 OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, v); 946 } 947 ahp->ah_diversity = (setting != 0); 948 return AH_TRUE; 949 case HAL_CAP_DIAG: /* hardware diagnostic support */ 950 /* 951 * NB: could split this up into virtual capabilities, 952 * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 953 * seems worth the additional complexity. 954 */ 955 AH_PRIVATE(ah)->ah_diagreg = setting; 956 OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 957 return AH_TRUE; 958 case HAL_CAP_TPC: 959 ahp->ah_tpcEnabled = (setting != 0); 960 return AH_TRUE; 961 case HAL_CAP_MCAST_KEYSRCH: /* multicast frame keycache search */ 962 if (setting) 963 ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; 964 else 965 ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; 966 return AH_TRUE; 967 case HAL_CAP_TPC_ACK: 968 case HAL_CAP_TPC_CTS: 969 setting += ahp->ah_txPowerIndexOffset; 970 if (setting > 63) 971 setting = 63; 972 if (type == HAL_CAP_TPC_ACK) { 973 ahp->ah_macTPC &= AR_TPC_ACK; 974 ahp->ah_macTPC |= MS(setting, AR_TPC_ACK); 975 } else { 976 ahp->ah_macTPC &= AR_TPC_CTS; 977 ahp->ah_macTPC |= MS(setting, AR_TPC_CTS); 978 } 979 OS_REG_WRITE(ah, AR_TPC, ahp->ah_macTPC); 980 return AH_TRUE; 981 case HAL_CAP_INTMIT: { /* interference mitigation */ 982 static const HAL_ANI_CMD cmds[] = { 983 HAL_ANI_PRESENT, 984 HAL_ANI_MODE, 985 HAL_ANI_NOISE_IMMUNITY_LEVEL, 986 HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, 987 HAL_ANI_CCK_WEAK_SIGNAL_THR, 988 HAL_ANI_FIRSTEP_LEVEL, 989 HAL_ANI_SPUR_IMMUNITY_LEVEL, 990 }; 991 return capability < N(cmds) ? 992 ar5212AniControl(ah, cmds[capability], setting) : 993 AH_FALSE; 994 } 995 case HAL_CAP_TSF_ADJUST: /* hardware has beacon tsf adjust */ 996 if (pCap->halTsfAddSupport) { 997 if (setting) 998 ahp->ah_miscMode |= AR_MISC_MODE_TX_ADD_TSF; 999 else 1000 ahp->ah_miscMode &= ~AR_MISC_MODE_TX_ADD_TSF; 1001 return AH_TRUE; 1002 } 1003 /* fall thru... */ 1004 default: 1005 return ath_hal_setcapability(ah, type, capability, 1006 setting, status); 1007 } 1008#undef N 1009} 1010 1011HAL_BOOL 1012ar5212GetDiagState(struct ath_hal *ah, int request, 1013 const void *args, uint32_t argsize, 1014 void **result, uint32_t *resultsize) 1015{ 1016 struct ath_hal_5212 *ahp = AH5212(ah); 1017 1018 (void) ahp; 1019 if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 1020 return AH_TRUE; 1021 switch (request) { 1022 case HAL_DIAG_EEPROM: 1023 case HAL_DIAG_EEPROM_EXP_11A: 1024 case HAL_DIAG_EEPROM_EXP_11B: 1025 case HAL_DIAG_EEPROM_EXP_11G: 1026 case HAL_DIAG_RFGAIN: 1027 return ath_hal_eepromDiag(ah, request, 1028 args, argsize, result, resultsize); 1029 case HAL_DIAG_RFGAIN_CURSTEP: 1030 *result = __DECONST(void *, ahp->ah_gainValues.currStep); 1031 *resultsize = (*result == AH_NULL) ? 1032 0 : sizeof(GAIN_OPTIMIZATION_STEP); 1033 return AH_TRUE; 1034 case HAL_DIAG_PCDAC: 1035 *result = ahp->ah_pcdacTable; 1036 *resultsize = ahp->ah_pcdacTableSize; 1037 return AH_TRUE; 1038 case HAL_DIAG_TXRATES: 1039 *result = &ahp->ah_ratesArray[0]; 1040 *resultsize = sizeof(ahp->ah_ratesArray); 1041 return AH_TRUE; 1042 case HAL_DIAG_ANI_CURRENT: 1043 *result = ar5212AniGetCurrentState(ah); 1044 *resultsize = (*result == AH_NULL) ? 1045 0 : sizeof(struct ar5212AniState); 1046 return AH_TRUE; 1047 case HAL_DIAG_ANI_STATS: 1048 *result = ar5212AniGetCurrentStats(ah); 1049 *resultsize = (*result == AH_NULL) ? 1050 0 : sizeof(struct ar5212Stats); 1051 return AH_TRUE; 1052 case HAL_DIAG_ANI_CMD: 1053 if (argsize != 2*sizeof(uint32_t)) 1054 return AH_FALSE; 1055 ar5212AniControl(ah, ((const uint32_t *)args)[0], 1056 ((const uint32_t *)args)[1]); 1057 return AH_TRUE; 1058 case HAL_DIAG_ANI_PARAMS: 1059 /* 1060 * NB: We assume struct ar5212AniParams is identical 1061 * to HAL_ANI_PARAMS; if they diverge then we'll need 1062 * to handle it here 1063 */ 1064 if (argsize == 0 && args == AH_NULL) { 1065 struct ar5212AniState *aniState = 1066 ar5212AniGetCurrentState(ah); 1067 if (aniState == AH_NULL) 1068 return AH_FALSE; 1069 *result = __DECONST(void *, aniState->params); 1070 *resultsize = sizeof(struct ar5212AniParams); 1071 return AH_TRUE; 1072 } else { 1073 if (argsize != sizeof(struct ar5212AniParams)) 1074 return AH_FALSE; 1075 return ar5212AniSetParams(ah, args, args); 1076 } 1077 } 1078 return AH_FALSE; 1079} 1080#endif /* AH_SUPPORT_AR5212 */ 1081