ar5416_misc.c revision 220323
1168404Spjd/*
2168404Spjd * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3168404Spjd * Copyright (c) 2002-2008 Atheros Communications, Inc.
4168404Spjd *
5168404Spjd * Permission to use, copy, modify, and/or distribute this software for any
6168404Spjd * purpose with or without fee is hereby granted, provided that the above
7168404Spjd * copyright notice and this permission notice appear in all copies.
8168404Spjd *
9168404Spjd * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10168404Spjd * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11168404Spjd * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12168404Spjd * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13168404Spjd * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14168404Spjd * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15168404Spjd * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16168404Spjd *
17168404Spjd * $FreeBSD: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 220323 2011-04-04 11:01:53Z adrian $
18168404Spjd */
19168404Spjd#include "opt_ah.h"
20168404Spjd
21168404Spjd#include "ah.h"
22168404Spjd#include "ah_internal.h"
23219089Spjd#include "ah_devid.h"
24227497Smm#ifdef AH_DEBUG
25236155Smm#include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
26236145Smm#endif
27236155Smm
28168404Spjd#include "ar5416/ar5416.h"
29168404Spjd#include "ar5416/ar5416reg.h"
30168404Spjd#include "ar5416/ar5416phy.h"
31168404Spjd
32168404Spjd/*
33168404Spjd * Return the wireless modes (a,b,g,n,t) supported by hardware.
34168404Spjd *
35168404Spjd * This value is what is actually supported by the hardware
36168404Spjd * and is unaffected by regulatory/country code settings.
37168404Spjd *
38168404Spjd */
39168404Spjdu_int
40168404Spjdar5416GetWirelessModes(struct ath_hal *ah)
41168404Spjd{
42168404Spjd	u_int mode;
43168404Spjd	struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
44168404Spjd	HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
45168404Spjd
46185029Spjd	mode = ar5212GetWirelessModes(ah);
47185029Spjd
48168404Spjd	/* Only enable HT modes if the NIC supports HT */
49236155Smm	if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A))
50168404Spjd		mode |= HAL_MODE_11NA_HT20
51168404Spjd		     |  HAL_MODE_11NA_HT40PLUS
52168404Spjd		     |  HAL_MODE_11NA_HT40MINUS
53168404Spjd		     ;
54168404Spjd	if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11G))
55168404Spjd		mode |= HAL_MODE_11NG_HT20
56185029Spjd		     |  HAL_MODE_11NG_HT40PLUS
57236884Smm		     |  HAL_MODE_11NG_HT40MINUS
58168404Spjd		     ;
59219089Spjd	return mode;
60219089Spjd}
61168404Spjd
62168404Spjd/*
63168404Spjd * Change the LED blinking pattern to correspond to the connectivity
64168404Spjd */
65168404Spjdvoid
66224171Sgibbsar5416SetLedState(struct ath_hal *ah, HAL_LED_STATE state)
67168404Spjd{
68168404Spjd	static const uint32_t ledbits[8] = {
69168404Spjd		AR_MAC_LED_ASSOC_NONE,		/* HAL_LED_INIT */
70168404Spjd		AR_MAC_LED_ASSOC_PEND,		/* HAL_LED_SCAN */
71168404Spjd		AR_MAC_LED_ASSOC_PEND,		/* HAL_LED_AUTH */
72168404Spjd		AR_MAC_LED_ASSOC_ACTIVE,	/* HAL_LED_ASSOC*/
73168404Spjd		AR_MAC_LED_ASSOC_ACTIVE,	/* HAL_LED_RUN */
74168404Spjd		AR_MAC_LED_ASSOC_NONE,
75236155Smm		AR_MAC_LED_ASSOC_NONE,
76168404Spjd		AR_MAC_LED_ASSOC_NONE,
77228103Smm	};
78228103Smm	uint32_t bits;
79168404Spjd
80168404Spjd	bits = OS_REG_READ(ah, AR_MAC_LED);
81168404Spjd	bits = (bits &~ AR_MAC_LED_MODE)
82219089Spjd	     | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE)
83168404Spjd#if 1
84168404Spjd	     | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE)
85168404Spjd#endif
86168404Spjd	     ;
87168404Spjd	bits = (bits &~ AR_MAC_LED_ASSOC)
88168404Spjd	     | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC);
89168404Spjd	OS_REG_WRITE(ah, AR_MAC_LED, bits);
90168404Spjd}
91168404Spjd
92168404Spjd/*
93168404Spjd * Reset the current hardware tsf for stamlme.
94168404Spjd */
95168404Spjdvoid
96168404Spjdar5416ResetTsf(struct ath_hal *ah)
97168404Spjd{
98168404Spjd	uint32_t v;
99168404Spjd	int i;
100185029Spjd
101185029Spjd	for (i = 0; i < 10; i++) {
102168404Spjd		v = OS_REG_READ(ah, AR_SLP32_MODE);
103168404Spjd		if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0)
104168404Spjd			break;
105168404Spjd		OS_DELAY(10);
106168404Spjd	}
107168404Spjd	OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
108168404Spjd}
109168404Spjd
110168404SpjdHAL_BOOL
111168404Spjdar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
112168404Spjd{
113185029Spjd	return AH_TRUE;
114168404Spjd}
115168404Spjd
116168404Spjd/* Setup decompression for given key index */
117168404SpjdHAL_BOOL
118168404Spjdar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
119168404Spjd{
120168404Spjd	return HAL_OK;
121168404Spjd}
122168404Spjd
123168404Spjd/* Setup coverage class */
124168404Spjdvoid
125168404Spjdar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
126224171Sgibbs{
127168404Spjd	AH_PRIVATE(ah)->ah_coverageClass = coverageclass;
128168404Spjd}
129168404Spjd
130168404Spjd/*
131168404Spjd * Return approximation of extension channel busy over an time interval
132168404Spjd * 0% (clear) -> 100% (busy)
133168404Spjd *
134168404Spjd */
135168404Spjduint32_t
136219089Spjdar5416Get11nExtBusy(struct ath_hal *ah)
137228103Smm{
138236155Smm    struct ath_hal_5416 *ahp = AH5416(ah);
139236155Smm    uint32_t busy; /* percentage */
140168404Spjd    uint32_t cycleCount, ctlBusy, extBusy;
141168404Spjd
142168404Spjd    ctlBusy = OS_REG_READ(ah, AR_RCCNT);
143168404Spjd    extBusy = OS_REG_READ(ah, AR_EXTRCCNT);
144168404Spjd    cycleCount = OS_REG_READ(ah, AR_CCCNT);
145168404Spjd
146168404Spjd    if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) {
147168404Spjd        /*
148168404Spjd         * Cycle counter wrap (or initial call); it's not possible
149168404Spjd         * to accurately calculate a value because the registers
150168404Spjd         * right shift rather than wrap--so punt and return 0.
151168404Spjd         */
152168404Spjd        busy = 0;
153168404Spjd        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n",
154168404Spjd	    __func__);
155168404Spjd
156168404Spjd    } else {
157168404Spjd        uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount;
158168404Spjd        uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy;
159168404Spjd        uint32_t extBusyDelta = extBusy - ahp->ah_extBusy;
160168404Spjd        uint32_t ctlClearDelta = 0;
161168404Spjd
162168404Spjd        /* Compute control channel rxclear.
163168404Spjd         * The cycle delta may be less than the control channel delta.
164168404Spjd         * This could be solved by freezing the timers (or an atomic read,
165224171Sgibbs         * if one was available). Checking for the condition should be
166224171Sgibbs         * sufficient.
167168404Spjd         */
168168404Spjd        if (cycleDelta > ctlBusyDelta) {
169168404Spjd            ctlClearDelta = cycleDelta - ctlBusyDelta;
170168404Spjd        }
171168404Spjd
172168404Spjd        /* Compute ratio of extension channel busy to control channel clear
173168404Spjd         * as an approximation to extension channel cleanliness.
174236155Smm         *
175168404Spjd         * According to the hardware folks, ext rxclear is undefined
176168404Spjd         * if the ctrl rxclear is de-asserted (i.e. busy)
177168404Spjd         */
178168404Spjd        if (ctlClearDelta) {
179219089Spjd            busy = (extBusyDelta * 100) / ctlClearDelta;
180168404Spjd        } else {
181168404Spjd            busy = 100;
182168404Spjd        }
183168404Spjd        if (busy > 100) {
184168404Spjd            busy = 100;
185168404Spjd        }
186228103Smm#if 0
187168404Spjd        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, "
188168404Spjd             "extBusyDelta 0x%x, ctlClearDelta 0x%x, "
189168404Spjd             "busy %d\n",
190168404Spjd              __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy);
191168404Spjd#endif
192168404Spjd    }
193168404Spjd
194168404Spjd    ahp->ah_cycleCount = cycleCount;
195248571Smm    ahp->ah_ctlBusy = ctlBusy;
196185029Spjd    ahp->ah_extBusy = extBusy;
197248571Smm
198219089Spjd    return busy;
199219089Spjd}
200168404Spjd
201168404Spjd/*
202168404Spjd * Configure 20/40 operation
203168404Spjd *
204168404Spjd * 20/40 = joint rx clear (control and extension)
205168404Spjd * 20    = rx clear (control)
206168404Spjd *
207185029Spjd * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing
208168404Spjd *         from 20/40 => 20 only
209219089Spjd */
210168404Spjdvoid
211236884Smmar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode)
212185029Spjd{
213185029Spjd    uint32_t macmode;
214168404Spjd
215168404Spjd    /* Configure MAC for 20/40 operation */
216168404Spjd    if (mode == HAL_HT_MACMODE_2040) {
217168404Spjd        macmode = AR_2040_JOINED_RX_CLEAR;
218168404Spjd    } else {
219168404Spjd        macmode = 0;
220168404Spjd    }
221185029Spjd    OS_REG_WRITE(ah, AR_2040_MODE, macmode);
222168404Spjd}
223168404Spjd
224219089Spjd/*
225185029Spjd * Get Rx clear (control/extension channel)
226219089Spjd *
227219089Spjd * Returns active low (busy) for ctrl/ext channel
228185029Spjd * Owl 2.0
229219089Spjd */
230219089SpjdHAL_HT_RXCLEAR
231219089Spjdar5416Get11nRxClear(struct ath_hal *ah)
232168404Spjd{
233219089Spjd    HAL_HT_RXCLEAR rxclear = 0;
234168404Spjd    uint32_t val;
235224171Sgibbs
236224171Sgibbs    val = OS_REG_READ(ah, AR_DIAG_SW);
237168404Spjd
238236960Smm    /* control channel */
239219089Spjd    if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
240168404Spjd        rxclear |= HAL_RX_CLEAR_CTL_LOW;
241168404Spjd    }
242168404Spjd    /* extension channel */
243228020Smm    if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
244168404Spjd        rxclear |= HAL_RX_CLEAR_EXT_LOW;
245168404Spjd    }
246185029Spjd    return rxclear;
247168404Spjd}
248185029Spjd
249236155Smm/*
250236155Smm * Set Rx clear (control/extension channel)
251168404Spjd *
252168404Spjd * Useful for forcing the channel to appear busy for
253168404Spjd * debugging/diagnostics
254219089Spjd * Owl 2.0
255219089Spjd */
256168404Spjdvoid
257228020Smmar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear)
258185029Spjd{
259168404Spjd    /* control channel */
260185029Spjd    if (rxclear & HAL_RX_CLEAR_CTL_LOW) {
261168404Spjd        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
262168404Spjd    } else {
263168404Spjd        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
264219089Spjd    }
265219089Spjd    /* extension channel */
266219089Spjd    if (rxclear & HAL_RX_CLEAR_EXT_LOW) {
267219089Spjd        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
268228103Smm    } else {
269228103Smm        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
270168404Spjd    }
271168404Spjd}
272168404Spjd
273168404SpjdHAL_STATUS
274168404Spjdar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
275168404Spjd        uint32_t capability, uint32_t *result)
276168404Spjd{
277168404Spjd	switch (type) {
278168404Spjd	case HAL_CAP_BB_HANG:
279168404Spjd		switch (capability) {
280185029Spjd		case HAL_BB_HANG_RIFS:
281185029Spjd			return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP;
282168404Spjd		case HAL_BB_HANG_DFS:
283168404Spjd			return AR_SREV_SOWL(ah) ? HAL_OK : HAL_ENOTSUPP;
284168404Spjd		case HAL_BB_HANG_RX_CLEAR:
285219089Spjd			return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP;
286168404Spjd		}
287185029Spjd		break;
288185029Spjd	case HAL_CAP_MAC_HANG:
289185029Spjd		return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) ||
290219089Spjd		    (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) ||
291185029Spjd		    AR_SREV_SOWL(ah)) ?
292168404Spjd			HAL_OK : HAL_ENOTSUPP;
293168404Spjd	default:
294168404Spjd		break;
295168404Spjd	}
296168404Spjd	return ar5212GetCapability(ah, type, capability, result);
297185029Spjd}
298168404Spjd
299168404Spjdstatic int ar5416DetectMacHang(struct ath_hal *ah);
300168404Spjdstatic int ar5416DetectBBHang(struct ath_hal *ah);
301168404Spjd
302168404SpjdHAL_BOOL
303168404Spjdar5416GetDiagState(struct ath_hal *ah, int request,
304168404Spjd	const void *args, uint32_t argsize,
305168404Spjd	void **result, uint32_t *resultsize)
306168404Spjd{
307168404Spjd	struct ath_hal_5416 *ahp = AH5416(ah);
308168404Spjd	int hangs;
309168404Spjd
310168404Spjd	if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
311168404Spjd		return AH_TRUE;
312168404Spjd	switch (request) {
313168404Spjd	case HAL_DIAG_EEPROM:
314168404Spjd		return ath_hal_eepromDiag(ah, request,
315168404Spjd		    args, argsize, result, resultsize);
316168404Spjd	case HAL_DIAG_CHECK_HANGS:
317168404Spjd		if (argsize != sizeof(int))
318168404Spjd			return AH_FALSE;
319168404Spjd		hangs = *(const int *) args;
320168404Spjd		ahp->ah_hangs = 0;
321168404Spjd		if (hangs & HAL_BB_HANGS)
322168404Spjd			ahp->ah_hangs |= ar5416DetectBBHang(ah);
323168404Spjd		/* NB: if BB is hung MAC will be hung too so skip check */
324168404Spjd		if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS))
325168404Spjd			ahp->ah_hangs |= ar5416DetectMacHang(ah);
326168404Spjd		*result = &ahp->ah_hangs;
327168404Spjd		*resultsize = sizeof(ahp->ah_hangs);
328168404Spjd		return AH_TRUE;
329168404Spjd	}
330168404Spjd	return ar5212GetDiagState(ah, request,
331185029Spjd	    args, argsize, result, resultsize);
332185029Spjd}
333168404Spjd
334168404Spjdtypedef struct {
335168404Spjd	uint32_t dma_dbg_3;
336168404Spjd	uint32_t dma_dbg_4;
337219089Spjd	uint32_t dma_dbg_5;
338185029Spjd	uint32_t dma_dbg_6;
339168404Spjd} mac_dbg_regs_t;
340168404Spjd
341185029Spjdtypedef enum {
342185029Spjd	dcu_chain_state		= 0x1,
343236884Smm	dcu_complete_state	= 0x2,
344236884Smm	qcu_state		= 0x4,
345236884Smm	qcu_fsp_ok		= 0x8,
346236884Smm	qcu_fsp_state		= 0x10,
347236884Smm	qcu_stitch_state	= 0x20,
348243014Smm	qcu_fetch_state		= 0x40,
349168404Spjd	qcu_complete_state	= 0x80
350168404Spjd} hal_mac_hangs_t;
351168404Spjd
352168404Spjdtypedef struct {
353168404Spjd	int states;
354168404Spjd	uint8_t dcu_chain_state;
355168404Spjd	uint8_t dcu_complete_state;
356168404Spjd	uint8_t qcu_state;
357168404Spjd	uint8_t qcu_fsp_ok;
358168404Spjd	uint8_t qcu_fsp_state;
359168404Spjd	uint8_t qcu_stitch_state;
360168404Spjd	uint8_t qcu_fetch_state;
361168404Spjd	uint8_t qcu_complete_state;
362168404Spjd} hal_mac_hang_check_t;
363185029Spjd
364185029Spjdstatic HAL_BOOL
365168404Spjdar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs,
366168404Spjd    const hal_mac_hang_check_t *check)
367168404Spjd{
368168404Spjd	int found_states;
369168404Spjd
370168404Spjd	found_states = 0;
371168404Spjd	if (check->states & dcu_chain_state) {
372168404Spjd		int i;
373168404Spjd
374168404Spjd		for (i = 0; i < 6; i++) {
375168404Spjd			if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) ==
376168404Spjd			    check->dcu_chain_state)
377168404Spjd				found_states |= dcu_chain_state;
378185029Spjd		}
379185029Spjd		for (i = 0; i < 4; i++) {
380185029Spjd			if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) ==
381185029Spjd			    check->dcu_chain_state)
382185029Spjd				found_states |= dcu_chain_state;
383185029Spjd		}
384185029Spjd	}
385219089Spjd	if (check->states & dcu_complete_state) {
386185029Spjd		if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state)
387185029Spjd			found_states |= dcu_complete_state;
388168404Spjd	}
389168404Spjd	if (check->states & qcu_stitch_state) {
390168404Spjd		if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state)
391168404Spjd			found_states |= qcu_stitch_state;
392238926Smm	}
393238926Smm	if (check->states & qcu_fetch_state) {
394238926Smm		if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state)
395238926Smm			found_states |= qcu_fetch_state;
396238926Smm	}
397238926Smm	if (check->states & qcu_complete_state) {
398238926Smm		if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state)
399238926Smm			found_states |= qcu_complete_state;
400238926Smm	}
401238926Smm	return (found_states == check->states);
402238926Smm}
403238926Smm
404168404Spjd#define NUM_STATUS_READS 50
405185029Spjd
406185029Spjdstatic int
407185029Spjdar5416DetectMacHang(struct ath_hal *ah)
408185029Spjd{
409185029Spjd	static const hal_mac_hang_check_t hang_sig1 = {
410185029Spjd		.dcu_chain_state	= 0x6,
411185029Spjd		.dcu_complete_state	= 0x1,
412185029Spjd		.states			= dcu_chain_state
413185029Spjd					| dcu_complete_state,
414185029Spjd	};
415185029Spjd	static const hal_mac_hang_check_t hang_sig2 = {
416185029Spjd		.qcu_stitch_state	= 0x9,
417185029Spjd		.qcu_fetch_state	= 0x8,
418185029Spjd		.qcu_complete_state	= 0x4,
419185029Spjd		.states			= qcu_stitch_state
420185029Spjd					| qcu_fetch_state
421185029Spjd					| qcu_complete_state,
422185029Spjd        };
423185029Spjd	mac_dbg_regs_t mac_dbg;
424185029Spjd	int i;
425185029Spjd
426185029Spjd	mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3);
427238926Smm	mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4);
428238926Smm	mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5);
429236884Smm	mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6);
430236884Smm	for (i = 1; i <= NUM_STATUS_READS; i++) {
431185029Spjd		if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) ||
432185029Spjd		    mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) ||
433185029Spjd		    mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) ||
434185029Spjd		    mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6))
435238926Smm			return 0;
436238926Smm	}
437238926Smm
438238926Smm	if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1))
439238926Smm		return HAL_MAC_HANG_SIG1;
440238926Smm	if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2))
441238926Smm		return HAL_MAC_HANG_SIG2;
442238926Smm
443238926Smm	HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown MAC hang signature "
444238926Smm	    "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n",
445238926Smm	    __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5,
446238926Smm	    mac_dbg.dma_dbg_6);
447238926Smm
448238926Smm	return HAL_MAC_HANG_UNKNOWN;
449238926Smm}
450238926Smm
451236884Smm/*
452236884Smm * Determine if the baseband using the Observation Bus Register
453236884Smm */
454236884Smmstatic int
455185029Spjdar5416DetectBBHang(struct ath_hal *ah)
456209962Smm{
457209962Smm#define N(a) (sizeof(a)/sizeof(a[0]))
458209962Smm	/*
459209962Smm	 * Check the PCU Observation Bus 1 register (0x806c)
460185029Spjd	 * NUM_STATUS_READS times
461185029Spjd	 *
462185029Spjd	 * 4 known BB hang signatures -
463185029Spjd	 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E
464185029Spjd	 * [2] bits 8,9 are 1, bit 11 is 0. State machine state
465185029Spjd	 *     (bits 25-31) is 0x52
466185029Spjd	 * [3] bits 8,9 are 1, bit 11 is 0. State machine state
467185029Spjd	 *     (bits 25-31) is 0x18
468185029Spjd	 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2,
469185029Spjd	 *     Rx State (bits 20-24) is 0x7.
470185029Spjd	 */
471185029Spjd	static const struct {
472185029Spjd		uint32_t val;
473185029Spjd		uint32_t mask;
474185029Spjd		int code;
475185029Spjd	} hang_list[] = {
476185029Spjd		/* Reg Value   Reg Mask    Hang Code XXX */
477185029Spjd		{ 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS },
478185029Spjd		{ 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS },
479185029Spjd		{ 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR },
480168404Spjd		{ 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR }
481168404Spjd	};
482168404Spjd	uint32_t hang_sig;
483168404Spjd	int i;
484168404Spjd
485168404Spjd	hang_sig = OS_REG_READ(ah, AR_OBSERV_1);
486168404Spjd	for (i = 1; i <= NUM_STATUS_READS; i++) {
487168404Spjd		if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1))
488168404Spjd			return 0;
489168404Spjd	}
490168404Spjd	for (i = 0; i < N(hang_list); i++)
491168404Spjd		if ((hang_sig & hang_list[i].mask) == hang_list[i].val) {
492168404Spjd			HALDEBUG(ah, HAL_DEBUG_ANY,
493168404Spjd			    "%s BB hang, signature 0x%x, code 0x%x\n",
494168404Spjd			    __func__, hang_sig, hang_list[i].code);
495168404Spjd			return hang_list[i].code;
496168404Spjd		}
497168404Spjd
498168404Spjd	HALDEBUG(ah, HAL_DEBUG_ANY, "%s Found an unknown BB hang signature! "
499168404Spjd	    "<0x806c>=0x%x\n", __func__, hang_sig);
500168404Spjd
501168404Spjd	return HAL_BB_HANG_UNKNOWN;
502168404Spjd#undef N
503168404Spjd}
504168404Spjd#undef NUM_STATUS_READS
505168404Spjd