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