xref: /wlan-dirver/qca-wifi-host-cmn/spectral/core/spectral_common.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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