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   */
dfs_find_first_index_within_window(struct dfs_pulseline * pl,uint32_t index,uint64_t start_ts)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   */
dfs_ts_within_window(struct wlan_dfs * dfs,struct dfs_pulseline * pl,uint32_t * index,uint32_t dur,int * numpulses)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   */
dfs_ts_eq_prevts(struct wlan_dfs * dfs,struct dfs_pulseline * pl,uint64_t next_event_ts,uint64_t event_ts,uint32_t refpri,uint32_t * index,uint32_t dur,int * numpulses)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   */
dfs_pulses_within_window(struct wlan_dfs * dfs,uint64_t window_start,uint64_t window_end,uint32_t * index,uint32_t dur,uint32_t refpri)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   */
dfs_count_pulses(struct wlan_dfs * dfs,struct dfs_filter * rf,uint32_t dur,int ext_chan_flag,int primargin,uint32_t index,uint32_t refpri,uint64_t start_ts)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   */
dfs_bin_fixedpattern_check(struct wlan_dfs * dfs,struct dfs_filter * rf,uint32_t dur,int ext_chan_flag)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  
dfs_add_pulse(struct wlan_dfs * dfs,struct dfs_filter * rf,struct dfs_event * re,uint32_t deltaT,uint64_t this_ts)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   */
dfs_find_lowestpri(struct dfs_delayline * dl,uint32_t * lowpriindex,uint32_t * lowpri)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   */
dfs_calculate_score(struct dfs_delayline * dl,struct dfs_filter * rf,int * score,uint32_t refpri,uint32_t primargin,uint32_t score_index)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   */
dfs_find_priscores(struct dfs_delayline * dl,struct dfs_filter * rf,int * score,uint32_t primargin)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   */
dfs_find_highscore(struct dfs_delayline * dl,int * score,uint32_t * highscore,uint32_t * highscoreindex)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   */
dfs_get_durmargin(struct dfs_filter * rf,uint32_t * durmargin)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   */
dfs_handle_fixedpattern(struct wlan_dfs * dfs,struct dfs_delayline * dl,struct dfs_filter * rf,uint32_t dur,int ext_chan_flag)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   */
dfs_bin_basic_sanity(struct dfs_delayline * dl,struct dfs_filter * rf,uint32_t * deltaT)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
dfs_pick_lowpri(struct wlan_dfs * dfs,struct dfs_delayline * dl,struct dfs_filter * rf,uint32_t lowpriindex,uint32_t * scoreindex,uint32_t primargin)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
dfs_pick_lowpri(struct wlan_dfs * dfs,struct dfs_delayline * dl,struct dfs_filter * rf,uint32_t lowpriindex,uint32_t * scoreindex,uint32_t primargin)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   */
dfs_find_scoreindex(struct dfs_filter * rf,uint32_t highscore,uint32_t lowpriindex,uint32_t highscoreindex,uint32_t * scoreindex)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   */
dfs_find_refs(struct dfs_delayline * dl,struct dfs_filter * rf,uint32_t scoreindex,uint32_t * refdur,uint32_t * refpri)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   */
dfs_bin_success_print(struct wlan_dfs * dfs,struct dfs_filter * rf,int ext_chan_flag,int numpulses,uint32_t refpri,uint32_t refdur,uint32_t primargin)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  
dfs_bin_check(struct wlan_dfs * dfs,struct dfs_filter * rf,uint32_t deltaT,uint32_t width,int ext_chan_flag)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   */
dfs_update_min_and_max_sidx(struct dfs_delayline * dl,int delayindex,int32_t * sidx_min,int32_t * sidx_max,uint8_t * delta_peak_match_count,uint8_t * psidx_diff_match_count,struct dfs_filter * rf)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   */
dfs_check_pulses_for_delta_variance(struct dfs_filter * rf,int numpulsetochk,uint32_t delta_time_stamps,int fundamentalpri,uint32_t primargin,int * numpulses,int delayindex,int32_t * sidx_min,int32_t * sidx_max,uint8_t * delta_peak_match_count,uint8_t * psidx_diff_match_count,struct dfs_delayline * dl)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   */
dfs_count_the_other_delay_elements(struct wlan_dfs * dfs,struct dfs_filter * rf,struct dfs_delayline * dl,uint32_t i,uint32_t refpri,uint32_t refdur,uint32_t primargin,uint32_t durmargin,int * numpulses,uint8_t * delta_peak_match_count,uint8_t * psidx_diff_match_count,uint32_t * prev_good_timestamp,int fundamentalpri)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  
dfs_bin_pri_check(struct wlan_dfs * dfs,struct dfs_filter * rf,struct dfs_delayline * dl,uint32_t score,uint32_t refpri,uint32_t refdur,int ext_chan_flag,int fundamentalpri)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