ar5416_misc.c revision 185377
1185377Ssam/* 2185377Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc. 4185377Ssam * 5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any 6185377Ssam * purpose with or without fee is hereby granted, provided that the above 7185377Ssam * copyright notice and this permission notice appear in all copies. 8185377Ssam * 9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16185377Ssam * 17185377Ssam * $Id: ar5416_misc.c,v 1.9 2008/11/10 04:08:04 sam Exp $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#ifdef AH_SUPPORT_AR5416 22185377Ssam 23185377Ssam#include "ah.h" 24185377Ssam#include "ah_internal.h" 25185377Ssam#include "ah_devid.h" 26185377Ssam#ifdef AH_DEBUG 27185377Ssam#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 28185377Ssam#endif 29185377Ssam 30185377Ssam#include "ar5416/ar5416.h" 31185377Ssam#include "ar5416/ar5416reg.h" 32185377Ssam#include "ar5416/ar5416phy.h" 33185377Ssam 34185377Ssam/* 35185377Ssam * Return the wireless modes (a,b,g,t) supported by hardware. 36185377Ssam * 37185377Ssam * This value is what is actually supported by the hardware 38185377Ssam * and is unaffected by regulatory/country code settings. 39185377Ssam * 40185377Ssam */ 41185377Ssamu_int 42185377Ssamar5416GetWirelessModes(struct ath_hal *ah) 43185377Ssam{ 44185377Ssam u_int mode; 45185377Ssam 46185377Ssam mode = ar5212GetWirelessModes(ah); 47185377Ssam if (mode & HAL_MODE_11A) 48185377Ssam mode |= HAL_MODE_11NA_HT20 49185377Ssam | HAL_MODE_11NA_HT40PLUS 50185377Ssam | HAL_MODE_11NA_HT40MINUS 51185377Ssam ; 52185377Ssam if (mode & HAL_MODE_11G) 53185377Ssam mode |= HAL_MODE_11NG_HT20 54185377Ssam | HAL_MODE_11NG_HT40PLUS 55185377Ssam | HAL_MODE_11NG_HT40MINUS 56185377Ssam ; 57185377Ssam return mode; 58185377Ssam} 59185377Ssam 60185377Ssam/* 61185377Ssam * Change the LED blinking pattern to correspond to the connectivity 62185377Ssam */ 63185377Ssamvoid 64185377Ssamar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 65185377Ssam{ 66185377Ssam static const uint32_t ledbits[8] = { 67185377Ssam AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 68185377Ssam AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 69185377Ssam AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 70185377Ssam AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 71185377Ssam AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 72185377Ssam AR_MAC_LED_ASSOC_NONE, 73185377Ssam AR_MAC_LED_ASSOC_NONE, 74185377Ssam AR_MAC_LED_ASSOC_NONE, 75185377Ssam }; 76185377Ssam uint32_t bits; 77185377Ssam 78185377Ssam bits = OS_REG_READ(ah, AR_MAC_LED); 79185377Ssam bits = (bits &~ AR_MAC_LED_MODE) 80185377Ssam | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 81185377Ssam#if 1 82185377Ssam | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 83185377Ssam#endif 84185377Ssam ; 85185377Ssam bits = (bits &~ AR_MAC_LED_ASSOC) 86185377Ssam | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 87185377Ssam OS_REG_WRITE(ah, AR_MAC_LED, bits); 88185377Ssam} 89185377Ssam 90185377Ssam/* 91185377Ssam * Reset the current hardware tsf for stamlme. 92185377Ssam */ 93185377Ssamvoid 94185377Ssamar5416ResetTsf(struct ath_hal *ah) 95185377Ssam{ 96185377Ssam uint32_t v; 97185377Ssam int i; 98185377Ssam 99185377Ssam for (i = 0; i < 10; i++) { 100185377Ssam v = OS_REG_READ(ah, AR_SLP32_MODE); 101185377Ssam if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 102185377Ssam break; 103185377Ssam OS_DELAY(10); 104185377Ssam } 105185377Ssam OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 106185377Ssam} 107185377Ssam 108185377SsamHAL_BOOL 109185377Ssamar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 110185377Ssam{ 111185377Ssam return AH_TRUE; 112185377Ssam} 113185377Ssam 114185377Ssam/* Setup decompression for given key index */ 115185377SsamHAL_BOOL 116185377Ssamar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 117185377Ssam{ 118185377Ssam return HAL_OK; 119185377Ssam} 120185377Ssam 121185377Ssam/* Setup coverage class */ 122185377Ssamvoid 123185377Ssamar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 124185377Ssam{ 125185377Ssam} 126185377Ssam 127185377Ssam/* 128185377Ssam * Return approximation of extension channel busy over an time interval 129185377Ssam * 0% (clear) -> 100% (busy) 130185377Ssam * 131185377Ssam */ 132185377Ssamuint32_t 133185377Ssamar5416Get11nExtBusy(struct ath_hal *ah) 134185377Ssam{ 135185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 136185377Ssam uint32_t busy; /* percentage */ 137185377Ssam uint32_t cycleCount, ctlBusy, extBusy; 138185377Ssam 139185377Ssam ctlBusy = OS_REG_READ(ah, AR_RCCNT); 140185377Ssam extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 141185377Ssam cycleCount = OS_REG_READ(ah, AR_CCCNT); 142185377Ssam 143185377Ssam if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 144185377Ssam /* 145185377Ssam * Cycle counter wrap (or initial call); it's not possible 146185377Ssam * to accurately calculate a value because the registers 147185377Ssam * right shift rather than wrap--so punt and return 0. 148185377Ssam */ 149185377Ssam busy = 0; 150185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 151185377Ssam __func__); 152185377Ssam 153185377Ssam } else { 154185377Ssam uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 155185377Ssam uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 156185377Ssam uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 157185377Ssam uint32_t ctlClearDelta = 0; 158185377Ssam 159185377Ssam /* Compute control channel rxclear. 160185377Ssam * The cycle delta may be less than the control channel delta. 161185377Ssam * This could be solved by freezing the timers (or an atomic read, 162185377Ssam * if one was available). Checking for the condition should be 163185377Ssam * sufficient. 164185377Ssam */ 165185377Ssam if (cycleDelta > ctlBusyDelta) { 166185377Ssam ctlClearDelta = cycleDelta - ctlBusyDelta; 167185377Ssam } 168185377Ssam 169185377Ssam /* Compute ratio of extension channel busy to control channel clear 170185377Ssam * as an approximation to extension channel cleanliness. 171185377Ssam * 172185377Ssam * According to the hardware folks, ext rxclear is undefined 173185377Ssam * if the ctrl rxclear is de-asserted (i.e. busy) 174185377Ssam */ 175185377Ssam if (ctlClearDelta) { 176185377Ssam busy = (extBusyDelta * 100) / ctlClearDelta; 177185377Ssam } else { 178185377Ssam busy = 100; 179185377Ssam } 180185377Ssam if (busy > 100) { 181185377Ssam busy = 100; 182185377Ssam } 183185377Ssam#if 0 184185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 185185377Ssam "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 186185377Ssam "busy %d\n", 187185377Ssam __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 188185377Ssam#endif 189185377Ssam } 190185377Ssam 191185377Ssam ahp->ah_cycleCount = cycleCount; 192185377Ssam ahp->ah_ctlBusy = ctlBusy; 193185377Ssam ahp->ah_extBusy = extBusy; 194185377Ssam 195185377Ssam return busy; 196185377Ssam} 197185377Ssam 198185377Ssam/* 199185377Ssam * Configure 20/40 operation 200185377Ssam * 201185377Ssam * 20/40 = joint rx clear (control and extension) 202185377Ssam * 20 = rx clear (control) 203185377Ssam * 204185377Ssam * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 205185377Ssam * from 20/40 => 20 only 206185377Ssam */ 207185377Ssamvoid 208185377Ssamar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 209185377Ssam{ 210185377Ssam uint32_t macmode; 211185377Ssam 212185377Ssam /* Configure MAC for 20/40 operation */ 213185377Ssam if (mode == HAL_HT_MACMODE_2040) { 214185377Ssam macmode = AR_2040_JOINED_RX_CLEAR; 215185377Ssam } else { 216185377Ssam macmode = 0; 217185377Ssam } 218185377Ssam OS_REG_WRITE(ah, AR_2040_MODE, macmode); 219185377Ssam} 220185377Ssam 221185377Ssam/* 222185377Ssam * Get Rx clear (control/extension channel) 223185377Ssam * 224185377Ssam * Returns active low (busy) for ctrl/ext channel 225185377Ssam * Owl 2.0 226185377Ssam */ 227185377SsamHAL_HT_RXCLEAR 228185377Ssamar5416Get11nRxClear(struct ath_hal *ah) 229185377Ssam{ 230185377Ssam HAL_HT_RXCLEAR rxclear = 0; 231185377Ssam uint32_t val; 232185377Ssam 233185377Ssam val = OS_REG_READ(ah, AR_DIAG_SW); 234185377Ssam 235185377Ssam /* control channel */ 236185377Ssam if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 237185377Ssam rxclear |= HAL_RX_CLEAR_CTL_LOW; 238185377Ssam } 239185377Ssam /* extension channel */ 240185377Ssam if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 241185377Ssam rxclear |= HAL_RX_CLEAR_EXT_LOW; 242185377Ssam } 243185377Ssam return rxclear; 244185377Ssam} 245185377Ssam 246185377Ssam/* 247185377Ssam * Set Rx clear (control/extension channel) 248185377Ssam * 249185377Ssam * Useful for forcing the channel to appear busy for 250185377Ssam * debugging/diagnostics 251185377Ssam * Owl 2.0 252185377Ssam */ 253185377Ssamvoid 254185377Ssamar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 255185377Ssam{ 256185377Ssam /* control channel */ 257185377Ssam if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 258185377Ssam OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 259185377Ssam } else { 260185377Ssam OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 261185377Ssam } 262185377Ssam /* extension channel */ 263185377Ssam if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 264185377Ssam OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 265185377Ssam } else { 266185377Ssam OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 267185377Ssam } 268185377Ssam} 269185377Ssam 270185377SsamHAL_STATUS 271185377Ssamar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 272185377Ssam uint32_t capability, uint32_t *result) 273185377Ssam{ 274185377Ssam switch (type) { 275185377Ssam case HAL_CAP_BB_HANG: 276185377Ssam switch (capability) { 277185377Ssam case HAL_BB_HANG_RIFS: 278185377Ssam return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 279185377Ssam case HAL_BB_HANG_DFS: 280185377Ssam return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 281185377Ssam case HAL_BB_HANG_RX_CLEAR: 282185377Ssam return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 283185377Ssam } 284185377Ssam break; 285185377Ssam case HAL_CAP_MAC_HANG: 286185377Ssam return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 287185377Ssam (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 288185377Ssam AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 289185377Ssam default: 290185377Ssam break; 291185377Ssam } 292185377Ssam return ar5212GetCapability(ah, type, capability, result); 293185377Ssam} 294185377Ssam 295185377Ssamstatic int ar5416DetectMacHang(struct ath_hal *ah); 296185377Ssamstatic int ar5416DetectBBHang(struct ath_hal *ah); 297185377Ssam 298185377SsamHAL_BOOL 299185377Ssamar5416GetDiagState(struct ath_hal *ah, int request, 300185377Ssam const void *args, uint32_t argsize, 301185377Ssam void **result, uint32_t *resultsize) 302185377Ssam{ 303185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 304185377Ssam int hangs; 305185377Ssam 306185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 307185377Ssam return AH_TRUE; 308185377Ssam switch (request) { 309185377Ssam case HAL_DIAG_EEPROM: 310185377Ssam return ath_hal_eepromDiag(ah, request, 311185377Ssam args, argsize, result, resultsize); 312185377Ssam case HAL_DIAG_CHECK_HANGS: 313185377Ssam if (argsize != sizeof(int)) 314185377Ssam return AH_FALSE; 315185377Ssam hangs = *(const int *) args; 316185377Ssam ahp->ah_hangs = 0; 317185377Ssam if (hangs & HAL_BB_HANGS) 318185377Ssam ahp->ah_hangs |= ar5416DetectBBHang(ah); 319185377Ssam if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 320185377Ssam ahp->ah_hangs |= ar5416DetectMacHang(ah); 321185377Ssam *result = &ahp->ah_hangs; 322185377Ssam *resultsize = sizeof(ahp->ah_hangs); 323185377Ssam return AH_TRUE; 324185377Ssam } 325185377Ssam return ar5212GetDiagState(ah, request, 326185377Ssam args, argsize, result, resultsize); 327185377Ssam} 328185377Ssam 329185377Ssamtypedef struct { 330185377Ssam uint32_t dma_dbg_3; 331185377Ssam uint32_t dma_dbg_4; 332185377Ssam uint32_t dma_dbg_5; 333185377Ssam uint32_t dma_dbg_6; 334185377Ssam} mac_dbg_regs_t; 335185377Ssam 336185377Ssamtypedef enum { 337185377Ssam dcu_chain_state = 0x1, 338185377Ssam dcu_complete_state = 0x2, 339185377Ssam qcu_state = 0x4, 340185377Ssam qcu_fsp_ok = 0x8, 341185377Ssam qcu_fsp_state = 0x10, 342185377Ssam qcu_stitch_state = 0x20, 343185377Ssam qcu_fetch_state = 0x40, 344185377Ssam qcu_complete_state = 0x80 345185377Ssam} hal_mac_hangs_t; 346185377Ssam 347185377Ssamtypedef struct { 348185377Ssam int states; 349185377Ssam uint8_t dcu_chain_state; 350185377Ssam uint8_t dcu_complete_state; 351185377Ssam uint8_t qcu_state; 352185377Ssam uint8_t qcu_fsp_ok; 353185377Ssam uint8_t qcu_fsp_state; 354185377Ssam uint8_t qcu_stitch_state; 355185377Ssam uint8_t qcu_fetch_state; 356185377Ssam uint8_t qcu_complete_state; 357185377Ssam} hal_mac_hang_check_t; 358185377Ssam 359185377Ssamstatic HAL_BOOL 360185377Ssamar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 361185377Ssam const hal_mac_hang_check_t *check) 362185377Ssam{ 363185377Ssam int found_states; 364185377Ssam 365185377Ssam found_states = 0; 366185377Ssam if (check->states & dcu_chain_state) { 367185377Ssam int i; 368185377Ssam 369185377Ssam for (i = 0; i < 6; i++) { 370185377Ssam if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 371185377Ssam check->dcu_chain_state) 372185377Ssam found_states |= dcu_chain_state; 373185377Ssam } 374185377Ssam for (i = 0; i < 4; i++) { 375185377Ssam if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 376185377Ssam check->dcu_chain_state) 377185377Ssam found_states |= dcu_chain_state; 378185377Ssam } 379185377Ssam } 380185377Ssam if (check->states & dcu_complete_state) { 381185377Ssam if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 382185377Ssam found_states |= dcu_complete_state; 383185377Ssam } 384185377Ssam if (check->states & qcu_stitch_state) { 385185377Ssam if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 386185377Ssam found_states |= qcu_stitch_state; 387185377Ssam } 388185377Ssam if (check->states & qcu_fetch_state) { 389185377Ssam if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 390185377Ssam found_states |= qcu_fetch_state; 391185377Ssam } 392185377Ssam if (check->states & qcu_complete_state) { 393185377Ssam if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 394185377Ssam found_states |= qcu_complete_state; 395185377Ssam } 396185377Ssam return (found_states == check->states); 397185377Ssam} 398185377Ssam 399185377Ssam#define NUM_STATUS_READS 50 400185377Ssam 401185377Ssamstatic int 402185377Ssamar5416DetectMacHang(struct ath_hal *ah) 403185377Ssam{ 404185377Ssam static const hal_mac_hang_check_t hang_sig1 = { 405185377Ssam .dcu_chain_state = 0x6, 406185377Ssam .dcu_complete_state = 0x1, 407185377Ssam .states = dcu_chain_state 408185377Ssam | dcu_complete_state, 409185377Ssam }; 410185377Ssam static const hal_mac_hang_check_t hang_sig2 = { 411185377Ssam .qcu_stitch_state = 0x9, 412185377Ssam .qcu_fetch_state = 0x8, 413185377Ssam .qcu_complete_state = 0x4, 414185377Ssam .states = qcu_stitch_state 415185377Ssam | qcu_fetch_state 416185377Ssam | qcu_complete_state, 417185377Ssam }; 418185377Ssam mac_dbg_regs_t mac_dbg; 419185377Ssam int i; 420185377Ssam 421185377Ssam mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 422185377Ssam mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 423185377Ssam mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 424185377Ssam mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 425185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 426185377Ssam if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 427185377Ssam mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 428185377Ssam mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 429185377Ssam mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 430185377Ssam return 0; 431185377Ssam } 432185377Ssam 433185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 434185377Ssam return HAL_MAC_HANG_SIG1; 435185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 436185377Ssam return HAL_MAC_HANG_SIG2; 437185377Ssam 438185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " 439185377Ssam "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 440185377Ssam __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 441185377Ssam mac_dbg.dma_dbg_6); 442185377Ssam 443185377Ssam return HAL_MAC_HANG_UNKNOWN; 444185377Ssam} 445185377Ssam 446185377Ssam/* 447185377Ssam * Determine if the baseband using the Observation Bus Register 448185377Ssam */ 449185377Ssamstatic int 450185377Ssamar5416DetectBBHang(struct ath_hal *ah) 451185377Ssam{ 452185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 453185377Ssam /* 454185377Ssam * Check the PCU Observation Bus 1 register (0x806c) 455185377Ssam * NUM_STATUS_READS times 456185377Ssam * 457185377Ssam * 4 known BB hang signatures - 458185377Ssam * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 459185377Ssam * [2] bits 8,9 are 1, bit 11 is 0. State machine state 460185377Ssam * (bits 25-31) is 0x52 461185377Ssam * [3] bits 8,9 are 1, bit 11 is 0. State machine state 462185377Ssam * (bits 25-31) is 0x18 463185377Ssam * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 464185377Ssam * Rx State (bits 20-24) is 0x7. 465185377Ssam */ 466185377Ssam static const struct { 467185377Ssam uint32_t val; 468185377Ssam uint32_t mask; 469185377Ssam int code; 470185377Ssam } hang_list[] = { 471185377Ssam /* Reg Value Reg Mask Hang Code XXX */ 472185377Ssam { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 473185377Ssam { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 474185377Ssam { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 475185377Ssam { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 476185377Ssam }; 477185377Ssam uint32_t hang_sig; 478185377Ssam int i; 479185377Ssam 480185377Ssam hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 481185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 482185377Ssam if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 483185377Ssam return 0; 484185377Ssam } 485185377Ssam for (i = 0; i < N(hang_list); i++) 486185377Ssam if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 487185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 488185377Ssam "%s BB hang, signature 0x%x, code 0x%x\n", 489185377Ssam __func__, hang_sig, hang_list[i].code); 490185377Ssam return hang_list[i].code; 491185377Ssam } 492185377Ssam 493185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " 494185377Ssam "<0x806c>=0x%x\n", __func__, hang_sig); 495185377Ssam 496185377Ssam return HAL_BB_HANG_UNKNOWN; 497185377Ssam#undef N 498185377Ssam} 499185377Ssam#undef NUM_STATUS_READS 500185377Ssam#endif /* AH_SUPPORT_AR5416 */ 501