ar5416_misc.c revision 223459
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 223459 2011-06-23 02:38:36Z 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 276222644Sadrian/* XXX shouldn't be here! */ 277222644Sadrian#define TU_TO_USEC(_tu) ((_tu) << 10) 278222644Sadrian 279185377SsamHAL_STATUS 280222644Sadrianar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, 281222644Sadrian uint32_t nextStart, HAL_QUIET_FLAG flag) 282222644Sadrian{ 283222644Sadrian uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */ 284222644Sadrian uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */ 285222644Sadrian if (flag & HAL_QUIET_ENABLE) { 286222644Sadrian if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) { 287222644Sadrian /* Add the nextStart offset to the current TSF */ 288222644Sadrian nextStart_us += OS_REG_READ(ah, AR_TSF_L32); 289222644Sadrian } 290222644Sadrian if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) { 291223459Sadrian nextStart_us += ah->ah_config.ah_sw_beacon_response_time; 292222644Sadrian } 293222644Sadrian OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 294222644Sadrian OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR)); 295222644Sadrian OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us); 296222644Sadrian OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us); 297222644Sadrian OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 298222644Sadrian } else { 299222644Sadrian OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 300222644Sadrian } 301222644Sadrian return HAL_OK; 302222644Sadrian} 303222644Sadrian#undef TU_TO_USEC 304222644Sadrian 305222644SadrianHAL_STATUS 306185377Ssamar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 307185377Ssam uint32_t capability, uint32_t *result) 308185377Ssam{ 309185377Ssam switch (type) { 310185377Ssam case HAL_CAP_BB_HANG: 311185377Ssam switch (capability) { 312185377Ssam case HAL_BB_HANG_RIFS: 313221580Sadrian return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 314185377Ssam case HAL_BB_HANG_DFS: 315221580Sadrian return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 316185377Ssam case HAL_BB_HANG_RX_CLEAR: 317185377Ssam return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 318185377Ssam } 319185377Ssam break; 320185377Ssam case HAL_CAP_MAC_HANG: 321185377Ssam return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 322185377Ssam (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 323221580Sadrian AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? 324185380Ssam HAL_OK : HAL_ENOTSUPP; 325220718Sadrian case HAL_CAP_DIVERSITY: /* disable classic fast diversity */ 326220718Sadrian return HAL_ENXIO; 327185377Ssam default: 328185377Ssam break; 329185377Ssam } 330185377Ssam return ar5212GetCapability(ah, type, capability, result); 331185377Ssam} 332185377Ssam 333185377Ssamstatic int ar5416DetectMacHang(struct ath_hal *ah); 334185377Ssamstatic int ar5416DetectBBHang(struct ath_hal *ah); 335185377Ssam 336185377SsamHAL_BOOL 337185377Ssamar5416GetDiagState(struct ath_hal *ah, int request, 338185377Ssam const void *args, uint32_t argsize, 339185377Ssam void **result, uint32_t *resultsize) 340185377Ssam{ 341185377Ssam struct ath_hal_5416 *ahp = AH5416(ah); 342185377Ssam int hangs; 343185377Ssam 344185377Ssam if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 345185377Ssam return AH_TRUE; 346185377Ssam switch (request) { 347185377Ssam case HAL_DIAG_EEPROM: 348185377Ssam return ath_hal_eepromDiag(ah, request, 349185377Ssam args, argsize, result, resultsize); 350185377Ssam case HAL_DIAG_CHECK_HANGS: 351185377Ssam if (argsize != sizeof(int)) 352185377Ssam return AH_FALSE; 353185377Ssam hangs = *(const int *) args; 354185377Ssam ahp->ah_hangs = 0; 355185377Ssam if (hangs & HAL_BB_HANGS) 356185377Ssam ahp->ah_hangs |= ar5416DetectBBHang(ah); 357185380Ssam /* NB: if BB is hung MAC will be hung too so skip check */ 358185377Ssam if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 359185377Ssam ahp->ah_hangs |= ar5416DetectMacHang(ah); 360185377Ssam *result = &ahp->ah_hangs; 361185377Ssam *resultsize = sizeof(ahp->ah_hangs); 362185377Ssam return AH_TRUE; 363185377Ssam } 364185377Ssam return ar5212GetDiagState(ah, request, 365185377Ssam args, argsize, result, resultsize); 366185377Ssam} 367185377Ssam 368185377Ssamtypedef struct { 369185377Ssam uint32_t dma_dbg_3; 370185377Ssam uint32_t dma_dbg_4; 371185377Ssam uint32_t dma_dbg_5; 372185377Ssam uint32_t dma_dbg_6; 373185377Ssam} mac_dbg_regs_t; 374185377Ssam 375185377Ssamtypedef enum { 376185377Ssam dcu_chain_state = 0x1, 377185377Ssam dcu_complete_state = 0x2, 378185377Ssam qcu_state = 0x4, 379185377Ssam qcu_fsp_ok = 0x8, 380185377Ssam qcu_fsp_state = 0x10, 381185377Ssam qcu_stitch_state = 0x20, 382185377Ssam qcu_fetch_state = 0x40, 383185377Ssam qcu_complete_state = 0x80 384185377Ssam} hal_mac_hangs_t; 385185377Ssam 386185377Ssamtypedef struct { 387185377Ssam int states; 388185377Ssam uint8_t dcu_chain_state; 389185377Ssam uint8_t dcu_complete_state; 390185377Ssam uint8_t qcu_state; 391185377Ssam uint8_t qcu_fsp_ok; 392185377Ssam uint8_t qcu_fsp_state; 393185377Ssam uint8_t qcu_stitch_state; 394185377Ssam uint8_t qcu_fetch_state; 395185377Ssam uint8_t qcu_complete_state; 396185377Ssam} hal_mac_hang_check_t; 397185377Ssam 398221535SadrianHAL_BOOL 399221878Sadrianar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan, 400221878Sadrian HAL_BOOL enable) 401221535Sadrian{ 402221535Sadrian uint32_t val; 403221878Sadrian HAL_BOOL is_chan_2g = AH_FALSE; 404221878Sadrian HAL_BOOL is_ht40 = AH_FALSE; 405221535Sadrian 406221878Sadrian if (chan) 407221878Sadrian is_chan_2g = IEEE80211_IS_CHAN_2GHZ(chan); 408221878Sadrian 409221878Sadrian if (chan) 410221878Sadrian is_ht40 = IEEE80211_IS_CHAN_HT40(chan); 411221878Sadrian 412221535Sadrian /* Only support disabling RIFS delay for now */ 413221535Sadrian HALASSERT(enable == AH_FALSE); 414221535Sadrian 415221535Sadrian if (enable == AH_TRUE) 416221535Sadrian return AH_FALSE; 417221535Sadrian 418221535Sadrian /* Change RIFS init delay to 0 */ 419221535Sadrian val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); 420221535Sadrian val &= ~AR_PHY_RIFS_INIT_DELAY; 421221535Sadrian OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); 422221535Sadrian 423221878Sadrian /* 424221878Sadrian * For Owl, RIFS RX parameters are controlled differently; 425221878Sadrian * it isn't enabled in the inivals by default. 426221878Sadrian * 427221878Sadrian * For Sowl/Howl, RIFS RX is enabled in the inivals by default; 428221878Sadrian * the following code sets them back to non-RIFS values. 429221878Sadrian * 430221878Sadrian * For > Sowl/Howl, RIFS RX can be left on by default and so 431221878Sadrian * this function shouldn't be called. 432221878Sadrian */ 433221878Sadrian if ((! AR_SREV_SOWL(ah)) && (! AR_SREV_HOWL(ah))) 434221878Sadrian return AH_TRUE; 435221878Sadrian 436221878Sadrian /* Reset search delay to default values */ 437221878Sadrian if (is_chan_2g) 438221878Sadrian if (is_ht40) 439221878Sadrian OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x268); 440221878Sadrian else 441221878Sadrian OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x134); 442221878Sadrian else 443221878Sadrian if (is_ht40) 444221878Sadrian OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x370); 445221878Sadrian else 446221878Sadrian OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x1b8); 447221878Sadrian 448221535Sadrian return AH_TRUE; 449221535Sadrian} 450221535Sadrian 451185377Ssamstatic HAL_BOOL 452185377Ssamar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 453185377Ssam const hal_mac_hang_check_t *check) 454185377Ssam{ 455185377Ssam int found_states; 456185377Ssam 457185377Ssam found_states = 0; 458185377Ssam if (check->states & dcu_chain_state) { 459185377Ssam int i; 460185377Ssam 461185377Ssam for (i = 0; i < 6; i++) { 462185377Ssam if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 463185377Ssam check->dcu_chain_state) 464185377Ssam found_states |= dcu_chain_state; 465185377Ssam } 466185377Ssam for (i = 0; i < 4; i++) { 467185377Ssam if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 468185377Ssam check->dcu_chain_state) 469185377Ssam found_states |= dcu_chain_state; 470185377Ssam } 471185377Ssam } 472185377Ssam if (check->states & dcu_complete_state) { 473185377Ssam if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 474185377Ssam found_states |= dcu_complete_state; 475185377Ssam } 476185377Ssam if (check->states & qcu_stitch_state) { 477185377Ssam if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 478185377Ssam found_states |= qcu_stitch_state; 479185377Ssam } 480185377Ssam if (check->states & qcu_fetch_state) { 481185377Ssam if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 482185377Ssam found_states |= qcu_fetch_state; 483185377Ssam } 484185377Ssam if (check->states & qcu_complete_state) { 485185377Ssam if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 486185377Ssam found_states |= qcu_complete_state; 487185377Ssam } 488185377Ssam return (found_states == check->states); 489185377Ssam} 490185377Ssam 491185377Ssam#define NUM_STATUS_READS 50 492185377Ssam 493185377Ssamstatic int 494185377Ssamar5416DetectMacHang(struct ath_hal *ah) 495185377Ssam{ 496185377Ssam static const hal_mac_hang_check_t hang_sig1 = { 497185377Ssam .dcu_chain_state = 0x6, 498185377Ssam .dcu_complete_state = 0x1, 499185377Ssam .states = dcu_chain_state 500185377Ssam | dcu_complete_state, 501185377Ssam }; 502185377Ssam static const hal_mac_hang_check_t hang_sig2 = { 503185377Ssam .qcu_stitch_state = 0x9, 504185377Ssam .qcu_fetch_state = 0x8, 505185377Ssam .qcu_complete_state = 0x4, 506185377Ssam .states = qcu_stitch_state 507185377Ssam | qcu_fetch_state 508185377Ssam | qcu_complete_state, 509185377Ssam }; 510185377Ssam mac_dbg_regs_t mac_dbg; 511185377Ssam int i; 512185377Ssam 513185377Ssam mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 514185377Ssam mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 515185377Ssam mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 516185377Ssam mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 517185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 518185377Ssam if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 519185377Ssam mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 520185377Ssam mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 521185377Ssam mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 522185377Ssam return 0; 523185377Ssam } 524185377Ssam 525185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 526185377Ssam return HAL_MAC_HANG_SIG1; 527185377Ssam if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 528185377Ssam return HAL_MAC_HANG_SIG2; 529185377Ssam 530221580Sadrian HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature " 531185377Ssam "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 532185377Ssam __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 533185377Ssam mac_dbg.dma_dbg_6); 534185377Ssam 535221582Sadrian return 0; 536185377Ssam} 537185377Ssam 538185377Ssam/* 539185377Ssam * Determine if the baseband using the Observation Bus Register 540185377Ssam */ 541185377Ssamstatic int 542185377Ssamar5416DetectBBHang(struct ath_hal *ah) 543185377Ssam{ 544185377Ssam#define N(a) (sizeof(a)/sizeof(a[0])) 545185377Ssam /* 546185377Ssam * Check the PCU Observation Bus 1 register (0x806c) 547185377Ssam * NUM_STATUS_READS times 548185377Ssam * 549185377Ssam * 4 known BB hang signatures - 550185377Ssam * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 551185377Ssam * [2] bits 8,9 are 1, bit 11 is 0. State machine state 552185377Ssam * (bits 25-31) is 0x52 553185377Ssam * [3] bits 8,9 are 1, bit 11 is 0. State machine state 554185377Ssam * (bits 25-31) is 0x18 555185377Ssam * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 556185377Ssam * Rx State (bits 20-24) is 0x7. 557185377Ssam */ 558185377Ssam static const struct { 559185377Ssam uint32_t val; 560185377Ssam uint32_t mask; 561185377Ssam int code; 562185377Ssam } hang_list[] = { 563185377Ssam /* Reg Value Reg Mask Hang Code XXX */ 564185377Ssam { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 565185377Ssam { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 566185377Ssam { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 567185377Ssam { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 568185377Ssam }; 569185377Ssam uint32_t hang_sig; 570185377Ssam int i; 571185377Ssam 572185377Ssam hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 573185377Ssam for (i = 1; i <= NUM_STATUS_READS; i++) { 574185377Ssam if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 575185377Ssam return 0; 576185377Ssam } 577185377Ssam for (i = 0; i < N(hang_list); i++) 578185377Ssam if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 579221580Sadrian HALDEBUG(ah, HAL_DEBUG_HANG, 580185377Ssam "%s BB hang, signature 0x%x, code 0x%x\n", 581185377Ssam __func__, hang_sig, hang_list[i].code); 582185377Ssam return hang_list[i].code; 583185377Ssam } 584185377Ssam 585221580Sadrian HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! " 586185377Ssam "<0x806c>=0x%x\n", __func__, hang_sig); 587185377Ssam 588221582Sadrian return 0; 589185377Ssam#undef N 590185377Ssam} 591185377Ssam#undef NUM_STATUS_READS 592222584Sadrian 593222584Sadrian/* 594222584Sadrian * Get the radar parameter values and return them in the pe 595222584Sadrian * structure 596222584Sadrian */ 597222584Sadrianvoid 598222584Sadrianar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 599222584Sadrian{ 600222584Sadrian uint32_t val, temp; 601222584Sadrian 602222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_0); 603222584Sadrian 604222584Sadrian temp = MS(val,AR_PHY_RADAR_0_FIRPWR); 605222584Sadrian temp |= 0xFFFFFF80; 606222584Sadrian pe->pe_firpwr = temp; 607222584Sadrian pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI); 608222584Sadrian pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT); 609222584Sadrian pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI); 610222584Sadrian pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND); 611222584Sadrian 612222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_1); 613222584Sadrian temp = val & AR_PHY_RADAR_1_RELPWR_ENA; 614222584Sadrian pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH); 615222584Sadrian if (temp) 616222584Sadrian pe->pe_relpwr |= HAL_PHYERR_PARAM_ENABLE; 617222584Sadrian temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK; 618222584Sadrian pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH); 619222584Sadrian if (temp) 620222584Sadrian pe->pe_relstep |= HAL_PHYERR_PARAM_ENABLE; 621222584Sadrian pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN); 622222584Sadrian pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) & 623222584Sadrian AR_PHY_RADAR_EXT_ENA); 624222584Sadrian} 625222584Sadrian 626222584Sadrian/* 627222584Sadrian * Enable radar detection and set the radar parameters per the 628222584Sadrian * values in pe 629222584Sadrian */ 630222584Sadrianvoid 631222584Sadrianar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 632222584Sadrian{ 633222584Sadrian uint32_t val; 634222584Sadrian 635222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_0); 636222584Sadrian 637222584Sadrian if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { 638222584Sadrian val &= ~AR_PHY_RADAR_0_FIRPWR; 639222584Sadrian val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); 640222584Sadrian } 641222584Sadrian if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { 642222584Sadrian val &= ~AR_PHY_RADAR_0_RRSSI; 643222584Sadrian val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); 644222584Sadrian } 645222584Sadrian if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { 646222584Sadrian val &= ~AR_PHY_RADAR_0_HEIGHT; 647222584Sadrian val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); 648222584Sadrian } 649222584Sadrian if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { 650222584Sadrian val &= ~AR_PHY_RADAR_0_PRSSI; 651222584Sadrian val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); 652222584Sadrian } 653222584Sadrian if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { 654222584Sadrian val &= ~AR_PHY_RADAR_0_INBAND; 655222584Sadrian val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); 656222584Sadrian } 657222584Sadrian 658222584Sadrian /*Enable FFT data*/ 659222584Sadrian val |= AR_PHY_RADAR_0_FFT_ENA; 660222584Sadrian 661222584Sadrian OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA); 662222584Sadrian 663222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_1); 664222584Sadrian val |= (AR_PHY_RADAR_1_MAX_RRSSI | AR_PHY_RADAR_1_BLOCK_CHECK); 665222584Sadrian 666222584Sadrian if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) { 667222584Sadrian val &= ~AR_PHY_RADAR_1_MAXLEN; 668222584Sadrian val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN); 669222584Sadrian } 670222584Sadrian OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 671222584Sadrian 672222584Sadrian /* 673222584Sadrian * Enable HT/40 if the upper layer asks; 674222584Sadrian * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS 675222584Sadrian * is available. 676222584Sadrian */ 677222584Sadrian if (pe->pe_extchannel) 678222584Sadrian OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); 679222584Sadrian else 680222584Sadrian OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); 681222584Sadrian 682222584Sadrian if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) { 683222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_1); 684222584Sadrian val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH; 685222584Sadrian val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH); 686222584Sadrian OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 687222584Sadrian } 688222584Sadrian if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) { 689222584Sadrian val = OS_REG_READ(ah, AR_PHY_RADAR_1); 690222584Sadrian val &= ~AR_PHY_RADAR_1_RELPWR_THRESH; 691222584Sadrian val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH); 692222584Sadrian OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 693222584Sadrian } 694222584Sadrian} 695222815Sadrian 696222815Sadrian/* 697222815Sadrian * Extract the radar event information from the given phy error. 698222815Sadrian * 699222815Sadrian * Returns AH_TRUE if the phy error was actually a phy error, 700222815Sadrian * AH_FALSE if the phy error wasn't a phy error. 701222815Sadrian */ 702222815SadrianHAL_BOOL 703222815Sadrianar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, 704222815Sadrian uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event) 705222815Sadrian{ 706222815Sadrian /* 707222815Sadrian * For now, this isn't implemented. 708222815Sadrian */ 709222815Sadrian return AH_FALSE; 710222815Sadrian} 711