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