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