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