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