2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2006 Atheros Communications, Inc.
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.
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.
17 * $Id: ar5211_misc.c,v 1.1.1.1 2008/12/11 04:46:32 alc Exp $
22 #include "ah_internal.h"
24 #include "ar5211/ar5211.h"
25 #include "ar5211/ar5211reg.h"
26 #include "ar5211/ar5211phy.h"
28 #include "ah_eeprom_v3.h"
30 #define AR_NUM_GPIO 6 /* 6 GPIO bits */
31 #define AR_GPIOD_MASK 0x2f /* 6-bit mask */
34 ar5211GetMacAddress(struct ath_hal
*ah
, uint8_t *mac
)
36 struct ath_hal_5211
*ahp
= AH5211(ah
);
38 OS_MEMCPY(mac
, ahp
->ah_macaddr
, IEEE80211_ADDR_LEN
);
42 ar5211SetMacAddress(struct ath_hal
*ah
, const uint8_t *mac
)
44 struct ath_hal_5211
*ahp
= AH5211(ah
);
46 OS_MEMCPY(ahp
->ah_macaddr
, mac
, IEEE80211_ADDR_LEN
);
51 ar5211GetBssIdMask(struct ath_hal
*ah
, uint8_t *mask
)
53 static const uint8_t ones
[IEEE80211_ADDR_LEN
] =
54 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
55 OS_MEMCPY(mask
, ones
, IEEE80211_ADDR_LEN
);
59 ar5211SetBssIdMask(struct ath_hal
*ah
, const uint8_t *mask
)
65 * Read 16 bits of data from the specified EEPROM offset.
68 ar5211EepromRead(struct ath_hal
*ah
, u_int off
, uint16_t *data
)
70 OS_REG_WRITE(ah
, AR_EEPROM_ADDR
, off
);
71 OS_REG_WRITE(ah
, AR_EEPROM_CMD
, AR_EEPROM_CMD_READ
);
73 if (!ath_hal_wait(ah
, AR_EEPROM_STS
,
74 AR_EEPROM_STS_READ_COMPLETE
| AR_EEPROM_STS_READ_ERROR
,
75 AR_EEPROM_STS_READ_COMPLETE
)) {
76 HALDEBUG(ah
, HAL_DEBUG_ANY
,
77 "%s: read failed for entry 0x%x\n", __func__
, off
);
80 *data
= OS_REG_READ(ah
, AR_EEPROM_DATA
) & 0xffff;
84 #ifdef AH_SUPPORT_WRITE_EEPROM
86 * Write 16 bits of data to the specified EEPROM offset.
89 ar5211EepromWrite(struct ath_hal
*ah
, u_int off
, uint16_t data
)
93 #endif /* AH_SUPPORT_WRITE_EEPROM */
96 * Attempt to change the cards operating regulatory domain to the given value
99 ar5211SetRegulatoryDomain(struct ath_hal
*ah
,
100 uint16_t regDomain
, HAL_STATUS
*status
)
104 if (AH_PRIVATE(ah
)->ah_currentRD
== regDomain
) {
109 * Check if EEPROM is configured to allow this; must
110 * be a proper version and the protection bits must
111 * permit re-writing that segment of the EEPROM.
113 if (ath_hal_eepromGetFlag(ah
, AR_EEP_WRITEPROTECT
)) {
117 #ifdef AH_SUPPORT_WRITE_REGDOMAIN
118 if (ar5211EepromWrite(ah
, AR_EEPROM_REG_DOMAIN
, regDomain
)) {
119 HALDEBUG(ah
, HAL_DEBUG_ANY
,
120 "%s: set regulatory domain to %u (0x%x)\n",
121 __func__
, regDomain
, regDomain
);
122 AH_PRIVATE(ah
)->ah_currentRD
= regDomain
;
134 * Return the wireless modes (a,b,g,t) supported by hardware.
136 * This value is what is actually supported by the hardware
137 * and is unaffected by regulatory/country code settings.
141 ar5211GetWirelessModes(struct ath_hal
*ah
)
145 if (ath_hal_eepromGetFlag(ah
, AR_EEP_AMODE
)) {
147 if (!ath_hal_eepromGetFlag(ah
, AR_EEP_TURBO5DISABLE
))
148 mode
|= HAL_MODE_TURBO
| HAL_MODE_108A
;
150 if (ath_hal_eepromGetFlag(ah
, AR_EEP_BMODE
))
151 mode
|= HAL_MODE_11B
;
157 ar5211GetTurboDisable(struct ath_hal
*ah
)
159 return (AH5211(ah
)->ah_turboDisable
!= 0);
164 * Called if RfKill is supported (according to EEPROM). Set the interrupt and
165 * GPIO values so the ISR and can disable RF on a switch signal
168 ar5211EnableRfKill(struct ath_hal
*ah
)
170 uint16_t rfsilent
= AH_PRIVATE(ah
)->ah_rfsilent
;
171 int select
= MS(rfsilent
, AR_EEPROM_RFSILENT_GPIO_SEL
);
172 int polarity
= MS(rfsilent
, AR_EEPROM_RFSILENT_POLARITY
);
175 * Configure the desired GPIO port for input
176 * and enable baseband rf silence.
178 ar5211GpioCfgInput(ah
, select
);
179 OS_REG_SET_BIT(ah
, AR_PHY_BASE
, 0x00002000);
181 * If radio disable switch connection to GPIO bit x is enabled
182 * program GPIO interrupt.
183 * If rfkill bit on eeprom is 1, setupeeprommap routine has already
184 * verified that it is a later version of eeprom, it has a place for
185 * rfkill bit and it is set to 1, indicating that GPIO bit x hardware
186 * connection is present.
188 ar5211GpioSetIntr(ah
, select
, (ar5211GpioGet(ah
, select
) != polarity
));
192 * Configure GPIO Output lines
195 ar5211GpioCfgOutput(struct ath_hal
*ah
, uint32_t gpio
)
199 HALASSERT(gpio
< AR_NUM_GPIO
);
201 reg
= OS_REG_READ(ah
, AR_GPIOCR
);
202 reg
&= ~(AR_GPIOCR_0_CR_A
<< (gpio
* AR_GPIOCR_CR_SHIFT
));
203 reg
|= AR_GPIOCR_0_CR_A
<< (gpio
* AR_GPIOCR_CR_SHIFT
);
205 OS_REG_WRITE(ah
, AR_GPIOCR
, reg
);
210 * Configure GPIO Input lines
213 ar5211GpioCfgInput(struct ath_hal
*ah
, uint32_t gpio
)
217 HALASSERT(gpio
< AR_NUM_GPIO
);
219 reg
= OS_REG_READ(ah
, AR_GPIOCR
);
220 reg
&= ~(AR_GPIOCR_0_CR_A
<< (gpio
* AR_GPIOCR_CR_SHIFT
));
221 reg
|= AR_GPIOCR_0_CR_N
<< (gpio
* AR_GPIOCR_CR_SHIFT
);
223 OS_REG_WRITE(ah
, AR_GPIOCR
, reg
);
228 * Once configured for I/O - set output lines
231 ar5211GpioSet(struct ath_hal
*ah
, uint32_t gpio
, uint32_t val
)
235 HALASSERT(gpio
< AR_NUM_GPIO
);
237 reg
= OS_REG_READ(ah
, AR_GPIODO
);
239 reg
|= (val
&1) << gpio
;
241 OS_REG_WRITE(ah
, AR_GPIODO
, reg
);
246 * Once configured for I/O - get input lines
249 ar5211GpioGet(struct ath_hal
*ah
, uint32_t gpio
)
251 if (gpio
< AR_NUM_GPIO
) {
252 uint32_t val
= OS_REG_READ(ah
, AR_GPIODI
);
253 val
= ((val
& AR_GPIOD_MASK
) >> gpio
) & 0x1;
261 * Set the GPIO 0 Interrupt (gpio is ignored)
264 ar5211GpioSetIntr(struct ath_hal
*ah
, u_int gpio
, uint32_t ilevel
)
266 uint32_t val
= OS_REG_READ(ah
, AR_GPIOCR
);
268 /* Clear the bits that we will modify. */
269 val
&= ~(AR_GPIOCR_INT_SEL0
| AR_GPIOCR_INT_SELH
| AR_GPIOCR_INT_ENA
|
272 val
|= AR_GPIOCR_INT_SEL0
| AR_GPIOCR_INT_ENA
;
274 val
|= AR_GPIOCR_INT_SELH
;
276 /* Don't need to change anything for low level interrupt. */
277 OS_REG_WRITE(ah
, AR_GPIOCR
, val
);
279 /* Change the interrupt mask. */
280 ar5211SetInterrupts(ah
, AH5211(ah
)->ah_maskReg
| HAL_INT_GPIO
);
284 * Change the LED blinking pattern to correspond to the connectivity
287 ar5211SetLedState(struct ath_hal
*ah
, HAL_LED_STATE state
)
289 static const uint32_t ledbits
[8] = {
290 AR_PCICFG_LEDCTL_NONE
|AR_PCICFG_LEDMODE_PROP
, /* HAL_LED_INIT */
291 AR_PCICFG_LEDCTL_PEND
|AR_PCICFG_LEDMODE_PROP
, /* HAL_LED_SCAN */
292 AR_PCICFG_LEDCTL_PEND
|AR_PCICFG_LEDMODE_PROP
, /* HAL_LED_AUTH */
293 AR_PCICFG_LEDCTL_ASSOC
|AR_PCICFG_LEDMODE_PROP
,/* HAL_LED_ASSOC*/
294 AR_PCICFG_LEDCTL_ASSOC
|AR_PCICFG_LEDMODE_PROP
,/* HAL_LED_RUN */
295 AR_PCICFG_LEDCTL_NONE
|AR_PCICFG_LEDMODE_RAND
,
296 AR_PCICFG_LEDCTL_NONE
|AR_PCICFG_LEDMODE_RAND
,
297 AR_PCICFG_LEDCTL_NONE
|AR_PCICFG_LEDMODE_RAND
,
299 OS_REG_WRITE(ah
, AR_PCICFG
,
300 (OS_REG_READ(ah
, AR_PCICFG
) &~
301 (AR_PCICFG_LEDCTL
| AR_PCICFG_LEDMODE
))
302 | ledbits
[state
& 0x7]
307 * Change association related fields programmed into the hardware.
308 * Writing a valid BSSID to the hardware effectively enables the hardware
309 * to synchronize its TSF to the correct beacons and receive frames coming
310 * from that BSSID. It is called by the SME JOIN operation.
313 ar5211WriteAssocid(struct ath_hal
*ah
, const uint8_t *bssid
, uint16_t assocId
)
315 struct ath_hal_5211
*ahp
= AH5211(ah
);
317 /* XXX save bssid for possible re-use on reset */
318 OS_MEMCPY(ahp
->ah_bssid
, bssid
, IEEE80211_ADDR_LEN
);
319 OS_REG_WRITE(ah
, AR_BSS_ID0
, LE_READ_4(ahp
->ah_bssid
));
320 OS_REG_WRITE(ah
, AR_BSS_ID1
, LE_READ_2(ahp
->ah_bssid
+4) |
321 ((assocId
& 0x3fff)<<AR_BSS_ID1_AID_S
));
325 * Get the current hardware tsf for stamlme.
328 ar5211GetTsf64(struct ath_hal
*ah
)
330 uint32_t low1
, low2
, u32
;
332 /* sync multi-word read */
333 low1
= OS_REG_READ(ah
, AR_TSF_L32
);
334 u32
= OS_REG_READ(ah
, AR_TSF_U32
);
335 low2
= OS_REG_READ(ah
, AR_TSF_L32
);
336 if (low2
< low1
) { /* roll over */
338 * If we are not preempted this will work. If we are
339 * then we re-reading AR_TSF_U32 does no good as the
340 * low bits will be meaningless. Likewise reading
341 * L32, U32, U32, then comparing the last two reads
342 * to check for rollover doesn't help if preempted--so
343 * we take this approach as it costs one less PCI
344 * read which can be noticeable when doing things
345 * like timestamping packets in monitor mode.
349 return (((uint64_t) u32
) << 32) | ((uint64_t) low2
);
353 * Get the current hardware tsf for stamlme.
356 ar5211GetTsf32(struct ath_hal
*ah
)
358 return OS_REG_READ(ah
, AR_TSF_L32
);
362 * Reset the current hardware tsf for stamlme
365 ar5211ResetTsf(struct ath_hal
*ah
)
367 uint32_t val
= OS_REG_READ(ah
, AR_BEACON
);
369 OS_REG_WRITE(ah
, AR_BEACON
, val
| AR_BEACON_RESET_TSF
);
373 * Grab a semi-random value from hardware registers - may not
377 ar5211GetRandomSeed(struct ath_hal
*ah
)
381 nf
= (OS_REG_READ(ah
, AR_PHY(25)) >> 19) & 0x1ff;
383 nf
= 0 - ((nf
^ 0x1ff) + 1);
384 return (OS_REG_READ(ah
, AR_TSF_U32
) ^
385 OS_REG_READ(ah
, AR_TSF_L32
) ^ nf
);
389 * Detect if our card is present
392 ar5211DetectCardPresent(struct ath_hal
*ah
)
394 uint16_t macVersion
, macRev
;
398 * Read the Silicon Revision register and compare that
399 * to what we read at attach time. If the same, we say
400 * a card/device is present.
402 v
= OS_REG_READ(ah
, AR_SREV
) & AR_SREV_ID_M
;
403 macVersion
= v
>> AR_SREV_ID_S
;
404 macRev
= v
& AR_SREV_REVISION_M
;
405 return (AH_PRIVATE(ah
)->ah_macVersion
== macVersion
&&
406 AH_PRIVATE(ah
)->ah_macRev
== macRev
);
410 * Update MIB Counters
413 ar5211UpdateMibCounters(struct ath_hal
*ah
, HAL_MIB_STATS
*stats
)
415 stats
->ackrcv_bad
+= OS_REG_READ(ah
, AR_ACK_FAIL
);
416 stats
->rts_bad
+= OS_REG_READ(ah
, AR_RTS_FAIL
);
417 stats
->fcs_bad
+= OS_REG_READ(ah
, AR_FCS_FAIL
);
418 stats
->rts_good
+= OS_REG_READ(ah
, AR_RTS_OK
);
419 stats
->beacons
+= OS_REG_READ(ah
, AR_BEACON_CNT
);
423 ar5211SetSifsTime(struct ath_hal
*ah
, u_int us
)
425 struct ath_hal_5211
*ahp
= AH5211(ah
);
427 if (us
> ath_hal_mac_usec(ah
, 0xffff)) {
428 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad SIFS time %u\n",
430 ahp
->ah_sifstime
= (u_int
) -1; /* restore default handling */
433 /* convert to system clocks */
434 OS_REG_WRITE(ah
, AR_D_GBL_IFS_SIFS
, ath_hal_mac_clks(ah
, us
));
435 ahp
->ah_slottime
= us
;
441 ar5211GetSifsTime(struct ath_hal
*ah
)
443 u_int clks
= OS_REG_READ(ah
, AR_D_GBL_IFS_SIFS
) & 0xffff;
444 return ath_hal_mac_usec(ah
, clks
); /* convert from system clocks */
448 ar5211SetSlotTime(struct ath_hal
*ah
, u_int us
)
450 struct ath_hal_5211
*ahp
= AH5211(ah
);
452 if (us
< HAL_SLOT_TIME_9
|| us
> ath_hal_mac_usec(ah
, 0xffff)) {
453 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad slot time %u\n",
455 ahp
->ah_slottime
= us
; /* restore default handling */
458 /* convert to system clocks */
459 OS_REG_WRITE(ah
, AR_D_GBL_IFS_SLOT
, ath_hal_mac_clks(ah
, us
));
460 ahp
->ah_slottime
= us
;
466 ar5211GetSlotTime(struct ath_hal
*ah
)
468 u_int clks
= OS_REG_READ(ah
, AR_D_GBL_IFS_SLOT
) & 0xffff;
469 return ath_hal_mac_usec(ah
, clks
); /* convert from system clocks */
473 ar5211SetAckTimeout(struct ath_hal
*ah
, u_int us
)
475 struct ath_hal_5211
*ahp
= AH5211(ah
);
477 if (us
> ath_hal_mac_usec(ah
, MS(0xffffffff, AR_TIME_OUT_ACK
))) {
478 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad ack timeout %u\n",
480 ahp
->ah_acktimeout
= (u_int
) -1; /* restore default handling */
483 /* convert to system clocks */
484 OS_REG_RMW_FIELD(ah
, AR_TIME_OUT
,
485 AR_TIME_OUT_ACK
, ath_hal_mac_clks(ah
, us
));
486 ahp
->ah_acktimeout
= us
;
492 ar5211GetAckTimeout(struct ath_hal
*ah
)
494 u_int clks
= MS(OS_REG_READ(ah
, AR_TIME_OUT
), AR_TIME_OUT_ACK
);
495 return ath_hal_mac_usec(ah
, clks
); /* convert from system clocks */
499 ar5211GetAckCTSRate(struct ath_hal
*ah
)
501 return ((AH5211(ah
)->ah_staId1Defaults
& AR_STA_ID1_ACKCTS_6MB
) == 0);
505 ar5211SetAckCTSRate(struct ath_hal
*ah
, u_int high
)
507 struct ath_hal_5211
*ahp
= AH5211(ah
);
510 OS_REG_CLR_BIT(ah
, AR_STA_ID1
, AR_STA_ID1_ACKCTS_6MB
);
511 ahp
->ah_staId1Defaults
&= ~AR_STA_ID1_ACKCTS_6MB
;
513 OS_REG_SET_BIT(ah
, AR_STA_ID1
, AR_STA_ID1_ACKCTS_6MB
);
514 ahp
->ah_staId1Defaults
|= AR_STA_ID1_ACKCTS_6MB
;
520 ar5211SetCTSTimeout(struct ath_hal
*ah
, u_int us
)
522 struct ath_hal_5211
*ahp
= AH5211(ah
);
524 if (us
> ath_hal_mac_usec(ah
, MS(0xffffffff, AR_TIME_OUT_CTS
))) {
525 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: bad cts timeout %u\n",
527 ahp
->ah_ctstimeout
= (u_int
) -1; /* restore default handling */
530 /* convert to system clocks */
531 OS_REG_RMW_FIELD(ah
, AR_TIME_OUT
,
532 AR_TIME_OUT_CTS
, ath_hal_mac_clks(ah
, us
));
533 ahp
->ah_ctstimeout
= us
;
539 ar5211GetCTSTimeout(struct ath_hal
*ah
)
541 u_int clks
= MS(OS_REG_READ(ah
, AR_TIME_OUT
), AR_TIME_OUT_CTS
);
542 return ath_hal_mac_usec(ah
, clks
); /* convert from system clocks */
546 ar5211SetDecompMask(struct ath_hal
*ah
, uint16_t keyidx
, int en
)
553 ar5211SetCoverageClass(struct ath_hal
*ah
, uint8_t coverageclass
, int now
)
558 * Control Adaptive Noise Immunity Parameters
561 ar5211AniControl(struct ath_hal
*ah
, HAL_ANI_CMD cmd
, int param
)
567 ar5211AniPoll(struct ath_hal
*ah
, const HAL_NODE_STATS
*stats
, HAL_CHANNEL
*chan
)
572 ar5211MibEvent(struct ath_hal
*ah
, const HAL_NODE_STATS
*stats
)
577 * Get the rssi of frame curently being received.
580 ar5211GetCurRssi(struct ath_hal
*ah
)
582 return (OS_REG_READ(ah
, AR_PHY_CURRENT_RSSI
) & 0xff);
586 ar5211GetDefAntenna(struct ath_hal
*ah
)
588 return (OS_REG_READ(ah
, AR_DEF_ANTENNA
) & 0x7);
592 ar5211SetDefAntenna(struct ath_hal
*ah
, u_int antenna
)
594 OS_REG_WRITE(ah
, AR_DEF_ANTENNA
, (antenna
& 0x7));
598 ar5211GetAntennaSwitch(struct ath_hal
*ah
)
600 return AH5211(ah
)->ah_diversityControl
;
604 ar5211SetAntennaSwitch(struct ath_hal
*ah
, HAL_ANT_SETTING settings
)
606 const HAL_CHANNEL
*chan
=
607 (const HAL_CHANNEL
*) AH_PRIVATE(ah
)->ah_curchan
;
609 if (chan
== AH_NULL
) {
610 AH5211(ah
)->ah_diversityControl
= settings
;
613 return ar5211SetAntennaSwitchInternal(ah
, settings
, chan
);
617 ar5211GetCapability(struct ath_hal
*ah
, HAL_CAPABILITY_TYPE type
,
618 uint32_t capability
, uint32_t *result
)
622 case HAL_CAP_CIPHER
: /* cipher handled in hardware */
623 switch (capability
) {
624 case HAL_CIPHER_AES_OCB
:
632 return ath_hal_getcapability(ah
, type
, capability
, result
);
637 ar5211SetCapability(struct ath_hal
*ah
, HAL_CAPABILITY_TYPE type
,
638 uint32_t capability
, uint32_t setting
, HAL_STATUS
*status
)
641 case HAL_CAP_DIAG
: /* hardware diagnostic support */
643 * NB: could split this up into virtual capabilities,
644 * (e.g. 1 => ACK, 2 => CTS, etc.) but it hardly
645 * seems worth the additional complexity.
648 AH_PRIVATE(ah
)->ah_diagreg
= setting
;
650 AH_PRIVATE(ah
)->ah_diagreg
= setting
& 0x6; /* ACK+CTS */
652 OS_REG_WRITE(ah
, AR_DIAG_SW
, AH_PRIVATE(ah
)->ah_diagreg
);
655 return ath_hal_setcapability(ah
, type
, capability
,
661 ar5211GetDiagState(struct ath_hal
*ah
, int request
,
662 const void *args
, uint32_t argsize
,
663 void **result
, uint32_t *resultsize
)
665 struct ath_hal_5211
*ahp
= AH5211(ah
);
668 if (ath_hal_getdiagstate(ah
, request
, args
, argsize
, result
, resultsize
))
671 case HAL_DIAG_EEPROM
:
672 return ath_hal_eepromDiag(ah
, request
,
673 args
, argsize
, result
, resultsize
);
674 case HAL_DIAG_RFGAIN
:
675 *result
= &ahp
->ah_gainValues
;
676 *resultsize
= sizeof(GAIN_VALUES
);
678 case HAL_DIAG_RFGAIN_CURSTEP
:
679 *result
= __DECONST(void *, ahp
->ah_gainValues
.currStep
);
680 *resultsize
= (*result
== AH_NULL
) ?
681 0 : sizeof(GAIN_OPTIMIZATION_STEP
);