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