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