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