ar5416_misc.c revision 221580
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 221580 2011-05-07 06:45:35Z 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: 286221580Sadrian return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 287185377Ssam case HAL_BB_HANG_DFS: 288221580Sadrian return (AR_SREV_HOWL(ah) || 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) || 296221580Sadrian AR_SREV_HOWL(ah) || 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 371221535SadrianHAL_BOOL 372221535Sadrianar5416SetRifsDelay(struct ath_hal *ah, HAL_BOOL enable) 373221535Sadrian{ 374221535Sadrian uint32_t val; 375221535Sadrian 376221535Sadrian /* Only support disabling RIFS delay for now */ 377221535Sadrian HALASSERT(enable == AH_FALSE); 378221535Sadrian 379221535Sadrian if (enable == AH_TRUE) 380221535Sadrian return AH_FALSE; 381221535Sadrian 382221535Sadrian /* Change RIFS init delay to 0 */ 383221535Sadrian val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); 384221535Sadrian val &= ~AR_PHY_RIFS_INIT_DELAY; 385221535Sadrian OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); 386221535Sadrian 387221535Sadrian return AH_TRUE; 388221535Sadrian} 389221535Sadrian 390185377Ssamstatic HAL_BOOL 391185377Ssamar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 392185377Ssam const hal_mac_hang_check_t *check) 393185377Ssam{ 394185377Ssam int found_states; 395185377Ssam 396185377Ssam found_states = 0; 397185377Ssam if (check->states & dcu_chain_state) { 398185377Ssam int i; 399185377Ssam 400185377Ssam for (i = 0; i < 6; i++) { 401185377Ssam if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 402185377Ssam check->dcu_chain_state) 403185377Ssam found_states |= dcu_chain_state; 404185377Ssam } 405185377Ssam for (i = 0; i < 4; i++) { 406185377Ssam if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 407185377Ssam check->dcu_chain_state) 408185377Ssam found_states |= dcu_chain_state; 409185377Ssam } 410185377Ssam } 411185377Ssam if (check->states & dcu_complete_state) { 412185377Ssam if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 413185377Ssam found_states |= dcu_complete_state; 414185377Ssam } 415185377Ssam if (check->states & qcu_stitch_state) { 416185377Ssam if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 417185377Ssam found_states |= qcu_stitch_state; 418185377Ssam } 419185377Ssam if (check->states & qcu_fetch_state) { 420185377Ssam if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 421185377Ssam found_states |= qcu_fetch_state; 422185377Ssam } 423185377Ssam if (check->states & qcu_complete_state) { 424185377Ssam if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 425185377Ssam found_states |= qcu_complete_state; 426185377Ssam } 427185377Ssam return (found_states == check->states); 428185377Ssam} 429185377Ssam 430185377Ssam#define NUM_STATUS_READS 50 431185377Ssam 432185377Ssamstatic int 433185377Ssamar5416DetectMacHang(struct ath_hal *ah) 434185377Ssam{ 435185377Ssam static const hal_mac_hang_check_t hang_sig1 = { 436185377Ssam .dcu_chain_state = 0x6, 437185377Ssam .dcu_complete_state = 0x1, 438185377Ssam .states = dcu_chain_state 439185377Ssam | dcu_complete_state, 440185377Ssam }; 441185377Ssam static const hal_mac_hang_check_t hang_sig2 = { 442185377Ssam .qcu_stitch_state = 0x9, 443185377Ssam .qcu_fetch_state = 0x8, 444185377Ssam .qcu_complete_state = 0x4, 445185377Ssam .states = qcu_stitch_state 446185377Ssam | qcu_fetch_state 447185377Ssam | qcu_complete_state, 448185377Ssam }; 449185377Ssam mac_dbg_regs_t mac_dbg; 450185377Ssam int i; 451185377Ssam 452185377Ssam mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 453185377Ssam mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 454185377Ssam mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 455185377Ssam mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 456185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 457185377Ssam if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 458185377Ssam mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 459185377Ssam mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 460185377Ssam mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 461185377Ssam return 0; 462185377Ssam } 463185377Ssam 464185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 465185377Ssam return HAL_MAC_HANG_SIG1; 466185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 467185377Ssam return HAL_MAC_HANG_SIG2; 468185377Ssam 469221580Sadrian HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature " 470185377Ssam "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 471185377Ssam __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 472185377Ssam mac_dbg.dma_dbg_6); 473185377Ssam 474185377Ssam return HAL_MAC_HANG_UNKNOWN; 475185377Ssam} 476185377Ssam 477185377Ssam/* 478185377Ssam * Determine if the baseband using the Observation Bus Register 479185377Ssam */ 480185377Ssamstatic int 481185377Ssamar5416DetectBBHang(struct ath_hal *ah) 482185377Ssam{ 483185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 484185377Ssam /* 485185377Ssam * Check the PCU Observation Bus 1 register (0x806c) 486185377Ssam * NUM_STATUS_READS times 487185377Ssam * 488185377Ssam * 4 known BB hang signatures - 489185377Ssam * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 490185377Ssam * [2] bits 8,9 are 1, bit 11 is 0. State machine state 491185377Ssam * (bits 25-31) is 0x52 492185377Ssam * [3] bits 8,9 are 1, bit 11 is 0. State machine state 493185377Ssam * (bits 25-31) is 0x18 494185377Ssam * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 495185377Ssam * Rx State (bits 20-24) is 0x7. 496185377Ssam */ 497185377Ssam static const struct { 498185377Ssam uint32_t val; 499185377Ssam uint32_t mask; 500185377Ssam int code; 501185377Ssam } hang_list[] = { 502185377Ssam /* Reg Value Reg Mask Hang Code XXX */ 503185377Ssam { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 504185377Ssam { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 505185377Ssam { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 506185377Ssam { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 507185377Ssam }; 508185377Ssam uint32_t hang_sig; 509185377Ssam int i; 510185377Ssam 511185377Ssam hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 512185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 513185377Ssam if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 514185377Ssam return 0; 515185377Ssam } 516185377Ssam for (i = 0; i < N(hang_list); i++) 517185377Ssam if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 518221580Sadrian HALDEBUG(ah, HAL_DEBUG_HANG, 519185377Ssam "%s BB hang, signature 0x%x, code 0x%x\n", 520185377Ssam __func__, hang_sig, hang_list[i].code); 521185377Ssam return hang_list[i].code; 522185377Ssam } 523185377Ssam 524221580Sadrian HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! " 525185377Ssam "<0x806c>=0x%x\n", __func__, hang_sig); 526185377Ssam 527185377Ssam return HAL_BB_HANG_UNKNOWN; 528185377Ssam#undef N 529185377Ssam} 530185377Ssam#undef NUM_STATUS_READS 531