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