Home | History | Annotate | Line # | Download | only in ar5416
      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.2 2012/02/12 13:47:19 wiz Exp $
     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,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 AH_TRUE;
    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