xref: /wlan-dirver/qca-wifi-host-cmn/spectral/core/spectral_common.c (revision bea437e2293c3d4fb1b5704fcf633aedac996962)
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 	case SPECTRAL_SET_DMA_DEBUG:
475 		if (sc->sptrlc_set_dma_debug)
476 			sc->sptrlc_set_dma_debug(
477 			     pdev,
478 			     sscan_req->dma_debug_req.dma_debug_type,
479 			     sscan_req->dma_debug_req.dma_debug_enable);
480 		break;
481 
482 	default:
483 		goto bad;
484 		break;
485 	}
486 
487 	status = QDF_STATUS_SUCCESS;
488 bad:
489 	return status;
490 }
491 
492 /**
493  * spectral_ctx_deinit() - De-initialize function pointers from spectral context
494  * @sc - Reference to spectral_context object
495  *
496  * Return: None
497  */
498 static void
499 spectral_ctx_deinit(struct spectral_context *sc)
500 {
501 	if (sc) {
502 		sc->sptrlc_ucfg_phyerr_config = NULL;
503 		sc->sptrlc_pdev_spectral_init = NULL;
504 		sc->sptrlc_pdev_spectral_deinit = NULL;
505 		sc->sptrlc_set_spectral_config = NULL;
506 		sc->sptrlc_get_spectral_config = NULL;
507 		sc->sptrlc_start_spectral_scan = NULL;
508 		sc->sptrlc_stop_spectral_scan = NULL;
509 		sc->sptrlc_is_spectral_active = NULL;
510 		sc->sptrlc_is_spectral_enabled = NULL;
511 		sc->sptrlc_set_debug_level = NULL;
512 		sc->sptrlc_get_debug_level = NULL;
513 		sc->sptrlc_get_spectral_capinfo = NULL;
514 		sc->sptrlc_get_spectral_diagstats = NULL;
515 	}
516 }
517 
518 #ifdef DA_SUPPORT
519 /**
520  * wlan_spectral_init_da() - init context of DA devices
521  *
522  * init context of DA device
523  *
524  * Return: void
525  */
526 static void
527 wlan_spectral_init_da(struct spectral_context *sc)
528 {
529 	spectral_ctx_init_da(sc);
530 }
531 #else
532 static void
533 wlan_spectral_init_da(struct spectral_context *sc)
534 {
535 }
536 #endif
537 
538 QDF_STATUS
539 wlan_spectral_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
540 {
541 	struct spectral_context *sc = NULL;
542 
543 	if (!psoc) {
544 		spectral_err("PSOC is NULL");
545 		return QDF_STATUS_E_FAILURE;
546 	}
547 
548 	if (cfg_get(psoc, CFG_SPECTRAL_DISABLE)) {
549 		wlan_psoc_nif_feat_cap_set(psoc, WLAN_SOC_F_SPECTRAL_DISABLE);
550 		spectral_info("Spectral is disabled");
551 		return QDF_STATUS_COMP_DISABLED;
552 	}
553 
554 	sc = (struct spectral_context *)
555 	    qdf_mem_malloc(sizeof(struct spectral_context));
556 	if (!sc)
557 		return QDF_STATUS_E_NOMEM;
558 
559 	qdf_mem_zero(sc, sizeof(struct spectral_context));
560 	sc->psoc_obj = psoc;
561 	if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL)
562 		spectral_ctx_init_ol(sc);
563 	else if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_DA)
564 		wlan_spectral_init_da(sc);
565 	wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_SPECTRAL,
566 					      (void *)sc, QDF_STATUS_SUCCESS);
567 
568 	return QDF_STATUS_SUCCESS;
569 }
570 
571 QDF_STATUS
572 wlan_spectral_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc,
573 				       void *arg)
574 {
575 	struct spectral_context *sc = NULL;
576 
577 	if (!psoc) {
578 		spectral_err("PSOC is NULL");
579 		return QDF_STATUS_E_FAILURE;
580 	}
581 
582 	if (wlan_spectral_is_feature_disabled(psoc)) {
583 		spectral_info("Spectral is disabled");
584 		return QDF_STATUS_COMP_DISABLED;
585 	}
586 
587 	sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
588 						   WLAN_UMAC_COMP_SPECTRAL);
589 	if (sc) {
590 		wlan_objmgr_psoc_component_obj_detach(psoc,
591 						      WLAN_UMAC_COMP_SPECTRAL,
592 						      (void *)sc);
593 		/* Deinitilise function pointers from spectral context */
594 		spectral_ctx_deinit(sc);
595 		qdf_mem_free(sc);
596 	}
597 
598 	return QDF_STATUS_SUCCESS;
599 }
600 
601 QDF_STATUS
602 wlan_spectral_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
603 {
604 	struct pdev_spectral *ps = NULL;
605 	struct spectral_context *sc = NULL;
606 	void *target_handle = NULL;
607 
608 	if (!pdev) {
609 		spectral_err("PDEV is NULL");
610 		return QDF_STATUS_E_FAILURE;
611 	}
612 
613 	if (wlan_spectral_is_feature_disabled(wlan_pdev_get_psoc(pdev))) {
614 		spectral_info("Spectral is disabled");
615 		return QDF_STATUS_COMP_DISABLED;
616 	}
617 
618 	ps = (struct pdev_spectral *)
619 	    qdf_mem_malloc(sizeof(struct pdev_spectral));
620 	if (!ps)
621 		return QDF_STATUS_E_NOMEM;
622 
623 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
624 	if (!sc) {
625 		spectral_err("Spectral context is NULL!");
626 		goto cleanup;
627 	}
628 
629 	qdf_mem_zero(ps, sizeof(struct pdev_spectral));
630 	ps->psptrl_pdev = pdev;
631 
632 	spectral_register_cfg80211_handlers(pdev);
633 	if (sc->sptrlc_pdev_spectral_init) {
634 		target_handle = sc->sptrlc_pdev_spectral_init(pdev);
635 		if (!target_handle) {
636 			spectral_err("Spectral lmac object is NULL!");
637 			goto cleanup;
638 		}
639 		ps->psptrl_target_handle = target_handle;
640 	}
641 	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_SPECTRAL,
642 					      (void *)ps, QDF_STATUS_SUCCESS);
643 
644 	return QDF_STATUS_SUCCESS;
645  cleanup:
646 	qdf_mem_free(ps);
647 	return QDF_STATUS_E_FAILURE;
648 }
649 
650 QDF_STATUS
651 wlan_spectral_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev,
652 				       void *arg)
653 {
654 	struct pdev_spectral *ps = NULL;
655 	struct spectral_context *sc = NULL;
656 
657 	if (!pdev) {
658 		spectral_err("PDEV is NULL");
659 		return QDF_STATUS_E_FAILURE;
660 	}
661 
662 	if (wlan_spectral_is_feature_disabled(wlan_pdev_get_psoc(pdev))) {
663 		spectral_info("Spectral is disabled");
664 		return QDF_STATUS_COMP_DISABLED;
665 	}
666 
667 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
668 	if (!sc) {
669 		spectral_err("Spectral context is NULL!");
670 		return QDF_STATUS_E_FAILURE;
671 	}
672 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
673 						   WLAN_UMAC_COMP_SPECTRAL);
674 	if (ps) {
675 		if (sc->sptrlc_pdev_spectral_deinit)
676 			sc->sptrlc_pdev_spectral_deinit(pdev);
677 		ps->psptrl_target_handle = NULL;
678 		wlan_objmgr_pdev_component_obj_detach(pdev,
679 						      WLAN_UMAC_COMP_SPECTRAL,
680 						      (void *)ps);
681 		qdf_mem_free(ps);
682 	}
683 
684 	return QDF_STATUS_SUCCESS;
685 }
686