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