xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2002-2006, Atheros Communications Inc.
4  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
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: This file contains the dfs_attach() and dfs_detach() functions as well
21  * as the dfs_control() function which is used to process ioctls related to DFS.
22  * For Linux/Mac,  "radartool" is the command line tool that can be used to call
23  * various ioctls to set and get radar detection thresholds.
24  */
25 
26 #include "../dfs_zero_cac.h"
27 #include "wlan_dfs_lmac_api.h"
28 #include "wlan_dfs_mlme_api.h"
29 #include "wlan_dfs_tgt_api.h"
30 #include "../dfs_internal.h"
31 #include "../dfs_filter_init.h"
32 #include <wlan_objmgr_vdev_obj.h>
33 #include "wlan_dfs_utils_api.h"
34 #include "../dfs_process_radar_found_ind.h"
35 #include "../dfs_partial_offload_radar.h"
36 
37 /* Disable NOL in FW. */
38 #define DISABLE_NOL_FW 0
39 
40 #ifndef WLAN_DFS_STATIC_MEM_ALLOC
41 /*
42  * dfs_alloc_wlan_dfs() - allocate wlan_dfs buffer
43  *
44  * Return: buffer, null on failure.
45  */
46 static inline struct wlan_dfs *dfs_alloc_wlan_dfs(void)
47 {
48 	return qdf_mem_malloc(sizeof(struct wlan_dfs));
49 }
50 
51 /*
52  * dfs_free_wlan_dfs() - Free wlan_dfs buffer
53  * @dfs: wlan_dfs buffer pointer
54  *
55  * Return: None
56  */
57 static inline void dfs_free_wlan_dfs(struct wlan_dfs *dfs)
58 {
59 	qdf_mem_free(dfs);
60 }
61 
62 /*
63  * dfs_alloc_dfs_curchan() - allocate dfs_channel buffer
64  *
65  * Return: buffer, null on failure.
66  */
67 static inline struct dfs_channel *dfs_alloc_dfs_curchan(void)
68 {
69 	return qdf_mem_malloc(sizeof(struct dfs_channel));
70 }
71 
72 static inline struct dfs_channel *dfs_alloc_dfs_prevchan(void)
73 {
74 	return qdf_mem_malloc(sizeof(struct dfs_channel));
75 }
76 
77 /*
78  * dfs_free_dfs_chan() - Free dfs_channel buffer
79  * @dfs_chan: dfs_channel buffer pointer
80  *
81  * Return: None
82  */
83 static inline void dfs_free_dfs_chan(struct dfs_channel *dfs_chan)
84 {
85 	qdf_mem_free(dfs_chan);
86 }
87 
88 #else
89 
90 /* Static buffers for DFS objects */
91 static struct wlan_dfs global_dfs;
92 static struct dfs_channel global_dfs_curchan;
93 static struct dfs_channel global_dfs_prevchan;
94 
95 static inline struct wlan_dfs *dfs_alloc_wlan_dfs(void)
96 {
97 	return &global_dfs;
98 }
99 
100 static inline void dfs_free_wlan_dfs(struct wlan_dfs *dfs)
101 {
102 }
103 
104 static inline struct dfs_channel *dfs_alloc_dfs_curchan(void)
105 {
106 	return &global_dfs_curchan;
107 }
108 
109 static inline struct dfs_channel *dfs_alloc_dfs_prevchan(void)
110 {
111 	return &global_dfs_prevchan;
112 }
113 
114 static inline void dfs_free_dfs_chan(struct dfs_channel *dfs_chan)
115 {
116 }
117 #endif
118 
119 /**
120  * dfs_testtimer_task() - Sends CSA in the current channel.
121  *
122  * When the user sets usenol to 0 and inject the RADAR, AP does not mark the
123  * channel as RADAR and does not add the channel to NOL. It sends the CSA in
124  * the current channel.
125  */
126 #ifdef CONFIG_CHAN_FREQ_API
127 static os_timer_func(dfs_testtimer_task)
128 {
129 	struct wlan_dfs *dfs = NULL;
130 
131 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
132 	dfs->wlan_dfstest = 0;
133 
134 	/*
135 	 * Flip the channel back to the original channel.
136 	 * Make sure this is done properly with a CSA.
137 	 */
138 	dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "go back to channel %d",
139 		  dfs->wlan_dfstest_ieeechan);
140 	dfs_mlme_start_csa_for_freq(dfs->dfs_pdev_obj,
141 				    dfs->wlan_dfstest_ieeechan,
142 				    dfs->dfs_curchan->dfs_ch_freq,
143 				    dfs->dfs_curchan->dfs_ch_mhz_freq_seg2,
144 				    dfs->dfs_curchan->dfs_ch_flags);
145 }
146 #endif
147 
148 int dfs_get_debug_info(struct wlan_dfs *dfs, void *data)
149 {
150 	if (data)
151 		*(uint32_t *)data = dfs->dfs_proc_phyerr;
152 
153 	return (int)dfs->dfs_proc_phyerr;
154 }
155 
156 void dfs_main_task_testtimer_init(struct wlan_dfs *dfs)
157 {
158 	qdf_timer_init(NULL,
159 		&(dfs->wlan_dfstesttimer),
160 		dfs_testtimer_task, (void *)dfs,
161 		QDF_TIMER_TYPE_WAKE_APPS);
162 }
163 
164 int dfs_create_object(struct wlan_dfs **dfs)
165 {
166 	*dfs = dfs_alloc_wlan_dfs();
167 	if (!(*dfs))
168 		return 1;
169 
170 	qdf_mem_zero(*dfs, sizeof(**dfs));
171 
172 	(*dfs)->dfs_curchan = dfs_alloc_dfs_curchan();
173 	if (!((*dfs)->dfs_curchan)) {
174 		dfs_free_wlan_dfs(*dfs);
175 		return 1;
176 	}
177 
178 	(*dfs)->dfs_prevchan = dfs_alloc_dfs_prevchan();
179 	if (!((*dfs)->dfs_prevchan)) {
180 		dfs_free_wlan_dfs(*dfs);
181 		return 1;
182 	}
183 	qdf_mem_zero((*dfs)->dfs_prevchan, sizeof(struct dfs_channel));
184 	return 0;
185 }
186 
187 int dfs_attach(struct wlan_dfs *dfs)
188 {
189 	int ret;
190 
191 	if (!dfs->dfs_is_offload_enabled) {
192 		ret = dfs_main_attach(dfs);
193 
194 		/*
195 		 * For full offload we have a wmi handler registered to process
196 		 * a radar event from firmware in the event of a radar detect.
197 		 * So, init of timer, dfs_task is not required for
198 		 * full-offload. dfs_task timer is called in
199 		 * dfs_main_timer_init within dfs_main_attach for
200 		 * partial-offload in the event of radar detect.
201 		 */
202 		if (ret) {
203 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_main_attach failed");
204 			return ret;
205 		}
206 	}
207 	dfs_cac_timer_attach(dfs);
208 	dfs_zero_cac_attach(dfs);
209 	dfs_nol_attach(dfs);
210 	dfs_postnol_attach(dfs);
211 
212 	/*
213 	 * Init of timer ,dfs_testtimer_task is required by both partial
214 	 * and full offload, indicating test mode timer initialization for both.
215 	 */
216 	dfs_main_task_testtimer_init(dfs);
217 	return 0;
218 }
219 
220 void dfs_stop(struct wlan_dfs *dfs)
221 {
222 	dfs_nol_timer_cleanup(dfs);
223 	dfs_nol_workqueue_cleanup(dfs);
224 	dfs_clear_nolhistory(dfs);
225 }
226 
227 void dfs_task_testtimer_reset(struct wlan_dfs *dfs)
228 {
229 	if (dfs->wlan_dfstest) {
230 		qdf_timer_sync_cancel(&dfs->wlan_dfstesttimer);
231 		dfs->wlan_dfstest = 0;
232 	}
233 }
234 
235 void dfs_task_testtimer_detach(struct wlan_dfs *dfs)
236 {
237 	qdf_timer_free(&dfs->wlan_dfstesttimer);
238 	dfs->wlan_dfstest = 0;
239 }
240 
241 void dfs_reset(struct wlan_dfs *dfs)
242 {
243 	if (!dfs) {
244 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
245 		return;
246 	}
247 
248 	dfs_cac_timer_reset(dfs);
249 	dfs_zero_cac_reset(dfs);
250 	if (!dfs->dfs_is_offload_enabled) {
251 		dfs_main_timer_reset(dfs);
252 		dfs_host_wait_timer_reset(dfs);
253 		dfs_false_radarfound_reset_vars(dfs);
254 	}
255 	dfs_task_testtimer_reset(dfs);
256 }
257 
258 void dfs_timer_detach(struct wlan_dfs *dfs)
259 {
260 	dfs_cac_timer_detach(dfs);
261 	dfs_zero_cac_timer_detach(dfs->dfs_soc_obj);
262 
263 	if (!dfs->dfs_is_offload_enabled) {
264 		dfs_main_timer_detach(dfs);
265 		dfs_host_wait_timer_detach(dfs);
266 	}
267 
268 	dfs_task_testtimer_detach(dfs);
269 }
270 
271 void dfs_detach(struct wlan_dfs *dfs)
272 {
273 	dfs_timer_detach(dfs);
274 	if (!dfs->dfs_is_offload_enabled)
275 		dfs_main_detach(dfs);
276 	dfs_zero_cac_detach(dfs);
277 	dfs_nol_detach(dfs);
278 }
279 
280 #ifndef WLAN_DFS_STATIC_MEM_ALLOC
281 void dfs_destroy_object(struct wlan_dfs *dfs)
282 {
283 	dfs_free_dfs_chan(dfs->dfs_prevchan);
284 	dfs_free_dfs_chan(dfs->dfs_curchan);
285 	dfs_free_wlan_dfs(dfs);
286 }
287 #else
288 void dfs_destroy_object(struct wlan_dfs *dfs)
289 {
290 }
291 #endif
292 
293 /* dfs_set_disable_radar_marking()- Set the flag to mark/unmark a radar flag
294  * on NOL channel.
295  * @dfs: Pointer to wlan_dfs structure.
296  * @disable_radar_marking: Flag to enable/disable marking channel as radar.
297  */
298 #if defined(WLAN_DFS_FULL_OFFLOAD) && defined(QCA_DFS_NOL_OFFLOAD)
299 static void dfs_set_disable_radar_marking(struct wlan_dfs *dfs,
300 					  bool disable_radar_marking)
301 {
302 	dfs->dfs_disable_radar_marking = disable_radar_marking;
303 }
304 #else
305 static inline void dfs_set_disable_radar_marking(struct wlan_dfs *dfs,
306 						 bool disable_radar_marking)
307 {
308 }
309 #endif
310 
311 #if defined(WLAN_DFS_FULL_OFFLOAD) && defined(QCA_DFS_NOL_OFFLOAD)
312 bool dfs_get_disable_radar_marking(struct wlan_dfs *dfs)
313 {
314 	return dfs->dfs_disable_radar_marking;
315 }
316 #endif
317 
318 int dfs_control(struct wlan_dfs *dfs,
319 		u_int id,
320 		void *indata,
321 		uint32_t insize,
322 		void *outdata,
323 		uint32_t *outsize)
324 {
325 	struct wlan_dfs_phyerr_param peout;
326 	struct dfs_ioctl_params *dfsparams;
327 	int error = 0;
328 	uint32_t val = 0;
329 	struct dfsreq_nolinfo *nol;
330 	uint32_t *data = NULL;
331 	int i;
332 	int usenol_pdev_param;
333 
334 	if (!dfs) {
335 		dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
336 		goto bad;
337 	}
338 
339 	switch (id) {
340 	case DFS_SET_THRESH:
341 		if (insize < sizeof(struct dfs_ioctl_params) || !indata) {
342 			dfs_debug(dfs, WLAN_DEBUG_DFS1,
343 					"insize = %d, expected = %zu bytes, indata = %pK",
344 					insize,
345 					sizeof(struct dfs_ioctl_params),
346 					indata);
347 			error = -EINVAL;
348 			break;
349 		}
350 		dfsparams = (struct dfs_ioctl_params *)indata;
351 		if (!dfs_set_thresholds(dfs, DFS_PARAM_FIRPWR,
352 					dfsparams->dfs_firpwr))
353 			error = -EINVAL;
354 		if (!dfs_set_thresholds(dfs, DFS_PARAM_RRSSI,
355 					dfsparams->dfs_rrssi))
356 			error = -EINVAL;
357 		if (!dfs_set_thresholds(dfs, DFS_PARAM_HEIGHT,
358 					dfsparams->dfs_height))
359 			error = -EINVAL;
360 		if (!dfs_set_thresholds(dfs, DFS_PARAM_PRSSI,
361 					dfsparams->dfs_prssi))
362 			error = -EINVAL;
363 		if (!dfs_set_thresholds(dfs, DFS_PARAM_INBAND,
364 					dfsparams->dfs_inband))
365 			error = -EINVAL;
366 
367 		/* 5413 speicfic. */
368 		if (!dfs_set_thresholds(dfs, DFS_PARAM_RELPWR,
369 					dfsparams->dfs_relpwr))
370 			error = -EINVAL;
371 		if (!dfs_set_thresholds(dfs, DFS_PARAM_RELSTEP,
372 					dfsparams->dfs_relstep))
373 			error = -EINVAL;
374 		if (!dfs_set_thresholds(dfs, DFS_PARAM_MAXLEN,
375 					dfsparams->dfs_maxlen))
376 			error = -EINVAL;
377 		break;
378 	case DFS_BANGRADAR:
379 		error = dfs_bang_radar(dfs, indata, insize);
380 		break;
381 	case DFS_GET_THRESH:
382 		if (!outdata || !outsize ||
383 				*outsize < sizeof(struct dfs_ioctl_params)) {
384 			error = -EINVAL;
385 			break;
386 		}
387 		*outsize = sizeof(struct dfs_ioctl_params);
388 		dfsparams = (struct dfs_ioctl_params *) outdata;
389 
390 		qdf_mem_zero(&peout, sizeof(struct wlan_dfs_phyerr_param));
391 
392 		/* Fetch the DFS thresholds using the internal representation */
393 		(void) dfs_get_thresholds(dfs, &peout);
394 
395 		/* Convert them to the dfs IOCTL representation. */
396 		wlan_dfs_dfsparam_to_ioctlparam(&peout, dfsparams);
397 		break;
398 	case DFS_RADARDETECTS:
399 		if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
400 			error = -EINVAL;
401 			break;
402 		}
403 		*outsize = sizeof(uint32_t);
404 		*((uint32_t *)outdata) = dfs->wlan_dfs_stats.num_radar_detects;
405 		break;
406 	case DFS_DISABLE_DETECT:
407 		dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN;
408 		dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN;
409 		dfs->dfs_ignore_dfs = 1;
410 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
411 			  "enable detects, ignore_dfs %d",
412 			  dfs->dfs_ignore_dfs ? 1 : 0);
413 		break;
414 	case DFS_ENABLE_DETECT:
415 		dfs->dfs_proc_phyerr |= DFS_RADAR_EN;
416 		dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN;
417 		dfs->dfs_ignore_dfs = 0;
418 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
419 			  "enable detects, ignore_dfs %d",
420 			  dfs->dfs_ignore_dfs ? 1 : 0);
421 		break;
422 	case DFS_DISABLE_FFT:
423 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
424 			  "TODO disable FFT val=0x%x", val);
425 		break;
426 	case DFS_ENABLE_FFT:
427 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
428 			  "TODO enable FFT val=0x%x", val);
429 		break;
430 	case DFS_SET_DEBUG_LEVEL:
431 		if (insize < sizeof(uint32_t) || !indata) {
432 			error = -EINVAL;
433 			break;
434 		}
435 		dfs->dfs_debug_mask = *(uint32_t *)indata;
436 
437 		/* Do not allow user to set the ALWAYS/MAX bit.
438 		 * It will be used internally  by dfs print macro(s)
439 		 * to print messages when dfs is NULL.
440 		 */
441 		dfs->dfs_debug_mask &= ~(WLAN_DEBUG_DFS_ALWAYS);
442 
443 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
444 			  "debug level now = 0x%x", dfs->dfs_debug_mask);
445 		if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS3) {
446 			/* Enable debug Radar Event */
447 			dfs->dfs_event_log_on = 1;
448 		} else if ((utils_get_dfsdomain(dfs->dfs_pdev_obj) ==
449 		    DFS_FCC_DOMAIN) &&
450 		    lmac_is_host_dfs_check_support_enabled(dfs->dfs_pdev_obj)) {
451 			dfs->dfs_event_log_on = 1;
452 		} else {
453 			dfs->dfs_event_log_on = 0;
454 		}
455 		break;
456 	case DFS_SET_FALSE_RSSI_THRES:
457 		if (insize < sizeof(uint32_t) || !indata) {
458 			error = -EINVAL;
459 			break;
460 		}
461 		dfs->wlan_dfs_false_rssi_thres = *(uint32_t *)indata;
462 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
463 			  "false RSSI threshold now = 0x%x",
464 			  dfs->wlan_dfs_false_rssi_thres);
465 		break;
466 	case DFS_SET_PEAK_MAG:
467 		if (insize < sizeof(uint32_t) || !indata) {
468 			error = -EINVAL;
469 			break;
470 		}
471 		dfs->wlan_dfs_peak_mag = *(uint32_t *)indata;
472 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
473 			  "peak_mag now = 0x%x",
474 				dfs->wlan_dfs_peak_mag);
475 		break;
476 	case DFS_GET_CAC_VALID_TIME:
477 		if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
478 			error = -EINVAL;
479 			break;
480 		}
481 		*outsize = sizeof(uint32_t);
482 		*((uint32_t *)outdata) = dfs->dfs_cac_valid_time;
483 		break;
484 	case DFS_SET_CAC_VALID_TIME:
485 		if (insize < sizeof(uint32_t) || !indata) {
486 			error = -EINVAL;
487 			break;
488 		}
489 		dfs->dfs_cac_valid_time = *(uint32_t *)indata;
490 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
491 			  "dfs timeout = %d", dfs->dfs_cac_valid_time);
492 		break;
493 	case DFS_IGNORE_CAC:
494 		if (insize < sizeof(uint32_t) || !indata) {
495 			error = -EINVAL;
496 			break;
497 		}
498 
499 		if (*(uint32_t *)indata)
500 			dfs->dfs_ignore_cac = 1;
501 		else
502 			dfs->dfs_ignore_cac = 0;
503 
504 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
505 			  "ignore cac = 0x%x", dfs->dfs_ignore_cac);
506 		break;
507 	case DFS_SET_NOL_TIMEOUT:
508 		if (insize < sizeof(uint32_t) || !indata) {
509 			error = -EINVAL;
510 			break;
511 		}
512 		if (*(int *)indata)
513 			dfs->wlan_dfs_nol_timeout = *(int *)indata;
514 		else
515 			dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
516 
517 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "nol timeout = %d sec",
518 			  dfs->wlan_dfs_nol_timeout);
519 		break;
520 	case DFS_MUTE_TIME:
521 		if (insize < sizeof(uint32_t) || !indata) {
522 			error = -EINVAL;
523 			break;
524 		}
525 		data = (uint32_t *) indata;
526 		dfs->wlan_dfstesttime = *data;
527 		dfs->wlan_dfstesttime *= (1000); /* convert sec into ms */
528 		break;
529 	case DFS_GET_USENOL:
530 		if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
531 			error = -EINVAL;
532 			break;
533 		}
534 		*outsize = sizeof(uint32_t);
535 		*((uint32_t *)outdata) = dfs->dfs_use_nol;
536 
537 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
538 			  "#Phyerr=%d, #false detect=%d, #queued=%d",
539 			  dfs->dfs_phyerr_count,
540 			  dfs->dfs_phyerr_reject_count,
541 			  dfs->dfs_phyerr_queued_count);
542 
543 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
544 			 "dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d",
545 			 dfs->dfs_phyerr_freq_min,
546 			 dfs->dfs_phyerr_freq_max);
547 
548 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
549 			 "Total radar events detected=%d, entries in the radar queue follows:",
550 			 dfs->dfs_event_log_count);
551 
552 		for (i = 0; (i < DFS_EVENT_LOG_SIZE) &&
553 				(i < dfs->dfs_event_log_count); i++) {
554 #define FREQ_OFFSET1 ((int)dfs->radar_log[i].freq_offset_khz / 1000)
555 #define FREQ_OFFSET2 ((int)abs(dfs->radar_log[i].freq_offset_khz) % 1000)
556 			dfs_debug(dfs, WLAN_DEBUG_DFS,
557 				  "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\n",
558 				  dfs->radar_log[i].ts,
559 				  dfs->radar_log[i].diff_ts,
560 				  dfs->radar_log[i].rssi,
561 				  dfs->radar_log[i].dur,
562 				  dfs->radar_log[i].is_chirp,
563 				  dfs->radar_log[i].seg_id,
564 				  dfs->radar_log[i].sidx,
565 				  FREQ_OFFSET1,
566 				  FREQ_OFFSET2,
567 				  dfs->radar_log[i].peak_mag,
568 				  dfs->radar_log[i].total_gain,
569 				  dfs->radar_log[i].mb_gain,
570 				  dfs->radar_log[i].relpwr_db,
571 				  dfs->radar_log[i].delta_diff,
572 				  dfs->radar_log[i].delta_peak,
573 				  dfs->radar_log[i].psidx_diff);
574 		}
575 		dfs->dfs_event_log_count = 0;
576 		dfs->dfs_phyerr_count = 0;
577 		dfs->dfs_phyerr_reject_count = 0;
578 		dfs->dfs_phyerr_queued_count = 0;
579 		dfs->dfs_phyerr_freq_min = 0x7fffffff;
580 		dfs->dfs_phyerr_freq_max = 0;
581 		break;
582 	case DFS_SET_USENOL:
583 		if (insize < sizeof(uint32_t) || !indata) {
584 			error = -EINVAL;
585 			break;
586 		}
587 		dfs->dfs_use_nol = *(uint32_t *)indata;
588 		usenol_pdev_param = dfs->dfs_use_nol;
589 		if (dfs->dfs_is_offload_enabled) {
590 			if (dfs->dfs_use_nol ==
591 				USENOL_ENABLE_NOL_HOST_DISABLE_NOL_FW)
592 				usenol_pdev_param = DISABLE_NOL_FW;
593 			tgt_dfs_send_usenol_pdev_param(dfs->dfs_pdev_obj,
594 						       usenol_pdev_param);
595 		}
596 		break;
597 	case DFS_SET_DISABLE_RADAR_MARKING:
598 		if (dfs->dfs_is_offload_enabled &&
599 		    (utils_get_dfsdomain(dfs->dfs_pdev_obj) ==
600 			 DFS_FCC_DOMAIN)) {
601 			if (insize < sizeof(uint32_t) || !indata) {
602 				error = -EINVAL;
603 				break;
604 			}
605 			dfs_set_disable_radar_marking(dfs, *(uint8_t *)indata);
606 		}
607 		break;
608 	case DFS_GET_DISABLE_RADAR_MARKING:
609 		if (!outdata || !outsize || *outsize < sizeof(uint8_t)) {
610 			error = -EINVAL;
611 			break;
612 		}
613 		if (dfs->dfs_is_offload_enabled) {
614 			*outsize = sizeof(uint8_t);
615 			*((uint8_t *)outdata) =
616 				dfs_get_disable_radar_marking(dfs);
617 		}
618 		break;
619 	case DFS_GET_NOL:
620 		if (!outdata || !outsize ||
621 				*outsize < sizeof(struct dfsreq_nolinfo)) {
622 			error = -EINVAL;
623 			break;
624 		}
625 		*outsize = sizeof(struct dfsreq_nolinfo);
626 		nol = (struct dfsreq_nolinfo *)outdata;
627 		DFS_GET_NOL_LOCKED(dfs,
628 				(struct dfsreq_nolelem *)nol->dfs_nol,
629 				&nol->dfs_ch_nchans);
630 		DFS_PRINT_NOL_LOCKED(dfs);
631 		break;
632 	case DFS_SET_NOL:
633 		if (insize < sizeof(struct dfsreq_nolinfo) || !indata) {
634 			error = -EINVAL;
635 			break;
636 		}
637 		nol = (struct dfsreq_nolinfo *) indata;
638 		dfs_set_nol(dfs,
639 				(struct dfsreq_nolelem *)nol->dfs_nol,
640 				nol->dfs_ch_nchans);
641 		break;
642 	case DFS_SHOW_NOL:
643 		DFS_PRINT_NOL_LOCKED(dfs);
644 		break;
645 	case DFS_SHOW_NOLHISTORY:
646 		dfs_print_nolhistory(dfs);
647 		break;
648 	case DFS_SHOW_PRECAC_LISTS:
649 		dfs_print_precaclists(dfs);
650 		break;
651 	case DFS_RESET_PRECAC_LISTS:
652 		dfs_reset_precac_lists(dfs);
653 		break;
654 	case DFS_INJECT_SEQUENCE:
655 		error = dfs_inject_synthetic_pulse_sequence(dfs, indata);
656 		if (error)
657 			dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
658 				  "Not injected Synthetic pulse");
659 		break;
660 
661 	case DFS_ALLOW_HW_PULSES:
662 		if (insize < sizeof(u_int8_t) || !indata) {
663 			error = -EINVAL;
664 			break;
665 		}
666 		dfs_allow_hw_pulses(dfs, !!(*(u_int8_t *)indata));
667 		break;
668 	case DFS_SET_PRI_MULTIPILER:
669 		dfs->dfs_pri_multiplier = *(int *)indata;
670 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
671 			  "Set dfs pri multiplier to %d, dfsdomain %d",
672 			  dfs->dfs_pri_multiplier, dfs->dfsdomain);
673 		break;
674 	default:
675 		error = -EINVAL;
676 	}
677 
678 bad:
679 	return error;
680 }
681 
682 #ifdef WLAN_FEATURE_11BE
683 static inline bool
684 dfs_is_chan_punc_same_as_given_punc(struct dfs_channel *dfs_curchan,
685 				    uint16_t dfs_chan_punc_pattern)
686 {
687 	return (dfs_curchan->dfs_ch_punc_pattern == dfs_chan_punc_pattern);
688 }
689 #else
690 static inline bool
691 dfs_is_chan_punc_same_as_given_punc(struct dfs_channel *dfs_curchan,
692 				    uint16_t dfs_chan_punc_pattern)
693 {
694 	return true;
695 }
696 #endif
697 /**
698  * dfs_is_curchan_same_as_given_chan() - Find if dfs_curchan has the same
699  * channel parameters provided.
700  * @dfs_curchan: Pointer to DFS current channel structure.
701  * @dfs_ch_freq: New curchan's primary frequency.
702  * @dfs_ch_flags: New curchan's channel flags.
703  * @dfs_ch_flagext: New curchan's channel flags extension.
704  * @dfs_ch_vhtop_ch_freq_seg1: New curchan's primary centre IEEE.
705  * @dfs_ch_vhtop_ch_freq_seg2: New curchan's secondary centre IEEE.
706  *
707  * Return: True if curchan has the same channel parameters of the given channel,
708  * else false.
709  */
710 static bool
711 dfs_is_curchan_same_as_given_chan(struct dfs_channel *dfs_curchan,
712 				  uint16_t dfs_ch_freq,
713 				  uint64_t dfs_ch_flags,
714 				  uint16_t dfs_ch_flagext,
715 				  uint8_t dfs_ch_vhtop_ch_freq_seg1,
716 				  uint8_t dfs_ch_vhtop_ch_freq_seg2,
717 				  uint16_t dfs_chan_punc_pattern)
718 {
719 	if ((dfs_curchan->dfs_ch_freq == dfs_ch_freq) &&
720 	    (dfs_curchan->dfs_ch_flags == dfs_ch_flags) &&
721 	    (dfs_curchan->dfs_ch_flagext == dfs_ch_flagext) &&
722 	    (dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 ==
723 	     dfs_ch_vhtop_ch_freq_seg1) &&
724 	    (dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 ==
725 	     dfs_ch_vhtop_ch_freq_seg2) &&
726 	    (dfs_is_chan_punc_same_as_given_punc(dfs_curchan,
727 						 dfs_chan_punc_pattern)))
728 		return true;
729 
730 	return false;
731 }
732 
733 #ifdef WLAN_FEATURE_11BE
734 static inline void
735 dfs_set_cur_chan_punc_pattern(struct wlan_dfs *dfs,
736 			      uint16_t dfs_ch_punc_pattern)
737 {
738 	dfs->dfs_curchan->dfs_ch_punc_pattern = dfs_ch_punc_pattern;
739 }
740 #else
741 static inline void
742 dfs_set_cur_chan_punc_pattern(struct wlan_dfs *dfs,
743 			      uint16_t dfs_ch_punc_pattern)
744 {
745 }
746 #endif
747 
748 #ifdef CONFIG_CHAN_FREQ_API
749 void dfs_set_current_channel_for_freq(struct wlan_dfs *dfs,
750 				      uint16_t dfs_chan_freq,
751 				      uint64_t dfs_chan_flags,
752 				      uint16_t dfs_chan_flagext,
753 				      uint8_t dfs_chan_ieee,
754 				      uint8_t dfs_chan_vhtop_freq_seg1,
755 				      uint8_t dfs_chan_vhtop_freq_seg2,
756 				      uint16_t dfs_chan_mhz_freq_seg1,
757 				      uint16_t dfs_chan_mhz_freq_seg2,
758 				      uint16_t dfs_ch_punc_pattern,
759 				      bool *is_channel_updated)
760 {
761 	if (is_channel_updated)
762 		*is_channel_updated = false;
763 
764 	if (!dfs) {
765 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
766 		return;
767 	}
768 
769 	/* Check if the input parameters are the same as that of dfs_curchan */
770 	if (dfs_is_curchan_same_as_given_chan(dfs->dfs_curchan,
771 					      dfs_chan_freq,
772 					      dfs_chan_flags,
773 					      dfs_chan_flagext,
774 					      dfs_chan_vhtop_freq_seg1,
775 					      dfs_chan_vhtop_freq_seg2,
776 					      dfs_ch_punc_pattern)) {
777 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
778 			 "dfs_curchan already updated");
779 		return;
780 	}
781 
782 	/* Update dfs previous channel with the old dfs_curchan, if it exists */
783 	if (dfs->dfs_curchan->dfs_ch_freq)
784 		qdf_mem_copy(dfs->dfs_prevchan,
785 			     dfs->dfs_curchan,
786 			     sizeof(struct dfs_channel));
787 
788 	dfs->dfs_curchan->dfs_ch_freq = dfs_chan_freq;
789 	dfs->dfs_curchan->dfs_ch_flags = dfs_chan_flags;
790 	dfs->dfs_curchan->dfs_ch_flagext = dfs_chan_flagext;
791 	dfs->dfs_curchan->dfs_ch_ieee = dfs_chan_ieee;
792 	dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 = dfs_chan_vhtop_freq_seg1;
793 	dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 = dfs_chan_vhtop_freq_seg2;
794 	dfs->dfs_curchan->dfs_ch_mhz_freq_seg1 = dfs_chan_mhz_freq_seg1;
795 	dfs->dfs_curchan->dfs_ch_mhz_freq_seg2 = dfs_chan_mhz_freq_seg2;
796 	dfs_set_cur_chan_punc_pattern(dfs, dfs_ch_punc_pattern);
797 
798 	if (is_channel_updated)
799 		*is_channel_updated = true;
800 }
801 #endif
802 
803 void dfs_update_cur_chan_flags(struct wlan_dfs *dfs,
804 		uint64_t flags,
805 		uint16_t flagext)
806 {
807 	dfs->dfs_curchan->dfs_ch_flags = flags;
808 	dfs->dfs_curchan->dfs_ch_flagext = flagext;
809 }
810 
811 int dfs_reinit_timers(struct wlan_dfs *dfs)
812 {
813 	dfs_cac_timer_attach(dfs);
814 	dfs_zero_cac_timer_init(dfs->dfs_soc_obj);
815 	dfs_main_task_testtimer_init(dfs);
816 	return 0;
817 }
818 
819 void dfs_reset_dfs_prevchan(struct wlan_dfs *dfs)
820 {
821 	qdf_mem_zero(dfs->dfs_prevchan, sizeof(struct dfs_channel));
822 }
823 
824 #ifdef WLAN_DFS_TRUE_160MHZ_SUPPORT
825 bool dfs_is_true_160mhz_supported(struct wlan_dfs *dfs)
826 {
827 	struct wlan_objmgr_psoc *psoc = dfs->dfs_soc_obj->psoc;
828 	struct wlan_lmac_if_target_tx_ops *tgt_tx_ops;
829 	struct wlan_lmac_if_tx_ops *tx_ops;
830 	uint32_t target_type;
831 
832 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
833 	if (!tx_ops) {
834 		 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "tx_ops is NULL");
835 		 return false;
836 	}
837 	target_type = lmac_get_target_type(dfs->dfs_pdev_obj);
838 	tgt_tx_ops = &tx_ops->target_tx_ops;
839 	if (tgt_tx_ops->tgt_is_tgt_type_qcn9000 &&
840 	    tgt_tx_ops->tgt_is_tgt_type_qcn9000(target_type))
841 		return true;
842 
843 	if (tgt_tx_ops->tgt_is_tgt_type_qcn6122 &&
844 	    tgt_tx_ops->tgt_is_tgt_type_qcn6122(target_type))
845 		return true;
846 
847 	if (tgt_tx_ops->tgt_is_tgt_type_qcn9160 &&
848 	    tgt_tx_ops->tgt_is_tgt_type_qcn9160(target_type))
849 		return true;
850 	return false;
851 }
852 
853 bool dfs_is_restricted_80p80mhz_supported(struct wlan_dfs *dfs)
854 {
855 	return wlan_psoc_nif_fw_ext_cap_get(dfs->dfs_soc_obj->psoc,
856 					    WLAN_SOC_RESTRICTED_80P80_SUPPORT);
857 }
858 #endif
859 
860 #ifdef QCA_SUPPORT_AGILE_DFS
861 uint8_t dfs_get_agile_detector_id(struct wlan_dfs *dfs)
862 {
863 	return dfs->dfs_agile_detector_id;
864 }
865 #endif
866 
867 /**
868  * dfs_chan_to_ch_width: Outputs the channel width in MHz of the given input
869  * dfs_channel.
870  * @chan: Pointer to the input dfs_channel structure.
871  *
872  * Return: Channel width in MHz. BW_INVALID(0MHz) on invalid channel.
873  */
874 uint16_t dfs_chan_to_ch_width(struct dfs_channel *chan)
875 {
876 	uint16_t ch_width;
877 
878 	if (!chan)
879 		return BW_INVALID;
880 
881 	if (WLAN_IS_CHAN_MODE_320(chan))
882 		ch_width = BW_320;
883 	else if (WLAN_IS_CHAN_MODE_160(chan))
884 		ch_width = BW_160;
885 	else if (WLAN_IS_CHAN_MODE_80(chan))
886 		ch_width = BW_80;
887 	else if (WLAN_IS_CHAN_MODE_40(chan))
888 		ch_width = BW_40;
889 	else if (WLAN_IS_CHAN_MODE_20(chan))
890 		ch_width = BW_20;
891 	else
892 		ch_width = BW_INVALID;
893 
894 	return ch_width;
895 }
896