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