ar5210_misc.c revision 185377
1/* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2004 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: ar5210_misc.c,v 1.4 2008/11/10 04:08:02 sam Exp $ 18 */ 19#include "opt_ah.h" 20 21#ifdef AH_SUPPORT_AR5210 22 23#include "ah.h" 24#include "ah_internal.h" 25 26#include "ar5210/ar5210.h" 27#include "ar5210/ar5210reg.h" 28#include "ar5210/ar5210phy.h" 29 30#define AR_NUM_GPIO 6 /* 6 GPIO bits */ 31#define AR_GPIOD_MASK 0x2f /* 6-bit mask */ 32 33void 34ar5210GetMacAddress(struct ath_hal *ah, uint8_t *mac) 35{ 36 struct ath_hal_5210 *ahp = AH5210(ah); 37 38 OS_MEMCPY(mac, ahp->ah_macaddr, IEEE80211_ADDR_LEN); 39} 40 41HAL_BOOL 42ar5210SetMacAddress(struct ath_hal *ah, const uint8_t *mac) 43{ 44 struct ath_hal_5210 *ahp = AH5210(ah); 45 46 OS_MEMCPY(ahp->ah_macaddr, mac, IEEE80211_ADDR_LEN); 47 return AH_TRUE; 48} 49 50void 51ar5210GetBssIdMask(struct ath_hal *ah, uint8_t *mask) 52{ 53 static const uint8_t ones[IEEE80211_ADDR_LEN] = 54 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 55 OS_MEMCPY(mask, ones, IEEE80211_ADDR_LEN); 56} 57 58HAL_BOOL 59ar5210SetBssIdMask(struct ath_hal *ah, const uint8_t *mask) 60{ 61 return AH_FALSE; 62} 63 64/* 65 * Read 16 bits of data from the specified EEPROM offset. 66 */ 67HAL_BOOL 68ar5210EepromRead(struct ath_hal *ah, u_int off, uint16_t *data) 69{ 70 (void) OS_REG_READ(ah, AR_EP_AIR(off)); /* activate read op */ 71 if (!ath_hal_wait(ah, AR_EP_STA, 72 AR_EP_STA_RDCMPLT | AR_EP_STA_RDERR, AR_EP_STA_RDCMPLT)) { 73 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: read failed for entry 0x%x\n", 74 __func__, AR_EP_AIR(off)); 75 return AH_FALSE; 76 } 77 *data = OS_REG_READ(ah, AR_EP_RDATA) & 0xffff; 78 return AH_TRUE; 79} 80 81/* 82 * Return the wireless modes (a,b,g,t) supported by hardware. 83 * 84 * This value is what is actually supported by the hardware 85 * and is unaffected by regulatory/country code settings. 86 * 87 */ 88u_int 89ar5210GetWirelessModes(struct ath_hal *ah) 90{ 91 /* XXX could enable turbo mode but can't do all rates */ 92 return HAL_MODE_11A; 93} 94 95/* 96 * Called if RfKill is supported (according to EEPROM). Set the interrupt and 97 * GPIO values so the ISR and can disable RF on a switch signal 98 */ 99void 100ar5210EnableRfKill(struct ath_hal *ah) 101{ 102 uint16_t rfsilent = AH_PRIVATE(ah)->ah_rfsilent; 103 int select = MS(rfsilent, AR_EEPROM_RFSILENT_GPIO_SEL); 104 int polarity = MS(rfsilent, AR_EEPROM_RFSILENT_POLARITY); 105 106 /* 107 * If radio disable switch connection to GPIO bit 0 is enabled 108 * program GPIO interrupt. 109 * If rfkill bit on eeprom is 1, setupeeprommap routine has already 110 * verified that it is a later version of eeprom, it has a place for 111 * rfkill bit and it is set to 1, indicating that GPIO bit 0 hardware 112 * connection is present. 113 */ 114 ar5210Gpio0SetIntr(ah, select, (ar5210GpioGet(ah, select) == polarity)); 115} 116 117/* 118 * Configure GPIO Output lines 119 */ 120HAL_BOOL 121ar5210GpioCfgOutput(struct ath_hal *ah, uint32_t gpio) 122{ 123 HALASSERT(gpio < AR_NUM_GPIO); 124 125 OS_REG_WRITE(ah, AR_GPIOCR, 126 (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio)) 127 | AR_GPIOCR_OUT1(gpio)); 128 129 return AH_TRUE; 130} 131 132/* 133 * Configure GPIO Input lines 134 */ 135HAL_BOOL 136ar5210GpioCfgInput(struct ath_hal *ah, uint32_t gpio) 137{ 138 HALASSERT(gpio < AR_NUM_GPIO); 139 140 OS_REG_WRITE(ah, AR_GPIOCR, 141 (OS_REG_READ(ah, AR_GPIOCR) &~ AR_GPIOCR_ALL(gpio)) 142 | AR_GPIOCR_IN(gpio)); 143 144 return AH_TRUE; 145} 146 147/* 148 * Once configured for I/O - set output lines 149 */ 150HAL_BOOL 151ar5210GpioSet(struct ath_hal *ah, uint32_t gpio, uint32_t val) 152{ 153 uint32_t reg; 154 155 HALASSERT(gpio < AR_NUM_GPIO); 156 157 reg = OS_REG_READ(ah, AR_GPIODO); 158 reg &= ~(1 << gpio); 159 reg |= (val&1) << gpio; 160 161 OS_REG_WRITE(ah, AR_GPIODO, reg); 162 return AH_TRUE; 163} 164 165/* 166 * Once configured for I/O - get input lines 167 */ 168uint32_t 169ar5210GpioGet(struct ath_hal *ah, uint32_t gpio) 170{ 171 if (gpio < AR_NUM_GPIO) { 172 uint32_t val = OS_REG_READ(ah, AR_GPIODI); 173 val = ((val & AR_GPIOD_MASK) >> gpio) & 0x1; 174 return val; 175 } else { 176 return 0xffffffff; 177 } 178} 179 180/* 181 * Set the GPIO 0 Interrupt 182 */ 183void 184ar5210Gpio0SetIntr(struct ath_hal *ah, u_int gpio, uint32_t ilevel) 185{ 186 uint32_t val = OS_REG_READ(ah, AR_GPIOCR); 187 188 /* Clear the bits that we will modify. */ 189 val &= ~(AR_GPIOCR_INT_SEL(gpio) | AR_GPIOCR_INT_SELH | AR_GPIOCR_INT_ENA | 190 AR_GPIOCR_ALL(gpio)); 191 192 val |= AR_GPIOCR_INT_SEL(gpio) | AR_GPIOCR_INT_ENA; 193 if (ilevel) 194 val |= AR_GPIOCR_INT_SELH; 195 196 /* Don't need to change anything for low level interrupt. */ 197 OS_REG_WRITE(ah, AR_GPIOCR, val); 198 199 /* Change the interrupt mask. */ 200 ar5210SetInterrupts(ah, AH5210(ah)->ah_maskReg | HAL_INT_GPIO); 201} 202 203/* 204 * Change the LED blinking pattern to correspond to the connectivity 205 */ 206void 207ar5210SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 208{ 209 uint32_t val; 210 211 val = OS_REG_READ(ah, AR_PCICFG); 212 switch (state) { 213 case HAL_LED_INIT: 214 val &= ~(AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT); 215 break; 216 case HAL_LED_RUN: 217 /* normal blink when connected */ 218 val &= ~AR_PCICFG_LED_PEND; 219 val |= AR_PCICFG_LED_ACT; 220 break; 221 default: 222 val |= AR_PCICFG_LED_PEND; 223 val &= ~AR_PCICFG_LED_ACT; 224 break; 225 } 226 OS_REG_WRITE(ah, AR_PCICFG, val); 227} 228 229/* 230 * Return 1 or 2 for the corresponding antenna that is in use 231 */ 232u_int 233ar5210GetDefAntenna(struct ath_hal *ah) 234{ 235 uint32_t val = OS_REG_READ(ah, AR_STA_ID1); 236 return (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1); 237} 238 239void 240ar5210SetDefAntenna(struct ath_hal *ah, u_int antenna) 241{ 242 uint32_t val = OS_REG_READ(ah, AR_STA_ID1); 243 244 if (antenna != (val & AR_STA_ID1_DEFAULT_ANTENNA ? 2 : 1)) { 245 /* 246 * Antenna change requested, force a toggle of the default. 247 */ 248 OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_DEFAULT_ANTENNA); 249 } 250} 251 252HAL_ANT_SETTING 253ar5210GetAntennaSwitch(struct ath_hal *ah) 254{ 255 return HAL_ANT_VARIABLE; 256} 257 258HAL_BOOL 259ar5210SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 260{ 261 /* XXX not sure how to fix antenna */ 262 return (settings == HAL_ANT_VARIABLE); 263} 264 265/* 266 * Change association related fields programmed into the hardware. 267 * Writing a valid BSSID to the hardware effectively enables the hardware 268 * to synchronize its TSF to the correct beacons and receive frames coming 269 * from that BSSID. It is called by the SME JOIN operation. 270 */ 271void 272ar5210WriteAssocid(struct ath_hal *ah, const uint8_t *bssid, uint16_t assocId) 273{ 274 struct ath_hal_5210 *ahp = AH5210(ah); 275 276 /* XXX save bssid for possible re-use on reset */ 277 OS_MEMCPY(ahp->ah_bssid, bssid, IEEE80211_ADDR_LEN); 278 OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); 279 OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid+4) | 280 ((assocId & 0x3fff)<<AR_BSS_ID1_AID_S)); 281 if (assocId == 0) 282 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL); 283 else 284 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_NO_PSPOLL); 285} 286 287/* 288 * Get the current hardware tsf for stamlme. 289 */ 290uint64_t 291ar5210GetTsf64(struct ath_hal *ah) 292{ 293 uint32_t low1, low2, u32; 294 295 /* sync multi-word read */ 296 low1 = OS_REG_READ(ah, AR_TSF_L32); 297 u32 = OS_REG_READ(ah, AR_TSF_U32); 298 low2 = OS_REG_READ(ah, AR_TSF_L32); 299 if (low2 < low1) { /* roll over */ 300 /* 301 * If we are not preempted this will work. If we are 302 * then we re-reading AR_TSF_U32 does no good as the 303 * low bits will be meaningless. Likewise reading 304 * L32, U32, U32, then comparing the last two reads 305 * to check for rollover 306 * doesn't help if preempted--so we take this approach 307 * as it costs one less PCI read which can be noticeable 308 * when doing things like timestamping packets in 309 * monitor mode. 310 */ 311 u32++; 312 } 313 return (((uint64_t) u32) << 32) | ((uint64_t) low2); 314} 315 316/* 317 * Get the current hardware tsf for stamlme. 318 */ 319uint32_t 320ar5210GetTsf32(struct ath_hal *ah) 321{ 322 return OS_REG_READ(ah, AR_TSF_L32); 323} 324 325/* 326 * Reset the current hardware tsf for stamlme 327 */ 328void 329ar5210ResetTsf(struct ath_hal *ah) 330{ 331 uint32_t val = OS_REG_READ(ah, AR_BEACON); 332 333 OS_REG_WRITE(ah, AR_BEACON, val | AR_BEACON_RESET_TSF); 334} 335 336/* 337 * Grab a semi-random value from hardware registers - may not 338 * change often 339 */ 340uint32_t 341ar5210GetRandomSeed(struct ath_hal *ah) 342{ 343 uint32_t nf; 344 345 nf = (OS_REG_READ(ah, AR_PHY_BASE + (25 << 2)) >> 19) & 0x1ff; 346 if (nf & 0x100) 347 nf = 0 - ((nf ^ 0x1ff) + 1); 348 return (OS_REG_READ(ah, AR_TSF_U32) ^ 349 OS_REG_READ(ah, AR_TSF_L32) ^ nf); 350} 351 352/* 353 * Detect if our card is present 354 */ 355HAL_BOOL 356ar5210DetectCardPresent(struct ath_hal *ah) 357{ 358 /* 359 * Read the Silicon Revision register and compare that 360 * to what we read at attach time. If the same, we say 361 * a card/device is present. 362 */ 363 return (AH_PRIVATE(ah)->ah_macRev == (OS_REG_READ(ah, AR_SREV) & 0xff)); 364} 365 366/* 367 * Update MIB Counters 368 */ 369void 370ar5210UpdateMibCounters(struct ath_hal *ah, HAL_MIB_STATS *stats) 371{ 372 stats->ackrcv_bad += OS_REG_READ(ah, AR_ACK_FAIL); 373 stats->rts_bad += OS_REG_READ(ah, AR_RTS_FAIL); 374 stats->fcs_bad += OS_REG_READ(ah, AR_FCS_FAIL); 375 stats->rts_good += OS_REG_READ(ah, AR_RTS_OK); 376 stats->beacons += OS_REG_READ(ah, AR_BEACON_CNT); 377} 378 379HAL_BOOL 380ar5210SetSifsTime(struct ath_hal *ah, u_int us) 381{ 382 struct ath_hal_5210 *ahp = AH5210(ah); 383 384 if (us > ath_hal_mac_usec(ah, 0x7ff)) { 385 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad SIFS time %u\n", 386 __func__, us); 387 ahp->ah_sifstime = (u_int) -1; /* restore default handling */ 388 return AH_FALSE; 389 } else { 390 /* convert to system clocks */ 391 OS_REG_RMW_FIELD(ah, AR_IFS0, AR_IFS0_SIFS, 392 ath_hal_mac_clks(ah, us)); 393 ahp->ah_sifstime = us; 394 return AH_TRUE; 395 } 396} 397 398u_int 399ar5210GetSifsTime(struct ath_hal *ah) 400{ 401 u_int clks = OS_REG_READ(ah, AR_IFS0) & 0x7ff; 402 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 403} 404 405HAL_BOOL 406ar5210SetSlotTime(struct ath_hal *ah, u_int us) 407{ 408 struct ath_hal_5210 *ahp = AH5210(ah); 409 410 if (us < HAL_SLOT_TIME_9 || us > ath_hal_mac_usec(ah, 0xffff)) { 411 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad slot time %u\n", 412 __func__, us); 413 ahp->ah_slottime = (u_int) -1; /* restore default handling */ 414 return AH_FALSE; 415 } else { 416 /* convert to system clocks */ 417 OS_REG_WRITE(ah, AR_SLOT_TIME, ath_hal_mac_clks(ah, us)); 418 ahp->ah_slottime = us; 419 return AH_TRUE; 420 } 421} 422 423u_int 424ar5210GetSlotTime(struct ath_hal *ah) 425{ 426 u_int clks = OS_REG_READ(ah, AR_SLOT_TIME) & 0xffff; 427 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 428} 429 430HAL_BOOL 431ar5210SetAckTimeout(struct ath_hal *ah, u_int us) 432{ 433 struct ath_hal_5210 *ahp = AH5210(ah); 434 435 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { 436 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad ack timeout %u\n", 437 __func__, us); 438 ahp->ah_acktimeout = (u_int) -1; /* restore default handling */ 439 return AH_FALSE; 440 } else { 441 /* convert to system clocks */ 442 OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 443 AR_TIME_OUT_ACK, ath_hal_mac_clks(ah, us)); 444 ahp->ah_acktimeout = us; 445 return AH_TRUE; 446 } 447} 448 449u_int 450ar5210GetAckTimeout(struct ath_hal *ah) 451{ 452 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_ACK); 453 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 454} 455 456u_int 457ar5210GetAckCTSRate(struct ath_hal *ah) 458{ 459 return ((AH5210(ah)->ah_staId1Defaults & AR_STA_ID1_ACKCTS_6MB) == 0); 460} 461 462HAL_BOOL 463ar5210SetAckCTSRate(struct ath_hal *ah, u_int high) 464{ 465 struct ath_hal_5210 *ahp = AH5210(ah); 466 467 if (high) { 468 OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 469 ahp->ah_staId1Defaults &= ~AR_STA_ID1_ACKCTS_6MB; 470 } else { 471 OS_REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_ACKCTS_6MB); 472 ahp->ah_staId1Defaults |= AR_STA_ID1_ACKCTS_6MB; 473 } 474 return AH_TRUE; 475} 476 477HAL_BOOL 478ar5210SetCTSTimeout(struct ath_hal *ah, u_int us) 479{ 480 struct ath_hal_5210 *ahp = AH5210(ah); 481 482 if (us > ath_hal_mac_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { 483 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: bad cts timeout %u\n", 484 __func__, us); 485 ahp->ah_ctstimeout = (u_int) -1; /* restore default handling */ 486 return AH_FALSE; 487 } else { 488 /* convert to system clocks */ 489 OS_REG_RMW_FIELD(ah, AR_TIME_OUT, 490 AR_TIME_OUT_CTS, ath_hal_mac_clks(ah, us)); 491 ahp->ah_ctstimeout = us; 492 return AH_TRUE; 493 } 494} 495 496u_int 497ar5210GetCTSTimeout(struct ath_hal *ah) 498{ 499 u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); 500 return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ 501} 502 503HAL_BOOL 504ar5210SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 505{ 506 /* nothing to do */ 507 return AH_TRUE; 508} 509 510void 511ar5210SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 512{ 513} 514 515/* 516 * Control Adaptive Noise Immunity Parameters 517 */ 518HAL_BOOL 519ar5210AniControl(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) 520{ 521 return AH_FALSE; 522} 523 524void 525ar5210AniPoll(struct ath_hal *ah, const HAL_NODE_STATS *stats, HAL_CHANNEL *chan) 526{ 527} 528 529void 530ar5210MibEvent(struct ath_hal *ah, const HAL_NODE_STATS *stats) 531{ 532} 533 534#define AR_DIAG_SW_DIS_CRYPTO (AR_DIAG_SW_DIS_ENC | AR_DIAG_SW_DIS_DEC) 535 536HAL_STATUS 537ar5210GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 538 uint32_t capability, uint32_t *result) 539{ 540 541 switch (type) { 542 case HAL_CAP_CIPHER: /* cipher handled in hardware */ 543 return (capability == HAL_CIPHER_WEP ? HAL_OK : HAL_ENOTSUPP); 544 default: 545 return ath_hal_getcapability(ah, type, capability, result); 546 } 547} 548 549HAL_BOOL 550ar5210SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 551 uint32_t capability, uint32_t setting, HAL_STATUS *status) 552{ 553 554 switch (type) { 555 case HAL_CAP_DIAG: /* hardware diagnostic support */ 556 /* 557 * NB: could split this up into virtual capabilities, 558 * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly 559 * seems worth the additional complexity. 560 */ 561#ifdef AH_DEBUG 562 AH_PRIVATE(ah)->ah_diagreg = setting; 563#else 564 AH_PRIVATE(ah)->ah_diagreg = setting & 0x6; /* ACK+CTS */ 565#endif 566 OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); 567 return AH_TRUE; 568 case HAL_CAP_RXORN_FATAL: /* HAL_INT_RXORN treated as fatal */ 569 return AH_FALSE; /* NB: disallow */ 570 default: 571 return ath_hal_setcapability(ah, type, capability, 572 setting, status); 573 } 574} 575 576HAL_BOOL 577ar5210GetDiagState(struct ath_hal *ah, int request, 578 const void *args, uint32_t argsize, 579 void **result, uint32_t *resultsize) 580{ 581#ifdef AH_PRIVATE_DIAG 582 uint32_t pcicfg; 583 HAL_BOOL ok; 584 585 switch (request) { 586 case HAL_DIAG_EEPROM: 587 /* XXX */ 588 break; 589 case HAL_DIAG_EEREAD: 590 if (argsize != sizeof(uint16_t)) 591 return AH_FALSE; 592 pcicfg = OS_REG_READ(ah, AR_PCICFG); 593 OS_REG_WRITE(ah, AR_PCICFG, pcicfg | AR_PCICFG_EEPROMSEL); 594 ok = ath_hal_eepromRead(ah, *(const uint16_t *)args, *result); 595 OS_REG_WRITE(ah, AR_PCICFG, pcicfg); 596 if (ok) 597 *resultsize = sizeof(uint16_t); 598 return ok; 599 } 600#endif 601 return ath_hal_getdiagstate(ah, request, 602 args, argsize, result, resultsize); 603} 604#endif /* AH_SUPPORT_AR5210 */ 605