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