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