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