xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_bindetects.c (revision 928e3ecad0fabf5320100a0d8fbde785757aa071)
1 /*
2  * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2002-2010, Atheros Communications Inc.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: DFS specs specify various types of radars to be detected.
20  * Each separate type is called a Bin and has different characteristics.
21  * This file contains the functionality to look at a group of pulses and
22  * to detect whether we have detected a valid radar waveform. To do that,
23  * it must match the group against each different Bin's characteristics.
24  */
25 
26 #include "../dfs.h"
27 
28 int dfs_bin_fixedpattern_check(struct wlan_dfs *dfs,
29 		struct dfs_filter *rf,
30 		uint32_t dur,
31 		int ext_chan_flag)
32 {
33 	struct dfs_pulseline *pl = dfs->pulses;
34 	int i, n, refpri, primargin, numpulses = 0;
35 	uint64_t start_ts, end_ts, event_ts, prev_event_ts;
36 	uint64_t next_event_ts, window_start, window_end;
37 	uint32_t index, next_index, deltadur;
38 
39 	/* For fixed pattern types, rf->rf_patterntype=1. */
40 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
41 		(rf->rf_patterntype == 1));
42 
43 	refpri = (rf->rf_minpri + rf->rf_maxpri)/2;
44 	index = pl->pl_lastelem;
45 	end_ts = pl->pl_elems[index].p_time;
46 	start_ts = end_ts - (refpri*rf->rf_numpulses);
47 
48 	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS3,
49 		"lastelem ts=%llu start_ts=%llu, end_ts=%llu\n",
50 		(unsigned long long)pl->pl_elems[index].p_time,
51 		(unsigned long long)start_ts,
52 		(unsigned long long) end_ts);
53 
54 	/* Find the index of first element in our window of interest. */
55 	for (i = 0; i < pl->pl_numelems; i++) {
56 		index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK;
57 		if (pl->pl_elems[index].p_time >= start_ts)
58 			continue;
59 		else {
60 			index = (index) & DFS_MAX_PULSE_BUFFER_MASK;
61 			break;
62 		}
63 	}
64 	for (n = 0; n <= rf->rf_numpulses; n++) {
65 		window_start = (start_ts + (refpri*n))-(primargin+n);
66 		window_end = window_start + 2*(primargin+n);
67 		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2,
68 			"window_start %u window_end %u\n",
69 			(uint32_t)window_start, (uint32_t)window_end);
70 
71 		for (i = 0; i < pl->pl_numelems; i++) {
72 			prev_event_ts = pl->pl_elems[index].p_time;
73 			index = (index+1) & DFS_MAX_PULSE_BUFFER_MASK;
74 			event_ts = pl->pl_elems[index].p_time;
75 			next_index = (index+1) & DFS_MAX_PULSE_BUFFER_MASK;
76 			next_event_ts = pl->pl_elems[next_index].p_time;
77 			DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, "ts %u\n",
78 				(uint32_t)event_ts);
79 
80 			if ((event_ts <= window_end) &&
81 				(event_ts >= window_start)) {
82 				deltadur = DFS_DIFF(pl->pl_elems[index].p_dur,
83 					dur);
84 				if ((pl->pl_elems[index].p_dur == 1) ||
85 					((dur != 1) && (deltadur <= 2))) {
86 					numpulses++;
87 					DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2,
88 						"numpulses %u\n", numpulses);
89 					break;
90 				}
91 			} else if (event_ts > window_end) {
92 				index = (index-1) & DFS_MAX_PULSE_BUFFER_MASK;
93 				break;
94 			} else if (event_ts == prev_event_ts) {
95 				if (((next_event_ts - event_ts) > refpri) ||
96 					((next_event_ts - event_ts) == 0)) {
97 					deltadur =
98 					    DFS_DIFF(pl->pl_elems[index].p_dur,
99 						    dur);
100 					if ((pl->pl_elems[index].p_dur == 1) ||
101 						((pl->pl_elems[index].p_dur !=
102 						  1) && (deltadur <= 2))) {
103 						numpulses++;
104 						DFS_DPRINTK(dfs,
105 							WLAN_DEBUG_DFS2,
106 							"zero PRI: numpulses %u\n",
107 							numpulses);
108 						break;
109 					}
110 				}
111 			}
112 		}
113 	}
114 	if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) {
115 		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS1,
116 			"%s FOUND filterID=%u numpulses=%d unadj thresh=%d\n",
117 			__func__, rf->rf_pulseid, numpulses, rf->rf_threshold);
118 		return 1;
119 	} else
120 		return 0;
121 }
122 
123 void dfs_add_pulse(struct wlan_dfs *dfs,
124 		struct dfs_filter *rf,
125 		struct dfs_event *re,
126 		uint32_t deltaT,
127 		uint64_t this_ts)
128 {
129 	uint32_t index, n, window;
130 	struct dfs_delayline *dl;
131 
132 	dl = &rf->rf_dl;
133 	/* Circular buffer of size 2^n */
134 	index = (dl->dl_lastelem + 1) & DFS_MAX_DL_MASK;
135 	if ((dl->dl_numelems) == DFS_MAX_DL_SIZE)
136 		dl->dl_firstelem = (dl->dl_firstelem + 1) & DFS_MAX_DL_MASK;
137 	else
138 		dl->dl_numelems++;
139 	dl->dl_lastelem = index;
140 	dl->dl_elems[index].de_time = deltaT;
141 	dl->dl_elems[index].de_ts = this_ts;
142 	window = deltaT;
143 	dl->dl_elems[index].de_dur = re->re_dur;
144 	dl->dl_elems[index].de_rssi = re->re_rssi;
145 
146 	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2,
147 		"%s: adding: filter id %d, dur=%d, rssi=%d, ts=%llu\n",
148 		__func__, rf->rf_pulseid, re->re_dur,
149 		re->re_rssi, (unsigned long long int)this_ts);
150 
151 	for (n = 0; n < dl->dl_numelems-1; n++) {
152 		index = (index-1) & DFS_MAX_DL_MASK;
153 		/*
154 		 * Calculate window based on full time stamp instead of deltaT
155 		 * deltaT (de_time) may result in incorrect window value
156 		 */
157 		window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts);
158 
159 		if (window > rf->rf_filterlen) {
160 			dl->dl_firstelem = (index+1) & DFS_MAX_DL_MASK;
161 			dl->dl_numelems = n+1;
162 		}
163 	}
164 	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2, "dl firstElem = %d  lastElem = %d\n",
165 			dl->dl_firstelem, dl->dl_lastelem);
166 }
167 
168 int dfs_bin_check(struct wlan_dfs *dfs,
169 		struct dfs_filter *rf,
170 		uint32_t deltaT,
171 		uint32_t width,
172 		int ext_chan_flag)
173 {
174 	struct dfs_delayline *dl;
175 	uint32_t refpri, refdur, searchpri, deltapri, deltapri_2, deltapri_3;
176 	uint32_t averagerefpri, n, i, primargin, durmargin, highscore;
177 	uint32_t highscoreindex;
178 	int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0;
179 	uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff;
180 	int numpulses = 0;
181 	int lowprichk = 3, pri_match = 0;
182 
183 	dl = &rf->rf_dl;
184 	if (dl->dl_numelems < (rf->rf_threshold-1))
185 		return 0;
186 
187 	if (deltaT > rf->rf_filterlen)
188 		return 0;
189 
190 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
191 			(rf->rf_patterntype == 1));
192 
193 	if (rf->rf_maxdur < 10)
194 		durmargin = 4;
195 	else
196 		durmargin = 6;
197 
198 	if (rf->rf_patterntype == 1) {
199 		found = dfs_bin_fixedpattern_check(dfs, rf, width,
200 				ext_chan_flag);
201 		if (found)
202 			dl->dl_numelems = 0;
203 		return found;
204 	}
205 
206 	qdf_mem_zero(score, sizeof(int)*DFS_MAX_DL_SIZE);
207 	/* Find out the lowest pri. */
208 	for (n = 0; n < dl->dl_numelems; n++) {
209 		delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
210 		refpri = dl->dl_elems[delayindex].de_time;
211 		if (refpri == 0) {
212 			continue;
213 		} else if (refpri < lowpri) {
214 			lowpri = dl->dl_elems[delayindex].de_time;
215 			lowpriindex = n;
216 		}
217 	}
218 	/* Find out the each delay element's pri score. */
219 	for (n = 0; n < dl->dl_numelems; n++) {
220 		delayindex = (dl->dl_firstelem + n) &
221 			DFS_MAX_DL_MASK;
222 		refpri = dl->dl_elems[delayindex].de_time;
223 		if (refpri == 0)
224 			continue;
225 		if (refpri < rf->rf_maxpri) {
226 			/* Use only valid PRI range for high score. */
227 			for (i = 0; i < dl->dl_numelems; i++) {
228 				dindex = (dl->dl_firstelem + i) &
229 				    DFS_MAX_DL_MASK;
230 				searchpri = dl->dl_elems[dindex].de_time;
231 				deltapri = DFS_DIFF(searchpri, refpri);
232 				deltapri_2 = DFS_DIFF(searchpri, 2*refpri);
233 				deltapri_3 = DFS_DIFF(searchpri, 3*refpri);
234 				if (rf->rf_ignore_pri_window == 2) {
235 					pri_match = ((deltapri < primargin) ||
236 						(deltapri_2 < primargin) ||
237 						(deltapri_3 < primargin));
238 				} else {
239 					pri_match = (deltapri < primargin);
240 				}
241 				if (pri_match)
242 					score[n]++;
243 			}
244 		} else {
245 			score[n] = 0;
246 		}
247 		if (score[n] > rf->rf_threshold) {
248 			/*
249 			 * We got the most possible candidate,
250 			 * no need to continue further.
251 			 */
252 			break;
253 		}
254 	}
255 
256 	/* Find out the high scorer. */
257 	highscore = 0;
258 	highscoreindex = 0;
259 	for (n = 0; n < dl->dl_numelems; n++) {
260 		if (score[n] > highscore) {
261 			highscore = score[n];
262 			highscoreindex = n;
263 		} else if (score[n] == highscore) {
264 			/*
265 			 * More than one pri has highscore take the least pri.
266 			 */
267 			delayindex = (dl->dl_firstelem + highscoreindex) &
268 				DFS_MAX_DL_MASK;
269 			dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK;
270 			if (dl->dl_elems[dindex].de_time <=
271 					dl->dl_elems[delayindex].de_time) {
272 				highscoreindex = n;
273 			}
274 		}
275 	}
276 
277 	/*
278 	 * Find the average pri of pulses around the pri of highscore
279 	 * or the pulses around the lowest pri.
280 	 */
281 	if (rf->rf_ignore_pri_window > 0)
282 		lowprichk = (rf->rf_threshold >> 1)+1;
283 	else
284 		lowprichk = 3;
285 
286 	if (highscore < lowprichk)
287 		scoreindex = lowpriindex;
288 	else
289 		scoreindex = highscoreindex;
290 
291 	/* We got the possible pri, save its parameters as reference. */
292 	delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK;
293 	refdur = dl->dl_elems[delayindex].de_dur;
294 	refpri = dl->dl_elems[delayindex].de_time;
295 	averagerefpri = 0;
296 
297 	if (rf->rf_fixed_pri_radar_pulse)
298 		refpri = (rf->rf_minpri + rf->rf_maxpri)/2;
299 
300 	numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri,
301 			refdur, ext_chan_flag, refpri);
302 	if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) {
303 		found = 1;
304 		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS1,
305 			"ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d\n",
306 			ext_chan_flag, rf->rf_pulseid, numpulses,
307 			rf->rf_threshold, refdur, refpri, primargin);
308 		dfs_print_delayline(dfs, &rf->rf_dl);
309 		dfs_print_filter(dfs, rf);
310 	}
311 
312 	return found;
313 }
314 
315 void count_the_other_delay_elements(struct wlan_dfs *dfs,
316 		struct dfs_filter *rf,
317 		struct dfs_delayline *dl,
318 		uint32_t i,
319 		uint32_t refpri,
320 		uint32_t refdur,
321 		uint32_t primargin,
322 		uint32_t durmargin,
323 		int *numpulses,
324 		uint32_t *prev_good_timestamp,
325 		int fundamentalpri
326 		)
327 {
328 	int delayindex;
329 	uint32_t searchpri, searchdur, deltadur, deltapri1, deltapri2;
330 	uint32_t j = 0, delta_time_stamps, delta_ts_variance, deltapri;
331 	int dindex, primatch, numpulsetochk = 2;
332 
333 	delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
334 	searchpri = dl->dl_elems[delayindex].de_time;
335 	if (searchpri == 0) {
336 		/*
337 		 * This events PRI is zero, take it as a valid pulse
338 		 * but decrement next event's PRI by refpri.
339 		 */
340 		dindex = (delayindex + 1) & DFS_MAX_DL_MASK;
341 		dl->dl_elems[dindex].de_time -=  refpri;
342 		searchpri = refpri;
343 	}
344 	searchdur = dl->dl_elems[delayindex].de_dur;
345 	deltadur = DFS_DIFF(searchdur, refdur);
346 	deltapri = DFS_DIFF(searchpri, refpri);
347 	deltapri1 = DFS_DIFF(searchpri, refpri);
348 	deltapri2 = DFS_DIFF(searchpri, 2 * refpri);
349 	primatch = 0;
350 
351 	if ((rf->rf_ignore_pri_window > 0) &&
352 			(rf->rf_patterntype != 2)) {
353 		for (j = 0; j < rf->rf_numpulses; j++) {
354 			deltapri1 = DFS_DIFF(searchpri,
355 					(j + 1) * refpri);
356 			if (deltapri1 < (2 * primargin)) {
357 				primatch = 1;
358 				break;
359 			}
360 		}
361 	} else {
362 		if ((deltapri1 < primargin) ||
363 				(deltapri2 < primargin)) {
364 			primatch = 1;
365 		}
366 	}
367 
368 	if (primatch && (deltadur < durmargin)) {
369 		if ((*numpulses == 1)) {
370 			(*numpulses)++;
371 		} else {
372 			delta_time_stamps = (dl->dl_elems[delayindex].de_ts -
373 				*prev_good_timestamp);
374 			if ((rf->rf_ignore_pri_window > 0)) {
375 				numpulsetochk = rf->rf_numpulses;
376 				if ((rf->rf_patterntype == 2) &&
377 					(fundamentalpri < refpri + 100)) {
378 					numpulsetochk = 4;
379 				}
380 			} else {
381 				numpulsetochk = 4;
382 			}
383 			for (j = 0; j < numpulsetochk; j++) {
384 				delta_ts_variance = DFS_DIFF(delta_time_stamps,
385 					((j + 1) * fundamentalpri));
386 				if (delta_ts_variance <
387 					(2 * (j + 1) * primargin)) {
388 					(*numpulses)++;
389 					if (rf->rf_ignore_pri_window > 0)
390 						break;
391 				}
392 			}
393 		}
394 		*prev_good_timestamp = dl->dl_elems[delayindex].de_ts;
395 
396 		DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2,
397 			"rf->minpri=%d rf->maxpri=%d searchpri = %d index = %d numpulses = %d deltapri=%d j=%d\n",
398 			rf->rf_minpri, rf->rf_maxpri, searchpri,
399 			i, *numpulses, deltapri, j);
400 	}
401 }
402 
403 int dfs_bin_pri_check(struct wlan_dfs *dfs,
404 		struct dfs_filter *rf,
405 		struct dfs_delayline *dl,
406 		uint32_t score,
407 		uint32_t refpri,
408 		uint32_t refdur,
409 		int ext_chan_flag,
410 		int fundamentalpri)
411 {
412 	uint32_t searchpri, deltapri = 0;
413 	uint32_t averagerefpri = 0, MatchCount = 0;
414 	uint32_t prev_good_timestamp = 0;
415 	int dindex;
416 	uint32_t i, primargin, durmargin, highscore = score;
417 	uint32_t highscoreindex = 0;
418 	/*
419 	 * First pulse in the burst is most likely being filtered out based on
420 	 * maxfilterlen.
421 	 */
422 	int numpulses = 1;
423 	int priscorechk = 1;
424 
425 	/* Use the adjusted PRI margin to reduce false alarms
426 	 * For non fixed pattern types, rf->rf_patterntype=0.
427 	 */
428 	primargin = dfs_get_pri_margin(dfs, ext_chan_flag,
429 			(rf->rf_patterntype == 1));
430 
431 	if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) {
432 		numpulses = 0;
433 		return numpulses;
434 	}
435 
436 	if (rf->rf_maxdur < 10)
437 		durmargin = 4;
438 	else
439 		durmargin = 6;
440 
441 	if ((!rf->rf_fixed_pri_radar_pulse)) {
442 		if (rf->rf_ignore_pri_window == 1)
443 			priscorechk = (rf->rf_threshold >> 1);
444 		else
445 			priscorechk = 1;
446 
447 		MatchCount = 0;
448 		if (score > priscorechk) {
449 			for (i = 0; i < dl->dl_numelems; i++) {
450 				dindex = (dl->dl_firstelem + i) &
451 					DFS_MAX_DL_MASK;
452 				searchpri = dl->dl_elems[dindex].de_time;
453 				deltapri = DFS_DIFF(searchpri, refpri);
454 				if (deltapri < primargin) {
455 					averagerefpri += searchpri;
456 					MatchCount++;
457 				}
458 			}
459 			if (rf->rf_patterntype != 2) {
460 				if (MatchCount > 0)
461 					refpri = (averagerefpri / MatchCount);
462 			} else {
463 				refpri = (averagerefpri / score);
464 			}
465 		}
466 	}
467 
468 	/* Note: Following primultiple calculation should be done
469 	 * once per filter during initialization stage (dfs_attach)
470 	 * and stored in its array atleast for fixed frequency
471 	 * types like FCC Bin1 to save some CPU cycles.
472 	 * multiplication, devide operators in the following code
473 	 * are left as it is for readability hoping the complier
474 	 * will use left/right shifts wherever possible.
475 	 */
476 	DFS_DPRINTK(dfs, WLAN_DEBUG_DFS2,
477 		"refpri = %d high score = %d index = %d numpulses = %d\n",
478 		refpri, highscore, highscoreindex, numpulses);
479 	/*
480 	 * Count the other delay elements that have pri and dur with
481 	 * in the acceptable range from the reference one.
482 	 */
483 	for (i = 0; i < dl->dl_numelems; i++)
484 		count_the_other_delay_elements(dfs, rf, dl, i, refpri, refdur,
485 			primargin, durmargin, &numpulses, &prev_good_timestamp,
486 			fundamentalpri);
487 
488 	return numpulses;
489 }
490