ar5416_misc.c revision 221163
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 221163 2011-04-28 12:47:40Z adrian $ 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/* 33203750Srpaulo * Return the wireless modes (a,b,g,n,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; 43217634Sadrian struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 44217634Sadrian HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; 45185377Ssam 46185377Ssam mode = ar5212GetWirelessModes(ah); 47217634Sadrian 48217634Sadrian /* Only enable HT modes if the NIC supports HT */ 49217634Sadrian if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A)) 50185377Ssam mode |= HAL_MODE_11NA_HT20 51185377Ssam | HAL_MODE_11NA_HT40PLUS 52185377Ssam | HAL_MODE_11NA_HT40MINUS 53185377Ssam ; 54217634Sadrian if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G)) 55185377Ssam mode |= HAL_MODE_11NG_HT20 56185377Ssam | HAL_MODE_11NG_HT40PLUS 57185377Ssam | HAL_MODE_11NG_HT40MINUS 58185377Ssam ; 59185377Ssam return mode; 60185377Ssam} 61185377Ssam 62185377Ssam/* 63185377Ssam * Change the LED blinking pattern to correspond to the connectivity 64185377Ssam */ 65185377Ssamvoid 66185377Ssamar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 67185377Ssam{ 68185377Ssam static const uint32_t ledbits[8] = { 69185377Ssam AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 70185377Ssam AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 71185377Ssam AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 72185377Ssam AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 73185377Ssam AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 74185377Ssam AR_MAC_LED_ASSOC_NONE, 75185377Ssam AR_MAC_LED_ASSOC_NONE, 76185377Ssam AR_MAC_LED_ASSOC_NONE, 77185377Ssam }; 78185377Ssam uint32_t bits; 79185377Ssam 80221163Sadrian if (AR_SREV_HOWL(ah)) 81221163Sadrian return; 82221163Sadrian 83185377Ssam bits = OS_REG_READ(ah, AR_MAC_LED); 84185377Ssam bits = (bits &~ AR_MAC_LED_MODE) 85185377Ssam | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 86185377Ssam#if 1 87185377Ssam | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 88185377Ssam#endif 89185377Ssam ; 90185377Ssam bits = (bits &~ AR_MAC_LED_ASSOC) 91185377Ssam | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 92185377Ssam OS_REG_WRITE(ah, AR_MAC_LED, bits); 93185377Ssam} 94185377Ssam 95185377Ssam/* 96185377Ssam * Reset the current hardware tsf for stamlme. 97185377Ssam */ 98185377Ssamvoid 99185377Ssamar5416ResetTsf(struct ath_hal *ah) 100185377Ssam{ 101185377Ssam uint32_t v; 102185377Ssam int i; 103185377Ssam 104185377Ssam for (i = 0; i < 10; i++) { 105185377Ssam v = OS_REG_READ(ah, AR_SLP32_MODE); 106185377Ssam if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 107185377Ssam break; 108185377Ssam OS_DELAY(10); 109185377Ssam } 110185377Ssam OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 111185377Ssam} 112185377Ssam 113185377SsamHAL_BOOL 114185377Ssamar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 115185377Ssam{ 116185377Ssam return AH_TRUE; 117185377Ssam} 118185377Ssam 119185377Ssam/* Setup decompression for given key index */ 120185377SsamHAL_BOOL 121185377Ssamar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 122185377Ssam{ 123185377Ssam return HAL_OK; 124185377Ssam} 125185377Ssam 126185377Ssam/* Setup coverage class */ 127185377Ssamvoid 128185377Ssamar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 129185377Ssam{ 130220323Sadrian AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 131185377Ssam} 132185377Ssam 133185377Ssam/* 134185377Ssam * Return approximation of extension channel busy over an time interval 135185377Ssam * 0% (clear) -> 100% (busy) 136185377Ssam * 137185377Ssam */ 138185377Ssamuint32_t 139185377Ssamar5416Get11nExtBusy(struct ath_hal *ah) 140185377Ssam{ 141185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 142185377Ssam uint32_t busy; /* percentage */ 143185377Ssam uint32_t cycleCount, ctlBusy, extBusy; 144185377Ssam 145185377Ssam ctlBusy = OS_REG_READ(ah, AR_RCCNT); 146185377Ssam extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 147185377Ssam cycleCount = OS_REG_READ(ah, AR_CCCNT); 148185377Ssam 149185377Ssam if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 150185377Ssam /* 151185377Ssam * Cycle counter wrap (or initial call); it's not possible 152185377Ssam * to accurately calculate a value because the registers 153185377Ssam * right shift rather than wrap--so punt and return 0. 154185377Ssam */ 155185377Ssam busy = 0; 156185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 157185377Ssam __func__); 158185377Ssam 159185377Ssam } else { 160185377Ssam uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 161185377Ssam uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 162185377Ssam uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 163185377Ssam uint32_t ctlClearDelta = 0; 164185377Ssam 165185377Ssam /* Compute control channel rxclear. 166185377Ssam * The cycle delta may be less than the control channel delta. 167185377Ssam * This could be solved by freezing the timers (or an atomic read, 168185377Ssam * if one was available). Checking for the condition should be 169185377Ssam * sufficient. 170185377Ssam */ 171185377Ssam if (cycleDelta > ctlBusyDelta) { 172185377Ssam ctlClearDelta = cycleDelta - ctlBusyDelta; 173185377Ssam } 174185377Ssam 175185377Ssam /* Compute ratio of extension channel busy to control channel clear 176185377Ssam * as an approximation to extension channel cleanliness. 177185377Ssam * 178185377Ssam * According to the hardware folks, ext rxclear is undefined 179185377Ssam * if the ctrl rxclear is de-asserted (i.e. busy) 180185377Ssam */ 181185377Ssam if (ctlClearDelta) { 182185377Ssam busy = (extBusyDelta * 100) / ctlClearDelta; 183185377Ssam } else { 184185377Ssam busy = 100; 185185377Ssam } 186185377Ssam if (busy > 100) { 187185377Ssam busy = 100; 188185377Ssam } 189185377Ssam#if 0 190185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 191185377Ssam "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 192185377Ssam "busy %d\n", 193185377Ssam __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 194185377Ssam#endif 195185377Ssam } 196185377Ssam 197185377Ssam ahp->ah_cycleCount = cycleCount; 198185377Ssam ahp->ah_ctlBusy = ctlBusy; 199185377Ssam ahp->ah_extBusy = extBusy; 200185377Ssam 201185377Ssam return busy; 202185377Ssam} 203185377Ssam 204185377Ssam/* 205185377Ssam * Configure 20/40 operation 206185377Ssam * 207185377Ssam * 20/40 = joint rx clear (control and extension) 208185377Ssam * 20 = rx clear (control) 209185377Ssam * 210185377Ssam * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 211185377Ssam * from 20/40 => 20 only 212185377Ssam */ 213185377Ssamvoid 214185377Ssamar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 215185377Ssam{ 216185377Ssam uint32_t macmode; 217185377Ssam 218185377Ssam /* Configure MAC for 20/40 operation */ 219185377Ssam if (mode == HAL_HT_MACMODE_2040) { 220185377Ssam macmode = AR_2040_JOINED_RX_CLEAR; 221185377Ssam } else { 222185377Ssam macmode = 0; 223185377Ssam } 224185377Ssam OS_REG_WRITE(ah, AR_2040_MODE, macmode); 225185377Ssam} 226185377Ssam 227185377Ssam/* 228185377Ssam * Get Rx clear (control/extension channel) 229185377Ssam * 230185377Ssam * Returns active low (busy) for ctrl/ext channel 231185377Ssam * Owl 2.0 232185377Ssam */ 233185377SsamHAL_HT_RXCLEAR 234185377Ssamar5416Get11nRxClear(struct ath_hal *ah) 235185377Ssam{ 236185377Ssam HAL_HT_RXCLEAR rxclear = 0; 237185377Ssam uint32_t val; 238185377Ssam 239185377Ssam val = OS_REG_READ(ah, AR_DIAG_SW); 240185377Ssam 241185377Ssam /* control channel */ 242185377Ssam if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 243185377Ssam rxclear |= HAL_RX_CLEAR_CTL_LOW; 244185377Ssam } 245185377Ssam /* extension channel */ 246185377Ssam if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 247185377Ssam rxclear |= HAL_RX_CLEAR_EXT_LOW; 248185377Ssam } 249185377Ssam return rxclear; 250185377Ssam} 251185377Ssam 252185377Ssam/* 253185377Ssam * Set Rx clear (control/extension channel) 254185377Ssam * 255185377Ssam * Useful for forcing the channel to appear busy for 256185377Ssam * debugging/diagnostics 257185377Ssam * Owl 2.0 258185377Ssam */ 259185377Ssamvoid 260185377Ssamar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 261185377Ssam{ 262185377Ssam /* control channel */ 263185377Ssam if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 264185377Ssam OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 265185377Ssam } else { 266185377Ssam OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 267185377Ssam } 268185377Ssam /* extension channel */ 269185377Ssam if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 270185377Ssam OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 271185377Ssam } else { 272185377Ssam OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 273185377Ssam } 274185377Ssam} 275185377Ssam 276185377SsamHAL_STATUS 277185377Ssamar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 278185377Ssam uint32_t capability, uint32_t *result) 279185377Ssam{ 280185377Ssam switch (type) { 281220772Sadrian case HAL_CAP_GTXTO: 282220772Sadrian return HAL_OK; /* All AR5416+ supports Global TX Timeout */ 283185377Ssam case HAL_CAP_BB_HANG: 284185377Ssam switch (capability) { 285185377Ssam case HAL_BB_HANG_RIFS: 286185377Ssam return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 287185377Ssam case HAL_BB_HANG_DFS: 288185380Ssam return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 289185377Ssam case HAL_BB_HANG_RX_CLEAR: 290185377Ssam return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 291185377Ssam } 292185377Ssam break; 293185377Ssam case HAL_CAP_MAC_HANG: 294185377Ssam return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 295185377Ssam (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 296185380Ssam AR_SREV_SOWL(ah)) ? 297185380Ssam HAL_OK : HAL_ENOTSUPP; 298220718Sadrian case HAL_CAP_DIVERSITY: /* disable classic fast diversity */ 299220718Sadrian return HAL_ENXIO; 300185377Ssam default: 301185377Ssam break; 302185377Ssam } 303185377Ssam return ar5212GetCapability(ah, type, capability, result); 304185377Ssam} 305185377Ssam 306185377Ssamstatic int ar5416DetectMacHang(struct ath_hal *ah); 307185377Ssamstatic int ar5416DetectBBHang(struct ath_hal *ah); 308185377Ssam 309185377SsamHAL_BOOL 310185377Ssamar5416GetDiagState(struct ath_hal *ah, int request, 311185377Ssam const void *args, uint32_t argsize, 312185377Ssam void **result, uint32_t *resultsize) 313185377Ssam{ 314185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 315185377Ssam int hangs; 316185377Ssam 317185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 318185377Ssam return AH_TRUE; 319185377Ssam switch (request) { 320185377Ssam case HAL_DIAG_EEPROM: 321185377Ssam return ath_hal_eepromDiag(ah, request, 322185377Ssam args, argsize, result, resultsize); 323185377Ssam case HAL_DIAG_CHECK_HANGS: 324185377Ssam if (argsize != sizeof(int)) 325185377Ssam return AH_FALSE; 326185377Ssam hangs = *(const int *) args; 327185377Ssam ahp->ah_hangs = 0; 328185377Ssam if (hangs & HAL_BB_HANGS) 329185377Ssam ahp->ah_hangs |= ar5416DetectBBHang(ah); 330185380Ssam /* NB: if BB is hung MAC will be hung too so skip check */ 331185377Ssam if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 332185377Ssam ahp->ah_hangs |= ar5416DetectMacHang(ah); 333185377Ssam *result = &ahp->ah_hangs; 334185377Ssam *resultsize = sizeof(ahp->ah_hangs); 335185377Ssam return AH_TRUE; 336185377Ssam } 337185377Ssam return ar5212GetDiagState(ah, request, 338185377Ssam args, argsize, result, resultsize); 339185377Ssam} 340185377Ssam 341185377Ssamtypedef struct { 342185377Ssam uint32_t dma_dbg_3; 343185377Ssam uint32_t dma_dbg_4; 344185377Ssam uint32_t dma_dbg_5; 345185377Ssam uint32_t dma_dbg_6; 346185377Ssam} mac_dbg_regs_t; 347185377Ssam 348185377Ssamtypedef enum { 349185377Ssam dcu_chain_state = 0x1, 350185377Ssam dcu_complete_state = 0x2, 351185377Ssam qcu_state = 0x4, 352185377Ssam qcu_fsp_ok = 0x8, 353185377Ssam qcu_fsp_state = 0x10, 354185377Ssam qcu_stitch_state = 0x20, 355185377Ssam qcu_fetch_state = 0x40, 356185377Ssam qcu_complete_state = 0x80 357185377Ssam} hal_mac_hangs_t; 358185377Ssam 359185377Ssamtypedef struct { 360185377Ssam int states; 361185377Ssam uint8_t dcu_chain_state; 362185377Ssam uint8_t dcu_complete_state; 363185377Ssam uint8_t qcu_state; 364185377Ssam uint8_t qcu_fsp_ok; 365185377Ssam uint8_t qcu_fsp_state; 366185377Ssam uint8_t qcu_stitch_state; 367185377Ssam uint8_t qcu_fetch_state; 368185377Ssam uint8_t qcu_complete_state; 369185377Ssam} hal_mac_hang_check_t; 370185377Ssam 371185377Ssamstatic HAL_BOOL 372185377Ssamar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 373185377Ssam const hal_mac_hang_check_t *check) 374185377Ssam{ 375185377Ssam int found_states; 376185377Ssam 377185377Ssam found_states = 0; 378185377Ssam if (check->states & dcu_chain_state) { 379185377Ssam int i; 380185377Ssam 381185377Ssam for (i = 0; i < 6; i++) { 382185377Ssam if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 383185377Ssam check->dcu_chain_state) 384185377Ssam found_states |= dcu_chain_state; 385185377Ssam } 386185377Ssam for (i = 0; i < 4; i++) { 387185377Ssam if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 388185377Ssam check->dcu_chain_state) 389185377Ssam found_states |= dcu_chain_state; 390185377Ssam } 391185377Ssam } 392185377Ssam if (check->states & dcu_complete_state) { 393185377Ssam if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 394185377Ssam found_states |= dcu_complete_state; 395185377Ssam } 396185377Ssam if (check->states & qcu_stitch_state) { 397185377Ssam if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 398185377Ssam found_states |= qcu_stitch_state; 399185377Ssam } 400185377Ssam if (check->states & qcu_fetch_state) { 401185377Ssam if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 402185377Ssam found_states |= qcu_fetch_state; 403185377Ssam } 404185377Ssam if (check->states & qcu_complete_state) { 405185377Ssam if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 406185377Ssam found_states |= qcu_complete_state; 407185377Ssam } 408185377Ssam return (found_states == check->states); 409185377Ssam} 410185377Ssam 411185377Ssam#define NUM_STATUS_READS 50 412185377Ssam 413185377Ssamstatic int 414185377Ssamar5416DetectMacHang(struct ath_hal *ah) 415185377Ssam{ 416185377Ssam static const hal_mac_hang_check_t hang_sig1 = { 417185377Ssam .dcu_chain_state = 0x6, 418185377Ssam .dcu_complete_state = 0x1, 419185377Ssam .states = dcu_chain_state 420185377Ssam | dcu_complete_state, 421185377Ssam }; 422185377Ssam static const hal_mac_hang_check_t hang_sig2 = { 423185377Ssam .qcu_stitch_state = 0x9, 424185377Ssam .qcu_fetch_state = 0x8, 425185377Ssam .qcu_complete_state = 0x4, 426185377Ssam .states = qcu_stitch_state 427185377Ssam | qcu_fetch_state 428185377Ssam | qcu_complete_state, 429185377Ssam }; 430185377Ssam mac_dbg_regs_t mac_dbg; 431185377Ssam int i; 432185377Ssam 433185377Ssam mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 434185377Ssam mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 435185377Ssam mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 436185377Ssam mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 437185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 438185377Ssam if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 439185377Ssam mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 440185377Ssam mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 441185377Ssam mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 442185377Ssam return 0; 443185377Ssam } 444185377Ssam 445185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 446185377Ssam return HAL_MAC_HANG_SIG1; 447185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 448185377Ssam return HAL_MAC_HANG_SIG2; 449185377Ssam 450185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " 451185377Ssam "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 452185377Ssam __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 453185377Ssam mac_dbg.dma_dbg_6); 454185377Ssam 455185377Ssam return HAL_MAC_HANG_UNKNOWN; 456185377Ssam} 457185377Ssam 458185377Ssam/* 459185377Ssam * Determine if the baseband using the Observation Bus Register 460185377Ssam */ 461185377Ssamstatic int 462185377Ssamar5416DetectBBHang(struct ath_hal *ah) 463185377Ssam{ 464185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 465185377Ssam /* 466185377Ssam * Check the PCU Observation Bus 1 register (0x806c) 467185377Ssam * NUM_STATUS_READS times 468185377Ssam * 469185377Ssam * 4 known BB hang signatures - 470185377Ssam * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 471185377Ssam * [2] bits 8,9 are 1, bit 11 is 0. State machine state 472185377Ssam * (bits 25-31) is 0x52 473185377Ssam * [3] bits 8,9 are 1, bit 11 is 0. State machine state 474185377Ssam * (bits 25-31) is 0x18 475185377Ssam * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 476185377Ssam * Rx State (bits 20-24) is 0x7. 477185377Ssam */ 478185377Ssam static const struct { 479185377Ssam uint32_t val; 480185377Ssam uint32_t mask; 481185377Ssam int code; 482185377Ssam } hang_list[] = { 483185377Ssam /* Reg Value Reg Mask Hang Code XXX */ 484185377Ssam { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 485185377Ssam { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 486185377Ssam { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 487185377Ssam { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 488185377Ssam }; 489185377Ssam uint32_t hang_sig; 490185377Ssam int i; 491185377Ssam 492185377Ssam hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 493185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 494185377Ssam if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 495185377Ssam return 0; 496185377Ssam } 497185377Ssam for (i = 0; i < N(hang_list); i++) 498185377Ssam if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 499185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, 500185377Ssam "%s BB hang, signature 0x%x, code 0x%x\n", 501185377Ssam __func__, hang_sig, hang_list[i].code); 502185377Ssam return hang_list[i].code; 503185377Ssam } 504185377Ssam 505185377Ssam HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " 506185377Ssam "<0x806c>=0x%x\n", __func__, hang_sig); 507185377Ssam 508185377Ssam return HAL_BB_HANG_UNKNOWN; 509185377Ssam#undef N 510185377Ssam} 511185377Ssam#undef NUM_STATUS_READS 512