xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2011,2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
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 <wlan_tgt_def_config.h>
21 #include <hif.h>
22 #include <target_type.h>
23 #include <hif_hw_version.h>
24 #include <wmi_unified_api.h>
25 #include <target_if_spectral.h>
26 #include <wlan_lmac_if_def.h>
27 #include <wlan_osif_priv.h>
28 #include <init_deinit_lmac.h>
29 #include <reg_services_public_struct.h>
30 #include <target_if_spectral_sim.h>
31 #include <target_if.h>
32 #include <qdf_module.h>
33 #include <wlan_reg_services_api.h>
34 #include <wlan_dfs_ucfg_api.h>
35 
36 /**
37  * @spectral_ops - Spectral function table, holds the Spectral functions that
38  * depend on whether the architecture is Direct Attach or Offload. This is used
39  * to populate the actual Spectral function table present in the Spectral
40  * module.
41  */
42 struct target_if_spectral_ops spectral_ops;
43 int spectral_debug_level = DEBUG_SPECTRAL;
44 struct spectral_tgt_ops ops_tgt;
45 
46 #ifdef SPECTRAL_MODULIZED_ENABLE
47 /**
48  * target_if_spectral_wmi_service_enabled() - API to check whether a
49  * given WMI service is enabled
50  * @psoc: Pointer to psoc
51  * @wmi_handle: WMI handle
52  * @service_id: service id
53  *
54  * Return: true or false
55  */
56 static
57 bool target_if_spectral_wmi_service_enabled(struct wlan_objmgr_psoc *psoc,
58 					    wmi_unified_t wmi_handle,
59 					    uint32_t service_id)
60 {
61 	struct target_if_psoc_spectral *psoc_spectral;
62 
63 	if (!psoc) {
64 		spectral_err("psoc is null");
65 		return false;
66 	}
67 
68 	if (!wmi_handle) {
69 		spectral_err("wmi handle is null");
70 		return false;
71 	}
72 
73 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
74 	if (!psoc_spectral) {
75 		spectral_err("psoc spectral object is null");
76 		return false;
77 	}
78 
79 	return psoc_spectral->wmi_ops.wmi_service_enabled(wmi_handle,
80 							  service_id);
81 }
82 #else
83 /**
84  * target_if_spectral_wmi_service_enabled() - API to check whether a
85  * given WMI service is enabled
86  * @psoc: Pointer to psoc
87  * @wmi_handle: WMI handle
88  * @service_id: service id
89  *
90  * Return: true or false
91  */
92 static
93 bool target_if_spectral_wmi_service_enabled(struct wlan_objmgr_psoc *psoc,
94 					    wmi_unified_t wmi_handle,
95 					    uint32_t service_id)
96 {
97 	return wmi_service_enabled(wmi_handle, service_id);
98 }
99 #endif /* SPECTRAL_MODULIZED_ENABLE */
100 
101 struct target_if_spectral *get_target_if_spectral_handle_from_pdev(
102 	struct wlan_objmgr_pdev *pdev)
103 {
104 	struct target_if_spectral *spectral;
105 	struct wlan_objmgr_psoc *psoc;
106 	struct wlan_lmac_if_rx_ops *rx_ops;
107 
108 	if (!pdev) {
109 		spectral_err("pdev is null");
110 		return NULL;
111 	}
112 
113 	psoc = wlan_pdev_get_psoc(pdev);
114 	if (!psoc) {
115 		spectral_err("psoc is null");
116 		return NULL;
117 	}
118 
119 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
120 	if (!rx_ops) {
121 		spectral_err("rx_ops is null");
122 		return NULL;
123 	}
124 
125 	spectral = (struct target_if_spectral *)
126 		rx_ops->sptrl_rx_ops.sptrlro_get_pdev_target_handle(pdev);
127 
128 	return spectral;
129 }
130 
131 qdf_export_symbol(get_target_if_spectral_handle_from_pdev);
132 
133 /**
134  * target_if_spectral_get_normal_mode_cap() - API to get normal
135  * Spectral scan capability of a given pdev
136  * @pdev: pdev handle
137  * @normal_mode_disable: Pointer to caller variable
138  *
139  * API to get normal Spectral scan mode capability a given pdev.
140  * This information is derived from the WMI service
141  * "WMI_SERVICE_SPECTRAL_SCAN_DISABLED".
142  *
143  * Return: QDF_STATUS on success
144  */
145 static QDF_STATUS
146 target_if_spectral_get_normal_mode_cap(struct wlan_objmgr_pdev *pdev,
147 				       bool *normal_mode_disable)
148 {
149 	struct wlan_objmgr_psoc *psoc;
150 	struct wmi_unified *wmi_handle;
151 	struct target_if_psoc_spectral *psoc_spectral;
152 
153 	if (!pdev) {
154 		spectral_err("pdev is null");
155 		return QDF_STATUS_E_INVAL;
156 	}
157 
158 	psoc = wlan_pdev_get_psoc(pdev);
159 	if (!psoc) {
160 		spectral_err("psoc is null");
161 		return QDF_STATUS_E_INVAL;
162 	}
163 
164 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
165 	if (!psoc_spectral) {
166 		spectral_err("psoc spectral object is null");
167 		return QDF_STATUS_E_INVAL;
168 	}
169 
170 	wmi_handle =  get_wmi_unified_hdl_from_psoc(psoc);
171 	if (!wmi_handle) {
172 		spectral_err("wmi handle is null");
173 		return QDF_STATUS_E_INVAL;
174 	}
175 
176 	*normal_mode_disable = target_if_spectral_wmi_service_enabled(psoc,
177 				wmi_handle, wmi_service_spectral_scan_disabled);
178 
179 	return QDF_STATUS_SUCCESS;
180 }
181 
182 /**
183  * target_if_spectral_get_agile_mode_cap() - API to check agile
184  * Spectral scan mode capability of a given pdev.
185  * @pdev: pdev handle
186  * @agile_cap: Pointer to caller variable
187  *
188  * API to check agile Spectral scan mode is disabled for a given pdev.
189  * This information is derived from the chain mask table entries.
190  *
191  * Return: QDF_STATUS on success
192  */
193 static QDF_STATUS
194 target_if_spectral_get_agile_mode_cap(
195 			struct wlan_objmgr_pdev *pdev,
196 			struct target_if_spectral_agile_mode_cap *agile_cap)
197 {
198 	struct wlan_objmgr_psoc *psoc;
199 	struct target_psoc_info *tgt_psoc_info;
200 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr;
201 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
202 	uint8_t pdev_id, i;
203 	uint32_t table_id;
204 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
205 	struct wlan_psoc_host_chainmask_table *table;
206 	struct wmi_unified *wmi_handle;
207 
208 	if (!pdev) {
209 		spectral_err("pdev is null");
210 		return QDF_STATUS_E_INVAL;
211 	}
212 
213 	psoc = wlan_pdev_get_psoc(pdev);
214 	if (!psoc) {
215 		spectral_err("psoc is null");
216 		return QDF_STATUS_E_FAILURE;
217 	}
218 
219 	wmi_handle =  get_wmi_unified_hdl_from_psoc(psoc);
220 	if (!wmi_handle) {
221 		spectral_err("wmi handle is null");
222 		return QDF_STATUS_E_INVAL;
223 	}
224 
225 	/* Agile Spectral is disabled for legacy targets */
226 	if (!target_if_spectral_wmi_service_enabled(psoc, wmi_handle,
227 						    wmi_service_ext_msg)) {
228 		agile_cap->agile_spectral_cap  = false;
229 		agile_cap->agile_spectral_cap_160 = false;
230 		agile_cap->agile_spectral_cap_80p80 = false;
231 		agile_cap->agile_spectral_cap_320 = false;
232 
233 		return QDF_STATUS_SUCCESS;
234 	}
235 
236 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
237 	if (!tgt_psoc_info) {
238 		spectral_err("target_psoc_info is null");
239 		return QDF_STATUS_E_FAILURE;
240 	}
241 
242 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
243 	if (!mac_phy_cap_arr) {
244 		spectral_err("mac phy cap array is null");
245 		return QDF_STATUS_E_FAILURE;
246 	}
247 
248 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
249 	mac_phy_cap = &mac_phy_cap_arr[pdev_id];
250 	table_id = mac_phy_cap->chainmask_table_id;
251 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
252 	if (!ext_svc_param) {
253 		spectral_err("Extended service ready params null");
254 		return QDF_STATUS_E_FAILURE;
255 	}
256 
257 	table =  &ext_svc_param->chainmask_table[table_id];
258 
259 	for (i = 0; i < table->num_valid_chainmasks; i++) {
260 		agile_cap->agile_spectral_cap |=
261 			table->cap_list[i].supports_aSpectral;
262 		agile_cap->agile_spectral_cap_160 |=
263 			table->cap_list[i].supports_aSpectral_160;
264 		agile_cap->agile_spectral_cap_320 |= 0;
265 	}
266 
267 	agile_cap->agile_spectral_cap_80p80 = agile_cap->agile_spectral_cap_160;
268 
269 	return QDF_STATUS_SUCCESS;
270 }
271 
272 /**
273  * target_if_spectral_init_pdev_feature_cap_per_mode() - API to initialize
274  * Spectral scan pdev feature caps for a given Spectral mode
275  * @pdev: pdev handle
276  * @smode: Spectral scan mode
277  *
278  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE/
279  * QDF_STATUS_E_INVAL on failure
280  */
281 static QDF_STATUS
282 target_if_spectral_init_pdev_feature_cap_per_mode(struct wlan_objmgr_pdev *pdev,
283 						  enum spectral_scan_mode smode)
284 {
285 	struct wlan_objmgr_psoc *psoc;
286 	bool normal_mode_disable;
287 	struct target_if_spectral_agile_mode_cap agile_cap = { 0 };
288 	QDF_STATUS status;
289 
290 	if (!pdev) {
291 		spectral_err("pdev is null");
292 		return QDF_STATUS_E_INVAL;
293 	}
294 
295 	psoc = wlan_pdev_get_psoc(pdev);
296 	if (!psoc) {
297 		spectral_err("psoc is null");
298 		return QDF_STATUS_E_INVAL;
299 	}
300 
301 	switch (smode) {
302 	case SPECTRAL_SCAN_MODE_NORMAL:
303 		if (target_if_spectral_is_feature_disabled_psoc(psoc)) {
304 			wlan_pdev_nif_feat_ext_cap_set(
305 				pdev, WLAN_PDEV_FEXT_NORMAL_SPECTRAL_SCAN_DIS);
306 
307 			return QDF_STATUS_SUCCESS;
308 		}
309 
310 		status = target_if_spectral_get_normal_mode_cap(
311 				pdev, &normal_mode_disable);
312 		if (QDF_IS_STATUS_ERROR(status)) {
313 			spectral_err("Failed to get normal spectral scan caps");
314 			return QDF_STATUS_E_FAILURE;
315 		}
316 
317 		if (normal_mode_disable)
318 			wlan_pdev_nif_feat_ext_cap_set(
319 				pdev, WLAN_PDEV_FEXT_NORMAL_SPECTRAL_SCAN_DIS);
320 		else
321 			wlan_pdev_nif_feat_ext_cap_clear(
322 				pdev, WLAN_PDEV_FEXT_NORMAL_SPECTRAL_SCAN_DIS);
323 		break;
324 
325 	case SPECTRAL_SCAN_MODE_AGILE:
326 		if (target_if_spectral_is_feature_disabled_psoc(psoc)) {
327 			wlan_pdev_nif_feat_ext_cap_set(
328 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_DIS);
329 			wlan_pdev_nif_feat_ext_cap_set(
330 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_160_DIS);
331 			wlan_pdev_nif_feat_ext_cap_set(
332 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_80P80_DIS);
333 			wlan_pdev_nif_feat_ext_cap_set(
334 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_320_DIS);
335 
336 			return QDF_STATUS_SUCCESS;
337 		}
338 		status = target_if_spectral_get_agile_mode_cap(
339 				pdev, &agile_cap);
340 		if (QDF_IS_STATUS_ERROR(status)) {
341 			spectral_err("Failed to get agile Spectral capability");
342 			return QDF_STATUS_E_FAILURE;
343 		}
344 
345 		if (!agile_cap.agile_spectral_cap)
346 			wlan_pdev_nif_feat_ext_cap_set(
347 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_DIS);
348 		else
349 			wlan_pdev_nif_feat_ext_cap_clear(
350 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_DIS);
351 
352 		if (!agile_cap.agile_spectral_cap_160)
353 			wlan_pdev_nif_feat_ext_cap_set(
354 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_160_DIS);
355 		else
356 			wlan_pdev_nif_feat_ext_cap_clear(
357 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_160_DIS);
358 
359 		if (!agile_cap.agile_spectral_cap_80p80)
360 			wlan_pdev_nif_feat_ext_cap_set(
361 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_80P80_DIS);
362 		else
363 			wlan_pdev_nif_feat_ext_cap_clear(
364 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_80P80_DIS);
365 
366 		if (!agile_cap.agile_spectral_cap_320)
367 			wlan_pdev_nif_feat_ext_cap_set(
368 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_320_DIS);
369 		else
370 			wlan_pdev_nif_feat_ext_cap_clear(
371 			  pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_320_DIS);
372 
373 		break;
374 
375 	default:
376 		spectral_err("Invalid Spectral scan mode %d", smode);
377 		return QDF_STATUS_E_INVAL;
378 	}
379 
380 	return QDF_STATUS_SUCCESS;
381 }
382 
383 /**
384  * target_if_spectral_init_pdev_feature_caps() - API to initialize
385  * Spectral scan pdev feature caps for a given pdev
386  * @pdev: pdev handle
387  *
388  * API initialize normal and agile Spectral scan pdev
389  * feature caps for a given pdev.
390  *
391  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
392  */
393 static QDF_STATUS
394 target_if_spectral_init_pdev_feature_caps(struct wlan_objmgr_pdev *pdev)
395 {
396 	enum spectral_scan_mode smode;
397 
398 	if (!pdev) {
399 		spectral_err("pdev is NULL!");
400 		return QDF_STATUS_E_INVAL;
401 	}
402 
403 	smode = SPECTRAL_SCAN_MODE_NORMAL;
404 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
405 		QDF_STATUS status;
406 
407 		status = target_if_spectral_init_pdev_feature_cap_per_mode(
408 				pdev, smode);
409 		if (QDF_IS_STATUS_ERROR(status))
410 			return QDF_STATUS_E_INVAL;
411 	}
412 
413 	return QDF_STATUS_SUCCESS;
414 }
415 
416 static void target_if_spectral_get_firstvdev_pdev(struct wlan_objmgr_pdev *pdev,
417 						  void *obj, void *arg)
418 {
419 	struct wlan_objmgr_vdev *vdev = obj;
420 	struct wlan_objmgr_vdev **first_vdev = arg;
421 
422 	if (!(*first_vdev))
423 		*first_vdev = vdev;
424 }
425 
426 struct wlan_objmgr_vdev *
427 target_if_spectral_get_vdev(struct target_if_spectral *spectral,
428 			    enum spectral_scan_mode smode)
429 {
430 	struct wlan_objmgr_pdev *pdev = NULL;
431 	struct wlan_objmgr_vdev *first_vdev = NULL;
432 
433 	qdf_assert_always(spectral);
434 	pdev = spectral->pdev_obj;
435 	qdf_assert_always(pdev);
436 
437 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
438 		spectral_err("Invalid Spectral mode %u", smode);
439 		return NULL;
440 	}
441 
442 	if (spectral->vdev_id[smode] != WLAN_INVALID_VDEV_ID) {
443 		first_vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
444 						pdev, spectral->vdev_id[smode],
445 						WLAN_SPECTRAL_ID);
446 		return first_vdev;
447 	}
448 
449 	if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_SPECTRAL_ID) !=
450 	    QDF_STATUS_SUCCESS) {
451 		spectral_err("Unable to get pdev reference.");
452 		return NULL;
453 	}
454 
455 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
456 					  target_if_spectral_get_firstvdev_pdev,
457 					  &first_vdev, 0, WLAN_SPECTRAL_ID);
458 
459 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
460 
461 	if (!first_vdev)
462 		return NULL;
463 
464 	if (wlan_objmgr_vdev_try_get_ref(first_vdev, WLAN_SPECTRAL_ID) !=
465 			QDF_STATUS_SUCCESS)
466 		first_vdev = NULL;
467 
468 	return first_vdev;
469 }
470 
471 /**
472  * target_if_send_vdev_spectral_configure_cmd() - Send WMI command to configure
473  * spectral parameters
474  * @spectral: Pointer to Spectral target_if internal private data
475  * @smode: Spectral scan mode
476  * @param: Pointer to spectral_config giving the Spectral configuration
477  *
478  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
479  */
480 static int
481 target_if_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral,
482 					   enum spectral_scan_mode smode,
483 					   struct spectral_config *param)
484 {
485 	struct vdev_spectral_configure_params sparam;
486 	struct wlan_objmgr_psoc *psoc;
487 	struct wlan_objmgr_pdev *pdev = NULL;
488 	struct wlan_objmgr_vdev *vdev = NULL;
489 	struct target_if_psoc_spectral *psoc_spectral;
490 
491 	qdf_assert_always(spectral);
492 	qdf_assert_always(param);
493 
494 	pdev = spectral->pdev_obj;
495 
496 	qdf_assert_always(pdev);
497 
498 	psoc = wlan_pdev_get_psoc(pdev);
499 	if (!psoc) {
500 		spectral_err("psoc is null");
501 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
502 	}
503 
504 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
505 	if (!psoc_spectral) {
506 		spectral_err("psoc spectral object is null");
507 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
508 	}
509 
510 	vdev = target_if_spectral_get_vdev(spectral, smode);
511 	if (!vdev)
512 		return QDF_STATUS_E_NOENT;
513 
514 	qdf_mem_zero(&sparam, sizeof(sparam));
515 
516 	sparam.vdev_id = wlan_vdev_get_id(vdev);
517 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
518 
519 	sparam.count = param->ss_count;
520 	sparam.period = param->ss_period;
521 	sparam.fft_recap = param->ss_recapture;
522 	sparam.spectral_pri = param->ss_spectral_pri;
523 	sparam.fft_size = param->ss_fft_size;
524 	sparam.gc_enable = param->ss_gc_ena;
525 	sparam.restart_enable = param->ss_restart_ena;
526 	sparam.noise_floor_ref = param->ss_noise_floor_ref;
527 	sparam.init_delay = param->ss_init_delay;
528 	sparam.nb_tone_thr = param->ss_nb_tone_thr;
529 	sparam.str_bin_thr = param->ss_str_bin_thr;
530 	sparam.wb_rpt_mode = param->ss_wb_rpt_mode;
531 	sparam.rssi_rpt_mode = param->ss_rssi_rpt_mode;
532 	sparam.rssi_thr = param->ss_rssi_thr;
533 	sparam.pwr_format = param->ss_pwr_format;
534 	sparam.rpt_mode = param->ss_rpt_mode;
535 	sparam.bin_scale = param->ss_bin_scale;
536 	sparam.dbm_adj = param->ss_dbm_adj;
537 	sparam.chn_mask = param->ss_chn_mask;
538 	sparam.mode = smode;
539 	sparam.center_freq1 = param->ss_frequency.cfreq1;
540 	sparam.center_freq2 = param->ss_frequency.cfreq2;
541 	sparam.chan_width = param->ss_bandwidth;
542 
543 	return psoc_spectral->wmi_ops.wmi_spectral_configure_cmd_send(
544 				GET_WMI_HDL_FROM_PDEV(pdev), &sparam);
545 }
546 
547 /**
548  * target_if_send_vdev_spectral_enable_cmd() - Send WMI command to
549  * enable/disable Spectral
550  * @spectral: Pointer to Spectral target_if internal private data
551  * @smode: Spectral scan mode
552  * @is_spectral_active_valid: Flag to indicate if spectral activate (trigger) is
553  * valid
554  * @is_spectral_active: Value of spectral activate
555  * @is_spectral_enabled_valid: Flag to indicate if spectral enable is valid
556  * @is_spectral_enabled: Value of spectral enable
557  *
558  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
559  */
560 static int
561 target_if_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral,
562 					enum spectral_scan_mode smode,
563 					uint8_t is_spectral_active_valid,
564 					uint8_t is_spectral_active,
565 					uint8_t is_spectral_enabled_valid,
566 					uint8_t is_spectral_enabled)
567 {
568 	struct vdev_spectral_enable_params param;
569 	struct wlan_objmgr_psoc *psoc;
570 	struct wlan_objmgr_pdev *pdev = NULL;
571 	struct wlan_objmgr_vdev *vdev = NULL;
572 	struct target_if_psoc_spectral *psoc_spectral;
573 
574 	qdf_assert_always(spectral);
575 
576 	pdev = spectral->pdev_obj;
577 
578 	qdf_assert_always(pdev);
579 
580 	psoc = wlan_pdev_get_psoc(pdev);
581 	if (!psoc) {
582 		spectral_err("psoc is null");
583 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
584 	}
585 
586 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
587 	if (!psoc_spectral) {
588 		spectral_err("psoc spectral object is null");
589 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
590 	}
591 
592 	vdev = target_if_spectral_get_vdev(spectral, smode);
593 	if (!vdev)
594 		return QDF_STATUS_E_NOENT;
595 
596 	qdf_mem_zero(&param, sizeof(param));
597 
598 	param.vdev_id = wlan_vdev_get_id(vdev);
599 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
600 
601 	param.active_valid = is_spectral_active_valid;
602 	param.enabled_valid = is_spectral_enabled_valid;
603 	param.active = is_spectral_active;
604 	param.enabled = is_spectral_enabled;
605 	param.mode = smode;
606 
607 	return psoc_spectral->wmi_ops.wmi_spectral_enable_cmd_send(
608 				GET_WMI_HDL_FROM_PDEV(pdev), &param);
609 }
610 
611 /**
612  * is_spectral_arch_beryllium() - Check whether the given target Spectral
613  * architecture is Beryllium
614  * @target_tpe: Target type
615  *
616  * Return: true if the spectral architecture is Beryllium, else false
617  */
618 static inline bool is_spectral_arch_beryllium(uint32_t target_tpe)
619 {
620 	if ((target_tpe == TARGET_TYPE_QCN9224) ||
621 	    (target_tpe == TARGET_TYPE_QCA5332))
622 		return true;
623 
624 	return false;
625 }
626 
627 /**
628  * List of supported sscan BWs. Make sure to maintain the array elements in the
629  * same order of BWs as that of struct spectral_supported_bws bitmap.
630  */
631 static const enum phy_ch_width supported_sscan_bw_list[] = {
632 	CH_WIDTH_5MHZ,
633 	CH_WIDTH_10MHZ,
634 	CH_WIDTH_20MHZ,
635 	CH_WIDTH_40MHZ,
636 	CH_WIDTH_80MHZ,
637 	CH_WIDTH_160MHZ,
638 	CH_WIDTH_80P80MHZ,
639 #ifdef WLAN_FEATURE_11BE
640 	CH_WIDTH_320MHZ,
641 #endif
642 };
643 
644 #define INVALID_SSCAN_BW_POS (-1)
645 int get_supported_sscan_bw_pos(enum phy_ch_width sscan_bw)
646 {
647 	int max_pos, pos;
648 
649 	max_pos =  QDF_ARRAY_SIZE(supported_sscan_bw_list);
650 	for (pos = 0; pos < max_pos; pos++) {
651 		if (supported_sscan_bw_list[pos] == sscan_bw)
652 			return pos;
653 	}
654 
655 	return INVALID_SSCAN_BW_POS;
656 }
657 
658 /**
659  * target_if_is_sscan_bw_supported() - Check whether the given sscan_bw is
660  * supported
661  * @spectral: Spectral LMAC object
662  * @smode: Spectral scan mode
663  * @sscan_bw: Spectral scan bandwidth
664  * @op_bw: operating bandwidth
665  * @is_bw_supported: Pointer to the caller variable where this function
666  * populates whether @sscan_bw is supported
667  * @is_80_80_agile: Indicates an 80+80 agile Scan request
668  *
669  * Return: QDF_STATUS of operation
670  */
671 static QDF_STATUS
672 target_if_is_sscan_bw_supported(struct target_if_spectral *spectral,
673 				enum spectral_scan_mode smode,
674 				enum phy_ch_width sscan_bw,
675 				enum phy_ch_width op_bw,
676 				bool *is_bw_supported,
677 				bool is_80_80_agile)
678 {
679 	struct spectral_supported_bws *supported_bws;
680 
681 	*is_bw_supported = false;
682 
683 	if (op_bw >= CH_WIDTH_INVALID) {
684 		spectral_err("Invalid channel width %d", op_bw);
685 		return QDF_STATUS_E_INVAL;
686 	}
687 
688 	if ((is_80_80_agile && sscan_bw != CH_WIDTH_80P80MHZ) ||
689 	    (!is_80_80_agile && sscan_bw == CH_WIDTH_80P80MHZ)) {
690 		*is_bw_supported = false;
691 		return QDF_STATUS_SUCCESS;
692 	}
693 
694 	/* Get the supported sscan bandwidths for this operating bandwidth */
695 	supported_bws = &spectral->supported_bws[smode][op_bw];
696 	*is_bw_supported = supported_bws->bandwidths &
697 				(1 << get_supported_sscan_bw_pos(sscan_bw));
698 
699 	return QDF_STATUS_SUCCESS;
700 }
701 
702 /**
703  * get_max_sscan_bw() - Get the maximum sscan bandwidth for a given operating
704  * bandwidth
705  * @spectral: Spectral LMAC object
706  * @smode: Spectral scan mode
707  * @op_bw: operating bandwidth
708  *
709  * Return: Maximum sscan bandwidth for @op_bw on success, else CH_WIDTH_INVALID
710  */
711 static enum phy_ch_width
712 get_max_sscan_bw(struct target_if_spectral *spectral,
713 		 enum spectral_scan_mode smode,
714 		 enum phy_ch_width op_bw)
715 {
716 	int op_bw_pos, pos;
717 	struct spectral_supported_bws *supported_bws;
718 
719 	supported_bws = &spectral->supported_bws[smode][op_bw];
720 	op_bw_pos = get_supported_sscan_bw_pos(op_bw);
721 
722 	/**
723 	 * Start with operating bandwidth, and keep reducing the bandwidth until
724 	 * a supported sscan BW is found.
725 	 */
726 	for (pos = op_bw_pos; pos >= 0; pos--) {
727 		if (supported_bws->bandwidths & (1 << pos))
728 			return supported_sscan_bw_list[pos];
729 	}
730 
731 	return CH_WIDTH_INVALID;
732 }
733 
734 /* target_if_spectral_find_agile_width() - Given a channel width enum, find the
735  * corresponding translation for Agile channel width.
736  * @spectral: pointer to Spectral object
737  * @op_width: operating channel width
738  * @is_80_80_agile: Indicates an 80+80 agile Scan request
739  *
740  * Return: The translated channel width enum.
741  */
742 static enum phy_ch_width
743 target_if_spectral_find_agile_width(struct target_if_spectral *spectral,
744 				    enum phy_ch_width op_bw,
745 				    bool is_80_80_agile)
746 {
747 	enum phy_ch_width agile_width;
748 	struct wlan_objmgr_pdev *pdev;
749 	struct wlan_objmgr_psoc *psoc;
750 
751 	if (!spectral) {
752 		spectral_err("Spectral object is null");
753 		return CH_WIDTH_INVALID;
754 	}
755 
756 	pdev =  spectral->pdev_obj;
757 	if (!pdev) {
758 		spectral_err("pdev is null");
759 		return CH_WIDTH_INVALID;
760 	}
761 
762 	psoc = wlan_pdev_get_psoc(pdev);
763 	if (!psoc) {
764 		spectral_err("psoc is null");
765 		return CH_WIDTH_INVALID;
766 	}
767 
768 	agile_width = get_max_sscan_bw(spectral, SPECTRAL_SCAN_MODE_AGILE,
769 				       op_bw);
770 
771 	if (wlan_psoc_nif_fw_ext_cap_get(psoc,
772 					 WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
773 		switch (op_bw) {
774 		case CH_WIDTH_80P80MHZ:
775 			if (!is_80_80_agile)
776 				agile_width = CH_WIDTH_160MHZ;
777 			else
778 				agile_width = CH_WIDTH_80P80MHZ;
779 
780 			break;
781 
782 		case CH_WIDTH_160MHZ:
783 			if (is_80_80_agile)
784 				agile_width = CH_WIDTH_80P80MHZ;
785 			else
786 				agile_width = CH_WIDTH_160MHZ;
787 
788 			break;
789 
790 		default:
791 			break;
792 		}
793 	}
794 
795 	return agile_width;
796 }
797 
798 /**
799  * get_default_sscan_bw() - Get the default sscan bandwidth for a given
800  * operating bandwidth
801  * @spectral: Spectral LMAC object
802  * @smode: Spectral scan mode
803  * @is_80_80_agile: Indicates an 80+80 agile Scan request
804  *
805  * Return: Default sscan bandwidth for @op_bw on success, else CH_WIDTH_INVALID
806  */
807 static enum phy_ch_width
808 get_default_sscan_bw(struct target_if_spectral *spectral,
809 		     enum spectral_scan_mode smode,
810 		     bool is_80_80_agile)
811 {
812 	struct wlan_objmgr_vdev *vdev;
813 	enum phy_ch_width vdev_ch_width, sscan_width;
814 
815 	vdev = target_if_spectral_get_vdev(spectral, smode);
816 	if (!vdev) {
817 		spectral_err("vdev is null");
818 		return CH_WIDTH_INVALID;
819 	}
820 
821 	vdev_ch_width = target_if_vdev_get_ch_width(vdev);
822 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
823 	if (vdev_ch_width >= CH_WIDTH_INVALID) {
824 		spectral_err("Invalid vdev channel width %d", vdev_ch_width);
825 		return CH_WIDTH_INVALID;
826 	}
827 
828 	switch (smode) {
829 	case SPECTRAL_SCAN_MODE_NORMAL:
830 		sscan_width = get_max_sscan_bw(spectral, smode, vdev_ch_width);
831 		break;
832 
833 	case SPECTRAL_SCAN_MODE_AGILE:
834 		sscan_width = target_if_spectral_find_agile_width(
835 				spectral, vdev_ch_width, is_80_80_agile);
836 		break;
837 
838 	default:
839 		sscan_width = CH_WIDTH_INVALID;
840 		break;
841 	}
842 
843 	return sscan_width;
844 }
845 
846 /**
847  * target_if_spectral_info_init_defaults() - Helper function to load defaults
848  * for Spectral information (parameters and state) into cache.
849  * @spectral: Pointer to Spectral target_if internal private data
850  * @smode: Spectral scan mode
851  *
852  * It is assumed that the caller has obtained the requisite lock if applicable.
853  * Note that this is currently treated as a temporary function.  Ideally, we
854  * would like to get defaults from the firmware.
855  *
856  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
857  */
858 static QDF_STATUS
859 target_if_spectral_info_init_defaults(struct target_if_spectral *spectral,
860 				      enum spectral_scan_mode smode)
861 {
862 	struct target_if_spectral_param_state_info *info;
863 	struct wlan_objmgr_vdev *vdev = NULL;
864 	enum phy_ch_width sscan_bw;
865 
866 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
867 		spectral_err("Invalid Spectral mode %u", smode);
868 		return QDF_STATUS_E_FAILURE;
869 	}
870 
871 	info = &spectral->param_info[smode];
872 
873 	/* State */
874 	info->osps_cache.osc_spectral_active = SPECTRAL_SCAN_ACTIVE_DEFAULT;
875 
876 	info->osps_cache.osc_spectral_enabled = SPECTRAL_SCAN_ENABLE_DEFAULT;
877 
878 	/* Parameters */
879 	info->osps_cache.osc_params.ss_count = SPECTRAL_SCAN_COUNT_DEFAULT;
880 
881 	if (spectral->spectral_gen == SPECTRAL_GEN3)
882 		info->osps_cache.osc_params.ss_period =
883 			SPECTRAL_SCAN_PERIOD_GEN_III_DEFAULT;
884 	else
885 		info->osps_cache.osc_params.ss_period =
886 			SPECTRAL_SCAN_PERIOD_GEN_II_DEFAULT;
887 
888 	info->osps_cache.osc_params.ss_recapture =
889 				SPECTRAL_FFT_RECAPTURE_DEFAULT;
890 	info->osps_cache.osc_params.ss_spectral_pri =
891 	    SPECTRAL_SCAN_PRIORITY_DEFAULT;
892 
893 	info->osps_cache.osc_params.ss_fft_size =
894 	    SPECTRAL_SCAN_FFT_SIZE_DEFAULT;
895 
896 	info->osps_cache.osc_params.ss_gc_ena = SPECTRAL_SCAN_GC_ENA_DEFAULT;
897 
898 	info->osps_cache.osc_params.ss_restart_ena =
899 	    SPECTRAL_SCAN_RESTART_ENA_DEFAULT;
900 
901 	info->osps_cache.osc_params.ss_noise_floor_ref =
902 	    SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT;
903 
904 	info->osps_cache.osc_params.ss_init_delay =
905 	    SPECTRAL_SCAN_INIT_DELAY_DEFAULT;
906 
907 	info->osps_cache.osc_params.ss_nb_tone_thr =
908 	    SPECTRAL_SCAN_NB_TONE_THR_DEFAULT;
909 
910 	info->osps_cache.osc_params.ss_str_bin_thr =
911 	    SPECTRAL_SCAN_STR_BIN_THR_DEFAULT;
912 
913 	info->osps_cache.osc_params.ss_wb_rpt_mode =
914 	    SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT;
915 
916 	info->osps_cache.osc_params.ss_rssi_rpt_mode =
917 	    SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT;
918 
919 	info->osps_cache.osc_params.ss_rssi_thr =
920 	    SPECTRAL_SCAN_RSSI_THR_DEFAULT;
921 
922 	info->osps_cache.osc_params.ss_pwr_format =
923 	    SPECTRAL_SCAN_PWR_FORMAT_DEFAULT;
924 
925 	info->osps_cache.osc_params.ss_rpt_mode =
926 	    SPECTRAL_SCAN_RPT_MODE_DEFAULT;
927 
928 	info->osps_cache.osc_params.ss_bin_scale =
929 	    SPECTRAL_SCAN_BIN_SCALE_DEFAULT;
930 
931 	info->osps_cache.osc_params.ss_dbm_adj = SPECTRAL_SCAN_DBM_ADJ_DEFAULT;
932 
933 	vdev = target_if_spectral_get_vdev(spectral, smode);
934 	if (!vdev)
935 		return QDF_STATUS_E_NOENT;
936 
937 	info->osps_cache.osc_params.ss_chn_mask =
938 	    wlan_vdev_mlme_get_rxchainmask(vdev);
939 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
940 
941 	info->osps_cache.osc_params.ss_short_report =
942 		SPECTRAL_SCAN_SHORT_REPORT_DEFAULT;
943 
944 	info->osps_cache.osc_params.ss_fft_period =
945 		SPECTRAL_SCAN_FFT_PERIOD_DEFAULT;
946 
947 	info->osps_cache.osc_params.ss_frequency.cfreq1 =
948 		SPECTRAL_SCAN_FREQUENCY_DEFAULT;
949 	info->osps_cache.osc_params.ss_frequency.cfreq2 =
950 		SPECTRAL_SCAN_FREQUENCY_DEFAULT;
951 
952 	sscan_bw = get_default_sscan_bw(spectral, smode, false);
953 	if (sscan_bw >= CH_WIDTH_INVALID) {
954 		spectral_err("Invalid sscan BW %u", sscan_bw);
955 		return QDF_STATUS_E_FAILURE;
956 	}
957 	info->osps_cache.osc_params.ss_bandwidth = sscan_bw;
958 
959 	/* The cache is now valid */
960 	info->osps_cache.osc_is_valid = 1;
961 
962 	return QDF_STATUS_SUCCESS;
963 }
964 
965 /**
966  * target_if_log_read_spectral_active() - Helper function to log whether
967  * spectral is active after reading cache
968  * @function_name: Function name
969  * @output: whether spectral is active or not
970  *
971  * Helper function to log whether spectral is active after reading cache
972  *
973  * Return: none
974  */
975 static void
976 target_if_log_read_spectral_active(
977 	const char *function_name,
978 	unsigned char output)
979 {
980 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE. Returning val=%u",
981 		       function_name, output);
982 }
983 
984 /**
985  * target_if_log_read_spectral_enabled() - Helper function to log whether
986  * spectral is enabled after reading cache
987  * @function_name: Function name
988  * @output: whether spectral is enabled or not
989  *
990  * Helper function to log whether spectral is enabled after reading cache
991  *
992  * Return: none
993  */
994 static void
995 target_if_log_read_spectral_enabled(
996 	const char *function_name,
997 	unsigned char output)
998 {
999 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED. Returning val=%u",
1000 		       function_name, output);
1001 }
1002 
1003 /**
1004  * target_if_log_read_spectral_enabled() - Helper function to log spectral
1005  * parameters after reading cache
1006  * @function_name: Function name
1007  * @pparam: Spectral parameters
1008  *
1009  * Helper function to log spectral parameters after reading cache
1010  *
1011  * Return: none
1012  */
1013 static void
1014 target_if_log_read_spectral_params(
1015 	const char *function_name,
1016 	struct spectral_config *pparam)
1017 {
1018 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_PARAMS. Returning following params:\nss_count = %u\nss_period = %u\nss_recapture = %u\nss_spectral_pri = %u\nss_fft_size = %u\nss_gc_ena = %u\nss_restart_ena = %u\nss_noise_floor_ref = %d\nss_init_delay = %u\nss_nb_tone_thr = %u\nss_str_bin_thr = %u\nss_wb_rpt_mode = %u\nss_rssi_rpt_mode = %u\nss_rssi_thr = %d\nss_pwr_format = %u\nss_rpt_mode = %u\nss_bin_scale = %u\nss_dbm_adj = %u\nss_chn_mask = %u\nss_frequency1=%u\nss_frequency2=%u\n",
1019 		       function_name,
1020 		       pparam->ss_count,
1021 		       pparam->ss_period,
1022 		       pparam->ss_recapture,
1023 		       pparam->ss_spectral_pri,
1024 		       pparam->ss_fft_size,
1025 		       pparam->ss_gc_ena,
1026 		       pparam->ss_restart_ena,
1027 		       (int8_t)pparam->ss_noise_floor_ref,
1028 		       pparam->ss_init_delay,
1029 		       pparam->ss_nb_tone_thr,
1030 		       pparam->ss_str_bin_thr,
1031 		       pparam->ss_wb_rpt_mode,
1032 		       pparam->ss_rssi_rpt_mode,
1033 		       (int8_t)pparam->ss_rssi_thr,
1034 		       pparam->ss_pwr_format,
1035 		       pparam->ss_rpt_mode,
1036 		       pparam->ss_bin_scale,
1037 		       pparam->ss_dbm_adj,
1038 		       pparam->ss_chn_mask,
1039 		       pparam->ss_frequency.cfreq1,
1040 		       pparam->ss_frequency.cfreq2);
1041 }
1042 
1043 /**
1044  * target_if_log_read_spectral_active_catch_validate() - Helper function to
1045  * log whether spectral is active after initializing the cache
1046  * @function_name: Function name
1047  * @output: whether spectral is active or not
1048  *
1049  * Helper function to log whether spectral is active after initializing cache
1050  *
1051  * Return: none
1052  */
1053 static void
1054 target_if_log_read_spectral_active_catch_validate(
1055 	const char *function_name,
1056 	unsigned char output)
1057 {
1058 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE on initial cache validation\nReturning val=%u",
1059 		       function_name, output);
1060 }
1061 
1062 /**
1063  * target_if_log_read_spectral_enabled_catch_validate() - Helper function to
1064  * log whether spectral is enabled after initializing the cache
1065  * @function_name: Function name
1066  * @output: whether spectral is enabled or not
1067  *
1068  * Helper function to log whether spectral is enabled after initializing cache
1069  *
1070  * Return: none
1071  */
1072 static void
1073 target_if_log_read_spectral_enabled_catch_validate(
1074 	const char *function_name,
1075 	unsigned char output)
1076 {
1077 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED on initial cache validation\nReturning val=%u\n",
1078 		       function_name, output);
1079 }
1080 
1081 /**
1082  * target_if_log_read_spectral_params_catch_validate() - Helper function to
1083  * log spectral parameters after initializing the cache
1084  * @function_name: Function name
1085  * @pparam: Spectral parameters
1086  *
1087  * Helper function to log spectral parameters after initializing the cache
1088  *
1089  * Return: none
1090  */
1091 static void
1092 target_if_log_read_spectral_params_catch_validate(
1093 	const char *function_name,
1094 	struct spectral_config *pparam)
1095 {
1096 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_PARAMS on initial cache validation\nReturning following params:\nss_count = %u\nss_period = %u\nss_recapture = %u\nss_spectral_pri = %u\nss_fft_size = %u\nss_gc_ena = %u\nss_restart_ena = %u\nss_noise_floor_ref = %d\nss_init_delay = %u\nss_nb_tone_thr = %u\nss_str_bin_thr = %u\nss_wb_rpt_mode = %u\nss_rssi_rpt_mode = %u\nss_rssi_thr = %d\nss_pwr_format = %u\nss_rpt_mode = %u\nss_bin_scale = %u\nss_dbm_adj = %u\nss_chn_mask = %u",
1097 		       function_name,
1098 		       pparam->ss_count,
1099 		       pparam->ss_period,
1100 		       pparam->ss_recapture,
1101 		       pparam->ss_spectral_pri,
1102 		       pparam->ss_fft_size,
1103 		       pparam->ss_gc_ena,
1104 		       pparam->ss_restart_ena,
1105 		       (int8_t)pparam->ss_noise_floor_ref,
1106 		       pparam->ss_init_delay,
1107 		       pparam->ss_nb_tone_thr,
1108 		       pparam->ss_str_bin_thr,
1109 		       pparam->ss_wb_rpt_mode,
1110 		       pparam->ss_rssi_rpt_mode,
1111 		       (int8_t)pparam->ss_rssi_thr,
1112 		       pparam->ss_pwr_format,
1113 		       pparam->ss_rpt_mode,
1114 		       pparam->ss_bin_scale,
1115 		       pparam->ss_dbm_adj, pparam->ss_chn_mask);
1116 }
1117 
1118 /**
1119  * target_if_spectral_info_read() - Read spectral information from the cache.
1120  * @spectral: Pointer to Spectral target_if internal private data
1121  * @smode: Spectral scan mode
1122  * @specifier: target_if_spectral_info enumeration specifying which
1123  * information is required
1124  * @output: Void output pointer into which the information will be read
1125  * @output_len: size of object pointed to by output pointer
1126  *
1127  * Read spectral parameters or the desired state information from the cache.
1128  *
1129  * Return: 0 on success, negative error code on failure
1130  */
1131 static int
1132 target_if_spectral_info_read(
1133 	struct target_if_spectral *spectral,
1134 	enum spectral_scan_mode smode,
1135 	enum target_if_spectral_info specifier,
1136 	void *output, int output_len)
1137 {
1138 	/*
1139 	 * Note: This function is designed to be able to accommodate
1140 	 * WMI reads for defaults, non-cacheable information, etc
1141 	 * if required.
1142 	 */
1143 	struct target_if_spectral_param_state_info *info;
1144 	int is_cacheable = 0;
1145 	int init_def_retval = 0;
1146 
1147 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1148 		spectral_err("Invalid Spectral mode %u", smode);
1149 		return -EINVAL;
1150 	}
1151 	info = &spectral->param_info[smode];
1152 
1153 	if (!output)
1154 		return -EINVAL;
1155 
1156 	switch (specifier) {
1157 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
1158 		if (output_len != sizeof(info->osps_cache.osc_spectral_active))
1159 			return -EINVAL;
1160 		is_cacheable = 1;
1161 		break;
1162 
1163 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
1164 		if (output_len != sizeof(info->osps_cache.osc_spectral_enabled))
1165 			return -EINVAL;
1166 		is_cacheable = 1;
1167 		break;
1168 
1169 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
1170 		if (output_len != sizeof(info->osps_cache.osc_params))
1171 			return -EINVAL;
1172 		is_cacheable = 1;
1173 		break;
1174 
1175 	default:
1176 		spectral_err("Unknown target_if_spectral_info specifier");
1177 		return -EINVAL;
1178 	}
1179 
1180 	qdf_spin_lock_bh(&info->osps_lock);
1181 
1182 	if (is_cacheable) {
1183 		if (info->osps_cache.osc_is_valid) {
1184 			switch (specifier) {
1185 			case TARGET_IF_SPECTRAL_INFO_ACTIVE:
1186 				qdf_mem_copy(
1187 				  output,
1188 				  &info->osps_cache.osc_spectral_active,
1189 				  sizeof(info->osps_cache.osc_spectral_active));
1190 
1191 				target_if_log_read_spectral_active(
1192 					__func__,
1193 					*((unsigned char *)output));
1194 				break;
1195 
1196 			case TARGET_IF_SPECTRAL_INFO_ENABLED:
1197 				qdf_mem_copy(
1198 				  output,
1199 				  &info->osps_cache.osc_spectral_enabled,
1200 				  sizeof(
1201 					info->osps_cache.osc_spectral_enabled));
1202 
1203 				target_if_log_read_spectral_enabled(
1204 					__func__,
1205 					*((unsigned char *)output));
1206 				break;
1207 
1208 			case TARGET_IF_SPECTRAL_INFO_PARAMS:
1209 				qdf_mem_copy(
1210 				  output,
1211 				  &info->osps_cache.osc_params,
1212 				  sizeof(info->osps_cache.osc_params));
1213 
1214 				target_if_log_read_spectral_params(
1215 					__func__,
1216 					(struct spectral_config *)output);
1217 				break;
1218 
1219 			default:
1220 				/* We can't reach this point */
1221 				break;
1222 			}
1223 			qdf_spin_unlock_bh(&info->osps_lock);
1224 			return 0;
1225 		}
1226 	}
1227 
1228 	/* Cache is invalid */
1229 
1230 	/*
1231 	 * If WMI Reads are implemented to fetch defaults/non-cacheable info,
1232 	 * then the below implementation will change
1233 	 */
1234 	init_def_retval =
1235 			target_if_spectral_info_init_defaults(spectral, smode);
1236 	if (init_def_retval != QDF_STATUS_SUCCESS) {
1237 		qdf_spin_unlock_bh(&info->osps_lock);
1238 		if (init_def_retval == QDF_STATUS_E_NOENT)
1239 			return -ENOENT;
1240 		else
1241 			return -EINVAL;
1242 	}
1243 	/* target_if_spectral_info_init_defaults() has set cache to valid */
1244 
1245 	switch (specifier) {
1246 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
1247 		qdf_mem_copy(output,
1248 			     &info->osps_cache.osc_spectral_active,
1249 			     sizeof(info->osps_cache.osc_spectral_active));
1250 
1251 		target_if_log_read_spectral_active_catch_validate(
1252 			__func__,
1253 			*((unsigned char *)output));
1254 		break;
1255 
1256 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
1257 		qdf_mem_copy(output,
1258 			     &info->osps_cache.osc_spectral_enabled,
1259 			     sizeof(info->osps_cache.osc_spectral_enabled));
1260 
1261 		target_if_log_read_spectral_enabled_catch_validate(
1262 			__func__,
1263 			*((unsigned char *)output));
1264 		break;
1265 
1266 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
1267 		qdf_mem_copy(output,
1268 			     &info->osps_cache.osc_params,
1269 			     sizeof(info->osps_cache.osc_params));
1270 
1271 		target_if_log_read_spectral_params_catch_validate(
1272 			__func__,
1273 			(struct spectral_config *)output);
1274 
1275 		break;
1276 
1277 	default:
1278 		/* We can't reach this point */
1279 		break;
1280 	}
1281 
1282 	qdf_spin_unlock_bh(&info->osps_lock);
1283 
1284 	return 0;
1285 }
1286 
1287 /**
1288  * target_if_log_write_spectral_active() - Helper function to log inputs and
1289  * return value of call to configure the Spectral 'active' configuration,
1290  * TARGET_IF_SPECTRAL_INFO_ACTIVE into firmware
1291  * @function_name: Function name in which this is called
1292  * @pval: whether spectral is active or not
1293  * @ret: return value of the firmware write function
1294  *
1295  * Return: none
1296  */
1297 static void
1298 target_if_log_write_spectral_active(
1299 	const char *function_name,
1300 	uint8_t pval,
1301 	int ret)
1302 {
1303 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE with val=%u status=%d",
1304 		       function_name, pval, ret);
1305 }
1306 
1307 /**
1308  * target_if_log_write_spectral_enabled() - Helper function to log inputs and
1309  * return value of call to configure the Spectral 'enabled' configuration,
1310  * TARGET_IF_SPECTRAL_INFO_ENABLED into firmware
1311  * @function_name: Function name in which this is called
1312  * @pval: whether spectral is enabled or not
1313  * @ret: return value of the firmware write function
1314  *
1315  * Return: none
1316  */
1317 static void
1318 target_if_log_write_spectral_enabled(
1319 	const char *function_name,
1320 	uint8_t pval,
1321 	int ret)
1322 {
1323 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED with val=%u status=%d",
1324 		       function_name, pval, ret);
1325 }
1326 
1327 /**
1328  * target_if_log_write_spectral_params() - Helper function to log inputs and
1329  * return value of call to configure Spectral parameters,
1330  * TARGET_IF_SPECTRAL_INFO_PARAMS into firmware
1331  * @param: Spectral parameters
1332  * @function_name: Function name in which this is called
1333  * @ret: return value of the firmware write function
1334  *
1335  * Return: none
1336  */
1337 static void
1338 target_if_log_write_spectral_params(
1339 	struct spectral_config *param,
1340 	const char *function_name,
1341 	int ret)
1342 {
1343 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_PARAMS. Params:\nss_count = %u\nss_period = %u\nss_recapture = %u\nss_spectral_pri = %u\nss_fft_size = %u\nss_gc_ena = %u\nss_restart_ena = %u\nss_noise_floor_ref = %d\nss_init_delay = %u\nss_nb_tone_thr = %u\nss_str_bin_thr = %u\nss_wb_rpt_mode = %u\nss_rssi_rpt_mode = %u\nss_rssi_thr = %d\nss_pwr_format = %u\nss_rpt_mode = %u\nss_bin_scale = %u\nss_dbm_adj = %u\nss_chn_mask = %u\nss_frequency1=%u\nss_frequency2=%u\nstatus = %d",
1344 		       function_name,
1345 		       param->ss_count,
1346 		       param->ss_period,
1347 		       param->ss_recapture,
1348 		       param->ss_spectral_pri,
1349 		       param->ss_fft_size,
1350 		       param->ss_gc_ena,
1351 		       param->ss_restart_ena,
1352 		       (int8_t)param->ss_noise_floor_ref,
1353 		       param->ss_init_delay,
1354 		       param->ss_nb_tone_thr,
1355 		       param->ss_str_bin_thr,
1356 		       param->ss_wb_rpt_mode,
1357 		       param->ss_rssi_rpt_mode,
1358 		       (int8_t)param->ss_rssi_thr,
1359 		       param->ss_pwr_format,
1360 		       param->ss_rpt_mode,
1361 		       param->ss_bin_scale,
1362 		       param->ss_dbm_adj,
1363 		       param->ss_chn_mask,
1364 		       param->ss_frequency.cfreq1,
1365 		       param->ss_frequency.cfreq2,
1366 		       ret);
1367 }
1368 
1369 /**
1370  * target_if_spectral_info_write() - Write Spectral information to the
1371  * firmware, and update cache
1372  * @spectral: Pointer to Spectral target_if internal private data
1373  * @smode: Spectral scan mode
1374  * @specifier: target_if_spectral_info enumeration specifying which
1375  * information is involved
1376  * @input: void input pointer containing the information to be written
1377  * @input_len: size of object pointed to by input pointer
1378  *
1379  * Write Spectral parameters or the desired state information to
1380  * the firmware, and update cache
1381  *
1382  * Return: 0 on success, negative error code on failure
1383  */
1384 static int
1385 target_if_spectral_info_write(
1386 	struct target_if_spectral *spectral,
1387 	enum spectral_scan_mode smode,
1388 	enum target_if_spectral_info specifier,
1389 	void *input, int input_len)
1390 {
1391 	struct target_if_spectral_param_state_info *info;
1392 	int ret;
1393 	uint8_t *pval = NULL;
1394 	struct spectral_config *param = NULL;
1395 
1396 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1397 		spectral_err("Invalid Spectral mode %u", smode);
1398 		return -EINVAL;
1399 	}
1400 	info = &spectral->param_info[smode];
1401 
1402 	if (!input)
1403 		return -EINVAL;
1404 
1405 	switch (specifier) {
1406 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
1407 		if (input_len != sizeof(info->osps_cache.osc_spectral_active))
1408 			return -EINVAL;
1409 
1410 		pval = (uint8_t *)input;
1411 
1412 		qdf_spin_lock_bh(&info->osps_lock);
1413 		ret = target_if_send_vdev_spectral_enable_cmd(spectral, smode,
1414 							      1, *pval, 0, 0);
1415 
1416 		target_if_log_write_spectral_active(
1417 			__func__,
1418 			*pval,
1419 			ret);
1420 
1421 		if (ret < 0) {
1422 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
1423 				     ret);
1424 			qdf_spin_unlock_bh(&info->osps_lock);
1425 			return ret;
1426 		}
1427 
1428 		info->osps_cache.osc_spectral_active = *pval;
1429 
1430 		/* The cache is now valid */
1431 		info->osps_cache.osc_is_valid = 1;
1432 
1433 		qdf_spin_unlock_bh(&info->osps_lock);
1434 		break;
1435 
1436 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
1437 		if (input_len != sizeof(info->osps_cache.osc_spectral_enabled))
1438 			return -EINVAL;
1439 
1440 		pval = (uint8_t *)input;
1441 
1442 		qdf_spin_lock_bh(&info->osps_lock);
1443 		ret = target_if_send_vdev_spectral_enable_cmd(spectral, smode,
1444 							      0, 0, 1, *pval);
1445 
1446 		target_if_log_write_spectral_enabled(
1447 			__func__,
1448 			*pval,
1449 			ret);
1450 
1451 		if (ret < 0) {
1452 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
1453 				     ret);
1454 			qdf_spin_unlock_bh(&info->osps_lock);
1455 			return ret;
1456 		}
1457 
1458 		info->osps_cache.osc_spectral_enabled = *pval;
1459 
1460 		/* The cache is now valid */
1461 		info->osps_cache.osc_is_valid = 1;
1462 
1463 		qdf_spin_unlock_bh(&info->osps_lock);
1464 		break;
1465 
1466 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
1467 		if (input_len != sizeof(info->osps_cache.osc_params))
1468 			return -EINVAL;
1469 
1470 		param = (struct spectral_config *)input;
1471 
1472 		qdf_spin_lock_bh(&info->osps_lock);
1473 		ret = target_if_send_vdev_spectral_configure_cmd(spectral,
1474 								 smode, param);
1475 
1476 		target_if_log_write_spectral_params(
1477 			param,
1478 			__func__,
1479 			ret);
1480 
1481 		if (ret < 0) {
1482 			spectral_err("target_if_send_vdev_spectral_configure_cmd failed with error=%d",
1483 				     ret);
1484 			qdf_spin_unlock_bh(&info->osps_lock);
1485 			return ret;
1486 		}
1487 
1488 		qdf_mem_copy(&info->osps_cache.osc_params,
1489 			     param, sizeof(info->osps_cache.osc_params));
1490 
1491 		/* The cache is now valid */
1492 		info->osps_cache.osc_is_valid = 1;
1493 
1494 		qdf_spin_unlock_bh(&info->osps_lock);
1495 		break;
1496 
1497 	default:
1498 		spectral_err("Unknown target_if_spectral_info specifier");
1499 		return -EINVAL;
1500 	}
1501 
1502 	return 0;
1503 }
1504 
1505 /**
1506  * target_if_spectral_get_tsf64() - Function to get the TSF value
1507  * @arg: Pointer to handle for Spectral target_if internal private data
1508  *
1509  * Get the last TSF received in WMI buffer
1510  *
1511  * Return: TSF value
1512  */
1513 static uint64_t
1514 target_if_spectral_get_tsf64(void *arg)
1515 {
1516 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1517 
1518 	return spectral->tsf64;
1519 }
1520 
1521 /**
1522  * target_if_spectral_get_capability() - Function to get whether a
1523  * given Spectral hardware capability is available
1524  * @arg: Pointer to handle for Spectral target_if internal private data
1525  * @type: Spectral hardware capability type
1526  *
1527  * Get whether a given Spectral hardware capability is available
1528  *
1529  * Return: True if the capability is available, false if the capability is not
1530  * available
1531  */
1532 uint32_t
1533 target_if_spectral_get_capability(void *arg, enum spectral_capability_type type)
1534 {
1535 	int status = STATUS_FAIL;
1536 
1537 	switch (type) {
1538 	case SPECTRAL_CAP_PHYDIAG:
1539 	case SPECTRAL_CAP_RADAR:
1540 	case SPECTRAL_CAP_SPECTRAL_SCAN:
1541 	case SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN:
1542 		status = STATUS_PASS;
1543 		break;
1544 	default:
1545 		status = STATUS_FAIL;
1546 	}
1547 	return status;
1548 }
1549 
1550 /**
1551  * target_if_spectral_set_rxfilter() - Set the RX Filter before Spectral start
1552  * @arg: Pointer to handle for Spectral target_if internal private data
1553  * @rxfilter: Rx filter to be used
1554  *
1555  * Note: This is only a placeholder function. It is not currently required since
1556  * FW should be taking care of setting the required filters.
1557  *
1558  * Return: 0
1559  */
1560 uint32_t
1561 target_if_spectral_set_rxfilter(void *arg, int rxfilter)
1562 {
1563 	/*
1564 	 * Will not be required since enabling of spectral in firmware
1565 	 * will take care of this
1566 	 */
1567 	return 0;
1568 }
1569 
1570 /**
1571  * target_if_spectral_get_rxfilter() - Get the current RX Filter settings
1572  * @arg: Pointer to handle for Spectral target_if internal private data
1573  *
1574  * Note: This is only a placeholder function. It is not currently required since
1575  * FW should be taking care of setting the required filters.
1576  *
1577  * Return: 0
1578  */
1579 uint32_t
1580 target_if_spectral_get_rxfilter(void *arg)
1581 {
1582 	/*
1583 	 * Will not be required since enabling of spectral in firmware
1584 	 * will take care of this
1585 	 */
1586 	return 0;
1587 }
1588 
1589 /**
1590  * target_if_sops_is_spectral_active() - Get whether Spectral is active
1591  * @arg: Pointer to handle for Spectral target_if internal private data
1592  * @smode: Spectral scan mode
1593  *
1594  * Function to check whether Spectral is active
1595  *
1596  * Return: True if Spectral is active, false if Spectral is not active
1597  */
1598 uint32_t
1599 target_if_sops_is_spectral_active(void *arg, enum spectral_scan_mode smode)
1600 {
1601 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1602 	uint8_t val = 0;
1603 	int ret;
1604 
1605 	ret = target_if_spectral_info_read(
1606 		spectral,
1607 		smode,
1608 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
1609 		&val, sizeof(val));
1610 
1611 	if (ret != 0) {
1612 		/*
1613 		 * Could not determine if Spectral is active.
1614 		 * Return false as a safe value.
1615 		 * XXX: Consider changing the function prototype
1616 		 * to be able to indicate failure to fetch value.
1617 		 */
1618 		return 0;
1619 	}
1620 
1621 	return val;
1622 }
1623 
1624 /**
1625  * target_if_sops_is_spectral_enabled() - Get whether Spectral is enabled
1626  * @arg: Pointer to handle for Spectral target_if internal private data
1627  * @smode: Spectral scan mode
1628  *
1629  * Function to check whether Spectral is enabled
1630  *
1631  * Return: True if Spectral is enabled, false if Spectral is not enabled
1632  */
1633 uint32_t
1634 target_if_sops_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
1635 {
1636 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1637 	uint8_t val = 0;
1638 	int ret;
1639 
1640 	ret = target_if_spectral_info_read(
1641 		spectral,
1642 		smode,
1643 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1644 		&val, sizeof(val));
1645 
1646 	if (ret != 0) {
1647 		/*
1648 		 * Could not determine if Spectral is enabled.
1649 		 * Return false as a safe value.
1650 		 * XXX: Consider changing the function prototype
1651 		 * to be able to indicate failure to fetch value.
1652 		 */
1653 		return 0;
1654 	}
1655 
1656 	return val;
1657 }
1658 
1659 /**
1660  * target_if_sops_start_spectral_scan() - Start Spectral scan
1661  * @arg: Pointer to handle for Spectral target_if internal private data
1662  * @smode: Spectral scan mode
1663  * @err: Spectral error code
1664  *
1665  * Function to start spectral scan
1666  *
1667  * Return: 0 on success else failure
1668  */
1669 uint32_t
1670 target_if_sops_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
1671 				   enum spectral_cp_error_code *err)
1672 {
1673 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1674 	uint8_t val = 1;
1675 	uint8_t enabled = 0;
1676 	int ret;
1677 
1678 	ret = target_if_spectral_info_read(
1679 		spectral,
1680 		smode,
1681 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1682 		&enabled, sizeof(enabled));
1683 
1684 	if (ret != 0) {
1685 		/*
1686 		 * Could not determine if Spectral is enabled. Assume we need
1687 		 * to enable it
1688 		 */
1689 		enabled = 0;
1690 	}
1691 
1692 	if (!enabled) {
1693 		ret = target_if_spectral_info_write(
1694 			spectral,
1695 			smode,
1696 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1697 			&val, sizeof(val));
1698 
1699 		if (ret != 0)
1700 			return ret;
1701 	}
1702 
1703 	ret = target_if_spectral_info_write(
1704 		spectral,
1705 		smode,
1706 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
1707 		&val, sizeof(val));
1708 
1709 	if (ret != 0)
1710 		return ret;
1711 
1712 	return 0;
1713 }
1714 
1715 /**
1716  * target_if_sops_stop_spectral_scan() - Stop Spectral scan
1717  * @arg: Pointer to handle for Spectral target_if internal private data
1718  * @smode: Spectral scan mode
1719  *
1720  * Function to stop spectral scan
1721  *
1722  * Return: 0 on success else failure
1723  */
1724 uint32_t
1725 target_if_sops_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
1726 {
1727 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1728 	uint8_t val = 0;
1729 	int tempret, ret = 0;
1730 	uint8_t enabled = 0;
1731 
1732 	tempret = target_if_spectral_info_read(
1733 		spectral,
1734 		smode,
1735 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1736 		&enabled, sizeof(enabled));
1737 
1738 	if (tempret)
1739 		/*
1740 		 * Could not determine if Spectral is enabled. Assume scan is
1741 		 * not in progress
1742 		 */
1743 		enabled = 0;
1744 
1745 	/* if scan is not enabled, no need to send stop to FW */
1746 	if (!enabled)
1747 		return -EPERM;
1748 
1749 	tempret = target_if_spectral_info_write(
1750 			spectral,
1751 			smode,
1752 			TARGET_IF_SPECTRAL_INFO_ACTIVE,
1753 			&val, sizeof(val));
1754 
1755 	if (tempret != 0)
1756 		ret = tempret;
1757 
1758 	tempret = target_if_spectral_info_write(
1759 			spectral,
1760 			smode,
1761 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1762 			&val, sizeof(val));
1763 
1764 	if (tempret != 0)
1765 		ret = tempret;
1766 
1767 	if (ret == 0 && smode == SPECTRAL_SCAN_MODE_AGILE) {
1768 		struct target_if_spectral_ops *p_sops;
1769 		struct spectral_config *sparams;
1770 
1771 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1772 		sparams = &spectral->params[smode];
1773 		sparams->ss_frequency.cfreq1 = 0;
1774 		sparams->ss_frequency.cfreq2 = 0;
1775 
1776 		p_sops->configure_spectral(spectral, sparams, smode);
1777 	}
1778 
1779 	return ret;
1780 }
1781 
1782 /**
1783  * target_if_spectral_get_extension_channel() - Get the Extension channel
1784  * @arg: Pointer to handle for Spectral target_if internal private data
1785  * @smode: Spectral scan mode
1786  *
1787  * Function to get the current Extension channel (in MHz)
1788  *
1789  * Return: Current Extension channel (in MHz) on success, 0 on failure or if
1790  * extension channel is not present.
1791  */
1792 uint32_t
1793 target_if_spectral_get_extension_channel(void *arg,
1794 					 enum spectral_scan_mode smode)
1795 {
1796 	/*
1797 	 * XXX: Once we expand to use cases where Spectral could be activated
1798 	 * without a channel being set to VDEV, we need to consider returning a
1799 	 * negative value in case of failure and having all callers handle this.
1800 	 */
1801 
1802 	struct target_if_spectral *spectral = NULL;
1803 	struct wlan_objmgr_vdev *vdev = NULL;
1804 	uint16_t sec20chan_freq = 0;
1805 
1806 	qdf_assert_always(arg);
1807 	spectral = (struct target_if_spectral *)arg;
1808 
1809 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1810 		spectral_err("Invalid Spectral mode %u", smode);
1811 		return 0;
1812 	}
1813 	vdev = target_if_spectral_get_vdev(spectral, smode);
1814 	if (!vdev)
1815 		return 0;
1816 
1817 	if (target_if_vdev_get_sec20chan_freq_mhz(vdev, &sec20chan_freq) < 0) {
1818 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1819 		return 0;
1820 	}
1821 
1822 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1823 
1824 	return sec20chan_freq;
1825 }
1826 
1827 /**
1828  * target_if_spectral_get_current_channel() - Get the current channel
1829  * @arg: Pointer to handle for Spectral target_if internal private data
1830  * @smode: Spectral scan mode
1831  *
1832  * Function to get the current channel (in MHz)
1833  *
1834  * Return: Current channel (in MHz) on success, 0 on failure
1835  */
1836 uint32_t
1837 target_if_spectral_get_current_channel(void *arg, enum spectral_scan_mode smode)
1838 {
1839 	/*
1840 	 * XXX: Once we expand to use cases where Spectral could be activated
1841 	 * without a channel being set to VDEV, we need to consider returning a
1842 	 * negative value in case of failure and having all callers handle this.
1843 	 */
1844 
1845 	struct target_if_spectral *spectral = NULL;
1846 	int16_t chan_freq = 0;
1847 	struct wlan_objmgr_vdev *vdev = NULL;
1848 
1849 	qdf_assert_always(arg);
1850 	spectral = (struct target_if_spectral *)arg;
1851 
1852 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1853 		spectral_err("Invalid Spectral mode %u", smode);
1854 		return 0;
1855 	}
1856 	vdev = target_if_spectral_get_vdev(spectral, smode);
1857 	if (!vdev)
1858 		return 0;
1859 
1860 	chan_freq = target_if_vdev_get_chan_freq(vdev);
1861 	if (chan_freq < 0) {
1862 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1863 		return 0;
1864 	}
1865 
1866 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1867 
1868 	return chan_freq;
1869 }
1870 
1871 /**
1872  * target_if_spectral_reset_hw() - Reset the hardware
1873  * @arg: Pointer to handle for Spectral target_if internal private data
1874  *
1875  * This is only a placeholder since it is not currently required in the offload
1876  * case.
1877  *
1878  * Return: 0
1879  */
1880 uint32_t
1881 target_if_spectral_reset_hw(void *arg)
1882 {
1883 	not_yet_implemented();
1884 	return 0;
1885 }
1886 
1887 /**
1888  * target_if_spectral_get_chain_noise_floor() - Get the Chain noise floor from
1889  * Noisefloor history buffer
1890  * @arg: Pointer to handle for Spectral target_if internal private data
1891  * @nf_buf: Pointer to buffer into which chain Noise Floor data should be copied
1892  *
1893  * This is only a placeholder since it is not currently required in the offload
1894  * case.
1895  *
1896  * Return: 0
1897  */
1898 uint32_t
1899 target_if_spectral_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1900 {
1901 	not_yet_implemented();
1902 	return 0;
1903 }
1904 
1905 /**
1906  * target_if_spectral_get_ext_noisefloor() - Get the extension channel
1907  * noisefloor
1908  * @arg: Pointer to handle for Spectral target_if internal private data
1909  *
1910  * This is only a placeholder since it is not currently required in the offload
1911  * case.
1912  *
1913  * Return: 0
1914  */
1915 int8_t
1916 target_if_spectral_get_ext_noisefloor(void *arg)
1917 {
1918 	not_yet_implemented();
1919 	return 0;
1920 }
1921 
1922 /**
1923  * target_if_spectral_get_ctl_noisefloor() - Get the control channel noisefloor
1924  * @arg: Pointer to handle for Spectral target_if internal private data
1925  *
1926  * This is only a placeholder since it is not currently required in the offload
1927  * case.
1928  *
1929  * Return: 0
1930  */
1931 int8_t
1932 target_if_spectral_get_ctl_noisefloor(void *arg)
1933 {
1934 	not_yet_implemented();
1935 	return 0;
1936 }
1937 
1938 /**
1939  * target_if_spectral_sops_configure_params() - Configure user supplied Spectral
1940  *                                         parameters
1941  * @arg: Pointer to handle for Spectral target_if internal private data
1942  * @params: Spectral parameters
1943  * @smode: Spectral scan mode
1944  *
1945  * Function to configure spectral parameters
1946  *
1947  * Return: 0 on success else failure
1948  */
1949 uint32_t
1950 target_if_spectral_sops_configure_params(
1951 	void *arg, struct spectral_config *params,
1952 	enum spectral_scan_mode smode)
1953 {
1954 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1955 
1956 	return target_if_spectral_info_write(
1957 		spectral,
1958 		smode,
1959 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1960 		params, sizeof(*params));
1961 }
1962 
1963 /**
1964  * target_if_spectral_sops_get_params() - Get user configured Spectral
1965  * parameters
1966  * @arg: Pointer to handle for Spectral target_if internal private data
1967  * @params: Pointer to buffer into which Spectral parameters should be copied
1968  * @smode: Spectral scan mode
1969  *
1970  * Function to get the configured spectral parameters
1971  *
1972  * Return: 0 on success else failure
1973  */
1974 uint32_t
1975 target_if_spectral_sops_get_params(void *arg, struct spectral_config *params,
1976 				   enum spectral_scan_mode smode)
1977 {
1978 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1979 
1980 	return target_if_spectral_info_read(
1981 		spectral,
1982 		smode,
1983 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1984 		params, sizeof(*params));
1985 }
1986 
1987 /**
1988  * target_if_spectral_get_ent_mask() - Get enterprise mask
1989  * @arg: Pointer to handle for Spectral target_if internal private data
1990  *
1991  * This is only a placeholder since it is not currently required in the offload
1992  * case.
1993  *
1994  * Return: 0
1995  */
1996 static uint32_t
1997 target_if_spectral_get_ent_mask(void *arg)
1998 {
1999 	not_yet_implemented();
2000 	return 0;
2001 }
2002 
2003 /**
2004  * target_if_spectral_get_macaddr() - Get radio MAC address
2005  * @arg: Pointer to handle for Spectral target_if internal private data
2006  * @addr: Pointer to buffer into which MAC address should be copied
2007  *
2008  * Function to get the MAC address of the pdev
2009  *
2010  * Return: 0 on success, -1 on failure
2011  */
2012 static uint32_t
2013 target_if_spectral_get_macaddr(void *arg, char *addr)
2014 {
2015 	uint8_t *myaddr = NULL;
2016 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
2017 	struct wlan_objmgr_pdev *pdev = NULL;
2018 
2019 	pdev = spectral->pdev_obj;
2020 
2021 	wlan_pdev_obj_lock(pdev);
2022 	myaddr = wlan_pdev_get_hw_macaddr(pdev);
2023 	wlan_pdev_obj_unlock(pdev);
2024 	qdf_mem_copy(addr, myaddr, QDF_MAC_ADDR_SIZE);
2025 
2026 	return 0;
2027 }
2028 
2029 /**
2030  * target_if_init_spectral_param_min_max_be() - Initialize Spectral parameter
2031  * min and max values for beryllium chipsets
2032  *
2033  * @spectral: Spectral LMAC object
2034  *
2035  * Return: QDF_STATUS of operation
2036  */
2037 static QDF_STATUS
2038 target_if_init_spectral_param_min_max_be(struct target_if_spectral *spectral)
2039 {
2040 	struct spectral_param_min_max *param_min_max;
2041 	enum phy_ch_width op_bw;
2042 	QDF_STATUS status;
2043 
2044 	param_min_max = &spectral->param_min_max;
2045 	param_min_max->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN3_BE;
2046 
2047 	for (op_bw = CH_WIDTH_20MHZ; op_bw < CH_WIDTH_MAX; op_bw++) {
2048 		bool is_supported;
2049 
2050 		status = wlan_reg_is_chwidth_supported(spectral->pdev_obj,
2051 						       op_bw, &is_supported);
2052 		if (QDF_IS_STATUS_ERROR(status)) {
2053 			spectral_err("Unable to check if ch_width(%d) is supported",
2054 				     op_bw);
2055 			return QDF_STATUS_E_FAILURE;
2056 		}
2057 
2058 		if (!is_supported) {
2059 			param_min_max->fft_size_max[op_bw] = INVALID_FFT_SIZE;
2060 			continue;
2061 		}
2062 
2063 		switch (op_bw) {
2064 		case CH_WIDTH_20MHZ:
2065 			param_min_max->fft_size_max[op_bw] =
2066 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_BE_20MHZ;
2067 			break;
2068 
2069 		case CH_WIDTH_40MHZ:
2070 			param_min_max->fft_size_max[op_bw] =
2071 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_BE_40MHZ;
2072 			break;
2073 
2074 		default:
2075 			param_min_max->fft_size_max[op_bw] =
2076 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_BE;
2077 		}
2078 	}
2079 
2080 	return QDF_STATUS_SUCCESS;
2081 }
2082 
2083 /**
2084  * target_if_init_spectral_param_min_max() - Initialize Spectral parameter
2085  * min and max values
2086  *
2087  * @spectral: Spectral LMAC object
2088  * @gen: Spectral HW generation
2089  * @target_type: Target type
2090  *
2091  * Initialize Spectral parameter min and max values
2092  *
2093  * Return: QDF_STATUS
2094  */
2095 static QDF_STATUS
2096 target_if_init_spectral_param_min_max(
2097 				struct target_if_spectral *spectral,
2098 				enum spectral_gen gen, uint32_t target_type)
2099 {
2100 	struct spectral_param_min_max *param_min_max;
2101 
2102 	if (!spectral) {
2103 		spectral_err("Spectral LMAC object is null");
2104 		return QDF_STATUS_E_NULL_VALUE;
2105 	}
2106 
2107 	if (is_spectral_arch_beryllium(target_type))
2108 		return target_if_init_spectral_param_min_max_be(spectral);
2109 
2110 	param_min_max = &spectral->param_min_max;
2111 	switch (gen) {
2112 	case SPECTRAL_GEN3:
2113 		param_min_max->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN3;
2114 		param_min_max->fft_size_max[CH_WIDTH_20MHZ] =
2115 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
2116 		if (target_type == TARGET_TYPE_QCN9000 ||
2117 		    target_type == TARGET_TYPE_QCN6122 ||
2118 		    target_type == TARGET_TYPE_QCN9160 ||
2119 		    target_type == TARGET_TYPE_QCA5018 ||
2120 		    target_type == TARGET_TYPE_QCA6490 ||
2121 		    target_type == TARGET_TYPE_KIWI ||
2122 		    target_type == TARGET_TYPE_MANGO) {
2123 			param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
2124 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
2125 			param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
2126 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
2127 			param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
2128 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
2129 			param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
2130 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
2131 		} else {
2132 			param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
2133 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
2134 			param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
2135 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
2136 			param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
2137 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
2138 			param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
2139 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
2140 		}
2141 		break;
2142 
2143 	case SPECTRAL_GEN2:
2144 		param_min_max->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN2;
2145 		param_min_max->fft_size_max[CH_WIDTH_20MHZ] =
2146 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
2147 		param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
2148 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
2149 		param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
2150 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
2151 		param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
2152 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
2153 		param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
2154 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
2155 		break;
2156 
2157 	default:
2158 		spectral_err("Invalid spectral generation %d", gen);
2159 		return QDF_STATUS_E_INVAL;
2160 	}
2161 
2162 	return QDF_STATUS_SUCCESS;
2163 }
2164 
2165 /**
2166  * target_if_init_spectral_param_properties() - Initialize Spectral parameter
2167  *                                              properties
2168  * @spectral: Pointer to Spectral target_if internal private data
2169  *
2170  * Initialize Spectral parameter properties
2171  *
2172  * Return: QDF_STATUS
2173  */
2174 static QDF_STATUS
2175 target_if_init_spectral_param_properties(struct target_if_spectral *spectral)
2176 {
2177 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
2178 	int param;
2179 
2180 	/* Initialize default values for properties.
2181 	 * Default values are supported for all the parameters for all modes
2182 	 * and allows different values for each mode for all the parameters .
2183 	 */
2184 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2185 		for (param = 0; param < SPECTRAL_PARAM_MAX; param++) {
2186 			spectral->properties[smode][param].supported = true;
2187 			spectral->properties[smode][param].common_all_modes =
2188 									false;
2189 		}
2190 	}
2191 
2192 	/* Once FW advertisement is in place remove this hard coding */
2193 	smode = SPECTRAL_SCAN_MODE_NORMAL;
2194 	spectral->properties[SPECTRAL_SCAN_MODE_NORMAL]
2195 			[SPECTRAL_PARAM_FREQUENCY].supported = false;
2196 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2197 		spectral->properties[smode]
2198 			[SPECTRAL_PARAM_SPECT_PRI].common_all_modes = true;
2199 		spectral->properties[smode]
2200 			[SPECTRAL_PARAM_SCAN_PERIOD].common_all_modes = true;
2201 		spectral->properties[smode]
2202 			[SPECTRAL_PARAM_INIT_DELAY].common_all_modes = true;
2203 	}
2204 
2205 	return QDF_STATUS_SUCCESS;
2206 }
2207 
2208 /* Bandwidth to half bandwidth mapping */
2209 static const enum phy_ch_width half_bw_map[] = {
2210 #ifdef WLAN_FEATURE_11BE
2211 	[CH_WIDTH_320MHZ] = CH_WIDTH_160MHZ,
2212 #endif
2213 	[CH_WIDTH_80P80MHZ] = CH_WIDTH_80MHZ,
2214 	[CH_WIDTH_160MHZ] = CH_WIDTH_80MHZ,
2215 	[CH_WIDTH_80MHZ] = CH_WIDTH_40MHZ,
2216 	[CH_WIDTH_40MHZ] = CH_WIDTH_20MHZ,
2217 	[CH_WIDTH_20MHZ] = CH_WIDTH_10MHZ,
2218 	[CH_WIDTH_10MHZ] = CH_WIDTH_5MHZ,
2219 	[CH_WIDTH_5MHZ] = CH_WIDTH_INVALID
2220 };
2221 
2222 /**
2223  * target_if_get_half_bandwidth() - Get half bandwidth for a given bandwidth
2224  * @bw: bandwidth
2225  *
2226  * Return: Half bandwidth of @bw
2227  */
2228 static enum phy_ch_width target_if_get_half_bandwidth(enum phy_ch_width bw)
2229 {
2230 	if (bw >= CH_WIDTH_INVALID)
2231 		return CH_WIDTH_INVALID;
2232 
2233 	return half_bw_map[bw];
2234 }
2235 
2236 /**
2237  * target_if_populate_supported_sscan_bws_be() - Populate supported spectral
2238  * scan bandwidths for beryllium chipsets
2239  * @spectral: Spectral LMAC object
2240  *
2241  * Return: QDF_STATUS of operation
2242  */
2243 static QDF_STATUS
2244 target_if_populate_supported_sscan_bws_be(struct target_if_spectral *spectral)
2245 {
2246 	enum phy_ch_width op_bw;
2247 	struct spectral_supported_bws *supported_bws;
2248 	QDF_STATUS status;
2249 
2250 	qdf_assert_always(spectral);
2251 
2252 	/* 20MHz */
2253 	op_bw = CH_WIDTH_20MHZ;
2254 	supported_bws = &spectral->supported_bws
2255 			[SPECTRAL_SCAN_MODE_NORMAL][op_bw];
2256 	supported_bws->bandwidths |= 1 << get_supported_sscan_bw_pos(op_bw);
2257 	spectral->supported_sscan_bw_list
2258 		[SPECTRAL_SCAN_MODE_NORMAL][op_bw] = true;
2259 	supported_bws = &spectral->supported_bws
2260 			[SPECTRAL_SCAN_MODE_AGILE][op_bw];
2261 	supported_bws->bandwidths |= 1 << get_supported_sscan_bw_pos(op_bw);
2262 	spectral->supported_sscan_bw_list
2263 		[SPECTRAL_SCAN_MODE_AGILE][op_bw] = true;
2264 
2265 	for (op_bw = CH_WIDTH_40MHZ; op_bw < CH_WIDTH_MAX; op_bw++) {
2266 		bool is_supported;
2267 		enum phy_ch_width half_op_bw;
2268 
2269 		status = wlan_reg_is_chwidth_supported(spectral->pdev_obj,
2270 						       op_bw, &is_supported);
2271 		if (QDF_IS_STATUS_ERROR(status)) {
2272 			spectral_err("Unable to check if ch_width(%d) is supported",
2273 				     op_bw);
2274 			return QDF_STATUS_E_FAILURE;
2275 		}
2276 
2277 		if (!is_supported)
2278 			continue;
2279 
2280 		spectral_debug("Updating supported bw for op_bw: %d", op_bw);
2281 		/* Normal mode */
2282 		supported_bws = &spectral->supported_bws
2283 				[SPECTRAL_SCAN_MODE_NORMAL][op_bw];
2284 		supported_bws->bandwidths |=
2285 				1 << get_supported_sscan_bw_pos(op_bw);
2286 		spectral->supported_sscan_bw_list
2287 			[SPECTRAL_SCAN_MODE_NORMAL][op_bw] = true;
2288 
2289 		/* Agile mode */
2290 		supported_bws = &spectral->supported_bws
2291 				[SPECTRAL_SCAN_MODE_AGILE][op_bw];
2292 		supported_bws->bandwidths |=
2293 				1 << get_supported_sscan_bw_pos(op_bw);
2294 		spectral->supported_sscan_bw_list
2295 			[SPECTRAL_SCAN_MODE_AGILE][op_bw] = true;
2296 
2297 		half_op_bw = target_if_get_half_bandwidth(op_bw);
2298 		if (half_op_bw != CH_WIDTH_INVALID) {
2299 			supported_bws->bandwidths |=
2300 				1 << get_supported_sscan_bw_pos(half_op_bw);
2301 			spectral->supported_sscan_bw_list
2302 				[SPECTRAL_SCAN_MODE_AGILE][half_op_bw] = true;
2303 		}
2304 	}
2305 
2306 	return QDF_STATUS_SUCCESS;
2307 }
2308 
2309 /**
2310  * target_if_populate_supported_sscan_bws() - Populate supported spectral
2311  * scan bandwidths
2312  * @spectral: Spectral LMAC object
2313  * @target_type: Target type
2314  *
2315  * Return: QDF_STATUS of operation
2316  */
2317 static QDF_STATUS
2318 target_if_populate_supported_sscan_bws(struct target_if_spectral *spectral,
2319 				       uint32_t target_type)
2320 {
2321 	enum spectral_scan_mode smode;
2322 	enum phy_ch_width op_bw;
2323 	struct spectral_supported_bws *supported_bws;
2324 	struct wlan_objmgr_psoc *psoc;
2325 	QDF_STATUS status;
2326 
2327 	qdf_assert_always(spectral);
2328 
2329 	if (is_spectral_arch_beryllium(target_type))
2330 		return target_if_populate_supported_sscan_bws_be(spectral);
2331 
2332 	psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
2333 	if (!psoc) {
2334 		spectral_err("psoc is null");
2335 		return QDF_STATUS_E_NULL_VALUE;
2336 	}
2337 
2338 	for (op_bw = CH_WIDTH_20MHZ; op_bw < CH_WIDTH_MAX; op_bw++) {
2339 		bool is_supported;
2340 
2341 		status = wlan_reg_is_chwidth_supported(spectral->pdev_obj,
2342 						       op_bw, &is_supported);
2343 		if (QDF_IS_STATUS_ERROR(status)) {
2344 			spectral_err("Unable to check if ch_width(%d) is supported",
2345 				     op_bw);
2346 			return QDF_STATUS_E_FAILURE;
2347 		}
2348 
2349 		if (!is_supported)
2350 			continue;
2351 
2352 		spectral_debug("Updating supported bw for op_bw: %d", op_bw);
2353 		smode = SPECTRAL_SCAN_MODE_NORMAL;
2354 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2355 			supported_bws = &spectral->supported_bws[smode][op_bw];
2356 
2357 			if (is_ch_width_160_or_80p80(op_bw) &&
2358 			    smode == SPECTRAL_SCAN_MODE_AGILE) {
2359 				/**
2360 				 * If fragmentation is supported, then only 80Hz
2361 				 * agile width is supported
2362 				 */
2363 				if (spectral->rparams.
2364 				    fragmentation_160[smode]) {
2365 					supported_bws->bandwidths |=
2366 					 1 << get_supported_sscan_bw_pos(
2367 						CH_WIDTH_80MHZ);
2368 					spectral->supported_sscan_bw_list
2369 						[smode][CH_WIDTH_80MHZ] = true;
2370 				}
2371 
2372 				/**
2373 				 * If restricted 80p80 is supported, then both
2374 				 * 160 and 80p80 agile widths are supported for
2375 				 * 160MHz, and only 160MHz agile width is
2376 				 * supported for 80p80
2377 				 */
2378 				if (wlan_psoc_nif_fw_ext_cap_get(
2379 				     psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
2380 					supported_bws->bandwidths |=
2381 						1 << get_supported_sscan_bw_pos(
2382 							CH_WIDTH_160MHZ);
2383 					spectral->supported_sscan_bw_list
2384 						[smode][CH_WIDTH_160MHZ] = true;
2385 
2386 					if (op_bw == CH_WIDTH_160MHZ) {
2387 						supported_bws->bandwidths |=
2388 						1 << get_supported_sscan_bw_pos(
2389 							CH_WIDTH_80P80MHZ);
2390 						spectral->supported_sscan_bw_list
2391 							[smode][CH_WIDTH_80P80MHZ] = true;
2392 					}
2393 				}
2394 			} else {
2395 				supported_bws->bandwidths |=
2396 					1 << get_supported_sscan_bw_pos(
2397 						op_bw);
2398 					spectral->supported_sscan_bw_list
2399 						[smode][op_bw] = true;
2400 			}
2401 		}
2402 	}
2403 
2404 	return QDF_STATUS_SUCCESS;
2405 }
2406 
2407 QDF_STATUS
2408 target_if_init_spectral_capability(struct target_if_spectral *spectral,
2409 				   uint32_t target_type)
2410 {
2411 	struct wlan_objmgr_psoc *psoc;
2412 	struct wlan_objmgr_pdev *pdev;
2413 	struct wlan_psoc_host_spectral_scaling_params *scaling_params;
2414 	uint8_t num_bin_scaling_params, param_idx, pdev_id;
2415 	struct target_psoc_info *tgt_psoc_info;
2416 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
2417 	struct spectral_caps *pcap = &spectral->capability;
2418 	QDF_STATUS status;
2419 
2420 	pdev = spectral->pdev_obj;
2421 	psoc = wlan_pdev_get_psoc(pdev);
2422 	if (!psoc) {
2423 		spectral_err("psoc is null");
2424 		return QDF_STATUS_E_FAILURE;
2425 	}
2426 
2427 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
2428 	if (!tgt_psoc_info) {
2429 		spectral_err("target_psoc_info is null");
2430 		return QDF_STATUS_E_FAILURE;
2431 	}
2432 
2433 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
2434 	num_bin_scaling_params = ext_svc_param->num_bin_scaling_params;
2435 	scaling_params = target_psoc_get_spectral_scaling_params(tgt_psoc_info);
2436 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
2437 
2438 	/* XXX : Workaround: Set Spectral capability */
2439 	pcap = &spectral->capability;
2440 	pcap->phydiag_cap = 1;
2441 	pcap->radar_cap = 1;
2442 	pcap->spectral_cap = wlan_pdev_nif_feat_ext_cap_get(
2443 			pdev, WLAN_PDEV_FEXT_NORMAL_SPECTRAL_SCAN_DIS);
2444 	pcap->advncd_spectral_cap = pcap->spectral_cap;
2445 	pcap->hw_gen = spectral->spectral_gen;
2446 
2447 	pcap->agile_spectral_cap = !wlan_pdev_nif_feat_ext_cap_get(
2448 			pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_DIS);
2449 	pcap->agile_spectral_cap_160 = !wlan_pdev_nif_feat_ext_cap_get(
2450 			pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_160_DIS);
2451 	pcap->agile_spectral_cap_80p80 = !wlan_pdev_nif_feat_ext_cap_get(
2452 			pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_80P80_DIS);
2453 	pcap->agile_spectral_cap_320 = !wlan_pdev_nif_feat_ext_cap_get(
2454 			pdev, WLAN_PDEV_FEXT_AGILE_SPECTRAL_SCAN_320_DIS);
2455 
2456 	if (scaling_params) {
2457 		for (param_idx = 0; param_idx < num_bin_scaling_params;
2458 		     param_idx++) {
2459 			if (scaling_params[param_idx].pdev_id == pdev_id) {
2460 				pcap->is_scaling_params_populated = true;
2461 				pcap->formula_id =
2462 				    scaling_params[param_idx].formula_id;
2463 				pcap->low_level_offset =
2464 				    scaling_params[param_idx].low_level_offset;
2465 				pcap->high_level_offset =
2466 				    scaling_params[param_idx].high_level_offset;
2467 				pcap->rssi_thr =
2468 				    scaling_params[param_idx].rssi_thr;
2469 				pcap->default_agc_max_gain =
2470 				 scaling_params[param_idx].default_agc_max_gain;
2471 				break;
2472 			}
2473 		}
2474 	}
2475 
2476 	pcap->num_detectors_20mhz = 1;
2477 	pcap->num_detectors_40mhz = 1;
2478 	pcap->num_detectors_80mhz = 1;
2479 	if (target_type == TARGET_TYPE_QCN9000 ||
2480 	    target_type == TARGET_TYPE_QCN6122 ||
2481 	    target_type == TARGET_TYPE_QCN9160 ||
2482 	    target_type == TARGET_TYPE_QCA6490 ||
2483 	    target_type == TARGET_TYPE_KIWI ||
2484 	    target_type == TARGET_TYPE_MANGO) {
2485 		pcap->num_detectors_160mhz = 1;
2486 		pcap->num_detectors_80p80mhz = 1;
2487 		pcap->num_detectors_320mhz = 0;
2488 	} else if (is_spectral_arch_beryllium(target_type)) {
2489 		pcap->num_detectors_160mhz = 1;
2490 		pcap->num_detectors_80p80mhz = 0;
2491 		pcap->num_detectors_320mhz = 1;
2492 	} else {
2493 		pcap->num_detectors_160mhz = 2;
2494 		pcap->num_detectors_80p80mhz = 2;
2495 		pcap->num_detectors_320mhz = 0;
2496 	}
2497 
2498 	status = target_if_populate_supported_sscan_bws(spectral, target_type);
2499 	if (QDF_IS_STATUS_ERROR(status)) {
2500 		spectral_err("Unable to populate supported sscan BWs");
2501 		return QDF_STATUS_E_FAILURE;
2502 	}
2503 
2504 	return QDF_STATUS_SUCCESS;
2505 }
2506 
2507 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
2508 /**
2509  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
2510  * internal operations with functions related to spectral simulation
2511  * @p_sops: spectral low level ops table
2512  *
2513  * Initialize spectral target_if internal operations with functions
2514  * related to spectral simulation
2515  *
2516  * Return: None
2517  */
2518 static void
2519 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
2520 {
2521 	/*
2522 	 * Spectral simulation is currently intended for platform transitions
2523 	 * where underlying HW support may not be available for some time.
2524 	 * Hence, we do not currently provide a runtime switch to turn the
2525 	 * simulation on or off.
2526 	 * In case of future requirements where runtime switches are required,
2527 	 * this can be added. But it is suggested to use application layer
2528 	 * simulation as far as possible in such cases, since the main
2529 	 * use of record and replay of samples would concern higher
2530 	 * level sample processing rather than lower level delivery.
2531 	 */
2532 	p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled;
2533 	p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active;
2534 	p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan;
2535 	p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan;
2536 	p_sops->configure_spectral =
2537 		target_if_spectral_sops_sim_configure_params;
2538 	p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params;
2539 }
2540 
2541 #else
2542 /**
2543  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
2544  * internal operations
2545  * @p_sops: spectral low level ops table
2546  *
2547  * Return: None
2548  */
2549 static void
2550 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
2551 {
2552 	p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled;
2553 	p_sops->is_spectral_active = target_if_sops_is_spectral_active;
2554 	p_sops->start_spectral_scan = target_if_sops_start_spectral_scan;
2555 	p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan;
2556 	p_sops->configure_spectral = target_if_spectral_sops_configure_params;
2557 	p_sops->get_spectral_config = target_if_spectral_sops_get_params;
2558 }
2559 #endif
2560 
2561 /**
2562  * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
2563  * operations common to all Spectral chipset generations
2564  *
2565  * Initializes target_if_spectral_ops common to all chipset generations
2566  *
2567  * Return: None
2568  */
2569 static void
2570 target_if_init_spectral_ops_common(void)
2571 {
2572 	struct target_if_spectral_ops *p_sops = &spectral_ops;
2573 
2574 	p_sops->get_tsf64 = target_if_spectral_get_tsf64;
2575 	p_sops->get_capability = target_if_spectral_get_capability;
2576 	p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
2577 	p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
2578 
2579 	target_if_init_spectral_simulation_ops(p_sops);
2580 
2581 	p_sops->get_extension_channel =
2582 	    target_if_spectral_get_extension_channel;
2583 	p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor;
2584 	p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor;
2585 	p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
2586 	p_sops->get_mac_address = target_if_spectral_get_macaddr;
2587 	p_sops->get_current_channel = target_if_spectral_get_current_channel;
2588 	p_sops->reset_hw = target_if_spectral_reset_hw;
2589 	p_sops->get_chain_noise_floor =
2590 	    target_if_spectral_get_chain_noise_floor;
2591 }
2592 
2593 /**
2594  * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
2595  * operations specific to Spectral chipset generation 2.
2596  *
2597  * Initializes target_if_spectral_ops specific to Spectral chipset generation 2.
2598  *
2599  * Return: None
2600  */
2601 static void
2602 target_if_init_spectral_ops_gen2(void)
2603 {
2604 	struct target_if_spectral_ops *p_sops = &spectral_ops;
2605 
2606 	p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2;
2607 }
2608 
2609 #ifdef BIG_ENDIAN_HOST
2610 /**
2611  * spectral_is_host_byte_swap_required() - Check if byte swap has to be done
2612  * on the Host
2613  * @pdev: pdev pointer
2614  * @is_swap_required: Pointer to caller variable
2615  *
2616  * Return: QDF_STATUS of operation
2617  */
2618 static QDF_STATUS
2619 spectral_is_host_byte_swap_required(struct wlan_objmgr_pdev *pdev,
2620 				    bool *is_swap_required)
2621 {
2622 	struct wlan_objmgr_psoc *psoc;
2623 	struct wmi_unified *wmi_handle;
2624 
2625 	if (!pdev) {
2626 		spectral_err("pdev is null");
2627 		return QDF_STATUS_E_INVAL;
2628 	}
2629 
2630 	psoc = wlan_pdev_get_psoc(pdev);
2631 	if (!psoc) {
2632 		spectral_err("psoc is null");
2633 		return QDF_STATUS_E_INVAL;
2634 	}
2635 
2636 	wmi_handle =  get_wmi_unified_hdl_from_psoc(psoc);
2637 	if (!wmi_handle) {
2638 		spectral_err("wmi handle is null");
2639 		return QDF_STATUS_E_INVAL;
2640 	}
2641 
2642 	/**
2643 	 * If a chipset supports byte-swap inside the target itself, then no
2644 	 * need to apply byte swap on the Host.
2645 	 */
2646 	*is_swap_required = !target_if_spectral_wmi_service_enabled(
2647 				psoc, wmi_handle,
2648 				wmi_service_phy_dma_byte_swap_support);
2649 
2650 	return QDF_STATUS_SUCCESS;
2651 }
2652 
2653 /**
2654  * target_if_spectral_init_byte_swap_funcs_gen3() - Initialize byte-swap
2655  * operations for Spectral chipset generation 3.
2656  * @spectral: Spectral LMAC object
2657  * @p_sops: Spectral function pointer table
2658  *
2659  * Return: None
2660  */
2661 static void
2662 target_if_spectral_init_byte_swap_funcs_gen3(
2663 	struct target_if_spectral *spectral,
2664 	struct target_if_spectral_ops *p_sops)
2665 {
2666 	bool is_swap_required;
2667 	QDF_STATUS status;
2668 
2669 	qdf_assert_always(spectral);
2670 	qdf_assert_always(p_sops);
2671 
2672 	status = spectral_is_host_byte_swap_required(spectral->pdev_obj,
2673 						     &is_swap_required);
2674 	if (QDF_IS_STATUS_ERROR(status)) {
2675 		spectral_err("Failed to check whether byte swap is required");
2676 		return;
2677 	}
2678 
2679 	if (is_swap_required) {
2680 		p_sops->byte_swap_headers =
2681 			target_if_byte_swap_spectral_headers_gen3;
2682 		p_sops->byte_swap_fft_bins =
2683 			target_if_byte_swap_spectral_fft_bins_gen3;
2684 	} else {
2685 		p_sops->byte_swap_headers = NULL;
2686 		p_sops->byte_swap_fft_bins = NULL;
2687 	}
2688 }
2689 #else
2690 static void
2691 target_if_spectral_init_byte_swap_funcs_gen3(
2692 	struct target_if_spectral *spectral,
2693 	struct target_if_spectral_ops *p_sops)
2694 {
2695 	qdf_assert_always(p_sops);
2696 
2697 	/* Byte-swap is not required for little-endian Hosts */
2698 	p_sops->byte_swap_headers = NULL;
2699 	p_sops->byte_swap_fft_bins = NULL;
2700 }
2701 #endif /* BIG_ENDIAN_HOST */
2702 
2703 /**
2704  * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
2705  * operations specific to Spectral chipset generation 3.
2706  * @spectral: Spectral LMAC object
2707  *
2708  * Initializes target_if_spectral_ops specific to Spectral chipset generation 3.
2709  *
2710  * Return: None
2711  */
2712 static void
2713 target_if_init_spectral_ops_gen3(struct target_if_spectral *spectral)
2714 {
2715 	struct target_if_spectral_ops *p_sops = &spectral_ops;
2716 
2717 	p_sops->process_spectral_report =
2718 			target_if_spectral_process_report_gen3;
2719 
2720 	target_if_spectral_init_byte_swap_funcs_gen3(spectral, p_sops);
2721 }
2722 
2723 /**
2724  * target_if_init_spectral_ops() - Initialize target_if internal Spectral
2725  * operations.
2726  * @spectral: Pointer to Spectral target_if internal private data
2727  *
2728  * Initializes all function pointers in target_if_spectral_ops for
2729  * all generations
2730  *
2731  * Return: None
2732  */
2733 static void
2734 target_if_init_spectral_ops(struct target_if_spectral *spectral)
2735 {
2736 	target_if_init_spectral_ops_common();
2737 	if (spectral->spectral_gen == SPECTRAL_GEN2)
2738 		target_if_init_spectral_ops_gen2();
2739 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
2740 		target_if_init_spectral_ops_gen3(spectral);
2741 	else
2742 		spectral_err("Invalid Spectral generation");
2743 }
2744 
2745 /*
2746  * Dummy Functions:
2747  * These functions are initially registered to avoid any crashes due to
2748  * invocation of spectral functions before they are registered.
2749  */
2750 
2751 static uint64_t
2752 null_get_tsf64(void *arg)
2753 {
2754 	spectral_ops_not_registered("get_tsf64");
2755 	return 0;
2756 }
2757 
2758 static uint32_t
2759 null_get_capability(void *arg, enum spectral_capability_type type)
2760 {
2761 	/*
2762 	 * TODO : We should have conditional compilation to get the capability
2763 	 *      : We have not yet attahced ATH layer here, so there is no
2764 	 *      : way to check the HAL capbalities
2765 	 */
2766 	spectral_ops_not_registered("get_capability");
2767 
2768 	/* TODO : For the time being, we are returning TRUE */
2769 	return true;
2770 }
2771 
2772 static uint32_t
2773 null_set_rxfilter(void *arg, int rxfilter)
2774 {
2775 	spectral_ops_not_registered("set_rxfilter");
2776 	return 1;
2777 }
2778 
2779 static uint32_t
2780 null_get_rxfilter(void *arg)
2781 {
2782 	spectral_ops_not_registered("get_rxfilter");
2783 	return 0;
2784 }
2785 
2786 static uint32_t
2787 null_is_spectral_active(void *arg, enum spectral_scan_mode smode)
2788 {
2789 	spectral_ops_not_registered("is_spectral_active");
2790 	return 1;
2791 }
2792 
2793 static uint32_t
2794 null_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
2795 {
2796 	spectral_ops_not_registered("is_spectral_enabled");
2797 	return 1;
2798 }
2799 
2800 static uint32_t
2801 null_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
2802 			 enum spectral_cp_error_code *err)
2803 {
2804 	spectral_ops_not_registered("start_spectral_scan");
2805 	return 1;
2806 }
2807 
2808 static uint32_t
2809 null_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
2810 {
2811 	spectral_ops_not_registered("stop_spectral_scan");
2812 	return 1;
2813 }
2814 
2815 static uint32_t
2816 null_get_extension_channel(void *arg, enum spectral_scan_mode smode)
2817 {
2818 	spectral_ops_not_registered("get_extension_channel");
2819 	return 1;
2820 }
2821 
2822 static int8_t
2823 null_get_ctl_noisefloor(void *arg)
2824 {
2825 	spectral_ops_not_registered("get_ctl_noisefloor");
2826 	return 1;
2827 }
2828 
2829 static int8_t
2830 null_get_ext_noisefloor(void *arg)
2831 {
2832 	spectral_ops_not_registered("get_ext_noisefloor");
2833 	return 0;
2834 }
2835 
2836 static uint32_t
2837 null_configure_spectral(void *arg, struct spectral_config *params,
2838 			enum spectral_scan_mode smode)
2839 {
2840 	spectral_ops_not_registered("configure_spectral");
2841 	return 0;
2842 }
2843 
2844 static uint32_t
2845 null_get_spectral_config(void *arg, struct spectral_config *params,
2846 			 enum spectral_scan_mode smode)
2847 {
2848 	spectral_ops_not_registered("get_spectral_config");
2849 	return 0;
2850 }
2851 
2852 static uint32_t
2853 null_get_ent_spectral_mask(void *arg)
2854 {
2855 	spectral_ops_not_registered("get_ent_spectral_mask");
2856 	return 0;
2857 }
2858 
2859 static uint32_t
2860 null_get_mac_address(void *arg, char *addr)
2861 {
2862 	spectral_ops_not_registered("get_mac_address");
2863 	return 0;
2864 }
2865 
2866 static uint32_t
2867 null_get_current_channel(void *arg, enum spectral_scan_mode smode)
2868 {
2869 	spectral_ops_not_registered("get_current_channel");
2870 	return 0;
2871 }
2872 
2873 static uint32_t
2874 null_reset_hw(void *arg)
2875 {
2876 	spectral_ops_not_registered("get_current_channel");
2877 	return 0;
2878 }
2879 
2880 static uint32_t
2881 null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
2882 {
2883 	spectral_ops_not_registered("get_chain_noise_floor");
2884 	return 0;
2885 }
2886 
2887 static int
2888 null_spectral_process_phyerr(struct target_if_spectral *spectral,
2889 			     uint8_t *data,
2890 			     uint32_t datalen,
2891 			     struct target_if_spectral_rfqual_info *p_rfqual,
2892 			     struct target_if_spectral_chan_info *p_chaninfo,
2893 			     uint64_t tsf64,
2894 			     struct target_if_spectral_acs_stats *acs_stats)
2895 {
2896 	spectral_ops_not_registered("spectral_process_phyerr");
2897 	return 0;
2898 }
2899 
2900 static int
2901 null_process_spectral_report(struct wlan_objmgr_pdev *pdev,
2902 			     void *payload)
2903 {
2904 	spectral_ops_not_registered("process_spectral_report");
2905 	return 0;
2906 }
2907 /**
2908  * target_if_spectral_init_dummy_function_table() -
2909  * Initialize target_if internal
2910  * Spectral operations to dummy functions
2911  * @ps: Pointer to Spectral target_if internal private data
2912  *
2913  * Initialize all the function pointers in target_if_spectral_ops with
2914  * dummy functions.
2915  *
2916  * Return: None
2917  */
2918 static void
2919 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps)
2920 {
2921 	struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps);
2922 
2923 	p_sops->get_tsf64 = null_get_tsf64;
2924 	p_sops->get_capability = null_get_capability;
2925 	p_sops->set_rxfilter = null_set_rxfilter;
2926 	p_sops->get_rxfilter = null_get_rxfilter;
2927 	p_sops->is_spectral_enabled = null_is_spectral_enabled;
2928 	p_sops->is_spectral_active = null_is_spectral_active;
2929 	p_sops->start_spectral_scan = null_start_spectral_scan;
2930 	p_sops->stop_spectral_scan = null_stop_spectral_scan;
2931 	p_sops->get_extension_channel = null_get_extension_channel;
2932 	p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
2933 	p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
2934 	p_sops->configure_spectral = null_configure_spectral;
2935 	p_sops->get_spectral_config = null_get_spectral_config;
2936 	p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
2937 	p_sops->get_mac_address = null_get_mac_address;
2938 	p_sops->get_current_channel = null_get_current_channel;
2939 	p_sops->reset_hw = null_reset_hw;
2940 	p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
2941 	p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
2942 	p_sops->process_spectral_report = null_process_spectral_report;
2943 }
2944 
2945 /**
2946  * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
2947  * operations
2948  * @spectral: Pointer to Spectral target_if internal private data
2949  * @p: Pointer to Spectral function table
2950  *
2951  * Return: None
2952  */
2953 static void
2954 target_if_spectral_register_funcs(struct target_if_spectral *spectral,
2955 				  struct target_if_spectral_ops *p)
2956 {
2957 	struct target_if_spectral_ops *p_sops =
2958 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2959 
2960 	*p_sops = *p;
2961 }
2962 
2963 /**
2964  * target_if_spectral_clear_stats() - Clear Spectral stats
2965  * @spectral: Pointer to Spectral target_if internal private data
2966  *
2967  * Function to clear spectral stats
2968  *
2969  * Return: None
2970  */
2971 static void
2972 target_if_spectral_clear_stats(struct target_if_spectral *spectral)
2973 {
2974 	struct target_if_spectral_ops *p_sops =
2975 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2976 
2977 	qdf_mem_zero(&spectral->spectral_stats,
2978 		     sizeof(struct target_if_spectral_stats));
2979 	spectral->spectral_stats.last_reset_tstamp =
2980 	    p_sops->get_tsf64(spectral);
2981 }
2982 
2983 /**
2984  * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
2985  * @spectral: Pointer to Spectral target_if internal private data
2986  *
2987  * Function to check whether hardware supports spectral
2988  *
2989  * Return: True if HW supports Spectral, false if HW does not support Spectral
2990  */
2991 static int
2992 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
2993 {
2994 	struct target_if_spectral_ops *p_sops = NULL;
2995 	struct spectral_caps *pcap = NULL;
2996 	int is_spectral_supported = true;
2997 
2998 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2999 	pcap = &spectral->capability;
3000 
3001 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
3002 		is_spectral_supported = false;
3003 		spectral_info("SPECTRAL : No PHYDIAG support");
3004 		return is_spectral_supported;
3005 	}
3006 	pcap->phydiag_cap = 1;
3007 
3008 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
3009 		is_spectral_supported = false;
3010 		spectral_info("SPECTRAL : No RADAR support");
3011 		return is_spectral_supported;
3012 	}
3013 	pcap->radar_cap = 1;
3014 
3015 	if (p_sops->get_capability(spectral,
3016 				   SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
3017 		is_spectral_supported = false;
3018 		spectral_info("SPECTRAL : No SPECTRAL SUPPORT");
3019 		return is_spectral_supported;
3020 	}
3021 	pcap->spectral_cap = 1;
3022 
3023 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
3024 	    == false) {
3025 		spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT");
3026 	} else {
3027 		pcap->advncd_spectral_cap = 1;
3028 	}
3029 
3030 	return is_spectral_supported;
3031 }
3032 
3033 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
3034 /**
3035  * target_if_spectral_detach_simulation() - De-initialize Spectral
3036  * Simulation functionality
3037  * @spectral: Pointer to Spectral target_if internal private data
3038  *
3039  * Function to de-initialize Spectral Simulation functionality
3040  *
3041  * Return: None
3042  */
3043 static void
3044 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
3045 {
3046 	target_if_spectral_sim_detach(spectral);
3047 }
3048 
3049 #else
3050 static void
3051 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
3052 {
3053 }
3054 #endif
3055 
3056 /**
3057  * target_if_spectral_detach() - De-initialize target_if Spectral
3058  * @pdev: Pointer to pdev object
3059  *
3060  * Function to detach target_if spectral
3061  *
3062  * Return: None
3063  */
3064 static void
3065 target_if_spectral_detach(struct target_if_spectral *spectral)
3066 {
3067 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
3068 	spectral_info("spectral detach");
3069 
3070 	if (spectral) {
3071 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
3072 			qdf_spinlock_destroy
3073 				(&spectral->param_info[smode].osps_lock);
3074 
3075 		target_if_spectral_detach_simulation(spectral);
3076 
3077 		qdf_spinlock_destroy(&spectral->spectral_lock);
3078 		qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
3079 
3080 		qdf_spinlock_destroy(&spectral->detector_list_lock);
3081 		qdf_spinlock_destroy(&spectral->session_report_info_lock);
3082 		qdf_spinlock_destroy(&spectral->session_det_map_lock);
3083 
3084 		qdf_mem_free(spectral);
3085 		spectral = NULL;
3086 	}
3087 }
3088 
3089 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
3090 /**
3091  * target_if_spectral_attach_simulation() - Initialize Spectral Simulation
3092  * functionality
3093  * @spectral: Pointer to Spectral target_if internal private data
3094  *
3095  * Function to initialize spectral simulation functionality
3096  *
3097  * Return: 0 on success, negative error code on failure
3098  */
3099 static int
3100 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
3101 {
3102 	if (target_if_spectral_sim_attach(spectral)) {
3103 		qdf_mem_free(spectral);
3104 		return -EPERM;
3105 	}
3106 	return 0;
3107 }
3108 
3109 #else
3110 static int
3111 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
3112 {
3113 	return 0;
3114 }
3115 #endif
3116 
3117 /**
3118  * target_if_spectral_len_adj_swar_init() - Initialize FFT bin length adjustment
3119  * related info
3120  * @swar: Pointer to Spectral FFT bin length adjustment SWAR params
3121  * @rparams: Pointer to Spectral report parameter object
3122  * @target_type: Target type
3123  *
3124  * Function to Initialize parameters related to Spectral FFT bin
3125  * length adjustment SWARs.
3126  *
3127  * Return: void
3128  */
3129 static void
3130 target_if_spectral_len_adj_swar_init(struct spectral_fft_bin_len_adj_swar *swar,
3131 				     struct spectral_report_params *rparams,
3132 				     uint32_t target_type)
3133 {
3134 	if (target_type == TARGET_TYPE_QCA8074V2 ||
3135 	    target_type == TARGET_TYPE_QCA9574 ||
3136 	    target_type == TARGET_TYPE_QCN9000 ||
3137 	    target_type == TARGET_TYPE_QCN6122 ||
3138 	    target_type == TARGET_TYPE_QCN9160 ||
3139 	    target_type == TARGET_TYPE_QCA5018 ||
3140 	    target_type == TARGET_TYPE_QCA6750 ||
3141 	    target_type == TARGET_TYPE_QCA6490 ||
3142 	    target_type == TARGET_TYPE_KIWI ||
3143 	    target_type == TARGET_TYPE_MANGO) {
3144 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE;
3145 		rparams->hw_fft_bin_width = 2;
3146 	} else if (target_type == TARGET_TYPE_QCA8074 ||
3147 		 target_type == TARGET_TYPE_QCA6018 ||
3148 		 target_type == TARGET_TYPE_QCA6390) {
3149 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE;
3150 		rparams->hw_fft_bin_width = 4;
3151 	} else {
3152 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR;
3153 		rparams->hw_fft_bin_width = 1;
3154 	}
3155 
3156 	if (target_type == TARGET_TYPE_QCA8074 ||
3157 	    target_type == TARGET_TYPE_QCA8074V2 ||
3158 	    target_type == TARGET_TYPE_QCA9574 ||
3159 	    target_type == TARGET_TYPE_QCA6018 ||
3160 	    target_type == TARGET_TYPE_QCN6122 ||
3161 	    target_type == TARGET_TYPE_QCN9160 ||
3162 	    target_type == TARGET_TYPE_QCA5332 ||
3163 	    target_type == TARGET_TYPE_QCA5018 ||
3164 	    target_type == TARGET_TYPE_QCN9000 ||
3165 	    target_type == TARGET_TYPE_QCA6490 ||
3166 	    target_type == TARGET_TYPE_QCN9224 ||
3167 	    target_type == TARGET_TYPE_KIWI ||
3168 	    target_type == TARGET_TYPE_MANGO) {
3169 		swar->inband_fftbin_size_adj = 1;
3170 		swar->null_fftbin_adj = 1;
3171 	} else {
3172 		swar->inband_fftbin_size_adj = 0;
3173 		swar->null_fftbin_adj = 0;
3174 	}
3175 
3176 	if (target_type == TARGET_TYPE_QCA8074V2)
3177 		swar->packmode_fftbin_size_adj = 1;
3178 	else
3179 		swar->packmode_fftbin_size_adj = 0;
3180 }
3181 
3182 /**
3183  * target_if_spectral_report_params_init() - Initialize parameters which
3184  * describes the structure of Spectral reports
3185  *
3186  * @rparams: Pointer to Spectral report parameter object
3187  * @target_type: target type
3188  *
3189  * Function to Initialize parameters related to the structure of Spectral
3190  * reports.
3191  *
3192  * Return: void
3193  */
3194 static void
3195 target_if_spectral_report_params_init(
3196 			struct spectral_report_params *rparams,
3197 			uint32_t target_type)
3198 {
3199 	enum spectral_scan_mode smode;
3200 
3201 	/* This entries are currently used by gen3 chipsets only. Hence
3202 	 * initialization is done for gen3 alone. In future if other generations
3203 	 * needs to use them they have to add proper initial values.
3204 	 */
3205 	if (target_type == TARGET_TYPE_QCN9000 ||
3206 	    target_type == TARGET_TYPE_QCN6122 ||
3207 	    target_type == TARGET_TYPE_QCN9160 ||
3208 	    target_type == TARGET_TYPE_QCA5018 ||
3209 	    target_type == TARGET_TYPE_QCA6750 ||
3210 	    target_type == TARGET_TYPE_QCA6490 ||
3211 	    target_type == TARGET_TYPE_QCA5332 ||
3212 	    target_type == TARGET_TYPE_QCN9224 ||
3213 	    target_type == TARGET_TYPE_KIWI ||
3214 	    target_type == TARGET_TYPE_MANGO) {
3215 		rparams->version = SPECTRAL_REPORT_FORMAT_VERSION_2;
3216 		rparams->num_spectral_detectors =
3217 				NUM_SPECTRAL_DETECTORS_GEN3_V2;
3218 		smode = SPECTRAL_SCAN_MODE_NORMAL;
3219 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
3220 			rparams->fragmentation_160[smode] = false;
3221 	} else {
3222 		rparams->version = SPECTRAL_REPORT_FORMAT_VERSION_1;
3223 		rparams->num_spectral_detectors =
3224 				NUM_SPECTRAL_DETECTORS_GEN3_V1;
3225 		smode = SPECTRAL_SCAN_MODE_NORMAL;
3226 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
3227 			rparams->fragmentation_160[smode] = true;
3228 	}
3229 
3230 	switch (rparams->version) {
3231 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
3232 		rparams->ssumaary_padding_bytes =
3233 			NUM_PADDING_BYTES_SSCAN_SUMARY_REPORT_GEN3_V1;
3234 		rparams->fft_report_hdr_len =
3235 			FFT_REPORT_HEADER_LENGTH_GEN3_V1;
3236 		break;
3237 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
3238 		rparams->ssumaary_padding_bytes =
3239 			NUM_PADDING_BYTES_SSCAN_SUMARY_REPORT_GEN3_V2;
3240 		rparams->fft_report_hdr_len =
3241 			FFT_REPORT_HEADER_LENGTH_GEN3_V2;
3242 		break;
3243 	default:
3244 		qdf_assert_always(0);
3245 	}
3246 
3247 	rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_0] =
3248 						SPECTRAL_SCAN_MODE_NORMAL;
3249 	if (target_type == TARGET_TYPE_QCN9000 ||
3250 	    target_type == TARGET_TYPE_QCN6122 ||
3251 	    target_type == TARGET_TYPE_QCN9224 ||
3252 	    target_type == TARGET_TYPE_QCN9160 ||
3253 	    target_type == TARGET_TYPE_QCA6490 ||
3254 	    target_type == TARGET_TYPE_KIWI ||
3255 	    target_type == TARGET_TYPE_MANGO) {
3256 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
3257 						SPECTRAL_SCAN_MODE_AGILE;
3258 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
3259 						SPECTRAL_SCAN_MODE_INVALID;
3260 	} else {
3261 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
3262 						SPECTRAL_SCAN_MODE_NORMAL;
3263 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
3264 						SPECTRAL_SCAN_MODE_AGILE;
3265 	}
3266 }
3267 
3268 /**
3269  * target_if_spectral_timestamp_war_init() - Initialize Spectral timestamp WAR
3270  * related info
3271  * @twar: Pointer to Spectral timstamp WAR related info
3272  *
3273  * Function to Initialize parameters related to Spectral timestamp WAR
3274  *
3275  * Return: void
3276  */
3277 static void
3278 target_if_spectral_timestamp_war_init(struct spectral_timestamp_war *twar)
3279 {
3280 	enum spectral_scan_mode smode;
3281 
3282 	smode = SPECTRAL_SCAN_MODE_NORMAL;
3283 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
3284 		twar->last_fft_timestamp[smode] = 0;
3285 		twar->timestamp_war_offset[smode] = 0;
3286 	}
3287 	twar->target_reset_count = 0;
3288 }
3289 
3290 #ifdef OPTIMIZED_SAMP_MESSAGE
3291 /**
3292  * target_if_spectral_is_hw_mode_sbs() - Check if the given pdev is in SBS mode
3293  * @pdev: pdev pointer
3294  * @is_hw_mode_sbs: Pointer to the variable where this function should write
3295  * whether the given pdev is in SBS mode
3296  *
3297  * Return: QDF_STATUS of operation
3298  */
3299 static QDF_STATUS
3300 target_if_spectral_is_hw_mode_sbs(struct wlan_objmgr_pdev *pdev,
3301 				  bool *is_hw_mode_sbs)
3302 {
3303 	struct wlan_objmgr_psoc *psoc;
3304 	struct target_psoc_info *tgt_hdl;
3305 	enum wmi_host_hw_mode_config_type mode;
3306 
3307 	qdf_assert_always(is_hw_mode_sbs);
3308 
3309 	psoc = wlan_pdev_get_psoc(pdev);
3310 	if (!psoc) {
3311 		spectral_err("psoc is null");
3312 		return QDF_STATUS_E_NULL_VALUE;
3313 	}
3314 
3315 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
3316 	if (!tgt_hdl) {
3317 		spectral_err("target_psoc_info is null");
3318 		return QDF_STATUS_E_NULL_VALUE;
3319 	}
3320 
3321 	mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
3322 	switch (mode) {
3323 	case WMI_HOST_HW_MODE_SBS_PASSIVE:
3324 	case WMI_HOST_HW_MODE_SBS:
3325 	case WMI_HOST_HW_MODE_DBS_SBS:
3326 	case WMI_HOST_HW_MODE_DBS_OR_SBS:
3327 		*is_hw_mode_sbs = true;
3328 		break;
3329 	default:
3330 		*is_hw_mode_sbs = false;
3331 		break;
3332 	}
3333 
3334 	return QDF_STATUS_SUCCESS;
3335 }
3336 
3337 /**
3338  * target_if_get_pdev_mac_phy_caps() - Get the MAC_PHY capabilities of a pdev
3339  * @pdev: pdev pointer
3340  *
3341  * Return: On success, pointer to  MAC_PHY capabilities of @pdev.
3342  * On failure, NULL
3343  */
3344 static struct wlan_psoc_host_mac_phy_caps *
3345 target_if_get_pdev_mac_phy_caps(struct wlan_objmgr_pdev *pdev)
3346 {
3347 	struct wlan_objmgr_psoc *psoc;
3348 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr;
3349 	struct target_psoc_info *tgt_psoc_info;
3350 	uint8_t pdev_id;
3351 
3352 	if (!pdev) {
3353 		spectral_err("pdev is NULL");
3354 		return NULL;
3355 	}
3356 
3357 	psoc = wlan_pdev_get_psoc(pdev);
3358 	if (!psoc) {
3359 		spectral_err("psoc is null");
3360 		return NULL;
3361 	}
3362 
3363 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
3364 	if (!tgt_psoc_info) {
3365 		spectral_err("target_psoc_info is null");
3366 		return NULL;
3367 	}
3368 
3369 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
3370 	if (!mac_phy_cap_arr) {
3371 		spectral_err("mac phy cap array is null");
3372 		return NULL;
3373 	}
3374 
3375 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
3376 	return &mac_phy_cap_arr[pdev_id];
3377 }
3378 
3379 /**
3380  * struct target_if_sscan_pdev_phy_info - PHY information of the pdev on
3381  * which sscan is done. A pointer to an instance of this structure is passed
3382  * as an argument to the iterator function target_if_find_sscan_pdev_phya1()
3383  * @phy_id: PHY ID of this pdev
3384  * @is_using_phya1: Pointer to the variable where the iterator function should
3385  * populate whether the given pdev is using PHYA1
3386  */
3387 struct target_if_sscan_pdev_phy_info {
3388 	uint8_t phy_id;
3389 	bool *is_using_phya1;
3390 };
3391 
3392 /**
3393  * target_if_find_sscan_pdev_phya1() - This is an iterator function to
3394  * wlan_objmgr_iterate_obj_list(). It checks whether a given sscan_pdev (pdev on
3395  * which sscan is currently issued) is using PHYA1 by comparing against the pdev
3396  * argument given by the wlan_objmgr_iterate_obj_list()
3397  * @psoc: Pointer to psoc
3398  * @object: Pointer to pdev
3399  * @arg: Pointer to target_if_sscan_pdev_phy_info of the sscan_pdev for which
3400  * we want to check if it uses PHYA1
3401  *
3402  * Return: None
3403  */
3404 static void
3405 target_if_find_sscan_pdev_phya1(struct wlan_objmgr_psoc *psoc,
3406 				void *object, void *arg)
3407 {
3408 	struct target_if_sscan_pdev_phy_info *sscan_pdev_phy_info = arg;
3409 	struct wlan_objmgr_pdev *cur_pdev = object;
3410 	struct wlan_psoc_host_mac_phy_caps *cur_mac_phy_caps;
3411 
3412 	cur_mac_phy_caps = target_if_get_pdev_mac_phy_caps(cur_pdev);
3413 	if (!cur_mac_phy_caps) {
3414 		spectral_err("Failed to get MAC PHY Capabilities of"
3415 			     "pdev %pK", cur_pdev);
3416 		return;
3417 	}
3418 
3419 	spectral_debug("supported_bands: %0x phy_id: %d",
3420 		       cur_mac_phy_caps->supported_bands,
3421 		       cur_mac_phy_caps->phy_id);
3422 
3423 	/* No need to do anything if the current pdev is same as sscan_pdev */
3424 	if (sscan_pdev_phy_info->phy_id == cur_mac_phy_caps->phy_id)
3425 		return;
3426 
3427 	/**
3428 	 * Compare the phy_id of both the SBS pdevs to figure out if
3429 	 * the sscan_pdev using PHYA1
3430 	 */
3431 	if (sscan_pdev_phy_info->phy_id > cur_mac_phy_caps->phy_id)
3432 		*sscan_pdev_phy_info->is_using_phya1 = true;
3433 	else
3434 		*sscan_pdev_phy_info->is_using_phya1 = false;
3435 }
3436 
3437 /**
3438  * target_if_spectral_detector_list_init() - Initialize Spectral detector list
3439  * based on target type
3440  * @spectral: Pointer to Spectral target_if
3441  *
3442  * Function to initialize Spectral detector list for possible combinations of
3443  * Spectral scan mode and channel width, based on target type.
3444  *
3445  * Return: Success/Failure
3446  */
3447 static QDF_STATUS
3448 target_if_spectral_detector_list_init(struct target_if_spectral *spectral)
3449 {
3450 	struct sscan_detector_list *det_list;
3451 	enum spectral_scan_mode smode;
3452 	enum phy_ch_width ch_width;
3453 	QDF_STATUS ret;
3454 	bool is_hw_mode_sbs = false, is_using_phya1 = false;
3455 
3456 	if (!spectral) {
3457 		spectral_err_rl("Spectral LMAC object is null");
3458 		return QDF_STATUS_E_NULL_VALUE;
3459 	}
3460 
3461 	/**
3462 	 * Special handling is required for SBS mode where the detector
3463 	 * list should be the following.
3464 	 * For the pdev that use PHYA0:
3465 	 *    detector 0 for normal mode
3466 	 *    detector 2 for agile mode
3467 	 * For the pdev that use PHYA1:
3468 	 *    detector 1 for normal mode
3469 	 *    detector 2 for agile mode
3470 	 *
3471 	 * There is no direct way of knowing which pdevs are using PHYA0 or
3472 	 * PHYA1. We need to look at the phy_id of a given pdev and compare
3473 	 * against other pdevs on the same psoc to figure out whether the given
3474 	 * pdev is operating using PHYA1.
3475 	 */
3476 
3477 	/* First check whether this pdev is in SBS mode */
3478 	ret = target_if_spectral_is_hw_mode_sbs(spectral->pdev_obj,
3479 						&is_hw_mode_sbs);
3480 	if (QDF_IS_STATUS_ERROR(ret)) {
3481 		spectral_err("Failed to check whether hw mode is SBS");
3482 		return ret;
3483 	}
3484 
3485 	if (is_hw_mode_sbs) {
3486 		struct wlan_psoc_host_mac_phy_caps *mac_phy_caps;
3487 		struct target_if_sscan_pdev_phy_info pdev_phy_info;
3488 
3489 		mac_phy_caps =
3490 			target_if_get_pdev_mac_phy_caps(spectral->pdev_obj);
3491 		if (!mac_phy_caps) {
3492 			spectral_err("Failed to get MAC PHY Capabilities of"
3493 				     "pdev %pK", spectral->pdev_obj);
3494 			return QDF_STATUS_E_FAILURE;
3495 		}
3496 
3497 		spectral_debug("bands: %0x phy_id: %d",
3498 			       mac_phy_caps->supported_bands,
3499 			       mac_phy_caps->phy_id);
3500 
3501 		pdev_phy_info.phy_id = mac_phy_caps->phy_id;
3502 		pdev_phy_info.is_using_phya1 = &is_using_phya1;
3503 
3504 		/* Iterate over all pdevs on this psoc */
3505 		wlan_objmgr_iterate_obj_list
3506 			(wlan_pdev_get_psoc(spectral->pdev_obj),
3507 			 WLAN_PDEV_OP,
3508 			 target_if_find_sscan_pdev_phya1,
3509 			 &pdev_phy_info, 0,
3510 			 WLAN_SPECTRAL_ID);
3511 	}
3512 
3513 	/**
3514 	 * We assume there are 2 detectors. The Detector ID coming first will
3515 	 * always be pri80 detector, and second detector for sec80.
3516 	 */
3517 	ch_width = CH_WIDTH_20MHZ;
3518 	for (; ch_width < CH_WIDTH_MAX; ch_width++) {
3519 		/* Normal spectral scan */
3520 		smode = SPECTRAL_SCAN_MODE_NORMAL;
3521 		spectral_debug("is_hw_mode_sbs: %d is_using_phya1:%d",
3522 			       is_hw_mode_sbs, is_using_phya1);
3523 
3524 		qdf_spin_lock_bh(&spectral->detector_list_lock);
3525 
3526 		if (!spectral->supported_sscan_bw_list[smode][ch_width])
3527 			goto agile_handling;
3528 
3529 		det_list = &spectral->detector_list[smode][ch_width];
3530 		det_list->num_detectors = 1;
3531 
3532 		if (is_hw_mode_sbs && is_using_phya1)
3533 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_1;
3534 		else
3535 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_0;
3536 
3537 		if (is_ch_width_160_or_80p80(ch_width) &&
3538 		    spectral->rparams.fragmentation_160[smode]) {
3539 			det_list->num_detectors += 1;
3540 			det_list->detectors[1] = SPECTRAL_DETECTOR_ID_1;
3541 		}
3542 
3543 agile_handling:
3544 		/* Agile spectral scan */
3545 		smode = SPECTRAL_SCAN_MODE_AGILE;
3546 		if (!spectral->supported_sscan_bw_list[smode][ch_width]) {
3547 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
3548 			continue;
3549 		}
3550 
3551 		det_list = &spectral->detector_list[smode][ch_width];
3552 		det_list->num_detectors = 1;
3553 
3554 		if (spectral->rparams.fragmentation_160[smode])
3555 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_2;
3556 		else
3557 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_1;
3558 
3559 		qdf_spin_unlock_bh(&spectral->detector_list_lock);
3560 	}
3561 
3562 	return QDF_STATUS_SUCCESS;
3563 }
3564 #else
3565 
3566 static QDF_STATUS
3567 target_if_spectral_detector_list_init(struct target_if_spectral *spectral)
3568 {
3569 	return QDF_STATUS_SUCCESS;
3570 }
3571 #endif /* OPTIMIZED_SAMP_MESSAGE */
3572 
3573 /**
3574  * target_if_pdev_spectral_init() - Initialize target_if Spectral
3575  * functionality for the given pdev
3576  * @pdev: Pointer to pdev object
3577  *
3578  * Function to initialize pointer to spectral target_if internal private data
3579  *
3580  * Return: On success, pointer to Spectral target_if internal private data, on
3581  * failure, NULL
3582  */
3583 void *
3584 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
3585 {
3586 	struct target_if_spectral_ops *p_sops = NULL;
3587 	struct target_if_spectral *spectral = NULL;
3588 	uint32_t target_type;
3589 	uint32_t target_revision;
3590 	struct wlan_objmgr_psoc *psoc;
3591 	struct wlan_lmac_if_target_tx_ops *tgt_tx_ops;
3592 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
3593 	QDF_STATUS status;
3594 	struct wlan_lmac_if_tx_ops *tx_ops;
3595 
3596 	if (!pdev) {
3597 		spectral_err("SPECTRAL: pdev is NULL!");
3598 		return NULL;
3599 	}
3600 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
3601 			sizeof(struct target_if_spectral));
3602 	if (!spectral)
3603 		return spectral;
3604 
3605 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
3606 	/* Store pdev in Spectral */
3607 	spectral->pdev_obj = pdev;
3608 	spectral->vdev_id[SPECTRAL_SCAN_MODE_NORMAL] = WLAN_INVALID_VDEV_ID;
3609 	spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE] = WLAN_INVALID_VDEV_ID;
3610 
3611 	psoc = wlan_pdev_get_psoc(pdev);
3612 
3613 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
3614 	if (!tx_ops) {
3615 		spectral_err("tx_ops is NULL");
3616 		qdf_mem_free(spectral);
3617 		return NULL;
3618 	}
3619 
3620 	tgt_tx_ops = &tx_ops->target_tx_ops;
3621 
3622 	if (tgt_tx_ops->tgt_get_tgt_type) {
3623 		target_type = tgt_tx_ops->tgt_get_tgt_type(psoc);
3624 	} else {
3625 		qdf_mem_free(spectral);
3626 		return NULL;
3627 	}
3628 
3629 	if (tgt_tx_ops->tgt_get_tgt_revision) {
3630 		target_revision = tgt_tx_ops->tgt_get_tgt_revision(psoc);
3631 	} else {
3632 		qdf_mem_free(spectral);
3633 		return NULL;
3634 	}
3635 
3636 	/* init the function ptr table */
3637 	target_if_spectral_init_dummy_function_table(spectral);
3638 
3639 	/* get spectral function table */
3640 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3641 	/* TODO : Should this be called here of after ath_attach ? */
3642 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
3643 		spectral_info("HAL_CAP_PHYDIAG : Capable");
3644 
3645 	/* TODO: Need to fix the capability check for RADAR */
3646 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
3647 		spectral_info("HAL_CAP_RADAR   : Capable");
3648 
3649 	/* TODO : Need to fix the capability check for SPECTRAL */
3650 	/* TODO : Should this be called here of after ath_attach ? */
3651 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
3652 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
3653 
3654 	qdf_spinlock_create(&spectral->spectral_lock);
3655 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
3656 	target_if_spectral_clear_stats(spectral);
3657 
3658 	if (target_type == TARGET_TYPE_QCA8074 ||
3659 	    target_type == TARGET_TYPE_QCA8074V2 ||
3660 	    target_type == TARGET_TYPE_QCA9574 ||
3661 	    target_type == TARGET_TYPE_QCA5332 ||
3662 	    target_type == TARGET_TYPE_QCA6018 ||
3663 	    target_type == TARGET_TYPE_QCA5018 ||
3664 	    target_type == TARGET_TYPE_QCA6390 ||
3665 	    target_type == TARGET_TYPE_QCN6122 ||
3666 	    target_type == TARGET_TYPE_QCN9160 ||
3667 	    target_type == TARGET_TYPE_QCA6490 ||
3668 	    target_type == TARGET_TYPE_QCN9000 ||
3669 	    target_type == TARGET_TYPE_QCA6750 ||
3670 	    target_type == TARGET_TYPE_QCN9224 ||
3671 	    target_type == TARGET_TYPE_KIWI ||
3672 	    target_type == TARGET_TYPE_MANGO)
3673 		spectral->direct_dma_support = true;
3674 
3675 	target_if_spectral_report_params_init(&spectral->rparams,
3676 					      target_type);
3677 	target_if_spectral_len_adj_swar_init(&spectral->len_adj_swar,
3678 					     &spectral->rparams,
3679 					     target_type);
3680 
3681 	if ((target_type == TARGET_TYPE_QCA8074) ||
3682 	    (target_type == TARGET_TYPE_QCA8074V2) ||
3683 	    (target_type == TARGET_TYPE_QCA9574) ||
3684 	    (target_type == TARGET_TYPE_QCA6018) ||
3685 	    (target_type == TARGET_TYPE_QCA5018) ||
3686 	    (target_type == TARGET_TYPE_QCA5332) ||
3687 	    (target_type == TARGET_TYPE_QCN6122) ||
3688 	    (target_type == TARGET_TYPE_QCN9160) ||
3689 	    (target_type == TARGET_TYPE_QCN9000) ||
3690 	    (target_type == TARGET_TYPE_QCA6290) ||
3691 	    (target_type == TARGET_TYPE_QCA6390) ||
3692 	    (target_type == TARGET_TYPE_QCA6490) ||
3693 	    (target_type == TARGET_TYPE_QCN9224) ||
3694 	    (target_type == TARGET_TYPE_QCA6750) ||
3695 	    (target_type == TARGET_TYPE_KIWI) ||
3696 	    (target_type == TARGET_TYPE_MANGO)) {
3697 		spectral->spectral_gen = SPECTRAL_GEN3;
3698 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
3699 		spectral->tag_sscan_summary_exp =
3700 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
3701 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
3702 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
3703 	} else {
3704 		spectral->spectral_gen = SPECTRAL_GEN2;
3705 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
3706 		spectral->tag_sscan_summary_exp =
3707 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
3708 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
3709 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
3710 	}
3711 
3712 	status = target_if_init_spectral_param_min_max(
3713 					spectral,
3714 					spectral->spectral_gen, target_type);
3715 	if (QDF_IS_STATUS_ERROR(status)) {
3716 		spectral_err("Failed to initialize parameter min max values");
3717 		goto fail;
3718 	}
3719 
3720 	target_if_init_spectral_param_properties(spectral);
3721 	/* Init spectral capability */
3722 	if (target_if_init_spectral_capability(spectral, target_type) !=
3723 					QDF_STATUS_SUCCESS) {
3724 		qdf_mem_free(spectral);
3725 		return NULL;
3726 	}
3727 	if (target_if_spectral_attach_simulation(spectral) < 0)
3728 		return NULL;
3729 
3730 	target_if_init_spectral_ops(spectral);
3731 	target_if_spectral_timestamp_war_init(&spectral->timestamp_war);
3732 
3733 	/* Spectral mode specific init */
3734 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
3735 		spectral->params_valid[smode] = false;
3736 		qdf_spinlock_create(&spectral->param_info[smode].osps_lock);
3737 		spectral->param_info[smode].osps_cache.osc_is_valid = 0;
3738 	}
3739 
3740 	target_if_spectral_register_funcs(spectral, &spectral_ops);
3741 
3742 	if (target_if_spectral_check_hw_capability(spectral) == false) {
3743 		goto fail;
3744 	} else {
3745 		/*
3746 		 * TODO: Once the driver architecture transitions to chipset
3747 		 * versioning based checks, reflect this here.
3748 		 */
3749 		spectral->is_160_format = false;
3750 		spectral->is_lb_edge_extrabins_format = false;
3751 		spectral->is_rb_edge_extrabins_format = false;
3752 
3753 		if (target_type == TARGET_TYPE_QCA9984 ||
3754 		    target_type == TARGET_TYPE_QCA9888) {
3755 			spectral->is_160_format = true;
3756 			spectral->is_lb_edge_extrabins_format = true;
3757 			spectral->is_rb_edge_extrabins_format = true;
3758 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
3759 			    (target_revision == AR900B_REV_2)) {
3760 			spectral->is_rb_edge_extrabins_format = true;
3761 		}
3762 
3763 		if (target_type == TARGET_TYPE_QCA9984 ||
3764 		    target_type == TARGET_TYPE_QCA9888)
3765 			spectral->is_sec80_rssi_war_required = true;
3766 
3767 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
3768 
3769 		if (spectral->spectral_gen == SPECTRAL_GEN3)
3770 			init_160mhz_delivery_state_machine(spectral);
3771 	}
3772 
3773 	qdf_spinlock_create(&spectral->detector_list_lock);
3774 	qdf_spinlock_create(&spectral->session_report_info_lock);
3775 	qdf_spinlock_create(&spectral->session_det_map_lock);
3776 
3777 	return spectral;
3778 
3779 fail:
3780 	target_if_spectral_detach(spectral);
3781 	return NULL;
3782 }
3783 
3784 /**
3785  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
3786  * functionality for the given pdev
3787  * @pdev: Pointer to pdev object
3788  *
3789  * Function to de-initialize pointer to spectral target_if internal private data
3790  *
3791  * Return: None
3792  */
3793 void
3794 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
3795 {
3796 	struct target_if_spectral *spectral = NULL;
3797 
3798 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3799 	if (!spectral) {
3800 		spectral_err("SPECTRAL : Module doesn't exist");
3801 		return;
3802 	}
3803 	target_if_spectral_detach(spectral);
3804 
3805 	return;
3806 }
3807 
3808 /**
3809  * target_if_psoc_spectral_deinit() - De-initialize target_if Spectral
3810  * functionality for the given psoc
3811  * @psoc: Pointer to psoc object
3812  *
3813  * Function to de-initialize pointer to psoc spectral target_if internal
3814  * private data
3815  *
3816  * Return: None
3817  */
3818 static void
3819 target_if_psoc_spectral_deinit(struct wlan_objmgr_psoc *psoc)
3820 {
3821 	struct target_if_psoc_spectral *psoc_spectral;
3822 
3823 	if (!psoc) {
3824 		spectral_err("psoc is null");
3825 		return;
3826 	}
3827 
3828 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
3829 	if (!psoc_spectral) {
3830 		spectral_err("Spectral target_if psoc object is null");
3831 		return;
3832 	}
3833 
3834 	qdf_mem_free(psoc_spectral);
3835 }
3836 
3837 /**
3838  * target_if_psoc_spectral_init() - Initialize target_if Spectral
3839  * functionality for the given psoc
3840  * @psoc: Pointer to psoc object
3841  *
3842  * Function to initialize pointer to psoc spectral target_if internal
3843  * private data
3844  *
3845  * Return: On success, pointer to Spectral psoc target_if internal
3846  * private data, on failure, NULL
3847  */
3848 static void *
3849 target_if_psoc_spectral_init(struct wlan_objmgr_psoc *psoc)
3850 {
3851 	struct target_if_psoc_spectral *psoc_spectral = NULL;
3852 
3853 	if (!psoc) {
3854 		spectral_err("psoc is null");
3855 		goto fail;
3856 	}
3857 
3858 	psoc_spectral = (struct target_if_psoc_spectral *)qdf_mem_malloc(
3859 			sizeof(struct target_if_psoc_spectral));
3860 	if (!psoc_spectral) {
3861 		spectral_err("Spectral lmac psoc object allocation failed");
3862 		goto fail;
3863 	}
3864 
3865 	psoc_spectral->psoc_obj = psoc;
3866 
3867 	return psoc_spectral;
3868 
3869 fail:
3870 	if (psoc_spectral)
3871 		target_if_psoc_spectral_deinit(psoc);
3872 
3873 	return psoc_spectral;
3874 }
3875 
3876 /**
3877  * target_if_calculate_center_freq() - Helper routine to
3878  * check whether given frequency is center frequency of a
3879  * WLAN channel
3880  *
3881  * @spectral: Pointer to Spectral object
3882  * @chan_freq: Center frequency of a WLAN channel
3883  * @is_valid: Indicates whether given frequency is valid
3884  *
3885  * Return: QDF_STATUS
3886  */
3887 static QDF_STATUS
3888 target_if_is_center_freq_of_any_chan(struct wlan_objmgr_pdev *pdev,
3889 				     uint32_t chan_freq,
3890 				     bool *is_valid)
3891 {
3892 	struct regulatory_channel *cur_chan_list;
3893 	int i;
3894 
3895 	if (!pdev) {
3896 		spectral_err("pdev object is null");
3897 		return QDF_STATUS_E_FAILURE;
3898 	}
3899 
3900 	if (!is_valid) {
3901 		spectral_err("is valid argument is null");
3902 		return QDF_STATUS_E_FAILURE;
3903 	}
3904 
3905 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
3906 	if (!cur_chan_list)
3907 		return QDF_STATUS_E_FAILURE;
3908 
3909 	if (wlan_reg_get_current_chan_list(
3910 			pdev, cur_chan_list) != QDF_STATUS_SUCCESS) {
3911 		spectral_err("Failed to get cur_chan list");
3912 		qdf_mem_free(cur_chan_list);
3913 		return QDF_STATUS_E_FAILURE;
3914 	}
3915 
3916 	*is_valid = false;
3917 	for (i = 0; i < NUM_CHANNELS; i++) {
3918 		uint32_t flags;
3919 		uint32_t center_freq;
3920 
3921 		flags = cur_chan_list[i].chan_flags;
3922 		center_freq = cur_chan_list[i].center_freq;
3923 
3924 		if (!(flags & REGULATORY_CHAN_DISABLED) &&
3925 		    (center_freq == chan_freq)) {
3926 			*is_valid = true;
3927 			break;
3928 		}
3929 	}
3930 
3931 	qdf_mem_free(cur_chan_list);
3932 
3933 	return QDF_STATUS_SUCCESS;
3934 }
3935 
3936 /**
3937  * target_if_calculate_center_freq() - Helper routine to
3938  * find the center frequency of the agile span from a
3939  * WLAN channel center frequency
3940  *
3941  * @spectral: Pointer to Spectral object
3942  * @ch_width: Channel width array
3943  * @chan_freq: Center frequency of a WLAN channel
3944  * @center_freq: Pointer to center frequency
3945  *
3946  * Return: QDF_STATUS
3947  */
3948 static QDF_STATUS
3949 target_if_calculate_center_freq(struct target_if_spectral *spectral,
3950 				enum phy_ch_width *ch_width,
3951 				uint16_t chan_freq,
3952 				uint16_t *center_freq)
3953 {
3954 	enum phy_ch_width agile_ch_width;
3955 
3956 	if (!spectral) {
3957 		spectral_err("spectral target if object is null");
3958 		return QDF_STATUS_E_FAILURE;
3959 	}
3960 
3961 	if (!ch_width) {
3962 		spectral_err("Channel width array is null");
3963 		return QDF_STATUS_E_INVAL;
3964 	}
3965 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
3966 
3967 	if (!center_freq) {
3968 		spectral_err("center_freq argument is null");
3969 		return QDF_STATUS_E_FAILURE;
3970 	}
3971 
3972 	if (agile_ch_width == CH_WIDTH_20MHZ) {
3973 		*center_freq = chan_freq;
3974 	} else {
3975 		uint16_t start_freq;
3976 		uint16_t end_freq;
3977 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
3978 		enum channel_state state;
3979 
3980 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
3981 			(spectral->pdev_obj, chan_freq, agile_ch_width,
3982 			 &bonded_chan_ptr, REG_CURRENT_PWR_MODE,
3983 			 NO_SCHANS_PUNC);
3984 		if (state == CHANNEL_STATE_DISABLE ||
3985 		    state == CHANNEL_STATE_INVALID) {
3986 			spectral_err("Channel state is disable or invalid");
3987 			return QDF_STATUS_E_FAILURE;
3988 		}
3989 		if (!bonded_chan_ptr) {
3990 			spectral_err("Bonded channel is not found");
3991 			return QDF_STATUS_E_FAILURE;
3992 		}
3993 		start_freq = bonded_chan_ptr->start_freq;
3994 		end_freq = bonded_chan_ptr->end_freq;
3995 		*center_freq = (start_freq + end_freq) >> 1;
3996 	}
3997 
3998 	return QDF_STATUS_SUCCESS;
3999 }
4000 
4001 /**
4002  * target_if_validate_center_freq() - Helper routine to
4003  * validate user provided agile center frequency
4004  *
4005  * @spectral: Pointer to Spectral object
4006  * @ch_width: Channel width array
4007  * @center_freq: User provided agile span center frequency
4008  * @is_valid: Indicates whether agile span center frequency is valid
4009  *
4010  * Return: QDF_STATUS
4011  */
4012 static QDF_STATUS
4013 target_if_validate_center_freq(struct target_if_spectral *spectral,
4014 			       enum phy_ch_width *ch_width,
4015 			       uint16_t center_freq,
4016 			       bool *is_valid)
4017 {
4018 	enum phy_ch_width agile_ch_width;
4019 	struct wlan_objmgr_pdev *pdev;
4020 	QDF_STATUS status;
4021 
4022 	if (!spectral) {
4023 		spectral_err("spectral target if object is null");
4024 		return QDF_STATUS_E_FAILURE;
4025 	}
4026 
4027 	if (!ch_width) {
4028 		spectral_err("channel width array is null");
4029 		return QDF_STATUS_E_INVAL;
4030 	}
4031 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
4032 
4033 	if (!is_valid) {
4034 		spectral_err("is_valid argument is null");
4035 		return QDF_STATUS_E_FAILURE;
4036 	}
4037 
4038 	pdev = spectral->pdev_obj;
4039 
4040 	if (agile_ch_width == CH_WIDTH_20MHZ) {
4041 		status = target_if_is_center_freq_of_any_chan
4042 				(pdev, center_freq, is_valid);
4043 		if (QDF_IS_STATUS_ERROR(status))
4044 			return QDF_STATUS_E_FAILURE;
4045 	} else {
4046 		uint16_t start_freq;
4047 		uint16_t end_freq;
4048 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
4049 		bool is_chan;
4050 
4051 		status = target_if_is_center_freq_of_any_chan
4052 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
4053 				 &is_chan);
4054 		if (QDF_IS_STATUS_ERROR(status))
4055 			return QDF_STATUS_E_FAILURE;
4056 
4057 		if (is_chan) {
4058 			uint32_t calulated_center_freq;
4059 			enum channel_state st;
4060 
4061 			st =
4062 			    wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
4063 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
4064 				 agile_ch_width,
4065 				 &bonded_chan_ptr,
4066 				 REG_CURRENT_PWR_MODE,
4067 				 NO_SCHANS_PUNC);
4068 			if (st == CHANNEL_STATE_DISABLE ||
4069 			    st == CHANNEL_STATE_INVALID) {
4070 				spectral_err("Channel state disable/invalid");
4071 				return QDF_STATUS_E_FAILURE;
4072 			}
4073 			if (!bonded_chan_ptr) {
4074 				spectral_err("Bonded channel is not found");
4075 				return QDF_STATUS_E_FAILURE;
4076 			}
4077 			start_freq = bonded_chan_ptr->start_freq;
4078 			end_freq = bonded_chan_ptr->end_freq;
4079 			calulated_center_freq = (start_freq + end_freq) >> 1;
4080 			*is_valid = (center_freq == calulated_center_freq);
4081 		} else {
4082 			*is_valid = false;
4083 		}
4084 	}
4085 
4086 	return QDF_STATUS_SUCCESS;
4087 }
4088 
4089 /**
4090  * target_if_is_agile_span_overlap_with_operating_span() - Helper routine to
4091  * check whether agile span overlaps with current operating band.
4092  *
4093  * @spectral: Pointer to Spectral object
4094  * @ch_width: Channel width array
4095  * @center_freq: Agile span center frequency
4096  * @is_overlapping: Indicates whether Agile span overlaps with operating span
4097  *
4098  * Helper routine to check whether agile span overlaps with current
4099  * operating band.
4100  *
4101  * Return: QDF_STATUS
4102  */
4103 static QDF_STATUS
4104 target_if_is_agile_span_overlap_with_operating_span
4105 			(struct target_if_spectral *spectral,
4106 			 enum phy_ch_width *ch_width,
4107 			 struct spectral_config_frequency *center_freq,
4108 			 bool *is_overlapping)
4109 {
4110 	enum phy_ch_width op_ch_width;
4111 	enum phy_ch_width agile_ch_width;
4112 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
4113 	struct wlan_objmgr_vdev *vdev;
4114 	struct wlan_objmgr_pdev *pdev;
4115 	int16_t chan_freq;
4116 	uint32_t op_start_freq;
4117 	uint32_t op_end_freq;
4118 	uint32_t agile_start_freq;
4119 	uint32_t agile_end_freq;
4120 	uint32_t cfreq2;
4121 
4122 	if (!spectral) {
4123 		spectral_err("Spectral object is NULL");
4124 		return QDF_STATUS_E_FAILURE;
4125 	}
4126 
4127 	pdev  = spectral->pdev_obj;
4128 	if (!pdev) {
4129 		spectral_err("pdev object is NULL");
4130 		return QDF_STATUS_E_FAILURE;
4131 	}
4132 
4133 	if (!ch_width) {
4134 		spectral_err("channel width array is null");
4135 		return QDF_STATUS_E_FAILURE;
4136 	}
4137 	op_ch_width = ch_width[SPECTRAL_SCAN_MODE_NORMAL];
4138 	if (op_ch_width == CH_WIDTH_INVALID) {
4139 		spectral_err("Invalid channel width");
4140 		return QDF_STATUS_E_INVAL;
4141 	}
4142 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
4143 	if (agile_ch_width == CH_WIDTH_INVALID) {
4144 		spectral_err("Invalid channel width");
4145 		return QDF_STATUS_E_INVAL;
4146 	}
4147 
4148 	if (!is_overlapping) {
4149 		spectral_err("Argument(is_overlapping) is NULL");
4150 		return QDF_STATUS_E_FAILURE;
4151 	}
4152 	*is_overlapping = false;
4153 
4154 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
4155 	if (!vdev) {
4156 		spectral_err("vdev is NULL");
4157 		return QDF_STATUS_E_FAILURE;
4158 	}
4159 	chan_freq = target_if_vdev_get_chan_freq(vdev);
4160 	cfreq2 = target_if_vdev_get_chan_freq_seg2(vdev);
4161 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4162 	if (cfreq2 < 0) {
4163 		spectral_err("cfreq2 is invalid");
4164 		return QDF_STATUS_E_FAILURE;
4165 	}
4166 
4167 	if (op_ch_width == CH_WIDTH_20MHZ) {
4168 		op_start_freq = chan_freq - FREQ_OFFSET_10MHZ;
4169 		op_end_freq = chan_freq + FREQ_OFFSET_10MHZ;
4170 	} else {
4171 		enum channel_state state;
4172 
4173 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
4174 			(pdev, chan_freq, op_ch_width, &bonded_chan_ptr,
4175 			 REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC);
4176 		if (state == CHANNEL_STATE_DISABLE ||
4177 		    state == CHANNEL_STATE_INVALID) {
4178 			spectral_err("Channel state is disable or invalid");
4179 			return QDF_STATUS_E_FAILURE;
4180 		}
4181 		if (!bonded_chan_ptr) {
4182 			spectral_err("Bonded channel is not found");
4183 			return QDF_STATUS_E_FAILURE;
4184 		}
4185 		op_start_freq = bonded_chan_ptr->start_freq - FREQ_OFFSET_10MHZ;
4186 		op_end_freq = bonded_chan_ptr->end_freq - FREQ_OFFSET_10MHZ;
4187 	}
4188 
4189 	if (agile_ch_width == CH_WIDTH_80P80MHZ) {
4190 		agile_start_freq = center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
4191 		agile_end_freq = center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
4192 		if (agile_end_freq > op_start_freq &&
4193 		    op_end_freq > agile_start_freq)
4194 			*is_overlapping = true;
4195 
4196 		agile_start_freq = center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
4197 		agile_end_freq = center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
4198 		if (agile_end_freq > op_start_freq &&
4199 		    op_end_freq > agile_start_freq)
4200 			*is_overlapping = true;
4201 	} else {
4202 		agile_start_freq = center_freq->cfreq1 -
4203 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4204 		agile_end_freq = center_freq->cfreq1 +
4205 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4206 		if (agile_end_freq > op_start_freq &&
4207 		    op_end_freq > agile_start_freq)
4208 			*is_overlapping = true;
4209 	}
4210 
4211 	if (op_ch_width == CH_WIDTH_80P80MHZ) {
4212 		uint32_t sec80_start_feq;
4213 		uint32_t sec80_end_freq;
4214 
4215 		sec80_start_feq = cfreq2 - FREQ_OFFSET_40MHZ;
4216 		sec80_end_freq = cfreq2 + FREQ_OFFSET_40MHZ;
4217 
4218 		if (agile_ch_width == CH_WIDTH_80P80MHZ) {
4219 			agile_start_freq =
4220 					center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
4221 			agile_end_freq =
4222 					center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
4223 			if (agile_end_freq > sec80_start_feq &&
4224 			    sec80_end_freq > agile_start_freq)
4225 				*is_overlapping = true;
4226 
4227 			agile_start_freq =
4228 					center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
4229 			agile_end_freq =
4230 					center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
4231 			if (agile_end_freq > sec80_start_feq &&
4232 			    sec80_end_freq > agile_start_freq)
4233 				*is_overlapping = true;
4234 		} else {
4235 			agile_start_freq = center_freq->cfreq1 -
4236 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4237 			agile_end_freq = center_freq->cfreq1 +
4238 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4239 			if (agile_end_freq > sec80_start_feq &&
4240 			    sec80_end_freq > agile_start_freq)
4241 				*is_overlapping = true;
4242 		}
4243 	}
4244 
4245 	return QDF_STATUS_SUCCESS;
4246 }
4247 
4248 /**
4249  * target_if_spectral_populate_chwidth() - Helper routine to
4250  * populate channel width for different Spectral modes
4251  *
4252  * @spectral: Pointer to Spectral object
4253  * @ch_width: Channel width array
4254  * @is_80_80_agile: Indicates whether 80+80 agile scan is requested
4255  *
4256  * Helper routine to populate channel width for different Spectral modes
4257  *
4258  * Return: QDF_STATUS
4259  */
4260 static QDF_STATUS
4261 target_if_spectral_populate_chwidth(struct target_if_spectral *spectral,
4262 				    enum phy_ch_width *ch_width,
4263 				    bool is_80_80_agile)
4264 {
4265 	enum spectral_scan_mode smode;
4266 
4267 	qdf_assert_always(spectral);
4268 
4269 	smode = SPECTRAL_SCAN_MODE_NORMAL;
4270 	for (; smode < SPECTRAL_SCAN_MODE_MAX; ++smode) {
4271 		/* If user has configured sscan bandwidth, use it */
4272 		if (spectral->sscan_width_configured[smode]) {
4273 			ch_width[smode] = spectral->params[smode].ss_bandwidth;
4274 		} else {
4275 			/* Otherwise, derive the default sscan bandwidth */
4276 			ch_width[smode] = get_default_sscan_bw(spectral, smode,
4277 							       is_80_80_agile);
4278 			if (ch_width[smode] >= CH_WIDTH_INVALID) {
4279 				spectral_err("Invalid sscan BW %u",
4280 					     ch_width[smode]);
4281 				return QDF_STATUS_E_FAILURE;
4282 			}
4283 			spectral->params[smode].ss_bandwidth = ch_width[smode];
4284 		}
4285 	}
4286 
4287 	return QDF_STATUS_SUCCESS;
4288 }
4289 
4290 /**
4291  * target_if_spectral_is_valid_80p80_freq() - API to check whether given
4292  * (cfreq1, cfreq2) pair forms a valid 80+80 combination
4293  * @pdev: pointer to pdev
4294  * @cfreq1: center frequency 1
4295  * @cfreq2: center frequency 2
4296  *
4297  * API to check whether given (cfreq1, cfreq2) pair forms a valid 80+80
4298  * combination
4299  *
4300  * Return: true or false
4301  */
4302 static bool
4303 target_if_spectral_is_valid_80p80_freq(struct wlan_objmgr_pdev *pdev,
4304 				       uint32_t cfreq1, uint32_t cfreq2)
4305 {
4306 	struct ch_params ch_params = {0};
4307 	enum channel_state chan_state1;
4308 	enum channel_state chan_state2;
4309 	struct wlan_objmgr_psoc *psoc;
4310 	struct ch_params temp_params = {0};
4311 
4312 	qdf_assert_always(pdev);
4313 	psoc = wlan_pdev_get_psoc(pdev);
4314 	qdf_assert_always(psoc);
4315 
4316 	/* In restricted 80P80 MHz enabled, only one 80+80 MHz
4317 	 * channel is supported with cfreq=5690 and cfreq=5775.
4318 	 */
4319 	if (wlan_psoc_nif_fw_ext_cap_get(
4320 				psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT))
4321 		return CHAN_WITHIN_RESTRICTED_80P80(cfreq1, cfreq2);
4322 
4323 	ch_params.center_freq_seg1 = wlan_reg_freq_to_chan(pdev, cfreq2);
4324 	ch_params.mhz_freq_seg1 = cfreq2;
4325 	ch_params.ch_width = CH_WIDTH_80P80MHZ;
4326 	wlan_reg_set_channel_params_for_pwrmode(
4327 					pdev,
4328 					cfreq1 - FREQ_OFFSET_10MHZ,
4329 					0,
4330 					&ch_params,
4331 					REG_CURRENT_PWR_MODE);
4332 
4333 	if (ch_params.ch_width != CH_WIDTH_80P80MHZ)
4334 		return false;
4335 
4336 	if (ch_params.mhz_freq_seg0 != cfreq1 ||
4337 	    ch_params.mhz_freq_seg1 != cfreq2)
4338 		return false;
4339 
4340 	temp_params.ch_width = CH_WIDTH_80MHZ;
4341 	chan_state1 = wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
4342 				pdev,
4343 				ch_params.mhz_freq_seg0 - FREQ_OFFSET_10MHZ,
4344 				&temp_params,
4345 				REG_CURRENT_PWR_MODE);
4346 	if ((chan_state1 == CHANNEL_STATE_DISABLE) ||
4347 	    (chan_state1 == CHANNEL_STATE_INVALID))
4348 		return false;
4349 
4350 	temp_params.ch_width = CH_WIDTH_80MHZ;
4351 	chan_state2 = wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
4352 				pdev,
4353 				ch_params.mhz_freq_seg1 - FREQ_OFFSET_10MHZ,
4354 				&temp_params,
4355 				REG_CURRENT_PWR_MODE);
4356 	if ((chan_state2 == CHANNEL_STATE_DISABLE) ||
4357 	    (chan_state2 == CHANNEL_STATE_INVALID))
4358 		return false;
4359 
4360 	if (abs(ch_params.mhz_freq_seg0 - ch_params.mhz_freq_seg1) <=
4361 	    FREQ_OFFSET_80MHZ)
4362 		return false;
4363 
4364 	return true;
4365 }
4366 
4367 /**
4368  * _target_if_set_spectral_config() - Set spectral config
4369  * @spectral:       Pointer to spectral object
4370  * @param: Spectral parameter id and value
4371  * @smode: Spectral scan mode
4372  * @err: Spectral error code
4373  *
4374  * API to set spectral configurations
4375  *
4376  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4377  */
4378 static QDF_STATUS
4379 _target_if_set_spectral_config(struct target_if_spectral *spectral,
4380 			       const struct spectral_cp_param *param,
4381 			       const enum spectral_scan_mode smode,
4382 			       enum spectral_cp_error_code *err)
4383 {
4384 	struct spectral_config params;
4385 	struct target_if_spectral_ops *p_sops;
4386 	struct spectral_config *sparams;
4387 	QDF_STATUS status;
4388 	bool is_overlapping;
4389 	uint16_t agile_cfreq;
4390 	bool is_valid_chan;
4391 	struct spectral_param_min_max *param_min_max;
4392 	enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
4393 	enum spectral_scan_mode m;
4394 	struct spectral_config_frequency center_freq = {0};
4395 	bool is_bw_supported;
4396 	struct wlan_objmgr_vdev *vdev;
4397 	enum phy_ch_width op_bw;
4398 
4399 	if (!err) {
4400 		spectral_err("Error code argument is null");
4401 		QDF_ASSERT(0);
4402 		return QDF_STATUS_E_FAILURE;
4403 	}
4404 	*err = SPECTRAL_SCAN_ERR_INVALID;
4405 
4406 	if (!param) {
4407 		spectral_err("Parameter object is null");
4408 		return QDF_STATUS_E_FAILURE;
4409 	}
4410 
4411 	if (!spectral) {
4412 		spectral_err("spectral object is NULL");
4413 		return QDF_STATUS_E_FAILURE;
4414 	}
4415 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4416 	param_min_max = &spectral->param_min_max;
4417 
4418 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4419 		spectral_err("Invalid Spectral mode %u", smode);
4420 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4421 		return QDF_STATUS_E_FAILURE;
4422 	}
4423 
4424 	sparams = &spectral->params[smode];
4425 	m = SPECTRAL_SCAN_MODE_NORMAL;
4426 	for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
4427 		ch_width[m] = CH_WIDTH_INVALID;
4428 
4429 	if (!spectral->params_valid[smode]) {
4430 		target_if_spectral_info_read(spectral,
4431 					     smode,
4432 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
4433 					     &spectral->params[smode],
4434 					     sizeof(spectral->params[smode]));
4435 		spectral->params_valid[smode] = true;
4436 	}
4437 
4438 	switch (param->id) {
4439 	case SPECTRAL_PARAM_FFT_PERIOD:
4440 		sparams->ss_fft_period = param->value;
4441 		break;
4442 	case SPECTRAL_PARAM_SCAN_PERIOD:
4443 		sparams->ss_period = param->value;
4444 		if (sparams->ss_recapture && ((sparams->ss_period <
4445 		    SPECTRAL_RECAPTURE_SCAN_PERIOD_THRESHOLD) ||
4446 		    (smode == SPECTRAL_SCAN_MODE_AGILE))) {
4447 			sparams->ss_recapture = false;
4448 			spectral_err("FFT recapture cannot be enabled due to scan period: %d us or spectral scan mode: %d",
4449 				     sparams->ss_period, smode);
4450 		}
4451 		break;
4452 	case SPECTRAL_PARAM_FFT_RECAPTURE:
4453 		if (param->value) {
4454 			if (sparams->ss_period >=
4455 			    SPECTRAL_RECAPTURE_SCAN_PERIOD_THRESHOLD &&
4456 			    smode == SPECTRAL_SCAN_MODE_NORMAL) {
4457 				sparams->ss_recapture = true;
4458 			} else {
4459 				spectral_err("FFT recapture cannot be enabled due to scan period: %d us or spectral scan mode: %d",
4460 					     sparams->ss_period, smode);
4461 				sparams->ss_recapture = false;
4462 			}
4463 		} else {
4464 			sparams->ss_recapture = false;
4465 		}
4466 		break;
4467 	case SPECTRAL_PARAM_SCAN_COUNT:
4468 		sparams->ss_count = param->value;
4469 		break;
4470 	case SPECTRAL_PARAM_SHORT_REPORT:
4471 		sparams->ss_short_report = (!!param->value) ? true : false;
4472 		break;
4473 	case SPECTRAL_PARAM_SPECT_PRI:
4474 		sparams->ss_spectral_pri = (!!param->value) ? true : false;
4475 		break;
4476 	case SPECTRAL_PARAM_FFT_SIZE:
4477 		status = target_if_spectral_populate_chwidth
4478 			(spectral, ch_width, spectral->params
4479 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
4480 		if (QDF_IS_STATUS_ERROR(status))
4481 			return QDF_STATUS_E_FAILURE;
4482 		if ((param->value < param_min_max->fft_size_min) ||
4483 		    (param->value > param_min_max->fft_size_max
4484 		    [ch_width[smode]])) {
4485 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4486 			return QDF_STATUS_E_FAILURE;
4487 		}
4488 		sparams->ss_fft_size = param->value;
4489 		break;
4490 	case SPECTRAL_PARAM_GC_ENA:
4491 		sparams->ss_gc_ena = !!param->value;
4492 		break;
4493 	case SPECTRAL_PARAM_RESTART_ENA:
4494 		sparams->ss_restart_ena = !!param->value;
4495 		break;
4496 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
4497 		sparams->ss_noise_floor_ref = param->value;
4498 		break;
4499 	case SPECTRAL_PARAM_INIT_DELAY:
4500 		sparams->ss_init_delay = param->value;
4501 		break;
4502 	case SPECTRAL_PARAM_NB_TONE_THR:
4503 		sparams->ss_nb_tone_thr = param->value;
4504 		break;
4505 	case SPECTRAL_PARAM_STR_BIN_THR:
4506 		sparams->ss_str_bin_thr = param->value;
4507 		break;
4508 	case SPECTRAL_PARAM_WB_RPT_MODE:
4509 		sparams->ss_wb_rpt_mode = !!param->value;
4510 		break;
4511 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
4512 		sparams->ss_rssi_rpt_mode = !!param->value;
4513 		break;
4514 	case SPECTRAL_PARAM_RSSI_THR:
4515 		sparams->ss_rssi_thr = param->value;
4516 		break;
4517 	case SPECTRAL_PARAM_PWR_FORMAT:
4518 		sparams->ss_pwr_format = !!param->value;
4519 		break;
4520 	case SPECTRAL_PARAM_RPT_MODE:
4521 		if ((param->value < SPECTRAL_PARAM_RPT_MODE_MIN) ||
4522 		    (param->value > SPECTRAL_PARAM_RPT_MODE_MAX)) {
4523 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4524 			return QDF_STATUS_E_FAILURE;
4525 		}
4526 		sparams->ss_rpt_mode = param->value;
4527 		break;
4528 	case SPECTRAL_PARAM_BIN_SCALE:
4529 		sparams->ss_bin_scale = param->value;
4530 		break;
4531 	case SPECTRAL_PARAM_DBM_ADJ:
4532 		sparams->ss_dbm_adj = !!param->value;
4533 		break;
4534 	case SPECTRAL_PARAM_CHN_MASK:
4535 		sparams->ss_chn_mask = param->value;
4536 		break;
4537 	case SPECTRAL_PARAM_FREQUENCY:
4538 		status = target_if_spectral_populate_chwidth(
4539 				spectral, ch_width, param->freq.cfreq2 > 0);
4540 		if (QDF_IS_STATUS_ERROR(status)) {
4541 			spectral_err("Failed to populate channel width");
4542 			return QDF_STATUS_E_FAILURE;
4543 		}
4544 
4545 		if (ch_width[smode] != CH_WIDTH_80P80MHZ &&
4546 		    param->freq.cfreq2) {
4547 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4548 			spectral_err("Non zero cfreq2 expected for 80p80 only");
4549 			return QDF_STATUS_E_INVAL;
4550 		}
4551 
4552 		if (ch_width[smode] == CH_WIDTH_80P80MHZ &&
4553 		    !param->freq.cfreq2) {
4554 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4555 			spectral_err("Non zero cfreq2 expected for 80p80");
4556 			return QDF_STATUS_E_INVAL;
4557 		}
4558 
4559 		status = target_if_is_center_freq_of_any_chan
4560 				(spectral->pdev_obj, param->freq.cfreq1,
4561 				 &is_valid_chan);
4562 		if (QDF_IS_STATUS_ERROR(status))
4563 			return QDF_STATUS_E_FAILURE;
4564 
4565 		if (is_valid_chan) {
4566 			status = target_if_calculate_center_freq(
4567 							spectral, ch_width,
4568 							param->freq.cfreq1,
4569 							&agile_cfreq);
4570 			if (QDF_IS_STATUS_ERROR(status)) {
4571 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4572 				return QDF_STATUS_E_FAILURE;
4573 			}
4574 		} else {
4575 			bool is_valid_agile_cfreq;
4576 
4577 			status = target_if_validate_center_freq
4578 				(spectral, ch_width, param->freq.cfreq1,
4579 				 &is_valid_agile_cfreq);
4580 			if (QDF_IS_STATUS_ERROR(status))
4581 				return QDF_STATUS_E_FAILURE;
4582 
4583 			if (!is_valid_agile_cfreq) {
4584 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4585 				spectral_err("Invalid agile center frequency");
4586 				return QDF_STATUS_E_FAILURE;
4587 			}
4588 
4589 			agile_cfreq = param->freq.cfreq1;
4590 		}
4591 		center_freq.cfreq1 = agile_cfreq;
4592 
4593 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
4594 			status = target_if_is_center_freq_of_any_chan
4595 					(spectral->pdev_obj, param->freq.cfreq2,
4596 					 &is_valid_chan);
4597 			if (QDF_IS_STATUS_ERROR(status))
4598 				return QDF_STATUS_E_FAILURE;
4599 
4600 			if (is_valid_chan) {
4601 				status = target_if_calculate_center_freq(
4602 						spectral, ch_width,
4603 						param->freq.cfreq2,
4604 						&agile_cfreq);
4605 				if (QDF_IS_STATUS_ERROR(status)) {
4606 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4607 					return QDF_STATUS_E_FAILURE;
4608 				}
4609 			} else {
4610 				bool is_valid_agile_cfreq;
4611 
4612 				status = target_if_validate_center_freq
4613 					(spectral, ch_width, param->freq.cfreq2,
4614 					 &is_valid_agile_cfreq);
4615 				if (QDF_IS_STATUS_ERROR(status))
4616 					return QDF_STATUS_E_FAILURE;
4617 
4618 				if (!is_valid_agile_cfreq) {
4619 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4620 					spectral_err("Invalid agile center frequency");
4621 					return QDF_STATUS_E_FAILURE;
4622 				}
4623 
4624 				agile_cfreq = param->freq.cfreq2;
4625 			}
4626 			center_freq.cfreq2 = agile_cfreq;
4627 		}
4628 
4629 		status = target_if_is_agile_span_overlap_with_operating_span
4630 				(spectral, ch_width,
4631 				 &center_freq, &is_overlapping);
4632 		if (QDF_IS_STATUS_ERROR(status))
4633 			return QDF_STATUS_E_FAILURE;
4634 
4635 		if (is_overlapping) {
4636 			spectral_err("Agile freq %u, %u overlaps with operating span",
4637 				     center_freq.cfreq1, center_freq.cfreq2);
4638 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4639 			return QDF_STATUS_E_FAILURE;
4640 		}
4641 
4642 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
4643 			bool is_valid_80p80;
4644 
4645 			is_valid_80p80 = target_if_spectral_is_valid_80p80_freq(
4646 						spectral->pdev_obj,
4647 						center_freq.cfreq1,
4648 						center_freq.cfreq2);
4649 
4650 			if (!is_valid_80p80) {
4651 				spectral_err("Agile freq %u, %u is invalid 80+80 combination",
4652 					     center_freq.cfreq1,
4653 					     center_freq.cfreq2);
4654 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4655 				return QDF_STATUS_E_FAILURE;
4656 			}
4657 		}
4658 
4659 		sparams->ss_frequency.cfreq1 = center_freq.cfreq1;
4660 		sparams->ss_frequency.cfreq2 = center_freq.cfreq2;
4661 
4662 		break;
4663 
4664 	case SPECTRAL_PARAM_CHAN_WIDTH:
4665 		if (param->value >= CH_WIDTH_INVALID) {
4666 			spectral_err("invalid sscan width: %u", param->value);
4667 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4668 			return QDF_STATUS_E_FAILURE;
4669 		}
4670 
4671 		vdev = target_if_spectral_get_vdev(spectral, smode);
4672 		if (!vdev) {
4673 			spectral_err("vdev is null");
4674 			return QDF_STATUS_E_NULL_VALUE;
4675 		}
4676 		op_bw = target_if_vdev_get_ch_width(vdev);
4677 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4678 
4679 		/* Validate the bandwidth */
4680 		status = target_if_is_sscan_bw_supported(
4681 				spectral, smode,
4682 				param->value, op_bw, &is_bw_supported,
4683 				spectral->params[SPECTRAL_SCAN_MODE_AGILE].
4684 				ss_frequency.cfreq2 > 0);
4685 		if (QDF_IS_STATUS_ERROR(status)) {
4686 			spectral_err("Unable to check if given sscan_bw is supported");
4687 			return QDF_STATUS_E_FAILURE;
4688 		}
4689 
4690 		if (!is_bw_supported) {
4691 			spectral_err("sscan bw(%u) is not supported for the current operating width(%u) and sscan mode(%u)",
4692 				     param->value, op_bw, smode);
4693 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4694 			return QDF_STATUS_E_FAILURE;
4695 		}
4696 
4697 		sparams->ss_bandwidth = param->value;
4698 		spectral->sscan_width_configured[smode] = true;
4699 
4700 		break;
4701 	}
4702 
4703 	p_sops->configure_spectral(spectral, sparams, smode);
4704 	/* only to validate the writes */
4705 	p_sops->get_spectral_config(spectral, &params, smode);
4706 	return QDF_STATUS_SUCCESS;
4707 }
4708 
4709 QDF_STATUS
4710 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
4711 			      const struct spectral_cp_param *param,
4712 			      const enum spectral_scan_mode smode,
4713 			      enum spectral_cp_error_code *err)
4714 {
4715 	enum spectral_scan_mode mode = SPECTRAL_SCAN_MODE_NORMAL;
4716 	struct target_if_spectral *spectral;
4717 	QDF_STATUS status;
4718 
4719 	if (!err) {
4720 		spectral_err("Error code argument is null");
4721 		QDF_ASSERT(0);
4722 		return QDF_STATUS_E_FAILURE;
4723 	}
4724 	*err = SPECTRAL_SCAN_ERR_INVALID;
4725 
4726 	if (!pdev) {
4727 		spectral_err("pdev object is NULL");
4728 		return QDF_STATUS_E_FAILURE;
4729 	}
4730 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4731 	if (!spectral) {
4732 		spectral_err("spectral object is NULL");
4733 		return QDF_STATUS_E_FAILURE;
4734 	}
4735 
4736 	if (!param) {
4737 		spectral_err("parameter object is NULL");
4738 		return QDF_STATUS_E_FAILURE;
4739 	}
4740 
4741 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4742 		spectral_err("Invalid Spectral mode %u", smode);
4743 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4744 		return QDF_STATUS_E_FAILURE;
4745 	}
4746 
4747 	if (!spectral->properties[smode][param->id].supported) {
4748 		spectral_err("Spectral parameter(%u) unsupported for mode %u",
4749 			     param->id, smode);
4750 		*err = SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED;
4751 		return QDF_STATUS_E_FAILURE;
4752 	}
4753 
4754 	if (spectral->properties[smode][param->id].common_all_modes) {
4755 		spectral_warn("Setting Spectral parameter %u for all modes",
4756 			      param->id);
4757 		for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) {
4758 			status = _target_if_set_spectral_config
4759 						(spectral, param, mode, err);
4760 			if (QDF_IS_STATUS_ERROR(status))
4761 				return QDF_STATUS_E_FAILURE;
4762 		}
4763 		return QDF_STATUS_SUCCESS;
4764 	}
4765 
4766 	return _target_if_set_spectral_config(spectral, param, smode, err);
4767 }
4768 
4769 /**
4770  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
4771  * @fft_len: FFT length
4772  * @pdev: Pointer to pdev object
4773  *
4774  * API to get fft bin count for a given fft length
4775  *
4776  * Return: FFt bin count
4777  */
4778 static int
4779 target_if_get_fft_bin_count(int fft_len)
4780 {
4781 	int bin_count = 0;
4782 
4783 	switch (fft_len) {
4784 	case 5:
4785 		bin_count = 16;
4786 		break;
4787 	case 6:
4788 		bin_count = 32;
4789 		break;
4790 	case 7:
4791 		bin_count = 64;
4792 		break;
4793 	case 8:
4794 		bin_count = 128;
4795 		break;
4796 	case 9:
4797 		bin_count = 256;
4798 		break;
4799 	default:
4800 		break;
4801 	}
4802 
4803 	return bin_count;
4804 }
4805 
4806 /**
4807  * target_if_init_upper_lower_flags() - Initializes control and extension
4808  * segment flags
4809  * @spectral: pointer to target if spectral object
4810  * @smode: Spectral scan mode
4811  *
4812  * API to initialize the control and extension flags with the lower/upper
4813  * segment based on the HT mode
4814  *
4815  * Return: FFt bin count
4816  */
4817 static void
4818 target_if_init_upper_lower_flags(struct target_if_spectral *spectral,
4819 				 enum spectral_scan_mode smode)
4820 {
4821 	int current_channel = 0;
4822 	int ext_channel = 0;
4823 	struct target_if_spectral_ops *p_sops =
4824 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
4825 
4826 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4827 		spectral_err("Invalid Spectral mode %u", smode);
4828 		return;
4829 	}
4830 	current_channel = p_sops->get_current_channel(spectral, smode);
4831 	ext_channel = p_sops->get_extension_channel(spectral, smode);
4832 
4833 	if ((current_channel == 0) || (ext_channel == 0))
4834 		return;
4835 
4836 	if (spectral->sc_spectral_20_40_mode) {
4837 		/* HT40 mode */
4838 		if (ext_channel < current_channel) {
4839 			spectral->lower_is_extension = 1;
4840 			spectral->upper_is_control = 1;
4841 			spectral->lower_is_control = 0;
4842 			spectral->upper_is_extension = 0;
4843 		} else {
4844 			spectral->lower_is_extension = 0;
4845 			spectral->upper_is_control = 0;
4846 			spectral->lower_is_control = 1;
4847 			spectral->upper_is_extension = 1;
4848 		}
4849 	} else {
4850 		/* HT20 mode, lower is always control */
4851 		spectral->lower_is_extension = 0;
4852 		spectral->upper_is_control = 0;
4853 		spectral->lower_is_control = 1;
4854 		spectral->upper_is_extension = 0;
4855 	}
4856 }
4857 
4858 /**
4859  * target_if_get_spectral_config() - Get spectral configuration
4860  * @pdev: Pointer to pdev object
4861  * @param: Pointer to spectral_config structure in which the configuration
4862  * should be returned
4863  * @smode: Spectral scan mode
4864  *
4865  * API to get the current spectral configuration
4866  *
4867  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4868  */
4869 QDF_STATUS
4870 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
4871 			      struct spectral_config *param,
4872 			      enum spectral_scan_mode smode)
4873 {
4874 	struct target_if_spectral_ops *p_sops = NULL;
4875 	struct target_if_spectral *spectral = NULL;
4876 
4877 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4878 
4879 	if (!spectral) {
4880 		spectral_err("SPECTRAL : Module doesn't exist");
4881 		return QDF_STATUS_E_FAILURE;
4882 	}
4883 
4884 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4885 
4886 	if (!p_sops) {
4887 		spectral_err("p_sops is null");
4888 		return QDF_STATUS_E_FAILURE;
4889 	}
4890 
4891 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4892 		spectral_err("Invalid Spectral mode %u", smode);
4893 		return QDF_STATUS_E_FAILURE;
4894 	}
4895 
4896 	qdf_mem_zero(param, sizeof(struct spectral_config));
4897 	p_sops->get_spectral_config(spectral, param, smode);
4898 
4899 	return QDF_STATUS_SUCCESS;
4900 }
4901 
4902 #ifdef WLAN_FEATURE_11BE
4903 /**
4904  * target_if_spectral_get_num_detectors_for_higher_bws() - Get number of
4905  * Spectral detectors for higher bandwidths
4906  * @spectral: Pointer to target if Spectral object
4907  * @ch_width: channel width
4908  * @num_detectors: Pointer to the variable to store number of Spectral detectors
4909  *
4910  * API to get number of Spectral detectors used for scan in the given channel
4911  * width.
4912  *
4913  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
4914  */
4915 static QDF_STATUS
4916 target_if_spectral_get_num_detectors_for_higher_bws(
4917 				struct target_if_spectral *spectral,
4918 				enum phy_ch_width ch_width,
4919 				uint32_t *num_detectors)
4920 {
4921 	switch (ch_width) {
4922 	case CH_WIDTH_320MHZ:
4923 		*num_detectors = spectral->capability.num_detectors_320mhz;
4924 		break;
4925 
4926 	default:
4927 		spectral_err("Unsupported channel width %d", ch_width);
4928 		return QDF_STATUS_E_INVAL;
4929 	}
4930 
4931 	return QDF_STATUS_SUCCESS;
4932 }
4933 #else
4934 static QDF_STATUS
4935 target_if_spectral_get_num_detectors_for_higher_bws(
4936 				struct target_if_spectral *spectral,
4937 				enum phy_ch_width ch_width,
4938 				uint32_t *num_detectors)
4939 {
4940 	spectral_err("Unsupported channel width %d", ch_width);
4941 	return QDF_STATUS_E_INVAL;
4942 }
4943 #endif
4944 
4945 /**
4946  * target_if_spectral_get_num_detectors() - Get number of Spectral detectors
4947  * @spectral: Pointer to target if Spectral object
4948  * @ch_width: channel width
4949  * @num_detectors: Pointer to the variable to store number of Spectral detectors
4950  *
4951  * API to get number of Spectral detectors used for scan in the given channel
4952  * width.
4953  *
4954  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
4955  */
4956 static QDF_STATUS
4957 target_if_spectral_get_num_detectors(struct target_if_spectral *spectral,
4958 				     enum phy_ch_width ch_width,
4959 				     uint32_t *num_detectors)
4960 {
4961 	if (!spectral) {
4962 		spectral_err("target if spectral object is null");
4963 		return QDF_STATUS_E_INVAL;
4964 	}
4965 
4966 	if (ch_width >= CH_WIDTH_INVALID) {
4967 		spectral_err("Invalid channel width %d", ch_width);
4968 		return QDF_STATUS_E_INVAL;
4969 	}
4970 
4971 	if (!num_detectors) {
4972 		spectral_err("Invalid argument, number of detectors");
4973 		return QDF_STATUS_E_INVAL;
4974 	}
4975 
4976 	switch (ch_width) {
4977 	case CH_WIDTH_20MHZ:
4978 		*num_detectors = spectral->capability.num_detectors_20mhz;
4979 		break;
4980 
4981 	case CH_WIDTH_40MHZ:
4982 		*num_detectors = spectral->capability.num_detectors_40mhz;
4983 		break;
4984 
4985 	case CH_WIDTH_80MHZ:
4986 		*num_detectors = spectral->capability.num_detectors_80mhz;
4987 		break;
4988 
4989 	case CH_WIDTH_160MHZ:
4990 		*num_detectors = spectral->capability.num_detectors_160mhz;
4991 		break;
4992 
4993 	case CH_WIDTH_80P80MHZ:
4994 		*num_detectors = spectral->capability.num_detectors_80p80mhz;
4995 		break;
4996 
4997 	default:
4998 		return target_if_spectral_get_num_detectors_for_higher_bws(
4999 			spectral, ch_width, num_detectors);
5000 	}
5001 
5002 	return QDF_STATUS_SUCCESS;
5003 }
5004 
5005 /**
5006  * target_if_spectral_finite_scan_init() - Initializations required for finite
5007  * Spectral scan
5008  * @spectral: Pointer to target of Spctral object
5009  * @smode: Spectral scan mode
5010  *
5011  * This routine initializes the finite Spectral scan. Finite Spectral scan is
5012  * triggered by configuring a non zero scan count.
5013  *
5014  * Return: QDF_STATUS_SUCCESS on success
5015  */
5016 static QDF_STATUS
5017 target_if_spectral_finite_scan_init(struct target_if_spectral *spectral,
5018 				    enum spectral_scan_mode smode)
5019 {
5020 	struct target_if_finite_spectral_scan_params *finite_scan;
5021 	enum phy_ch_width ch_width;
5022 	uint32_t num_detectors;
5023 	QDF_STATUS status;
5024 	uint16_t sscan_count;
5025 
5026 	if (!spectral) {
5027 		spectral_err("target if spectral object is null");
5028 		return QDF_STATUS_E_INVAL;
5029 	}
5030 
5031 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5032 		spectral_err("Invalid Spectral mode");
5033 		return QDF_STATUS_E_INVAL;
5034 	}
5035 
5036 	ch_width = spectral->ch_width[smode];
5037 	status = target_if_spectral_get_num_detectors(spectral, ch_width,
5038 						      &num_detectors);
5039 
5040 	if (QDF_IS_STATUS_ERROR(status)) {
5041 		spectral_err("Failed to get number of detectors");
5042 		return QDF_STATUS_E_FAILURE;
5043 	}
5044 
5045 	finite_scan = &spectral->finite_scan[smode];
5046 	sscan_count =  spectral->params[smode].ss_count;
5047 
5048 	finite_scan->finite_spectral_scan =  true;
5049 	finite_scan->num_reports_expected = num_detectors * sscan_count;
5050 
5051 	return QDF_STATUS_SUCCESS;
5052 }
5053 
5054 /**
5055  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
5056  *                                           parameters
5057  * @spectral: Pointer to Spectral target_if internal private data
5058  * @spectral_params: Pointer to Spectral parameters
5059  * @smode: Spectral scan mode
5060  * @err: Spectral error code
5061  *
5062  * Enable use of desired Spectral parameters by configuring them into HW, and
5063  * starting Spectral scan
5064  *
5065  * Return: 0 on success, 1 on failure
5066  */
5067 int
5068 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
5069 				      struct spectral_config *spectral_params,
5070 				      enum spectral_scan_mode smode,
5071 				      enum spectral_cp_error_code *err)
5072 {
5073 	int extension_channel = 0;
5074 	int current_channel = 0;
5075 	struct target_if_spectral_ops *p_sops = NULL;
5076 	QDF_STATUS status;
5077 	struct wlan_objmgr_pdev *pdev;
5078 	struct wlan_objmgr_psoc *psoc;
5079 
5080 	if (!spectral) {
5081 		spectral_err("Spectral LMAC object is NULL");
5082 		return 1;
5083 	}
5084 
5085 	pdev =  spectral->pdev_obj;
5086 	if (!pdev) {
5087 		spectral_err("pdev is null");
5088 		return QDF_STATUS_E_INVAL;
5089 	}
5090 
5091 	psoc = wlan_pdev_get_psoc(pdev);
5092 	if (!psoc) {
5093 		spectral_err("psoc is null");
5094 		return QDF_STATUS_E_INVAL;
5095 	}
5096 
5097 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5098 		spectral_err("Invalid Spectral mode %u", smode);
5099 		return 1;
5100 	}
5101 
5102 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5103 
5104 	if (!p_sops) {
5105 		spectral_err("p_sops is NULL");
5106 		return 1;
5107 	}
5108 
5109 	spectral->sc_spectral_noise_pwr_cal =
5110 	    spectral_params->ss_spectral_pri ? 1 : 0;
5111 
5112 	/* check if extension channel is present */
5113 	extension_channel = p_sops->get_extension_channel(spectral, smode);
5114 	current_channel = p_sops->get_current_channel(spectral, smode);
5115 
5116 	if (spectral->capability.advncd_spectral_cap) {
5117 		spectral->lb_edge_extrabins = 0;
5118 		spectral->rb_edge_extrabins = 0;
5119 
5120 		if (spectral->is_lb_edge_extrabins_format &&
5121 		    spectral->params[smode].ss_rpt_mode == 2) {
5122 			spectral->lb_edge_extrabins = 4;
5123 		}
5124 
5125 		if (spectral->is_rb_edge_extrabins_format &&
5126 		    spectral->params[smode].ss_rpt_mode == 2) {
5127 			spectral->rb_edge_extrabins = 4;
5128 		}
5129 
5130 		if (spectral->ch_width[smode] == CH_WIDTH_20MHZ) {
5131 			spectral->sc_spectral_20_40_mode = 0;
5132 
5133 			spectral->spectral_numbins =
5134 			    target_if_get_fft_bin_count(
5135 				spectral->params[smode].ss_fft_size);
5136 			spectral->spectral_fft_len =
5137 			    target_if_get_fft_bin_count(
5138 				spectral->params[smode].ss_fft_size);
5139 			spectral->spectral_data_len =
5140 			    target_if_get_fft_bin_count(
5141 				spectral->params[smode].ss_fft_size);
5142 			/*
5143 			 * Initialize classifier params to be sent to user
5144 			 * space classifier
5145 			 */
5146 			spectral->classifier_params.lower_chan_in_mhz =
5147 			    current_channel;
5148 			spectral->classifier_params.upper_chan_in_mhz = 0;
5149 
5150 		} else if (spectral->ch_width[smode] == CH_WIDTH_40MHZ) {
5151 			/* TODO : Remove this variable */
5152 			spectral->sc_spectral_20_40_mode = 1;
5153 			spectral->spectral_numbins =
5154 			    target_if_get_fft_bin_count(
5155 				spectral->params[smode].ss_fft_size);
5156 			spectral->spectral_fft_len =
5157 			    target_if_get_fft_bin_count(
5158 				spectral->params[smode].ss_fft_size);
5159 			spectral->spectral_data_len =
5160 			    target_if_get_fft_bin_count(
5161 				spectral->params[smode].ss_fft_size);
5162 
5163 			/*
5164 			 * Initialize classifier params to be sent to user
5165 			 * space classifier
5166 			 */
5167 			if (extension_channel < current_channel) {
5168 				spectral->classifier_params.lower_chan_in_mhz =
5169 				    extension_channel;
5170 				spectral->classifier_params.upper_chan_in_mhz =
5171 				    current_channel;
5172 			} else {
5173 				spectral->classifier_params.lower_chan_in_mhz =
5174 				    current_channel;
5175 				spectral->classifier_params.upper_chan_in_mhz =
5176 				    extension_channel;
5177 			}
5178 
5179 		} else if (spectral->ch_width[smode] == CH_WIDTH_80MHZ) {
5180 			/* Set the FFT Size */
5181 			/* TODO : Remove this variable */
5182 			spectral->sc_spectral_20_40_mode = 0;
5183 			spectral->spectral_numbins =
5184 			    target_if_get_fft_bin_count(
5185 				spectral->params[smode].ss_fft_size);
5186 			spectral->spectral_fft_len =
5187 			    target_if_get_fft_bin_count(
5188 				spectral->params[smode].ss_fft_size);
5189 			spectral->spectral_data_len =
5190 			    target_if_get_fft_bin_count(
5191 				spectral->params[smode].ss_fft_size);
5192 
5193 			/*
5194 			 * Initialize classifier params to be sent to user
5195 			 * space classifier
5196 			 */
5197 			spectral->classifier_params.lower_chan_in_mhz =
5198 			    current_channel;
5199 			spectral->classifier_params.upper_chan_in_mhz = 0;
5200 
5201 			/*
5202 			 * Initialize classifier params to be sent to user
5203 			 * space classifier
5204 			 */
5205 			if (extension_channel < current_channel) {
5206 				spectral->classifier_params.lower_chan_in_mhz =
5207 				    extension_channel;
5208 				spectral->classifier_params.upper_chan_in_mhz =
5209 				    current_channel;
5210 			} else {
5211 				spectral->classifier_params.lower_chan_in_mhz =
5212 				    current_channel;
5213 				spectral->classifier_params.upper_chan_in_mhz =
5214 				    extension_channel;
5215 			}
5216 
5217 		} else if (is_ch_width_160_or_80p80(
5218 			   spectral->ch_width[smode])) {
5219 			/* Set the FFT Size */
5220 
5221 			/* The below applies to both 160 and 80+80 cases */
5222 
5223 			/* TODO : Remove this variable */
5224 			spectral->sc_spectral_20_40_mode = 0;
5225 			spectral->spectral_numbins =
5226 			    target_if_get_fft_bin_count(
5227 				spectral->params[smode].ss_fft_size);
5228 			spectral->spectral_fft_len =
5229 			    target_if_get_fft_bin_count(
5230 				spectral->params[smode].ss_fft_size);
5231 			spectral->spectral_data_len =
5232 			    target_if_get_fft_bin_count(
5233 				spectral->params[smode].ss_fft_size);
5234 
5235 			/*
5236 			 * Initialize classifier params to be sent to user
5237 			 * space classifier
5238 			 */
5239 			spectral->classifier_params.lower_chan_in_mhz =
5240 			    current_channel;
5241 			spectral->classifier_params.upper_chan_in_mhz = 0;
5242 
5243 			/*
5244 			 * Initialize classifier params to be sent to user
5245 			 * space classifier
5246 			 */
5247 			if (extension_channel < current_channel) {
5248 				spectral->classifier_params.lower_chan_in_mhz =
5249 				    extension_channel;
5250 				spectral->classifier_params.upper_chan_in_mhz =
5251 				    current_channel;
5252 			} else {
5253 				spectral->classifier_params.lower_chan_in_mhz =
5254 				    current_channel;
5255 				spectral->classifier_params.upper_chan_in_mhz =
5256 				    extension_channel;
5257 			}
5258 		}
5259 
5260 		if (spectral->spectral_numbins) {
5261 			spectral->spectral_numbins +=
5262 			    spectral->lb_edge_extrabins;
5263 			spectral->spectral_numbins +=
5264 			    spectral->rb_edge_extrabins;
5265 		}
5266 
5267 		if (spectral->spectral_fft_len) {
5268 			spectral->spectral_fft_len +=
5269 			    spectral->lb_edge_extrabins;
5270 			spectral->spectral_fft_len +=
5271 			    spectral->rb_edge_extrabins;
5272 		}
5273 
5274 		if (spectral->spectral_data_len) {
5275 			spectral->spectral_data_len +=
5276 			    spectral->lb_edge_extrabins;
5277 			spectral->spectral_data_len +=
5278 			    spectral->rb_edge_extrabins;
5279 		}
5280 	} else {
5281 		/*
5282 		 * The decision to find 20/40 mode is found based on the
5283 		 * presence of extension channel
5284 		 * instead of channel width, as the channel width can
5285 		 * dynamically change
5286 		 */
5287 
5288 		if (extension_channel == 0) {
5289 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
5290 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
5291 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
5292 			spectral->spectral_data_len =
5293 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
5294 			/* only valid in 20-40 mode */
5295 			spectral->spectral_lower_max_index_offset = -1;
5296 			/* only valid in 20-40 mode */
5297 			spectral->spectral_upper_max_index_offset = -1;
5298 			spectral->spectral_max_index_offset =
5299 			    spectral->spectral_fft_len + 2;
5300 			spectral->sc_spectral_20_40_mode = 0;
5301 
5302 			/*
5303 			 * Initialize classifier params to be sent to user
5304 			 * space classifier
5305 			 */
5306 			spectral->classifier_params.lower_chan_in_mhz =
5307 			    current_channel;
5308 			spectral->classifier_params.upper_chan_in_mhz = 0;
5309 
5310 		} else {
5311 			spectral->spectral_numbins =
5312 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
5313 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
5314 			spectral->spectral_data_len =
5315 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
5316 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
5317 			/* only valid in 20 mode */
5318 			spectral->spectral_max_index_offset = -1;
5319 			spectral->spectral_lower_max_index_offset =
5320 			    spectral->spectral_fft_len + 2;
5321 			spectral->spectral_upper_max_index_offset =
5322 			    spectral->spectral_fft_len + 5;
5323 			spectral->sc_spectral_20_40_mode = 1;
5324 
5325 			/*
5326 			 * Initialize classifier params to be sent to user
5327 			 * space classifier
5328 			 */
5329 			if (extension_channel < current_channel) {
5330 				spectral->classifier_params.lower_chan_in_mhz =
5331 				    extension_channel;
5332 				spectral->classifier_params.upper_chan_in_mhz =
5333 				    current_channel;
5334 			} else {
5335 				spectral->classifier_params.lower_chan_in_mhz =
5336 				    current_channel;
5337 				spectral->classifier_params.upper_chan_in_mhz =
5338 				    extension_channel;
5339 			}
5340 		}
5341 	}
5342 
5343 	spectral->send_single_packet = 0;
5344 	spectral->classifier_params.spectral_20_40_mode =
5345 	    spectral->sc_spectral_20_40_mode;
5346 	spectral->classifier_params.spectral_dc_index =
5347 	    spectral->spectral_dc_index;
5348 	spectral->spectral_sent_msg = 0;
5349 	spectral->classify_scan = 0;
5350 	spectral->num_spectral_data = 0;
5351 
5352 	if (!p_sops->is_spectral_active(spectral, smode)) {
5353 		p_sops->configure_spectral(spectral, spectral_params, smode);
5354 		spectral->rparams.marker[smode].is_valid = false;
5355 
5356 		if (spectral->params[smode].ss_count) {
5357 			status = target_if_spectral_finite_scan_init(spectral,
5358 								     smode);
5359 			if (QDF_IS_STATUS_ERROR(status)) {
5360 				spectral_err("Failed to init finite scan");
5361 				return 1;
5362 			}
5363 		}
5364 		p_sops->start_spectral_scan(spectral, smode, err);
5365 		spectral->timestamp_war.timestamp_war_offset[smode] = 0;
5366 		spectral->timestamp_war.last_fft_timestamp[smode] = 0;
5367 	}
5368 
5369 	/* get current spectral configuration */
5370 	p_sops->get_spectral_config(spectral, &spectral->params[smode], smode);
5371 
5372 	target_if_init_upper_lower_flags(spectral, smode);
5373 
5374 	return 0;
5375 }
5376 
5377 /**
5378  * target_if_is_aspectral_prohibited_by_adfs() - Is Agile Spectral prohibited by
5379  * Agile DFS
5380  * @psoc: Pointer to psoc
5381  * @object: Pointer to pdev
5382  * @arg: Pointer to flag which indicates whether Agile Spectral is prohibited
5383  *
5384  * This API checks whether Agile DFS is running on any of the pdevs. If so, it
5385  * indicates that Agile Spectral scan is prohibited by Agile DFS.
5386  *
5387  * Return: void
5388  */
5389 static void
5390 target_if_is_aspectral_prohibited_by_adfs(struct wlan_objmgr_psoc *psoc,
5391 					  void *object, void *arg)
5392 {
5393 	bool *is_aspectral_prohibited = arg;
5394 	struct wlan_objmgr_pdev *cur_pdev = object;
5395 	bool is_agile_precac_enabled_cur_pdev = false;
5396 	bool is_agile_rcac_enabled_cur_pdev = false;
5397 	QDF_STATUS status;
5398 
5399 	qdf_assert_always(is_aspectral_prohibited);
5400 	if (*is_aspectral_prohibited)
5401 		return;
5402 
5403 	qdf_assert_always(psoc);
5404 	qdf_assert_always(cur_pdev);
5405 
5406 	status = ucfg_dfs_get_agile_precac_enable
5407 				(cur_pdev,
5408 				 &is_agile_precac_enabled_cur_pdev);
5409 	if (QDF_IS_STATUS_ERROR(status)) {
5410 		spectral_err("Get agile precac failed, prohibiting aSpectral");
5411 		*is_aspectral_prohibited = true;
5412 		return;
5413 	}
5414 
5415 	status = ucfg_dfs_get_rcac_enable(cur_pdev,
5416 					  &is_agile_rcac_enabled_cur_pdev);
5417 
5418 	if (QDF_IS_STATUS_ERROR(status)) {
5419 		spectral_err("Get agile RCAC failed, prohibiting aSpectral");
5420 		*is_aspectral_prohibited = true;
5421 		return;
5422 	}
5423 
5424 	if (is_agile_precac_enabled_cur_pdev) {
5425 		spectral_err("aDFS preCAC is in progress on one of the pdevs");
5426 		*is_aspectral_prohibited = true;
5427 	} else if (is_agile_rcac_enabled_cur_pdev) {
5428 		spectral_err("aDFS RCAC is in progress on one of the pdevs");
5429 		*is_aspectral_prohibited = true;
5430 	}
5431 }
5432 
5433 /**
5434  * target_if_get_curr_band() - Get current operating band of pdev
5435  *
5436  * @pdev: pointer to pdev object
5437  *
5438  * API to get current operating band of a given pdev.
5439  *
5440  * Return: if success enum reg_wifi_band, REG_BAND_UNKNOWN in case of failure
5441  */
5442 static enum reg_wifi_band
5443 target_if_get_curr_band(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id)
5444 {
5445 	struct wlan_objmgr_vdev *vdev;
5446 	int16_t chan_freq;
5447 	enum reg_wifi_band cur_band;
5448 
5449 	if (!pdev) {
5450 		spectral_err("pdev is NULL");
5451 		return REG_BAND_UNKNOWN;
5452 	}
5453 
5454 	if (vdev_id == WLAN_INVALID_VDEV_ID)
5455 		vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID);
5456 	else
5457 		vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
5458 							    WLAN_SPECTRAL_ID);
5459 	if (!vdev) {
5460 		spectral_debug("vdev is NULL");
5461 		return REG_BAND_UNKNOWN;
5462 	}
5463 	chan_freq = target_if_vdev_get_chan_freq(vdev);
5464 	cur_band = wlan_reg_freq_to_band(chan_freq);
5465 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5466 
5467 	return cur_band;
5468 }
5469 
5470 /**
5471  * target_if_is_agile_scan_active_in_5g() - Is Agile Spectral scan active on
5472  * any of the 5G pdevs
5473  * @psoc: Pointer to psoc
5474  * @object: Pointer to pdev
5475  * @arg: Pointer to flag which indicates whether Agile Spectral scan is in
5476  *       progress in any 5G pdevs
5477  *
5478  * Return: void
5479  */
5480 static void
5481 target_if_is_agile_scan_active_in_5g(struct wlan_objmgr_psoc *psoc,
5482 				     void *object, void *arg)
5483 {
5484 	enum reg_wifi_band band;
5485 	bool *is_agile_scan_inprog_5g_pdev = arg;
5486 	struct target_if_spectral *spectral;
5487 	struct wlan_objmgr_pdev *cur_pdev = object;
5488 	struct target_if_spectral_ops *p_sops;
5489 
5490 	if (*is_agile_scan_inprog_5g_pdev)
5491 		return;
5492 
5493 	spectral = get_target_if_spectral_handle_from_pdev(cur_pdev);
5494 	if (!spectral) {
5495 		spectral_err("target if spectral handle is NULL");
5496 		return;
5497 	}
5498 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5499 
5500 	band = target_if_get_curr_band(
5501 			cur_pdev, spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE]);
5502 	if (band == REG_BAND_UNKNOWN) {
5503 		spectral_debug("Failed to get current band");
5504 		return;
5505 	}
5506 
5507 	if (band == REG_BAND_5G &&
5508 	    p_sops->is_spectral_active(spectral, SPECTRAL_SCAN_MODE_AGILE))
5509 		*is_agile_scan_inprog_5g_pdev = true;
5510 }
5511 
5512 /**
5513  * target_if_is_agile_supported_cur_chmask() - Is Agile Spectral scan supported
5514  * for current vdev rx chainmask.
5515  *
5516  * @spectral: Pointer to Spectral object
5517  * @is_supported: Pointer to is_supported
5518  *
5519  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
5520  */
5521 static QDF_STATUS
5522 target_if_is_agile_supported_cur_chmask(struct target_if_spectral *spectral,
5523 					bool *is_supported)
5524 {
5525 	struct wlan_objmgr_vdev *vdev;
5526 	uint8_t vdev_rxchainmask;
5527 	struct wlan_objmgr_psoc *psoc;
5528 	struct wlan_objmgr_pdev *pdev;
5529 	struct target_psoc_info *tgt_psoc_info;
5530 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
5531 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr = NULL;
5532 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = NULL;
5533 	struct wlan_psoc_host_chainmask_table *table;
5534 	int j;
5535 	uint32_t table_id;
5536 	enum phy_ch_width ch_width;
5537 	uint8_t pdev_id;
5538 
5539 	if (!spectral) {
5540 		spectral_err("spectral target if object is null");
5541 		return QDF_STATUS_E_FAILURE;
5542 	}
5543 
5544 	if (!is_supported) {
5545 		spectral_err("is supported argument is null");
5546 		return QDF_STATUS_E_FAILURE;
5547 	}
5548 
5549 	if (spectral->spectral_gen <= SPECTRAL_GEN2) {
5550 		spectral_err("HW Agile mode is not supported up to gen 2");
5551 		return QDF_STATUS_E_FAILURE;
5552 	}
5553 
5554 	pdev = spectral->pdev_obj;
5555 	if (!pdev) {
5556 		spectral_err("pdev is null");
5557 		return QDF_STATUS_E_FAILURE;
5558 	}
5559 
5560 	psoc = wlan_pdev_get_psoc(pdev);
5561 	if (!psoc) {
5562 		spectral_err("psoc is null");
5563 		return QDF_STATUS_E_FAILURE;
5564 	}
5565 
5566 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
5567 	if (!vdev) {
5568 		spectral_err("First vdev is NULL");
5569 		return QDF_STATUS_E_FAILURE;
5570 	}
5571 
5572 	vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
5573 	if (!vdev_rxchainmask) {
5574 		spectral_err("vdev rx chainmask is zero");
5575 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5576 		return QDF_STATUS_E_FAILURE;
5577 	}
5578 
5579 	ch_width = target_if_vdev_get_ch_width(vdev);
5580 	if (ch_width == CH_WIDTH_INVALID) {
5581 		spectral_err("Invalid channel width");
5582 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5583 		return QDF_STATUS_E_FAILURE;
5584 	}
5585 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5586 
5587 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
5588 	if (!tgt_psoc_info) {
5589 		spectral_err("target_psoc_info is null");
5590 		return QDF_STATUS_E_FAILURE;
5591 	}
5592 
5593 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
5594 	if (!ext_svc_param) {
5595 		spectral_err("Extended service ready param null");
5596 		return QDF_STATUS_E_FAILURE;
5597 	}
5598 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
5599 
5600 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
5601 	if (!mac_phy_cap_arr) {
5602 		spectral_err("mac phy cap array is null");
5603 		return QDF_STATUS_E_FAILURE;
5604 	}
5605 
5606 	mac_phy_cap = &mac_phy_cap_arr[pdev_id];
5607 	if (!mac_phy_cap) {
5608 		spectral_err("mac phy cap is null");
5609 		return QDF_STATUS_E_FAILURE;
5610 	}
5611 
5612 	table_id = mac_phy_cap->chainmask_table_id;
5613 	table =  &ext_svc_param->chainmask_table[table_id];
5614 	if (!table) {
5615 		spectral_err("chainmask table not found");
5616 		return QDF_STATUS_E_FAILURE;
5617 	}
5618 
5619 	for (j = 0; j < table->num_valid_chainmasks; j++) {
5620 		if (table->cap_list[j].chainmask == vdev_rxchainmask) {
5621 			if (ch_width <= CH_WIDTH_80MHZ)
5622 				*is_supported =
5623 					table->cap_list[j].supports_aSpectral;
5624 			else
5625 				*is_supported =
5626 				      table->cap_list[j].supports_aSpectral_160;
5627 			break;
5628 		}
5629 	}
5630 
5631 	if (j == table->num_valid_chainmasks) {
5632 		spectral_err("vdev rx chainmask %u not found in table id = %u",
5633 			     vdev_rxchainmask, table_id);
5634 		return QDF_STATUS_E_FAILURE;
5635 	}
5636 
5637 	return QDF_STATUS_SUCCESS;
5638 }
5639 
5640 #define INVALID_SPAN_NUM (-1)
5641 /**
5642  * target_if_spectral_get_num_spans() - Get number of spans for a given sscan_bw
5643  * @pdev: Pointer to pdev object
5644  * @sscan_bw: Spectral scan bandwidth
5645  *
5646  * Return: Number of spans on success, INVALID_SPAN_NUM on failure
5647  */
5648 static int
5649 target_if_spectral_get_num_spans(
5650 		struct wlan_objmgr_pdev *pdev,
5651 		enum phy_ch_width sscan_bw)
5652 {
5653 	struct wlan_objmgr_psoc *psoc;
5654 	int num_spans;
5655 
5656 	if (!pdev) {
5657 		spectral_err_rl("pdev is null");
5658 		return INVALID_SPAN_NUM;
5659 	}
5660 
5661 	psoc = wlan_pdev_get_psoc(pdev);
5662 	if (!psoc) {
5663 		spectral_err_rl("psoc is null");
5664 		return INVALID_SPAN_NUM;
5665 	}
5666 
5667 	if (sscan_bw == CH_WIDTH_80P80MHZ) {
5668 		num_spans = 2;
5669 		if (wlan_psoc_nif_fw_ext_cap_get(
5670 		    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT))
5671 			/* 5 MHz frequency span in restricted 80p80 case */
5672 			num_spans += 1;
5673 	} else {
5674 		num_spans = 1;
5675 	}
5676 
5677 	return num_spans;
5678 }
5679 
5680 #ifdef OPTIMIZED_SAMP_MESSAGE
5681 /**
5682  * target_if_spectral_populate_session_report_info() - Populate per-session
5683  * report level information.
5684  *
5685  * @spectral: Pointer to Spectral object
5686  * @smode: Spectral scan mode
5687  *
5688  * Return: Success/Failure
5689  */
5690 static QDF_STATUS
5691 target_if_spectral_populate_session_report_info(
5692 				struct target_if_spectral *spectral,
5693 				enum spectral_scan_mode smode)
5694 {
5695 	struct per_session_report_info *rpt_info;
5696 
5697 	if (!spectral) {
5698 		spectral_err_rl("Spectral LMAC object is null");
5699 		return QDF_STATUS_E_NULL_VALUE;
5700 	}
5701 	if (smode > SPECTRAL_SCAN_MODE_MAX) {
5702 		spectral_err_rl("Invalid Spectral scan mode");
5703 		return QDF_STATUS_E_FAILURE;
5704 	}
5705 
5706 
5707 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
5708 	/* Fill per-session report information, based on the spectral mode */
5709 	rpt_info = &spectral->report_info[smode];
5710 
5711 	rpt_info->operating_bw = spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL];
5712 	rpt_info->sscan_bw = spectral->ch_width[smode];
5713 	rpt_info->sscan_cfreq1 = spectral->params[smode].ss_frequency.cfreq1;
5714 	rpt_info->sscan_cfreq2 = spectral->params[smode].ss_frequency.cfreq2;
5715 	rpt_info->num_spans = target_if_spectral_get_num_spans(
5716 						spectral->pdev_obj,
5717 						rpt_info->sscan_bw);
5718 
5719 	qdf_assert_always(rpt_info->num_spans != INVALID_SPAN_NUM);
5720 	rpt_info->valid = true;
5721 
5722 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
5723 
5724 	return QDF_STATUS_SUCCESS;
5725 }
5726 
5727 /**
5728  * target_if_spectral_populate_session_det_host_info() - Populate per-session
5729  * detector level information that is known to the Host
5730  *
5731  * @spectral: Pointer to Spectral object
5732  * @smode: Spectral scan mode
5733  *
5734  * Return: Success/Failure
5735  */
5736 static QDF_STATUS
5737 target_if_spectral_populate_session_det_host_info(
5738 				struct target_if_spectral *spectral,
5739 				enum spectral_scan_mode smode)
5740 {
5741 	struct per_session_report_info *rpt_info;
5742 	struct sscan_detector_list *detector_list;
5743 	struct wlan_objmgr_psoc *psoc;
5744 	uint16_t dest_det_idx = 0;
5745 	uint16_t dest_span_idx = 0;
5746 	bool is_sec80 = false;
5747 	uint8_t det, dest_det;
5748 
5749 	if (!spectral) {
5750 		spectral_err_rl("Spectral LMAC object is null");
5751 		return QDF_STATUS_E_NULL_VALUE;
5752 	}
5753 	if (smode > SPECTRAL_SCAN_MODE_MAX) {
5754 		spectral_err_rl("Invalid Spectral scan mode");
5755 		return QDF_STATUS_E_FAILURE;
5756 	}
5757 
5758 	if (!spectral->pdev_obj) {
5759 		spectral_err_rl("Spectral PDEV is null");
5760 		return QDF_STATUS_E_NULL_VALUE;
5761 	}
5762 
5763 	psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
5764 	if (!psoc) {
5765 		spectral_err_rl("psoc is null");
5766 		return QDF_STATUS_E_NULL_VALUE;
5767 	}
5768 
5769 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
5770 	rpt_info = &spectral->report_info[smode];
5771 
5772 	qdf_spin_lock_bh(&spectral->detector_list_lock);
5773 	/* Fill per-sesion detector-level information */
5774 	detector_list = &spectral->detector_list[smode][rpt_info->sscan_bw];
5775 
5776 	for (det = 0; det < detector_list->num_detectors; det++) {
5777 		struct per_session_det_map *det_map;
5778 
5779 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
5780 		det_map = &spectral->det_map[detector_list->detectors[det]];
5781 		if (detector_list->num_detectors > 1) {
5782 			if (det == 0) {
5783 				det_map->buf_type = SPECTRAL_MSG_BUF_NEW;
5784 				det_map->send_to_upper_layers = false;
5785 			} else if (det == detector_list->num_detectors - 1) {
5786 				det_map->buf_type = SPECTRAL_MSG_BUF_SAVED;
5787 				det_map->send_to_upper_layers = true;
5788 			} else {
5789 				/* middle fragments */
5790 				det_map->buf_type = SPECTRAL_MSG_BUF_SAVED;
5791 				det_map->send_to_upper_layers = false;
5792 			}
5793 		} else {
5794 			det_map->buf_type = SPECTRAL_MSG_BUF_NEW;
5795 			det_map->send_to_upper_layers = true;
5796 		}
5797 
5798 		det_map->num_dest_det_info = 1;
5799 		if (rpt_info->sscan_bw == CH_WIDTH_80P80MHZ &&
5800 		    wlan_psoc_nif_fw_ext_cap_get(
5801 		    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
5802 			/**
5803 			 * In 165MHz case, 1 Spectral HW detector maps to 3
5804 			 * detectors in SAMP msg.
5805 			 */
5806 			det_map->num_dest_det_info += 2;
5807 		}
5808 
5809 		for (dest_det = 0; dest_det < det_map->num_dest_det_info;
5810 		     dest_det++) {
5811 			struct per_session_dest_det_info *map_det_info;
5812 
5813 			map_det_info = &det_map->dest_det_info[dest_det];
5814 			map_det_info->freq_span_id = dest_span_idx;
5815 			map_det_info->det_id = dest_det_idx;
5816 			map_det_info->is_sec80 = is_sec80;
5817 			if (rpt_info->sscan_bw == CH_WIDTH_80P80MHZ) {
5818 			/* Increment span ID for non-contiguous modes */
5819 				dest_det_idx = 0;
5820 				dest_span_idx++;
5821 			} else {
5822 			/* Increment detector ID for contiguous modes */
5823 				dest_det_idx++;
5824 			}
5825 			is_sec80 = !is_sec80;
5826 		}
5827 		det_map->det_map_valid[smode] = true;
5828 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
5829 	}
5830 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
5831 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
5832 
5833 	return QDF_STATUS_SUCCESS;
5834 }
5835 
5836 #else
5837 static QDF_STATUS
5838 target_if_spectral_populate_session_report_info(
5839 				struct target_if_spectral *spectral,
5840 				enum spectral_scan_mode smode)
5841 {
5842 	return QDF_STATUS_SUCCESS;
5843 }
5844 
5845 static QDF_STATUS
5846 target_if_spectral_populate_session_det_host_info(
5847 				struct target_if_spectral *spectral,
5848 				enum spectral_scan_mode smode)
5849 {
5850 	return QDF_STATUS_SUCCESS;
5851 }
5852 #endif /* OPTIMIZED_SAMP_MESSAGE */
5853 
5854 QDF_STATUS
5855 spectral_is_session_info_expected_from_target(struct wlan_objmgr_pdev *pdev,
5856 					      bool *is_session_info_expected)
5857 {
5858 	struct wlan_objmgr_psoc *psoc;
5859 	struct wmi_unified *wmi_handle;
5860 
5861 	if (!pdev) {
5862 		spectral_err("pdev is null");
5863 		return QDF_STATUS_E_NULL_VALUE;
5864 	}
5865 
5866 	psoc = wlan_pdev_get_psoc(pdev);
5867 	if (!psoc) {
5868 		spectral_err("psoc is null");
5869 		return QDF_STATUS_E_NULL_VALUE;
5870 	}
5871 
5872 	wmi_handle =  get_wmi_unified_hdl_from_psoc(psoc);
5873 	if (!wmi_handle) {
5874 		spectral_err("wmi handle is null");
5875 		return QDF_STATUS_E_NULL_VALUE;
5876 	}
5877 
5878 	*is_session_info_expected = target_if_spectral_wmi_service_enabled(
5879 				psoc, wmi_handle,
5880 				wmi_service_spectral_session_info_support);
5881 
5882 	return QDF_STATUS_SUCCESS;
5883 }
5884 
5885 QDF_STATUS
5886 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev,
5887 			      uint8_t vdev_id,
5888 			      const enum spectral_scan_mode smode,
5889 			      enum spectral_cp_error_code *err)
5890 {
5891 	struct target_if_spectral_ops *p_sops;
5892 	struct target_if_spectral *spectral;
5893 	struct wlan_objmgr_psoc *psoc;
5894 	enum reg_wifi_band band;
5895 	QDF_STATUS ret;
5896 	bool is_session_info_expected;
5897 
5898 	if (!err) {
5899 		spectral_err("Error code argument is null");
5900 		QDF_ASSERT(0);
5901 		return QDF_STATUS_E_FAILURE;
5902 	}
5903 	*err = SPECTRAL_SCAN_ERR_INVALID;
5904 
5905 	if (!pdev) {
5906 		spectral_err("pdev object is NUll");
5907 		return QDF_STATUS_E_FAILURE;
5908 	}
5909 
5910 	psoc = wlan_pdev_get_psoc(pdev);
5911 	if (!psoc) {
5912 		spectral_err("psoc is null");
5913 		return QDF_STATUS_E_FAILURE;
5914 	}
5915 
5916 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5917 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5918 		spectral_err("Invalid Spectral mode %u", smode);
5919 		return QDF_STATUS_E_FAILURE;
5920 	}
5921 
5922 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5923 	if (!spectral) {
5924 		spectral_err("Spectral LMAC object is NUll");
5925 		return QDF_STATUS_E_FAILURE;
5926 	}
5927 
5928 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5929 	if (!p_sops) {
5930 		spectral_err("p_sops is null");
5931 		return QDF_STATUS_E_FAILURE;
5932 	}
5933 
5934 	if (p_sops->is_spectral_active(spectral, smode)) {
5935 		spectral_err("spectral in progress in current pdev, mode %d",
5936 			     smode);
5937 		return QDF_STATUS_E_FAILURE;
5938 	}
5939 	spectral->vdev_id[smode] = vdev_id;
5940 
5941 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
5942 		QDF_STATUS status;
5943 		bool is_supported = false;
5944 
5945 		status = target_if_is_agile_supported_cur_chmask(spectral,
5946 								 &is_supported);
5947 		if (QDF_IS_STATUS_ERROR(status)) {
5948 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5949 			return QDF_STATUS_E_FAILURE;
5950 		}
5951 
5952 		if (!is_supported) {
5953 			spectral_err("aSpectral unsupported for cur chainmask");
5954 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5955 			return QDF_STATUS_E_FAILURE;
5956 		}
5957 	}
5958 
5959 	band = target_if_get_curr_band(spectral->pdev_obj, vdev_id);
5960 	if (band == REG_BAND_UNKNOWN) {
5961 		spectral_err("Failed to get current band");
5962 		return QDF_STATUS_E_FAILURE;
5963 	}
5964 	if ((band == REG_BAND_5G) && (smode == SPECTRAL_SCAN_MODE_AGILE)) {
5965 		struct target_psoc_info *tgt_hdl;
5966 		enum wmi_host_hw_mode_config_type mode;
5967 		bool is_agile_scan_inprog_5g_pdev;
5968 
5969 		tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
5970 		if (!tgt_hdl) {
5971 			target_if_err("target_psoc_info is null");
5972 			return QDF_STATUS_E_FAILURE;
5973 		}
5974 
5975 		mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
5976 		switch (mode) {
5977 		case WMI_HOST_HW_MODE_SBS_PASSIVE:
5978 		case WMI_HOST_HW_MODE_SBS:
5979 		case WMI_HOST_HW_MODE_DBS_SBS:
5980 		case WMI_HOST_HW_MODE_DBS_OR_SBS:
5981 			is_agile_scan_inprog_5g_pdev = false;
5982 			wlan_objmgr_iterate_obj_list
5983 				(psoc, WLAN_PDEV_OP,
5984 				 target_if_is_agile_scan_active_in_5g,
5985 				 &is_agile_scan_inprog_5g_pdev, 0,
5986 				 WLAN_SPECTRAL_ID);
5987 			break;
5988 		default:
5989 			is_agile_scan_inprog_5g_pdev = false;
5990 			break;
5991 		}
5992 
5993 		if (is_agile_scan_inprog_5g_pdev) {
5994 			spectral_err("Agile Scan in progress in one of the SBS 5G pdev");
5995 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5996 			return QDF_STATUS_E_FAILURE;
5997 		}
5998 	}
5999 
6000 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
6001 		bool is_aspectral_prohibited = false;
6002 		QDF_STATUS status;
6003 
6004 		status = wlan_objmgr_iterate_obj_list
6005 				(psoc, WLAN_PDEV_OP,
6006 				 target_if_is_aspectral_prohibited_by_adfs,
6007 				 &is_aspectral_prohibited, 0,
6008 				 WLAN_SPECTRAL_ID);
6009 		if (QDF_IS_STATUS_ERROR(status)) {
6010 			spectral_err("Failed to iterate over pdevs");
6011 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6012 			return QDF_STATUS_E_FAILURE;
6013 		}
6014 
6015 		if (is_aspectral_prohibited) {
6016 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6017 			return QDF_STATUS_E_FAILURE;
6018 		}
6019 	}
6020 
6021 	if (!spectral->params_valid[smode]) {
6022 		target_if_spectral_info_read(spectral,
6023 					     smode,
6024 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
6025 					     &spectral->params[smode],
6026 					     sizeof(spectral->params[smode]));
6027 		spectral->params_valid[smode] = true;
6028 	}
6029 
6030 	qdf_spin_lock_bh(&spectral->spectral_lock);
6031 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
6032 		QDF_STATUS status;
6033 		bool is_overlapping;
6034 		enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
6035 		enum spectral_scan_mode m;
6036 		enum phy_ch_width agile_ch_width;
6037 
6038 		m = SPECTRAL_SCAN_MODE_NORMAL;
6039 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
6040 			ch_width[m] = CH_WIDTH_INVALID;
6041 		status = target_if_spectral_populate_chwidth
6042 			(spectral, ch_width, spectral->params
6043 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
6044 		if (QDF_IS_STATUS_ERROR(status)) {
6045 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6046 			spectral_err("Failed to populate channel width");
6047 			return QDF_STATUS_E_FAILURE;
6048 		}
6049 		agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
6050 
6051 		if (!spectral->params[smode].ss_frequency.cfreq1) {
6052 			*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
6053 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6054 			spectral_err("Agile Spectral cfreq1 is 0");
6055 			return QDF_STATUS_E_FAILURE;
6056 		} else if (agile_ch_width == CH_WIDTH_80P80MHZ &&
6057 			   !spectral->params[smode].ss_frequency.cfreq2) {
6058 			*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
6059 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6060 			spectral_err("Agile Spectral cfreq2 is 0");
6061 			return QDF_STATUS_E_FAILURE;
6062 		}
6063 
6064 		status = target_if_is_agile_span_overlap_with_operating_span
6065 				(spectral, ch_width,
6066 				 &spectral->params[smode].ss_frequency,
6067 				 &is_overlapping);
6068 		if (QDF_IS_STATUS_ERROR(status)) {
6069 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6070 			return QDF_STATUS_E_FAILURE;
6071 		}
6072 
6073 		if (is_overlapping) {
6074 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
6075 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6076 			return QDF_STATUS_E_FAILURE;
6077 		}
6078 	}
6079 
6080 	/* Populate detectot list first */
6081 	ret = target_if_spectral_detector_list_init(spectral);
6082 	if (QDF_IS_STATUS_ERROR(ret)) {
6083 		qdf_spin_unlock_bh(&spectral->spectral_lock);
6084 		spectral_err("Failed to initialize detector list");
6085 		return ret;
6086 	}
6087 
6088 	ret = target_if_spectral_populate_chwidth(
6089 			spectral, spectral->ch_width,
6090 			spectral->params[SPECTRAL_SCAN_MODE_AGILE].
6091 			ss_frequency.cfreq2 > 0);
6092 	if (QDF_IS_STATUS_ERROR(ret)) {
6093 		qdf_spin_unlock_bh(&spectral->spectral_lock);
6094 		spectral_err("Failed to get channel widths");
6095 		return ret;
6096 	}
6097 
6098 	ret = spectral_is_session_info_expected_from_target(
6099 				spectral->pdev_obj,
6100 				&is_session_info_expected);
6101 	if (QDF_IS_STATUS_ERROR(ret)) {
6102 		qdf_spin_unlock_bh(&spectral->spectral_lock);
6103 		spectral_err("Failed to check if session info is expected");
6104 		return ret;
6105 	}
6106 
6107 	/* If FW doesn't send session info, populate it */
6108 	if (!is_session_info_expected) {
6109 		ret = target_if_spectral_populate_session_report_info(spectral,
6110 								      smode);
6111 		if (QDF_IS_STATUS_ERROR(ret)) {
6112 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6113 			spectral_err("Failed to populate per-session report info");
6114 			return QDF_STATUS_E_FAILURE;
6115 		}
6116 
6117 		ret = target_if_spectral_populate_session_det_host_info(
6118 					spectral, smode);
6119 		if (QDF_IS_STATUS_ERROR(ret)) {
6120 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6121 			spectral_err("Failed to populate per-session detector info");
6122 			return QDF_STATUS_E_FAILURE;
6123 		}
6124 	}
6125 
6126 	target_if_spectral_scan_enable_params(spectral,
6127 					      &spectral->params[smode], smode,
6128 					      err);
6129 
6130 	spectral->sscan_width_configured[smode] = false;
6131 	qdf_spin_unlock_bh(&spectral->spectral_lock);
6132 
6133 	return QDF_STATUS_SUCCESS;
6134 }
6135 
6136 QDF_STATUS
6137 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev,
6138 			     const enum spectral_scan_mode smode,
6139 			     enum spectral_cp_error_code *err)
6140 {
6141 	struct target_if_spectral_ops *p_sops;
6142 	struct target_if_spectral *spectral;
6143 	uint8_t det;
6144 
6145 	if (!pdev) {
6146 		spectral_err("pdev object is NULL");
6147 		return QDF_STATUS_E_INVAL;
6148 	}
6149 
6150 	if (target_if_spectral_is_feature_disabled_pdev(pdev)) {
6151 		spectral_info("Spectral feature is disabled");
6152 		return QDF_STATUS_COMP_DISABLED;
6153 	}
6154 
6155 	if (!err) {
6156 		spectral_err("Error code argument is null");
6157 		QDF_ASSERT(0);
6158 		return QDF_STATUS_E_FAILURE;
6159 	}
6160 	*err = SPECTRAL_SCAN_ERR_INVALID;
6161 
6162 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
6163 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6164 		spectral_err("Invalid Spectral mode %u", smode);
6165 		return QDF_STATUS_E_FAILURE;
6166 	}
6167 
6168 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6169 	if (!spectral) {
6170 		spectral_err("Spectral LMAC object is NUll ");
6171 		return QDF_STATUS_E_FAILURE;
6172 	}
6173 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6174 
6175 	qdf_spin_lock_bh(&spectral->spectral_lock);
6176 	p_sops->stop_spectral_scan(spectral, smode);
6177 	if (spectral->classify_scan) {
6178 		/* TODO : Check if this logic is necessary */
6179 		spectral->detects_control_channel = 0;
6180 		spectral->detects_extension_channel = 0;
6181 		spectral->detects_above_dc = 0;
6182 		spectral->detects_below_dc = 0;
6183 		spectral->classify_scan = 0;
6184 	}
6185 
6186 	spectral->send_single_packet = 0;
6187 	spectral->sc_spectral_scan = 0;
6188 
6189 	qdf_spin_lock_bh(&spectral->session_det_map_lock);
6190 	for (det = 0; det < MAX_DETECTORS_PER_PDEV; det++)
6191 		spectral->det_map[det].det_map_valid[smode] = false;
6192 
6193 	qdf_spin_unlock_bh(&spectral->session_det_map_lock);
6194 
6195 	/* Mark report info as invalid */
6196 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
6197 	spectral->report_info[smode].valid = false;
6198 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
6199 
6200 	qdf_spin_unlock_bh(&spectral->spectral_lock);
6201 
6202 	return QDF_STATUS_SUCCESS;
6203 }
6204 
6205 /**
6206  * target_if_is_spectral_active() - Get whether Spectral is active
6207  * @pdev: Pointer to pdev object
6208  * @smode: Spectral scan mode
6209  *
6210  * API to get whether Spectral is active
6211  *
6212  * Return: True if Spectral is active, false if Spectral is not active
6213  */
6214 bool
6215 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev,
6216 			     const enum spectral_scan_mode smode)
6217 {
6218 	struct target_if_spectral *spectral = NULL;
6219 	struct target_if_spectral_ops *p_sops = NULL;
6220 
6221 	if (!pdev) {
6222 		spectral_err("pdev is null");
6223 		return false;
6224 	}
6225 
6226 	if (target_if_spectral_is_feature_disabled_pdev(pdev)) {
6227 		spectral_info("Spectral feature is disabled");
6228 		return false;
6229 	}
6230 
6231 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6232 
6233 	if (!spectral) {
6234 		spectral_err("SPECTRAL : Module doesn't exist");
6235 		return false;
6236 	}
6237 
6238 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6239 
6240 	if (!p_sops) {
6241 		spectral_err("p_sops is null");
6242 		return false;
6243 	}
6244 
6245 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
6246 		spectral_err("Invalid Spectral mode %u", smode);
6247 		return false;
6248 	}
6249 
6250 	return p_sops->is_spectral_active(spectral, smode);
6251 }
6252 
6253 /**
6254  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
6255  * @pdev: Pointer to pdev object
6256  * @smode: Spectral scan mode
6257  *
6258  * API to get whether Spectral is enabled
6259  *
6260  * Return: True if Spectral is enabled, false if Spectral is not enabled
6261  */
6262 bool
6263 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev,
6264 			      enum spectral_scan_mode smode)
6265 {
6266 	struct target_if_spectral *spectral = NULL;
6267 	struct target_if_spectral_ops *p_sops = NULL;
6268 
6269 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6270 
6271 	if (!spectral) {
6272 		spectral_err("SPECTRAL : Module doesn't exist");
6273 		return false;
6274 	}
6275 
6276 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6277 
6278 	if (!p_sops) {
6279 		spectral_err("p_sops is null");
6280 		return false;
6281 	}
6282 
6283 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
6284 		spectral_err("Invalid Spectral mode %u", smode);
6285 		return false;
6286 	}
6287 
6288 	return p_sops->is_spectral_enabled(spectral, smode);
6289 }
6290 
6291 #ifdef DIRECT_BUF_RX_DEBUG
6292 /**
6293  * target_if_spectral_do_dbr_ring_debug() - Start/Stop Spectral DMA ring debug
6294  * @pdev: Pointer to pdev object
6295  * @enable: Enable/Disable Spectral DMA ring debug
6296  *
6297  * Start/stop Spectral DMA ring debug based on @enable.
6298  * Also save the state for future use.
6299  *
6300  * Return: QDF_STATUS of operation
6301  */
6302 static QDF_STATUS
6303 target_if_spectral_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev, bool enable)
6304 {
6305 	struct target_if_spectral *spectral;
6306 	struct wlan_lmac_if_tx_ops *tx_ops;
6307 	struct wlan_objmgr_psoc *psoc;
6308 
6309 	if (!pdev)
6310 		return QDF_STATUS_E_FAILURE;
6311 
6312 	psoc = wlan_pdev_get_psoc(pdev);
6313 	if (!psoc) {
6314 		spectral_err("psoc is null");
6315 		return QDF_STATUS_E_INVAL;
6316 	}
6317 
6318 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
6319 	if (!tx_ops) {
6320 		spectral_err("tx_ops is NULL");
6321 		return QDF_STATUS_E_INVAL;
6322 	}
6323 
6324 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6325 	if (!spectral) {
6326 		spectral_err("Spectal LMAC object is NULL");
6327 		return QDF_STATUS_E_INVAL;
6328 	}
6329 
6330 	/* Save the state */
6331 	spectral->dbr_ring_debug = enable;
6332 
6333 	if (enable)
6334 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_ring_debug(
6335 				pdev, 0, SPECTRAL_DBR_RING_DEBUG_SIZE);
6336 	else
6337 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_ring_debug(
6338 				pdev, 0);
6339 
6340 	return QDF_STATUS_SUCCESS;
6341 }
6342 
6343 /**
6344  * target_if_spectral_do_dbr_buff_debug() - Start/Stop Spectral DMA buffer debug
6345  * @pdev: Pointer to pdev object
6346  * @enable: Enable/Disable Spectral DMA buffer debug
6347  *
6348  * Start/stop Spectral DMA buffer debug based on @enable.
6349  * Also save the state for future use.
6350  *
6351  * Return: QDF_STATUS of operation
6352  */
6353 static QDF_STATUS
6354 target_if_spectral_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev, bool enable)
6355 {
6356 	struct target_if_spectral *spectral;
6357 	struct wlan_lmac_if_tx_ops *tx_ops;
6358 	struct wlan_objmgr_psoc *psoc;
6359 
6360 	if (!pdev)
6361 		return QDF_STATUS_E_FAILURE;
6362 
6363 	psoc = wlan_pdev_get_psoc(pdev);
6364 	if (!psoc) {
6365 		spectral_err("psoc is null");
6366 		return QDF_STATUS_E_INVAL;
6367 	}
6368 
6369 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
6370 	if (!tx_ops) {
6371 		spectral_err("tx_ops is NULL");
6372 		return QDF_STATUS_E_INVAL;
6373 	}
6374 
6375 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6376 	if (!spectral) {
6377 		spectral_err("Spectal LMAC object is NULL");
6378 		return QDF_STATUS_E_INVAL;
6379 	}
6380 
6381 	/* Save the state */
6382 	spectral->dbr_buff_debug = enable;
6383 
6384 	if (enable)
6385 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_buffer_poisoning(
6386 				pdev, 0, MEM_POISON_SIGNATURE);
6387 	else
6388 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_buffer_poisoning(
6389 				pdev, 0);
6390 }
6391 
6392 /**
6393  * target_if_spectral_check_and_do_dbr_buff_debug() - Start/Stop Spectral buffer
6394  * debug based on the previous state
6395  * @pdev: Pointer to pdev object
6396  *
6397  * Return: QDF_STATUS of operation
6398  */
6399 static QDF_STATUS
6400 target_if_spectral_check_and_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev)
6401 {
6402 	struct target_if_spectral *spectral;
6403 
6404 	if (!pdev) {
6405 		spectral_err("pdev is NULL!");
6406 		return QDF_STATUS_E_FAILURE;
6407 	}
6408 
6409 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6410 	if (!spectral) {
6411 		spectral_err("Spectal LMAC object is NULL");
6412 		return QDF_STATUS_E_INVAL;
6413 	}
6414 
6415 	if (spectral->dbr_buff_debug)
6416 		return target_if_spectral_do_dbr_buff_debug(pdev, true);
6417 	else
6418 		return target_if_spectral_do_dbr_buff_debug(pdev, false);
6419 }
6420 
6421 /**
6422  * target_if_spectral_check_and_do_dbr_ring_debug() - Start/Stop Spectral ring
6423  * debug based on the previous state
6424  * @pdev: Pointer to pdev object
6425  *
6426  * Return: QDF_STATUS of operation
6427  */
6428 static QDF_STATUS
6429 target_if_spectral_check_and_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev)
6430 {
6431 	struct target_if_spectral *spectral;
6432 
6433 	if (!pdev) {
6434 		spectral_err("pdev is NULL!");
6435 		return QDF_STATUS_E_FAILURE;
6436 	}
6437 
6438 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6439 	if (!spectral) {
6440 		spectral_err("Spectal LMAC object is NULL");
6441 		return QDF_STATUS_E_INVAL;
6442 	}
6443 
6444 	if (spectral->dbr_ring_debug)
6445 		return target_if_spectral_do_dbr_ring_debug(pdev, true);
6446 	else
6447 		return target_if_spectral_do_dbr_ring_debug(pdev, false);
6448 }
6449 
6450 /**
6451  * target_if_spectral_set_dma_debug() - Set DMA debug for Spectral
6452  * @pdev: Pointer to pdev object
6453  * @dma_debug_type: Type of Spectral DMA debug i.e., ring or buffer debug
6454  * @debug_value: Value to be set for @dma_debug_type
6455  *
6456  * Set DMA debug for Spectral and start/stop Spectral DMA debug function
6457  * based on @debug_value
6458  *
6459  * Return: QDF_STATUS of operation
6460  */
6461 static QDF_STATUS
6462 target_if_spectral_set_dma_debug(
6463 	struct wlan_objmgr_pdev *pdev,
6464 	enum spectral_dma_debug dma_debug_type,
6465 	bool debug_value)
6466 {
6467 	struct target_if_spectral_ops *p_sops;
6468 	struct wlan_objmgr_psoc *psoc;
6469 	struct wlan_lmac_if_tx_ops *tx_ops;
6470 	struct target_if_spectral *spectral;
6471 
6472 	if (!pdev)
6473 		return QDF_STATUS_E_FAILURE;
6474 
6475 	psoc = wlan_pdev_get_psoc(pdev);
6476 	if (!psoc) {
6477 		spectral_err("psoc is null");
6478 		return QDF_STATUS_E_INVAL;
6479 	}
6480 
6481 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
6482 	if (!tx_ops) {
6483 		spectral_err("tx_ops is NULL");
6484 		return QDF_STATUS_E_FAILURE;
6485 	}
6486 
6487 	if (!tx_ops->target_tx_ops.tgt_get_tgt_type) {
6488 		spectral_err("Unable to fetch target type");
6489 		return QDF_STATUS_E_FAILURE;
6490 	}
6491 
6492 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6493 	if (!spectral) {
6494 		spectral_err("Spectal LMAC object is NULL");
6495 		return QDF_STATUS_E_INVAL;
6496 	}
6497 
6498 	if (spectral->direct_dma_support) {
6499 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6500 		if (p_sops->is_spectral_active(spectral,
6501 					       SPECTRAL_SCAN_MODE_NORMAL) ||
6502 		    p_sops->is_spectral_active(spectral,
6503 					       SPECTRAL_SCAN_MODE_AGILE)) {
6504 			spectral_err("Altering DBR debug config isn't allowed during an ongoing scan");
6505 			return QDF_STATUS_E_FAILURE;
6506 		}
6507 
6508 		switch (dma_debug_type) {
6509 		case SPECTRAL_DMA_RING_DEBUG:
6510 			target_if_spectral_do_dbr_ring_debug(pdev, debug_value);
6511 			break;
6512 
6513 		case SPECTRAL_DMA_BUFFER_DEBUG:
6514 			target_if_spectral_do_dbr_buff_debug(pdev, debug_value);
6515 			break;
6516 
6517 		default:
6518 			spectral_err("Unsupported DMA debug type : %d",
6519 				     dma_debug_type);
6520 			return QDF_STATUS_E_FAILURE;
6521 		}
6522 	}
6523 	return QDF_STATUS_SUCCESS;
6524 }
6525 #endif /* DIRECT_BUF_RX_DEBUG */
6526 
6527 /**
6528  * target_if_spectral_direct_dma_support() - Get Direct-DMA support
6529  * @pdev: Pointer to pdev object
6530  *
6531  * Return: Whether Direct-DMA is supported on this radio
6532  */
6533 static bool
6534 target_if_spectral_direct_dma_support(struct wlan_objmgr_pdev *pdev)
6535 {
6536 	struct target_if_spectral *spectral;
6537 
6538 	if (!pdev) {
6539 		spectral_err("pdev is NULL!");
6540 		return false;
6541 	}
6542 
6543 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6544 	if (!spectral) {
6545 		spectral_err("Spectral LMAC object is NULL");
6546 		return false;
6547 	}
6548 
6549 	return spectral->direct_dma_support;
6550 }
6551 
6552 /**
6553  * target_if_set_debug_level() - Set debug level for Spectral
6554  * @pdev: Pointer to pdev object
6555  * @debug_level: Debug level
6556  *
6557  * API to set the debug level for Spectral
6558  *
6559  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
6560  */
6561 QDF_STATUS
6562 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
6563 {
6564 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
6565 
6566 	return QDF_STATUS_SUCCESS;
6567 }
6568 
6569 /**
6570  * target_if_get_debug_level() - Get debug level for Spectral
6571  * @pdev: Pointer to pdev object
6572  *
6573  * API to get the debug level for Spectral
6574  *
6575  * Return: Current debug level
6576  */
6577 uint32_t
6578 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
6579 {
6580 	return spectral_debug_level;
6581 }
6582 
6583 /**
6584  * target_if_get_spectral_capinfo() - Get Spectral capability information
6585  * @pdev: Pointer to pdev object
6586  * @scaps: Buffer into which data should be copied
6587  *
6588  * API to get the spectral capability information
6589  *
6590  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
6591  */
6592 QDF_STATUS
6593 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev,
6594 			       struct spectral_caps *scaps)
6595 {
6596 	struct target_if_spectral *spectral = NULL;
6597 
6598 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6599 	if (!spectral) {
6600 		spectral_err("SPECTRAL : Module doesn't exist");
6601 		return QDF_STATUS_E_FAILURE;
6602 	}
6603 
6604 	qdf_mem_copy(scaps, &spectral->capability,
6605 		     sizeof(struct spectral_caps));
6606 
6607 	return QDF_STATUS_SUCCESS;
6608 }
6609 
6610 /**
6611  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
6612  * @pdev:  Pointer to pdev object
6613  * @stats: Buffer into which data should be copied
6614  *
6615  * API to get the spectral diagnostic statistics
6616  *
6617  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
6618  */
6619 QDF_STATUS
6620 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev,
6621 				 struct spectral_diag_stats *stats)
6622 {
6623 	struct target_if_spectral *spectral = NULL;
6624 
6625 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6626 	if (!spectral) {
6627 		spectral_err("SPECTRAL : Module doesn't exist");
6628 		return QDF_STATUS_E_FAILURE;
6629 	}
6630 
6631 	qdf_mem_copy(stats, &spectral->diag_stats,
6632 		     sizeof(struct spectral_diag_stats));
6633 
6634 	return QDF_STATUS_SUCCESS;
6635 }
6636 
6637 /**
6638  * target_if_register_spectral_wmi_ops() - Register Spectral WMI operations
6639  * @psoc: Pointer to psoc object
6640  * @wmi_ops: Pointer to the structure having Spectral WMI operations
6641  *
6642  * API for registering Spectral WMI operations in
6643  * spectral internal data structure
6644  *
6645  * Return: QDF_STATUS
6646  */
6647 static QDF_STATUS
6648 target_if_register_spectral_wmi_ops(struct wlan_objmgr_psoc *psoc,
6649 				    struct spectral_wmi_ops *wmi_ops)
6650 {
6651 	struct target_if_psoc_spectral *psoc_spectral;
6652 
6653 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6654 	if (!psoc_spectral) {
6655 		spectral_err("Spectral LMAC object is null");
6656 		return QDF_STATUS_E_INVAL;
6657 	}
6658 
6659 	psoc_spectral->wmi_ops = *wmi_ops;
6660 
6661 	return QDF_STATUS_SUCCESS;
6662 }
6663 
6664 /**
6665  * target_if_register_spectral_tgt_ops() - Register Spectral target operations
6666  * @psoc: Pointer to psoc object
6667  * @tgt_ops: Pointer to the structure having Spectral target operations
6668  *
6669  * API for registering Spectral target operations in
6670  * spectral internal data structure
6671  *
6672  * Return: QDF_STATUS
6673  */
6674 static QDF_STATUS
6675 target_if_register_spectral_tgt_ops(struct wlan_objmgr_psoc *psoc,
6676 				    struct spectral_tgt_ops *tgt_ops)
6677 {
6678 	if (!psoc) {
6679 		spectral_err("psoc is null");
6680 		return QDF_STATUS_E_INVAL;
6681 	}
6682 
6683 	ops_tgt = *tgt_ops;
6684 
6685 	return QDF_STATUS_SUCCESS;
6686 }
6687 
6688 /**
6689  * target_if_register_netlink_cb() - Register Netlink callbacks
6690  * @pdev: Pointer to pdev object
6691  * @nl_cb: Netlink callbacks to register
6692  *
6693  * Return: void
6694  */
6695 static void
6696 target_if_register_netlink_cb(
6697 	struct wlan_objmgr_pdev *pdev,
6698 	struct spectral_nl_cb *nl_cb)
6699 {
6700 	struct target_if_spectral *spectral = NULL;
6701 
6702 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6703 
6704 	if (!spectral) {
6705 		spectral_err("SPECTRAL : Module doesn't exist");
6706 		return;
6707 	}
6708 
6709 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
6710 
6711 	if (spectral->use_nl_bcast)
6712 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
6713 	else
6714 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
6715 }
6716 
6717 /**
6718  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
6719  * Netlink messages to the application layer
6720  * @pdev: Pointer to pdev object
6721  *
6722  * Return: true for broadcast, false for unicast
6723  */
6724 static bool
6725 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
6726 {
6727 	struct target_if_spectral *spectral = NULL;
6728 
6729 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6730 
6731 	if (!spectral) {
6732 		spectral_err("SPECTRAL : Module doesn't exist");
6733 		return false;
6734 	}
6735 
6736 	return spectral->use_nl_bcast;
6737 }
6738 
6739 /**
6740  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
6741  * @pdev: Pointer to pdev object
6742  *
6743  * Return: void
6744  */
6745 static void
6746 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
6747 {
6748 	struct target_if_spectral *spectral = NULL;
6749 
6750 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6751 	if (!spectral) {
6752 		spectral_err("SPECTRAL : Module doesn't exist");
6753 		return;
6754 	}
6755 
6756 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
6757 }
6758 
6759 static int
6760 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
6761 				  void *payload)
6762 {
6763 	struct target_if_spectral *spectral = NULL;
6764 	struct target_if_spectral_ops *p_sops = NULL;
6765 
6766 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6767 	if (!spectral) {
6768 		spectral_err("SPECTRAL : Module doesn't exist");
6769 		return -EPERM;
6770 	}
6771 
6772 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6773 
6774 	if (!p_sops) {
6775 		spectral_err("p_sops is null");
6776 		return -EPERM;
6777 	}
6778 
6779 	return p_sops->process_spectral_report(pdev, payload);
6780 }
6781 
6782 #ifdef DIRECT_BUF_RX_DEBUG
6783 static inline void
6784 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
6785 {
6786 	if (!tx_ops) {
6787 		spectral_err("tx_ops is NULL");
6788 		return;
6789 	}
6790 
6791 	tx_ops->sptrl_tx_ops.sptrlto_set_dma_debug =
6792 		target_if_spectral_set_dma_debug;
6793 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_ring_debug =
6794 		target_if_spectral_check_and_do_dbr_ring_debug;
6795 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_buff_debug =
6796 		target_if_spectral_check_and_do_dbr_buff_debug;
6797 }
6798 #else
6799 static inline void
6800 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
6801 {
6802 }
6803 #endif
6804 
6805 #if defined(WLAN_CONV_SPECTRAL_ENABLE) && defined(SPECTRAL_MODULIZED_ENABLE)
6806 /**
6807  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
6808  * register WMI event handler
6809  * @psoc: Pointer to psoc object
6810  * @event_id: Event id
6811  * @handler_func: Handler function
6812  * @rx_ctx: Context of WMI event processing
6813  *
6814  * Wrapper function to register WMI event handler
6815  *
6816  * Return: 0 for success else failure
6817  */
6818 static int
6819 target_if_spectral_wmi_unified_register_event_handler(
6820 				struct wlan_objmgr_psoc *psoc,
6821 				wmi_conv_event_id event_id,
6822 				wmi_unified_event_handler handler_func,
6823 				uint8_t rx_ctx)
6824 {
6825 	wmi_unified_t wmi_handle;
6826 	struct target_if_psoc_spectral *psoc_spectral;
6827 	QDF_STATUS ret;
6828 
6829 	if (!psoc) {
6830 		spectral_err("psoc is null");
6831 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6832 	}
6833 
6834 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6835 	if (!wmi_handle) {
6836 		spectral_err("WMI handle is null");
6837 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6838 	}
6839 
6840 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6841 	if (!psoc_spectral) {
6842 		spectral_err("spectral object is null");
6843 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
6844 	}
6845 
6846 	ret = psoc_spectral->wmi_ops.wmi_unified_register_event_handler(
6847 			wmi_handle, event_id, handler_func, rx_ctx);
6848 
6849 	return qdf_status_to_os_return(ret);
6850 }
6851 
6852 /**
6853  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
6854  * to unregister WMI event handler
6855  * @psoc: Pointer to psoc object
6856  * @event_id: Event id
6857  *
6858  * Wrapper function to unregister WMI event handler
6859  *
6860  * Return: 0 for success else failure
6861  */
6862 static int
6863 target_if_spectral_wmi_unified_unregister_event_handler(
6864 				struct wlan_objmgr_psoc *psoc,
6865 				wmi_conv_event_id event_id)
6866 {
6867 	wmi_unified_t wmi_handle;
6868 	struct target_if_psoc_spectral *psoc_spectral;
6869 	QDF_STATUS ret;
6870 
6871 	if (!psoc) {
6872 		spectral_err("psoc is null");
6873 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6874 	}
6875 
6876 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6877 	if (!wmi_handle) {
6878 		spectral_err("WMI handle is null");
6879 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6880 	}
6881 
6882 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6883 	if (!psoc_spectral) {
6884 		spectral_err("spectral object is null");
6885 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
6886 	}
6887 
6888 	ret = psoc_spectral->wmi_ops.wmi_unified_unregister_event_handler(
6889 					wmi_handle, event_id);
6890 
6891 	return qdf_status_to_os_return(ret);
6892 }
6893 
6894 /**
6895  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
6896  * function to extract fixed parameters from start scan response event
6897  * @psoc: Pointer to psoc object
6898  * @evt_buf: Event buffer
6899  * @param: Start scan response parameters
6900  *
6901  * Wrapper function to extract fixed parameters from start scan response event
6902  *
6903  * Return: QDF_STATUS
6904  */
6905 static QDF_STATUS
6906 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
6907 			struct wlan_objmgr_psoc *psoc,
6908 			uint8_t *evt_buf,
6909 			struct spectral_startscan_resp_params *param)
6910 {
6911 	wmi_unified_t wmi_handle;
6912 	struct target_if_psoc_spectral *psoc_spectral;
6913 
6914 	if (!psoc) {
6915 		spectral_err("psoc is null");
6916 		return QDF_STATUS_E_INVAL;
6917 	}
6918 
6919 	if (!evt_buf) {
6920 		spectral_err("WMI event buffer is null");
6921 		return QDF_STATUS_E_INVAL;
6922 	}
6923 
6924 	if (!param) {
6925 		spectral_err("Spectral startscan response parameters is null");
6926 		return QDF_STATUS_E_INVAL;
6927 	}
6928 
6929 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6930 	if (!wmi_handle) {
6931 		spectral_err("WMI handle is null");
6932 		return QDF_STATUS_E_INVAL;
6933 	}
6934 
6935 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6936 	if (!psoc_spectral) {
6937 		spectral_err("spectral object is null");
6938 		return QDF_STATUS_E_FAILURE;
6939 	}
6940 
6941 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fw_cmd_fixed_param(
6942 			wmi_handle, evt_buf, param);
6943 }
6944 
6945 /**
6946  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
6947  * function to extract start and end indices of primary 80 MHz, 5 MHz and
6948  * secondary 80 MHz FFT bins
6949  * @psoc: Pointer to psoc object
6950  * @evt_buf: Event buffer
6951  * @param: FFT bin start and end indices
6952  *
6953  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
6954  * and secondary 80 MHz FFT bins
6955  *
6956  * Return: QDF_STATUS
6957  */
6958 static QDF_STATUS
6959 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
6960 			struct wlan_objmgr_psoc *psoc,
6961 			uint8_t *evt_buf,
6962 			struct spectral_fft_bin_markers_160_165mhz *param)
6963 {
6964 	wmi_unified_t wmi_handle;
6965 	struct target_if_psoc_spectral *psoc_spectral;
6966 
6967 	if (!psoc) {
6968 		spectral_err("psoc is null");
6969 		return QDF_STATUS_E_INVAL;
6970 	}
6971 
6972 	if (!evt_buf) {
6973 		spectral_err("WMI event buffer is null");
6974 		return QDF_STATUS_E_INVAL;
6975 	}
6976 
6977 	if (!param) {
6978 		spectral_err("Spectral FFT bin markers is null");
6979 		return QDF_STATUS_E_INVAL;
6980 	}
6981 
6982 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6983 	if (!wmi_handle) {
6984 		spectral_err("WMI handle is null");
6985 		return QDF_STATUS_E_INVAL;
6986 	}
6987 
6988 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6989 	if (!psoc_spectral) {
6990 		spectral_err("spectral object is null");
6991 		return QDF_STATUS_E_FAILURE;
6992 	}
6993 
6994 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fft_bin_index(
6995 			wmi_handle, evt_buf, param);
6996 }
6997 
6998 /**
6999  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
7000  * object from scn handle
7001  * @scn: scn handle
7002  *
7003  * Wrapper function to get psoc object from scn handle
7004  *
7005  * Return: Pointer to psoc object
7006  */
7007 static struct wlan_objmgr_psoc *
7008 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
7009 {
7010 	if (!scn) {
7011 		spectral_err("scn is null");
7012 		return NULL;
7013 	}
7014 
7015 	return ops_tgt.tgt_get_psoc_from_scn_hdl(scn);
7016 }
7017 
7018 /**
7019  * target_if_extract_pdev_spectral_session_chan_info() - Wrapper
7020  * function to extract channel information for a spectral scan session
7021  * @psoc: Pointer to psoc object
7022  * @evt_buf: Event buffer
7023  * @chan_info: Spectral session channel information data structure to be filled
7024  * by this API
7025  *
7026  * Return: QDF_STATUS of operation
7027  */
7028 static QDF_STATUS
7029 target_if_extract_pdev_spectral_session_chan_info(
7030 			struct wlan_objmgr_psoc *psoc,
7031 			void *evt_buf,
7032 			struct spectral_session_chan_info *chan_info)
7033 {
7034 	wmi_unified_t wmi_handle;
7035 	struct target_if_psoc_spectral *psoc_spectral;
7036 
7037 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7038 	if (!wmi_handle) {
7039 		spectral_err("WMI handle is null");
7040 		return QDF_STATUS_E_NULL_VALUE;
7041 	}
7042 
7043 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7044 	if (!psoc_spectral) {
7045 		spectral_err("spectral object is null");
7046 		return QDF_STATUS_E_NULL_VALUE;
7047 	}
7048 
7049 	return psoc_spectral->wmi_ops.extract_pdev_spectral_session_chan_info(
7050 			wmi_handle, evt_buf, chan_info);
7051 }
7052 
7053 /**
7054  * target_if_extract_pdev_spectral_session_detector_info() - Wrapper
7055  * function to extract detector information for a spectral scan session
7056  * @psoc: Pointer to psoc object
7057  * @evt_buf: Event buffer
7058  * @det_info: Spectral session detector information data structure to be filled
7059  * by this API
7060  * @det_info_idx: index in the array of spectral scan detector info TLVs
7061  *
7062  * Return: QDF_STATUS of operation
7063  */
7064 static QDF_STATUS
7065 target_if_extract_pdev_spectral_session_detector_info(
7066 			struct wlan_objmgr_psoc *psoc, void *evt_buf,
7067 			struct spectral_session_det_info *det_info,
7068 			uint8_t det_info_idx)
7069 {
7070 	wmi_unified_t wmi_handle;
7071 	struct target_if_psoc_spectral *psoc_spectral;
7072 
7073 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7074 	if (!wmi_handle) {
7075 		spectral_err("WMI handle is null");
7076 		return QDF_STATUS_E_NULL_VALUE;
7077 	}
7078 
7079 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7080 	if (!psoc_spectral) {
7081 		spectral_err("spectral object is null");
7082 		return QDF_STATUS_E_NULL_VALUE;
7083 	}
7084 
7085 	return psoc_spectral->wmi_ops.
7086 			extract_pdev_spectral_session_detector_info(
7087 				wmi_handle, evt_buf, det_info, det_info_idx);
7088 }
7089 
7090 /**
7091  * target_if_wmi_extract_spectral_caps_fixed_param() - Wrapper function to
7092  * extract fixed params from Spectral capabilities WMI event
7093  * @psoc: Pointer to psoc object
7094  * @evt_buf: Event buffer
7095  * @param: Spectral capabilities event parameters data structure to be filled
7096  * by this API
7097  *
7098  * Return: QDF_STATUS of operation
7099  */
7100 QDF_STATUS
7101 target_if_wmi_extract_spectral_caps_fixed_param(
7102 			struct wlan_objmgr_psoc *psoc,
7103 			uint8_t *evt_buf,
7104 			struct spectral_capabilities_event_params *param)
7105 {
7106 	struct target_if_psoc_spectral *psoc_spectral;
7107 	wmi_unified_t wmi_handle;
7108 
7109 	if (!psoc) {
7110 		spectral_err("psoc is null");
7111 		return QDF_STATUS_E_NULL_VALUE;
7112 	}
7113 
7114 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7115 	if (!wmi_handle) {
7116 		spectral_err("WMI handle is null");
7117 		return QDF_STATUS_E_NULL_VALUE;
7118 	}
7119 
7120 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7121 	if (!psoc_spectral) {
7122 		spectral_err("spectral object is null");
7123 		return QDF_STATUS_E_FAILURE;
7124 	}
7125 
7126 	return psoc_spectral->wmi_ops.extract_spectral_caps_fixed_param(
7127 			wmi_handle, evt_buf, param);
7128 }
7129 
7130 /**
7131  * target_if_wmi_extract_spectral_scan_bw_caps() - Wrapper function to
7132  * extract bandwidth capabilities from Spectral capabilities WMI event
7133  * @psoc: Pointer to psoc object
7134  * @evt_buf: Event buffer
7135  * @bw_caps: Data structure to be filled by this API after extraction
7136  *
7137  * Return: QDF_STATUS of operation
7138  */
7139 QDF_STATUS
7140 target_if_wmi_extract_spectral_scan_bw_caps(
7141 			struct wlan_objmgr_psoc *psoc,
7142 			uint8_t *evt_buf,
7143 			struct spectral_scan_bw_capabilities *bw_caps)
7144 {
7145 	struct target_if_psoc_spectral *psoc_spectral;
7146 	wmi_unified_t wmi_handle;
7147 
7148 	if (!psoc) {
7149 		spectral_err("psoc is null");
7150 		return QDF_STATUS_E_INVAL;
7151 	}
7152 
7153 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7154 	if (!wmi_handle) {
7155 		spectral_err("WMI handle is null");
7156 		return QDF_STATUS_E_INVAL;
7157 	}
7158 
7159 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7160 	if (!psoc_spectral) {
7161 		spectral_err("spectral object is null");
7162 		return QDF_STATUS_E_FAILURE;
7163 	}
7164 
7165 	return psoc_spectral->wmi_ops.extract_spectral_scan_bw_caps(
7166 			wmi_handle, evt_buf, bw_caps);
7167 }
7168 
7169 /**
7170  * target_if_wmi_extract_spectral_fft_size_caps() - Wrapper function to
7171  * extract fft size capabilities from Spectral capabilities WMI event
7172  * @psoc: Pointer to psoc object
7173  * @evt_buf: Event buffer
7174  * @fft_size_caps: Data structure to be filled by this API after extraction
7175  *
7176  * Return: QDF_STATUS of operation
7177  */
7178 QDF_STATUS
7179 target_if_wmi_extract_spectral_fft_size_caps(
7180 			struct wlan_objmgr_psoc *psoc,
7181 			uint8_t *evt_buf,
7182 			struct spectral_fft_size_capabilities *fft_size_caps)
7183 {
7184 	struct target_if_psoc_spectral *psoc_spectral;
7185 	wmi_unified_t wmi_handle;
7186 
7187 	if (!psoc) {
7188 		spectral_err("psoc is null");
7189 		return QDF_STATUS_E_INVAL;
7190 	}
7191 
7192 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7193 	if (!wmi_handle) {
7194 		spectral_err("WMI handle is null");
7195 		return QDF_STATUS_E_INVAL;
7196 	}
7197 
7198 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7199 	if (!psoc_spectral) {
7200 		spectral_err("spectral object is null");
7201 		return QDF_STATUS_E_FAILURE;
7202 	}
7203 
7204 	return psoc_spectral->wmi_ops.extract_spectral_fft_size_caps(
7205 			wmi_handle, evt_buf, fft_size_caps);
7206 }
7207 #else
7208 /**
7209  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
7210  * register WMI event handler
7211  * @psoc: Pointer to psoc object
7212  * @event_id: Event id
7213  * @handler_func: Handler function
7214  * @rx_ctx: Context of WMI event processing
7215  *
7216  * Wrapper function to register WMI event handler
7217  *
7218  * Return: 0 for success else failure
7219  */
7220 static int
7221 target_if_spectral_wmi_unified_register_event_handler(
7222 				struct wlan_objmgr_psoc *psoc,
7223 				wmi_conv_event_id event_id,
7224 				wmi_unified_event_handler handler_func,
7225 				uint8_t rx_ctx)
7226 {
7227 	wmi_unified_t wmi_handle;
7228 	QDF_STATUS ret;
7229 
7230 	if (!psoc) {
7231 		spectral_err("psoc is null");
7232 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7233 	}
7234 
7235 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7236 	if (!wmi_handle) {
7237 		spectral_err("WMI handle is null");
7238 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7239 	}
7240 
7241 	ret = wmi_unified_register_event_handler(wmi_handle, event_id,
7242 						 handler_func, rx_ctx);
7243 
7244 	return qdf_status_to_os_return(ret);
7245 }
7246 
7247 /**
7248  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
7249  * to unregister WMI event handler
7250  * @psoc: Pointer to psoc object
7251  * @event_id: Event id
7252  *
7253  * Wrapper function to unregister WMI event handler
7254  *
7255  * Return: 0 for success else failure
7256  */
7257 static int
7258 target_if_spectral_wmi_unified_unregister_event_handler(
7259 				struct wlan_objmgr_psoc *psoc,
7260 				wmi_conv_event_id event_id)
7261 {
7262 	wmi_unified_t wmi_handle;
7263 	QDF_STATUS ret;
7264 
7265 	if (!psoc) {
7266 		spectral_err("psoc is null");
7267 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7268 	}
7269 
7270 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7271 	if (!wmi_handle) {
7272 		spectral_err("WMI handle is null");
7273 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7274 	}
7275 
7276 	ret = wmi_unified_unregister_event_handler(wmi_handle, event_id);
7277 
7278 	return qdf_status_to_os_return(ret);
7279 }
7280 
7281 /**
7282  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
7283  * function to extract fixed parameters from start scan response event
7284  * @psoc: Pointer to psoc object
7285  * @evt_buf: Event buffer
7286  * @param: Start scan response parameters
7287  *
7288  * Wrapper function to extract fixed parameters from start scan response event
7289  *
7290  * Return: QDF_STATUS
7291  */
7292 static QDF_STATUS
7293 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
7294 			struct wlan_objmgr_psoc *psoc,
7295 			uint8_t *evt_buf,
7296 			struct spectral_startscan_resp_params *param)
7297 {
7298 	wmi_unified_t wmi_handle;
7299 
7300 	if (!psoc) {
7301 		spectral_err("psoc is null");
7302 		return QDF_STATUS_E_INVAL;
7303 	}
7304 
7305 	if (!evt_buf) {
7306 		spectral_err("WMI event buffer is null");
7307 		return QDF_STATUS_E_INVAL;
7308 	}
7309 
7310 	if (!param) {
7311 		spectral_err("Spectral startscan response parameters is null");
7312 		return QDF_STATUS_E_INVAL;
7313 	}
7314 
7315 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7316 	if (!wmi_handle) {
7317 		spectral_err("WMI handle is null");
7318 		return QDF_STATUS_E_INVAL;
7319 	}
7320 
7321 	return wmi_extract_pdev_sscan_fw_cmd_fixed_param(wmi_handle, evt_buf,
7322 							 param);
7323 }
7324 
7325 /**
7326  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
7327  * function to extract start and end indices of primary 80 MHz, 5 MHz and
7328  * secondary 80 MHz FFT bins
7329  * @psoc: Pointer to psoc object
7330  * @evt_buf: Event buffer
7331  * @param: FFT bin start and end indices
7332  *
7333  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
7334  * and secondary 80 MHz FFT bins
7335  *
7336  * Return: QDF_STATUS
7337  */
7338 static QDF_STATUS
7339 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
7340 			struct wlan_objmgr_psoc *psoc,
7341 			uint8_t *evt_buf,
7342 			struct spectral_fft_bin_markers_160_165mhz *param)
7343 {
7344 	wmi_unified_t wmi_handle;
7345 
7346 	if (!psoc) {
7347 		spectral_err("psoc is null");
7348 		return QDF_STATUS_E_INVAL;
7349 	}
7350 
7351 	if (!evt_buf) {
7352 		spectral_err("WMI event buffer is null");
7353 		return QDF_STATUS_E_INVAL;
7354 	}
7355 
7356 	if (!param) {
7357 		spectral_err("Spectral FFT bin markers is null");
7358 		return QDF_STATUS_E_INVAL;
7359 	}
7360 
7361 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7362 	if (!wmi_handle) {
7363 		spectral_err("WMI handle is null");
7364 		return QDF_STATUS_E_INVAL;
7365 	}
7366 
7367 	return wmi_extract_pdev_sscan_fft_bin_index(wmi_handle, evt_buf, param);
7368 }
7369 
7370 /**
7371  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
7372  * object from scn handle
7373  * @scn: scn handle
7374  *
7375  * Wrapper function to get psoc object from scn handle
7376  *
7377  * Return: Pointer to psoc object
7378  */
7379 static struct wlan_objmgr_psoc *
7380 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
7381 {
7382 	if (!scn) {
7383 		spectral_err("scn is null");
7384 		return NULL;
7385 	}
7386 
7387 	return target_if_get_psoc_from_scn_hdl(scn);
7388 }
7389 
7390 /**
7391  * target_if_extract_pdev_spectral_session_chan_info() - Wrapper
7392  * function to extract channel information for a spectral scan session
7393  * @psoc: Pointer to psoc object
7394  * @evt_buf: Event buffer
7395  * @chan_info: Spectral session channel information data structure to be filled
7396  * by this API
7397  *
7398  * Return: QDF_STATUS of operation
7399  */
7400 static QDF_STATUS
7401 target_if_extract_pdev_spectral_session_chan_info(
7402 			struct wlan_objmgr_psoc *psoc,
7403 			void *evt_buf,
7404 			struct spectral_session_chan_info *chan_info)
7405 {
7406 	wmi_unified_t wmi_handle;
7407 
7408 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7409 	if (!wmi_handle) {
7410 		spectral_err("WMI handle is null");
7411 		return QDF_STATUS_E_NULL_VALUE;
7412 	}
7413 
7414 	return wmi_extract_pdev_spectral_session_chan_info(
7415 			wmi_handle, evt_buf, chan_info);
7416 }
7417 
7418 /**
7419  * target_if_extract_pdev_spectral_session_detector_info() - Wrapper
7420  * function to extract detector information for a spectral scan session
7421  * @psoc: Pointer to psoc object
7422  * @evt_buf: Event buffer
7423  * @det_info: Spectral session detector information data structure to be filled
7424  * by this API
7425  * @det_info_idx: index in the array of spectral scan detector info TLVs
7426  *
7427  * Return: QDF_STATUS of operation
7428  */
7429 static QDF_STATUS
7430 target_if_extract_pdev_spectral_session_detector_info(
7431 			struct wlan_objmgr_psoc *psoc, void *evt_buf,
7432 			struct spectral_session_det_info *det_info,
7433 			uint8_t det_info_idx)
7434 {
7435 	wmi_unified_t wmi_handle;
7436 
7437 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7438 	if (!wmi_handle) {
7439 		spectral_err("WMI handle is null");
7440 		return QDF_STATUS_E_NULL_VALUE;
7441 	}
7442 
7443 	return wmi_extract_pdev_spectral_session_detector_info(
7444 				wmi_handle, evt_buf, det_info, det_info_idx);
7445 }
7446 
7447 QDF_STATUS
7448 target_if_wmi_extract_spectral_caps_fixed_param(
7449 			struct wlan_objmgr_psoc *psoc,
7450 			uint8_t *evt_buf,
7451 			struct spectral_capabilities_event_params *param)
7452 {
7453 	wmi_unified_t wmi_handle;
7454 
7455 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7456 	if (!wmi_handle) {
7457 		spectral_err("WMI handle is null");
7458 		return QDF_STATUS_E_INVAL;
7459 	}
7460 
7461 	return wmi_extract_spectral_caps_fixed_param(wmi_handle, evt_buf,
7462 						     param);
7463 }
7464 
7465 QDF_STATUS
7466 target_if_wmi_extract_spectral_scan_bw_caps(
7467 			struct wlan_objmgr_psoc *psoc,
7468 			uint8_t *evt_buf,
7469 			struct spectral_scan_bw_capabilities *bw_caps)
7470 {
7471 	wmi_unified_t wmi_handle;
7472 
7473 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7474 	if (!wmi_handle) {
7475 		spectral_err("WMI handle is null");
7476 		return QDF_STATUS_E_INVAL;
7477 	}
7478 
7479 	return wmi_extract_spectral_scan_bw_caps(wmi_handle, evt_buf, bw_caps);
7480 }
7481 
7482 QDF_STATUS
7483 target_if_wmi_extract_spectral_fft_size_caps(
7484 			struct wlan_objmgr_psoc *psoc,
7485 			uint8_t *evt_buf,
7486 			struct spectral_fft_size_capabilities *fft_size_caps)
7487 {
7488 	wmi_unified_t wmi_handle;
7489 
7490 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7491 	if (!wmi_handle) {
7492 		spectral_err("WMI handle is null");
7493 		return QDF_STATUS_E_INVAL;
7494 	}
7495 
7496 	return wmi_extract_spectral_fft_size_caps(wmi_handle, evt_buf,
7497 						  fft_size_caps);
7498 }
7499 #endif
7500 
7501 /**
7502  * target_if_update_det_info_in_spectral_session() - Update detector
7503  * information in spectral scan session
7504  * @spectral: Spectral LMAC object
7505  * @det_info: Pointer to spectral session detector information
7506  * @smode: Spectral scan mode
7507  *
7508  * Return: QDF_STATUS of operation
7509  */
7510 static QDF_STATUS
7511 target_if_update_det_info_in_spectral_session(
7512 	struct target_if_spectral *spectral,
7513 	const struct spectral_session_det_info *det_info,
7514 	enum spectral_scan_mode smode)
7515 {
7516 	struct per_session_det_map *det_map;
7517 	struct per_session_dest_det_info *dest_det_info;
7518 
7519 	if (!spectral) {
7520 		spectral_err_rl("Spectral LMAC object is null");
7521 		return QDF_STATUS_E_NULL_VALUE;
7522 	}
7523 
7524 	qdf_assert_always(det_info->det_id < MAX_DETECTORS_PER_PDEV);
7525 
7526 	qdf_spin_lock_bh(&spectral->session_det_map_lock);
7527 
7528 	det_map = &spectral->det_map[det_info->det_id];
7529 	dest_det_info = &det_map->dest_det_info[0];
7530 
7531 	dest_det_info->start_freq = det_info->start_freq;
7532 	dest_det_info->end_freq = det_info->end_freq;
7533 
7534 	qdf_spin_unlock_bh(&spectral->session_det_map_lock);
7535 
7536 	/* This detector will be used for this smode throughout this session */
7537 	spectral->rparams.detid_mode_table[det_info->det_id] = smode;
7538 
7539 	return QDF_STATUS_SUCCESS;
7540 }
7541 
7542 /**
7543  * target_if_update_chan_info_in_spectral_session() - Update channel information
7544  * in spectral scan session
7545  * @spectral: Spectral LMAC object
7546  * @chan_info: Pointer to spectral session channel information
7547  * @smode: Spectral scan mode
7548  *
7549  * Return: QDF_STATUS of operation
7550  */
7551 static QDF_STATUS
7552 target_if_update_chan_info_in_spectral_session(
7553 	struct target_if_spectral *spectral,
7554 	const struct spectral_session_chan_info *chan_info,
7555 	enum spectral_scan_mode smode)
7556 {
7557 	struct per_session_report_info *rpt_info;
7558 
7559 	if (!spectral) {
7560 		spectral_err_rl("Spectral LMAC object is null");
7561 		return QDF_STATUS_E_NULL_VALUE;
7562 	}
7563 
7564 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
7565 		spectral_err_rl("Invalid Spectral scan mode :%u", smode);
7566 		return QDF_STATUS_E_FAILURE;
7567 	}
7568 
7569 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
7570 	rpt_info = &spectral->report_info[smode];
7571 
7572 	/* Update per-session report info */
7573 	rpt_info->pri20_freq = chan_info->operating_pri20_freq;
7574 	rpt_info->cfreq1 = chan_info->operating_cfreq1;
7575 	rpt_info->cfreq2 = chan_info->operating_cfreq2;
7576 	rpt_info->operating_bw = chan_info->operating_bw;
7577 	rpt_info->sscan_cfreq1 = chan_info->sscan_cfreq1;
7578 	rpt_info->sscan_cfreq2 = chan_info->sscan_cfreq2;
7579 	rpt_info->sscan_bw = chan_info->sscan_bw;
7580 
7581 	/* num_spans depends on sscan_bw, update it */
7582 	rpt_info->num_spans = target_if_spectral_get_num_spans(
7583 					spectral->pdev_obj,
7584 					rpt_info->sscan_bw);
7585 	qdf_assert_always(rpt_info->num_spans != INVALID_SPAN_NUM);
7586 
7587 	rpt_info->valid = true;
7588 
7589 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
7590 
7591 	return QDF_STATUS_SUCCESS;
7592 }
7593 
7594 /**
7595  * target_if_spectral_fw_param_event_handler() - WMI event handler to
7596  * process start scan response event
7597  * @scn: Pointer to scn object
7598  * @data_buf: Pointer to event buffer
7599  * @data_len: Length of event buffer
7600  *
7601  * Return: 0 for success, else failure
7602  */
7603 static int
7604 target_if_spectral_fw_param_event_handler(ol_scn_t scn, uint8_t *data_buf,
7605 					  uint32_t data_len)
7606 {
7607 	QDF_STATUS status;
7608 	struct wlan_objmgr_psoc *psoc;
7609 	struct wlan_objmgr_pdev *pdev;
7610 	struct wmi_unified *wmi_handle;
7611 	struct spectral_startscan_resp_params event_params = {0};
7612 	struct target_if_psoc_spectral *psoc_spectral;
7613 	struct target_if_spectral *spectral;
7614 	bool is_session_info_expected;
7615 
7616 	if (!scn) {
7617 		spectral_err("scn handle is null");
7618 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7619 	}
7620 
7621 	if (!data_buf) {
7622 		spectral_err("WMI event buffer null");
7623 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7624 	}
7625 
7626 	psoc = target_if_spectral_get_psoc_from_scn_handle(scn);
7627 	if (!psoc) {
7628 		spectral_err("psoc is null");
7629 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7630 	}
7631 
7632 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7633 	if (!psoc_spectral) {
7634 		spectral_err("spectral object is null");
7635 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7636 	}
7637 
7638 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7639 	if (!wmi_handle) {
7640 		spectral_err("WMI handle is null");
7641 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7642 	}
7643 
7644 	status = target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
7645 				psoc, data_buf, &event_params);
7646 	if (QDF_IS_STATUS_ERROR(status)) {
7647 		spectral_err("unable to extract sscan fw fixed params");
7648 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7649 	}
7650 
7651 	if (event_params.smode >= SPECTRAL_SCAN_MODE_MAX ||
7652 	    event_params.smode < SPECTRAL_SCAN_MODE_NORMAL) {
7653 		spectral_err("Invalid smode %d", event_params.smode);
7654 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7655 	}
7656 
7657 	pdev = wlan_objmgr_get_pdev_by_id(psoc, event_params.pdev_id,
7658 					  WLAN_SPECTRAL_ID);
7659 	if (!pdev) {
7660 		spectral_err("pdev is null");
7661 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7662 	}
7663 
7664 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
7665 	if (!spectral) {
7666 		spectral_err("spectral object is null");
7667 		status = QDF_STATUS_E_FAILURE;
7668 		goto release_pdev_ref;
7669 	}
7670 
7671 	if (event_params.num_fft_bin_index == 1) {
7672 		status =
7673 			target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
7674 				psoc, data_buf,
7675 				&spectral->rparams.marker[event_params.smode]);
7676 		if (QDF_IS_STATUS_ERROR(status)) {
7677 			spectral_err("unable to extract sscan fw fixed params");
7678 			goto release_pdev_ref;
7679 		}
7680 	} else {
7681 		spectral->rparams.marker[event_params.smode].is_valid = false;
7682 	}
7683 
7684 	status = spectral_is_session_info_expected_from_target(
7685 					pdev, &is_session_info_expected);
7686 	if (QDF_IS_STATUS_ERROR(status)) {
7687 		spectral_err("Failed to check if session info is expected");
7688 		goto release_pdev_ref;
7689 	}
7690 
7691 	if (is_session_info_expected) {
7692 		struct spectral_session_chan_info chan_info;
7693 		uint8_t det_info_idx = 0;
7694 
7695 		status = target_if_extract_pdev_spectral_session_chan_info(
7696 				psoc, data_buf, &chan_info);
7697 		if (QDF_IS_STATUS_ERROR(status)) {
7698 			spectral_err("Unable to extract spectral session channel info");
7699 			goto release_pdev_ref;
7700 		}
7701 
7702 		status = target_if_update_chan_info_in_spectral_session(
7703 				spectral, &chan_info, event_params.smode);
7704 		if (QDF_IS_STATUS_ERROR(status)) {
7705 			spectral_err("Unable to update channel info");
7706 			goto release_pdev_ref;
7707 		}
7708 
7709 		/* FFT bins info depends upon sscan_bw, update it */
7710 		status = target_if_populate_fft_bins_info(spectral,
7711 							  event_params.smode);
7712 		if (QDF_IS_STATUS_ERROR(status)) {
7713 			spectral_err("Failed to populate FFT bins info");
7714 			goto release_pdev_ref;
7715 		}
7716 
7717 		/**
7718 		 * per-session det info that depends on sscan_bw needs to be
7719 		 * updated here
7720 		 */
7721 		status = target_if_spectral_populate_session_det_host_info(
7722 					spectral, event_params.smode);
7723 		if (QDF_IS_STATUS_ERROR(status)) {
7724 			spectral_err("Failed to populate per-session det info");
7725 			goto release_pdev_ref;
7726 		}
7727 
7728 		for (; det_info_idx < event_params.num_det_info;
7729 		     ++det_info_idx) {
7730 			struct spectral_session_det_info det_info;
7731 
7732 			status =
7733 			  target_if_extract_pdev_spectral_session_detector_info
7734 				(psoc, data_buf, &det_info, det_info_idx);
7735 
7736 			if (QDF_IS_STATUS_ERROR(status)) {
7737 				spectral_err("Unable to extract spectral session detector info for %u",
7738 					     det_info_idx);
7739 				goto release_pdev_ref;
7740 			}
7741 
7742 			status = target_if_update_det_info_in_spectral_session(
7743 					spectral, &det_info,
7744 					event_params.smode);
7745 			if (QDF_IS_STATUS_ERROR(status)) {
7746 				spectral_err("Unable to update detector info");
7747 				goto release_pdev_ref;
7748 			}
7749 		}
7750 	}
7751 
7752 	status = QDF_STATUS_SUCCESS;
7753 
7754 release_pdev_ref:
7755 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
7756 	return qdf_status_to_os_return(status);
7757 }
7758 
7759 /**
7760  * target_if_spectral_capabilities_event_handler() - Handler for the Spectral
7761  * Capabilities event
7762  * @scn: Pointer to scn object
7763  * @data_buf: Pointer to event buffer
7764  * @data_len: Length of event buffer
7765  *
7766  * Return: 0 for success, else failure
7767  */
7768 static int
7769 target_if_spectral_capabilities_event_handler(ol_scn_t scn, uint8_t *data_buf,
7770 					      uint32_t data_len)
7771 {
7772 	QDF_STATUS status;
7773 	struct wlan_objmgr_psoc *psoc;
7774 	struct wmi_unified *wmi_handle;
7775 	struct spectral_capabilities_event_params event_params = {0};
7776 	struct spectral_scan_bw_capabilities *bw_caps;
7777 	struct spectral_fft_size_capabilities *fft_size_caps;
7778 
7779 	if (!scn) {
7780 		spectral_err("scn handle is null");
7781 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7782 	}
7783 
7784 	if (!data_buf) {
7785 		spectral_err("WMI event buffer null");
7786 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7787 	}
7788 
7789 	psoc = target_if_spectral_get_psoc_from_scn_handle(scn);
7790 	if (!psoc) {
7791 		spectral_err("psoc is null");
7792 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7793 	}
7794 
7795 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7796 	if (!wmi_handle) {
7797 		spectral_err("WMI handle is null");
7798 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7799 	}
7800 
7801 	status = target_if_wmi_extract_spectral_caps_fixed_param(
7802 				psoc, data_buf, &event_params);
7803 	if (QDF_IS_STATUS_ERROR(status)) {
7804 		spectral_err("Failed to extract fixed parameters");
7805 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7806 	}
7807 
7808 	/* There should be atleast one capability */
7809 	qdf_assert(event_params.num_sscan_bw_caps > 0);
7810 	qdf_assert(event_params.num_fft_size_caps > 0);
7811 
7812 	bw_caps = qdf_mem_malloc(
7813 			sizeof(*bw_caps) * event_params.num_sscan_bw_caps);
7814 	if (!bw_caps) {
7815 		spectral_err("memory allocation failed");
7816 		return qdf_status_to_os_return(QDF_STATUS_E_NOMEM);
7817 	}
7818 
7819 	status = target_if_wmi_extract_spectral_scan_bw_caps(psoc, data_buf,
7820 							     bw_caps);
7821 	if (QDF_IS_STATUS_ERROR(status)) {
7822 		spectral_err("Failed to extract BW caps");
7823 		status = QDF_STATUS_E_FAILURE;
7824 		goto free_bw_caps;
7825 	}
7826 
7827 	fft_size_caps = qdf_mem_malloc(
7828 		sizeof(*fft_size_caps) * event_params.num_fft_size_caps);
7829 	if (!fft_size_caps) {
7830 		spectral_err("memory allocation failed");
7831 		status = QDF_STATUS_E_NOMEM;
7832 		goto free_bw_caps;
7833 	}
7834 
7835 	status = target_if_wmi_extract_spectral_fft_size_caps(psoc, data_buf,
7836 							      fft_size_caps);
7837 	if (QDF_IS_STATUS_ERROR(status)) {
7838 		spectral_err("Failed to extract fft size caps");
7839 		status = QDF_STATUS_E_FAILURE;
7840 		goto free_fft_size_caps;
7841 	}
7842 
7843 	status = QDF_STATUS_SUCCESS;
7844 
7845 free_fft_size_caps:
7846 	qdf_mem_free(fft_size_caps);
7847 
7848 free_bw_caps:
7849 	qdf_mem_free(bw_caps);
7850 
7851 	return qdf_status_to_os_return(status);
7852 }
7853 
7854 static QDF_STATUS
7855 target_if_spectral_register_events(struct wlan_objmgr_psoc *psoc)
7856 {
7857 	int ret;
7858 
7859 	if (!psoc) {
7860 		spectral_err("psoc is null");
7861 		return QDF_STATUS_E_INVAL;
7862 	}
7863 
7864 	ret = target_if_spectral_wmi_unified_register_event_handler(
7865 			psoc,
7866 			wmi_pdev_sscan_fw_param_eventid,
7867 			target_if_spectral_fw_param_event_handler,
7868 			WMI_RX_UMAC_CTX);
7869 
7870 	if (ret)
7871 		spectral_debug("event handler not supported, ret=%d", ret);
7872 
7873 	ret = target_if_spectral_wmi_unified_register_event_handler(
7874 			psoc,
7875 			wmi_spectral_capabilities_eventid,
7876 			target_if_spectral_capabilities_event_handler,
7877 			WMI_RX_UMAC_CTX);
7878 	if (ret)
7879 		spectral_debug("event handler not supported, ret=%d", ret);
7880 
7881 	return QDF_STATUS_SUCCESS;
7882 }
7883 
7884 static QDF_STATUS
7885 target_if_spectral_unregister_events(struct wlan_objmgr_psoc *psoc)
7886 {
7887 	int ret;
7888 
7889 	if (!psoc) {
7890 		spectral_err("psoc is null");
7891 		return QDF_STATUS_E_INVAL;
7892 	}
7893 
7894 	target_if_spectral_wmi_unified_unregister_event_handler(
7895 			psoc, wmi_spectral_capabilities_eventid);
7896 
7897 	ret = target_if_spectral_wmi_unified_unregister_event_handler(
7898 			psoc, wmi_pdev_sscan_fw_param_eventid);
7899 
7900 	if (ret)
7901 		spectral_debug("Unregister WMI event handler failed, ret = %d",
7902 			       ret);
7903 
7904 	return QDF_STATUS_SUCCESS;
7905 }
7906 
7907 void
7908 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
7909 {
7910 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
7911 	    target_if_pdev_spectral_init;
7912 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
7913 	    target_if_pdev_spectral_deinit;
7914 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_init =
7915 	    target_if_psoc_spectral_init;
7916 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_deinit =
7917 	    target_if_psoc_spectral_deinit;
7918 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
7919 	    target_if_set_spectral_config;
7920 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
7921 	    target_if_get_spectral_config;
7922 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
7923 	    target_if_start_spectral_scan;
7924 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
7925 	    target_if_stop_spectral_scan;
7926 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
7927 	    target_if_is_spectral_active;
7928 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
7929 	    target_if_is_spectral_enabled;
7930 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
7931 	    target_if_set_debug_level;
7932 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
7933 	    target_if_get_debug_level;
7934 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
7935 	    target_if_get_spectral_capinfo;
7936 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
7937 	    target_if_get_spectral_diagstats;
7938 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_wmi_ops =
7939 	    target_if_register_spectral_wmi_ops;
7940 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_tgt_ops =
7941 	    target_if_register_spectral_tgt_ops;
7942 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
7943 	    target_if_register_netlink_cb;
7944 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
7945 	    target_if_use_nl_bcast;
7946 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
7947 	    target_if_deregister_netlink_cb;
7948 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
7949 	    target_if_process_spectral_report;
7950 	tx_ops->sptrl_tx_ops.sptrlto_direct_dma_support =
7951 		target_if_spectral_direct_dma_support;
7952 	tx_ops->sptrl_tx_ops.sptrlto_register_events =
7953 		target_if_spectral_register_events;
7954 	tx_ops->sptrl_tx_ops.sptrlto_unregister_events =
7955 		target_if_spectral_unregister_events;
7956 	tx_ops->sptrl_tx_ops.sptrlto_init_pdev_feature_caps =
7957 		target_if_spectral_init_pdev_feature_caps;
7958 
7959 	target_if_sptrl_debug_register_tx_ops(tx_ops);
7960 }
7961 qdf_export_symbol(target_if_sptrl_register_tx_ops);
7962 
7963 void
7964 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
7965 				       uint16_t cw_int, uint32_t dcs_enabled)
7966 {
7967 	struct spectral_samp_msg *msg = NULL;
7968 	struct target_if_spectral_ops *p_sops = NULL;
7969 	struct target_if_spectral *spectral = NULL;
7970 
7971 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
7972 
7973 	if (!spectral) {
7974 		spectral_err("SPECTRAL : Module doesn't exist");
7975 		return;
7976 	}
7977 
7978 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
7979 	if (!p_sops) {
7980 		spectral_err("p_sops is null");
7981 		return;
7982 	}
7983 
7984 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_sbuff(
7985 			spectral->pdev_obj,
7986 			SPECTRAL_MSG_INTERFERENCE_NOTIFICATION,
7987 			SPECTRAL_MSG_BUF_NEW);
7988 
7989 	if (msg) {
7990 		msg->int_type = cw_int ?
7991 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
7992 		msg->dcs_enabled = dcs_enabled;
7993 		msg->signature = SPECTRAL_SIGNATURE;
7994 		p_sops->get_mac_address(spectral, msg->macaddr);
7995 		if (spectral->send_phy_data
7996 				(pdev,
7997 				 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION) == 0)
7998 			spectral->spectral_sent_msg++;
7999 	}
8000 }
8001 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
8002 
8003 QDF_STATUS
8004 target_if_spectral_is_finite_scan(struct target_if_spectral *spectral,
8005 				  enum spectral_scan_mode smode,
8006 				  bool *finite_spectral_scan)
8007 {
8008 	struct target_if_finite_spectral_scan_params *finite_scan;
8009 
8010 	if (!spectral) {
8011 		spectral_err_rl("target if spectral object is null");
8012 		return QDF_STATUS_E_INVAL;
8013 	}
8014 
8015 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
8016 		spectral_err_rl("invalid spectral mode %d", smode);
8017 		return QDF_STATUS_E_INVAL;
8018 	}
8019 
8020 	if (!finite_spectral_scan) {
8021 		spectral_err_rl("Invalid pointer");
8022 		return QDF_STATUS_E_INVAL;
8023 	}
8024 
8025 	finite_scan = &spectral->finite_scan[smode];
8026 	*finite_spectral_scan = finite_scan->finite_spectral_scan;
8027 
8028 	return QDF_STATUS_SUCCESS;
8029 }
8030 
8031 QDF_STATUS
8032 target_if_spectral_finite_scan_update(struct target_if_spectral *spectral,
8033 				      enum spectral_scan_mode smode)
8034 {
8035 	struct target_if_finite_spectral_scan_params *finite_scan;
8036 
8037 	if (!spectral) {
8038 		spectral_err_rl("target if spectral object is null");
8039 		return QDF_STATUS_E_INVAL;
8040 	}
8041 
8042 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
8043 		spectral_err_rl("Invalid Spectral mode");
8044 		return QDF_STATUS_E_INVAL;
8045 	}
8046 
8047 	finite_scan = &spectral->finite_scan[smode];
8048 
8049 	if (!finite_scan->num_reports_expected) {
8050 		spectral_err_rl("Error, No reports expected");
8051 		return QDF_STATUS_E_FAILURE;
8052 	}
8053 
8054 	finite_scan->num_reports_expected--;
8055 	if (!finite_scan->num_reports_expected) {
8056 		QDF_STATUS status;
8057 		enum spectral_cp_error_code err;
8058 
8059 		/* received expected number of reports from target, stop scan */
8060 		status = target_if_stop_spectral_scan(spectral->pdev_obj, smode,
8061 						      &err);
8062 		if (QDF_IS_STATUS_ERROR(status)) {
8063 			spectral_err_rl("Failed to stop finite Spectral scan");
8064 			return QDF_STATUS_E_FAILURE;
8065 		}
8066 		finite_scan->finite_spectral_scan =  false;
8067 	}
8068 
8069 	return QDF_STATUS_SUCCESS;
8070 }
8071