ar5416_misc.c revision 203158
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 * 17203158Srpaulo * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 203158 2010-01-29 10:07:17Z rpaulo $ 18185377Ssam */ 19185377Ssam#include "opt_ah.h" 20185377Ssam 21185377Ssam#include "ah.h" 22185377Ssam#include "ah_internal.h" 23185377Ssam#include "ah_devid.h" 24185377Ssam#ifdef AH_DEBUG 25185377Ssam#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 26185377Ssam#endif 27185377Ssam 28185377Ssam#include "ar5416/ar5416.h" 29185377Ssam#include "ar5416/ar5416reg.h" 30185377Ssam#include "ar5416/ar5416phy.h" 31185377Ssam 32185377Ssam/* 33185377Ssam * Return the wireless modes (a,b,g,t) supported by hardware. 34185377Ssam * 35185377Ssam * This value is what is actually supported by the hardware 36185377Ssam * and is unaffected by regulatory/country code settings. 37185377Ssam * 38185377Ssam */ 39185377Ssamu_int 40185377Ssamar5416GetWirelessModes(struct ath_hal *ah) 41185377Ssam{ 42185377Ssam u_int mode; 43185377Ssam 44185377Ssam mode = ar5212GetWirelessModes(ah); 45185377Ssam if (mode & HAL_MODE_11A) 46185377Ssam mode |= HAL_MODE_11NA_HT20 47185377Ssam | HAL_MODE_11NA_HT40PLUS 48185377Ssam | HAL_MODE_11NA_HT40MINUS 49185377Ssam ; 50185377Ssam if (mode & HAL_MODE_11G) 51185377Ssam mode |= HAL_MODE_11NG_HT20 52185377Ssam | HAL_MODE_11NG_HT40PLUS 53185377Ssam | HAL_MODE_11NG_HT40MINUS 54185377Ssam ; 55185377Ssam return mode; 56185377Ssam} 57185377Ssam 58185377Ssam/* 59185377Ssam * Change the LED blinking pattern to correspond to the connectivity 60185377Ssam */ 61185377Ssamvoid 62185377Ssamar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 63185377Ssam{ 64185377Ssam static const uint32_t ledbits[8] = { 65185377Ssam AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 66185377Ssam AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 67185377Ssam AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 68185377Ssam AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 69185377Ssam AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 70185377Ssam AR_MAC_LED_ASSOC_NONE, 71185377Ssam AR_MAC_LED_ASSOC_NONE, 72185377Ssam AR_MAC_LED_ASSOC_NONE, 73185377Ssam }; 74185377Ssam uint32_t bits; 75185377Ssam 76185377Ssam bits = OS_REG_READ(ah, AR_MAC_LED); 77185377Ssam bits = (bits &~ AR_MAC_LED_MODE) 78185377Ssam | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 79185377Ssam#if 1 80185377Ssam | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 81185377Ssam#endif 82185377Ssam ; 83185377Ssam bits = (bits &~ AR_MAC_LED_ASSOC) 84185377Ssam | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 85185377Ssam OS_REG_WRITE(ah, AR_MAC_LED, bits); 86185377Ssam} 87185377Ssam 88185377Ssam/* 89185377Ssam * Reset the current hardware tsf for stamlme. 90185377Ssam */ 91185377Ssamvoid 92185377Ssamar5416ResetTsf(struct ath_hal *ah) 93185377Ssam{ 94185377Ssam uint32_t v; 95185377Ssam int i; 96185377Ssam 97185377Ssam for (i = 0; i < 10; i++) { 98185377Ssam v = OS_REG_READ(ah, AR_SLP32_MODE); 99185377Ssam if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 100185377Ssam break; 101185377Ssam OS_DELAY(10); 102185377Ssam } 103185377Ssam OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 104185377Ssam} 105185377Ssam 106185377SsamHAL_BOOL 107185377Ssamar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 108185377Ssam{ 109185377Ssam return AH_TRUE; 110185377Ssam} 111185377Ssam 112185377Ssam/* Setup decompression for given key index */ 113185377SsamHAL_BOOL 114185377Ssamar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 115185377Ssam{ 116185377Ssam return HAL_OK; 117185377Ssam} 118185377Ssam 119185377Ssam/* Setup coverage class */ 120185377Ssamvoid 121185377Ssamar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 122185377Ssam{ 123185377Ssam} 124185377Ssam 125185377Ssam/* 126185377Ssam * Return approximation of extension channel busy over an time interval 127185377Ssam * 0% (clear) -> 100% (busy) 128185377Ssam * 129185377Ssam */ 130185377Ssamuint32_t 131185377Ssamar5416Get11nExtBusy(struct ath_hal *ah) 132185377Ssam{ 133185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 134185377Ssam uint32_t busy; /* percentage */ 135185377Ssam uint32_t cycleCount, ctlBusy, extBusy; 136185377Ssam 137185377Ssam ctlBusy = OS_REG_READ(ah, AR_RCCNT); 138185377Ssam extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 139185377Ssam cycleCount = OS_REG_READ(ah, AR_CCCNT); 140185377Ssam 141185377Ssam if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 142185377Ssam /* 143185377Ssam * Cycle counter wrap (or initial call); it's not possible 144185377Ssam * to accurately calculate a value because the registers 145185377Ssam * right shift rather than wrap--so punt and return 0. 146185377Ssam */ 147185377Ssam busy = 0; 148185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 149185377Ssam __func__); 150185377Ssam 151185377Ssam } else { 152185377Ssam uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 153185377Ssam uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 154185377Ssam uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 155185377Ssam uint32_t ctlClearDelta = 0; 156185377Ssam 157185377Ssam /* Compute control channel rxclear. 158185377Ssam * The cycle delta may be less than the control channel delta. 159185377Ssam * This could be solved by freezing the timers (or an atomic read, 160185377Ssam * if one was available). Checking for the condition should be 161185377Ssam * sufficient. 162185377Ssam */ 163185377Ssam if (cycleDelta > ctlBusyDelta) { 164185377Ssam ctlClearDelta = cycleDelta - ctlBusyDelta; 165185377Ssam } 166185377Ssam 167185377Ssam /* Compute ratio of extension channel busy to control channel clear 168185377Ssam * as an approximation to extension channel cleanliness. 169185377Ssam * 170185377Ssam * According to the hardware folks, ext rxclear is undefined 171185377Ssam * if the ctrl rxclear is de-asserted (i.e. busy) 172185377Ssam */ 173185377Ssam if (ctlClearDelta) { 174185377Ssam busy = (extBusyDelta * 100) / ctlClearDelta; 175185377Ssam } else { 176185377Ssam busy = 100; 177185377Ssam } 178185377Ssam if (busy > 100) { 179185377Ssam busy = 100; 180185377Ssam } 181185377Ssam#if 0 182185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 183185377Ssam "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 184185377Ssam "busy %d\n", 185185377Ssam __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 186185377Ssam#endif 187185377Ssam } 188185377Ssam 189185377Ssam ahp->ah_cycleCount = cycleCount; 190185377Ssam ahp->ah_ctlBusy = ctlBusy; 191185377Ssam ahp->ah_extBusy = extBusy; 192185377Ssam 193185377Ssam return busy; 194185377Ssam} 195185377Ssam 196185377Ssam/* 197185377Ssam * Configure 20/40 operation 198185377Ssam * 199185377Ssam * 20/40 = joint rx clear (control and extension) 200185377Ssam * 20 = rx clear (control) 201185377Ssam * 202185377Ssam * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 203185377Ssam * from 20/40 => 20 only 204185377Ssam */ 205185377Ssamvoid 206185377Ssamar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 207185377Ssam{ 208185377Ssam uint32_t macmode; 209185377Ssam 210185377Ssam /* Configure MAC for 20/40 operation */ 211185377Ssam if (mode == HAL_HT_MACMODE_2040) { 212185377Ssam macmode = AR_2040_JOINED_RX_CLEAR; 213185377Ssam } else { 214185377Ssam macmode = 0; 215185377Ssam } 216185377Ssam OS_REG_WRITE(ah, AR_2040_MODE, macmode); 217185377Ssam} 218185377Ssam 219185377Ssam/* 220185377Ssam * Get Rx clear (control/extension channel) 221185377Ssam * 222185377Ssam * Returns active low (busy) for ctrl/ext channel 223185377Ssam * Owl 2.0 224185377Ssam */ 225185377SsamHAL_HT_RXCLEAR 226185377Ssamar5416Get11nRxClear(struct ath_hal *ah) 227185377Ssam{ 228185377Ssam HAL_HT_RXCLEAR rxclear = 0; 229185377Ssam uint32_t val; 230185377Ssam 231185377Ssam val = OS_REG_READ(ah, AR_DIAG_SW); 232185377Ssam 233185377Ssam /* control channel */ 234185377Ssam if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 235185377Ssam rxclear |= HAL_RX_CLEAR_CTL_LOW; 236185377Ssam } 237185377Ssam /* extension channel */ 238185377Ssam if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 239185377Ssam rxclear |= HAL_RX_CLEAR_EXT_LOW; 240185377Ssam } 241185377Ssam return rxclear; 242185377Ssam} 243185377Ssam 244185377Ssam/* 245185377Ssam * Set Rx clear (control/extension channel) 246185377Ssam * 247185377Ssam * Useful for forcing the channel to appear busy for 248185377Ssam * debugging/diagnostics 249185377Ssam * Owl 2.0 250185377Ssam */ 251185377Ssamvoid 252185377Ssamar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 253185377Ssam{ 254185377Ssam /* control channel */ 255185377Ssam if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 256185377Ssam OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 257185377Ssam } else { 258185377Ssam OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 259185377Ssam } 260185377Ssam /* extension channel */ 261185377Ssam if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 262185377Ssam OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 263185377Ssam } else { 264185377Ssam OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 265185377Ssam } 266185377Ssam} 267185377Ssam 268185377SsamHAL_STATUS 269185377Ssamar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 270185377Ssam uint32_t capability, uint32_t *result) 271185377Ssam{ 272185377Ssam switch (type) { 273185377Ssam case HAL_CAP_BB_HANG: 274185377Ssam switch (capability) { 275185377Ssam case HAL_BB_HANG_RIFS: 276185377Ssam return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 277185377Ssam case HAL_BB_HANG_DFS: 278185380Ssam return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 279185377Ssam case HAL_BB_HANG_RX_CLEAR: 280185377Ssam return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 281185377Ssam } 282185377Ssam break; 283185377Ssam case HAL_CAP_MAC_HANG: 284185377Ssam return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 285185377Ssam (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 286185380Ssam AR_SREV_SOWL(ah)) ? 287185380Ssam HAL_OK : HAL_ENOTSUPP; 288185377Ssam default: 289185377Ssam break; 290185377Ssam } 291185377Ssam return ar5212GetCapability(ah, type, capability, result); 292185377Ssam} 293185377Ssam 294185377Ssamstatic int ar5416DetectMacHang(struct ath_hal *ah); 295185377Ssamstatic int ar5416DetectBBHang(struct ath_hal *ah); 296185377Ssam 297185377SsamHAL_BOOL 298185377Ssamar5416GetDiagState(struct ath_hal *ah, int request, 299185377Ssam const void *args, uint32_t argsize, 300185377Ssam void **result, uint32_t *resultsize) 301185377Ssam{ 302185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 303185377Ssam int hangs; 304185377Ssam 305185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 306185377Ssam return AH_TRUE; 307185377Ssam switch (request) { 308185377Ssam case HAL_DIAG_EEPROM: 309185377Ssam return ath_hal_eepromDiag(ah, request, 310185377Ssam args, argsize, result, resultsize); 311185377Ssam case HAL_DIAG_CHECK_HANGS: 312185377Ssam if (argsize != sizeof(int)) 313185377Ssam return AH_FALSE; 314185377Ssam hangs = *(const int *) args; 315185377Ssam ahp->ah_hangs = 0; 316185377Ssam if (hangs & HAL_BB_HANGS) 317185377Ssam ahp->ah_hangs |= ar5416DetectBBHang(ah); 318185380Ssam /* NB: if BB is hung MAC will be hung too so skip check */ 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 500