1 /*-
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2010-2011 Atheros Communications, Inc.
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * $FreeBSD$
19  */
20 #include "opt_ah.h"
21 
22 #include "ah.h"
23 #include "ah_internal.h"
24 #include "ah_devid.h"
25 #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
26 
27 #include "ar5416/ar5416.h"
28 #include "ar5416/ar5416reg.h"
29 #include "ar5416/ar5416phy.h"
30 
31 #include "ah_eeprom_v14.h"	/* for owl_get_ntxchains() */
32 
33 /*
34  * These are default parameters for the AR5416 and
35  * later 802.11n NICs.  They simply enable some
36  * radar pulse event generation.
37  *
38  * These are very likely not valid for the AR5212 era
39  * NICs.
40  *
41  * Since these define signal sizing and threshold
42  * parameters, they may need changing based on the
43  * specific antenna and receive amplifier
44  * configuration.
45  */
46 #define	AR5416_DFS_FIRPWR	-33
47 #define	AR5416_DFS_RRSSI	20
48 #define	AR5416_DFS_HEIGHT	10
49 #define	AR5416_DFS_PRSSI	15
50 #define	AR5416_DFS_INBAND	15
51 #define	AR5416_DFS_RELPWR	8
52 #define	AR5416_DFS_RELSTEP	12
53 #define	AR5416_DFS_MAXLEN	255
54 
55 HAL_BOOL
56 ar5416GetDfsDefaultThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
57 {
58 
59 	/*
60 	 * These are general examples of the parameter values
61 	 * to use when configuring radar pulse detection for
62 	 * the AR5416, AR91xx, AR92xx NICs.  They are only
63 	 * for testing and do require tuning depending upon the
64 	 * hardware and deployment specifics.
65 	 */
66 	pe->pe_firpwr = AR5416_DFS_FIRPWR;
67 	pe->pe_rrssi = AR5416_DFS_RRSSI;
68 	pe->pe_height = AR5416_DFS_HEIGHT;
69 	pe->pe_prssi = AR5416_DFS_PRSSI;
70 	pe->pe_inband = AR5416_DFS_INBAND;
71 	pe->pe_relpwr = AR5416_DFS_RELPWR;
72 	pe->pe_relstep = AR5416_DFS_RELSTEP;
73 	pe->pe_maxlen = AR5416_DFS_MAXLEN;
74 
75 	return (AH_TRUE);
76 }
77 
78 /*
79  * Get the radar parameter values and return them in the pe
80  * structure
81  */
82 void
83 ar5416GetDfsThresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
84 {
85 	uint32_t val, temp;
86 
87 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
88 
89 	temp = MS(val,AR_PHY_RADAR_0_FIRPWR);
90 	temp |= 0xFFFFFF80;
91 	pe->pe_firpwr = temp;
92 	pe->pe_rrssi = MS(val, AR_PHY_RADAR_0_RRSSI);
93 	pe->pe_height =  MS(val, AR_PHY_RADAR_0_HEIGHT);
94 	pe->pe_prssi = MS(val, AR_PHY_RADAR_0_PRSSI);
95 	pe->pe_inband = MS(val, AR_PHY_RADAR_0_INBAND);
96 
97 	/* RADAR_1 values */
98 	val = OS_REG_READ(ah, AR_PHY_RADAR_1);
99 	pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
100 	pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
101 	pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
102 
103 	pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
104 	    AR_PHY_RADAR_EXT_ENA);
105 
106 	pe->pe_usefir128 = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
107 	    AR_PHY_RADAR_1_USE_FIR128);
108 	pe->pe_blockradar = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
109 	    AR_PHY_RADAR_1_BLOCK_CHECK);
110 	pe->pe_enmaxrssi = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
111 	    AR_PHY_RADAR_1_MAX_RRSSI);
112 	pe->pe_enabled = !!
113 	    (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
114 	pe->pe_enrelpwr = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
115 	    AR_PHY_RADAR_1_RELPWR_ENA);
116 	pe->pe_en_relstep_check = !! (OS_REG_READ(ah, AR_PHY_RADAR_1) &
117 	    AR_PHY_RADAR_1_RELSTEP_CHECK);
118 }
119 
120 /*
121  * Enable radar detection and set the radar parameters per the
122  * values in pe
123  */
124 void
125 ar5416EnableDfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe)
126 {
127 	uint32_t val;
128 
129 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
130 
131 	if (pe->pe_firpwr != HAL_PHYERR_PARAM_NOVAL) {
132 		val &= ~AR_PHY_RADAR_0_FIRPWR;
133 		val |= SM(pe->pe_firpwr, AR_PHY_RADAR_0_FIRPWR);
134 	}
135 	if (pe->pe_rrssi != HAL_PHYERR_PARAM_NOVAL) {
136 		val &= ~AR_PHY_RADAR_0_RRSSI;
137 		val |= SM(pe->pe_rrssi, AR_PHY_RADAR_0_RRSSI);
138 	}
139 	if (pe->pe_height != HAL_PHYERR_PARAM_NOVAL) {
140 		val &= ~AR_PHY_RADAR_0_HEIGHT;
141 		val |= SM(pe->pe_height, AR_PHY_RADAR_0_HEIGHT);
142 	}
143 	if (pe->pe_prssi != HAL_PHYERR_PARAM_NOVAL) {
144 		val &= ~AR_PHY_RADAR_0_PRSSI;
145 		val |= SM(pe->pe_prssi, AR_PHY_RADAR_0_PRSSI);
146 	}
147 	if (pe->pe_inband != HAL_PHYERR_PARAM_NOVAL) {
148 		val &= ~AR_PHY_RADAR_0_INBAND;
149 		val |= SM(pe->pe_inband, AR_PHY_RADAR_0_INBAND);
150 	}
151 
152 	/*Enable FFT data*/
153 	val |= AR_PHY_RADAR_0_FFT_ENA;
154 	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
155 
156 	/* Implicitly enable */
157 	if (pe->pe_enabled == 1)
158 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
159 	else if (pe->pe_enabled == 0)
160 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
161 
162 	if (pe->pe_usefir128 == 1)
163 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
164 	else if (pe->pe_usefir128 == 0)
165 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
166 
167 	if (pe->pe_enmaxrssi == 1)
168 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
169 	else if (pe->pe_enmaxrssi == 0)
170 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_MAX_RRSSI);
171 
172 	if (pe->pe_blockradar == 1)
173 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
174 	else if (pe->pe_blockradar == 0)
175 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_BLOCK_CHECK);
176 
177 	if (pe->pe_relstep != HAL_PHYERR_PARAM_NOVAL) {
178 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
179 		val &= ~AR_PHY_RADAR_1_RELSTEP_THRESH;
180 		val |= SM(pe->pe_relstep, AR_PHY_RADAR_1_RELSTEP_THRESH);
181 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
182 	}
183 	if (pe->pe_relpwr != HAL_PHYERR_PARAM_NOVAL) {
184 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
185 		val &= ~AR_PHY_RADAR_1_RELPWR_THRESH;
186 		val |= SM(pe->pe_relpwr, AR_PHY_RADAR_1_RELPWR_THRESH);
187 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
188 	}
189 
190 	if (pe->pe_en_relstep_check == 1)
191 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
192 		    AR_PHY_RADAR_1_RELSTEP_CHECK);
193 	else if (pe->pe_en_relstep_check == 0)
194 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
195 		    AR_PHY_RADAR_1_RELSTEP_CHECK);
196 
197 	if (pe->pe_enrelpwr == 1)
198 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_1,
199 		    AR_PHY_RADAR_1_RELPWR_ENA);
200 	else if (pe->pe_enrelpwr == 0)
201 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1,
202 		    AR_PHY_RADAR_1_RELPWR_ENA);
203 
204 	if (pe->pe_maxlen != HAL_PHYERR_PARAM_NOVAL) {
205 		val = OS_REG_READ(ah, AR_PHY_RADAR_1);
206 		val &= ~AR_PHY_RADAR_1_MAXLEN;
207 		val |= SM(pe->pe_maxlen, AR_PHY_RADAR_1_MAXLEN);
208 		OS_REG_WRITE(ah, AR_PHY_RADAR_1, val);
209 	}
210 
211 	/*
212 	 * Enable HT/40 if the upper layer asks;
213 	 * it should check the channel is HT/40 and HAL_CAP_EXT_CHAN_DFS
214 	 * is available.
215 	 */
216 	if (pe->pe_extchannel == 1)
217 		OS_REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
218 	else if (pe->pe_extchannel == 0)
219 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
220 }
221 
222 /*
223  * Extract the radar event information from the given phy error.
224  *
225  * Returns AH_TRUE if the phy error was actually a phy error,
226  * AH_FALSE if the phy error wasn't a phy error.
227  */
228 
229 /* Flags for pulse_bw_info */
230 #define	PRI_CH_RADAR_FOUND		0x01
231 #define	EXT_CH_RADAR_FOUND		0x02
232 #define	EXT_CH_RADAR_EARLY_FOUND	0x04
233 
234 HAL_BOOL
235 ar5416ProcessRadarEvent(struct ath_hal *ah, struct ath_rx_status *rxs,
236     uint64_t fulltsf, const char *buf, HAL_DFS_EVENT *event)
237 {
238 	HAL_BOOL doDfsExtCh;
239 	HAL_BOOL doDfsEnhanced;
240 	HAL_BOOL doDfsCombinedRssi;
241 
242 	uint8_t rssi = 0, ext_rssi = 0;
243 	uint8_t pulse_bw_info = 0, pulse_length_ext = 0, pulse_length_pri = 0;
244 	uint32_t dur = 0;
245 	int pri_found = 1, ext_found = 0;
246 	int early_ext = 0;
247 	int is_dc = 0;
248 	uint16_t datalen;		/* length from the RX status field */
249 
250 	/* Check whether the given phy error is a radar event */
251 	if ((rxs->rs_phyerr != HAL_PHYERR_RADAR) &&
252 	    (rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) {
253 		return AH_FALSE;
254 	}
255 
256 	/* Grab copies of the capabilities; just to make the code clearer */
257 	doDfsExtCh = AH_PRIVATE(ah)->ah_caps.halExtChanDfsSupport;
258 	doDfsEnhanced = AH_PRIVATE(ah)->ah_caps.halEnhancedDfsSupport;
259 	doDfsCombinedRssi = AH_PRIVATE(ah)->ah_caps.halUseCombinedRadarRssi;
260 
261 	datalen = rxs->rs_datalen;
262 
263 	/* If hardware supports it, use combined RSSI, else use chain 0 RSSI */
264 	if (doDfsCombinedRssi)
265 		rssi = (uint8_t) rxs->rs_rssi;
266 	else
267 		rssi = (uint8_t) rxs->rs_rssi_ctl[0];
268 
269 	/* Set this; but only use it if doDfsExtCh is set */
270 	ext_rssi = (uint8_t) rxs->rs_rssi_ext[0];
271 
272 	/* Cap it at 0 if the RSSI is a negative number */
273 	if (rssi & 0x80)
274 		rssi = 0;
275 
276 	if (ext_rssi & 0x80)
277 		ext_rssi = 0;
278 
279 	/*
280 	 * Fetch the relevant data from the frame
281 	 */
282 	if (doDfsExtCh) {
283 		if (datalen < 3)
284 			return AH_FALSE;
285 
286 		/* Last three bytes of the frame are of interest */
287 		pulse_length_pri = *(buf + datalen - 3);
288 		pulse_length_ext = *(buf + datalen - 2);
289 		pulse_bw_info = *(buf + datalen - 1);
290 		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, ext_rssi=%d, pulse_length_pri=%d,"
291 		    " pulse_length_ext=%d, pulse_bw_info=%x\n",
292 		    __func__, rssi, ext_rssi, pulse_length_pri, pulse_length_ext,
293 		    pulse_bw_info);
294 	} else {
295 		/* The pulse width is byte 0 of the data */
296 		if (datalen >= 1)
297 			dur = ((uint8_t) buf[0]) & 0xff;
298 		else
299 			dur = 0;
300 
301 		if (dur == 0 && rssi == 0) {
302 			HALDEBUG(ah, HAL_DEBUG_DFS, "%s: dur and rssi are 0\n", __func__);
303 			return AH_FALSE;
304 		}
305 
306 		HALDEBUG(ah, HAL_DEBUG_DFS, "%s: rssi=%d, dur=%d\n", __func__, rssi, dur);
307 
308 		/* Single-channel only */
309 		pri_found = 1;
310 		ext_found = 0;
311 	}
312 
313 	/*
314 	 * If doing extended channel data, pulse_bw_info must
315 	 * have one of the flags set.
316 	 */
317 	if (doDfsExtCh && pulse_bw_info == 0x0)
318 		return AH_FALSE;
319 
320 	/*
321 	 * If the extended channel data is available, calculate
322 	 * which to pay attention to.
323 	 */
324 	if (doDfsExtCh) {
325 		/* If pulse is on DC, take the larger duration of the two */
326 		if ((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
327 		    (pulse_bw_info & PRI_CH_RADAR_FOUND)) {
328 			is_dc = 1;
329 			if (pulse_length_ext > pulse_length_pri) {
330 				dur = pulse_length_ext;
331 				pri_found = 0;
332 				ext_found = 1;
333 			} else {
334 				dur = pulse_length_pri;
335 				pri_found = 1;
336 				ext_found = 0;
337 			}
338 		} else if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
339 			dur = pulse_length_ext;
340 			pri_found = 0;
341 			ext_found = 1;
342 			early_ext = 1;
343 		} else if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
344 			dur = pulse_length_pri;
345 			pri_found = 1;
346 			ext_found = 0;
347 		} else if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
348 			dur = pulse_length_ext;
349 			pri_found = 0;
350 			ext_found = 1;
351 		}
352 
353 	}
354 
355 	/*
356 	 * For enhanced DFS (Merlin and later), pulse_bw_info has
357 	 * implications for selecting the correct RSSI value.
358 	 */
359 	if (doDfsEnhanced) {
360 		switch (pulse_bw_info & 0x03) {
361 		case 0:
362 			/* No radar? */
363 			rssi = 0;
364 			break;
365 		case PRI_CH_RADAR_FOUND:
366 			/* Radar in primary channel */
367 			/* Cannot use ctrl channel RSSI if ext channel is stronger */
368 			if (ext_rssi >= (rssi + 3)) {
369 				rssi = 0;
370 			}
371 			break;
372 		case EXT_CH_RADAR_FOUND:
373 			/* Radar in extended channel */
374 			/* Cannot use ext channel RSSI if ctrl channel is stronger */
375 			if (rssi >= (ext_rssi + 12)) {
376 				rssi = 0;
377 			} else {
378 				rssi = ext_rssi;
379 			}
380 			break;
381 		case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
382 			/* When both are present, use stronger one */
383 			if (rssi < ext_rssi)
384 				rssi = ext_rssi;
385 			break;
386 		}
387 	}
388 
389 	/*
390 	 * If not doing enhanced DFS, choose the ext channel if
391 	 * it is stronger than the main channel
392 	 */
393 	if (doDfsExtCh && !doDfsEnhanced) {
394 		if ((ext_rssi > rssi) && (ext_rssi < 128))
395 			rssi = ext_rssi;
396 	}
397 
398 	/*
399 	 * XXX what happens if the above code decides the RSSI
400 	 * XXX wasn't valid, an sets it to 0?
401 	 */
402 
403 	/*
404 	 * Fill out dfs_event structure.
405 	 */
406 	event->re_full_ts = fulltsf;
407 	event->re_ts = rxs->rs_tstamp;
408 	event->re_rssi = rssi;
409 	event->re_dur = dur;
410 
411 	event->re_flags = 0;
412 	if (pri_found)
413 		event->re_flags |= HAL_DFS_EVENT_PRICH;
414 	if (ext_found)
415 		event->re_flags |= HAL_DFS_EVENT_EXTCH;
416 	if (early_ext)
417 		event->re_flags |= HAL_DFS_EVENT_EXTEARLY;
418 	if (is_dc)
419 		event->re_flags |= HAL_DFS_EVENT_ISDC;
420 
421 	return AH_TRUE;
422 }
423 
424 /*
425  * Return whether fast-clock is currently enabled for this
426  * channel.
427  */
428 HAL_BOOL
429 ar5416IsFastClockEnabled(struct ath_hal *ah)
430 {
431 	struct ath_hal_private *ahp = AH_PRIVATE(ah);
432 
433 	return IS_5GHZ_FAST_CLOCK_EN(ah, ahp->ah_curchan);
434 }
435