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