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