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