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