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