ar5416_misc.c revision 224709
155682Smarkm/* 2233294Sstas * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3233294Sstas * Copyright (c) 2002-2008 Atheros Communications, Inc. 4233294Sstas * 555682Smarkm * Permission to use, copy, modify, and/or distribute this software for any 6233294Sstas * purpose with or without fee is hereby granted, provided that the above 755682Smarkm * copyright notice and this permission notice appear in all copies. 8233294Sstas * 9233294Sstas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10233294Sstas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1155682Smarkm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12233294Sstas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13233294Sstas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1455682Smarkm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15233294Sstas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16233294Sstas * 17233294Sstas * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 224709 2011-08-08 13:15:39Z adrian $ 1855682Smarkm */ 19233294Sstas#include "opt_ah.h" 20233294Sstas 21233294Sstas#include "ah.h" 22233294Sstas#include "ah_internal.h" 23233294Sstas#include "ah_devid.h" 24233294Sstas#ifdef AH_DEBUG 25233294Sstas#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 26233294Sstas#endif 27233294Sstas 28233294Sstas#include "ar5416/ar5416.h" 29233294Sstas#include "ar5416/ar5416reg.h" 30233294Sstas#include "ar5416/ar5416phy.h" 31233294Sstas 32233294Sstas/* 33233294Sstas * Return the wireless modes (a,b,g,n,t) supported by hardware. 3455682Smarkm * 3555682Smarkm * This value is what is actually supported by the hardware 3655682Smarkm * and is unaffected by regulatory/country code settings. 3755682Smarkm * 38233294Sstas */ 39233294Sstasu_int 40233294Sstasar5416GetWirelessModes(struct ath_hal *ah) 41233294Sstas{ 42233294Sstas u_int mode; 43233294Sstas struct ath_hal_private *ahpriv = AH_PRIVATE(ah); 44233294Sstas HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; 45233294Sstas 46233294Sstas mode = ar5212GetWirelessModes(ah); 47233294Sstas 48233294Sstas /* Only enable HT modes if the NIC supports HT */ 4955682Smarkm if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A)) 50233294Sstas mode |= HAL_MODE_11NA_HT20 5155682Smarkm | HAL_MODE_11NA_HT40PLUS 5255682Smarkm | HAL_MODE_11NA_HT40MINUS 5355682Smarkm ; 5455682Smarkm if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G)) 5555682Smarkm mode |= HAL_MODE_11NG_HT20 5655682Smarkm | HAL_MODE_11NG_HT40PLUS 57178825Sdfr | HAL_MODE_11NG_HT40MINUS 5855682Smarkm ; 5955682Smarkm return mode; 6055682Smarkm} 61233294Sstas 62233294Sstas/* 63233294Sstas * Change the LED blinking pattern to correspond to the connectivity 64233294Sstas */ 65233294Sstasvoid 66233294Sstasar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 67233294Sstas{ 68233294Sstas static const uint32_t ledbits[8] = { 69233294Sstas AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 70233294Sstas AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 71233294Sstas AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 72233294Sstas AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 73233294Sstas AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 74233294Sstas AR_MAC_LED_ASSOC_NONE, 7555682Smarkm AR_MAC_LED_ASSOC_NONE, 7655682Smarkm AR_MAC_LED_ASSOC_NONE, 7755682Smarkm }; 7855682Smarkm uint32_t bits; 7955682Smarkm 80127808Snectar if (AR_SREV_HOWL(ah)) 81127808Snectar return; 82127808Snectar 83127808Snectar bits = OS_REG_READ(ah, AR_MAC_LED); 8478527Sassar bits = (bits &~ AR_MAC_LED_MODE) 85233294Sstas | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 86233294Sstas#if 1 8755682Smarkm | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 8878527Sassar#endif 8955682Smarkm ; 9055682Smarkm bits = (bits &~ AR_MAC_LED_ASSOC) 9155682Smarkm | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 9255682Smarkm OS_REG_WRITE(ah, AR_MAC_LED, bits); 9355682Smarkm} 9455682Smarkm 9555682Smarkm/* 96127808Snectar * Reset the current hardware tsf for stamlme. 9755682Smarkm */ 9855682Smarkmvoid 99127808Snectarar5416ResetTsf(struct ath_hal *ah) 10055682Smarkm{ 10155682Smarkm uint32_t v; 10255682Smarkm int i; 103127808Snectar 10455682Smarkm for (i = 0; i < 10; i++) { 10555682Smarkm v = OS_REG_READ(ah, AR_SLP32_MODE); 10655682Smarkm if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 10755682Smarkm break; 10855682Smarkm OS_DELAY(10); 109178825Sdfr } 110233294Sstas OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 111233294Sstas} 112233294Sstas 113233294SstasHAL_BOOL 114233294Sstasar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 115233294Sstas{ 116233294Sstas return AH_TRUE; 117233294Sstas} 118233294Sstas 119233294Sstas/* Setup decompression for given key index */ 120233294SstasHAL_BOOL 121233294Sstasar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 122233294Sstas{ 123233294Sstas return HAL_OK; 124178825Sdfr} 125178825Sdfr 126178825Sdfr/* Setup coverage class */ 127178825Sdfrvoid 128178825Sdfrar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 129178825Sdfr{ 130178825Sdfr AH_PRIVATE(ah)->ah_coverageClass = coverageclass; 131233294Sstas} 132233294Sstas 133233294Sstas/* 134233294Sstas * Return approximation of extension channel busy over an time interval 135233294Sstas * 0% (clear) -> 100% (busy) 136233294Sstas * 137233294Sstas */ 138233294Sstasuint32_t 139233294Sstasar5416Get11nExtBusy(struct ath_hal *ah) 140233294Sstas{ 141233294Sstas struct ath_hal_5416 *ahp = AH5416(ah); 142233294Sstas uint32_t busy; /* percentage */ 143233294Sstas uint32_t cycleCount, ctlBusy, extBusy; 144233294Sstas 145178825Sdfr ctlBusy = OS_REG_READ(ah, AR_RCCNT); 146178825Sdfr extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 147178825Sdfr cycleCount = OS_REG_READ(ah, AR_CCCNT); 148178825Sdfr 149178825Sdfr if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 150178825Sdfr /* 151178825Sdfr * Cycle counter wrap (or initial call); it's not possible 152233294Sstas * to accurately calculate a value because the registers 153233294Sstas * right shift rather than wrap--so punt and return 0. 154233294Sstas */ 155233294Sstas busy = 0; 156233294Sstas HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 157233294Sstas __func__); 158233294Sstas 159233294Sstas } else { 160233294Sstas uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 161233294Sstas uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 162233294Sstas uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 163233294Sstas uint32_t ctlClearDelta = 0; 164178825Sdfr 165178825Sdfr /* Compute control channel rxclear. 166178825Sdfr * The cycle delta may be less than the control channel delta. 167178825Sdfr * This could be solved by freezing the timers (or an atomic read, 168178825Sdfr * if one was available). Checking for the condition should be 169178825Sdfr * sufficient. 170233294Sstas */ 171233294Sstas if (cycleDelta > ctlBusyDelta) { 172233294Sstas ctlClearDelta = cycleDelta - ctlBusyDelta; 173233294Sstas } 174233294Sstas 175233294Sstas /* Compute ratio of extension channel busy to control channel clear 176233294Sstas * as an approximation to extension channel cleanliness. 177233294Sstas * 178233294Sstas * According to the hardware folks, ext rxclear is undefined 179233294Sstas * if the ctrl rxclear is de-asserted (i.e. busy) 180233294Sstas */ 181233294Sstas if (ctlClearDelta) { 182233294Sstas busy = (extBusyDelta * 100) / ctlClearDelta; 183233294Sstas } else { 184233294Sstas busy = 100; 185233294Sstas } 186233294Sstas if (busy > 100) { 187178825Sdfr busy = 100; 188178825Sdfr } 189233294Sstas#if 0 190178825Sdfr HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 191178825Sdfr "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 192178825Sdfr "busy %d\n", 193178825Sdfr __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 194178825Sdfr#endif 195178825Sdfr } 196178825Sdfr 197178825Sdfr ahp->ah_cycleCount = cycleCount; 198233294Sstas ahp->ah_ctlBusy = ctlBusy; 199178825Sdfr ahp->ah_extBusy = extBusy; 200178825Sdfr 201178825Sdfr return busy; 202233294Sstas} 203233294Sstas 204233294Sstas/* 205233294Sstas * Configure 20/40 operation 206178825Sdfr * 207178825Sdfr * 20/40 = joint rx clear (control and extension) 208178825Sdfr * 20 = rx clear (control) 209178825Sdfr * 210178825Sdfr * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 211178825Sdfr * from 20/40 => 20 only 212178825Sdfr */ 213178825Sdfrvoid 214178825Sdfrar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 215178825Sdfr{ 216178825Sdfr uint32_t macmode; 217178825Sdfr 218233294Sstas /* Configure MAC for 20/40 operation */ 219233294Sstas if (mode == HAL_HT_MACMODE_2040) { 220178825Sdfr macmode = AR_2040_JOINED_RX_CLEAR; 221178825Sdfr } else { 222178825Sdfr macmode = 0; 223178825Sdfr } 224178825Sdfr OS_REG_WRITE(ah, AR_2040_MODE, macmode); 225178825Sdfr} 226178825Sdfr 227178825Sdfr/* 228178825Sdfr * Get Rx clear (control/extension channel) 229178825Sdfr * 230178825Sdfr * Returns active low (busy) for ctrl/ext channel 231178825Sdfr * Owl 2.0 232178825Sdfr */ 233233294SstasHAL_HT_RXCLEAR 234233294Sstasar5416Get11nRxClear(struct ath_hal *ah) 235233294Sstas{ 236233294Sstas HAL_HT_RXCLEAR rxclear = 0; 237178825Sdfr uint32_t val; 238178825Sdfr 239178825Sdfr val = OS_REG_READ(ah, AR_DIAG_SW); 240178825Sdfr 241178825Sdfr /* control channel */ 242178825Sdfr if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 243178825Sdfr rxclear |= HAL_RX_CLEAR_CTL_LOW; 244178825Sdfr } 245178825Sdfr /* extension channel */ 246178825Sdfr if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 247178825Sdfr rxclear |= HAL_RX_CLEAR_EXT_LOW; 248178825Sdfr } 249178825Sdfr return rxclear; 250178825Sdfr} 251178825Sdfr 252178825Sdfr/* 253178825Sdfr * Set Rx clear (control/extension channel) 254178825Sdfr * 255233294Sstas * Useful for forcing the channel to appear busy for 256233294Sstas * debugging/diagnostics 257233294Sstas * Owl 2.0 258233294Sstas */ 259178825Sdfrvoid 260178825Sdfrar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 261178825Sdfr{ 262178825Sdfr /* control channel */ 263178825Sdfr if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 264178825Sdfr OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 265178825Sdfr } else { 266233294Sstas OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 267178825Sdfr } 268178825Sdfr /* extension channel */ 269178825Sdfr if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 270233294Sstas OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 271178825Sdfr } else { 272178825Sdfr OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 273178825Sdfr } 274178825Sdfr} 275178825Sdfr 276178825Sdfr/* XXX shouldn't be here! */ 277178825Sdfr#define TU_TO_USEC(_tu) ((_tu) << 10) 278178825Sdfr 279178825SdfrHAL_STATUS 280178825Sdfrar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, 281178825Sdfr uint32_t nextStart, HAL_QUIET_FLAG flag) 282178825Sdfr{ 283178825Sdfr uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */ 284233294Sstas uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */ 285178825Sdfr if (flag & HAL_QUIET_ENABLE) { 286178825Sdfr if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) { 287178825Sdfr /* Add the nextStart offset to the current TSF */ 288178825Sdfr nextStart_us += OS_REG_READ(ah, AR_TSF_L32); 289178825Sdfr } 290178825Sdfr if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) { 291178825Sdfr nextStart_us += ah->ah_config.ah_sw_beacon_response_time; 292178825Sdfr } 293178825Sdfr OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 294178825Sdfr OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR)); 295178825Sdfr OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us); 296178825Sdfr OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us); 297178825Sdfr OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 298178825Sdfr } else { 299178825Sdfr OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET); 300178825Sdfr } 301178825Sdfr return HAL_OK; 302233294Sstas} 303233294Sstas#undef TU_TO_USEC 304233294Sstas 305233294SstasHAL_STATUS 306178825Sdfrar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 307178825Sdfr uint32_t capability, uint32_t *result) 308178825Sdfr{ 309178825Sdfr switch (type) { 310178825Sdfr case HAL_CAP_BB_HANG: 311233294Sstas switch (capability) { 312233294Sstas case HAL_BB_HANG_RIFS: 313233294Sstas return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 314233294Sstas case HAL_BB_HANG_DFS: 315178825Sdfr return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP; 316178825Sdfr case HAL_BB_HANG_RX_CLEAR: 317178825Sdfr return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 318178825Sdfr } 319178825Sdfr break; 320178825Sdfr case HAL_CAP_MAC_HANG: 321178825Sdfr return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 322178825Sdfr (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 323178825Sdfr AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? 324178825Sdfr HAL_OK : HAL_ENOTSUPP; 325178825Sdfr case HAL_CAP_DIVERSITY: /* disable classic fast diversity */ 326178825Sdfr return HAL_ENXIO; 327178825Sdfr default: 328233294Sstas break; 329233294Sstas } 330233294Sstas return ar5212GetCapability(ah, type, capability, result); 331233294Sstas} 332233294Sstas 333233294Sstasstatic int ar5416DetectMacHang(struct ath_hal *ah); 334233294Sstasstatic int ar5416DetectBBHang(struct ath_hal *ah); 335233294Sstas 336233294SstasHAL_BOOL 337233294Sstasar5416GetDiagState(struct ath_hal *ah, int request, 338233294Sstas const void *args, uint32_t argsize, 339178825Sdfr void **result, uint32_t *resultsize) 340178825Sdfr{ 341233294Sstas struct ath_hal_5416 *ahp = AH5416(ah); 342178825Sdfr int hangs; 343178825Sdfr 344178825Sdfr if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 345178825Sdfr return AH_TRUE; 346178825Sdfr switch (request) { 347178825Sdfr case HAL_DIAG_EEPROM: 348178825Sdfr return ath_hal_eepromDiag(ah, request, 349178825Sdfr args, argsize, result, resultsize); 350178825Sdfr case HAL_DIAG_CHECK_HANGS: 351178825Sdfr if (argsize != sizeof(int)) 352178825Sdfr return AH_FALSE; 353178825Sdfr hangs = *(const int *) args; 354178825Sdfr ahp->ah_hangs = 0; 355233294Sstas if (hangs & HAL_BB_HANGS) 356233294Sstas ahp->ah_hangs |= ar5416DetectBBHang(ah); 357178825Sdfr /* NB: if BB is hung MAC will be hung too so skip check */ 358178825Sdfr if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 359178825Sdfr ahp->ah_hangs |= ar5416DetectMacHang(ah); 360178825Sdfr *result = &ahp->ah_hangs; 361178825Sdfr *resultsize = sizeof(ahp->ah_hangs); 362178825Sdfr return AH_TRUE; 363178825Sdfr } 364178825Sdfr return ar5212GetDiagState(ah, request, 365233294Sstas args, argsize, result, resultsize); 366233294Sstas} 367233294Sstas 368233294Sstastypedef struct { 369178825Sdfr uint32_t dma_dbg_3; 370178825Sdfr uint32_t dma_dbg_4; 371178825Sdfr uint32_t dma_dbg_5; 372178825Sdfr uint32_t dma_dbg_6; 373233294Sstas} mac_dbg_regs_t; 374233294Sstas 375233294Sstastypedef enum { 376233294Sstas dcu_chain_state = 0x1, 377233294Sstas dcu_complete_state = 0x2, 378233294Sstas qcu_state = 0x4, 379233294Sstas qcu_fsp_ok = 0x8, 380233294Sstas qcu_fsp_state = 0x10, 381233294Sstas qcu_stitch_state = 0x20, 382233294Sstas qcu_fetch_state = 0x40, 383233294Sstas qcu_complete_state = 0x80 384233294Sstas} hal_mac_hangs_t; 385233294Sstas 386233294Sstastypedef struct { 387233294Sstas int states; 388233294Sstas uint8_t dcu_chain_state; 389233294Sstas uint8_t dcu_complete_state; 390233294Sstas uint8_t qcu_state; 391233294Sstas uint8_t qcu_fsp_ok; 392233294Sstas uint8_t qcu_fsp_state; 393233294Sstas uint8_t qcu_stitch_state; 394233294Sstas uint8_t qcu_fetch_state; 395233294Sstas uint8_t qcu_complete_state; 396233294Sstas} hal_mac_hang_check_t; 397233294Sstas 398233294SstasHAL_BOOL 399233294Sstasar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan, 400233294Sstas HAL_BOOL enable) 401233294Sstas{ 402233294Sstas uint32_t val; 403233294Sstas HAL_BOOL is_chan_2g = AH_FALSE; 404233294Sstas HAL_BOOL is_ht40 = AH_FALSE; 405233294Sstas 406233294Sstas if (chan) 407233294Sstas is_chan_2g = IEEE80211_IS_CHAN_2GHZ(chan); 408233294Sstas 409233294Sstas if (chan) 410233294Sstas is_ht40 = IEEE80211_IS_CHAN_HT40(chan); 411233294Sstas 412233294Sstas /* Only support disabling RIFS delay for now */ 413233294Sstas HALASSERT(enable == AH_FALSE); 414233294Sstas 415233294Sstas if (enable == AH_TRUE) 416233294Sstas return AH_FALSE; 417233294Sstas 418233294Sstas /* Change RIFS init delay to 0 */ 419233294Sstas val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS); 420233294Sstas val &= ~AR_PHY_RIFS_INIT_DELAY; 421233294Sstas OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val); 422233294Sstas 423233294Sstas /* 424233294Sstas * For Owl, RIFS RX parameters are controlled differently; 425233294Sstas * it isn't enabled in the inivals by default. 426233294Sstas * 427233294Sstas * For Sowl/Howl, RIFS RX is enabled in the inivals by default; 428233294Sstas * the following code sets them back to non-RIFS values. 429233294Sstas * 430233294Sstas * For > Sowl/Howl, RIFS RX can be left on by default and so 431233294Sstas * this function shouldn't be called. 432233294Sstas */ 433233294Sstas if ((! AR_SREV_SOWL(ah)) && (! AR_SREV_HOWL(ah))) 434233294Sstas return AH_TRUE; 435233294Sstas 436233294Sstas /* Reset search delay to default values */ 437233294Sstas if (is_chan_2g) 438233294Sstas if (is_ht40) 439233294Sstas OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x268); 440233294Sstas else 441233294Sstas OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x134); 442233294Sstas else 443233294Sstas if (is_ht40) 444233294Sstas OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x370); 445233294Sstas else 446233294Sstas OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x1b8); 447233294Sstas 448233294Sstas return AH_TRUE; 449233294Sstas} 450233294Sstas 451233294Sstasstatic HAL_BOOL 452233294Sstasar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 453233294Sstas const hal_mac_hang_check_t *check) 454233294Sstas{ 455233294Sstas int found_states; 456233294Sstas 457233294Sstas found_states = 0; 458233294Sstas if (check->states & dcu_chain_state) { 459233294Sstas int i; 460233294Sstas 461233294Sstas for (i = 0; i < 6; i++) { 462233294Sstas if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 463233294Sstas check->dcu_chain_state) 464233294Sstas found_states |= dcu_chain_state; 465233294Sstas } 466233294Sstas for (i = 0; i < 4; i++) { 467233294Sstas if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 468233294Sstas check->dcu_chain_state) 469233294Sstas found_states |= dcu_chain_state; 470233294Sstas } 471233294Sstas } 472233294Sstas if (check->states & dcu_complete_state) { 473233294Sstas if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 474233294Sstas found_states |= dcu_complete_state; 475233294Sstas } 476233294Sstas if (check->states & qcu_stitch_state) { 477233294Sstas if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 478233294Sstas found_states |= qcu_stitch_state; 479233294Sstas } 480233294Sstas if (check->states & qcu_fetch_state) { 481233294Sstas if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 482233294Sstas found_states |= qcu_fetch_state; 483233294Sstas } 484233294Sstas if (check->states & qcu_complete_state) { 485233294Sstas if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 486233294Sstas found_states |= qcu_complete_state; 487233294Sstas } 488233294Sstas return (found_states == check->states); 489233294Sstas} 490233294Sstas 491233294Sstas#define NUM_STATUS_READS 50 492233294Sstas 493233294Sstasstatic int 494233294Sstasar5416DetectMacHang(struct ath_hal *ah) 495233294Sstas{ 496233294Sstas static const hal_mac_hang_check_t hang_sig1 = { 497233294Sstas .dcu_chain_state = 0x6, 498233294Sstas .dcu_complete_state = 0x1, 499233294Sstas .states = dcu_chain_state 500233294Sstas | dcu_complete_state, 501233294Sstas }; 502233294Sstas static const hal_mac_hang_check_t hang_sig2 = { 503233294Sstas .qcu_stitch_state = 0x9, 504233294Sstas .qcu_fetch_state = 0x8, 505233294Sstas .qcu_complete_state = 0x4, 506233294Sstas .states = qcu_stitch_state 507233294Sstas | qcu_fetch_state 508233294Sstas | qcu_complete_state, 509233294Sstas }; 510233294Sstas mac_dbg_regs_t mac_dbg; 511233294Sstas int i; 512233294Sstas 513233294Sstas mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 514233294Sstas mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 515233294Sstas mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 516233294Sstas mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 517233294Sstas for (i = 1; i <= NUM_STATUS_READS; i++) { 518233294Sstas if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 519233294Sstas mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 520233294Sstas mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 521233294Sstas mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 522233294Sstas return 0; 523233294Sstas } 524233294Sstas 525233294Sstas if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 526233294Sstas return HAL_MAC_HANG_SIG1; 527233294Sstas if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 528233294Sstas return HAL_MAC_HANG_SIG2; 529233294Sstas 530233294Sstas HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature " 531233294Sstas "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 532233294Sstas __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 533233294Sstas mac_dbg.dma_dbg_6); 534233294Sstas 535233294Sstas return 0; 536233294Sstas} 537233294Sstas 538233294Sstas/* 539233294Sstas * Determine if the baseband using the Observation Bus Register 540233294Sstas */ 541233294Sstasstatic int 542233294Sstasar5416DetectBBHang(struct ath_hal *ah) 543233294Sstas{ 544233294Sstas#define N(a) (sizeof(a)/sizeof(a[0])) 545233294Sstas /* 546233294Sstas * Check the PCU Observation Bus 1 register (0x806c) 547233294Sstas * NUM_STATUS_READS times 548233294Sstas * 549233294Sstas * 4 known BB hang signatures - 550233294Sstas * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 551233294Sstas * [2] bits 8,9 are 1, bit 11 is 0. State machine state 552233294Sstas * (bits 25-31) is 0x52 553233294Sstas * [3] bits 8,9 are 1, bit 11 is 0. State machine state 554233294Sstas * (bits 25-31) is 0x18 555233294Sstas * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 556233294Sstas * Rx State (bits 20-24) is 0x7. 557233294Sstas */ 558233294Sstas static const struct { 559233294Sstas uint32_t val; 560233294Sstas uint32_t mask; 561233294Sstas int code; 562233294Sstas } hang_list[] = { 563233294Sstas /* Reg Value Reg Mask Hang Code XXX */ 564233294Sstas { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 565233294Sstas { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 566233294Sstas { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 567233294Sstas { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 568233294Sstas }; 569233294Sstas uint32_t hang_sig; 570233294Sstas int i; 571233294Sstas 572233294Sstas hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 573233294Sstas for (i = 1; i <= NUM_STATUS_READS; i++) { 574233294Sstas if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 575233294Sstas return 0; 576233294Sstas } 577233294Sstas for (i = 0; i < N(hang_list); i++) 578233294Sstas if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 579233294Sstas HALDEBUG(ah, HAL_DEBUG_HANG, 580233294Sstas "%s BB hang, signature 0x%x, code 0x%x\n", 581233294Sstas __func__, hang_sig, hang_list[i].code); 582233294Sstas return hang_list[i].code; 583233294Sstas } 584233294Sstas 585233294Sstas HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! " 586233294Sstas "<0x806c>=0x%x\n", __func__, hang_sig); 587233294Sstas 588233294Sstas return 0; 589233294Sstas#undef N 590233294Sstas} 591233294Sstas#undef NUM_STATUS_READS 592233294Sstas 593233294Sstas/* 594233294Sstas * Get the radar parameter values and return them in the pe 595233294Sstas * structure 596233294Sstas */ 597233294Sstasvoid 598233294Sstasar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 599233294Sstas{ 600233294Sstas uint32_t val, temp; 601233294Sstas 602233294Sstas val = OS_REG_READ(ah, AR_PHY_RADAR_0); 603233294Sstas 604233294Sstas temp = MS(val,AR_PHY_RADAR_0_FIRPWR); 605233294Sstas temp |= 0xFFFFFF80; 606233294Sstas pe->pe_firpwr = temp; 607233294Sstas pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI); 608233294Sstas pe->pe_height = MS(val, AR_PHY_RADAR_0_HEIGHT); 609233294Sstas pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI); 610233294Sstas pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND); 611233294Sstas 612233294Sstas val = OS_REG_READ(ah, AR_PHY_RADAR_1); 613233294Sstas temp = val & AR_PHY_RADAR_1_RELPWR_ENA; 614233294Sstas pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH); 615233294Sstas if (temp) 616233294Sstas pe->pe_relpwr |= HAL_PHYERR_PARAM_ENABLE; 617233294Sstas temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK; 618233294Sstas pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH); 619233294Sstas if (temp) 620233294Sstas pe->pe_enabled = 1; 621233294Sstas else 622233294Sstas pe->pe_enabled = 0; 623233294Sstas 624233294Sstas pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN); 625233294Sstas pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) & 626233294Sstas AR_PHY_RADAR_EXT_ENA); 627233294Sstas 628233294Sstas pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 629233294Sstas AR_PHY_RADAR_1_USE_FIR128); 630233294Sstas pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 631233294Sstas AR_PHY_RADAR_1_BLOCK_CHECK); 632233294Sstas pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) & 633233294Sstas AR_PHY_RADAR_1_MAX_RRSSI); 634233294Sstas} 635233294Sstas 636233294Sstas/* 637233294Sstas * Enable radar detection and set the radar parameters per the 638233294Sstas * values in pe 639233294Sstas */ 640233294Sstasvoid 641233294Sstasar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) 642233294Sstas{ 643233294Sstas uint32_t val; 644233294Sstas 645233294Sstas val = OS_REG_READ(ah, AR_PHY_RADAR_0); 646233294Sstas 647233294Sstas if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) { 648233294Sstas val &= ~AR_PHY_RADAR_0_FIRPWR; 649233294Sstas val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR); 650233294Sstas } 651233294Sstas if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) { 652233294Sstas val &= ~AR_PHY_RADAR_0_RRSSI; 653233294Sstas val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI); 654233294Sstas } 655233294Sstas if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) { 656233294Sstas val &= ~AR_PHY_RADAR_0_HEIGHT; 657233294Sstas val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT); 658233294Sstas } 659233294Sstas if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) { 660233294Sstas val &= ~AR_PHY_RADAR_0_PRSSI; 661233294Sstas val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI); 662233294Sstas } 663233294Sstas if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) { 664233294Sstas val &= ~AR_PHY_RADAR_0_INBAND; 665233294Sstas val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND); 666233294Sstas } 667233294Sstas 668233294Sstas /*Enable FFT data*/ 669233294Sstas val |= AR_PHY_RADAR_0_FFT_ENA; 670233294Sstas 671233294Sstas OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA); 672233294Sstas 673233294Sstas if (pe->pe_usefir128 == 1) 674233294Sstas OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); 675233294Sstas else if (pe->pe_usefir128 == 0) 676233294Sstas OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128); 677233294Sstas 678233294Sstas if (pe->pe_enmaxrssi == 1) 679233294Sstas OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); 680233294Sstas else if (pe->pe_enmaxrssi == 0) 681233294Sstas OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI); 682233294Sstas 683233294Sstas if (pe->pe_blockradar == 1) 684233294Sstas OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); 685233294Sstas else if (pe->pe_blockradar == 0) 686233294Sstas OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK); 687233294Sstas 688233294Sstas if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) { 689233294Sstas val = OS_REG_READ(ah, AR_PHY_RADAR_1); 690233294Sstas val &= ~AR_PHY_RADAR_1_MAXLEN; 691233294Sstas val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN); 692233294Sstas OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 693233294Sstas } 694233294Sstas 695233294Sstas /* 696233294Sstas * Enable HT/40 if the upper layer asks; 697233294Sstas * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS 698233294Sstas * is available. 699233294Sstas */ 700233294Sstas if (pe->pe_extchannel == 1) 701233294Sstas OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); 702233294Sstas else if (pe->pe_extchannel == 0) 703233294Sstas OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA); 704233294Sstas 705233294Sstas if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) { 706233294Sstas val = OS_REG_READ(ah, AR_PHY_RADAR_1); 707233294Sstas val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH; 708233294Sstas val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH); 709233294Sstas OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 710233294Sstas } 711233294Sstas if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) { 712233294Sstas val = OS_REG_READ(ah, AR_PHY_RADAR_1); 713233294Sstas val &= ~AR_PHY_RADAR_1_RELPWR_THRESH; 714233294Sstas val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH); 715233294Sstas OS_REG_WRITE(ah, AR_PHY_RADAR_1, val); 716320907Sdelphij } 717320907Sdelphij} 718233294Sstas 719233294Sstas/* 720233294Sstas * Extract the radar event information from the given phy error. 721233294Sstas * 722233294Sstas * Returns AH_TRUE if the phy error was actually a phy error, 723233294Sstas * AH_FALSE if the phy error wasn't a phy error. 724233294Sstas */ 725233294SstasHAL_BOOL 726233294Sstasar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs, 727233294Sstas uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event) 728233294Sstas{ 729233294Sstas /* 730233294Sstas * For now, this isn't implemented. 731233294Sstas */ 732233294Sstas return AH_FALSE; 733233294Sstas} 734233294Sstas 735233294Sstas/* 736233294Sstas * Return whether fast-clock is currently enabled for this 737233294Sstas * channel. 738233294Sstas */ 739233294SstasHAL_BOOL 740233294Sstasar5416IsFastClockEnabled(struct ath_hal *ah) 741233294Sstas{ 742233294Sstas struct ath_hal_private *ahp = AH_PRIVATE(ah); 743233294Sstas 744233294Sstas return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan); 745233294Sstas} 746233294Sstas