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