xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs.c (revision ad85c389289a03e320cd08dea21861f9857892fc)
1 /*
2  * Copyright (c) 2016-2019 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_etsi_precac.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 /*
73  * dfs_free_dfs_curchan() - Free dfs_channel buffer
74  * @dfs_curchan: dfs_channel buffer pointer
75  *
76  * Return: None
77  */
78 static inline void dfs_free_dfs_curchan(struct dfs_channel *dfs_curchan)
79 {
80 	qdf_mem_free(dfs_curchan);
81 }
82 
83 #else
84 
85 /* Static buffers for DFS objects */
86 static struct wlan_dfs global_dfs;
87 static struct dfs_channel global_dfs_curchan;
88 
89 static inline struct wlan_dfs *dfs_alloc_wlan_dfs(void)
90 {
91 	return &global_dfs;
92 }
93 
94 static inline void dfs_free_wlan_dfs(struct wlan_dfs *dfs)
95 {
96 }
97 
98 static inline struct dfs_channel *dfs_alloc_dfs_curchan(void)
99 {
100 	return &global_dfs_curchan;
101 }
102 
103 static inline void dfs_free_dfs_curchan(struct dfs_channel *dfs_curchan)
104 {
105 }
106 #endif
107 
108 /**
109  * dfs_testtimer_task() - Sends CSA in the current channel.
110  *
111  * When the user sets usenol to 0 and inject the RADAR, AP does not mark the
112  * channel as RADAR and does not add the channel to NOL. It sends the CSA in
113  * the current channel.
114  */
115 static os_timer_func(dfs_testtimer_task)
116 {
117 	struct wlan_dfs *dfs = NULL;
118 
119 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
120 	dfs->wlan_dfstest = 0;
121 
122 	/*
123 	 * Flip the channel back to the original channel.
124 	 * Make sure this is done properly with a CSA.
125 	 */
126 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "go back to channel %d",
127 			dfs->wlan_dfstest_ieeechan);
128 	dfs_mlme_start_csa(dfs->dfs_pdev_obj,
129 			dfs->wlan_dfstest_ieeechan,
130 			dfs->dfs_curchan->dfs_ch_freq,
131 			dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
132 			dfs->dfs_curchan->dfs_ch_flags);
133 }
134 
135 int dfs_get_debug_info(struct wlan_dfs *dfs, void *data)
136 {
137 	if (data)
138 		*(uint32_t *)data = dfs->dfs_proc_phyerr;
139 
140 	return (int)dfs->dfs_proc_phyerr;
141 }
142 
143 void dfs_main_task_testtimer_init(struct wlan_dfs *dfs)
144 {
145 	qdf_timer_init(NULL,
146 		&(dfs->wlan_dfstesttimer),
147 		dfs_testtimer_task, (void *)dfs,
148 		QDF_TIMER_TYPE_WAKE_APPS);
149 }
150 
151 int dfs_create_object(struct wlan_dfs **dfs)
152 {
153 	*dfs = dfs_alloc_wlan_dfs();
154 	if (!(*dfs)) {
155 		dfs_alert(NULL, WLAN_DEBUG_DFS_ALWAYS,
156 			  "wlan_dfs allocation failed");
157 		return 1;
158 	}
159 
160 	qdf_mem_zero(*dfs, sizeof(**dfs));
161 
162 	(*dfs)->dfs_curchan = dfs_alloc_dfs_curchan();
163 	if (!((*dfs)->dfs_curchan)) {
164 		dfs_free_wlan_dfs(*dfs);
165 		dfs_alert(*dfs, WLAN_DEBUG_DFS_ALWAYS,
166 			  "dfs_curchan allocation failed");
167 		return 1;
168 	}
169 
170 	return 0;
171 }
172 
173 int dfs_attach(struct wlan_dfs *dfs)
174 {
175 	int ret;
176 
177 	if (!dfs->dfs_is_offload_enabled) {
178 		ret = dfs_main_attach(dfs);
179 
180 		/*
181 		 * For full offload we have a wmi handler registered to process
182 		 * a radar event from firmware in the event of a radar detect.
183 		 * So, init of timer, dfs_task is not required for
184 		 * full-offload. dfs_task timer is called in
185 		 * dfs_main_timer_init within dfs_main_attach for
186 		 * partial-offload in the event of radar detect.
187 		 */
188 		if (ret) {
189 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_main_attach failed");
190 			return ret;
191 		}
192 	}
193 	dfs_cac_attach(dfs);
194 	dfs_zero_cac_attach(dfs);
195 	dfs_etsi_precac_attach(dfs);
196 	dfs_nol_attach(dfs);
197 
198 	/*
199 	 * Init of timer ,dfs_testtimer_task is required by both partial
200 	 * and full offload, indicating test mode timer initialization for both.
201 	 */
202 	dfs_main_task_testtimer_init(dfs);
203 	return 0;
204 }
205 
206 void dfs_stop(struct wlan_dfs *dfs)
207 {
208 	dfs_nol_timer_cleanup(dfs);
209 	dfs_nol_workqueue_cleanup(dfs);
210 	dfs_clear_nolhistory(dfs);
211 }
212 
213 void dfs_task_testtimer_reset(struct wlan_dfs *dfs)
214 {
215 	if (dfs->wlan_dfstest) {
216 		qdf_timer_sync_cancel(&dfs->wlan_dfstesttimer);
217 		dfs->wlan_dfstest = 0;
218 	}
219 }
220 
221 void dfs_task_testtimer_detach(struct wlan_dfs *dfs)
222 {
223 	qdf_timer_free(&dfs->wlan_dfstesttimer);
224 	dfs->wlan_dfstest = 0;
225 }
226 
227 void dfs_reset(struct wlan_dfs *dfs)
228 {
229 	if (!dfs) {
230 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
231 		return;
232 	}
233 
234 	dfs_cac_timer_reset(dfs);
235 	dfs_zero_cac_reset(dfs);
236 	if (!dfs->dfs_is_offload_enabled) {
237 		dfs_main_timer_reset(dfs);
238 		dfs_host_wait_timer_reset(dfs);
239 		dfs_false_radarfound_reset_vars(dfs);
240 	}
241 	dfs_task_testtimer_reset(dfs);
242 }
243 
244 void dfs_timer_detach(struct wlan_dfs *dfs)
245 {
246 	dfs_cac_timer_detach(dfs);
247 	dfs_zero_cac_timer_detach(dfs);
248 
249 	if (!dfs->dfs_is_offload_enabled) {
250 		dfs_main_timer_detach(dfs);
251 		dfs_host_wait_timer_detach(dfs);
252 	}
253 
254 	dfs_task_testtimer_detach(dfs);
255 	dfs_nol_timer_detach(dfs);
256 }
257 
258 void dfs_detach(struct wlan_dfs *dfs)
259 {
260 	dfs_timer_detach(dfs);
261 	if (!dfs->dfs_is_offload_enabled)
262 		dfs_main_detach(dfs);
263 	dfs_etsi_precac_detach(dfs);
264 	dfs_zero_cac_detach(dfs);
265 	dfs_nol_detach(dfs);
266 }
267 
268 #ifndef WLAN_DFS_STATIC_MEM_ALLOC
269 void dfs_destroy_object(struct wlan_dfs *dfs)
270 {
271 	dfs_free_dfs_curchan(dfs->dfs_curchan);
272 	dfs_free_wlan_dfs(dfs);
273 }
274 #else
275 void dfs_destroy_object(struct wlan_dfs *dfs)
276 {
277 }
278 #endif
279 
280 /* dfs_set_disable_radar_marking()- Set the flag to mark/unmark a radar flag
281  * on NOL channel.
282  * @dfs: Pointer to wlan_dfs structure.
283  * @disable_radar_marking: Flag to enable/disable marking channel as radar.
284  */
285 #if defined(WLAN_DFS_FULL_OFFLOAD) && defined(QCA_DFS_NOL_OFFLOAD)
286 static void dfs_set_disable_radar_marking(struct wlan_dfs *dfs,
287 					  bool disable_radar_marking)
288 {
289 	dfs->dfs_disable_radar_marking = disable_radar_marking;
290 }
291 #else
292 static inline void dfs_set_disable_radar_marking(struct wlan_dfs *dfs,
293 						 bool disable_radar_marking)
294 {
295 }
296 #endif
297 
298 #if defined(WLAN_DFS_FULL_OFFLOAD) && defined(QCA_DFS_NOL_OFFLOAD)
299 bool dfs_get_disable_radar_marking(struct wlan_dfs *dfs)
300 {
301 	return dfs->dfs_disable_radar_marking;
302 }
303 #else
304 static inline bool dfs_get_disable_radar_marking(struct wlan_dfs *dfs)
305 {
306 	return QDF_STATUS_SUCCESS;
307 }
308 #endif
309 int dfs_control(struct wlan_dfs *dfs,
310 		u_int id,
311 		void *indata,
312 		uint32_t insize,
313 		void *outdata,
314 		uint32_t *outsize)
315 {
316 	struct wlan_dfs_phyerr_param peout;
317 	struct dfs_ioctl_params *dfsparams;
318 	struct dfs_bangradar_params *bangradar_params;
319 	int error = 0;
320 	uint32_t val = 0;
321 	struct dfsreq_nolinfo *nol;
322 	uint32_t *data = NULL;
323 	int i;
324 	struct dfs_emulate_bang_radar_test_cmd dfs_unit_test;
325 	int usenol_pdev_param;
326 
327 	qdf_mem_zero(&dfs_unit_test, sizeof(dfs_unit_test));
328 
329 	if (!dfs) {
330 		dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
331 		goto bad;
332 	}
333 
334 	switch (id) {
335 	case DFS_SET_THRESH:
336 		if (insize < sizeof(struct dfs_ioctl_params) || !indata) {
337 			dfs_debug(dfs, WLAN_DEBUG_DFS1,
338 					"insize = %d, expected = %zu bytes, indata = %pK",
339 					insize,
340 					sizeof(struct dfs_ioctl_params),
341 					indata);
342 			error = -EINVAL;
343 			break;
344 		}
345 		dfsparams = (struct dfs_ioctl_params *)indata;
346 		if (!dfs_set_thresholds(dfs, DFS_PARAM_FIRPWR,
347 					dfsparams->dfs_firpwr))
348 			error = -EINVAL;
349 		if (!dfs_set_thresholds(dfs, DFS_PARAM_RRSSI,
350 					dfsparams->dfs_rrssi))
351 			error = -EINVAL;
352 		if (!dfs_set_thresholds(dfs, DFS_PARAM_HEIGHT,
353 					dfsparams->dfs_height))
354 			error = -EINVAL;
355 		if (!dfs_set_thresholds(dfs, DFS_PARAM_PRSSI,
356 					dfsparams->dfs_prssi))
357 			error = -EINVAL;
358 		if (!dfs_set_thresholds(dfs, DFS_PARAM_INBAND,
359 					dfsparams->dfs_inband))
360 			error = -EINVAL;
361 
362 		/* 5413 speicfic. */
363 		if (!dfs_set_thresholds(dfs, DFS_PARAM_RELPWR,
364 					dfsparams->dfs_relpwr))
365 			error = -EINVAL;
366 		if (!dfs_set_thresholds(dfs, DFS_PARAM_RELSTEP,
367 					dfsparams->dfs_relstep))
368 			error = -EINVAL;
369 		if (!dfs_set_thresholds(dfs, DFS_PARAM_MAXLEN,
370 					dfsparams->dfs_maxlen))
371 			error = -EINVAL;
372 		break;
373 	case DFS_BANGRADAR:
374 		/*
375 		 * Handle all types of Bangradar here.
376 		 * Bangradar arguments:
377 		 * seg_id      : Segment ID where radar should be injected.
378 		 * is_chirp    : Is chirp radar or non chirp radar.
379 		 * freq_offset : Frequency offset from center frequency.
380 		 *
381 		 * Type 1 (DFS_BANGRADAR_FOR_ALL_SUBCHANS): To add all subchans.
382 		 * Type 2 (DFS_BANGRADAR_FOR_ALL_SUBCHANS_OF_SEGID): To add all
383 		 *               subchans of given segment_id.
384 		 * Type 3 (DFS_BANGRADAR_FOR_SPECIFIC_SUBCHANS): To add specific
385 		 *               subchans based on the arguments.
386 		 *
387 		 * The arguments will already be filled in the indata structure
388 		 * based on the type.
389 		 * If an argument is not specified by user, it will be set to
390 		 * default (0) in the indata already and correspondingly,
391 		 * the type will change.
392 		 */
393 		if (insize < sizeof(struct dfs_bangradar_params) ||
394 		    !indata) {
395 			dfs_debug(dfs, WLAN_DEBUG_DFS1,
396 				  "insize = %d, expected = %zu bytes, indata = %pK",
397 				  insize,
398 				  sizeof(struct dfs_bangradar_params),
399 				  indata);
400 			error = -EINVAL;
401 			break;
402 		}
403 		bangradar_params = (struct dfs_bangradar_params *)indata;
404 		if (bangradar_params) {
405 			if (abs(bangradar_params->freq_offset) >
406 			    FREQ_OFFSET_BOUNDARY_FOR_80MHZ) {
407 				dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
408 					 "Frequency Offset out of bound");
409 				error = -EINVAL;
410 				break;
411 			} else if (bangradar_params->seg_id >
412 				   SEG_ID_SECONDARY) {
413 				dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
414 					 "Illegal segment ID");
415 				error = -EINVAL;
416 				break;
417 			}
418 			dfs->dfs_bangradar_type =
419 				bangradar_params->bangradar_type;
420 			dfs->dfs_seg_id = bangradar_params->seg_id;
421 			dfs->dfs_is_chirp = bangradar_params->is_chirp;
422 			dfs->dfs_freq_offset = bangradar_params->freq_offset;
423 
424 			if (dfs->dfs_is_offload_enabled) {
425 				error = dfs_fill_emulate_bang_radar_test
426 							(dfs, dfs->dfs_seg_id,
427 							 dfs->dfs_is_chirp,
428 							 dfs->dfs_freq_offset,
429 							 &dfs_unit_test);
430 			} else {
431 				error = dfs_start_host_based_bangradar(dfs);
432 			}
433 		} else {
434 			dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
435 				 "bangradar_params is NULL");
436 		}
437 
438 		break;
439 	case DFS_GET_THRESH:
440 		if (!outdata || !outsize ||
441 				*outsize < sizeof(struct dfs_ioctl_params)) {
442 			error = -EINVAL;
443 			break;
444 		}
445 		*outsize = sizeof(struct dfs_ioctl_params);
446 		dfsparams = (struct dfs_ioctl_params *) outdata;
447 
448 		qdf_mem_zero(&peout, sizeof(struct wlan_dfs_phyerr_param));
449 
450 		/* Fetch the DFS thresholds using the internal representation */
451 		(void) dfs_get_thresholds(dfs, &peout);
452 
453 		/* Convert them to the dfs IOCTL representation. */
454 		wlan_dfs_dfsparam_to_ioctlparam(&peout, dfsparams);
455 		break;
456 	case DFS_RADARDETECTS:
457 		if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
458 			error = -EINVAL;
459 			break;
460 		}
461 		*outsize = sizeof(uint32_t);
462 		*((uint32_t *)outdata) = dfs->wlan_dfs_stats.num_radar_detects;
463 		break;
464 	case DFS_DISABLE_DETECT:
465 		dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN;
466 		dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN;
467 		dfs->dfs_ignore_dfs = 1;
468 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
469 				"enable detects, ignore_dfs %d",
470 				dfs->dfs_ignore_dfs ? 1:0);
471 		break;
472 	case DFS_ENABLE_DETECT:
473 		dfs->dfs_proc_phyerr |= DFS_RADAR_EN;
474 		dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN;
475 		dfs->dfs_ignore_dfs = 0;
476 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS
477 				, "enable detects, ignore_dfs %d",
478 				dfs->dfs_ignore_dfs ? 1:0);
479 		break;
480 	case DFS_DISABLE_FFT:
481 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
482 				"TODO disable FFT val=0x%x", val);
483 		break;
484 	case DFS_ENABLE_FFT:
485 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
486 				"TODO enable FFT val=0x%x", val);
487 		break;
488 	case DFS_SET_DEBUG_LEVEL:
489 		if (insize < sizeof(uint32_t) || !indata) {
490 			error = -EINVAL;
491 			break;
492 		}
493 		dfs->dfs_debug_mask = *(uint32_t *)indata;
494 
495 		/* Do not allow user to set the ALWAYS/MAX bit.
496 		 * It will be used internally  by dfs print macro(s)
497 		 * to print messages when dfs is NULL.
498 		 */
499 		dfs->dfs_debug_mask &= ~(WLAN_DEBUG_DFS_ALWAYS);
500 
501 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
502 				"debug level now = 0x%x", dfs->dfs_debug_mask);
503 		if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS3) {
504 			/* Enable debug Radar Event */
505 			dfs->dfs_event_log_on = 1;
506 		} else if ((utils_get_dfsdomain(dfs->dfs_pdev_obj) ==
507 		    DFS_FCC_DOMAIN) &&
508 		    lmac_is_host_dfs_check_support_enabled(dfs->dfs_pdev_obj)) {
509 			dfs->dfs_event_log_on = 1;
510 		} else {
511 			dfs->dfs_event_log_on = 0;
512 		}
513 		break;
514 	case DFS_SET_FALSE_RSSI_THRES:
515 		if (insize < sizeof(uint32_t) || !indata) {
516 			error = -EINVAL;
517 			break;
518 		}
519 		dfs->wlan_dfs_false_rssi_thres = *(uint32_t *)indata;
520 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
521 				"false RSSI threshold now = 0x%x",
522 				dfs->wlan_dfs_false_rssi_thres);
523 		break;
524 	case DFS_SET_PEAK_MAG:
525 		if (insize < sizeof(uint32_t) || !indata) {
526 			error = -EINVAL;
527 			break;
528 		}
529 		dfs->wlan_dfs_peak_mag = *(uint32_t *)indata;
530 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
531 				"peak_mag now = 0x%x",
532 				dfs->wlan_dfs_peak_mag);
533 		break;
534 	case DFS_GET_CAC_VALID_TIME:
535 		if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
536 			error = -EINVAL;
537 			break;
538 		}
539 		*outsize = sizeof(uint32_t);
540 		*((uint32_t *)outdata) = dfs->dfs_cac_valid_time;
541 		break;
542 	case DFS_SET_CAC_VALID_TIME:
543 		if (insize < sizeof(uint32_t) || !indata) {
544 			error = -EINVAL;
545 			break;
546 		}
547 		dfs->dfs_cac_valid_time = *(uint32_t *)indata;
548 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
549 				"dfs timeout = %d", dfs->dfs_cac_valid_time);
550 		break;
551 	case DFS_IGNORE_CAC:
552 		if (insize < sizeof(uint32_t) || !indata) {
553 			error = -EINVAL;
554 			break;
555 		}
556 
557 		if (*(uint32_t *)indata)
558 			dfs->dfs_ignore_cac = 1;
559 		else
560 			dfs->dfs_ignore_cac = 0;
561 
562 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
563 				"ignore cac = 0x%x", dfs->dfs_ignore_cac);
564 		break;
565 	case DFS_SET_NOL_TIMEOUT:
566 		if (insize < sizeof(uint32_t) || !indata) {
567 			error = -EINVAL;
568 			break;
569 		}
570 		if (*(int *)indata)
571 			dfs->wlan_dfs_nol_timeout = *(int *)indata;
572 		else
573 			dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
574 
575 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "nol timeout = %d sec",
576 				dfs->wlan_dfs_nol_timeout);
577 		break;
578 	case DFS_MUTE_TIME:
579 		if (insize < sizeof(uint32_t) || !indata) {
580 			error = -EINVAL;
581 			break;
582 		}
583 		data = (uint32_t *) indata;
584 		dfs->wlan_dfstesttime = *data;
585 		dfs->wlan_dfstesttime *= (1000); /* convert sec into ms */
586 		break;
587 	case DFS_GET_USENOL:
588 		if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
589 			error = -EINVAL;
590 			break;
591 		}
592 		*outsize = sizeof(uint32_t);
593 		*((uint32_t *)outdata) = dfs->dfs_use_nol;
594 
595 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
596 				"#Phyerr=%d, #false detect=%d, #queued=%d",
597 				 dfs->dfs_phyerr_count,
598 				dfs->dfs_phyerr_reject_count,
599 				dfs->dfs_phyerr_queued_count);
600 
601 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
602 				"dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d",
603 				 dfs->dfs_phyerr_freq_min,
604 				dfs->dfs_phyerr_freq_max);
605 
606 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
607 				"Total radar events detected=%d, entries in the radar queue follows:",
608 				 dfs->dfs_event_log_count);
609 
610 		for (i = 0; (i < DFS_EVENT_LOG_SIZE) &&
611 				(i < dfs->dfs_event_log_count); i++) {
612 #define FREQ_OFFSET1 ((int)dfs->radar_log[i].freq_offset_khz / 1000)
613 #define FREQ_OFFSET2 ((int)abs(dfs->radar_log[i].freq_offset_khz) % 1000)
614 			dfs_debug(dfs, WLAN_DEBUG_DFS,
615 					"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",
616 					dfs->radar_log[i].ts,
617 					dfs->radar_log[i].diff_ts,
618 					dfs->radar_log[i].rssi,
619 					dfs->radar_log[i].dur,
620 					dfs->radar_log[i].is_chirp,
621 					dfs->radar_log[i].seg_id,
622 					dfs->radar_log[i].sidx,
623 					FREQ_OFFSET1,
624 					FREQ_OFFSET2,
625 					dfs->radar_log[i].peak_mag,
626 					dfs->radar_log[i].total_gain,
627 					dfs->radar_log[i].mb_gain,
628 					dfs->radar_log[i].relpwr_db,
629 					dfs->radar_log[i].delta_diff,
630 					dfs->radar_log[i].delta_peak,
631 					dfs->radar_log[i].psidx_diff);
632 		}
633 		dfs->dfs_event_log_count = 0;
634 		dfs->dfs_phyerr_count = 0;
635 		dfs->dfs_phyerr_reject_count = 0;
636 		dfs->dfs_phyerr_queued_count = 0;
637 		dfs->dfs_phyerr_freq_min = 0x7fffffff;
638 		dfs->dfs_phyerr_freq_max = 0;
639 		break;
640 	case DFS_SET_USENOL:
641 		if (insize < sizeof(uint32_t) || !indata) {
642 			error = -EINVAL;
643 			break;
644 		}
645 		dfs->dfs_use_nol = *(uint32_t *)indata;
646 		usenol_pdev_param = dfs->dfs_use_nol;
647 		if (dfs->dfs_is_offload_enabled) {
648 			if (dfs->dfs_use_nol ==
649 				USENOL_ENABLE_NOL_HOST_DISABLE_NOL_FW)
650 				usenol_pdev_param = DISABLE_NOL_FW;
651 			tgt_dfs_send_usenol_pdev_param(dfs->dfs_pdev_obj,
652 						       usenol_pdev_param);
653 		}
654 		break;
655 	case DFS_SET_DISABLE_RADAR_MARKING:
656 		if (dfs->dfs_is_offload_enabled &&
657 		    (utils_get_dfsdomain(dfs->dfs_pdev_obj) ==
658 			 DFS_FCC_DOMAIN)) {
659 			if (insize < sizeof(uint32_t) || !indata) {
660 				error = -EINVAL;
661 				break;
662 			}
663 			dfs_set_disable_radar_marking(dfs, *(uint8_t *)indata);
664 		}
665 		break;
666 	case DFS_GET_DISABLE_RADAR_MARKING:
667 		if (!outdata || !outsize || *outsize < sizeof(uint8_t)) {
668 			error = -EINVAL;
669 			break;
670 		}
671 		if (dfs->dfs_is_offload_enabled) {
672 			*outsize = sizeof(uint8_t);
673 			*((uint8_t *)outdata) =
674 				dfs_get_disable_radar_marking(dfs);
675 		}
676 		break;
677 	case DFS_GET_NOL:
678 		if (!outdata || !outsize ||
679 				*outsize < sizeof(struct dfsreq_nolinfo)) {
680 			error = -EINVAL;
681 			break;
682 		}
683 		*outsize = sizeof(struct dfsreq_nolinfo);
684 		nol = (struct dfsreq_nolinfo *)outdata;
685 		DFS_GET_NOL_LOCKED(dfs,
686 				(struct dfsreq_nolelem *)nol->dfs_nol,
687 				&nol->dfs_ch_nchans);
688 		DFS_PRINT_NOL_LOCKED(dfs);
689 		break;
690 	case DFS_SET_NOL:
691 		if (insize < sizeof(struct dfsreq_nolinfo) || !indata) {
692 			error = -EINVAL;
693 			break;
694 		}
695 		nol = (struct dfsreq_nolinfo *) indata;
696 		dfs_set_nol(dfs,
697 				(struct dfsreq_nolelem *)nol->dfs_nol,
698 				nol->dfs_ch_nchans);
699 		break;
700 	case DFS_SHOW_NOL:
701 		DFS_PRINT_NOL_LOCKED(dfs);
702 		break;
703 	case DFS_SHOW_NOLHISTORY:
704 		dfs_print_nolhistory(dfs);
705 		break;
706 	case DFS_SHOW_PRECAC_LISTS:
707 		dfs_print_precaclists(dfs);
708 		dfs_print_etsi_precaclists(dfs);
709 		break;
710 	case DFS_RESET_PRECAC_LISTS:
711 		dfs_reset_precac_lists(dfs);
712 		dfs_reset_etsi_precac_lists(dfs);
713 		break;
714 	default:
715 		error = -EINVAL;
716 	}
717 
718 bad:
719 	return error;
720 }
721 
722 void dfs_set_current_channel(struct wlan_dfs *dfs,
723 		uint16_t dfs_ch_freq,
724 		uint64_t dfs_ch_flags,
725 		uint16_t dfs_ch_flagext,
726 		uint8_t dfs_ch_ieee,
727 		uint8_t dfs_ch_vhtop_ch_freq_seg1,
728 		uint8_t dfs_ch_vhtop_ch_freq_seg2)
729 {
730 	if (!dfs) {
731 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
732 		return;
733 	}
734 
735 	dfs->dfs_curchan->dfs_ch_freq = dfs_ch_freq;
736 	dfs->dfs_curchan->dfs_ch_flags = dfs_ch_flags;
737 	dfs->dfs_curchan->dfs_ch_flagext = dfs_ch_flagext;
738 	dfs->dfs_curchan->dfs_ch_ieee = dfs_ch_ieee;
739 	dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 = dfs_ch_vhtop_ch_freq_seg1;
740 	dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 = dfs_ch_vhtop_ch_freq_seg2;
741 }
742 
743 void dfs_update_cur_chan_flags(struct wlan_dfs *dfs,
744 		uint64_t flags,
745 		uint16_t flagext)
746 {
747 	dfs->dfs_curchan->dfs_ch_flags = flags;
748 	dfs->dfs_curchan->dfs_ch_flagext = flagext;
749 }
750