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