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