xref: /wlan-driver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_fcc_bin5.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2013, 2016-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  * Copyright (c) 2002-2010, 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 
19 /**
20  * DOC: FCC Bin5 are special type of radars because they "chirp". Basically the
21  * pulses move across the frequency band and are called chirping pulses.
22  * dfs_check_chirping() actually examines the FFT data contained in the PHY
23  * error information to figure out whether the pulse is moving across
24  * frequencies.
25  */
26 
27 #include "../dfs.h"
28 #include "wlan_dfs_mlme_api.h"
29 #include "../dfs_channel.h"
30 
dfs_bin5_check_pulse(struct wlan_dfs * dfs,struct dfs_event * re,struct dfs_bin5radars * br)31 int dfs_bin5_check_pulse(struct wlan_dfs *dfs, struct dfs_event *re,
32 		struct dfs_bin5radars *br)
33 {
34 	int b5_rssithresh = br->br_pulse.b5_rssithresh;
35 
36 	dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_PULSE,
37 		"re_dur=%d, rssi=%d, check_chirp=%d, hw_chirp=%d, sw_chirp=%d",
38 		 (int)re->re_dur, (int)re->re_rssi,
39 		!!(re->re_flags & DFS_EVENT_CHECKCHIRP),
40 		!!(re->re_flags & DFS_EVENT_HW_CHIRP),
41 		!!(re->re_flags & DFS_EVENT_SW_CHIRP));
42 
43 	/* If the SW/HW chirp detection says to fail the pulse,do so. */
44 	if (DFS_EVENT_NOTCHIRP(re)) {
45 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
46 			"rejecting chirp: ts=%llu, dur=%d, rssi=%d checkchirp=%d, hwchirp=%d, swchirp=%d",
47 			 (unsigned long long)re->re_full_ts,
48 			(int)re->re_dur, (int)re->re_rssi,
49 			!!(re->re_flags & DFS_EVENT_CHECKCHIRP),
50 			!!(re->re_flags & DFS_EVENT_HW_CHIRP),
51 			!!(re->re_flags & DFS_EVENT_SW_CHIRP));
52 
53 		return 0;
54 	}
55 
56 	/* Adjust the filter threshold for rssi in non TURBO mode. */
57 	if (!WLAN_IS_CHAN_TURBO(dfs->dfs_curchan))
58 		b5_rssithresh += br->br_pulse.b5_rssimargin;
59 
60 	/* Check if the pulse is within duration and rssi thresholds. */
61 	if ((re->re_dur >= br->br_pulse.b5_mindur) &&
62 			(re->re_dur <= br->br_pulse.b5_maxdur) &&
63 			(re->re_rssi >= b5_rssithresh)) {
64 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
65 			"dur=%d, rssi=%d - adding!",
66 			 (int)re->re_dur, (int)re->re_rssi);
67 		return 1;
68 	}
69 
70 	dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
71 		"too low to be Bin5 pulse tsf=%llu, dur=%d, rssi=%d",
72 		 (unsigned long long)re->re_full_ts,
73 		(int)re->re_dur, (int)re->re_rssi);
74 
75 	return 0;
76 }
77 
dfs_bin5_addpulse(struct wlan_dfs * dfs,struct dfs_bin5radars * br,struct dfs_event * re,uint64_t thists)78 int dfs_bin5_addpulse(struct wlan_dfs *dfs,
79 		struct dfs_bin5radars *br,
80 		struct dfs_event *re,
81 		uint64_t thists)
82 {
83 	uint32_t index, stop;
84 	uint64_t tsDelta;
85 
86 	/*
87 	 * Check if this pulse is a valid pulse in terms of repetition,
88 	 * if not, return without adding it to the queue. PRI : Pulse
89 	 * Repitetion Interval.
90 	 * BRI : Burst Repitetion Interval.
91 	 */
92 	if (br->br_numelems != 0) {
93 		index = br->br_lastelem;
94 		tsDelta = thists - br->br_elems[index].be_ts;
95 		if ((tsDelta < DFS_BIN5_PRI_LOWER_LIMIT) ||
96 				((tsDelta > DFS_BIN5_PRI_HIGHER_LIMIT) &&
97 		 (tsDelta < DFS_BIN5_BRI_LOWER_LIMIT))) {
98 			return 0;
99 		}
100 	}
101 
102 	if (dfs->dfs_min_sidx > re->re_sidx)
103 		dfs->dfs_min_sidx = re->re_sidx;
104 
105 	if (dfs->dfs_max_sidx < re->re_sidx)
106 		dfs->dfs_max_sidx = re->re_sidx;
107 	/* Circular buffer of size 2^n. */
108 	index = (br->br_lastelem + 1) & DFS_MAX_B5_MASK;
109 	br->br_lastelem = index;
110 	if (br->br_numelems == DFS_MAX_B5_SIZE)
111 		br->br_firstelem = (br->br_firstelem + 1) & DFS_MAX_B5_MASK;
112 	else
113 		br->br_numelems++;
114 
115 	br->br_elems[index].be_ts = thists;
116 	br->br_elems[index].be_rssi = re->re_rssi;
117 	br->br_elems[index].be_dur = re->re_dur;  /* This is in u-sec */
118 	stop = 0;
119 	index = br->br_firstelem;
120 	while ((!stop) && (br->br_numelems - 1) > 0) {
121 		if ((thists - br->br_elems[index].be_ts) >
122 				((uint64_t)br->br_pulse.b5_timewindow)) {
123 			br->br_numelems--;
124 			br->br_firstelem =
125 				(br->br_firstelem + 1) & DFS_MAX_B5_MASK;
126 			index = br->br_firstelem;
127 		} else {
128 			stop = 1;
129 		}
130 	}
131 
132 	return 1;
133 }
134 
135 /**
136  * dfs_calculate_bursts_for_same_rssi() - Calculate bursts for same rssi.
137  * @dfs: Pointer to wlan_dfs structure.
138  * @br: Pointer to dfs_bin5radars structure.
139  * @bursts: Bursts.
140  * @numevents: Number of events.
141  * @prev: prev index.
142  * @this: index to br_elems[].
143  * @index: index array.
144  */
dfs_calculate_bursts_for_same_rssi(struct wlan_dfs * dfs,struct dfs_bin5radars * br,uint32_t * bursts,uint32_t * numevents,uint32_t prev,uint32_t this,int * index)145 static inline void dfs_calculate_bursts_for_same_rssi(
146 		struct wlan_dfs *dfs,
147 		struct dfs_bin5radars *br,
148 		uint32_t *bursts,
149 		uint32_t *numevents,
150 		uint32_t prev,
151 		uint32_t this,
152 		int *index)
153 {
154 	uint32_t rssi_diff;
155 
156 	if (br->br_elems[this].be_rssi >= br->br_elems[prev].be_rssi)
157 		rssi_diff = (br->br_elems[this].be_rssi -
158 				br->br_elems[prev].be_rssi);
159 	else
160 		rssi_diff = (br->br_elems[prev].be_rssi -
161 				br->br_elems[this].be_rssi);
162 
163 	if (rssi_diff <= DFS_BIN5_RSSI_MARGIN) {
164 		(*bursts)++;
165 		/*
166 		 * Save the indexes of this pair for later
167 		 * width variance check.
168 		 */
169 		if ((*numevents) >= 2) {
170 			/*
171 			 * Make sure the event is not duplicated, possible in
172 			 * a 3 pulse burst.
173 			 */
174 			if (index[(*numevents)-1] != prev)
175 				index[(*numevents)++] = prev;
176 		} else {
177 			index[(*numevents)++] = prev;
178 		}
179 
180 		index[(*numevents)++] = this;
181 	} else {
182 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
183 				"Bin5 rssi_diff=%d", rssi_diff);
184 	}
185 }
186 
bin5_rules_check_internal(struct wlan_dfs * dfs,struct dfs_bin5radars * br,uint32_t * bursts,uint32_t * numevents,uint32_t prev,uint32_t i,uint32_t this,int * index)187 void bin5_rules_check_internal(struct wlan_dfs *dfs,
188 		struct dfs_bin5radars *br,
189 		uint32_t *bursts,
190 		uint32_t *numevents,
191 		uint32_t prev,
192 		uint32_t i,
193 		uint32_t this,
194 		int *index)
195 {
196 	uint64_t pri = 0;
197 	uint32_t width_diff = 0;
198 
199 	/* Rule 1: 1000 <= PRI <= 2000 + some margin. */
200 	if (br->br_elems[this].be_ts >= br->br_elems[prev].be_ts) {
201 		pri = br->br_elems[this].be_ts - br->br_elems[prev].be_ts;
202 	} else {
203 		/* Roll over case */
204 		pri = br->br_elems[this].be_ts;
205 	}
206 	dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
207 		" pri=%llu this.ts=%llu this.dur=%d this.rssi=%d prev.ts=%llu",
208 		(uint64_t)pri,
209 		(uint64_t) br->br_elems[this].be_ts,
210 		(int) br->br_elems[this].be_dur,
211 		(int) br->br_elems[this].be_rssi,
212 		(uint64_t)br->br_elems[prev].be_ts);
213 
214 	if (((pri >= DFS_BIN5_PRI_LOWER_LIMIT) &&
215 		    /*pri: pulse repetition interval in us. */
216 		    (pri <= DFS_BIN5_PRI_HIGHER_LIMIT))) {
217 		/*
218 		 * Rule 2: pulse width of the pulses in the
219 		 * burst should be same (+/- margin).
220 		 */
221 		if (br->br_elems[this].be_dur >= br->br_elems[prev].be_dur) {
222 			width_diff = (br->br_elems[this].be_dur
223 					- br->br_elems[prev].be_dur);
224 		} else {
225 			width_diff = (br->br_elems[prev].be_dur
226 					- br->br_elems[this].be_dur);
227 		}
228 
229 		if (width_diff <= DFS_BIN5_WIDTH_MARGIN)
230 			/*
231 			 * Rule 3: RSSI of the pulses in the
232 			 * burst should be same (+/- margin)
233 			 */
234 			dfs_calculate_bursts_for_same_rssi(dfs, br, bursts,
235 					numevents, prev, this, index);
236 		 else
237 			dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
238 				"Bin5 width_diff=%d", width_diff);
239 	} else if ((pri >= DFS_BIN5_BRI_LOWER_LIMIT) &&
240 			(pri <= DFS_BIN5_BRI_UPPER_LIMIT)) {
241 		/* Check pulse width to make sure it is in range of bin 5. */
242 		(*bursts)++;
243 	} else{
244 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
245 			"Bin5 PRI check fail pri=%llu", (uint64_t)pri);
246 	}
247 }
248 
dfs_bin5_check(struct wlan_dfs * dfs)249 int dfs_bin5_check(struct wlan_dfs *dfs)
250 {
251 	struct dfs_bin5radars *br;
252 	uint32_t n = 0, i = 0, i1 = 0, this = 0, prev = 0;
253 	uint32_t bursts = 0, total_diff = 0, average_diff = 0;
254 	uint32_t total_width = 0, average_width = 0, numevents = 0;
255 	int index[DFS_MAX_B5_SIZE];
256 
257 	if (!dfs) {
258 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
259 		return 1;
260 	}
261 
262 	for (n = 0; n < dfs->dfs_rinfo.rn_numbin5radars; n++) {
263 		br = &(dfs->dfs_b5radars[n]);
264 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, "Num elems = %d",
265 				br->br_numelems);
266 
267 		/* Find a valid bin 5 pulse and use it as reference. */
268 		for (i1 = 0; i1 < br->br_numelems; i1++) {
269 			this = ((br->br_firstelem + i1) & DFS_MAX_B5_MASK);
270 			if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC)
271 				&& (br->br_elems[this].be_dur <=
272 				    MAX_BIN5_DUR_MICROSEC)) {
273 				break;
274 			}
275 		}
276 
277 		prev = this;
278 		for (i = i1 + 1; i < br->br_numelems; i++) {
279 			this = ((br->br_firstelem + i) & DFS_MAX_B5_MASK);
280 			/*
281 			 * First make sure it is a bin 5 pulse by checking
282 			 * the duration.
283 			 */
284 			if ((br->br_elems[this].be_dur < MIN_BIN5_DUR_MICROSEC)
285 				|| (br->br_elems[this].be_dur >
286 				    MAX_BIN5_DUR_MICROSEC)) {
287 				continue;
288 			}
289 			bin5_rules_check_internal(dfs, br, &bursts, &numevents,
290 					prev, i, this, index);
291 			prev = this;
292 		}
293 
294 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
295 			  "bursts=%u numevents=%u", bursts, numevents);
296 		if (bursts >= br->br_pulse.b5_threshold) {
297 			if ((br->br_elems[br->br_lastelem].be_ts -
298 					br->br_elems[br->br_firstelem].be_ts) <
299 					3000000)
300 				return 0;
301 
302 			dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
303 				  "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d",
304 				   bursts, numevents, total_width,
305 				   average_width, total_diff,
306 				   average_diff);
307 			dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
308 				  "bin 5 radar detected, bursts=%d",
309 				   bursts);
310 			return 1;
311 		}
312 	}
313 
314 	return 0;
315 }
316 
317 /**
318  * dfs_check_chirping_sowl() - Chirp detection for Sowl/Howl.
319  * @dfs: Pointer to wlan_dfs structure.
320  * @buf: Phyerr buffer.
321  * @datalen: Phyerr buf length
322  * @is_ctl: detected on primary channel.
323  * @is_ext: detected on extension channel.
324  * @slope: Slope
325  * @is_dc: DC found
326  *
327  * Return: Return TRUE if chirping pulse, FALSE if not. Decision is made
328  * based on processing the FFT data included with the PHY error.
329  * Calculate the slope using the maximum bin index reported in
330  * the FFT data. Calculate slope between FFT packet 0 and packet
331  * n-1. Also calculate slope between packet 1 and packet n. If a
332  * pulse is chirping, a slope of 5 and greater is seen.
333  * Non-chirping pulses have slopes of 0, 1, 2 or 3.
334  */
dfs_check_chirping_sowl(struct wlan_dfs * dfs,void * buf,uint16_t datalen,int is_ctl,int is_ext,int * slope,int * is_dc)335 static int dfs_check_chirping_sowl(struct wlan_dfs *dfs,
336 		void *buf,
337 		uint16_t datalen,
338 		int is_ctl,
339 		int is_ext,
340 		int *slope,
341 		int *is_dc)
342 {
343 #define FFT_LEN 70
344 #define FFT_LOWER_BIN_MAX_INDEX_BYTE 66
345 #define FFT_UPPER_BIN_MAX_INDEX_BYTE 69
346 #define MIN_CHIRPING_SLOPE 4
347 	int is_chirp = 0;
348 	int p, num_fft_packets = 0;
349 	int ctl_slope = 0, ext_slope = 0;
350 	int ctl_high0 = 0, ctl_low0 = 0, ctl_slope0 = 0;
351 	int ext_high0 = 0, ext_low0 = 0, ext_slope0 = 0;
352 	int ctl_high1 = 0, ctl_low1 = 0, ctl_slope1 = 0;
353 	int ext_high1 = 0, ext_low1 = 0, ext_slope1 = 0;
354 	uint8_t *fft_data_ptr;
355 
356 	*slope = 0;
357 	*is_dc = 0;
358 	num_fft_packets = datalen / FFT_LEN;
359 	fft_data_ptr = (uint8_t *)buf;
360 
361 	/* DEBUG - Print relevant portions of the FFT data. */
362 	for (p = 0; p < num_fft_packets; p++) {
363 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
364 			"fft_data_ptr=0x%pK\t", fft_data_ptr);
365 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
366 			"[66]=%d [69]=%d",
367 			*(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2,
368 			*(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2);
369 		fft_data_ptr += FFT_LEN;
370 	}
371 
372 	dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
373 		"datalen=%d num_fft_packets=%d", datalen, num_fft_packets);
374 
375 	/*
376 	 * There is not enough FFT data to figure out whether the pulse
377 	 * is chirping or not.
378 	 */
379 	if (num_fft_packets < 4)
380 		return 0;
381 
382 	fft_data_ptr = (uint8_t *)buf;
383 
384 	if (is_ctl) {
385 		fft_data_ptr = (uint8_t *)buf;
386 		ctl_low0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >>  2;
387 		fft_data_ptr += FFT_LEN;
388 		ctl_low1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >>  2;
389 
390 		/* Last packet with first packet. */
391 		fft_data_ptr =
392 		    (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 1));
393 		ctl_high1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2;
394 
395 		/* Second last packet with 0th packet. */
396 		fft_data_ptr =
397 		    (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 2));
398 		ctl_high0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2;
399 
400 		ctl_slope0 = ctl_high0 - ctl_low0;
401 		if (ctl_slope0 < 0)
402 			ctl_slope0 *= (-1);
403 
404 		ctl_slope1 = ctl_high1 - ctl_low1;
405 		if (ctl_slope1 < 0)
406 			ctl_slope1 *= (-1);
407 
408 		ctl_slope =
409 		    ((ctl_slope0 > ctl_slope1) ? ctl_slope0 : ctl_slope1);
410 		*slope = ctl_slope;
411 
412 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
413 			"ctl_slope0=%d ctl_slope1=%d ctl_slope=%d",
414 			ctl_slope0, ctl_slope1, ctl_slope);
415 	} else if (is_ext) {
416 		fft_data_ptr = (uint8_t *)buf;
417 		ext_low0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >>  2;
418 
419 		fft_data_ptr += FFT_LEN;
420 		ext_low1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >>  2;
421 
422 		fft_data_ptr =
423 		    (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 1));
424 		ext_high1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2;
425 		fft_data_ptr =
426 		    (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 2));
427 
428 		ext_high0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2;
429 
430 		ext_slope0 = ext_high0 - ext_low0;
431 		if (ext_slope0 < 0)
432 			ext_slope0 *= (-1);
433 
434 		ext_slope1 = ext_high1 - ext_low1;
435 		if (ext_slope1 < 0)
436 			ext_slope1 *= (-1);
437 
438 		ext_slope = ((ext_slope0 > ext_slope1) ?
439 				ext_slope0 : ext_slope1);
440 		*slope = ext_slope;
441 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT | WLAN_DEBUG_DFS_BIN5,
442 			"ext_slope0=%d ext_slope1=%d ext_slope=%d",
443 			ext_slope0, ext_slope1, ext_slope);
444 	} else
445 		return 0;
446 
447 	if ((ctl_slope >= MIN_CHIRPING_SLOPE) ||
448 			(ext_slope >= MIN_CHIRPING_SLOPE)) {
449 		is_chirp = 1;
450 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5 | WLAN_DEBUG_DFS_BIN5_FFT |
451 			WLAN_DEBUG_DFS_PHYERR_SUM, "is_chirp=%d is_dc=%d",
452 			is_chirp, *is_dc);
453 	}
454 
455 	return is_chirp;
456 
457 #undef FFT_LEN
458 #undef FFT_LOWER_BIN_MAX_INDEX_BYTE
459 #undef FFT_UPPER_BIN_MAX_INDEX_BYTE
460 #undef MIN_CHIRPING_SLOPE
461 }
462 
463 /**
464  * dfs_check_chirping_merlin() - Merlin (and Osprey, etc) chirp radar chirp
465  *                               detection.
466  * @dfs: Pointer to wlan_dfs structure.
467  * @buf: Phyerr buffer
468  * @datalen: Phyerr buf length
469  * @is_ctl: detected on primary channel.
470  * @is_ext: detected on extension channel.
471  * @slope: Slope
472  * @is_dc: DC found
473  */
dfs_check_chirping_merlin(struct wlan_dfs * dfs,void * buf,uint16_t datalen,int is_ctl,int is_ext,int * slope,int * is_dc)474 static int dfs_check_chirping_merlin(struct wlan_dfs *dfs,
475 		void *buf,
476 		uint16_t datalen,
477 		int is_ctl,
478 		int is_ext,
479 		int *slope,
480 		int *is_dc)
481 {
482 #define ABS_DIFF(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : \
483 		(int)_y - (int)_x)
484 #define ABS(_x) ((int)_x > 0 ? (int)_x : -(int)_x)
485 	/* This should be between 1 and 3. Default is 1. */
486 #define DELTA_STEP 1
487 	/* Number of Diffs to compute. valid range is 2-4. */
488 #define NUM_DIFFS  3
489 	/* Threshold for difference of delta peaks. */
490 #define MAX_DIFF   2
491 	/* Max. number of strong bins for narrow band. */
492 #define BIN_COUNT_MAX 6
493 
494 	/* Dynamic 20/40 mode FFT packet format related definition. */
495 #define NUM_FFT_BYTES_HT40      70
496 #define NUM_BIN_BYTES_HT40      64
497 #define NUM_SUBCHAN_BINS_HT40   64
498 #define LOWER_INDEX_BYTE_HT40   66
499 #define UPPER_INDEX_BYTE_HT40   69
500 #define LOWER_WEIGHT_BYTE_HT40  64
501 #define UPPER_WEIGHT_BYTE_HT40  67
502 #define LOWER_MAG_BYTE_HT40     65
503 #define UPPER_MAG_BYTE_HT40     68
504 
505 	/* Static 20 mode FFT packet format related definition. */
506 #define NUM_FFT_BYTES_HT20      31
507 #define NUM_BIN_BYTES_HT20      28
508 #define NUM_SUBCHAN_BINS_HT20   56
509 #define LOWER_INDEX_BYTE_HT20   30
510 #define UPPER_INDEX_BYTE_HT20   30
511 #define LOWER_WEIGHT_BYTE_HT20  28
512 #define UPPER_WEIGHT_BYTE_HT20  28
513 #define LOWER_MAG_BYTE_HT20     29
514 #define UPPER_MAG_BYTE_HT20     29
515 
516 	int num_fft_packets; /* number of FFT packets reported to software */
517 	int num_fft_bytes;
518 	int num_bin_bytes;
519 	int num_subchan_bins;
520 	int lower_index_byte;
521 	int upper_index_byte;
522 	int lower_weight_byte;
523 	int upper_weight_byte;
524 	int lower_mag_byte;
525 	int upper_mag_byte;
526 	int max_index_lower[DELTA_STEP + NUM_DIFFS];
527 	int max_index_upper[DELTA_STEP + NUM_DIFFS];
528 	int max_mag_lower[DELTA_STEP + NUM_DIFFS];
529 	int max_mag_upper[DELTA_STEP + NUM_DIFFS];
530 	int bin_wt_lower[DELTA_STEP + NUM_DIFFS];
531 	int bin_wt_upper[DELTA_STEP + NUM_DIFFS];
532 	int max_mag_sel[DELTA_STEP + NUM_DIFFS];
533 	int max_mag[DELTA_STEP + NUM_DIFFS];
534 	int max_index[DELTA_STEP + NUM_DIFFS];
535 	int max_d[] = {10, 19, 28};
536 	int min_d[] = {1, 2, 3};
537 	uint8_t *ptr; /* pointer to FFT data */
538 	int i;
539 	int fft_start;
540 	int chirp_found;
541 	int delta_peak[NUM_DIFFS];
542 	int j;
543 	int bin_count;
544 	int bw_mask;
545 	int delta_diff;
546 	int same_sign;
547 	int temp;
548 
549 	if (WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan)) {
550 		num_fft_bytes = NUM_FFT_BYTES_HT40;
551 		num_bin_bytes = NUM_BIN_BYTES_HT40;
552 		num_subchan_bins = NUM_SUBCHAN_BINS_HT40;
553 		lower_index_byte = LOWER_INDEX_BYTE_HT40;
554 		upper_index_byte = UPPER_INDEX_BYTE_HT40;
555 		lower_weight_byte = LOWER_WEIGHT_BYTE_HT40;
556 		upper_weight_byte = UPPER_WEIGHT_BYTE_HT40;
557 		lower_mag_byte = LOWER_MAG_BYTE_HT40;
558 		upper_mag_byte = UPPER_MAG_BYTE_HT40;
559 
560 		/* If we are in HT40MINUS then swap primary and extension. */
561 		if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan)) {
562 			temp = is_ctl;
563 			is_ctl = is_ext;
564 			is_ext = temp;
565 		}
566 	} else {
567 		num_fft_bytes = NUM_FFT_BYTES_HT20;
568 		num_bin_bytes = NUM_BIN_BYTES_HT20;
569 		num_subchan_bins = NUM_SUBCHAN_BINS_HT20;
570 		lower_index_byte = LOWER_INDEX_BYTE_HT20;
571 		upper_index_byte = UPPER_INDEX_BYTE_HT20;
572 		lower_weight_byte = LOWER_WEIGHT_BYTE_HT20;
573 		upper_weight_byte = UPPER_WEIGHT_BYTE_HT20;
574 		lower_mag_byte = LOWER_MAG_BYTE_HT20;
575 		upper_mag_byte = UPPER_MAG_BYTE_HT20;
576 	}
577 
578 	ptr = (uint8_t *)buf;
579 	/* Sanity check for FFT buffer. */
580 	if (!ptr || (datalen == 0)) {
581 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
582 			"FFT buffer pointer is null or size is 0");
583 		return 0;
584 	}
585 
586 	num_fft_packets = (datalen - 3) / num_fft_bytes;
587 	if (num_fft_packets < (NUM_DIFFS + DELTA_STEP)) {
588 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
589 			"datalen = %d, num_fft_packets = %d, too few packets... (exiting)",
590 			datalen, num_fft_packets);
591 		return 0;
592 	}
593 
594 	if ((((datalen - 3) % num_fft_bytes) == 2) &&
595 			(datalen > num_fft_bytes)) {
596 		ptr += 2;
597 		datalen -= 2;
598 	}
599 
600 	for (i = 0; i < (NUM_DIFFS + DELTA_STEP); i++) {
601 		fft_start = i * num_fft_bytes;
602 		bin_wt_lower[i] = ptr[fft_start + lower_weight_byte] & 0x3f;
603 		bin_wt_upper[i] = ptr[fft_start + upper_weight_byte] & 0x3f;
604 		max_index_lower[i] = ptr[fft_start + lower_index_byte] >> 2;
605 		max_index_upper[i] = (ptr[fft_start + upper_index_byte] >> 2) +
606 			num_subchan_bins;
607 
608 		if (!WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan)) {
609 			/* For HT20 mode indices are 6 bit signed number. */
610 			max_index_lower[i] ^= 0x20;
611 			max_index_upper[i] = 0;
612 		}
613 
614 		/*
615 		 * Reconstruct the maximum magnitude for each sub-channel.
616 		 * Also select and flag the max overall magnitude between
617 		 * the two sub-channels.
618 		 */
619 
620 		max_mag_lower[i] =
621 		    ((ptr[fft_start + lower_index_byte] & 0x03) << 8) +
622 			ptr[fft_start + lower_mag_byte];
623 		max_mag_upper[i] =
624 		    ((ptr[fft_start + upper_index_byte] & 0x03) << 8) +
625 			ptr[fft_start + upper_mag_byte];
626 		bw_mask = ((bin_wt_lower[i] == 0) ? 0 : is_ctl) +
627 			(((bin_wt_upper[i] == 0) ? 0 : is_ext) << 1);
628 
629 		/*
630 		 * Limit the max bin based on channel bandwidth
631 		 * If the upper sub-channel max index is stuck at '1',
632 		 * the signal is dominated * by residual DC
633 		 * (or carrier leak) and should be ignored.
634 		 */
635 
636 		if (bw_mask == 1) {
637 			max_mag_sel[i] = 0;
638 			max_mag[i] = max_mag_lower[i];
639 			max_index[i] = max_index_lower[i];
640 		} else if (bw_mask == 2) {
641 			max_mag_sel[i] = 1;
642 			max_mag[i] = max_mag_upper[i];
643 			max_index[i] = max_index_upper[i];
644 		} else if (max_index_upper[i] == num_subchan_bins) {
645 			max_mag_sel[i] = 0;  /* Ignore DC bin. */
646 			max_mag[i] = max_mag_lower[i];
647 			max_index[i] = max_index_lower[i];
648 		} else {
649 			if (max_mag_upper[i] > max_mag_lower[i]) {
650 				max_mag_sel[i] = 1;
651 				max_mag[i] = max_mag_upper[i];
652 				max_index[i] = max_index_upper[i];
653 			} else {
654 				max_mag_sel[i] = 0;
655 				max_mag[i] = max_mag_lower[i];
656 				max_index[i] = max_index_lower[i];
657 			}
658 		}
659 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
660 			"i=%d, max_index[i]=%d, max_index_lower[i]=%d, max_index_upper[i]=%d",
661 			i, max_index[i], max_index_lower[i],
662 			max_index_upper[i]);
663 	}
664 
665 	chirp_found = 1;
666 	delta_diff = 0;
667 	same_sign = 1;
668 
669 	/*
670 	 * delta_diff computation -- look for movement in peak.
671 	 * make sure that the chirp direction (i.e. sign) is
672 	 * always the same, i.e. sign of the two peaks should
673 	 * be same.
674 	 */
675 	for (i = 0; i < NUM_DIFFS; i++) {
676 		delta_peak[i] = max_index[i + DELTA_STEP] - max_index[i];
677 		if (i > 0) {
678 			delta_diff = delta_peak[i] - delta_peak[i-1];
679 			same_sign = !((delta_peak[i] & 0x80) ^
680 				(delta_peak[i-1] & 0x80));
681 		}
682 		chirp_found &=
683 			(ABS(delta_peak[i]) >= min_d[DELTA_STEP - 1]) &&
684 			(ABS(delta_peak[i]) <= max_d[DELTA_STEP - 1]) &&
685 			same_sign && (ABS(delta_diff) <= MAX_DIFF);
686 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
687 			"i=%d, delta_peak[i]=%d, delta_diff=%d",
688 			i, delta_peak[i], delta_diff);
689 	}
690 
691 	if (chirp_found) {
692 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
693 			"CHIRPING_BEFORE_STRONGBIN_YES");
694 	} else {
695 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
696 			"CHIRPING_BEFORE_STRONGBIN_NO");
697 	}
698 
699 	/*
700 	 * Work around for potential hardware data corruption bug.
701 	 * Check for wide band signal by counting strong bins
702 	 * indicated by bitmap flags. This check is done if
703 	 * chirp_found is true. We do this as a final check to
704 	 * weed out corrupt FFTs bytes. This looks expensive but
705 	 * in most cases it will exit early.
706 	 */
707 
708 	for (i = 0; (i < (NUM_DIFFS + DELTA_STEP)) &&
709 			(chirp_found == 1); i++) {
710 		bin_count = 0;
711 		/*
712 		 * Point to the start of the 1st byte of the selected
713 		 * sub-channel.
714 		 */
715 		fft_start = (i * num_fft_bytes) + (max_mag_sel[i] ?
716 				(num_subchan_bins >> 1) : 0);
717 		for (j = 0; j < (num_subchan_bins >> 1); j++) {
718 			/*
719 			 * If either bin is flagged "strong", accumulate
720 			 * the bin_count. It's not accurate, but good
721 			 * enough...
722 			 */
723 			bin_count += (ptr[fft_start + j] & 0x88) ? 1 : 0;
724 		}
725 		chirp_found &= (bin_count > BIN_COUNT_MAX) ? 0 : 1;
726 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
727 			"i=%d, computed bin_count=%d",
728 			i, bin_count);
729 	}
730 
731 	if (chirp_found) {
732 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT |
733 			WLAN_DEBUG_DFS_PHYERR_SUM,
734 			"CHIRPING_YES");
735 	} else {
736 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT |
737 			WLAN_DEBUG_DFS_PHYERR_SUM,
738 			"CHIRPING_NO");
739 	}
740 
741 	return chirp_found;
742 #undef ABS_DIFF
743 #undef ABS
744 #undef DELTA_STEP
745 #undef NUM_DIFFS
746 #undef MAX_DIFF
747 #undef BIN_COUNT_MAX
748 
749 #undef NUM_FFT_BYTES_HT40
750 #undef NUM_BIN_BYTES_HT40
751 #undef NUM_SUBCHAN_BINS_HT40
752 #undef LOWER_INDEX_BYTE_HT40
753 #undef UPPER_INDEX_BYTE_HT40
754 #undef LOWER_WEIGHT_BYTE_HT40
755 #undef UPPER_WEIGHT_BYTE_HT40
756 #undef LOWER_MAG_BYTE_HT40
757 #undef UPPER_MAG_BYTE_HT40
758 
759 #undef NUM_FFT_BYTES_HT40
760 #undef NUM_BIN_BYTES_HT40
761 #undef NUM_SUBCHAN_BINS_HT40
762 #undef LOWER_INDEX_BYTE_HT40
763 #undef UPPER_INDEX_BYTE_HT40
764 #undef LOWER_WEIGHT_BYTE_HT40
765 #undef UPPER_WEIGHT_BYTE_HT40
766 #undef LOWER_MAG_BYTE_HT40
767 #undef UPPER_MAG_BYTE_HT40
768 }
769 
dfs_check_chirping(struct wlan_dfs * dfs,void * buf,uint16_t datalen,int is_ctl,int is_ext,int * slope,int * is_dc)770 int dfs_check_chirping(struct wlan_dfs *dfs,
771 		void *buf,
772 		uint16_t datalen,
773 		int is_ctl,
774 		int is_ext,
775 		int *slope,
776 		int *is_dc)
777 {
778 	if (dfs->dfs_caps.wlan_dfs_use_enhancement) {
779 		return dfs_check_chirping_merlin(dfs, buf, datalen, is_ctl,
780 			is_ext, slope, is_dc);
781 	} else {
782 		return dfs_check_chirping_sowl(dfs, buf, datalen, is_ctl,
783 			is_ext, slope, is_dc);
784 	}
785 }
786 
dfs_retain_bin5_burst_pattern(struct wlan_dfs * dfs,uint32_t diff_ts,uint8_t old_dur)787 uint8_t dfs_retain_bin5_burst_pattern(struct wlan_dfs *dfs,
788 		uint32_t diff_ts,
789 		uint8_t old_dur)
790 {
791 	/*
792 	 * Pulses may get split into 2 during chirping, this print
793 	 * is only to show that it happened, we do not handle this
794 	 * condition if we cannot detect the chirping.
795 	 */
796 	/* SPLIT pulses will have a time stamp difference of < 50 */
797 	if (diff_ts < 50) {
798 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
799 			"SPLIT pulse diffTs=%u dur=%d (old_dur=%d)",
800 			 diff_ts,
801 			dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur);
802 	}
803 
804 	/*
805 	 * Check if this is the 2nd or 3rd pulse in the same burst,
806 	 * PRI will be between 1000 and 2000 us.
807 	 */
808 	if (((diff_ts >= DFS_BIN5_PRI_LOWER_LIMIT) &&
809 				(diff_ts <= DFS_BIN5_PRI_HIGHER_LIMIT))) {
810 		/*
811 		 * This pulse belongs to the same burst as the pulse before,
812 		 * so return the same random duration for it.
813 		 */
814 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
815 			"this pulse belongs to the same burst as before, give it same dur=%d (old_dur=%d)",
816 			 dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur);
817 		return dfs->dfs_rinfo.dfs_last_bin5_dur;
818 	}
819 
820 	/* This pulse does not belong to this burst, return unchanged duration*/
821 	return old_dur;
822 }
823 
dfs_get_random_bin5_dur(struct wlan_dfs * dfs,uint64_t tstamp)824 int dfs_get_random_bin5_dur(struct wlan_dfs *dfs,
825 		uint64_t tstamp)
826 {
827 	uint8_t new_dur = MIN_BIN5_DUR;
828 	int range;
829 
830 	get_random_bytes(&new_dur, sizeof(uint8_t));
831 	range = (MAX_BIN5_DUR - MIN_BIN5_DUR + 1);
832 	new_dur %= range;
833 	new_dur += MIN_BIN5_DUR;
834 
835 	return new_dur;
836 }
837