ar5416_misc.c revision 243424
1/* 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 243424 2012-11-23 05:32:24Z adrian $ 18 */ 19#include "opt_ah.h" 20 21#include "ah.h" 22#include "ah_internal.h" 23#include "ah_devid.h" 24#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 25 26#include "ar5416/ar5416.h" 27#include "ar5416/ar5416reg.h" 28#include "ar5416/ar5416phy.h" 29 30#include "ah_eeprom_v14.h" /* for owl_get_ntxchains() */ 31 32/* 33 * Return the wireless modes (a,b,g,n,t) supported by hardware. 34 * 35 * This value is what is actually supported by the hardware 36 * and is unaffected by regulatory/country code settings. 37 * 38 */ 39u_int 40ar5416GetWirelessModes(struct ath_hal *ah) 41{ 42 u_int mode; 43 struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 44 HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; 45 46 mode = ar5212GetWirelessModes(ah); 47 48 /* Only enable HT modes if the NIC supports HT */ 49 if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A)) 50 mode |= HAL_MODE_11NA_HT20 51 | HAL_MODE_11NA_HT40PLUS 52 | HAL_MODE_11NA_HT40MINUS 53 ; 54 if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G)) 55 mode |= HAL_MODE_11NG_HT20 56 | HAL_MODE_11NG_HT40PLUS 57 | HAL_MODE_11NG_HT40MINUS 58 ; 59 return mode; 60} 61 62/* 63 * Change the LED blinking pattern to correspond to the connectivity 64 */ 65void 66ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 67{ 68 static const uint32_t ledbits[8] = { 69 AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 70 AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 71 AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 72 AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 73 AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 74 AR_MAC_LED_ASSOC_NONE, 75 AR_MAC_LED_ASSOC_NONE, 76 AR_MAC_LED_ASSOC_NONE, 77 }; 78 79 if (AR_SREV_HOWL(ah)) 80 return; 81 82 /* 83 * Set the blink operating mode. 84 */ 85 OS_REG_RMW_FIELD(ah, AR_MAC_LED, 86 AR_MAC_LED_ASSOC, ledbits[state & 0x7]); 87 88 /* XXX Blink slow mode? */ 89 /* XXX Blink threshold? */ 90 /* XXX Blink sleep hystersis? */ 91 92 /* 93 * Set the LED blink configuration to be proportional 94 * to the current TX and RX filter bytes. (Ie, RX'ed 95 * frames that don't match the filter are ignored.) 96 * This means that higher TX/RX throughput will result 97 * in the blink rate increasing. 98 */ 99 OS_REG_RMW_FIELD(ah, AR_MAC_LED, AR_MAC_LED_MODE, 100 AR_MAC_LED_MODE_PROP); 101} 102 103/* 104 * Get the current hardware tsf for stamlme 105 */ 106uint64_t 107ar5416GetTsf64(struct ath_hal *ah) 108{ 109 uint32_t low1, low2, u32; 110 111 /* sync multi-word read */ 112 low1 = OS_REG_READ(ah, AR_TSF_L32); 113 u32 = OS_REG_READ(ah, AR_TSF_U32); 114 low2 = OS_REG_READ(ah, AR_TSF_L32); 115 if (low2 < low1) { /* roll over */ 116 /* 117 * If we are not preempted this will work. If we are 118 * then we re-reading AR_TSF_U32 does no good as the 119 * low bits will be meaningless. Likewise reading 120 * L32, U32, U32, then comparing the last two reads 121 * to check for rollover doesn't help if preempted--so 122 * we take this approach as it costs one less PCI read 123 * which can be noticeable when doing things like 124 * timestamping packets in monitor mode. 125 */ 126 u32++; 127 } 128 return (((uint64_t) u32) << 32) | ((uint64_t) low2); 129} 130 131void 132ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64) 133{ 134 /* XXX check if this is correct! */ 135#if 0 136 int i; 137 uint32_t v; 138 139 for (i = 0; i < 10; i++) { 140 v = OS_REG_READ(ah, AR_SLP32_MODE); 141 if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 142 break; 143 OS_DELAY(10); 144 } 145 if (i == 10) 146 ath_hal_printf(ah, "%s: couldn't slew things right!\n", __func__); 147#endif 148 149 OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff); 150 OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff); 151} 152 153/* 154 * Reset the current hardware tsf for stamlme. 155 */ 156void 157ar5416ResetTsf(struct ath_hal *ah) 158{ 159 uint32_t v; 160 int i; 161 162 for (i = 0; i < 10; i++) { 163 v = OS_REG_READ(ah, AR_SLP32_MODE); 164 if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 165 break; 166 OS_DELAY(10); 167 } 168 OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 169} 170 171uint32_t 172ar5416GetCurRssi(struct ath_hal *ah) 173{ 174 if (AR_SREV_OWL(ah)) 175 return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff); 176 return (OS_REG_READ(ah, AR9130_PHY_CURRENT_RSSI) & 0xff); 177} 178 179HAL_BOOL 180ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 181{ 182 return AH_TRUE; 183} 184 185/* Setup decompression for given key index */ 186HAL_BOOL 187ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 188{ 189 return AH_TRUE; 190} 191 192/* Setup coverage class */ 193void 194ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 195{ 196 197 ar5212SetCoverageClass(ah, coverageclass, now); 198} 199 200/* 201 * Return the busy for rx_frame, rx_clear, and tx_frame 202 */ 203HAL_BOOL 204ar5416GetMibCycleCounts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hsample) 205{ 206 struct ath_hal_5416 *ahp = AH5416(ah); 207 u_int32_t good = AH_TRUE; 208 209 /* XXX freeze/unfreeze mib counters */ 210 uint32_t rc = OS_REG_READ(ah, AR_RCCNT); 211 uint32_t ec = OS_REG_READ(ah, AR_EXTRCCNT); 212 uint32_t rf = OS_REG_READ(ah, AR_RFCNT); 213 uint32_t tf = OS_REG_READ(ah, AR_TFCNT); 214 uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */ 215 216 if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) { 217 /* 218 * Cycle counter wrap (or initial call); it's not possible 219 * to accurately calculate a value because the registers 220 * right shift rather than wrap--so punt and return 0. 221 */ 222 HALDEBUG(ah, HAL_DEBUG_ANY, 223 "%s: cycle counter wrap. ExtBusy = 0\n", __func__); 224 good = AH_FALSE; 225 } else { 226 hsample->cycle_count = cc - ahp->ah_cycleCount; 227 hsample->chan_busy = rc - ahp->ah_ctlBusy; 228 hsample->ext_chan_busy = ec - ahp->ah_extBusy; 229 hsample->rx_busy = rf - ahp->ah_rxBusy; 230 hsample->tx_busy = tf - ahp->ah_txBusy; 231 } 232 233 /* 234 * Keep a copy of the MIB results so the next sample has something 235 * to work from. 236 */ 237 ahp->ah_cycleCount = cc; 238 ahp->ah_rxBusy = rf; 239 ahp->ah_ctlBusy = rc; 240 ahp->ah_txBusy = tf; 241 ahp->ah_extBusy = ec; 242 243 return (good); 244} 245 246/* 247 * Return approximation of extension channel busy over an time interval 248 * 0% (clear) -> 100% (busy) 249 * 250 * XXX TODO: update this to correctly sample all the counters, 251 * rather than a subset of it. 252 */ 253uint32_t 254ar5416Get11nExtBusy(struct ath_hal *ah) 255{ 256 struct ath_hal_5416 *ahp = AH5416(ah); 257 uint32_t busy; /* percentage */ 258 uint32_t cycleCount, ctlBusy, extBusy; 259 260 ctlBusy = OS_REG_READ(ah, AR_RCCNT); 261 extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 262 cycleCount = OS_REG_READ(ah, AR_CCCNT); 263 264 if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 265 /* 266 * Cycle counter wrap (or initial call); it's not possible 267 * to accurately calculate a value because the registers 268 * right shift rather than wrap--so punt and return 0. 269 */ 270 busy = 0; 271 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 272 __func__); 273 274 } else { 275 uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 276 uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 277 uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 278 uint32_t ctlClearDelta = 0; 279 280 /* Compute control channel rxclear. 281 * The cycle delta may be less than the control channel delta. 282 * This could be solved by freezing the timers (or an atomic read, 283 * if one was available). Checking for the condition should be 284 * sufficient. 285 */ 286 if (cycleDelta > ctlBusyDelta) { 287 ctlClearDelta = cycleDelta - ctlBusyDelta; 288 } 289 290 /* Compute ratio of extension channel busy to control channel clear 291 * as an approximation to extension channel cleanliness. 292 * 293 * According to the hardware folks, ext rxclear is undefined 294 * if the ctrl rxclear is de-asserted (i.e. busy) 295 */ 296 if (ctlClearDelta) { 297 busy = (extBusyDelta * 100) / ctlClearDelta; 298 } else { 299 busy = 100; 300 } 301 if (busy > 100) { 302 busy = 100; 303 } 304#if 0 305 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 306 "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 307 "busy %d\n", 308 __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 309#endif 310 } 311 312 ahp->ah_cycleCount = cycleCount; 313 ahp->ah_ctlBusy = ctlBusy; 314 ahp->ah_extBusy = extBusy; 315 316 return busy; 317} 318 319/* 320 * Configure 20/40 operation 321 * 322 * 20/40 = joint rx clear (control and extension) 323 * 20 = rx clear (control) 324 * 325 * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 326 * from 20/40 => 20 only 327 */ 328void 329ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 330{ 331 uint32_t macmode; 332 333 /* Configure MAC for 20/40 operation */ 334 if (mode == HAL_HT_MACMODE_2040) { 335 macmode = AR_2040_JOINED_RX_CLEAR; 336 } else { 337 macmode = 0; 338 } 339 OS_REG_WRITE(ah, AR_2040_MODE, macmode); 340} 341 342/* 343 * Get Rx clear (control/extension channel) 344 * 345 * Returns active low (busy) for ctrl/ext channel 346 * Owl 2.0 347 */ 348HAL_HT_RXCLEAR 349ar5416Get11nRxClear(struct ath_hal *ah) 350{ 351 HAL_HT_RXCLEAR rxclear = 0; 352 uint32_t val; 353 354 val = OS_REG_READ(ah, AR_DIAG_SW); 355 356 /* control channel */ 357 if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 358 rxclear |= HAL_RX_CLEAR_CTL_LOW; 359 } 360 /* extension channel */ 361 if (val & AR_DIAG_RXCLEAR_EXT_LOW) { 362 rxclear |= HAL_RX_CLEAR_EXT_LOW; 363 } 364 return rxclear; 365} 366 367/* 368 * Set Rx clear (control/extension channel) 369 * 370 * Useful for forcing the channel to appear busy for 371 * debugging/diagnostics 372 * Owl 2.0 373 */ 374void 375ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 376{ 377 /* control channel */ 378 if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 379 OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 380 } else { 381 OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 382 } 383 /* extension channel */ 384 if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 385 OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 386 } else { 387 OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 388 } 389} 390 391/* XXX shouldn't be here! */ 392#define TU_TO_USEC(_tu) ((_tu) << 10) 393 394HAL_STATUS 395ar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, 396 uint32_t nextStart, HAL_QUIET_FLAG flag) 397{ 398 uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */ 399 uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */ 400 if (flag & HAL_QUIET_ENABLE) { 401 if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) { 402 /* Add the nextStart offset to the current TSF */ 403 nextStart_us += OS_REG_READ(ah, AR_TSF_L32); 404 } 405 if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) { 406 nextStart_us += ah->ah_config.ah_sw_beacon_response_time; 407 } 408 OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 409 OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR)); 410 OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us); 411 OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us); 412 OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 413 } else { 414 OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 415 } 416 return HAL_OK; 417} 418#undef TU_TO_USEC 419 420HAL_STATUS 421ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 422 uint32_t capability, uint32_t *result) 423{ 424 switch (type) { 425 case HAL_CAP_BB_HANG: 426 switch (capability) { 427 case HAL_BB_HANG_RIFS: 428 return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 429 case HAL_BB_HANG_DFS: 430 return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 431 case HAL_BB_HANG_RX_CLEAR: 432 return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 433 } 434 break; 435 case HAL_CAP_MAC_HANG: 436 return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 437 (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 438 AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? 439 HAL_OK : HAL_ENOTSUPP; 440 case HAL_CAP_DIVERSITY: /* disable classic fast diversity */ 441 return HAL_ENXIO; 442 default: 443 break; 444 } 445 return ar5212GetCapability(ah, type, capability, result); 446} 447 448HAL_BOOL 449ar5416SetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 450 u_int32_t capability, u_int32_t setting, HAL_STATUS *status) 451{ 452 HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; 453 454 switch (type) { 455 case HAL_CAP_RX_CHAINMASK: 456 setting &= ath_hal_eepromGet(ah, AR_EEP_RXMASK, NULL); 457 pCap->halRxChainMask = setting; 458 if (owl_get_ntxchains(setting) > 2) 459 pCap->halRxStreams = 2; 460 else 461 pCap->halRxStreams = 1; 462 return AH_TRUE; 463 case HAL_CAP_TX_CHAINMASK: 464 setting &= ath_hal_eepromGet(ah, AR_EEP_TXMASK, NULL); 465 pCap->halTxChainMask = setting; 466 if (owl_get_ntxchains(setting) > 2) 467 pCap->halTxStreams = 2; 468 else 469 pCap->halTxStreams = 1; 470 return AH_TRUE; 471 default: 472 break; 473 } 474 return ar5212SetCapability(ah, type, capability, setting, status); 475} 476 477static int ar5416DetectMacHang(struct ath_hal *ah); 478static int ar5416DetectBBHang(struct ath_hal *ah); 479 480HAL_BOOL 481ar5416GetDiagState(struct ath_hal *ah, int request, 482 const void *args, uint32_t argsize, 483 void **result, uint32_t *resultsize) 484{ 485 struct ath_hal_5416 *ahp = AH5416(ah); 486 int hangs; 487 488 if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 489 return AH_TRUE; 490 switch (request) { 491 case HAL_DIAG_EEPROM: 492 return ath_hal_eepromDiag(ah, request, 493 args, argsize, result, resultsize); 494 case HAL_DIAG_CHECK_HANGS: 495 if (argsize != sizeof(int)) 496 return AH_FALSE; 497 hangs = *(const int *) args; 498 ahp->ah_hangs = 0; 499 if (hangs & HAL_BB_HANGS) 500 ahp->ah_hangs |= ar5416DetectBBHang(ah); 501 /* NB: if BB is hung MAC will be hung too so skip check */ 502 if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 503 ahp->ah_hangs |= ar5416DetectMacHang(ah); 504 *result = &ahp->ah_hangs; 505 *resultsize = sizeof(ahp->ah_hangs); 506 return AH_TRUE; 507 } 508 return ar5212GetDiagState(ah, request, 509 args, argsize, result, resultsize); 510} 511 512HAL_BOOL 513ar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan, 514 HAL_BOOL enable) 515{ 516 uint32_t val; 517 HAL_BOOL is_chan_2g = AH_FALSE; 518 HAL_BOOL is_ht40 = AH_FALSE; 519 520 if (chan) 521 is_chan_2g = IEEE80211_IS_CHAN_2GHZ(chan); 522 523 if (chan) 524 is_ht40 = IEEE80211_IS_CHAN_HT40(chan); 525 526 /* Only support disabling RIFS delay for now */ 527 HALASSERT(enable == AH_FALSE); 528 529 if (enable == AH_TRUE) 530 return AH_FALSE; 531 532 /* Change RIFS init delay to 0 */ 533 val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); 534 val &= ~AR_PHY_RIFS_INIT_DELAY; 535 OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); 536 537 /* 538 * For Owl, RIFS RX parameters are controlled differently; 539 * it isn't enabled in the inivals by default. 540 * 541 * For Sowl/Howl, RIFS RX is enabled in the inivals by default; 542 * the following code sets them back to non-RIFS values. 543 * 544 * For > Sowl/Howl, RIFS RX can be left on by default and so 545 * this function shouldn't be called. 546 */ 547 if ((! AR_SREV_SOWL(ah)) && (! AR_SREV_HOWL(ah))) 548 return AH_TRUE; 549 550 /* Reset search delay to default values */ 551 if (is_chan_2g) 552 if (is_ht40) 553 OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x268); 554 else 555 OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x134); 556 else 557 if (is_ht40) 558 OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x370); 559 else 560 OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x1b8); 561 562 return AH_TRUE; 563} 564 565static HAL_BOOL 566ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 567 const hal_mac_hang_check_t *check) 568{ 569 int found_states; 570 571 found_states = 0; 572 if (check->states & dcu_chain_state) { 573 int i; 574 575 for (i = 0; i < 6; i++) { 576 if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 577 check->dcu_chain_state) 578 found_states |= dcu_chain_state; 579 } 580 for (i = 0; i < 4; i++) { 581 if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 582 check->dcu_chain_state) 583 found_states |= dcu_chain_state; 584 } 585 } 586 if (check->states & dcu_complete_state) { 587 if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 588 found_states |= dcu_complete_state; 589 } 590 if (check->states & qcu_stitch_state) { 591 if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 592 found_states |= qcu_stitch_state; 593 } 594 if (check->states & qcu_fetch_state) { 595 if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 596 found_states |= qcu_fetch_state; 597 } 598 if (check->states & qcu_complete_state) { 599 if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 600 found_states |= qcu_complete_state; 601 } 602 return (found_states == check->states); 603} 604 605#define NUM_STATUS_READS 50 606 607static int 608ar5416DetectMacHang(struct ath_hal *ah) 609{ 610 static const hal_mac_hang_check_t hang_sig1 = { 611 .dcu_chain_state = 0x6, 612 .dcu_complete_state = 0x1, 613 .states = dcu_chain_state 614 | dcu_complete_state, 615 }; 616 static const hal_mac_hang_check_t hang_sig2 = { 617 .qcu_stitch_state = 0x9, 618 .qcu_fetch_state = 0x8, 619 .qcu_complete_state = 0x4, 620 .states = qcu_stitch_state 621 | qcu_fetch_state 622 | qcu_complete_state, 623 }; 624 mac_dbg_regs_t mac_dbg; 625 int i; 626 627 mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 628 mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 629 mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 630 mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 631 for (i = 1; i <= NUM_STATUS_READS; i++) { 632 if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 633 mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 634 mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 635 mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 636 return 0; 637 } 638 639 if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 640 return HAL_MAC_HANG_SIG1; 641 if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 642 return HAL_MAC_HANG_SIG2; 643 644 HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature " 645 "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 646 __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 647 mac_dbg.dma_dbg_6); 648 649 return 0; 650} 651 652/* 653 * Determine if the baseband using the Observation Bus Register 654 */ 655static int 656ar5416DetectBBHang(struct ath_hal *ah) 657{ 658#define N(a) (sizeof(a)/sizeof(a[0])) 659 /* 660 * Check the PCU Observation Bus 1 register (0x806c) 661 * NUM_STATUS_READS times 662 * 663 * 4 known BB hang signatures - 664 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 665 * [2] bits 8,9 are 1, bit 11 is 0. State machine state 666 * (bits 25-31) is 0x52 667 * [3] bits 8,9 are 1, bit 11 is 0. State machine state 668 * (bits 25-31) is 0x18 669 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 670 * Rx State (bits 20-24) is 0x7. 671 */ 672 static const struct { 673 uint32_t val; 674 uint32_t mask; 675 int code; 676 } hang_list[] = { 677 /* Reg Value Reg Mask Hang Code XXX */ 678 { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 679 { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 680 { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 681 { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 682 }; 683 uint32_t hang_sig; 684 int i; 685 686 hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 687 for (i = 1; i <= NUM_STATUS_READS; i++) { 688 if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 689 return 0; 690 } 691 for (i = 0; i < N(hang_list); i++) 692 if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 693 HALDEBUG(ah, HAL_DEBUG_HANG, 694 "%s BB hang, signature 0x%x, code 0x%x\n", 695 __func__, hang_sig, hang_list[i].code); 696 return hang_list[i].code; 697 } 698 699 HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! " 700 "<0x806c>=0x%x\n", __func__, hang_sig); 701 702 return 0; 703#undef N 704} 705#undef NUM_STATUS_READS 706