xref: /dflybsd-src/sys/dev/netif/ath/ath_hal/ar5416/ar5416_radar.c (revision b14ca477c2f404b36ad553a9e4f1b8b18836304e)
1572ff6f6SMatthew Dillon /*
2572ff6f6SMatthew Dillon  * Copyright (c) 2010-2011 Atheros Communications, Inc.
3572ff6f6SMatthew Dillon  *
4572ff6f6SMatthew Dillon  * Permission to use, copy, modify, and/or distribute this software for any
5572ff6f6SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
6572ff6f6SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
7572ff6f6SMatthew Dillon  *
8572ff6f6SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9572ff6f6SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10572ff6f6SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11572ff6f6SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12572ff6f6SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13572ff6f6SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14572ff6f6SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15572ff6f6SMatthew Dillon  *
16572ff6f6SMatthew Dillon  * $FreeBSD$
17572ff6f6SMatthew Dillon  */
18572ff6f6SMatthew Dillon #include "opt_ah.h"
19572ff6f6SMatthew Dillon 
20572ff6f6SMatthew Dillon #include "ah.h"
21572ff6f6SMatthew Dillon #include "ah_internal.h"
22572ff6f6SMatthew Dillon #include "ah_devid.h"
23572ff6f6SMatthew Dillon #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
24572ff6f6SMatthew Dillon 
25572ff6f6SMatthew Dillon #include "ar5416/ar5416.h"
26572ff6f6SMatthew Dillon #include "ar5416/ar5416reg.h"
27572ff6f6SMatthew Dillon #include "ar5416/ar5416phy.h"
28572ff6f6SMatthew Dillon 
29572ff6f6SMatthew Dillon #include "ah_eeprom_v14.h"	/* for owl_get_ntxchains() */
30572ff6f6SMatthew Dillon 
31572ff6f6SMatthew Dillon /*
32572ff6f6SMatthew Dillon  * These are default parameters for the AR5416 and
33572ff6f6SMatthew Dillon  * later 802.11n NICs.  They simply enable some
34572ff6f6SMatthew Dillon  * radar pulse event generation.
35572ff6f6SMatthew Dillon  *
36572ff6f6SMatthew Dillon  * These are very likely not valid for the AR5212 era
37572ff6f6SMatthew Dillon  * NICs.
38572ff6f6SMatthew Dillon  *
39572ff6f6SMatthew Dillon  * Since these define signal sizing and threshold
40572ff6f6SMatthew Dillon  * parameters, they may need changing based on the
41572ff6f6SMatthew Dillon  * specific antenna and receive amplifier
42572ff6f6SMatthew Dillon  * configuration.
43572ff6f6SMatthew Dillon  */
44572ff6f6SMatthew Dillon #define	AR5416_DFS_FIRPWR	-33
45572ff6f6SMatthew Dillon #define	AR5416_DFS_RRSSI	20
46572ff6f6SMatthew Dillon #define	AR5416_DFS_HEIGHT	10
47572ff6f6SMatthew Dillon #define	AR5416_DFS_PRSSI	15
48572ff6f6SMatthew Dillon #define	AR5416_DFS_INBAND	15
49572ff6f6SMatthew Dillon #define	AR5416_DFS_RELPWR	8
50572ff6f6SMatthew Dillon #define	AR5416_DFS_RELSTEP	12
51572ff6f6SMatthew Dillon #define	AR5416_DFS_MAXLEN	255
52572ff6f6SMatthew Dillon 
53572ff6f6SMatthew Dillon HAL_BOOL
ar5416GetDfsDefaultThresh(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)54572ff6f6SMatthew Dillon ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
55572ff6f6SMatthew Dillon {
56572ff6f6SMatthew Dillon 
57572ff6f6SMatthew Dillon 	/*
58572ff6f6SMatthew Dillon 	 * These are general examples of the parameter values
59572ff6f6SMatthew Dillon 	 * to use when configuring radar pulse detection for
60572ff6f6SMatthew Dillon 	 * the AR5416, AR91xx, AR92xx NICs.  They are only
61572ff6f6SMatthew Dillon 	 * for testing and do require tuning depending upon the
62572ff6f6SMatthew Dillon 	 * hardware and deployment specifics.
63572ff6f6SMatthew Dillon 	 */
64572ff6f6SMatthew Dillon 	pe->pe_firpwr = AR5416_DFS_FIRPWR;
65572ff6f6SMatthew Dillon 	pe->pe_rrssi = AR5416_DFS_RRSSI;
66572ff6f6SMatthew Dillon 	pe->pe_height = AR5416_DFS_HEIGHT;
67572ff6f6SMatthew Dillon 	pe->pe_prssi = AR5416_DFS_PRSSI;
68572ff6f6SMatthew Dillon 	pe->pe_inband = AR5416_DFS_INBAND;
69572ff6f6SMatthew Dillon 	pe->pe_relpwr = AR5416_DFS_RELPWR;
70572ff6f6SMatthew Dillon 	pe->pe_relstep = AR5416_DFS_RELSTEP;
71572ff6f6SMatthew Dillon 	pe->pe_maxlen = AR5416_DFS_MAXLEN;
72572ff6f6SMatthew Dillon 
73572ff6f6SMatthew Dillon 	return (AH_TRUE);
74572ff6f6SMatthew Dillon }
75572ff6f6SMatthew Dillon 
76572ff6f6SMatthew Dillon /*
77572ff6f6SMatthew Dillon  * Get the radar parameter values and return them in the pe
78572ff6f6SMatthew Dillon  * structure
79572ff6f6SMatthew Dillon  */
80572ff6f6SMatthew Dillon void
ar5416GetDfsThresh(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)81572ff6f6SMatthew Dillon ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
82572ff6f6SMatthew Dillon {
83572ff6f6SMatthew Dillon 	uint32_t val, temp;
84572ff6f6SMatthew Dillon 
85572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
86572ff6f6SMatthew Dillon 
87572ff6f6SMatthew Dillon 	temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
88572ff6f6SMatthew Dillon 	temp |= 0xFFFFFF80;
89572ff6f6SMatthew Dillon 	pe->pe_firpwr = temp;
90572ff6f6SMatthew Dillon 	pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
91572ff6f6SMatthew Dillon 	pe->pe_height =  MS(val, AR_PHY_RADAR_0_HEIGHT);
92572ff6f6SMatthew Dillon 	pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
93572ff6f6SMatthew Dillon 	pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
94572ff6f6SMatthew Dillon 
95572ff6f6SMatthew Dillon 	/* RADAR_1 values */
96572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_RADAR_1);
97572ff6f6SMatthew Dillon 	pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
98572ff6f6SMatthew Dillon 	pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
99572ff6f6SMatthew Dillon 	pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
100572ff6f6SMatthew Dillon 
101572ff6f6SMatthew Dillon 	pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
102572ff6f6SMatthew Dillon 	    AR_PHY_RADAR_EXT_ENA);
103572ff6f6SMatthew Dillon 
104572ff6f6SMatthew Dillon 	pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
105572ff6f6SMatthew Dillon 	    AR_PHY_RADAR_1_USE_FIR128);
106572ff6f6SMatthew Dillon 	pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
107572ff6f6SMatthew Dillon 	    AR_PHY_RADAR_1_BLOCK_CHECK);
108572ff6f6SMatthew Dillon 	pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
109572ff6f6SMatthew Dillon 	    AR_PHY_RADAR_1_MAX_RRSSI);
110572ff6f6SMatthew Dillon 	pe->pe_enabled = !!
111572ff6f6SMatthew Dillon 	    (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
112572ff6f6SMatthew Dillon 	pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
113572ff6f6SMatthew Dillon 	    AR_PHY_RADAR_1_RELPWR_ENA);
114572ff6f6SMatthew Dillon 	pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
115572ff6f6SMatthew Dillon 	    AR_PHY_RADAR_1_RELSTEP_CHECK);
116572ff6f6SMatthew Dillon }
117572ff6f6SMatthew Dillon 
118572ff6f6SMatthew Dillon /*
119572ff6f6SMatthew Dillon  * Enable radar detection and set the radar parameters per the
120572ff6f6SMatthew Dillon  * values in pe
121572ff6f6SMatthew Dillon  */
122572ff6f6SMatthew Dillon void
ar5416EnableDfs(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)123572ff6f6SMatthew Dillon ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
124572ff6f6SMatthew Dillon {
125572ff6f6SMatthew Dillon 	uint32_t val;
126572ff6f6SMatthew Dillon 
127572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
128572ff6f6SMatthew Dillon 
129572ff6f6SMatthew Dillon 	if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
130572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_0_FIRPWR;
131572ff6f6SMatthew Dillon 		val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
132572ff6f6SMatthew Dillon 	}
133572ff6f6SMatthew Dillon 	if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
134572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_0_RRSSI;
135572ff6f6SMatthew Dillon 		val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
136572ff6f6SMatthew Dillon 	}
137572ff6f6SMatthew Dillon 	if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
138572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_0_HEIGHT;
139572ff6f6SMatthew Dillon 		val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
140572ff6f6SMatthew Dillon 	}
141572ff6f6SMatthew Dillon 	if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
142572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_0_PRSSI;
143572ff6f6SMatthew Dillon 		val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
144572ff6f6SMatthew Dillon 	}
145572ff6f6SMatthew Dillon 	if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
146572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_0_INBAND;
147572ff6f6SMatthew Dillon 		val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
148572ff6f6SMatthew Dillon 	}
149572ff6f6SMatthew Dillon 
150572ff6f6SMatthew Dillon 	/*Enable FFT data*/
151572ff6f6SMatthew Dillon 	val |= AR_PHY_RADAR_0_FFT_ENA;
152572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
153572ff6f6SMatthew Dillon 
154572ff6f6SMatthew Dillon 	/* Implicitly enable */
155572ff6f6SMatthew Dillon 	if (pe->pe_enabled == 1)
156572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
157572ff6f6SMatthew Dillon 	else if (pe->pe_enabled == 0)
158572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
159572ff6f6SMatthew Dillon 
160572ff6f6SMatthew Dillon 	if (pe->pe_usefir128 == 1)
161572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
162572ff6f6SMatthew Dillon 	else if (pe->pe_usefir128 == 0)
163572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
164572ff6f6SMatthew Dillon 
165572ff6f6SMatthew Dillon 	if (pe->pe_enmaxrssi == 1)
166572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
167572ff6f6SMatthew Dillon 	else if (pe->pe_enmaxrssi == 0)
168572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
169572ff6f6SMatthew Dillon 
170572ff6f6SMatthew Dillon 	if (pe->pe_blockradar == 1)
171572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
172572ff6f6SMatthew Dillon 	else if (pe->pe_blockradar == 0)
173572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
174572ff6f6SMatthew Dillon 
175572ff6f6SMatthew Dillon 	if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
176572ff6f6SMatthew Dillon 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
177572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
178572ff6f6SMatthew Dillon 		val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
179572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
180572ff6f6SMatthew Dillon 	}
181572ff6f6SMatthew Dillon 	if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
182572ff6f6SMatthew Dillon 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
183572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
184572ff6f6SMatthew Dillon 		val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
185572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
186572ff6f6SMatthew Dillon 	}
187572ff6f6SMatthew Dillon 
188572ff6f6SMatthew Dillon 	if (pe->pe_en_relstep_check == 1)
189572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
190572ff6f6SMatthew Dillon 		    AR_PHY_RADAR_1_RELSTEP_CHECK);
191572ff6f6SMatthew Dillon 	else if (pe->pe_en_relstep_check == 0)
192572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
193572ff6f6SMatthew Dillon 		    AR_PHY_RADAR_1_RELSTEP_CHECK);
194572ff6f6SMatthew Dillon 
195572ff6f6SMatthew Dillon 	if (pe->pe_enrelpwr == 1)
196572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
197572ff6f6SMatthew Dillon 		    AR_PHY_RADAR_1_RELPWR_ENA);
198572ff6f6SMatthew Dillon 	else if (pe->pe_enrelpwr == 0)
199572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
200572ff6f6SMatthew Dillon 		    AR_PHY_RADAR_1_RELPWR_ENA);
201572ff6f6SMatthew Dillon 
202572ff6f6SMatthew Dillon 	if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
203572ff6f6SMatthew Dillon 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
204572ff6f6SMatthew Dillon 		val &= ~AR_PHY_RADAR_1_MAXLEN;
205572ff6f6SMatthew Dillon 		val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
206572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
207572ff6f6SMatthew Dillon 	}
208572ff6f6SMatthew Dillon 
209572ff6f6SMatthew Dillon 	/*
210572ff6f6SMatthew Dillon 	 * Enable HT/40 if the upper layer asks;
211572ff6f6SMatthew Dillon 	 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
212572ff6f6SMatthew Dillon 	 * is available.
213572ff6f6SMatthew Dillon 	 */
214572ff6f6SMatthew Dillon 	if (pe->pe_extchannel == 1)
215572ff6f6SMatthew Dillon 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
216572ff6f6SMatthew Dillon 	else if (pe->pe_extchannel == 0)
217572ff6f6SMatthew Dillon 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
218572ff6f6SMatthew Dillon }
219572ff6f6SMatthew Dillon 
220572ff6f6SMatthew Dillon /*
221572ff6f6SMatthew Dillon  * Extract the radar event information from the given phy error.
222572ff6f6SMatthew Dillon  *
223572ff6f6SMatthew Dillon  * Returns AH_TRUE if the phy error was actually a phy error,
224572ff6f6SMatthew Dillon  * AH_FALSE if the phy error wasn't a phy error.
225572ff6f6SMatthew Dillon  */
226572ff6f6SMatthew Dillon 
227572ff6f6SMatthew Dillon /* Flags for pulse_bw_info */
228572ff6f6SMatthew Dillon #define	PRI_CH_RADAR_FOUND		0x01
229572ff6f6SMatthew Dillon #define	EXT_CH_RADAR_FOUND		0x02
230572ff6f6SMatthew Dillon #define	EXT_CH_RADAR_EARLY_FOUND	0x04
231572ff6f6SMatthew Dillon 
232572ff6f6SMatthew Dillon HAL_BOOL
ar5416ProcessRadarEvent(struct ath_hal * ah,struct ath_rx_status * rxs,uint64_t fulltsf,const char * buf,HAL_DFS_EVENT * event)233572ff6f6SMatthew Dillon ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
234572ff6f6SMatthew Dillon     uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
235572ff6f6SMatthew Dillon {
236572ff6f6SMatthew Dillon 	HAL_BOOL doDfsExtCh;
237572ff6f6SMatthew Dillon 	HAL_BOOL doDfsEnhanced;
238572ff6f6SMatthew Dillon 	HAL_BOOL doDfsCombinedRssi;
239572ff6f6SMatthew Dillon 
240572ff6f6SMatthew Dillon 	uint8_t rssi = 0, ext_rssi = 0;
241572ff6f6SMatthew Dillon 	uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
242572ff6f6SMatthew Dillon 	uint32_t dur = 0;
243572ff6f6SMatthew Dillon 	int pri_found = 1, ext_found = 0;
244572ff6f6SMatthew Dillon 	int early_ext = 0;
245572ff6f6SMatthew Dillon 	int is_dc = 0;
246572ff6f6SMatthew Dillon 	uint16_t datalen;		/* length from the RX status field */
247572ff6f6SMatthew Dillon 
248572ff6f6SMatthew Dillon 	/* Check whether the given phy error is a radar event */
249572ff6f6SMatthew Dillon 	if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
250572ff6f6SMatthew Dillon 	    (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
251572ff6f6SMatthew Dillon 		return AH_FALSE;
252572ff6f6SMatthew Dillon 	}
253572ff6f6SMatthew Dillon 
254572ff6f6SMatthew Dillon 	/* Grab copies of the capabilities; just to make the code clearer */
255572ff6f6SMatthew Dillon 	doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
256572ff6f6SMatthew Dillon 	doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
257572ff6f6SMatthew Dillon 	doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
258572ff6f6SMatthew Dillon 
259572ff6f6SMatthew Dillon 	datalen = rxs->rs_datalen;
260572ff6f6SMatthew Dillon 
261572ff6f6SMatthew Dillon 	/* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
262572ff6f6SMatthew Dillon 	if (doDfsCombinedRssi)
263572ff6f6SMatthew Dillon 		rssi = (uint8_t) rxs->rs_rssi;
264572ff6f6SMatthew Dillon 	else
265572ff6f6SMatthew Dillon 		rssi = (uint8_t) rxs->rs_rssi_ctl[0];
266572ff6f6SMatthew Dillon 
267572ff6f6SMatthew Dillon 	/* Set this; but only use it if doDfsExtCh is set */
268572ff6f6SMatthew Dillon 	ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
269572ff6f6SMatthew Dillon 
270572ff6f6SMatthew Dillon 	/* Cap it at 0 if the RSSI is a negative number */
271572ff6f6SMatthew Dillon 	if (rssi & 0x80)
272572ff6f6SMatthew Dillon 		rssi = 0;
273572ff6f6SMatthew Dillon 
274572ff6f6SMatthew Dillon 	if (ext_rssi & 0x80)
275572ff6f6SMatthew Dillon 		ext_rssi = 0;
276572ff6f6SMatthew Dillon 
277572ff6f6SMatthew Dillon 	/*
278572ff6f6SMatthew Dillon 	 * Fetch the relevant data from the frame
279572ff6f6SMatthew Dillon 	 */
280572ff6f6SMatthew Dillon 	if (doDfsExtCh) {
281572ff6f6SMatthew Dillon 		if (datalen < 3)
282572ff6f6SMatthew Dillon 			return AH_FALSE;
283572ff6f6SMatthew Dillon 
284572ff6f6SMatthew Dillon 		/* Last three bytes of the frame are of interest */
285572ff6f6SMatthew Dillon 		pulse_length_pri = *(buf + datalen - 3);
286572ff6f6SMatthew Dillon 		pulse_length_ext = *(buf + datalen - 2);
287572ff6f6SMatthew Dillon 		pulse_bw_info = *(buf + datalen - 1);
288572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
289572ff6f6SMatthew Dillon 		    " pulse_length_ext=%d, pulse_bw_info=%x\n",
290572ff6f6SMatthew Dillon 		    __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
291572ff6f6SMatthew Dillon 		    pulse_bw_info);
292572ff6f6SMatthew Dillon 	} else {
293572ff6f6SMatthew Dillon 		/* The pulse width is byte 0 of the data */
294572ff6f6SMatthew Dillon 		if (datalen >= 1)
295572ff6f6SMatthew Dillon 			dur = ((uint8_t) buf[0]) & 0xff;
296572ff6f6SMatthew Dillon 		else
297572ff6f6SMatthew Dillon 			dur = 0;
298572ff6f6SMatthew Dillon 
299572ff6f6SMatthew Dillon 		if (dur == 0 && rssi == 0) {
300572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
301572ff6f6SMatthew Dillon 			return AH_FALSE;
302572ff6f6SMatthew Dillon 		}
303572ff6f6SMatthew Dillon 
304572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
305572ff6f6SMatthew Dillon 
306572ff6f6SMatthew Dillon 		/* Single-channel only */
307572ff6f6SMatthew Dillon 		pri_found = 1;
308572ff6f6SMatthew Dillon 		ext_found = 0;
309572ff6f6SMatthew Dillon 	}
310572ff6f6SMatthew Dillon 
311572ff6f6SMatthew Dillon 	/*
312572ff6f6SMatthew Dillon 	 * If doing extended channel data, pulse_bw_info must
313572ff6f6SMatthew Dillon 	 * have one of the flags set.
314572ff6f6SMatthew Dillon 	 */
315572ff6f6SMatthew Dillon 	if (doDfsExtCh && pulse_bw_info == 0x0)
316572ff6f6SMatthew Dillon 		return AH_FALSE;
317572ff6f6SMatthew Dillon 
318572ff6f6SMatthew Dillon 	/*
319572ff6f6SMatthew Dillon 	 * If the extended channel data is available, calculate
320572ff6f6SMatthew Dillon 	 * which to pay attention to.
321572ff6f6SMatthew Dillon 	 */
322572ff6f6SMatthew Dillon 	if (doDfsExtCh) {
323572ff6f6SMatthew Dillon 		/* If pulse is on DC, take the larger duration of the two */
324572ff6f6SMatthew Dillon 		if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
325572ff6f6SMatthew Dillon 		    (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
326572ff6f6SMatthew Dillon 			is_dc = 1;
327572ff6f6SMatthew Dillon 			if (pulse_length_ext > pulse_length_pri) {
328572ff6f6SMatthew Dillon 				dur = pulse_length_ext;
329572ff6f6SMatthew Dillon 				pri_found = 0;
330572ff6f6SMatthew Dillon 				ext_found = 1;
331572ff6f6SMatthew Dillon 			} else {
332572ff6f6SMatthew Dillon 				dur = pulse_length_pri;
333572ff6f6SMatthew Dillon 				pri_found = 1;
334572ff6f6SMatthew Dillon 				ext_found = 0;
335572ff6f6SMatthew Dillon 			}
336572ff6f6SMatthew Dillon 		} else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
337572ff6f6SMatthew Dillon 			dur = pulse_length_ext;
338572ff6f6SMatthew Dillon 			pri_found = 0;
339572ff6f6SMatthew Dillon 			ext_found = 1;
340572ff6f6SMatthew Dillon 			early_ext = 1;
341572ff6f6SMatthew Dillon 		} else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
342572ff6f6SMatthew Dillon 			dur = pulse_length_pri;
343572ff6f6SMatthew Dillon 			pri_found = 1;
344572ff6f6SMatthew Dillon 			ext_found = 0;
345572ff6f6SMatthew Dillon 		} else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
346572ff6f6SMatthew Dillon 			dur = pulse_length_ext;
347572ff6f6SMatthew Dillon 			pri_found = 0;
348572ff6f6SMatthew Dillon 			ext_found = 1;
349572ff6f6SMatthew Dillon 		}
350572ff6f6SMatthew Dillon 
351572ff6f6SMatthew Dillon 	}
352572ff6f6SMatthew Dillon 
353572ff6f6SMatthew Dillon 	/*
354572ff6f6SMatthew Dillon 	 * For enhanced DFS (Merlin and later), pulse_bw_info has
355572ff6f6SMatthew Dillon 	 * implications for selecting the correct RSSI value.
356572ff6f6SMatthew Dillon 	 */
357572ff6f6SMatthew Dillon 	if (doDfsEnhanced) {
358572ff6f6SMatthew Dillon 		switch (pulse_bw_info & 0x03) {
359572ff6f6SMatthew Dillon 		case 0:
360572ff6f6SMatthew Dillon 			/* No radar? */
361572ff6f6SMatthew Dillon 			rssi = 0;
362572ff6f6SMatthew Dillon 			break;
363572ff6f6SMatthew Dillon 		case PRI_CH_RADAR_FOUND:
364572ff6f6SMatthew Dillon 			/* Radar in primary channel */
365572ff6f6SMatthew Dillon 			/* Cannot use ctrl channel RSSI if ext channel is stronger */
366572ff6f6SMatthew Dillon 			if (ext_rssi >= (rssi + 3)) {
367572ff6f6SMatthew Dillon 				rssi = 0;
368*b14ca477SMatthew Dillon 			}
369572ff6f6SMatthew Dillon 			break;
370572ff6f6SMatthew Dillon 		case EXT_CH_RADAR_FOUND:
371572ff6f6SMatthew Dillon 			/* Radar in extended channel */
372572ff6f6SMatthew Dillon 			/* Cannot use ext channel RSSI if ctrl channel is stronger */
373572ff6f6SMatthew Dillon 			if (rssi >= (ext_rssi + 12)) {
374572ff6f6SMatthew Dillon 				rssi = 0;
375572ff6f6SMatthew Dillon 			} else {
376572ff6f6SMatthew Dillon 				rssi = ext_rssi;
377572ff6f6SMatthew Dillon 			}
378572ff6f6SMatthew Dillon 			break;
379572ff6f6SMatthew Dillon 		case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
380572ff6f6SMatthew Dillon 			/* When both are present, use stronger one */
381572ff6f6SMatthew Dillon 			if (rssi < ext_rssi)
382572ff6f6SMatthew Dillon 				rssi = ext_rssi;
383572ff6f6SMatthew Dillon 			break;
384572ff6f6SMatthew Dillon 		}
385572ff6f6SMatthew Dillon 	}
386572ff6f6SMatthew Dillon 
387572ff6f6SMatthew Dillon 	/*
388572ff6f6SMatthew Dillon 	 * If not doing enhanced DFS, choose the ext channel if
389572ff6f6SMatthew Dillon 	 * it is stronger than the main channel
390572ff6f6SMatthew Dillon 	 */
391572ff6f6SMatthew Dillon 	if (doDfsExtCh && !doDfsEnhanced) {
392572ff6f6SMatthew Dillon 		if ((ext_rssi > rssi) && (ext_rssi < 128))
393572ff6f6SMatthew Dillon 			rssi = ext_rssi;
394572ff6f6SMatthew Dillon 	}
395572ff6f6SMatthew Dillon 
396572ff6f6SMatthew Dillon 	/*
397572ff6f6SMatthew Dillon 	 * XXX what happens if the above code decides the RSSI
398572ff6f6SMatthew Dillon 	 * XXX wasn't valid, an sets it to 0?
399572ff6f6SMatthew Dillon 	 */
400572ff6f6SMatthew Dillon 
401572ff6f6SMatthew Dillon 	/*
402572ff6f6SMatthew Dillon 	 * Fill out dfs_event structure.
403572ff6f6SMatthew Dillon 	 */
404572ff6f6SMatthew Dillon 	event->re_full_ts = fulltsf;
405572ff6f6SMatthew Dillon 	event->re_ts = rxs->rs_tstamp;
406572ff6f6SMatthew Dillon 	event->re_rssi = rssi;
407572ff6f6SMatthew Dillon 	event->re_dur = dur;
408572ff6f6SMatthew Dillon 
409572ff6f6SMatthew Dillon 	event->re_flags = 0;
410572ff6f6SMatthew Dillon 	if (pri_found)
411572ff6f6SMatthew Dillon 		event->re_flags |= HAL_DFS_EVENT_PRICH;
412572ff6f6SMatthew Dillon 	if (ext_found)
413572ff6f6SMatthew Dillon 		event->re_flags |= HAL_DFS_EVENT_EXTCH;
414572ff6f6SMatthew Dillon 	if (early_ext)
415572ff6f6SMatthew Dillon 		event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
416572ff6f6SMatthew Dillon 	if (is_dc)
417572ff6f6SMatthew Dillon 		event->re_flags |= HAL_DFS_EVENT_ISDC;
418572ff6f6SMatthew Dillon 
419572ff6f6SMatthew Dillon 	return AH_TRUE;
420572ff6f6SMatthew Dillon }
421572ff6f6SMatthew Dillon 
422572ff6f6SMatthew Dillon /*
423572ff6f6SMatthew Dillon  * Return whether fast-clock is currently enabled for this
424572ff6f6SMatthew Dillon  * channel.
425572ff6f6SMatthew Dillon  */
426572ff6f6SMatthew Dillon HAL_BOOL
ar5416IsFastClockEnabled(struct ath_hal * ah)427572ff6f6SMatthew Dillon ar5416IsFastClockEnabled(struct ath_hal *ah)
428572ff6f6SMatthew Dillon {
429572ff6f6SMatthew Dillon 	struct ath_hal_private *ahp = AH_PRIVATE(ah);
430572ff6f6SMatthew Dillon 
431572ff6f6SMatthew Dillon 	return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
432572ff6f6SMatthew Dillon }
433