2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 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: ar5416_misc.c,v 1.1.1.1 2008/12/11 04:46:48 alc Exp $
22 #include "ah_internal.h"
25 #include "ah_desc.h" /* NB: for HAL_PHYERR* */
28 #include "ar5416/ar5416.h"
29 #include "ar5416/ar5416reg.h"
30 #include "ar5416/ar5416phy.h"
33 * Return the wireless modes (a,b,g,t) supported by hardware.
35 * This value is what is actually supported by the hardware
36 * and is unaffected by regulatory/country code settings.
40 ar5416GetWirelessModes(struct ath_hal
*ah
)
44 mode
= ar5212GetWirelessModes(ah
);
45 if (mode
& HAL_MODE_11A
)
46 mode
|= HAL_MODE_11NA_HT20
47 | HAL_MODE_11NA_HT40PLUS
48 | HAL_MODE_11NA_HT40MINUS
50 if (mode
& HAL_MODE_11G
)
51 mode
|= HAL_MODE_11NG_HT20
52 | HAL_MODE_11NG_HT40PLUS
53 | HAL_MODE_11NG_HT40MINUS
59 * Change the LED blinking pattern to correspond to the connectivity
62 ar5416SetLedState(struct ath_hal
*ah
, HAL_LED_STATE state
)
64 static const uint32_t ledbits
[8] = {
65 AR_MAC_LED_ASSOC_NONE
, /* HAL_LED_INIT */
66 AR_MAC_LED_ASSOC_PEND
, /* HAL_LED_SCAN */
67 AR_MAC_LED_ASSOC_PEND
, /* HAL_LED_AUTH */
68 AR_MAC_LED_ASSOC_ACTIVE
, /* HAL_LED_ASSOC*/
69 AR_MAC_LED_ASSOC_ACTIVE
, /* HAL_LED_RUN */
70 AR_MAC_LED_ASSOC_NONE
,
71 AR_MAC_LED_ASSOC_NONE
,
72 AR_MAC_LED_ASSOC_NONE
,
76 bits
= OS_REG_READ(ah
, AR_MAC_LED
);
77 bits
= (bits
&~ AR_MAC_LED_MODE
)
78 | SM(AR_MAC_LED_MODE_POWON
, AR_MAC_LED_MODE
)
80 | SM(AR_MAC_LED_MODE_NETON
, AR_MAC_LED_MODE
)
83 bits
= (bits
&~ AR_MAC_LED_ASSOC
)
84 | SM(ledbits
[state
& 0x7], AR_MAC_LED_ASSOC
);
85 OS_REG_WRITE(ah
, AR_MAC_LED
, bits
);
89 * Reset the current hardware tsf for stamlme.
92 ar5416ResetTsf(struct ath_hal
*ah
)
97 for (i
= 0; i
< 10; i
++) {
98 v
= OS_REG_READ(ah
, AR_SLP32_MODE
);
99 if ((v
& AR_SLP32_TSF_WRITE_STATUS
) == 0)
103 OS_REG_WRITE(ah
, AR_RESET_TSF
, AR_RESET_TSF_ONCE
);
107 ar5416SetAntennaSwitch(struct ath_hal
*ah
, HAL_ANT_SETTING settings
)
112 /* Setup decompression for given key index */
114 ar5416SetDecompMask(struct ath_hal
*ah
, uint16_t keyidx
, int en
)
119 /* Setup coverage class */
121 ar5416SetCoverageClass(struct ath_hal
*ah
, uint8_t coverageclass
, int now
)
126 * Return approximation of extension channel busy over an time interval
127 * 0% (clear) -> 100% (busy)
131 ar5416Get11nExtBusy(struct ath_hal
*ah
)
133 struct ath_hal_5416
*ahp
= AH5416(ah
);
134 uint32_t busy
; /* percentage */
135 uint32_t cycleCount
, ctlBusy
, extBusy
;
137 ctlBusy
= OS_REG_READ(ah
, AR_RCCNT
);
138 extBusy
= OS_REG_READ(ah
, AR_EXTRCCNT
);
139 cycleCount
= OS_REG_READ(ah
, AR_CCCNT
);
141 if (ahp
->ah_cycleCount
== 0 || ahp
->ah_cycleCount
> cycleCount
) {
143 * Cycle counter wrap (or initial call); it's not possible
144 * to accurately calculate a value because the registers
145 * right shift rather than wrap--so punt and return 0.
148 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: cycle counter wrap. ExtBusy = 0\n",
152 uint32_t cycleDelta
= cycleCount
- ahp
->ah_cycleCount
;
153 uint32_t ctlBusyDelta
= ctlBusy
- ahp
->ah_ctlBusy
;
154 uint32_t extBusyDelta
= extBusy
- ahp
->ah_extBusy
;
155 uint32_t ctlClearDelta
= 0;
157 /* Compute control channel rxclear.
158 * The cycle delta may be less than the control channel delta.
159 * This could be solved by freezing the timers (or an atomic read,
160 * if one was available). Checking for the condition should be
163 if (cycleDelta
> ctlBusyDelta
) {
164 ctlClearDelta
= cycleDelta
- ctlBusyDelta
;
167 /* Compute ratio of extension channel busy to control channel clear
168 * as an approximation to extension channel cleanliness.
170 * According to the hardware folks, ext rxclear is undefined
171 * if the ctrl rxclear is de-asserted (i.e. busy)
174 busy
= (extBusyDelta
* 100) / ctlClearDelta
;
182 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, "
183 "extBusyDelta 0x%x, ctlClearDelta 0x%x, "
185 __func__
, cycleDelta
, ctlBusyDelta
, extBusyDelta
, ctlClearDelta
, busy
);
189 ahp
->ah_cycleCount
= cycleCount
;
190 ahp
->ah_ctlBusy
= ctlBusy
;
191 ahp
->ah_extBusy
= extBusy
;
197 * Configure 20/40 operation
199 * 20/40 = joint rx clear (control and extension)
200 * 20 = rx clear (control)
202 * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing
203 * from 20/40 => 20 only
206 ar5416Set11nMac2040(struct ath_hal
*ah
, HAL_HT_MACMODE mode
)
210 /* Configure MAC for 20/40 operation */
211 if (mode
== HAL_HT_MACMODE_2040
) {
212 macmode
= AR_2040_JOINED_RX_CLEAR
;
216 OS_REG_WRITE(ah
, AR_2040_MODE
, macmode
);
220 * Get Rx clear (control/extension channel)
222 * Returns active low (busy) for ctrl/ext channel
226 ar5416Get11nRxClear(struct ath_hal
*ah
)
228 HAL_HT_RXCLEAR rxclear
= 0;
231 val
= OS_REG_READ(ah
, AR_DIAG_SW
);
233 /* control channel */
234 if (val
& AR_DIAG_RXCLEAR_CTL_LOW
) {
235 rxclear
|= HAL_RX_CLEAR_CTL_LOW
;
237 /* extension channel */
238 if (val
& AR_DIAG_RXCLEAR_CTL_LOW
) {
239 rxclear
|= HAL_RX_CLEAR_EXT_LOW
;
245 * Set Rx clear (control/extension channel)
247 * Useful for forcing the channel to appear busy for
248 * debugging/diagnostics
252 ar5416Set11nRxClear(struct ath_hal
*ah
, HAL_HT_RXCLEAR rxclear
)
254 /* control channel */
255 if (rxclear
& HAL_RX_CLEAR_CTL_LOW
) {
256 OS_REG_SET_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_CTL_LOW
);
258 OS_REG_CLR_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_CTL_LOW
);
260 /* extension channel */
261 if (rxclear
& HAL_RX_CLEAR_EXT_LOW
) {
262 OS_REG_SET_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_EXT_LOW
);
264 OS_REG_CLR_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_EXT_LOW
);
269 ar5416GetCapability(struct ath_hal
*ah
, HAL_CAPABILITY_TYPE type
,
270 uint32_t capability
, uint32_t *result
)
273 case HAL_CAP_BB_HANG
:
274 switch (capability
) {
275 case HAL_BB_HANG_RIFS
:
276 return AR_SREV_SOWL(ah
) ? HAL_OK
: HAL_ENOTSUPP
;
277 case HAL_BB_HANG_DFS
:
278 return AR_SREV_SOWL(ah
) ? HAL_OK
: HAL_ENOTSUPP
;
279 case HAL_BB_HANG_RX_CLEAR
:
280 return AR_SREV_MERLIN(ah
) ? HAL_OK
: HAL_ENOTSUPP
;
283 case HAL_CAP_MAC_HANG
:
284 return ((ah
->ah_macVersion
== AR_XSREV_VERSION_OWL_PCI
) ||
285 (ah
->ah_macVersion
== AR_XSREV_VERSION_OWL_PCIE
) ||
287 HAL_OK
: HAL_ENOTSUPP
;
291 return ar5212GetCapability(ah
, type
, capability
, result
);
294 static int ar5416DetectMacHang(struct ath_hal
*ah
);
295 static int ar5416DetectBBHang(struct ath_hal
*ah
);
298 ar5416GetDiagState(struct ath_hal
*ah
, int request
,
299 const void *args
, uint32_t argsize
,
300 void **result
, uint32_t *resultsize
)
302 struct ath_hal_5416
*ahp
= AH5416(ah
);
305 if (ath_hal_getdiagstate(ah
, request
, args
, argsize
, result
, resultsize
))
308 case HAL_DIAG_EEPROM
:
309 return ath_hal_eepromDiag(ah
, request
,
310 args
, argsize
, result
, resultsize
);
311 case HAL_DIAG_CHECK_HANGS
:
312 if (argsize
!= sizeof(int))
314 hangs
= *(const int *) args
;
316 if (hangs
& HAL_BB_HANGS
)
317 ahp
->ah_hangs
|= ar5416DetectBBHang(ah
);
318 /* NB: if BB is hung MAC will be hung too so skip check */
319 if (ahp
->ah_hangs
== 0 && (hangs
& HAL_MAC_HANGS
))
320 ahp
->ah_hangs
|= ar5416DetectMacHang(ah
);
321 *result
= &ahp
->ah_hangs
;
322 *resultsize
= sizeof(ahp
->ah_hangs
);
325 return ar5212GetDiagState(ah
, request
,
326 args
, argsize
, result
, resultsize
);
337 dcu_chain_state
= 0x1,
338 dcu_complete_state
= 0x2,
341 qcu_fsp_state
= 0x10,
342 qcu_stitch_state
= 0x20,
343 qcu_fetch_state
= 0x40,
344 qcu_complete_state
= 0x80
349 uint8_t dcu_chain_state
;
350 uint8_t dcu_complete_state
;
353 uint8_t qcu_fsp_state
;
354 uint8_t qcu_stitch_state
;
355 uint8_t qcu_fetch_state
;
356 uint8_t qcu_complete_state
;
357 } hal_mac_hang_check_t
;
360 ar5416CompareDbgHang(struct ath_hal
*ah
, const mac_dbg_regs_t
*regs
,
361 const hal_mac_hang_check_t
*check
)
366 if (check
->states
& dcu_chain_state
) {
369 for (i
= 0; i
< 6; i
++) {
370 if (((regs
->dma_dbg_4
>> (5*i
)) & 0x1f) ==
371 check
->dcu_chain_state
)
372 found_states
|= dcu_chain_state
;
374 for (i
= 0; i
< 4; i
++) {
375 if (((regs
->dma_dbg_5
>> (5*i
)) & 0x1f) ==
376 check
->dcu_chain_state
)
377 found_states
|= dcu_chain_state
;
380 if (check
->states
& dcu_complete_state
) {
381 if ((regs
->dma_dbg_6
& 0x3) == check
->dcu_complete_state
)
382 found_states
|= dcu_complete_state
;
384 if (check
->states
& qcu_stitch_state
) {
385 if (((regs
->dma_dbg_3
>> 18) & 0xf) == check
->qcu_stitch_state
)
386 found_states
|= qcu_stitch_state
;
388 if (check
->states
& qcu_fetch_state
) {
389 if (((regs
->dma_dbg_3
>> 22) & 0xf) == check
->qcu_fetch_state
)
390 found_states
|= qcu_fetch_state
;
392 if (check
->states
& qcu_complete_state
) {
393 if (((regs
->dma_dbg_3
>> 26) & 0x7) == check
->qcu_complete_state
)
394 found_states
|= qcu_complete_state
;
396 return (found_states
== check
->states
);
399 #define NUM_STATUS_READS 50
402 ar5416DetectMacHang(struct ath_hal
*ah
)
404 static const hal_mac_hang_check_t hang_sig1
= {
405 .dcu_chain_state
= 0x6,
406 .dcu_complete_state
= 0x1,
407 .states
= dcu_chain_state
408 | dcu_complete_state
,
410 static const hal_mac_hang_check_t hang_sig2
= {
411 .qcu_stitch_state
= 0x9,
412 .qcu_fetch_state
= 0x8,
413 .qcu_complete_state
= 0x4,
414 .states
= qcu_stitch_state
416 | qcu_complete_state
,
418 mac_dbg_regs_t mac_dbg
;
421 mac_dbg
.dma_dbg_3
= OS_REG_READ(ah
, AR_DMADBG_3
);
422 mac_dbg
.dma_dbg_4
= OS_REG_READ(ah
, AR_DMADBG_4
);
423 mac_dbg
.dma_dbg_5
= OS_REG_READ(ah
, AR_DMADBG_5
);
424 mac_dbg
.dma_dbg_6
= OS_REG_READ(ah
, AR_DMADBG_6
);
425 for (i
= 1; i
<= NUM_STATUS_READS
; i
++) {
426 if (mac_dbg
.dma_dbg_3
!= OS_REG_READ(ah
, AR_DMADBG_3
) ||
427 mac_dbg
.dma_dbg_4
!= OS_REG_READ(ah
, AR_DMADBG_4
) ||
428 mac_dbg
.dma_dbg_5
!= OS_REG_READ(ah
, AR_DMADBG_5
) ||
429 mac_dbg
.dma_dbg_6
!= OS_REG_READ(ah
, AR_DMADBG_6
))
433 if (ar5416CompareDbgHang(ah
, &mac_dbg
, &hang_sig1
))
434 return HAL_MAC_HANG_SIG1
;
435 if (ar5416CompareDbgHang(ah
, &mac_dbg
, &hang_sig2
))
436 return HAL_MAC_HANG_SIG2
;
438 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s Found an unknown MAC hang signature "
439 "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n",
440 __func__
, mac_dbg
.dma_dbg_3
, mac_dbg
.dma_dbg_4
, mac_dbg
.dma_dbg_5
,
443 return HAL_MAC_HANG_UNKNOWN
;
447 * Determine if the baseband using the Observation Bus Register
450 ar5416DetectBBHang(struct ath_hal
*ah
)
452 #define N(a) (sizeof(a)/sizeof(a[0]))
454 * Check the PCU Observation Bus 1 register (0x806c)
455 * NUM_STATUS_READS times
457 * 4 known BB hang signatures -
458 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E
459 * [2] bits 8,9 are 1, bit 11 is 0. State machine state
460 * (bits 25-31) is 0x52
461 * [3] bits 8,9 are 1, bit 11 is 0. State machine state
462 * (bits 25-31) is 0x18
463 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2,
464 * Rx State (bits 20-24) is 0x7.
466 static const struct {
471 /* Reg Value Reg Mask Hang Code XXX */
472 { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS
},
473 { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS
},
474 { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR
},
475 { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR
}
480 hang_sig
= OS_REG_READ(ah
, AR_OBSERV_1
);
481 for (i
= 1; i
<= NUM_STATUS_READS
; i
++) {
482 if (hang_sig
!= OS_REG_READ(ah
, AR_OBSERV_1
))
485 for (i
= 0; i
< N(hang_list
); i
++)
486 if ((hang_sig
& hang_list
[i
].mask
) == hang_list
[i
].val
) {
487 HALDEBUG(ah
, HAL_DEBUG_ANY
,
488 "%s BB hang, signature 0x%x, code 0x%x\n",
489 __func__
, hang_sig
, hang_list
[i
].code
);
490 return hang_list
[i
].code
;
493 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s Found an unknown BB hang signature! "
494 "<0x806c>=0x%x\n", __func__
, hang_sig
);
496 return HAL_BB_HANG_UNKNOWN
;
499 #undef NUM_STATUS_READS