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