ar5416_misc.c (185380) | ar5416_misc.c (185406) |
---|---|
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 * $Id: ar5416_misc.c,v 1.12 2008/11/27 22:30:07 sam Exp $ 18 */ 19#include "opt_ah.h" 20 | 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 * $Id: ar5416_misc.c,v 1.12 2008/11/27 22:30:07 sam Exp $ 18 */ 19#include "opt_ah.h" 20 |
21#ifdef AH_SUPPORT_AR5416 22 | |
23#include "ah.h" 24#include "ah_internal.h" 25#include "ah_devid.h" 26#ifdef AH_DEBUG 27#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 28#endif 29 30#include "ar5416/ar5416.h" 31#include "ar5416/ar5416reg.h" 32#include "ar5416/ar5416phy.h" 33 34/* 35 * Return the wireless modes (a,b,g,t) supported by hardware. 36 * 37 * This value is what is actually supported by the hardware 38 * and is unaffected by regulatory/country code settings. 39 * 40 */ 41u_int 42ar5416GetWirelessModes(struct ath_hal *ah) 43{ 44 u_int mode; 45 46 mode = ar5212GetWirelessModes(ah); 47 if (mode & HAL_MODE_11A) 48 mode |= HAL_MODE_11NA_HT20 49 | HAL_MODE_11NA_HT40PLUS 50 | HAL_MODE_11NA_HT40MINUS 51 ; 52 if (mode & HAL_MODE_11G) 53 mode |= HAL_MODE_11NG_HT20 54 | HAL_MODE_11NG_HT40PLUS 55 | HAL_MODE_11NG_HT40MINUS 56 ; 57 return mode; 58} 59 60/* 61 * Change the LED blinking pattern to correspond to the connectivity 62 */ 63void 64ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 65{ 66 static const uint32_t ledbits[8] = { 67 AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 68 AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 69 AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 70 AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 71 AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 72 AR_MAC_LED_ASSOC_NONE, 73 AR_MAC_LED_ASSOC_NONE, 74 AR_MAC_LED_ASSOC_NONE, 75 }; 76 uint32_t bits; 77 78 bits = OS_REG_READ(ah, AR_MAC_LED); 79 bits = (bits &~ AR_MAC_LED_MODE) 80 | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 81#if 1 82 | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 83#endif 84 ; 85 bits = (bits &~ AR_MAC_LED_ASSOC) 86 | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 87 OS_REG_WRITE(ah, AR_MAC_LED, bits); 88} 89 90/* 91 * Reset the current hardware tsf for stamlme. 92 */ 93void 94ar5416ResetTsf(struct ath_hal *ah) 95{ 96 uint32_t v; 97 int i; 98 99 for (i = 0; i < 10; i++) { 100 v = OS_REG_READ(ah, AR_SLP32_MODE); 101 if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 102 break; 103 OS_DELAY(10); 104 } 105 OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 106} 107 108HAL_BOOL 109ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 110{ 111 return AH_TRUE; 112} 113 114/* Setup decompression for given key index */ 115HAL_BOOL 116ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 117{ 118 return HAL_OK; 119} 120 121/* Setup coverage class */ 122void 123ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 124{ 125} 126 127/* 128 * Return approximation of extension channel busy over an time interval 129 * 0% (clear) -> 100% (busy) 130 * 131 */ 132uint32_t 133ar5416Get11nExtBusy(struct ath_hal *ah) 134{ 135 struct ath_hal_5416 *ahp = AH5416(ah); 136 uint32_t busy; /* percentage */ 137 uint32_t cycleCount, ctlBusy, extBusy; 138 139 ctlBusy = OS_REG_READ(ah, AR_RCCNT); 140 extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 141 cycleCount = OS_REG_READ(ah, AR_CCCNT); 142 143 if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 144 /* 145 * Cycle counter wrap (or initial call); it's not possible 146 * to accurately calculate a value because the registers 147 * right shift rather than wrap--so punt and return 0. 148 */ 149 busy = 0; 150 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 151 __func__); 152 153 } else { 154 uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 155 uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 156 uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 157 uint32_t ctlClearDelta = 0; 158 159 /* Compute control channel rxclear. 160 * The cycle delta may be less than the control channel delta. 161 * This could be solved by freezing the timers (or an atomic read, 162 * if one was available). Checking for the condition should be 163 * sufficient. 164 */ 165 if (cycleDelta > ctlBusyDelta) { 166 ctlClearDelta = cycleDelta - ctlBusyDelta; 167 } 168 169 /* Compute ratio of extension channel busy to control channel clear 170 * as an approximation to extension channel cleanliness. 171 * 172 * According to the hardware folks, ext rxclear is undefined 173 * if the ctrl rxclear is de-asserted (i.e. busy) 174 */ 175 if (ctlClearDelta) { 176 busy = (extBusyDelta * 100) / ctlClearDelta; 177 } else { 178 busy = 100; 179 } 180 if (busy > 100) { 181 busy = 100; 182 } 183#if 0 184 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 185 "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 186 "busy %d\n", 187 __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 188#endif 189 } 190 191 ahp->ah_cycleCount = cycleCount; 192 ahp->ah_ctlBusy = ctlBusy; 193 ahp->ah_extBusy = extBusy; 194 195 return busy; 196} 197 198/* 199 * Configure 20/40 operation 200 * 201 * 20/40 = joint rx clear (control and extension) 202 * 20 = rx clear (control) 203 * 204 * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 205 * from 20/40 => 20 only 206 */ 207void 208ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 209{ 210 uint32_t macmode; 211 212 /* Configure MAC for 20/40 operation */ 213 if (mode == HAL_HT_MACMODE_2040) { 214 macmode = AR_2040_JOINED_RX_CLEAR; 215 } else { 216 macmode = 0; 217 } 218 OS_REG_WRITE(ah, AR_2040_MODE, macmode); 219} 220 221/* 222 * Get Rx clear (control/extension channel) 223 * 224 * Returns active low (busy) for ctrl/ext channel 225 * Owl 2.0 226 */ 227HAL_HT_RXCLEAR 228ar5416Get11nRxClear(struct ath_hal *ah) 229{ 230 HAL_HT_RXCLEAR rxclear = 0; 231 uint32_t val; 232 233 val = OS_REG_READ(ah, AR_DIAG_SW); 234 235 /* control channel */ 236 if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 237 rxclear |= HAL_RX_CLEAR_CTL_LOW; 238 } 239 /* extension channel */ 240 if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 241 rxclear |= HAL_RX_CLEAR_EXT_LOW; 242 } 243 return rxclear; 244} 245 246/* 247 * Set Rx clear (control/extension channel) 248 * 249 * Useful for forcing the channel to appear busy for 250 * debugging/diagnostics 251 * Owl 2.0 252 */ 253void 254ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 255{ 256 /* control channel */ 257 if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 258 OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 259 } else { 260 OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 261 } 262 /* extension channel */ 263 if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 264 OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 265 } else { 266 OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 267 } 268} 269 270HAL_STATUS 271ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 272 uint32_t capability, uint32_t *result) 273{ 274 switch (type) { 275 case HAL_CAP_BB_HANG: 276 switch (capability) { 277 case HAL_BB_HANG_RIFS: 278 return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 279 case HAL_BB_HANG_DFS: 280 return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 281 case HAL_BB_HANG_RX_CLEAR: 282 return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 283 } 284 break; 285 case HAL_CAP_MAC_HANG: 286 return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 287 (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 288 AR_SREV_SOWL(ah)) ? 289 HAL_OK : HAL_ENOTSUPP; 290 default: 291 break; 292 } 293 return ar5212GetCapability(ah, type, capability, result); 294} 295 296static int ar5416DetectMacHang(struct ath_hal *ah); 297static int ar5416DetectBBHang(struct ath_hal *ah); 298 299HAL_BOOL 300ar5416GetDiagState(struct ath_hal *ah, int request, 301 const void *args, uint32_t argsize, 302 void **result, uint32_t *resultsize) 303{ 304 struct ath_hal_5416 *ahp = AH5416(ah); 305 int hangs; 306 307 if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 308 return AH_TRUE; 309 switch (request) { 310 case HAL_DIAG_EEPROM: 311 return ath_hal_eepromDiag(ah, request, 312 args, argsize, result, resultsize); 313 case HAL_DIAG_CHECK_HANGS: 314 if (argsize != sizeof(int)) 315 return AH_FALSE; 316 hangs = *(const int *) args; 317 ahp->ah_hangs = 0; 318 if (hangs & HAL_BB_HANGS) 319 ahp->ah_hangs |= ar5416DetectBBHang(ah); 320 /* NB: if BB is hung MAC will be hung too so skip check */ 321 if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 322 ahp->ah_hangs |= ar5416DetectMacHang(ah); 323 *result = &ahp->ah_hangs; 324 *resultsize = sizeof(ahp->ah_hangs); 325 return AH_TRUE; 326 } 327 return ar5212GetDiagState(ah, request, 328 args, argsize, result, resultsize); 329} 330 331typedef struct { 332 uint32_t dma_dbg_3; 333 uint32_t dma_dbg_4; 334 uint32_t dma_dbg_5; 335 uint32_t dma_dbg_6; 336} mac_dbg_regs_t; 337 338typedef enum { 339 dcu_chain_state = 0x1, 340 dcu_complete_state = 0x2, 341 qcu_state = 0x4, 342 qcu_fsp_ok = 0x8, 343 qcu_fsp_state = 0x10, 344 qcu_stitch_state = 0x20, 345 qcu_fetch_state = 0x40, 346 qcu_complete_state = 0x80 347} hal_mac_hangs_t; 348 349typedef struct { 350 int states; 351 uint8_t dcu_chain_state; 352 uint8_t dcu_complete_state; 353 uint8_t qcu_state; 354 uint8_t qcu_fsp_ok; 355 uint8_t qcu_fsp_state; 356 uint8_t qcu_stitch_state; 357 uint8_t qcu_fetch_state; 358 uint8_t qcu_complete_state; 359} hal_mac_hang_check_t; 360 361static HAL_BOOL 362ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 363 const hal_mac_hang_check_t *check) 364{ 365 int found_states; 366 367 found_states = 0; 368 if (check->states & dcu_chain_state) { 369 int i; 370 371 for (i = 0; i < 6; i++) { 372 if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 373 check->dcu_chain_state) 374 found_states |= dcu_chain_state; 375 } 376 for (i = 0; i < 4; i++) { 377 if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 378 check->dcu_chain_state) 379 found_states |= dcu_chain_state; 380 } 381 } 382 if (check->states & dcu_complete_state) { 383 if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 384 found_states |= dcu_complete_state; 385 } 386 if (check->states & qcu_stitch_state) { 387 if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 388 found_states |= qcu_stitch_state; 389 } 390 if (check->states & qcu_fetch_state) { 391 if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 392 found_states |= qcu_fetch_state; 393 } 394 if (check->states & qcu_complete_state) { 395 if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 396 found_states |= qcu_complete_state; 397 } 398 return (found_states == check->states); 399} 400 401#define NUM_STATUS_READS 50 402 403static int 404ar5416DetectMacHang(struct ath_hal *ah) 405{ 406 static const hal_mac_hang_check_t hang_sig1 = { 407 .dcu_chain_state = 0x6, 408 .dcu_complete_state = 0x1, 409 .states = dcu_chain_state 410 | dcu_complete_state, 411 }; 412 static const hal_mac_hang_check_t hang_sig2 = { 413 .qcu_stitch_state = 0x9, 414 .qcu_fetch_state = 0x8, 415 .qcu_complete_state = 0x4, 416 .states = qcu_stitch_state 417 | qcu_fetch_state 418 | qcu_complete_state, 419 }; 420 mac_dbg_regs_t mac_dbg; 421 int i; 422 423 mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 424 mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 425 mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 426 mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 427 for (i = 1; i <= NUM_STATUS_READS; i++) { 428 if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 429 mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 430 mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 431 mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 432 return 0; 433 } 434 435 if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 436 return HAL_MAC_HANG_SIG1; 437 if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 438 return HAL_MAC_HANG_SIG2; 439 440 HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " 441 "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 442 __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 443 mac_dbg.dma_dbg_6); 444 445 return HAL_MAC_HANG_UNKNOWN; 446} 447 448/* 449 * Determine if the baseband using the Observation Bus Register 450 */ 451static int 452ar5416DetectBBHang(struct ath_hal *ah) 453{ 454#define N(a) (sizeof(a)/sizeof(a[0])) 455 /* 456 * Check the PCU Observation Bus 1 register (0x806c) 457 * NUM_STATUS_READS times 458 * 459 * 4 known BB hang signatures - 460 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 461 * [2] bits 8,9 are 1, bit 11 is 0. State machine state 462 * (bits 25-31) is 0x52 463 * [3] bits 8,9 are 1, bit 11 is 0. State machine state 464 * (bits 25-31) is 0x18 465 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 466 * Rx State (bits 20-24) is 0x7. 467 */ 468 static const struct { 469 uint32_t val; 470 uint32_t mask; 471 int code; 472 } hang_list[] = { 473 /* Reg Value Reg Mask Hang Code XXX */ 474 { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 475 { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 476 { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 477 { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 478 }; 479 uint32_t hang_sig; 480 int i; 481 482 hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 483 for (i = 1; i <= NUM_STATUS_READS; i++) { 484 if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 485 return 0; 486 } 487 for (i = 0; i < N(hang_list); i++) 488 if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 489 HALDEBUG(ah, HAL_DEBUG_ANY, 490 "%s BB hang, signature 0x%x, code 0x%x\n", 491 __func__, hang_sig, hang_list[i].code); 492 return hang_list[i].code; 493 } 494 495 HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " 496 "<0x806c>=0x%x\n", __func__, hang_sig); 497 498 return HAL_BB_HANG_UNKNOWN; 499#undef N 500} 501#undef NUM_STATUS_READS | 21#include "ah.h" 22#include "ah_internal.h" 23#include "ah_devid.h" 24#ifdef AH_DEBUG 25#include "ah_desc.h" /* NB: for HAL_PHYERR* */ 26#endif 27 28#include "ar5416/ar5416.h" 29#include "ar5416/ar5416reg.h" 30#include "ar5416/ar5416phy.h" 31 32/* 33 * Return the wireless modes (a,b,g,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 44 mode = ar5212GetWirelessModes(ah); 45 if (mode & HAL_MODE_11A) 46 mode |= HAL_MODE_11NA_HT20 47 | HAL_MODE_11NA_HT40PLUS 48 | HAL_MODE_11NA_HT40MINUS 49 ; 50 if (mode & HAL_MODE_11G) 51 mode |= HAL_MODE_11NG_HT20 52 | HAL_MODE_11NG_HT40PLUS 53 | HAL_MODE_11NG_HT40MINUS 54 ; 55 return mode; 56} 57 58/* 59 * Change the LED blinking pattern to correspond to the connectivity 60 */ 61void 62ar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state) 63{ 64 static const uint32_t ledbits[8] = { 65 AR_MAC_LED_ASSOC_NONE, /* HAL_LED_INIT */ 66 AR_MAC_LED_ASSOC_PEND, /* HAL_LED_SCAN */ 67 AR_MAC_LED_ASSOC_PEND, /* HAL_LED_AUTH */ 68 AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_ASSOC*/ 69 AR_MAC_LED_ASSOC_ACTIVE, /* HAL_LED_RUN */ 70 AR_MAC_LED_ASSOC_NONE, 71 AR_MAC_LED_ASSOC_NONE, 72 AR_MAC_LED_ASSOC_NONE, 73 }; 74 uint32_t bits; 75 76 bits = OS_REG_READ(ah, AR_MAC_LED); 77 bits = (bits &~ AR_MAC_LED_MODE) 78 | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE) 79#if 1 80 | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE) 81#endif 82 ; 83 bits = (bits &~ AR_MAC_LED_ASSOC) 84 | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC); 85 OS_REG_WRITE(ah, AR_MAC_LED, bits); 86} 87 88/* 89 * Reset the current hardware tsf for stamlme. 90 */ 91void 92ar5416ResetTsf(struct ath_hal *ah) 93{ 94 uint32_t v; 95 int i; 96 97 for (i = 0; i < 10; i++) { 98 v = OS_REG_READ(ah, AR_SLP32_MODE); 99 if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0) 100 break; 101 OS_DELAY(10); 102 } 103 OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); 104} 105 106HAL_BOOL 107ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 108{ 109 return AH_TRUE; 110} 111 112/* Setup decompression for given key index */ 113HAL_BOOL 114ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 115{ 116 return HAL_OK; 117} 118 119/* Setup coverage class */ 120void 121ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now) 122{ 123} 124 125/* 126 * Return approximation of extension channel busy over an time interval 127 * 0% (clear) -> 100% (busy) 128 * 129 */ 130uint32_t 131ar5416Get11nExtBusy(struct ath_hal *ah) 132{ 133 struct ath_hal_5416 *ahp = AH5416(ah); 134 uint32_t busy; /* percentage */ 135 uint32_t cycleCount, ctlBusy, extBusy; 136 137 ctlBusy = OS_REG_READ(ah, AR_RCCNT); 138 extBusy = OS_REG_READ(ah, AR_EXTRCCNT); 139 cycleCount = OS_REG_READ(ah, AR_CCCNT); 140 141 if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) { 142 /* 143 * Cycle counter wrap (or initial call); it's not possible 144 * to accurately calculate a value because the registers 145 * right shift rather than wrap--so punt and return 0. 146 */ 147 busy = 0; 148 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n", 149 __func__); 150 151 } else { 152 uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount; 153 uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy; 154 uint32_t extBusyDelta = extBusy - ahp->ah_extBusy; 155 uint32_t ctlClearDelta = 0; 156 157 /* Compute control channel rxclear. 158 * The cycle delta may be less than the control channel delta. 159 * This could be solved by freezing the timers (or an atomic read, 160 * if one was available). Checking for the condition should be 161 * sufficient. 162 */ 163 if (cycleDelta > ctlBusyDelta) { 164 ctlClearDelta = cycleDelta - ctlBusyDelta; 165 } 166 167 /* Compute ratio of extension channel busy to control channel clear 168 * as an approximation to extension channel cleanliness. 169 * 170 * According to the hardware folks, ext rxclear is undefined 171 * if the ctrl rxclear is de-asserted (i.e. busy) 172 */ 173 if (ctlClearDelta) { 174 busy = (extBusyDelta * 100) / ctlClearDelta; 175 } else { 176 busy = 100; 177 } 178 if (busy > 100) { 179 busy = 100; 180 } 181#if 0 182 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, " 183 "extBusyDelta 0x%x, ctlClearDelta 0x%x, " 184 "busy %d\n", 185 __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy); 186#endif 187 } 188 189 ahp->ah_cycleCount = cycleCount; 190 ahp->ah_ctlBusy = ctlBusy; 191 ahp->ah_extBusy = extBusy; 192 193 return busy; 194} 195 196/* 197 * Configure 20/40 operation 198 * 199 * 20/40 = joint rx clear (control and extension) 200 * 20 = rx clear (control) 201 * 202 * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing 203 * from 20/40 => 20 only 204 */ 205void 206ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode) 207{ 208 uint32_t macmode; 209 210 /* Configure MAC for 20/40 operation */ 211 if (mode == HAL_HT_MACMODE_2040) { 212 macmode = AR_2040_JOINED_RX_CLEAR; 213 } else { 214 macmode = 0; 215 } 216 OS_REG_WRITE(ah, AR_2040_MODE, macmode); 217} 218 219/* 220 * Get Rx clear (control/extension channel) 221 * 222 * Returns active low (busy) for ctrl/ext channel 223 * Owl 2.0 224 */ 225HAL_HT_RXCLEAR 226ar5416Get11nRxClear(struct ath_hal *ah) 227{ 228 HAL_HT_RXCLEAR rxclear = 0; 229 uint32_t val; 230 231 val = OS_REG_READ(ah, AR_DIAG_SW); 232 233 /* control channel */ 234 if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 235 rxclear |= HAL_RX_CLEAR_CTL_LOW; 236 } 237 /* extension channel */ 238 if (val & AR_DIAG_RXCLEAR_CTL_LOW) { 239 rxclear |= HAL_RX_CLEAR_EXT_LOW; 240 } 241 return rxclear; 242} 243 244/* 245 * Set Rx clear (control/extension channel) 246 * 247 * Useful for forcing the channel to appear busy for 248 * debugging/diagnostics 249 * Owl 2.0 250 */ 251void 252ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear) 253{ 254 /* control channel */ 255 if (rxclear & HAL_RX_CLEAR_CTL_LOW) { 256 OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 257 } else { 258 OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW); 259 } 260 /* extension channel */ 261 if (rxclear & HAL_RX_CLEAR_EXT_LOW) { 262 OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 263 } else { 264 OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW); 265 } 266} 267 268HAL_STATUS 269ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type, 270 uint32_t capability, uint32_t *result) 271{ 272 switch (type) { 273 case HAL_CAP_BB_HANG: 274 switch (capability) { 275 case HAL_BB_HANG_RIFS: 276 return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 277 case HAL_BB_HANG_DFS: 278 return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP; 279 case HAL_BB_HANG_RX_CLEAR: 280 return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP; 281 } 282 break; 283 case HAL_CAP_MAC_HANG: 284 return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) || 285 (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) || 286 AR_SREV_SOWL(ah)) ? 287 HAL_OK : HAL_ENOTSUPP; 288 default: 289 break; 290 } 291 return ar5212GetCapability(ah, type, capability, result); 292} 293 294static int ar5416DetectMacHang(struct ath_hal *ah); 295static int ar5416DetectBBHang(struct ath_hal *ah); 296 297HAL_BOOL 298ar5416GetDiagState(struct ath_hal *ah, int request, 299 const void *args, uint32_t argsize, 300 void **result, uint32_t *resultsize) 301{ 302 struct ath_hal_5416 *ahp = AH5416(ah); 303 int hangs; 304 305 if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize)) 306 return AH_TRUE; 307 switch (request) { 308 case HAL_DIAG_EEPROM: 309 return ath_hal_eepromDiag(ah, request, 310 args, argsize, result, resultsize); 311 case HAL_DIAG_CHECK_HANGS: 312 if (argsize != sizeof(int)) 313 return AH_FALSE; 314 hangs = *(const int *) args; 315 ahp->ah_hangs = 0; 316 if (hangs & HAL_BB_HANGS) 317 ahp->ah_hangs |= ar5416DetectBBHang(ah); 318 /* NB: if BB is hung MAC will be hung too so skip check */ 319 if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS)) 320 ahp->ah_hangs |= ar5416DetectMacHang(ah); 321 *result = &ahp->ah_hangs; 322 *resultsize = sizeof(ahp->ah_hangs); 323 return AH_TRUE; 324 } 325 return ar5212GetDiagState(ah, request, 326 args, argsize, result, resultsize); 327} 328 329typedef struct { 330 uint32_t dma_dbg_3; 331 uint32_t dma_dbg_4; 332 uint32_t dma_dbg_5; 333 uint32_t dma_dbg_6; 334} mac_dbg_regs_t; 335 336typedef enum { 337 dcu_chain_state = 0x1, 338 dcu_complete_state = 0x2, 339 qcu_state = 0x4, 340 qcu_fsp_ok = 0x8, 341 qcu_fsp_state = 0x10, 342 qcu_stitch_state = 0x20, 343 qcu_fetch_state = 0x40, 344 qcu_complete_state = 0x80 345} hal_mac_hangs_t; 346 347typedef struct { 348 int states; 349 uint8_t dcu_chain_state; 350 uint8_t dcu_complete_state; 351 uint8_t qcu_state; 352 uint8_t qcu_fsp_ok; 353 uint8_t qcu_fsp_state; 354 uint8_t qcu_stitch_state; 355 uint8_t qcu_fetch_state; 356 uint8_t qcu_complete_state; 357} hal_mac_hang_check_t; 358 359static HAL_BOOL 360ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs, 361 const hal_mac_hang_check_t *check) 362{ 363 int found_states; 364 365 found_states = 0; 366 if (check->states & dcu_chain_state) { 367 int i; 368 369 for (i = 0; i < 6; i++) { 370 if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) == 371 check->dcu_chain_state) 372 found_states |= dcu_chain_state; 373 } 374 for (i = 0; i < 4; i++) { 375 if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) == 376 check->dcu_chain_state) 377 found_states |= dcu_chain_state; 378 } 379 } 380 if (check->states & dcu_complete_state) { 381 if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state) 382 found_states |= dcu_complete_state; 383 } 384 if (check->states & qcu_stitch_state) { 385 if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state) 386 found_states |= qcu_stitch_state; 387 } 388 if (check->states & qcu_fetch_state) { 389 if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state) 390 found_states |= qcu_fetch_state; 391 } 392 if (check->states & qcu_complete_state) { 393 if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state) 394 found_states |= qcu_complete_state; 395 } 396 return (found_states == check->states); 397} 398 399#define NUM_STATUS_READS 50 400 401static int 402ar5416DetectMacHang(struct ath_hal *ah) 403{ 404 static const hal_mac_hang_check_t hang_sig1 = { 405 .dcu_chain_state = 0x6, 406 .dcu_complete_state = 0x1, 407 .states = dcu_chain_state 408 | dcu_complete_state, 409 }; 410 static const hal_mac_hang_check_t hang_sig2 = { 411 .qcu_stitch_state = 0x9, 412 .qcu_fetch_state = 0x8, 413 .qcu_complete_state = 0x4, 414 .states = qcu_stitch_state 415 | qcu_fetch_state 416 | qcu_complete_state, 417 }; 418 mac_dbg_regs_t mac_dbg; 419 int i; 420 421 mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3); 422 mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4); 423 mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5); 424 mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6); 425 for (i = 1; i <= NUM_STATUS_READS; i++) { 426 if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) || 427 mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) || 428 mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) || 429 mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6)) 430 return 0; 431 } 432 433 if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1)) 434 return HAL_MAC_HANG_SIG1; 435 if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2)) 436 return HAL_MAC_HANG_SIG2; 437 438 HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature " 439 "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n", 440 __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5, 441 mac_dbg.dma_dbg_6); 442 443 return HAL_MAC_HANG_UNKNOWN; 444} 445 446/* 447 * Determine if the baseband using the Observation Bus Register 448 */ 449static int 450ar5416DetectBBHang(struct ath_hal *ah) 451{ 452#define N(a) (sizeof(a)/sizeof(a[0])) 453 /* 454 * Check the PCU Observation Bus 1 register (0x806c) 455 * NUM_STATUS_READS times 456 * 457 * 4 known BB hang signatures - 458 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E 459 * [2] bits 8,9 are 1, bit 11 is 0. State machine state 460 * (bits 25-31) is 0x52 461 * [3] bits 8,9 are 1, bit 11 is 0. State machine state 462 * (bits 25-31) is 0x18 463 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2, 464 * Rx State (bits 20-24) is 0x7. 465 */ 466 static const struct { 467 uint32_t val; 468 uint32_t mask; 469 int code; 470 } hang_list[] = { 471 /* Reg Value Reg Mask Hang Code XXX */ 472 { 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS }, 473 { 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS }, 474 { 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR }, 475 { 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR } 476 }; 477 uint32_t hang_sig; 478 int i; 479 480 hang_sig = OS_REG_READ(ah, AR_OBSERV_1); 481 for (i = 1; i <= NUM_STATUS_READS; i++) { 482 if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1)) 483 return 0; 484 } 485 for (i = 0; i < N(hang_list); i++) 486 if ((hang_sig & hang_list[i].mask) == hang_list[i].val) { 487 HALDEBUG(ah, HAL_DEBUG_ANY, 488 "%s BB hang, signature 0x%x, code 0x%x\n", 489 __func__, hang_sig, hang_list[i].code); 490 return hang_list[i].code; 491 } 492 493 HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! " 494 "<0x806c>=0x%x\n", __func__, hang_sig); 495 496 return HAL_BB_HANG_UNKNOWN; 497#undef N 498} 499#undef NUM_STATUS_READS |
502#endif /* AH_SUPPORT_AR5416 */ | |