xref: /wlan-dirver/qca-wifi-host-cmn/spectral/core/spectral_common.c (revision 861af9fad3d20cded5a90c420dd1ed901be32691)
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 #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 	struct spectral_cp_param param;
130 
131 	if (!pdev) {
132 		spectral_err("PDEV is NULL!");
133 		goto bad;
134 	}
135 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
136 	if (!sc) {
137 		spectral_err("Spectral context is NULL!");
138 		goto bad;
139 	}
140 
141 	switch (sscan_req->req_id) {
142 	case SPECTRAL_SET_CONFIG:
143 		err =  &sscan_req->config_req.sscan_err_code;
144 		sp_in = &sscan_req->config_req.sscan_config;
145 		if (sp_in->ss_count != SPECTRAL_PHYERR_PARAM_NOVAL) {
146 			param.id = SPECTRAL_PARAM_SCAN_COUNT;
147 			param.value = sp_in->ss_count;
148 			ret = sc->sptrlc_set_spectral_config
149 						(pdev, &param, smode, err);
150 			if (QDF_IS_STATUS_ERROR(ret))
151 				goto bad;
152 		}
153 
154 		if (sp_in->ss_fft_period != SPECTRAL_PHYERR_PARAM_NOVAL) {
155 			param.id = SPECTRAL_PARAM_FFT_PERIOD;
156 			param.value = sp_in->ss_fft_period;
157 			ret = sc->sptrlc_set_spectral_config
158 						(pdev, &param, 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 			param.id = SPECTRAL_PARAM_SCAN_PERIOD;
165 			param.value = sp_in->ss_period;
166 			ret = sc->sptrlc_set_spectral_config
167 						(pdev, &param, 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 			param.id = SPECTRAL_PARAM_SHORT_REPORT;
174 			param.value = (uint32_t)sp_in->ss_short_report ? 1 : 0;
175 			ret = sc->sptrlc_set_spectral_config
176 						(pdev, &param, smode, err);
177 			if (QDF_IS_STATUS_ERROR(ret))
178 				goto bad;
179 		}
180 
181 		if (sp_in->ss_spectral_pri != SPECTRAL_PHYERR_PARAM_NOVAL) {
182 			param.id = SPECTRAL_PARAM_SPECT_PRI;
183 			param.value = (uint32_t)sp_in->ss_spectral_pri;
184 			ret = sc->sptrlc_set_spectral_config
185 						(pdev, &param, smode, err);
186 			if (QDF_IS_STATUS_ERROR(ret))
187 				goto bad;
188 		}
189 
190 		if (sp_in->ss_fft_size != SPECTRAL_PHYERR_PARAM_NOVAL) {
191 			param.id = SPECTRAL_PARAM_FFT_SIZE;
192 			param.value = sp_in->ss_fft_size;
193 			ret = sc->sptrlc_set_spectral_config
194 						(pdev, &param, smode, err);
195 			if (QDF_IS_STATUS_ERROR(ret))
196 				goto bad;
197 		}
198 
199 		if (sp_in->ss_gc_ena != SPECTRAL_PHYERR_PARAM_NOVAL) {
200 			param.id = SPECTRAL_PARAM_GC_ENA;
201 			param.value = sp_in->ss_gc_ena;
202 			ret = sc->sptrlc_set_spectral_config
203 						(pdev, &param, smode, err);
204 			if (QDF_IS_STATUS_ERROR(ret))
205 				goto bad;
206 		}
207 
208 		if (sp_in->ss_restart_ena != SPECTRAL_PHYERR_PARAM_NOVAL) {
209 			param.id = SPECTRAL_PARAM_RESTART_ENA;
210 			param.value = sp_in->ss_restart_ena;
211 			ret = sc->sptrlc_set_spectral_config
212 						(pdev, &param, smode, err);
213 			if (QDF_IS_STATUS_ERROR(ret))
214 				goto bad;
215 		}
216 
217 		if (sp_in->ss_noise_floor_ref != SPECTRAL_PHYERR_PARAM_NOVAL) {
218 			param.id = SPECTRAL_PARAM_NOISE_FLOOR_REF;
219 			param.value = sp_in->ss_noise_floor_ref;
220 			ret = sc->sptrlc_set_spectral_config
221 						(pdev, &param, smode, err);
222 			if (QDF_IS_STATUS_ERROR(ret))
223 				goto bad;
224 		}
225 
226 		if (sp_in->ss_init_delay != SPECTRAL_PHYERR_PARAM_NOVAL) {
227 			param.id = SPECTRAL_PARAM_INIT_DELAY;
228 			param.value = sp_in->ss_init_delay;
229 			ret = sc->sptrlc_set_spectral_config
230 						(pdev, &param, smode, err);
231 			if (QDF_IS_STATUS_ERROR(ret))
232 				goto bad;
233 		}
234 
235 		if (sp_in->ss_nb_tone_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
236 			param.id = SPECTRAL_PARAM_NB_TONE_THR;
237 			param.value = sp_in->ss_nb_tone_thr;
238 			ret = sc->sptrlc_set_spectral_config
239 						(pdev, &param, smode, err);
240 			if (QDF_IS_STATUS_ERROR(ret))
241 				goto bad;
242 		}
243 
244 		if (sp_in->ss_str_bin_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
245 			param.id = SPECTRAL_PARAM_STR_BIN_THR;
246 			param.value = sp_in->ss_str_bin_thr;
247 			ret = sc->sptrlc_set_spectral_config
248 						(pdev, &param, smode, err);
249 			if (QDF_IS_STATUS_ERROR(ret))
250 				goto bad;
251 		}
252 
253 		if (sp_in->ss_wb_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
254 			param.id = SPECTRAL_PARAM_WB_RPT_MODE;
255 			param.value = sp_in->ss_wb_rpt_mode;
256 			ret = sc->sptrlc_set_spectral_config
257 						(pdev, &param, smode, err);
258 			if (QDF_IS_STATUS_ERROR(ret))
259 				goto bad;
260 		}
261 
262 		if (sp_in->ss_rssi_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
263 			param.id = SPECTRAL_PARAM_RSSI_RPT_MODE;
264 			param.value = sp_in->ss_rssi_rpt_mode;
265 			ret = sc->sptrlc_set_spectral_config
266 						(pdev, &param, smode, err);
267 			if (QDF_IS_STATUS_ERROR(ret))
268 				goto bad;
269 		}
270 
271 		if (sp_in->ss_rssi_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
272 			param.id = SPECTRAL_PARAM_RSSI_THR;
273 			param.value = sp_in->ss_rssi_thr;
274 			ret = sc->sptrlc_set_spectral_config
275 						(pdev, &param, smode, err);
276 			if (QDF_IS_STATUS_ERROR(ret))
277 				goto bad;
278 		}
279 
280 		if (sp_in->ss_pwr_format != SPECTRAL_PHYERR_PARAM_NOVAL) {
281 			param.id = SPECTRAL_PARAM_PWR_FORMAT;
282 			param.value = sp_in->ss_pwr_format;
283 			ret = sc->sptrlc_set_spectral_config
284 						(pdev, &param, smode, err);
285 			if (QDF_IS_STATUS_ERROR(ret))
286 				goto bad;
287 		}
288 
289 		if (sp_in->ss_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
290 			param.id = SPECTRAL_PARAM_RPT_MODE;
291 			param.value = sp_in->ss_rpt_mode;
292 			ret = sc->sptrlc_set_spectral_config
293 						(pdev, &param, smode, err);
294 			if (QDF_IS_STATUS_ERROR(ret))
295 				goto bad;
296 		}
297 
298 		if (sp_in->ss_bin_scale != SPECTRAL_PHYERR_PARAM_NOVAL) {
299 			param.id = SPECTRAL_PARAM_BIN_SCALE;
300 			param.value = sp_in->ss_bin_scale;
301 			ret = sc->sptrlc_set_spectral_config
302 						(pdev, &param, smode, err);
303 			if (QDF_IS_STATUS_ERROR(ret))
304 				goto bad;
305 		}
306 
307 		if (sp_in->ss_dbm_adj != SPECTRAL_PHYERR_PARAM_NOVAL) {
308 			param.id = SPECTRAL_PARAM_DBM_ADJ;
309 			param.value = sp_in->ss_dbm_adj;
310 			ret = sc->sptrlc_set_spectral_config
311 						(pdev, &param, smode, err);
312 			if (QDF_IS_STATUS_ERROR(ret))
313 				goto bad;
314 		}
315 
316 		if (sp_in->ss_chn_mask != SPECTRAL_PHYERR_PARAM_NOVAL) {
317 			/*
318 			 * Check if any of the inactive Rx antenna
319 			 * chains is set active in spectral chainmask
320 			 */
321 			vdev = spectral_get_vdev(pdev);
322 			if (!vdev)
323 				goto bad;
324 
325 			vdev_rxchainmask =
326 			    wlan_vdev_mlme_get_rxchainmask(vdev);
327 			wlan_objmgr_vdev_release_ref(vdev,
328 						     WLAN_SPECTRAL_ID);
329 
330 			if (!(sp_in->ss_chn_mask & vdev_rxchainmask)) {
331 				spectral_err("Invalid Spectral Chainmask - Inactive Rx antenna chain cannot be an active spectral chain");
332 				goto bad;
333 			} else {
334 				param.id = SPECTRAL_PARAM_CHN_MASK;
335 				param.value = sp_in->ss_chn_mask;
336 				ret = sc->sptrlc_set_spectral_config
337 						(pdev, &param, smode, err);
338 				if (QDF_IS_STATUS_ERROR(ret))
339 					goto bad;
340 			}
341 		}
342 
343 		if (sp_in->ss_frequency.cfreq1 != SPECTRAL_PHYERR_PARAM_NOVAL) {
344 			param.id = SPECTRAL_PARAM_FREQUENCY;
345 			param.freq.cfreq1 = sp_in->ss_frequency.cfreq1;
346 			param.freq.cfreq2 = sp_in->ss_frequency.cfreq2;
347 			ret = sc->sptrlc_set_spectral_config
348 						(pdev, &param, smode, err);
349 			if (QDF_IS_STATUS_ERROR(ret))
350 				goto bad;
351 		}
352 
353 		break;
354 
355 	case SPECTRAL_GET_CONFIG:
356 		sc->sptrlc_get_spectral_config(pdev, &sp_out, smode);
357 		spectralparams = &sscan_req->config_req.sscan_config;
358 		spectralparams->ss_fft_period = sp_out.ss_fft_period;
359 		spectralparams->ss_period = sp_out.ss_period;
360 		spectralparams->ss_count = sp_out.ss_count;
361 		spectralparams->ss_short_report =
362 				sp_out.ss_short_report;
363 		spectralparams->ss_spectral_pri =
364 				sp_out.ss_spectral_pri;
365 		spectralparams->ss_fft_size = sp_out.ss_fft_size;
366 		spectralparams->ss_gc_ena = sp_out.ss_gc_ena;
367 		spectralparams->ss_restart_ena = sp_out.ss_restart_ena;
368 		spectralparams->ss_noise_floor_ref =
369 				sp_out.ss_noise_floor_ref;
370 		spectralparams->ss_init_delay = sp_out.ss_init_delay;
371 		spectralparams->ss_nb_tone_thr = sp_out.ss_nb_tone_thr;
372 		spectralparams->ss_str_bin_thr = sp_out.ss_str_bin_thr;
373 		spectralparams->ss_wb_rpt_mode = sp_out.ss_wb_rpt_mode;
374 		spectralparams->ss_rssi_rpt_mode =
375 				sp_out.ss_rssi_rpt_mode;
376 		spectralparams->ss_rssi_thr = sp_out.ss_rssi_thr;
377 		spectralparams->ss_pwr_format = sp_out.ss_pwr_format;
378 		spectralparams->ss_rpt_mode = sp_out.ss_rpt_mode;
379 		spectralparams->ss_bin_scale = sp_out.ss_bin_scale;
380 		spectralparams->ss_dbm_adj = sp_out.ss_dbm_adj;
381 		spectralparams->ss_chn_mask = sp_out.ss_chn_mask;
382 		spectralparams->ss_frequency = sp_out.ss_frequency;
383 		break;
384 
385 	case SPECTRAL_IS_ACTIVE:
386 		sscan_req->status_req.is_active =
387 					sc->sptrlc_is_spectral_active(pdev,
388 								      smode);
389 		break;
390 
391 	case SPECTRAL_IS_ENABLED:
392 		sscan_req->status_req.is_enabled =
393 					sc->sptrlc_is_spectral_enabled(pdev,
394 								       smode);
395 		break;
396 
397 	case SPECTRAL_SET_DEBUG_LEVEL:
398 		temp_debug = sscan_req->debug_req.spectral_dbg_level;
399 		sc->sptrlc_set_debug_level(pdev, temp_debug);
400 		break;
401 
402 	case SPECTRAL_GET_DEBUG_LEVEL:
403 		sscan_req->debug_req.spectral_dbg_level =
404 					sc->sptrlc_get_debug_level(pdev);
405 		break;
406 
407 	case SPECTRAL_ACTIVATE_SCAN:
408 		err = &sscan_req->action_req.sscan_err_code;
409 		ret = sc->sptrlc_start_spectral_scan(pdev, smode, err);
410 		if (QDF_IS_STATUS_ERROR(ret))
411 			goto bad;
412 		break;
413 
414 	case SPECTRAL_STOP_SCAN:
415 		err = &sscan_req->action_req.sscan_err_code;
416 		ret = sc->sptrlc_stop_spectral_scan(pdev, smode, err);
417 		if (QDF_IS_STATUS_ERROR(ret))
418 			goto bad;
419 		break;
420 
421 	case SPECTRAL_GET_CAPABILITY_INFO:
422 		{
423 			struct spectral_caps *caps;
424 
425 			caps  = &sscan_req->caps_req.sscan_caps;
426 			sc->sptrlc_get_spectral_capinfo(pdev, caps);
427 		}
428 		break;
429 
430 	case SPECTRAL_GET_DIAG_STATS:
431 		{
432 			struct spectral_diag_stats *diag;
433 
434 			diag  = &sscan_req->diag_req.sscan_diag;
435 			sc->sptrlc_get_spectral_diagstats(pdev, diag);
436 		}
437 		break;
438 
439 	case SPECTRAL_GET_CHAN_WIDTH:
440 		{
441 			uint32_t chan_width;
442 
443 			vdev = spectral_get_vdev(pdev);
444 			if (!vdev)
445 				goto bad;
446 
447 			chan_width = spectral_vdev_get_ch_width(vdev);
448 			wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
449 
450 			sscan_req->chan_width_req.chan_width =
451 							(uint32_t)chan_width;
452 		}
453 		break;
454 
455 	case SPECTRAL_SET_DMA_DEBUG:
456 		if (sc->sptrlc_set_dma_debug)
457 			sc->sptrlc_set_dma_debug(
458 			     pdev,
459 			     sscan_req->dma_debug_req.dma_debug_type,
460 			     sscan_req->dma_debug_req.dma_debug_enable);
461 		break;
462 
463 	default:
464 		goto bad;
465 		break;
466 	}
467 
468 	status = QDF_STATUS_SUCCESS;
469 bad:
470 	return status;
471 }
472 
473 /**
474  * spectral_ctx_deinit() - De-initialize function pointers from spectral context
475  * @sc - Reference to spectral_context object
476  *
477  * Return: None
478  */
479 static void
480 spectral_ctx_deinit(struct spectral_context *sc)
481 {
482 	if (sc) {
483 		sc->sptrlc_ucfg_phyerr_config = NULL;
484 		sc->sptrlc_pdev_spectral_init = NULL;
485 		sc->sptrlc_pdev_spectral_deinit = NULL;
486 		sc->sptrlc_set_spectral_config = NULL;
487 		sc->sptrlc_get_spectral_config = NULL;
488 		sc->sptrlc_start_spectral_scan = NULL;
489 		sc->sptrlc_stop_spectral_scan = NULL;
490 		sc->sptrlc_is_spectral_active = NULL;
491 		sc->sptrlc_is_spectral_enabled = NULL;
492 		sc->sptrlc_set_debug_level = NULL;
493 		sc->sptrlc_get_debug_level = NULL;
494 		sc->sptrlc_get_spectral_capinfo = NULL;
495 		sc->sptrlc_get_spectral_diagstats = NULL;
496 	}
497 }
498 
499 #ifdef DA_SUPPORT
500 /**
501  * wlan_spectral_init_da() - init context of DA devices
502  *
503  * init context of DA device
504  *
505  * Return: void
506  */
507 static void
508 wlan_spectral_init_da(struct spectral_context *sc)
509 {
510 	spectral_ctx_init_da(sc);
511 }
512 #else
513 static void
514 wlan_spectral_init_da(struct spectral_context *sc)
515 {
516 }
517 #endif
518 
519 QDF_STATUS
520 wlan_spectral_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
521 {
522 	struct spectral_context *sc = NULL;
523 
524 	if (!psoc) {
525 		spectral_err("PSOC is NULL");
526 		return QDF_STATUS_E_FAILURE;
527 	}
528 
529 	if (cfg_get(psoc, CFG_SPECTRAL_DISABLE)) {
530 		wlan_psoc_nif_feat_cap_set(psoc, WLAN_SOC_F_SPECTRAL_DISABLE);
531 		spectral_info("Spectral is disabled");
532 		return QDF_STATUS_COMP_DISABLED;
533 	}
534 
535 	sc = (struct spectral_context *)
536 	    qdf_mem_malloc(sizeof(struct spectral_context));
537 	if (!sc)
538 		return QDF_STATUS_E_NOMEM;
539 
540 	qdf_mem_zero(sc, sizeof(struct spectral_context));
541 	sc->psoc_obj = psoc;
542 	if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL)
543 		spectral_ctx_init_ol(sc);
544 	else if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_DA)
545 		wlan_spectral_init_da(sc);
546 	wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_SPECTRAL,
547 					      (void *)sc, QDF_STATUS_SUCCESS);
548 
549 	return QDF_STATUS_SUCCESS;
550 }
551 
552 QDF_STATUS
553 wlan_spectral_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc,
554 				       void *arg)
555 {
556 	struct spectral_context *sc = NULL;
557 
558 	if (!psoc) {
559 		spectral_err("PSOC is NULL");
560 		return QDF_STATUS_E_FAILURE;
561 	}
562 
563 	if (wlan_spectral_is_feature_disabled(psoc)) {
564 		spectral_info("Spectral is disabled");
565 		return QDF_STATUS_COMP_DISABLED;
566 	}
567 
568 	sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
569 						   WLAN_UMAC_COMP_SPECTRAL);
570 	if (sc) {
571 		wlan_objmgr_psoc_component_obj_detach(psoc,
572 						      WLAN_UMAC_COMP_SPECTRAL,
573 						      (void *)sc);
574 		/* Deinitilise function pointers from spectral context */
575 		spectral_ctx_deinit(sc);
576 		qdf_mem_free(sc);
577 	}
578 
579 	return QDF_STATUS_SUCCESS;
580 }
581 
582 QDF_STATUS
583 wlan_spectral_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
584 {
585 	struct pdev_spectral *ps = NULL;
586 	struct spectral_context *sc = NULL;
587 	void *target_handle = NULL;
588 
589 	if (!pdev) {
590 		spectral_err("PDEV is NULL");
591 		return QDF_STATUS_E_FAILURE;
592 	}
593 
594 	if (wlan_spectral_is_feature_disabled(wlan_pdev_get_psoc(pdev))) {
595 		spectral_info("Spectral is disabled");
596 		return QDF_STATUS_COMP_DISABLED;
597 	}
598 
599 	ps = (struct pdev_spectral *)
600 	    qdf_mem_malloc(sizeof(struct pdev_spectral));
601 	if (!ps)
602 		return QDF_STATUS_E_NOMEM;
603 
604 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
605 	if (!sc) {
606 		spectral_err("Spectral context is NULL!");
607 		goto cleanup;
608 	}
609 
610 	qdf_mem_zero(ps, sizeof(struct pdev_spectral));
611 	ps->psptrl_pdev = pdev;
612 
613 	spectral_register_cfg80211_handlers(pdev);
614 	if (sc->sptrlc_pdev_spectral_init) {
615 		target_handle = sc->sptrlc_pdev_spectral_init(pdev);
616 		if (!target_handle) {
617 			spectral_err("Spectral lmac object is NULL!");
618 			goto cleanup;
619 		}
620 		ps->psptrl_target_handle = target_handle;
621 	}
622 	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_SPECTRAL,
623 					      (void *)ps, QDF_STATUS_SUCCESS);
624 
625 	return QDF_STATUS_SUCCESS;
626  cleanup:
627 	qdf_mem_free(ps);
628 	return QDF_STATUS_E_FAILURE;
629 }
630 
631 QDF_STATUS
632 wlan_spectral_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev,
633 				       void *arg)
634 {
635 	struct pdev_spectral *ps = NULL;
636 	struct spectral_context *sc = NULL;
637 
638 	if (!pdev) {
639 		spectral_err("PDEV is NULL");
640 		return QDF_STATUS_E_FAILURE;
641 	}
642 
643 	if (wlan_spectral_is_feature_disabled(wlan_pdev_get_psoc(pdev))) {
644 		spectral_info("Spectral is disabled");
645 		return QDF_STATUS_COMP_DISABLED;
646 	}
647 
648 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
649 	if (!sc) {
650 		spectral_err("Spectral context is NULL!");
651 		return QDF_STATUS_E_FAILURE;
652 	}
653 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
654 						   WLAN_UMAC_COMP_SPECTRAL);
655 	if (ps) {
656 		if (sc->sptrlc_pdev_spectral_deinit)
657 			sc->sptrlc_pdev_spectral_deinit(pdev);
658 		ps->psptrl_target_handle = NULL;
659 		wlan_objmgr_pdev_component_obj_detach(pdev,
660 						      WLAN_UMAC_COMP_SPECTRAL,
661 						      (void *)ps);
662 		qdf_mem_free(ps);
663 	}
664 
665 	return QDF_STATUS_SUCCESS;
666 }
667