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