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$ 18 */ 19 #include "opt_ah.h" 20 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,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 */ 39 u_int 40 ar5416GetWirelessModes(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 */ 61 void 62 ar5416SetLedState(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 */ 91 void 92 ar5416ResetTsf(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 106 HAL_BOOL 107 ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) 108 { 109 return AH_TRUE; 110 } 111 112 /* Setup decompression for given key index */ 113 HAL_BOOL 114 ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en) 115 { 116 return HAL_OK; 117 } 118 119 /* Setup coverage class */ 120 void 121 ar5416SetCoverageClass(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 */ 130 uint32_t 131 ar5416Get11nExtBusy(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 */ 205 void 206 ar5416Set11nMac2040(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 */ 225 HAL_HT_RXCLEAR 226 ar5416Get11nRxClear(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 */ 251 void 252 ar5416Set11nRxClear(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 268 HAL_STATUS 269 ar5416GetCapability(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 294 static int ar5416DetectMacHang(struct ath_hal *ah); 295 static int ar5416DetectBBHang(struct ath_hal *ah); 296 297 HAL_BOOL 298 ar5416GetDiagState(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 329 typedef 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 336 typedef 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 347 typedef 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 359 static HAL_BOOL 360 ar5416CompareDbgHang(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 401 static int 402 ar5416DetectMacHang(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 */ 449 static int 450 ar5416DetectBBHang(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 500