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