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