ar5416_misc.c revision 220323
1168404Spjd/* 2168404Spjd * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3168404Spjd * Copyright (c) 2002-2008 Atheros Communications, Inc. 4168404Spjd * 5168404Spjd * Permission to use, copy, modify, and/or distribute this software for any 6168404Spjd * purpose with or without fee is hereby granted, provided that the above 7168404Spjd * copyright notice and this permission notice appear in all copies. 8168404Spjd * 9168404Spjd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10168404Spjd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11168404Spjd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12168404Spjd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13168404Spjd * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14168404Spjd * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15168404Spjd * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16168404Spjd * 17168404Spjd * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 220323 2011-04-04 11:01:53Z adrian $ 18168404Spjd */ 19168404Spjd#include "opt_ah.h" 20168404Spjd 21168404Spjd#include "ah.h" 22168404Spjd#include "ah_internal.h" 23219089Spjd#include "ah_devid.h" 24227497Smm#ifdef AH_DEBUG 25236155Smm#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 26236145Smm#endif 27236155Smm 28168404Spjd#include "ar5416/ar5416.h" 29168404Spjd#include "ar5416/ar5416reg.h" 30168404Spjd#include "ar5416/ar5416phy.h" 31168404Spjd 32168404Spjd/* 33168404Spjd * Return the wireless modes (a,b,g,n,t) supported by hardware. 34168404Spjd * 35168404Spjd * This value is what is actually supported by the hardware 36168404Spjd * and is unaffected by regulatory/country code settings. 37168404Spjd * 38168404Spjd */ 39168404Spjdu_int 40168404Spjdar5416GetWirelessModes(struct ath_hal *ah) 41168404Spjd{ 42168404Spjd u_int mode; 43168404Spjd struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 44168404Spjd HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; 45168404Spjd 46185029Spjd mode = ar5212GetWirelessModes(ah); 47185029Spjd 48168404Spjd /* Only enable HT modes if the NIC supports HT */ 49236155Smm if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A)) 50168404Spjd mode |= HAL_MODE_11NA_HT20 51168404Spjd | HAL_MODE_11NA_HT40PLUS 52168404Spjd | HAL_MODE_11NA_HT40MINUS 53168404Spjd ; 54168404Spjd if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G)) 55168404Spjd mode |= HAL_MODE_11NG_HT20 56185029Spjd | HAL_MODE_11NG_HT40PLUS 57236884Smm | HAL_MODE_11NG_HT40MINUS 58168404Spjd ; 59219089Spjd return mode; 60219089Spjd} 61168404Spjd 62168404Spjd/* 63168404Spjd * Change the LED blinking pattern to correspond to the connectivity 64168404Spjd */ 65168404Spjdvoid 66224171Sgibbsar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 67168404Spjd{ 68168404Spjd static const uint32_t ledbits[8] = { 69168404Spjd AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 70168404Spjd AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 71168404Spjd AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 72168404Spjd AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 73168404Spjd AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 74168404Spjd AR_MAC_LED_ASSOC_NONE, 75236155Smm AR_MAC_LED_ASSOC_NONE, 76168404Spjd AR_MAC_LED_ASSOC_NONE, 77228103Smm }; 78228103Smm uint32_t bits; 79168404Spjd 80168404Spjd bits = OS_REG_READ(ah, AR_MAC_LED); 81168404Spjd bits = (bits &~ AR_MAC_LED_MODE) 82219089Spjd | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 83168404Spjd#if 1 84168404Spjd | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 85168404Spjd#endif 86168404Spjd ; 87168404Spjd bits = (bits &~ AR_MAC_LED_ASSOC) 88168404Spjd | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 89168404Spjd OS_REG_WRITE(ah, AR_MAC_LED, bits); 90168404Spjd} 91168404Spjd 92168404Spjd/* 93168404Spjd * Reset the current hardware tsf for stamlme. 94168404Spjd */ 95168404Spjdvoid 96168404Spjdar5416ResetTsf(struct ath_hal *ah) 97168404Spjd{ 98168404Spjd uint32_t v; 99168404Spjd int i; 100185029Spjd 101185029Spjd for (i = 0; i < 10; i++) { 102168404Spjd v = OS_REG_READ(ah, AR_SLP32_MODE); 103168404Spjd if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 104168404Spjd break; 105168404Spjd OS_DELAY(10); 106168404Spjd } 107168404Spjd OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 108168404Spjd} 109168404Spjd 110168404SpjdHAL_BOOL 111168404Spjdar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 112168404Spjd{ 113185029Spjd return AH_TRUE; 114168404Spjd} 115168404Spjd 116168404Spjd/* Setup decompression for given key index */ 117168404SpjdHAL_BOOL 118168404Spjdar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 119168404Spjd{ 120168404Spjd return HAL_OK; 121168404Spjd} 122168404Spjd 123168404Spjd/* Setup coverage class */ 124168404Spjdvoid 125168404Spjdar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 126224171Sgibbs{ 127168404Spjd AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 128168404Spjd} 129168404Spjd 130168404Spjd/* 131168404Spjd * Return approximation of extension channel busy over an time interval 132168404Spjd * 0% (clear) -> 100% (busy) 133168404Spjd * 134168404Spjd */ 135168404Spjduint32_t 136219089Spjdar5416Get11nExtBusy(struct ath_hal *ah) 137228103Smm{ 138236155Smm struct ath_hal_5416 *ahp = AH5416(ah); 139236155Smm uint32_t busy; /* percentage */ 140168404Spjd uint32_t cycleCount, ctlBusy, extBusy; 141168404Spjd 142168404Spjd ctlBusy = OS_REG_READ(ah, AR_RCCNT); 143168404Spjd extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 144168404Spjd cycleCount = OS_REG_READ(ah, AR_CCCNT); 145168404Spjd 146168404Spjd if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 147168404Spjd /* 148168404Spjd * Cycle counter wrap (or initial call); it's not possible 149168404Spjd * to accurately calculate a value because the registers 150168404Spjd * right shift rather than wrap--so punt and return 0. 151168404Spjd */ 152168404Spjd busy = 0; 153168404Spjd HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 154168404Spjd __func__); 155168404Spjd 156168404Spjd } else { 157168404Spjd uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 158168404Spjd uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 159168404Spjd uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 160168404Spjd uint32_t ctlClearDelta = 0; 161168404Spjd 162168404Spjd /* Compute control channel rxclear. 163168404Spjd * The cycle delta may be less than the control channel delta. 164168404Spjd * This could be solved by freezing the timers (or an atomic read, 165224171Sgibbs * if one was available). Checking for the condition should be 166224171Sgibbs * sufficient. 167168404Spjd */ 168168404Spjd if (cycleDelta > ctlBusyDelta) { 169168404Spjd ctlClearDelta = cycleDelta - ctlBusyDelta; 170168404Spjd } 171168404Spjd 172168404Spjd /* Compute ratio of extension channel busy to control channel clear 173168404Spjd * as an approximation to extension channel cleanliness. 174236155Smm * 175168404Spjd * According to the hardware folks, ext rxclear is undefined 176168404Spjd * if the ctrl rxclear is de-asserted (i.e. busy) 177168404Spjd */ 178168404Spjd if (ctlClearDelta) { 179219089Spjd busy = (extBusyDelta * 100) / ctlClearDelta; 180168404Spjd } else { 181168404Spjd busy = 100; 182168404Spjd } 183168404Spjd if (busy > 100) { 184168404Spjd busy = 100; 185168404Spjd } 186228103Smm#if 0 187168404Spjd HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 188168404Spjd "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 189168404Spjd "busy %d\n", 190168404Spjd __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 191168404Spjd#endif 192168404Spjd } 193168404Spjd 194168404Spjd ahp->ah_cycleCount = cycleCount; 195248571Smm ahp->ah_ctlBusy = ctlBusy; 196185029Spjd ahp->ah_extBusy = extBusy; 197248571Smm 198219089Spjd return busy; 199219089Spjd} 200168404Spjd 201168404Spjd/* 202168404Spjd * Configure 20/40 operation 203168404Spjd * 204168404Spjd * 20/40 = joint rx clear (control and extension) 205168404Spjd * 20 = rx clear (control) 206168404Spjd * 207185029Spjd * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 208168404Spjd * from 20/40 => 20 only 209219089Spjd */ 210168404Spjdvoid 211236884Smmar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 212185029Spjd{ 213185029Spjd uint32_t macmode; 214168404Spjd 215168404Spjd /* Configure MAC for 20/40 operation */ 216168404Spjd if (mode == HAL_HT_MACMODE_2040) { 217168404Spjd macmode = AR_2040_JOINED_RX_CLEAR; 218168404Spjd } else { 219168404Spjd macmode = 0; 220168404Spjd } 221185029Spjd OS_REG_WRITE(ah, AR_2040_MODE, macmode); 222168404Spjd} 223168404Spjd 224219089Spjd/* 225185029Spjd * Get Rx clear (control/extension channel) 226219089Spjd * 227219089Spjd * Returns active low (busy) for ctrl/ext channel 228185029Spjd * Owl 2.0 229219089Spjd */ 230219089SpjdHAL_HT_RXCLEAR 231219089Spjdar5416Get11nRxClear(struct ath_hal *ah) 232168404Spjd{ 233219089Spjd HAL_HT_RXCLEAR rxclear = 0; 234168404Spjd uint32_t val; 235224171Sgibbs 236224171Sgibbs val = OS_REG_READ(ah, AR_DIAG_SW); 237168404Spjd 238236960Smm /* control channel */ 239219089Spjd if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 240168404Spjd rxclear |= HAL_RX_CLEAR_CTL_LOW; 241168404Spjd } 242168404Spjd /* extension channel */ 243228020Smm if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 244168404Spjd rxclear |= HAL_RX_CLEAR_EXT_LOW; 245168404Spjd } 246185029Spjd return rxclear; 247168404Spjd} 248185029Spjd 249236155Smm/* 250236155Smm * Set Rx clear (control/extension channel) 251168404Spjd * 252168404Spjd * Useful for forcing the channel to appear busy for 253168404Spjd * debugging/diagnostics 254219089Spjd * Owl 2.0 255219089Spjd */ 256168404Spjdvoid 257228020Smmar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 258185029Spjd{ 259168404Spjd /* control channel */ 260185029Spjd if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 261168404Spjd OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 262168404Spjd } else { 263168404Spjd OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 264219089Spjd } 265219089Spjd /* extension channel */ 266219089Spjd if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 267219089Spjd OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 268228103Smm } else { 269228103Smm OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 270168404Spjd } 271168404Spjd} 272168404Spjd 273168404SpjdHAL_STATUS 274168404Spjdar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 275168404Spjd uint32_t capability, uint32_t *result) 276168404Spjd{ 277168404Spjd switch (type) { 278168404Spjd case HAL_CAP_BB_HANG: 279168404Spjd switch (capability) { 280185029Spjd case HAL_BB_HANG_RIFS: 281185029Spjd return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 282168404Spjd case HAL_BB_HANG_DFS: 283168404Spjd return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 284168404Spjd case HAL_BB_HANG_RX_CLEAR: 285219089Spjd return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 286168404Spjd } 287185029Spjd break; 288185029Spjd case HAL_CAP_MAC_HANG: 289185029Spjd return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 290219089Spjd (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 291185029Spjd AR_SREV_SOWL(ah)) ? 292168404Spjd HAL_OK : HAL_ENOTSUPP; 293168404Spjd default: 294168404Spjd break; 295168404Spjd } 296168404Spjd return ar5212GetCapability(ah, type, capability, result); 297185029Spjd} 298168404Spjd 299168404Spjdstatic int ar5416DetectMacHang(struct ath_hal *ah); 300168404Spjdstatic int ar5416DetectBBHang(struct ath_hal *ah); 301168404Spjd 302168404SpjdHAL_BOOL 303168404Spjdar5416GetDiagState(struct ath_hal *ah, int request, 304168404Spjd const void *args, uint32_t argsize, 305168404Spjd void **result, uint32_t *resultsize) 306168404Spjd{ 307168404Spjd struct ath_hal_5416 *ahp = AH5416(ah); 308168404Spjd int hangs; 309168404Spjd 310168404Spjd if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 311168404Spjd return AH_TRUE; 312168404Spjd switch (request) { 313168404Spjd case HAL_DIAG_EEPROM: 314168404Spjd return ath_hal_eepromDiag(ah, request, 315168404Spjd args, argsize, result, resultsize); 316168404Spjd case HAL_DIAG_CHECK_HANGS: 317168404Spjd if (argsize != sizeof(int)) 318168404Spjd return AH_FALSE; 319168404Spjd hangs = *(const int *) args; 320168404Spjd ahp->ah_hangs = 0; 321168404Spjd if (hangs & HAL_BB_HANGS) 322168404Spjd ahp->ah_hangs |= ar5416DetectBBHang(ah); 323168404Spjd /* NB: if BB is hung MAC will be hung too so skip check */ 324168404Spjd if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 325168404Spjd ahp->ah_hangs |= ar5416DetectMacHang(ah); 326168404Spjd *result = &ahp->ah_hangs; 327168404Spjd *resultsize = sizeof(ahp->ah_hangs); 328168404Spjd return AH_TRUE; 329168404Spjd } 330168404Spjd return ar5212GetDiagState(ah, request, 331185029Spjd args, argsize, result, resultsize); 332185029Spjd} 333168404Spjd 334168404Spjdtypedef struct { 335168404Spjd uint32_t dma_dbg_3; 336168404Spjd uint32_t dma_dbg_4; 337219089Spjd uint32_t dma_dbg_5; 338185029Spjd uint32_t dma_dbg_6; 339168404Spjd} mac_dbg_regs_t; 340168404Spjd 341185029Spjdtypedef enum { 342185029Spjd dcu_chain_state = 0x1, 343236884Smm dcu_complete_state = 0x2, 344236884Smm qcu_state = 0x4, 345236884Smm qcu_fsp_ok = 0x8, 346236884Smm qcu_fsp_state = 0x10, 347236884Smm qcu_stitch_state = 0x20, 348243014Smm qcu_fetch_state = 0x40, 349168404Spjd qcu_complete_state = 0x80 350168404Spjd} hal_mac_hangs_t; 351168404Spjd 352168404Spjdtypedef struct { 353168404Spjd int states; 354168404Spjd uint8_t dcu_chain_state; 355168404Spjd uint8_t dcu_complete_state; 356168404Spjd uint8_t qcu_state; 357168404Spjd uint8_t qcu_fsp_ok; 358168404Spjd uint8_t qcu_fsp_state; 359168404Spjd uint8_t qcu_stitch_state; 360168404Spjd uint8_t qcu_fetch_state; 361168404Spjd uint8_t qcu_complete_state; 362168404Spjd} hal_mac_hang_check_t; 363185029Spjd 364185029Spjdstatic HAL_BOOL 365168404Spjdar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 366168404Spjd const hal_mac_hang_check_t *check) 367168404Spjd{ 368168404Spjd int found_states; 369168404Spjd 370168404Spjd found_states = 0; 371168404Spjd if (check->states & dcu_chain_state) { 372168404Spjd int i; 373168404Spjd 374168404Spjd for (i = 0; i < 6; i++) { 375168404Spjd if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 376168404Spjd check->dcu_chain_state) 377168404Spjd found_states |= dcu_chain_state; 378185029Spjd } 379185029Spjd for (i = 0; i < 4; i++) { 380185029Spjd if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 381185029Spjd check->dcu_chain_state) 382185029Spjd found_states |= dcu_chain_state; 383185029Spjd } 384185029Spjd } 385219089Spjd if (check->states & dcu_complete_state) { 386185029Spjd if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 387185029Spjd found_states |= dcu_complete_state; 388168404Spjd } 389168404Spjd if (check->states & qcu_stitch_state) { 390168404Spjd if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 391168404Spjd found_states |= qcu_stitch_state; 392238926Smm } 393238926Smm if (check->states & qcu_fetch_state) { 394238926Smm if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 395238926Smm found_states |= qcu_fetch_state; 396238926Smm } 397238926Smm if (check->states & qcu_complete_state) { 398238926Smm if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 399238926Smm found_states |= qcu_complete_state; 400238926Smm } 401238926Smm return (found_states == check->states); 402238926Smm} 403238926Smm 404168404Spjd#define NUM_STATUS_READS 50 405185029Spjd 406185029Spjdstatic int 407185029Spjdar5416DetectMacHang(struct ath_hal *ah) 408185029Spjd{ 409185029Spjd static const hal_mac_hang_check_t hang_sig1 = { 410185029Spjd .dcu_chain_state = 0x6, 411185029Spjd .dcu_complete_state = 0x1, 412185029Spjd .states = dcu_chain_state 413185029Spjd | dcu_complete_state, 414185029Spjd }; 415185029Spjd static const hal_mac_hang_check_t hang_sig2 = { 416185029Spjd .qcu_stitch_state = 0x9, 417185029Spjd .qcu_fetch_state = 0x8, 418185029Spjd .qcu_complete_state = 0x4, 419185029Spjd .states = qcu_stitch_state 420185029Spjd | qcu_fetch_state 421185029Spjd | qcu_complete_state, 422185029Spjd }; 423185029Spjd mac_dbg_regs_t mac_dbg; 424185029Spjd int i; 425185029Spjd 426185029Spjd mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 427238926Smm mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 428238926Smm mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 429236884Smm mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 430236884Smm for (i = 1; i <= NUM_STATUS_READS; i++) { 431185029Spjd if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 432185029Spjd mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 433185029Spjd mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 434185029Spjd mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 435238926Smm return 0; 436238926Smm } 437238926Smm 438238926Smm if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 439238926Smm return HAL_MAC_HANG_SIG1; 440238926Smm if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 441238926Smm return HAL_MAC_HANG_SIG2; 442238926Smm 443238926Smm HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " 444238926Smm "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 445238926Smm __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 446238926Smm mac_dbg.dma_dbg_6); 447238926Smm 448238926Smm return HAL_MAC_HANG_UNKNOWN; 449238926Smm} 450238926Smm 451236884Smm/* 452236884Smm * Determine if the baseband using the Observation Bus Register 453236884Smm */ 454236884Smmstatic int 455185029Spjdar5416DetectBBHang(struct ath_hal *ah) 456209962Smm{ 457209962Smm#define N(a) (sizeof(a)/sizeof(a[0])) 458209962Smm /* 459209962Smm * Check the PCU Observation Bus 1 register (0x806c) 460185029Spjd * NUM_STATUS_READS times 461185029Spjd * 462185029Spjd * 4 known BB hang signatures - 463185029Spjd * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 464185029Spjd * [2] bits 8,9 are 1, bit 11 is 0. State machine state 465185029Spjd * (bits 25-31) is 0x52 466185029Spjd * [3] bits 8,9 are 1, bit 11 is 0. State machine state 467185029Spjd * (bits 25-31) is 0x18 468185029Spjd * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 469185029Spjd * Rx State (bits 20-24) is 0x7. 470185029Spjd */ 471185029Spjd static const struct { 472185029Spjd uint32_t val; 473185029Spjd uint32_t mask; 474185029Spjd int code; 475185029Spjd } hang_list[] = { 476185029Spjd /* Reg Value Reg Mask Hang Code XXX */ 477185029Spjd { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 478185029Spjd { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 479185029Spjd { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 480168404Spjd { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 481168404Spjd }; 482168404Spjd uint32_t hang_sig; 483168404Spjd int i; 484168404Spjd 485168404Spjd hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 486168404Spjd for (i = 1; i <= NUM_STATUS_READS; i++) { 487168404Spjd if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 488168404Spjd return 0; 489168404Spjd } 490168404Spjd for (i = 0; i < N(hang_list); i++) 491168404Spjd if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 492168404Spjd HALDEBUG(ah, HAL_DEBUG_ANY, 493168404Spjd "%s BB hang, signature 0x%x, code 0x%x\n", 494168404Spjd __func__, hang_sig, hang_list[i].code); 495168404Spjd return hang_list[i].code; 496168404Spjd } 497168404Spjd 498168404Spjd HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " 499168404Spjd "<0x806c>=0x%x\n", __func__, hang_sig); 500168404Spjd 501168404Spjd return HAL_BB_HANG_UNKNOWN; 502168404Spjd#undef N 503168404Spjd} 504168404Spjd#undef NUM_STATUS_READS 505168404Spjd