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