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