ar5416_misc.c revision 228837
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: head/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c 228837 2011-12-23 09:09:10Z adrian $
18 */
19#include "opt_ah.h"
20
21#include "ah.h"
22#include "ah_internal.h"
23#include "ah_devid.h"
24#include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
25
26#include "ar5416/ar5416.h"
27#include "ar5416/ar5416reg.h"
28#include "ar5416/ar5416phy.h"
29
30/*
31 * Return the wireless modes (a,b,g,n,t) supported by hardware.
32 *
33 * This value is what is actually supported by the hardware
34 * and is unaffected by regulatory/country code settings.
35 *
36 */
37u_int
38ar5416GetWirelessModes(struct ath_hal *ah)
39{
40	u_int mode;
41	struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
42	HAL_CAPABILITIES *pCap = &ahpriv->ah_caps;
43
44	mode = ar5212GetWirelessModes(ah);
45
46	/* Only enable HT modes if the NIC supports HT */
47	if (pCap->halHTSupport == AH_TRUE && (mode & HAL_MODE_11A))
48		mode |= HAL_MODE_11NA_HT20
49		     |  HAL_MODE_11NA_HT40PLUS
50		     |  HAL_MODE_11NA_HT40MINUS
51		     ;
52	if (pCap->halHTSupport == AH_TRUE && (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#if 0
77	uint32_t bits;
78#endif
79
80	if (AR_SREV_HOWL(ah))
81		return;
82
83	OS_REG_RMW_FIELD(ah, AR_MAC_LED,
84	    AR_MAC_LED_ASSOC, ledbits[state & 0x7]);
85
86	/*
87	 * For now, don't override the power/network LED
88	 * "on" bits.  The reference driver notes that some
89	 * devices connect the LED pins to other functionality
90	 * so we can't just leave this on by default.
91	 */
92#if 0
93	bits = OS_REG_READ(ah, AR_MAC_LED);
94	bits = (bits &~ AR_MAC_LED_MODE)
95	     | SM(AR_MAC_LED_MODE_POWON, AR_MAC_LED_MODE)
96#if 1
97	     | SM(AR_MAC_LED_MODE_NETON, AR_MAC_LED_MODE)
98#endif
99	     ;
100	bits = (bits &~ AR_MAC_LED_ASSOC)
101	     | SM(ledbits[state & 0x7], AR_MAC_LED_ASSOC);
102	OS_REG_WRITE(ah, AR_MAC_LED, bits);
103#endif
104}
105
106/*
107 * Get the current hardware tsf for stamlme
108 */
109uint64_t
110ar5416GetTsf64(struct ath_hal *ah)
111{
112	uint32_t low1, low2, u32;
113
114	/* sync multi-word read */
115	low1 = OS_REG_READ(ah, AR_TSF_L32);
116	u32 = OS_REG_READ(ah, AR_TSF_U32);
117	low2 = OS_REG_READ(ah, AR_TSF_L32);
118	if (low2 < low1) {	/* roll over */
119		/*
120		 * If we are not preempted this will work.  If we are
121		 * then we re-reading AR_TSF_U32 does no good as the
122		 * low bits will be meaningless.  Likewise reading
123		 * L32, U32, U32, then comparing the last two reads
124		 * to check for rollover doesn't help if preempted--so
125		 * we take this approach as it costs one less PCI read
126		 * which can be noticeable when doing things like
127		 * timestamping packets in monitor mode.
128		 */
129		u32++;
130	}
131	return (((uint64_t) u32) << 32) | ((uint64_t) low2);
132}
133
134void
135ar5416SetTsf64(struct ath_hal *ah, uint64_t tsf64)
136{
137	OS_REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
138	OS_REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
139}
140
141/*
142 * Reset the current hardware tsf for stamlme.
143 */
144void
145ar5416ResetTsf(struct ath_hal *ah)
146{
147	uint32_t v;
148	int i;
149
150	for (i = 0; i < 10; i++) {
151		v = OS_REG_READ(ah, AR_SLP32_MODE);
152		if ((v & AR_SLP32_TSF_WRITE_STATUS) == 0)
153			break;
154		OS_DELAY(10);
155	}
156	OS_REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
157}
158
159uint32_t
160ar5416GetCurRssi(struct ath_hal *ah)
161{
162	if (AR_SREV_OWL(ah))
163		return (OS_REG_READ(ah, AR_PHY_CURRENT_RSSI) & 0xff);
164	return (OS_REG_READ(ah, AR9130_PHY_CURRENT_RSSI) & 0xff);
165}
166
167HAL_BOOL
168ar5416SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings)
169{
170	return AH_TRUE;
171}
172
173/* Setup decompression for given key index */
174HAL_BOOL
175ar5416SetDecompMask(struct ath_hal *ah, uint16_t keyidx, int en)
176{
177	return AH_TRUE;
178}
179
180/* Setup coverage class */
181void
182ar5416SetCoverageClass(struct ath_hal *ah, uint8_t coverageclass, int now)
183{
184	AH_PRIVATE(ah)->ah_coverageClass = coverageclass;
185}
186
187/*
188 * Return the busy for rx_frame, rx_clear, and tx_frame
189 */
190uint32_t
191ar5416GetMibCycleCountsPct(struct ath_hal *ah, uint32_t *rxc_pcnt,
192    uint32_t *extc_pcnt, uint32_t *rxf_pcnt, uint32_t *txf_pcnt)
193{
194	struct ath_hal_5416 *ahp = AH5416(ah);
195	u_int32_t good = 1;
196
197	/* XXX freeze/unfreeze mib counters */
198	uint32_t rc = OS_REG_READ(ah, AR_RCCNT);
199	uint32_t ec = OS_REG_READ(ah, AR_EXTRCCNT);
200	uint32_t rf = OS_REG_READ(ah, AR_RFCNT);
201	uint32_t tf = OS_REG_READ(ah, AR_TFCNT);
202	uint32_t cc = OS_REG_READ(ah, AR_CCCNT); /* read cycles last */
203
204	if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cc) {
205		/*
206		 * Cycle counter wrap (or initial call); it's not possible
207		 * to accurately calculate a value because the registers
208		 * right shift rather than wrap--so punt and return 0.
209		 */
210		HALDEBUG(ah, HAL_DEBUG_ANY,
211			    "%s: cycle counter wrap. ExtBusy = 0\n", __func__);
212			good = 0;
213	} else {
214		uint32_t cc_d = cc - ahp->ah_cycleCount;
215		uint32_t rc_d = rc - ahp->ah_ctlBusy;
216		uint32_t ec_d = ec - ahp->ah_extBusy;
217		uint32_t rf_d = rf - ahp->ah_rxBusy;
218		uint32_t tf_d = tf - ahp->ah_txBusy;
219
220		if (cc_d != 0) {
221			*rxc_pcnt = rc_d * 100 / cc_d;
222			*rxf_pcnt = rf_d * 100 / cc_d;
223			*txf_pcnt = tf_d * 100 / cc_d;
224			*extc_pcnt = ec_d * 100 / cc_d;
225		} else {
226			good = 0;
227		}
228	}
229	ahp->ah_cycleCount = cc;
230	ahp->ah_rxBusy = rf;
231	ahp->ah_ctlBusy = rc;
232	ahp->ah_txBusy = tf;
233	ahp->ah_extBusy = ec;
234
235	return good;
236}
237
238/*
239 * Return approximation of extension channel busy over an time interval
240 * 0% (clear) -> 100% (busy)
241 *
242 */
243uint32_t
244ar5416Get11nExtBusy(struct ath_hal *ah)
245{
246    struct ath_hal_5416 *ahp = AH5416(ah);
247    uint32_t busy; /* percentage */
248    uint32_t cycleCount, ctlBusy, extBusy;
249
250    ctlBusy = OS_REG_READ(ah, AR_RCCNT);
251    extBusy = OS_REG_READ(ah, AR_EXTRCCNT);
252    cycleCount = OS_REG_READ(ah, AR_CCCNT);
253
254    if (ahp->ah_cycleCount == 0 || ahp->ah_cycleCount > cycleCount) {
255        /*
256         * Cycle counter wrap (or initial call); it's not possible
257         * to accurately calculate a value because the registers
258         * right shift rather than wrap--so punt and return 0.
259         */
260        busy = 0;
261        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycle counter wrap. ExtBusy = 0\n",
262	    __func__);
263
264    } else {
265        uint32_t cycleDelta = cycleCount - ahp->ah_cycleCount;
266        uint32_t ctlBusyDelta = ctlBusy - ahp->ah_ctlBusy;
267        uint32_t extBusyDelta = extBusy - ahp->ah_extBusy;
268        uint32_t ctlClearDelta = 0;
269
270        /* Compute control channel rxclear.
271         * The cycle delta may be less than the control channel delta.
272         * This could be solved by freezing the timers (or an atomic read,
273         * if one was available). Checking for the condition should be
274         * sufficient.
275         */
276        if (cycleDelta > ctlBusyDelta) {
277            ctlClearDelta = cycleDelta - ctlBusyDelta;
278        }
279
280        /* Compute ratio of extension channel busy to control channel clear
281         * as an approximation to extension channel cleanliness.
282         *
283         * According to the hardware folks, ext rxclear is undefined
284         * if the ctrl rxclear is de-asserted (i.e. busy)
285         */
286        if (ctlClearDelta) {
287            busy = (extBusyDelta * 100) / ctlClearDelta;
288        } else {
289            busy = 100;
290        }
291        if (busy > 100) {
292            busy = 100;
293        }
294#if 0
295        HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cycleDelta 0x%x, ctlBusyDelta 0x%x, "
296             "extBusyDelta 0x%x, ctlClearDelta 0x%x, "
297             "busy %d\n",
298              __func__, cycleDelta, ctlBusyDelta, extBusyDelta, ctlClearDelta, busy);
299#endif
300    }
301
302    ahp->ah_cycleCount = cycleCount;
303    ahp->ah_ctlBusy = ctlBusy;
304    ahp->ah_extBusy = extBusy;
305
306    return busy;
307}
308
309/*
310 * Configure 20/40 operation
311 *
312 * 20/40 = joint rx clear (control and extension)
313 * 20    = rx clear (control)
314 *
315 * - NOTE: must stop MAC (tx) and requeue 40 MHz packets as 20 MHz when changing
316 *         from 20/40 => 20 only
317 */
318void
319ar5416Set11nMac2040(struct ath_hal *ah, HAL_HT_MACMODE mode)
320{
321    uint32_t macmode;
322
323    /* Configure MAC for 20/40 operation */
324    if (mode == HAL_HT_MACMODE_2040) {
325        macmode = AR_2040_JOINED_RX_CLEAR;
326    } else {
327        macmode = 0;
328    }
329    OS_REG_WRITE(ah, AR_2040_MODE, macmode);
330}
331
332/*
333 * Get Rx clear (control/extension channel)
334 *
335 * Returns active low (busy) for ctrl/ext channel
336 * Owl 2.0
337 */
338HAL_HT_RXCLEAR
339ar5416Get11nRxClear(struct ath_hal *ah)
340{
341    HAL_HT_RXCLEAR rxclear = 0;
342    uint32_t val;
343
344    val = OS_REG_READ(ah, AR_DIAG_SW);
345
346    /* control channel */
347    if (val & AR_DIAG_RXCLEAR_CTL_LOW) {
348        rxclear |= HAL_RX_CLEAR_CTL_LOW;
349    }
350    /* extension channel */
351    if (val & AR_DIAG_RXCLEAR_EXT_LOW) {
352        rxclear |= HAL_RX_CLEAR_EXT_LOW;
353    }
354    return rxclear;
355}
356
357/*
358 * Set Rx clear (control/extension channel)
359 *
360 * Useful for forcing the channel to appear busy for
361 * debugging/diagnostics
362 * Owl 2.0
363 */
364void
365ar5416Set11nRxClear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear)
366{
367    /* control channel */
368    if (rxclear & HAL_RX_CLEAR_CTL_LOW) {
369        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
370    } else {
371        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_CTL_LOW);
372    }
373    /* extension channel */
374    if (rxclear & HAL_RX_CLEAR_EXT_LOW) {
375        OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
376    } else {
377        OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_RXCLEAR_EXT_LOW);
378    }
379}
380
381/* XXX shouldn't be here! */
382#define	TU_TO_USEC(_tu)		((_tu) << 10)
383
384HAL_STATUS
385ar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration,
386    uint32_t nextStart, HAL_QUIET_FLAG flag)
387{
388	uint32_t period_us = TU_TO_USEC(period); /* convert to us unit */
389	uint32_t nextStart_us = TU_TO_USEC(nextStart); /* convert to us unit */
390	if (flag & HAL_QUIET_ENABLE) {
391		if ((!nextStart) || (flag & HAL_QUIET_ADD_CURRENT_TSF)) {
392			/* Add the nextStart offset to the current TSF */
393			nextStart_us += OS_REG_READ(ah, AR_TSF_L32);
394		}
395		if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) {
396			nextStart_us += ah->ah_config.ah_sw_beacon_response_time;
397		}
398		OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
399		OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR));
400		OS_REG_WRITE(ah, AR_QUIET_PERIOD, period_us);
401		OS_REG_WRITE(ah, AR_NEXT_QUIET, nextStart_us);
402		OS_REG_SET_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
403	} else {
404		OS_REG_CLR_BIT(ah, AR_TIMER_MODE, AR_TIMER_MODE_QUIET);
405	}
406	return HAL_OK;
407}
408#undef	TU_TO_USEC
409
410HAL_STATUS
411ar5416GetCapability(struct ath_hal *ah, HAL_CAPABILITY_TYPE type,
412        uint32_t capability, uint32_t *result)
413{
414	switch (type) {
415	case HAL_CAP_BB_HANG:
416		switch (capability) {
417		case HAL_BB_HANG_RIFS:
418			return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
419		case HAL_BB_HANG_DFS:
420			return (AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ? HAL_OK : HAL_ENOTSUPP;
421		case HAL_BB_HANG_RX_CLEAR:
422			return AR_SREV_MERLIN(ah) ? HAL_OK : HAL_ENOTSUPP;
423		}
424		break;
425	case HAL_CAP_MAC_HANG:
426		return ((ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCI) ||
427		    (ah->ah_macVersion == AR_XSREV_VERSION_OWL_PCIE) ||
428		    AR_SREV_HOWL(ah) || AR_SREV_SOWL(ah)) ?
429			HAL_OK : HAL_ENOTSUPP;
430	case HAL_CAP_DIVERSITY:		/* disable classic fast diversity */
431		return HAL_ENXIO;
432	default:
433		break;
434	}
435	return ar5212GetCapability(ah, type, capability, result);
436}
437
438static int ar5416DetectMacHang(struct ath_hal *ah);
439static int ar5416DetectBBHang(struct ath_hal *ah);
440
441HAL_BOOL
442ar5416GetDiagState(struct ath_hal *ah, int request,
443	const void *args, uint32_t argsize,
444	void **result, uint32_t *resultsize)
445{
446	struct ath_hal_5416 *ahp = AH5416(ah);
447	int hangs;
448
449	if (ath_hal_getdiagstate(ah, request, args, argsize, result, resultsize))
450		return AH_TRUE;
451	switch (request) {
452	case HAL_DIAG_EEPROM:
453		return ath_hal_eepromDiag(ah, request,
454		    args, argsize, result, resultsize);
455	case HAL_DIAG_CHECK_HANGS:
456		if (argsize != sizeof(int))
457			return AH_FALSE;
458		hangs = *(const int *) args;
459		ahp->ah_hangs = 0;
460		if (hangs & HAL_BB_HANGS)
461			ahp->ah_hangs |= ar5416DetectBBHang(ah);
462		/* NB: if BB is hung MAC will be hung too so skip check */
463		if (ahp->ah_hangs == 0 && (hangs & HAL_MAC_HANGS))
464			ahp->ah_hangs |= ar5416DetectMacHang(ah);
465		*result = &ahp->ah_hangs;
466		*resultsize = sizeof(ahp->ah_hangs);
467		return AH_TRUE;
468	}
469	return ar5212GetDiagState(ah, request,
470	    args, argsize, result, resultsize);
471}
472
473typedef struct {
474	uint32_t dma_dbg_3;
475	uint32_t dma_dbg_4;
476	uint32_t dma_dbg_5;
477	uint32_t dma_dbg_6;
478} mac_dbg_regs_t;
479
480typedef enum {
481	dcu_chain_state		= 0x1,
482	dcu_complete_state	= 0x2,
483	qcu_state		= 0x4,
484	qcu_fsp_ok		= 0x8,
485	qcu_fsp_state		= 0x10,
486	qcu_stitch_state	= 0x20,
487	qcu_fetch_state		= 0x40,
488	qcu_complete_state	= 0x80
489} hal_mac_hangs_t;
490
491typedef struct {
492	int states;
493	uint8_t dcu_chain_state;
494	uint8_t dcu_complete_state;
495	uint8_t qcu_state;
496	uint8_t qcu_fsp_ok;
497	uint8_t qcu_fsp_state;
498	uint8_t qcu_stitch_state;
499	uint8_t qcu_fetch_state;
500	uint8_t qcu_complete_state;
501} hal_mac_hang_check_t;
502
503HAL_BOOL
504ar5416SetRifsDelay(struct ath_hal *ah, const struct ieee80211_channel *chan,
505    HAL_BOOL enable)
506{
507	uint32_t val;
508	HAL_BOOL is_chan_2g = AH_FALSE;
509	HAL_BOOL is_ht40 = AH_FALSE;
510
511	if (chan)
512		is_chan_2g = IEEE80211_IS_CHAN_2GHZ(chan);
513
514	if (chan)
515		is_ht40 = IEEE80211_IS_CHAN_HT40(chan);
516
517	/* Only support disabling RIFS delay for now */
518	HALASSERT(enable == AH_FALSE);
519
520	if (enable == AH_TRUE)
521		return AH_FALSE;
522
523	/* Change RIFS init delay to 0 */
524	val = OS_REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
525	val &= ~AR_PHY_RIFS_INIT_DELAY;
526	OS_REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
527
528	/*
529	 * For Owl, RIFS RX parameters are controlled differently;
530	 * it isn't enabled in the inivals by default.
531	 *
532	 * For Sowl/Howl, RIFS RX is enabled in the inivals by default;
533	 * the following code sets them back to non-RIFS values.
534	 *
535	 * For > Sowl/Howl, RIFS RX can be left on by default and so
536	 * this function shouldn't be called.
537	 */
538	if ((! AR_SREV_SOWL(ah)) && (! AR_SREV_HOWL(ah)))
539		return AH_TRUE;
540
541	/* Reset search delay to default values */
542	if (is_chan_2g)
543		if (is_ht40)
544			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x268);
545		else
546			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x134);
547	else
548		if (is_ht40)
549			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x370);
550		else
551			OS_REG_WRITE(ah, AR_PHY_SEARCH_START_DELAY, 0x1b8);
552
553	return AH_TRUE;
554}
555
556static HAL_BOOL
557ar5416CompareDbgHang(struct ath_hal *ah, const mac_dbg_regs_t *regs,
558    const hal_mac_hang_check_t *check)
559{
560	int found_states;
561
562	found_states = 0;
563	if (check->states & dcu_chain_state) {
564		int i;
565
566		for (i = 0; i < 6; i++) {
567			if (((regs->dma_dbg_4 >> (5*i)) & 0x1f) ==
568			    check->dcu_chain_state)
569				found_states |= dcu_chain_state;
570		}
571		for (i = 0; i < 4; i++) {
572			if (((regs->dma_dbg_5 >> (5*i)) & 0x1f) ==
573			    check->dcu_chain_state)
574				found_states |= dcu_chain_state;
575		}
576	}
577	if (check->states & dcu_complete_state) {
578		if ((regs->dma_dbg_6 & 0x3) == check->dcu_complete_state)
579			found_states |= dcu_complete_state;
580	}
581	if (check->states & qcu_stitch_state) {
582		if (((regs->dma_dbg_3 >> 18) & 0xf) == check->qcu_stitch_state)
583			found_states |= qcu_stitch_state;
584	}
585	if (check->states & qcu_fetch_state) {
586		if (((regs->dma_dbg_3 >> 22) & 0xf) == check->qcu_fetch_state)
587			found_states |= qcu_fetch_state;
588	}
589	if (check->states & qcu_complete_state) {
590		if (((regs->dma_dbg_3 >> 26) & 0x7) == check->qcu_complete_state)
591			found_states |= qcu_complete_state;
592	}
593	return (found_states == check->states);
594}
595
596#define NUM_STATUS_READS 50
597
598static int
599ar5416DetectMacHang(struct ath_hal *ah)
600{
601	static const hal_mac_hang_check_t hang_sig1 = {
602		.dcu_chain_state	= 0x6,
603		.dcu_complete_state	= 0x1,
604		.states			= dcu_chain_state
605					| dcu_complete_state,
606	};
607	static const hal_mac_hang_check_t hang_sig2 = {
608		.qcu_stitch_state	= 0x9,
609		.qcu_fetch_state	= 0x8,
610		.qcu_complete_state	= 0x4,
611		.states			= qcu_stitch_state
612					| qcu_fetch_state
613					| qcu_complete_state,
614        };
615	mac_dbg_regs_t mac_dbg;
616	int i;
617
618	mac_dbg.dma_dbg_3 = OS_REG_READ(ah, AR_DMADBG_3);
619	mac_dbg.dma_dbg_4 = OS_REG_READ(ah, AR_DMADBG_4);
620	mac_dbg.dma_dbg_5 = OS_REG_READ(ah, AR_DMADBG_5);
621	mac_dbg.dma_dbg_6 = OS_REG_READ(ah, AR_DMADBG_6);
622	for (i = 1; i <= NUM_STATUS_READS; i++) {
623		if (mac_dbg.dma_dbg_3 != OS_REG_READ(ah, AR_DMADBG_3) ||
624		    mac_dbg.dma_dbg_4 != OS_REG_READ(ah, AR_DMADBG_4) ||
625		    mac_dbg.dma_dbg_5 != OS_REG_READ(ah, AR_DMADBG_5) ||
626		    mac_dbg.dma_dbg_6 != OS_REG_READ(ah, AR_DMADBG_6))
627			return 0;
628	}
629
630	if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig1))
631		return HAL_MAC_HANG_SIG1;
632	if (ar5416CompareDbgHang(ah, &mac_dbg, &hang_sig2))
633		return HAL_MAC_HANG_SIG2;
634
635	HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown MAC hang signature "
636	    "DMADBG_3=0x%x DMADBG_4=0x%x DMADBG_5=0x%x DMADBG_6=0x%x\n",
637	    __func__, mac_dbg.dma_dbg_3, mac_dbg.dma_dbg_4, mac_dbg.dma_dbg_5,
638	    mac_dbg.dma_dbg_6);
639
640	return 0;
641}
642
643/*
644 * Determine if the baseband using the Observation Bus Register
645 */
646static int
647ar5416DetectBBHang(struct ath_hal *ah)
648{
649#define N(a) (sizeof(a)/sizeof(a[0]))
650	/*
651	 * Check the PCU Observation Bus 1 register (0x806c)
652	 * NUM_STATUS_READS times
653	 *
654	 * 4 known BB hang signatures -
655	 * [1] bits 8,9,11 are 0. State machine state (bits 25-31) is 0x1E
656	 * [2] bits 8,9 are 1, bit 11 is 0. State machine state
657	 *     (bits 25-31) is 0x52
658	 * [3] bits 8,9 are 1, bit 11 is 0. State machine state
659	 *     (bits 25-31) is 0x18
660	 * [4] bit 10 is 1, bit 11 is 0. WEP state (bits 12-17) is 0x2,
661	 *     Rx State (bits 20-24) is 0x7.
662	 */
663	static const struct {
664		uint32_t val;
665		uint32_t mask;
666		int code;
667	} hang_list[] = {
668		/* Reg Value   Reg Mask    Hang Code XXX */
669		{ 0x1E000000, 0x7E000B00, HAL_BB_HANG_DFS },
670		{ 0x52000B00, 0x7E000B00, HAL_BB_HANG_RIFS },
671		{ 0x18000B00, 0x7E000B00, HAL_BB_HANG_RX_CLEAR },
672		{ 0x00702400, 0x7E7FFFEF, HAL_BB_HANG_RX_CLEAR }
673	};
674	uint32_t hang_sig;
675	int i;
676
677	hang_sig = OS_REG_READ(ah, AR_OBSERV_1);
678	for (i = 1; i <= NUM_STATUS_READS; i++) {
679		if (hang_sig != OS_REG_READ(ah, AR_OBSERV_1))
680			return 0;
681	}
682	for (i = 0; i < N(hang_list); i++)
683		if ((hang_sig & hang_list[i].mask) == hang_list[i].val) {
684			HALDEBUG(ah, HAL_DEBUG_HANG,
685			    "%s BB hang, signature 0x%x, code 0x%x\n",
686			    __func__, hang_sig, hang_list[i].code);
687			return hang_list[i].code;
688		}
689
690	HALDEBUG(ah, HAL_DEBUG_HANG, "%s Found an unknown BB hang signature! "
691	    "<0x806c>=0x%x\n", __func__, hang_sig);
692
693	return 0;
694#undef N
695}
696#undef NUM_STATUS_READS
697
698/*
699 * Get the radar parameter values and return them in the pe
700 * structure
701 */
702void
703ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
704{
705	uint32_t val, temp;
706
707	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
708
709	temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
710	temp |= 0xFFFFFF80;
711	pe->pe_firpwr = temp;
712	pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
713	pe->pe_height =  MS(val, AR_PHY_RADAR_0_HEIGHT);
714	pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
715	pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
716
717	val = OS_REG_READ(ah, AR_PHY_RADAR_1);
718	temp = val & AR_PHY_RADAR_1_RELPWR_ENA;
719	pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
720	if (temp)
721		pe->pe_relpwr |= HAL_PHYERR_PARAM_ENABLE;
722	temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK;
723	pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
724	if (temp)
725		pe->pe_enabled = 1;
726	else
727		pe->pe_enabled = 0;
728
729	pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
730	pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
731	    AR_PHY_RADAR_EXT_ENA);
732
733	pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
734	    AR_PHY_RADAR_1_USE_FIR128);
735	pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
736	    AR_PHY_RADAR_1_BLOCK_CHECK);
737	pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
738	    AR_PHY_RADAR_1_MAX_RRSSI);
739}
740
741/*
742 * Enable radar detection and set the radar parameters per the
743 * values in pe
744 */
745void
746ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
747{
748	uint32_t val;
749
750	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
751
752	if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
753		val &= ~AR_PHY_RADAR_0_FIRPWR;
754		val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
755	}
756	if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
757		val &= ~AR_PHY_RADAR_0_RRSSI;
758		val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
759	}
760	if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
761		val &= ~AR_PHY_RADAR_0_HEIGHT;
762		val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
763	}
764	if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
765		val &= ~AR_PHY_RADAR_0_PRSSI;
766		val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
767	}
768	if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
769		val &= ~AR_PHY_RADAR_0_INBAND;
770		val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
771	}
772
773	/*Enable FFT data*/
774	val |= AR_PHY_RADAR_0_FFT_ENA;
775
776	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA);
777
778	if (pe->pe_usefir128 == 1)
779		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
780	else if (pe->pe_usefir128 == 0)
781		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
782
783	if (pe->pe_enmaxrssi == 1)
784		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
785	else if (pe->pe_enmaxrssi == 0)
786		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
787
788	if (pe->pe_blockradar == 1)
789		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
790	else if (pe->pe_blockradar == 0)
791		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
792
793	if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
794		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
795		val &= ~AR_PHY_RADAR_1_MAXLEN;
796		val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
797		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
798	}
799
800	/*
801	 * Enable HT/40 if the upper layer asks;
802	 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
803	 * is available.
804	 */
805	if (pe->pe_extchannel == 1)
806		OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
807	else if (pe->pe_extchannel == 0)
808		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
809
810	if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
811		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
812		val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
813		val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
814		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
815	}
816	if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
817		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
818		val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
819		val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
820		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
821	}
822}
823
824/*
825 * Extract the radar event information from the given phy error.
826 *
827 * Returns AH_TRUE if the phy error was actually a phy error,
828 * AH_FALSE if the phy error wasn't a phy error.
829 */
830
831/* Flags for pulse_bw_info */
832#define	PRI_CH_RADAR_FOUND		0x01
833#define	EXT_CH_RADAR_FOUND		0x02
834#define	EXT_CH_RADAR_EARLY_FOUND	0x04
835
836HAL_BOOL
837ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
838    uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
839{
840	HAL_BOOL doDfsExtCh;
841	HAL_BOOL doDfsEnhanced;
842	HAL_BOOL doDfsCombinedRssi;
843
844	uint8_t rssi = 0, ext_rssi = 0;
845	uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
846	uint32_t dur = 0;
847	int pri_found = 1, ext_found = 0;
848	int early_ext = 0;
849	int is_dc = 0;
850	uint16_t datalen;		/* length from the RX status field */
851
852	/* Check whether the given phy error is a radar event */
853	if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
854	    (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
855		return AH_FALSE;
856	}
857
858	/* Grab copies of the capabilities; just to make the code clearer */
859	doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
860	doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
861	doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
862
863	datalen = rxs->rs_datalen;
864
865	/* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
866	if (doDfsCombinedRssi)
867		rssi = (uint8_t) rxs->rs_rssi;
868	else
869		rssi = (uint8_t) rxs->rs_rssi_ctl[0];
870
871	/* Set this; but only use it if doDfsExtCh is set */
872	ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
873
874	/* Cap it at 0 if the RSSI is a negative number */
875	if (rssi & 0x80)
876		rssi = 0;
877
878	if (ext_rssi & 0x80)
879		ext_rssi = 0;
880
881	/*
882	 * Fetch the relevant data from the frame
883	 */
884	if (doDfsExtCh) {
885		if (datalen < 3)
886			return AH_FALSE;
887
888		/* Last three bytes of the frame are of interest */
889		pulse_length_pri = *(buf + datalen - 3);
890		pulse_length_ext = *(buf + datalen - 2);
891		pulse_bw_info = *(buf + datalen - 1);
892		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
893		    " pulse_length_ext=%d, pulse_bw_info=%x\n",
894		    __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
895		    pulse_bw_info);
896	} else {
897		/* The pulse width is byte 0 of the data */
898		if (datalen >= 1)
899			dur = ((uint8_t) buf[0]) & 0xff;
900		else
901			dur = 0;
902
903		if (dur == 0 && rssi == 0) {
904			HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
905			return AH_FALSE;
906		}
907
908		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
909
910		/* Single-channel only */
911		pri_found = 1;
912		ext_found = 0;
913	}
914
915	/*
916	 * If doing extended channel data, pulse_bw_info must
917	 * have one of the flags set.
918	 */
919	if (doDfsExtCh && pulse_bw_info == 0x0)
920		return AH_FALSE;
921
922	/*
923	 * If the extended channel data is available, calculate
924	 * which to pay attention to.
925	 */
926	if (doDfsExtCh) {
927		/* If pulse is on DC, take the larger duration of the two */
928		if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
929		    (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
930			is_dc = 1;
931			if (pulse_length_ext > pulse_length_pri) {
932				dur = pulse_length_ext;
933				pri_found = 0;
934				ext_found = 1;
935			} else {
936				dur = pulse_length_pri;
937				pri_found = 1;
938				ext_found = 0;
939			}
940		} else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
941			dur = pulse_length_ext;
942			pri_found = 0;
943			ext_found = 1;
944			early_ext = 1;
945		} else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
946			dur = pulse_length_pri;
947			pri_found = 1;
948			ext_found = 0;
949		} else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
950			dur = pulse_length_ext;
951			pri_found = 0;
952			ext_found = 1;
953		}
954
955	}
956
957	/*
958	 * For enhanced DFS (Merlin and later), pulse_bw_info has
959	 * implications for selecting the correct RSSI value.
960	 */
961	if (doDfsEnhanced) {
962		switch (pulse_bw_info & 0x03) {
963		case 0:
964			/* No radar? */
965			rssi = 0;
966			break;
967		case PRI_CH_RADAR_FOUND:
968			/* Radar in primary channel */
969			/* Cannot use ctrl channel RSSI if ext channel is stronger */
970			if (ext_rssi >= (rssi + 3)) {
971				rssi = 0;
972			};
973			break;
974		case EXT_CH_RADAR_FOUND:
975			/* Radar in extended channel */
976			/* Cannot use ext channel RSSI if ctrl channel is stronger */
977			if (rssi >= (ext_rssi + 12)) {
978				rssi = 0;
979			} else {
980				rssi = ext_rssi;
981			}
982			break;
983		case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
984			/* When both are present, use stronger one */
985			if (rssi < ext_rssi)
986				rssi = ext_rssi;
987			break;
988		}
989	}
990
991	/*
992	 * If not doing enhanced DFS, choose the ext channel if
993	 * it is stronger than the main channel
994	 */
995	if (doDfsExtCh && !doDfsEnhanced) {
996		if ((ext_rssi > rssi) && (ext_rssi < 128))
997			rssi = ext_rssi;
998	}
999
1000	/*
1001	 * XXX what happens if the above code decides the RSSI
1002	 * XXX wasn't valid, an sets it to 0?
1003	 */
1004
1005	/*
1006	 * Fill out dfs_event structure.
1007	 */
1008	event->re_full_ts = fulltsf;
1009	event->re_ts = rxs->rs_tstamp;
1010	event->re_rssi = rssi;
1011	event->re_dur = dur;
1012
1013	event->re_flags = 0;
1014	if (pri_found)
1015		event->re_flags |= HAL_DFS_EVENT_PRICH;
1016	if (ext_found)
1017		event->re_flags |= HAL_DFS_EVENT_EXTCH;
1018	if (early_ext)
1019		event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
1020	if (is_dc)
1021		event->re_flags |= HAL_DFS_EVENT_ISDC;
1022
1023	return AH_TRUE;
1024}
1025
1026/*
1027 * Return whether fast-clock is currently enabled for this
1028 * channel.
1029 */
1030HAL_BOOL
1031ar5416IsFastClockEnabled(struct ath_hal *ah)
1032{
1033	struct ath_hal_private *ahp = AH_PRIVATE(ah);
1034
1035	return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
1036}
1037