xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_process_radarevent.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2013, 2016-2021 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: This contains the functionality to process the radar event generated
20  * for a pulse. This will group together pulses and call various detection
21  * functions to figure out whether a valid radar has been detected.
22  */
23 
24 #include "../dfs.h"
25 #include "../dfs_zero_cac.h"
26 #include "../dfs_channel.h"
27 #include "../dfs_internal.h"
28 #include "../dfs_process_radar_found_ind.h"
29 #include <wlan_objmgr_vdev_obj.h>
30 #include "wlan_dfs_utils_api.h"
31 #include "wlan_dfs_lmac_api.h"
32 #include "../dfs_partial_offload_radar.h"
33 #include "../dfs_confirm_radar.h"
34 
35 #ifdef DFS_FCC_TYPE4_DURATION_CHECK
36 #define DFS_WAR_30_MHZ_SEPARATION   30
37 #define DFS_WAR_PEAK_INDEX_ZERO 0
38 #define DFS_TYPE4_WAR_PULSE_DURATION_LOWER_LIMIT 11
39 #define DFS_TYPE4_WAR_PULSE_DURATION_UPPER_LIMIT 33
40 #define DFS_TYPE4_WAR_PRI_LOWER_LIMIT 200
41 #define DFS_TYPE4_WAR_PRI_UPPER_LIMIT 500
42 #define DFS_TYPE4_WAR_VALID_PULSE_DURATION 12
43 #endif
44 
45 #define FREQ_5500_MHZ  5500
46 #define FREQ_5500_MHZ       5500
47 
48 #define DFS_MAX_FREQ_SPREAD            (1375 * 1)
49 #define DFS_LARGE_PRI_MULTIPLIER       4
50 #define DFS_W53_DEFAULT_PRI_MULTIPLIER 2
51 #define DFS_BIG_SIDX          10000
52 
53 static char debug_dup[33];
54 static int debug_dup_cnt;
55 
56 /**
57  * dfs_process_pulse_dur() - Process pulse duration.
58  * @dfs: Pointer to wlan_dfs structure.
59  * @re_dur: Duration.
60  *
61  * Convert the hardware provided duration to TSF ticks (usecs) taking the clock
62  * (fast or normal) into account. Legacy (pre-11n, Owl, Sowl, Howl) operate
63  * 5GHz using a 40MHz clock.  Later 11n chips (Merlin, Osprey, etc) operate
64  * 5GHz using a 44MHz clock, so the reported pulse durations are different.
65  * Peregrine reports the pulse duration in microseconds regardless of the
66  * operating mode. (XXX TODO: verify this, obviously.)
67  *
68  * The hardware returns the duration in a variety of formats,
69  * so it's converted from the hardware format to TSF (usec)
70  * values here.
71  * XXX TODO: this should really be done when the PHY error
72  * is processed, rather than way out here..
73  *
74  *
75  * Return: Returns the duration.
76  */
77 static inline uint8_t dfs_process_pulse_dur(struct wlan_dfs *dfs,
78 		uint8_t re_dur)
79 {
80 	/*
81 	 * Short pulses are sometimes returned as having a duration of 0,
82 	 * so round those up to 1.
83 	 * XXX This holds true for BB TLV chips too, right?
84 	 */
85 	if (re_dur == 0)
86 		return 1;
87 
88 	/*
89 	 * For BB TLV chips, the hardware always returns microsecond pulse
90 	 * durations.
91 	 */
92 	if (dfs->dfs_caps.wlan_chip_is_bb_tlv)
93 		return re_dur;
94 
95 	/*
96 	 * This is for 11n and legacy chips, which may or may not use the 5GHz
97 	 * fast clock mode.
98 	 */
99 	/* Convert 0.8us durations to TSF ticks (usecs) */
100 	return (uint8_t)dfs_round((int32_t)((dfs->dur_multiplier)*re_dur));
101 }
102 
103 #ifdef DFS_FCC_TYPE4_DURATION_CHECK
104 /*
105  * dfs_dur_check() - Modify the pulse duration for FCC Type 4 and JAPAN W56
106  *                   Type 8 radar pulses when the conditions mentioned in the
107  *                   function body are reported in the radar summary report.
108  * @dfs: Pointer to wlan_dfs structure.
109  * @chan: Current  channel.
110  * @re: Pointer to dfs_event.
111  * @diff_ts: timestamp of current pulse - timestamp of last pulse.
112  *
113  * return: Void
114  */
115 static inline void dfs_dur_check(
116 	struct wlan_dfs *dfs,
117 	struct dfs_channel *chan,
118 	struct dfs_event *re,
119 	uint32_t diff_ts)
120 {
121 	if ((dfs->dfsdomain == DFS_FCC_DOMAIN ||
122 	     dfs->dfsdomain == DFS_MKK4_DOMAIN ||
123 		 dfs->dfsdomain == DFS_MKKN_DOMAIN) &&
124 	    ((chan->dfs_ch_flags & WLAN_CHAN_VHT80) == WLAN_CHAN_VHT80) &&
125 	    (DFS_DIFF(chan->dfs_ch_freq, chan->dfs_ch_mhz_freq_seg1) ==
126 	    DFS_WAR_30_MHZ_SEPARATION) &&
127 	    re->re_sidx == DFS_WAR_PEAK_INDEX_ZERO &&
128 	    (re->re_dur > DFS_TYPE4_WAR_PULSE_DURATION_LOWER_LIMIT &&
129 	    re->re_dur < DFS_TYPE4_WAR_PULSE_DURATION_UPPER_LIMIT) &&
130 	    (diff_ts > DFS_TYPE4_WAR_PRI_LOWER_LIMIT &&
131 	    diff_ts < DFS_TYPE4_WAR_PRI_UPPER_LIMIT)) {
132 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
133 			  "chan flags=%llu, Pri Chan %d MHz center %d MHZ",
134 			  chan->dfs_ch_flags,
135 			  chan->dfs_ch_freq, chan->dfs_ch_mhz_freq_seg1);
136 
137 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
138 			  "Report Peak Index = %d,re.re_dur = %d,diff_ts = %d",
139 			  re->re_sidx, re->re_dur, diff_ts);
140 
141 		re->re_dur = DFS_TYPE4_WAR_VALID_PULSE_DURATION;
142 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
143 			  "Modifying the pulse duration to %d", re->re_dur);
144 	}
145 }
146 #else
147 static inline void dfs_dur_check(
148 	struct wlan_dfs *dfs,
149 	struct dfs_channel *chan,
150 	struct dfs_event *re,
151 	uint32_t diff_ts)
152 {
153 }
154 #endif
155 
156 /*
157  * dfs_print_radar_events() - Prints the Radar events.
158  * @dfs: Pointer to wlan_dfs structure.
159  */
160 static void dfs_print_radar_events(struct wlan_dfs *dfs)
161 {
162 	int i;
163 
164 	dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "#Phyerr=%d, #false detect=%d, #queued=%d",
165 		  dfs->dfs_phyerr_count, dfs->dfs_phyerr_reject_count,
166 		  dfs->dfs_phyerr_queued_count);
167 
168 	dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d",
169 		  dfs->dfs_phyerr_freq_min, dfs->dfs_phyerr_freq_max);
170 
171 	dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
172 		  "Total radar events detected=%d, entries in the radar queue follows:",
173 		  dfs->dfs_event_log_count);
174 
175 	for (i = 0; (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count);
176 			i++) {
177 		dfs_debug(dfs, WLAN_DEBUG_DFS,
178 			  "ts=%llu diff_ts=%u rssi=%u dur=%u, is_chirp=%d, seg_id=%d, sidx=%d, freq_offset=%d.%dMHz, peak_mag=%d, total_gain=%d, mb_gain=%d, relpwr_db=%d, delta_diff=%d, delta_peak=%d, psidx_diff=%d",
179 			  dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts,
180 			  dfs->radar_log[i].rssi, dfs->radar_log[i].dur,
181 			  dfs->radar_log[i].is_chirp, dfs->radar_log[i].seg_id,
182 			  dfs->radar_log[i].sidx,
183 			  (int)dfs->radar_log[i].freq_offset_khz / 1000,
184 			  (int)abs(dfs->radar_log[i].freq_offset_khz) % 1000,
185 			  dfs->radar_log[i].peak_mag,
186 			  dfs->radar_log[i].total_gain,
187 			  dfs->radar_log[i].mb_gain,
188 			  dfs->radar_log[i].relpwr_db,
189 			  dfs->radar_log[i].delta_diff,
190 			  dfs->radar_log[i].delta_peak,
191 			  dfs->radar_log[i].psidx_diff);
192 	}
193 	dfs->dfs_event_log_count = 0;
194 	dfs->dfs_phyerr_count = 0;
195 	dfs->dfs_phyerr_reject_count = 0;
196 	dfs->dfs_phyerr_queued_count = 0;
197 	dfs->dfs_phyerr_freq_min = 0x7fffffff;
198 	dfs->dfs_phyerr_freq_max = 0;
199 }
200 
201 #ifndef CONFIG_EXT_RADAR_PROCESS
202 /**
203  * dfs_is_real_radar() - This function checks for fractional PRI and jitter in
204  * sidx index to determine if the radar is real or not.
205  * @dfs: Pointer to dfs structure.
206  * @rf: Pointer to dfs_filter structure.
207  * @ext_chan_flag: ext chan flags.
208  *
209  * Return : true if real RADAR else false.
210  */
211 static bool dfs_is_real_radar(struct wlan_dfs *dfs,
212 			      struct dfs_filter *rf,
213 			      int ext_chan_flag)
214 {
215 	int i = 0;
216 	int index;
217 	struct dfs_delayline *dl = &rf->rf_dl;
218 	struct dfs_delayelem *de;
219 	uint64_t target_ts = 0;
220 	struct dfs_pulseline *pl;
221 	int start_index = 0, current_index, next_index;
222 	unsigned char scores[FRAC_PRI_SCORE_ARRAY_SIZE];
223 	uint32_t pri_margin;
224 	uint64_t this_diff_ts;
225 	uint32_t search_bin;
226 
227 	unsigned char max_score = 0;
228 	int max_score_index = 0;
229 
230 	pl = dfs->pulses;
231 
232 	OS_MEMZERO(scores, sizeof(scores));
233 	scores[0] = rf->rf_threshold;
234 
235 	pri_margin = dfs_get_pri_margin(dfs, ext_chan_flag,
236 			(rf->rf_patterntype == 1));
237 
238 	/*
239 	 * Look for the entry that matches dl_seq_num_second.
240 	 * we need the time stamp and diff_ts from there.
241 	 */
242 
243 	for (i = 0; i < dl->dl_numelems; i++) {
244 		index = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK;
245 		de = &dl->dl_elems[index];
246 		if (dl->dl_seq_num_second == de->de_seq_num)
247 			target_ts = de->de_ts - de->de_time;
248 	}
249 
250 	if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS2) {
251 		dfs_print_delayline(dfs, &rf->rf_dl);
252 
253 		dfs_debug(dfs, WLAN_DEBUG_DFS2, "Pulse Line");
254 		for (i = 0; i < pl->pl_numelems; i++) {
255 			index =  (pl->pl_firstelem + i) &
256 				DFS_MAX_PULSE_BUFFER_MASK;
257 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
258 					"Elem %u: ts=%llu dur=%u, seq_num=%d, delta_peak=%d, psidx_diff=%d\n",
259 					i, pl->pl_elems[index].p_time,
260 					pl->pl_elems[index].p_dur,
261 					pl->pl_elems[index].p_seq_num,
262 					pl->pl_elems[index].p_delta_peak,
263 					pl->pl_elems[index].p_psidx_diff);
264 		}
265 	}
266 
267 	/*
268 	 * Walk through the pulse line and find pulse with target_ts.
269 	 * Then continue until we find entry with seq_number dl_seq_num_stop.
270 	 */
271 
272 	for (i = 0; i < pl->pl_numelems; i++) {
273 		index =  (pl->pl_firstelem + i) & DFS_MAX_PULSE_BUFFER_MASK;
274 		if (pl->pl_elems[index].p_time == target_ts) {
275 			dl->dl_seq_num_start = pl->pl_elems[index].p_seq_num;
276 			start_index = index; /* save for future use */
277 		}
278 	}
279 
280 	dfs_debug(dfs, WLAN_DEBUG_DFS2,
281 		  "target_ts=%llu, dl_seq_num_start=%d, dl_seq_num_second=%d, dl_seq_num_stop=%d",
282 		  target_ts, dl->dl_seq_num_start,
283 		  dl->dl_seq_num_second, dl->dl_seq_num_stop);
284 
285 	current_index = start_index;
286 	while (pl->pl_elems[current_index].p_seq_num < dl->dl_seq_num_stop) {
287 		next_index = (current_index + 1) & DFS_MAX_PULSE_BUFFER_MASK;
288 		this_diff_ts = pl->pl_elems[next_index].p_time -
289 			pl->pl_elems[current_index].p_time;
290 
291 		/* Now update the score for this diff_ts */
292 		for (i = 1; i < FRAC_PRI_SCORE_ARRAY_SIZE; i++) {
293 			search_bin = dl->dl_search_pri / (i + 1);
294 
295 			/*
296 			 * We do not give score to PRI that is lower then the
297 			 * limit.
298 			 */
299 			if (search_bin < dfs->dfs_lowest_pri_limit)
300 				break;
301 
302 			/*
303 			 * Increment the score if this_diff_ts belongs to this
304 			 * search_bin +/- margin.
305 			 */
306 			if ((this_diff_ts >= (search_bin - pri_margin)) &&
307 					(this_diff_ts <=
308 					 (search_bin + pri_margin))) {
309 				/*increment score */
310 				scores[i]++;
311 			}
312 		}
313 		current_index = next_index;
314 	}
315 
316 	for (i = 0; i < FRAC_PRI_SCORE_ARRAY_SIZE; i++)
317 		if (scores[i] > max_score) {
318 			max_score = scores[i];
319 			max_score_index = i;
320 		}
321 
322 	if (max_score_index != 0) {
323 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
324 			  "Rejecting Radar since Fractional PRI detected: searchpri=%d, threshold=%d, fractional PRI=%d, Fractional PRI score=%d",
325 			  dl->dl_search_pri, scores[0],
326 			  dl->dl_search_pri/(max_score_index + 1),
327 			  max_score);
328 		return 0;
329 	}
330 
331 
332 	/* Check for frequency spread */
333 	if (dl->dl_min_sidx > pl->pl_elems[start_index].p_sidx)
334 		dl->dl_min_sidx = pl->pl_elems[start_index].p_sidx;
335 
336 	if (dl->dl_max_sidx < pl->pl_elems[start_index].p_sidx)
337 		dl->dl_max_sidx = pl->pl_elems[start_index].p_sidx;
338 
339 	if ((dl->dl_max_sidx - dl->dl_min_sidx) > rf->rf_sidx_spread) {
340 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
341 			  "Rejecting Radar since frequency spread is too large : min_sidx=%d, max_sidx=%d, rf_sidx_spread=%d",
342 			  dl->dl_min_sidx, dl->dl_max_sidx,
343 			  rf->rf_sidx_spread);
344 		return 0;
345 	}
346 
347 	if ((rf->rf_check_delta_peak) &&
348 			((dl->dl_delta_peak_match_count +
349 			dl->dl_psidx_diff_match_count - 1) <
350 			rf->rf_threshold)) {
351 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
352 			  "Rejecting Radar since delta peak values are invalid : dl_delta_peak_match_count=%d, dl_psidx_diff_match_count=%d, rf_threshold=%d",
353 			  dl->dl_delta_peak_match_count,
354 			  dl->dl_psidx_diff_match_count,
355 			  rf->rf_threshold);
356 		return 0;
357 	}
358 	dfs_debug(dfs, WLAN_DEBUG_DFS_FALSE_DET,
359 		  "dl->dl_min_sidx: %d, dl->dl_max_sidx: %d",
360 		  dl->dl_min_sidx, dl->dl_max_sidx);
361 
362 	dfs->dfs_freq_offset = DFS_SIDX_TO_FREQ_OFFSET((dl->dl_min_sidx +
363 							dl->dl_max_sidx) / 2);
364 	return 1;
365 }
366 #endif /* CONFIG_EXT_RADAR_PROCESS */
367 
368 /*
369  * dfs_reject_on_pri() - Rejecting on individual filter based on min PRI .
370  * @dfs: Pointer to wlan_dfs structure.
371  * @rf: Pointer to dfs_filter structure.
372  * @deltaT: deltaT value.
373  * @this_ts: Timestamp.
374  */
375 static inline bool dfs_reject_on_pri(
376 		struct wlan_dfs *dfs,
377 		struct dfs_filter *rf,
378 		uint64_t deltaT,
379 		uint64_t this_ts)
380 {
381 	if ((deltaT < rf->rf_minpri) && (deltaT != 0)) {
382 		/* Second line of PRI filtering. */
383 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
384 				"filterID %d : Rejecting on individual filter min PRI deltaT=%lld rf->rf_minpri=%u",
385 				rf->rf_pulseid, (uint64_t)deltaT,
386 				rf->rf_minpri);
387 		return 1;
388 	}
389 
390 	if (rf->rf_ignore_pri_window > 0) {
391 		if (deltaT < rf->rf_minpri) {
392 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
393 					"filterID %d : Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u",
394 					rf->rf_pulseid, (uint64_t)deltaT,
395 					rf->rf_minpri);
396 			/* But update the last time stamp. */
397 			rf->rf_dl.dl_last_ts = this_ts;
398 			return 1;
399 		}
400 	} else {
401 		/*
402 		 * The HW may miss some pulses especially with
403 		 * high channel loading. This is true for Japan
404 		 * W53 where channel loaoding is 50%. Also for
405 		 * ETSI where channel loading is 30% this can
406 		 * be an issue too. To take care of missing
407 		 * pulses, we introduce pri_margin multiplie.
408 		 * This is normally 2 but can be higher for W53.
409 		 */
410 
411 		if ((deltaT > (dfs->dfs_pri_multiplier * rf->rf_maxpri)) ||
412 				(deltaT < rf->rf_minpri)) {
413 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
414 					"filterID %d : Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u",
415 					rf->rf_pulseid, (uint64_t) deltaT,
416 					rf->rf_minpri);
417 			/* But update the last time stamp. */
418 			rf->rf_dl.dl_last_ts = this_ts;
419 			return 1;
420 		}
421 	}
422 
423 	return 0;
424 }
425 
426 /**
427  * dfs_confirm_radar_check() - Do additioal check to conirm radar except for
428  * the staggered, chirp FCC Bin 5, frequency hopping indicated by
429  * rf_patterntype == 1.
430  * @dfs: Pointer to wlan_dfs structure.
431  * @rf: Pointer to dfs_filter structure.
432  * @ext_chan_event_flag: Extension channel event flag
433  * @found: Pointer to radar found flag (return value).
434  * @false_radar_found: Pointer to false radar found (return value).
435  */
436 
437 static inline void dfs_confirm_radar_check(
438 		struct wlan_dfs *dfs,
439 		struct dfs_filter *rf,
440 		int ext_chan_event_flag,
441 		int *found,
442 		int *false_radar_found)
443 {
444 	if (rf->rf_patterntype != 1) {
445 		*found = (int)dfs_is_real_radar(dfs, rf, ext_chan_event_flag);
446 		*false_radar_found = (*found == 1) ? 0 : 1;
447 	}
448 }
449 
450 void __dfs_process_radarevent(struct wlan_dfs *dfs,
451 		struct dfs_filtertype *ft,
452 		struct dfs_event *re,
453 		uint64_t this_ts,
454 		int *found,
455 		int *false_radar_found)
456 {
457 	int p;
458 	uint64_t deltaT = 0;
459 	int ext_chan_event_flag = 0;
460 	struct dfs_filter *rf = NULL;
461 	int8_t ori_rf_check_delta_peak = 0;
462 
463 	for (p = 0, *found = 0; (p < ft->ft_numfilters) &&
464 			(!(*found)) && !(*false_radar_found); p++) {
465 		rf = ft->ft_filters[p];
466 		if ((re->re_dur >= rf->rf_mindur) &&
467 				(re->re_dur <= rf->rf_maxdur)) {
468 			/* The above check is probably not necessary. */
469 			deltaT = (this_ts < rf->rf_dl.dl_last_ts) ?
470 			    (int64_t)((DFS_TSF_WRAP - rf->rf_dl.dl_last_ts) +
471 				    this_ts + 1) :
472 			    this_ts - rf->rf_dl.dl_last_ts;
473 
474 			if (dfs_reject_on_pri(dfs, rf, deltaT, this_ts))
475 				continue;
476 
477 			dfs_add_pulse(dfs, rf, re, deltaT, this_ts);
478 
479 			/*
480 			 * If this is an extension channel event, flag it for
481 			 * false alarm reduction.
482 			 */
483 			if (re->re_chanindex == dfs->dfs_extchan_radindex)
484 				ext_chan_event_flag = 1;
485 
486 			if (rf->rf_patterntype == 2) {
487 				*found = dfs_staggered_check(dfs, rf,
488 					(uint32_t) deltaT, re->re_dur);
489 			} else {
490 				*found = dfs_bin_check(dfs, rf,
491 					(uint32_t) deltaT, re->re_dur,
492 					ext_chan_event_flag);
493 
494 				if (*found &&
495 				    (utils_get_dfsdomain(dfs->dfs_pdev_obj) !=
496 				     DFS_CN_DOMAIN)) {
497 					ori_rf_check_delta_peak =
498 						rf->rf_check_delta_peak;
499 					/*
500 					 * If FW does not send valid psidx_diff
501 					 * Do not do chirp check.
502 					 */
503 					if (rf->rf_check_delta_peak &&
504 						(!(re->re_flags &
505 						DFS_EVENT_VALID_PSIDX_DIFF)))
506 						rf->rf_check_delta_peak = false;
507 					dfs_confirm_radar_check(dfs,
508 							rf, ext_chan_event_flag,
509 							found,
510 							false_radar_found);
511 					rf->rf_check_delta_peak =
512 						ori_rf_check_delta_peak;
513 				}
514 			}
515 
516 			if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS2)
517 				if (rf->rf_patterntype !=
518 						WLAN_DFS_RF_PATTERN_TYPE_1)
519 					dfs_print_delayline(dfs, &rf->rf_dl);
520 
521 			rf->rf_dl.dl_last_ts = this_ts;
522 		}
523 	}
524 
525 	if (*found) {
526 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
527 			  "Found on channel minDur = %d, filterId = %d",
528 			  ft->ft_mindur,
529 			  rf ?  rf->rf_pulseid : -1);
530 	}
531 
532 	return;
533 }
534 
535 /**
536  * dfs_cal_average_radar_parameters() - Calculate the average radar parameters.
537  * @dfs: Pointer to wlan_dfs structure.
538  */
539 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
540 static void dfs_cal_average_radar_parameters(struct wlan_dfs *dfs)
541 {
542 	int i, count = 0;
543 	u_int32_t total_pri = 0;
544 	u_int32_t total_duration = 0;
545 	u_int32_t total_sidx = 0;
546 
547 	/* Calculating average PRI, Duration, SIDX from
548 	 * the 2nd pulse, ignoring the 1st pulse (radar_log[0]).
549 	 * This is because for the first pulse, the diff_ts will be
550 	 * (0 - current_ts) which will be a huge value.
551 	 * Average PRI computation will be wrong. FW returns a
552 	 * failure test result as PRI does not match their expected
553 	 * value.
554 	 */
555 
556 	for (i = 1; (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count);
557 			i++) {
558 		total_pri +=  dfs->radar_log[i].diff_ts;
559 		total_duration += dfs->radar_log[i].dur;
560 		total_sidx +=  dfs->radar_log[i].sidx;
561 		count++;
562 	}
563 
564 	if (count > 0) {
565 		dfs->dfs_average_pri = total_pri / count;
566 		dfs->dfs_average_duration = total_duration / count;
567 		dfs->dfs_average_sidx = total_sidx / count;
568 
569 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
570 			  "Avg.PRI =%u, Avg.duration =%u Avg.sidx =%u",
571 			  dfs->dfs_average_pri,
572 			  dfs->dfs_average_duration,
573 			  dfs->dfs_average_sidx);
574 	}
575 }
576 #else
577 static void dfs_cal_average_radar_parameters(struct wlan_dfs *dfs)
578 {
579 }
580 #endif
581 
582 /**
583  * dfs_radarfound_reset_vars() - Reset dfs variables after radar found
584  * @dfs: Pointer to wlan_dfs structure.
585  * @rs: Pointer to dfs_state.
586  * @chan: Current  channel.
587  * @seg_id: Segment id.
588  */
589 static inline void dfs_radarfound_reset_vars(
590 		struct wlan_dfs *dfs,
591 		struct dfs_state *rs,
592 		struct dfs_channel *chan,
593 		uint8_t seg_id)
594 {
595 	struct dfs_channel *thischan;
596 
597 	/*
598 	 * TODO: Instead of discarding the radar, create a workqueue
599 	 * if the channel change is happenning through userspace and
600 	 * process the radar event once the channel change is completed.
601 	 */
602 
603 	/* Collect stats */
604 	dfs->wlan_dfs_stats.num_radar_detects++;
605 	thischan = &rs->rs_chan;
606 	if ((seg_id == SEG_ID_SECONDARY) &&
607 			(dfs_is_precac_timer_running(dfs)))
608 		dfs->is_radar_during_precac = 1;
609 
610 	/*
611 	 * If event log is on then dump the radar event queue on
612 	 * filter match. This can be used to collect information
613 	 * on false radar detection.
614 	 */
615 	if (dfs->dfs_event_log_on) {
616 		dfs_cal_average_radar_parameters(dfs);
617 		dfs_print_radar_events(dfs);
618 	}
619 
620 	dfs_reset_radarq(dfs);
621 	dfs_reset_alldelaylines(dfs);
622 
623 	dfs_debug(dfs, WLAN_DEBUG_DFS1,
624 			"Primary channel freq = %u flags=0x%x",
625 			chan->dfs_ch_freq, chan->dfs_ch_flagext);
626 
627 	if (chan->dfs_ch_freq != thischan->dfs_ch_freq)
628 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
629 				"Ext channel freq = %u flags=0x%x",
630 				thischan->dfs_ch_freq,
631 				thischan->dfs_ch_flagext);
632 
633 	dfs->dfs_phyerr_freq_min = 0x7fffffff;
634 	dfs->dfs_phyerr_freq_max = 0;
635 	dfs->dfs_phyerr_w53_counter = 0;
636 
637 	if (seg_id == SEG_ID_SECONDARY) {
638 		dfs->wlan_dfs_stats.num_seg_two_radar_detects++;
639 		dfs->is_radar_found_on_secondary_seg = 1;
640 	}
641 }
642 
643 /*
644  * dfs_print_radar_found_freq() - Print radar found frequency.
645  * @dfs: Pointer to wlan_dfs.
646  */
647 #ifdef CONFIG_CHAN_FREQ_API
648 static void dfs_print_radar_found_freq(struct wlan_dfs *dfs)
649 {
650 	dfs_debug(dfs, WLAN_DEBUG_DFS,
651 		  "bangradar on 2nd segment cfreq = %u",
652 		  dfs->dfs_precac_secondary_freq_mhz);
653 }
654 #endif
655 
656 /**
657  * dfs_handle_bangradar - Handle the case of bangradar
658  * @dfs: Pointer to wlan_dfs structure.
659  * @chan: Current channel.
660  * @rs: Pointer to dfs_state.
661  * Return: if bangradar then  return 1.  Otherwise, return 0.
662  */
663 static inline int dfs_handle_bangradar(
664 	struct wlan_dfs *dfs,
665 	struct dfs_channel *chan,
666 	struct dfs_state **rs,
667 	uint8_t *seg_id,
668 	int *retval)
669 {
670 
671 	if (dfs->dfs_bangradar_type) {
672 		if (dfs->dfs_bangradar_type >= DFS_INVALID_BANGRADAR_TYPE) {
673 			dfs_debug(dfs, WLAN_DEBUG_DFS,
674 				  "Invalid bangradar type");
675 			return 1;
676 		}
677 		/* All bangradars are processed similarly.
678 		 * arguments for the bangradar are already stored in
679 		 * respective dfs structures.
680 		 */
681 
682 		*rs = &dfs->dfs_radar[dfs->dfs_curchan_radindex];
683 		if (dfs->dfs_seg_id == SEG_ID_SECONDARY) {
684 			if (dfs_is_precac_timer_running(dfs) ||
685 			    WLAN_IS_CHAN_11AC_VHT160(chan) ||
686 			    WLAN_IS_CHAN_11AC_VHT80_80(chan)) {
687 				dfs->is_radar_found_on_secondary_seg = 1;
688 				dfs_print_radar_found_freq(dfs);
689 			} else {
690 				dfs_debug(dfs, WLAN_DEBUG_DFS,
691 					  "No second segment");
692 				return 1;
693 			}
694 		}
695 		*seg_id = dfs->dfs_seg_id;
696 		dfs_debug(dfs, WLAN_DEBUG_DFS, "bangradar %d",
697 			  dfs->dfs_bangradar_type);
698 		*retval = 1;
699 		return 1;
700 	}
701 	return 0;
702 }
703 
704 /**
705  * dfs_process_w53_pulses() - Prrocess w53 pulses
706  * @dfs: Pointer to wlan_dfs structure.
707  *
708  * For chips that support frequency information, we can relax PRI
709  * restriction if the frequency spread is narrow.
710  */
711 static inline void dfs_process_w53_pulses(
712 		struct wlan_dfs *dfs)
713 {
714 	if ((dfs->dfs_phyerr_freq_max - dfs->dfs_phyerr_freq_min) <
715 			DFS_MAX_FREQ_SPREAD)
716 		dfs->dfs_pri_multiplier = DFS_LARGE_PRI_MULTIPLIER;
717 
718 	dfs_debug(dfs, WLAN_DEBUG_DFS1,
719 			"w53_counter=%d, freq_max=%d, freq_min=%d, pri_multiplier=%d",
720 			 dfs->dfs_phyerr_w53_counter,
721 			dfs->dfs_phyerr_freq_max, dfs->dfs_phyerr_freq_min,
722 			dfs->dfs_pri_multiplier);
723 
724 	dfs->dfs_phyerr_freq_min = 0x7fffffff;
725 	dfs->dfs_phyerr_freq_max = 0;
726 }
727 
728 /**
729  * dfs_handle_missing_pulses - Handle the case of missing pulses
730  * @dfs: Pointer to wlan_dfs structure.
731  * @chan: Current channel.
732  *
733  * The HW may miss some pulses especially with high channel loading.
734  * This is true for Japan W53 where channel loaoding is 50%. Also
735  * for ETSI where channel loading is 30% this can be an issue too.
736  * To take care of missing pulses, we introduce pri_margin multiplie.
737  * This is normally 2 but can be higher for W53.
738  * Return: If not enough pulses return 0.  Otherwise, return 1.
739  */
740 static inline int dfs_handle_missing_pulses(
741 		struct wlan_dfs *dfs,
742 		struct dfs_channel *chan)
743 {
744 	if ((dfs->dfsdomain  == DFS_MKK4_DOMAIN ||
745 	     dfs->dfsdomain == DFS_MKKN_DOMAIN) &&
746 			(dfs->dfs_caps.wlan_chip_is_bb_tlv) &&
747 			(chan->dfs_ch_freq < FREQ_5500_MHZ)) {
748 		dfs->dfs_pri_multiplier = DFS_W53_DEFAULT_PRI_MULTIPLIER;
749 		/*
750 		 * Do not process W53 pulses unless we have a minimum number
751 		 * of them.
752 		 */
753 		if (dfs->dfs_phyerr_w53_counter >= 5)
754 			dfs_process_w53_pulses(dfs);
755 		else
756 			return 0;
757 	}
758 
759 	dfs_debug(dfs, WLAN_DEBUG_DFS1, "pri_multiplier=%d",
760 			 dfs->dfs_pri_multiplier);
761 
762 	return 1;
763 }
764 
765 /**
766  * dfs_is_radarq_empty - check if radarq is empty
767  * @dfs: Pointer to wlan_dfs structure.
768  * @empty: Pointer to empty
769  */
770 static inline void dfs_is_radarq_empty(
771 		struct wlan_dfs *dfs,
772 		int *empty)
773 {
774 	WLAN_DFSQ_LOCK(dfs);
775 	*empty = STAILQ_EMPTY(&(dfs->dfs_radarq));
776 	WLAN_DFSQ_UNLOCK(dfs);
777 }
778 
779 /**
780  * dfs_remove_event_from_radarq - remove event from radarq
781  * @dfs: Pointer to wlan_dfs structure.
782  * @event: Double pointer to the event structure
783  */
784 static inline void dfs_remove_event_from_radarq(
785 		struct wlan_dfs *dfs,
786 		struct dfs_event **event)
787 {
788 	WLAN_DFSQ_LOCK(dfs);
789 	*event = STAILQ_FIRST(&(dfs->dfs_radarq));
790 	if (*event)
791 		STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list);
792 	WLAN_DFSQ_UNLOCK(dfs);
793 }
794 
795 /**
796  * dfs_return_event_to_eventq - return event to eventq
797  * @dfs: Pointer to wlan_dfs structure.
798  * @event: Pointer to the event structure
799  */
800 static inline void dfs_return_event_to_eventq(
801 		struct wlan_dfs *dfs,
802 		struct dfs_event *event)
803 {
804 	qdf_mem_zero(event, sizeof(struct dfs_event));
805 	WLAN_DFSEVENTQ_LOCK(dfs);
806 	STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list);
807 	WLAN_DFSEVENTQ_UNLOCK(dfs);
808 }
809 
810 /**
811  * dfs_log_event - log dfs event
812  * @dfs: Pointer to wlan_dfs structure.
813  * @re:  Pointer to dfs_event re
814  * @this_ts: Current time stamp 64bit
815  * @diff_ts: Difference between 2 timestamps 32bit
816  * @index: Index value.
817  */
818 static inline void dfs_log_event(
819 		struct wlan_dfs *dfs,
820 		struct dfs_event *re,
821 		uint64_t this_ts,
822 		uint32_t diff_ts,
823 		uint32_t index)
824 {
825 	uint8_t i;
826 	struct dfs_pulseline *pl = dfs->pulses;
827 
828 	if (dfs->dfs_event_log_on) {
829 		i = dfs->dfs_event_log_count % DFS_EVENT_LOG_SIZE;
830 		dfs->radar_log[i].ts = this_ts;
831 		dfs->radar_log[i].diff_ts = diff_ts;
832 		dfs->radar_log[i].rssi = (*re).re_rssi;
833 		dfs->radar_log[i].dur = (*re).re_dur;
834 		dfs->radar_log[i].seg_id = (*re).re_seg_id;
835 		dfs->radar_log[i].sidx = (*re).re_sidx;
836 		dfs->radar_log[i].freq_offset_khz =
837 			(*re).re_freq_offset_khz;
838 		dfs->radar_log[i].peak_mag = (*re).re_peak_mag;
839 		dfs->radar_log[i].total_gain = (*re).re_total_gain;
840 		dfs->radar_log[i].mb_gain = (*re).re_mb_gain;
841 		dfs->radar_log[i].relpwr_db = (*re).re_relpwr_db;
842 		dfs->radar_log[i].delta_diff = (*re).re_delta_diff;
843 		dfs->radar_log[i].delta_peak = (*re).re_delta_peak;
844 		dfs->radar_log[i].psidx_diff = (*re).re_psidx_diff;
845 		dfs->radar_log[i].is_chirp = DFS_EVENT_NOTCHIRP(re) ?
846 			0 : 1;
847 		dfs->dfs_event_log_count++;
848 	}
849 
850 	dfs->dfs_seq_num++;
851 	pl->pl_elems[index].p_seq_num = dfs->dfs_seq_num;
852 }
853 
854 /**
855  * dfs_check_if_nonbin5 - Check if radar, other than bin5, is found
856  * @dfs: Pointer to wlan_dfs structure.
857  * @re: Pointer to re (radar event)
858  * @rs: Double Pointer to rs (radar state)
859  * @this_ts: Current time stamp 64bit
860  * @diff_ts: Difference between 2 timestamps 32bit
861  * @found: Pointer to found. If radar found or not.
862  * @retval: Pointer to retval(return value).
863  * @false_radar_found: Pointer to false_radar_found(return value).
864  */
865 static inline void dfs_check_if_nonbin5(
866 	struct wlan_dfs *dfs,
867 	struct dfs_event *re,
868 	struct dfs_state **rs,
869 	uint64_t this_ts,
870 	uint32_t diff_ts,
871 	int *found,
872 	int *retval,
873 	int *false_radar_found)
874 {
875 
876 	uint32_t tabledepth = 0;
877 	struct dfs_filtertype *ft;
878 	uint64_t deltaT;
879 
880 	dfs_debug(dfs, WLAN_DEBUG_DFS1,
881 			"  *** chan freq (%d): ts %llu dur %u rssi %u",
882 			(*rs)->rs_chan.dfs_ch_freq, (uint64_t)this_ts,
883 			(*re).re_dur, (*re).re_rssi);
884 
885 	while ((tabledepth < DFS_MAX_RADAR_OVERLAP) &&
886 			((dfs->dfs_ftindextable[(*re).re_dur])[tabledepth] !=
887 			 -1) && (!*retval) && !(*false_radar_found)) {
888 		ft = dfs->dfs_radarf[((dfs->dfs_ftindextable[(*re).re_dur])
889 				[tabledepth])];
890 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
891 				"  ** RD (%d): ts %x dur %u rssi %u",
892 				(*rs)->rs_chan.dfs_ch_freq, (*re).re_ts,
893 				(*re).re_dur, (*re).re_rssi);
894 
895 		if ((*re).re_rssi < ft->ft_rssithresh &&
896 				(*re).re_dur > MAX_DUR_FOR_LOW_RSSI) {
897 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
898 					"Rejecting on rssi rssi=%u thresh=%u",
899 					 (*re).re_rssi,
900 					ft->ft_rssithresh);
901 			tabledepth++;
902 			continue;
903 		}
904 		deltaT = this_ts - ft->ft_last_ts;
905 		dfs_debug(dfs, WLAN_DEBUG_DFS2,
906 				"deltaT = %lld (ts: 0x%llx) (last ts: 0x%llx)",
907 				(uint64_t)deltaT, (uint64_t)this_ts,
908 				(uint64_t)ft->ft_last_ts);
909 
910 		if ((deltaT < ft->ft_minpri) && (deltaT != 0)) {
911 			/*
912 			 * This check is for the whole filter type.
913 			 * Individual filters will check this again.
914 			 * This is first line of filtering.
915 			 */
916 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
917 					"Rejecting on pri pri=%lld minpri=%u",
918 					 (uint64_t)deltaT, ft->ft_minpri);
919 			tabledepth++;
920 			continue;
921 		}
922 
923 		__dfs_process_radarevent(dfs, ft, re, this_ts, found,
924 				false_radar_found);
925 
926 		ft->ft_last_ts = this_ts;
927 		*retval |= *found;
928 		tabledepth++;
929 	}
930 }
931 
932 /**
933  * dfs_check_each_b5radar() - Check each bin5 radar
934  * @dfs: Pointer to wlan_dfs structure.
935  * @re:  Pointer to re(radar event).
936  * @br: Pointer to dfs_bin5radars structure.
937  * @this_ts: Current time stamp 64bit.
938  * @diff_ts: Difference between 2 timestamps 32bit.
939  * @found: Pointer to found. If radar found or not.
940  */
941 static inline void dfs_check_each_b5radar(
942 		struct wlan_dfs *dfs,
943 		struct dfs_event *re,
944 		struct dfs_bin5radars *br,
945 		uint64_t this_ts,
946 		uint32_t diff_ts,
947 		int *found)
948 {
949 	if (dfs_bin5_check_pulse(dfs, re, br)) {
950 		/*
951 		 * This is a valid Bin5 pulse, check if it belongs to a
952 		 * burst.
953 		 */
954 		(*re).re_dur = dfs_retain_bin5_burst_pattern(dfs, diff_ts,
955 				(*re).re_dur);
956 		/*
957 		 * Remember our computed duration for the next pulse in the
958 		 * burst (if needed).
959 		 */
960 		dfs->dfs_rinfo.dfs_bin5_chirp_ts = this_ts;
961 		dfs->dfs_rinfo.dfs_last_bin5_dur = (*re).re_dur;
962 
963 		if (dfs_bin5_addpulse(dfs, br, re, this_ts))
964 			*found |= dfs_bin5_check(dfs);
965 	} else {
966 		dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_PULSE,
967 				"not a BIN5 pulse (dur=%d)", (*re).re_dur);
968 	}
969 }
970 
971 /**
972  * dfs_check_if_bin5() - Check if bin5 radar is found
973  * @dfs: Pointer to wlan_dfs structure.
974  * @re:  Pointer to re(radar event).
975  * @this_ts: Current time stamp 64bit.
976  * @diff_ts: Difference between 2 timestamps 32bit.
977  * @found: Pointer to found. If radar found or not.
978  */
979 static inline void dfs_check_if_bin5(
980 	struct wlan_dfs *dfs,
981 	struct dfs_event *re,
982 	uint64_t this_ts,
983 	uint32_t diff_ts,
984 	int *found)
985 {
986 	int p;
987 
988 	/* BIN5 pulses are FCC and Japan specific. */
989 	if ((dfs->dfsdomain == DFS_FCC_DOMAIN) ||
990 	    (dfs->dfsdomain == DFS_MKK4_DOMAIN) ||
991 	    (dfs->dfsdomain == DFS_MKKN_DOMAIN)) {
992 		for (p = 0; (p < dfs->dfs_rinfo.rn_numbin5radars) && (!*found);
993 				p++) {
994 			struct dfs_bin5radars *br;
995 
996 			br = &(dfs->dfs_b5radars[p]);
997 			dfs_check_each_b5radar(dfs, re, br, this_ts, diff_ts,
998 					found);
999 		}
1000 	}
1001 
1002 	if (*found)
1003 		dfs_debug(dfs, WLAN_DEBUG_DFS, "Found bin5 radar");
1004 }
1005 
1006 /**
1007  * dfs_skip_the_event() - Skip the Radar event
1008  * @dfs: Pointer to wlan_dfs structure.
1009  * @re: Pointer to re(radar event).
1010  * @rs: Pointer to dfs_state.
1011  */
1012 static inline bool dfs_skip_the_event(
1013 	struct wlan_dfs *dfs,
1014 	struct dfs_event *re,
1015 	struct dfs_state **rs)
1016 {
1017 	if ((*re).re_chanindex < DFS_NUM_RADAR_STATES)
1018 		(*rs) = &dfs->dfs_radar[(*re).re_chanindex];
1019 	else
1020 		return 1;
1021 
1022 	if ((*rs)->rs_chan.dfs_ch_flagext & CHANNEL_INTERFERENCE)
1023 		return 1;
1024 
1025 	return 0;
1026 }
1027 
1028 /**
1029  * dfs_check_ts_wrap() - dfs check for timestamp wrap.
1030  * @dfs: Pointer to wlan_dfs structure.
1031  * @re: Pointer to re(radar event).
1032  * @deltafull_ts: Deltafull ts.
1033  *
1034  * Return: Deltafull ts.
1035  */
1036 static inline uint64_t dfs_check_ts_wrap(
1037 		struct wlan_dfs *dfs,
1038 		struct dfs_event *re,
1039 		uint64_t deltafull_ts)
1040 {
1041 	if (deltafull_ts >
1042 			((uint64_t)((DFS_TSMASK -
1043 					dfs->dfs_rinfo.rn_last_ts) +
1044 				1 + (*re).re_ts)))
1045 		deltafull_ts -=
1046 			(DFS_TSMASK - dfs->dfs_rinfo.rn_last_ts) +
1047 			1 + (*re).re_ts;
1048 
1049 	return deltafull_ts;
1050 }
1051 
1052 /**
1053  * dfs_calculate_ts_prefix() - Calculate deltafull ts value.
1054  * @dfs: Pointer to wlan_dfs structure.
1055  * @re: Pointer to re(radar event).
1056  */
1057 static inline void dfs_calculate_ts_prefix(
1058 		struct wlan_dfs *dfs,
1059 		struct dfs_event *re)
1060 {
1061 	uint64_t deltafull_ts;
1062 
1063 	if ((*re).re_ts <= dfs->dfs_rinfo.rn_last_ts) {
1064 		dfs->dfs_rinfo.rn_ts_prefix += (((uint64_t) 1) << DFS_TSSHIFT);
1065 		/* Now, see if it's been more than 1 wrap */
1066 		deltafull_ts = (*re).re_full_ts - dfs->dfs_rinfo.rn_lastfull_ts;
1067 		deltafull_ts = dfs_check_ts_wrap(dfs, re, deltafull_ts);
1068 		deltafull_ts >>= DFS_TSSHIFT;
1069 
1070 		if (deltafull_ts > 1)
1071 			dfs->dfs_rinfo.rn_ts_prefix +=
1072 				((deltafull_ts - 1) << DFS_TSSHIFT);
1073 	} else {
1074 		deltafull_ts = (*re).re_full_ts -
1075 			dfs->dfs_rinfo.rn_lastfull_ts;
1076 		if (deltafull_ts > (uint64_t) DFS_TSMASK) {
1077 			deltafull_ts >>= DFS_TSSHIFT;
1078 			dfs->dfs_rinfo.rn_ts_prefix +=
1079 				((deltafull_ts - 1) << DFS_TSSHIFT);
1080 		}
1081 	}
1082 }
1083 
1084 /**
1085  * dfs_calculate_timestamps() - Calculate various timestamps
1086  * @dfs: Pointer to wlan_dfs structure.
1087  * @re: Pointer to re(radar event)
1088  * @this_ts : Pointer to  this_ts (this timestamp)
1089  */
1090 
1091 static inline void  dfs_calculate_timestamps(
1092 	struct wlan_dfs *dfs,
1093 	struct dfs_event *re,
1094 	uint64_t *this_ts)
1095 {
1096 	if (dfs->dfs_rinfo.rn_lastfull_ts == 0) {
1097 		/*
1098 		 * Either not started, or 64-bit rollover exactly to
1099 		 * zero Just prepend zeros to the 15-bit ts.
1100 		 */
1101 		dfs->dfs_rinfo.rn_ts_prefix = 0;
1102 	} else {
1103 		/* WAR 23031- patch duplicate ts on very short pulses.
1104 		 * This pacth has two problems in linux environment.
1105 		 * 1)The time stamp created and hence PRI depends
1106 		 * entirely on the latency. If the latency is high, it
1107 		 * possibly can split two consecutive pulses in the
1108 		 * same burst so far away (the same amount of latency)
1109 		 * that make them look like they are from differenct
1110 		 * bursts. It is observed to happen too often. It sure
1111 		 * makes the detection fail.
1112 		 * 2)Even if the latency is not that bad, it simply
1113 		 * shifts the duplicate timestamps to a new duplicate
1114 		 * timestamp based on how they are processed.
1115 		 * This is not worse but not good either.
1116 		 * Take this pulse as a good one and create a probable
1117 		 * PRI later.
1118 		 */
1119 		if ((*re).re_dur == 0 && (*re).re_ts ==
1120 				dfs->dfs_rinfo.rn_last_unique_ts) {
1121 			debug_dup[debug_dup_cnt++] = '1';
1122 			dfs_debug(dfs, WLAN_DEBUG_DFS1, "deltaT is 0");
1123 		} else {
1124 			dfs->dfs_rinfo.rn_last_unique_ts = (*re).re_ts;
1125 			debug_dup[debug_dup_cnt++] = '0';
1126 		}
1127 
1128 		if (debug_dup_cnt >= 32)
1129 			debug_dup_cnt = 0;
1130 
1131 		dfs_calculate_ts_prefix(dfs, re);
1132 	}
1133 
1134 	/*
1135 	 * At this stage rn_ts_prefix has either been blanked or
1136 	 * calculated, so it's safe to use.
1137 	 */
1138 	*this_ts = dfs->dfs_rinfo.rn_ts_prefix | ((uint64_t) (*re).re_ts);
1139 	dfs->dfs_rinfo.rn_lastfull_ts = (*re).re_full_ts;
1140 	dfs->dfs_rinfo.rn_last_ts = (*re).re_ts;
1141 }
1142 
1143 /**
1144  * dfs_add_to_pulseline - Extract necessary items from dfs_event and
1145  * add it as pulse in the pulseline
1146  * @dfs: Pointer to wlan_dfs structure.
1147  * @re:  Pointer to re(radar event)
1148  * @this_ts: Pointer to  this_ts (this timestamp)
1149  * @diff_ts: Diff ts.
1150  * @index: Pointer to get index value.
1151  */
1152 static inline void dfs_add_to_pulseline(
1153 	struct wlan_dfs *dfs,
1154 	struct dfs_event *re,
1155 	uint64_t *this_ts,
1156 	uint32_t *test_ts,
1157 	uint32_t *diff_ts,
1158 	uint32_t *index)
1159 {
1160 	struct dfs_pulseline *pl;
1161 
1162 	/*
1163 	 * Calculate the start of the radar pulse.
1164 	 *
1165 	 * The TSF is stamped by the MAC upon reception of the event,
1166 	 * which is (typically?) at the end of the event. But the
1167 	 * pattern matching code expects the event timestamps to be at
1168 	 * the start of the event. So to fake it, we subtract the pulse
1169 	 * duration from the given TSF. This is done after the 64-bit
1170 	 * timestamp has been calculated so long pulses correctly
1171 	 * under-wrap the counter.  Ie, if this was done on the 32
1172 	 * (or 15!) bit TSF when the TSF value is closed to 0, it will
1173 	 * underflow to 0xfffffXX, which would mess up the logical "OR"
1174 	 * operation done above.
1175 	 * This isn't valid for Peregrine as the hardware gives us the
1176 	 * actual TSF offset of the radar event, not just the MAC TSF
1177 	 * of the completed receive.
1178 	 *
1179 	 * XXX TODO: ensure that the TLV PHY error processing code will
1180 	 * correctly calculate the TSF to be the start of the radar
1181 	 * pulse.
1182 	 *
1183 	 * XXX TODO TODO: modify the TLV parsing code to subtract the
1184 	 * duration from the TSF, based on the current fast clock value.
1185 	 */
1186 	if ((!dfs->dfs_caps.wlan_chip_is_bb_tlv) && (*re).re_dur != 1)
1187 		*this_ts -= (*re).re_dur;
1188 
1189 	pl = dfs->pulses;
1190 	/* Save the pulse parameters in the pulse buffer(pulse line). */
1191 	*index = (pl->pl_lastelem + 1) & DFS_MAX_PULSE_BUFFER_MASK;
1192 
1193 	if (pl->pl_numelems == DFS_MAX_PULSE_BUFFER_SIZE)
1194 		pl->pl_firstelem = (pl->pl_firstelem+1) &
1195 			DFS_MAX_PULSE_BUFFER_MASK;
1196 	else
1197 		pl->pl_numelems++;
1198 
1199 	pl->pl_lastelem = *index;
1200 	pl->pl_elems[*index].p_time = *this_ts;
1201 	pl->pl_elems[*index].p_dur = (*re).re_dur;
1202 	pl->pl_elems[*index].p_rssi = (*re).re_rssi;
1203 	pl->pl_elems[*index].p_sidx = (*re).re_sidx;
1204 	pl->pl_elems[*index].p_delta_peak = (*re).re_delta_peak;
1205 	pl->pl_elems[*index].p_psidx_diff = (*re).re_psidx_diff;
1206 	*diff_ts = (uint32_t)*this_ts - *test_ts;
1207 	*test_ts = (uint32_t)*this_ts;
1208 
1209 	dfs_debug(dfs, WLAN_DEBUG_DFS1,
1210 			"ts%u %u %u diff %u pl->pl_lastelem.p_time=%llu",
1211 			(uint32_t)*this_ts, (*re).re_dur,
1212 			(*re).re_rssi, *diff_ts,
1213 			(uint64_t)pl->pl_elems[*index].p_time);
1214 }
1215 
1216 /**
1217  * dfs_conditional_clear_delaylines - Clear delay lines to remove  the
1218  * false pulses.
1219  * @dfs: Pointer to wlan_dfs structure.
1220  * @diff_ts: diff between timerstamps.
1221  * @this_ts: this timestamp value.
1222  * @re: Pointer to dfs_event structure.
1223  */
1224 static inline void dfs_conditional_clear_delaylines(
1225 	struct wlan_dfs *dfs,
1226 	uint32_t diff_ts,
1227 	uint64_t this_ts,
1228 	struct dfs_event re)
1229 {
1230 	struct dfs_pulseline *pl = dfs->pulses;
1231 	uint32_t index;
1232 
1233 	/* If diff_ts is very small, we might be getting false pulse
1234 	 * detects due to heavy interference. We might be getting
1235 	 * spectral splatter from adjacent channel. In order to prevent
1236 	 * false alarms we clear the delay-lines. This might impact
1237 	 * positive detections under harsh environments, but helps with
1238 	 * false detects.
1239 	 */
1240 
1241 	if (diff_ts < dfs->dfs_lowest_pri_limit) {
1242 		dfs->dfs_seq_num = 0;
1243 		dfs_reset_alldelaylines(dfs);
1244 		dfs_reset_radarq(dfs);
1245 
1246 		index = (pl->pl_lastelem + 1) & DFS_MAX_PULSE_BUFFER_MASK;
1247 		if (pl->pl_numelems == DFS_MAX_PULSE_BUFFER_SIZE)
1248 			pl->pl_firstelem = (pl->pl_firstelem+1) &
1249 				DFS_MAX_PULSE_BUFFER_MASK;
1250 		else
1251 			pl->pl_numelems++;
1252 
1253 		pl->pl_lastelem = index;
1254 		pl->pl_elems[index].p_time = this_ts;
1255 		pl->pl_elems[index].p_dur = re.re_dur;
1256 		pl->pl_elems[index].p_rssi = re.re_rssi;
1257 		pl->pl_elems[index].p_sidx = re.re_sidx;
1258 		pl->pl_elems[index].p_delta_peak = re.re_delta_peak;
1259 		pl->pl_elems[index].p_psidx_diff = re.re_psidx_diff;
1260 		dfs->dfs_seq_num++;
1261 		pl->pl_elems[index].p_seq_num = dfs->dfs_seq_num;
1262 	}
1263 }
1264 
1265 /**
1266  * dfs_process_each_radarevent - remove each event from the dfs radar queue
1267  * and process it.
1268  * @dfs: Pointer to wlan_dfs structure.
1269  * @chan: Pointer to DFS current channel.
1270  * @rs: Pointer to dfs_state structure.
1271  * @seg_id: segment id.
1272  * @retval: pointer to retval.
1273  * @false_radar_found: pointer to false radar found.
1274  *
1275  * Return: If radar found then return 1 else return 0.
1276  */
1277 static inline int dfs_process_each_radarevent(
1278 	struct wlan_dfs *dfs,
1279 	struct dfs_channel *chan,
1280 	struct dfs_state **rs,
1281 	uint8_t *seg_id,
1282 	int *retval,
1283 	int *false_radar_found)
1284 {
1285 	struct dfs_event re, *event;
1286 	int found, empty;
1287 	int events_processed = 0;
1288 	uint64_t this_ts;
1289 	static uint32_t test_ts;
1290 	static uint32_t diff_ts;
1291 	uint32_t index;
1292 
1293 	dfs_is_radarq_empty(dfs, &empty);
1294 
1295 	while ((!empty) && (!*retval) && !(*false_radar_found) &&
1296 			(events_processed < MAX_EVENTS)) {
1297 		dfs_remove_event_from_radarq(dfs, &event);
1298 		if (!event) {
1299 			empty = 1;
1300 			break;
1301 		}
1302 		events_processed++;
1303 		re = *event;
1304 
1305 		dfs_return_event_to_eventq(dfs, event);
1306 
1307 		*seg_id = re.re_seg_id;
1308 		found = 0;
1309 		if (dfs_skip_the_event(dfs, &re, rs)) {
1310 			dfs_is_radarq_empty(dfs, &empty);
1311 			continue;
1312 		}
1313 
1314 		dfs_calculate_timestamps(dfs, &re, &this_ts);
1315 
1316 		re.re_dur = dfs_process_pulse_dur(dfs, re.re_dur);
1317 
1318 		dfs_add_to_pulseline(dfs, &re, &this_ts, &test_ts, &diff_ts,
1319 				&index);
1320 
1321 		dfs_dur_check(dfs, chan, &re, diff_ts);
1322 
1323 		dfs_log_event(dfs, &re, this_ts, diff_ts, index);
1324 
1325 		dfs_conditional_clear_delaylines(dfs, diff_ts, this_ts, re);
1326 
1327 		found = 0;
1328 		if (events_processed == 1) {
1329 			dfs->dfs_min_sidx = (re).re_sidx;
1330 			dfs->dfs_max_sidx = (re).re_sidx;
1331 		}
1332 
1333 		dfs_check_if_bin5(dfs, &re, this_ts, diff_ts, &found);
1334 		if (found) {
1335 			*retval |= found;
1336 			dfs->dfs_freq_offset = DFS_SIDX_TO_FREQ_OFFSET(
1337 				   (dfs->dfs_min_sidx + dfs->dfs_max_sidx) / 2);
1338 			return 1;
1339 		}
1340 
1341 		dfs_check_if_nonbin5(dfs, &re, rs, this_ts, diff_ts, &found,
1342 				retval, false_radar_found);
1343 
1344 		dfs_is_radarq_empty(dfs, &empty);
1345 	}
1346 
1347 	return 0;
1348 }
1349 
1350 /**
1351  * dfs_false_radarfound_reset_vars () - Reset dfs variables after false radar
1352  *                                      found.
1353  * @dfs: Pointer to wlan_dfs structure.
1354  */
1355 void dfs_false_radarfound_reset_vars(
1356 	struct wlan_dfs *dfs)
1357 {
1358 	dfs->dfs_seq_num = 0;
1359 	dfs_reset_radarq(dfs);
1360 	dfs_reset_alldelaylines(dfs);
1361 	dfs->dfs_phyerr_freq_min     = 0x7fffffff;
1362 	dfs->dfs_phyerr_freq_max     = 0;
1363 	dfs->dfs_phyerr_w53_counter  = 0;
1364 	dfs->dfs_event_log_count = 0;
1365 	dfs->dfs_phyerr_count = 0;
1366 	dfs->dfs_phyerr_reject_count = 0;
1367 	dfs->dfs_phyerr_queued_count = 0;
1368 }
1369 
1370 /**
1371  * dfs_process_radarevent() - For Full Offload, FW sends segment id,freq_offset
1372  * and chirp information and gets assigned when there is radar detect. In
1373  * case of radartool bangradar enhanced command and real radar for DA and PO,
1374  * we assign these information here.
1375  *
1376  * @dfs: Pointer to wlan_dfs structure.
1377  * @radar_found: Pointer to radar_found_info structure.
1378  */
1379 
1380 static void
1381 dfs_fill_radar_found_info(struct wlan_dfs *dfs,
1382 			  struct radar_found_info *radar_found)
1383 {
1384 	radar_found->segment_id = dfs->dfs_seg_id;
1385 	radar_found->freq_offset = dfs->dfs_freq_offset;
1386 	radar_found->is_chirp = dfs->dfs_is_chirp;
1387 }
1388 
1389 void dfs_radarfound_action_generic(struct wlan_dfs *dfs, uint8_t seg_id)
1390 {
1391 	struct radar_found_info *radar_found;
1392 
1393 	radar_found = qdf_mem_malloc(sizeof(*radar_found));
1394 	if (!radar_found)
1395 		return;
1396 
1397 	qdf_mem_zero(radar_found, sizeof(*radar_found));
1398 	radar_found->segment_id = seg_id;
1399 	dfs->dfs_seg_id = seg_id;
1400 	radar_found->pdev_id =
1401 		wlan_objmgr_pdev_get_pdev_id(dfs->dfs_pdev_obj);
1402 
1403 	dfs_fill_radar_found_info(dfs, radar_found);
1404 	dfs_process_radar_ind(dfs, radar_found);
1405 	qdf_mem_free(radar_found);
1406 }
1407 
1408 void dfs_radar_found_action(struct wlan_dfs *dfs,
1409 			    bool bangradar,
1410 			    uint8_t seg_id)
1411 {
1412 	/* If Host DFS confirmation is supported, save the curchan as
1413 	 * radar found chan, send radar found indication along with
1414 	 * average radar parameters to FW and start the host status
1415 	 * wait timer.
1416 	 */
1417 	if (!bangradar &&
1418 	   (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_FCC_DOMAIN) &&
1419 	   lmac_is_host_dfs_check_support_enabled(dfs->dfs_pdev_obj) &&
1420 	   (dfs->dfs_spoof_test_done ? dfs->dfs_use_nol : 1)) {
1421 		dfs_radarfound_action_fcc(dfs, seg_id);
1422 	} else {
1423 		dfs_radarfound_action_generic(dfs, seg_id);
1424 	}
1425 }
1426 
1427 /**
1428  * dfs_is_radar_source_legacy_agile() - Check if radar pulse event is received
1429  * on a Zero CAC agile channel.
1430  * @dfs: Pointer to wlan_dfs structure.
1431  *
1432  * Return: If a radar pulse event is received on a zero cac agile
1433  * channel return true. Otherwise, return false.
1434  */
1435 #if defined(ATH_SUPPORT_ZERO_CAC_DFS)
1436 static
1437 bool dfs_is_radar_source_legacy_agile(struct wlan_dfs *dfs)
1438 {
1439 	if (dfs_is_legacy_precac_enabled(dfs) &&
1440 	    dfs_is_precac_timer_running(dfs) &&
1441 	    dfs->dfs_precac_secondary_freq_mhz)
1442 		return true;
1443 	return false;
1444 }
1445 #else
1446 static
1447 bool dfs_is_radar_source_legacy_agile(struct wlan_dfs *dfs)
1448 {
1449 	return false;
1450 }
1451 #endif
1452 
1453 /**
1454  * dfs_radar_pulse_event_basic_sanity() - Check if radar pulse event is received
1455  * on a DFS channel or Zero CAC agile channel.
1456  * @dfs: Pointer to wlan_dfs structure.
1457  * @chan: Current channel.
1458  *
1459  * Return: If a radar pulse event is received on DFS channel or zero cac agile
1460  * channel return true. Otherwise, return false.
1461  */
1462 static
1463 bool dfs_radar_pulse_event_basic_sanity(struct wlan_dfs *dfs,
1464 					struct dfs_channel *chan)
1465 {
1466 	if (!chan) {
1467 		dfs_err(dfs, WLAN_DEBUG_DFS1,
1468 			"dfs->dfs_curchan is NULL");
1469 		return false;
1470 	}
1471 
1472 	if (dfs_is_radar_source_legacy_agile(dfs))
1473 		return true;
1474 
1475 	if (!WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(chan)) {
1476 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
1477 			  "radar event on a non-DFS chan");
1478 		dfs_reset_radarq(dfs);
1479 		dfs_reset_alldelaylines(dfs);
1480 		dfs_reset_bangradar(dfs);
1481 		return false;
1482 	}
1483 	return true;
1484 }
1485 
1486 void dfs_process_radarevent(
1487 	struct wlan_dfs *dfs,
1488 	struct dfs_channel *chan)
1489 {
1490 	struct dfs_state *rs = NULL;
1491 	uint8_t   seg_id = 0;
1492 	int retval = 0;
1493 	int false_radar_found = 0;
1494 	bool bangradar = false;
1495 
1496 	if (!dfs_radar_pulse_event_basic_sanity(dfs, chan))
1497 		return;
1498 
1499 	/*
1500 	 * TEST : Simulate radar bang, make sure we add the channel to NOL
1501 	 * (bug 29968)
1502 	 */
1503 	if (dfs_handle_bangradar(dfs, chan, &rs, &seg_id, &retval)) {
1504 		if (retval)
1505 			bangradar = true;
1506 		goto dfsfound;
1507 	}
1508 
1509 	if (!dfs_handle_missing_pulses(dfs, chan))
1510 		return;
1511 
1512 	dfs_process_each_radarevent(dfs, chan, &rs, &seg_id, &retval,
1513 			&false_radar_found);
1514 
1515 dfsfound:
1516 	if (retval) {
1517 		dfs_radarfound_reset_vars(dfs, rs, chan, seg_id);
1518 		dfs_radar_found_action(dfs, bangradar, seg_id);
1519 	}
1520 
1521 	if (false_radar_found)
1522 		dfs_false_radarfound_reset_vars(dfs);
1523 }
1524