1 /* 2 * Copyright (c) 2011,2017-2019 The Linux Foundation. All rights reserved. 3 * 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <wlan_tgt_def_config.h> 21 #include <hif.h> 22 #include <target_type.h> 23 #include <hif_hw_version.h> 24 #include <wmi_unified_api.h> 25 #include <target_if_spectral.h> 26 #include <wlan_lmac_if_def.h> 27 #include <wlan_osif_priv.h> 28 #include <init_deinit_lmac.h> 29 #include <reg_services_public_struct.h> 30 #include <target_if_spectral_sim.h> 31 #include <target_if.h> 32 #include <qdf_module.h> 33 #include <wlan_reg_services_api.h> 34 #include <wlan_dfs_ucfg_api.h> 35 36 /** 37 * @spectral_ops - Spectral function table, holds the Spectral functions that 38 * depend on whether the architecture is Direct Attach or Offload. This is used 39 * to populate the actual Spectral function table present in the Spectral 40 * module. 41 */ 42 struct target_if_spectral_ops spectral_ops; 43 int spectral_debug_level = DEBUG_SPECTRAL; 44 45 static void target_if_spectral_get_firstvdev_pdev(struct wlan_objmgr_pdev *pdev, 46 void *obj, void *arg) 47 { 48 struct wlan_objmgr_vdev *vdev = obj; 49 struct wlan_objmgr_vdev **first_vdev = arg; 50 51 if (!(*first_vdev)) 52 *first_vdev = vdev; 53 } 54 55 struct wlan_objmgr_vdev * 56 target_if_spectral_get_vdev(struct target_if_spectral *spectral) 57 { 58 struct wlan_objmgr_pdev *pdev = NULL; 59 struct wlan_objmgr_vdev *first_vdev = NULL; 60 61 qdf_assert_always(spectral); 62 pdev = spectral->pdev_obj; 63 qdf_assert_always(pdev); 64 65 if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_SPECTRAL_ID) != 66 QDF_STATUS_SUCCESS) { 67 spectral_err("Unable to get pdev reference."); 68 return NULL; 69 } 70 71 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 72 target_if_spectral_get_firstvdev_pdev, 73 &first_vdev, 0, WLAN_SPECTRAL_ID); 74 75 wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID); 76 77 if (!first_vdev) 78 return NULL; 79 80 if (wlan_objmgr_vdev_try_get_ref(first_vdev, WLAN_SPECTRAL_ID) != 81 QDF_STATUS_SUCCESS) 82 first_vdev = NULL; 83 84 85 return first_vdev; 86 } 87 88 /** 89 * target_if_send_vdev_spectral_configure_cmd() - Send WMI command to configure 90 * spectral parameters 91 * @spectral: Pointer to Spectral target_if internal private data 92 * @param: Pointer to spectral_config giving the Spectral configuration 93 * 94 * Return: QDF_STATUS_SUCCESS on success, negative error code on failure 95 */ 96 static int 97 target_if_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral, 98 struct spectral_config *param) 99 { 100 struct vdev_spectral_configure_params sparam; 101 struct wlan_objmgr_pdev *pdev = NULL; 102 struct wlan_objmgr_vdev *vdev = NULL; 103 104 qdf_assert_always(spectral && param); 105 106 pdev = spectral->pdev_obj; 107 108 qdf_assert_always(pdev); 109 110 vdev = target_if_spectral_get_vdev(spectral); 111 if (!vdev) 112 return QDF_STATUS_E_NOENT; 113 114 qdf_mem_zero(&sparam, sizeof(sparam)); 115 116 sparam.vdev_id = wlan_vdev_get_id(vdev); 117 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 118 119 sparam.count = param->ss_count; 120 sparam.period = param->ss_period; 121 sparam.spectral_pri = param->ss_spectral_pri; 122 sparam.fft_size = param->ss_fft_size; 123 sparam.gc_enable = param->ss_gc_ena; 124 sparam.restart_enable = param->ss_restart_ena; 125 sparam.noise_floor_ref = param->ss_noise_floor_ref; 126 sparam.init_delay = param->ss_init_delay; 127 sparam.nb_tone_thr = param->ss_nb_tone_thr; 128 sparam.str_bin_thr = param->ss_str_bin_thr; 129 sparam.wb_rpt_mode = param->ss_wb_rpt_mode; 130 sparam.rssi_rpt_mode = param->ss_rssi_rpt_mode; 131 sparam.rssi_thr = param->ss_rssi_thr; 132 sparam.pwr_format = param->ss_pwr_format; 133 sparam.rpt_mode = param->ss_rpt_mode; 134 sparam.bin_scale = param->ss_bin_scale; 135 sparam.dbm_adj = param->ss_dbm_adj; 136 sparam.chn_mask = param->ss_chn_mask; 137 138 return spectral->param_wmi_cmd_ops.wmi_spectral_configure_cmd_send( 139 GET_WMI_HDL_FROM_PDEV(pdev), &sparam); 140 } 141 142 /** 143 * target_if_send_vdev_spectral_enable_cmd() - Send WMI command to 144 * enable/disable Spectral 145 * @spectral: Pointer to Spectral target_if internal private data 146 * @is_spectral_active_valid: Flag to indicate if spectral activate (trigger) is 147 * valid 148 * @is_spectral_active: Value of spectral activate 149 * @is_spectral_enabled_valid: Flag to indicate if spectral enable is valid 150 * @is_spectral_enabled: Value of spectral enable 151 * 152 * Return: QDF_STATUS_SUCCESS on success, negative error code on failure 153 */ 154 static int 155 target_if_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral, 156 uint8_t is_spectral_active_valid, 157 uint8_t is_spectral_active, 158 uint8_t is_spectral_enabled_valid, 159 uint8_t is_spectral_enabled) 160 { 161 struct vdev_spectral_enable_params param; 162 struct wlan_objmgr_pdev *pdev = NULL; 163 struct wlan_objmgr_vdev *vdev = NULL; 164 165 qdf_assert_always(spectral); 166 167 pdev = spectral->pdev_obj; 168 169 qdf_assert_always(pdev); 170 171 vdev = target_if_spectral_get_vdev(spectral); 172 if (!vdev) 173 return QDF_STATUS_E_NOENT; 174 175 qdf_mem_zero(¶m, sizeof(param)); 176 177 param.vdev_id = wlan_vdev_get_id(vdev); 178 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 179 180 param.active_valid = is_spectral_active_valid; 181 param.enabled_valid = is_spectral_enabled_valid; 182 param.active = is_spectral_active; 183 param.enabled = is_spectral_enabled; 184 185 return spectral->param_wmi_cmd_ops.wmi_spectral_enable_cmd_send( 186 GET_WMI_HDL_FROM_PDEV(pdev), ¶m); 187 } 188 189 /** 190 * target_if_spectral_info_init_defaults() - Helper function to load defaults 191 * for Spectral information (parameters and state) into cache. 192 * @spectral: Pointer to Spectral target_if internal private data 193 * @smode: Spectral scan mode 194 * 195 * It is assumed that the caller has obtained the requisite lock if applicable. 196 * Note that this is currently treated as a temporary function. Ideally, we 197 * would like to get defaults from the firmware. 198 * 199 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure 200 */ 201 static QDF_STATUS 202 target_if_spectral_info_init_defaults(struct target_if_spectral *spectral, 203 enum spectral_scan_mode smode) 204 { 205 struct target_if_spectral_param_state_info *info; 206 struct wlan_objmgr_vdev *vdev = NULL; 207 208 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 209 spectral_err("Invalid Spectral mode %u", smode); 210 return QDF_STATUS_E_FAILURE; 211 } 212 213 info = &spectral->param_info[smode]; 214 215 /* State */ 216 info->osps_cache.osc_spectral_active = SPECTRAL_SCAN_ACTIVE_DEFAULT; 217 218 info->osps_cache.osc_spectral_enabled = SPECTRAL_SCAN_ENABLE_DEFAULT; 219 220 /* Parameters */ 221 info->osps_cache.osc_params.ss_count = SPECTRAL_SCAN_COUNT_DEFAULT; 222 223 if (spectral->spectral_gen == SPECTRAL_GEN3) 224 info->osps_cache.osc_params.ss_period = 225 SPECTRAL_SCAN_PERIOD_GEN_III_DEFAULT; 226 else 227 info->osps_cache.osc_params.ss_period = 228 SPECTRAL_SCAN_PERIOD_GEN_II_DEFAULT; 229 230 info->osps_cache.osc_params.ss_spectral_pri = 231 SPECTRAL_SCAN_PRIORITY_DEFAULT; 232 233 info->osps_cache.osc_params.ss_fft_size = 234 SPECTRAL_SCAN_FFT_SIZE_DEFAULT; 235 236 info->osps_cache.osc_params.ss_gc_ena = SPECTRAL_SCAN_GC_ENA_DEFAULT; 237 238 info->osps_cache.osc_params.ss_restart_ena = 239 SPECTRAL_SCAN_RESTART_ENA_DEFAULT; 240 241 info->osps_cache.osc_params.ss_noise_floor_ref = 242 SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT; 243 244 info->osps_cache.osc_params.ss_init_delay = 245 SPECTRAL_SCAN_INIT_DELAY_DEFAULT; 246 247 info->osps_cache.osc_params.ss_nb_tone_thr = 248 SPECTRAL_SCAN_NB_TONE_THR_DEFAULT; 249 250 info->osps_cache.osc_params.ss_str_bin_thr = 251 SPECTRAL_SCAN_STR_BIN_THR_DEFAULT; 252 253 info->osps_cache.osc_params.ss_wb_rpt_mode = 254 SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT; 255 256 info->osps_cache.osc_params.ss_rssi_rpt_mode = 257 SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT; 258 259 info->osps_cache.osc_params.ss_rssi_thr = 260 SPECTRAL_SCAN_RSSI_THR_DEFAULT; 261 262 info->osps_cache.osc_params.ss_pwr_format = 263 SPECTRAL_SCAN_PWR_FORMAT_DEFAULT; 264 265 info->osps_cache.osc_params.ss_rpt_mode = 266 SPECTRAL_SCAN_RPT_MODE_DEFAULT; 267 268 info->osps_cache.osc_params.ss_bin_scale = 269 SPECTRAL_SCAN_BIN_SCALE_DEFAULT; 270 271 info->osps_cache.osc_params.ss_dbm_adj = SPECTRAL_SCAN_DBM_ADJ_DEFAULT; 272 273 vdev = target_if_spectral_get_vdev(spectral); 274 if (!vdev) 275 return QDF_STATUS_E_NOENT; 276 277 info->osps_cache.osc_params.ss_chn_mask = 278 wlan_vdev_mlme_get_rxchainmask(vdev); 279 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 280 281 info->osps_cache.osc_params.ss_short_report = 282 SPECTRAL_SCAN_SHORT_REPORT_DEFAULT; 283 284 info->osps_cache.osc_params.ss_fft_period = 285 SPECTRAL_SCAN_FFT_PERIOD_DEFAULT; 286 287 info->osps_cache.osc_params.ss_frequency = 288 SPECTRAL_SCAN_FREQUENCY_DEFAULT; 289 290 /* The cache is now valid */ 291 info->osps_cache.osc_is_valid = 1; 292 293 return QDF_STATUS_SUCCESS; 294 } 295 296 /** 297 * target_if_log_read_spectral_active() - Helper function to log whether 298 * spectral is active after reading cache 299 * @function_name: Function name 300 * @output: whether spectral is active or not 301 * 302 * Helper function to log whether spectral is active after reading cache 303 * 304 * Return: none 305 */ 306 static void 307 target_if_log_read_spectral_active( 308 const char *function_name, 309 unsigned char output) 310 { 311 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE. Returning val=%u", 312 function_name, output); 313 } 314 315 /** 316 * target_if_log_read_spectral_enabled() - Helper function to log whether 317 * spectral is enabled after reading cache 318 * @function_name: Function name 319 * @output: whether spectral is enabled or not 320 * 321 * Helper function to log whether spectral is enabled after reading cache 322 * 323 * Return: none 324 */ 325 static void 326 target_if_log_read_spectral_enabled( 327 const char *function_name, 328 unsigned char output) 329 { 330 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED. Returning val=%u", 331 function_name, output); 332 } 333 334 /** 335 * target_if_log_read_spectral_enabled() - Helper function to log spectral 336 * parameters after reading cache 337 * @function_name: Function name 338 * @pparam: Spectral parameters 339 * 340 * Helper function to log spectral parameters after reading cache 341 * 342 * Return: none 343 */ 344 static void 345 target_if_log_read_spectral_params( 346 const char *function_name, 347 struct spectral_config *pparam) 348 { 349 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_PARAMS. Returning following params:\nss_count = %u\nss_period = %u\nss_spectral_pri = %u\nss_fft_size = %u\nss_gc_ena = %u\nss_restart_ena = %u\nss_noise_floor_ref = %d\nss_init_delay = %u\nss_nb_tone_thr = %u\nss_str_bin_thr = %u\nss_wb_rpt_mode = %u\nss_rssi_rpt_mode = %u\nss_rssi_thr = %d\nss_pwr_format = %u\nss_rpt_mode = %u\nss_bin_scale = %u\nss_dbm_adj = %u\nss_chn_mask = %u\nss_frequency=%u\n", 350 function_name, 351 pparam->ss_count, 352 pparam->ss_period, 353 pparam->ss_spectral_pri, 354 pparam->ss_fft_size, 355 pparam->ss_gc_ena, 356 pparam->ss_restart_ena, 357 (int8_t)pparam->ss_noise_floor_ref, 358 pparam->ss_init_delay, 359 pparam->ss_nb_tone_thr, 360 pparam->ss_str_bin_thr, 361 pparam->ss_wb_rpt_mode, 362 pparam->ss_rssi_rpt_mode, 363 (int8_t)pparam->ss_rssi_thr, 364 pparam->ss_pwr_format, 365 pparam->ss_rpt_mode, 366 pparam->ss_bin_scale, 367 pparam->ss_dbm_adj, 368 pparam->ss_chn_mask, 369 pparam->ss_frequency); 370 } 371 372 /** 373 * target_if_log_read_spectral_active_catch_validate() - Helper function to 374 * log whether spectral is active after intializing the cache 375 * @function_name: Function name 376 * @output: whether spectral is active or not 377 * 378 * Helper function to log whether spectral is active after intializing cache 379 * 380 * Return: none 381 */ 382 static void 383 target_if_log_read_spectral_active_catch_validate( 384 const char *function_name, 385 unsigned char output) 386 { 387 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE on initial cache validation\nReturning val=%u", 388 function_name, output); 389 } 390 391 /** 392 * target_if_log_read_spectral_enabled_catch_validate() - Helper function to 393 * log whether spectral is enabled after intializing the cache 394 * @function_name: Function name 395 * @output: whether spectral is enabled or not 396 * 397 * Helper function to log whether spectral is enabled after intializing cache 398 * 399 * Return: none 400 */ 401 static void 402 target_if_log_read_spectral_enabled_catch_validate( 403 const char *function_name, 404 unsigned char output) 405 { 406 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED on initial cache validation\nReturning val=%u\n", 407 function_name, output); 408 } 409 410 /** 411 * target_if_log_read_spectral_params_catch_validate() - Helper function to 412 * log spectral parameters after intializing the cache 413 * @function_name: Function name 414 * @pparam: Spectral parameters 415 * 416 * Helper function to log spectral parameters after intializing the cache 417 * 418 * Return: none 419 */ 420 static void 421 target_if_log_read_spectral_params_catch_validate( 422 const char *function_name, 423 struct spectral_config *pparam) 424 { 425 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_PARAMS on initial cache validation\nReturning following params:\nss_count = %u\nss_period = %u\nss_spectral_pri = %u\nss_fft_size = %u\nss_gc_ena = %u\nss_restart_ena = %u\nss_noise_floor_ref = %d\nss_init_delay = %u\nss_nb_tone_thr = %u\nss_str_bin_thr = %u\nss_wb_rpt_mode = %u\nss_rssi_rpt_mode = %u\nss_rssi_thr = %d\nss_pwr_format = %u\nss_rpt_mode = %u\nss_bin_scale = %u\nss_dbm_adj = %u\nss_chn_mask = %u", 426 function_name, 427 pparam->ss_count, 428 pparam->ss_period, 429 pparam->ss_spectral_pri, 430 pparam->ss_fft_size, 431 pparam->ss_gc_ena, 432 pparam->ss_restart_ena, 433 (int8_t)pparam->ss_noise_floor_ref, 434 pparam->ss_init_delay, 435 pparam->ss_nb_tone_thr, 436 pparam->ss_str_bin_thr, 437 pparam->ss_wb_rpt_mode, 438 pparam->ss_rssi_rpt_mode, 439 (int8_t)pparam->ss_rssi_thr, 440 pparam->ss_pwr_format, 441 pparam->ss_rpt_mode, 442 pparam->ss_bin_scale, 443 pparam->ss_dbm_adj, pparam->ss_chn_mask); 444 } 445 446 /** 447 * target_if_spectral_info_read() - Read spectral information from the cache. 448 * @spectral: Pointer to Spectral target_if internal private data 449 * @smode: Spectral scan mode 450 * @specifier: target_if_spectral_info enumeration specifying which 451 * information is required 452 * @output: Void output pointer into which the information will be read 453 * @output_len: size of object pointed to by output pointer 454 * 455 * Read spectral parameters or the desired state information from the cache. 456 * 457 * Return: 0 on success, negative error code on failure 458 */ 459 static int 460 target_if_spectral_info_read( 461 struct target_if_spectral *spectral, 462 enum spectral_scan_mode smode, 463 enum target_if_spectral_info specifier, 464 void *output, int output_len) 465 { 466 /* 467 * Note: This function is designed to be able to accommodate 468 * WMI reads for defaults, non-cacheable information, etc 469 * if required. 470 */ 471 struct target_if_spectral_param_state_info *info; 472 int is_cacheable = 0; 473 int init_def_retval = 0; 474 475 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 476 spectral_err("Invalid Spectral mode %u", smode); 477 return -EINVAL; 478 } 479 info = &spectral->param_info[smode]; 480 481 if (!output) 482 return -EINVAL; 483 484 switch (specifier) { 485 case TARGET_IF_SPECTRAL_INFO_ACTIVE: 486 if (output_len != sizeof(info->osps_cache.osc_spectral_active)) 487 return -EINVAL; 488 is_cacheable = 1; 489 break; 490 491 case TARGET_IF_SPECTRAL_INFO_ENABLED: 492 if (output_len != sizeof(info->osps_cache.osc_spectral_enabled)) 493 return -EINVAL; 494 is_cacheable = 1; 495 break; 496 497 case TARGET_IF_SPECTRAL_INFO_PARAMS: 498 if (output_len != sizeof(info->osps_cache.osc_params)) 499 return -EINVAL; 500 is_cacheable = 1; 501 break; 502 503 default: 504 spectral_err("Unknown target_if_spectral_info specifier"); 505 return -EINVAL; 506 } 507 508 qdf_spin_lock(&info->osps_lock); 509 510 if (is_cacheable) { 511 if (info->osps_cache.osc_is_valid) { 512 switch (specifier) { 513 case TARGET_IF_SPECTRAL_INFO_ACTIVE: 514 qdf_mem_copy( 515 output, 516 &info->osps_cache.osc_spectral_active, 517 sizeof(info->osps_cache.osc_spectral_active)); 518 519 target_if_log_read_spectral_active( 520 __func__, 521 *((unsigned char *)output)); 522 break; 523 524 case TARGET_IF_SPECTRAL_INFO_ENABLED: 525 qdf_mem_copy( 526 output, 527 &info->osps_cache.osc_spectral_enabled, 528 sizeof( 529 info->osps_cache.osc_spectral_enabled)); 530 531 target_if_log_read_spectral_enabled( 532 __func__, 533 *((unsigned char *)output)); 534 break; 535 536 case TARGET_IF_SPECTRAL_INFO_PARAMS: 537 qdf_mem_copy( 538 output, 539 &info->osps_cache.osc_params, 540 sizeof(info->osps_cache.osc_params)); 541 542 target_if_log_read_spectral_params( 543 __func__, 544 (struct spectral_config *)output); 545 break; 546 547 default: 548 /* We can't reach this point */ 549 break; 550 } 551 qdf_spin_unlock(&info->osps_lock); 552 return 0; 553 } 554 } 555 556 /* Cache is invalid */ 557 558 /* 559 * If WMI Reads are implemented to fetch defaults/non-cacheable info, 560 * then the below implementation will change 561 */ 562 init_def_retval = 563 target_if_spectral_info_init_defaults(spectral, smode); 564 if (init_def_retval != QDF_STATUS_SUCCESS) { 565 qdf_spin_unlock(&info->osps_lock); 566 if (init_def_retval == QDF_STATUS_E_NOENT) 567 return -ENOENT; 568 else 569 return -EINVAL; 570 } 571 /* target_if_spectral_info_init_defaults() has set cache to valid */ 572 573 switch (specifier) { 574 case TARGET_IF_SPECTRAL_INFO_ACTIVE: 575 qdf_mem_copy(output, 576 &info->osps_cache.osc_spectral_active, 577 sizeof(info->osps_cache.osc_spectral_active)); 578 579 target_if_log_read_spectral_active_catch_validate( 580 __func__, 581 *((unsigned char *)output)); 582 break; 583 584 case TARGET_IF_SPECTRAL_INFO_ENABLED: 585 qdf_mem_copy(output, 586 &info->osps_cache.osc_spectral_enabled, 587 sizeof(info->osps_cache.osc_spectral_enabled)); 588 589 target_if_log_read_spectral_enabled_catch_validate( 590 __func__, 591 *((unsigned char *)output)); 592 break; 593 594 case TARGET_IF_SPECTRAL_INFO_PARAMS: 595 qdf_mem_copy(output, 596 &info->osps_cache.osc_params, 597 sizeof(info->osps_cache.osc_params)); 598 599 target_if_log_read_spectral_params_catch_validate( 600 __func__, 601 (struct spectral_config *)output); 602 603 break; 604 605 default: 606 /* We can't reach this point */ 607 break; 608 } 609 610 qdf_spin_unlock(&info->osps_lock); 611 612 return 0; 613 } 614 615 /** 616 * target_if_log_write_spectral_active() - Helper function to log inputs and 617 * return value of call to configure the Spectral 'active' configuration, 618 * TARGET_IF_SPECTRAL_INFO_ACTIVE into firmware 619 * @function_name: Function name in which this is called 620 * @pval: whether spectral is active or not 621 * @ret: return value of the firmware write function 622 * 623 * Return: none 624 */ 625 static void 626 target_if_log_write_spectral_active( 627 const char *function_name, 628 uint8_t pval, 629 int ret) 630 { 631 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE with val=%u status=%d", 632 function_name, pval, ret); 633 } 634 635 /** 636 * target_if_log_write_spectral_enabled() - Helper function to log inputs and 637 * return value of call to configure the Spectral 'enabled' configuration, 638 * TARGET_IF_SPECTRAL_INFO_ENABLED into firmware 639 * @function_name: Function name in which this is called 640 * @pval: whether spectral is enabled or not 641 * @ret: return value of the firmware write function 642 * 643 * Return: none 644 */ 645 static void 646 target_if_log_write_spectral_enabled( 647 const char *function_name, 648 uint8_t pval, 649 int ret) 650 { 651 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED with val=%u status=%d", 652 function_name, pval, ret); 653 } 654 655 /** 656 * target_if_log_write_spectral_params() - Helper function to log inputs and 657 * return value of call to configure Spectral parameters, 658 * TARGET_IF_SPECTRAL_INFO_PARAMS into firmware 659 * @param: Spectral parameters 660 * @function_name: Function name in which this is called 661 * @ret: return value of the firmware write function 662 * 663 * Return: none 664 */ 665 static void 666 target_if_log_write_spectral_params( 667 struct spectral_config *param, 668 const char *function_name, 669 int ret) 670 { 671 spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_PARAMS. Params:\nss_count = %u\nss_period = %u\nss_spectral_pri = %u\nss_fft_size = %u\nss_gc_ena = %u\nss_restart_ena = %u\nss_noise_floor_ref = %d\nss_init_delay = %u\nss_nb_tone_thr = %u\nss_str_bin_thr = %u\nss_wb_rpt_mode = %u\nss_rssi_rpt_mode = %u\nss_rssi_thr = %d\nss_pwr_format = %u\nss_rpt_mode = %u\nss_bin_scale = %u\nss_dbm_adj = %u\nss_chn_mask = %u\nss_frequency=%u\nstatus = %d", 672 function_name, 673 param->ss_count, 674 param->ss_period, 675 param->ss_spectral_pri, 676 param->ss_fft_size, 677 param->ss_gc_ena, 678 param->ss_restart_ena, 679 (int8_t)param->ss_noise_floor_ref, 680 param->ss_init_delay, 681 param->ss_nb_tone_thr, 682 param->ss_str_bin_thr, 683 param->ss_wb_rpt_mode, 684 param->ss_rssi_rpt_mode, 685 (int8_t)param->ss_rssi_thr, 686 param->ss_pwr_format, 687 param->ss_rpt_mode, 688 param->ss_bin_scale, 689 param->ss_dbm_adj, 690 param->ss_chn_mask, 691 param->ss_frequency, 692 ret); 693 } 694 695 /** 696 * target_if_spectral_info_write() - Write Spectral information to the 697 * firmware, and update cache 698 * @spectral: Pointer to Spectral target_if internal private data 699 * @smode: Spectral scan mode 700 * @specifier: target_if_spectral_info enumeration specifying which 701 * information is involved 702 * @input: void input pointer containing the information to be written 703 * @input_len: size of object pointed to by input pointer 704 * 705 * Write Spectral parameters or the desired state information to 706 * the firmware, and update cache 707 * 708 * Return: 0 on success, negative error code on failure 709 */ 710 static int 711 target_if_spectral_info_write( 712 struct target_if_spectral *spectral, 713 enum spectral_scan_mode smode, 714 enum target_if_spectral_info specifier, 715 void *input, int input_len) 716 { 717 struct target_if_spectral_param_state_info *info; 718 int ret; 719 uint8_t *pval = NULL; 720 struct spectral_config *param = NULL; 721 722 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 723 spectral_err("Invalid Spectral mode %u", smode); 724 return -EINVAL; 725 } 726 info = &spectral->param_info[smode]; 727 728 if (!input) 729 return -EINVAL; 730 731 switch (specifier) { 732 case TARGET_IF_SPECTRAL_INFO_ACTIVE: 733 if (input_len != sizeof(info->osps_cache.osc_spectral_active)) 734 return -EINVAL; 735 736 pval = (uint8_t *)input; 737 738 qdf_spin_lock(&info->osps_lock); 739 ret = target_if_send_vdev_spectral_enable_cmd(spectral, 740 1, *pval, 0, 0); 741 742 target_if_log_write_spectral_active( 743 __func__, 744 *pval, 745 ret); 746 747 if (ret < 0) { 748 spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d", 749 ret); 750 qdf_spin_unlock(&info->osps_lock); 751 return ret; 752 } 753 754 info->osps_cache.osc_spectral_active = *pval; 755 756 /* The cache is now valid */ 757 info->osps_cache.osc_is_valid = 1; 758 759 qdf_spin_unlock(&info->osps_lock); 760 break; 761 762 case TARGET_IF_SPECTRAL_INFO_ENABLED: 763 if (input_len != sizeof(info->osps_cache.osc_spectral_enabled)) 764 return -EINVAL; 765 766 pval = (uint8_t *)input; 767 768 qdf_spin_lock(&info->osps_lock); 769 ret = target_if_send_vdev_spectral_enable_cmd(spectral, 770 0, 0, 1, *pval); 771 772 target_if_log_write_spectral_enabled( 773 __func__, 774 *pval, 775 ret); 776 777 if (ret < 0) { 778 spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d", 779 ret); 780 qdf_spin_unlock(&info->osps_lock); 781 return ret; 782 } 783 784 info->osps_cache.osc_spectral_enabled = *pval; 785 786 /* The cache is now valid */ 787 info->osps_cache.osc_is_valid = 1; 788 789 qdf_spin_unlock(&info->osps_lock); 790 break; 791 792 case TARGET_IF_SPECTRAL_INFO_PARAMS: 793 if (input_len != sizeof(info->osps_cache.osc_params)) 794 return -EINVAL; 795 796 param = (struct spectral_config *)input; 797 798 qdf_spin_lock(&info->osps_lock); 799 ret = target_if_send_vdev_spectral_configure_cmd(spectral, 800 param); 801 802 target_if_log_write_spectral_params( 803 param, 804 __func__, 805 ret); 806 807 if (ret < 0) { 808 spectral_err("target_if_send_vdev_spectral_configure_cmd failed with error=%d", 809 ret); 810 qdf_spin_unlock(&info->osps_lock); 811 return ret; 812 } 813 814 qdf_mem_copy(&info->osps_cache.osc_params, 815 param, sizeof(info->osps_cache.osc_params)); 816 817 /* The cache is now valid */ 818 info->osps_cache.osc_is_valid = 1; 819 820 qdf_spin_unlock(&info->osps_lock); 821 break; 822 823 default: 824 spectral_err("Unknown target_if_spectral_info specifier"); 825 return -EINVAL; 826 } 827 828 return 0; 829 } 830 831 /** 832 * target_if_spectral_get_tsf64() - Function to get the TSF value 833 * @arg: Pointer to handle for Spectral target_if internal private data 834 * 835 * Get the last TSF received in WMI buffer 836 * 837 * Return: TSF value 838 */ 839 static uint64_t 840 target_if_spectral_get_tsf64(void *arg) 841 { 842 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 843 844 return spectral->tsf64; 845 } 846 847 /** 848 * target_if_spectral_get_capability() - Function to get whether a 849 * given Spectral hardware capability is available 850 * @arg: Pointer to handle for Spectral target_if internal private data 851 * @type: Spectral hardware capability type 852 * 853 * Get whether a given Spectral hardware capability is available 854 * 855 * Return: True if the capability is available, false if the capability is not 856 * available 857 */ 858 uint32_t 859 target_if_spectral_get_capability(void *arg, enum spectral_capability_type type) 860 { 861 int status = STATUS_FAIL; 862 863 switch (type) { 864 case SPECTRAL_CAP_PHYDIAG: 865 case SPECTRAL_CAP_RADAR: 866 case SPECTRAL_CAP_SPECTRAL_SCAN: 867 case SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN: 868 status = STATUS_PASS; 869 break; 870 default: 871 status = STATUS_FAIL; 872 } 873 return status; 874 } 875 876 /** 877 * target_if_spectral_set_rxfilter() - Set the RX Filter before Spectral start 878 * @arg: Pointer to handle for Spectral target_if internal private data 879 * @rxfilter: Rx filter to be used 880 * 881 * Note: This is only a placeholder function. It is not currently required since 882 * FW should be taking care of setting the required filters. 883 * 884 * Return: 0 885 */ 886 uint32_t 887 target_if_spectral_set_rxfilter(void *arg, int rxfilter) 888 { 889 /* 890 * Will not be required since enabling of spectral in firmware 891 * will take care of this 892 */ 893 return 0; 894 } 895 896 /** 897 * target_if_spectral_get_rxfilter() - Get the current RX Filter settings 898 * @arg: Pointer to handle for Spectral target_if internal private data 899 * 900 * Note: This is only a placeholder function. It is not currently required since 901 * FW should be taking care of setting the required filters. 902 * 903 * Return: 0 904 */ 905 uint32_t 906 target_if_spectral_get_rxfilter(void *arg) 907 { 908 /* 909 * Will not be required since enabling of spectral in firmware 910 * will take care of this 911 */ 912 return 0; 913 } 914 915 /** 916 * target_if_sops_is_spectral_active() - Get whether Spectral is active 917 * @arg: Pointer to handle for Spectral target_if internal private data 918 * @smode: Spectral scan mode 919 * 920 * Function to check whether Spectral is active 921 * 922 * Return: True if Spectral is active, false if Spectral is not active 923 */ 924 uint32_t 925 target_if_sops_is_spectral_active(void *arg, enum spectral_scan_mode smode) 926 { 927 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 928 uint8_t val = 0; 929 int ret; 930 931 ret = target_if_spectral_info_read( 932 spectral, 933 smode, 934 TARGET_IF_SPECTRAL_INFO_ACTIVE, 935 &val, sizeof(val)); 936 937 if (ret != 0) { 938 /* 939 * Could not determine if Spectral is active. 940 * Return false as a safe value. 941 * XXX: Consider changing the function prototype 942 * to be able to indicate failure to fetch value. 943 */ 944 return 0; 945 } 946 947 return val; 948 } 949 950 /** 951 * target_if_sops_is_spectral_enabled() - Get whether Spectral is enabled 952 * @arg: Pointer to handle for Spectral target_if internal private data 953 * @smode: Spectral scan mode 954 * 955 * Function to check whether Spectral is enabled 956 * 957 * Return: True if Spectral is enabled, false if Spectral is not enabled 958 */ 959 uint32_t 960 target_if_sops_is_spectral_enabled(void *arg, enum spectral_scan_mode smode) 961 { 962 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 963 uint8_t val = 0; 964 int ret; 965 966 ret = target_if_spectral_info_read( 967 spectral, 968 smode, 969 TARGET_IF_SPECTRAL_INFO_ENABLED, 970 &val, sizeof(val)); 971 972 if (ret != 0) { 973 /* 974 * Could not determine if Spectral is enabled. 975 * Return false as a safe value. 976 * XXX: Consider changing the function prototype 977 * to be able to indicate failure to fetch value. 978 */ 979 return 0; 980 } 981 982 return val; 983 } 984 985 /** 986 * target_if_sops_start_spectral_scan() - Start Spectral scan 987 * @arg: Pointer to handle for Spectral target_if internal private data 988 * @smode: Spectral scan mode 989 * @err: Spectral error code 990 * 991 * Function to start spectral scan 992 * 993 * Return: 0 on success else failure 994 */ 995 uint32_t 996 target_if_sops_start_spectral_scan(void *arg, enum spectral_scan_mode smode, 997 enum spectral_cp_error_code *err) 998 { 999 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 1000 uint8_t val = 1; 1001 uint8_t enabled = 0; 1002 int ret; 1003 1004 ret = target_if_spectral_info_read( 1005 spectral, 1006 smode, 1007 TARGET_IF_SPECTRAL_INFO_ENABLED, 1008 &enabled, sizeof(enabled)); 1009 1010 if (ret != 0) { 1011 /* 1012 * Could not determine if Spectral is enabled. Assume we need 1013 * to enable it 1014 */ 1015 enabled = 0; 1016 } 1017 1018 if (!enabled) { 1019 ret = target_if_spectral_info_write( 1020 spectral, 1021 smode, 1022 TARGET_IF_SPECTRAL_INFO_ENABLED, 1023 &val, sizeof(val)); 1024 1025 if (ret != 0) 1026 return ret; 1027 } 1028 1029 ret = target_if_spectral_info_write( 1030 spectral, 1031 smode, 1032 TARGET_IF_SPECTRAL_INFO_ACTIVE, 1033 &val, sizeof(val)); 1034 1035 if (ret != 0) 1036 return ret; 1037 1038 return 0; 1039 } 1040 1041 /** 1042 * target_if_sops_stop_spectral_scan() - Stop Spectral scan 1043 * @arg: Pointer to handle for Spectral target_if internal private data 1044 * @smode: Spectral scan mode 1045 * 1046 * Function to stop spectral scan 1047 * 1048 * Return: 0 on success else failure 1049 */ 1050 uint32_t 1051 target_if_sops_stop_spectral_scan(void *arg, enum spectral_scan_mode smode) 1052 { 1053 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 1054 uint8_t val = 0; 1055 int tempret, ret = 0; 1056 uint8_t enabled = 0; 1057 1058 tempret = target_if_spectral_info_read( 1059 spectral, 1060 smode, 1061 TARGET_IF_SPECTRAL_INFO_ENABLED, 1062 &enabled, sizeof(enabled)); 1063 1064 if (tempret) 1065 /* 1066 * Could not determine if Spectral is enabled. Assume scan is 1067 * not in progress 1068 */ 1069 enabled = 0; 1070 1071 /* if scan is not enabled, no need to send stop to FW */ 1072 if (!enabled) 1073 return -EPERM; 1074 1075 tempret = target_if_spectral_info_write( 1076 spectral, 1077 smode, 1078 TARGET_IF_SPECTRAL_INFO_ACTIVE, 1079 &val, sizeof(val)); 1080 1081 if (tempret != 0) 1082 ret = tempret; 1083 1084 tempret = target_if_spectral_info_write( 1085 spectral, 1086 smode, 1087 TARGET_IF_SPECTRAL_INFO_ENABLED, 1088 &val, sizeof(val)); 1089 1090 if (tempret != 0) 1091 ret = tempret; 1092 1093 return ret; 1094 } 1095 1096 /** 1097 * target_if_spectral_get_extension_channel() - Get the Extension channel 1098 * @arg: Pointer to handle for Spectral target_if internal private data 1099 * 1100 * Function to get the current Extension channel (in MHz) 1101 * 1102 * Return: Current Extension channel (in MHz) on success, 0 on failure or if 1103 * extension channel is not present. 1104 */ 1105 uint32_t 1106 target_if_spectral_get_extension_channel(void *arg) 1107 { 1108 /* 1109 * XXX: Once we expand to use cases where Spectral could be activated 1110 * without a channel being set to VDEV, we need to consider returning a 1111 * negative value in case of failure and having all callers handle this. 1112 */ 1113 1114 struct target_if_spectral *spectral = NULL; 1115 struct wlan_objmgr_vdev *vdev = NULL; 1116 uint16_t sec20chan_freq = 0; 1117 1118 qdf_assert_always(arg); 1119 spectral = (struct target_if_spectral *)arg; 1120 1121 vdev = target_if_spectral_get_vdev(spectral); 1122 if (!vdev) 1123 return 0; 1124 1125 if (target_if_vdev_get_sec20chan_freq_mhz(vdev, &sec20chan_freq) < 0) { 1126 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1127 return 0; 1128 } 1129 1130 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1131 1132 return sec20chan_freq; 1133 } 1134 1135 /** 1136 * target_if_spectral_get_current_channel() - Get the current channel 1137 * @arg: Pointer to handle for Spectral target_if internal private data 1138 * 1139 * Function to get the current channel (in MHz) 1140 * 1141 * Return: Current channel (in MHz) on success, 0 on failure 1142 */ 1143 uint32_t 1144 target_if_spectral_get_current_channel(void *arg) 1145 { 1146 /* 1147 * XXX: Once we expand to use cases where Spectral could be activated 1148 * without a channel being set to VDEV, we need to consider returning a 1149 * negative value in case of failure and having all callers handle this. 1150 */ 1151 1152 struct target_if_spectral *spectral = NULL; 1153 int16_t chan_freq = 0; 1154 struct wlan_objmgr_vdev *vdev = NULL; 1155 1156 qdf_assert_always(arg); 1157 spectral = (struct target_if_spectral *)arg; 1158 1159 vdev = target_if_spectral_get_vdev(spectral); 1160 if (!vdev) 1161 return 0; 1162 1163 chan_freq = target_if_vdev_get_chan_freq(vdev); 1164 if (chan_freq < 0) { 1165 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1166 return 0; 1167 } 1168 1169 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1170 1171 return chan_freq; 1172 } 1173 1174 /** 1175 * target_if_spectral_reset_hw() - Reset the hardware 1176 * @arg: Pointer to handle for Spectral target_if internal private data 1177 * 1178 * This is only a placeholder since it is not currently required in the offload 1179 * case. 1180 * 1181 * Return: 0 1182 */ 1183 uint32_t 1184 target_if_spectral_reset_hw(void *arg) 1185 { 1186 not_yet_implemented(); 1187 return 0; 1188 } 1189 1190 /** 1191 * target_if_spectral_get_chain_noise_floor() - Get the Chain noise floor from 1192 * Noisefloor history buffer 1193 * @arg: Pointer to handle for Spectral target_if internal private data 1194 * @nf_buf: Pointer to buffer into which chain Noise Floor data should be copied 1195 * 1196 * This is only a placeholder since it is not currently required in the offload 1197 * case. 1198 * 1199 * Return: 0 1200 */ 1201 uint32_t 1202 target_if_spectral_get_chain_noise_floor(void *arg, int16_t *nf_buf) 1203 { 1204 not_yet_implemented(); 1205 return 0; 1206 } 1207 1208 /** 1209 * target_if_spectral_get_ext_noisefloor() - Get the extension channel 1210 * noisefloor 1211 * @arg: Pointer to handle for Spectral target_if internal private data 1212 * 1213 * This is only a placeholder since it is not currently required in the offload 1214 * case. 1215 * 1216 * Return: 0 1217 */ 1218 int8_t 1219 target_if_spectral_get_ext_noisefloor(void *arg) 1220 { 1221 not_yet_implemented(); 1222 return 0; 1223 } 1224 1225 /** 1226 * target_if_spectral_get_ctl_noisefloor() - Get the control channel noisefloor 1227 * @arg: Pointer to handle for Spectral target_if internal private data 1228 * 1229 * This is only a placeholder since it is not currently required in the offload 1230 * case. 1231 * 1232 * Return: 0 1233 */ 1234 int8_t 1235 target_if_spectral_get_ctl_noisefloor(void *arg) 1236 { 1237 not_yet_implemented(); 1238 return 0; 1239 } 1240 1241 /** 1242 * target_if_spectral_sops_configure_params() - Configure user supplied Spectral 1243 * parameters 1244 * @arg: Pointer to handle for Spectral target_if internal private data 1245 * @params: Spectral parameters 1246 * @smode: Spectral scan mode 1247 * 1248 * Function to configure spectral parameters 1249 * 1250 * Return: 0 on success else failure 1251 */ 1252 uint32_t 1253 target_if_spectral_sops_configure_params( 1254 void *arg, struct spectral_config *params, 1255 enum spectral_scan_mode smode) 1256 { 1257 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 1258 1259 return target_if_spectral_info_write( 1260 spectral, 1261 smode, 1262 TARGET_IF_SPECTRAL_INFO_PARAMS, 1263 params, sizeof(*params)); 1264 } 1265 1266 /** 1267 * target_if_spectral_sops_get_params() - Get user configured Spectral 1268 * parameters 1269 * @arg: Pointer to handle for Spectral target_if internal private data 1270 * @params: Pointer to buffer into which Spectral parameters should be copied 1271 * @smode: Spectral scan mode 1272 * 1273 * Function to get the configured spectral parameters 1274 * 1275 * Return: 0 on success else failure 1276 */ 1277 uint32_t 1278 target_if_spectral_sops_get_params(void *arg, struct spectral_config *params, 1279 enum spectral_scan_mode smode) 1280 { 1281 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 1282 1283 return target_if_spectral_info_read( 1284 spectral, 1285 smode, 1286 TARGET_IF_SPECTRAL_INFO_PARAMS, 1287 params, sizeof(*params)); 1288 } 1289 1290 /** 1291 * target_if_spectral_get_ent_mask() - Get enterprise mask 1292 * @arg: Pointer to handle for Spectral target_if internal private data 1293 * 1294 * This is only a placeholder since it is not currently required in the offload 1295 * case. 1296 * 1297 * Return: 0 1298 */ 1299 static uint32_t 1300 target_if_spectral_get_ent_mask(void *arg) 1301 { 1302 not_yet_implemented(); 1303 return 0; 1304 } 1305 1306 /** 1307 * target_if_spectral_get_macaddr() - Get radio MAC address 1308 * @arg: Pointer to handle for Spectral target_if internal private data 1309 * @addr: Pointer to buffer into which MAC address should be copied 1310 * 1311 * Function to get the MAC address of the pdev 1312 * 1313 * Return: 0 on success, -1 on failure 1314 */ 1315 static uint32_t 1316 target_if_spectral_get_macaddr(void *arg, char *addr) 1317 { 1318 uint8_t *myaddr = NULL; 1319 struct target_if_spectral *spectral = (struct target_if_spectral *)arg; 1320 struct wlan_objmgr_pdev *pdev = NULL; 1321 1322 pdev = spectral->pdev_obj; 1323 1324 wlan_pdev_obj_lock(pdev); 1325 myaddr = wlan_pdev_get_hw_macaddr(pdev); 1326 wlan_pdev_obj_unlock(pdev); 1327 qdf_mem_copy(addr, myaddr, QDF_MAC_ADDR_SIZE); 1328 1329 return 0; 1330 } 1331 1332 /** 1333 * target_if_init_spectral_param_properties() - Initialize Spectral parameter 1334 * properties 1335 * @spectral: Pointer to Spectral target_if internal private data 1336 * 1337 * Initialize Spectral parameter properties 1338 * 1339 * Return: QDF_STATUS 1340 */ 1341 static QDF_STATUS 1342 target_if_init_spectral_param_properties(struct target_if_spectral *spectral) 1343 { 1344 enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL; 1345 int param; 1346 1347 /* Initialize default values for properties. 1348 * Default values are supported for all the parameters for all modes 1349 * and allows different values for each mode for all the parameters . 1350 */ 1351 for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) { 1352 for (param = 0; param < SPECTRAL_PARAM_MAX; param++) { 1353 spectral->properties[smode][param].supported = true; 1354 spectral->properties[smode][param].common_all_modes = 1355 false; 1356 } 1357 } 1358 1359 return QDF_STATUS_SUCCESS; 1360 } 1361 1362 /** 1363 * target_if_init_spectral_capability() - Initialize Spectral capability 1364 * @spectral: Pointer to Spectral target_if internal private data 1365 * 1366 * This is a workaround. 1367 * 1368 * Return: QDF_STATUS 1369 */ 1370 QDF_STATUS 1371 target_if_init_spectral_capability(struct target_if_spectral *spectral) 1372 { 1373 struct wlan_objmgr_psoc *psoc; 1374 struct wlan_objmgr_pdev *pdev; 1375 struct wlan_psoc_host_spectral_scaling_params *scaling_params; 1376 uint8_t num_bin_scaling_params, param_idx, pdev_id; 1377 struct target_psoc_info *tgt_psoc_info; 1378 struct wlan_psoc_host_service_ext_param *ext_svc_param; 1379 struct spectral_caps *pcap = &spectral->capability; 1380 1381 pdev = spectral->pdev_obj; 1382 psoc = wlan_pdev_get_psoc(pdev); 1383 if (!psoc) { 1384 spectral_err("psoc is null"); 1385 return QDF_STATUS_E_FAILURE; 1386 } 1387 1388 tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); 1389 if (!tgt_psoc_info) { 1390 spectral_err("target_psoc_info is null"); 1391 return QDF_STATUS_E_FAILURE; 1392 } 1393 1394 ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info); 1395 num_bin_scaling_params = ext_svc_param->num_bin_scaling_params; 1396 scaling_params = target_psoc_get_spectral_scaling_params(tgt_psoc_info); 1397 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 1398 1399 /* XXX : Workaround: Set Spectral capability */ 1400 pcap = &spectral->capability; 1401 pcap->phydiag_cap = 1; 1402 pcap->radar_cap = 1; 1403 pcap->spectral_cap = 1; 1404 pcap->advncd_spectral_cap = 1; 1405 pcap->hw_gen = spectral->spectral_gen; 1406 1407 for (param_idx = 0; param_idx < num_bin_scaling_params; param_idx++) { 1408 if (scaling_params[param_idx].pdev_id == pdev_id) { 1409 pcap->is_scaling_params_populated = true; 1410 pcap->formula_id = scaling_params[param_idx].formula_id; 1411 pcap->low_level_offset = 1412 scaling_params[param_idx].low_level_offset; 1413 pcap->high_level_offset = 1414 scaling_params[param_idx].high_level_offset; 1415 pcap->rssi_thr = scaling_params[param_idx].rssi_thr; 1416 pcap->default_agc_max_gain = 1417 scaling_params[param_idx].default_agc_max_gain; 1418 break; 1419 } 1420 } 1421 1422 return QDF_STATUS_SUCCESS; 1423 } 1424 1425 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION 1426 /** 1427 * target_if_init_spectral_simulation_ops() - Initialize spectral target_if 1428 * internal operations with functions related to spectral simulation 1429 * @p_sops: spectral low level ops table 1430 * 1431 * Initialize spectral target_if internal operations with functions 1432 * related to spectral simulation 1433 * 1434 * Return: None 1435 */ 1436 static void 1437 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops) 1438 { 1439 /* 1440 * Spectral simulation is currently intended for platform transitions 1441 * where underlying HW support may not be available for some time. 1442 * Hence, we do not currently provide a runtime switch to turn the 1443 * simulation on or off. 1444 * In case of future requirements where runtime switches are required, 1445 * this can be added. But it is suggested to use application layer 1446 * simulation as far as possible in such cases, since the main 1447 * use of record and replay of samples would concern higher 1448 * level sample processing rather than lower level delivery. 1449 */ 1450 p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled; 1451 p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active; 1452 p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan; 1453 p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan; 1454 p_sops->configure_spectral = 1455 target_if_spectral_sops_sim_configure_params; 1456 p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params; 1457 } 1458 1459 #else 1460 /** 1461 * target_if_init_spectral_simulation_ops() - Initialize spectral target_if 1462 * internal operations 1463 * @p_sops: spectral low level ops table 1464 * 1465 * Return: None 1466 */ 1467 static void 1468 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops) 1469 { 1470 p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled; 1471 p_sops->is_spectral_active = target_if_sops_is_spectral_active; 1472 p_sops->start_spectral_scan = target_if_sops_start_spectral_scan; 1473 p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan; 1474 p_sops->configure_spectral = target_if_spectral_sops_configure_params; 1475 p_sops->get_spectral_config = target_if_spectral_sops_get_params; 1476 } 1477 #endif 1478 1479 /** 1480 * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal 1481 * operations common to all Spectral chipset generations 1482 * 1483 * Initializes target_if_spectral_ops common to all chipset generations 1484 * 1485 * Return: None 1486 */ 1487 static void 1488 target_if_init_spectral_ops_common(void) 1489 { 1490 struct target_if_spectral_ops *p_sops = &spectral_ops; 1491 1492 p_sops->get_tsf64 = target_if_spectral_get_tsf64; 1493 p_sops->get_capability = target_if_spectral_get_capability; 1494 p_sops->set_rxfilter = target_if_spectral_set_rxfilter; 1495 p_sops->get_rxfilter = target_if_spectral_get_rxfilter; 1496 1497 target_if_init_spectral_simulation_ops(p_sops); 1498 1499 p_sops->get_extension_channel = 1500 target_if_spectral_get_extension_channel; 1501 p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor; 1502 p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor; 1503 p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask; 1504 p_sops->get_mac_address = target_if_spectral_get_macaddr; 1505 p_sops->get_current_channel = target_if_spectral_get_current_channel; 1506 p_sops->reset_hw = target_if_spectral_reset_hw; 1507 p_sops->get_chain_noise_floor = 1508 target_if_spectral_get_chain_noise_floor; 1509 } 1510 1511 /** 1512 * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal 1513 * operations specific to Spectral chipset generation 2. 1514 * 1515 * Initializes target_if_spectral_ops specific to Spectral chipset generation 2. 1516 * 1517 * Return: None 1518 */ 1519 static void 1520 target_if_init_spectral_ops_gen2(void) 1521 { 1522 struct target_if_spectral_ops *p_sops = &spectral_ops; 1523 1524 p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2; 1525 } 1526 1527 /** 1528 * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal 1529 * operations specific to Spectral chipset generation 3. 1530 * 1531 * Initializes target_if_spectral_ops specific to Spectral chipset generation 3. 1532 * 1533 * Return: None 1534 */ 1535 static void 1536 target_if_init_spectral_ops_gen3(void) 1537 { 1538 struct target_if_spectral_ops *p_sops = &spectral_ops; 1539 1540 p_sops->process_spectral_report = 1541 target_if_spectral_process_report_gen3; 1542 return; 1543 } 1544 1545 /** 1546 * target_if_init_spectral_ops() - Initialize target_if internal Spectral 1547 * operations. 1548 * @spectral: Pointer to Spectral target_if internal private data 1549 * 1550 * Initializes all function pointers in target_if_spectral_ops for 1551 * all generations 1552 * 1553 * Return: None 1554 */ 1555 static void 1556 target_if_init_spectral_ops(struct target_if_spectral *spectral) 1557 { 1558 target_if_init_spectral_ops_common(); 1559 if (spectral->spectral_gen == SPECTRAL_GEN2) 1560 target_if_init_spectral_ops_gen2(); 1561 else if (spectral->spectral_gen == SPECTRAL_GEN3) 1562 target_if_init_spectral_ops_gen3(); 1563 else 1564 spectral_err("Invalid Spectral generation"); 1565 } 1566 1567 /* 1568 * Dummy Functions: 1569 * These functions are initially registered to avoid any crashes due to 1570 * invocation of spectral functions before they are registered. 1571 */ 1572 1573 static uint64_t 1574 null_get_tsf64(void *arg) 1575 { 1576 spectral_ops_not_registered("get_tsf64"); 1577 return 0; 1578 } 1579 1580 static uint32_t 1581 null_get_capability(void *arg, enum spectral_capability_type type) 1582 { 1583 /* 1584 * TODO : We should have conditional compilation to get the capability 1585 * : We have not yet attahced ATH layer here, so there is no 1586 * : way to check the HAL capbalities 1587 */ 1588 spectral_ops_not_registered("get_capability"); 1589 1590 /* TODO : For the time being, we are returning TRUE */ 1591 return true; 1592 } 1593 1594 static uint32_t 1595 null_set_rxfilter(void *arg, int rxfilter) 1596 { 1597 spectral_ops_not_registered("set_rxfilter"); 1598 return 1; 1599 } 1600 1601 static uint32_t 1602 null_get_rxfilter(void *arg) 1603 { 1604 spectral_ops_not_registered("get_rxfilter"); 1605 return 0; 1606 } 1607 1608 static uint32_t 1609 null_is_spectral_active(void *arg, enum spectral_scan_mode smode) 1610 { 1611 spectral_ops_not_registered("is_spectral_active"); 1612 return 1; 1613 } 1614 1615 static uint32_t 1616 null_is_spectral_enabled(void *arg, enum spectral_scan_mode smode) 1617 { 1618 spectral_ops_not_registered("is_spectral_enabled"); 1619 return 1; 1620 } 1621 1622 static uint32_t 1623 null_start_spectral_scan(void *arg, enum spectral_scan_mode smode, 1624 enum spectral_cp_error_code *err) 1625 { 1626 spectral_ops_not_registered("start_spectral_scan"); 1627 return 1; 1628 } 1629 1630 static uint32_t 1631 null_stop_spectral_scan(void *arg, enum spectral_scan_mode smode) 1632 { 1633 spectral_ops_not_registered("stop_spectral_scan"); 1634 return 1; 1635 } 1636 1637 static uint32_t 1638 null_get_extension_channel(void *arg) 1639 { 1640 spectral_ops_not_registered("get_extension_channel"); 1641 return 1; 1642 } 1643 1644 static int8_t 1645 null_get_ctl_noisefloor(void *arg) 1646 { 1647 spectral_ops_not_registered("get_ctl_noisefloor"); 1648 return 1; 1649 } 1650 1651 static int8_t 1652 null_get_ext_noisefloor(void *arg) 1653 { 1654 spectral_ops_not_registered("get_ext_noisefloor"); 1655 return 0; 1656 } 1657 1658 static uint32_t 1659 null_configure_spectral(void *arg, struct spectral_config *params, 1660 enum spectral_scan_mode smode) 1661 { 1662 spectral_ops_not_registered("configure_spectral"); 1663 return 0; 1664 } 1665 1666 static uint32_t 1667 null_get_spectral_config(void *arg, struct spectral_config *params, 1668 enum spectral_scan_mode smode) 1669 { 1670 spectral_ops_not_registered("get_spectral_config"); 1671 return 0; 1672 } 1673 1674 static uint32_t 1675 null_get_ent_spectral_mask(void *arg) 1676 { 1677 spectral_ops_not_registered("get_ent_spectral_mask"); 1678 return 0; 1679 } 1680 1681 static uint32_t 1682 null_get_mac_address(void *arg, char *addr) 1683 { 1684 spectral_ops_not_registered("get_mac_address"); 1685 return 0; 1686 } 1687 1688 static uint32_t 1689 null_get_current_channel(void *arg) 1690 { 1691 spectral_ops_not_registered("get_current_channel"); 1692 return 0; 1693 } 1694 1695 static uint32_t 1696 null_reset_hw(void *arg) 1697 { 1698 spectral_ops_not_registered("get_current_channel"); 1699 return 0; 1700 } 1701 1702 static uint32_t 1703 null_get_chain_noise_floor(void *arg, int16_t *nf_buf) 1704 { 1705 spectral_ops_not_registered("get_chain_noise_floor"); 1706 return 0; 1707 } 1708 1709 static int 1710 null_spectral_process_phyerr(struct target_if_spectral *spectral, 1711 uint8_t *data, 1712 uint32_t datalen, 1713 struct target_if_spectral_rfqual_info *p_rfqual, 1714 struct target_if_spectral_chan_info *p_chaninfo, 1715 uint64_t tsf64, 1716 struct target_if_spectral_acs_stats *acs_stats) 1717 { 1718 spectral_ops_not_registered("spectral_process_phyerr"); 1719 return 0; 1720 } 1721 1722 static int 1723 null_process_spectral_report(struct wlan_objmgr_pdev *pdev, 1724 void *payload) 1725 { 1726 spectral_ops_not_registered("process_spectral_report"); 1727 return 0; 1728 } 1729 /** 1730 * target_if_spectral_init_dummy_function_table() - 1731 * Initialize target_if internal 1732 * Spectral operations to dummy functions 1733 * @ps: Pointer to Spectral target_if internal private data 1734 * 1735 * Initialize all the function pointers in target_if_spectral_ops with 1736 * dummy functions. 1737 * 1738 * Return: None 1739 */ 1740 static void 1741 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps) 1742 { 1743 struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps); 1744 1745 p_sops->get_tsf64 = null_get_tsf64; 1746 p_sops->get_capability = null_get_capability; 1747 p_sops->set_rxfilter = null_set_rxfilter; 1748 p_sops->get_rxfilter = null_get_rxfilter; 1749 p_sops->is_spectral_enabled = null_is_spectral_enabled; 1750 p_sops->is_spectral_active = null_is_spectral_active; 1751 p_sops->start_spectral_scan = null_start_spectral_scan; 1752 p_sops->stop_spectral_scan = null_stop_spectral_scan; 1753 p_sops->get_extension_channel = null_get_extension_channel; 1754 p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor; 1755 p_sops->get_ext_noisefloor = null_get_ext_noisefloor; 1756 p_sops->configure_spectral = null_configure_spectral; 1757 p_sops->get_spectral_config = null_get_spectral_config; 1758 p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask; 1759 p_sops->get_mac_address = null_get_mac_address; 1760 p_sops->get_current_channel = null_get_current_channel; 1761 p_sops->reset_hw = null_reset_hw; 1762 p_sops->get_chain_noise_floor = null_get_chain_noise_floor; 1763 p_sops->spectral_process_phyerr = null_spectral_process_phyerr; 1764 p_sops->process_spectral_report = null_process_spectral_report; 1765 } 1766 1767 /** 1768 * target_if_spectral_register_funcs() - Initialize target_if internal Spectral 1769 * operations 1770 * @spectral: Pointer to Spectral target_if internal private data 1771 * @p: Pointer to Spectral function table 1772 * 1773 * Return: None 1774 */ 1775 static void 1776 target_if_spectral_register_funcs(struct target_if_spectral *spectral, 1777 struct target_if_spectral_ops *p) 1778 { 1779 struct target_if_spectral_ops *p_sops = 1780 GET_TARGET_IF_SPECTRAL_OPS(spectral); 1781 1782 p_sops->get_tsf64 = p->get_tsf64; 1783 p_sops->get_capability = p->get_capability; 1784 p_sops->set_rxfilter = p->set_rxfilter; 1785 p_sops->get_rxfilter = p->get_rxfilter; 1786 p_sops->is_spectral_enabled = p->is_spectral_enabled; 1787 p_sops->is_spectral_active = p->is_spectral_active; 1788 p_sops->start_spectral_scan = p->start_spectral_scan; 1789 p_sops->stop_spectral_scan = p->stop_spectral_scan; 1790 p_sops->get_extension_channel = p->get_extension_channel; 1791 p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor; 1792 p_sops->get_ext_noisefloor = p->get_ext_noisefloor; 1793 p_sops->configure_spectral = p->configure_spectral; 1794 p_sops->get_spectral_config = p->get_spectral_config; 1795 p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask; 1796 p_sops->get_mac_address = p->get_mac_address; 1797 p_sops->get_current_channel = p->get_current_channel; 1798 p_sops->reset_hw = p->reset_hw; 1799 p_sops->get_chain_noise_floor = p->get_chain_noise_floor; 1800 p_sops->spectral_process_phyerr = p->spectral_process_phyerr; 1801 p_sops->process_spectral_report = p->process_spectral_report; 1802 } 1803 1804 /** 1805 * target_if_spectral_clear_stats() - Clear Spectral stats 1806 * @spectral: Pointer to Spectral target_if internal private data 1807 * 1808 * Function to clear spectral stats 1809 * 1810 * Return: None 1811 */ 1812 static void 1813 target_if_spectral_clear_stats(struct target_if_spectral *spectral) 1814 { 1815 struct target_if_spectral_ops *p_sops = 1816 GET_TARGET_IF_SPECTRAL_OPS(spectral); 1817 1818 qdf_mem_zero(&spectral->spectral_stats, 1819 sizeof(struct target_if_spectral_stats)); 1820 spectral->spectral_stats.last_reset_tstamp = 1821 p_sops->get_tsf64(spectral); 1822 } 1823 1824 /** 1825 * target_if_spectral_check_hw_capability() - Check whether HW supports spectral 1826 * @spectral: Pointer to Spectral target_if internal private data 1827 * 1828 * Function to check whether hardware supports spectral 1829 * 1830 * Return: True if HW supports Spectral, false if HW does not support Spectral 1831 */ 1832 static int 1833 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral) 1834 { 1835 struct target_if_spectral_ops *p_sops = NULL; 1836 struct spectral_caps *pcap = NULL; 1837 int is_spectral_supported = true; 1838 1839 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 1840 pcap = &spectral->capability; 1841 1842 if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) { 1843 is_spectral_supported = false; 1844 spectral_info("SPECTRAL : No PHYDIAG support"); 1845 return is_spectral_supported; 1846 } 1847 pcap->phydiag_cap = 1; 1848 1849 if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) { 1850 is_spectral_supported = false; 1851 spectral_info("SPECTRAL : No RADAR support"); 1852 return is_spectral_supported; 1853 } 1854 pcap->radar_cap = 1; 1855 1856 if (p_sops->get_capability(spectral, 1857 SPECTRAL_CAP_SPECTRAL_SCAN) == false) { 1858 is_spectral_supported = false; 1859 spectral_info("SPECTRAL : No SPECTRAL SUPPORT"); 1860 return is_spectral_supported; 1861 } 1862 pcap->spectral_cap = 1; 1863 1864 if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN) 1865 == false) { 1866 spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT"); 1867 } else { 1868 pcap->advncd_spectral_cap = 1; 1869 } 1870 1871 return is_spectral_supported; 1872 } 1873 1874 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION 1875 /** 1876 * target_if_spectral_detach_simulation() - De-initialize Spectral 1877 * Simulation functionality 1878 * @spectral: Pointer to Spectral target_if internal private data 1879 * 1880 * Function to de-initialize Spectral Simulation functionality 1881 * 1882 * Return: None 1883 */ 1884 static void 1885 target_if_spectral_detach_simulation(struct target_if_spectral *spectral) 1886 { 1887 target_if_spectral_sim_detach(spectral); 1888 } 1889 1890 #else 1891 static void 1892 target_if_spectral_detach_simulation(struct target_if_spectral *spectral) 1893 { 1894 } 1895 #endif 1896 1897 /** 1898 * target_if_spectral_detach() - De-initialize target_if Spectral 1899 * @pdev: Pointer to pdev object 1900 * 1901 * Function to detach target_if spectral 1902 * 1903 * Return: None 1904 */ 1905 static void 1906 target_if_spectral_detach(struct target_if_spectral *spectral) 1907 { 1908 enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL; 1909 spectral_info("spectral detach"); 1910 1911 if (spectral) { 1912 for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) 1913 qdf_spinlock_destroy 1914 (&spectral->param_info[smode].osps_lock); 1915 1916 target_if_spectral_detach_simulation(spectral); 1917 1918 qdf_spinlock_destroy(&spectral->spectral_lock); 1919 qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock); 1920 1921 qdf_mem_free(spectral); 1922 spectral = NULL; 1923 } 1924 } 1925 1926 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION 1927 /** 1928 * target_if_spectral_attach_simulation() - Initialize Spectral Simulation 1929 * functionality 1930 * @spectral: Pointer to Spectral target_if internal private data 1931 * 1932 * Function to initialize spectral simulation functionality 1933 * 1934 * Return: 0 on success, negative error code on failure 1935 */ 1936 static int 1937 target_if_spectral_attach_simulation(struct target_if_spectral *spectral) 1938 { 1939 if (target_if_spectral_sim_attach(spectral)) { 1940 qdf_mem_free(spectral); 1941 return -EPERM; 1942 } 1943 return 0; 1944 } 1945 1946 #else 1947 static int 1948 target_if_spectral_attach_simulation(struct target_if_spectral *spectral) 1949 { 1950 return 0; 1951 } 1952 #endif 1953 1954 /** 1955 * target_if_pdev_spectral_init() - Initialize target_if Spectral 1956 * functionality for the given pdev 1957 * @pdev: Pointer to pdev object 1958 * 1959 * Function to initialize pointer to spectral target_if internal private data 1960 * 1961 * Return: On success, pointer to Spectral target_if internal private data, on 1962 * failure, NULL 1963 */ 1964 void * 1965 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev) 1966 { 1967 struct target_if_spectral_ops *p_sops = NULL; 1968 struct target_if_spectral *spectral = NULL; 1969 uint32_t target_type; 1970 uint32_t target_revision; 1971 struct wlan_objmgr_psoc *psoc; 1972 struct wlan_lmac_if_target_tx_ops *tx_ops; 1973 enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL; 1974 1975 if (!pdev) { 1976 spectral_err("SPECTRAL: pdev is NULL!"); 1977 return NULL; 1978 } 1979 spectral = (struct target_if_spectral *)qdf_mem_malloc( 1980 sizeof(struct target_if_spectral)); 1981 if (!spectral) 1982 return spectral; 1983 1984 qdf_mem_zero(spectral, sizeof(struct target_if_spectral)); 1985 /* Store pdev in Spectral */ 1986 spectral->pdev_obj = pdev; 1987 1988 psoc = wlan_pdev_get_psoc(pdev); 1989 1990 tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops; 1991 1992 if (tx_ops->tgt_get_tgt_type) { 1993 target_type = tx_ops->tgt_get_tgt_type(psoc); 1994 } else { 1995 qdf_mem_free(spectral); 1996 return NULL; 1997 } 1998 1999 if (tx_ops->tgt_get_tgt_revision) { 2000 target_revision = tx_ops->tgt_get_tgt_revision(psoc); 2001 } else { 2002 qdf_mem_free(spectral); 2003 return NULL; 2004 } 2005 2006 /* init the function ptr table */ 2007 target_if_spectral_init_dummy_function_table(spectral); 2008 2009 /* get spectral function table */ 2010 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 2011 /* TODO : Should this be called here of after ath_attach ? */ 2012 if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG)) 2013 spectral_info("HAL_CAP_PHYDIAG : Capable"); 2014 2015 /* TODO: Need to fix the capablity check for RADAR */ 2016 if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR)) 2017 spectral_info("HAL_CAP_RADAR : Capable"); 2018 2019 /* TODO : Need to fix the capablity check for SPECTRAL */ 2020 /* TODO : Should this be called here of after ath_attach ? */ 2021 if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN)) 2022 spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable"); 2023 2024 qdf_spinlock_create(&spectral->spectral_lock); 2025 qdf_spinlock_create(&spectral->noise_pwr_reports_lock); 2026 target_if_spectral_clear_stats(spectral); 2027 2028 if (target_type == TARGET_TYPE_QCA8074V2) 2029 spectral->fftbin_size_war = 2030 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE; 2031 else if (target_type == TARGET_TYPE_QCA8074 || 2032 target_type == TARGET_TYPE_QCA6018 || 2033 target_type == TARGET_TYPE_QCA6390) 2034 spectral->fftbin_size_war = 2035 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE; 2036 else 2037 spectral->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR; 2038 2039 if (target_type == TARGET_TYPE_QCA8074 || 2040 target_type == TARGET_TYPE_QCA8074V2 || 2041 target_type == TARGET_TYPE_QCA6018) { 2042 spectral->inband_fftbin_size_adj = 1; 2043 spectral->null_fftbin_adj = 1; 2044 } else { 2045 spectral->inband_fftbin_size_adj = 0; 2046 spectral->null_fftbin_adj = 0; 2047 } 2048 2049 if ((target_type == TARGET_TYPE_QCA8074) || 2050 (target_type == TARGET_TYPE_QCA8074V2) || 2051 (target_type == TARGET_TYPE_QCA6018) || 2052 (target_type == TARGET_TYPE_QCN9000) || 2053 (target_type == TARGET_TYPE_QCA6290) || 2054 (target_type == TARGET_TYPE_QCA6390)) { 2055 spectral->spectral_gen = SPECTRAL_GEN3; 2056 spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3; 2057 spectral->tag_sscan_summary_exp = 2058 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3; 2059 spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3; 2060 spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3; 2061 spectral->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN3; 2062 spectral->fft_size_max = SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3; 2063 } else { 2064 spectral->spectral_gen = SPECTRAL_GEN2; 2065 spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2; 2066 spectral->tag_sscan_summary_exp = 2067 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2; 2068 spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2; 2069 spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2); 2070 spectral->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN2; 2071 spectral->fft_size_max = SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2; 2072 } 2073 2074 target_if_init_spectral_param_properties(spectral); 2075 /* Init spectral capability */ 2076 if (target_if_init_spectral_capability(spectral) != 2077 QDF_STATUS_SUCCESS) { 2078 qdf_mem_free(spectral); 2079 return NULL; 2080 } 2081 if (target_if_spectral_attach_simulation(spectral) < 0) 2082 return NULL; 2083 2084 target_if_init_spectral_ops(spectral); 2085 2086 /* Spectral mode specific init */ 2087 for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) { 2088 spectral->last_fft_timestamp[smode] = 0; 2089 spectral->timestamp_war_offset[smode] = 0; 2090 spectral->params_valid[smode] = false; 2091 qdf_spinlock_create(&spectral->param_info[smode].osps_lock); 2092 spectral->param_info[smode].osps_cache.osc_is_valid = 0; 2093 } 2094 2095 target_if_spectral_register_funcs(spectral, &spectral_ops); 2096 2097 if (target_if_spectral_check_hw_capability(spectral) == false) { 2098 target_if_spectral_detach(spectral); 2099 spectral = NULL; 2100 } else { 2101 /* 2102 * TODO: Once the driver architecture transitions to chipset 2103 * versioning based checks, reflect this here. 2104 */ 2105 spectral->is_160_format = false; 2106 spectral->is_lb_edge_extrabins_format = false; 2107 spectral->is_rb_edge_extrabins_format = false; 2108 2109 if (target_type == TARGET_TYPE_QCA9984 || 2110 target_type == TARGET_TYPE_QCA9888) { 2111 spectral->is_160_format = true; 2112 spectral->is_lb_edge_extrabins_format = true; 2113 spectral->is_rb_edge_extrabins_format = true; 2114 } else if ((target_type == TARGET_TYPE_AR900B) && 2115 (target_revision == AR900B_REV_2)) { 2116 spectral->is_rb_edge_extrabins_format = true; 2117 } 2118 2119 if (target_type == TARGET_TYPE_QCA9984 || 2120 target_type == TARGET_TYPE_QCA9888) 2121 spectral->is_sec80_rssi_war_required = true; 2122 2123 spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST; 2124 2125 if (spectral->spectral_gen == SPECTRAL_GEN3) 2126 init_160mhz_delivery_state_machine(spectral); 2127 } 2128 2129 return spectral; 2130 } 2131 2132 /** 2133 * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral 2134 * functionality for the given pdev 2135 * @pdev: Pointer to pdev object 2136 * 2137 * Function to de-initialize pointer to spectral target_if internal private data 2138 * 2139 * Return: None 2140 */ 2141 void 2142 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev) 2143 { 2144 struct target_if_spectral *spectral = NULL; 2145 2146 spectral = get_target_if_spectral_handle_from_pdev(pdev); 2147 if (!spectral) { 2148 spectral_err("SPECTRAL : Module doesn't exist"); 2149 return; 2150 } 2151 target_if_spectral_detach(spectral); 2152 2153 return; 2154 } 2155 2156 /* target_if_spectral_find_agile_width() - Given a channel width enum, find the 2157 * corresponding translation for Agile channel width. 2158 * Translation schema of different operating modes: 2159 * 20 -> 20, 40 -> 40, (80 & 160 & 80_80) -> 80. 2160 * @chwidth: Channel width enum. 2161 * 2162 * Return: The translated channel width enum. 2163 */ 2164 static enum phy_ch_width 2165 target_if_spectral_find_agile_width(enum phy_ch_width chwidth) 2166 { 2167 switch (chwidth) { 2168 case CH_WIDTH_20MHZ: 2169 return CH_WIDTH_20MHZ; 2170 case CH_WIDTH_40MHZ: 2171 return CH_WIDTH_40MHZ; 2172 case CH_WIDTH_80MHZ: 2173 case CH_WIDTH_80P80MHZ: 2174 case CH_WIDTH_160MHZ: 2175 return CH_WIDTH_80MHZ; 2176 default: 2177 spectral_err("Invalid chwidth enum %d", chwidth); 2178 return CH_WIDTH_INVALID; 2179 } 2180 } 2181 2182 /** 2183 * target_if_calculate_center_freq() - Helper routine to 2184 * check whether given frequency is center frequency of a 2185 * WLAN channel 2186 * 2187 * @spectral: Pointer to Spectral object 2188 * @chan_freq: Center frequency of a WLAN channel 2189 * @is_valid: Indicates whether given frequency is valid 2190 * 2191 * Return: QDF_STATUS 2192 */ 2193 static QDF_STATUS 2194 target_if_is_center_freq_of_any_chan(struct wlan_objmgr_pdev *pdev, 2195 uint32_t chan_freq, 2196 bool *is_valid) 2197 { 2198 struct regulatory_channel *cur_chan_list; 2199 int i; 2200 2201 if (!pdev) { 2202 spectral_err("pdev object is null"); 2203 return QDF_STATUS_E_FAILURE; 2204 } 2205 2206 if (!is_valid) { 2207 spectral_err("is valid argument is null"); 2208 return QDF_STATUS_E_FAILURE; 2209 } 2210 2211 cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list)); 2212 if (!cur_chan_list) 2213 return QDF_STATUS_E_FAILURE; 2214 2215 if (wlan_reg_get_current_chan_list( 2216 pdev, cur_chan_list) != QDF_STATUS_SUCCESS) { 2217 spectral_err("Failed to get cur_chan list"); 2218 qdf_mem_free(cur_chan_list); 2219 return QDF_STATUS_E_FAILURE; 2220 } 2221 2222 *is_valid = false; 2223 for (i = 0; i < NUM_CHANNELS; i++) { 2224 uint32_t flags; 2225 uint32_t center_freq; 2226 2227 flags = cur_chan_list[i].chan_flags; 2228 center_freq = cur_chan_list[i].center_freq; 2229 2230 if (!(flags & REGULATORY_CHAN_DISABLED) && 2231 (center_freq == chan_freq)) { 2232 *is_valid = true; 2233 break; 2234 } 2235 } 2236 2237 qdf_mem_free(cur_chan_list); 2238 2239 return QDF_STATUS_SUCCESS; 2240 } 2241 2242 /** 2243 * target_if_calculate_center_freq() - Helper routine to 2244 * find the center frequency of the agile span from a 2245 * WLAN channel center frequency 2246 * 2247 * @spectral: Pointer to Spectral object 2248 * @chan_freq: Center frequency of a WLAN channel 2249 * @center_freq: Pointer to center frequency 2250 * 2251 * Return: QDF_STATUS 2252 */ 2253 static QDF_STATUS 2254 target_if_calculate_center_freq(struct target_if_spectral *spectral, 2255 uint16_t chan_freq, 2256 uint16_t *center_freq) 2257 { 2258 struct wlan_objmgr_vdev *vdev; 2259 enum phy_ch_width ch_width; 2260 enum phy_ch_width agile_ch_width; 2261 uint16_t chan_num; 2262 2263 if (!spectral) { 2264 spectral_err("spectral target if object is null"); 2265 return QDF_STATUS_E_FAILURE; 2266 } 2267 2268 if (!center_freq) { 2269 spectral_err("center_freq argument is null"); 2270 return QDF_STATUS_E_FAILURE; 2271 } 2272 2273 chan_num = wlan_reg_freq_to_chan(spectral->pdev_obj, chan_freq); 2274 2275 vdev = target_if_spectral_get_vdev(spectral); 2276 if (!vdev) { 2277 spectral_err("vdev is NULL"); 2278 return QDF_STATUS_E_FAILURE; 2279 } 2280 ch_width = target_if_vdev_get_ch_width(vdev); 2281 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 2282 agile_ch_width = target_if_spectral_find_agile_width(ch_width); 2283 2284 if (agile_ch_width == CH_WIDTH_20MHZ) { 2285 *center_freq = chan_freq; 2286 } else { 2287 uint16_t start_freq; 2288 uint16_t end_freq; 2289 const struct bonded_channel *bonded_chan_ptr = NULL; 2290 2291 wlan_reg_get_5g_bonded_channel_and_state 2292 (spectral->pdev_obj, chan_num, agile_ch_width, 2293 &bonded_chan_ptr); 2294 if (!bonded_chan_ptr) { 2295 spectral_err("Bonded channel is not found"); 2296 return QDF_STATUS_E_FAILURE; 2297 } 2298 start_freq = wlan_reg_chan_to_freq(spectral->pdev_obj, 2299 bonded_chan_ptr->start_ch); 2300 end_freq = wlan_reg_chan_to_freq(spectral->pdev_obj, 2301 bonded_chan_ptr->end_ch); 2302 *center_freq = (start_freq + end_freq) >> 1; 2303 } 2304 2305 return QDF_STATUS_SUCCESS; 2306 } 2307 2308 /** 2309 * target_if_validate_center_freq() - Helper routine to 2310 * validate user provided agile center frequency 2311 * 2312 * @spectral: Pointer to Spectral object 2313 * @center_freq: User provided agile span center frequency 2314 * @is_valid: Indicates whether agile span center frequency is valid 2315 * 2316 * Return: QDF_STATUS 2317 */ 2318 static QDF_STATUS 2319 target_if_validate_center_freq(struct target_if_spectral *spectral, 2320 uint16_t center_freq, 2321 bool *is_valid) 2322 { 2323 struct wlan_objmgr_vdev *vdev; 2324 enum phy_ch_width ch_width; 2325 enum phy_ch_width agile_ch_width; 2326 uint16_t chan_num; 2327 struct wlan_objmgr_pdev *pdev; 2328 QDF_STATUS status; 2329 2330 if (!spectral) { 2331 spectral_err("spectral target if object is null"); 2332 return QDF_STATUS_E_FAILURE; 2333 } 2334 2335 if (!is_valid) { 2336 spectral_err("is_valid argument is null"); 2337 return QDF_STATUS_E_FAILURE; 2338 } 2339 2340 pdev = spectral->pdev_obj; 2341 vdev = target_if_spectral_get_vdev(spectral); 2342 if (!vdev) { 2343 spectral_err("vdev is NULL"); 2344 return QDF_STATUS_E_FAILURE; 2345 } 2346 ch_width = target_if_vdev_get_ch_width(vdev); 2347 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 2348 agile_ch_width = target_if_spectral_find_agile_width(ch_width); 2349 2350 if (agile_ch_width == CH_WIDTH_20MHZ) { 2351 status = target_if_is_center_freq_of_any_chan 2352 (pdev, center_freq, is_valid); 2353 if (QDF_IS_STATUS_ERROR(status)) 2354 return QDF_STATUS_E_FAILURE; 2355 } else { 2356 uint16_t start_freq; 2357 uint16_t end_freq; 2358 const struct bonded_channel *bonded_chan_ptr = NULL; 2359 bool is_chan; 2360 2361 status = target_if_is_center_freq_of_any_chan 2362 (pdev, center_freq + 10, &is_chan); 2363 if (QDF_IS_STATUS_ERROR(status)) 2364 return QDF_STATUS_E_FAILURE; 2365 2366 if (is_chan) { 2367 uint32_t calulated_center_freq; 2368 2369 chan_num = wlan_reg_freq_to_chan(pdev, 2370 center_freq + 10); 2371 wlan_reg_get_5g_bonded_channel_and_state 2372 (pdev, chan_num, agile_ch_width, 2373 &bonded_chan_ptr); 2374 if (!bonded_chan_ptr) { 2375 spectral_err("Bonded channel is not found"); 2376 return QDF_STATUS_E_FAILURE; 2377 } 2378 start_freq = wlan_reg_chan_to_freq 2379 (pdev, bonded_chan_ptr->start_ch); 2380 end_freq = wlan_reg_chan_to_freq 2381 (pdev, bonded_chan_ptr->end_ch); 2382 calulated_center_freq = (start_freq + end_freq) >> 1; 2383 *is_valid = (center_freq == calulated_center_freq); 2384 } else { 2385 *is_valid = false; 2386 } 2387 } 2388 2389 return QDF_STATUS_SUCCESS; 2390 } 2391 2392 /** 2393 * target_if_is_agile_span_overlap_with_operating_span() - Helper routine to 2394 * check whether agile span overlaps with current operating band. 2395 * 2396 * @spectral: Pointer to Spectral object 2397 * @ss_frequency: Agile span center frequency 2398 * @is_overlapping: Indicates whether Agile span overlaps with operating span 2399 * 2400 * Helper routine to check whether agile span overlaps with current 2401 * operating band. 2402 * 2403 * Return: QDF_STATUS 2404 */ 2405 static QDF_STATUS 2406 target_if_is_agile_span_overlap_with_operating_span 2407 (struct target_if_spectral *spectral, 2408 uint32_t ss_frequency, 2409 bool *is_overlapping) 2410 { 2411 uint32_t chan_num; 2412 enum phy_ch_width ch_width; 2413 enum phy_ch_width agile_ch_width; 2414 const struct bonded_channel *bonded_chan_ptr = NULL; 2415 struct wlan_objmgr_vdev *vdev; 2416 struct wlan_objmgr_pdev *pdev; 2417 int16_t chan_freq; 2418 uint32_t op_start_freq; 2419 uint32_t op_end_freq; 2420 uint32_t agile_start_freq; 2421 uint32_t agile_end_freq; 2422 uint32_t cfreq2; 2423 2424 if (!spectral) { 2425 spectral_err("Spectral object is NULL"); 2426 return QDF_STATUS_E_FAILURE; 2427 } 2428 2429 pdev = spectral->pdev_obj; 2430 if (!pdev) { 2431 spectral_err("pdev object is NULL"); 2432 return QDF_STATUS_E_FAILURE; 2433 } 2434 2435 if (!is_overlapping) { 2436 spectral_err("Argument(is_overlapping) is NULL"); 2437 return QDF_STATUS_E_FAILURE; 2438 } 2439 2440 vdev = target_if_spectral_get_vdev(spectral); 2441 if (!vdev) { 2442 spectral_err("vdev is NULL"); 2443 return QDF_STATUS_E_FAILURE; 2444 } 2445 ch_width = target_if_vdev_get_ch_width(vdev); 2446 chan_freq = target_if_vdev_get_chan_freq(vdev); 2447 cfreq2 = target_if_vdev_get_chan_freq_seg2(vdev); 2448 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 2449 if (cfreq2 < 0) 2450 return QDF_STATUS_E_FAILURE; 2451 2452 chan_num = wlan_reg_freq_to_chan(pdev, chan_freq); 2453 2454 if (ch_width == CH_WIDTH_20MHZ) { 2455 op_start_freq = chan_freq - 10; 2456 op_end_freq = chan_freq + 10; 2457 } else { 2458 wlan_reg_get_5g_bonded_channel_and_state 2459 (pdev, chan_num, ch_width, &bonded_chan_ptr); 2460 if (!bonded_chan_ptr) { 2461 spectral_err("Bonded channel is not found"); 2462 return QDF_STATUS_E_FAILURE; 2463 } 2464 op_start_freq = 2465 wlan_reg_chan_to_freq(pdev, 2466 bonded_chan_ptr->start_ch) - 10; 2467 op_end_freq = 2468 wlan_reg_chan_to_freq(pdev, 2469 bonded_chan_ptr->end_ch) + 10; 2470 } 2471 2472 agile_ch_width = target_if_spectral_find_agile_width(ch_width); 2473 if (agile_ch_width == CH_WIDTH_INVALID) 2474 return QDF_STATUS_E_FAILURE; 2475 agile_start_freq = ss_frequency - 2476 (wlan_reg_get_bw_value(agile_ch_width) >> 1); 2477 agile_end_freq = ss_frequency + 2478 (wlan_reg_get_bw_value(agile_ch_width) >> 1); 2479 if (agile_end_freq <= op_start_freq || op_end_freq <= agile_start_freq) 2480 *is_overlapping = false; 2481 else 2482 *is_overlapping = true; 2483 2484 /* Use non zero cfreq2 to identify 80p80 */ 2485 if (cfreq2) { 2486 uint32_t sec80_start_feq; 2487 uint32_t sec80_end_freq; 2488 2489 sec80_start_feq = cfreq2 - 40; 2490 sec80_end_freq = cfreq2 + 40; 2491 2492 if ((agile_end_freq > sec80_start_feq) && 2493 (sec80_end_freq > agile_start_freq)) 2494 *is_overlapping = true; 2495 } 2496 2497 return QDF_STATUS_SUCCESS; 2498 } 2499 2500 /** 2501 * _target_if_set_spectral_config() - Set spectral config 2502 * @spectral: Pointer to spectral object 2503 * @threshtype: config type 2504 * @value: config value 2505 * @smode: Spectral scan mode 2506 * @err: Spectral error code 2507 * 2508 * API to set spectral configurations 2509 * 2510 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure 2511 */ 2512 static QDF_STATUS 2513 _target_if_set_spectral_config(struct target_if_spectral *spectral, 2514 const uint32_t threshtype, const uint32_t value, 2515 const enum spectral_scan_mode smode, 2516 enum spectral_cp_error_code *err) 2517 { 2518 struct spectral_config params; 2519 struct target_if_spectral_ops *p_sops; 2520 struct spectral_config *sparams; 2521 QDF_STATUS status; 2522 bool is_overlapping; 2523 uint16_t agile_cfreq; 2524 bool is_valid_chan; 2525 2526 if (!err) { 2527 spectral_err("Error code argument is null"); 2528 QDF_ASSERT(0); 2529 } 2530 *err = SPECTRAL_SCAN_ERR_INVALID; 2531 2532 if (!spectral) { 2533 spectral_err("spectral object is NULL"); 2534 return QDF_STATUS_E_FAILURE; 2535 } 2536 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 2537 2538 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 2539 spectral_err("Invalid Spectral mode %u", smode); 2540 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 2541 return QDF_STATUS_E_FAILURE; 2542 } 2543 2544 sparams = &spectral->params[smode]; 2545 2546 if (!spectral->params_valid[smode]) { 2547 target_if_spectral_info_read(spectral, 2548 smode, 2549 TARGET_IF_SPECTRAL_INFO_PARAMS, 2550 &spectral->params[smode], 2551 sizeof(spectral->params[smode])); 2552 spectral->params_valid[smode] = true; 2553 } 2554 2555 switch (threshtype) { 2556 case SPECTRAL_PARAM_FFT_PERIOD: 2557 sparams->ss_fft_period = value; 2558 break; 2559 case SPECTRAL_PARAM_SCAN_PERIOD: 2560 sparams->ss_period = value; 2561 break; 2562 case SPECTRAL_PARAM_SCAN_COUNT: 2563 sparams->ss_count = value; 2564 break; 2565 case SPECTRAL_PARAM_SHORT_REPORT: 2566 sparams->ss_short_report = (!!value) ? true : false; 2567 break; 2568 case SPECTRAL_PARAM_SPECT_PRI: 2569 sparams->ss_spectral_pri = (!!value) ? true : false; 2570 break; 2571 case SPECTRAL_PARAM_FFT_SIZE: 2572 if ((value < spectral->fft_size_min) || 2573 (value > spectral->fft_size_max)) { 2574 *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; 2575 return QDF_STATUS_E_FAILURE; 2576 } 2577 sparams->ss_fft_size = value; 2578 break; 2579 case SPECTRAL_PARAM_GC_ENA: 2580 sparams->ss_gc_ena = !!value; 2581 break; 2582 case SPECTRAL_PARAM_RESTART_ENA: 2583 sparams->ss_restart_ena = !!value; 2584 break; 2585 case SPECTRAL_PARAM_NOISE_FLOOR_REF: 2586 sparams->ss_noise_floor_ref = value; 2587 break; 2588 case SPECTRAL_PARAM_INIT_DELAY: 2589 sparams->ss_init_delay = value; 2590 break; 2591 case SPECTRAL_PARAM_NB_TONE_THR: 2592 sparams->ss_nb_tone_thr = value; 2593 break; 2594 case SPECTRAL_PARAM_STR_BIN_THR: 2595 sparams->ss_str_bin_thr = value; 2596 break; 2597 case SPECTRAL_PARAM_WB_RPT_MODE: 2598 sparams->ss_wb_rpt_mode = !!value; 2599 break; 2600 case SPECTRAL_PARAM_RSSI_RPT_MODE: 2601 sparams->ss_rssi_rpt_mode = !!value; 2602 break; 2603 case SPECTRAL_PARAM_RSSI_THR: 2604 sparams->ss_rssi_thr = value; 2605 break; 2606 case SPECTRAL_PARAM_PWR_FORMAT: 2607 sparams->ss_pwr_format = !!value; 2608 break; 2609 case SPECTRAL_PARAM_RPT_MODE: 2610 if ((value < SPECTRAL_PARAM_RPT_MODE_MIN) || 2611 (value > SPECTRAL_PARAM_RPT_MODE_MAX)) { 2612 *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; 2613 return QDF_STATUS_E_FAILURE; 2614 } 2615 sparams->ss_rpt_mode = value; 2616 break; 2617 case SPECTRAL_PARAM_BIN_SCALE: 2618 sparams->ss_bin_scale = value; 2619 break; 2620 case SPECTRAL_PARAM_DBM_ADJ: 2621 sparams->ss_dbm_adj = !!value; 2622 break; 2623 case SPECTRAL_PARAM_CHN_MASK: 2624 sparams->ss_chn_mask = value; 2625 break; 2626 case SPECTRAL_PARAM_FREQUENCY: 2627 status = target_if_is_center_freq_of_any_chan 2628 (spectral->pdev_obj, value, &is_valid_chan); 2629 if (QDF_IS_STATUS_ERROR(status)) 2630 return QDF_STATUS_E_FAILURE; 2631 2632 if (is_valid_chan) { 2633 status = target_if_calculate_center_freq(spectral, 2634 value, 2635 &agile_cfreq); 2636 if (QDF_IS_STATUS_ERROR(status)) { 2637 *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; 2638 return QDF_STATUS_E_FAILURE; 2639 } 2640 } else { 2641 bool is_valid_agile_cfreq; 2642 2643 status = target_if_validate_center_freq 2644 (spectral, value, &is_valid_agile_cfreq); 2645 if (QDF_IS_STATUS_ERROR(status)) 2646 return QDF_STATUS_E_FAILURE; 2647 2648 if (!is_valid_agile_cfreq) { 2649 *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; 2650 spectral_err("Invalid agile center frequency"); 2651 return QDF_STATUS_E_FAILURE; 2652 } 2653 2654 agile_cfreq = value; 2655 } 2656 2657 status = target_if_is_agile_span_overlap_with_operating_span 2658 (spectral, agile_cfreq, &is_overlapping); 2659 if (QDF_IS_STATUS_ERROR(status)) 2660 return QDF_STATUS_E_FAILURE; 2661 2662 if (is_overlapping) { 2663 spectral_err("Agile span overlapping with current BW"); 2664 *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; 2665 return QDF_STATUS_E_FAILURE; 2666 } 2667 sparams->ss_frequency = agile_cfreq; 2668 break; 2669 } 2670 2671 p_sops->configure_spectral(spectral, sparams, smode); 2672 /* only to validate the writes */ 2673 p_sops->get_spectral_config(spectral, ¶ms, smode); 2674 return QDF_STATUS_SUCCESS; 2675 } 2676 2677 QDF_STATUS 2678 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev, 2679 const uint32_t threshtype, const uint32_t value, 2680 const enum spectral_scan_mode smode, 2681 enum spectral_cp_error_code *err) 2682 { 2683 enum spectral_scan_mode mode = SPECTRAL_SCAN_MODE_NORMAL; 2684 struct target_if_spectral *spectral; 2685 QDF_STATUS status; 2686 2687 if (!err) { 2688 spectral_err("Error code argument is null"); 2689 QDF_ASSERT(0); 2690 } 2691 *err = SPECTRAL_SCAN_ERR_INVALID; 2692 2693 if (!pdev) { 2694 spectral_err("pdev object is NULL"); 2695 return QDF_STATUS_E_FAILURE; 2696 } 2697 spectral = get_target_if_spectral_handle_from_pdev(pdev); 2698 if (!spectral) { 2699 spectral_err("spectral object is NULL"); 2700 return QDF_STATUS_E_FAILURE; 2701 } 2702 2703 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 2704 spectral_err("Invalid Spectral mode %u", smode); 2705 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 2706 return QDF_STATUS_E_FAILURE; 2707 } 2708 2709 if (!spectral->properties[smode][threshtype].supported) { 2710 spectral_err("Spectral parameter(%u) unsupported for mode %u", 2711 threshtype, smode); 2712 *err = SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED; 2713 return QDF_STATUS_E_FAILURE; 2714 } 2715 2716 if (spectral->properties[smode][threshtype].common_all_modes) { 2717 spectral_warn("Setting Spectral parameter %u for all modes", 2718 threshtype); 2719 for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) { 2720 status = _target_if_set_spectral_config 2721 (spectral, threshtype, value, 2722 mode, err); 2723 if (QDF_IS_STATUS_ERROR(status)) 2724 return QDF_STATUS_E_FAILURE; 2725 } 2726 return QDF_STATUS_SUCCESS; 2727 } 2728 2729 return _target_if_set_spectral_config(spectral, threshtype, 2730 value, smode, err); 2731 } 2732 2733 /** 2734 * target_if_get_fft_bin_count() - Get fft bin count for a given fft length 2735 * @fft_len: FFT length 2736 * @pdev: Pointer to pdev object 2737 * 2738 * API to get fft bin count for a given fft length 2739 * 2740 * Return: FFt bin count 2741 */ 2742 static int 2743 target_if_get_fft_bin_count(int fft_len) 2744 { 2745 int bin_count = 0; 2746 2747 switch (fft_len) { 2748 case 5: 2749 bin_count = 16; 2750 break; 2751 case 6: 2752 bin_count = 32; 2753 break; 2754 case 7: 2755 bin_count = 64; 2756 break; 2757 case 8: 2758 bin_count = 128; 2759 break; 2760 case 9: 2761 bin_count = 256; 2762 break; 2763 default: 2764 break; 2765 } 2766 2767 return bin_count; 2768 } 2769 2770 /** 2771 * target_if_init_upper_lower_flags() - Initializes control and extension 2772 * segment flags 2773 * @fft_len: FFT length 2774 * @pdev: Pointer to pdev object 2775 * 2776 * API to initialize the control and extension flags with the lower/upper 2777 * segment based on the HT mode 2778 * 2779 * Return: FFt bin count 2780 */ 2781 static void 2782 target_if_init_upper_lower_flags(struct target_if_spectral *spectral) 2783 { 2784 int current_channel = 0; 2785 int ext_channel = 0; 2786 struct target_if_spectral_ops *p_sops = 2787 GET_TARGET_IF_SPECTRAL_OPS(spectral); 2788 2789 current_channel = p_sops->get_current_channel(spectral); 2790 ext_channel = p_sops->get_extension_channel(spectral); 2791 2792 if ((current_channel == 0) || (ext_channel == 0)) 2793 return; 2794 2795 if (spectral->sc_spectral_20_40_mode) { 2796 /* HT40 mode */ 2797 if (ext_channel < current_channel) { 2798 spectral->lower_is_extension = 1; 2799 spectral->upper_is_control = 1; 2800 spectral->lower_is_control = 0; 2801 spectral->upper_is_extension = 0; 2802 } else { 2803 spectral->lower_is_extension = 0; 2804 spectral->upper_is_control = 0; 2805 spectral->lower_is_control = 1; 2806 spectral->upper_is_extension = 1; 2807 } 2808 } else { 2809 /* HT20 mode, lower is always control */ 2810 spectral->lower_is_extension = 0; 2811 spectral->upper_is_control = 0; 2812 spectral->lower_is_control = 1; 2813 spectral->upper_is_extension = 0; 2814 } 2815 } 2816 2817 /** 2818 * target_if_get_spectral_config() - Get spectral configuration 2819 * @pdev: Pointer to pdev object 2820 * @param: Pointer to spectral_config structure in which the configuration 2821 * should be returned 2822 * @smode: Spectral scan mode 2823 * 2824 * API to get the current spectral configuration 2825 * 2826 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure 2827 */ 2828 QDF_STATUS 2829 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev, 2830 struct spectral_config *param, 2831 enum spectral_scan_mode smode) 2832 { 2833 struct target_if_spectral_ops *p_sops = NULL; 2834 struct target_if_spectral *spectral = NULL; 2835 2836 spectral = get_target_if_spectral_handle_from_pdev(pdev); 2837 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 2838 2839 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 2840 spectral_err("Invalid Spectral mode %u", smode); 2841 return QDF_STATUS_E_FAILURE; 2842 } 2843 2844 qdf_mem_zero(param, sizeof(struct spectral_config)); 2845 p_sops->get_spectral_config(spectral, param, smode); 2846 2847 return QDF_STATUS_SUCCESS; 2848 } 2849 2850 /** 2851 * target_if_spectral_scan_enable_params() - Enable use of desired Spectral 2852 * parameters 2853 * @spectral: Pointer to Spectral target_if internal private data 2854 * @spectral_params: Pointer to Spectral parameters 2855 * @smode: Spectral scan mode 2856 * @err: Spectral error code 2857 * 2858 * Enable use of desired Spectral parameters by configuring them into HW, and 2859 * starting Spectral scan 2860 * 2861 * Return: 0 on success, 1 on failure 2862 */ 2863 int 2864 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral, 2865 struct spectral_config *spectral_params, 2866 enum spectral_scan_mode smode, 2867 enum spectral_cp_error_code *err) 2868 { 2869 int extension_channel = 0; 2870 int current_channel = 0; 2871 struct target_if_spectral_ops *p_sops = NULL; 2872 struct wlan_objmgr_vdev *vdev = NULL; 2873 2874 if (!spectral) { 2875 spectral_err("Spectral LMAC object is NULL"); 2876 return 1; 2877 } 2878 2879 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 2880 spectral_err("Invalid Spectral mode %u", smode); 2881 return 1; 2882 } 2883 2884 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 2885 2886 if (!p_sops) { 2887 spectral_err("p_sops is NULL"); 2888 return 1; 2889 } 2890 2891 spectral->sc_spectral_noise_pwr_cal = 2892 spectral_params->ss_spectral_pri ? 1 : 0; 2893 2894 /* check if extension channel is present */ 2895 extension_channel = p_sops->get_extension_channel(spectral); 2896 current_channel = p_sops->get_current_channel(spectral); 2897 2898 vdev = target_if_spectral_get_vdev(spectral); 2899 if (!vdev) 2900 return 1; 2901 2902 spectral->ch_width = target_if_vdev_get_ch_width(vdev); 2903 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 2904 2905 if (spectral->ch_width == CH_WIDTH_INVALID) 2906 return 1; 2907 2908 if (spectral->capability.advncd_spectral_cap) { 2909 spectral->lb_edge_extrabins = 0; 2910 spectral->rb_edge_extrabins = 0; 2911 2912 if (spectral->is_lb_edge_extrabins_format && 2913 spectral->params[smode].ss_rpt_mode == 2) { 2914 spectral->lb_edge_extrabins = 4; 2915 } 2916 2917 if (spectral->is_rb_edge_extrabins_format && 2918 spectral->params[smode].ss_rpt_mode == 2) { 2919 spectral->rb_edge_extrabins = 4; 2920 } 2921 2922 if (spectral->ch_width == CH_WIDTH_20MHZ) { 2923 spectral->sc_spectral_20_40_mode = 0; 2924 2925 spectral->spectral_numbins = 2926 target_if_get_fft_bin_count( 2927 spectral->params[smode].ss_fft_size); 2928 spectral->spectral_fft_len = 2929 target_if_get_fft_bin_count( 2930 spectral->params[smode].ss_fft_size); 2931 spectral->spectral_data_len = 2932 target_if_get_fft_bin_count( 2933 spectral->params[smode].ss_fft_size); 2934 /* 2935 * Initialize classifier params to be sent to user 2936 * space classifier 2937 */ 2938 spectral->classifier_params.lower_chan_in_mhz = 2939 current_channel; 2940 spectral->classifier_params.upper_chan_in_mhz = 0; 2941 2942 } else if (spectral->ch_width == CH_WIDTH_40MHZ) { 2943 /* TODO : Remove this variable */ 2944 spectral->sc_spectral_20_40_mode = 1; 2945 spectral->spectral_numbins = 2946 target_if_get_fft_bin_count( 2947 spectral->params[smode].ss_fft_size); 2948 spectral->spectral_fft_len = 2949 target_if_get_fft_bin_count( 2950 spectral->params[smode].ss_fft_size); 2951 spectral->spectral_data_len = 2952 target_if_get_fft_bin_count( 2953 spectral->params[smode].ss_fft_size); 2954 2955 /* 2956 * Initialize classifier params to be sent to user 2957 * space classifier 2958 */ 2959 if (extension_channel < current_channel) { 2960 spectral->classifier_params.lower_chan_in_mhz = 2961 extension_channel; 2962 spectral->classifier_params.upper_chan_in_mhz = 2963 current_channel; 2964 } else { 2965 spectral->classifier_params.lower_chan_in_mhz = 2966 current_channel; 2967 spectral->classifier_params.upper_chan_in_mhz = 2968 extension_channel; 2969 } 2970 2971 } else if (spectral->ch_width == CH_WIDTH_80MHZ) { 2972 /* Set the FFT Size */ 2973 /* TODO : Remove this variable */ 2974 spectral->sc_spectral_20_40_mode = 0; 2975 spectral->spectral_numbins = 2976 target_if_get_fft_bin_count( 2977 spectral->params[smode].ss_fft_size); 2978 spectral->spectral_fft_len = 2979 target_if_get_fft_bin_count( 2980 spectral->params[smode].ss_fft_size); 2981 spectral->spectral_data_len = 2982 target_if_get_fft_bin_count( 2983 spectral->params[smode].ss_fft_size); 2984 2985 /* 2986 * Initialize classifier params to be sent to user 2987 * space classifier 2988 */ 2989 spectral->classifier_params.lower_chan_in_mhz = 2990 current_channel; 2991 spectral->classifier_params.upper_chan_in_mhz = 0; 2992 2993 /* 2994 * Initialize classifier params to be sent to user 2995 * space classifier 2996 */ 2997 if (extension_channel < current_channel) { 2998 spectral->classifier_params.lower_chan_in_mhz = 2999 extension_channel; 3000 spectral->classifier_params.upper_chan_in_mhz = 3001 current_channel; 3002 } else { 3003 spectral->classifier_params.lower_chan_in_mhz = 3004 current_channel; 3005 spectral->classifier_params.upper_chan_in_mhz = 3006 extension_channel; 3007 } 3008 3009 } else if (spectral->ch_width == CH_WIDTH_160MHZ) { 3010 /* Set the FFT Size */ 3011 3012 /* The below applies to both 160 and 80+80 cases */ 3013 3014 /* TODO : Remove this variable */ 3015 spectral->sc_spectral_20_40_mode = 0; 3016 spectral->spectral_numbins = 3017 target_if_get_fft_bin_count( 3018 spectral->params[smode].ss_fft_size); 3019 spectral->spectral_fft_len = 3020 target_if_get_fft_bin_count( 3021 spectral->params[smode].ss_fft_size); 3022 spectral->spectral_data_len = 3023 target_if_get_fft_bin_count( 3024 spectral->params[smode].ss_fft_size); 3025 3026 /* 3027 * Initialize classifier params to be sent to user 3028 * space classifier 3029 */ 3030 spectral->classifier_params.lower_chan_in_mhz = 3031 current_channel; 3032 spectral->classifier_params.upper_chan_in_mhz = 0; 3033 3034 /* 3035 * Initialize classifier params to be sent to user 3036 * space classifier 3037 */ 3038 if (extension_channel < current_channel) { 3039 spectral->classifier_params.lower_chan_in_mhz = 3040 extension_channel; 3041 spectral->classifier_params.upper_chan_in_mhz = 3042 current_channel; 3043 } else { 3044 spectral->classifier_params.lower_chan_in_mhz = 3045 current_channel; 3046 spectral->classifier_params.upper_chan_in_mhz = 3047 extension_channel; 3048 } 3049 } 3050 3051 if (spectral->spectral_numbins) { 3052 spectral->spectral_numbins += 3053 spectral->lb_edge_extrabins; 3054 spectral->spectral_numbins += 3055 spectral->rb_edge_extrabins; 3056 } 3057 3058 if (spectral->spectral_fft_len) { 3059 spectral->spectral_fft_len += 3060 spectral->lb_edge_extrabins; 3061 spectral->spectral_fft_len += 3062 spectral->rb_edge_extrabins; 3063 } 3064 3065 if (spectral->spectral_data_len) { 3066 spectral->spectral_data_len += 3067 spectral->lb_edge_extrabins; 3068 spectral->spectral_data_len += 3069 spectral->rb_edge_extrabins; 3070 } 3071 } else { 3072 /* 3073 * The decision to find 20/40 mode is found based on the 3074 * presence of extension channel 3075 * instead of channel width, as the channel width can 3076 * dynamically change 3077 */ 3078 3079 if (extension_channel == 0) { 3080 spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS; 3081 spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX; 3082 spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN; 3083 spectral->spectral_data_len = 3084 SPECTRAL_HT20_TOTAL_DATA_LEN; 3085 /* only valid in 20-40 mode */ 3086 spectral->spectral_lower_max_index_offset = -1; 3087 /* only valid in 20-40 mode */ 3088 spectral->spectral_upper_max_index_offset = -1; 3089 spectral->spectral_max_index_offset = 3090 spectral->spectral_fft_len + 2; 3091 spectral->sc_spectral_20_40_mode = 0; 3092 3093 /* 3094 * Initialize classifier params to be sent to user 3095 * space classifier 3096 */ 3097 spectral->classifier_params.lower_chan_in_mhz = 3098 current_channel; 3099 spectral->classifier_params.upper_chan_in_mhz = 0; 3100 3101 } else { 3102 spectral->spectral_numbins = 3103 SPECTRAL_HT40_TOTAL_NUM_BINS; 3104 spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN; 3105 spectral->spectral_data_len = 3106 SPECTRAL_HT40_TOTAL_DATA_LEN; 3107 spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX; 3108 /* only valid in 20 mode */ 3109 spectral->spectral_max_index_offset = -1; 3110 spectral->spectral_lower_max_index_offset = 3111 spectral->spectral_fft_len + 2; 3112 spectral->spectral_upper_max_index_offset = 3113 spectral->spectral_fft_len + 5; 3114 spectral->sc_spectral_20_40_mode = 1; 3115 3116 /* 3117 * Initialize classifier params to be sent to user 3118 * space classifier 3119 */ 3120 if (extension_channel < current_channel) { 3121 spectral->classifier_params.lower_chan_in_mhz = 3122 extension_channel; 3123 spectral->classifier_params.upper_chan_in_mhz = 3124 current_channel; 3125 } else { 3126 spectral->classifier_params.lower_chan_in_mhz = 3127 current_channel; 3128 spectral->classifier_params.upper_chan_in_mhz = 3129 extension_channel; 3130 } 3131 } 3132 } 3133 3134 spectral->send_single_packet = 0; 3135 spectral->classifier_params.spectral_20_40_mode = 3136 spectral->sc_spectral_20_40_mode; 3137 spectral->classifier_params.spectral_dc_index = 3138 spectral->spectral_dc_index; 3139 spectral->spectral_sent_msg = 0; 3140 spectral->classify_scan = 0; 3141 spectral->num_spectral_data = 0; 3142 3143 if (!p_sops->is_spectral_active(spectral, smode)) { 3144 p_sops->configure_spectral(spectral, spectral_params, smode); 3145 p_sops->start_spectral_scan(spectral, smode, err); 3146 spectral->timestamp_war_offset[smode] = 0; 3147 spectral->last_fft_timestamp[smode] = 0; 3148 } 3149 3150 /* get current spectral configuration */ 3151 p_sops->get_spectral_config(spectral, &spectral->params[smode], smode); 3152 3153 target_if_init_upper_lower_flags(spectral); 3154 3155 return 0; 3156 } 3157 3158 /** 3159 * target_if_is_aspectral_prohibited_by_adfs() - Is Agile Spectral prohibited by 3160 * Agile DFS 3161 * @psoc: Pointer to psoc 3162 * @object: Pointer to pdev 3163 * @arg: Pointer to flag which indicates whether Agile Spectral is prohibited 3164 * 3165 * This API checks whether Agile DFS is running on any of the pdevs. If so, it 3166 * indicates that Agile Spectral scan is prohibited by Agile DFS. 3167 * 3168 * Return: void 3169 */ 3170 static void 3171 target_if_is_aspectral_prohibited_by_adfs(struct wlan_objmgr_psoc *psoc, 3172 void *object, void *arg) 3173 { 3174 bool *is_aspectral_prohibited = arg; 3175 struct wlan_objmgr_pdev *cur_pdev = object; 3176 bool is_agile_dfs_enabled_cur_pdev = false; 3177 QDF_STATUS status; 3178 3179 qdf_assert_always(is_aspectral_prohibited); 3180 if (*is_aspectral_prohibited) 3181 return; 3182 3183 qdf_assert_always(psoc); 3184 qdf_assert_always(cur_pdev); 3185 3186 status = ucfg_dfs_get_agile_precac_enable 3187 (cur_pdev, 3188 &is_agile_dfs_enabled_cur_pdev); 3189 if (QDF_IS_STATUS_ERROR(status)) { 3190 spectral_err("Get agile precac failed, prohibiting aSpectral"); 3191 *is_aspectral_prohibited = true; 3192 return; 3193 } 3194 3195 if (is_agile_dfs_enabled_cur_pdev) { 3196 spectral_err("aDFS is in progress on one of the pdevs"); 3197 *is_aspectral_prohibited = true; 3198 } 3199 } 3200 3201 /** 3202 * target_if_get_curr_band() - Get current operating band of pdev 3203 * 3204 * @spectral: pointer to spectral object 3205 * 3206 * API to get current operating band of a given pdev. 3207 * 3208 * Return: if success enum band_info, BAND_UNKNOWN in case of failure 3209 */ 3210 static enum band_info 3211 target_if_get_curr_band(struct wlan_objmgr_pdev *pdev) 3212 { 3213 struct wlan_objmgr_vdev *vdev; 3214 int16_t chan_freq; 3215 enum band_info cur_band; 3216 uint32_t chan_num; 3217 3218 if (!pdev) { 3219 spectral_err("pdev is NULL"); 3220 return BAND_UNKNOWN; 3221 } 3222 3223 vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID); 3224 if (!vdev) { 3225 spectral_debug("vdev is NULL"); 3226 return BAND_UNKNOWN; 3227 } 3228 chan_freq = target_if_vdev_get_chan_freq(vdev); 3229 chan_num = wlan_reg_freq_to_chan(pdev, chan_freq); 3230 cur_band = wlan_reg_chan_to_band(chan_num); 3231 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 3232 3233 return cur_band; 3234 } 3235 3236 /** 3237 * target_if_is_agile_scan_active_in_5g() - Is Agile Spectral scan active on 3238 * any of the 5G pdevs 3239 * @psoc: Pointer to psoc 3240 * @object: Pointer to pdev 3241 * @arg: Pointer to flag which indicates whether Agile Spectral scan is in 3242 * progress in any 5G pdevs 3243 * 3244 * Return: void 3245 */ 3246 static void 3247 target_if_is_agile_scan_active_in_5g(struct wlan_objmgr_psoc *psoc, 3248 void *object, void *arg) 3249 { 3250 enum band_info band; 3251 bool *is_agile_scan_inprog_5g_pdev = arg; 3252 struct target_if_spectral *spectral; 3253 struct wlan_objmgr_pdev *cur_pdev = object; 3254 struct target_if_spectral_ops *p_sops; 3255 3256 if (*is_agile_scan_inprog_5g_pdev) 3257 return; 3258 3259 spectral = get_target_if_spectral_handle_from_pdev(cur_pdev); 3260 if (!spectral) { 3261 spectral_err("target if spectral handle is NULL"); 3262 return; 3263 } 3264 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3265 3266 band = target_if_get_curr_band(cur_pdev); 3267 if (band == BAND_UNKNOWN) { 3268 spectral_debug("Failed to get current band"); 3269 return; 3270 } 3271 3272 if (band == BAND_5G && 3273 p_sops->is_spectral_active(spectral, SPECTRAL_SCAN_MODE_AGILE)) 3274 *is_agile_scan_inprog_5g_pdev = true; 3275 } 3276 3277 QDF_STATUS 3278 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev, 3279 const enum spectral_scan_mode smode, 3280 enum spectral_cp_error_code *err) 3281 { 3282 struct target_if_spectral_ops *p_sops; 3283 struct target_if_spectral *spectral; 3284 struct wlan_objmgr_psoc *psoc; 3285 enum band_info band; 3286 3287 if (!err) { 3288 spectral_err("Error code argument is null"); 3289 QDF_ASSERT(0); 3290 } 3291 *err = SPECTRAL_SCAN_ERR_INVALID; 3292 3293 psoc = wlan_pdev_get_psoc(pdev); 3294 if (!psoc) { 3295 spectral_err("psoc is null"); 3296 return QDF_STATUS_E_FAILURE; 3297 } 3298 3299 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 3300 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 3301 spectral_err("Invalid Spectral mode %u", smode); 3302 return QDF_STATUS_E_FAILURE; 3303 } 3304 3305 if (!pdev) { 3306 spectral_err("pdev object is NUll"); 3307 return QDF_STATUS_E_FAILURE; 3308 } 3309 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3310 if (!spectral) { 3311 spectral_err("Spectral LMAC object is NUll"); 3312 return QDF_STATUS_E_FAILURE; 3313 } 3314 3315 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3316 3317 band = target_if_get_curr_band(spectral->pdev_obj); 3318 if (band == BAND_UNKNOWN) { 3319 spectral_err("Failed to get current band"); 3320 return QDF_STATUS_E_FAILURE; 3321 } 3322 if ((band == BAND_5G) && (smode == SPECTRAL_SCAN_MODE_AGILE)) { 3323 struct target_psoc_info *tgt_hdl; 3324 enum wmi_host_hw_mode_config_type mode; 3325 bool is_agile_scan_inprog_5g_pdev; 3326 3327 if (p_sops->is_spectral_active(spectral, 3328 SPECTRAL_SCAN_MODE_AGILE)) { 3329 spectral_err("Agile Scan in progress in current pdev"); 3330 return QDF_STATUS_E_FAILURE; 3331 } 3332 3333 tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); 3334 if (!tgt_hdl) { 3335 target_if_err("target_psoc_info is null"); 3336 return QDF_STATUS_E_FAILURE; 3337 } 3338 3339 mode = target_psoc_get_preferred_hw_mode(tgt_hdl); 3340 switch (mode) { 3341 case WMI_HOST_HW_MODE_SBS_PASSIVE: 3342 case WMI_HOST_HW_MODE_SBS: 3343 case WMI_HOST_HW_MODE_DBS_SBS: 3344 case WMI_HOST_HW_MODE_DBS_OR_SBS: 3345 is_agile_scan_inprog_5g_pdev = false; 3346 wlan_objmgr_iterate_obj_list 3347 (psoc, WLAN_PDEV_OP, 3348 target_if_is_agile_scan_active_in_5g, 3349 &is_agile_scan_inprog_5g_pdev, 0, 3350 WLAN_SPECTRAL_ID); 3351 break; 3352 default: 3353 is_agile_scan_inprog_5g_pdev = false; 3354 break; 3355 } 3356 3357 if (is_agile_scan_inprog_5g_pdev) { 3358 spectral_err("Agile Scan in progress in one of the SBS 5G pdev"); 3359 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 3360 return QDF_STATUS_E_FAILURE; 3361 } 3362 } 3363 3364 if (smode == SPECTRAL_SCAN_MODE_AGILE) { 3365 bool is_aspectral_prohibited = false; 3366 QDF_STATUS status; 3367 3368 status = wlan_objmgr_iterate_obj_list 3369 (psoc, WLAN_PDEV_OP, 3370 target_if_is_aspectral_prohibited_by_adfs, 3371 &is_aspectral_prohibited, 0, 3372 WLAN_SPECTRAL_ID); 3373 if (QDF_IS_STATUS_ERROR(status)) { 3374 spectral_err("Failed to iterate over pdevs"); 3375 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 3376 return QDF_STATUS_E_FAILURE; 3377 } 3378 3379 if (is_aspectral_prohibited) { 3380 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 3381 return QDF_STATUS_E_FAILURE; 3382 } 3383 } 3384 3385 if (!spectral->params_valid[smode]) { 3386 target_if_spectral_info_read(spectral, 3387 smode, 3388 TARGET_IF_SPECTRAL_INFO_PARAMS, 3389 &spectral->params[smode], 3390 sizeof(spectral->params[smode])); 3391 spectral->params_valid[smode] = true; 3392 } 3393 3394 qdf_spin_lock(&spectral->spectral_lock); 3395 if (smode == SPECTRAL_SCAN_MODE_AGILE && 3396 !spectral->params[smode].ss_frequency) { 3397 *err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED; 3398 qdf_spin_unlock(&spectral->spectral_lock); 3399 return QDF_STATUS_E_FAILURE; 3400 } 3401 3402 if (smode == SPECTRAL_SCAN_MODE_AGILE) { 3403 QDF_STATUS status; 3404 bool is_overlapping; 3405 3406 status = target_if_is_agile_span_overlap_with_operating_span 3407 (spectral, 3408 spectral->params[smode].ss_frequency, 3409 &is_overlapping); 3410 if (QDF_IS_STATUS_ERROR(status)) { 3411 qdf_spin_unlock(&spectral->spectral_lock); 3412 return QDF_STATUS_E_FAILURE; 3413 } 3414 3415 if (is_overlapping) { 3416 *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; 3417 qdf_spin_unlock(&spectral->spectral_lock); 3418 return QDF_STATUS_E_FAILURE; 3419 } 3420 } 3421 3422 target_if_spectral_scan_enable_params(spectral, 3423 &spectral->params[smode], smode, 3424 err); 3425 qdf_spin_unlock(&spectral->spectral_lock); 3426 3427 return QDF_STATUS_SUCCESS; 3428 } 3429 3430 QDF_STATUS 3431 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev, 3432 const enum spectral_scan_mode smode, 3433 enum spectral_cp_error_code *err) 3434 { 3435 struct target_if_spectral_ops *p_sops; 3436 struct target_if_spectral *spectral; 3437 3438 if (!err) { 3439 spectral_err("Error code argument is null"); 3440 QDF_ASSERT(0); 3441 } 3442 *err = SPECTRAL_SCAN_ERR_INVALID; 3443 3444 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 3445 *err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED; 3446 spectral_err("Invalid Spectral mode %u", smode); 3447 return QDF_STATUS_E_FAILURE; 3448 } 3449 3450 if (!pdev) { 3451 spectral_err("pdev object is NUll "); 3452 return QDF_STATUS_E_FAILURE; 3453 } 3454 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3455 if (!spectral) { 3456 spectral_err("Spectral LMAC object is NUll "); 3457 return QDF_STATUS_E_FAILURE; 3458 } 3459 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3460 3461 qdf_spin_lock(&spectral->spectral_lock); 3462 p_sops->stop_spectral_scan(spectral, smode); 3463 if (spectral->classify_scan) { 3464 /* TODO : Check if this logic is necessary */ 3465 spectral->detects_control_channel = 0; 3466 spectral->detects_extension_channel = 0; 3467 spectral->detects_above_dc = 0; 3468 spectral->detects_below_dc = 0; 3469 spectral->classify_scan = 0; 3470 } 3471 3472 spectral->send_single_packet = 0; 3473 spectral->sc_spectral_scan = 0; 3474 3475 qdf_spin_unlock(&spectral->spectral_lock); 3476 3477 return QDF_STATUS_SUCCESS; 3478 } 3479 3480 /** 3481 * target_if_is_spectral_active() - Get whether Spectral is active 3482 * @pdev: Pointer to pdev object 3483 * @smode: Spectral scan mode 3484 * 3485 * API to get whether Spectral is active 3486 * 3487 * Return: True if Spectral is active, false if Spectral is not active 3488 */ 3489 bool 3490 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev, 3491 const enum spectral_scan_mode smode) 3492 { 3493 struct target_if_spectral *spectral = NULL; 3494 struct target_if_spectral_ops *p_sops = NULL; 3495 3496 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3497 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3498 3499 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 3500 spectral_err("Invalid Spectral mode %u", smode); 3501 return QDF_STATUS_E_FAILURE; 3502 } 3503 3504 return p_sops->is_spectral_active(spectral, smode); 3505 } 3506 3507 /** 3508 * target_if_is_spectral_enabled() - Get whether Spectral is enabled 3509 * @pdev: Pointer to pdev object 3510 * @smode: Spectral scan mode 3511 * 3512 * API to get whether Spectral is enabled 3513 * 3514 * Return: True if Spectral is enabled, false if Spectral is not enabled 3515 */ 3516 bool 3517 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev, 3518 enum spectral_scan_mode smode) 3519 { 3520 struct target_if_spectral *spectral = NULL; 3521 struct target_if_spectral_ops *p_sops = NULL; 3522 3523 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3524 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3525 3526 if (smode >= SPECTRAL_SCAN_MODE_MAX) { 3527 spectral_err("Invalid Spectral mode %u", smode); 3528 return QDF_STATUS_E_FAILURE; 3529 } 3530 3531 return p_sops->is_spectral_enabled(spectral, smode); 3532 } 3533 3534 /** 3535 * target_if_set_debug_level() - Set debug level for Spectral 3536 * @pdev: Pointer to pdev object 3537 * @debug_level: Debug level 3538 * 3539 * API to set the debug level for Spectral 3540 * 3541 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure 3542 */ 3543 QDF_STATUS 3544 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level) 3545 { 3546 spectral_debug_level = (DEBUG_SPECTRAL << debug_level); 3547 3548 return QDF_STATUS_SUCCESS; 3549 } 3550 3551 /** 3552 * target_if_get_debug_level() - Get debug level for Spectral 3553 * @pdev: Pointer to pdev object 3554 * 3555 * API to get the debug level for Spectral 3556 * 3557 * Return: Current debug level 3558 */ 3559 uint32_t 3560 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev) 3561 { 3562 return spectral_debug_level; 3563 } 3564 3565 /** 3566 * target_if_get_spectral_capinfo() - Get Spectral capability information 3567 * @pdev: Pointer to pdev object 3568 * @scaps: Buffer into which data should be copied 3569 * 3570 * API to get the spectral capability information 3571 * 3572 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure 3573 */ 3574 QDF_STATUS 3575 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev, 3576 struct spectral_caps *scaps) 3577 { 3578 struct target_if_spectral *spectral = NULL; 3579 3580 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3581 qdf_mem_copy(scaps, &spectral->capability, 3582 sizeof(struct spectral_caps)); 3583 3584 return QDF_STATUS_SUCCESS; 3585 } 3586 3587 /** 3588 * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics 3589 * @pdev: Pointer to pdev object 3590 * @stats: Buffer into which data should be copied 3591 * 3592 * API to get the spectral diagnostic statistics 3593 * 3594 * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure 3595 */ 3596 QDF_STATUS 3597 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev, 3598 struct spectral_diag_stats *stats) 3599 { 3600 struct target_if_spectral *spectral = NULL; 3601 3602 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3603 qdf_mem_copy(stats, &spectral->diag_stats, 3604 sizeof(struct spectral_diag_stats)); 3605 3606 return QDF_STATUS_SUCCESS; 3607 } 3608 3609 /** 3610 * target_if_register_wmi_spectral_cmd_ops() - Register wmi_spectral_cmd_ops 3611 * @cmd_ops: Pointer to the structure having wmi_spectral_cmd function pointers 3612 * @pdev: Pointer to pdev object 3613 * 3614 * API for register wmi_spectral_cmd_ops in spectral internal data structure 3615 * 3616 * Return: void 3617 */ 3618 void 3619 target_if_register_wmi_spectral_cmd_ops(struct wlan_objmgr_pdev *pdev, 3620 struct wmi_spectral_cmd_ops *cmd_ops) 3621 { 3622 struct target_if_spectral *spectral = 3623 get_target_if_spectral_handle_from_pdev(pdev); 3624 3625 if (!spectral) { 3626 spectral_err("Spectral LMAC object is null"); 3627 return; 3628 } 3629 spectral->param_wmi_cmd_ops = *cmd_ops; 3630 } 3631 3632 /** 3633 * target_if_register_netlink_cb() - Register Netlink callbacks 3634 * @pdev: Pointer to pdev object 3635 * @nl_cb: Netlink callbacks to register 3636 * 3637 * Return: void 3638 */ 3639 static void 3640 target_if_register_netlink_cb( 3641 struct wlan_objmgr_pdev *pdev, 3642 struct spectral_nl_cb *nl_cb) 3643 { 3644 struct target_if_spectral *spectral = NULL; 3645 3646 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3647 qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb)); 3648 3649 if (spectral->use_nl_bcast) 3650 spectral->send_phy_data = spectral->nl_cb.send_nl_bcast; 3651 else 3652 spectral->send_phy_data = spectral->nl_cb.send_nl_unicast; 3653 } 3654 3655 /** 3656 * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending 3657 * Netlink messages to the application layer 3658 * @pdev: Pointer to pdev object 3659 * 3660 * Return: true for broadcast, false for unicast 3661 */ 3662 static bool 3663 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev) 3664 { 3665 struct target_if_spectral *spectral = NULL; 3666 3667 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3668 return spectral->use_nl_bcast; 3669 } 3670 3671 /** 3672 * target_if_deregister_netlink_cb() - De-register Netlink callbacks 3673 * @pdev: Pointer to pdev object 3674 * 3675 * Return: void 3676 */ 3677 static void 3678 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev) 3679 { 3680 struct target_if_spectral *spectral = NULL; 3681 3682 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3683 if (!spectral) { 3684 spectral_err("SPECTRAL : Module doesn't exist"); 3685 return; 3686 } 3687 3688 qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb)); 3689 } 3690 3691 static int 3692 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev, 3693 void *payload) 3694 { 3695 struct target_if_spectral *spectral = NULL; 3696 struct target_if_spectral_ops *p_sops = NULL; 3697 3698 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3699 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3700 3701 return p_sops->process_spectral_report(pdev, payload); 3702 } 3703 3704 void 3705 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 3706 { 3707 tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init = 3708 target_if_pdev_spectral_init; 3709 tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit = 3710 target_if_pdev_spectral_deinit; 3711 tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config = 3712 target_if_set_spectral_config; 3713 tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config = 3714 target_if_get_spectral_config; 3715 tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan = 3716 target_if_start_spectral_scan; 3717 tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan = 3718 target_if_stop_spectral_scan; 3719 tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active = 3720 target_if_is_spectral_active; 3721 tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled = 3722 target_if_is_spectral_enabled; 3723 tx_ops->sptrl_tx_ops.sptrlto_set_debug_level = 3724 target_if_set_debug_level; 3725 tx_ops->sptrl_tx_ops.sptrlto_get_debug_level = 3726 target_if_get_debug_level; 3727 tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo = 3728 target_if_get_spectral_capinfo; 3729 tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats = 3730 target_if_get_spectral_diagstats; 3731 tx_ops->sptrl_tx_ops.sptrlto_register_wmi_spectral_cmd_ops = 3732 target_if_register_wmi_spectral_cmd_ops; 3733 tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb = 3734 target_if_register_netlink_cb; 3735 tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast = 3736 target_if_use_nl_bcast; 3737 tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb = 3738 target_if_deregister_netlink_cb; 3739 tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report = 3740 target_if_process_spectral_report; 3741 } 3742 qdf_export_symbol(target_if_sptrl_register_tx_ops); 3743 3744 void 3745 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev, 3746 uint16_t cw_int, uint32_t dcs_enabled) 3747 { 3748 struct spectral_samp_msg *msg = NULL; 3749 struct target_if_spectral_ops *p_sops = NULL; 3750 struct target_if_spectral *spectral = NULL; 3751 3752 spectral = get_target_if_spectral_handle_from_pdev(pdev); 3753 msg = (struct spectral_samp_msg *)spectral->nl_cb.get_sbuff( 3754 spectral->pdev_obj, 3755 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION, 3756 SPECTRAL_MSG_BUF_NEW); 3757 3758 if (msg) { 3759 msg->int_type = cw_int ? 3760 SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI; 3761 msg->dcs_enabled = dcs_enabled; 3762 msg->signature = SPECTRAL_SIGNATURE; 3763 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); 3764 p_sops->get_mac_address(spectral, msg->macaddr); 3765 if (spectral->send_phy_data 3766 (pdev, 3767 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION) == 0) 3768 spectral->spectral_sent_msg++; 3769 } 3770 } 3771 qdf_export_symbol(target_if_spectral_send_intf_found_msg); 3772