xref: /freebsd/sys/dev/ath/ath_hal/ar5416/ar5416_radar.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1*6e778a7eSPedro F. Giffuni /*-
2*6e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
3*6e778a7eSPedro F. Giffuni  *
47b1144d2SAdrian Chadd  * Copyright (c) 2010-2011 Atheros Communications, Inc.
57b1144d2SAdrian Chadd  *
67b1144d2SAdrian Chadd  * Permission to use, copy, modify, and/or distribute this software for any
77b1144d2SAdrian Chadd  * purpose with or without fee is hereby granted, provided that the above
87b1144d2SAdrian Chadd  * copyright notice and this permission notice appear in all copies.
97b1144d2SAdrian Chadd  *
107b1144d2SAdrian Chadd  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117b1144d2SAdrian Chadd  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127b1144d2SAdrian Chadd  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137b1144d2SAdrian Chadd  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147b1144d2SAdrian Chadd  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157b1144d2SAdrian Chadd  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167b1144d2SAdrian Chadd  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177b1144d2SAdrian Chadd  */
187b1144d2SAdrian Chadd #include "opt_ah.h"
197b1144d2SAdrian Chadd 
207b1144d2SAdrian Chadd #include "ah.h"
217b1144d2SAdrian Chadd #include "ah_internal.h"
227b1144d2SAdrian Chadd #include "ah_devid.h"
237b1144d2SAdrian Chadd #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
247b1144d2SAdrian Chadd 
257b1144d2SAdrian Chadd #include "ar5416/ar5416.h"
267b1144d2SAdrian Chadd #include "ar5416/ar5416reg.h"
277b1144d2SAdrian Chadd #include "ar5416/ar5416phy.h"
287b1144d2SAdrian Chadd 
297b1144d2SAdrian Chadd #include "ah_eeprom_v14.h"	/* for owl_get_ntxchains() */
307b1144d2SAdrian Chadd 
317b1144d2SAdrian Chadd /*
3254798be0SAdrian Chadd  * These are default parameters for the AR5416 and
3354798be0SAdrian Chadd  * later 802.11n NICs.  They simply enable some
3454798be0SAdrian Chadd  * radar pulse event generation.
3554798be0SAdrian Chadd  *
3654798be0SAdrian Chadd  * These are very likely not valid for the AR5212 era
3754798be0SAdrian Chadd  * NICs.
3854798be0SAdrian Chadd  *
3954798be0SAdrian Chadd  * Since these define signal sizing and threshold
4054798be0SAdrian Chadd  * parameters, they may need changing based on the
4154798be0SAdrian Chadd  * specific antenna and receive amplifier
4254798be0SAdrian Chadd  * configuration.
4354798be0SAdrian Chadd  */
4454798be0SAdrian Chadd #define	AR5416_DFS_FIRPWR	-33
4554798be0SAdrian Chadd #define	AR5416_DFS_RRSSI	20
4654798be0SAdrian Chadd #define	AR5416_DFS_HEIGHT	10
4754798be0SAdrian Chadd #define	AR5416_DFS_PRSSI	15
4854798be0SAdrian Chadd #define	AR5416_DFS_INBAND	15
4954798be0SAdrian Chadd #define	AR5416_DFS_RELPWR	8
5054798be0SAdrian Chadd #define	AR5416_DFS_RELSTEP	12
5154798be0SAdrian Chadd #define	AR5416_DFS_MAXLEN	255
5254798be0SAdrian Chadd 
5354798be0SAdrian Chadd HAL_BOOL
ar5416GetDfsDefaultThresh(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)5454798be0SAdrian Chadd ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
5554798be0SAdrian Chadd {
5654798be0SAdrian Chadd 
5754798be0SAdrian Chadd 	/*
5854798be0SAdrian Chadd 	 * These are general examples of the parameter values
5954798be0SAdrian Chadd 	 * to use when configuring radar pulse detection for
6054798be0SAdrian Chadd 	 * the AR5416, AR91xx, AR92xx NICs.  They are only
6154798be0SAdrian Chadd 	 * for testing and do require tuning depending upon the
6254798be0SAdrian Chadd 	 * hardware and deployment specifics.
6354798be0SAdrian Chadd 	 */
6454798be0SAdrian Chadd 	pe->pe_firpwr = AR5416_DFS_FIRPWR;
6554798be0SAdrian Chadd 	pe->pe_rrssi = AR5416_DFS_RRSSI;
6654798be0SAdrian Chadd 	pe->pe_height = AR5416_DFS_HEIGHT;
6754798be0SAdrian Chadd 	pe->pe_prssi = AR5416_DFS_PRSSI;
6854798be0SAdrian Chadd 	pe->pe_inband = AR5416_DFS_INBAND;
6954798be0SAdrian Chadd 	pe->pe_relpwr = AR5416_DFS_RELPWR;
7054798be0SAdrian Chadd 	pe->pe_relstep = AR5416_DFS_RELSTEP;
7154798be0SAdrian Chadd 	pe->pe_maxlen = AR5416_DFS_MAXLEN;
7254798be0SAdrian Chadd 
7354798be0SAdrian Chadd 	return (AH_TRUE);
7454798be0SAdrian Chadd }
7554798be0SAdrian Chadd 
7654798be0SAdrian Chadd /*
777b1144d2SAdrian Chadd  * Get the radar parameter values and return them in the pe
787b1144d2SAdrian Chadd  * structure
797b1144d2SAdrian Chadd  */
807b1144d2SAdrian Chadd void
ar5416GetDfsThresh(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)817b1144d2SAdrian Chadd ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
827b1144d2SAdrian Chadd {
837b1144d2SAdrian Chadd 	uint32_t val, temp;
847b1144d2SAdrian Chadd 
857b1144d2SAdrian Chadd 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
867b1144d2SAdrian Chadd 
877b1144d2SAdrian Chadd 	temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
887b1144d2SAdrian Chadd 	temp |= 0xFFFFFF80;
897b1144d2SAdrian Chadd 	pe->pe_firpwr = temp;
907b1144d2SAdrian Chadd 	pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
917b1144d2SAdrian Chadd 	pe->pe_height =  MS(val, AR_PHY_RADAR_0_HEIGHT);
927b1144d2SAdrian Chadd 	pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
937b1144d2SAdrian Chadd 	pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
947b1144d2SAdrian Chadd 
957b1144d2SAdrian Chadd 	/* RADAR_1 values */
967b1144d2SAdrian Chadd 	val = OS_REG_READ(ah, AR_PHY_RADAR_1);
977b1144d2SAdrian Chadd 	pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
987b1144d2SAdrian Chadd 	pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
997b1144d2SAdrian Chadd 	pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
1007b1144d2SAdrian Chadd 
1017b1144d2SAdrian Chadd 	pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
1027b1144d2SAdrian Chadd 	    AR_PHY_RADAR_EXT_ENA);
1037b1144d2SAdrian Chadd 
1047b1144d2SAdrian Chadd 	pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
1057b1144d2SAdrian Chadd 	    AR_PHY_RADAR_1_USE_FIR128);
1067b1144d2SAdrian Chadd 	pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
1077b1144d2SAdrian Chadd 	    AR_PHY_RADAR_1_BLOCK_CHECK);
1087b1144d2SAdrian Chadd 	pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
1097b1144d2SAdrian Chadd 	    AR_PHY_RADAR_1_MAX_RRSSI);
1107b1144d2SAdrian Chadd 	pe->pe_enabled = !!
1117b1144d2SAdrian Chadd 	    (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
1127b1144d2SAdrian Chadd 	pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
1137b1144d2SAdrian Chadd 	    AR_PHY_RADAR_1_RELPWR_ENA);
1147b1144d2SAdrian Chadd 	pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
1157b1144d2SAdrian Chadd 	    AR_PHY_RADAR_1_RELSTEP_CHECK);
1167b1144d2SAdrian Chadd }
1177b1144d2SAdrian Chadd 
1187b1144d2SAdrian Chadd /*
1197b1144d2SAdrian Chadd  * Enable radar detection and set the radar parameters per the
1207b1144d2SAdrian Chadd  * values in pe
1217b1144d2SAdrian Chadd  */
1227b1144d2SAdrian Chadd void
ar5416EnableDfs(struct ath_hal * ah,HAL_PHYERR_PARAM * pe)1237b1144d2SAdrian Chadd ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
1247b1144d2SAdrian Chadd {
1257b1144d2SAdrian Chadd 	uint32_t val;
1267b1144d2SAdrian Chadd 
1277b1144d2SAdrian Chadd 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
1287b1144d2SAdrian Chadd 
1297b1144d2SAdrian Chadd 	if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
1307b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_0_FIRPWR;
1317b1144d2SAdrian Chadd 		val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
1327b1144d2SAdrian Chadd 	}
1337b1144d2SAdrian Chadd 	if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
1347b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_0_RRSSI;
1357b1144d2SAdrian Chadd 		val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
1367b1144d2SAdrian Chadd 	}
1377b1144d2SAdrian Chadd 	if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
1387b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_0_HEIGHT;
1397b1144d2SAdrian Chadd 		val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
1407b1144d2SAdrian Chadd 	}
1417b1144d2SAdrian Chadd 	if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
1427b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_0_PRSSI;
1437b1144d2SAdrian Chadd 		val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
1447b1144d2SAdrian Chadd 	}
1457b1144d2SAdrian Chadd 	if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
1467b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_0_INBAND;
1477b1144d2SAdrian Chadd 		val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
1487b1144d2SAdrian Chadd 	}
1497b1144d2SAdrian Chadd 
1507b1144d2SAdrian Chadd 	/*Enable FFT data*/
1517b1144d2SAdrian Chadd 	val |= AR_PHY_RADAR_0_FFT_ENA;
1527b1144d2SAdrian Chadd 	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
1537b1144d2SAdrian Chadd 
1547b1144d2SAdrian Chadd 	/* Implicitly enable */
1557b1144d2SAdrian Chadd 	if (pe->pe_enabled == 1)
1567b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
1577b1144d2SAdrian Chadd 	else if (pe->pe_enabled == 0)
1587b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
1597b1144d2SAdrian Chadd 
1607b1144d2SAdrian Chadd 	if (pe->pe_usefir128 == 1)
1617b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
1627b1144d2SAdrian Chadd 	else if (pe->pe_usefir128 == 0)
1637b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
1647b1144d2SAdrian Chadd 
1657b1144d2SAdrian Chadd 	if (pe->pe_enmaxrssi == 1)
1667b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
1677b1144d2SAdrian Chadd 	else if (pe->pe_enmaxrssi == 0)
1687b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
1697b1144d2SAdrian Chadd 
1707b1144d2SAdrian Chadd 	if (pe->pe_blockradar == 1)
1717b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
1727b1144d2SAdrian Chadd 	else if (pe->pe_blockradar == 0)
1737b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
1747b1144d2SAdrian Chadd 
1757b1144d2SAdrian Chadd 	if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
1767b1144d2SAdrian Chadd 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
1777b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
1787b1144d2SAdrian Chadd 		val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
1797b1144d2SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
1807b1144d2SAdrian Chadd 	}
1817b1144d2SAdrian Chadd 	if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
1827b1144d2SAdrian Chadd 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
1837b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
1847b1144d2SAdrian Chadd 		val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
1857b1144d2SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
1867b1144d2SAdrian Chadd 	}
1877b1144d2SAdrian Chadd 
1887b1144d2SAdrian Chadd 	if (pe->pe_en_relstep_check == 1)
1897b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
1907b1144d2SAdrian Chadd 		    AR_PHY_RADAR_1_RELSTEP_CHECK);
1917b1144d2SAdrian Chadd 	else if (pe->pe_en_relstep_check == 0)
1927b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
1937b1144d2SAdrian Chadd 		    AR_PHY_RADAR_1_RELSTEP_CHECK);
1947b1144d2SAdrian Chadd 
1957b1144d2SAdrian Chadd 	if (pe->pe_enrelpwr == 1)
1967b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
1977b1144d2SAdrian Chadd 		    AR_PHY_RADAR_1_RELPWR_ENA);
1987b1144d2SAdrian Chadd 	else if (pe->pe_enrelpwr == 0)
1997b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
2007b1144d2SAdrian Chadd 		    AR_PHY_RADAR_1_RELPWR_ENA);
2017b1144d2SAdrian Chadd 
2027b1144d2SAdrian Chadd 	if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
2037b1144d2SAdrian Chadd 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
2047b1144d2SAdrian Chadd 		val &= ~AR_PHY_RADAR_1_MAXLEN;
2057b1144d2SAdrian Chadd 		val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
2067b1144d2SAdrian Chadd 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
2077b1144d2SAdrian Chadd 	}
2087b1144d2SAdrian Chadd 
2097b1144d2SAdrian Chadd 	/*
2107b1144d2SAdrian Chadd 	 * Enable HT/40 if the upper layer asks;
2117b1144d2SAdrian Chadd 	 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
2127b1144d2SAdrian Chadd 	 * is available.
2137b1144d2SAdrian Chadd 	 */
2147b1144d2SAdrian Chadd 	if (pe->pe_extchannel == 1)
2157b1144d2SAdrian Chadd 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
2167b1144d2SAdrian Chadd 	else if (pe->pe_extchannel == 0)
2177b1144d2SAdrian Chadd 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
2187b1144d2SAdrian Chadd }
2197b1144d2SAdrian Chadd 
2207b1144d2SAdrian Chadd /*
2217b1144d2SAdrian Chadd  * Extract the radar event information from the given phy error.
2227b1144d2SAdrian Chadd  *
2237b1144d2SAdrian Chadd  * Returns AH_TRUE if the phy error was actually a phy error,
2247b1144d2SAdrian Chadd  * AH_FALSE if the phy error wasn't a phy error.
2257b1144d2SAdrian Chadd  */
2267b1144d2SAdrian Chadd 
2277b1144d2SAdrian Chadd /* Flags for pulse_bw_info */
2287b1144d2SAdrian Chadd #define	PRI_CH_RADAR_FOUND		0x01
2297b1144d2SAdrian Chadd #define	EXT_CH_RADAR_FOUND		0x02
2307b1144d2SAdrian Chadd #define	EXT_CH_RADAR_EARLY_FOUND	0x04
2317b1144d2SAdrian Chadd 
2327b1144d2SAdrian Chadd HAL_BOOL
ar5416ProcessRadarEvent(struct ath_hal * ah,struct ath_rx_status * rxs,uint64_t fulltsf,const char * buf,HAL_DFS_EVENT * event)2337b1144d2SAdrian Chadd ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
2347b1144d2SAdrian Chadd     uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
2357b1144d2SAdrian Chadd {
2367b1144d2SAdrian Chadd 	HAL_BOOL doDfsExtCh;
2377b1144d2SAdrian Chadd 	HAL_BOOL doDfsEnhanced;
2387b1144d2SAdrian Chadd 	HAL_BOOL doDfsCombinedRssi;
2397b1144d2SAdrian Chadd 
2407b1144d2SAdrian Chadd 	uint8_t rssi = 0, ext_rssi = 0;
2417b1144d2SAdrian Chadd 	uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
2427b1144d2SAdrian Chadd 	uint32_t dur = 0;
2437b1144d2SAdrian Chadd 	int pri_found = 1, ext_found = 0;
2447b1144d2SAdrian Chadd 	int early_ext = 0;
2457b1144d2SAdrian Chadd 	int is_dc = 0;
2467b1144d2SAdrian Chadd 	uint16_t datalen;		/* length from the RX status field */
2477b1144d2SAdrian Chadd 
2487b1144d2SAdrian Chadd 	/* Check whether the given phy error is a radar event */
2497b1144d2SAdrian Chadd 	if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
2507b1144d2SAdrian Chadd 	    (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
2517b1144d2SAdrian Chadd 		return AH_FALSE;
2527b1144d2SAdrian Chadd 	}
2537b1144d2SAdrian Chadd 
2547b1144d2SAdrian Chadd 	/* Grab copies of the capabilities; just to make the code clearer */
2557b1144d2SAdrian Chadd 	doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
2567b1144d2SAdrian Chadd 	doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
2577b1144d2SAdrian Chadd 	doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
2587b1144d2SAdrian Chadd 
2597b1144d2SAdrian Chadd 	datalen = rxs->rs_datalen;
2607b1144d2SAdrian Chadd 
2617b1144d2SAdrian Chadd 	/* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
2627b1144d2SAdrian Chadd 	if (doDfsCombinedRssi)
2637b1144d2SAdrian Chadd 		rssi = (uint8_t) rxs->rs_rssi;
2647b1144d2SAdrian Chadd 	else
2657b1144d2SAdrian Chadd 		rssi = (uint8_t) rxs->rs_rssi_ctl[0];
2667b1144d2SAdrian Chadd 
2677b1144d2SAdrian Chadd 	/* Set this; but only use it if doDfsExtCh is set */
2687b1144d2SAdrian Chadd 	ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
2697b1144d2SAdrian Chadd 
2707b1144d2SAdrian Chadd 	/* Cap it at 0 if the RSSI is a negative number */
2717b1144d2SAdrian Chadd 	if (rssi & 0x80)
2727b1144d2SAdrian Chadd 		rssi = 0;
2737b1144d2SAdrian Chadd 
2747b1144d2SAdrian Chadd 	if (ext_rssi & 0x80)
2757b1144d2SAdrian Chadd 		ext_rssi = 0;
2767b1144d2SAdrian Chadd 
2777b1144d2SAdrian Chadd 	/*
2787b1144d2SAdrian Chadd 	 * Fetch the relevant data from the frame
2797b1144d2SAdrian Chadd 	 */
2807b1144d2SAdrian Chadd 	if (doDfsExtCh) {
2817b1144d2SAdrian Chadd 		if (datalen < 3)
2827b1144d2SAdrian Chadd 			return AH_FALSE;
2837b1144d2SAdrian Chadd 
2847b1144d2SAdrian Chadd 		/* Last three bytes of the frame are of interest */
2857b1144d2SAdrian Chadd 		pulse_length_pri = *(buf + datalen - 3);
2867b1144d2SAdrian Chadd 		pulse_length_ext = *(buf + datalen - 2);
2877b1144d2SAdrian Chadd 		pulse_bw_info = *(buf + datalen - 1);
2887b1144d2SAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
2897b1144d2SAdrian Chadd 		    " pulse_length_ext=%d, pulse_bw_info=%x\n",
2907b1144d2SAdrian Chadd 		    __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
2917b1144d2SAdrian Chadd 		    pulse_bw_info);
2927b1144d2SAdrian Chadd 	} else {
2937b1144d2SAdrian Chadd 		/* The pulse width is byte 0 of the data */
2947b1144d2SAdrian Chadd 		if (datalen >= 1)
2957b1144d2SAdrian Chadd 			dur = ((uint8_t) buf[0]) & 0xff;
2967b1144d2SAdrian Chadd 		else
2977b1144d2SAdrian Chadd 			dur = 0;
2987b1144d2SAdrian Chadd 
2997b1144d2SAdrian Chadd 		if (dur == 0 && rssi == 0) {
3007b1144d2SAdrian Chadd 			HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
3017b1144d2SAdrian Chadd 			return AH_FALSE;
3027b1144d2SAdrian Chadd 		}
3037b1144d2SAdrian Chadd 
3047b1144d2SAdrian Chadd 		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
3057b1144d2SAdrian Chadd 
3067b1144d2SAdrian Chadd 		/* Single-channel only */
3077b1144d2SAdrian Chadd 		pri_found = 1;
3087b1144d2SAdrian Chadd 		ext_found = 0;
3097b1144d2SAdrian Chadd 	}
3107b1144d2SAdrian Chadd 
3117b1144d2SAdrian Chadd 	/*
3127b1144d2SAdrian Chadd 	 * If doing extended channel data, pulse_bw_info must
3137b1144d2SAdrian Chadd 	 * have one of the flags set.
3147b1144d2SAdrian Chadd 	 */
3157b1144d2SAdrian Chadd 	if (doDfsExtCh && pulse_bw_info == 0x0)
3167b1144d2SAdrian Chadd 		return AH_FALSE;
3177b1144d2SAdrian Chadd 
3187b1144d2SAdrian Chadd 	/*
3197b1144d2SAdrian Chadd 	 * If the extended channel data is available, calculate
3207b1144d2SAdrian Chadd 	 * which to pay attention to.
3217b1144d2SAdrian Chadd 	 */
3227b1144d2SAdrian Chadd 	if (doDfsExtCh) {
3237b1144d2SAdrian Chadd 		/* If pulse is on DC, take the larger duration of the two */
3247b1144d2SAdrian Chadd 		if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
3257b1144d2SAdrian Chadd 		    (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
3267b1144d2SAdrian Chadd 			is_dc = 1;
3277b1144d2SAdrian Chadd 			if (pulse_length_ext > pulse_length_pri) {
3287b1144d2SAdrian Chadd 				dur = pulse_length_ext;
3297b1144d2SAdrian Chadd 				pri_found = 0;
3307b1144d2SAdrian Chadd 				ext_found = 1;
3317b1144d2SAdrian Chadd 			} else {
3327b1144d2SAdrian Chadd 				dur = pulse_length_pri;
3337b1144d2SAdrian Chadd 				pri_found = 1;
3347b1144d2SAdrian Chadd 				ext_found = 0;
3357b1144d2SAdrian Chadd 			}
3367b1144d2SAdrian Chadd 		} else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
3377b1144d2SAdrian Chadd 			dur = pulse_length_ext;
3387b1144d2SAdrian Chadd 			pri_found = 0;
3397b1144d2SAdrian Chadd 			ext_found = 1;
3407b1144d2SAdrian Chadd 			early_ext = 1;
3417b1144d2SAdrian Chadd 		} else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
3427b1144d2SAdrian Chadd 			dur = pulse_length_pri;
3437b1144d2SAdrian Chadd 			pri_found = 1;
3447b1144d2SAdrian Chadd 			ext_found = 0;
3457b1144d2SAdrian Chadd 		} else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
3467b1144d2SAdrian Chadd 			dur = pulse_length_ext;
3477b1144d2SAdrian Chadd 			pri_found = 0;
3487b1144d2SAdrian Chadd 			ext_found = 1;
3497b1144d2SAdrian Chadd 		}
3507b1144d2SAdrian Chadd 
3517b1144d2SAdrian Chadd 	}
3527b1144d2SAdrian Chadd 
3537b1144d2SAdrian Chadd 	/*
3547b1144d2SAdrian Chadd 	 * For enhanced DFS (Merlin and later), pulse_bw_info has
3557b1144d2SAdrian Chadd 	 * implications for selecting the correct RSSI value.
3567b1144d2SAdrian Chadd 	 */
3577b1144d2SAdrian Chadd 	if (doDfsEnhanced) {
3587b1144d2SAdrian Chadd 		switch (pulse_bw_info & 0x03) {
3597b1144d2SAdrian Chadd 		case 0:
3607b1144d2SAdrian Chadd 			/* No radar? */
3617b1144d2SAdrian Chadd 			rssi = 0;
3627b1144d2SAdrian Chadd 			break;
3637b1144d2SAdrian Chadd 		case PRI_CH_RADAR_FOUND:
3647b1144d2SAdrian Chadd 			/* Radar in primary channel */
3657b1144d2SAdrian Chadd 			/* Cannot use ctrl channel RSSI if ext channel is stronger */
3667b1144d2SAdrian Chadd 			if (ext_rssi >= (rssi + 3)) {
3677b1144d2SAdrian Chadd 				rssi = 0;
36874b8d63dSPedro F. Giffuni 			}
3697b1144d2SAdrian Chadd 			break;
3707b1144d2SAdrian Chadd 		case EXT_CH_RADAR_FOUND:
3717b1144d2SAdrian Chadd 			/* Radar in extended channel */
3727b1144d2SAdrian Chadd 			/* Cannot use ext channel RSSI if ctrl channel is stronger */
3737b1144d2SAdrian Chadd 			if (rssi >= (ext_rssi + 12)) {
3747b1144d2SAdrian Chadd 				rssi = 0;
3757b1144d2SAdrian Chadd 			} else {
3767b1144d2SAdrian Chadd 				rssi = ext_rssi;
3777b1144d2SAdrian Chadd 			}
3787b1144d2SAdrian Chadd 			break;
3797b1144d2SAdrian Chadd 		case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
3807b1144d2SAdrian Chadd 			/* When both are present, use stronger one */
3817b1144d2SAdrian Chadd 			if (rssi < ext_rssi)
3827b1144d2SAdrian Chadd 				rssi = ext_rssi;
3837b1144d2SAdrian Chadd 			break;
3847b1144d2SAdrian Chadd 		}
3857b1144d2SAdrian Chadd 	}
3867b1144d2SAdrian Chadd 
3877b1144d2SAdrian Chadd 	/*
3887b1144d2SAdrian Chadd 	 * If not doing enhanced DFS, choose the ext channel if
3897b1144d2SAdrian Chadd 	 * it is stronger than the main channel
3907b1144d2SAdrian Chadd 	 */
3917b1144d2SAdrian Chadd 	if (doDfsExtCh && !doDfsEnhanced) {
3927b1144d2SAdrian Chadd 		if ((ext_rssi > rssi) && (ext_rssi < 128))
3937b1144d2SAdrian Chadd 			rssi = ext_rssi;
3947b1144d2SAdrian Chadd 	}
3957b1144d2SAdrian Chadd 
3967b1144d2SAdrian Chadd 	/*
3977b1144d2SAdrian Chadd 	 * XXX what happens if the above code decides the RSSI
3987b1144d2SAdrian Chadd 	 * XXX wasn't valid, an sets it to 0?
3997b1144d2SAdrian Chadd 	 */
4007b1144d2SAdrian Chadd 
4017b1144d2SAdrian Chadd 	/*
4027b1144d2SAdrian Chadd 	 * Fill out dfs_event structure.
4037b1144d2SAdrian Chadd 	 */
4047b1144d2SAdrian Chadd 	event->re_full_ts = fulltsf;
4057b1144d2SAdrian Chadd 	event->re_ts = rxs->rs_tstamp;
4067b1144d2SAdrian Chadd 	event->re_rssi = rssi;
4077b1144d2SAdrian Chadd 	event->re_dur = dur;
4087b1144d2SAdrian Chadd 
4097b1144d2SAdrian Chadd 	event->re_flags = 0;
4107b1144d2SAdrian Chadd 	if (pri_found)
4117b1144d2SAdrian Chadd 		event->re_flags |= HAL_DFS_EVENT_PRICH;
4127b1144d2SAdrian Chadd 	if (ext_found)
4137b1144d2SAdrian Chadd 		event->re_flags |= HAL_DFS_EVENT_EXTCH;
4147b1144d2SAdrian Chadd 	if (early_ext)
4157b1144d2SAdrian Chadd 		event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
4167b1144d2SAdrian Chadd 	if (is_dc)
4177b1144d2SAdrian Chadd 		event->re_flags |= HAL_DFS_EVENT_ISDC;
4187b1144d2SAdrian Chadd 
4197b1144d2SAdrian Chadd 	return AH_TRUE;
4207b1144d2SAdrian Chadd }
4217b1144d2SAdrian Chadd 
4227b1144d2SAdrian Chadd /*
4237b1144d2SAdrian Chadd  * Return whether fast-clock is currently enabled for this
4247b1144d2SAdrian Chadd  * channel.
4257b1144d2SAdrian Chadd  */
4267b1144d2SAdrian Chadd HAL_BOOL
ar5416IsFastClockEnabled(struct ath_hal * ah)4277b1144d2SAdrian Chadd ar5416IsFastClockEnabled(struct ath_hal *ah)
4287b1144d2SAdrian Chadd {
4297b1144d2SAdrian Chadd 	struct ath_hal_private *ahp = AH_PRIVATE(ah);
4307b1144d2SAdrian Chadd 
4317b1144d2SAdrian Chadd 	return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
4327b1144d2SAdrian Chadd }
433