xref: /wlan-dirver/qca-wifi-host-cmn/spectral/core/spectral_common.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2011,2017-2018 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_da_api_i.h"
22 #include "spectral_ol_api_i.h"
23 #include <qdf_mem.h>
24 #include <qdf_types.h>
25 #ifdef CONFIG_WIN
26 #include <osif_private.h>
27 #include <wlan_mlme_dispatcher.h>
28 #endif /*CONFIG_WIN*/
29 #include <wlan_spectral_public_structs.h>
30 #include <wlan_cfg80211_spectral.h>
31 
32 /**
33  * spectral_get_vdev() - Get pointer to vdev to be used for Spectral
34  * operations
35  * @pdev: Pointer to pdev
36  *
37  * Spectral operates on pdev. However, in order to retrieve some WLAN
38  * properties, a vdev is required. To facilitate this, the function returns the
39  * first vdev in our pdev. The caller should release the reference to the vdev
40  * once it is done using it. Additionally, the caller should ensure it has a
41  * reference to the pdev at the time of calling this function, and should
42  * release the pdev reference either after this function returns or at a later
43  * time when the caller is done using pdev.
44  * TODO:
45  *  - If the framework later provides an API to obtain the first active
46  *    vdev, then it would be preferable to use this API.
47  *  - Use a common get_vdev() handler for core and target_if using Rx ops. This
48  *    is deferred till details emerge on framework providing API to get first
49  *    active vdev.
50  *
51  * Return: Pointer to vdev on success, NULL on failure
52  */
53 static struct wlan_objmgr_vdev*
54 spectral_get_vdev(struct wlan_objmgr_pdev *pdev)
55 {
56 	struct wlan_objmgr_vdev *vdev = NULL;
57 
58 	qdf_assert_always(pdev);
59 
60 	vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID);
61 
62 	if (!vdev) {
63 		spectral_warn("Unable to get first vdev of pdev");
64 		return NULL;
65 	}
66 
67 	return vdev;
68 }
69 
70 #ifndef CONFIG_MCL
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 for WIN and MCL
77  *
78  * Return: None
79  */
80 static void
81 spectral_register_cfg80211_handlers(struct wlan_objmgr_pdev *pdev)
82 {
83 	wlan_cfg80211_register_spectral_cmd_handler(
84 		pdev,
85 		SPECTRAL_SCAN_START_HANDLER_IDX,
86 		wlan_cfg80211_spectral_scan_config_and_start);
87 	wlan_cfg80211_register_spectral_cmd_handler(
88 		pdev,
89 		SPECTRAL_SCAN_STOP_HANDLER_IDX,
90 		wlan_cfg80211_spectral_scan_stop);
91 	wlan_cfg80211_register_spectral_cmd_handler(
92 		pdev,
93 		SPECTRAL_SCAN_GET_CONFIG_HANDLER_IDX,
94 		wlan_cfg80211_spectral_scan_get_config);
95 	wlan_cfg80211_register_spectral_cmd_handler(
96 		pdev,
97 		SPECTRAL_SCAN_GET_DIAG_STATS_HANDLER_IDX,
98 		wlan_cfg80211_spectral_scan_get_diag_stats);
99 	wlan_cfg80211_register_spectral_cmd_handler(
100 		pdev,
101 		SPECTRAL_SCAN_GET_CAP_HANDLER_IDX,
102 		wlan_cfg80211_spectral_scan_get_cap);
103 	wlan_cfg80211_register_spectral_cmd_handler(
104 		pdev,
105 		SPECTRAL_SCAN_GET_STATUS_HANDLER_IDX,
106 		wlan_cfg80211_spectral_scan_get_status);
107 }
108 #else
109 static void
110 spectral_register_cfg80211_handlers(struct wlan_objmgr_pdev *pdev)
111 {
112 }
113 #endif
114 
115 int
116 spectral_control_cmn(struct wlan_objmgr_pdev *pdev,
117 		     u_int id,
118 		     void *indata,
119 		     uint32_t insize, void *outdata, uint32_t *outsize)
120 {
121 	int error = 0;
122 	int temp_debug;
123 	struct spectral_config sp_out;
124 	struct spectral_config *sp_in;
125 	struct spectral_config *spectralparams;
126 	struct spectral_context *sc;
127 	struct wlan_objmgr_vdev *vdev = NULL;
128 	uint8_t vdev_rxchainmask = 0;
129 
130 	if (!pdev) {
131 		spectral_err("PDEV is NULL!");
132 		error = -EINVAL;
133 		goto bad;
134 	}
135 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
136 	if (!sc) {
137 		spectral_err("atf context is NULL!");
138 		error = -EINVAL;
139 		goto bad;
140 	}
141 
142 	switch (id) {
143 	case SPECTRAL_SET_CONFIG:
144 		{
145 			if (insize < sizeof(struct spectral_config) ||
146 			    !indata) {
147 				error = -EINVAL;
148 				break;
149 			}
150 			sp_in = (struct spectral_config *)indata;
151 			if (sp_in->ss_count !=
152 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
153 				if (sc->sptrlc_set_spectral_config(
154 					pdev,
155 					SPECTRAL_PARAM_SCAN_COUNT,
156 					sp_in->ss_count))
157 					error = -EINVAL;
158 			}
159 
160 			if (sp_in->ss_fft_period !=
161 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
162 				if (sc->sptrlc_set_spectral_config(
163 					pdev,
164 					SPECTRAL_PARAM_FFT_PERIOD,
165 					sp_in->ss_fft_period))
166 					error = -EINVAL;
167 			}
168 
169 			if (sp_in->ss_period != SPECTRAL_PHYERR_PARAM_NOVAL) {
170 				if (sc->sptrlc_set_spectral_config(
171 					pdev,
172 					SPECTRAL_PARAM_SCAN_PERIOD,
173 					sp_in->ss_period))
174 					error = -EINVAL;
175 			}
176 
177 			if (sp_in->ss_short_report !=
178 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
179 				if (sc->sptrlc_set_spectral_config(
180 					pdev,
181 					SPECTRAL_PARAM_SHORT_REPORT,
182 					(uint32_t)
183 					(sp_in->ss_short_report ? 1 : 0)))
184 					error = -EINVAL;
185 			}
186 
187 			if (sp_in->ss_spectral_pri !=
188 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
189 				if (sc->sptrlc_set_spectral_config(
190 					pdev,
191 					SPECTRAL_PARAM_SPECT_PRI,
192 					(uint32_t)(sp_in->ss_spectral_pri)))
193 					error = -EINVAL;
194 			}
195 
196 			if (sp_in->ss_fft_size != SPECTRAL_PHYERR_PARAM_NOVAL) {
197 				if (sc->sptrlc_set_spectral_config(
198 					pdev,
199 					SPECTRAL_PARAM_FFT_SIZE,
200 					sp_in->ss_fft_size))
201 					error = -EINVAL;
202 			}
203 
204 			if (sp_in->ss_gc_ena != SPECTRAL_PHYERR_PARAM_NOVAL) {
205 				if (sc->sptrlc_set_spectral_config(
206 					pdev,
207 					SPECTRAL_PARAM_GC_ENA,
208 					sp_in->ss_gc_ena))
209 					error = -EINVAL;
210 			}
211 
212 			if (sp_in->ss_restart_ena !=
213 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
214 				if (sc->sptrlc_set_spectral_config(
215 					pdev,
216 					SPECTRAL_PARAM_RESTART_ENA,
217 					sp_in->ss_restart_ena))
218 					error = -EINVAL;
219 			}
220 
221 			if (sp_in->ss_noise_floor_ref !=
222 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
223 				if (sc->sptrlc_set_spectral_config(
224 					pdev,
225 					SPECTRAL_PARAM_NOISE_FLOOR_REF,
226 					sp_in->ss_noise_floor_ref))
227 					error = -EINVAL;
228 			}
229 
230 			if (sp_in->ss_init_delay !=
231 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
232 				if (sc->sptrlc_set_spectral_config(
233 					pdev,
234 					SPECTRAL_PARAM_INIT_DELAY,
235 					sp_in->ss_init_delay))
236 					error = -EINVAL;
237 			}
238 
239 			if (sp_in->ss_nb_tone_thr !=
240 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
241 				if (sc->sptrlc_set_spectral_config(
242 					pdev,
243 					SPECTRAL_PARAM_NB_TONE_THR,
244 					sp_in->ss_nb_tone_thr))
245 					error = -EINVAL;
246 			}
247 
248 			if (sp_in->ss_str_bin_thr !=
249 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
250 				if (sc->sptrlc_set_spectral_config(
251 					pdev,
252 					SPECTRAL_PARAM_STR_BIN_THR,
253 					sp_in->ss_str_bin_thr))
254 					error = -EINVAL;
255 			}
256 
257 			if (sp_in->ss_wb_rpt_mode !=
258 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
259 				if (sc->sptrlc_set_spectral_config(
260 					pdev,
261 					SPECTRAL_PARAM_WB_RPT_MODE,
262 					sp_in->ss_wb_rpt_mode))
263 					error = -EINVAL;
264 			}
265 
266 			if (sp_in->ss_rssi_rpt_mode !=
267 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
268 				if (sc->sptrlc_set_spectral_config(
269 					pdev,
270 					SPECTRAL_PARAM_RSSI_RPT_MODE,
271 					sp_in->ss_rssi_rpt_mode))
272 					error = -EINVAL;
273 			}
274 
275 			if (sp_in->ss_rssi_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
276 				if (sc->sptrlc_set_spectral_config(
277 					pdev,
278 					SPECTRAL_PARAM_RSSI_THR,
279 					sp_in->ss_rssi_thr))
280 					error = -EINVAL;
281 			}
282 
283 			if (sp_in->ss_pwr_format !=
284 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
285 				if (sc->sptrlc_set_spectral_config(
286 					pdev,
287 					SPECTRAL_PARAM_PWR_FORMAT,
288 					sp_in->ss_pwr_format))
289 					error = -EINVAL;
290 			}
291 
292 			if (sp_in->ss_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
293 				if (sc->sptrlc_set_spectral_config(
294 					pdev,
295 					SPECTRAL_PARAM_RPT_MODE,
296 					sp_in->ss_rpt_mode))
297 					error = -EINVAL;
298 			}
299 
300 			if (sp_in->ss_bin_scale !=
301 			    SPECTRAL_PHYERR_PARAM_NOVAL) {
302 				if (sc->sptrlc_set_spectral_config(
303 					pdev,
304 					SPECTRAL_PARAM_BIN_SCALE,
305 					sp_in->ss_bin_scale))
306 					error = -EINVAL;
307 			}
308 
309 			if (sp_in->ss_dbm_adj != SPECTRAL_PHYERR_PARAM_NOVAL) {
310 				if (sc->sptrlc_set_spectral_config(
311 					pdev,
312 					SPECTRAL_PARAM_DBM_ADJ,
313 					sp_in->ss_dbm_adj))
314 					error = -EINVAL;
315 			}
316 
317 			if (sp_in->ss_chn_mask != SPECTRAL_PHYERR_PARAM_NOVAL) {
318 				/*
319 				 * Check if any of the inactive Rx antenna
320 				 * chains is set active in spectral chainmask
321 				 */
322 				vdev = spectral_get_vdev(pdev);
323 				if (!vdev) {
324 					error = -ENOENT;
325 					break;
326 				}
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 					error = -EINVAL;
336 					break;
337 				} else if (sc->sptrlc_set_spectral_config(
338 						pdev,
339 						SPECTRAL_PARAM_CHN_MASK,
340 						sp_in->ss_chn_mask)) {
341 					error = -EINVAL;
342 				}
343 			}
344 		}
345 		break;
346 
347 	case SPECTRAL_GET_CONFIG:
348 		{
349 			if (!outdata || !outsize ||
350 			    (*outsize < sizeof(struct spectral_config))) {
351 				error = -EINVAL;
352 				break;
353 			}
354 			*outsize = sizeof(struct spectral_config);
355 			sc->sptrlc_get_spectral_config(pdev, &sp_out);
356 			spectralparams = (struct spectral_config *)outdata;
357 			spectralparams->ss_fft_period = sp_out.ss_fft_period;
358 			spectralparams->ss_period = sp_out.ss_period;
359 			spectralparams->ss_count = sp_out.ss_count;
360 			spectralparams->ss_short_report =
361 			    sp_out.ss_short_report;
362 			spectralparams->ss_spectral_pri =
363 			    sp_out.ss_spectral_pri;
364 			spectralparams->ss_fft_size = sp_out.ss_fft_size;
365 			spectralparams->ss_gc_ena = sp_out.ss_gc_ena;
366 			spectralparams->ss_restart_ena = sp_out.ss_restart_ena;
367 			spectralparams->ss_noise_floor_ref =
368 			    sp_out.ss_noise_floor_ref;
369 			spectralparams->ss_init_delay = sp_out.ss_init_delay;
370 			spectralparams->ss_nb_tone_thr = sp_out.ss_nb_tone_thr;
371 			spectralparams->ss_str_bin_thr = sp_out.ss_str_bin_thr;
372 			spectralparams->ss_wb_rpt_mode = sp_out.ss_wb_rpt_mode;
373 			spectralparams->ss_rssi_rpt_mode =
374 			    sp_out.ss_rssi_rpt_mode;
375 			spectralparams->ss_rssi_thr = sp_out.ss_rssi_thr;
376 			spectralparams->ss_pwr_format = sp_out.ss_pwr_format;
377 			spectralparams->ss_rpt_mode = sp_out.ss_rpt_mode;
378 			spectralparams->ss_bin_scale = sp_out.ss_bin_scale;
379 			spectralparams->ss_dbm_adj = sp_out.ss_dbm_adj;
380 			spectralparams->ss_chn_mask = sp_out.ss_chn_mask;
381 		}
382 		break;
383 
384 	case SPECTRAL_IS_ACTIVE:
385 		{
386 			if (!outdata || !outsize ||
387 			    *outsize < sizeof(uint32_t)) {
388 				error = -EINVAL;
389 				break;
390 			}
391 			*outsize = sizeof(uint32_t);
392 			*((uint32_t *)outdata) =
393 			    (uint32_t)sc->sptrlc_is_spectral_active(pdev);
394 		}
395 		break;
396 
397 	case SPECTRAL_IS_ENABLED:
398 		{
399 			if (!outdata || !outsize ||
400 			    *outsize < sizeof(uint32_t)) {
401 				error = -EINVAL;
402 				break;
403 			}
404 			*outsize = sizeof(uint32_t);
405 			*((uint32_t *)outdata) =
406 			    (uint32_t)sc->sptrlc_is_spectral_enabled(pdev);
407 		}
408 		break;
409 
410 	case SPECTRAL_SET_DEBUG_LEVEL:
411 		{
412 			if (insize < sizeof(uint32_t) || !indata) {
413 				error = -EINVAL;
414 				break;
415 			}
416 			temp_debug = *(uint32_t *)indata;
417 			sc->sptrlc_set_debug_level(pdev, temp_debug);
418 		}
419 		break;
420 
421 	case SPECTRAL_GET_DEBUG_LEVEL:
422 		{
423 			if (!outdata || !outsize ||
424 			    *outsize < sizeof(uint32_t)) {
425 				error = -EINVAL;
426 				break;
427 			}
428 			*outsize = sizeof(uint32_t);
429 			*((uint32_t *)outdata) =
430 			    (uint32_t)sc->sptrlc_get_debug_level(pdev);
431 		}
432 		break;
433 
434 	case SPECTRAL_ACTIVATE_SCAN:
435 		{
436 			sc->sptrlc_start_spectral_scan(pdev);
437 		}
438 		break;
439 
440 	case SPECTRAL_STOP_SCAN:
441 		{
442 			sc->sptrlc_stop_spectral_scan(pdev);
443 		}
444 		break;
445 
446 	case SPECTRAL_GET_CAPABILITY_INFO:
447 		{
448 			if (!outdata || !outsize ||
449 			    *outsize < sizeof(struct spectral_caps)) {
450 				error = -EINVAL;
451 				break;
452 			}
453 			*outsize = sizeof(struct spectral_caps);
454 			sc->sptrlc_get_spectral_capinfo(pdev, outdata);
455 		}
456 		break;
457 
458 	case SPECTRAL_GET_DIAG_STATS:
459 		{
460 			if (!outdata || !outsize ||
461 			    (*outsize < sizeof(struct spectral_diag_stats))) {
462 				error = -EINVAL;
463 				break;
464 			}
465 			*outsize = sizeof(struct spectral_diag_stats);
466 			sc->sptrlc_get_spectral_diagstats(pdev, outdata);
467 		}
468 		break;
469 
470 	case SPECTRAL_GET_CHAN_WIDTH:
471 		{
472 			uint32_t chan_width;
473 
474 			vdev = spectral_get_vdev(pdev);
475 			if (!vdev)
476 				return -ENOENT;
477 
478 			chan_width = spectral_vdev_get_ch_width(vdev);
479 			wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
480 
481 			if (!outdata || !outsize ||
482 			    *outsize < sizeof(chan_width)) {
483 				error = -EINVAL;
484 				break;
485 			}
486 			*outsize = sizeof(chan_width);
487 			*((uint32_t *)outdata) = (uint32_t)chan_width;
488 		}
489 		break;
490 
491 	default:
492 		error = -EINVAL;
493 		break;
494 	}
495 
496  bad:
497 	return error;
498 }
499 
500 /**
501  * spectral_ctx_deinit() - De-initialize function pointers from spectral context
502  * @sc - Reference to spectral_context object
503  *
504  * Return: None
505  */
506 static void
507 spectral_ctx_deinit(struct spectral_context *sc)
508 {
509 	if (sc) {
510 		sc->sptrlc_ucfg_phyerr_config = NULL;
511 		sc->sptrlc_pdev_spectral_init = NULL;
512 		sc->sptrlc_pdev_spectral_deinit = NULL;
513 		sc->sptrlc_set_spectral_config = NULL;
514 		sc->sptrlc_get_spectral_config = NULL;
515 		sc->sptrlc_start_spectral_scan = NULL;
516 		sc->sptrlc_stop_spectral_scan = NULL;
517 		sc->sptrlc_is_spectral_active = NULL;
518 		sc->sptrlc_is_spectral_enabled = NULL;
519 		sc->sptrlc_set_debug_level = NULL;
520 		sc->sptrlc_get_debug_level = NULL;
521 		sc->sptrlc_get_spectral_capinfo = NULL;
522 		sc->sptrlc_get_spectral_diagstats = NULL;
523 	}
524 }
525 
526 QDF_STATUS
527 wlan_spectral_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
528 {
529 	struct spectral_context *sc = NULL;
530 
531 	if (!psoc) {
532 		spectral_err("PSOC is NULL");
533 		return QDF_STATUS_E_FAILURE;
534 	}
535 	sc = (struct spectral_context *)
536 	    qdf_mem_malloc(sizeof(struct spectral_context));
537 	if (!sc) {
538 		spectral_err("Failed to allocate spectral_ctx object");
539 		return QDF_STATUS_E_NOMEM;
540 	}
541 	qdf_mem_zero(sc, sizeof(struct spectral_context));
542 	sc->psoc_obj = psoc;
543 	if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL)
544 		spectral_ctx_init_ol(sc);
545 #ifdef CONFIG_WIN
546 	else if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_DA)
547 		spectral_ctx_init_da(sc);
548 #endif
549 	wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_SPECTRAL,
550 					      (void *)sc, QDF_STATUS_SUCCESS);
551 
552 	return QDF_STATUS_SUCCESS;
553 }
554 
555 QDF_STATUS
556 wlan_spectral_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc,
557 				       void *arg)
558 {
559 	struct spectral_context *sc = NULL;
560 
561 	if (!psoc) {
562 		spectral_err("PSOC is NULL");
563 		return QDF_STATUS_E_FAILURE;
564 	}
565 	sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
566 						   WLAN_UMAC_COMP_SPECTRAL);
567 	if (sc) {
568 		wlan_objmgr_psoc_component_obj_detach(psoc,
569 						      WLAN_UMAC_COMP_SPECTRAL,
570 						      (void *)sc);
571 		/* Deinitilise function pointers from spectral context */
572 		spectral_ctx_deinit(sc);
573 		qdf_mem_free(sc);
574 	}
575 
576 	return QDF_STATUS_SUCCESS;
577 }
578 
579 QDF_STATUS
580 wlan_spectral_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
581 {
582 	struct pdev_spectral *ps = NULL;
583 	struct spectral_context *sc = NULL;
584 	void *target_handle = NULL;
585 
586 	if (!pdev) {
587 		spectral_err("PDEV is NULL");
588 		return QDF_STATUS_E_FAILURE;
589 	}
590 	ps = (struct pdev_spectral *)
591 	    qdf_mem_malloc(sizeof(struct pdev_spectral));
592 	if (!ps) {
593 		spectral_err("Failed to allocate pdev_spectral object");
594 		return QDF_STATUS_E_NOMEM;
595 	}
596 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
597 	if (!sc) {
598 		spectral_err("Spectral context is NULL!");
599 		goto cleanup;
600 	}
601 
602 	qdf_mem_zero(ps, sizeof(struct pdev_spectral));
603 	ps->psptrl_pdev = pdev;
604 
605 	spectral_register_cfg80211_handlers(pdev);
606 	if (sc->sptrlc_pdev_spectral_init) {
607 		target_handle = sc->sptrlc_pdev_spectral_init(pdev);
608 		if (!target_handle) {
609 			spectral_err("Spectral lmac object is NULL!");
610 			goto cleanup;
611 		}
612 		ps->psptrl_target_handle = target_handle;
613 	}
614 	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_SPECTRAL,
615 					      (void *)ps, QDF_STATUS_SUCCESS);
616 
617 	return QDF_STATUS_SUCCESS;
618  cleanup:
619 	qdf_mem_free(ps);
620 	return QDF_STATUS_E_FAILURE;
621 }
622 
623 QDF_STATUS
624 wlan_spectral_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev,
625 				       void *arg)
626 {
627 	struct pdev_spectral *ps = NULL;
628 	struct spectral_context *sc = NULL;
629 
630 	if (!pdev) {
631 		spectral_err("PDEV is NULL");
632 		return QDF_STATUS_E_FAILURE;
633 	}
634 	sc = spectral_get_spectral_ctx_from_pdev(pdev);
635 	if (!sc) {
636 		spectral_err("Spectral context is NULL!");
637 		return QDF_STATUS_E_FAILURE;
638 	}
639 	ps = wlan_objmgr_pdev_get_comp_private_obj(pdev,
640 						   WLAN_UMAC_COMP_SPECTRAL);
641 	if (ps) {
642 		if (sc->sptrlc_pdev_spectral_deinit)
643 			sc->sptrlc_pdev_spectral_deinit(pdev);
644 		ps->psptrl_target_handle = NULL;
645 		wlan_objmgr_pdev_component_obj_detach(pdev,
646 						      WLAN_UMAC_COMP_SPECTRAL,
647 						      (void *)ps);
648 		qdf_mem_free(ps);
649 	}
650 
651 	return QDF_STATUS_SUCCESS;
652 }
653