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