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