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 int dfs_control(struct wlan_dfs *dfs, 345 u_int id, 346 void *indata, 347 uint32_t insize, 348 void *outdata, 349 uint32_t *outsize) 350 { 351 struct wlan_dfs_phyerr_param peout; 352 struct dfs_ioctl_params *dfsparams; 353 struct dfs_bangradar_params *bangradar_params; 354 int error = 0; 355 uint32_t val = 0; 356 struct dfsreq_nolinfo *nol; 357 uint32_t *data = NULL; 358 int i; 359 struct dfs_emulate_bang_radar_test_cmd dfs_unit_test; 360 int usenol_pdev_param; 361 362 qdf_mem_zero(&dfs_unit_test, sizeof(dfs_unit_test)); 363 364 if (!dfs) { 365 dfs_err(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 366 goto bad; 367 } 368 369 switch (id) { 370 case DFS_SET_THRESH: 371 if (insize < sizeof(struct dfs_ioctl_params) || !indata) { 372 dfs_debug(dfs, WLAN_DEBUG_DFS1, 373 "insize = %d, expected = %zu bytes, indata = %pK", 374 insize, 375 sizeof(struct dfs_ioctl_params), 376 indata); 377 error = -EINVAL; 378 break; 379 } 380 dfsparams = (struct dfs_ioctl_params *)indata; 381 if (!dfs_set_thresholds(dfs, DFS_PARAM_FIRPWR, 382 dfsparams->dfs_firpwr)) 383 error = -EINVAL; 384 if (!dfs_set_thresholds(dfs, DFS_PARAM_RRSSI, 385 dfsparams->dfs_rrssi)) 386 error = -EINVAL; 387 if (!dfs_set_thresholds(dfs, DFS_PARAM_HEIGHT, 388 dfsparams->dfs_height)) 389 error = -EINVAL; 390 if (!dfs_set_thresholds(dfs, DFS_PARAM_PRSSI, 391 dfsparams->dfs_prssi)) 392 error = -EINVAL; 393 if (!dfs_set_thresholds(dfs, DFS_PARAM_INBAND, 394 dfsparams->dfs_inband)) 395 error = -EINVAL; 396 397 /* 5413 speicfic. */ 398 if (!dfs_set_thresholds(dfs, DFS_PARAM_RELPWR, 399 dfsparams->dfs_relpwr)) 400 error = -EINVAL; 401 if (!dfs_set_thresholds(dfs, DFS_PARAM_RELSTEP, 402 dfsparams->dfs_relstep)) 403 error = -EINVAL; 404 if (!dfs_set_thresholds(dfs, DFS_PARAM_MAXLEN, 405 dfsparams->dfs_maxlen)) 406 error = -EINVAL; 407 break; 408 case DFS_BANGRADAR: 409 /* 410 * Handle all types of Bangradar here. 411 * Bangradar arguments: 412 * seg_id : Segment ID where radar should be injected. 413 * is_chirp : Is chirp radar or non chirp radar. 414 * freq_offset : Frequency offset from center frequency. 415 * 416 * Type 1 (DFS_BANGRADAR_FOR_ALL_SUBCHANS): To add all subchans. 417 * Type 2 (DFS_BANGRADAR_FOR_ALL_SUBCHANS_OF_SEGID): To add all 418 * subchans of given segment_id. 419 * Type 3 (DFS_BANGRADAR_FOR_SPECIFIC_SUBCHANS): To add specific 420 * subchans based on the arguments. 421 * 422 * The arguments will already be filled in the indata structure 423 * based on the type. 424 * If an argument is not specified by user, it will be set to 425 * default (0) in the indata already and correspondingly, 426 * the type will change. 427 */ 428 if (insize < sizeof(struct dfs_bangradar_params) || 429 !indata) { 430 dfs_debug(dfs, WLAN_DEBUG_DFS1, 431 "insize = %d, expected = %zu bytes, indata = %pK", 432 insize, 433 sizeof(struct dfs_bangradar_params), 434 indata); 435 error = -EINVAL; 436 break; 437 } 438 bangradar_params = (struct dfs_bangradar_params *)indata; 439 if (bangradar_params) { 440 if (abs(bangradar_params->freq_offset) > 441 FREQ_OFFSET_BOUNDARY_FOR_80MHZ) { 442 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 443 "Frequency Offset out of bound"); 444 error = -EINVAL; 445 break; 446 } else if (bangradar_params->seg_id > 447 SEG_ID_SECONDARY) { 448 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 449 "Illegal segment ID"); 450 error = -EINVAL; 451 break; 452 } 453 dfs->dfs_bangradar_type = 454 bangradar_params->bangradar_type; 455 dfs->dfs_seg_id = bangradar_params->seg_id; 456 dfs->dfs_is_chirp = bangradar_params->is_chirp; 457 dfs->dfs_freq_offset = bangradar_params->freq_offset; 458 459 if (dfs->dfs_is_offload_enabled) { 460 error = dfs_fill_emulate_bang_radar_test 461 (dfs, dfs->dfs_seg_id, 462 dfs->dfs_is_chirp, 463 dfs->dfs_freq_offset, 464 &dfs_unit_test); 465 } else { 466 error = dfs_start_host_based_bangradar(dfs); 467 } 468 } else { 469 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 470 "bangradar_params is NULL"); 471 } 472 473 break; 474 case DFS_GET_THRESH: 475 if (!outdata || !outsize || 476 *outsize < sizeof(struct dfs_ioctl_params)) { 477 error = -EINVAL; 478 break; 479 } 480 *outsize = sizeof(struct dfs_ioctl_params); 481 dfsparams = (struct dfs_ioctl_params *) outdata; 482 483 qdf_mem_zero(&peout, sizeof(struct wlan_dfs_phyerr_param)); 484 485 /* Fetch the DFS thresholds using the internal representation */ 486 (void) dfs_get_thresholds(dfs, &peout); 487 488 /* Convert them to the dfs IOCTL representation. */ 489 wlan_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); 490 break; 491 case DFS_RADARDETECTS: 492 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 493 error = -EINVAL; 494 break; 495 } 496 *outsize = sizeof(uint32_t); 497 *((uint32_t *)outdata) = dfs->wlan_dfs_stats.num_radar_detects; 498 break; 499 case DFS_DISABLE_DETECT: 500 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; 501 dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN; 502 dfs->dfs_ignore_dfs = 1; 503 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 504 "enable detects, ignore_dfs %d", 505 dfs->dfs_ignore_dfs ? 1:0); 506 break; 507 case DFS_ENABLE_DETECT: 508 dfs->dfs_proc_phyerr |= DFS_RADAR_EN; 509 dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN; 510 dfs->dfs_ignore_dfs = 0; 511 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS 512 , "enable detects, ignore_dfs %d", 513 dfs->dfs_ignore_dfs ? 1:0); 514 break; 515 case DFS_DISABLE_FFT: 516 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 517 "TODO disable FFT val=0x%x", val); 518 break; 519 case DFS_ENABLE_FFT: 520 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 521 "TODO enable FFT val=0x%x", val); 522 break; 523 case DFS_SET_DEBUG_LEVEL: 524 if (insize < sizeof(uint32_t) || !indata) { 525 error = -EINVAL; 526 break; 527 } 528 dfs->dfs_debug_mask = *(uint32_t *)indata; 529 530 /* Do not allow user to set the ALWAYS/MAX bit. 531 * It will be used internally by dfs print macro(s) 532 * to print messages when dfs is NULL. 533 */ 534 dfs->dfs_debug_mask &= ~(WLAN_DEBUG_DFS_ALWAYS); 535 536 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 537 "debug level now = 0x%x", dfs->dfs_debug_mask); 538 if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS3) { 539 /* Enable debug Radar Event */ 540 dfs->dfs_event_log_on = 1; 541 } else if ((utils_get_dfsdomain(dfs->dfs_pdev_obj) == 542 DFS_FCC_DOMAIN) && 543 lmac_is_host_dfs_check_support_enabled(dfs->dfs_pdev_obj)) { 544 dfs->dfs_event_log_on = 1; 545 } else { 546 dfs->dfs_event_log_on = 0; 547 } 548 break; 549 case DFS_SET_FALSE_RSSI_THRES: 550 if (insize < sizeof(uint32_t) || !indata) { 551 error = -EINVAL; 552 break; 553 } 554 dfs->wlan_dfs_false_rssi_thres = *(uint32_t *)indata; 555 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 556 "false RSSI threshold now = 0x%x", 557 dfs->wlan_dfs_false_rssi_thres); 558 break; 559 case DFS_SET_PEAK_MAG: 560 if (insize < sizeof(uint32_t) || !indata) { 561 error = -EINVAL; 562 break; 563 } 564 dfs->wlan_dfs_peak_mag = *(uint32_t *)indata; 565 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 566 "peak_mag now = 0x%x", 567 dfs->wlan_dfs_peak_mag); 568 break; 569 case DFS_GET_CAC_VALID_TIME: 570 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 571 error = -EINVAL; 572 break; 573 } 574 *outsize = sizeof(uint32_t); 575 *((uint32_t *)outdata) = dfs->dfs_cac_valid_time; 576 break; 577 case DFS_SET_CAC_VALID_TIME: 578 if (insize < sizeof(uint32_t) || !indata) { 579 error = -EINVAL; 580 break; 581 } 582 dfs->dfs_cac_valid_time = *(uint32_t *)indata; 583 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 584 "dfs timeout = %d", dfs->dfs_cac_valid_time); 585 break; 586 case DFS_IGNORE_CAC: 587 if (insize < sizeof(uint32_t) || !indata) { 588 error = -EINVAL; 589 break; 590 } 591 592 if (*(uint32_t *)indata) 593 dfs->dfs_ignore_cac = 1; 594 else 595 dfs->dfs_ignore_cac = 0; 596 597 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 598 "ignore cac = 0x%x", dfs->dfs_ignore_cac); 599 break; 600 case DFS_SET_NOL_TIMEOUT: 601 if (insize < sizeof(uint32_t) || !indata) { 602 error = -EINVAL; 603 break; 604 } 605 if (*(int *)indata) 606 dfs->wlan_dfs_nol_timeout = *(int *)indata; 607 else 608 dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; 609 610 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "nol timeout = %d sec", 611 dfs->wlan_dfs_nol_timeout); 612 break; 613 case DFS_MUTE_TIME: 614 if (insize < sizeof(uint32_t) || !indata) { 615 error = -EINVAL; 616 break; 617 } 618 data = (uint32_t *) indata; 619 dfs->wlan_dfstesttime = *data; 620 dfs->wlan_dfstesttime *= (1000); /* convert sec into ms */ 621 break; 622 case DFS_GET_USENOL: 623 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { 624 error = -EINVAL; 625 break; 626 } 627 *outsize = sizeof(uint32_t); 628 *((uint32_t *)outdata) = dfs->dfs_use_nol; 629 630 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 631 "#Phyerr=%d, #false detect=%d, #queued=%d", 632 dfs->dfs_phyerr_count, 633 dfs->dfs_phyerr_reject_count, 634 dfs->dfs_phyerr_queued_count); 635 636 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 637 "dfs_phyerr_freq_min=%d, dfs_phyerr_freq_max=%d", 638 dfs->dfs_phyerr_freq_min, 639 dfs->dfs_phyerr_freq_max); 640 641 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 642 "Total radar events detected=%d, entries in the radar queue follows:", 643 dfs->dfs_event_log_count); 644 645 for (i = 0; (i < DFS_EVENT_LOG_SIZE) && 646 (i < dfs->dfs_event_log_count); i++) { 647 #define FREQ_OFFSET1 ((int)dfs->radar_log[i].freq_offset_khz / 1000) 648 #define FREQ_OFFSET2 ((int)abs(dfs->radar_log[i].freq_offset_khz) % 1000) 649 dfs_debug(dfs, WLAN_DEBUG_DFS, 650 "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", 651 dfs->radar_log[i].ts, 652 dfs->radar_log[i].diff_ts, 653 dfs->radar_log[i].rssi, 654 dfs->radar_log[i].dur, 655 dfs->radar_log[i].is_chirp, 656 dfs->radar_log[i].seg_id, 657 dfs->radar_log[i].sidx, 658 FREQ_OFFSET1, 659 FREQ_OFFSET2, 660 dfs->radar_log[i].peak_mag, 661 dfs->radar_log[i].total_gain, 662 dfs->radar_log[i].mb_gain, 663 dfs->radar_log[i].relpwr_db, 664 dfs->radar_log[i].delta_diff, 665 dfs->radar_log[i].delta_peak, 666 dfs->radar_log[i].psidx_diff); 667 } 668 dfs->dfs_event_log_count = 0; 669 dfs->dfs_phyerr_count = 0; 670 dfs->dfs_phyerr_reject_count = 0; 671 dfs->dfs_phyerr_queued_count = 0; 672 dfs->dfs_phyerr_freq_min = 0x7fffffff; 673 dfs->dfs_phyerr_freq_max = 0; 674 break; 675 case DFS_SET_USENOL: 676 if (insize < sizeof(uint32_t) || !indata) { 677 error = -EINVAL; 678 break; 679 } 680 dfs->dfs_use_nol = *(uint32_t *)indata; 681 usenol_pdev_param = dfs->dfs_use_nol; 682 if (dfs->dfs_is_offload_enabled) { 683 if (dfs->dfs_use_nol == 684 USENOL_ENABLE_NOL_HOST_DISABLE_NOL_FW) 685 usenol_pdev_param = DISABLE_NOL_FW; 686 tgt_dfs_send_usenol_pdev_param(dfs->dfs_pdev_obj, 687 usenol_pdev_param); 688 } 689 break; 690 case DFS_SET_DISABLE_RADAR_MARKING: 691 if (dfs->dfs_is_offload_enabled && 692 (utils_get_dfsdomain(dfs->dfs_pdev_obj) == 693 DFS_FCC_DOMAIN)) { 694 if (insize < sizeof(uint32_t) || !indata) { 695 error = -EINVAL; 696 break; 697 } 698 dfs_set_disable_radar_marking(dfs, *(uint8_t *)indata); 699 } 700 break; 701 case DFS_GET_DISABLE_RADAR_MARKING: 702 if (!outdata || !outsize || *outsize < sizeof(uint8_t)) { 703 error = -EINVAL; 704 break; 705 } 706 if (dfs->dfs_is_offload_enabled) { 707 *outsize = sizeof(uint8_t); 708 *((uint8_t *)outdata) = 709 dfs_get_disable_radar_marking(dfs); 710 } 711 break; 712 case DFS_GET_NOL: 713 if (!outdata || !outsize || 714 *outsize < sizeof(struct dfsreq_nolinfo)) { 715 error = -EINVAL; 716 break; 717 } 718 *outsize = sizeof(struct dfsreq_nolinfo); 719 nol = (struct dfsreq_nolinfo *)outdata; 720 DFS_GET_NOL_LOCKED(dfs, 721 (struct dfsreq_nolelem *)nol->dfs_nol, 722 &nol->dfs_ch_nchans); 723 DFS_PRINT_NOL_LOCKED(dfs); 724 break; 725 case DFS_SET_NOL: 726 if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { 727 error = -EINVAL; 728 break; 729 } 730 nol = (struct dfsreq_nolinfo *) indata; 731 dfs_set_nol(dfs, 732 (struct dfsreq_nolelem *)nol->dfs_nol, 733 nol->dfs_ch_nchans); 734 break; 735 case DFS_SHOW_NOL: 736 DFS_PRINT_NOL_LOCKED(dfs); 737 break; 738 case DFS_SHOW_NOLHISTORY: 739 dfs_print_nolhistory(dfs); 740 break; 741 case DFS_SHOW_PRECAC_LISTS: 742 dfs_print_precaclists(dfs); 743 break; 744 case DFS_RESET_PRECAC_LISTS: 745 dfs_reset_precac_lists(dfs); 746 break; 747 case DFS_INJECT_SEQUENCE: 748 error = dfs_inject_synthetic_pulse_sequence(dfs, indata); 749 if (error) 750 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 751 "Not injected Synthetic pulse"); 752 break; 753 754 case DFS_ALLOW_HW_PULSES: 755 if (insize < sizeof(u_int8_t) || !indata) { 756 error = -EINVAL; 757 break; 758 } 759 dfs_allow_hw_pulses(dfs, !!(*(u_int8_t *)indata)); 760 break; 761 case DFS_SET_PRI_MULTIPILER: 762 dfs->dfs_pri_multiplier = *(int *)indata; 763 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 764 "Set dfs pri multiplier to %d, dfsdomain %d", 765 dfs->dfs_pri_multiplier, dfs->dfsdomain); 766 break; 767 default: 768 error = -EINVAL; 769 } 770 771 bad: 772 return error; 773 } 774 775 /** 776 * dfs_is_curchan_same_as_given_chan() - Find if dfs_curchan has the same 777 * channel parameters provided. 778 * @dfs_curchan: Pointer to DFS current channel structure. 779 * @dfs_ch_freq: New curchan's primary frequency. 780 * @dfs_ch_flags: New curchan's channel flags. 781 * @dfs_ch_flagext: New curchan's channel flags extension. 782 * @dfs_ch_vhtop_ch_freq_seg1: New curchan's primary centre IEEE. 783 * @dfs_ch_vhtop_ch_freq_seg2: New curchan's secondary centre IEEE. 784 * 785 * Return: True if curchan has the same channel parameters of the given channel, 786 * else false. 787 */ 788 static bool 789 dfs_is_curchan_same_as_given_chan(struct dfs_channel *dfs_curchan, 790 uint16_t dfs_ch_freq, 791 uint64_t dfs_ch_flags, 792 uint16_t dfs_ch_flagext, 793 uint8_t dfs_ch_vhtop_ch_freq_seg1, 794 uint8_t dfs_ch_vhtop_ch_freq_seg2) 795 { 796 if ((dfs_curchan->dfs_ch_freq == dfs_ch_freq) && 797 (dfs_curchan->dfs_ch_flags == dfs_ch_flags) && 798 (dfs_curchan->dfs_ch_flagext == dfs_ch_flagext) && 799 (dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 == 800 dfs_ch_vhtop_ch_freq_seg1) && 801 (dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 == 802 dfs_ch_vhtop_ch_freq_seg2)) 803 return true; 804 805 return false; 806 } 807 808 #ifdef CONFIG_CHAN_NUM_API 809 void dfs_set_current_channel(struct wlan_dfs *dfs, 810 uint16_t dfs_ch_freq, 811 uint64_t dfs_ch_flags, 812 uint16_t dfs_ch_flagext, 813 uint8_t dfs_ch_ieee, 814 uint8_t dfs_ch_vhtop_ch_freq_seg1, 815 uint8_t dfs_ch_vhtop_ch_freq_seg2) 816 { 817 if (!dfs) { 818 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 819 return; 820 } 821 822 if (!dfs->dfs_curchan) { 823 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_curchan is NULL"); 824 return; 825 } 826 827 /* Check if the input parameters are the same as that of dfs_curchan */ 828 if (dfs_is_curchan_same_as_given_chan(dfs->dfs_curchan, 829 dfs_ch_freq, 830 dfs_ch_flags, 831 dfs_ch_flagext, 832 dfs_ch_vhtop_ch_freq_seg1, 833 dfs_ch_vhtop_ch_freq_seg2)) { 834 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 835 "dfs_curchan already updated"); 836 return; 837 } 838 839 /* Update dfs previous channel with the old dfs_curchan, if it exists */ 840 if (dfs->dfs_curchan->dfs_ch_freq) 841 qdf_mem_copy(dfs->dfs_prevchan, 842 dfs->dfs_curchan, 843 sizeof(struct dfs_channel)); 844 845 dfs->dfs_curchan->dfs_ch_freq = dfs_ch_freq; 846 dfs->dfs_curchan->dfs_ch_flags = dfs_ch_flags; 847 dfs->dfs_curchan->dfs_ch_flagext = dfs_ch_flagext; 848 dfs->dfs_curchan->dfs_ch_ieee = dfs_ch_ieee; 849 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 = dfs_ch_vhtop_ch_freq_seg1; 850 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 = dfs_ch_vhtop_ch_freq_seg2; 851 } 852 #endif 853 854 #ifdef CONFIG_CHAN_FREQ_API 855 void dfs_set_current_channel_for_freq(struct wlan_dfs *dfs, 856 uint16_t dfs_chan_freq, 857 uint64_t dfs_chan_flags, 858 uint16_t dfs_chan_flagext, 859 uint8_t dfs_chan_ieee, 860 uint8_t dfs_chan_vhtop_freq_seg1, 861 uint8_t dfs_chan_vhtop_freq_seg2, 862 uint16_t dfs_chan_mhz_freq_seg1, 863 uint16_t dfs_chan_mhz_freq_seg2) 864 865 { 866 if (!dfs) { 867 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 868 return; 869 } 870 871 /* Check if the input parameters are the same as that of dfs_curchan */ 872 if (dfs_is_curchan_same_as_given_chan(dfs->dfs_curchan, 873 dfs_chan_freq, 874 dfs_chan_flags, 875 dfs_chan_flagext, 876 dfs_chan_vhtop_freq_seg1, 877 dfs_chan_vhtop_freq_seg2)) { 878 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, 879 "dfs_curchan already updated"); 880 return; 881 } 882 883 /* Update dfs previous channel with the old dfs_curchan, if it exists */ 884 if (dfs->dfs_curchan->dfs_ch_freq) 885 qdf_mem_copy(dfs->dfs_prevchan, 886 dfs->dfs_curchan, 887 sizeof(struct dfs_channel)); 888 889 dfs->dfs_curchan->dfs_ch_freq = dfs_chan_freq; 890 dfs->dfs_curchan->dfs_ch_flags = dfs_chan_flags; 891 dfs->dfs_curchan->dfs_ch_flagext = dfs_chan_flagext; 892 dfs->dfs_curchan->dfs_ch_ieee = dfs_chan_ieee; 893 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1 = dfs_chan_vhtop_freq_seg1; 894 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2 = dfs_chan_vhtop_freq_seg2; 895 dfs->dfs_curchan->dfs_ch_mhz_freq_seg1 = dfs_chan_mhz_freq_seg1; 896 dfs->dfs_curchan->dfs_ch_mhz_freq_seg2 = dfs_chan_mhz_freq_seg2; 897 } 898 #endif 899 900 void dfs_update_cur_chan_flags(struct wlan_dfs *dfs, 901 uint64_t flags, 902 uint16_t flagext) 903 { 904 dfs->dfs_curchan->dfs_ch_flags = flags; 905 dfs->dfs_curchan->dfs_ch_flagext = flagext; 906 } 907 908 int dfs_reinit_timers(struct wlan_dfs *dfs) 909 { 910 dfs_cac_timer_attach(dfs); 911 dfs_zero_cac_timer_init(dfs->dfs_soc_obj); 912 dfs_nol_timer_init(dfs); 913 dfs_main_task_testtimer_init(dfs); 914 return 0; 915 } 916 917 void dfs_reset_dfs_prevchan(struct wlan_dfs *dfs) 918 { 919 qdf_mem_zero(dfs->dfs_prevchan, sizeof(struct dfs_channel)); 920 } 921 922 bool dfs_is_hw_mode_switch_in_progress(struct wlan_dfs *dfs) 923 { 924 return lmac_dfs_is_hw_mode_switch_in_progress(dfs->dfs_pdev_obj); 925 } 926 927 void dfs_complete_deferred_tasks(struct wlan_dfs *dfs) 928 { 929 if (dfs->dfs_defer_params.is_radar_detected) { 930 /* Handle radar event that was deferred and free the temporary 931 * storage of the radar event parameters. 932 */ 933 dfs_process_radar_ind(dfs, dfs->dfs_defer_params.radar_params); 934 qdf_mem_free(dfs->dfs_defer_params.radar_params); 935 dfs->dfs_defer_params.is_radar_detected = false; 936 } else if (dfs->dfs_defer_params.is_cac_completed) { 937 /* Handle CAC completion event that was deferred for HW mode 938 * switch. 939 */ 940 dfs_process_cac_completion(dfs); 941 dfs->dfs_defer_params.is_cac_completed = false; 942 } 943 } 944