xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_bindetects.c (revision 92d87f51612f6c3b2285266215edee8911647c2f)
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_psidx_diff = re->re_psidx_diff;
296 	dl->dl_elems[index].de_seq_num = dfs->dfs_seq_num;
297 
298 	dfs_debug(dfs, WLAN_DEBUG_DFS2,
299 		"adding: filter id %d, dur=%d, rssi=%d, ts=%llu",
300 		 rf->rf_pulseid, re->re_dur,
301 		re->re_rssi, (unsigned long long int)this_ts);
302 
303 	for (n = 0; n < dl->dl_numelems-1; n++) {
304 		index = (index-1) & DFS_MAX_DL_MASK;
305 		/*
306 		 * Calculate window based on full time stamp instead of deltaT
307 		 * deltaT (de_time) may result in incorrect window value
308 		 */
309 		window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts);
310 
311 		if (window > rf->rf_filterlen) {
312 			dl->dl_firstelem = (index+1) & DFS_MAX_DL_MASK;
313 			dl->dl_numelems = n+1;
314 		}
315 	}
316 	dfs_debug(dfs, WLAN_DEBUG_DFS2, "dl firstElem = %d  lastElem = %d",
317 			dl->dl_firstelem, dl->dl_lastelem);
318 }
319 
320 /**
321  * dfs_find_lowestpri() - Find lowest PRI
322  * @dl: Pointer to dfs delayline.
323  * @lowpriindex: Low PRI index.
324  * @lowpri: Low PRI
325  */
326 static inline void dfs_find_lowestpri(
327 	struct dfs_delayline *dl,
328 	uint32_t *lowpriindex,
329 	uint32_t *lowpri)
330 {
331 	int delayindex;
332 	uint32_t refpri;
333 	uint32_t n;
334 
335 	/* Find out the lowest pri. */
336 	for (n = 0; n < dl->dl_numelems; n++) {
337 		delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
338 		refpri = dl->dl_elems[delayindex].de_time;
339 		if (refpri == 0) {
340 			continue;
341 		} else if (refpri < *lowpri) {
342 			*lowpri = dl->dl_elems[delayindex].de_time;
343 			*lowpriindex = n;
344 		}
345 	}
346 }
347 
348 /**
349  * dfs_calculate_score() - Calculate score for the score index
350  * if PRI match is found
351  * @dl: Pointer to dfs delayline.
352  * @rf: Pointer to dfs_filter structure.
353  * @score: score array.
354  * @refpri: reference PRI.
355  * @primargin: PRI margin.
356  * @score_index: Score index.
357  */
358 static inline void dfs_calculate_score(
359 	struct dfs_delayline *dl,
360 	struct dfs_filter *rf,
361 	int *score,
362 	uint32_t refpri,
363 	uint32_t primargin,
364 	uint32_t score_index)
365 {
366 	int pri_match = 0;
367 	int dindex;
368 	uint32_t searchpri, deltapri, deltapri_2, deltapri_3;
369 	uint32_t i;
370 
371 	for (i = 0; i < dl->dl_numelems; i++) {
372 		dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
373 		searchpri = dl->dl_elems[dindex].de_time;
374 		deltapri = DFS_DIFF(searchpri, refpri);
375 		deltapri_2 = DFS_DIFF(searchpri, 2*refpri);
376 		deltapri_3 = DFS_DIFF(searchpri, 3*refpri);
377 		if (rf->rf_ignore_pri_window == 2)
378 			pri_match = ((deltapri < primargin) ||
379 					(deltapri_2 < primargin) ||
380 					(deltapri_3 < primargin));
381 		else
382 			pri_match = (deltapri < primargin);
383 
384 		if (pri_match)
385 			score[score_index]++;
386 	}
387 }
388 
389 /**
390  * dfs_find_priscores() - Find PRI score
391  * @dl: Pointer to dfs delayline.
392  * @rf: Pointer to dfs_filter structure.
393  * @score: score array.
394  * @primargin: PRI margin.
395  */
396 static void dfs_find_priscores(
397 	struct dfs_delayline *dl,
398 	struct dfs_filter *rf,
399 	int *score,
400 	uint32_t primargin)
401 {
402 	int delayindex;
403 	uint32_t refpri;
404 	uint32_t n;
405 
406 	qdf_mem_zero(score, sizeof(int)*DFS_MAX_DL_SIZE);
407 
408 	for (n = 0; n < dl->dl_numelems; n++) {
409 		delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
410 		refpri = dl->dl_elems[delayindex].de_time;
411 		if (refpri == 0)
412 			continue;
413 		if (refpri < rf->rf_maxpri) {
414 			/* Use only valid PRI range for high score. */
415 			dfs_calculate_score(dl, rf, score, refpri, primargin,
416 				n);
417 		} else {
418 			score[n] = 0;
419 		}
420 
421 		if (score[n] > rf->rf_threshold) {
422 			/*
423 			 * We got the most possible candidate,
424 			 * no need to continue further.
425 			 */
426 			break;
427 		}
428 	}
429 }
430 
431 /**
432  * dfs_find_highscore() - Find PRI high score
433  * @dl: Pointer to dfs delayline.
434  * @score: score array.
435  * @highscore: High score.
436  * @highscoreindex: High score index.
437  */
438 static inline void dfs_find_highscore(
439 		struct dfs_delayline *dl,
440 		int *score,
441 		uint32_t *highscore,
442 		uint32_t *highscoreindex)
443 {
444 	int delayindex, dindex;
445 	uint32_t n;
446 
447 	*highscore = 0;
448 	*highscoreindex = 0;
449 
450 	for (n = 0; n < dl->dl_numelems; n++) {
451 		if (score[n] > *highscore) {
452 			*highscore = score[n];
453 			*highscoreindex = n;
454 		} else if (score[n] == *highscore) {
455 			/*
456 			 * More than one pri has highscore take the least pri.
457 			 */
458 			delayindex = (dl->dl_firstelem + *highscoreindex) &
459 				DFS_MAX_DL_MASK;
460 			dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
461 			if (dl->dl_elems[dindex].de_time <=
462 					dl->dl_elems[delayindex].de_time) {
463 				*highscoreindex = n;
464 			}
465 		}
466 	}
467 
468 	return;
469 }
470 
471 /**
472  * dfs_get_durmargin() - Find duration margin
473  * @rf: Pointer to dfs_filter structure.
474  * @durmargin: Duration margin
475  */
476 static inline void dfs_get_durmargin(
477 		struct dfs_filter *rf,
478 		uint32_t *durmargin)
479 {
480 #define DUR_THRESH 10
481 #define LOW_MARGIN 4
482 #define HIGH_MARGIN 6
483 
484 	if (rf->rf_maxdur < DUR_THRESH)
485 		*durmargin = LOW_MARGIN;
486 	else
487 		*durmargin = HIGH_MARGIN;
488 
489 #undef DUR_THRESH
490 #undef LOW_MARGIN
491 #undef HIGH_MARGIN
492 }
493 
494 /**
495  * dfs_handle_fixedpattern() - Handle Fixed pattern radar
496  * @dfs: Pointer to wlan_dfs structure.
497  * @dl: Pointer to dfs delayline.
498  * @rf: Pointer to dfs_filter structure.
499  * @dur: Pulse duration/width
500  * @ext_chan_flag : Ext channel flag.
501  */
502 static inline int dfs_handle_fixedpattern(
503 		struct wlan_dfs *dfs,
504 		struct dfs_delayline *dl,
505 		struct dfs_filter *rf,
506 		uint32_t dur,
507 		int ext_chan_flag)
508 {
509 	int found = 0;
510 
511 	found = dfs_bin_fixedpattern_check(dfs, rf, dur, ext_chan_flag);
512 	if (found)
513 		dl->dl_numelems = 0;
514 
515 	return found;
516 }
517 
518 /**
519  * dfs_bin_basic_sanity() - Sanity check
520  * @dl: Pointer to dfs delayline.
521  * @rf: Pointer to dfs_filter structure.
522  * @deltaT: Delta time.
523  */
524 static inline int dfs_bin_basic_sanity(
525 		struct dfs_delayline *dl,
526 		struct dfs_filter *rf,
527 		uint32_t *deltaT)
528 {
529 	if (dl->dl_numelems < (rf->rf_threshold-1))
530 		return 0;
531 
532 	if (*deltaT > rf->rf_filterlen)
533 		return 0;
534 
535 	return 1;
536 }
537 
538 /**
539  * dfs_find_scoreindex() - Find score index
540  * @rf: Pointer to dfs_filter structure.
541  * @highscore: High score.
542  * @lowpriindex: Low PRI index.
543  * @highscoreindex: High score index.
544  * @scoreindex: score index.
545  */
546 static inline void dfs_find_scoreindex(
547 		struct dfs_filter *rf,
548 		uint32_t highscore,
549 		uint32_t lowpriindex,
550 		uint32_t highscoreindex,
551 		uint32_t *scoreindex)
552 {
553 	int lowprichk = 3;
554 
555 	if (rf->rf_ignore_pri_window > 0)
556 		lowprichk = (rf->rf_threshold >> 1)+1;
557 	else
558 		lowprichk = 3;
559 
560 	if (highscore < lowprichk)
561 		*scoreindex = lowpriindex;
562 	else
563 		*scoreindex = highscoreindex;
564 }
565 
566 /**
567  * dfs_find_refs() - Find reference values.
568  * @dl: Pointer to dfs delayline.
569  * @rf: Pointer to dfs_filter structure.
570  * @scoreindex: score index.
571  * @refdur: Duration value.
572  * @refpri: Current "filter" time for start of pulse in usecs.
573  */
574 static inline void dfs_find_refs(
575 		struct dfs_delayline *dl,
576 		struct dfs_filter *rf,
577 		uint32_t scoreindex,
578 		uint32_t *refdur,
579 		uint32_t *refpri)
580 {
581 	int delayindex;
582 
583 	delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK;
584 	*refdur = dl->dl_elems[delayindex].de_dur;
585 	*refpri = dl->dl_elems[delayindex].de_time;
586 
587 	if (rf->rf_fixed_pri_radar_pulse)
588 		*refpri = (rf->rf_minpri + rf->rf_maxpri)/2;
589 }
590 
591 /**
592  * dfs_bin_success_print() - Debug print
593  * @dfs: Pointer to wlan_dfs structure.
594  * @rf: Pointer to dfs_filter structure.
595  * @ext_chan_flag: Extension channel flag.
596  * @numpulses: Number of pulses.
597  * @refpri: Current "filter" time for start of pulse in usecs.
598  * @refdur: Duration value.
599  * @primargin: PRI margin.
600  */
601 static inline void dfs_bin_success_print(
602 		struct wlan_dfs *dfs,
603 		struct dfs_filter *rf,
604 		int ext_chan_flag,
605 		int numpulses,
606 		uint32_t refpri,
607 		uint32_t refdur,
608 		uint32_t primargin)
609 {
610 	dfs_debug(dfs, WLAN_DEBUG_DFS1,
611 			"ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d",
612 			ext_chan_flag, rf->rf_pulseid, numpulses,
613 			rf->rf_threshold, refdur, refpri, primargin);
614 	dfs_print_delayline(dfs, &rf->rf_dl);
615 	dfs_print_filter(dfs, rf);
616 }
617 
618 int dfs_bin_check(
619 		struct wlan_dfs *dfs,
620 		struct dfs_filter *rf,
621 		uint32_t deltaT,
622 		uint32_t width,
623 		int ext_chan_flag)
624 {
625 	struct dfs_delayline *dl;
626 	uint32_t refpri, refdur;
627 	uint32_t highscoreindex;
628 	uint32_t primargin, highscore;
629 	int score[DFS_MAX_DL_SIZE], found = 0;
630 	uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff;
631 	int numpulses = 0;
632 	int fil_thresh;
633 
634 	dl = &rf->rf_dl;
635 	if (!dfs_bin_basic_sanity(dl, rf, &deltaT))
636 		return 0;
637 
638 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
639 			(rf->rf_patterntype == 1));
640 
641 
642 	if (rf->rf_patterntype == 1)
643 		return dfs_handle_fixedpattern(dfs, dl, rf, width,
644 				ext_chan_flag);
645 
646 	dfs_find_lowestpri(dl, &lowpriindex, &lowpri);
647 
648 	/* Find out the each delay element's pri score. */
649 	dfs_find_priscores(dl, rf, score, primargin);
650 
651 	/* Find out the high scorer. */
652 	dfs_find_highscore(dl, score, &highscore, &highscoreindex);
653 
654 	/*
655 	 * Find the average pri of pulses around the pri of highscore
656 	 * or the pulses around the lowest pri.
657 	 */
658 	dfs_find_scoreindex(rf, highscore, lowpriindex, highscoreindex,
659 			&scoreindex);
660 
661 	/* We got the possible pri, save its parameters as reference. */
662 	dfs_find_refs(dl, rf, scoreindex, &refdur, &refpri);
663 
664 	numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri,
665 			refdur, ext_chan_flag, refpri);
666 
667 	fil_thresh = dfs_get_filter_threshold(dfs, rf, ext_chan_flag);
668 
669 	if (numpulses >= fil_thresh) {
670 		found = 1;
671 		dfs_bin_success_print(dfs, rf, ext_chan_flag, numpulses,
672 				refpri, refdur, primargin);
673 	}
674 
675 	return found;
676 }
677 
678 /**
679  * dfs_update_min_and_max_sidx() - Calculate min and max sidx.
680  * @dl: Pointer to dfs_delayline structure.
681  * @delayindex: Delay index.
682  * @sidx_min: Sidx min.
683  * @sidx_max: Sidx max.
684  * @delta_peak_match_count: Delta peak match count.
685  * @psidx_diff_match_count: Psidx diff match count.
686  * @rf: Pointer to dfs_filter structure.
687  */
688 static inline void dfs_update_min_and_max_sidx(
689 		struct dfs_delayline *dl,
690 		int delayindex,
691 		int32_t *sidx_min,
692 		int32_t *sidx_max,
693 		uint8_t *delta_peak_match_count,
694 		uint8_t *psidx_diff_match_count,
695 		struct dfs_filter *rf)
696 {
697 	/* update sidx min/max for false detection check later */
698 	if (*sidx_min > dl->dl_elems[delayindex].de_sidx)
699 		*sidx_min = dl->dl_elems[delayindex].de_sidx;
700 
701 	if (*sidx_max < dl->dl_elems[delayindex].de_sidx)
702 		*sidx_max = dl->dl_elems[delayindex].de_sidx;
703 
704 	if (rf->rf_check_delta_peak) {
705 		if (dl->dl_elems[delayindex].de_delta_peak != 0)
706 			(*delta_peak_match_count)++;
707 		else if ((dl->dl_elems[delayindex].de_psidx_diff >=
708 				DFS_MIN_PSIDX_DIFF) &&
709 			(dl->dl_elems[delayindex].de_psidx_diff <=
710 				DFS_MAX_PSIDX_DIFF))
711 			(*psidx_diff_match_count)++;
712 	}
713 }
714 
715 /**
716  * dfs_check_pulses_for_delta_variance() - Check pulses for delta variance.
717  * @rf: Pointer to dfs_filter structure.
718  * @numpulsetochk: Number of pulses to check.
719  * @delta_time_stamps: Delta time stamp.
720  * @fundamentalpri: Highest PRI.
721  * @primargin: Primary margin.
722  * @numpulses: Number of pulses.
723  * @delayindex: Delay index.
724  * @sidx_min: Sidx min.
725  * @sidx_max: Sidx max.
726  * @delta_peak_match_count: Delta peak match count.
727  * @psidx_diff_match_count: Psidx diff match count.
728  * @dl: Pointer to dfs_delayline structure.
729  */
730 static inline void dfs_check_pulses_for_delta_variance(
731 		struct dfs_filter *rf,
732 		int numpulsetochk,
733 		uint32_t delta_time_stamps,
734 		int fundamentalpri,
735 		uint32_t primargin,
736 		int *numpulses,
737 		int delayindex,
738 		int32_t *sidx_min,
739 		int32_t *sidx_max,
740 		uint8_t *delta_peak_match_count,
741 		uint8_t *psidx_diff_match_count,
742 		struct dfs_delayline *dl)
743 {
744 	uint32_t delta_ts_variance, j;
745 
746 	for (j = 0; j < numpulsetochk; j++) {
747 		delta_ts_variance = DFS_DIFF(delta_time_stamps,
748 				((j + 1) * fundamentalpri));
749 		if (delta_ts_variance < (2 * (j + 1) * primargin)) {
750 			dl->dl_seq_num_stop =
751 				dl->dl_elems[delayindex].de_seq_num;
752 			dfs_update_min_and_max_sidx(dl, delayindex,
753 					sidx_min, sidx_max,
754 					delta_peak_match_count,
755 					psidx_diff_match_count,
756 					rf);
757 			(*numpulses)++;
758 			if (rf->rf_ignore_pri_window > 0)
759 				break;
760 		}
761 	}
762 }
763 
764 /**
765  * dfs_count_the_other_delay_elements() - Counts the ther delay elements.
766  * @dfs: Pointer to wlan_dfs structure.
767  * @rf: Pointer to dfs_filter structure.
768  * @dl: Pointer to dfs_delayline structure.
769  * @i: Index value.
770  * @refpri: Current "filter" time for start of pulse in usecs.
771  * @refdur: Duration value.
772  * @primargin: Primary margin.
773  * @durmargin: Duration margin.
774  * @numpulses: Number of pulses.
775  * @delta_peak_match_count: Pointer to delta_peak_match_count.
776  * @psidx_diff_match_count: Pointer to psidx_diff_match_count.
777  * @prev_good_timestamp: Previous good timestamp.
778  * @fundamentalpri: Highest PRI.
779  */
780 static void dfs_count_the_other_delay_elements(
781 		struct wlan_dfs *dfs,
782 		struct dfs_filter *rf,
783 		struct dfs_delayline *dl,
784 		uint32_t i,
785 		uint32_t refpri,
786 		uint32_t refdur,
787 		uint32_t primargin,
788 		uint32_t durmargin,
789 		int *numpulses,
790 		uint8_t *delta_peak_match_count,
791 		uint8_t *psidx_diff_match_count,
792 		uint32_t *prev_good_timestamp,
793 		int fundamentalpri)
794 {
795 	int delayindex;
796 	uint32_t searchpri, searchdur, deltadur, deltapri1, deltapri2;
797 	uint32_t j = 0, delta_time_stamps, deltapri;
798 	int dindex, primatch, numpulsetochk = 2;
799 	int32_t sidx_min = DFS_BIG_SIDX;
800 	int32_t sidx_max = -DFS_BIG_SIDX;
801 
802 	delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
803 	searchpri = dl->dl_elems[delayindex].de_time;
804 	if (searchpri == 0) {
805 		/*
806 		 * This events PRI is zero, take it as a valid pulse
807 		 * but decrement next event's PRI by refpri.
808 		 */
809 		dindex = (delayindex + 1) & DFS_MAX_DL_MASK;
810 		dl->dl_elems[dindex].de_time -=  refpri;
811 		searchpri = refpri;
812 	}
813 	searchdur = dl->dl_elems[delayindex].de_dur;
814 	deltadur = DFS_DIFF(searchdur, refdur);
815 	deltapri = DFS_DIFF(searchpri, refpri);
816 	deltapri1 = DFS_DIFF(searchpri, refpri);
817 	deltapri2 = DFS_DIFF(searchpri, 2 * refpri);
818 	primatch = 0;
819 
820 	if ((rf->rf_ignore_pri_window > 0) && (rf->rf_patterntype != 2)) {
821 		for (j = 0; j < rf->rf_numpulses; j++) {
822 			deltapri1 = DFS_DIFF(searchpri, (j + 1) * refpri);
823 			if (deltapri1 < (2 * primargin)) {
824 				primatch = 1;
825 				break;
826 			}
827 		}
828 	} else if ((deltapri1 < primargin) || (deltapri2 < primargin)) {
829 		primatch = 1;
830 	}
831 
832 	if (primatch && (deltadur < durmargin)) {
833 		if (*numpulses == 1) {
834 			dl->dl_seq_num_second =
835 				dl->dl_elems[delayindex].de_seq_num;
836 			dfs_update_min_and_max_sidx(dl, delayindex,
837 					&sidx_min, &sidx_max,
838 					delta_peak_match_count,
839 					psidx_diff_match_count,
840 					rf);
841 			(*numpulses)++;
842 		} else {
843 			delta_time_stamps = (dl->dl_elems[delayindex].de_ts -
844 				*prev_good_timestamp);
845 			if ((rf->rf_ignore_pri_window > 0)) {
846 				numpulsetochk = rf->rf_numpulses;
847 				if ((rf->rf_patterntype == 2) &&
848 					(fundamentalpri < refpri + 100)) {
849 					numpulsetochk = 4;
850 				}
851 			} else {
852 				numpulsetochk = 4;
853 			}
854 
855 			dfs_check_pulses_for_delta_variance(rf, numpulsetochk,
856 					delta_time_stamps, fundamentalpri,
857 					primargin, numpulses, delayindex,
858 					&sidx_min, &sidx_max,
859 					delta_peak_match_count,
860 					psidx_diff_match_count,
861 					dl);
862 		}
863 		*prev_good_timestamp = dl->dl_elems[delayindex].de_ts;
864 		dl->dl_search_pri = searchpri;
865 		dl->dl_min_sidx = sidx_min;
866 		dl->dl_max_sidx = sidx_max;
867 		dl->dl_delta_peak_match_count = *delta_peak_match_count;
868 		dl->dl_psidx_diff_match_count = *psidx_diff_match_count;
869 
870 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
871 			"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",
872 			rf->rf_minpri, rf->rf_maxpri, searchpri, i,
873 			*numpulses, *delta_peak_match_count,
874 			*psidx_diff_match_count, deltapri, j);
875 	}
876 }
877 
878 int dfs_bin_pri_check(
879 		struct wlan_dfs *dfs,
880 		struct dfs_filter *rf,
881 		struct dfs_delayline *dl,
882 		uint32_t score,
883 		uint32_t refpri,
884 		uint32_t refdur,
885 		int ext_chan_flag,
886 		int fundamentalpri)
887 {
888 	uint32_t searchpri, deltapri = 0;
889 	uint32_t averagerefpri = 0, MatchCount = 0;
890 	uint32_t prev_good_timestamp = 0;
891 	int dindex;
892 	uint32_t i, primargin, durmargin, highscore = score;
893 	uint32_t highscoreindex = 0;
894 	/*
895 	 * First pulse in the burst is most likely being filtered out based on
896 	 * maxfilterlen.
897 	 */
898 	int numpulses = 1;
899 	uint8_t delta_peak_match_count = 1;
900 	uint8_t psidx_diff_match_count = 1;
901 	int priscorechk = 1;
902 
903 	/* Use the adjusted PRI margin to reduce false alarms
904 	 * For non fixed pattern types, rf->rf_patterntype=0.
905 	 */
906 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
907 			(rf->rf_patterntype == 1));
908 
909 	if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) {
910 		numpulses = 0;
911 		return numpulses;
912 	}
913 
914 	dfs_get_durmargin(rf, &durmargin);
915 
916 	if ((!rf->rf_fixed_pri_radar_pulse)) {
917 		if (rf->rf_ignore_pri_window == 1)
918 			priscorechk = (rf->rf_threshold >> 1);
919 		else
920 			priscorechk = 1;
921 
922 		MatchCount = 0;
923 		if (score > priscorechk) {
924 			for (i = 0; i < dl->dl_numelems; i++) {
925 				dindex = (dl->dl_firstelem + i) &
926 					DFS_MAX_DL_MASK;
927 				searchpri = dl->dl_elems[dindex].de_time;
928 				deltapri = DFS_DIFF(searchpri, refpri);
929 				if (deltapri < primargin) {
930 					averagerefpri += searchpri;
931 					MatchCount++;
932 				}
933 			}
934 			if (rf->rf_patterntype != 2) {
935 				if (MatchCount > 0)
936 					refpri = (averagerefpri / MatchCount);
937 			} else {
938 				refpri = (averagerefpri / score);
939 			}
940 		}
941 	}
942 
943 	/* Note: Following primultiple calculation should be done
944 	 * once per filter during initialization stage (dfs_attach)
945 	 * and stored in its array atleast for fixed frequency
946 	 * types like FCC Bin1 to save some CPU cycles.
947 	 * multiplication, devide operators in the following code
948 	 * are left as it is for readability hoping the complier
949 	 * will use left/right shifts wherever possible.
950 	 */
951 	dfs_debug(dfs, WLAN_DEBUG_DFS2,
952 		"refpri = %d high score = %d index = %d numpulses = %d",
953 		refpri, highscore, highscoreindex, numpulses);
954 	/*
955 	 * Count the other delay elements that have pri and dur with
956 	 * in the acceptable range from the reference one.
957 	 */
958 	for (i = 0; i < dl->dl_numelems; i++)
959 		dfs_count_the_other_delay_elements(dfs, rf, dl, i, refpri,
960 				refdur, primargin, durmargin, &numpulses,
961 				&delta_peak_match_count,
962 				&psidx_diff_match_count,
963 				&prev_good_timestamp, fundamentalpri);
964 
965 	return numpulses;
966 }
967