xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_bindetects.c (revision bea437e2293c3d4fb1b5704fcf633aedac996962)
1 /*
2  * Copyright (c) 2016-2019 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: DFS specs specify various types of radars to be detected.
20  * Each separate type is called a Bin and has different characteristics.
21  * This file contains the functionality to look at a group of pulses and
22  * to detect whether we have detected a valid radar waveform. To do that,
23  * it must match the group against each different Bin's characteristics.
24  */
25 
26 #include "../dfs.h"
27 #include "../dfs_process_radar_found_ind.h"
28 
29 /**
30  * dfs_find_first_index_within_window() - Find first index within window
31  * @pl: Pointer to dfs_pulseline structure.
32  * @index: Index to dfs pulse elements.
33  * @start_ts: Start timestamp.
34  *
35  * Return: Returns index.
36  */
37 static inline uint32_t dfs_find_first_index_within_window(
38 		struct dfs_pulseline *pl,
39 		uint32_t index,
40 		uint64_t start_ts)
41 {
42 	uint16_t i;
43 
44 	/* Find the index of first element in our window of interest. */
45 	for (i = 0; i < pl->pl_numelems; i++) {
46 		index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK;
47 		if (pl->pl_elems[index].p_time >= start_ts) {
48 			continue;
49 		} else {
50 			index = (index) & DFS_MAX_PULSE_BUFFER_MASK;
51 			break;
52 		}
53 	}
54 
55 	return index;
56 }
57 
58 /**
59  * dfs_ts_within_window() - Calculate pulses for timestamp within window
60  * @dfs: Pointer to wlan_dfs structure.
61  * @pl: Pointer to dfs_pulseline structure.
62  * @index: Index to dfs pulse elements.
63  * @dur: Pulse duration/width
64  * @numpulses: Number of pulses
65  *
66  * Return: Returns 1 if pulse count is incremented else returns 0.
67  */
68 static inline bool dfs_ts_within_window(
69 		struct wlan_dfs *dfs,
70 		struct dfs_pulseline *pl,
71 		uint32_t *index,
72 		uint32_t dur,
73 		int *numpulses)
74 {
75 	uint32_t deltadur;
76 
77 	deltadur = DFS_DIFF(pl->pl_elems[*index].p_dur, dur);
78 	if ((pl->pl_elems[*index].p_dur == 1) ||
79 			((dur != 1) && (deltadur <= 2))) {
80 		(*numpulses)++;
81 		dfs_debug(dfs, WLAN_DEBUG_DFS2, "numpulses %u", *numpulses);
82 		return 1;
83 	}
84 
85 	return 0;
86 }
87 
88 /**
89  * dfs_ts_eq_prevts() - Calculate pulses for timestamp equals to prev event
90  * @dfs: Pointer to wlan_dfs structure.
91  * @pl: Pointer to dfs_pulseline structure.
92  * @index: Index to dfs pulse elements.
93  * @dur: Pulse duration/width
94  * @numpulses: Number of pulses
95  *
96  * Return: Returns 1 if pulse count is incremented else returns 0.
97  */
98 static inline bool dfs_ts_eq_prevts(
99 		struct wlan_dfs *dfs,
100 		struct dfs_pulseline *pl,
101 		uint64_t next_event_ts,
102 		uint64_t event_ts,
103 		uint32_t refpri,
104 		uint32_t *index,
105 		uint32_t dur,
106 		int *numpulses)
107 
108 {
109 	uint32_t deltadur;
110 
111 	if (((next_event_ts - event_ts) > refpri) ||
112 			((next_event_ts - event_ts) == 0)) {
113 		deltadur = DFS_DIFF(pl->pl_elems[*index].p_dur, dur);
114 		if ((pl->pl_elems[*index].p_dur == 1) ||
115 				((pl->pl_elems[*index].p_dur != 1) &&
116 				 (deltadur <= 2))) {
117 			(*numpulses)++;
118 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
119 					"zero PRI: numpulses %u", *numpulses);
120 			return 1;
121 		}
122 	}
123 
124 	return 0;
125 }
126 
127 /**
128  * dfs_pulses_within_window() - Calculate pulses within window
129  * @dfs: Pointer to wlan_dfs structure.
130  * @window_start: Start of the window.
131  * @window_end: End of the window.
132  * @index: Index to dfs pulse elements.
133  * @dur: Pulse duration/width.
134  * @refpri: reference PRI.
135  *
136  * Return: Returns 1 if pulse count is incremented else returns 0.
137  */
138 static inline int dfs_pulses_within_window(
139 		struct wlan_dfs *dfs,
140 		uint64_t window_start,
141 		uint64_t window_end,
142 		uint32_t *index,
143 		uint32_t dur,
144 		uint32_t refpri)
145 {
146 	int numpulses = 0;
147 	uint32_t i;
148 	struct dfs_pulseline *pl = dfs->pulses;
149 	uint64_t event_ts, prev_event_ts, next_event_ts;
150 	uint32_t next_index;
151 
152 	for (i = 0; i < pl->pl_numelems; i++) {
153 		prev_event_ts = pl->pl_elems[*index].p_time;
154 		*index = (*index+1) & DFS_MAX_PULSE_BUFFER_MASK;
155 		event_ts = pl->pl_elems[*index].p_time;
156 		next_index = (*index+1) & DFS_MAX_PULSE_BUFFER_MASK;
157 		next_event_ts = pl->pl_elems[next_index].p_time;
158 		dfs_debug(dfs, WLAN_DEBUG_DFS2, "ts %u",
159 				(uint32_t)event_ts);
160 
161 		if ((event_ts <= window_end) && (event_ts >= window_start)) {
162 			if (dfs_ts_within_window(dfs, pl, index, dur,
163 					&numpulses))
164 				break;
165 		} else if (event_ts > window_end) {
166 			*index = (*index-1) & DFS_MAX_PULSE_BUFFER_MASK;
167 			break;
168 		} else if (event_ts == prev_event_ts) {
169 			if (dfs_ts_eq_prevts(dfs, pl, next_event_ts, event_ts,
170 					refpri, index, dur, &numpulses))
171 				break;
172 		}
173 		if (dfs->dfs_min_sidx > pl->pl_elems[*index].p_sidx)
174 			dfs->dfs_min_sidx = pl->pl_elems[*index].p_sidx;
175 
176 		if (dfs->dfs_max_sidx < pl->pl_elems[*index].p_sidx)
177 			dfs->dfs_max_sidx = pl->pl_elems[*index].p_sidx;
178 	}
179 
180 	dfs->dfs_freq_offset =
181 		DFS_SIDX_TO_FREQ_OFFSET((dfs->dfs_min_sidx +
182 					 dfs->dfs_min_sidx) / 2);
183 	return numpulses;
184 }
185 
186 /**
187  * dfs_count_pulses() - Count pulses
188  * @dfs: Pointer to wlan_dfs structure.
189  * @rf:  Pointer to dfs_filter structure.
190  * @dur: Pulse duration/width.
191  * @ext_chan_flag : Ext channel flag.
192  * @primargin: Primary margin.
193  * @index: Index to dfs pulse elements.
194  * @refpri: reference PRI.
195  * @start_ts: Start timestamp.
196  *
197  * Return: Returns number of pulses within window.
198  */
199 static inline int dfs_count_pulses(
200 		struct wlan_dfs *dfs,
201 		struct dfs_filter *rf,
202 		uint32_t dur,
203 		int ext_chan_flag,
204 		int primargin,
205 		uint32_t index,
206 		uint32_t refpri,
207 		uint64_t start_ts)
208 {
209 	uint32_t n;
210 	int numpulses = 0;
211 	uint64_t window_start, window_end;
212 
213 	for (n = 0; n <= rf->rf_numpulses; n++) {
214 		window_start = (start_ts + (refpri*n))-(primargin+n);
215 		window_end = window_start + 2*(primargin+n);
216 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
217 				"window_start %u window_end %u",
218 				(uint32_t)window_start, (uint32_t)window_end);
219 		numpulses += dfs_pulses_within_window(dfs, window_start,
220 				window_end, &index, dur, refpri);
221 	}
222 
223 	return numpulses;
224 }
225 
226 /**
227  * dfs_bin_fixedpattern_check() - Fixed pattern check
228  * @dfs: Pointer to wlan_dfs structure.
229  * @rf:  Pointer to dfs_filter structure.
230  * @dur: Pulse duration/width.
231  * @ext_chan_flag : Ext channel flag.
232  */
233 static int  dfs_bin_fixedpattern_check(
234 		struct wlan_dfs *dfs,
235 		struct dfs_filter *rf,
236 		uint32_t dur,
237 		int ext_chan_flag)
238 {
239 	struct dfs_pulseline *pl = dfs->pulses;
240 	int primargin, numpulses, fil_thresh;
241 	uint64_t start_ts, end_ts;
242 	uint32_t last_index, first_index;
243 	uint32_t refpri;
244 
245 	refpri = (rf->rf_minpri + rf->rf_maxpri)/2;
246 	last_index = pl->pl_lastelem;
247 	end_ts = pl->pl_elems[last_index].p_time;
248 	start_ts = end_ts - (refpri*rf->rf_numpulses);
249 
250 	dfs_debug(dfs, WLAN_DEBUG_DFS3,
251 		"lastelem ts=%llu start_ts=%llu, end_ts=%llu",
252 		(unsigned long long)pl->pl_elems[last_index].p_time,
253 		(unsigned long long)start_ts,
254 		(unsigned long long) end_ts);
255 
256 	first_index = dfs_find_first_index_within_window(pl, last_index,
257 			start_ts);
258 
259 	/* For fixed pattern types, rf->rf_patterntype=1. */
260 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
261 			(rf->rf_patterntype == 1));
262 
263 	numpulses = dfs_count_pulses(dfs, rf, dur, ext_chan_flag, primargin,
264 			first_index, refpri, start_ts);
265 
266 	fil_thresh = dfs_get_filter_threshold(dfs, rf, ext_chan_flag);
267 
268 	if (numpulses >= fil_thresh) {
269 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
270 			"FOUND filterID=%u numpulses=%d unadj thresh=%d",
271 			 rf->rf_pulseid, numpulses, rf->rf_threshold);
272 		return 1;
273 	} else {
274 		return 0;
275 	}
276 }
277 
278 void dfs_add_pulse(
279 		struct wlan_dfs *dfs,
280 		struct dfs_filter *rf,
281 		struct dfs_event *re,
282 		uint32_t deltaT,
283 		uint64_t this_ts)
284 {
285 	uint32_t index, n, window;
286 	struct dfs_delayline *dl;
287 
288 	dl = &rf->rf_dl;
289 	/* Circular buffer of size 2^n */
290 	index = (dl->dl_lastelem + 1) & DFS_MAX_DL_MASK;
291 	if ((dl->dl_numelems) == DFS_MAX_DL_SIZE)
292 		dl->dl_firstelem = (dl->dl_firstelem + 1) & DFS_MAX_DL_MASK;
293 	else
294 		dl->dl_numelems++;
295 	dl->dl_lastelem = index;
296 	dl->dl_elems[index].de_time = deltaT;
297 	dl->dl_elems[index].de_ts = this_ts;
298 	window = deltaT;
299 	dl->dl_elems[index].de_dur = re->re_dur;
300 	dl->dl_elems[index].de_rssi = re->re_rssi;
301 	dl->dl_elems[index].de_seg_id = re->re_seg_id;
302 	dl->dl_elems[index].de_sidx = re->re_sidx;
303 	dl->dl_elems[index].de_delta_peak = re->re_delta_peak;
304 	dl->dl_elems[index].de_psidx_diff = re->re_psidx_diff;
305 	dl->dl_elems[index].de_seq_num = dfs->dfs_seq_num;
306 
307 	dfs_debug(dfs, WLAN_DEBUG_DFS2,
308 		"adding: filter id %d, dur=%d, rssi=%d, ts=%llu",
309 		 rf->rf_pulseid, re->re_dur,
310 		re->re_rssi, (unsigned long long int)this_ts);
311 
312 	for (n = 0; n < dl->dl_numelems-1; n++) {
313 		index = (index-1) & DFS_MAX_DL_MASK;
314 		/*
315 		 * Calculate window based on full time stamp instead of deltaT
316 		 * deltaT (de_time) may result in incorrect window value
317 		 */
318 		window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts);
319 
320 		if (window > rf->rf_filterlen) {
321 			dl->dl_firstelem = (index+1) & DFS_MAX_DL_MASK;
322 			dl->dl_numelems = n+1;
323 		}
324 	}
325 
326 	dfs_debug(dfs, WLAN_DEBUG_DFS2, "dl firstElem = %d  lastElem = %d",
327 			dl->dl_firstelem, dl->dl_lastelem);
328 }
329 
330 /**
331  * dfs_find_lowestpri() - Find lowest PRI
332  * @dl: Pointer to dfs delayline.
333  * @lowpriindex: Low PRI index.
334  * @lowpri: Low PRI
335  */
336 static inline void dfs_find_lowestpri(
337 	struct dfs_delayline *dl,
338 	uint32_t *lowpriindex,
339 	uint32_t *lowpri)
340 {
341 	int delayindex;
342 	uint32_t refpri;
343 	uint32_t n;
344 
345 	/* Find out the lowest pri. */
346 	for (n = 0; n < dl->dl_numelems; n++) {
347 		delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
348 		refpri = dl->dl_elems[delayindex].de_time;
349 		if (refpri == 0) {
350 			continue;
351 		} else if (refpri < *lowpri) {
352 			*lowpri = dl->dl_elems[delayindex].de_time;
353 			*lowpriindex = n;
354 		}
355 	}
356 }
357 
358 /**
359  * dfs_calculate_score() - Calculate score for the score index
360  * if PRI match is found
361  * @dl: Pointer to dfs delayline.
362  * @rf: Pointer to dfs_filter structure.
363  * @score: score array.
364  * @refpri: reference PRI.
365  * @primargin: PRI margin.
366  * @score_index: Score index.
367  */
368 static inline void dfs_calculate_score(
369 	struct dfs_delayline *dl,
370 	struct dfs_filter *rf,
371 	int *score,
372 	uint32_t refpri,
373 	uint32_t primargin,
374 	uint32_t score_index)
375 {
376 	int pri_match = 0;
377 	int dindex;
378 	uint32_t searchpri, deltapri, deltapri_2, deltapri_3;
379 	uint32_t i;
380 
381 	for (i = 0; i < dl->dl_numelems; i++) {
382 		dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
383 		searchpri = dl->dl_elems[dindex].de_time;
384 		deltapri = DFS_DIFF(searchpri, refpri);
385 		deltapri_2 = DFS_DIFF(searchpri, 2*refpri);
386 		deltapri_3 = DFS_DIFF(searchpri, 3*refpri);
387 		if (rf->rf_ignore_pri_window == 2)
388 			pri_match = ((deltapri < primargin) ||
389 					(deltapri_2 < primargin) ||
390 					(deltapri_3 < primargin));
391 		else
392 			pri_match = (deltapri < primargin);
393 
394 		if (pri_match)
395 			score[score_index]++;
396 	}
397 }
398 
399 /**
400  * dfs_find_priscores() - Find PRI score
401  * @dl: Pointer to dfs delayline.
402  * @rf: Pointer to dfs_filter structure.
403  * @score: score array.
404  * @primargin: PRI margin.
405  */
406 static void dfs_find_priscores(
407 	struct dfs_delayline *dl,
408 	struct dfs_filter *rf,
409 	int *score,
410 	uint32_t primargin)
411 {
412 	int delayindex;
413 	uint32_t refpri;
414 	uint32_t n;
415 
416 	qdf_mem_zero(score, sizeof(int)*DFS_MAX_DL_SIZE);
417 
418 	for (n = 0; n < dl->dl_numelems; n++) {
419 		delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
420 		refpri = dl->dl_elems[delayindex].de_time;
421 		if (refpri == 0)
422 			continue;
423 		if (refpri < rf->rf_maxpri) {
424 			/* Use only valid PRI range for high score. */
425 			dfs_calculate_score(dl, rf, score, refpri, primargin,
426 				n);
427 		} else {
428 			score[n] = 0;
429 		}
430 
431 		if (score[n] > rf->rf_threshold) {
432 			/*
433 			 * We got the most possible candidate,
434 			 * no need to continue further.
435 			 */
436 			break;
437 		}
438 	}
439 }
440 
441 /**
442  * dfs_find_highscore() - Find PRI high score
443  * @dl: Pointer to dfs delayline.
444  * @score: score array.
445  * @highscore: High score.
446  * @highscoreindex: High score index.
447  */
448 static inline void dfs_find_highscore(
449 		struct dfs_delayline *dl,
450 		int *score,
451 		uint32_t *highscore,
452 		uint32_t *highscoreindex)
453 {
454 	int delayindex, dindex;
455 	uint32_t n;
456 
457 	*highscore = 0;
458 	*highscoreindex = 0;
459 
460 	for (n = 0; n < dl->dl_numelems; n++) {
461 		if (score[n] > *highscore) {
462 			*highscore = score[n];
463 			*highscoreindex = n;
464 		} else if (score[n] == *highscore) {
465 			/*
466 			 * More than one pri has highscore take the least pri.
467 			 */
468 			delayindex = (dl->dl_firstelem + *highscoreindex) &
469 				DFS_MAX_DL_MASK;
470 			dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
471 			if (dl->dl_elems[dindex].de_time <=
472 					dl->dl_elems[delayindex].de_time) {
473 				*highscoreindex = n;
474 			}
475 		}
476 	}
477 
478 	return;
479 }
480 
481 /**
482  * dfs_get_durmargin() - Find duration margin
483  * @rf: Pointer to dfs_filter structure.
484  * @durmargin: Duration margin
485  */
486 static inline void dfs_get_durmargin(
487 		struct dfs_filter *rf,
488 		uint32_t *durmargin)
489 {
490 #define DUR_THRESH 10
491 #define LOW_MARGIN 4
492 #define HIGH_MARGIN 6
493 
494 	if (rf->rf_maxdur < DUR_THRESH)
495 		*durmargin = LOW_MARGIN;
496 	else
497 		*durmargin = HIGH_MARGIN;
498 
499 #undef DUR_THRESH
500 #undef LOW_MARGIN
501 #undef HIGH_MARGIN
502 }
503 
504 /**
505  * dfs_handle_fixedpattern() - Handle Fixed pattern radar
506  * @dfs: Pointer to wlan_dfs structure.
507  * @dl: Pointer to dfs delayline.
508  * @rf: Pointer to dfs_filter structure.
509  * @dur: Pulse duration/width
510  * @ext_chan_flag : Ext channel flag.
511  */
512 static inline int dfs_handle_fixedpattern(
513 		struct wlan_dfs *dfs,
514 		struct dfs_delayline *dl,
515 		struct dfs_filter *rf,
516 		uint32_t dur,
517 		int ext_chan_flag)
518 {
519 	int found = 0;
520 
521 	found = dfs_bin_fixedpattern_check(dfs, rf, dur, ext_chan_flag);
522 	if (found)
523 		dl->dl_numelems = 0;
524 
525 	return found;
526 }
527 
528 /**
529  * dfs_bin_basic_sanity() - Sanity check
530  * @dl: Pointer to dfs delayline.
531  * @rf: Pointer to dfs_filter structure.
532  * @deltaT: Delta time.
533  */
534 static inline int dfs_bin_basic_sanity(
535 		struct dfs_delayline *dl,
536 		struct dfs_filter *rf,
537 		uint32_t *deltaT)
538 {
539 	if (dl->dl_numelems < (rf->rf_threshold-1))
540 		return 0;
541 
542 	if (*deltaT > rf->rf_filterlen)
543 		return 0;
544 
545 	return 1;
546 }
547 
548 /**
549  * dfs_pick_lowpri() - Pick lowpri as refpri
550  * @dfs: Pointer to wlan_dfs structure.
551  * @dl: Pointer to dfs delayline.
552  * @rf: Pointer to dfs_filter structure.
553  * @lowpriindex: Low PRI index.
554  * @scoreindex: score index.
555  * @primargin: PRI margin.
556  */
557 #ifdef DFS_PRI_MULTIPLIER
558 static inline void dfs_pick_lowpri(struct wlan_dfs *dfs,
559 				   struct dfs_delayline *dl,
560 				   struct dfs_filter *rf,
561 				   uint32_t lowpriindex,
562 				   uint32_t *scoreindex,
563 				   uint32_t primargin)
564 {
565 	uint32_t candidate_refpri, deltapri, lowpri;
566 	uint32_t dindex_candidate, dindex_lowpri;
567 	uint32_t i;
568 
569 	dindex_candidate = (dl->dl_firstelem + *scoreindex) & DFS_MAX_DL_MASK;
570 	dindex_lowpri = (dl->dl_firstelem + lowpriindex) & DFS_MAX_DL_MASK;
571 
572 	candidate_refpri = dl->dl_elems[dindex_candidate].de_time;
573 	lowpri = dl->dl_elems[dindex_lowpri].de_time;
574 
575 	if (rf->rf_ignore_pri_window == 0 &&
576 	    candidate_refpri != lowpri) {
577 		for (i = 1; i <= dfs->dfs_pri_multiplier; i++) {
578 			deltapri = DFS_DIFF(candidate_refpri, i * lowpri);
579 			if (deltapri < primargin) {
580 				*scoreindex = lowpriindex;
581 				break;
582 			}
583 		}
584 	}
585 }
586 #else
587 static inline void dfs_pick_lowpri(struct wlan_dfs *dfs,
588 				   struct dfs_delayline *dl,
589 				   struct dfs_filter *rf,
590 				   uint32_t lowpriindex,
591 				   uint32_t *scoreindex,
592 				   uint32_t primargin)
593 {
594 }
595 #endif
596 
597 /**
598  * dfs_find_scoreindex() - Find score index
599  * @rf: Pointer to dfs_filter structure.
600  * @highscore: High score.
601  * @lowpriindex: Low PRI index.
602  * @highscoreindex: High score index.
603  * @scoreindex: score index.
604  */
605 static inline void dfs_find_scoreindex(
606 		struct dfs_filter *rf,
607 		uint32_t highscore,
608 		uint32_t lowpriindex,
609 		uint32_t highscoreindex,
610 		uint32_t *scoreindex)
611 {
612 	int lowprichk = 3;
613 
614 	if (rf->rf_ignore_pri_window > 0)
615 		lowprichk = (rf->rf_threshold >> 1)+1;
616 	else
617 		lowprichk = 3;
618 
619 	if (highscore < lowprichk)
620 		*scoreindex = lowpriindex;
621 	else
622 		*scoreindex = highscoreindex;
623 }
624 
625 /**
626  * dfs_find_refs() - Find reference values.
627  * @dl: Pointer to dfs delayline.
628  * @rf: Pointer to dfs_filter structure.
629  * @scoreindex: score index.
630  * @refdur: Duration value.
631  * @refpri: Current "filter" time for start of pulse in usecs.
632  */
633 static inline void dfs_find_refs(
634 		struct dfs_delayline *dl,
635 		struct dfs_filter *rf,
636 		uint32_t scoreindex,
637 		uint32_t *refdur,
638 		uint32_t *refpri)
639 {
640 	int delayindex;
641 
642 	delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK;
643 	*refdur = dl->dl_elems[delayindex].de_dur;
644 	*refpri = dl->dl_elems[delayindex].de_time;
645 
646 	if (rf->rf_fixed_pri_radar_pulse)
647 		*refpri = (rf->rf_minpri + rf->rf_maxpri)/2;
648 }
649 
650 /**
651  * dfs_bin_success_print() - Debug print
652  * @dfs: Pointer to wlan_dfs structure.
653  * @rf: Pointer to dfs_filter structure.
654  * @ext_chan_flag: Extension channel flag.
655  * @numpulses: Number of pulses.
656  * @refpri: Current "filter" time for start of pulse in usecs.
657  * @refdur: Duration value.
658  * @primargin: PRI margin.
659  */
660 static inline void dfs_bin_success_print(
661 		struct wlan_dfs *dfs,
662 		struct dfs_filter *rf,
663 		int ext_chan_flag,
664 		int numpulses,
665 		uint32_t refpri,
666 		uint32_t refdur,
667 		uint32_t primargin)
668 {
669 	dfs_debug(dfs, WLAN_DEBUG_DFS1,
670 			"ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d",
671 			ext_chan_flag, rf->rf_pulseid, numpulses,
672 			rf->rf_threshold, refdur, refpri, primargin);
673 	dfs_print_delayline(dfs, &rf->rf_dl);
674 	dfs_print_filter(dfs, rf);
675 }
676 
677 int dfs_bin_check(
678 		struct wlan_dfs *dfs,
679 		struct dfs_filter *rf,
680 		uint32_t deltaT,
681 		uint32_t width,
682 		int ext_chan_flag)
683 {
684 	struct dfs_delayline *dl;
685 	uint32_t refpri, refdur;
686 	uint32_t highscoreindex;
687 	uint32_t primargin, highscore;
688 	int score[DFS_MAX_DL_SIZE], found = 0;
689 	uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff;
690 	int numpulses = 0;
691 	int fil_thresh;
692 
693 	dl = &rf->rf_dl;
694 	if (!dfs_bin_basic_sanity(dl, rf, &deltaT))
695 		return 0;
696 
697 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
698 			(rf->rf_patterntype == 1));
699 
700 
701 	if (rf->rf_patterntype == 1)
702 		return dfs_handle_fixedpattern(dfs, dl, rf, width,
703 				ext_chan_flag);
704 
705 	dfs_find_lowestpri(dl, &lowpriindex, &lowpri);
706 
707 	/* Find out the each delay element's pri score. */
708 	dfs_find_priscores(dl, rf, score, primargin);
709 
710 	/* Find out the high scorer. */
711 	dfs_find_highscore(dl, score, &highscore, &highscoreindex);
712 
713 	/*
714 	 * Find the average pri of pulses around the pri of highscore
715 	 * or the pulses around the lowest pri.
716 	 */
717 	dfs_find_scoreindex(rf, highscore, lowpriindex, highscoreindex,
718 			&scoreindex);
719 
720 	/*
721 	 * Observed ETSI type2 while channel loading 31% with pulse pri:
722 	 * 1489, 2978, 2978, 2978, 1489, 2978, 1489 us. With above logic,
723 	 * the highscore will be 4 (2978), scoreindex is 5. In this case,
724 	 * index 0, 4, 6 pulses will be not matched later in
725 	 * dfs_count_the_other_delay_elements(), which leads to the radar was
726 	 * not detected. The fix is: compare the highscore pri with lowpri,
727 	 * if they have relationship, within primargin of
728 	 * [1, dfs_pri_multiplier] times of lowpri, choose lowpri as refpri.
729 	 */
730 	dfs_pick_lowpri(dfs, dl, rf, lowpriindex, &scoreindex, primargin);
731 
732 	/* We got the possible pri, save its parameters as reference. */
733 	dfs_find_refs(dl, rf, scoreindex, &refdur, &refpri);
734 
735 	numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri,
736 			refdur, ext_chan_flag, refpri);
737 
738 	fil_thresh = dfs_get_filter_threshold(dfs, rf, ext_chan_flag);
739 
740 	if (numpulses >= fil_thresh) {
741 		found = 1;
742 		dfs_bin_success_print(dfs, rf, ext_chan_flag, numpulses,
743 				refpri, refdur, primargin);
744 	}
745 
746 	return found;
747 }
748 
749 /**
750  * dfs_update_min_and_max_sidx() - Calculate min and max sidx.
751  * @dl: Pointer to dfs_delayline structure.
752  * @delayindex: Delay index.
753  * @sidx_min: Sidx min.
754  * @sidx_max: Sidx max.
755  * @delta_peak_match_count: Delta peak match count.
756  * @psidx_diff_match_count: Psidx diff match count.
757  * @rf: Pointer to dfs_filter structure.
758  */
759 static inline void dfs_update_min_and_max_sidx(
760 		struct dfs_delayline *dl,
761 		int delayindex,
762 		int32_t *sidx_min,
763 		int32_t *sidx_max,
764 		uint8_t *delta_peak_match_count,
765 		uint8_t *psidx_diff_match_count,
766 		struct dfs_filter *rf)
767 {
768 	/* update sidx min/max for false detection check later */
769 	if (*sidx_min > dl->dl_elems[delayindex].de_sidx)
770 		*sidx_min = dl->dl_elems[delayindex].de_sidx;
771 
772 	if (*sidx_max < dl->dl_elems[delayindex].de_sidx)
773 		*sidx_max = dl->dl_elems[delayindex].de_sidx;
774 
775 	if (rf->rf_check_delta_peak) {
776 		if (dl->dl_elems[delayindex].de_delta_peak != 0)
777 			(*delta_peak_match_count)++;
778 		else if ((dl->dl_elems[delayindex].de_psidx_diff >=
779 				DFS_MIN_PSIDX_DIFF) &&
780 			(dl->dl_elems[delayindex].de_psidx_diff <=
781 				DFS_MAX_PSIDX_DIFF))
782 			(*psidx_diff_match_count)++;
783 	}
784 }
785 
786 /**
787  * dfs_check_pulses_for_delta_variance() - Check pulses for delta variance.
788  * @rf: Pointer to dfs_filter structure.
789  * @numpulsetochk: Number of pulses to check.
790  * @delta_time_stamps: Delta time stamp.
791  * @fundamentalpri: Highest PRI.
792  * @primargin: Primary margin.
793  * @numpulses: Number of pulses.
794  * @delayindex: Delay index.
795  * @sidx_min: Sidx min.
796  * @sidx_max: Sidx max.
797  * @delta_peak_match_count: Delta peak match count.
798  * @psidx_diff_match_count: Psidx diff match count.
799  * @dl: Pointer to dfs_delayline structure.
800  */
801 static inline void dfs_check_pulses_for_delta_variance(
802 		struct dfs_filter *rf,
803 		int numpulsetochk,
804 		uint32_t delta_time_stamps,
805 		int fundamentalpri,
806 		uint32_t primargin,
807 		int *numpulses,
808 		int delayindex,
809 		int32_t *sidx_min,
810 		int32_t *sidx_max,
811 		uint8_t *delta_peak_match_count,
812 		uint8_t *psidx_diff_match_count,
813 		struct dfs_delayline *dl)
814 {
815 	uint32_t delta_ts_variance, j;
816 
817 	for (j = 0; j < numpulsetochk; j++) {
818 		delta_ts_variance = DFS_DIFF(delta_time_stamps,
819 				((j + 1) * fundamentalpri));
820 		if (delta_ts_variance < (2 * (j + 1) * primargin)) {
821 			dl->dl_seq_num_stop =
822 				dl->dl_elems[delayindex].de_seq_num;
823 			dfs_update_min_and_max_sidx(dl, delayindex,
824 					sidx_min, sidx_max,
825 					delta_peak_match_count,
826 					psidx_diff_match_count,
827 					rf);
828 			(*numpulses)++;
829 			if (rf->rf_ignore_pri_window > 0)
830 				break;
831 		}
832 	}
833 }
834 
835 /**
836  * dfs_count_the_other_delay_elements() - Counts the ther delay elements.
837  * @dfs: Pointer to wlan_dfs structure.
838  * @rf: Pointer to dfs_filter structure.
839  * @dl: Pointer to dfs_delayline structure.
840  * @i: Index value.
841  * @refpri: Current "filter" time for start of pulse in usecs.
842  * @refdur: Duration value.
843  * @primargin: Primary margin.
844  * @durmargin: Duration margin.
845  * @numpulses: Number of pulses.
846  * @delta_peak_match_count: Pointer to delta_peak_match_count.
847  * @psidx_diff_match_count: Pointer to psidx_diff_match_count.
848  * @prev_good_timestamp: Previous good timestamp.
849  * @fundamentalpri: Highest PRI.
850  */
851 static void dfs_count_the_other_delay_elements(
852 		struct wlan_dfs *dfs,
853 		struct dfs_filter *rf,
854 		struct dfs_delayline *dl,
855 		uint32_t i,
856 		uint32_t refpri,
857 		uint32_t refdur,
858 		uint32_t primargin,
859 		uint32_t durmargin,
860 		int *numpulses,
861 		uint8_t *delta_peak_match_count,
862 		uint8_t *psidx_diff_match_count,
863 		uint32_t *prev_good_timestamp,
864 		int fundamentalpri)
865 {
866 	int delayindex;
867 	uint32_t searchpri, searchdur, deltadur;
868 	uint32_t j = 0, delta_time_stamps, deltapri, k;
869 	int dindex, primatch, numpulsetochk = 2;
870 	int32_t sidx_min = DFS_BIG_SIDX;
871 	int32_t sidx_max = -DFS_BIG_SIDX;
872 
873 	delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
874 	searchpri = dl->dl_elems[delayindex].de_time;
875 	if (searchpri == 0) {
876 		/*
877 		 * This events PRI is zero, take it as a valid pulse
878 		 * but decrement next event's PRI by refpri.
879 		 */
880 		dindex = (delayindex + 1) & DFS_MAX_DL_MASK;
881 		dl->dl_elems[dindex].de_time -=  refpri;
882 		searchpri = refpri;
883 	}
884 
885 	searchdur = dl->dl_elems[delayindex].de_dur;
886 	deltadur = DFS_DIFF(searchdur, refdur);
887 	deltapri = DFS_DIFF(searchpri, refpri);
888 	primatch = 0;
889 
890 	if ((rf->rf_ignore_pri_window > 0) && (rf->rf_patterntype != 2)) {
891 		for (j = 0; j < rf->rf_numpulses; j++) {
892 			deltapri = DFS_DIFF(searchpri, (j + 1) * refpri);
893 			if (deltapri < (2 * primargin)) {
894 				primatch = 1;
895 				break;
896 			}
897 		}
898 	} else if (rf->rf_patterntype == 2) {
899 		primatch = 1;
900 	} else {
901 		for (k = 1; k <= dfs->dfs_pri_multiplier; k++) {
902 			deltapri = DFS_DIFF(searchpri, k * refpri);
903 			if (deltapri < primargin) {
904 				primatch = 1;
905 				break;
906 			}
907 		}
908 	}
909 
910 	if (primatch && (deltadur < durmargin)) {
911 		if (*numpulses == 1) {
912 			dl->dl_seq_num_second =
913 				dl->dl_elems[delayindex].de_seq_num;
914 			dfs_update_min_and_max_sidx(dl, delayindex,
915 					&sidx_min, &sidx_max,
916 					delta_peak_match_count,
917 					psidx_diff_match_count,
918 					rf);
919 			(*numpulses)++;
920 		} else {
921 			delta_time_stamps = (dl->dl_elems[delayindex].de_ts -
922 				*prev_good_timestamp);
923 			if ((rf->rf_ignore_pri_window > 0)) {
924 				numpulsetochk = rf->rf_numpulses;
925 				if ((rf->rf_patterntype == 2) &&
926 					(fundamentalpri < refpri + 100)) {
927 					numpulsetochk = 4;
928 				}
929 			} else {
930 				numpulsetochk = 4;
931 			}
932 
933 			dfs_check_pulses_for_delta_variance(rf, numpulsetochk,
934 					delta_time_stamps, fundamentalpri,
935 					primargin, numpulses, delayindex,
936 					&sidx_min, &sidx_max,
937 					delta_peak_match_count,
938 					psidx_diff_match_count,
939 					dl);
940 		}
941 		*prev_good_timestamp = dl->dl_elems[delayindex].de_ts;
942 		dl->dl_search_pri = searchpri;
943 		dl->dl_min_sidx = sidx_min;
944 		dl->dl_max_sidx = sidx_max;
945 		dl->dl_delta_peak_match_count = *delta_peak_match_count;
946 		dl->dl_psidx_diff_match_count = *psidx_diff_match_count;
947 
948 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
949 			"rf->minpri=%d rf->maxpri=%d searchpri = %d index = %d numpulses = %d delta peak match count = %d psidx diff match count = %d deltapri=%d j=%d",
950 			rf->rf_minpri, rf->rf_maxpri, searchpri, i,
951 			*numpulses, *delta_peak_match_count,
952 			*psidx_diff_match_count, deltapri, j);
953 	}
954 }
955 
956 int dfs_bin_pri_check(
957 		struct wlan_dfs *dfs,
958 		struct dfs_filter *rf,
959 		struct dfs_delayline *dl,
960 		uint32_t score,
961 		uint32_t refpri,
962 		uint32_t refdur,
963 		int ext_chan_flag,
964 		int fundamentalpri)
965 {
966 	uint32_t searchpri, deltapri = 0;
967 	uint32_t averagerefpri = 0, MatchCount = 0;
968 	uint32_t prev_good_timestamp = 0;
969 	int dindex;
970 	uint32_t i, primargin, durmargin, highscore = score;
971 	uint32_t highscoreindex = 0;
972 	/*
973 	 * First pulse in the burst is most likely being filtered out based on
974 	 * maxfilterlen.
975 	 */
976 	int numpulses = 1;
977 	uint8_t delta_peak_match_count = 1;
978 	uint8_t psidx_diff_match_count = 1;
979 	int priscorechk = 1;
980 
981 	/* Use the adjusted PRI margin to reduce false alarms
982 	 * For non fixed pattern types, rf->rf_patterntype=0.
983 	 */
984 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
985 			(rf->rf_patterntype == 1));
986 
987 	if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) {
988 		numpulses = 0;
989 		return numpulses;
990 	}
991 
992 	dfs_get_durmargin(rf, &durmargin);
993 
994 	if ((!rf->rf_fixed_pri_radar_pulse)) {
995 		if (rf->rf_ignore_pri_window == 1)
996 			priscorechk = (rf->rf_threshold >> 1);
997 		else
998 			priscorechk = 1;
999 
1000 		MatchCount = 0;
1001 		if (score > priscorechk) {
1002 			for (i = 0; i < dl->dl_numelems; i++) {
1003 				dindex = (dl->dl_firstelem + i) &
1004 					DFS_MAX_DL_MASK;
1005 				searchpri = dl->dl_elems[dindex].de_time;
1006 				deltapri = DFS_DIFF(searchpri, refpri);
1007 				if (deltapri < primargin) {
1008 					averagerefpri += searchpri;
1009 					MatchCount++;
1010 				}
1011 			}
1012 			if (rf->rf_patterntype != 2) {
1013 				if (MatchCount > 0)
1014 					refpri = (averagerefpri / MatchCount);
1015 			} else {
1016 				refpri = (averagerefpri / score);
1017 			}
1018 		}
1019 	}
1020 
1021 	/* Note: Following primultiple calculation should be done
1022 	 * once per filter during initialization stage (dfs_attach)
1023 	 * and stored in its array atleast for fixed frequency
1024 	 * types like FCC Bin1 to save some CPU cycles.
1025 	 * multiplication, devide operators in the following code
1026 	 * are left as it is for readability hoping the complier
1027 	 * will use left/right shifts wherever possible.
1028 	 */
1029 	dfs_debug(dfs, WLAN_DEBUG_DFS2,
1030 		"refpri = %d high score = %d index = %d numpulses = %d",
1031 		refpri, highscore, highscoreindex, numpulses);
1032 	/*
1033 	 * Count the other delay elements that have pri and dur with
1034 	 * in the acceptable range from the reference one.
1035 	 */
1036 	for (i = 0; i < dl->dl_numelems; i++)
1037 		dfs_count_the_other_delay_elements(dfs, rf, dl, i, refpri,
1038 				refdur, primargin, durmargin, &numpulses,
1039 				&delta_peak_match_count,
1040 				&psidx_diff_match_count,
1041 				&prev_good_timestamp, fundamentalpri);
1042 
1043 	return numpulses;
1044 }
1045