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.
21 #ifdef AH_SUPPORT_AR5416
24 #include "ah_internal.h"
27 #include "ah_desc.h" /* NB: for HAL_PHYERR* */
30 #include "ar5416/ar5416.h"
31 #include "ar5416/ar5416reg.h"
32 #include "ar5416/ar5416phy.h"
35 * Return the wireless modes (a,b,g,t) supported by hardware.
37 * This value is what is actually supported by the hardware
38 * and is unaffected by regulatory/country code settings.
42 ar5416GetWirelessModes(struct ath_hal
*ah
)
46 mode
= ar5212GetWirelessModes(ah
);
47 if (mode
& HAL_MODE_11A
)
48 mode
|= HAL_MODE_11NA_HT20
49 | HAL_MODE_11NA_HT40PLUS
50 | HAL_MODE_11NA_HT40MINUS
52 if (mode
& HAL_MODE_11G
)
53 mode
|= HAL_MODE_11NG_HT20
54 | HAL_MODE_11NG_HT40PLUS
55 | HAL_MODE_11NG_HT40MINUS
61 * Change the LED blinking pattern to correspond to the connectivity
64 ar5416SetLedState(struct ath_hal
*ah
, HAL_LED_STATE state
)
66 static const uint32_t ledbits
[8] = {
67 AR_MAC_LED_ASSOC_NONE
, /* HAL_LED_INIT */
68 AR_MAC_LED_ASSOC_PEND
, /* HAL_LED_SCAN */
69 AR_MAC_LED_ASSOC_PEND
, /* HAL_LED_AUTH */
70 AR_MAC_LED_ASSOC_ACTIVE
, /* HAL_LED_ASSOC*/
71 AR_MAC_LED_ASSOC_ACTIVE
, /* HAL_LED_RUN */
72 AR_MAC_LED_ASSOC_NONE
,
73 AR_MAC_LED_ASSOC_NONE
,
74 AR_MAC_LED_ASSOC_NONE
,
78 bits
= OS_REG_READ(ah
, AR_MAC_LED
);
79 bits
= (bits
&~ AR_MAC_LED_MODE
)
80 | SM(AR_MAC_LED_MODE_POWON
, AR_MAC_LED_MODE
)
82 | SM(AR_MAC_LED_MODE_NETON
, AR_MAC_LED_MODE
)
85 bits
= (bits
&~ AR_MAC_LED_ASSOC
)
86 | SM(ledbits
[state
& 0x7], AR_MAC_LED_ASSOC
);
87 OS_REG_WRITE(ah
, AR_MAC_LED
, bits
);
91 * Reset the current hardware tsf for stamlme.
94 ar5416ResetTsf(struct ath_hal
*ah
)
99 for (i
= 0; i
< 10; i
++) {
100 v
= OS_REG_READ(ah
, AR_SLP32_MODE
);
101 if ((v
& AR_SLP32_TSF_WRITE_STATUS
) == 0)
105 OS_REG_WRITE(ah
, AR_RESET_TSF
, AR_RESET_TSF_ONCE
);
109 ar5416SetAntennaSwitch(struct ath_hal
*ah
, HAL_ANT_SETTING settings
)
114 /* Setup decompression for given key index */
116 ar5416SetDecompMask(struct ath_hal
*ah
, uint16_t keyidx
, int en
)
121 /* Setup coverage class */
123 ar5416SetCoverageClass(struct ath_hal
*ah
, uint8_t coverageclass
, int now
)
128 * Return approximation of extension channel busy over an time interval
129 * 0% (clear) -> 100% (busy)
133 ar5416Get11nExtBusy(struct ath_hal
*ah
)
135 struct ath_hal_5416
*ahp
= AH5416(ah
);
136 uint32_t busy
; /* percentage */
137 uint32_t cycleCount
, ctlBusy
, extBusy
;
139 ctlBusy
= OS_REG_READ(ah
, AR_RCCNT
);
140 extBusy
= OS_REG_READ(ah
, AR_EXTRCCNT
);
141 cycleCount
= OS_REG_READ(ah
, AR_CCCNT
);
143 if (ahp
->ah_cycleCount
== 0 || ahp
->ah_cycleCount
> cycleCount
) {
145 * Cycle counter wrap (or initial call); it's not possible
146 * to accurately calculate a value because the registers
147 * right shift rather than wrap--so punt and return 0.
150 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: cycle counter wrap. ExtBusy = 0\n",
154 uint32_t cycleDelta
= cycleCount
- ahp
->ah_cycleCount
;
155 uint32_t ctlBusyDelta
= ctlBusy
- ahp
->ah_ctlBusy
;
156 uint32_t extBusyDelta
= extBusy
- ahp
->ah_extBusy
;
157 uint32_t ctlClearDelta
= 0;
159 /* Compute control channel rxclear.
160 * The cycle delta may be less than the control channel delta.
161 * This could be solved by freezing the timers (or an atomic read,
162 * if one was available). Checking for the condition should be
165 if (cycleDelta
> ctlBusyDelta
) {
166 ctlClearDelta
= cycleDelta
- ctlBusyDelta
;
169 /* Compute ratio of extension channel busy to control channel clear
170 * as an approximation to extension channel cleanliness.
172 * According to the hardware folks, ext rxclear is undefined
173 * if the ctrl rxclear is de-asserted (i.e. busy)
176 busy
= (extBusyDelta
* 100) / ctlClearDelta
;
184 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, "
185 "extBusyDelta 0x%x, ctlClearDelta 0x%x, "
187 __func__
, cycleDelta
, ctlBusyDelta
, extBusyDelta
, ctlClearDelta
, busy
);
191 ahp
->ah_cycleCount
= cycleCount
;
192 ahp
->ah_ctlBusy
= ctlBusy
;
193 ahp
->ah_extBusy
= extBusy
;
199 * Configure 20/40 operation
201 * 20/40 = joint rx clear (control and extension)
202 * 20 = rx clear (control)
204 * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing
205 * from 20/40 => 20 only
208 ar5416Set11nMac2040(struct ath_hal
*ah
, HAL_HT_MACMODE mode
)
212 /* Configure MAC for 20/40 operation */
213 if (mode
== HAL_HT_MACMODE_2040
) {
214 macmode
= AR_2040_JOINED_RX_CLEAR
;
218 OS_REG_WRITE(ah
, AR_2040_MODE
, macmode
);
222 * Get Rx clear (control/extension channel)
224 * Returns active low (busy) for ctrl/ext channel
228 ar5416Get11nRxClear(struct ath_hal
*ah
)
230 HAL_HT_RXCLEAR rxclear
= 0;
233 val
= OS_REG_READ(ah
, AR_DIAG_SW
);
235 /* control channel */
236 if (val
& AR_DIAG_RXCLEAR_CTL_LOW
) {
237 rxclear
|= HAL_RX_CLEAR_CTL_LOW
;
239 /* extension channel */
240 if (val
& AR_DIAG_RXCLEAR_CTL_LOW
) {
241 rxclear
|= HAL_RX_CLEAR_EXT_LOW
;
247 * Set Rx clear (control/extension channel)
249 * Useful for forcing the channel to appear busy for
250 * debugging/diagnostics
254 ar5416Set11nRxClear(struct ath_hal
*ah
, HAL_HT_RXCLEAR rxclear
)
256 /* control channel */
257 if (rxclear
& HAL_RX_CLEAR_CTL_LOW
) {
258 OS_REG_SET_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_CTL_LOW
);
260 OS_REG_CLR_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_CTL_LOW
);
262 /* extension channel */
263 if (rxclear
& HAL_RX_CLEAR_EXT_LOW
) {
264 OS_REG_SET_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_EXT_LOW
);
266 OS_REG_CLR_BIT(ah
, AR_DIAG_SW
, AR_DIAG_RXCLEAR_EXT_LOW
);
271 ar5416GetCapability(struct ath_hal
*ah
, HAL_CAPABILITY_TYPE type
,
272 uint32_t capability
, uint32_t *result
)
275 case HAL_CAP_BB_HANG
:
276 switch (capability
) {
277 case HAL_BB_HANG_RIFS
:
278 return AR_SREV_SOWL(ah
) ? HAL_OK
: HAL_ENOTSUPP
;
279 case HAL_BB_HANG_DFS
:
280 return AR_SREV_SOWL(ah
) ? HAL_OK
: HAL_ENOTSUPP
;
281 case HAL_BB_HANG_RX_CLEAR
:
282 return AR_SREV_MERLIN(ah
) ? HAL_OK
: HAL_ENOTSUPP
;
285 case HAL_CAP_MAC_HANG
:
286 return ((ah
->ah_macVersion
== AR_XSREV_VERSION_OWL_PCI
) ||
287 (ah
->ah_macVersion
== AR_XSREV_VERSION_OWL_PCIE
) ||
288 AR_SREV_SOWL(ah
)) ? HAL_OK
: HAL_ENOTSUPP
;
292 return ar5212GetCapability(ah
, type
, capability
, result
);
295 static int ar5416DetectMacHang(struct ath_hal
*ah
);
296 static int ar5416DetectBBHang(struct ath_hal
*ah
);
299 ar5416GetDiagState(struct ath_hal
*ah
, int request
,
300 const void *args
, uint32_t argsize
,
301 void **result
, uint32_t *resultsize
)
303 struct ath_hal_5416
*ahp
= AH5416(ah
);
306 if (ath_hal_getdiagstate(ah
, request
, args
, argsize
, result
, resultsize
))
309 case HAL_DIAG_EEPROM
:
310 return ath_hal_eepromDiag(ah
, request
,
311 args
, argsize
, result
, resultsize
);
312 case HAL_DIAG_CHECK_HANGS
:
313 if (argsize
!= sizeof(int))
315 hangs
= *(const int *) args
;
317 if (hangs
& HAL_BB_HANGS
)
318 ahp
->ah_hangs
|= ar5416DetectBBHang(ah
);
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
500 #endif /* AH_SUPPORT_AR5416 */