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 "spectral_cmn_api_i.h" 21 #include "spectral_ol_api_i.h" 22 #include <qdf_mem.h> 23 #include <qdf_types.h> 24 #ifdef DA_SUPPORT 25 #include "spectral_da_api_i.h" 26 #endif 27 #include <wlan_spectral_public_structs.h> 28 #include <wlan_cfg80211_spectral.h> 29 #include <cfg_ucfg_api.h> 30 31 /** 32 * spectral_get_vdev() - Get pointer to vdev to be used for Spectral 33 * operations 34 * @pdev: Pointer to pdev 35 * 36 * Spectral operates on pdev. However, in order to retrieve some WLAN 37 * properties, a vdev is required. To facilitate this, the function returns the 38 * first vdev in our pdev. The caller should release the reference to the vdev 39 * once it is done using it. Additionally, the caller should ensure it has a 40 * reference to the pdev at the time of calling this function, and should 41 * release the pdev reference either after this function returns or at a later 42 * time when the caller is done using pdev. 43 * TODO: 44 * - If the framework later provides an API to obtain the first active 45 * vdev, then it would be preferable to use this API. 46 * - Use a common get_vdev() handler for core and target_if using Rx ops. This 47 * is deferred till details emerge on framework providing API to get first 48 * active vdev. 49 * 50 * Return: Pointer to vdev on success, NULL on failure 51 */ 52 static struct wlan_objmgr_vdev* 53 spectral_get_vdev(struct wlan_objmgr_pdev *pdev) 54 { 55 struct wlan_objmgr_vdev *vdev = NULL; 56 57 qdf_assert_always(pdev); 58 59 vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID); 60 61 if (!vdev) { 62 spectral_warn("Unable to get first vdev of pdev"); 63 return NULL; 64 } 65 66 return vdev; 67 } 68 69 #ifdef SPECTRAL_MODULIZED_ENABLE 70 /** 71 * spectral_register_cfg80211_handlers() - Register spectral cfg80211 handlers 72 * @pdev: Pointer to pdev 73 * 74 * Register spectral cfg80211 handlers 75 * Handlers can be different depending on whether spectral modulized or not 76 * 77 * Return: None 78 */ 79 static void 80 spectral_register_cfg80211_handlers(struct wlan_objmgr_pdev *pdev) 81 { 82 wlan_cfg80211_register_spectral_cmd_handler( 83 pdev, 84 SPECTRAL_SCAN_START_HANDLER_IDX, 85 wlan_cfg80211_spectral_scan_config_and_start); 86 wlan_cfg80211_register_spectral_cmd_handler( 87 pdev, 88 SPECTRAL_SCAN_STOP_HANDLER_IDX, 89 wlan_cfg80211_spectral_scan_stop); 90 wlan_cfg80211_register_spectral_cmd_handler( 91 pdev, 92 SPECTRAL_SCAN_GET_CONFIG_HANDLER_IDX, 93 wlan_cfg80211_spectral_scan_get_config); 94 wlan_cfg80211_register_spectral_cmd_handler( 95 pdev, 96 SPECTRAL_SCAN_GET_DIAG_STATS_HANDLER_IDX, 97 wlan_cfg80211_spectral_scan_get_diag_stats); 98 wlan_cfg80211_register_spectral_cmd_handler( 99 pdev, 100 SPECTRAL_SCAN_GET_CAP_HANDLER_IDX, 101 wlan_cfg80211_spectral_scan_get_cap); 102 wlan_cfg80211_register_spectral_cmd_handler( 103 pdev, 104 SPECTRAL_SCAN_GET_STATUS_HANDLER_IDX, 105 wlan_cfg80211_spectral_scan_get_status); 106 } 107 #else 108 static void 109 spectral_register_cfg80211_handlers(struct wlan_objmgr_pdev *pdev) 110 { 111 } 112 #endif 113 114 QDF_STATUS 115 spectral_control_cmn(struct wlan_objmgr_pdev *pdev, 116 struct spectral_cp_request *sscan_req) 117 { 118 QDF_STATUS status = QDF_STATUS_E_FAILURE; 119 int temp_debug; 120 struct spectral_config sp_out; 121 struct spectral_config *sp_in; 122 struct spectral_config *spectralparams; 123 struct spectral_context *sc; 124 struct wlan_objmgr_vdev *vdev = NULL; 125 uint8_t vdev_rxchainmask = 0; 126 enum spectral_scan_mode smode = sscan_req->ss_mode; 127 enum spectral_cp_error_code *err; 128 QDF_STATUS ret; 129 130 if (!pdev) { 131 spectral_err("PDEV is NULL!"); 132 goto bad; 133 } 134 sc = spectral_get_spectral_ctx_from_pdev(pdev); 135 if (!sc) { 136 spectral_err("Spectral context is NULL!"); 137 goto bad; 138 } 139 140 switch (sscan_req->req_id) { 141 case SPECTRAL_SET_CONFIG: 142 err = &sscan_req->config_req.sscan_err_code; 143 sp_in = &sscan_req->config_req.sscan_config; 144 if (sp_in->ss_count != SPECTRAL_PHYERR_PARAM_NOVAL) { 145 ret = sc->sptrlc_set_spectral_config 146 (pdev, 147 SPECTRAL_PARAM_SCAN_COUNT, 148 sp_in->ss_count, smode, err); 149 if (QDF_IS_STATUS_ERROR(ret)) 150 goto bad; 151 } 152 153 if (sp_in->ss_fft_period != SPECTRAL_PHYERR_PARAM_NOVAL) { 154 ret = sc->sptrlc_set_spectral_config 155 (pdev, 156 SPECTRAL_PARAM_FFT_PERIOD, 157 sp_in->ss_fft_period, 158 smode, err); 159 if (QDF_IS_STATUS_ERROR(ret)) 160 goto bad; 161 } 162 163 if (sp_in->ss_period != SPECTRAL_PHYERR_PARAM_NOVAL) { 164 ret = sc->sptrlc_set_spectral_config 165 (pdev, 166 SPECTRAL_PARAM_SCAN_PERIOD, 167 sp_in->ss_period, smode, err); 168 if (QDF_IS_STATUS_ERROR(ret)) 169 goto bad; 170 } 171 172 if (sp_in->ss_short_report != SPECTRAL_PHYERR_PARAM_NOVAL) { 173 ret = sc->sptrlc_set_spectral_config 174 (pdev, 175 SPECTRAL_PARAM_SHORT_REPORT, 176 (uint32_t) 177 sp_in->ss_short_report ? 1 : 0, 178 smode, err); 179 if (QDF_IS_STATUS_ERROR(ret)) 180 goto bad; 181 } 182 183 if (sp_in->ss_spectral_pri != SPECTRAL_PHYERR_PARAM_NOVAL) { 184 ret = sc->sptrlc_set_spectral_config 185 (pdev, 186 SPECTRAL_PARAM_SPECT_PRI, 187 (uint32_t) 188 (sp_in->ss_spectral_pri), 189 smode, err); 190 if (QDF_IS_STATUS_ERROR(ret)) 191 goto bad; 192 } 193 194 if (sp_in->ss_fft_size != SPECTRAL_PHYERR_PARAM_NOVAL) { 195 ret = sc->sptrlc_set_spectral_config 196 (pdev, 197 SPECTRAL_PARAM_FFT_SIZE, 198 sp_in->ss_fft_size, 199 smode, err); 200 if (QDF_IS_STATUS_ERROR(ret)) 201 goto bad; 202 } 203 204 if (sp_in->ss_gc_ena != SPECTRAL_PHYERR_PARAM_NOVAL) { 205 ret = sc->sptrlc_set_spectral_config 206 (pdev, 207 SPECTRAL_PARAM_GC_ENA, 208 sp_in->ss_gc_ena, 209 smode, err); 210 if (QDF_IS_STATUS_ERROR(ret)) 211 goto bad; 212 } 213 214 if (sp_in->ss_restart_ena != SPECTRAL_PHYERR_PARAM_NOVAL) { 215 ret = sc->sptrlc_set_spectral_config 216 (pdev, 217 SPECTRAL_PARAM_RESTART_ENA, 218 sp_in->ss_restart_ena, 219 smode, err); 220 if (QDF_IS_STATUS_ERROR(ret)) 221 goto bad; 222 } 223 224 if (sp_in->ss_noise_floor_ref != SPECTRAL_PHYERR_PARAM_NOVAL) { 225 ret = sc->sptrlc_set_spectral_config 226 (pdev, 227 SPECTRAL_PARAM_NOISE_FLOOR_REF, 228 sp_in->ss_noise_floor_ref, 229 smode, err); 230 if (QDF_IS_STATUS_ERROR(ret)) 231 goto bad; 232 } 233 234 if (sp_in->ss_init_delay != SPECTRAL_PHYERR_PARAM_NOVAL) { 235 ret = sc->sptrlc_set_spectral_config 236 (pdev, 237 SPECTRAL_PARAM_INIT_DELAY, 238 sp_in->ss_init_delay, 239 smode, err); 240 if (QDF_IS_STATUS_ERROR(ret)) 241 goto bad; 242 } 243 244 if (sp_in->ss_nb_tone_thr != SPECTRAL_PHYERR_PARAM_NOVAL) { 245 ret = sc->sptrlc_set_spectral_config 246 (pdev, 247 SPECTRAL_PARAM_NB_TONE_THR, 248 sp_in->ss_nb_tone_thr, 249 smode, err); 250 if (QDF_IS_STATUS_ERROR(ret)) 251 goto bad; 252 } 253 254 if (sp_in->ss_str_bin_thr != SPECTRAL_PHYERR_PARAM_NOVAL) { 255 ret = sc->sptrlc_set_spectral_config 256 (pdev, 257 SPECTRAL_PARAM_STR_BIN_THR, 258 sp_in->ss_str_bin_thr, 259 smode, err); 260 if (QDF_IS_STATUS_ERROR(ret)) 261 goto bad; 262 } 263 264 if (sp_in->ss_wb_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) { 265 ret = sc->sptrlc_set_spectral_config 266 (pdev, 267 SPECTRAL_PARAM_WB_RPT_MODE, 268 sp_in->ss_wb_rpt_mode, 269 smode, err); 270 if (QDF_IS_STATUS_ERROR(ret)) 271 goto bad; 272 } 273 274 if (sp_in->ss_rssi_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) { 275 ret = sc->sptrlc_set_spectral_config 276 (pdev, 277 SPECTRAL_PARAM_RSSI_RPT_MODE, 278 sp_in->ss_rssi_rpt_mode, 279 smode, err); 280 if (QDF_IS_STATUS_ERROR(ret)) 281 goto bad; 282 } 283 284 if (sp_in->ss_rssi_thr != SPECTRAL_PHYERR_PARAM_NOVAL) { 285 ret = sc->sptrlc_set_spectral_config 286 (pdev, 287 SPECTRAL_PARAM_RSSI_THR, 288 sp_in->ss_rssi_thr, 289 smode, err); 290 if (QDF_IS_STATUS_ERROR(ret)) 291 goto bad; 292 } 293 294 if (sp_in->ss_pwr_format != SPECTRAL_PHYERR_PARAM_NOVAL) { 295 ret = sc->sptrlc_set_spectral_config 296 (pdev, 297 SPECTRAL_PARAM_PWR_FORMAT, 298 sp_in->ss_pwr_format, 299 smode, err); 300 if (QDF_IS_STATUS_ERROR(ret)) 301 goto bad; 302 } 303 304 if (sp_in->ss_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) { 305 ret = sc->sptrlc_set_spectral_config 306 (pdev, 307 SPECTRAL_PARAM_RPT_MODE, 308 sp_in->ss_rpt_mode, 309 smode, err); 310 if (QDF_IS_STATUS_ERROR(ret)) 311 goto bad; 312 } 313 314 if (sp_in->ss_bin_scale != SPECTRAL_PHYERR_PARAM_NOVAL) { 315 ret = sc->sptrlc_set_spectral_config 316 (pdev, 317 SPECTRAL_PARAM_BIN_SCALE, 318 sp_in->ss_bin_scale, 319 smode, err); 320 if (QDF_IS_STATUS_ERROR(ret)) 321 goto bad; 322 } 323 324 if (sp_in->ss_dbm_adj != SPECTRAL_PHYERR_PARAM_NOVAL) { 325 ret = sc->sptrlc_set_spectral_config 326 (pdev, 327 SPECTRAL_PARAM_DBM_ADJ, 328 sp_in->ss_dbm_adj, 329 smode, err); 330 if (QDF_IS_STATUS_ERROR(ret)) 331 goto bad; 332 } 333 334 if (sp_in->ss_chn_mask != SPECTRAL_PHYERR_PARAM_NOVAL) { 335 /* 336 * Check if any of the inactive Rx antenna 337 * chains is set active in spectral chainmask 338 */ 339 vdev = spectral_get_vdev(pdev); 340 if (!vdev) 341 goto bad; 342 343 vdev_rxchainmask = 344 wlan_vdev_mlme_get_rxchainmask(vdev); 345 wlan_objmgr_vdev_release_ref(vdev, 346 WLAN_SPECTRAL_ID); 347 348 if (!(sp_in->ss_chn_mask & vdev_rxchainmask)) { 349 spectral_err("Invalid Spectral Chainmask - Inactive Rx antenna chain cannot be an active spectral chain"); 350 goto bad; 351 } else { 352 ret = sc->sptrlc_set_spectral_config 353 (pdev, 354 SPECTRAL_PARAM_CHN_MASK, 355 sp_in->ss_chn_mask, 356 smode, err); 357 if (QDF_IS_STATUS_ERROR(ret)) 358 goto bad; 359 } 360 } 361 362 if (sp_in->ss_frequency != SPECTRAL_PHYERR_PARAM_NOVAL) { 363 ret = sc->sptrlc_set_spectral_config 364 (pdev, 365 SPECTRAL_PARAM_FREQUENCY, 366 sp_in->ss_frequency, 367 smode, err); 368 if (QDF_IS_STATUS_ERROR(ret)) 369 goto bad; 370 } 371 372 break; 373 374 case SPECTRAL_GET_CONFIG: 375 sc->sptrlc_get_spectral_config(pdev, &sp_out, smode); 376 spectralparams = &sscan_req->config_req.sscan_config; 377 spectralparams->ss_fft_period = sp_out.ss_fft_period; 378 spectralparams->ss_period = sp_out.ss_period; 379 spectralparams->ss_count = sp_out.ss_count; 380 spectralparams->ss_short_report = 381 sp_out.ss_short_report; 382 spectralparams->ss_spectral_pri = 383 sp_out.ss_spectral_pri; 384 spectralparams->ss_fft_size = sp_out.ss_fft_size; 385 spectralparams->ss_gc_ena = sp_out.ss_gc_ena; 386 spectralparams->ss_restart_ena = sp_out.ss_restart_ena; 387 spectralparams->ss_noise_floor_ref = 388 sp_out.ss_noise_floor_ref; 389 spectralparams->ss_init_delay = sp_out.ss_init_delay; 390 spectralparams->ss_nb_tone_thr = sp_out.ss_nb_tone_thr; 391 spectralparams->ss_str_bin_thr = sp_out.ss_str_bin_thr; 392 spectralparams->ss_wb_rpt_mode = sp_out.ss_wb_rpt_mode; 393 spectralparams->ss_rssi_rpt_mode = 394 sp_out.ss_rssi_rpt_mode; 395 spectralparams->ss_rssi_thr = sp_out.ss_rssi_thr; 396 spectralparams->ss_pwr_format = sp_out.ss_pwr_format; 397 spectralparams->ss_rpt_mode = sp_out.ss_rpt_mode; 398 spectralparams->ss_bin_scale = sp_out.ss_bin_scale; 399 spectralparams->ss_dbm_adj = sp_out.ss_dbm_adj; 400 spectralparams->ss_chn_mask = sp_out.ss_chn_mask; 401 spectralparams->ss_frequency = sp_out.ss_frequency; 402 break; 403 404 case SPECTRAL_IS_ACTIVE: 405 sscan_req->status_req.is_active = 406 sc->sptrlc_is_spectral_active(pdev, 407 smode); 408 break; 409 410 case SPECTRAL_IS_ENABLED: 411 sscan_req->status_req.is_enabled = 412 sc->sptrlc_is_spectral_enabled(pdev, 413 smode); 414 break; 415 416 case SPECTRAL_SET_DEBUG_LEVEL: 417 temp_debug = sscan_req->debug_req.spectral_dbg_level; 418 sc->sptrlc_set_debug_level(pdev, temp_debug); 419 break; 420 421 case SPECTRAL_GET_DEBUG_LEVEL: 422 sscan_req->debug_req.spectral_dbg_level = 423 sc->sptrlc_get_debug_level(pdev); 424 break; 425 426 case SPECTRAL_ACTIVATE_SCAN: 427 err = &sscan_req->action_req.sscan_err_code; 428 ret = sc->sptrlc_start_spectral_scan(pdev, smode, err); 429 if (QDF_IS_STATUS_ERROR(ret)) 430 goto bad; 431 break; 432 433 case SPECTRAL_STOP_SCAN: 434 err = &sscan_req->action_req.sscan_err_code; 435 ret = sc->sptrlc_stop_spectral_scan(pdev, smode, err); 436 if (QDF_IS_STATUS_ERROR(ret)) 437 goto bad; 438 break; 439 440 case SPECTRAL_GET_CAPABILITY_INFO: 441 { 442 struct spectral_caps *caps; 443 444 caps = &sscan_req->caps_req.sscan_caps; 445 sc->sptrlc_get_spectral_capinfo(pdev, caps); 446 } 447 break; 448 449 case SPECTRAL_GET_DIAG_STATS: 450 { 451 struct spectral_diag_stats *diag; 452 453 diag = &sscan_req->diag_req.sscan_diag; 454 sc->sptrlc_get_spectral_diagstats(pdev, diag); 455 } 456 break; 457 458 case SPECTRAL_GET_CHAN_WIDTH: 459 { 460 uint32_t chan_width; 461 462 vdev = spectral_get_vdev(pdev); 463 if (!vdev) 464 goto bad; 465 466 chan_width = spectral_vdev_get_ch_width(vdev); 467 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 468 469 sscan_req->chan_width_req.chan_width = 470 (uint32_t)chan_width; 471 } 472 break; 473 474 default: 475 goto bad; 476 break; 477 } 478 479 status = QDF_STATUS_SUCCESS; 480 bad: 481 return status; 482 } 483 484 /** 485 * spectral_ctx_deinit() - De-initialize function pointers from spectral context 486 * @sc - Reference to spectral_context object 487 * 488 * Return: None 489 */ 490 static void 491 spectral_ctx_deinit(struct spectral_context *sc) 492 { 493 if (sc) { 494 sc->sptrlc_ucfg_phyerr_config = NULL; 495 sc->sptrlc_pdev_spectral_init = NULL; 496 sc->sptrlc_pdev_spectral_deinit = NULL; 497 sc->sptrlc_set_spectral_config = NULL; 498 sc->sptrlc_get_spectral_config = NULL; 499 sc->sptrlc_start_spectral_scan = NULL; 500 sc->sptrlc_stop_spectral_scan = NULL; 501 sc->sptrlc_is_spectral_active = NULL; 502 sc->sptrlc_is_spectral_enabled = NULL; 503 sc->sptrlc_set_debug_level = NULL; 504 sc->sptrlc_get_debug_level = NULL; 505 sc->sptrlc_get_spectral_capinfo = NULL; 506 sc->sptrlc_get_spectral_diagstats = NULL; 507 } 508 } 509 510 #ifdef DA_SUPPORT 511 /** 512 * wlan_spectral_init_da() - init context of DA devices 513 * 514 * init context of DA device 515 * 516 * Return: void 517 */ 518 static void 519 wlan_spectral_init_da(struct spectral_context *sc) 520 { 521 spectral_ctx_init_da(sc); 522 } 523 #else 524 static void 525 wlan_spectral_init_da(struct spectral_context *sc) 526 { 527 } 528 #endif 529 530 QDF_STATUS 531 wlan_spectral_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg) 532 { 533 struct spectral_context *sc = NULL; 534 535 if (!psoc) { 536 spectral_err("PSOC is NULL"); 537 return QDF_STATUS_E_FAILURE; 538 } 539 540 if (cfg_get(psoc, CFG_SPECTRAL_DISABLE)) { 541 wlan_psoc_nif_feat_cap_set(psoc, WLAN_SOC_F_SPECTRAL_DISABLE); 542 spectral_info("Spectral is disabled"); 543 return QDF_STATUS_COMP_DISABLED; 544 } 545 546 sc = (struct spectral_context *) 547 qdf_mem_malloc(sizeof(struct spectral_context)); 548 if (!sc) 549 return QDF_STATUS_E_NOMEM; 550 551 qdf_mem_zero(sc, sizeof(struct spectral_context)); 552 sc->psoc_obj = psoc; 553 if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL) 554 spectral_ctx_init_ol(sc); 555 else if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_DA) 556 wlan_spectral_init_da(sc); 557 wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_SPECTRAL, 558 (void *)sc, QDF_STATUS_SUCCESS); 559 560 return QDF_STATUS_SUCCESS; 561 } 562 563 QDF_STATUS 564 wlan_spectral_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, 565 void *arg) 566 { 567 struct spectral_context *sc = NULL; 568 569 if (!psoc) { 570 spectral_err("PSOC is NULL"); 571 return QDF_STATUS_E_FAILURE; 572 } 573 574 if (wlan_spectral_is_feature_disabled(psoc)) { 575 spectral_info("Spectral is disabled"); 576 return QDF_STATUS_COMP_DISABLED; 577 } 578 579 sc = wlan_objmgr_psoc_get_comp_private_obj(psoc, 580 WLAN_UMAC_COMP_SPECTRAL); 581 if (sc) { 582 wlan_objmgr_psoc_component_obj_detach(psoc, 583 WLAN_UMAC_COMP_SPECTRAL, 584 (void *)sc); 585 /* Deinitilise function pointers from spectral context */ 586 spectral_ctx_deinit(sc); 587 qdf_mem_free(sc); 588 } 589 590 return QDF_STATUS_SUCCESS; 591 } 592 593 QDF_STATUS 594 wlan_spectral_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg) 595 { 596 struct pdev_spectral *ps = NULL; 597 struct spectral_context *sc = NULL; 598 void *target_handle = NULL; 599 600 if (!pdev) { 601 spectral_err("PDEV is NULL"); 602 return QDF_STATUS_E_FAILURE; 603 } 604 605 if (wlan_spectral_is_feature_disabled(wlan_pdev_get_psoc(pdev))) { 606 spectral_info("Spectral is disabled"); 607 return QDF_STATUS_COMP_DISABLED; 608 } 609 610 ps = (struct pdev_spectral *) 611 qdf_mem_malloc(sizeof(struct pdev_spectral)); 612 if (!ps) 613 return QDF_STATUS_E_NOMEM; 614 615 sc = spectral_get_spectral_ctx_from_pdev(pdev); 616 if (!sc) { 617 spectral_err("Spectral context is NULL!"); 618 goto cleanup; 619 } 620 621 qdf_mem_zero(ps, sizeof(struct pdev_spectral)); 622 ps->psptrl_pdev = pdev; 623 624 spectral_register_cfg80211_handlers(pdev); 625 if (sc->sptrlc_pdev_spectral_init) { 626 target_handle = sc->sptrlc_pdev_spectral_init(pdev); 627 if (!target_handle) { 628 spectral_err("Spectral lmac object is NULL!"); 629 goto cleanup; 630 } 631 ps->psptrl_target_handle = target_handle; 632 } 633 wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_SPECTRAL, 634 (void *)ps, QDF_STATUS_SUCCESS); 635 636 return QDF_STATUS_SUCCESS; 637 cleanup: 638 qdf_mem_free(ps); 639 return QDF_STATUS_E_FAILURE; 640 } 641 642 QDF_STATUS 643 wlan_spectral_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, 644 void *arg) 645 { 646 struct pdev_spectral *ps = NULL; 647 struct spectral_context *sc = NULL; 648 649 if (!pdev) { 650 spectral_err("PDEV is NULL"); 651 return QDF_STATUS_E_FAILURE; 652 } 653 654 if (wlan_spectral_is_feature_disabled(wlan_pdev_get_psoc(pdev))) { 655 spectral_info("Spectral is disabled"); 656 return QDF_STATUS_COMP_DISABLED; 657 } 658 659 sc = spectral_get_spectral_ctx_from_pdev(pdev); 660 if (!sc) { 661 spectral_err("Spectral context is NULL!"); 662 return QDF_STATUS_E_FAILURE; 663 } 664 ps = wlan_objmgr_pdev_get_comp_private_obj(pdev, 665 WLAN_UMAC_COMP_SPECTRAL); 666 if (ps) { 667 if (sc->sptrlc_pdev_spectral_deinit) 668 sc->sptrlc_pdev_spectral_deinit(pdev); 669 ps->psptrl_target_handle = NULL; 670 wlan_objmgr_pdev_component_obj_detach(pdev, 671 WLAN_UMAC_COMP_SPECTRAL, 672 (void *)ps); 673 qdf_mem_free(ps); 674 } 675 676 return QDF_STATUS_SUCCESS; 677 } 678