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