xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision 70a19e16789e308182f63b15c75decec7bf0b342)
1 /*
2  * Copyright (c) 2011,2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 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 if (target_type == TARGET_TYPE_QCA5332) {
3261 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
3262 						SPECTRAL_SCAN_MODE_INVALID;
3263 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
3264 						SPECTRAL_SCAN_MODE_INVALID;
3265 	} else {
3266 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
3267 						SPECTRAL_SCAN_MODE_NORMAL;
3268 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
3269 						SPECTRAL_SCAN_MODE_AGILE;
3270 	}
3271 }
3272 
3273 /**
3274  * target_if_spectral_timestamp_war_init() - Initialize Spectral timestamp WAR
3275  * related info
3276  * @twar: Pointer to Spectral timstamp WAR related info
3277  *
3278  * Function to Initialize parameters related to Spectral timestamp WAR
3279  *
3280  * Return: void
3281  */
3282 static void
3283 target_if_spectral_timestamp_war_init(struct spectral_timestamp_war *twar)
3284 {
3285 	enum spectral_scan_mode smode;
3286 
3287 	smode = SPECTRAL_SCAN_MODE_NORMAL;
3288 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
3289 		twar->last_fft_timestamp[smode] = 0;
3290 		twar->timestamp_war_offset[smode] = 0;
3291 	}
3292 	twar->target_reset_count = 0;
3293 }
3294 
3295 #ifdef OPTIMIZED_SAMP_MESSAGE
3296 /**
3297  * target_if_spectral_is_hw_mode_sbs() - Check if the given pdev is in SBS mode
3298  * @pdev: pdev pointer
3299  * @is_hw_mode_sbs: Pointer to the variable where this function should write
3300  * whether the given pdev is in SBS mode
3301  *
3302  * Return: QDF_STATUS of operation
3303  */
3304 static QDF_STATUS
3305 target_if_spectral_is_hw_mode_sbs(struct wlan_objmgr_pdev *pdev,
3306 				  bool *is_hw_mode_sbs)
3307 {
3308 	struct wlan_objmgr_psoc *psoc;
3309 	struct target_psoc_info *tgt_hdl;
3310 	enum wmi_host_hw_mode_config_type mode;
3311 
3312 	qdf_assert_always(is_hw_mode_sbs);
3313 
3314 	psoc = wlan_pdev_get_psoc(pdev);
3315 	if (!psoc) {
3316 		spectral_err("psoc is null");
3317 		return QDF_STATUS_E_NULL_VALUE;
3318 	}
3319 
3320 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
3321 	if (!tgt_hdl) {
3322 		spectral_err("target_psoc_info is null");
3323 		return QDF_STATUS_E_NULL_VALUE;
3324 	}
3325 
3326 	mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
3327 	switch (mode) {
3328 	case WMI_HOST_HW_MODE_SBS_PASSIVE:
3329 	case WMI_HOST_HW_MODE_SBS:
3330 	case WMI_HOST_HW_MODE_DBS_SBS:
3331 	case WMI_HOST_HW_MODE_DBS_OR_SBS:
3332 		*is_hw_mode_sbs = true;
3333 		break;
3334 	default:
3335 		*is_hw_mode_sbs = false;
3336 		break;
3337 	}
3338 
3339 	return QDF_STATUS_SUCCESS;
3340 }
3341 
3342 /**
3343  * target_if_get_pdev_mac_phy_caps() - Get the MAC_PHY capabilities of a pdev
3344  * @pdev: pdev pointer
3345  *
3346  * Return: On success, pointer to  MAC_PHY capabilities of @pdev.
3347  * On failure, NULL
3348  */
3349 static struct wlan_psoc_host_mac_phy_caps *
3350 target_if_get_pdev_mac_phy_caps(struct wlan_objmgr_pdev *pdev)
3351 {
3352 	struct wlan_objmgr_psoc *psoc;
3353 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr;
3354 	struct target_psoc_info *tgt_psoc_info;
3355 	uint8_t pdev_id;
3356 
3357 	if (!pdev) {
3358 		spectral_err("pdev is NULL");
3359 		return NULL;
3360 	}
3361 
3362 	psoc = wlan_pdev_get_psoc(pdev);
3363 	if (!psoc) {
3364 		spectral_err("psoc is null");
3365 		return NULL;
3366 	}
3367 
3368 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
3369 	if (!tgt_psoc_info) {
3370 		spectral_err("target_psoc_info is null");
3371 		return NULL;
3372 	}
3373 
3374 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
3375 	if (!mac_phy_cap_arr) {
3376 		spectral_err("mac phy cap array is null");
3377 		return NULL;
3378 	}
3379 
3380 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
3381 	return &mac_phy_cap_arr[pdev_id];
3382 }
3383 
3384 /**
3385  * struct target_if_sscan_pdev_phy_info - PHY information of the pdev on
3386  * which sscan is done. A pointer to an instance of this structure is passed
3387  * as an argument to the iterator function target_if_find_sscan_pdev_phya1()
3388  * @phy_id: PHY ID of this pdev
3389  * @is_using_phya1: Pointer to the variable where the iterator function should
3390  * populate whether the given pdev is using PHYA1
3391  */
3392 struct target_if_sscan_pdev_phy_info {
3393 	uint8_t phy_id;
3394 	bool *is_using_phya1;
3395 };
3396 
3397 /**
3398  * target_if_find_sscan_pdev_phya1() - This is an iterator function to
3399  * wlan_objmgr_iterate_obj_list(). It checks whether a given sscan_pdev (pdev on
3400  * which sscan is currently issued) is using PHYA1 by comparing against the pdev
3401  * argument given by the wlan_objmgr_iterate_obj_list()
3402  * @psoc: Pointer to psoc
3403  * @object: Pointer to pdev
3404  * @arg: Pointer to target_if_sscan_pdev_phy_info of the sscan_pdev for which
3405  * we want to check if it uses PHYA1
3406  *
3407  * Return: None
3408  */
3409 static void
3410 target_if_find_sscan_pdev_phya1(struct wlan_objmgr_psoc *psoc,
3411 				void *object, void *arg)
3412 {
3413 	struct target_if_sscan_pdev_phy_info *sscan_pdev_phy_info = arg;
3414 	struct wlan_objmgr_pdev *cur_pdev = object;
3415 	struct wlan_psoc_host_mac_phy_caps *cur_mac_phy_caps;
3416 
3417 	cur_mac_phy_caps = target_if_get_pdev_mac_phy_caps(cur_pdev);
3418 	if (!cur_mac_phy_caps) {
3419 		spectral_err("Failed to get MAC PHY Capabilities of"
3420 			     "pdev %pK", cur_pdev);
3421 		return;
3422 	}
3423 
3424 	spectral_debug("supported_bands: %0x phy_id: %d",
3425 		       cur_mac_phy_caps->supported_bands,
3426 		       cur_mac_phy_caps->phy_id);
3427 
3428 	/* No need to do anything if the current pdev is same as sscan_pdev */
3429 	if (sscan_pdev_phy_info->phy_id == cur_mac_phy_caps->phy_id)
3430 		return;
3431 
3432 	/**
3433 	 * Compare the phy_id of both the SBS pdevs to figure out if
3434 	 * the sscan_pdev using PHYA1
3435 	 */
3436 	if (sscan_pdev_phy_info->phy_id > cur_mac_phy_caps->phy_id)
3437 		*sscan_pdev_phy_info->is_using_phya1 = true;
3438 	else
3439 		*sscan_pdev_phy_info->is_using_phya1 = false;
3440 }
3441 
3442 /**
3443  * target_if_spectral_detector_list_init() - Initialize Spectral detector list
3444  * based on target type
3445  * @spectral: Pointer to Spectral target_if
3446  *
3447  * Function to initialize Spectral detector list for possible combinations of
3448  * Spectral scan mode and channel width, based on target type.
3449  *
3450  * Return: Success/Failure
3451  */
3452 static QDF_STATUS
3453 target_if_spectral_detector_list_init(struct target_if_spectral *spectral)
3454 {
3455 	struct sscan_detector_list *det_list;
3456 	enum spectral_scan_mode smode;
3457 	enum phy_ch_width ch_width;
3458 	QDF_STATUS ret;
3459 	bool is_hw_mode_sbs = false, is_using_phya1 = false;
3460 
3461 	if (!spectral) {
3462 		spectral_err_rl("Spectral LMAC object is null");
3463 		return QDF_STATUS_E_NULL_VALUE;
3464 	}
3465 
3466 	/**
3467 	 * Special handling is required for SBS mode where the detector
3468 	 * list should be the following.
3469 	 * For the pdev that use PHYA0:
3470 	 *    detector 0 for normal mode
3471 	 *    detector 2 for agile mode
3472 	 * For the pdev that use PHYA1:
3473 	 *    detector 1 for normal mode
3474 	 *    detector 2 for agile mode
3475 	 *
3476 	 * There is no direct way of knowing which pdevs are using PHYA0 or
3477 	 * PHYA1. We need to look at the phy_id of a given pdev and compare
3478 	 * against other pdevs on the same psoc to figure out whether the given
3479 	 * pdev is operating using PHYA1.
3480 	 */
3481 
3482 	/* First check whether this pdev is in SBS mode */
3483 	ret = target_if_spectral_is_hw_mode_sbs(spectral->pdev_obj,
3484 						&is_hw_mode_sbs);
3485 	if (QDF_IS_STATUS_ERROR(ret)) {
3486 		spectral_err("Failed to check whether hw mode is SBS");
3487 		return ret;
3488 	}
3489 
3490 	if (is_hw_mode_sbs) {
3491 		struct wlan_psoc_host_mac_phy_caps *mac_phy_caps;
3492 		struct target_if_sscan_pdev_phy_info pdev_phy_info;
3493 
3494 		mac_phy_caps =
3495 			target_if_get_pdev_mac_phy_caps(spectral->pdev_obj);
3496 		if (!mac_phy_caps) {
3497 			spectral_err("Failed to get MAC PHY Capabilities of"
3498 				     "pdev %pK", spectral->pdev_obj);
3499 			return QDF_STATUS_E_FAILURE;
3500 		}
3501 
3502 		spectral_debug("bands: %0x phy_id: %d",
3503 			       mac_phy_caps->supported_bands,
3504 			       mac_phy_caps->phy_id);
3505 
3506 		pdev_phy_info.phy_id = mac_phy_caps->phy_id;
3507 		pdev_phy_info.is_using_phya1 = &is_using_phya1;
3508 
3509 		/* Iterate over all pdevs on this psoc */
3510 		wlan_objmgr_iterate_obj_list
3511 			(wlan_pdev_get_psoc(spectral->pdev_obj),
3512 			 WLAN_PDEV_OP,
3513 			 target_if_find_sscan_pdev_phya1,
3514 			 &pdev_phy_info, 0,
3515 			 WLAN_SPECTRAL_ID);
3516 	}
3517 
3518 	/**
3519 	 * We assume there are 2 detectors. The Detector ID coming first will
3520 	 * always be pri80 detector, and second detector for sec80.
3521 	 */
3522 	ch_width = CH_WIDTH_20MHZ;
3523 	for (; ch_width < CH_WIDTH_MAX; ch_width++) {
3524 		/* Normal spectral scan */
3525 		smode = SPECTRAL_SCAN_MODE_NORMAL;
3526 		spectral_debug("is_hw_mode_sbs: %d is_using_phya1:%d",
3527 			       is_hw_mode_sbs, is_using_phya1);
3528 
3529 		qdf_spin_lock_bh(&spectral->detector_list_lock);
3530 
3531 		if (!spectral->supported_sscan_bw_list[smode][ch_width])
3532 			goto agile_handling;
3533 
3534 		det_list = &spectral->detector_list[smode][ch_width];
3535 		det_list->num_detectors = 1;
3536 
3537 		if (is_hw_mode_sbs && is_using_phya1)
3538 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_1;
3539 		else
3540 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_0;
3541 
3542 		if (is_ch_width_160_or_80p80(ch_width) &&
3543 		    spectral->rparams.fragmentation_160[smode]) {
3544 			det_list->num_detectors += 1;
3545 			det_list->detectors[1] = SPECTRAL_DETECTOR_ID_1;
3546 		}
3547 
3548 agile_handling:
3549 		/* Agile spectral scan */
3550 		smode = SPECTRAL_SCAN_MODE_AGILE;
3551 		if (!spectral->supported_sscan_bw_list[smode][ch_width]) {
3552 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
3553 			continue;
3554 		}
3555 
3556 		det_list = &spectral->detector_list[smode][ch_width];
3557 		det_list->num_detectors = 1;
3558 
3559 		if (spectral->rparams.fragmentation_160[smode])
3560 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_2;
3561 		else
3562 			det_list->detectors[0] = SPECTRAL_DETECTOR_ID_1;
3563 
3564 		qdf_spin_unlock_bh(&spectral->detector_list_lock);
3565 	}
3566 
3567 	return QDF_STATUS_SUCCESS;
3568 }
3569 #else
3570 
3571 static QDF_STATUS
3572 target_if_spectral_detector_list_init(struct target_if_spectral *spectral)
3573 {
3574 	return QDF_STATUS_SUCCESS;
3575 }
3576 #endif /* OPTIMIZED_SAMP_MESSAGE */
3577 
3578 /**
3579  * target_if_pdev_spectral_init() - Initialize target_if Spectral
3580  * functionality for the given pdev
3581  * @pdev: Pointer to pdev object
3582  *
3583  * Function to initialize pointer to spectral target_if internal private data
3584  *
3585  * Return: On success, pointer to Spectral target_if internal private data, on
3586  * failure, NULL
3587  */
3588 void *
3589 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
3590 {
3591 	struct target_if_spectral_ops *p_sops = NULL;
3592 	struct target_if_spectral *spectral = NULL;
3593 	uint32_t target_type;
3594 	uint32_t target_revision;
3595 	struct wlan_objmgr_psoc *psoc;
3596 	struct wlan_lmac_if_target_tx_ops *tgt_tx_ops;
3597 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
3598 	QDF_STATUS status;
3599 	struct wlan_lmac_if_tx_ops *tx_ops;
3600 
3601 	if (!pdev) {
3602 		spectral_err("SPECTRAL: pdev is NULL!");
3603 		return NULL;
3604 	}
3605 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
3606 			sizeof(struct target_if_spectral));
3607 	if (!spectral)
3608 		return spectral;
3609 
3610 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
3611 	/* Store pdev in Spectral */
3612 	spectral->pdev_obj = pdev;
3613 	spectral->vdev_id[SPECTRAL_SCAN_MODE_NORMAL] = WLAN_INVALID_VDEV_ID;
3614 	spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE] = WLAN_INVALID_VDEV_ID;
3615 
3616 	psoc = wlan_pdev_get_psoc(pdev);
3617 
3618 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
3619 	if (!tx_ops) {
3620 		spectral_err("tx_ops is NULL");
3621 		qdf_mem_free(spectral);
3622 		return NULL;
3623 	}
3624 
3625 	tgt_tx_ops = &tx_ops->target_tx_ops;
3626 
3627 	if (tgt_tx_ops->tgt_get_tgt_type) {
3628 		target_type = tgt_tx_ops->tgt_get_tgt_type(psoc);
3629 	} else {
3630 		qdf_mem_free(spectral);
3631 		return NULL;
3632 	}
3633 
3634 	if (tgt_tx_ops->tgt_get_tgt_revision) {
3635 		target_revision = tgt_tx_ops->tgt_get_tgt_revision(psoc);
3636 	} else {
3637 		qdf_mem_free(spectral);
3638 		return NULL;
3639 	}
3640 
3641 	/* init the function ptr table */
3642 	target_if_spectral_init_dummy_function_table(spectral);
3643 
3644 	/* get spectral function table */
3645 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3646 	/* TODO : Should this be called here of after ath_attach ? */
3647 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
3648 		spectral_info("HAL_CAP_PHYDIAG : Capable");
3649 
3650 	/* TODO: Need to fix the capability check for RADAR */
3651 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
3652 		spectral_info("HAL_CAP_RADAR   : Capable");
3653 
3654 	/* TODO : Need to fix the capability check for SPECTRAL */
3655 	/* TODO : Should this be called here of after ath_attach ? */
3656 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
3657 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
3658 
3659 	qdf_spinlock_create(&spectral->spectral_lock);
3660 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
3661 	target_if_spectral_clear_stats(spectral);
3662 
3663 	if (target_type == TARGET_TYPE_QCA8074 ||
3664 	    target_type == TARGET_TYPE_QCA8074V2 ||
3665 	    target_type == TARGET_TYPE_QCA9574 ||
3666 	    target_type == TARGET_TYPE_QCA5332 ||
3667 	    target_type == TARGET_TYPE_QCA6018 ||
3668 	    target_type == TARGET_TYPE_QCA5018 ||
3669 	    target_type == TARGET_TYPE_QCA6390 ||
3670 	    target_type == TARGET_TYPE_QCN6122 ||
3671 	    target_type == TARGET_TYPE_QCN9160 ||
3672 	    target_type == TARGET_TYPE_QCA6490 ||
3673 	    target_type == TARGET_TYPE_QCN9000 ||
3674 	    target_type == TARGET_TYPE_QCA6750 ||
3675 	    target_type == TARGET_TYPE_QCN9224 ||
3676 	    target_type == TARGET_TYPE_KIWI ||
3677 	    target_type == TARGET_TYPE_MANGO)
3678 		spectral->direct_dma_support = true;
3679 
3680 	target_if_spectral_report_params_init(&spectral->rparams,
3681 					      target_type);
3682 	target_if_spectral_len_adj_swar_init(&spectral->len_adj_swar,
3683 					     &spectral->rparams,
3684 					     target_type);
3685 
3686 	if ((target_type == TARGET_TYPE_QCA8074) ||
3687 	    (target_type == TARGET_TYPE_QCA8074V2) ||
3688 	    (target_type == TARGET_TYPE_QCA9574) ||
3689 	    (target_type == TARGET_TYPE_QCA6018) ||
3690 	    (target_type == TARGET_TYPE_QCA5018) ||
3691 	    (target_type == TARGET_TYPE_QCA5332) ||
3692 	    (target_type == TARGET_TYPE_QCN6122) ||
3693 	    (target_type == TARGET_TYPE_QCN9160) ||
3694 	    (target_type == TARGET_TYPE_QCN9000) ||
3695 	    (target_type == TARGET_TYPE_QCA6290) ||
3696 	    (target_type == TARGET_TYPE_QCA6390) ||
3697 	    (target_type == TARGET_TYPE_QCA6490) ||
3698 	    (target_type == TARGET_TYPE_QCN9224) ||
3699 	    (target_type == TARGET_TYPE_QCA6750) ||
3700 	    (target_type == TARGET_TYPE_KIWI) ||
3701 	    (target_type == TARGET_TYPE_MANGO)) {
3702 		spectral->spectral_gen = SPECTRAL_GEN3;
3703 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
3704 		spectral->tag_sscan_summary_exp =
3705 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
3706 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
3707 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
3708 	} else {
3709 		spectral->spectral_gen = SPECTRAL_GEN2;
3710 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
3711 		spectral->tag_sscan_summary_exp =
3712 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
3713 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
3714 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
3715 	}
3716 
3717 	status = target_if_init_spectral_param_min_max(
3718 					spectral,
3719 					spectral->spectral_gen, target_type);
3720 	if (QDF_IS_STATUS_ERROR(status)) {
3721 		spectral_err("Failed to initialize parameter min max values");
3722 		goto fail;
3723 	}
3724 
3725 	target_if_init_spectral_param_properties(spectral);
3726 	/* Init spectral capability */
3727 	if (target_if_init_spectral_capability(spectral, target_type) !=
3728 					QDF_STATUS_SUCCESS) {
3729 		qdf_mem_free(spectral);
3730 		return NULL;
3731 	}
3732 	if (target_if_spectral_attach_simulation(spectral) < 0)
3733 		return NULL;
3734 
3735 	target_if_init_spectral_ops(spectral);
3736 	target_if_spectral_timestamp_war_init(&spectral->timestamp_war);
3737 
3738 	/* Spectral mode specific init */
3739 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
3740 		spectral->params_valid[smode] = false;
3741 		qdf_spinlock_create(&spectral->param_info[smode].osps_lock);
3742 		spectral->param_info[smode].osps_cache.osc_is_valid = 0;
3743 	}
3744 
3745 	target_if_spectral_register_funcs(spectral, &spectral_ops);
3746 
3747 	if (target_if_spectral_check_hw_capability(spectral) == false) {
3748 		goto fail;
3749 	} else {
3750 		/*
3751 		 * TODO: Once the driver architecture transitions to chipset
3752 		 * versioning based checks, reflect this here.
3753 		 */
3754 		spectral->is_160_format = false;
3755 		spectral->is_lb_edge_extrabins_format = false;
3756 		spectral->is_rb_edge_extrabins_format = false;
3757 
3758 		if (target_type == TARGET_TYPE_QCA9984 ||
3759 		    target_type == TARGET_TYPE_QCA9888) {
3760 			spectral->is_160_format = true;
3761 			spectral->is_lb_edge_extrabins_format = true;
3762 			spectral->is_rb_edge_extrabins_format = true;
3763 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
3764 			    (target_revision == AR900B_REV_2)) {
3765 			spectral->is_rb_edge_extrabins_format = true;
3766 		}
3767 
3768 		if (target_type == TARGET_TYPE_QCA9984 ||
3769 		    target_type == TARGET_TYPE_QCA9888)
3770 			spectral->is_sec80_rssi_war_required = true;
3771 
3772 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
3773 
3774 		if (spectral->spectral_gen == SPECTRAL_GEN3)
3775 			init_160mhz_delivery_state_machine(spectral);
3776 	}
3777 
3778 	qdf_spinlock_create(&spectral->detector_list_lock);
3779 	qdf_spinlock_create(&spectral->session_report_info_lock);
3780 	qdf_spinlock_create(&spectral->session_det_map_lock);
3781 
3782 	return spectral;
3783 
3784 fail:
3785 	target_if_spectral_detach(spectral);
3786 	return NULL;
3787 }
3788 
3789 /**
3790  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
3791  * functionality for the given pdev
3792  * @pdev: Pointer to pdev object
3793  *
3794  * Function to de-initialize pointer to spectral target_if internal private data
3795  *
3796  * Return: None
3797  */
3798 void
3799 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
3800 {
3801 	struct target_if_spectral *spectral = NULL;
3802 
3803 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3804 	if (!spectral) {
3805 		spectral_err("SPECTRAL : Module doesn't exist");
3806 		return;
3807 	}
3808 	target_if_spectral_detach(spectral);
3809 
3810 	return;
3811 }
3812 
3813 /**
3814  * target_if_psoc_spectral_deinit() - De-initialize target_if Spectral
3815  * functionality for the given psoc
3816  * @psoc: Pointer to psoc object
3817  *
3818  * Function to de-initialize pointer to psoc spectral target_if internal
3819  * private data
3820  *
3821  * Return: None
3822  */
3823 static void
3824 target_if_psoc_spectral_deinit(struct wlan_objmgr_psoc *psoc)
3825 {
3826 	struct target_if_psoc_spectral *psoc_spectral;
3827 
3828 	if (!psoc) {
3829 		spectral_err("psoc is null");
3830 		return;
3831 	}
3832 
3833 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
3834 	if (!psoc_spectral) {
3835 		spectral_err("Spectral target_if psoc object is null");
3836 		return;
3837 	}
3838 
3839 	qdf_mem_free(psoc_spectral);
3840 }
3841 
3842 /**
3843  * target_if_psoc_spectral_init() - Initialize target_if Spectral
3844  * functionality for the given psoc
3845  * @psoc: Pointer to psoc object
3846  *
3847  * Function to initialize pointer to psoc spectral target_if internal
3848  * private data
3849  *
3850  * Return: On success, pointer to Spectral psoc target_if internal
3851  * private data, on failure, NULL
3852  */
3853 static void *
3854 target_if_psoc_spectral_init(struct wlan_objmgr_psoc *psoc)
3855 {
3856 	struct target_if_psoc_spectral *psoc_spectral = NULL;
3857 
3858 	if (!psoc) {
3859 		spectral_err("psoc is null");
3860 		goto fail;
3861 	}
3862 
3863 	psoc_spectral = (struct target_if_psoc_spectral *)qdf_mem_malloc(
3864 			sizeof(struct target_if_psoc_spectral));
3865 	if (!psoc_spectral) {
3866 		spectral_err("Spectral lmac psoc object allocation failed");
3867 		goto fail;
3868 	}
3869 
3870 	psoc_spectral->psoc_obj = psoc;
3871 
3872 	return psoc_spectral;
3873 
3874 fail:
3875 	if (psoc_spectral)
3876 		target_if_psoc_spectral_deinit(psoc);
3877 
3878 	return psoc_spectral;
3879 }
3880 
3881 /**
3882  * target_if_calculate_center_freq() - Helper routine to
3883  * check whether given frequency is center frequency of a
3884  * WLAN channel
3885  *
3886  * @spectral: Pointer to Spectral object
3887  * @chan_freq: Center frequency of a WLAN channel
3888  * @is_valid: Indicates whether given frequency is valid
3889  *
3890  * Return: QDF_STATUS
3891  */
3892 static QDF_STATUS
3893 target_if_is_center_freq_of_any_chan(struct wlan_objmgr_pdev *pdev,
3894 				     uint32_t chan_freq,
3895 				     bool *is_valid)
3896 {
3897 	struct regulatory_channel *cur_chan_list;
3898 	int i;
3899 
3900 	if (!pdev) {
3901 		spectral_err("pdev object is null");
3902 		return QDF_STATUS_E_FAILURE;
3903 	}
3904 
3905 	if (!is_valid) {
3906 		spectral_err("is valid argument is null");
3907 		return QDF_STATUS_E_FAILURE;
3908 	}
3909 
3910 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
3911 	if (!cur_chan_list)
3912 		return QDF_STATUS_E_FAILURE;
3913 
3914 	if (wlan_reg_get_current_chan_list(
3915 			pdev, cur_chan_list) != QDF_STATUS_SUCCESS) {
3916 		spectral_err("Failed to get cur_chan list");
3917 		qdf_mem_free(cur_chan_list);
3918 		return QDF_STATUS_E_FAILURE;
3919 	}
3920 
3921 	*is_valid = false;
3922 	for (i = 0; i < NUM_CHANNELS; i++) {
3923 		uint32_t flags;
3924 		uint32_t center_freq;
3925 
3926 		flags = cur_chan_list[i].chan_flags;
3927 		center_freq = cur_chan_list[i].center_freq;
3928 
3929 		if (!(flags & REGULATORY_CHAN_DISABLED) &&
3930 		    (center_freq == chan_freq)) {
3931 			*is_valid = true;
3932 			break;
3933 		}
3934 	}
3935 
3936 	qdf_mem_free(cur_chan_list);
3937 
3938 	return QDF_STATUS_SUCCESS;
3939 }
3940 
3941 /**
3942  * target_if_calculate_center_freq() - Helper routine to
3943  * find the center frequency of the agile span from a
3944  * WLAN channel center frequency
3945  *
3946  * @spectral: Pointer to Spectral object
3947  * @ch_width: Channel width array
3948  * @chan_freq: Center frequency of a WLAN channel
3949  * @center_freq: Pointer to center frequency
3950  *
3951  * Return: QDF_STATUS
3952  */
3953 static QDF_STATUS
3954 target_if_calculate_center_freq(struct target_if_spectral *spectral,
3955 				enum phy_ch_width *ch_width,
3956 				uint16_t chan_freq,
3957 				uint16_t *center_freq)
3958 {
3959 	enum phy_ch_width agile_ch_width;
3960 
3961 	if (!spectral) {
3962 		spectral_err("spectral target if object is null");
3963 		return QDF_STATUS_E_FAILURE;
3964 	}
3965 
3966 	if (!ch_width) {
3967 		spectral_err("Channel width array is null");
3968 		return QDF_STATUS_E_INVAL;
3969 	}
3970 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
3971 
3972 	if (!center_freq) {
3973 		spectral_err("center_freq argument is null");
3974 		return QDF_STATUS_E_FAILURE;
3975 	}
3976 
3977 	if (agile_ch_width == CH_WIDTH_20MHZ) {
3978 		*center_freq = chan_freq;
3979 	} else {
3980 		uint16_t start_freq;
3981 		uint16_t end_freq;
3982 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
3983 		enum channel_state state;
3984 
3985 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
3986 			(spectral->pdev_obj, chan_freq, agile_ch_width,
3987 			 &bonded_chan_ptr, REG_CURRENT_PWR_MODE,
3988 			 NO_SCHANS_PUNC);
3989 		if (state == CHANNEL_STATE_DISABLE ||
3990 		    state == CHANNEL_STATE_INVALID) {
3991 			spectral_err("Channel state is disable or invalid");
3992 			return QDF_STATUS_E_FAILURE;
3993 		}
3994 		if (!bonded_chan_ptr) {
3995 			spectral_err("Bonded channel is not found");
3996 			return QDF_STATUS_E_FAILURE;
3997 		}
3998 		start_freq = bonded_chan_ptr->start_freq;
3999 		end_freq = bonded_chan_ptr->end_freq;
4000 		*center_freq = (start_freq + end_freq) >> 1;
4001 	}
4002 
4003 	return QDF_STATUS_SUCCESS;
4004 }
4005 
4006 /**
4007  * target_if_validate_center_freq() - Helper routine to
4008  * validate user provided agile center frequency
4009  *
4010  * @spectral: Pointer to Spectral object
4011  * @ch_width: Channel width array
4012  * @center_freq: User provided agile span center frequency
4013  * @is_valid: Indicates whether agile span center frequency is valid
4014  *
4015  * Return: QDF_STATUS
4016  */
4017 static QDF_STATUS
4018 target_if_validate_center_freq(struct target_if_spectral *spectral,
4019 			       enum phy_ch_width *ch_width,
4020 			       uint16_t center_freq,
4021 			       bool *is_valid)
4022 {
4023 	enum phy_ch_width agile_ch_width;
4024 	struct wlan_objmgr_pdev *pdev;
4025 	QDF_STATUS status;
4026 
4027 	if (!spectral) {
4028 		spectral_err("spectral target if object is null");
4029 		return QDF_STATUS_E_FAILURE;
4030 	}
4031 
4032 	if (!ch_width) {
4033 		spectral_err("channel width array is null");
4034 		return QDF_STATUS_E_INVAL;
4035 	}
4036 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
4037 
4038 	if (!is_valid) {
4039 		spectral_err("is_valid argument is null");
4040 		return QDF_STATUS_E_FAILURE;
4041 	}
4042 
4043 	pdev = spectral->pdev_obj;
4044 
4045 	if (agile_ch_width == CH_WIDTH_20MHZ) {
4046 		status = target_if_is_center_freq_of_any_chan
4047 				(pdev, center_freq, is_valid);
4048 		if (QDF_IS_STATUS_ERROR(status))
4049 			return QDF_STATUS_E_FAILURE;
4050 	} else {
4051 		uint16_t start_freq;
4052 		uint16_t end_freq;
4053 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
4054 		bool is_chan;
4055 
4056 		status = target_if_is_center_freq_of_any_chan
4057 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
4058 				 &is_chan);
4059 		if (QDF_IS_STATUS_ERROR(status))
4060 			return QDF_STATUS_E_FAILURE;
4061 
4062 		if (is_chan) {
4063 			uint32_t calulated_center_freq;
4064 			enum channel_state st;
4065 
4066 			st =
4067 			    wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
4068 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
4069 				 agile_ch_width,
4070 				 &bonded_chan_ptr,
4071 				 REG_CURRENT_PWR_MODE,
4072 				 NO_SCHANS_PUNC);
4073 			if (st == CHANNEL_STATE_DISABLE ||
4074 			    st == CHANNEL_STATE_INVALID) {
4075 				spectral_err("Channel state disable/invalid");
4076 				return QDF_STATUS_E_FAILURE;
4077 			}
4078 			if (!bonded_chan_ptr) {
4079 				spectral_err("Bonded channel is not found");
4080 				return QDF_STATUS_E_FAILURE;
4081 			}
4082 			start_freq = bonded_chan_ptr->start_freq;
4083 			end_freq = bonded_chan_ptr->end_freq;
4084 			calulated_center_freq = (start_freq + end_freq) >> 1;
4085 			*is_valid = (center_freq == calulated_center_freq);
4086 		} else {
4087 			*is_valid = false;
4088 		}
4089 	}
4090 
4091 	return QDF_STATUS_SUCCESS;
4092 }
4093 
4094 /**
4095  * target_if_is_agile_span_overlap_with_operating_span() - Helper routine to
4096  * check whether agile span overlaps with current operating band.
4097  *
4098  * @spectral: Pointer to Spectral object
4099  * @ch_width: Channel width array
4100  * @center_freq: Agile span center frequency
4101  * @is_overlapping: Indicates whether Agile span overlaps with operating span
4102  *
4103  * Helper routine to check whether agile span overlaps with current
4104  * operating band.
4105  *
4106  * Return: QDF_STATUS
4107  */
4108 static QDF_STATUS
4109 target_if_is_agile_span_overlap_with_operating_span
4110 			(struct target_if_spectral *spectral,
4111 			 enum phy_ch_width *ch_width,
4112 			 struct spectral_config_frequency *center_freq,
4113 			 bool *is_overlapping)
4114 {
4115 	enum phy_ch_width op_ch_width;
4116 	enum phy_ch_width agile_ch_width;
4117 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
4118 	struct wlan_objmgr_vdev *vdev;
4119 	struct wlan_objmgr_pdev *pdev;
4120 	int16_t chan_freq;
4121 	uint32_t op_start_freq;
4122 	uint32_t op_end_freq;
4123 	uint32_t agile_start_freq;
4124 	uint32_t agile_end_freq;
4125 	uint32_t cfreq2;
4126 
4127 	if (!spectral) {
4128 		spectral_err("Spectral object is NULL");
4129 		return QDF_STATUS_E_FAILURE;
4130 	}
4131 
4132 	pdev  = spectral->pdev_obj;
4133 	if (!pdev) {
4134 		spectral_err("pdev object is NULL");
4135 		return QDF_STATUS_E_FAILURE;
4136 	}
4137 
4138 	if (!ch_width) {
4139 		spectral_err("channel width array is null");
4140 		return QDF_STATUS_E_FAILURE;
4141 	}
4142 	op_ch_width = ch_width[SPECTRAL_SCAN_MODE_NORMAL];
4143 	if (op_ch_width == CH_WIDTH_INVALID) {
4144 		spectral_err("Invalid channel width");
4145 		return QDF_STATUS_E_INVAL;
4146 	}
4147 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
4148 	if (agile_ch_width == CH_WIDTH_INVALID) {
4149 		spectral_err("Invalid channel width");
4150 		return QDF_STATUS_E_INVAL;
4151 	}
4152 
4153 	if (!is_overlapping) {
4154 		spectral_err("Argument(is_overlapping) is NULL");
4155 		return QDF_STATUS_E_FAILURE;
4156 	}
4157 	*is_overlapping = false;
4158 
4159 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
4160 	if (!vdev) {
4161 		spectral_err("vdev is NULL");
4162 		return QDF_STATUS_E_FAILURE;
4163 	}
4164 	chan_freq = target_if_vdev_get_chan_freq(vdev);
4165 	cfreq2 = target_if_vdev_get_chan_freq_seg2(vdev);
4166 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4167 	if (cfreq2 < 0) {
4168 		spectral_err("cfreq2 is invalid");
4169 		return QDF_STATUS_E_FAILURE;
4170 	}
4171 
4172 	if (op_ch_width == CH_WIDTH_20MHZ) {
4173 		op_start_freq = chan_freq - FREQ_OFFSET_10MHZ;
4174 		op_end_freq = chan_freq + FREQ_OFFSET_10MHZ;
4175 	} else {
4176 		enum channel_state state;
4177 
4178 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
4179 			(pdev, chan_freq, op_ch_width, &bonded_chan_ptr,
4180 			 REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC);
4181 		if (state == CHANNEL_STATE_DISABLE ||
4182 		    state == CHANNEL_STATE_INVALID) {
4183 			spectral_err("Channel state is disable or invalid");
4184 			return QDF_STATUS_E_FAILURE;
4185 		}
4186 		if (!bonded_chan_ptr) {
4187 			spectral_err("Bonded channel is not found");
4188 			return QDF_STATUS_E_FAILURE;
4189 		}
4190 		op_start_freq = bonded_chan_ptr->start_freq - FREQ_OFFSET_10MHZ;
4191 		op_end_freq = bonded_chan_ptr->end_freq - FREQ_OFFSET_10MHZ;
4192 	}
4193 
4194 	if (agile_ch_width == CH_WIDTH_80P80MHZ) {
4195 		agile_start_freq = center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
4196 		agile_end_freq = center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
4197 		if (agile_end_freq > op_start_freq &&
4198 		    op_end_freq > agile_start_freq)
4199 			*is_overlapping = true;
4200 
4201 		agile_start_freq = center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
4202 		agile_end_freq = center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
4203 		if (agile_end_freq > op_start_freq &&
4204 		    op_end_freq > agile_start_freq)
4205 			*is_overlapping = true;
4206 	} else {
4207 		agile_start_freq = center_freq->cfreq1 -
4208 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4209 		agile_end_freq = center_freq->cfreq1 +
4210 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4211 		if (agile_end_freq > op_start_freq &&
4212 		    op_end_freq > agile_start_freq)
4213 			*is_overlapping = true;
4214 	}
4215 
4216 	if (op_ch_width == CH_WIDTH_80P80MHZ) {
4217 		uint32_t sec80_start_feq;
4218 		uint32_t sec80_end_freq;
4219 
4220 		sec80_start_feq = cfreq2 - FREQ_OFFSET_40MHZ;
4221 		sec80_end_freq = cfreq2 + FREQ_OFFSET_40MHZ;
4222 
4223 		if (agile_ch_width == CH_WIDTH_80P80MHZ) {
4224 			agile_start_freq =
4225 					center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
4226 			agile_end_freq =
4227 					center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
4228 			if (agile_end_freq > sec80_start_feq &&
4229 			    sec80_end_freq > agile_start_freq)
4230 				*is_overlapping = true;
4231 
4232 			agile_start_freq =
4233 					center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
4234 			agile_end_freq =
4235 					center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
4236 			if (agile_end_freq > sec80_start_feq &&
4237 			    sec80_end_freq > agile_start_freq)
4238 				*is_overlapping = true;
4239 		} else {
4240 			agile_start_freq = center_freq->cfreq1 -
4241 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4242 			agile_end_freq = center_freq->cfreq1 +
4243 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
4244 			if (agile_end_freq > sec80_start_feq &&
4245 			    sec80_end_freq > agile_start_freq)
4246 				*is_overlapping = true;
4247 		}
4248 	}
4249 
4250 	return QDF_STATUS_SUCCESS;
4251 }
4252 
4253 /**
4254  * target_if_spectral_populate_chwidth() - Helper routine to
4255  * populate channel width for different Spectral modes
4256  *
4257  * @spectral: Pointer to Spectral object
4258  * @ch_width: Channel width array
4259  * @is_80_80_agile: Indicates whether 80+80 agile scan is requested
4260  *
4261  * Helper routine to populate channel width for different Spectral modes
4262  *
4263  * Return: QDF_STATUS
4264  */
4265 static QDF_STATUS
4266 target_if_spectral_populate_chwidth(struct target_if_spectral *spectral,
4267 				    enum phy_ch_width *ch_width,
4268 				    bool is_80_80_agile)
4269 {
4270 	enum spectral_scan_mode smode;
4271 
4272 	qdf_assert_always(spectral);
4273 
4274 	smode = SPECTRAL_SCAN_MODE_NORMAL;
4275 	for (; smode < SPECTRAL_SCAN_MODE_MAX; ++smode) {
4276 		/* If user has configured sscan bandwidth, use it */
4277 		if (spectral->sscan_width_configured[smode]) {
4278 			ch_width[smode] = spectral->params[smode].ss_bandwidth;
4279 		} else {
4280 			/* Otherwise, derive the default sscan bandwidth */
4281 			ch_width[smode] = get_default_sscan_bw(spectral, smode,
4282 							       is_80_80_agile);
4283 			if (ch_width[smode] >= CH_WIDTH_INVALID) {
4284 				spectral_err("Invalid sscan BW %u",
4285 					     ch_width[smode]);
4286 				return QDF_STATUS_E_FAILURE;
4287 			}
4288 			spectral->params[smode].ss_bandwidth = ch_width[smode];
4289 		}
4290 	}
4291 
4292 	return QDF_STATUS_SUCCESS;
4293 }
4294 
4295 /**
4296  * target_if_spectral_is_valid_80p80_freq() - API to check whether given
4297  * (cfreq1, cfreq2) pair forms a valid 80+80 combination
4298  * @pdev: pointer to pdev
4299  * @cfreq1: center frequency 1
4300  * @cfreq2: center frequency 2
4301  *
4302  * API to check whether given (cfreq1, cfreq2) pair forms a valid 80+80
4303  * combination
4304  *
4305  * Return: true or false
4306  */
4307 static bool
4308 target_if_spectral_is_valid_80p80_freq(struct wlan_objmgr_pdev *pdev,
4309 				       uint32_t cfreq1, uint32_t cfreq2)
4310 {
4311 	struct ch_params ch_params = {0};
4312 	enum channel_state chan_state1;
4313 	enum channel_state chan_state2;
4314 	struct wlan_objmgr_psoc *psoc;
4315 	struct ch_params temp_params = {0};
4316 
4317 	qdf_assert_always(pdev);
4318 	psoc = wlan_pdev_get_psoc(pdev);
4319 	qdf_assert_always(psoc);
4320 
4321 	/* In restricted 80P80 MHz enabled, only one 80+80 MHz
4322 	 * channel is supported with cfreq=5690 and cfreq=5775.
4323 	 */
4324 	if (wlan_psoc_nif_fw_ext_cap_get(
4325 				psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT))
4326 		return CHAN_WITHIN_RESTRICTED_80P80(cfreq1, cfreq2);
4327 
4328 	ch_params.center_freq_seg1 = wlan_reg_freq_to_chan(pdev, cfreq2);
4329 	ch_params.mhz_freq_seg1 = cfreq2;
4330 	ch_params.ch_width = CH_WIDTH_80P80MHZ;
4331 	wlan_reg_set_channel_params_for_pwrmode(
4332 					pdev,
4333 					cfreq1 - FREQ_OFFSET_10MHZ,
4334 					0,
4335 					&ch_params,
4336 					REG_CURRENT_PWR_MODE);
4337 
4338 	if (ch_params.ch_width != CH_WIDTH_80P80MHZ)
4339 		return false;
4340 
4341 	if (ch_params.mhz_freq_seg0 != cfreq1 ||
4342 	    ch_params.mhz_freq_seg1 != cfreq2)
4343 		return false;
4344 
4345 	temp_params.ch_width = CH_WIDTH_80MHZ;
4346 	chan_state1 = wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
4347 				pdev,
4348 				ch_params.mhz_freq_seg0 - FREQ_OFFSET_10MHZ,
4349 				&temp_params,
4350 				REG_CURRENT_PWR_MODE);
4351 	if ((chan_state1 == CHANNEL_STATE_DISABLE) ||
4352 	    (chan_state1 == CHANNEL_STATE_INVALID))
4353 		return false;
4354 
4355 	temp_params.ch_width = CH_WIDTH_80MHZ;
4356 	chan_state2 = wlan_reg_get_5g_bonded_channel_state_for_pwrmode(
4357 				pdev,
4358 				ch_params.mhz_freq_seg1 - FREQ_OFFSET_10MHZ,
4359 				&temp_params,
4360 				REG_CURRENT_PWR_MODE);
4361 	if ((chan_state2 == CHANNEL_STATE_DISABLE) ||
4362 	    (chan_state2 == CHANNEL_STATE_INVALID))
4363 		return false;
4364 
4365 	if (abs(ch_params.mhz_freq_seg0 - ch_params.mhz_freq_seg1) <=
4366 	    FREQ_OFFSET_80MHZ)
4367 		return false;
4368 
4369 	return true;
4370 }
4371 
4372 /**
4373  * _target_if_set_spectral_config() - Set spectral config
4374  * @spectral:       Pointer to spectral object
4375  * @param: Spectral parameter id and value
4376  * @smode: Spectral scan mode
4377  * @err: Spectral error code
4378  *
4379  * API to set spectral configurations
4380  *
4381  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4382  */
4383 static QDF_STATUS
4384 _target_if_set_spectral_config(struct target_if_spectral *spectral,
4385 			       const struct spectral_cp_param *param,
4386 			       const enum spectral_scan_mode smode,
4387 			       enum spectral_cp_error_code *err)
4388 {
4389 	struct spectral_config params;
4390 	struct target_if_spectral_ops *p_sops;
4391 	struct spectral_config *sparams;
4392 	QDF_STATUS status;
4393 	bool is_overlapping;
4394 	uint16_t agile_cfreq;
4395 	bool is_valid_chan;
4396 	struct spectral_param_min_max *param_min_max;
4397 	enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
4398 	enum spectral_scan_mode m;
4399 	struct spectral_config_frequency center_freq = {0};
4400 	bool is_bw_supported;
4401 	struct wlan_objmgr_vdev *vdev;
4402 	enum phy_ch_width op_bw;
4403 
4404 	if (!err) {
4405 		spectral_err("Error code argument is null");
4406 		QDF_ASSERT(0);
4407 		return QDF_STATUS_E_FAILURE;
4408 	}
4409 	*err = SPECTRAL_SCAN_ERR_INVALID;
4410 
4411 	if (!param) {
4412 		spectral_err("Parameter object is null");
4413 		return QDF_STATUS_E_FAILURE;
4414 	}
4415 
4416 	if (!spectral) {
4417 		spectral_err("spectral object is NULL");
4418 		return QDF_STATUS_E_FAILURE;
4419 	}
4420 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4421 	param_min_max = &spectral->param_min_max;
4422 
4423 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4424 		spectral_err("Invalid Spectral mode %u", smode);
4425 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4426 		return QDF_STATUS_E_FAILURE;
4427 	}
4428 
4429 	sparams = &spectral->params[smode];
4430 	m = SPECTRAL_SCAN_MODE_NORMAL;
4431 	for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
4432 		ch_width[m] = CH_WIDTH_INVALID;
4433 
4434 	if (!spectral->params_valid[smode]) {
4435 		target_if_spectral_info_read(spectral,
4436 					     smode,
4437 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
4438 					     &spectral->params[smode],
4439 					     sizeof(spectral->params[smode]));
4440 		spectral->params_valid[smode] = true;
4441 	}
4442 
4443 	switch (param->id) {
4444 	case SPECTRAL_PARAM_FFT_PERIOD:
4445 		sparams->ss_fft_period = param->value;
4446 		break;
4447 	case SPECTRAL_PARAM_SCAN_PERIOD:
4448 		sparams->ss_period = param->value;
4449 		if (sparams->ss_recapture && ((sparams->ss_period <
4450 		    SPECTRAL_RECAPTURE_SCAN_PERIOD_THRESHOLD) ||
4451 		    (smode == SPECTRAL_SCAN_MODE_AGILE))) {
4452 			sparams->ss_recapture = false;
4453 			spectral_err("FFT recapture cannot be enabled due to scan period: %d us or spectral scan mode: %d",
4454 				     sparams->ss_period, smode);
4455 		}
4456 		break;
4457 	case SPECTRAL_PARAM_FFT_RECAPTURE:
4458 		if (param->value) {
4459 			if (sparams->ss_period >=
4460 			    SPECTRAL_RECAPTURE_SCAN_PERIOD_THRESHOLD &&
4461 			    smode == SPECTRAL_SCAN_MODE_NORMAL) {
4462 				sparams->ss_recapture = true;
4463 			} else {
4464 				spectral_err("FFT recapture cannot be enabled due to scan period: %d us or spectral scan mode: %d",
4465 					     sparams->ss_period, smode);
4466 				sparams->ss_recapture = false;
4467 			}
4468 		} else {
4469 			sparams->ss_recapture = false;
4470 		}
4471 		break;
4472 	case SPECTRAL_PARAM_SCAN_COUNT:
4473 		sparams->ss_count = param->value;
4474 		break;
4475 	case SPECTRAL_PARAM_SHORT_REPORT:
4476 		sparams->ss_short_report = (!!param->value) ? true : false;
4477 		break;
4478 	case SPECTRAL_PARAM_SPECT_PRI:
4479 		sparams->ss_spectral_pri = (!!param->value) ? true : false;
4480 		break;
4481 	case SPECTRAL_PARAM_FFT_SIZE:
4482 		status = target_if_spectral_populate_chwidth
4483 			(spectral, ch_width, spectral->params
4484 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
4485 		if (QDF_IS_STATUS_ERROR(status))
4486 			return QDF_STATUS_E_FAILURE;
4487 		if ((param->value < param_min_max->fft_size_min) ||
4488 		    (param->value > param_min_max->fft_size_max
4489 		    [ch_width[smode]])) {
4490 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4491 			return QDF_STATUS_E_FAILURE;
4492 		}
4493 		sparams->ss_fft_size = param->value;
4494 		break;
4495 	case SPECTRAL_PARAM_GC_ENA:
4496 		sparams->ss_gc_ena = !!param->value;
4497 		break;
4498 	case SPECTRAL_PARAM_RESTART_ENA:
4499 		sparams->ss_restart_ena = !!param->value;
4500 		break;
4501 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
4502 		sparams->ss_noise_floor_ref = param->value;
4503 		break;
4504 	case SPECTRAL_PARAM_INIT_DELAY:
4505 		sparams->ss_init_delay = param->value;
4506 		break;
4507 	case SPECTRAL_PARAM_NB_TONE_THR:
4508 		sparams->ss_nb_tone_thr = param->value;
4509 		break;
4510 	case SPECTRAL_PARAM_STR_BIN_THR:
4511 		sparams->ss_str_bin_thr = param->value;
4512 		break;
4513 	case SPECTRAL_PARAM_WB_RPT_MODE:
4514 		sparams->ss_wb_rpt_mode = !!param->value;
4515 		break;
4516 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
4517 		sparams->ss_rssi_rpt_mode = !!param->value;
4518 		break;
4519 	case SPECTRAL_PARAM_RSSI_THR:
4520 		sparams->ss_rssi_thr = param->value;
4521 		break;
4522 	case SPECTRAL_PARAM_PWR_FORMAT:
4523 		sparams->ss_pwr_format = !!param->value;
4524 		break;
4525 	case SPECTRAL_PARAM_RPT_MODE:
4526 		if ((param->value < SPECTRAL_PARAM_RPT_MODE_MIN) ||
4527 		    (param->value > SPECTRAL_PARAM_RPT_MODE_MAX)) {
4528 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4529 			return QDF_STATUS_E_FAILURE;
4530 		}
4531 		sparams->ss_rpt_mode = param->value;
4532 		break;
4533 	case SPECTRAL_PARAM_BIN_SCALE:
4534 		sparams->ss_bin_scale = param->value;
4535 		break;
4536 	case SPECTRAL_PARAM_DBM_ADJ:
4537 		sparams->ss_dbm_adj = !!param->value;
4538 		break;
4539 	case SPECTRAL_PARAM_CHN_MASK:
4540 		sparams->ss_chn_mask = param->value;
4541 		break;
4542 	case SPECTRAL_PARAM_FREQUENCY:
4543 		status = target_if_spectral_populate_chwidth(
4544 				spectral, ch_width, param->freq.cfreq2 > 0);
4545 		if (QDF_IS_STATUS_ERROR(status)) {
4546 			spectral_err("Failed to populate channel width");
4547 			return QDF_STATUS_E_FAILURE;
4548 		}
4549 
4550 		if (ch_width[smode] != CH_WIDTH_80P80MHZ &&
4551 		    param->freq.cfreq2) {
4552 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4553 			spectral_err("Non zero cfreq2 expected for 80p80 only");
4554 			return QDF_STATUS_E_INVAL;
4555 		}
4556 
4557 		if (ch_width[smode] == CH_WIDTH_80P80MHZ &&
4558 		    !param->freq.cfreq2) {
4559 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4560 			spectral_err("Non zero cfreq2 expected for 80p80");
4561 			return QDF_STATUS_E_INVAL;
4562 		}
4563 
4564 		status = target_if_is_center_freq_of_any_chan
4565 				(spectral->pdev_obj, param->freq.cfreq1,
4566 				 &is_valid_chan);
4567 		if (QDF_IS_STATUS_ERROR(status))
4568 			return QDF_STATUS_E_FAILURE;
4569 
4570 		if (is_valid_chan) {
4571 			status = target_if_calculate_center_freq(
4572 							spectral, ch_width,
4573 							param->freq.cfreq1,
4574 							&agile_cfreq);
4575 			if (QDF_IS_STATUS_ERROR(status)) {
4576 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4577 				return QDF_STATUS_E_FAILURE;
4578 			}
4579 		} else {
4580 			bool is_valid_agile_cfreq;
4581 
4582 			status = target_if_validate_center_freq
4583 				(spectral, ch_width, param->freq.cfreq1,
4584 				 &is_valid_agile_cfreq);
4585 			if (QDF_IS_STATUS_ERROR(status))
4586 				return QDF_STATUS_E_FAILURE;
4587 
4588 			if (!is_valid_agile_cfreq) {
4589 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4590 				spectral_err("Invalid agile center frequency");
4591 				return QDF_STATUS_E_FAILURE;
4592 			}
4593 
4594 			agile_cfreq = param->freq.cfreq1;
4595 		}
4596 		center_freq.cfreq1 = agile_cfreq;
4597 
4598 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
4599 			status = target_if_is_center_freq_of_any_chan
4600 					(spectral->pdev_obj, param->freq.cfreq2,
4601 					 &is_valid_chan);
4602 			if (QDF_IS_STATUS_ERROR(status))
4603 				return QDF_STATUS_E_FAILURE;
4604 
4605 			if (is_valid_chan) {
4606 				status = target_if_calculate_center_freq(
4607 						spectral, ch_width,
4608 						param->freq.cfreq2,
4609 						&agile_cfreq);
4610 				if (QDF_IS_STATUS_ERROR(status)) {
4611 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4612 					return QDF_STATUS_E_FAILURE;
4613 				}
4614 			} else {
4615 				bool is_valid_agile_cfreq;
4616 
4617 				status = target_if_validate_center_freq
4618 					(spectral, ch_width, param->freq.cfreq2,
4619 					 &is_valid_agile_cfreq);
4620 				if (QDF_IS_STATUS_ERROR(status))
4621 					return QDF_STATUS_E_FAILURE;
4622 
4623 				if (!is_valid_agile_cfreq) {
4624 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4625 					spectral_err("Invalid agile center frequency");
4626 					return QDF_STATUS_E_FAILURE;
4627 				}
4628 
4629 				agile_cfreq = param->freq.cfreq2;
4630 			}
4631 			center_freq.cfreq2 = agile_cfreq;
4632 		}
4633 
4634 		status = target_if_is_agile_span_overlap_with_operating_span
4635 				(spectral, ch_width,
4636 				 &center_freq, &is_overlapping);
4637 		if (QDF_IS_STATUS_ERROR(status))
4638 			return QDF_STATUS_E_FAILURE;
4639 
4640 		if (is_overlapping) {
4641 			spectral_err("Agile freq %u, %u overlaps with operating span",
4642 				     center_freq.cfreq1, center_freq.cfreq2);
4643 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4644 			return QDF_STATUS_E_FAILURE;
4645 		}
4646 
4647 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
4648 			bool is_valid_80p80;
4649 
4650 			is_valid_80p80 = target_if_spectral_is_valid_80p80_freq(
4651 						spectral->pdev_obj,
4652 						center_freq.cfreq1,
4653 						center_freq.cfreq2);
4654 
4655 			if (!is_valid_80p80) {
4656 				spectral_err("Agile freq %u, %u is invalid 80+80 combination",
4657 					     center_freq.cfreq1,
4658 					     center_freq.cfreq2);
4659 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4660 				return QDF_STATUS_E_FAILURE;
4661 			}
4662 		}
4663 
4664 		sparams->ss_frequency.cfreq1 = center_freq.cfreq1;
4665 		sparams->ss_frequency.cfreq2 = center_freq.cfreq2;
4666 
4667 		break;
4668 
4669 	case SPECTRAL_PARAM_CHAN_WIDTH:
4670 		if (param->value >= CH_WIDTH_INVALID) {
4671 			spectral_err("invalid sscan width: %u", param->value);
4672 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4673 			return QDF_STATUS_E_FAILURE;
4674 		}
4675 
4676 		vdev = target_if_spectral_get_vdev(spectral, smode);
4677 		if (!vdev) {
4678 			spectral_err("vdev is null");
4679 			return QDF_STATUS_E_NULL_VALUE;
4680 		}
4681 		op_bw = target_if_vdev_get_ch_width(vdev);
4682 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4683 
4684 		/* Validate the bandwidth */
4685 		status = target_if_is_sscan_bw_supported(
4686 				spectral, smode,
4687 				param->value, op_bw, &is_bw_supported,
4688 				spectral->params[SPECTRAL_SCAN_MODE_AGILE].
4689 				ss_frequency.cfreq2 > 0);
4690 		if (QDF_IS_STATUS_ERROR(status)) {
4691 			spectral_err("Unable to check if given sscan_bw is supported");
4692 			return QDF_STATUS_E_FAILURE;
4693 		}
4694 
4695 		if (!is_bw_supported) {
4696 			spectral_err("sscan bw(%u) is not supported for the current operating width(%u) and sscan mode(%u)",
4697 				     param->value, op_bw, smode);
4698 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4699 			return QDF_STATUS_E_FAILURE;
4700 		}
4701 
4702 		sparams->ss_bandwidth = param->value;
4703 		spectral->sscan_width_configured[smode] = true;
4704 
4705 		break;
4706 	}
4707 
4708 	p_sops->configure_spectral(spectral, sparams, smode);
4709 	/* only to validate the writes */
4710 	p_sops->get_spectral_config(spectral, &params, smode);
4711 	return QDF_STATUS_SUCCESS;
4712 }
4713 
4714 QDF_STATUS
4715 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
4716 			      const struct spectral_cp_param *param,
4717 			      const enum spectral_scan_mode smode,
4718 			      enum spectral_cp_error_code *err)
4719 {
4720 	enum spectral_scan_mode mode = SPECTRAL_SCAN_MODE_NORMAL;
4721 	struct target_if_spectral *spectral;
4722 	QDF_STATUS status;
4723 
4724 	if (!err) {
4725 		spectral_err("Error code argument is null");
4726 		QDF_ASSERT(0);
4727 		return QDF_STATUS_E_FAILURE;
4728 	}
4729 	*err = SPECTRAL_SCAN_ERR_INVALID;
4730 
4731 	if (!pdev) {
4732 		spectral_err("pdev object is NULL");
4733 		return QDF_STATUS_E_FAILURE;
4734 	}
4735 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4736 	if (!spectral) {
4737 		spectral_err("spectral object is NULL");
4738 		return QDF_STATUS_E_FAILURE;
4739 	}
4740 
4741 	if (!param) {
4742 		spectral_err("parameter object is NULL");
4743 		return QDF_STATUS_E_FAILURE;
4744 	}
4745 
4746 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4747 		spectral_err("Invalid Spectral mode %u", smode);
4748 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4749 		return QDF_STATUS_E_FAILURE;
4750 	}
4751 
4752 	if (!spectral->properties[smode][param->id].supported) {
4753 		spectral_err("Spectral parameter(%u) unsupported for mode %u",
4754 			     param->id, smode);
4755 		*err = SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED;
4756 		return QDF_STATUS_E_FAILURE;
4757 	}
4758 
4759 	if (spectral->properties[smode][param->id].common_all_modes) {
4760 		spectral_warn("Setting Spectral parameter %u for all modes",
4761 			      param->id);
4762 		for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) {
4763 			status = _target_if_set_spectral_config
4764 						(spectral, param, mode, err);
4765 			if (QDF_IS_STATUS_ERROR(status))
4766 				return QDF_STATUS_E_FAILURE;
4767 		}
4768 		return QDF_STATUS_SUCCESS;
4769 	}
4770 
4771 	return _target_if_set_spectral_config(spectral, param, smode, err);
4772 }
4773 
4774 /**
4775  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
4776  * @fft_len: FFT length
4777  * @pdev: Pointer to pdev object
4778  *
4779  * API to get fft bin count for a given fft length
4780  *
4781  * Return: FFt bin count
4782  */
4783 static int
4784 target_if_get_fft_bin_count(int fft_len)
4785 {
4786 	int bin_count = 0;
4787 
4788 	switch (fft_len) {
4789 	case 5:
4790 		bin_count = 16;
4791 		break;
4792 	case 6:
4793 		bin_count = 32;
4794 		break;
4795 	case 7:
4796 		bin_count = 64;
4797 		break;
4798 	case 8:
4799 		bin_count = 128;
4800 		break;
4801 	case 9:
4802 		bin_count = 256;
4803 		break;
4804 	default:
4805 		break;
4806 	}
4807 
4808 	return bin_count;
4809 }
4810 
4811 /**
4812  * target_if_init_upper_lower_flags() - Initializes control and extension
4813  * segment flags
4814  * @spectral: pointer to target if spectral object
4815  * @smode: Spectral scan mode
4816  *
4817  * API to initialize the control and extension flags with the lower/upper
4818  * segment based on the HT mode
4819  *
4820  * Return: FFt bin count
4821  */
4822 static void
4823 target_if_init_upper_lower_flags(struct target_if_spectral *spectral,
4824 				 enum spectral_scan_mode smode)
4825 {
4826 	int current_channel = 0;
4827 	int ext_channel = 0;
4828 	struct target_if_spectral_ops *p_sops =
4829 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
4830 
4831 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4832 		spectral_err("Invalid Spectral mode %u", smode);
4833 		return;
4834 	}
4835 	current_channel = p_sops->get_current_channel(spectral, smode);
4836 	ext_channel = p_sops->get_extension_channel(spectral, smode);
4837 
4838 	if ((current_channel == 0) || (ext_channel == 0))
4839 		return;
4840 
4841 	if (spectral->sc_spectral_20_40_mode) {
4842 		/* HT40 mode */
4843 		if (ext_channel < current_channel) {
4844 			spectral->lower_is_extension = 1;
4845 			spectral->upper_is_control = 1;
4846 			spectral->lower_is_control = 0;
4847 			spectral->upper_is_extension = 0;
4848 		} else {
4849 			spectral->lower_is_extension = 0;
4850 			spectral->upper_is_control = 0;
4851 			spectral->lower_is_control = 1;
4852 			spectral->upper_is_extension = 1;
4853 		}
4854 	} else {
4855 		/* HT20 mode, lower is always control */
4856 		spectral->lower_is_extension = 0;
4857 		spectral->upper_is_control = 0;
4858 		spectral->lower_is_control = 1;
4859 		spectral->upper_is_extension = 0;
4860 	}
4861 }
4862 
4863 /**
4864  * target_if_get_spectral_config() - Get spectral configuration
4865  * @pdev: Pointer to pdev object
4866  * @param: Pointer to spectral_config structure in which the configuration
4867  * should be returned
4868  * @smode: Spectral scan mode
4869  *
4870  * API to get the current spectral configuration
4871  *
4872  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4873  */
4874 QDF_STATUS
4875 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
4876 			      struct spectral_config *param,
4877 			      enum spectral_scan_mode smode)
4878 {
4879 	struct target_if_spectral_ops *p_sops = NULL;
4880 	struct target_if_spectral *spectral = NULL;
4881 
4882 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4883 
4884 	if (!spectral) {
4885 		spectral_err("SPECTRAL : Module doesn't exist");
4886 		return QDF_STATUS_E_FAILURE;
4887 	}
4888 
4889 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4890 
4891 	if (!p_sops) {
4892 		spectral_err("p_sops is null");
4893 		return QDF_STATUS_E_FAILURE;
4894 	}
4895 
4896 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4897 		spectral_err("Invalid Spectral mode %u", smode);
4898 		return QDF_STATUS_E_FAILURE;
4899 	}
4900 
4901 	qdf_mem_zero(param, sizeof(struct spectral_config));
4902 	p_sops->get_spectral_config(spectral, param, smode);
4903 
4904 	return QDF_STATUS_SUCCESS;
4905 }
4906 
4907 #ifdef WLAN_FEATURE_11BE
4908 /**
4909  * target_if_spectral_get_num_detectors_for_higher_bws() - Get number of
4910  * Spectral detectors for higher bandwidths
4911  * @spectral: Pointer to target if Spectral object
4912  * @ch_width: channel width
4913  * @num_detectors: Pointer to the variable to store number of Spectral detectors
4914  *
4915  * API to get number of Spectral detectors used for scan in the given channel
4916  * width.
4917  *
4918  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
4919  */
4920 static QDF_STATUS
4921 target_if_spectral_get_num_detectors_for_higher_bws(
4922 				struct target_if_spectral *spectral,
4923 				enum phy_ch_width ch_width,
4924 				uint32_t *num_detectors)
4925 {
4926 	switch (ch_width) {
4927 	case CH_WIDTH_320MHZ:
4928 		*num_detectors = spectral->capability.num_detectors_320mhz;
4929 		break;
4930 
4931 	default:
4932 		spectral_err("Unsupported channel width %d", ch_width);
4933 		return QDF_STATUS_E_INVAL;
4934 	}
4935 
4936 	return QDF_STATUS_SUCCESS;
4937 }
4938 #else
4939 static QDF_STATUS
4940 target_if_spectral_get_num_detectors_for_higher_bws(
4941 				struct target_if_spectral *spectral,
4942 				enum phy_ch_width ch_width,
4943 				uint32_t *num_detectors)
4944 {
4945 	spectral_err("Unsupported channel width %d", ch_width);
4946 	return QDF_STATUS_E_INVAL;
4947 }
4948 #endif
4949 
4950 /**
4951  * target_if_spectral_get_num_detectors() - Get number of Spectral detectors
4952  * @spectral: Pointer to target if Spectral object
4953  * @ch_width: channel width
4954  * @num_detectors: Pointer to the variable to store number of Spectral detectors
4955  *
4956  * API to get number of Spectral detectors used for scan in the given channel
4957  * width.
4958  *
4959  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
4960  */
4961 static QDF_STATUS
4962 target_if_spectral_get_num_detectors(struct target_if_spectral *spectral,
4963 				     enum phy_ch_width ch_width,
4964 				     uint32_t *num_detectors)
4965 {
4966 	if (!spectral) {
4967 		spectral_err("target if spectral object is null");
4968 		return QDF_STATUS_E_INVAL;
4969 	}
4970 
4971 	if (ch_width >= CH_WIDTH_INVALID) {
4972 		spectral_err("Invalid channel width %d", ch_width);
4973 		return QDF_STATUS_E_INVAL;
4974 	}
4975 
4976 	if (!num_detectors) {
4977 		spectral_err("Invalid argument, number of detectors");
4978 		return QDF_STATUS_E_INVAL;
4979 	}
4980 
4981 	switch (ch_width) {
4982 	case CH_WIDTH_20MHZ:
4983 		*num_detectors = spectral->capability.num_detectors_20mhz;
4984 		break;
4985 
4986 	case CH_WIDTH_40MHZ:
4987 		*num_detectors = spectral->capability.num_detectors_40mhz;
4988 		break;
4989 
4990 	case CH_WIDTH_80MHZ:
4991 		*num_detectors = spectral->capability.num_detectors_80mhz;
4992 		break;
4993 
4994 	case CH_WIDTH_160MHZ:
4995 		*num_detectors = spectral->capability.num_detectors_160mhz;
4996 		break;
4997 
4998 	case CH_WIDTH_80P80MHZ:
4999 		*num_detectors = spectral->capability.num_detectors_80p80mhz;
5000 		break;
5001 
5002 	default:
5003 		return target_if_spectral_get_num_detectors_for_higher_bws(
5004 			spectral, ch_width, num_detectors);
5005 	}
5006 
5007 	return QDF_STATUS_SUCCESS;
5008 }
5009 
5010 /**
5011  * target_if_spectral_finite_scan_init() - Initializations required for finite
5012  * Spectral scan
5013  * @spectral: Pointer to target of Spctral object
5014  * @smode: Spectral scan mode
5015  *
5016  * This routine initializes the finite Spectral scan. Finite Spectral scan is
5017  * triggered by configuring a non zero scan count.
5018  *
5019  * Return: QDF_STATUS_SUCCESS on success
5020  */
5021 static QDF_STATUS
5022 target_if_spectral_finite_scan_init(struct target_if_spectral *spectral,
5023 				    enum spectral_scan_mode smode)
5024 {
5025 	struct target_if_finite_spectral_scan_params *finite_scan;
5026 	enum phy_ch_width ch_width;
5027 	uint32_t num_detectors;
5028 	QDF_STATUS status;
5029 	uint16_t sscan_count;
5030 
5031 	if (!spectral) {
5032 		spectral_err("target if spectral object is null");
5033 		return QDF_STATUS_E_INVAL;
5034 	}
5035 
5036 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5037 		spectral_err("Invalid Spectral mode");
5038 		return QDF_STATUS_E_INVAL;
5039 	}
5040 
5041 	ch_width = spectral->ch_width[smode];
5042 	status = target_if_spectral_get_num_detectors(spectral, ch_width,
5043 						      &num_detectors);
5044 
5045 	if (QDF_IS_STATUS_ERROR(status)) {
5046 		spectral_err("Failed to get number of detectors");
5047 		return QDF_STATUS_E_FAILURE;
5048 	}
5049 
5050 	finite_scan = &spectral->finite_scan[smode];
5051 	sscan_count =  spectral->params[smode].ss_count;
5052 
5053 	finite_scan->finite_spectral_scan =  true;
5054 	finite_scan->num_reports_expected = num_detectors * sscan_count;
5055 
5056 	return QDF_STATUS_SUCCESS;
5057 }
5058 
5059 /**
5060  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
5061  *                                           parameters
5062  * @spectral: Pointer to Spectral target_if internal private data
5063  * @spectral_params: Pointer to Spectral parameters
5064  * @smode: Spectral scan mode
5065  * @err: Spectral error code
5066  *
5067  * Enable use of desired Spectral parameters by configuring them into HW, and
5068  * starting Spectral scan
5069  *
5070  * Return: 0 on success, 1 on failure
5071  */
5072 int
5073 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
5074 				      struct spectral_config *spectral_params,
5075 				      enum spectral_scan_mode smode,
5076 				      enum spectral_cp_error_code *err)
5077 {
5078 	int extension_channel = 0;
5079 	int current_channel = 0;
5080 	struct target_if_spectral_ops *p_sops = NULL;
5081 	QDF_STATUS status;
5082 	struct wlan_objmgr_pdev *pdev;
5083 	struct wlan_objmgr_psoc *psoc;
5084 
5085 	if (!spectral) {
5086 		spectral_err("Spectral LMAC object is NULL");
5087 		return 1;
5088 	}
5089 
5090 	pdev =  spectral->pdev_obj;
5091 	if (!pdev) {
5092 		spectral_err("pdev is null");
5093 		return QDF_STATUS_E_INVAL;
5094 	}
5095 
5096 	psoc = wlan_pdev_get_psoc(pdev);
5097 	if (!psoc) {
5098 		spectral_err("psoc is null");
5099 		return QDF_STATUS_E_INVAL;
5100 	}
5101 
5102 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5103 		spectral_err("Invalid Spectral mode %u", smode);
5104 		return 1;
5105 	}
5106 
5107 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5108 
5109 	if (!p_sops) {
5110 		spectral_err("p_sops is NULL");
5111 		return 1;
5112 	}
5113 
5114 	spectral->sc_spectral_noise_pwr_cal =
5115 	    spectral_params->ss_spectral_pri ? 1 : 0;
5116 
5117 	/* check if extension channel is present */
5118 	extension_channel = p_sops->get_extension_channel(spectral, smode);
5119 	current_channel = p_sops->get_current_channel(spectral, smode);
5120 
5121 	if (spectral->capability.advncd_spectral_cap) {
5122 		spectral->lb_edge_extrabins = 0;
5123 		spectral->rb_edge_extrabins = 0;
5124 
5125 		if (spectral->is_lb_edge_extrabins_format &&
5126 		    spectral->params[smode].ss_rpt_mode == 2) {
5127 			spectral->lb_edge_extrabins = 4;
5128 		}
5129 
5130 		if (spectral->is_rb_edge_extrabins_format &&
5131 		    spectral->params[smode].ss_rpt_mode == 2) {
5132 			spectral->rb_edge_extrabins = 4;
5133 		}
5134 
5135 		if (spectral->ch_width[smode] == CH_WIDTH_20MHZ) {
5136 			spectral->sc_spectral_20_40_mode = 0;
5137 
5138 			spectral->spectral_numbins =
5139 			    target_if_get_fft_bin_count(
5140 				spectral->params[smode].ss_fft_size);
5141 			spectral->spectral_fft_len =
5142 			    target_if_get_fft_bin_count(
5143 				spectral->params[smode].ss_fft_size);
5144 			spectral->spectral_data_len =
5145 			    target_if_get_fft_bin_count(
5146 				spectral->params[smode].ss_fft_size);
5147 			/*
5148 			 * Initialize classifier params to be sent to user
5149 			 * space classifier
5150 			 */
5151 			spectral->classifier_params.lower_chan_in_mhz =
5152 			    current_channel;
5153 			spectral->classifier_params.upper_chan_in_mhz = 0;
5154 
5155 		} else if (spectral->ch_width[smode] == CH_WIDTH_40MHZ) {
5156 			/* TODO : Remove this variable */
5157 			spectral->sc_spectral_20_40_mode = 1;
5158 			spectral->spectral_numbins =
5159 			    target_if_get_fft_bin_count(
5160 				spectral->params[smode].ss_fft_size);
5161 			spectral->spectral_fft_len =
5162 			    target_if_get_fft_bin_count(
5163 				spectral->params[smode].ss_fft_size);
5164 			spectral->spectral_data_len =
5165 			    target_if_get_fft_bin_count(
5166 				spectral->params[smode].ss_fft_size);
5167 
5168 			/*
5169 			 * Initialize classifier params to be sent to user
5170 			 * space classifier
5171 			 */
5172 			if (extension_channel < current_channel) {
5173 				spectral->classifier_params.lower_chan_in_mhz =
5174 				    extension_channel;
5175 				spectral->classifier_params.upper_chan_in_mhz =
5176 				    current_channel;
5177 			} else {
5178 				spectral->classifier_params.lower_chan_in_mhz =
5179 				    current_channel;
5180 				spectral->classifier_params.upper_chan_in_mhz =
5181 				    extension_channel;
5182 			}
5183 
5184 		} else if (spectral->ch_width[smode] == CH_WIDTH_80MHZ) {
5185 			/* Set the FFT Size */
5186 			/* TODO : Remove this variable */
5187 			spectral->sc_spectral_20_40_mode = 0;
5188 			spectral->spectral_numbins =
5189 			    target_if_get_fft_bin_count(
5190 				spectral->params[smode].ss_fft_size);
5191 			spectral->spectral_fft_len =
5192 			    target_if_get_fft_bin_count(
5193 				spectral->params[smode].ss_fft_size);
5194 			spectral->spectral_data_len =
5195 			    target_if_get_fft_bin_count(
5196 				spectral->params[smode].ss_fft_size);
5197 
5198 			/*
5199 			 * Initialize classifier params to be sent to user
5200 			 * space classifier
5201 			 */
5202 			spectral->classifier_params.lower_chan_in_mhz =
5203 			    current_channel;
5204 			spectral->classifier_params.upper_chan_in_mhz = 0;
5205 
5206 			/*
5207 			 * Initialize classifier params to be sent to user
5208 			 * space classifier
5209 			 */
5210 			if (extension_channel < current_channel) {
5211 				spectral->classifier_params.lower_chan_in_mhz =
5212 				    extension_channel;
5213 				spectral->classifier_params.upper_chan_in_mhz =
5214 				    current_channel;
5215 			} else {
5216 				spectral->classifier_params.lower_chan_in_mhz =
5217 				    current_channel;
5218 				spectral->classifier_params.upper_chan_in_mhz =
5219 				    extension_channel;
5220 			}
5221 
5222 		} else if (is_ch_width_160_or_80p80(
5223 			   spectral->ch_width[smode])) {
5224 			/* Set the FFT Size */
5225 
5226 			/* The below applies to both 160 and 80+80 cases */
5227 
5228 			/* TODO : Remove this variable */
5229 			spectral->sc_spectral_20_40_mode = 0;
5230 			spectral->spectral_numbins =
5231 			    target_if_get_fft_bin_count(
5232 				spectral->params[smode].ss_fft_size);
5233 			spectral->spectral_fft_len =
5234 			    target_if_get_fft_bin_count(
5235 				spectral->params[smode].ss_fft_size);
5236 			spectral->spectral_data_len =
5237 			    target_if_get_fft_bin_count(
5238 				spectral->params[smode].ss_fft_size);
5239 
5240 			/*
5241 			 * Initialize classifier params to be sent to user
5242 			 * space classifier
5243 			 */
5244 			spectral->classifier_params.lower_chan_in_mhz =
5245 			    current_channel;
5246 			spectral->classifier_params.upper_chan_in_mhz = 0;
5247 
5248 			/*
5249 			 * Initialize classifier params to be sent to user
5250 			 * space classifier
5251 			 */
5252 			if (extension_channel < current_channel) {
5253 				spectral->classifier_params.lower_chan_in_mhz =
5254 				    extension_channel;
5255 				spectral->classifier_params.upper_chan_in_mhz =
5256 				    current_channel;
5257 			} else {
5258 				spectral->classifier_params.lower_chan_in_mhz =
5259 				    current_channel;
5260 				spectral->classifier_params.upper_chan_in_mhz =
5261 				    extension_channel;
5262 			}
5263 		}
5264 
5265 		if (spectral->spectral_numbins) {
5266 			spectral->spectral_numbins +=
5267 			    spectral->lb_edge_extrabins;
5268 			spectral->spectral_numbins +=
5269 			    spectral->rb_edge_extrabins;
5270 		}
5271 
5272 		if (spectral->spectral_fft_len) {
5273 			spectral->spectral_fft_len +=
5274 			    spectral->lb_edge_extrabins;
5275 			spectral->spectral_fft_len +=
5276 			    spectral->rb_edge_extrabins;
5277 		}
5278 
5279 		if (spectral->spectral_data_len) {
5280 			spectral->spectral_data_len +=
5281 			    spectral->lb_edge_extrabins;
5282 			spectral->spectral_data_len +=
5283 			    spectral->rb_edge_extrabins;
5284 		}
5285 	} else {
5286 		/*
5287 		 * The decision to find 20/40 mode is found based on the
5288 		 * presence of extension channel
5289 		 * instead of channel width, as the channel width can
5290 		 * dynamically change
5291 		 */
5292 
5293 		if (extension_channel == 0) {
5294 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
5295 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
5296 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
5297 			spectral->spectral_data_len =
5298 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
5299 			/* only valid in 20-40 mode */
5300 			spectral->spectral_lower_max_index_offset = -1;
5301 			/* only valid in 20-40 mode */
5302 			spectral->spectral_upper_max_index_offset = -1;
5303 			spectral->spectral_max_index_offset =
5304 			    spectral->spectral_fft_len + 2;
5305 			spectral->sc_spectral_20_40_mode = 0;
5306 
5307 			/*
5308 			 * Initialize classifier params to be sent to user
5309 			 * space classifier
5310 			 */
5311 			spectral->classifier_params.lower_chan_in_mhz =
5312 			    current_channel;
5313 			spectral->classifier_params.upper_chan_in_mhz = 0;
5314 
5315 		} else {
5316 			spectral->spectral_numbins =
5317 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
5318 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
5319 			spectral->spectral_data_len =
5320 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
5321 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
5322 			/* only valid in 20 mode */
5323 			spectral->spectral_max_index_offset = -1;
5324 			spectral->spectral_lower_max_index_offset =
5325 			    spectral->spectral_fft_len + 2;
5326 			spectral->spectral_upper_max_index_offset =
5327 			    spectral->spectral_fft_len + 5;
5328 			spectral->sc_spectral_20_40_mode = 1;
5329 
5330 			/*
5331 			 * Initialize classifier params to be sent to user
5332 			 * space classifier
5333 			 */
5334 			if (extension_channel < current_channel) {
5335 				spectral->classifier_params.lower_chan_in_mhz =
5336 				    extension_channel;
5337 				spectral->classifier_params.upper_chan_in_mhz =
5338 				    current_channel;
5339 			} else {
5340 				spectral->classifier_params.lower_chan_in_mhz =
5341 				    current_channel;
5342 				spectral->classifier_params.upper_chan_in_mhz =
5343 				    extension_channel;
5344 			}
5345 		}
5346 	}
5347 
5348 	spectral->send_single_packet = 0;
5349 	spectral->classifier_params.spectral_20_40_mode =
5350 	    spectral->sc_spectral_20_40_mode;
5351 	spectral->classifier_params.spectral_dc_index =
5352 	    spectral->spectral_dc_index;
5353 	spectral->spectral_sent_msg = 0;
5354 	spectral->classify_scan = 0;
5355 	spectral->num_spectral_data = 0;
5356 
5357 	if (!p_sops->is_spectral_active(spectral, smode)) {
5358 		p_sops->configure_spectral(spectral, spectral_params, smode);
5359 		spectral->rparams.marker[smode].is_valid = false;
5360 
5361 		if (spectral->params[smode].ss_count) {
5362 			status = target_if_spectral_finite_scan_init(spectral,
5363 								     smode);
5364 			if (QDF_IS_STATUS_ERROR(status)) {
5365 				spectral_err("Failed to init finite scan");
5366 				return 1;
5367 			}
5368 		}
5369 		p_sops->start_spectral_scan(spectral, smode, err);
5370 		spectral->timestamp_war.timestamp_war_offset[smode] = 0;
5371 		spectral->timestamp_war.last_fft_timestamp[smode] = 0;
5372 	}
5373 
5374 	/* get current spectral configuration */
5375 	p_sops->get_spectral_config(spectral, &spectral->params[smode], smode);
5376 
5377 	target_if_init_upper_lower_flags(spectral, smode);
5378 
5379 	return 0;
5380 }
5381 
5382 /**
5383  * target_if_is_aspectral_prohibited_by_adfs() - Is Agile Spectral prohibited by
5384  * Agile DFS
5385  * @psoc: Pointer to psoc
5386  * @object: Pointer to pdev
5387  * @arg: Pointer to flag which indicates whether Agile Spectral is prohibited
5388  *
5389  * This API checks whether Agile DFS is running on any of the pdevs. If so, it
5390  * indicates that Agile Spectral scan is prohibited by Agile DFS.
5391  *
5392  * Return: void
5393  */
5394 static void
5395 target_if_is_aspectral_prohibited_by_adfs(struct wlan_objmgr_psoc *psoc,
5396 					  void *object, void *arg)
5397 {
5398 	bool *is_aspectral_prohibited = arg;
5399 	struct wlan_objmgr_pdev *cur_pdev = object;
5400 	bool is_agile_precac_enabled_cur_pdev = false;
5401 	bool is_agile_rcac_enabled_cur_pdev = false;
5402 	QDF_STATUS status;
5403 
5404 	qdf_assert_always(is_aspectral_prohibited);
5405 	if (*is_aspectral_prohibited)
5406 		return;
5407 
5408 	qdf_assert_always(psoc);
5409 	qdf_assert_always(cur_pdev);
5410 
5411 	status = ucfg_dfs_get_agile_precac_enable
5412 				(cur_pdev,
5413 				 &is_agile_precac_enabled_cur_pdev);
5414 	if (QDF_IS_STATUS_ERROR(status)) {
5415 		spectral_err("Get agile precac failed, prohibiting aSpectral");
5416 		*is_aspectral_prohibited = true;
5417 		return;
5418 	}
5419 
5420 	status = ucfg_dfs_get_rcac_enable(cur_pdev,
5421 					  &is_agile_rcac_enabled_cur_pdev);
5422 
5423 	if (QDF_IS_STATUS_ERROR(status)) {
5424 		spectral_err("Get agile RCAC failed, prohibiting aSpectral");
5425 		*is_aspectral_prohibited = true;
5426 		return;
5427 	}
5428 
5429 	if (is_agile_precac_enabled_cur_pdev) {
5430 		spectral_err("aDFS preCAC is in progress on one of the pdevs");
5431 		*is_aspectral_prohibited = true;
5432 	} else if (is_agile_rcac_enabled_cur_pdev) {
5433 		spectral_err("aDFS RCAC is in progress on one of the pdevs");
5434 		*is_aspectral_prohibited = true;
5435 	}
5436 }
5437 
5438 /**
5439  * target_if_get_curr_band() - Get current operating band of pdev
5440  *
5441  * @pdev: pointer to pdev object
5442  *
5443  * API to get current operating band of a given pdev.
5444  *
5445  * Return: if success enum reg_wifi_band, REG_BAND_UNKNOWN in case of failure
5446  */
5447 static enum reg_wifi_band
5448 target_if_get_curr_band(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id)
5449 {
5450 	struct wlan_objmgr_vdev *vdev;
5451 	int16_t chan_freq;
5452 	enum reg_wifi_band cur_band;
5453 
5454 	if (!pdev) {
5455 		spectral_err("pdev is NULL");
5456 		return REG_BAND_UNKNOWN;
5457 	}
5458 
5459 	if (vdev_id == WLAN_INVALID_VDEV_ID)
5460 		vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID);
5461 	else
5462 		vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
5463 							    WLAN_SPECTRAL_ID);
5464 	if (!vdev) {
5465 		spectral_debug("vdev is NULL");
5466 		return REG_BAND_UNKNOWN;
5467 	}
5468 	chan_freq = target_if_vdev_get_chan_freq(vdev);
5469 	cur_band = wlan_reg_freq_to_band(chan_freq);
5470 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5471 
5472 	return cur_band;
5473 }
5474 
5475 /**
5476  * target_if_is_agile_scan_active_in_5g() - Is Agile Spectral scan active on
5477  * any of the 5G pdevs
5478  * @psoc: Pointer to psoc
5479  * @object: Pointer to pdev
5480  * @arg: Pointer to flag which indicates whether Agile Spectral scan is in
5481  *       progress in any 5G pdevs
5482  *
5483  * Return: void
5484  */
5485 static void
5486 target_if_is_agile_scan_active_in_5g(struct wlan_objmgr_psoc *psoc,
5487 				     void *object, void *arg)
5488 {
5489 	enum reg_wifi_band band;
5490 	bool *is_agile_scan_inprog_5g_pdev = arg;
5491 	struct target_if_spectral *spectral;
5492 	struct wlan_objmgr_pdev *cur_pdev = object;
5493 	struct target_if_spectral_ops *p_sops;
5494 
5495 	if (*is_agile_scan_inprog_5g_pdev)
5496 		return;
5497 
5498 	spectral = get_target_if_spectral_handle_from_pdev(cur_pdev);
5499 	if (!spectral) {
5500 		spectral_err("target if spectral handle is NULL");
5501 		return;
5502 	}
5503 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5504 
5505 	band = target_if_get_curr_band(
5506 			cur_pdev, spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE]);
5507 	if (band == REG_BAND_UNKNOWN) {
5508 		spectral_debug("Failed to get current band");
5509 		return;
5510 	}
5511 
5512 	if (band == REG_BAND_5G &&
5513 	    p_sops->is_spectral_active(spectral, SPECTRAL_SCAN_MODE_AGILE))
5514 		*is_agile_scan_inprog_5g_pdev = true;
5515 }
5516 
5517 /**
5518  * target_if_is_agile_supported_cur_chmask() - Is Agile Spectral scan supported
5519  * for current vdev rx chainmask.
5520  *
5521  * @spectral: Pointer to Spectral object
5522  * @is_supported: Pointer to is_supported
5523  *
5524  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
5525  */
5526 static QDF_STATUS
5527 target_if_is_agile_supported_cur_chmask(struct target_if_spectral *spectral,
5528 					bool *is_supported)
5529 {
5530 	struct wlan_objmgr_vdev *vdev;
5531 	uint8_t vdev_rxchainmask;
5532 	struct wlan_objmgr_psoc *psoc;
5533 	struct wlan_objmgr_pdev *pdev;
5534 	struct target_psoc_info *tgt_psoc_info;
5535 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
5536 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr = NULL;
5537 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = NULL;
5538 	struct wlan_psoc_host_chainmask_table *table;
5539 	int j;
5540 	uint32_t table_id;
5541 	enum phy_ch_width ch_width;
5542 	uint8_t pdev_id;
5543 
5544 	if (!spectral) {
5545 		spectral_err("spectral target if object is null");
5546 		return QDF_STATUS_E_FAILURE;
5547 	}
5548 
5549 	if (!is_supported) {
5550 		spectral_err("is supported argument is null");
5551 		return QDF_STATUS_E_FAILURE;
5552 	}
5553 
5554 	if (spectral->spectral_gen <= SPECTRAL_GEN2) {
5555 		spectral_err("HW Agile mode is not supported up to gen 2");
5556 		return QDF_STATUS_E_FAILURE;
5557 	}
5558 
5559 	pdev = spectral->pdev_obj;
5560 	if (!pdev) {
5561 		spectral_err("pdev is null");
5562 		return QDF_STATUS_E_FAILURE;
5563 	}
5564 
5565 	psoc = wlan_pdev_get_psoc(pdev);
5566 	if (!psoc) {
5567 		spectral_err("psoc is null");
5568 		return QDF_STATUS_E_FAILURE;
5569 	}
5570 
5571 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
5572 	if (!vdev) {
5573 		spectral_err("First vdev is NULL");
5574 		return QDF_STATUS_E_FAILURE;
5575 	}
5576 
5577 	vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
5578 	if (!vdev_rxchainmask) {
5579 		spectral_err("vdev rx chainmask is zero");
5580 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5581 		return QDF_STATUS_E_FAILURE;
5582 	}
5583 
5584 	ch_width = target_if_vdev_get_ch_width(vdev);
5585 	if (ch_width == CH_WIDTH_INVALID) {
5586 		spectral_err("Invalid channel width");
5587 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5588 		return QDF_STATUS_E_FAILURE;
5589 	}
5590 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
5591 
5592 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
5593 	if (!tgt_psoc_info) {
5594 		spectral_err("target_psoc_info is null");
5595 		return QDF_STATUS_E_FAILURE;
5596 	}
5597 
5598 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
5599 	if (!ext_svc_param) {
5600 		spectral_err("Extended service ready param null");
5601 		return QDF_STATUS_E_FAILURE;
5602 	}
5603 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
5604 
5605 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
5606 	if (!mac_phy_cap_arr) {
5607 		spectral_err("mac phy cap array is null");
5608 		return QDF_STATUS_E_FAILURE;
5609 	}
5610 
5611 	mac_phy_cap = &mac_phy_cap_arr[pdev_id];
5612 	if (!mac_phy_cap) {
5613 		spectral_err("mac phy cap is null");
5614 		return QDF_STATUS_E_FAILURE;
5615 	}
5616 
5617 	table_id = mac_phy_cap->chainmask_table_id;
5618 	table =  &ext_svc_param->chainmask_table[table_id];
5619 	if (!table) {
5620 		spectral_err("chainmask table not found");
5621 		return QDF_STATUS_E_FAILURE;
5622 	}
5623 
5624 	for (j = 0; j < table->num_valid_chainmasks; j++) {
5625 		if (table->cap_list[j].chainmask == vdev_rxchainmask) {
5626 			if (ch_width <= CH_WIDTH_80MHZ)
5627 				*is_supported =
5628 					table->cap_list[j].supports_aSpectral;
5629 			else
5630 				*is_supported =
5631 				      table->cap_list[j].supports_aSpectral_160;
5632 			break;
5633 		}
5634 	}
5635 
5636 	if (j == table->num_valid_chainmasks) {
5637 		spectral_err("vdev rx chainmask %u not found in table id = %u",
5638 			     vdev_rxchainmask, table_id);
5639 		return QDF_STATUS_E_FAILURE;
5640 	}
5641 
5642 	return QDF_STATUS_SUCCESS;
5643 }
5644 
5645 #define INVALID_SPAN_NUM (-1)
5646 /**
5647  * target_if_spectral_get_num_spans() - Get number of spans for a given sscan_bw
5648  * @pdev: Pointer to pdev object
5649  * @sscan_bw: Spectral scan bandwidth
5650  *
5651  * Return: Number of spans on success, INVALID_SPAN_NUM on failure
5652  */
5653 static int
5654 target_if_spectral_get_num_spans(
5655 		struct wlan_objmgr_pdev *pdev,
5656 		enum phy_ch_width sscan_bw)
5657 {
5658 	struct wlan_objmgr_psoc *psoc;
5659 	int num_spans;
5660 
5661 	if (!pdev) {
5662 		spectral_err_rl("pdev is null");
5663 		return INVALID_SPAN_NUM;
5664 	}
5665 
5666 	psoc = wlan_pdev_get_psoc(pdev);
5667 	if (!psoc) {
5668 		spectral_err_rl("psoc is null");
5669 		return INVALID_SPAN_NUM;
5670 	}
5671 
5672 	if (sscan_bw == CH_WIDTH_80P80MHZ) {
5673 		num_spans = 2;
5674 		if (wlan_psoc_nif_fw_ext_cap_get(
5675 		    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT))
5676 			/* 5 MHz frequency span in restricted 80p80 case */
5677 			num_spans += 1;
5678 	} else {
5679 		num_spans = 1;
5680 	}
5681 
5682 	return num_spans;
5683 }
5684 
5685 #ifdef OPTIMIZED_SAMP_MESSAGE
5686 /**
5687  * target_if_spectral_populate_session_report_info() - Populate per-session
5688  * report level information.
5689  *
5690  * @spectral: Pointer to Spectral object
5691  * @smode: Spectral scan mode
5692  *
5693  * Return: Success/Failure
5694  */
5695 static QDF_STATUS
5696 target_if_spectral_populate_session_report_info(
5697 				struct target_if_spectral *spectral,
5698 				enum spectral_scan_mode smode)
5699 {
5700 	struct per_session_report_info *rpt_info;
5701 
5702 	if (!spectral) {
5703 		spectral_err_rl("Spectral LMAC object is null");
5704 		return QDF_STATUS_E_NULL_VALUE;
5705 	}
5706 	if (smode > SPECTRAL_SCAN_MODE_MAX) {
5707 		spectral_err_rl("Invalid Spectral scan mode");
5708 		return QDF_STATUS_E_FAILURE;
5709 	}
5710 
5711 
5712 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
5713 	/* Fill per-session report information, based on the spectral mode */
5714 	rpt_info = &spectral->report_info[smode];
5715 
5716 	rpt_info->operating_bw = spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL];
5717 	rpt_info->sscan_bw = spectral->ch_width[smode];
5718 	rpt_info->sscan_cfreq1 = spectral->params[smode].ss_frequency.cfreq1;
5719 	rpt_info->sscan_cfreq2 = spectral->params[smode].ss_frequency.cfreq2;
5720 	rpt_info->num_spans = target_if_spectral_get_num_spans(
5721 						spectral->pdev_obj,
5722 						rpt_info->sscan_bw);
5723 
5724 	qdf_assert_always(rpt_info->num_spans != INVALID_SPAN_NUM);
5725 	rpt_info->valid = true;
5726 
5727 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
5728 
5729 	return QDF_STATUS_SUCCESS;
5730 }
5731 
5732 /**
5733  * target_if_spectral_populate_session_det_host_info() - Populate per-session
5734  * detector level information that is known to the Host
5735  *
5736  * @spectral: Pointer to Spectral object
5737  * @smode: Spectral scan mode
5738  *
5739  * Return: Success/Failure
5740  */
5741 static QDF_STATUS
5742 target_if_spectral_populate_session_det_host_info(
5743 				struct target_if_spectral *spectral,
5744 				enum spectral_scan_mode smode)
5745 {
5746 	struct per_session_report_info *rpt_info;
5747 	struct sscan_detector_list *detector_list;
5748 	struct wlan_objmgr_psoc *psoc;
5749 	uint16_t dest_det_idx = 0;
5750 	uint16_t dest_span_idx = 0;
5751 	bool is_sec80 = false;
5752 	uint8_t det, dest_det;
5753 
5754 	if (!spectral) {
5755 		spectral_err_rl("Spectral LMAC object is null");
5756 		return QDF_STATUS_E_NULL_VALUE;
5757 	}
5758 	if (smode > SPECTRAL_SCAN_MODE_MAX) {
5759 		spectral_err_rl("Invalid Spectral scan mode");
5760 		return QDF_STATUS_E_FAILURE;
5761 	}
5762 
5763 	if (!spectral->pdev_obj) {
5764 		spectral_err_rl("Spectral PDEV is null");
5765 		return QDF_STATUS_E_NULL_VALUE;
5766 	}
5767 
5768 	psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
5769 	if (!psoc) {
5770 		spectral_err_rl("psoc is null");
5771 		return QDF_STATUS_E_NULL_VALUE;
5772 	}
5773 
5774 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
5775 	rpt_info = &spectral->report_info[smode];
5776 
5777 	qdf_spin_lock_bh(&spectral->detector_list_lock);
5778 	/* Fill per-sesion detector-level information */
5779 	detector_list = &spectral->detector_list[smode][rpt_info->sscan_bw];
5780 
5781 	for (det = 0; det < detector_list->num_detectors; det++) {
5782 		struct per_session_det_map *det_map;
5783 
5784 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
5785 		det_map = &spectral->det_map[detector_list->detectors[det]];
5786 		if (detector_list->num_detectors > 1) {
5787 			if (det == 0) {
5788 				det_map->buf_type = SPECTRAL_MSG_BUF_NEW;
5789 				det_map->send_to_upper_layers = false;
5790 			} else if (det == detector_list->num_detectors - 1) {
5791 				det_map->buf_type = SPECTRAL_MSG_BUF_SAVED;
5792 				det_map->send_to_upper_layers = true;
5793 			} else {
5794 				/* middle fragments */
5795 				det_map->buf_type = SPECTRAL_MSG_BUF_SAVED;
5796 				det_map->send_to_upper_layers = false;
5797 			}
5798 		} else {
5799 			det_map->buf_type = SPECTRAL_MSG_BUF_NEW;
5800 			det_map->send_to_upper_layers = true;
5801 		}
5802 
5803 		det_map->num_dest_det_info = 1;
5804 		if (rpt_info->sscan_bw == CH_WIDTH_80P80MHZ &&
5805 		    wlan_psoc_nif_fw_ext_cap_get(
5806 		    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
5807 			/**
5808 			 * In 165MHz case, 1 Spectral HW detector maps to 3
5809 			 * detectors in SAMP msg.
5810 			 */
5811 			det_map->num_dest_det_info += 2;
5812 		}
5813 
5814 		for (dest_det = 0; dest_det < det_map->num_dest_det_info;
5815 		     dest_det++) {
5816 			struct per_session_dest_det_info *map_det_info;
5817 
5818 			map_det_info = &det_map->dest_det_info[dest_det];
5819 			map_det_info->freq_span_id = dest_span_idx;
5820 			map_det_info->det_id = dest_det_idx;
5821 			map_det_info->is_sec80 = is_sec80;
5822 			if (rpt_info->sscan_bw == CH_WIDTH_80P80MHZ) {
5823 			/* Increment span ID for non-contiguous modes */
5824 				dest_det_idx = 0;
5825 				dest_span_idx++;
5826 			} else {
5827 			/* Increment detector ID for contiguous modes */
5828 				dest_det_idx++;
5829 			}
5830 			is_sec80 = !is_sec80;
5831 		}
5832 		det_map->det_map_valid[smode] = true;
5833 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
5834 	}
5835 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
5836 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
5837 
5838 	return QDF_STATUS_SUCCESS;
5839 }
5840 
5841 #else
5842 static QDF_STATUS
5843 target_if_spectral_populate_session_report_info(
5844 				struct target_if_spectral *spectral,
5845 				enum spectral_scan_mode smode)
5846 {
5847 	return QDF_STATUS_SUCCESS;
5848 }
5849 
5850 static QDF_STATUS
5851 target_if_spectral_populate_session_det_host_info(
5852 				struct target_if_spectral *spectral,
5853 				enum spectral_scan_mode smode)
5854 {
5855 	return QDF_STATUS_SUCCESS;
5856 }
5857 #endif /* OPTIMIZED_SAMP_MESSAGE */
5858 
5859 QDF_STATUS
5860 spectral_is_session_info_expected_from_target(struct wlan_objmgr_pdev *pdev,
5861 					      bool *is_session_info_expected)
5862 {
5863 	struct wlan_objmgr_psoc *psoc;
5864 	struct wmi_unified *wmi_handle;
5865 
5866 	if (!pdev) {
5867 		spectral_err("pdev is null");
5868 		return QDF_STATUS_E_NULL_VALUE;
5869 	}
5870 
5871 	psoc = wlan_pdev_get_psoc(pdev);
5872 	if (!psoc) {
5873 		spectral_err("psoc is null");
5874 		return QDF_STATUS_E_NULL_VALUE;
5875 	}
5876 
5877 	wmi_handle =  get_wmi_unified_hdl_from_psoc(psoc);
5878 	if (!wmi_handle) {
5879 		spectral_err("wmi handle is null");
5880 		return QDF_STATUS_E_NULL_VALUE;
5881 	}
5882 
5883 	*is_session_info_expected = target_if_spectral_wmi_service_enabled(
5884 				psoc, wmi_handle,
5885 				wmi_service_spectral_session_info_support);
5886 
5887 	return QDF_STATUS_SUCCESS;
5888 }
5889 
5890 QDF_STATUS
5891 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev,
5892 			      uint8_t vdev_id,
5893 			      const enum spectral_scan_mode smode,
5894 			      enum spectral_cp_error_code *err)
5895 {
5896 	struct target_if_spectral_ops *p_sops;
5897 	struct target_if_spectral *spectral;
5898 	struct wlan_objmgr_psoc *psoc;
5899 	enum reg_wifi_band band;
5900 	QDF_STATUS ret;
5901 	bool is_session_info_expected;
5902 
5903 	if (!err) {
5904 		spectral_err("Error code argument is null");
5905 		QDF_ASSERT(0);
5906 		return QDF_STATUS_E_FAILURE;
5907 	}
5908 	*err = SPECTRAL_SCAN_ERR_INVALID;
5909 
5910 	if (!pdev) {
5911 		spectral_err("pdev object is NUll");
5912 		return QDF_STATUS_E_FAILURE;
5913 	}
5914 
5915 	psoc = wlan_pdev_get_psoc(pdev);
5916 	if (!psoc) {
5917 		spectral_err("psoc is null");
5918 		return QDF_STATUS_E_FAILURE;
5919 	}
5920 
5921 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5922 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5923 		spectral_err("Invalid Spectral mode %u", smode);
5924 		return QDF_STATUS_E_FAILURE;
5925 	}
5926 
5927 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5928 	if (!spectral) {
5929 		spectral_err("Spectral LMAC object is NUll");
5930 		return QDF_STATUS_E_FAILURE;
5931 	}
5932 
5933 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5934 	if (!p_sops) {
5935 		spectral_err("p_sops is null");
5936 		return QDF_STATUS_E_FAILURE;
5937 	}
5938 
5939 	if (p_sops->is_spectral_active(spectral, smode)) {
5940 		spectral_err("spectral in progress in current pdev, mode %d",
5941 			     smode);
5942 		return QDF_STATUS_E_FAILURE;
5943 	}
5944 	spectral->vdev_id[smode] = vdev_id;
5945 
5946 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
5947 		QDF_STATUS status;
5948 		bool is_supported = false;
5949 
5950 		status = target_if_is_agile_supported_cur_chmask(spectral,
5951 								 &is_supported);
5952 		if (QDF_IS_STATUS_ERROR(status)) {
5953 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5954 			return QDF_STATUS_E_FAILURE;
5955 		}
5956 
5957 		if (!is_supported) {
5958 			spectral_err("aSpectral unsupported for cur chainmask");
5959 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
5960 			return QDF_STATUS_E_FAILURE;
5961 		}
5962 	}
5963 
5964 	band = target_if_get_curr_band(spectral->pdev_obj, vdev_id);
5965 	if (band == REG_BAND_UNKNOWN) {
5966 		spectral_err("Failed to get current band");
5967 		return QDF_STATUS_E_FAILURE;
5968 	}
5969 	if ((band == REG_BAND_5G) && (smode == SPECTRAL_SCAN_MODE_AGILE)) {
5970 		struct target_psoc_info *tgt_hdl;
5971 		enum wmi_host_hw_mode_config_type mode;
5972 		bool is_agile_scan_inprog_5g_pdev;
5973 
5974 		tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
5975 		if (!tgt_hdl) {
5976 			target_if_err("target_psoc_info is null");
5977 			return QDF_STATUS_E_FAILURE;
5978 		}
5979 
5980 		mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
5981 		switch (mode) {
5982 		case WMI_HOST_HW_MODE_SBS_PASSIVE:
5983 		case WMI_HOST_HW_MODE_SBS:
5984 		case WMI_HOST_HW_MODE_DBS_SBS:
5985 		case WMI_HOST_HW_MODE_DBS_OR_SBS:
5986 			is_agile_scan_inprog_5g_pdev = false;
5987 			wlan_objmgr_iterate_obj_list
5988 				(psoc, WLAN_PDEV_OP,
5989 				 target_if_is_agile_scan_active_in_5g,
5990 				 &is_agile_scan_inprog_5g_pdev, 0,
5991 				 WLAN_SPECTRAL_ID);
5992 			break;
5993 		default:
5994 			is_agile_scan_inprog_5g_pdev = false;
5995 			break;
5996 		}
5997 
5998 		if (is_agile_scan_inprog_5g_pdev) {
5999 			spectral_err("Agile Scan in progress in one of the SBS 5G pdev");
6000 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6001 			return QDF_STATUS_E_FAILURE;
6002 		}
6003 	}
6004 
6005 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
6006 		bool is_aspectral_prohibited = false;
6007 		QDF_STATUS status;
6008 
6009 		status = wlan_objmgr_iterate_obj_list
6010 				(psoc, WLAN_PDEV_OP,
6011 				 target_if_is_aspectral_prohibited_by_adfs,
6012 				 &is_aspectral_prohibited, 0,
6013 				 WLAN_SPECTRAL_ID);
6014 		if (QDF_IS_STATUS_ERROR(status)) {
6015 			spectral_err("Failed to iterate over pdevs");
6016 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6017 			return QDF_STATUS_E_FAILURE;
6018 		}
6019 
6020 		if (is_aspectral_prohibited) {
6021 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6022 			return QDF_STATUS_E_FAILURE;
6023 		}
6024 	}
6025 
6026 	if (!spectral->params_valid[smode]) {
6027 		target_if_spectral_info_read(spectral,
6028 					     smode,
6029 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
6030 					     &spectral->params[smode],
6031 					     sizeof(spectral->params[smode]));
6032 		spectral->params_valid[smode] = true;
6033 	}
6034 
6035 	qdf_spin_lock_bh(&spectral->spectral_lock);
6036 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
6037 		QDF_STATUS status;
6038 		bool is_overlapping;
6039 		enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
6040 		enum spectral_scan_mode m;
6041 		enum phy_ch_width agile_ch_width;
6042 
6043 		m = SPECTRAL_SCAN_MODE_NORMAL;
6044 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
6045 			ch_width[m] = CH_WIDTH_INVALID;
6046 		status = target_if_spectral_populate_chwidth
6047 			(spectral, ch_width, spectral->params
6048 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
6049 		if (QDF_IS_STATUS_ERROR(status)) {
6050 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6051 			spectral_err("Failed to populate channel width");
6052 			return QDF_STATUS_E_FAILURE;
6053 		}
6054 		agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
6055 
6056 		if (!spectral->params[smode].ss_frequency.cfreq1) {
6057 			*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
6058 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6059 			spectral_err("Agile Spectral cfreq1 is 0");
6060 			return QDF_STATUS_E_FAILURE;
6061 		} else if (agile_ch_width == CH_WIDTH_80P80MHZ &&
6062 			   !spectral->params[smode].ss_frequency.cfreq2) {
6063 			*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
6064 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6065 			spectral_err("Agile Spectral cfreq2 is 0");
6066 			return QDF_STATUS_E_FAILURE;
6067 		}
6068 
6069 		status = target_if_is_agile_span_overlap_with_operating_span
6070 				(spectral, ch_width,
6071 				 &spectral->params[smode].ss_frequency,
6072 				 &is_overlapping);
6073 		if (QDF_IS_STATUS_ERROR(status)) {
6074 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6075 			return QDF_STATUS_E_FAILURE;
6076 		}
6077 
6078 		if (is_overlapping) {
6079 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
6080 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6081 			return QDF_STATUS_E_FAILURE;
6082 		}
6083 	}
6084 
6085 	/* Populate detectot list first */
6086 	ret = target_if_spectral_detector_list_init(spectral);
6087 	if (QDF_IS_STATUS_ERROR(ret)) {
6088 		qdf_spin_unlock_bh(&spectral->spectral_lock);
6089 		spectral_err("Failed to initialize detector list");
6090 		return ret;
6091 	}
6092 
6093 	ret = target_if_spectral_populate_chwidth(
6094 			spectral, spectral->ch_width,
6095 			spectral->params[SPECTRAL_SCAN_MODE_AGILE].
6096 			ss_frequency.cfreq2 > 0);
6097 	if (QDF_IS_STATUS_ERROR(ret)) {
6098 		qdf_spin_unlock_bh(&spectral->spectral_lock);
6099 		spectral_err("Failed to get channel widths");
6100 		return ret;
6101 	}
6102 
6103 	ret = spectral_is_session_info_expected_from_target(
6104 				spectral->pdev_obj,
6105 				&is_session_info_expected);
6106 	if (QDF_IS_STATUS_ERROR(ret)) {
6107 		qdf_spin_unlock_bh(&spectral->spectral_lock);
6108 		spectral_err("Failed to check if session info is expected");
6109 		return ret;
6110 	}
6111 
6112 	/* If FW doesn't send session info, populate it */
6113 	if (!is_session_info_expected) {
6114 		ret = target_if_spectral_populate_session_report_info(spectral,
6115 								      smode);
6116 		if (QDF_IS_STATUS_ERROR(ret)) {
6117 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6118 			spectral_err("Failed to populate per-session report info");
6119 			return QDF_STATUS_E_FAILURE;
6120 		}
6121 
6122 		ret = target_if_spectral_populate_session_det_host_info(
6123 					spectral, smode);
6124 		if (QDF_IS_STATUS_ERROR(ret)) {
6125 			qdf_spin_unlock_bh(&spectral->spectral_lock);
6126 			spectral_err("Failed to populate per-session detector info");
6127 			return QDF_STATUS_E_FAILURE;
6128 		}
6129 	}
6130 
6131 	target_if_spectral_scan_enable_params(spectral,
6132 					      &spectral->params[smode], smode,
6133 					      err);
6134 
6135 	spectral->sscan_width_configured[smode] = false;
6136 	qdf_spin_unlock_bh(&spectral->spectral_lock);
6137 
6138 	return QDF_STATUS_SUCCESS;
6139 }
6140 
6141 QDF_STATUS
6142 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev,
6143 			     const enum spectral_scan_mode smode,
6144 			     enum spectral_cp_error_code *err)
6145 {
6146 	struct target_if_spectral_ops *p_sops;
6147 	struct target_if_spectral *spectral;
6148 	uint8_t det;
6149 
6150 	if (!pdev) {
6151 		spectral_err("pdev object is NULL");
6152 		return QDF_STATUS_E_INVAL;
6153 	}
6154 
6155 	if (target_if_spectral_is_feature_disabled_pdev(pdev)) {
6156 		spectral_info("Spectral feature is disabled");
6157 		return QDF_STATUS_COMP_DISABLED;
6158 	}
6159 
6160 	if (!err) {
6161 		spectral_err("Error code argument is null");
6162 		QDF_ASSERT(0);
6163 		return QDF_STATUS_E_FAILURE;
6164 	}
6165 	*err = SPECTRAL_SCAN_ERR_INVALID;
6166 
6167 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
6168 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
6169 		spectral_err("Invalid Spectral mode %u", smode);
6170 		return QDF_STATUS_E_FAILURE;
6171 	}
6172 
6173 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6174 	if (!spectral) {
6175 		spectral_err("Spectral LMAC object is NUll ");
6176 		return QDF_STATUS_E_FAILURE;
6177 	}
6178 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6179 
6180 	qdf_spin_lock_bh(&spectral->spectral_lock);
6181 	p_sops->stop_spectral_scan(spectral, smode);
6182 	if (spectral->classify_scan) {
6183 		/* TODO : Check if this logic is necessary */
6184 		spectral->detects_control_channel = 0;
6185 		spectral->detects_extension_channel = 0;
6186 		spectral->detects_above_dc = 0;
6187 		spectral->detects_below_dc = 0;
6188 		spectral->classify_scan = 0;
6189 	}
6190 
6191 	spectral->send_single_packet = 0;
6192 	spectral->sc_spectral_scan = 0;
6193 
6194 	qdf_spin_lock_bh(&spectral->session_det_map_lock);
6195 	for (det = 0; det < MAX_DETECTORS_PER_PDEV; det++)
6196 		spectral->det_map[det].det_map_valid[smode] = false;
6197 
6198 	qdf_spin_unlock_bh(&spectral->session_det_map_lock);
6199 
6200 	/* Mark report info as invalid */
6201 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
6202 	spectral->report_info[smode].valid = false;
6203 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
6204 
6205 	qdf_spin_unlock_bh(&spectral->spectral_lock);
6206 
6207 	return QDF_STATUS_SUCCESS;
6208 }
6209 
6210 /**
6211  * target_if_is_spectral_active() - Get whether Spectral is active
6212  * @pdev: Pointer to pdev object
6213  * @smode: Spectral scan mode
6214  *
6215  * API to get whether Spectral is active
6216  *
6217  * Return: True if Spectral is active, false if Spectral is not active
6218  */
6219 bool
6220 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev,
6221 			     const enum spectral_scan_mode smode)
6222 {
6223 	struct target_if_spectral *spectral = NULL;
6224 	struct target_if_spectral_ops *p_sops = NULL;
6225 
6226 	if (!pdev) {
6227 		spectral_err("pdev is null");
6228 		return false;
6229 	}
6230 
6231 	if (target_if_spectral_is_feature_disabled_pdev(pdev)) {
6232 		spectral_info("Spectral feature is disabled");
6233 		return false;
6234 	}
6235 
6236 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6237 
6238 	if (!spectral) {
6239 		spectral_err("SPECTRAL : Module doesn't exist");
6240 		return false;
6241 	}
6242 
6243 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6244 
6245 	if (!p_sops) {
6246 		spectral_err("p_sops is null");
6247 		return false;
6248 	}
6249 
6250 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
6251 		spectral_err("Invalid Spectral mode %u", smode);
6252 		return false;
6253 	}
6254 
6255 	return p_sops->is_spectral_active(spectral, smode);
6256 }
6257 
6258 /**
6259  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
6260  * @pdev: Pointer to pdev object
6261  * @smode: Spectral scan mode
6262  *
6263  * API to get whether Spectral is enabled
6264  *
6265  * Return: True if Spectral is enabled, false if Spectral is not enabled
6266  */
6267 bool
6268 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev,
6269 			      enum spectral_scan_mode smode)
6270 {
6271 	struct target_if_spectral *spectral = NULL;
6272 	struct target_if_spectral_ops *p_sops = NULL;
6273 
6274 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6275 
6276 	if (!spectral) {
6277 		spectral_err("SPECTRAL : Module doesn't exist");
6278 		return false;
6279 	}
6280 
6281 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6282 
6283 	if (!p_sops) {
6284 		spectral_err("p_sops is null");
6285 		return false;
6286 	}
6287 
6288 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
6289 		spectral_err("Invalid Spectral mode %u", smode);
6290 		return false;
6291 	}
6292 
6293 	return p_sops->is_spectral_enabled(spectral, smode);
6294 }
6295 
6296 #ifdef DIRECT_BUF_RX_DEBUG
6297 /**
6298  * target_if_spectral_do_dbr_ring_debug() - Start/Stop Spectral DMA ring debug
6299  * @pdev: Pointer to pdev object
6300  * @enable: Enable/Disable Spectral DMA ring debug
6301  *
6302  * Start/stop Spectral DMA ring debug based on @enable.
6303  * Also save the state for future use.
6304  *
6305  * Return: QDF_STATUS of operation
6306  */
6307 static QDF_STATUS
6308 target_if_spectral_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev, bool enable)
6309 {
6310 	struct target_if_spectral *spectral;
6311 	struct wlan_lmac_if_tx_ops *tx_ops;
6312 	struct wlan_objmgr_psoc *psoc;
6313 
6314 	if (!pdev)
6315 		return QDF_STATUS_E_FAILURE;
6316 
6317 	psoc = wlan_pdev_get_psoc(pdev);
6318 	if (!psoc) {
6319 		spectral_err("psoc is null");
6320 		return QDF_STATUS_E_INVAL;
6321 	}
6322 
6323 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
6324 	if (!tx_ops) {
6325 		spectral_err("tx_ops is NULL");
6326 		return QDF_STATUS_E_INVAL;
6327 	}
6328 
6329 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6330 	if (!spectral) {
6331 		spectral_err("Spectal LMAC object is NULL");
6332 		return QDF_STATUS_E_INVAL;
6333 	}
6334 
6335 	/* Save the state */
6336 	spectral->dbr_ring_debug = enable;
6337 
6338 	if (enable)
6339 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_ring_debug(
6340 				pdev, 0, SPECTRAL_DBR_RING_DEBUG_SIZE);
6341 	else
6342 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_ring_debug(
6343 				pdev, 0);
6344 
6345 	return QDF_STATUS_SUCCESS;
6346 }
6347 
6348 /**
6349  * target_if_spectral_do_dbr_buff_debug() - Start/Stop Spectral DMA buffer debug
6350  * @pdev: Pointer to pdev object
6351  * @enable: Enable/Disable Spectral DMA buffer debug
6352  *
6353  * Start/stop Spectral DMA buffer debug based on @enable.
6354  * Also save the state for future use.
6355  *
6356  * Return: QDF_STATUS of operation
6357  */
6358 static QDF_STATUS
6359 target_if_spectral_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev, bool enable)
6360 {
6361 	struct target_if_spectral *spectral;
6362 	struct wlan_lmac_if_tx_ops *tx_ops;
6363 	struct wlan_objmgr_psoc *psoc;
6364 
6365 	if (!pdev)
6366 		return QDF_STATUS_E_FAILURE;
6367 
6368 	psoc = wlan_pdev_get_psoc(pdev);
6369 	if (!psoc) {
6370 		spectral_err("psoc is null");
6371 		return QDF_STATUS_E_INVAL;
6372 	}
6373 
6374 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
6375 	if (!tx_ops) {
6376 		spectral_err("tx_ops is NULL");
6377 		return QDF_STATUS_E_INVAL;
6378 	}
6379 
6380 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6381 	if (!spectral) {
6382 		spectral_err("Spectal LMAC object is NULL");
6383 		return QDF_STATUS_E_INVAL;
6384 	}
6385 
6386 	/* Save the state */
6387 	spectral->dbr_buff_debug = enable;
6388 
6389 	if (enable)
6390 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_buffer_poisoning(
6391 				pdev, 0, MEM_POISON_SIGNATURE);
6392 	else
6393 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_buffer_poisoning(
6394 				pdev, 0);
6395 }
6396 
6397 /**
6398  * target_if_spectral_check_and_do_dbr_buff_debug() - Start/Stop Spectral buffer
6399  * debug based on the previous state
6400  * @pdev: Pointer to pdev object
6401  *
6402  * Return: QDF_STATUS of operation
6403  */
6404 static QDF_STATUS
6405 target_if_spectral_check_and_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev)
6406 {
6407 	struct target_if_spectral *spectral;
6408 
6409 	if (!pdev) {
6410 		spectral_err("pdev is NULL!");
6411 		return QDF_STATUS_E_FAILURE;
6412 	}
6413 
6414 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6415 	if (!spectral) {
6416 		spectral_err("Spectal LMAC object is NULL");
6417 		return QDF_STATUS_E_INVAL;
6418 	}
6419 
6420 	if (spectral->dbr_buff_debug)
6421 		return target_if_spectral_do_dbr_buff_debug(pdev, true);
6422 	else
6423 		return target_if_spectral_do_dbr_buff_debug(pdev, false);
6424 }
6425 
6426 /**
6427  * target_if_spectral_check_and_do_dbr_ring_debug() - Start/Stop Spectral ring
6428  * debug based on the previous state
6429  * @pdev: Pointer to pdev object
6430  *
6431  * Return: QDF_STATUS of operation
6432  */
6433 static QDF_STATUS
6434 target_if_spectral_check_and_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev)
6435 {
6436 	struct target_if_spectral *spectral;
6437 
6438 	if (!pdev) {
6439 		spectral_err("pdev is NULL!");
6440 		return QDF_STATUS_E_FAILURE;
6441 	}
6442 
6443 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6444 	if (!spectral) {
6445 		spectral_err("Spectal LMAC object is NULL");
6446 		return QDF_STATUS_E_INVAL;
6447 	}
6448 
6449 	if (spectral->dbr_ring_debug)
6450 		return target_if_spectral_do_dbr_ring_debug(pdev, true);
6451 	else
6452 		return target_if_spectral_do_dbr_ring_debug(pdev, false);
6453 }
6454 
6455 /**
6456  * target_if_spectral_set_dma_debug() - Set DMA debug for Spectral
6457  * @pdev: Pointer to pdev object
6458  * @dma_debug_type: Type of Spectral DMA debug i.e., ring or buffer debug
6459  * @debug_value: Value to be set for @dma_debug_type
6460  *
6461  * Set DMA debug for Spectral and start/stop Spectral DMA debug function
6462  * based on @debug_value
6463  *
6464  * Return: QDF_STATUS of operation
6465  */
6466 static QDF_STATUS
6467 target_if_spectral_set_dma_debug(
6468 	struct wlan_objmgr_pdev *pdev,
6469 	enum spectral_dma_debug dma_debug_type,
6470 	bool debug_value)
6471 {
6472 	struct target_if_spectral_ops *p_sops;
6473 	struct wlan_objmgr_psoc *psoc;
6474 	struct wlan_lmac_if_tx_ops *tx_ops;
6475 	struct target_if_spectral *spectral;
6476 
6477 	if (!pdev)
6478 		return QDF_STATUS_E_FAILURE;
6479 
6480 	psoc = wlan_pdev_get_psoc(pdev);
6481 	if (!psoc) {
6482 		spectral_err("psoc is null");
6483 		return QDF_STATUS_E_INVAL;
6484 	}
6485 
6486 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
6487 	if (!tx_ops) {
6488 		spectral_err("tx_ops is NULL");
6489 		return QDF_STATUS_E_FAILURE;
6490 	}
6491 
6492 	if (!tx_ops->target_tx_ops.tgt_get_tgt_type) {
6493 		spectral_err("Unable to fetch target type");
6494 		return QDF_STATUS_E_FAILURE;
6495 	}
6496 
6497 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6498 	if (!spectral) {
6499 		spectral_err("Spectal LMAC object is NULL");
6500 		return QDF_STATUS_E_INVAL;
6501 	}
6502 
6503 	if (spectral->direct_dma_support) {
6504 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6505 		if (p_sops->is_spectral_active(spectral,
6506 					       SPECTRAL_SCAN_MODE_NORMAL) ||
6507 		    p_sops->is_spectral_active(spectral,
6508 					       SPECTRAL_SCAN_MODE_AGILE)) {
6509 			spectral_err("Altering DBR debug config isn't allowed during an ongoing scan");
6510 			return QDF_STATUS_E_FAILURE;
6511 		}
6512 
6513 		switch (dma_debug_type) {
6514 		case SPECTRAL_DMA_RING_DEBUG:
6515 			target_if_spectral_do_dbr_ring_debug(pdev, debug_value);
6516 			break;
6517 
6518 		case SPECTRAL_DMA_BUFFER_DEBUG:
6519 			target_if_spectral_do_dbr_buff_debug(pdev, debug_value);
6520 			break;
6521 
6522 		default:
6523 			spectral_err("Unsupported DMA debug type : %d",
6524 				     dma_debug_type);
6525 			return QDF_STATUS_E_FAILURE;
6526 		}
6527 	}
6528 	return QDF_STATUS_SUCCESS;
6529 }
6530 #endif /* DIRECT_BUF_RX_DEBUG */
6531 
6532 /**
6533  * target_if_spectral_direct_dma_support() - Get Direct-DMA support
6534  * @pdev: Pointer to pdev object
6535  *
6536  * Return: Whether Direct-DMA is supported on this radio
6537  */
6538 static bool
6539 target_if_spectral_direct_dma_support(struct wlan_objmgr_pdev *pdev)
6540 {
6541 	struct target_if_spectral *spectral;
6542 
6543 	if (!pdev) {
6544 		spectral_err("pdev is NULL!");
6545 		return false;
6546 	}
6547 
6548 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6549 	if (!spectral) {
6550 		spectral_err("Spectral LMAC object is NULL");
6551 		return false;
6552 	}
6553 
6554 	return spectral->direct_dma_support;
6555 }
6556 
6557 /**
6558  * target_if_set_debug_level() - Set debug level for Spectral
6559  * @pdev: Pointer to pdev object
6560  * @debug_level: Debug level
6561  *
6562  * API to set the debug level for Spectral
6563  *
6564  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
6565  */
6566 QDF_STATUS
6567 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
6568 {
6569 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
6570 
6571 	return QDF_STATUS_SUCCESS;
6572 }
6573 
6574 /**
6575  * target_if_get_debug_level() - Get debug level for Spectral
6576  * @pdev: Pointer to pdev object
6577  *
6578  * API to get the debug level for Spectral
6579  *
6580  * Return: Current debug level
6581  */
6582 uint32_t
6583 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
6584 {
6585 	return spectral_debug_level;
6586 }
6587 
6588 /**
6589  * target_if_get_spectral_capinfo() - Get Spectral capability information
6590  * @pdev: Pointer to pdev object
6591  * @scaps: Buffer into which data should be copied
6592  *
6593  * API to get the spectral capability information
6594  *
6595  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
6596  */
6597 QDF_STATUS
6598 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev,
6599 			       struct spectral_caps *scaps)
6600 {
6601 	struct target_if_spectral *spectral = NULL;
6602 
6603 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6604 	if (!spectral) {
6605 		spectral_err("SPECTRAL : Module doesn't exist");
6606 		return QDF_STATUS_E_FAILURE;
6607 	}
6608 
6609 	qdf_mem_copy(scaps, &spectral->capability,
6610 		     sizeof(struct spectral_caps));
6611 
6612 	return QDF_STATUS_SUCCESS;
6613 }
6614 
6615 /**
6616  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
6617  * @pdev:  Pointer to pdev object
6618  * @stats: Buffer into which data should be copied
6619  *
6620  * API to get the spectral diagnostic statistics
6621  *
6622  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
6623  */
6624 QDF_STATUS
6625 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev,
6626 				 struct spectral_diag_stats *stats)
6627 {
6628 	struct target_if_spectral *spectral = NULL;
6629 
6630 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6631 	if (!spectral) {
6632 		spectral_err("SPECTRAL : Module doesn't exist");
6633 		return QDF_STATUS_E_FAILURE;
6634 	}
6635 
6636 	qdf_mem_copy(stats, &spectral->diag_stats,
6637 		     sizeof(struct spectral_diag_stats));
6638 
6639 	return QDF_STATUS_SUCCESS;
6640 }
6641 
6642 /**
6643  * target_if_register_spectral_wmi_ops() - Register Spectral WMI operations
6644  * @psoc: Pointer to psoc object
6645  * @wmi_ops: Pointer to the structure having Spectral WMI operations
6646  *
6647  * API for registering Spectral WMI operations in
6648  * spectral internal data structure
6649  *
6650  * Return: QDF_STATUS
6651  */
6652 static QDF_STATUS
6653 target_if_register_spectral_wmi_ops(struct wlan_objmgr_psoc *psoc,
6654 				    struct spectral_wmi_ops *wmi_ops)
6655 {
6656 	struct target_if_psoc_spectral *psoc_spectral;
6657 
6658 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6659 	if (!psoc_spectral) {
6660 		spectral_err("Spectral LMAC object is null");
6661 		return QDF_STATUS_E_INVAL;
6662 	}
6663 
6664 	psoc_spectral->wmi_ops = *wmi_ops;
6665 
6666 	return QDF_STATUS_SUCCESS;
6667 }
6668 
6669 /**
6670  * target_if_register_spectral_tgt_ops() - Register Spectral target operations
6671  * @psoc: Pointer to psoc object
6672  * @tgt_ops: Pointer to the structure having Spectral target operations
6673  *
6674  * API for registering Spectral target operations in
6675  * spectral internal data structure
6676  *
6677  * Return: QDF_STATUS
6678  */
6679 static QDF_STATUS
6680 target_if_register_spectral_tgt_ops(struct wlan_objmgr_psoc *psoc,
6681 				    struct spectral_tgt_ops *tgt_ops)
6682 {
6683 	if (!psoc) {
6684 		spectral_err("psoc is null");
6685 		return QDF_STATUS_E_INVAL;
6686 	}
6687 
6688 	ops_tgt = *tgt_ops;
6689 
6690 	return QDF_STATUS_SUCCESS;
6691 }
6692 
6693 /**
6694  * target_if_register_netlink_cb() - Register Netlink callbacks
6695  * @pdev: Pointer to pdev object
6696  * @nl_cb: Netlink callbacks to register
6697  *
6698  * Return: void
6699  */
6700 static void
6701 target_if_register_netlink_cb(
6702 	struct wlan_objmgr_pdev *pdev,
6703 	struct spectral_nl_cb *nl_cb)
6704 {
6705 	struct target_if_spectral *spectral = NULL;
6706 
6707 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6708 
6709 	if (!spectral) {
6710 		spectral_err("SPECTRAL : Module doesn't exist");
6711 		return;
6712 	}
6713 
6714 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
6715 
6716 	if (spectral->use_nl_bcast)
6717 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
6718 	else
6719 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
6720 }
6721 
6722 /**
6723  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
6724  * Netlink messages to the application layer
6725  * @pdev: Pointer to pdev object
6726  *
6727  * Return: true for broadcast, false for unicast
6728  */
6729 static bool
6730 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
6731 {
6732 	struct target_if_spectral *spectral = NULL;
6733 
6734 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6735 
6736 	if (!spectral) {
6737 		spectral_err("SPECTRAL : Module doesn't exist");
6738 		return false;
6739 	}
6740 
6741 	return spectral->use_nl_bcast;
6742 }
6743 
6744 /**
6745  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
6746  * @pdev: Pointer to pdev object
6747  *
6748  * Return: void
6749  */
6750 static void
6751 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
6752 {
6753 	struct target_if_spectral *spectral = NULL;
6754 
6755 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6756 	if (!spectral) {
6757 		spectral_err("SPECTRAL : Module doesn't exist");
6758 		return;
6759 	}
6760 
6761 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
6762 }
6763 
6764 static int
6765 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
6766 				  void *payload)
6767 {
6768 	struct target_if_spectral *spectral = NULL;
6769 	struct target_if_spectral_ops *p_sops = NULL;
6770 
6771 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
6772 	if (!spectral) {
6773 		spectral_err("SPECTRAL : Module doesn't exist");
6774 		return -EPERM;
6775 	}
6776 
6777 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
6778 
6779 	if (!p_sops) {
6780 		spectral_err("p_sops is null");
6781 		return -EPERM;
6782 	}
6783 
6784 	return p_sops->process_spectral_report(pdev, payload);
6785 }
6786 
6787 #ifdef DIRECT_BUF_RX_DEBUG
6788 static inline void
6789 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
6790 {
6791 	if (!tx_ops) {
6792 		spectral_err("tx_ops is NULL");
6793 		return;
6794 	}
6795 
6796 	tx_ops->sptrl_tx_ops.sptrlto_set_dma_debug =
6797 		target_if_spectral_set_dma_debug;
6798 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_ring_debug =
6799 		target_if_spectral_check_and_do_dbr_ring_debug;
6800 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_buff_debug =
6801 		target_if_spectral_check_and_do_dbr_buff_debug;
6802 }
6803 #else
6804 static inline void
6805 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
6806 {
6807 }
6808 #endif
6809 
6810 #if defined(WLAN_CONV_SPECTRAL_ENABLE) && defined(SPECTRAL_MODULIZED_ENABLE)
6811 /**
6812  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
6813  * register WMI event handler
6814  * @psoc: Pointer to psoc object
6815  * @event_id: Event id
6816  * @handler_func: Handler function
6817  * @rx_ctx: Context of WMI event processing
6818  *
6819  * Wrapper function to register WMI event handler
6820  *
6821  * Return: 0 for success else failure
6822  */
6823 static int
6824 target_if_spectral_wmi_unified_register_event_handler(
6825 				struct wlan_objmgr_psoc *psoc,
6826 				wmi_conv_event_id event_id,
6827 				wmi_unified_event_handler handler_func,
6828 				uint8_t rx_ctx)
6829 {
6830 	wmi_unified_t wmi_handle;
6831 	struct target_if_psoc_spectral *psoc_spectral;
6832 	QDF_STATUS ret;
6833 
6834 	if (!psoc) {
6835 		spectral_err("psoc is null");
6836 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6837 	}
6838 
6839 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6840 	if (!wmi_handle) {
6841 		spectral_err("WMI handle is null");
6842 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6843 	}
6844 
6845 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6846 	if (!psoc_spectral) {
6847 		spectral_err("spectral object is null");
6848 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
6849 	}
6850 
6851 	ret = psoc_spectral->wmi_ops.wmi_unified_register_event_handler(
6852 			wmi_handle, event_id, handler_func, rx_ctx);
6853 
6854 	return qdf_status_to_os_return(ret);
6855 }
6856 
6857 /**
6858  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
6859  * to unregister WMI event handler
6860  * @psoc: Pointer to psoc object
6861  * @event_id: Event id
6862  *
6863  * Wrapper function to unregister WMI event handler
6864  *
6865  * Return: 0 for success else failure
6866  */
6867 static int
6868 target_if_spectral_wmi_unified_unregister_event_handler(
6869 				struct wlan_objmgr_psoc *psoc,
6870 				wmi_conv_event_id event_id)
6871 {
6872 	wmi_unified_t wmi_handle;
6873 	struct target_if_psoc_spectral *psoc_spectral;
6874 	QDF_STATUS ret;
6875 
6876 	if (!psoc) {
6877 		spectral_err("psoc is null");
6878 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6879 	}
6880 
6881 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6882 	if (!wmi_handle) {
6883 		spectral_err("WMI handle is null");
6884 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
6885 	}
6886 
6887 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6888 	if (!psoc_spectral) {
6889 		spectral_err("spectral object is null");
6890 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
6891 	}
6892 
6893 	ret = psoc_spectral->wmi_ops.wmi_unified_unregister_event_handler(
6894 					wmi_handle, event_id);
6895 
6896 	return qdf_status_to_os_return(ret);
6897 }
6898 
6899 /**
6900  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
6901  * function to extract fixed parameters from start scan response event
6902  * @psoc: Pointer to psoc object
6903  * @evt_buf: Event buffer
6904  * @param: Start scan response parameters
6905  *
6906  * Wrapper function to extract fixed parameters from start scan response event
6907  *
6908  * Return: QDF_STATUS
6909  */
6910 static QDF_STATUS
6911 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
6912 			struct wlan_objmgr_psoc *psoc,
6913 			uint8_t *evt_buf,
6914 			struct spectral_startscan_resp_params *param)
6915 {
6916 	wmi_unified_t wmi_handle;
6917 	struct target_if_psoc_spectral *psoc_spectral;
6918 
6919 	if (!psoc) {
6920 		spectral_err("psoc is null");
6921 		return QDF_STATUS_E_INVAL;
6922 	}
6923 
6924 	if (!evt_buf) {
6925 		spectral_err("WMI event buffer is null");
6926 		return QDF_STATUS_E_INVAL;
6927 	}
6928 
6929 	if (!param) {
6930 		spectral_err("Spectral startscan response parameters is null");
6931 		return QDF_STATUS_E_INVAL;
6932 	}
6933 
6934 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6935 	if (!wmi_handle) {
6936 		spectral_err("WMI handle is null");
6937 		return QDF_STATUS_E_INVAL;
6938 	}
6939 
6940 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6941 	if (!psoc_spectral) {
6942 		spectral_err("spectral object is null");
6943 		return QDF_STATUS_E_FAILURE;
6944 	}
6945 
6946 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fw_cmd_fixed_param(
6947 			wmi_handle, evt_buf, param);
6948 }
6949 
6950 /**
6951  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
6952  * function to extract start and end indices of primary 80 MHz, 5 MHz and
6953  * secondary 80 MHz FFT bins
6954  * @psoc: Pointer to psoc object
6955  * @evt_buf: Event buffer
6956  * @param: FFT bin start and end indices
6957  *
6958  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
6959  * and secondary 80 MHz FFT bins
6960  *
6961  * Return: QDF_STATUS
6962  */
6963 static QDF_STATUS
6964 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
6965 			struct wlan_objmgr_psoc *psoc,
6966 			uint8_t *evt_buf,
6967 			struct spectral_fft_bin_markers_160_165mhz *param)
6968 {
6969 	wmi_unified_t wmi_handle;
6970 	struct target_if_psoc_spectral *psoc_spectral;
6971 
6972 	if (!psoc) {
6973 		spectral_err("psoc is null");
6974 		return QDF_STATUS_E_INVAL;
6975 	}
6976 
6977 	if (!evt_buf) {
6978 		spectral_err("WMI event buffer is null");
6979 		return QDF_STATUS_E_INVAL;
6980 	}
6981 
6982 	if (!param) {
6983 		spectral_err("Spectral FFT bin markers is null");
6984 		return QDF_STATUS_E_INVAL;
6985 	}
6986 
6987 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
6988 	if (!wmi_handle) {
6989 		spectral_err("WMI handle is null");
6990 		return QDF_STATUS_E_INVAL;
6991 	}
6992 
6993 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
6994 	if (!psoc_spectral) {
6995 		spectral_err("spectral object is null");
6996 		return QDF_STATUS_E_FAILURE;
6997 	}
6998 
6999 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fft_bin_index(
7000 			wmi_handle, evt_buf, param);
7001 }
7002 
7003 /**
7004  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
7005  * object from scn handle
7006  * @scn: scn handle
7007  *
7008  * Wrapper function to get psoc object from scn handle
7009  *
7010  * Return: Pointer to psoc object
7011  */
7012 static struct wlan_objmgr_psoc *
7013 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
7014 {
7015 	if (!scn) {
7016 		spectral_err("scn is null");
7017 		return NULL;
7018 	}
7019 
7020 	return ops_tgt.tgt_get_psoc_from_scn_hdl(scn);
7021 }
7022 
7023 /**
7024  * target_if_extract_pdev_spectral_session_chan_info() - Wrapper
7025  * function to extract channel information for a spectral scan session
7026  * @psoc: Pointer to psoc object
7027  * @evt_buf: Event buffer
7028  * @chan_info: Spectral session channel information data structure to be filled
7029  * by this API
7030  *
7031  * Return: QDF_STATUS of operation
7032  */
7033 static QDF_STATUS
7034 target_if_extract_pdev_spectral_session_chan_info(
7035 			struct wlan_objmgr_psoc *psoc,
7036 			void *evt_buf,
7037 			struct spectral_session_chan_info *chan_info)
7038 {
7039 	wmi_unified_t wmi_handle;
7040 	struct target_if_psoc_spectral *psoc_spectral;
7041 
7042 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7043 	if (!wmi_handle) {
7044 		spectral_err("WMI handle is null");
7045 		return QDF_STATUS_E_NULL_VALUE;
7046 	}
7047 
7048 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7049 	if (!psoc_spectral) {
7050 		spectral_err("spectral object is null");
7051 		return QDF_STATUS_E_NULL_VALUE;
7052 	}
7053 
7054 	return psoc_spectral->wmi_ops.extract_pdev_spectral_session_chan_info(
7055 			wmi_handle, evt_buf, chan_info);
7056 }
7057 
7058 /**
7059  * target_if_extract_pdev_spectral_session_detector_info() - Wrapper
7060  * function to extract detector information for a spectral scan session
7061  * @psoc: Pointer to psoc object
7062  * @evt_buf: Event buffer
7063  * @det_info: Spectral session detector information data structure to be filled
7064  * by this API
7065  * @det_info_idx: index in the array of spectral scan detector info TLVs
7066  *
7067  * Return: QDF_STATUS of operation
7068  */
7069 static QDF_STATUS
7070 target_if_extract_pdev_spectral_session_detector_info(
7071 			struct wlan_objmgr_psoc *psoc, void *evt_buf,
7072 			struct spectral_session_det_info *det_info,
7073 			uint8_t det_info_idx)
7074 {
7075 	wmi_unified_t wmi_handle;
7076 	struct target_if_psoc_spectral *psoc_spectral;
7077 
7078 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7079 	if (!wmi_handle) {
7080 		spectral_err("WMI handle is null");
7081 		return QDF_STATUS_E_NULL_VALUE;
7082 	}
7083 
7084 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7085 	if (!psoc_spectral) {
7086 		spectral_err("spectral object is null");
7087 		return QDF_STATUS_E_NULL_VALUE;
7088 	}
7089 
7090 	return psoc_spectral->wmi_ops.
7091 			extract_pdev_spectral_session_detector_info(
7092 				wmi_handle, evt_buf, det_info, det_info_idx);
7093 }
7094 
7095 /**
7096  * target_if_wmi_extract_spectral_caps_fixed_param() - Wrapper function to
7097  * extract fixed params from Spectral capabilities WMI event
7098  * @psoc: Pointer to psoc object
7099  * @evt_buf: Event buffer
7100  * @param: Spectral capabilities event parameters data structure to be filled
7101  * by this API
7102  *
7103  * Return: QDF_STATUS of operation
7104  */
7105 QDF_STATUS
7106 target_if_wmi_extract_spectral_caps_fixed_param(
7107 			struct wlan_objmgr_psoc *psoc,
7108 			uint8_t *evt_buf,
7109 			struct spectral_capabilities_event_params *param)
7110 {
7111 	struct target_if_psoc_spectral *psoc_spectral;
7112 	wmi_unified_t wmi_handle;
7113 
7114 	if (!psoc) {
7115 		spectral_err("psoc is null");
7116 		return QDF_STATUS_E_NULL_VALUE;
7117 	}
7118 
7119 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7120 	if (!wmi_handle) {
7121 		spectral_err("WMI handle is null");
7122 		return QDF_STATUS_E_NULL_VALUE;
7123 	}
7124 
7125 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7126 	if (!psoc_spectral) {
7127 		spectral_err("spectral object is null");
7128 		return QDF_STATUS_E_FAILURE;
7129 	}
7130 
7131 	return psoc_spectral->wmi_ops.extract_spectral_caps_fixed_param(
7132 			wmi_handle, evt_buf, param);
7133 }
7134 
7135 /**
7136  * target_if_wmi_extract_spectral_scan_bw_caps() - Wrapper function to
7137  * extract bandwidth capabilities from Spectral capabilities WMI event
7138  * @psoc: Pointer to psoc object
7139  * @evt_buf: Event buffer
7140  * @bw_caps: Data structure to be filled by this API after extraction
7141  *
7142  * Return: QDF_STATUS of operation
7143  */
7144 QDF_STATUS
7145 target_if_wmi_extract_spectral_scan_bw_caps(
7146 			struct wlan_objmgr_psoc *psoc,
7147 			uint8_t *evt_buf,
7148 			struct spectral_scan_bw_capabilities *bw_caps)
7149 {
7150 	struct target_if_psoc_spectral *psoc_spectral;
7151 	wmi_unified_t wmi_handle;
7152 
7153 	if (!psoc) {
7154 		spectral_err("psoc is null");
7155 		return QDF_STATUS_E_INVAL;
7156 	}
7157 
7158 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7159 	if (!wmi_handle) {
7160 		spectral_err("WMI handle is null");
7161 		return QDF_STATUS_E_INVAL;
7162 	}
7163 
7164 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7165 	if (!psoc_spectral) {
7166 		spectral_err("spectral object is null");
7167 		return QDF_STATUS_E_FAILURE;
7168 	}
7169 
7170 	return psoc_spectral->wmi_ops.extract_spectral_scan_bw_caps(
7171 			wmi_handle, evt_buf, bw_caps);
7172 }
7173 
7174 /**
7175  * target_if_wmi_extract_spectral_fft_size_caps() - Wrapper function to
7176  * extract fft size capabilities from Spectral capabilities WMI event
7177  * @psoc: Pointer to psoc object
7178  * @evt_buf: Event buffer
7179  * @fft_size_caps: Data structure to be filled by this API after extraction
7180  *
7181  * Return: QDF_STATUS of operation
7182  */
7183 QDF_STATUS
7184 target_if_wmi_extract_spectral_fft_size_caps(
7185 			struct wlan_objmgr_psoc *psoc,
7186 			uint8_t *evt_buf,
7187 			struct spectral_fft_size_capabilities *fft_size_caps)
7188 {
7189 	struct target_if_psoc_spectral *psoc_spectral;
7190 	wmi_unified_t wmi_handle;
7191 
7192 	if (!psoc) {
7193 		spectral_err("psoc is null");
7194 		return QDF_STATUS_E_INVAL;
7195 	}
7196 
7197 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7198 	if (!wmi_handle) {
7199 		spectral_err("WMI handle is null");
7200 		return QDF_STATUS_E_INVAL;
7201 	}
7202 
7203 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7204 	if (!psoc_spectral) {
7205 		spectral_err("spectral object is null");
7206 		return QDF_STATUS_E_FAILURE;
7207 	}
7208 
7209 	return psoc_spectral->wmi_ops.extract_spectral_fft_size_caps(
7210 			wmi_handle, evt_buf, fft_size_caps);
7211 }
7212 #else
7213 /**
7214  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
7215  * register WMI event handler
7216  * @psoc: Pointer to psoc object
7217  * @event_id: Event id
7218  * @handler_func: Handler function
7219  * @rx_ctx: Context of WMI event processing
7220  *
7221  * Wrapper function to register WMI event handler
7222  *
7223  * Return: 0 for success else failure
7224  */
7225 static int
7226 target_if_spectral_wmi_unified_register_event_handler(
7227 				struct wlan_objmgr_psoc *psoc,
7228 				wmi_conv_event_id event_id,
7229 				wmi_unified_event_handler handler_func,
7230 				uint8_t rx_ctx)
7231 {
7232 	wmi_unified_t wmi_handle;
7233 	QDF_STATUS ret;
7234 
7235 	if (!psoc) {
7236 		spectral_err("psoc is null");
7237 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7238 	}
7239 
7240 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7241 	if (!wmi_handle) {
7242 		spectral_err("WMI handle is null");
7243 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7244 	}
7245 
7246 	ret = wmi_unified_register_event_handler(wmi_handle, event_id,
7247 						 handler_func, rx_ctx);
7248 
7249 	return qdf_status_to_os_return(ret);
7250 }
7251 
7252 /**
7253  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
7254  * to unregister WMI event handler
7255  * @psoc: Pointer to psoc object
7256  * @event_id: Event id
7257  *
7258  * Wrapper function to unregister WMI event handler
7259  *
7260  * Return: 0 for success else failure
7261  */
7262 static int
7263 target_if_spectral_wmi_unified_unregister_event_handler(
7264 				struct wlan_objmgr_psoc *psoc,
7265 				wmi_conv_event_id event_id)
7266 {
7267 	wmi_unified_t wmi_handle;
7268 	QDF_STATUS ret;
7269 
7270 	if (!psoc) {
7271 		spectral_err("psoc is null");
7272 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7273 	}
7274 
7275 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7276 	if (!wmi_handle) {
7277 		spectral_err("WMI handle is null");
7278 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7279 	}
7280 
7281 	ret = wmi_unified_unregister_event_handler(wmi_handle, event_id);
7282 
7283 	return qdf_status_to_os_return(ret);
7284 }
7285 
7286 /**
7287  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
7288  * function to extract fixed parameters from start scan response event
7289  * @psoc: Pointer to psoc object
7290  * @evt_buf: Event buffer
7291  * @param: Start scan response parameters
7292  *
7293  * Wrapper function to extract fixed parameters from start scan response event
7294  *
7295  * Return: QDF_STATUS
7296  */
7297 static QDF_STATUS
7298 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
7299 			struct wlan_objmgr_psoc *psoc,
7300 			uint8_t *evt_buf,
7301 			struct spectral_startscan_resp_params *param)
7302 {
7303 	wmi_unified_t wmi_handle;
7304 
7305 	if (!psoc) {
7306 		spectral_err("psoc is null");
7307 		return QDF_STATUS_E_INVAL;
7308 	}
7309 
7310 	if (!evt_buf) {
7311 		spectral_err("WMI event buffer is null");
7312 		return QDF_STATUS_E_INVAL;
7313 	}
7314 
7315 	if (!param) {
7316 		spectral_err("Spectral startscan response parameters is null");
7317 		return QDF_STATUS_E_INVAL;
7318 	}
7319 
7320 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7321 	if (!wmi_handle) {
7322 		spectral_err("WMI handle is null");
7323 		return QDF_STATUS_E_INVAL;
7324 	}
7325 
7326 	return wmi_extract_pdev_sscan_fw_cmd_fixed_param(wmi_handle, evt_buf,
7327 							 param);
7328 }
7329 
7330 /**
7331  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
7332  * function to extract start and end indices of primary 80 MHz, 5 MHz and
7333  * secondary 80 MHz FFT bins
7334  * @psoc: Pointer to psoc object
7335  * @evt_buf: Event buffer
7336  * @param: FFT bin start and end indices
7337  *
7338  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
7339  * and secondary 80 MHz FFT bins
7340  *
7341  * Return: QDF_STATUS
7342  */
7343 static QDF_STATUS
7344 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
7345 			struct wlan_objmgr_psoc *psoc,
7346 			uint8_t *evt_buf,
7347 			struct spectral_fft_bin_markers_160_165mhz *param)
7348 {
7349 	wmi_unified_t wmi_handle;
7350 
7351 	if (!psoc) {
7352 		spectral_err("psoc is null");
7353 		return QDF_STATUS_E_INVAL;
7354 	}
7355 
7356 	if (!evt_buf) {
7357 		spectral_err("WMI event buffer is null");
7358 		return QDF_STATUS_E_INVAL;
7359 	}
7360 
7361 	if (!param) {
7362 		spectral_err("Spectral FFT bin markers is null");
7363 		return QDF_STATUS_E_INVAL;
7364 	}
7365 
7366 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7367 	if (!wmi_handle) {
7368 		spectral_err("WMI handle is null");
7369 		return QDF_STATUS_E_INVAL;
7370 	}
7371 
7372 	return wmi_extract_pdev_sscan_fft_bin_index(wmi_handle, evt_buf, param);
7373 }
7374 
7375 /**
7376  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
7377  * object from scn handle
7378  * @scn: scn handle
7379  *
7380  * Wrapper function to get psoc object from scn handle
7381  *
7382  * Return: Pointer to psoc object
7383  */
7384 static struct wlan_objmgr_psoc *
7385 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
7386 {
7387 	if (!scn) {
7388 		spectral_err("scn is null");
7389 		return NULL;
7390 	}
7391 
7392 	return target_if_get_psoc_from_scn_hdl(scn);
7393 }
7394 
7395 /**
7396  * target_if_extract_pdev_spectral_session_chan_info() - Wrapper
7397  * function to extract channel information for a spectral scan session
7398  * @psoc: Pointer to psoc object
7399  * @evt_buf: Event buffer
7400  * @chan_info: Spectral session channel information data structure to be filled
7401  * by this API
7402  *
7403  * Return: QDF_STATUS of operation
7404  */
7405 static QDF_STATUS
7406 target_if_extract_pdev_spectral_session_chan_info(
7407 			struct wlan_objmgr_psoc *psoc,
7408 			void *evt_buf,
7409 			struct spectral_session_chan_info *chan_info)
7410 {
7411 	wmi_unified_t wmi_handle;
7412 
7413 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7414 	if (!wmi_handle) {
7415 		spectral_err("WMI handle is null");
7416 		return QDF_STATUS_E_NULL_VALUE;
7417 	}
7418 
7419 	return wmi_extract_pdev_spectral_session_chan_info(
7420 			wmi_handle, evt_buf, chan_info);
7421 }
7422 
7423 /**
7424  * target_if_extract_pdev_spectral_session_detector_info() - Wrapper
7425  * function to extract detector information for a spectral scan session
7426  * @psoc: Pointer to psoc object
7427  * @evt_buf: Event buffer
7428  * @det_info: Spectral session detector information data structure to be filled
7429  * by this API
7430  * @det_info_idx: index in the array of spectral scan detector info TLVs
7431  *
7432  * Return: QDF_STATUS of operation
7433  */
7434 static QDF_STATUS
7435 target_if_extract_pdev_spectral_session_detector_info(
7436 			struct wlan_objmgr_psoc *psoc, void *evt_buf,
7437 			struct spectral_session_det_info *det_info,
7438 			uint8_t det_info_idx)
7439 {
7440 	wmi_unified_t wmi_handle;
7441 
7442 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7443 	if (!wmi_handle) {
7444 		spectral_err("WMI handle is null");
7445 		return QDF_STATUS_E_NULL_VALUE;
7446 	}
7447 
7448 	return wmi_extract_pdev_spectral_session_detector_info(
7449 				wmi_handle, evt_buf, det_info, det_info_idx);
7450 }
7451 
7452 QDF_STATUS
7453 target_if_wmi_extract_spectral_caps_fixed_param(
7454 			struct wlan_objmgr_psoc *psoc,
7455 			uint8_t *evt_buf,
7456 			struct spectral_capabilities_event_params *param)
7457 {
7458 	wmi_unified_t wmi_handle;
7459 
7460 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7461 	if (!wmi_handle) {
7462 		spectral_err("WMI handle is null");
7463 		return QDF_STATUS_E_INVAL;
7464 	}
7465 
7466 	return wmi_extract_spectral_caps_fixed_param(wmi_handle, evt_buf,
7467 						     param);
7468 }
7469 
7470 QDF_STATUS
7471 target_if_wmi_extract_spectral_scan_bw_caps(
7472 			struct wlan_objmgr_psoc *psoc,
7473 			uint8_t *evt_buf,
7474 			struct spectral_scan_bw_capabilities *bw_caps)
7475 {
7476 	wmi_unified_t wmi_handle;
7477 
7478 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7479 	if (!wmi_handle) {
7480 		spectral_err("WMI handle is null");
7481 		return QDF_STATUS_E_INVAL;
7482 	}
7483 
7484 	return wmi_extract_spectral_scan_bw_caps(wmi_handle, evt_buf, bw_caps);
7485 }
7486 
7487 QDF_STATUS
7488 target_if_wmi_extract_spectral_fft_size_caps(
7489 			struct wlan_objmgr_psoc *psoc,
7490 			uint8_t *evt_buf,
7491 			struct spectral_fft_size_capabilities *fft_size_caps)
7492 {
7493 	wmi_unified_t wmi_handle;
7494 
7495 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7496 	if (!wmi_handle) {
7497 		spectral_err("WMI handle is null");
7498 		return QDF_STATUS_E_INVAL;
7499 	}
7500 
7501 	return wmi_extract_spectral_fft_size_caps(wmi_handle, evt_buf,
7502 						  fft_size_caps);
7503 }
7504 #endif
7505 
7506 /**
7507  * target_if_update_det_info_in_spectral_session() - Update detector
7508  * information in spectral scan session
7509  * @spectral: Spectral LMAC object
7510  * @det_info: Pointer to spectral session detector information
7511  * @smode: Spectral scan mode
7512  *
7513  * Return: QDF_STATUS of operation
7514  */
7515 static QDF_STATUS
7516 target_if_update_det_info_in_spectral_session(
7517 	struct target_if_spectral *spectral,
7518 	const struct spectral_session_det_info *det_info,
7519 	enum spectral_scan_mode smode)
7520 {
7521 	struct per_session_det_map *det_map;
7522 	struct per_session_dest_det_info *dest_det_info;
7523 
7524 	if (!spectral) {
7525 		spectral_err_rl("Spectral LMAC object is null");
7526 		return QDF_STATUS_E_NULL_VALUE;
7527 	}
7528 
7529 	qdf_assert_always(det_info->det_id < MAX_DETECTORS_PER_PDEV);
7530 
7531 	qdf_spin_lock_bh(&spectral->session_det_map_lock);
7532 
7533 	det_map = &spectral->det_map[det_info->det_id];
7534 	dest_det_info = &det_map->dest_det_info[0];
7535 
7536 	dest_det_info->start_freq = det_info->start_freq;
7537 	dest_det_info->end_freq = det_info->end_freq;
7538 
7539 	qdf_spin_unlock_bh(&spectral->session_det_map_lock);
7540 
7541 	/* This detector will be used for this smode throughout this session */
7542 	spectral->rparams.detid_mode_table[det_info->det_id] = smode;
7543 
7544 	return QDF_STATUS_SUCCESS;
7545 }
7546 
7547 /**
7548  * target_if_update_chan_info_in_spectral_session() - Update channel information
7549  * in spectral scan session
7550  * @spectral: Spectral LMAC object
7551  * @chan_info: Pointer to spectral session channel information
7552  * @smode: Spectral scan mode
7553  *
7554  * Return: QDF_STATUS of operation
7555  */
7556 static QDF_STATUS
7557 target_if_update_chan_info_in_spectral_session(
7558 	struct target_if_spectral *spectral,
7559 	const struct spectral_session_chan_info *chan_info,
7560 	enum spectral_scan_mode smode)
7561 {
7562 	struct per_session_report_info *rpt_info;
7563 
7564 	if (!spectral) {
7565 		spectral_err_rl("Spectral LMAC object is null");
7566 		return QDF_STATUS_E_NULL_VALUE;
7567 	}
7568 
7569 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
7570 		spectral_err_rl("Invalid Spectral scan mode :%u", smode);
7571 		return QDF_STATUS_E_FAILURE;
7572 	}
7573 
7574 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
7575 	rpt_info = &spectral->report_info[smode];
7576 
7577 	/* Update per-session report info */
7578 	rpt_info->pri20_freq = chan_info->operating_pri20_freq;
7579 	rpt_info->cfreq1 = chan_info->operating_cfreq1;
7580 	rpt_info->cfreq2 = chan_info->operating_cfreq2;
7581 	rpt_info->operating_bw = chan_info->operating_bw;
7582 	rpt_info->sscan_cfreq1 = chan_info->sscan_cfreq1;
7583 	rpt_info->sscan_cfreq2 = chan_info->sscan_cfreq2;
7584 	rpt_info->sscan_bw = chan_info->sscan_bw;
7585 
7586 	/* num_spans depends on sscan_bw, update it */
7587 	rpt_info->num_spans = target_if_spectral_get_num_spans(
7588 					spectral->pdev_obj,
7589 					rpt_info->sscan_bw);
7590 	qdf_assert_always(rpt_info->num_spans != INVALID_SPAN_NUM);
7591 
7592 	rpt_info->valid = true;
7593 
7594 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
7595 
7596 	return QDF_STATUS_SUCCESS;
7597 }
7598 
7599 /**
7600  * target_if_spectral_fw_param_event_handler() - WMI event handler to
7601  * process start scan response event
7602  * @scn: Pointer to scn object
7603  * @data_buf: Pointer to event buffer
7604  * @data_len: Length of event buffer
7605  *
7606  * Return: 0 for success, else failure
7607  */
7608 static int
7609 target_if_spectral_fw_param_event_handler(ol_scn_t scn, uint8_t *data_buf,
7610 					  uint32_t data_len)
7611 {
7612 	QDF_STATUS status;
7613 	struct wlan_objmgr_psoc *psoc;
7614 	struct wlan_objmgr_pdev *pdev;
7615 	struct wmi_unified *wmi_handle;
7616 	struct spectral_startscan_resp_params event_params = {0};
7617 	struct target_if_psoc_spectral *psoc_spectral;
7618 	struct target_if_spectral *spectral;
7619 	bool is_session_info_expected;
7620 
7621 	if (!scn) {
7622 		spectral_err("scn handle is null");
7623 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7624 	}
7625 
7626 	if (!data_buf) {
7627 		spectral_err("WMI event buffer null");
7628 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7629 	}
7630 
7631 	psoc = target_if_spectral_get_psoc_from_scn_handle(scn);
7632 	if (!psoc) {
7633 		spectral_err("psoc is null");
7634 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7635 	}
7636 
7637 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
7638 	if (!psoc_spectral) {
7639 		spectral_err("spectral object is null");
7640 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7641 	}
7642 
7643 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7644 	if (!wmi_handle) {
7645 		spectral_err("WMI handle is null");
7646 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7647 	}
7648 
7649 	status = target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
7650 				psoc, data_buf, &event_params);
7651 	if (QDF_IS_STATUS_ERROR(status)) {
7652 		spectral_err("unable to extract sscan fw fixed params");
7653 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7654 	}
7655 
7656 	if (event_params.smode >= SPECTRAL_SCAN_MODE_MAX ||
7657 	    event_params.smode < SPECTRAL_SCAN_MODE_NORMAL) {
7658 		spectral_err("Invalid smode %d", event_params.smode);
7659 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7660 	}
7661 
7662 	pdev = wlan_objmgr_get_pdev_by_id(psoc, event_params.pdev_id,
7663 					  WLAN_SPECTRAL_ID);
7664 	if (!pdev) {
7665 		spectral_err("pdev is null");
7666 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7667 	}
7668 
7669 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
7670 	if (!spectral) {
7671 		spectral_err("spectral object is null");
7672 		status = QDF_STATUS_E_FAILURE;
7673 		goto release_pdev_ref;
7674 	}
7675 
7676 	if (event_params.num_fft_bin_index == 1) {
7677 		status =
7678 			target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
7679 				psoc, data_buf,
7680 				&spectral->rparams.marker[event_params.smode]);
7681 		if (QDF_IS_STATUS_ERROR(status)) {
7682 			spectral_err("unable to extract sscan fw fixed params");
7683 			goto release_pdev_ref;
7684 		}
7685 	} else {
7686 		spectral->rparams.marker[event_params.smode].is_valid = false;
7687 	}
7688 
7689 	status = spectral_is_session_info_expected_from_target(
7690 					pdev, &is_session_info_expected);
7691 	if (QDF_IS_STATUS_ERROR(status)) {
7692 		spectral_err("Failed to check if session info is expected");
7693 		goto release_pdev_ref;
7694 	}
7695 
7696 	if (is_session_info_expected) {
7697 		struct spectral_session_chan_info chan_info;
7698 		uint8_t det_info_idx = 0;
7699 
7700 		status = target_if_extract_pdev_spectral_session_chan_info(
7701 				psoc, data_buf, &chan_info);
7702 		if (QDF_IS_STATUS_ERROR(status)) {
7703 			spectral_err("Unable to extract spectral session channel info");
7704 			goto release_pdev_ref;
7705 		}
7706 
7707 		status = target_if_update_chan_info_in_spectral_session(
7708 				spectral, &chan_info, event_params.smode);
7709 		if (QDF_IS_STATUS_ERROR(status)) {
7710 			spectral_err("Unable to update channel info");
7711 			goto release_pdev_ref;
7712 		}
7713 
7714 		/* FFT bins info depends upon sscan_bw, update it */
7715 		status = target_if_populate_fft_bins_info(spectral,
7716 							  event_params.smode);
7717 		if (QDF_IS_STATUS_ERROR(status)) {
7718 			spectral_err("Failed to populate FFT bins info");
7719 			goto release_pdev_ref;
7720 		}
7721 
7722 		/**
7723 		 * per-session det info that depends on sscan_bw needs to be
7724 		 * updated here
7725 		 */
7726 		status = target_if_spectral_populate_session_det_host_info(
7727 					spectral, event_params.smode);
7728 		if (QDF_IS_STATUS_ERROR(status)) {
7729 			spectral_err("Failed to populate per-session det info");
7730 			goto release_pdev_ref;
7731 		}
7732 
7733 		for (; det_info_idx < event_params.num_det_info;
7734 		     ++det_info_idx) {
7735 			struct spectral_session_det_info det_info;
7736 
7737 			status =
7738 			  target_if_extract_pdev_spectral_session_detector_info
7739 				(psoc, data_buf, &det_info, det_info_idx);
7740 
7741 			if (QDF_IS_STATUS_ERROR(status)) {
7742 				spectral_err("Unable to extract spectral session detector info for %u",
7743 					     det_info_idx);
7744 				goto release_pdev_ref;
7745 			}
7746 
7747 			status = target_if_update_det_info_in_spectral_session(
7748 					spectral, &det_info,
7749 					event_params.smode);
7750 			if (QDF_IS_STATUS_ERROR(status)) {
7751 				spectral_err("Unable to update detector info");
7752 				goto release_pdev_ref;
7753 			}
7754 		}
7755 	}
7756 
7757 	status = QDF_STATUS_SUCCESS;
7758 
7759 release_pdev_ref:
7760 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
7761 	return qdf_status_to_os_return(status);
7762 }
7763 
7764 /**
7765  * target_if_spectral_capabilities_event_handler() - Handler for the Spectral
7766  * Capabilities event
7767  * @scn: Pointer to scn object
7768  * @data_buf: Pointer to event buffer
7769  * @data_len: Length of event buffer
7770  *
7771  * Return: 0 for success, else failure
7772  */
7773 static int
7774 target_if_spectral_capabilities_event_handler(ol_scn_t scn, uint8_t *data_buf,
7775 					      uint32_t data_len)
7776 {
7777 	QDF_STATUS status;
7778 	struct wlan_objmgr_psoc *psoc;
7779 	struct wmi_unified *wmi_handle;
7780 	struct spectral_capabilities_event_params event_params = {0};
7781 	struct spectral_scan_bw_capabilities *bw_caps;
7782 	struct spectral_fft_size_capabilities *fft_size_caps;
7783 
7784 	if (!scn) {
7785 		spectral_err("scn handle is null");
7786 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7787 	}
7788 
7789 	if (!data_buf) {
7790 		spectral_err("WMI event buffer null");
7791 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
7792 	}
7793 
7794 	psoc = target_if_spectral_get_psoc_from_scn_handle(scn);
7795 	if (!psoc) {
7796 		spectral_err("psoc is null");
7797 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7798 	}
7799 
7800 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
7801 	if (!wmi_handle) {
7802 		spectral_err("WMI handle is null");
7803 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7804 	}
7805 
7806 	status = target_if_wmi_extract_spectral_caps_fixed_param(
7807 				psoc, data_buf, &event_params);
7808 	if (QDF_IS_STATUS_ERROR(status)) {
7809 		spectral_err("Failed to extract fixed parameters");
7810 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
7811 	}
7812 
7813 	/* There should be atleast one capability */
7814 	qdf_assert(event_params.num_sscan_bw_caps > 0);
7815 	qdf_assert(event_params.num_fft_size_caps > 0);
7816 
7817 	bw_caps = qdf_mem_malloc(
7818 			sizeof(*bw_caps) * event_params.num_sscan_bw_caps);
7819 	if (!bw_caps) {
7820 		spectral_err("memory allocation failed");
7821 		return qdf_status_to_os_return(QDF_STATUS_E_NOMEM);
7822 	}
7823 
7824 	status = target_if_wmi_extract_spectral_scan_bw_caps(psoc, data_buf,
7825 							     bw_caps);
7826 	if (QDF_IS_STATUS_ERROR(status)) {
7827 		spectral_err("Failed to extract BW caps");
7828 		status = QDF_STATUS_E_FAILURE;
7829 		goto free_bw_caps;
7830 	}
7831 
7832 	fft_size_caps = qdf_mem_malloc(
7833 		sizeof(*fft_size_caps) * event_params.num_fft_size_caps);
7834 	if (!fft_size_caps) {
7835 		spectral_err("memory allocation failed");
7836 		status = QDF_STATUS_E_NOMEM;
7837 		goto free_bw_caps;
7838 	}
7839 
7840 	status = target_if_wmi_extract_spectral_fft_size_caps(psoc, data_buf,
7841 							      fft_size_caps);
7842 	if (QDF_IS_STATUS_ERROR(status)) {
7843 		spectral_err("Failed to extract fft size caps");
7844 		status = QDF_STATUS_E_FAILURE;
7845 		goto free_fft_size_caps;
7846 	}
7847 
7848 	status = QDF_STATUS_SUCCESS;
7849 
7850 free_fft_size_caps:
7851 	qdf_mem_free(fft_size_caps);
7852 
7853 free_bw_caps:
7854 	qdf_mem_free(bw_caps);
7855 
7856 	return qdf_status_to_os_return(status);
7857 }
7858 
7859 static QDF_STATUS
7860 target_if_spectral_register_events(struct wlan_objmgr_psoc *psoc)
7861 {
7862 	int ret;
7863 
7864 	if (!psoc) {
7865 		spectral_err("psoc is null");
7866 		return QDF_STATUS_E_INVAL;
7867 	}
7868 
7869 	ret = target_if_spectral_wmi_unified_register_event_handler(
7870 			psoc,
7871 			wmi_pdev_sscan_fw_param_eventid,
7872 			target_if_spectral_fw_param_event_handler,
7873 			WMI_RX_UMAC_CTX);
7874 
7875 	if (ret)
7876 		spectral_debug("event handler not supported, ret=%d", ret);
7877 
7878 	ret = target_if_spectral_wmi_unified_register_event_handler(
7879 			psoc,
7880 			wmi_spectral_capabilities_eventid,
7881 			target_if_spectral_capabilities_event_handler,
7882 			WMI_RX_UMAC_CTX);
7883 	if (ret)
7884 		spectral_debug("event handler not supported, ret=%d", ret);
7885 
7886 	return QDF_STATUS_SUCCESS;
7887 }
7888 
7889 static QDF_STATUS
7890 target_if_spectral_unregister_events(struct wlan_objmgr_psoc *psoc)
7891 {
7892 	int ret;
7893 
7894 	if (!psoc) {
7895 		spectral_err("psoc is null");
7896 		return QDF_STATUS_E_INVAL;
7897 	}
7898 
7899 	target_if_spectral_wmi_unified_unregister_event_handler(
7900 			psoc, wmi_spectral_capabilities_eventid);
7901 
7902 	ret = target_if_spectral_wmi_unified_unregister_event_handler(
7903 			psoc, wmi_pdev_sscan_fw_param_eventid);
7904 
7905 	if (ret)
7906 		spectral_debug("Unregister WMI event handler failed, ret = %d",
7907 			       ret);
7908 
7909 	return QDF_STATUS_SUCCESS;
7910 }
7911 
7912 void
7913 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
7914 {
7915 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
7916 	    target_if_pdev_spectral_init;
7917 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
7918 	    target_if_pdev_spectral_deinit;
7919 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_init =
7920 	    target_if_psoc_spectral_init;
7921 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_deinit =
7922 	    target_if_psoc_spectral_deinit;
7923 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
7924 	    target_if_set_spectral_config;
7925 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
7926 	    target_if_get_spectral_config;
7927 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
7928 	    target_if_start_spectral_scan;
7929 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
7930 	    target_if_stop_spectral_scan;
7931 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
7932 	    target_if_is_spectral_active;
7933 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
7934 	    target_if_is_spectral_enabled;
7935 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
7936 	    target_if_set_debug_level;
7937 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
7938 	    target_if_get_debug_level;
7939 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
7940 	    target_if_get_spectral_capinfo;
7941 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
7942 	    target_if_get_spectral_diagstats;
7943 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_wmi_ops =
7944 	    target_if_register_spectral_wmi_ops;
7945 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_tgt_ops =
7946 	    target_if_register_spectral_tgt_ops;
7947 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
7948 	    target_if_register_netlink_cb;
7949 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
7950 	    target_if_use_nl_bcast;
7951 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
7952 	    target_if_deregister_netlink_cb;
7953 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
7954 	    target_if_process_spectral_report;
7955 	tx_ops->sptrl_tx_ops.sptrlto_direct_dma_support =
7956 		target_if_spectral_direct_dma_support;
7957 	tx_ops->sptrl_tx_ops.sptrlto_register_events =
7958 		target_if_spectral_register_events;
7959 	tx_ops->sptrl_tx_ops.sptrlto_unregister_events =
7960 		target_if_spectral_unregister_events;
7961 	tx_ops->sptrl_tx_ops.sptrlto_init_pdev_feature_caps =
7962 		target_if_spectral_init_pdev_feature_caps;
7963 
7964 	target_if_sptrl_debug_register_tx_ops(tx_ops);
7965 }
7966 qdf_export_symbol(target_if_sptrl_register_tx_ops);
7967 
7968 void
7969 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
7970 				       uint16_t cw_int, uint32_t dcs_enabled)
7971 {
7972 	struct spectral_samp_msg *msg = NULL;
7973 	struct target_if_spectral_ops *p_sops = NULL;
7974 	struct target_if_spectral *spectral = NULL;
7975 
7976 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
7977 
7978 	if (!spectral) {
7979 		spectral_err("SPECTRAL : Module doesn't exist");
7980 		return;
7981 	}
7982 
7983 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
7984 	if (!p_sops) {
7985 		spectral_err("p_sops is null");
7986 		return;
7987 	}
7988 
7989 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_sbuff(
7990 			spectral->pdev_obj,
7991 			SPECTRAL_MSG_INTERFERENCE_NOTIFICATION,
7992 			SPECTRAL_MSG_BUF_NEW);
7993 
7994 	if (msg) {
7995 		msg->int_type = cw_int ?
7996 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
7997 		msg->dcs_enabled = dcs_enabled;
7998 		msg->signature = SPECTRAL_SIGNATURE;
7999 		p_sops->get_mac_address(spectral, msg->macaddr);
8000 		if (spectral->send_phy_data
8001 				(pdev,
8002 				 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION) == 0)
8003 			spectral->spectral_sent_msg++;
8004 	}
8005 }
8006 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
8007 
8008 QDF_STATUS
8009 target_if_spectral_is_finite_scan(struct target_if_spectral *spectral,
8010 				  enum spectral_scan_mode smode,
8011 				  bool *finite_spectral_scan)
8012 {
8013 	struct target_if_finite_spectral_scan_params *finite_scan;
8014 
8015 	if (!spectral) {
8016 		spectral_err_rl("target if spectral object is null");
8017 		return QDF_STATUS_E_INVAL;
8018 	}
8019 
8020 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
8021 		spectral_err_rl("invalid spectral mode %d", smode);
8022 		return QDF_STATUS_E_INVAL;
8023 	}
8024 
8025 	if (!finite_spectral_scan) {
8026 		spectral_err_rl("Invalid pointer");
8027 		return QDF_STATUS_E_INVAL;
8028 	}
8029 
8030 	finite_scan = &spectral->finite_scan[smode];
8031 	*finite_spectral_scan = finite_scan->finite_spectral_scan;
8032 
8033 	return QDF_STATUS_SUCCESS;
8034 }
8035 
8036 QDF_STATUS
8037 target_if_spectral_finite_scan_update(struct target_if_spectral *spectral,
8038 				      enum spectral_scan_mode smode)
8039 {
8040 	struct target_if_finite_spectral_scan_params *finite_scan;
8041 
8042 	if (!spectral) {
8043 		spectral_err_rl("target if spectral object is null");
8044 		return QDF_STATUS_E_INVAL;
8045 	}
8046 
8047 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
8048 		spectral_err_rl("Invalid Spectral mode");
8049 		return QDF_STATUS_E_INVAL;
8050 	}
8051 
8052 	finite_scan = &spectral->finite_scan[smode];
8053 
8054 	if (!finite_scan->num_reports_expected) {
8055 		spectral_err_rl("Error, No reports expected");
8056 		return QDF_STATUS_E_FAILURE;
8057 	}
8058 
8059 	finite_scan->num_reports_expected--;
8060 	if (!finite_scan->num_reports_expected) {
8061 		QDF_STATUS status;
8062 		enum spectral_cp_error_code err;
8063 
8064 		/* received expected number of reports from target, stop scan */
8065 		status = target_if_stop_spectral_scan(spectral->pdev_obj, smode,
8066 						      &err);
8067 		if (QDF_IS_STATUS_ERROR(status)) {
8068 			spectral_err_rl("Failed to stop finite Spectral scan");
8069 			return QDF_STATUS_E_FAILURE;
8070 		}
8071 		finite_scan->finite_spectral_scan =  false;
8072 	}
8073 
8074 	return QDF_STATUS_SUCCESS;
8075 }
8076