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