xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
1 /*
2  * Copyright (c) 2011,2017-2020 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 static void target_if_spectral_get_firstvdev_pdev(struct wlan_objmgr_pdev *pdev,
47 						  void *obj, void *arg)
48 {
49 	struct wlan_objmgr_vdev *vdev = obj;
50 	struct wlan_objmgr_vdev **first_vdev = arg;
51 
52 	if (!(*first_vdev))
53 		*first_vdev = vdev;
54 }
55 
56 struct wlan_objmgr_vdev *
57 target_if_spectral_get_vdev(struct target_if_spectral *spectral,
58 			    enum spectral_scan_mode smode)
59 {
60 	struct wlan_objmgr_pdev *pdev = NULL;
61 	struct wlan_objmgr_vdev *first_vdev = NULL;
62 
63 	qdf_assert_always(spectral);
64 	pdev = spectral->pdev_obj;
65 	qdf_assert_always(pdev);
66 
67 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
68 		spectral_err("Invalid Spectral mode %u", smode);
69 		return NULL;
70 	}
71 
72 	if (spectral->vdev_id[smode] != WLAN_INVALID_VDEV_ID) {
73 		first_vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
74 						pdev, spectral->vdev_id[smode],
75 						WLAN_SPECTRAL_ID);
76 		return first_vdev;
77 	}
78 
79 	if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_SPECTRAL_ID) !=
80 	    QDF_STATUS_SUCCESS) {
81 		spectral_err("Unable to get pdev reference.");
82 		return NULL;
83 	}
84 
85 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
86 					  target_if_spectral_get_firstvdev_pdev,
87 					  &first_vdev, 0, WLAN_SPECTRAL_ID);
88 
89 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
90 
91 	if (!first_vdev)
92 		return NULL;
93 
94 	if (wlan_objmgr_vdev_try_get_ref(first_vdev, WLAN_SPECTRAL_ID) !=
95 			QDF_STATUS_SUCCESS)
96 		first_vdev = NULL;
97 
98 	return first_vdev;
99 }
100 
101 /**
102  * target_if_send_vdev_spectral_configure_cmd() - Send WMI command to configure
103  * spectral parameters
104  * @spectral: Pointer to Spectral target_if internal private data
105  * @smode: Spectral scan mode
106  * @param: Pointer to spectral_config giving the Spectral configuration
107  *
108  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
109  */
110 static int
111 target_if_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral,
112 					   enum spectral_scan_mode smode,
113 					   struct spectral_config *param)
114 {
115 	struct vdev_spectral_configure_params sparam;
116 	struct wlan_objmgr_psoc *psoc;
117 	struct wlan_objmgr_pdev *pdev = NULL;
118 	struct wlan_objmgr_vdev *vdev = NULL;
119 	struct target_if_psoc_spectral *psoc_spectral;
120 
121 	qdf_assert_always(spectral && param);
122 
123 	pdev = spectral->pdev_obj;
124 
125 	qdf_assert_always(pdev);
126 
127 	psoc = wlan_pdev_get_psoc(pdev);
128 	if (!psoc) {
129 		spectral_err("psoc is null");
130 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
131 	}
132 
133 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
134 	if (!psoc_spectral) {
135 		spectral_err("psoc spectral object is null");
136 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
137 	}
138 
139 	vdev = target_if_spectral_get_vdev(spectral, smode);
140 	if (!vdev)
141 		return QDF_STATUS_E_NOENT;
142 
143 	qdf_mem_zero(&sparam, sizeof(sparam));
144 
145 	sparam.vdev_id = wlan_vdev_get_id(vdev);
146 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
147 
148 	sparam.count = param->ss_count;
149 	sparam.period = param->ss_period;
150 	sparam.spectral_pri = param->ss_spectral_pri;
151 	sparam.fft_size = param->ss_fft_size;
152 	sparam.gc_enable = param->ss_gc_ena;
153 	sparam.restart_enable = param->ss_restart_ena;
154 	sparam.noise_floor_ref = param->ss_noise_floor_ref;
155 	sparam.init_delay = param->ss_init_delay;
156 	sparam.nb_tone_thr = param->ss_nb_tone_thr;
157 	sparam.str_bin_thr = param->ss_str_bin_thr;
158 	sparam.wb_rpt_mode = param->ss_wb_rpt_mode;
159 	sparam.rssi_rpt_mode = param->ss_rssi_rpt_mode;
160 	sparam.rssi_thr = param->ss_rssi_thr;
161 	sparam.pwr_format = param->ss_pwr_format;
162 	sparam.rpt_mode = param->ss_rpt_mode;
163 	sparam.bin_scale = param->ss_bin_scale;
164 	sparam.dbm_adj = param->ss_dbm_adj;
165 	sparam.chn_mask = param->ss_chn_mask;
166 	sparam.mode = smode;
167 	sparam.center_freq1 = param->ss_frequency.cfreq1;
168 	sparam.center_freq2 = param->ss_frequency.cfreq2;
169 	sparam.chan_width = spectral->ch_width[smode];
170 
171 	return psoc_spectral->wmi_ops.wmi_spectral_configure_cmd_send(
172 				GET_WMI_HDL_FROM_PDEV(pdev), &sparam);
173 }
174 
175 /**
176  * target_if_send_vdev_spectral_enable_cmd() - Send WMI command to
177  * enable/disable Spectral
178  * @spectral: Pointer to Spectral target_if internal private data
179  * @smode: Spectral scan mode
180  * @is_spectral_active_valid: Flag to indicate if spectral activate (trigger) is
181  * valid
182  * @is_spectral_active: Value of spectral activate
183  * @is_spectral_enabled_valid: Flag to indicate if spectral enable is valid
184  * @is_spectral_enabled: Value of spectral enable
185  *
186  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
187  */
188 static int
189 target_if_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral,
190 					enum spectral_scan_mode smode,
191 					uint8_t is_spectral_active_valid,
192 					uint8_t is_spectral_active,
193 					uint8_t is_spectral_enabled_valid,
194 					uint8_t is_spectral_enabled)
195 {
196 	struct vdev_spectral_enable_params param;
197 	struct wlan_objmgr_psoc *psoc;
198 	struct wlan_objmgr_pdev *pdev = NULL;
199 	struct wlan_objmgr_vdev *vdev = NULL;
200 	struct target_if_psoc_spectral *psoc_spectral;
201 
202 	qdf_assert_always(spectral);
203 
204 	pdev = spectral->pdev_obj;
205 
206 	qdf_assert_always(pdev);
207 
208 	psoc = wlan_pdev_get_psoc(pdev);
209 	if (!psoc) {
210 		spectral_err("psoc is null");
211 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
212 	}
213 
214 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
215 	if (!psoc_spectral) {
216 		spectral_err("psoc spectral object is null");
217 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
218 	}
219 
220 	vdev = target_if_spectral_get_vdev(spectral, smode);
221 	if (!vdev)
222 		return QDF_STATUS_E_NOENT;
223 
224 	qdf_mem_zero(&param, sizeof(param));
225 
226 	param.vdev_id = wlan_vdev_get_id(vdev);
227 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
228 
229 	param.active_valid = is_spectral_active_valid;
230 	param.enabled_valid = is_spectral_enabled_valid;
231 	param.active = is_spectral_active;
232 	param.enabled = is_spectral_enabled;
233 	param.mode = smode;
234 
235 	return psoc_spectral->wmi_ops.wmi_spectral_enable_cmd_send(
236 				GET_WMI_HDL_FROM_PDEV(pdev), &param);
237 }
238 
239 /**
240  * target_if_spectral_info_init_defaults() - Helper function to load defaults
241  * for Spectral information (parameters and state) into cache.
242  * @spectral: Pointer to Spectral target_if internal private data
243  * @smode: Spectral scan mode
244  *
245  * It is assumed that the caller has obtained the requisite lock if applicable.
246  * Note that this is currently treated as a temporary function.  Ideally, we
247  * would like to get defaults from the firmware.
248  *
249  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
250  */
251 static QDF_STATUS
252 target_if_spectral_info_init_defaults(struct target_if_spectral *spectral,
253 				      enum spectral_scan_mode smode)
254 {
255 	struct target_if_spectral_param_state_info *info;
256 	struct wlan_objmgr_vdev *vdev = NULL;
257 
258 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
259 		spectral_err("Invalid Spectral mode %u", smode);
260 		return QDF_STATUS_E_FAILURE;
261 	}
262 
263 	info = &spectral->param_info[smode];
264 
265 	/* State */
266 	info->osps_cache.osc_spectral_active = SPECTRAL_SCAN_ACTIVE_DEFAULT;
267 
268 	info->osps_cache.osc_spectral_enabled = SPECTRAL_SCAN_ENABLE_DEFAULT;
269 
270 	/* Parameters */
271 	info->osps_cache.osc_params.ss_count = SPECTRAL_SCAN_COUNT_DEFAULT;
272 
273 	if (spectral->spectral_gen == SPECTRAL_GEN3)
274 		info->osps_cache.osc_params.ss_period =
275 			SPECTRAL_SCAN_PERIOD_GEN_III_DEFAULT;
276 	else
277 		info->osps_cache.osc_params.ss_period =
278 			SPECTRAL_SCAN_PERIOD_GEN_II_DEFAULT;
279 
280 	info->osps_cache.osc_params.ss_spectral_pri =
281 	    SPECTRAL_SCAN_PRIORITY_DEFAULT;
282 
283 	info->osps_cache.osc_params.ss_fft_size =
284 	    SPECTRAL_SCAN_FFT_SIZE_DEFAULT;
285 
286 	info->osps_cache.osc_params.ss_gc_ena = SPECTRAL_SCAN_GC_ENA_DEFAULT;
287 
288 	info->osps_cache.osc_params.ss_restart_ena =
289 	    SPECTRAL_SCAN_RESTART_ENA_DEFAULT;
290 
291 	info->osps_cache.osc_params.ss_noise_floor_ref =
292 	    SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT;
293 
294 	info->osps_cache.osc_params.ss_init_delay =
295 	    SPECTRAL_SCAN_INIT_DELAY_DEFAULT;
296 
297 	info->osps_cache.osc_params.ss_nb_tone_thr =
298 	    SPECTRAL_SCAN_NB_TONE_THR_DEFAULT;
299 
300 	info->osps_cache.osc_params.ss_str_bin_thr =
301 	    SPECTRAL_SCAN_STR_BIN_THR_DEFAULT;
302 
303 	info->osps_cache.osc_params.ss_wb_rpt_mode =
304 	    SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT;
305 
306 	info->osps_cache.osc_params.ss_rssi_rpt_mode =
307 	    SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT;
308 
309 	info->osps_cache.osc_params.ss_rssi_thr =
310 	    SPECTRAL_SCAN_RSSI_THR_DEFAULT;
311 
312 	info->osps_cache.osc_params.ss_pwr_format =
313 	    SPECTRAL_SCAN_PWR_FORMAT_DEFAULT;
314 
315 	info->osps_cache.osc_params.ss_rpt_mode =
316 	    SPECTRAL_SCAN_RPT_MODE_DEFAULT;
317 
318 	info->osps_cache.osc_params.ss_bin_scale =
319 	    SPECTRAL_SCAN_BIN_SCALE_DEFAULT;
320 
321 	info->osps_cache.osc_params.ss_dbm_adj = SPECTRAL_SCAN_DBM_ADJ_DEFAULT;
322 
323 	vdev = target_if_spectral_get_vdev(spectral, smode);
324 	if (!vdev)
325 		return QDF_STATUS_E_NOENT;
326 
327 	info->osps_cache.osc_params.ss_chn_mask =
328 	    wlan_vdev_mlme_get_rxchainmask(vdev);
329 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
330 
331 	info->osps_cache.osc_params.ss_short_report =
332 		SPECTRAL_SCAN_SHORT_REPORT_DEFAULT;
333 
334 	info->osps_cache.osc_params.ss_fft_period =
335 		SPECTRAL_SCAN_FFT_PERIOD_DEFAULT;
336 
337 	info->osps_cache.osc_params.ss_frequency.cfreq1 =
338 		SPECTRAL_SCAN_FREQUENCY_DEFAULT;
339 	info->osps_cache.osc_params.ss_frequency.cfreq2 =
340 		SPECTRAL_SCAN_FREQUENCY_DEFAULT;
341 
342 	/* The cache is now valid */
343 	info->osps_cache.osc_is_valid = 1;
344 
345 	return QDF_STATUS_SUCCESS;
346 }
347 
348 /**
349  * target_if_log_read_spectral_active() - Helper function to log whether
350  * spectral is active after reading cache
351  * @function_name: Function name
352  * @output: whether spectral is active or not
353  *
354  * Helper function to log whether spectral is active after reading cache
355  *
356  * Return: none
357  */
358 static void
359 target_if_log_read_spectral_active(
360 	const char *function_name,
361 	unsigned char output)
362 {
363 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE. Returning val=%u",
364 		       function_name, output);
365 }
366 
367 /**
368  * target_if_log_read_spectral_enabled() - Helper function to log whether
369  * spectral is enabled after reading cache
370  * @function_name: Function name
371  * @output: whether spectral is enabled or not
372  *
373  * Helper function to log whether spectral is enabled after reading cache
374  *
375  * Return: none
376  */
377 static void
378 target_if_log_read_spectral_enabled(
379 	const char *function_name,
380 	unsigned char output)
381 {
382 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED. Returning val=%u",
383 		       function_name, output);
384 }
385 
386 /**
387  * target_if_log_read_spectral_enabled() - Helper function to log spectral
388  * parameters after reading cache
389  * @function_name: Function name
390  * @pparam: Spectral parameters
391  *
392  * Helper function to log spectral parameters after reading cache
393  *
394  * Return: none
395  */
396 static void
397 target_if_log_read_spectral_params(
398 	const char *function_name,
399 	struct spectral_config *pparam)
400 {
401 	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",
402 		       function_name,
403 		       pparam->ss_count,
404 		       pparam->ss_period,
405 		       pparam->ss_spectral_pri,
406 		       pparam->ss_fft_size,
407 		       pparam->ss_gc_ena,
408 		       pparam->ss_restart_ena,
409 		       (int8_t)pparam->ss_noise_floor_ref,
410 		       pparam->ss_init_delay,
411 		       pparam->ss_nb_tone_thr,
412 		       pparam->ss_str_bin_thr,
413 		       pparam->ss_wb_rpt_mode,
414 		       pparam->ss_rssi_rpt_mode,
415 		       (int8_t)pparam->ss_rssi_thr,
416 		       pparam->ss_pwr_format,
417 		       pparam->ss_rpt_mode,
418 		       pparam->ss_bin_scale,
419 		       pparam->ss_dbm_adj,
420 		       pparam->ss_chn_mask,
421 		       pparam->ss_frequency.cfreq1,
422 		       pparam->ss_frequency.cfreq2);
423 }
424 
425 /**
426  * target_if_log_read_spectral_active_catch_validate() - Helper function to
427  * log whether spectral is active after intializing the cache
428  * @function_name: Function name
429  * @output: whether spectral is active or not
430  *
431  * Helper function to log whether spectral is active after intializing cache
432  *
433  * Return: none
434  */
435 static void
436 target_if_log_read_spectral_active_catch_validate(
437 	const char *function_name,
438 	unsigned char output)
439 {
440 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE on initial cache validation\nReturning val=%u",
441 		       function_name, output);
442 }
443 
444 /**
445  * target_if_log_read_spectral_enabled_catch_validate() - Helper function to
446  * log whether spectral is enabled after intializing the cache
447  * @function_name: Function name
448  * @output: whether spectral is enabled or not
449  *
450  * Helper function to log whether spectral is enabled after intializing cache
451  *
452  * Return: none
453  */
454 static void
455 target_if_log_read_spectral_enabled_catch_validate(
456 	const char *function_name,
457 	unsigned char output)
458 {
459 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED on initial cache validation\nReturning val=%u\n",
460 		       function_name, output);
461 }
462 
463 /**
464  * target_if_log_read_spectral_params_catch_validate() - Helper function to
465  * log spectral parameters after intializing the cache
466  * @function_name: Function name
467  * @pparam: Spectral parameters
468  *
469  * Helper function to log spectral parameters after intializing the cache
470  *
471  * Return: none
472  */
473 static void
474 target_if_log_read_spectral_params_catch_validate(
475 	const char *function_name,
476 	struct spectral_config *pparam)
477 {
478 	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",
479 		       function_name,
480 		       pparam->ss_count,
481 		       pparam->ss_period,
482 		       pparam->ss_spectral_pri,
483 		       pparam->ss_fft_size,
484 		       pparam->ss_gc_ena,
485 		       pparam->ss_restart_ena,
486 		       (int8_t)pparam->ss_noise_floor_ref,
487 		       pparam->ss_init_delay,
488 		       pparam->ss_nb_tone_thr,
489 		       pparam->ss_str_bin_thr,
490 		       pparam->ss_wb_rpt_mode,
491 		       pparam->ss_rssi_rpt_mode,
492 		       (int8_t)pparam->ss_rssi_thr,
493 		       pparam->ss_pwr_format,
494 		       pparam->ss_rpt_mode,
495 		       pparam->ss_bin_scale,
496 		       pparam->ss_dbm_adj, pparam->ss_chn_mask);
497 }
498 
499 /**
500  * target_if_spectral_info_read() - Read spectral information from the cache.
501  * @spectral: Pointer to Spectral target_if internal private data
502  * @smode: Spectral scan mode
503  * @specifier: target_if_spectral_info enumeration specifying which
504  * information is required
505  * @output: Void output pointer into which the information will be read
506  * @output_len: size of object pointed to by output pointer
507  *
508  * Read spectral parameters or the desired state information from the cache.
509  *
510  * Return: 0 on success, negative error code on failure
511  */
512 static int
513 target_if_spectral_info_read(
514 	struct target_if_spectral *spectral,
515 	enum spectral_scan_mode smode,
516 	enum target_if_spectral_info specifier,
517 	void *output, int output_len)
518 {
519 	/*
520 	 * Note: This function is designed to be able to accommodate
521 	 * WMI reads for defaults, non-cacheable information, etc
522 	 * if required.
523 	 */
524 	struct target_if_spectral_param_state_info *info;
525 	int is_cacheable = 0;
526 	int init_def_retval = 0;
527 
528 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
529 		spectral_err("Invalid Spectral mode %u", smode);
530 		return -EINVAL;
531 	}
532 	info = &spectral->param_info[smode];
533 
534 	if (!output)
535 		return -EINVAL;
536 
537 	switch (specifier) {
538 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
539 		if (output_len != sizeof(info->osps_cache.osc_spectral_active))
540 			return -EINVAL;
541 		is_cacheable = 1;
542 		break;
543 
544 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
545 		if (output_len != sizeof(info->osps_cache.osc_spectral_enabled))
546 			return -EINVAL;
547 		is_cacheable = 1;
548 		break;
549 
550 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
551 		if (output_len != sizeof(info->osps_cache.osc_params))
552 			return -EINVAL;
553 		is_cacheable = 1;
554 		break;
555 
556 	default:
557 		spectral_err("Unknown target_if_spectral_info specifier");
558 		return -EINVAL;
559 	}
560 
561 	qdf_spin_lock_bh(&info->osps_lock);
562 
563 	if (is_cacheable) {
564 		if (info->osps_cache.osc_is_valid) {
565 			switch (specifier) {
566 			case TARGET_IF_SPECTRAL_INFO_ACTIVE:
567 				qdf_mem_copy(
568 				  output,
569 				  &info->osps_cache.osc_spectral_active,
570 				  sizeof(info->osps_cache.osc_spectral_active));
571 
572 				target_if_log_read_spectral_active(
573 					__func__,
574 					*((unsigned char *)output));
575 				break;
576 
577 			case TARGET_IF_SPECTRAL_INFO_ENABLED:
578 				qdf_mem_copy(
579 				  output,
580 				  &info->osps_cache.osc_spectral_enabled,
581 				  sizeof(
582 					info->osps_cache.osc_spectral_enabled));
583 
584 				target_if_log_read_spectral_enabled(
585 					__func__,
586 					*((unsigned char *)output));
587 				break;
588 
589 			case TARGET_IF_SPECTRAL_INFO_PARAMS:
590 				qdf_mem_copy(
591 				  output,
592 				  &info->osps_cache.osc_params,
593 				  sizeof(info->osps_cache.osc_params));
594 
595 				target_if_log_read_spectral_params(
596 					__func__,
597 					(struct spectral_config *)output);
598 				break;
599 
600 			default:
601 				/* We can't reach this point */
602 				break;
603 			}
604 			qdf_spin_unlock_bh(&info->osps_lock);
605 			return 0;
606 		}
607 	}
608 
609 	/* Cache is invalid */
610 
611 	/*
612 	 * If WMI Reads are implemented to fetch defaults/non-cacheable info,
613 	 * then the below implementation will change
614 	 */
615 	init_def_retval =
616 			target_if_spectral_info_init_defaults(spectral, smode);
617 	if (init_def_retval != QDF_STATUS_SUCCESS) {
618 		qdf_spin_unlock_bh(&info->osps_lock);
619 		if (init_def_retval == QDF_STATUS_E_NOENT)
620 			return -ENOENT;
621 		else
622 			return -EINVAL;
623 	}
624 	/* target_if_spectral_info_init_defaults() has set cache to valid */
625 
626 	switch (specifier) {
627 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
628 		qdf_mem_copy(output,
629 			     &info->osps_cache.osc_spectral_active,
630 			     sizeof(info->osps_cache.osc_spectral_active));
631 
632 		target_if_log_read_spectral_active_catch_validate(
633 			__func__,
634 			*((unsigned char *)output));
635 		break;
636 
637 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
638 		qdf_mem_copy(output,
639 			     &info->osps_cache.osc_spectral_enabled,
640 			     sizeof(info->osps_cache.osc_spectral_enabled));
641 
642 		target_if_log_read_spectral_enabled_catch_validate(
643 			__func__,
644 			*((unsigned char *)output));
645 		break;
646 
647 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
648 		qdf_mem_copy(output,
649 			     &info->osps_cache.osc_params,
650 			     sizeof(info->osps_cache.osc_params));
651 
652 		target_if_log_read_spectral_params_catch_validate(
653 			__func__,
654 			(struct spectral_config *)output);
655 
656 		break;
657 
658 	default:
659 		/* We can't reach this point */
660 		break;
661 	}
662 
663 	qdf_spin_unlock_bh(&info->osps_lock);
664 
665 	return 0;
666 }
667 
668 /**
669  * target_if_log_write_spectral_active() - Helper function to log inputs and
670  * return value of call to configure the Spectral 'active' configuration,
671  * TARGET_IF_SPECTRAL_INFO_ACTIVE into firmware
672  * @function_name: Function name in which this is called
673  * @pval: whether spectral is active or not
674  * @ret: return value of the firmware write function
675  *
676  * Return: none
677  */
678 static void
679 target_if_log_write_spectral_active(
680 	const char *function_name,
681 	uint8_t pval,
682 	int ret)
683 {
684 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE with val=%u status=%d",
685 		       function_name, pval, ret);
686 }
687 
688 /**
689  * target_if_log_write_spectral_enabled() - Helper function to log inputs and
690  * return value of call to configure the Spectral 'enabled' configuration,
691  * TARGET_IF_SPECTRAL_INFO_ENABLED into firmware
692  * @function_name: Function name in which this is called
693  * @pval: whether spectral is enabled or not
694  * @ret: return value of the firmware write function
695  *
696  * Return: none
697  */
698 static void
699 target_if_log_write_spectral_enabled(
700 	const char *function_name,
701 	uint8_t pval,
702 	int ret)
703 {
704 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED with val=%u status=%d",
705 		       function_name, pval, ret);
706 }
707 
708 /**
709  * target_if_log_write_spectral_params() - Helper function to log inputs and
710  * return value of call to configure Spectral parameters,
711  * TARGET_IF_SPECTRAL_INFO_PARAMS into firmware
712  * @param: Spectral parameters
713  * @function_name: Function name in which this is called
714  * @ret: return value of the firmware write function
715  *
716  * Return: none
717  */
718 static void
719 target_if_log_write_spectral_params(
720 	struct spectral_config *param,
721 	const char *function_name,
722 	int ret)
723 {
724 	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",
725 		       function_name,
726 		       param->ss_count,
727 		       param->ss_period,
728 		       param->ss_spectral_pri,
729 		       param->ss_fft_size,
730 		       param->ss_gc_ena,
731 		       param->ss_restart_ena,
732 		       (int8_t)param->ss_noise_floor_ref,
733 		       param->ss_init_delay,
734 		       param->ss_nb_tone_thr,
735 		       param->ss_str_bin_thr,
736 		       param->ss_wb_rpt_mode,
737 		       param->ss_rssi_rpt_mode,
738 		       (int8_t)param->ss_rssi_thr,
739 		       param->ss_pwr_format,
740 		       param->ss_rpt_mode,
741 		       param->ss_bin_scale,
742 		       param->ss_dbm_adj,
743 		       param->ss_chn_mask,
744 		       param->ss_frequency.cfreq1,
745 		       param->ss_frequency.cfreq2,
746 		       ret);
747 }
748 
749 /**
750  * target_if_spectral_info_write() - Write Spectral information to the
751  * firmware, and update cache
752  * @spectral: Pointer to Spectral target_if internal private data
753  * @smode: Spectral scan mode
754  * @specifier: target_if_spectral_info enumeration specifying which
755  * information is involved
756  * @input: void input pointer containing the information to be written
757  * @input_len: size of object pointed to by input pointer
758  *
759  * Write Spectral parameters or the desired state information to
760  * the firmware, and update cache
761  *
762  * Return: 0 on success, negative error code on failure
763  */
764 static int
765 target_if_spectral_info_write(
766 	struct target_if_spectral *spectral,
767 	enum spectral_scan_mode smode,
768 	enum target_if_spectral_info specifier,
769 	void *input, int input_len)
770 {
771 	struct target_if_spectral_param_state_info *info;
772 	int ret;
773 	uint8_t *pval = NULL;
774 	struct spectral_config *param = NULL;
775 
776 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
777 		spectral_err("Invalid Spectral mode %u", smode);
778 		return -EINVAL;
779 	}
780 	info = &spectral->param_info[smode];
781 
782 	if (!input)
783 		return -EINVAL;
784 
785 	switch (specifier) {
786 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
787 		if (input_len != sizeof(info->osps_cache.osc_spectral_active))
788 			return -EINVAL;
789 
790 		pval = (uint8_t *)input;
791 
792 		qdf_spin_lock_bh(&info->osps_lock);
793 		ret = target_if_send_vdev_spectral_enable_cmd(spectral, smode,
794 							      1, *pval, 0, 0);
795 
796 		target_if_log_write_spectral_active(
797 			__func__,
798 			*pval,
799 			ret);
800 
801 		if (ret < 0) {
802 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
803 				     ret);
804 			qdf_spin_unlock_bh(&info->osps_lock);
805 			return ret;
806 		}
807 
808 		info->osps_cache.osc_spectral_active = *pval;
809 
810 		/* The cache is now valid */
811 		info->osps_cache.osc_is_valid = 1;
812 
813 		qdf_spin_unlock_bh(&info->osps_lock);
814 		break;
815 
816 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
817 		if (input_len != sizeof(info->osps_cache.osc_spectral_enabled))
818 			return -EINVAL;
819 
820 		pval = (uint8_t *)input;
821 
822 		qdf_spin_lock_bh(&info->osps_lock);
823 		ret = target_if_send_vdev_spectral_enable_cmd(spectral, smode,
824 							      0, 0, 1, *pval);
825 
826 		target_if_log_write_spectral_enabled(
827 			__func__,
828 			*pval,
829 			ret);
830 
831 		if (ret < 0) {
832 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
833 				     ret);
834 			qdf_spin_unlock_bh(&info->osps_lock);
835 			return ret;
836 		}
837 
838 		info->osps_cache.osc_spectral_enabled = *pval;
839 
840 		/* The cache is now valid */
841 		info->osps_cache.osc_is_valid = 1;
842 
843 		qdf_spin_unlock_bh(&info->osps_lock);
844 		break;
845 
846 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
847 		if (input_len != sizeof(info->osps_cache.osc_params))
848 			return -EINVAL;
849 
850 		param = (struct spectral_config *)input;
851 
852 		qdf_spin_lock_bh(&info->osps_lock);
853 		ret = target_if_send_vdev_spectral_configure_cmd(spectral,
854 								 smode, param);
855 
856 		target_if_log_write_spectral_params(
857 			param,
858 			__func__,
859 			ret);
860 
861 		if (ret < 0) {
862 			spectral_err("target_if_send_vdev_spectral_configure_cmd failed with error=%d",
863 				     ret);
864 			qdf_spin_unlock_bh(&info->osps_lock);
865 			return ret;
866 		}
867 
868 		qdf_mem_copy(&info->osps_cache.osc_params,
869 			     param, sizeof(info->osps_cache.osc_params));
870 
871 		/* The cache is now valid */
872 		info->osps_cache.osc_is_valid = 1;
873 
874 		qdf_spin_unlock_bh(&info->osps_lock);
875 		break;
876 
877 	default:
878 		spectral_err("Unknown target_if_spectral_info specifier");
879 		return -EINVAL;
880 	}
881 
882 	return 0;
883 }
884 
885 /**
886  * target_if_spectral_get_tsf64() - Function to get the TSF value
887  * @arg: Pointer to handle for Spectral target_if internal private data
888  *
889  * Get the last TSF received in WMI buffer
890  *
891  * Return: TSF value
892  */
893 static uint64_t
894 target_if_spectral_get_tsf64(void *arg)
895 {
896 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
897 
898 	return spectral->tsf64;
899 }
900 
901 /**
902  * target_if_spectral_get_capability() - Function to get whether a
903  * given Spectral hardware capability is available
904  * @arg: Pointer to handle for Spectral target_if internal private data
905  * @type: Spectral hardware capability type
906  *
907  * Get whether a given Spectral hardware capability is available
908  *
909  * Return: True if the capability is available, false if the capability is not
910  * available
911  */
912 uint32_t
913 target_if_spectral_get_capability(void *arg, enum spectral_capability_type type)
914 {
915 	int status = STATUS_FAIL;
916 
917 	switch (type) {
918 	case SPECTRAL_CAP_PHYDIAG:
919 	case SPECTRAL_CAP_RADAR:
920 	case SPECTRAL_CAP_SPECTRAL_SCAN:
921 	case SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN:
922 		status = STATUS_PASS;
923 		break;
924 	default:
925 		status = STATUS_FAIL;
926 	}
927 	return status;
928 }
929 
930 /**
931  * target_if_spectral_set_rxfilter() - Set the RX Filter before Spectral start
932  * @arg: Pointer to handle for Spectral target_if internal private data
933  * @rxfilter: Rx filter to be used
934  *
935  * Note: This is only a placeholder function. It is not currently required since
936  * FW should be taking care of setting the required filters.
937  *
938  * Return: 0
939  */
940 uint32_t
941 target_if_spectral_set_rxfilter(void *arg, int rxfilter)
942 {
943 	/*
944 	 * Will not be required since enabling of spectral in firmware
945 	 * will take care of this
946 	 */
947 	return 0;
948 }
949 
950 /**
951  * target_if_spectral_get_rxfilter() - Get the current RX Filter settings
952  * @arg: Pointer to handle for Spectral target_if internal private data
953  *
954  * Note: This is only a placeholder function. It is not currently required since
955  * FW should be taking care of setting the required filters.
956  *
957  * Return: 0
958  */
959 uint32_t
960 target_if_spectral_get_rxfilter(void *arg)
961 {
962 	/*
963 	 * Will not be required since enabling of spectral in firmware
964 	 * will take care of this
965 	 */
966 	return 0;
967 }
968 
969 /**
970  * target_if_sops_is_spectral_active() - Get whether Spectral is active
971  * @arg: Pointer to handle for Spectral target_if internal private data
972  * @smode: Spectral scan mode
973  *
974  * Function to check whether Spectral is active
975  *
976  * Return: True if Spectral is active, false if Spectral is not active
977  */
978 uint32_t
979 target_if_sops_is_spectral_active(void *arg, enum spectral_scan_mode smode)
980 {
981 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
982 	uint8_t val = 0;
983 	int ret;
984 
985 	ret = target_if_spectral_info_read(
986 		spectral,
987 		smode,
988 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
989 		&val, sizeof(val));
990 
991 	if (ret != 0) {
992 		/*
993 		 * Could not determine if Spectral is active.
994 		 * Return false as a safe value.
995 		 * XXX: Consider changing the function prototype
996 		 * to be able to indicate failure to fetch value.
997 		 */
998 		return 0;
999 	}
1000 
1001 	return val;
1002 }
1003 
1004 /**
1005  * target_if_sops_is_spectral_enabled() - Get whether Spectral is enabled
1006  * @arg: Pointer to handle for Spectral target_if internal private data
1007  * @smode: Spectral scan mode
1008  *
1009  * Function to check whether Spectral is enabled
1010  *
1011  * Return: True if Spectral is enabled, false if Spectral is not enabled
1012  */
1013 uint32_t
1014 target_if_sops_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
1015 {
1016 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1017 	uint8_t val = 0;
1018 	int ret;
1019 
1020 	ret = target_if_spectral_info_read(
1021 		spectral,
1022 		smode,
1023 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1024 		&val, sizeof(val));
1025 
1026 	if (ret != 0) {
1027 		/*
1028 		 * Could not determine if Spectral is enabled.
1029 		 * Return false as a safe value.
1030 		 * XXX: Consider changing the function prototype
1031 		 * to be able to indicate failure to fetch value.
1032 		 */
1033 		return 0;
1034 	}
1035 
1036 	return val;
1037 }
1038 
1039 /**
1040  * target_if_sops_start_spectral_scan() - Start Spectral scan
1041  * @arg: Pointer to handle for Spectral target_if internal private data
1042  * @smode: Spectral scan mode
1043  * @err: Spectral error code
1044  *
1045  * Function to start spectral scan
1046  *
1047  * Return: 0 on success else failure
1048  */
1049 uint32_t
1050 target_if_sops_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
1051 				   enum spectral_cp_error_code *err)
1052 {
1053 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1054 	uint8_t val = 1;
1055 	uint8_t enabled = 0;
1056 	int ret;
1057 
1058 	ret = target_if_spectral_info_read(
1059 		spectral,
1060 		smode,
1061 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1062 		&enabled, sizeof(enabled));
1063 
1064 	if (ret != 0) {
1065 		/*
1066 		 * Could not determine if Spectral is enabled. Assume we need
1067 		 * to enable it
1068 		 */
1069 		enabled = 0;
1070 	}
1071 
1072 	if (!enabled) {
1073 		ret = target_if_spectral_info_write(
1074 			spectral,
1075 			smode,
1076 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1077 			&val, sizeof(val));
1078 
1079 		if (ret != 0)
1080 			return ret;
1081 	}
1082 
1083 	ret = target_if_spectral_info_write(
1084 		spectral,
1085 		smode,
1086 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
1087 		&val, sizeof(val));
1088 
1089 	if (ret != 0)
1090 		return ret;
1091 
1092 	return 0;
1093 }
1094 
1095 /**
1096  * target_if_sops_stop_spectral_scan() - Stop Spectral scan
1097  * @arg: Pointer to handle for Spectral target_if internal private data
1098  * @smode: Spectral scan mode
1099  *
1100  * Function to stop spectral scan
1101  *
1102  * Return: 0 on success else failure
1103  */
1104 uint32_t
1105 target_if_sops_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
1106 {
1107 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1108 	uint8_t val = 0;
1109 	int tempret, ret = 0;
1110 	uint8_t enabled = 0;
1111 
1112 	tempret = target_if_spectral_info_read(
1113 		spectral,
1114 		smode,
1115 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1116 		&enabled, sizeof(enabled));
1117 
1118 	if (tempret)
1119 		/*
1120 		 * Could not determine if Spectral is enabled. Assume scan is
1121 		 * not in progress
1122 		 */
1123 		enabled = 0;
1124 
1125 	/* if scan is not enabled, no need to send stop to FW */
1126 	if (!enabled)
1127 		return -EPERM;
1128 
1129 	tempret = target_if_spectral_info_write(
1130 			spectral,
1131 			smode,
1132 			TARGET_IF_SPECTRAL_INFO_ACTIVE,
1133 			&val, sizeof(val));
1134 
1135 	if (tempret != 0)
1136 		ret = tempret;
1137 
1138 	tempret = target_if_spectral_info_write(
1139 			spectral,
1140 			smode,
1141 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1142 			&val, sizeof(val));
1143 
1144 	if (tempret != 0)
1145 		ret = tempret;
1146 
1147 	return ret;
1148 }
1149 
1150 /**
1151  * target_if_spectral_get_extension_channel() - Get the Extension channel
1152  * @arg: Pointer to handle for Spectral target_if internal private data
1153  * @smode: Spectral scan mode
1154  *
1155  * Function to get the current Extension channel (in MHz)
1156  *
1157  * Return: Current Extension channel (in MHz) on success, 0 on failure or if
1158  * extension channel is not present.
1159  */
1160 uint32_t
1161 target_if_spectral_get_extension_channel(void *arg,
1162 					 enum spectral_scan_mode smode)
1163 {
1164 	/*
1165 	 * XXX: Once we expand to use cases where Spectral could be activated
1166 	 * without a channel being set to VDEV, we need to consider returning a
1167 	 * negative value in case of failure and having all callers handle this.
1168 	 */
1169 
1170 	struct target_if_spectral *spectral = NULL;
1171 	struct wlan_objmgr_vdev *vdev = NULL;
1172 	uint16_t sec20chan_freq = 0;
1173 
1174 	qdf_assert_always(arg);
1175 	spectral = (struct target_if_spectral *)arg;
1176 
1177 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1178 		spectral_err("Invalid Spectral mode %u", smode);
1179 		return 0;
1180 	}
1181 	vdev = target_if_spectral_get_vdev(spectral, smode);
1182 	if (!vdev)
1183 		return 0;
1184 
1185 	if (target_if_vdev_get_sec20chan_freq_mhz(vdev, &sec20chan_freq) < 0) {
1186 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1187 		return 0;
1188 	}
1189 
1190 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1191 
1192 	return sec20chan_freq;
1193 }
1194 
1195 /**
1196  * target_if_spectral_get_current_channel() - Get the current channel
1197  * @arg: Pointer to handle for Spectral target_if internal private data
1198  * @smode: Spectral scan mode
1199  *
1200  * Function to get the current channel (in MHz)
1201  *
1202  * Return: Current channel (in MHz) on success, 0 on failure
1203  */
1204 uint32_t
1205 target_if_spectral_get_current_channel(void *arg, enum spectral_scan_mode smode)
1206 {
1207 	/*
1208 	 * XXX: Once we expand to use cases where Spectral could be activated
1209 	 * without a channel being set to VDEV, we need to consider returning a
1210 	 * negative value in case of failure and having all callers handle this.
1211 	 */
1212 
1213 	struct target_if_spectral *spectral = NULL;
1214 	int16_t chan_freq = 0;
1215 	struct wlan_objmgr_vdev *vdev = NULL;
1216 
1217 	qdf_assert_always(arg);
1218 	spectral = (struct target_if_spectral *)arg;
1219 
1220 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1221 		spectral_err("Invalid Spectral mode %u", smode);
1222 		return 0;
1223 	}
1224 	vdev = target_if_spectral_get_vdev(spectral, smode);
1225 	if (!vdev)
1226 		return 0;
1227 
1228 	chan_freq = target_if_vdev_get_chan_freq(vdev);
1229 	if (chan_freq < 0) {
1230 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1231 		return 0;
1232 	}
1233 
1234 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1235 
1236 	return chan_freq;
1237 }
1238 
1239 /**
1240  * target_if_spectral_reset_hw() - Reset the hardware
1241  * @arg: Pointer to handle for Spectral target_if internal private data
1242  *
1243  * This is only a placeholder since it is not currently required in the offload
1244  * case.
1245  *
1246  * Return: 0
1247  */
1248 uint32_t
1249 target_if_spectral_reset_hw(void *arg)
1250 {
1251 	not_yet_implemented();
1252 	return 0;
1253 }
1254 
1255 /**
1256  * target_if_spectral_get_chain_noise_floor() - Get the Chain noise floor from
1257  * Noisefloor history buffer
1258  * @arg: Pointer to handle for Spectral target_if internal private data
1259  * @nf_buf: Pointer to buffer into which chain Noise Floor data should be copied
1260  *
1261  * This is only a placeholder since it is not currently required in the offload
1262  * case.
1263  *
1264  * Return: 0
1265  */
1266 uint32_t
1267 target_if_spectral_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1268 {
1269 	not_yet_implemented();
1270 	return 0;
1271 }
1272 
1273 /**
1274  * target_if_spectral_get_ext_noisefloor() - Get the extension channel
1275  * noisefloor
1276  * @arg: Pointer to handle for Spectral target_if internal private data
1277  *
1278  * This is only a placeholder since it is not currently required in the offload
1279  * case.
1280  *
1281  * Return: 0
1282  */
1283 int8_t
1284 target_if_spectral_get_ext_noisefloor(void *arg)
1285 {
1286 	not_yet_implemented();
1287 	return 0;
1288 }
1289 
1290 /**
1291  * target_if_spectral_get_ctl_noisefloor() - Get the control channel noisefloor
1292  * @arg: Pointer to handle for Spectral target_if internal private data
1293  *
1294  * This is only a placeholder since it is not currently required in the offload
1295  * case.
1296  *
1297  * Return: 0
1298  */
1299 int8_t
1300 target_if_spectral_get_ctl_noisefloor(void *arg)
1301 {
1302 	not_yet_implemented();
1303 	return 0;
1304 }
1305 
1306 /**
1307  * target_if_spectral_sops_configure_params() - Configure user supplied Spectral
1308  *                                         parameters
1309  * @arg: Pointer to handle for Spectral target_if internal private data
1310  * @params: Spectral parameters
1311  * @smode: Spectral scan mode
1312  *
1313  * Function to configure spectral parameters
1314  *
1315  * Return: 0 on success else failure
1316  */
1317 uint32_t
1318 target_if_spectral_sops_configure_params(
1319 	void *arg, struct spectral_config *params,
1320 	enum spectral_scan_mode smode)
1321 {
1322 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1323 
1324 	return target_if_spectral_info_write(
1325 		spectral,
1326 		smode,
1327 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1328 		params, sizeof(*params));
1329 }
1330 
1331 /**
1332  * target_if_spectral_sops_get_params() - Get user configured Spectral
1333  * parameters
1334  * @arg: Pointer to handle for Spectral target_if internal private data
1335  * @params: Pointer to buffer into which Spectral parameters should be copied
1336  * @smode: Spectral scan mode
1337  *
1338  * Function to get the configured spectral parameters
1339  *
1340  * Return: 0 on success else failure
1341  */
1342 uint32_t
1343 target_if_spectral_sops_get_params(void *arg, struct spectral_config *params,
1344 				   enum spectral_scan_mode smode)
1345 {
1346 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1347 
1348 	return target_if_spectral_info_read(
1349 		spectral,
1350 		smode,
1351 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1352 		params, sizeof(*params));
1353 }
1354 
1355 /**
1356  * target_if_spectral_get_ent_mask() - Get enterprise mask
1357  * @arg: Pointer to handle for Spectral target_if internal private data
1358  *
1359  * This is only a placeholder since it is not currently required in the offload
1360  * case.
1361  *
1362  * Return: 0
1363  */
1364 static uint32_t
1365 target_if_spectral_get_ent_mask(void *arg)
1366 {
1367 	not_yet_implemented();
1368 	return 0;
1369 }
1370 
1371 /**
1372  * target_if_spectral_get_macaddr() - Get radio MAC address
1373  * @arg: Pointer to handle for Spectral target_if internal private data
1374  * @addr: Pointer to buffer into which MAC address should be copied
1375  *
1376  * Function to get the MAC address of the pdev
1377  *
1378  * Return: 0 on success, -1 on failure
1379  */
1380 static uint32_t
1381 target_if_spectral_get_macaddr(void *arg, char *addr)
1382 {
1383 	uint8_t *myaddr = NULL;
1384 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1385 	struct wlan_objmgr_pdev *pdev = NULL;
1386 
1387 	pdev = spectral->pdev_obj;
1388 
1389 	wlan_pdev_obj_lock(pdev);
1390 	myaddr = wlan_pdev_get_hw_macaddr(pdev);
1391 	wlan_pdev_obj_unlock(pdev);
1392 	qdf_mem_copy(addr, myaddr, QDF_MAC_ADDR_SIZE);
1393 
1394 	return 0;
1395 }
1396 
1397 /**
1398  * target_if_init_spectral_param_min_max() - Initialize Spectral parameter
1399  * min and max values
1400  *
1401  * @param_min_max: Pointer to Spectral parameter min and max structure
1402  * @gen: Spectral HW generation
1403  * @target_type: Target type
1404  *
1405  * Initialize Spectral parameter min and max values
1406  *
1407  * Return: QDF_STATUS
1408  */
1409 static QDF_STATUS
1410 target_if_init_spectral_param_min_max(
1411 				struct spectral_param_min_max *param_min_max,
1412 				enum spectral_gen gen, uint32_t target_type)
1413 {
1414 	switch (gen) {
1415 	case SPECTRAL_GEN3:
1416 		param_min_max->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN3;
1417 		param_min_max->fft_size_max[CH_WIDTH_20MHZ] =
1418 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1419 		if (target_type == TARGET_TYPE_QCN9000 ||
1420 		    target_type == TARGET_TYPE_QCN9100 ||
1421 		    target_type == TARGET_TYPE_QCA5018 ||
1422 		    target_type == TARGET_TYPE_QCA6490) {
1423 			param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
1424 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1425 			param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
1426 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1427 			param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
1428 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1429 			param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
1430 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1431 		} else {
1432 			param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
1433 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1434 			param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
1435 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1436 			param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
1437 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1438 			param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
1439 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1440 		}
1441 		break;
1442 
1443 	case SPECTRAL_GEN2:
1444 		param_min_max->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN2;
1445 		param_min_max->fft_size_max[CH_WIDTH_20MHZ] =
1446 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1447 		param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
1448 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1449 		param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
1450 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1451 		param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
1452 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1453 		param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
1454 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1455 		break;
1456 
1457 	default:
1458 		spectral_err("Invalid spectral generation %d", gen);
1459 		return QDF_STATUS_E_INVAL;
1460 	}
1461 
1462 	return QDF_STATUS_SUCCESS;
1463 }
1464 
1465 /**
1466  * target_if_init_spectral_param_properties() - Initialize Spectral parameter
1467  *                                              properties
1468  * @spectral: Pointer to Spectral target_if internal private data
1469  *
1470  * Initialize Spectral parameter properties
1471  *
1472  * Return: QDF_STATUS
1473  */
1474 static QDF_STATUS
1475 target_if_init_spectral_param_properties(struct target_if_spectral *spectral)
1476 {
1477 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1478 	int param;
1479 
1480 	/* Initialize default values for properties.
1481 	 * Default values are supported for all the parameters for all modes
1482 	 * and allows different values for each mode for all the parameters .
1483 	 */
1484 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
1485 		for (param = 0; param < SPECTRAL_PARAM_MAX; param++) {
1486 			spectral->properties[smode][param].supported = true;
1487 			spectral->properties[smode][param].common_all_modes =
1488 									false;
1489 		}
1490 	}
1491 
1492 	/* Once FW advertisement is in place remove this hard coding */
1493 	smode = SPECTRAL_SCAN_MODE_NORMAL;
1494 	spectral->properties[SPECTRAL_SCAN_MODE_NORMAL]
1495 			[SPECTRAL_PARAM_FREQUENCY].supported = false;
1496 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
1497 		spectral->properties[smode]
1498 			[SPECTRAL_PARAM_SPECT_PRI].common_all_modes = true;
1499 		spectral->properties[smode]
1500 			[SPECTRAL_PARAM_SCAN_PERIOD].common_all_modes = true;
1501 		spectral->properties[smode]
1502 			[SPECTRAL_PARAM_INIT_DELAY].common_all_modes = true;
1503 	}
1504 
1505 	return QDF_STATUS_SUCCESS;
1506 }
1507 
1508 QDF_STATUS
1509 target_if_init_spectral_capability(struct target_if_spectral *spectral,
1510 				   uint32_t target_type)
1511 {
1512 	struct wlan_objmgr_psoc *psoc;
1513 	struct wlan_objmgr_pdev *pdev;
1514 	struct wlan_psoc_host_spectral_scaling_params *scaling_params;
1515 	uint8_t num_bin_scaling_params, param_idx, pdev_id;
1516 	struct target_psoc_info *tgt_psoc_info;
1517 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
1518 	struct spectral_caps *pcap = &spectral->capability;
1519 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr = NULL;
1520 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = NULL;
1521 	struct wlan_psoc_host_chainmask_table *table;
1522 	int j;
1523 	uint32_t table_id;
1524 
1525 	pdev = spectral->pdev_obj;
1526 	psoc = wlan_pdev_get_psoc(pdev);
1527 	if (!psoc) {
1528 		spectral_err("psoc is null");
1529 		return QDF_STATUS_E_FAILURE;
1530 	}
1531 
1532 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
1533 	if (!tgt_psoc_info) {
1534 		spectral_err("target_psoc_info is null");
1535 		return QDF_STATUS_E_FAILURE;
1536 	}
1537 
1538 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
1539 	num_bin_scaling_params = ext_svc_param->num_bin_scaling_params;
1540 	scaling_params = target_psoc_get_spectral_scaling_params(tgt_psoc_info);
1541 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1542 
1543 	/* XXX : Workaround: Set Spectral capability */
1544 	pcap = &spectral->capability;
1545 	pcap->phydiag_cap = 1;
1546 	pcap->radar_cap = 1;
1547 	pcap->spectral_cap = 1;
1548 	pcap->advncd_spectral_cap = 1;
1549 	pcap->hw_gen = spectral->spectral_gen;
1550 	if (spectral->spectral_gen >= SPECTRAL_GEN3) {
1551 		mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
1552 		if (!mac_phy_cap_arr) {
1553 			spectral_err("mac phy cap array is null");
1554 			return QDF_STATUS_E_FAILURE;
1555 		}
1556 
1557 		mac_phy_cap = &mac_phy_cap_arr[pdev_id];
1558 		if (!mac_phy_cap) {
1559 			spectral_err("mac phy cap is null");
1560 			return QDF_STATUS_E_FAILURE;
1561 		}
1562 
1563 		table_id = mac_phy_cap->chainmask_table_id;
1564 		table =  &ext_svc_param->chainmask_table[table_id];
1565 		if (!table) {
1566 			spectral_err("chainmask table not found");
1567 			return QDF_STATUS_E_FAILURE;
1568 		}
1569 
1570 		for (j = 0; j < table->num_valid_chainmasks; j++) {
1571 			pcap->agile_spectral_cap |=
1572 				table->cap_list[j].supports_aSpectral;
1573 			pcap->agile_spectral_cap_160 |=
1574 				table->cap_list[j].supports_aSpectral_160;
1575 		}
1576 		pcap->agile_spectral_cap_80p80 = pcap->agile_spectral_cap_160;
1577 	} else {
1578 		pcap->agile_spectral_cap = false;
1579 		pcap->agile_spectral_cap_160 = false;
1580 		pcap->agile_spectral_cap_80p80 = false;
1581 	}
1582 
1583 	if (scaling_params) {
1584 		for (param_idx = 0; param_idx < num_bin_scaling_params;
1585 		     param_idx++) {
1586 			if (scaling_params[param_idx].pdev_id == pdev_id) {
1587 				pcap->is_scaling_params_populated = true;
1588 				pcap->formula_id =
1589 				    scaling_params[param_idx].formula_id;
1590 				pcap->low_level_offset =
1591 				    scaling_params[param_idx].low_level_offset;
1592 				pcap->high_level_offset =
1593 				    scaling_params[param_idx].high_level_offset;
1594 				pcap->rssi_thr =
1595 				    scaling_params[param_idx].rssi_thr;
1596 				pcap->default_agc_max_gain =
1597 				 scaling_params[param_idx].default_agc_max_gain;
1598 				break;
1599 			}
1600 		}
1601 	}
1602 
1603 	pcap->num_detectors_20mhz = 1;
1604 	pcap->num_detectors_40mhz = 1;
1605 	pcap->num_detectors_80mhz = 1;
1606 	if (target_type == TARGET_TYPE_QCN9000 ||
1607 	    target_type == TARGET_TYPE_QCN9100 ||
1608 	    target_type == TARGET_TYPE_QCA6490) {
1609 		pcap->num_detectors_160mhz = 1;
1610 		pcap->num_detectors_80p80mhz = 1;
1611 	} else {
1612 		pcap->num_detectors_160mhz = 2;
1613 		pcap->num_detectors_80p80mhz = 2;
1614 	}
1615 
1616 	return QDF_STATUS_SUCCESS;
1617 }
1618 
1619 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1620 /**
1621  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1622  * internal operations with functions related to spectral simulation
1623  * @p_sops: spectral low level ops table
1624  *
1625  * Initialize spectral target_if internal operations with functions
1626  * related to spectral simulation
1627  *
1628  * Return: None
1629  */
1630 static void
1631 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1632 {
1633 	/*
1634 	 * Spectral simulation is currently intended for platform transitions
1635 	 * where underlying HW support may not be available for some time.
1636 	 * Hence, we do not currently provide a runtime switch to turn the
1637 	 * simulation on or off.
1638 	 * In case of future requirements where runtime switches are required,
1639 	 * this can be added. But it is suggested to use application layer
1640 	 * simulation as far as possible in such cases, since the main
1641 	 * use of record and replay of samples would concern higher
1642 	 * level sample processing rather than lower level delivery.
1643 	 */
1644 	p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled;
1645 	p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active;
1646 	p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan;
1647 	p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan;
1648 	p_sops->configure_spectral =
1649 		target_if_spectral_sops_sim_configure_params;
1650 	p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params;
1651 }
1652 
1653 #else
1654 /**
1655  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1656  * internal operations
1657  * @p_sops: spectral low level ops table
1658  *
1659  * Return: None
1660  */
1661 static void
1662 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1663 {
1664 	p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled;
1665 	p_sops->is_spectral_active = target_if_sops_is_spectral_active;
1666 	p_sops->start_spectral_scan = target_if_sops_start_spectral_scan;
1667 	p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan;
1668 	p_sops->configure_spectral = target_if_spectral_sops_configure_params;
1669 	p_sops->get_spectral_config = target_if_spectral_sops_get_params;
1670 }
1671 #endif
1672 
1673 /**
1674  * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
1675  * operations common to all Spectral chipset generations
1676  *
1677  * Initializes target_if_spectral_ops common to all chipset generations
1678  *
1679  * Return: None
1680  */
1681 static void
1682 target_if_init_spectral_ops_common(void)
1683 {
1684 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1685 
1686 	p_sops->get_tsf64 = target_if_spectral_get_tsf64;
1687 	p_sops->get_capability = target_if_spectral_get_capability;
1688 	p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
1689 	p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
1690 
1691 	target_if_init_spectral_simulation_ops(p_sops);
1692 
1693 	p_sops->get_extension_channel =
1694 	    target_if_spectral_get_extension_channel;
1695 	p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor;
1696 	p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor;
1697 	p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
1698 	p_sops->get_mac_address = target_if_spectral_get_macaddr;
1699 	p_sops->get_current_channel = target_if_spectral_get_current_channel;
1700 	p_sops->reset_hw = target_if_spectral_reset_hw;
1701 	p_sops->get_chain_noise_floor =
1702 	    target_if_spectral_get_chain_noise_floor;
1703 }
1704 
1705 /**
1706  * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
1707  * operations specific to Spectral chipset generation 2.
1708  *
1709  * Initializes target_if_spectral_ops specific to Spectral chipset generation 2.
1710  *
1711  * Return: None
1712  */
1713 static void
1714 target_if_init_spectral_ops_gen2(void)
1715 {
1716 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1717 
1718 	p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2;
1719 }
1720 
1721 /**
1722  * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
1723  * operations specific to Spectral chipset generation 3.
1724  *
1725  * Initializes target_if_spectral_ops specific to Spectral chipset generation 3.
1726  *
1727  * Return: None
1728  */
1729 static void
1730 target_if_init_spectral_ops_gen3(void)
1731 {
1732 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1733 
1734 	p_sops->process_spectral_report =
1735 			target_if_spectral_process_report_gen3;
1736 	return;
1737 }
1738 
1739 /**
1740  * target_if_init_spectral_ops() - Initialize target_if internal Spectral
1741  * operations.
1742  * @spectral: Pointer to Spectral target_if internal private data
1743  *
1744  * Initializes all function pointers in target_if_spectral_ops for
1745  * all generations
1746  *
1747  * Return: None
1748  */
1749 static void
1750 target_if_init_spectral_ops(struct target_if_spectral *spectral)
1751 {
1752 	target_if_init_spectral_ops_common();
1753 	if (spectral->spectral_gen == SPECTRAL_GEN2)
1754 		target_if_init_spectral_ops_gen2();
1755 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
1756 		target_if_init_spectral_ops_gen3();
1757 	else
1758 		spectral_err("Invalid Spectral generation");
1759 }
1760 
1761 /*
1762  * Dummy Functions:
1763  * These functions are initially registered to avoid any crashes due to
1764  * invocation of spectral functions before they are registered.
1765  */
1766 
1767 static uint64_t
1768 null_get_tsf64(void *arg)
1769 {
1770 	spectral_ops_not_registered("get_tsf64");
1771 	return 0;
1772 }
1773 
1774 static uint32_t
1775 null_get_capability(void *arg, enum spectral_capability_type type)
1776 {
1777 	/*
1778 	 * TODO : We should have conditional compilation to get the capability
1779 	 *      : We have not yet attahced ATH layer here, so there is no
1780 	 *      : way to check the HAL capbalities
1781 	 */
1782 	spectral_ops_not_registered("get_capability");
1783 
1784 	/* TODO : For the time being, we are returning TRUE */
1785 	return true;
1786 }
1787 
1788 static uint32_t
1789 null_set_rxfilter(void *arg, int rxfilter)
1790 {
1791 	spectral_ops_not_registered("set_rxfilter");
1792 	return 1;
1793 }
1794 
1795 static uint32_t
1796 null_get_rxfilter(void *arg)
1797 {
1798 	spectral_ops_not_registered("get_rxfilter");
1799 	return 0;
1800 }
1801 
1802 static uint32_t
1803 null_is_spectral_active(void *arg, enum spectral_scan_mode smode)
1804 {
1805 	spectral_ops_not_registered("is_spectral_active");
1806 	return 1;
1807 }
1808 
1809 static uint32_t
1810 null_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
1811 {
1812 	spectral_ops_not_registered("is_spectral_enabled");
1813 	return 1;
1814 }
1815 
1816 static uint32_t
1817 null_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
1818 			 enum spectral_cp_error_code *err)
1819 {
1820 	spectral_ops_not_registered("start_spectral_scan");
1821 	return 1;
1822 }
1823 
1824 static uint32_t
1825 null_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
1826 {
1827 	spectral_ops_not_registered("stop_spectral_scan");
1828 	return 1;
1829 }
1830 
1831 static uint32_t
1832 null_get_extension_channel(void *arg, enum spectral_scan_mode smode)
1833 {
1834 	spectral_ops_not_registered("get_extension_channel");
1835 	return 1;
1836 }
1837 
1838 static int8_t
1839 null_get_ctl_noisefloor(void *arg)
1840 {
1841 	spectral_ops_not_registered("get_ctl_noisefloor");
1842 	return 1;
1843 }
1844 
1845 static int8_t
1846 null_get_ext_noisefloor(void *arg)
1847 {
1848 	spectral_ops_not_registered("get_ext_noisefloor");
1849 	return 0;
1850 }
1851 
1852 static uint32_t
1853 null_configure_spectral(void *arg, struct spectral_config *params,
1854 			enum spectral_scan_mode smode)
1855 {
1856 	spectral_ops_not_registered("configure_spectral");
1857 	return 0;
1858 }
1859 
1860 static uint32_t
1861 null_get_spectral_config(void *arg, struct spectral_config *params,
1862 			 enum spectral_scan_mode smode)
1863 {
1864 	spectral_ops_not_registered("get_spectral_config");
1865 	return 0;
1866 }
1867 
1868 static uint32_t
1869 null_get_ent_spectral_mask(void *arg)
1870 {
1871 	spectral_ops_not_registered("get_ent_spectral_mask");
1872 	return 0;
1873 }
1874 
1875 static uint32_t
1876 null_get_mac_address(void *arg, char *addr)
1877 {
1878 	spectral_ops_not_registered("get_mac_address");
1879 	return 0;
1880 }
1881 
1882 static uint32_t
1883 null_get_current_channel(void *arg, enum spectral_scan_mode smode)
1884 {
1885 	spectral_ops_not_registered("get_current_channel");
1886 	return 0;
1887 }
1888 
1889 static uint32_t
1890 null_reset_hw(void *arg)
1891 {
1892 	spectral_ops_not_registered("get_current_channel");
1893 	return 0;
1894 }
1895 
1896 static uint32_t
1897 null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1898 {
1899 	spectral_ops_not_registered("get_chain_noise_floor");
1900 	return 0;
1901 }
1902 
1903 static int
1904 null_spectral_process_phyerr(struct target_if_spectral *spectral,
1905 			     uint8_t *data,
1906 			     uint32_t datalen,
1907 			     struct target_if_spectral_rfqual_info *p_rfqual,
1908 			     struct target_if_spectral_chan_info *p_chaninfo,
1909 			     uint64_t tsf64,
1910 			     struct target_if_spectral_acs_stats *acs_stats)
1911 {
1912 	spectral_ops_not_registered("spectral_process_phyerr");
1913 	return 0;
1914 }
1915 
1916 static int
1917 null_process_spectral_report(struct wlan_objmgr_pdev *pdev,
1918 			     void *payload)
1919 {
1920 	spectral_ops_not_registered("process_spectral_report");
1921 	return 0;
1922 }
1923 /**
1924  * target_if_spectral_init_dummy_function_table() -
1925  * Initialize target_if internal
1926  * Spectral operations to dummy functions
1927  * @ps: Pointer to Spectral target_if internal private data
1928  *
1929  * Initialize all the function pointers in target_if_spectral_ops with
1930  * dummy functions.
1931  *
1932  * Return: None
1933  */
1934 static void
1935 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps)
1936 {
1937 	struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps);
1938 
1939 	p_sops->get_tsf64 = null_get_tsf64;
1940 	p_sops->get_capability = null_get_capability;
1941 	p_sops->set_rxfilter = null_set_rxfilter;
1942 	p_sops->get_rxfilter = null_get_rxfilter;
1943 	p_sops->is_spectral_enabled = null_is_spectral_enabled;
1944 	p_sops->is_spectral_active = null_is_spectral_active;
1945 	p_sops->start_spectral_scan = null_start_spectral_scan;
1946 	p_sops->stop_spectral_scan = null_stop_spectral_scan;
1947 	p_sops->get_extension_channel = null_get_extension_channel;
1948 	p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
1949 	p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
1950 	p_sops->configure_spectral = null_configure_spectral;
1951 	p_sops->get_spectral_config = null_get_spectral_config;
1952 	p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
1953 	p_sops->get_mac_address = null_get_mac_address;
1954 	p_sops->get_current_channel = null_get_current_channel;
1955 	p_sops->reset_hw = null_reset_hw;
1956 	p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
1957 	p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
1958 	p_sops->process_spectral_report = null_process_spectral_report;
1959 }
1960 
1961 /**
1962  * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
1963  * operations
1964  * @spectral: Pointer to Spectral target_if internal private data
1965  * @p: Pointer to Spectral function table
1966  *
1967  * Return: None
1968  */
1969 static void
1970 target_if_spectral_register_funcs(struct target_if_spectral *spectral,
1971 				  struct target_if_spectral_ops *p)
1972 {
1973 	struct target_if_spectral_ops *p_sops =
1974 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1975 
1976 	p_sops->get_tsf64 = p->get_tsf64;
1977 	p_sops->get_capability = p->get_capability;
1978 	p_sops->set_rxfilter = p->set_rxfilter;
1979 	p_sops->get_rxfilter = p->get_rxfilter;
1980 	p_sops->is_spectral_enabled = p->is_spectral_enabled;
1981 	p_sops->is_spectral_active = p->is_spectral_active;
1982 	p_sops->start_spectral_scan = p->start_spectral_scan;
1983 	p_sops->stop_spectral_scan = p->stop_spectral_scan;
1984 	p_sops->get_extension_channel = p->get_extension_channel;
1985 	p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor;
1986 	p_sops->get_ext_noisefloor = p->get_ext_noisefloor;
1987 	p_sops->configure_spectral = p->configure_spectral;
1988 	p_sops->get_spectral_config = p->get_spectral_config;
1989 	p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask;
1990 	p_sops->get_mac_address = p->get_mac_address;
1991 	p_sops->get_current_channel = p->get_current_channel;
1992 	p_sops->reset_hw = p->reset_hw;
1993 	p_sops->get_chain_noise_floor = p->get_chain_noise_floor;
1994 	p_sops->spectral_process_phyerr = p->spectral_process_phyerr;
1995 	p_sops->process_spectral_report = p->process_spectral_report;
1996 }
1997 
1998 /**
1999  * target_if_spectral_clear_stats() - Clear Spectral stats
2000  * @spectral: Pointer to Spectral target_if internal private data
2001  *
2002  * Function to clear spectral stats
2003  *
2004  * Return: None
2005  */
2006 static void
2007 target_if_spectral_clear_stats(struct target_if_spectral *spectral)
2008 {
2009 	struct target_if_spectral_ops *p_sops =
2010 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2011 
2012 	qdf_mem_zero(&spectral->spectral_stats,
2013 		     sizeof(struct target_if_spectral_stats));
2014 	spectral->spectral_stats.last_reset_tstamp =
2015 	    p_sops->get_tsf64(spectral);
2016 }
2017 
2018 /**
2019  * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
2020  * @spectral: Pointer to Spectral target_if internal private data
2021  *
2022  * Function to check whether hardware supports spectral
2023  *
2024  * Return: True if HW supports Spectral, false if HW does not support Spectral
2025  */
2026 static int
2027 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
2028 {
2029 	struct target_if_spectral_ops *p_sops = NULL;
2030 	struct spectral_caps *pcap = NULL;
2031 	int is_spectral_supported = true;
2032 
2033 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2034 	pcap = &spectral->capability;
2035 
2036 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
2037 		is_spectral_supported = false;
2038 		spectral_info("SPECTRAL : No PHYDIAG support");
2039 		return is_spectral_supported;
2040 	}
2041 	pcap->phydiag_cap = 1;
2042 
2043 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
2044 		is_spectral_supported = false;
2045 		spectral_info("SPECTRAL : No RADAR support");
2046 		return is_spectral_supported;
2047 	}
2048 	pcap->radar_cap = 1;
2049 
2050 	if (p_sops->get_capability(spectral,
2051 				   SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
2052 		is_spectral_supported = false;
2053 		spectral_info("SPECTRAL : No SPECTRAL SUPPORT");
2054 		return is_spectral_supported;
2055 	}
2056 	pcap->spectral_cap = 1;
2057 
2058 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
2059 	    == false) {
2060 		spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT");
2061 	} else {
2062 		pcap->advncd_spectral_cap = 1;
2063 	}
2064 
2065 	return is_spectral_supported;
2066 }
2067 
2068 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
2069 /**
2070  * target_if_spectral_detach_simulation() - De-initialize Spectral
2071  * Simulation functionality
2072  * @spectral: Pointer to Spectral target_if internal private data
2073  *
2074  * Function to de-initialize Spectral Simulation functionality
2075  *
2076  * Return: None
2077  */
2078 static void
2079 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
2080 {
2081 	target_if_spectral_sim_detach(spectral);
2082 }
2083 
2084 #else
2085 static void
2086 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
2087 {
2088 }
2089 #endif
2090 
2091 /**
2092  * target_if_spectral_detach() - De-initialize target_if Spectral
2093  * @pdev: Pointer to pdev object
2094  *
2095  * Function to detach target_if spectral
2096  *
2097  * Return: None
2098  */
2099 static void
2100 target_if_spectral_detach(struct target_if_spectral *spectral)
2101 {
2102 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
2103 	spectral_info("spectral detach");
2104 
2105 	if (spectral) {
2106 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
2107 			qdf_spinlock_destroy
2108 				(&spectral->param_info[smode].osps_lock);
2109 
2110 		target_if_spectral_detach_simulation(spectral);
2111 
2112 		qdf_spinlock_destroy(&spectral->spectral_lock);
2113 		qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
2114 
2115 		qdf_mem_free(spectral);
2116 		spectral = NULL;
2117 	}
2118 }
2119 
2120 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
2121 /**
2122  * target_if_spectral_attach_simulation() - Initialize Spectral Simulation
2123  * functionality
2124  * @spectral: Pointer to Spectral target_if internal private data
2125  *
2126  * Function to initialize spectral simulation functionality
2127  *
2128  * Return: 0 on success, negative error code on failure
2129  */
2130 static int
2131 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
2132 {
2133 	if (target_if_spectral_sim_attach(spectral)) {
2134 		qdf_mem_free(spectral);
2135 		return -EPERM;
2136 	}
2137 	return 0;
2138 }
2139 
2140 #else
2141 static int
2142 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
2143 {
2144 	return 0;
2145 }
2146 #endif
2147 
2148 /**
2149  * target_if_spectral_len_adj_swar_init() - Initialize FFT bin length adjustment
2150  * related info
2151  * @swar: Pointer to Spectral FFT bin length adjustment SWAR params
2152  * @target_type: Target type
2153  *
2154  * Function to Initialize parameters related to Spectral FFT bin
2155  * length adjustment SWARs.
2156  *
2157  * Return: void
2158  */
2159 static void
2160 target_if_spectral_len_adj_swar_init(struct spectral_fft_bin_len_adj_swar *swar,
2161 				     uint32_t target_type)
2162 {
2163 	if (target_type == TARGET_TYPE_QCA8074V2 ||
2164 	    target_type == TARGET_TYPE_QCN9000 ||
2165 	    target_type == TARGET_TYPE_QCN9100 ||
2166 	    target_type == TARGET_TYPE_QCA5018 ||
2167 	    target_type == TARGET_TYPE_QCA6750 ||
2168 	    target_type == TARGET_TYPE_QCA6490)
2169 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE;
2170 	else if (target_type == TARGET_TYPE_QCA8074 ||
2171 		 target_type == TARGET_TYPE_QCA6018 ||
2172 		 target_type == TARGET_TYPE_QCA6390)
2173 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE;
2174 	else
2175 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR;
2176 
2177 	if (target_type == TARGET_TYPE_QCA8074 ||
2178 	    target_type == TARGET_TYPE_QCA8074V2 ||
2179 	    target_type == TARGET_TYPE_QCA6018 ||
2180 	    target_type == TARGET_TYPE_QCN9100 ||
2181 	    target_type == TARGET_TYPE_QCA5018 ||
2182 	    target_type == TARGET_TYPE_QCN9000 ||
2183 	    target_type == TARGET_TYPE_QCA6490) {
2184 		swar->inband_fftbin_size_adj = 1;
2185 		swar->null_fftbin_adj = 1;
2186 	} else {
2187 		swar->inband_fftbin_size_adj = 0;
2188 		swar->null_fftbin_adj = 0;
2189 	}
2190 
2191 	if (target_type == TARGET_TYPE_QCA8074V2)
2192 		swar->packmode_fftbin_size_adj = 1;
2193 	else
2194 		swar->packmode_fftbin_size_adj = 0;
2195 }
2196 
2197 /**
2198  * target_if_spectral_report_params_init() - Initialize parameters which
2199  * describes the structure of Spectral reports
2200  *
2201  * @rparams: Pointer to Spectral report parameter object
2202  * @target_type: target type
2203  *
2204  * Function to Initialize parameters related to the structure of Spectral
2205  * reports.
2206  *
2207  * Return: void
2208  */
2209 static void
2210 target_if_spectral_report_params_init(
2211 			struct spectral_report_params *rparams,
2212 			uint32_t target_type)
2213 {
2214 	enum spectral_scan_mode smode;
2215 
2216 	/* This entries are currently used by gen3 chipsets only. Hence
2217 	 * initialization is done for gen3 alone. In future if other generations
2218 	 * needs to use them they have to add proper initial values.
2219 	 */
2220 	if (target_type == TARGET_TYPE_QCN9000 ||
2221 	    target_type == TARGET_TYPE_QCN9100 ||
2222 	    target_type == TARGET_TYPE_QCA5018 ||
2223 	    target_type == TARGET_TYPE_QCA6750 ||
2224 	    target_type == TARGET_TYPE_QCA6490) {
2225 		rparams->version = SPECTRAL_REPORT_FORMAT_VERSION_2;
2226 		rparams->num_spectral_detectors =
2227 				NUM_SPECTRAL_DETECTORS_GEN3_V2;
2228 		smode = SPECTRAL_SCAN_MODE_NORMAL;
2229 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
2230 			rparams->fragmentation_160[smode] = false;
2231 		rparams->max_agile_ch_width = CH_WIDTH_80P80MHZ;
2232 	} else {
2233 		rparams->version = SPECTRAL_REPORT_FORMAT_VERSION_1;
2234 		rparams->num_spectral_detectors =
2235 				NUM_SPECTRAL_DETECTORS_GEN3_V1;
2236 		smode = SPECTRAL_SCAN_MODE_NORMAL;
2237 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
2238 			rparams->fragmentation_160[smode] = true;
2239 		rparams->max_agile_ch_width = CH_WIDTH_80MHZ;
2240 	}
2241 
2242 	switch (rparams->version) {
2243 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
2244 		rparams->ssumaary_padding_bytes =
2245 			NUM_PADDING_BYTES_SSCAN_SUMARY_REPORT_GEN3_V1;
2246 		rparams->fft_report_hdr_len =
2247 			FFT_REPORT_HEADER_LENGTH_GEN3_V1;
2248 		break;
2249 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
2250 		rparams->ssumaary_padding_bytes =
2251 			NUM_PADDING_BYTES_SSCAN_SUMARY_REPORT_GEN3_V2;
2252 		rparams->fft_report_hdr_len =
2253 			FFT_REPORT_HEADER_LENGTH_GEN3_V2;
2254 		break;
2255 	default:
2256 		qdf_assert_always(0);
2257 	}
2258 
2259 	rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_0] =
2260 						SPECTRAL_SCAN_MODE_NORMAL;
2261 	if (target_type == TARGET_TYPE_QCN9000 ||
2262 	    target_type == TARGET_TYPE_QCN9100 ||
2263 	    target_type == TARGET_TYPE_QCA6490) {
2264 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
2265 						SPECTRAL_SCAN_MODE_AGILE;
2266 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
2267 						SPECTRAL_SCAN_MODE_INVALID;
2268 	} else {
2269 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
2270 						SPECTRAL_SCAN_MODE_NORMAL;
2271 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
2272 						SPECTRAL_SCAN_MODE_AGILE;
2273 	}
2274 }
2275 
2276 /**
2277  * target_if_spectral_timestamp_war_init() - Initialize Spectral timestamp WAR
2278  * related info
2279  * @twar: Pointer to Spectral timstamp WAR related info
2280  *
2281  * Function to Initialize parameters related to Spectral timestamp WAR
2282  *
2283  * Return: void
2284  */
2285 static void
2286 target_if_spectral_timestamp_war_init(struct spectral_timestamp_war *twar)
2287 {
2288 	enum spectral_scan_mode smode;
2289 
2290 	smode = SPECTRAL_SCAN_MODE_NORMAL;
2291 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2292 		twar->last_fft_timestamp[smode] = 0;
2293 		twar->timestamp_war_offset[smode] = 0;
2294 	}
2295 	twar->target_reset_count = 0;
2296 }
2297 
2298 /**
2299  * target_if_pdev_spectral_init() - Initialize target_if Spectral
2300  * functionality for the given pdev
2301  * @pdev: Pointer to pdev object
2302  *
2303  * Function to initialize pointer to spectral target_if internal private data
2304  *
2305  * Return: On success, pointer to Spectral target_if internal private data, on
2306  * failure, NULL
2307  */
2308 void *
2309 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
2310 {
2311 	struct target_if_spectral_ops *p_sops = NULL;
2312 	struct target_if_spectral *spectral = NULL;
2313 	uint32_t target_type;
2314 	uint32_t target_revision;
2315 	struct wlan_objmgr_psoc *psoc;
2316 	struct wlan_lmac_if_target_tx_ops *tgt_tx_ops;
2317 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
2318 	QDF_STATUS status;
2319 	struct wlan_lmac_if_tx_ops *tx_ops;
2320 
2321 	if (!pdev) {
2322 		spectral_err("SPECTRAL: pdev is NULL!");
2323 		return NULL;
2324 	}
2325 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
2326 			sizeof(struct target_if_spectral));
2327 	if (!spectral)
2328 		return spectral;
2329 
2330 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
2331 	/* Store pdev in Spectral */
2332 	spectral->pdev_obj = pdev;
2333 	spectral->vdev_id[SPECTRAL_SCAN_MODE_NORMAL] = WLAN_INVALID_VDEV_ID;
2334 	spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE] = WLAN_INVALID_VDEV_ID;
2335 
2336 	psoc = wlan_pdev_get_psoc(pdev);
2337 
2338 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
2339 	if (!tx_ops) {
2340 		spectral_err("tx_ops is NULL");
2341 		qdf_mem_free(spectral);
2342 		return NULL;
2343 	}
2344 
2345 	tgt_tx_ops = &tx_ops->target_tx_ops;
2346 
2347 	if (tgt_tx_ops->tgt_get_tgt_type) {
2348 		target_type = tgt_tx_ops->tgt_get_tgt_type(psoc);
2349 	} else {
2350 		qdf_mem_free(spectral);
2351 		return NULL;
2352 	}
2353 
2354 	if (tgt_tx_ops->tgt_get_tgt_revision) {
2355 		target_revision = tgt_tx_ops->tgt_get_tgt_revision(psoc);
2356 	} else {
2357 		qdf_mem_free(spectral);
2358 		return NULL;
2359 	}
2360 
2361 	/* init the function ptr table */
2362 	target_if_spectral_init_dummy_function_table(spectral);
2363 
2364 	/* get spectral function table */
2365 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2366 	/* TODO : Should this be called here of after ath_attach ? */
2367 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
2368 		spectral_info("HAL_CAP_PHYDIAG : Capable");
2369 
2370 	/* TODO: Need to fix the capablity check for RADAR */
2371 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
2372 		spectral_info("HAL_CAP_RADAR   : Capable");
2373 
2374 	/* TODO : Need to fix the capablity check for SPECTRAL */
2375 	/* TODO : Should this be called here of after ath_attach ? */
2376 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
2377 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
2378 
2379 	qdf_spinlock_create(&spectral->spectral_lock);
2380 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
2381 	target_if_spectral_clear_stats(spectral);
2382 
2383 	if (target_type == TARGET_TYPE_QCA8074 ||
2384 	    target_type == TARGET_TYPE_QCA8074V2 ||
2385 	    target_type == TARGET_TYPE_QCA6018 ||
2386 	    target_type == TARGET_TYPE_QCA5018 ||
2387 	    target_type == TARGET_TYPE_QCA6390 ||
2388 	    target_type == TARGET_TYPE_QCN9100 ||
2389 	    target_type == TARGET_TYPE_QCA6490 ||
2390 	    target_type == TARGET_TYPE_QCN9000 ||
2391 	    target_type == TARGET_TYPE_QCA6750)
2392 		spectral->direct_dma_support = true;
2393 
2394 	target_if_spectral_len_adj_swar_init(&spectral->len_adj_swar,
2395 					     target_type);
2396 	target_if_spectral_report_params_init(&spectral->rparams, target_type);
2397 
2398 	if ((target_type == TARGET_TYPE_QCA8074) ||
2399 	    (target_type == TARGET_TYPE_QCA8074V2) ||
2400 	    (target_type == TARGET_TYPE_QCA6018) ||
2401 	    (target_type == TARGET_TYPE_QCA5018) ||
2402 	    (target_type == TARGET_TYPE_QCN9100) ||
2403 	    (target_type == TARGET_TYPE_QCN9000) ||
2404 	    (target_type == TARGET_TYPE_QCA6290) ||
2405 	    (target_type == TARGET_TYPE_QCA6390) ||
2406 	    (target_type == TARGET_TYPE_QCA6490) ||
2407 	    (target_type == TARGET_TYPE_QCA6750)) {
2408 		spectral->spectral_gen = SPECTRAL_GEN3;
2409 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
2410 		spectral->tag_sscan_summary_exp =
2411 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
2412 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
2413 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
2414 	} else {
2415 		spectral->spectral_gen = SPECTRAL_GEN2;
2416 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
2417 		spectral->tag_sscan_summary_exp =
2418 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
2419 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
2420 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
2421 	}
2422 
2423 	status = target_if_init_spectral_param_min_max(
2424 					&spectral->param_min_max,
2425 					spectral->spectral_gen, target_type);
2426 	if (QDF_IS_STATUS_ERROR(status)) {
2427 		spectral_err("Failed to initialize parameter min max values");
2428 		goto fail;
2429 	}
2430 
2431 	target_if_init_spectral_param_properties(spectral);
2432 	/* Init spectral capability */
2433 	if (target_if_init_spectral_capability(spectral, target_type) !=
2434 					QDF_STATUS_SUCCESS) {
2435 		qdf_mem_free(spectral);
2436 		return NULL;
2437 	}
2438 	if (target_if_spectral_attach_simulation(spectral) < 0)
2439 		return NULL;
2440 
2441 	target_if_init_spectral_ops(spectral);
2442 	target_if_spectral_timestamp_war_init(&spectral->timestamp_war);
2443 
2444 	/* Spectral mode specific init */
2445 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2446 		spectral->params_valid[smode] = false;
2447 		qdf_spinlock_create(&spectral->param_info[smode].osps_lock);
2448 		spectral->param_info[smode].osps_cache.osc_is_valid = 0;
2449 	}
2450 
2451 	target_if_spectral_register_funcs(spectral, &spectral_ops);
2452 
2453 	if (target_if_spectral_check_hw_capability(spectral) == false) {
2454 		goto fail;
2455 	} else {
2456 		/*
2457 		 * TODO: Once the driver architecture transitions to chipset
2458 		 * versioning based checks, reflect this here.
2459 		 */
2460 		spectral->is_160_format = false;
2461 		spectral->is_lb_edge_extrabins_format = false;
2462 		spectral->is_rb_edge_extrabins_format = false;
2463 
2464 		if (target_type == TARGET_TYPE_QCA9984 ||
2465 		    target_type == TARGET_TYPE_QCA9888) {
2466 			spectral->is_160_format = true;
2467 			spectral->is_lb_edge_extrabins_format = true;
2468 			spectral->is_rb_edge_extrabins_format = true;
2469 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
2470 			    (target_revision == AR900B_REV_2)) {
2471 			spectral->is_rb_edge_extrabins_format = true;
2472 		}
2473 
2474 		if (target_type == TARGET_TYPE_QCA9984 ||
2475 		    target_type == TARGET_TYPE_QCA9888)
2476 			spectral->is_sec80_rssi_war_required = true;
2477 
2478 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
2479 
2480 		if (spectral->spectral_gen == SPECTRAL_GEN3)
2481 			init_160mhz_delivery_state_machine(spectral);
2482 	}
2483 
2484 	return spectral;
2485 
2486 fail:
2487 	target_if_spectral_detach(spectral);
2488 	return NULL;
2489 }
2490 
2491 /**
2492  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
2493  * functionality for the given pdev
2494  * @pdev: Pointer to pdev object
2495  *
2496  * Function to de-initialize pointer to spectral target_if internal private data
2497  *
2498  * Return: None
2499  */
2500 void
2501 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
2502 {
2503 	struct target_if_spectral *spectral = NULL;
2504 
2505 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2506 	if (!spectral) {
2507 		spectral_err("SPECTRAL : Module doesn't exist");
2508 		return;
2509 	}
2510 	target_if_spectral_detach(spectral);
2511 
2512 	return;
2513 }
2514 
2515 /**
2516  * target_if_psoc_spectral_deinit() - De-initialize target_if Spectral
2517  * functionality for the given psoc
2518  * @psoc: Pointer to psoc object
2519  *
2520  * Function to de-initialize pointer to psoc spectral target_if internal
2521  * private data
2522  *
2523  * Return: None
2524  */
2525 static void
2526 target_if_psoc_spectral_deinit(struct wlan_objmgr_psoc *psoc)
2527 {
2528 	struct target_if_psoc_spectral *psoc_spectral;
2529 
2530 	if (!psoc) {
2531 		spectral_err("psoc is null");
2532 		return;
2533 	}
2534 
2535 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
2536 	if (!psoc_spectral) {
2537 		spectral_err("Spectral target_if psoc object is null");
2538 		return;
2539 	}
2540 
2541 	qdf_mem_free(psoc_spectral);
2542 }
2543 
2544 /**
2545  * target_if_psoc_spectral_init() - Initialize target_if Spectral
2546  * functionality for the given psoc
2547  * @psoc: Pointer to psoc object
2548  *
2549  * Function to initialize pointer to psoc spectral target_if internal
2550  * private data
2551  *
2552  * Return: On success, pointer to Spectral psoc target_if internal
2553  * private data, on failure, NULL
2554  */
2555 static void *
2556 target_if_psoc_spectral_init(struct wlan_objmgr_psoc *psoc)
2557 {
2558 	struct target_if_psoc_spectral *psoc_spectral = NULL;
2559 
2560 	if (!psoc) {
2561 		spectral_err("psoc is null");
2562 		goto fail;
2563 	}
2564 
2565 	psoc_spectral = (struct target_if_psoc_spectral *)qdf_mem_malloc(
2566 			sizeof(struct target_if_psoc_spectral));
2567 	if (!psoc_spectral) {
2568 		spectral_err("Spectral lmac psoc object allocation failed");
2569 		goto fail;
2570 	}
2571 
2572 	psoc_spectral->psoc_obj = psoc;
2573 
2574 	return psoc_spectral;
2575 
2576 fail:
2577 	if (psoc_spectral)
2578 		target_if_psoc_spectral_deinit(psoc);
2579 
2580 	return psoc_spectral;
2581 }
2582 
2583 /* target_if_spectral_find_agile_width() - Given a channel width enum, find the
2584  * corresponding translation for Agile channel width.
2585  * @spectral: pointer to Spectral object
2586  * @chwidth: operating channel width
2587  * @is_80_80_agile: Indicates an 80+80 agile Scan request
2588  *
2589  * Return: The translated channel width enum.
2590  */
2591 static enum phy_ch_width
2592 target_if_spectral_find_agile_width(struct target_if_spectral *spectral,
2593 				    enum phy_ch_width chwidth,
2594 				    bool is_80_80_agile)
2595 {
2596 	enum phy_ch_width agile_width;
2597 	struct wlan_objmgr_pdev *pdev;
2598 	struct wlan_objmgr_psoc *psoc;
2599 
2600 	if (!spectral) {
2601 		spectral_err("Spectral object is null");
2602 		return CH_WIDTH_INVALID;
2603 	}
2604 
2605 	pdev =  spectral->pdev_obj;
2606 	if (!pdev) {
2607 		spectral_err("pdev is null");
2608 		return CH_WIDTH_INVALID;
2609 	}
2610 
2611 	psoc = wlan_pdev_get_psoc(pdev);
2612 	if (!psoc) {
2613 		spectral_err("psoc is null");
2614 		return CH_WIDTH_INVALID;
2615 	}
2616 
2617 	switch (chwidth) {
2618 	case CH_WIDTH_20MHZ:
2619 		agile_width = CH_WIDTH_20MHZ;
2620 		break;
2621 
2622 	case CH_WIDTH_40MHZ:
2623 		agile_width = CH_WIDTH_40MHZ;
2624 		break;
2625 
2626 	case CH_WIDTH_80MHZ:
2627 		agile_width = CH_WIDTH_80MHZ;
2628 		break;
2629 
2630 	case CH_WIDTH_80P80MHZ:
2631 		if (wlan_psoc_nif_fw_ext_cap_get(psoc,
2632 		    WLAN_SOC_RESTRICTED_80P80_SUPPORT) && !is_80_80_agile)
2633 			agile_width = CH_WIDTH_160MHZ;
2634 		else
2635 			agile_width = CH_WIDTH_80P80MHZ;
2636 
2637 		if (agile_width > spectral->rparams.max_agile_ch_width)
2638 			agile_width = spectral->rparams.max_agile_ch_width;
2639 		break;
2640 
2641 	case CH_WIDTH_160MHZ:
2642 		if (wlan_psoc_nif_fw_ext_cap_get(psoc,
2643 		    WLAN_SOC_RESTRICTED_80P80_SUPPORT) && is_80_80_agile)
2644 			agile_width = CH_WIDTH_80P80MHZ;
2645 		else
2646 			agile_width = CH_WIDTH_160MHZ;
2647 
2648 		if (agile_width > spectral->rparams.max_agile_ch_width)
2649 			agile_width = spectral->rparams.max_agile_ch_width;
2650 		break;
2651 
2652 	default:
2653 		spectral_err("Invalid channel width %d", chwidth);
2654 		agile_width = CH_WIDTH_INVALID;
2655 		break;
2656 	}
2657 
2658 	return agile_width;
2659 }
2660 
2661 /**
2662  * target_if_calculate_center_freq() - Helper routine to
2663  * check whether given frequency is center frequency of a
2664  * WLAN channel
2665  *
2666  * @spectral: Pointer to Spectral object
2667  * @chan_freq: Center frequency of a WLAN channel
2668  * @is_valid: Indicates whether given frequency is valid
2669  *
2670  * Return: QDF_STATUS
2671  */
2672 static QDF_STATUS
2673 target_if_is_center_freq_of_any_chan(struct wlan_objmgr_pdev *pdev,
2674 				     uint32_t chan_freq,
2675 				     bool *is_valid)
2676 {
2677 	struct regulatory_channel *cur_chan_list;
2678 	int i;
2679 
2680 	if (!pdev) {
2681 		spectral_err("pdev object is null");
2682 		return QDF_STATUS_E_FAILURE;
2683 	}
2684 
2685 	if (!is_valid) {
2686 		spectral_err("is valid argument is null");
2687 		return QDF_STATUS_E_FAILURE;
2688 	}
2689 
2690 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
2691 	if (!cur_chan_list)
2692 		return QDF_STATUS_E_FAILURE;
2693 
2694 	if (wlan_reg_get_current_chan_list(
2695 			pdev, cur_chan_list) != QDF_STATUS_SUCCESS) {
2696 		spectral_err("Failed to get cur_chan list");
2697 		qdf_mem_free(cur_chan_list);
2698 		return QDF_STATUS_E_FAILURE;
2699 	}
2700 
2701 	*is_valid = false;
2702 	for (i = 0; i < NUM_CHANNELS; i++) {
2703 		uint32_t flags;
2704 		uint32_t center_freq;
2705 
2706 		flags = cur_chan_list[i].chan_flags;
2707 		center_freq = cur_chan_list[i].center_freq;
2708 
2709 		if (!(flags & REGULATORY_CHAN_DISABLED) &&
2710 		    (center_freq == chan_freq)) {
2711 			*is_valid = true;
2712 			break;
2713 		}
2714 	}
2715 
2716 	qdf_mem_free(cur_chan_list);
2717 
2718 	return QDF_STATUS_SUCCESS;
2719 }
2720 
2721 /**
2722  * target_if_calculate_center_freq() - Helper routine to
2723  * find the center frequency of the agile span from a
2724  * WLAN channel center frequency
2725  *
2726  * @spectral: Pointer to Spectral object
2727  * @ch_width: Channel width array
2728  * @chan_freq: Center frequency of a WLAN channel
2729  * @center_freq: Pointer to center frequency
2730  *
2731  * Return: QDF_STATUS
2732  */
2733 static QDF_STATUS
2734 target_if_calculate_center_freq(struct target_if_spectral *spectral,
2735 				enum phy_ch_width *ch_width,
2736 				uint16_t chan_freq,
2737 				uint16_t *center_freq)
2738 {
2739 	enum phy_ch_width agile_ch_width;
2740 
2741 	if (!spectral) {
2742 		spectral_err("spectral target if object is null");
2743 		return QDF_STATUS_E_FAILURE;
2744 	}
2745 
2746 	if (!ch_width) {
2747 		spectral_err("Channel width array is null");
2748 		return QDF_STATUS_E_INVAL;
2749 	}
2750 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
2751 
2752 	if (!center_freq) {
2753 		spectral_err("center_freq argument is null");
2754 		return QDF_STATUS_E_FAILURE;
2755 	}
2756 
2757 	if (agile_ch_width == CH_WIDTH_20MHZ) {
2758 		*center_freq = chan_freq;
2759 	} else {
2760 		uint16_t start_freq;
2761 		uint16_t end_freq;
2762 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
2763 		enum channel_state state;
2764 
2765 		state = wlan_reg_get_5g_bonded_channel_and_state_for_freq
2766 			(spectral->pdev_obj, chan_freq, agile_ch_width,
2767 			 &bonded_chan_ptr);
2768 		if (state == CHANNEL_STATE_DISABLE ||
2769 		    state == CHANNEL_STATE_INVALID) {
2770 			spectral_err("Channel state is disable or invalid");
2771 			return QDF_STATUS_E_FAILURE;
2772 		}
2773 		if (!bonded_chan_ptr) {
2774 			spectral_err("Bonded channel is not found");
2775 			return QDF_STATUS_E_FAILURE;
2776 		}
2777 		start_freq = bonded_chan_ptr->start_freq;
2778 		end_freq = bonded_chan_ptr->end_freq;
2779 		*center_freq = (start_freq + end_freq) >> 1;
2780 	}
2781 
2782 	return QDF_STATUS_SUCCESS;
2783 }
2784 
2785 /**
2786  * target_if_validate_center_freq() - Helper routine to
2787  * validate user provided agile center frequency
2788  *
2789  * @spectral: Pointer to Spectral object
2790  * @ch_width: Channel width array
2791  * @center_freq: User provided agile span center frequency
2792  * @is_valid: Indicates whether agile span center frequency is valid
2793  *
2794  * Return: QDF_STATUS
2795  */
2796 static QDF_STATUS
2797 target_if_validate_center_freq(struct target_if_spectral *spectral,
2798 			       enum phy_ch_width *ch_width,
2799 			       uint16_t center_freq,
2800 			       bool *is_valid)
2801 {
2802 	enum phy_ch_width agile_ch_width;
2803 	struct wlan_objmgr_pdev *pdev;
2804 	QDF_STATUS status;
2805 
2806 	if (!spectral) {
2807 		spectral_err("spectral target if object is null");
2808 		return QDF_STATUS_E_FAILURE;
2809 	}
2810 
2811 	if (!ch_width) {
2812 		spectral_err("channel width array is null");
2813 		return QDF_STATUS_E_INVAL;
2814 	}
2815 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
2816 
2817 	if (!is_valid) {
2818 		spectral_err("is_valid argument is null");
2819 		return QDF_STATUS_E_FAILURE;
2820 	}
2821 
2822 	pdev = spectral->pdev_obj;
2823 
2824 	if (agile_ch_width == CH_WIDTH_20MHZ) {
2825 		status = target_if_is_center_freq_of_any_chan
2826 				(pdev, center_freq, is_valid);
2827 		if (QDF_IS_STATUS_ERROR(status))
2828 			return QDF_STATUS_E_FAILURE;
2829 	} else {
2830 		uint16_t start_freq;
2831 		uint16_t end_freq;
2832 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
2833 		bool is_chan;
2834 
2835 		status = target_if_is_center_freq_of_any_chan
2836 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
2837 				 &is_chan);
2838 		if (QDF_IS_STATUS_ERROR(status))
2839 			return QDF_STATUS_E_FAILURE;
2840 
2841 		if (is_chan) {
2842 			uint32_t calulated_center_freq;
2843 			enum channel_state st;
2844 
2845 			st = wlan_reg_get_5g_bonded_channel_and_state_for_freq
2846 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
2847 				 agile_ch_width,
2848 				 &bonded_chan_ptr);
2849 			if (st == CHANNEL_STATE_DISABLE ||
2850 			    st == CHANNEL_STATE_INVALID) {
2851 				spectral_err("Channel state disable/invalid");
2852 				return QDF_STATUS_E_FAILURE;
2853 			}
2854 			if (!bonded_chan_ptr) {
2855 				spectral_err("Bonded channel is not found");
2856 				return QDF_STATUS_E_FAILURE;
2857 			}
2858 			start_freq = bonded_chan_ptr->start_freq;
2859 			end_freq = bonded_chan_ptr->end_freq;
2860 			calulated_center_freq = (start_freq + end_freq) >> 1;
2861 			*is_valid = (center_freq == calulated_center_freq);
2862 		} else {
2863 			*is_valid = false;
2864 		}
2865 	}
2866 
2867 	return QDF_STATUS_SUCCESS;
2868 }
2869 
2870 /**
2871  * target_if_is_agile_span_overlap_with_operating_span() - Helper routine to
2872  * check whether agile span overlaps with current operating band.
2873  *
2874  * @spectral: Pointer to Spectral object
2875  * @ch_width: Channel width array
2876  * @center_freq: Agile span center frequency
2877  * @is_overlapping: Indicates whether Agile span overlaps with operating span
2878  *
2879  * Helper routine to check whether agile span overlaps with current
2880  * operating band.
2881  *
2882  * Return: QDF_STATUS
2883  */
2884 static QDF_STATUS
2885 target_if_is_agile_span_overlap_with_operating_span
2886 			(struct target_if_spectral *spectral,
2887 			 enum phy_ch_width *ch_width,
2888 			 struct spectral_config_frequency *center_freq,
2889 			 bool *is_overlapping)
2890 {
2891 	enum phy_ch_width op_ch_width;
2892 	enum phy_ch_width agile_ch_width;
2893 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
2894 	struct wlan_objmgr_vdev *vdev;
2895 	struct wlan_objmgr_pdev *pdev;
2896 	int16_t chan_freq;
2897 	uint32_t op_start_freq;
2898 	uint32_t op_end_freq;
2899 	uint32_t agile_start_freq;
2900 	uint32_t agile_end_freq;
2901 	uint32_t cfreq2;
2902 
2903 	if (!spectral) {
2904 		spectral_err("Spectral object is NULL");
2905 		return QDF_STATUS_E_FAILURE;
2906 	}
2907 
2908 	pdev  = spectral->pdev_obj;
2909 	if (!pdev) {
2910 		spectral_err("pdev object is NULL");
2911 		return QDF_STATUS_E_FAILURE;
2912 	}
2913 
2914 	if (!ch_width) {
2915 		spectral_err("channel width array is null");
2916 		return QDF_STATUS_E_FAILURE;
2917 	}
2918 	op_ch_width = ch_width[SPECTRAL_SCAN_MODE_NORMAL];
2919 	if (op_ch_width == CH_WIDTH_INVALID) {
2920 		spectral_err("Invalid channel width");
2921 		return QDF_STATUS_E_INVAL;
2922 	}
2923 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
2924 	if (agile_ch_width == CH_WIDTH_INVALID) {
2925 		spectral_err("Invalid channel width");
2926 		return QDF_STATUS_E_INVAL;
2927 	}
2928 
2929 	if (!is_overlapping) {
2930 		spectral_err("Argument(is_overlapping) is NULL");
2931 		return QDF_STATUS_E_FAILURE;
2932 	}
2933 	*is_overlapping = false;
2934 
2935 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
2936 	if (!vdev) {
2937 		spectral_err("vdev is NULL");
2938 		return QDF_STATUS_E_FAILURE;
2939 	}
2940 	chan_freq = target_if_vdev_get_chan_freq(vdev);
2941 	cfreq2 = target_if_vdev_get_chan_freq_seg2(vdev);
2942 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2943 	if (cfreq2 < 0) {
2944 		spectral_err("cfreq2 is invalid");
2945 		return QDF_STATUS_E_FAILURE;
2946 	}
2947 
2948 	if (op_ch_width == CH_WIDTH_20MHZ) {
2949 		op_start_freq = chan_freq - FREQ_OFFSET_10MHZ;
2950 		op_end_freq = chan_freq + FREQ_OFFSET_10MHZ;
2951 	} else {
2952 		enum channel_state state;
2953 
2954 		state = wlan_reg_get_5g_bonded_channel_and_state_for_freq
2955 			(pdev, chan_freq, op_ch_width, &bonded_chan_ptr);
2956 		if (state == CHANNEL_STATE_DISABLE ||
2957 		    state == CHANNEL_STATE_INVALID) {
2958 			spectral_err("Channel state is disable or invalid");
2959 			return QDF_STATUS_E_FAILURE;
2960 		}
2961 		if (!bonded_chan_ptr) {
2962 			spectral_err("Bonded channel is not found");
2963 			return QDF_STATUS_E_FAILURE;
2964 		}
2965 		op_start_freq = bonded_chan_ptr->start_freq - FREQ_OFFSET_10MHZ;
2966 		op_end_freq = bonded_chan_ptr->end_freq - FREQ_OFFSET_10MHZ;
2967 	}
2968 
2969 	if (agile_ch_width == CH_WIDTH_80P80MHZ) {
2970 		agile_start_freq = center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
2971 		agile_end_freq = center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
2972 		if (agile_end_freq > op_start_freq &&
2973 		    op_end_freq > agile_start_freq)
2974 			*is_overlapping = true;
2975 
2976 		agile_start_freq = center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
2977 		agile_end_freq = center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
2978 		if (agile_end_freq > op_start_freq &&
2979 		    op_end_freq > agile_start_freq)
2980 			*is_overlapping = true;
2981 	} else {
2982 		agile_start_freq = center_freq->cfreq1 -
2983 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
2984 		agile_end_freq = center_freq->cfreq1 +
2985 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
2986 		if (agile_end_freq > op_start_freq &&
2987 		    op_end_freq > agile_start_freq)
2988 			*is_overlapping = true;
2989 	}
2990 
2991 	if (op_ch_width == CH_WIDTH_80P80MHZ) {
2992 		uint32_t sec80_start_feq;
2993 		uint32_t sec80_end_freq;
2994 
2995 		sec80_start_feq = cfreq2 - FREQ_OFFSET_40MHZ;
2996 		sec80_end_freq = cfreq2 + FREQ_OFFSET_40MHZ;
2997 
2998 		if (agile_ch_width == CH_WIDTH_80P80MHZ) {
2999 			agile_start_freq =
3000 					center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
3001 			agile_end_freq =
3002 					center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
3003 			if (agile_end_freq > sec80_start_feq &&
3004 			    sec80_end_freq > agile_start_freq)
3005 				*is_overlapping = true;
3006 
3007 			agile_start_freq =
3008 					center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
3009 			agile_end_freq =
3010 					center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
3011 			if (agile_end_freq > sec80_start_feq &&
3012 			    sec80_end_freq > agile_start_freq)
3013 				*is_overlapping = true;
3014 		} else {
3015 			agile_start_freq = center_freq->cfreq1 -
3016 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
3017 			agile_end_freq = center_freq->cfreq1 +
3018 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
3019 			if (agile_end_freq > sec80_start_feq &&
3020 			    sec80_end_freq > agile_start_freq)
3021 				*is_overlapping = true;
3022 		}
3023 	}
3024 
3025 	return QDF_STATUS_SUCCESS;
3026 }
3027 
3028 /**
3029  * target_if_spectral_populate_chwidth() - Helper routine to
3030  * populate channel width for different Spectral modes
3031  *
3032  * @spectral: Pointer to Spectral object
3033  * @ch_width: Channel width array
3034  * @is_80_80_agile: Indicates whether 80+80 agile scan is requested
3035  *
3036  * Helper routine to populate channel width for different Spectral modes
3037  *
3038  * Return: QDF_STATUS
3039  */
3040 static QDF_STATUS
3041 target_if_spectral_populate_chwidth(struct target_if_spectral *spectral,
3042 				    enum phy_ch_width *ch_width,
3043 				    bool is_80_80_agile) {
3044 	struct wlan_objmgr_vdev *vdev;
3045 	enum spectral_scan_mode smode;
3046 	enum phy_ch_width vdev_ch_width;
3047 
3048 	smode = SPECTRAL_SCAN_MODE_NORMAL;
3049 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
3050 		ch_width[smode] = CH_WIDTH_INVALID;
3051 
3052 	if (!spectral) {
3053 		spectral_err("Spectral object is null");
3054 		return QDF_STATUS_E_INVAL;
3055 	}
3056 
3057 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_NORMAL);
3058 	if (!vdev) {
3059 		spectral_err("vdev is null");
3060 		return QDF_STATUS_E_FAILURE;
3061 	}
3062 
3063 	vdev_ch_width = target_if_vdev_get_ch_width(vdev);
3064 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3065 	if (vdev_ch_width == CH_WIDTH_INVALID) {
3066 		spectral_err("Invalid channel width %d", vdev_ch_width);
3067 		return QDF_STATUS_E_FAILURE;
3068 	}
3069 
3070 	ch_width[SPECTRAL_SCAN_MODE_NORMAL] = vdev_ch_width;
3071 	ch_width[SPECTRAL_SCAN_MODE_AGILE] =
3072 		target_if_spectral_find_agile_width(spectral, vdev_ch_width,
3073 						    is_80_80_agile);
3074 
3075 	return QDF_STATUS_SUCCESS;
3076 }
3077 
3078 /**
3079  * target_if_spectral_is_valid_80p80_freq() - API to check whether given
3080  * (cfreq1, cfreq2) pair forms a valid 80+80 combination
3081  * @pdev: pointer to pdev
3082  * @cfreq1: center frequency 1
3083  * @cfreq2: center frequency 2
3084  *
3085  * API to check whether given (cfreq1, cfreq2) pair forms a valid 80+80
3086  * combination
3087  *
3088  * Return: true or false
3089  */
3090 static bool
3091 target_if_spectral_is_valid_80p80_freq(struct wlan_objmgr_pdev *pdev,
3092 				       uint32_t cfreq1, uint32_t cfreq2)
3093 {
3094 	struct ch_params ch_params;
3095 	enum channel_state chan_state1;
3096 	enum channel_state chan_state2;
3097 	struct wlan_objmgr_psoc *psoc;
3098 
3099 	qdf_assert_always(pdev);
3100 	psoc = wlan_pdev_get_psoc(pdev);
3101 	qdf_assert_always(psoc);
3102 
3103 	/* In restricted 80P80 MHz enabled, only one 80+80 MHz
3104 	 * channel is supported with cfreq=5690 and cfreq=5775.
3105 	 */
3106 	if (wlan_psoc_nif_fw_ext_cap_get(
3107 				psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT))
3108 		return CHAN_WITHIN_RESTRICTED_80P80(cfreq1, cfreq2);
3109 
3110 	ch_params.center_freq_seg1 = wlan_reg_freq_to_chan(pdev, cfreq2);
3111 	ch_params.mhz_freq_seg1 = cfreq2;
3112 	ch_params.ch_width = CH_WIDTH_80P80MHZ;
3113 	wlan_reg_set_channel_params_for_freq(pdev, cfreq1 - FREQ_OFFSET_10MHZ,
3114 					     0, &ch_params);
3115 
3116 	if (ch_params.ch_width != CH_WIDTH_80P80MHZ)
3117 		return false;
3118 
3119 	if (ch_params.mhz_freq_seg0 != cfreq1 ||
3120 	    ch_params.mhz_freq_seg1 != cfreq2)
3121 		return false;
3122 
3123 	chan_state1 = wlan_reg_get_5g_bonded_channel_state_for_freq(
3124 				pdev,
3125 				ch_params.mhz_freq_seg0 - FREQ_OFFSET_10MHZ,
3126 				CH_WIDTH_80MHZ);
3127 	if ((chan_state1 == CHANNEL_STATE_DISABLE) ||
3128 	    (chan_state1 == CHANNEL_STATE_INVALID))
3129 		return false;
3130 
3131 	chan_state2 = wlan_reg_get_5g_bonded_channel_state_for_freq(
3132 				pdev,
3133 				ch_params.mhz_freq_seg1 - FREQ_OFFSET_10MHZ,
3134 				CH_WIDTH_80MHZ);
3135 	if ((chan_state2 == CHANNEL_STATE_DISABLE) ||
3136 	    (chan_state2 == CHANNEL_STATE_INVALID))
3137 		return false;
3138 
3139 	if (abs(ch_params.mhz_freq_seg0 - ch_params.mhz_freq_seg1) <=
3140 	    FREQ_OFFSET_80MHZ)
3141 		return false;
3142 
3143 	return true;
3144 }
3145 
3146 /**
3147  * _target_if_set_spectral_config() - Set spectral config
3148  * @spectral:       Pointer to spectral object
3149  * @param: Spectral parameter id and value
3150  * @smode: Spectral scan mode
3151  * @err: Spectral error code
3152  *
3153  * API to set spectral configurations
3154  *
3155  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3156  */
3157 static QDF_STATUS
3158 _target_if_set_spectral_config(struct target_if_spectral *spectral,
3159 			       const struct spectral_cp_param *param,
3160 			       const enum spectral_scan_mode smode,
3161 			       enum spectral_cp_error_code *err)
3162 {
3163 	struct spectral_config params;
3164 	struct target_if_spectral_ops *p_sops;
3165 	struct spectral_config *sparams;
3166 	QDF_STATUS status;
3167 	bool is_overlapping;
3168 	uint16_t agile_cfreq;
3169 	bool is_valid_chan;
3170 	struct spectral_param_min_max *param_min_max;
3171 	enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
3172 	enum spectral_scan_mode m;
3173 	struct spectral_config_frequency center_freq = {0};
3174 
3175 	if (!err) {
3176 		spectral_err("Error code argument is null");
3177 		QDF_ASSERT(0);
3178 		return QDF_STATUS_E_FAILURE;
3179 	}
3180 	*err = SPECTRAL_SCAN_ERR_INVALID;
3181 
3182 	if (!param) {
3183 		spectral_err("Parameter object is null");
3184 		return QDF_STATUS_E_FAILURE;
3185 	}
3186 
3187 	if (!spectral) {
3188 		spectral_err("spectral object is NULL");
3189 		return QDF_STATUS_E_FAILURE;
3190 	}
3191 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3192 	param_min_max = &spectral->param_min_max;
3193 
3194 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3195 		spectral_err("Invalid Spectral mode %u", smode);
3196 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3197 		return QDF_STATUS_E_FAILURE;
3198 	}
3199 
3200 	sparams = &spectral->params[smode];
3201 	m = SPECTRAL_SCAN_MODE_NORMAL;
3202 	for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
3203 		ch_width[m] = CH_WIDTH_INVALID;
3204 
3205 	if (!spectral->params_valid[smode]) {
3206 		target_if_spectral_info_read(spectral,
3207 					     smode,
3208 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
3209 					     &spectral->params[smode],
3210 					     sizeof(spectral->params[smode]));
3211 		spectral->params_valid[smode] = true;
3212 	}
3213 
3214 	switch (param->id) {
3215 	case SPECTRAL_PARAM_FFT_PERIOD:
3216 		sparams->ss_fft_period = param->value;
3217 		break;
3218 	case SPECTRAL_PARAM_SCAN_PERIOD:
3219 		sparams->ss_period = param->value;
3220 		break;
3221 	case SPECTRAL_PARAM_SCAN_COUNT:
3222 		sparams->ss_count = param->value;
3223 		break;
3224 	case SPECTRAL_PARAM_SHORT_REPORT:
3225 		sparams->ss_short_report = (!!param->value) ? true : false;
3226 		break;
3227 	case SPECTRAL_PARAM_SPECT_PRI:
3228 		sparams->ss_spectral_pri = (!!param->value) ? true : false;
3229 		break;
3230 	case SPECTRAL_PARAM_FFT_SIZE:
3231 		status = target_if_spectral_populate_chwidth
3232 			(spectral, ch_width, spectral->params
3233 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
3234 		if (QDF_IS_STATUS_ERROR(status))
3235 			return QDF_STATUS_E_FAILURE;
3236 		if ((param->value < param_min_max->fft_size_min) ||
3237 		    (param->value > param_min_max->fft_size_max
3238 		    [ch_width[smode]])) {
3239 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3240 			return QDF_STATUS_E_FAILURE;
3241 		}
3242 		sparams->ss_fft_size = param->value;
3243 		break;
3244 	case SPECTRAL_PARAM_GC_ENA:
3245 		sparams->ss_gc_ena = !!param->value;
3246 		break;
3247 	case SPECTRAL_PARAM_RESTART_ENA:
3248 		sparams->ss_restart_ena = !!param->value;
3249 		break;
3250 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
3251 		sparams->ss_noise_floor_ref = param->value;
3252 		break;
3253 	case SPECTRAL_PARAM_INIT_DELAY:
3254 		sparams->ss_init_delay = param->value;
3255 		break;
3256 	case SPECTRAL_PARAM_NB_TONE_THR:
3257 		sparams->ss_nb_tone_thr = param->value;
3258 		break;
3259 	case SPECTRAL_PARAM_STR_BIN_THR:
3260 		sparams->ss_str_bin_thr = param->value;
3261 		break;
3262 	case SPECTRAL_PARAM_WB_RPT_MODE:
3263 		sparams->ss_wb_rpt_mode = !!param->value;
3264 		break;
3265 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
3266 		sparams->ss_rssi_rpt_mode = !!param->value;
3267 		break;
3268 	case SPECTRAL_PARAM_RSSI_THR:
3269 		sparams->ss_rssi_thr = param->value;
3270 		break;
3271 	case SPECTRAL_PARAM_PWR_FORMAT:
3272 		sparams->ss_pwr_format = !!param->value;
3273 		break;
3274 	case SPECTRAL_PARAM_RPT_MODE:
3275 		if ((param->value < SPECTRAL_PARAM_RPT_MODE_MIN) ||
3276 		    (param->value > SPECTRAL_PARAM_RPT_MODE_MAX)) {
3277 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3278 			return QDF_STATUS_E_FAILURE;
3279 		}
3280 		sparams->ss_rpt_mode = param->value;
3281 		break;
3282 	case SPECTRAL_PARAM_BIN_SCALE:
3283 		sparams->ss_bin_scale = param->value;
3284 		break;
3285 	case SPECTRAL_PARAM_DBM_ADJ:
3286 		sparams->ss_dbm_adj = !!param->value;
3287 		break;
3288 	case SPECTRAL_PARAM_CHN_MASK:
3289 		sparams->ss_chn_mask = param->value;
3290 		break;
3291 	case SPECTRAL_PARAM_FREQUENCY:
3292 		status = target_if_spectral_populate_chwidth(
3293 				spectral, ch_width, param->freq.cfreq2 > 0);
3294 		if (QDF_IS_STATUS_ERROR(status)) {
3295 			spectral_err("Failed to populate channel width");
3296 			return QDF_STATUS_E_FAILURE;
3297 		}
3298 
3299 		if (ch_width[smode] != CH_WIDTH_80P80MHZ &&
3300 		    param->freq.cfreq2) {
3301 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3302 			spectral_err("Non zero cfreq2 expected for 80p80 only");
3303 			return QDF_STATUS_E_INVAL;
3304 		}
3305 
3306 		if (ch_width[smode] == CH_WIDTH_80P80MHZ &&
3307 		    !param->freq.cfreq2) {
3308 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3309 			spectral_err("Non zero cfreq2 expected for 80p80");
3310 			return QDF_STATUS_E_INVAL;
3311 		}
3312 
3313 		status = target_if_is_center_freq_of_any_chan
3314 				(spectral->pdev_obj, param->freq.cfreq1,
3315 				 &is_valid_chan);
3316 		if (QDF_IS_STATUS_ERROR(status))
3317 			return QDF_STATUS_E_FAILURE;
3318 
3319 		if (is_valid_chan) {
3320 			status = target_if_calculate_center_freq(
3321 							spectral, ch_width,
3322 							param->freq.cfreq1,
3323 							&agile_cfreq);
3324 			if (QDF_IS_STATUS_ERROR(status)) {
3325 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3326 				return QDF_STATUS_E_FAILURE;
3327 			}
3328 		} else {
3329 			bool is_valid_agile_cfreq;
3330 
3331 			status = target_if_validate_center_freq
3332 				(spectral, ch_width, param->freq.cfreq1,
3333 				 &is_valid_agile_cfreq);
3334 			if (QDF_IS_STATUS_ERROR(status))
3335 				return QDF_STATUS_E_FAILURE;
3336 
3337 			if (!is_valid_agile_cfreq) {
3338 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3339 				spectral_err("Invalid agile center frequency");
3340 				return QDF_STATUS_E_FAILURE;
3341 			}
3342 
3343 			agile_cfreq = param->freq.cfreq1;
3344 		}
3345 		center_freq.cfreq1 = agile_cfreq;
3346 
3347 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
3348 			status = target_if_is_center_freq_of_any_chan
3349 					(spectral->pdev_obj, param->freq.cfreq2,
3350 					 &is_valid_chan);
3351 			if (QDF_IS_STATUS_ERROR(status))
3352 				return QDF_STATUS_E_FAILURE;
3353 
3354 			if (is_valid_chan) {
3355 				status = target_if_calculate_center_freq(
3356 						spectral, ch_width,
3357 						param->freq.cfreq2,
3358 						&agile_cfreq);
3359 				if (QDF_IS_STATUS_ERROR(status)) {
3360 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3361 					return QDF_STATUS_E_FAILURE;
3362 				}
3363 			} else {
3364 				bool is_valid_agile_cfreq;
3365 
3366 				status = target_if_validate_center_freq
3367 					(spectral, ch_width, param->freq.cfreq2,
3368 					 &is_valid_agile_cfreq);
3369 				if (QDF_IS_STATUS_ERROR(status))
3370 					return QDF_STATUS_E_FAILURE;
3371 
3372 				if (!is_valid_agile_cfreq) {
3373 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3374 					spectral_err("Invalid agile center frequency");
3375 					return QDF_STATUS_E_FAILURE;
3376 				}
3377 
3378 				agile_cfreq = param->freq.cfreq2;
3379 			}
3380 			center_freq.cfreq2 = agile_cfreq;
3381 		}
3382 
3383 		status = target_if_is_agile_span_overlap_with_operating_span
3384 				(spectral, ch_width,
3385 				 &center_freq, &is_overlapping);
3386 		if (QDF_IS_STATUS_ERROR(status))
3387 			return QDF_STATUS_E_FAILURE;
3388 
3389 		if (is_overlapping) {
3390 			spectral_err("Agile freq %u, %u overlaps with operating span",
3391 				     center_freq.cfreq1, center_freq.cfreq2);
3392 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3393 			return QDF_STATUS_E_FAILURE;
3394 		}
3395 
3396 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
3397 			bool is_valid_80p80;
3398 
3399 			is_valid_80p80 = target_if_spectral_is_valid_80p80_freq(
3400 						spectral->pdev_obj,
3401 						center_freq.cfreq1,
3402 						center_freq.cfreq2);
3403 
3404 			if (!is_valid_80p80) {
3405 				spectral_err("Agile freq %u, %u is invalid 80+80 combination",
3406 					     center_freq.cfreq1,
3407 					     center_freq.cfreq2);
3408 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3409 				return QDF_STATUS_E_FAILURE;
3410 			}
3411 		}
3412 
3413 		sparams->ss_frequency.cfreq1 = center_freq.cfreq1;
3414 		sparams->ss_frequency.cfreq2 = center_freq.cfreq2;
3415 
3416 		break;
3417 	}
3418 
3419 	p_sops->configure_spectral(spectral, sparams, smode);
3420 	/* only to validate the writes */
3421 	p_sops->get_spectral_config(spectral, &params, smode);
3422 	return QDF_STATUS_SUCCESS;
3423 }
3424 
3425 QDF_STATUS
3426 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
3427 			      const struct spectral_cp_param *param,
3428 			      const enum spectral_scan_mode smode,
3429 			      enum spectral_cp_error_code *err)
3430 {
3431 	enum spectral_scan_mode mode = SPECTRAL_SCAN_MODE_NORMAL;
3432 	struct target_if_spectral *spectral;
3433 	QDF_STATUS status;
3434 
3435 	if (!err) {
3436 		spectral_err("Error code argument is null");
3437 		QDF_ASSERT(0);
3438 		return QDF_STATUS_E_FAILURE;
3439 	}
3440 	*err = SPECTRAL_SCAN_ERR_INVALID;
3441 
3442 	if (!pdev) {
3443 		spectral_err("pdev object is NULL");
3444 		return QDF_STATUS_E_FAILURE;
3445 	}
3446 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3447 	if (!spectral) {
3448 		spectral_err("spectral object is NULL");
3449 		return QDF_STATUS_E_FAILURE;
3450 	}
3451 
3452 	if (!param) {
3453 		spectral_err("parameter object is NULL");
3454 		return QDF_STATUS_E_FAILURE;
3455 	}
3456 
3457 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3458 		spectral_err("Invalid Spectral mode %u", smode);
3459 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3460 		return QDF_STATUS_E_FAILURE;
3461 	}
3462 
3463 	if (!spectral->properties[smode][param->id].supported) {
3464 		spectral_err("Spectral parameter(%u) unsupported for mode %u",
3465 			     param->id, smode);
3466 		*err = SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED;
3467 		return QDF_STATUS_E_FAILURE;
3468 	}
3469 
3470 	if (spectral->properties[smode][param->id].common_all_modes) {
3471 		spectral_warn("Setting Spectral parameter %u for all modes",
3472 			      param->id);
3473 		for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) {
3474 			status = _target_if_set_spectral_config
3475 						(spectral, param, mode, err);
3476 			if (QDF_IS_STATUS_ERROR(status))
3477 				return QDF_STATUS_E_FAILURE;
3478 		}
3479 		return QDF_STATUS_SUCCESS;
3480 	}
3481 
3482 	return _target_if_set_spectral_config(spectral, param, smode, err);
3483 }
3484 
3485 /**
3486  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
3487  * @fft_len: FFT length
3488  * @pdev: Pointer to pdev object
3489  *
3490  * API to get fft bin count for a given fft length
3491  *
3492  * Return: FFt bin count
3493  */
3494 static int
3495 target_if_get_fft_bin_count(int fft_len)
3496 {
3497 	int bin_count = 0;
3498 
3499 	switch (fft_len) {
3500 	case 5:
3501 		bin_count = 16;
3502 		break;
3503 	case 6:
3504 		bin_count = 32;
3505 		break;
3506 	case 7:
3507 		bin_count = 64;
3508 		break;
3509 	case 8:
3510 		bin_count = 128;
3511 		break;
3512 	case 9:
3513 		bin_count = 256;
3514 		break;
3515 	default:
3516 		break;
3517 	}
3518 
3519 	return bin_count;
3520 }
3521 
3522 /**
3523  * target_if_init_upper_lower_flags() - Initializes control and extension
3524  * segment flags
3525  * @spectral: pointer to target if spectral object
3526  * @smode: Spectral scan mode
3527  *
3528  * API to initialize the control and extension flags with the lower/upper
3529  * segment based on the HT mode
3530  *
3531  * Return: FFt bin count
3532  */
3533 static void
3534 target_if_init_upper_lower_flags(struct target_if_spectral *spectral,
3535 				 enum spectral_scan_mode smode)
3536 {
3537 	int current_channel = 0;
3538 	int ext_channel = 0;
3539 	struct target_if_spectral_ops *p_sops =
3540 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
3541 
3542 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3543 		spectral_err("Invalid Spectral mode %u", smode);
3544 		return;
3545 	}
3546 	current_channel = p_sops->get_current_channel(spectral, smode);
3547 	ext_channel = p_sops->get_extension_channel(spectral, smode);
3548 
3549 	if ((current_channel == 0) || (ext_channel == 0))
3550 		return;
3551 
3552 	if (spectral->sc_spectral_20_40_mode) {
3553 		/* HT40 mode */
3554 		if (ext_channel < current_channel) {
3555 			spectral->lower_is_extension = 1;
3556 			spectral->upper_is_control = 1;
3557 			spectral->lower_is_control = 0;
3558 			spectral->upper_is_extension = 0;
3559 		} else {
3560 			spectral->lower_is_extension = 0;
3561 			spectral->upper_is_control = 0;
3562 			spectral->lower_is_control = 1;
3563 			spectral->upper_is_extension = 1;
3564 		}
3565 	} else {
3566 		/* HT20 mode, lower is always control */
3567 		spectral->lower_is_extension = 0;
3568 		spectral->upper_is_control = 0;
3569 		spectral->lower_is_control = 1;
3570 		spectral->upper_is_extension = 0;
3571 	}
3572 }
3573 
3574 /**
3575  * target_if_get_spectral_config() - Get spectral configuration
3576  * @pdev: Pointer to pdev object
3577  * @param: Pointer to spectral_config structure in which the configuration
3578  * should be returned
3579  * @smode: Spectral scan mode
3580  *
3581  * API to get the current spectral configuration
3582  *
3583  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3584  */
3585 QDF_STATUS
3586 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
3587 			      struct spectral_config *param,
3588 			      enum spectral_scan_mode smode)
3589 {
3590 	struct target_if_spectral_ops *p_sops = NULL;
3591 	struct target_if_spectral *spectral = NULL;
3592 
3593 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3594 
3595 	if (!spectral) {
3596 		spectral_err("SPECTRAL : Module doesn't exist");
3597 		return QDF_STATUS_E_FAILURE;
3598 	}
3599 
3600 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3601 
3602 	if (!p_sops) {
3603 		spectral_err("p_sops is null");
3604 		return QDF_STATUS_E_FAILURE;
3605 	}
3606 
3607 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3608 		spectral_err("Invalid Spectral mode %u", smode);
3609 		return QDF_STATUS_E_FAILURE;
3610 	}
3611 
3612 	qdf_mem_zero(param, sizeof(struct spectral_config));
3613 	p_sops->get_spectral_config(spectral, param, smode);
3614 
3615 	return QDF_STATUS_SUCCESS;
3616 }
3617 
3618 /**
3619  * target_if_spectral_get_num_detectors() - Get number of Spectral detectors
3620  * @spectral: Pointer to target if Spectral object
3621  * @ch_width: channel width
3622  * @num_detectors: Pointer to the variable to store number of Spectral detectors
3623  *
3624  * API to get number of Spectral detectors used for scan in the given channel
3625  * width.
3626  *
3627  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
3628  */
3629 static QDF_STATUS
3630 target_if_spectral_get_num_detectors(struct target_if_spectral *spectral,
3631 				     enum phy_ch_width ch_width,
3632 				     uint32_t *num_detectors)
3633 {
3634 	if (!spectral) {
3635 		spectral_err("target if spectral object is null");
3636 		return QDF_STATUS_E_INVAL;
3637 	}
3638 
3639 	if (ch_width >= CH_WIDTH_INVALID) {
3640 		spectral_err("Invalid channel width %d", ch_width);
3641 		return QDF_STATUS_E_INVAL;
3642 	}
3643 
3644 	if (!num_detectors) {
3645 		spectral_err("Invalid argument, number of detectors");
3646 		return QDF_STATUS_E_INVAL;
3647 	}
3648 
3649 	switch (ch_width) {
3650 	case CH_WIDTH_20MHZ:
3651 		*num_detectors = spectral->capability.num_detectors_20mhz;
3652 		break;
3653 
3654 	case CH_WIDTH_40MHZ:
3655 		*num_detectors = spectral->capability.num_detectors_40mhz;
3656 		break;
3657 
3658 	case CH_WIDTH_80MHZ:
3659 		*num_detectors = spectral->capability.num_detectors_80mhz;
3660 		break;
3661 
3662 	case CH_WIDTH_160MHZ:
3663 		*num_detectors = spectral->capability.num_detectors_160mhz;
3664 		break;
3665 
3666 	case CH_WIDTH_80P80MHZ:
3667 		*num_detectors = spectral->capability.num_detectors_80p80mhz;
3668 		break;
3669 
3670 	default:
3671 		spectral_err("Unsupported channel width %d", ch_width);
3672 		return QDF_STATUS_E_INVAL;
3673 	}
3674 
3675 	return QDF_STATUS_SUCCESS;
3676 }
3677 
3678 /**
3679  * target_if_spectral_finite_scan_init() - Initializations required for finite
3680  * Spectral scan
3681  * @spectral: Pointer to target of Spctral object
3682  * @smode: Spectral scan mode
3683  *
3684  * This routine initializes the finite Spectral scan. Finite Spectral scan is
3685  * triggered by configuring a non zero scan count.
3686  *
3687  * Return: QDF_STATUS_SUCCESS on success
3688  */
3689 static QDF_STATUS
3690 target_if_spectral_finite_scan_init(struct target_if_spectral *spectral,
3691 				    enum spectral_scan_mode smode)
3692 {
3693 	struct target_if_finite_spectral_scan_params *finite_scan;
3694 	enum phy_ch_width ch_width;
3695 	uint32_t num_detectors;
3696 	QDF_STATUS status;
3697 	uint16_t sscan_count;
3698 
3699 	if (!spectral) {
3700 		spectral_err("target if spectral object is null");
3701 		return QDF_STATUS_E_INVAL;
3702 	}
3703 
3704 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3705 		spectral_err("Invalid Spectral mode");
3706 		return QDF_STATUS_E_INVAL;
3707 	}
3708 
3709 	ch_width = spectral->ch_width[smode];
3710 	status = target_if_spectral_get_num_detectors(spectral, ch_width,
3711 						      &num_detectors);
3712 
3713 	if (QDF_IS_STATUS_ERROR(status)) {
3714 		spectral_err("Failed to get number of detectors");
3715 		return QDF_STATUS_E_FAILURE;
3716 	}
3717 
3718 	finite_scan = &spectral->finite_scan[smode];
3719 	sscan_count =  spectral->params[smode].ss_count;
3720 
3721 	finite_scan->finite_spectral_scan =  true;
3722 	finite_scan->num_reports_expected = num_detectors * sscan_count;
3723 
3724 	return QDF_STATUS_SUCCESS;
3725 }
3726 
3727 /**
3728  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
3729  *                                           parameters
3730  * @spectral: Pointer to Spectral target_if internal private data
3731  * @spectral_params: Pointer to Spectral parameters
3732  * @smode: Spectral scan mode
3733  * @err: Spectral error code
3734  *
3735  * Enable use of desired Spectral parameters by configuring them into HW, and
3736  * starting Spectral scan
3737  *
3738  * Return: 0 on success, 1 on failure
3739  */
3740 int
3741 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
3742 				      struct spectral_config *spectral_params,
3743 				      enum spectral_scan_mode smode,
3744 				      enum spectral_cp_error_code *err)
3745 {
3746 	int extension_channel = 0;
3747 	int current_channel = 0;
3748 	struct target_if_spectral_ops *p_sops = NULL;
3749 	QDF_STATUS status;
3750 	struct wlan_objmgr_pdev *pdev;
3751 	struct wlan_objmgr_psoc *psoc;
3752 
3753 	if (!spectral) {
3754 		spectral_err("Spectral LMAC object is NULL");
3755 		return 1;
3756 	}
3757 
3758 	pdev =  spectral->pdev_obj;
3759 	if (!pdev) {
3760 		spectral_err("pdev is null");
3761 		return QDF_STATUS_E_INVAL;
3762 	}
3763 
3764 	psoc = wlan_pdev_get_psoc(pdev);
3765 	if (!psoc) {
3766 		spectral_err("psoc is null");
3767 		return QDF_STATUS_E_INVAL;
3768 	}
3769 
3770 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3771 		spectral_err("Invalid Spectral mode %u", smode);
3772 		return 1;
3773 	}
3774 
3775 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3776 
3777 	if (!p_sops) {
3778 		spectral_err("p_sops is NULL");
3779 		return 1;
3780 	}
3781 
3782 	spectral->sc_spectral_noise_pwr_cal =
3783 	    spectral_params->ss_spectral_pri ? 1 : 0;
3784 
3785 	/* check if extension channel is present */
3786 	extension_channel = p_sops->get_extension_channel(spectral, smode);
3787 	current_channel = p_sops->get_current_channel(spectral, smode);
3788 
3789 	status = target_if_spectral_populate_chwidth(
3790 			spectral, spectral->ch_width,
3791 			spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3792 			ss_frequency.cfreq2 > 0);
3793 	if (QDF_IS_STATUS_ERROR(status)) {
3794 		spectral_err("Failed to get channel widths");
3795 		return 1;
3796 	}
3797 
3798 	if (spectral->capability.advncd_spectral_cap) {
3799 		spectral->lb_edge_extrabins = 0;
3800 		spectral->rb_edge_extrabins = 0;
3801 
3802 		if (spectral->is_lb_edge_extrabins_format &&
3803 		    spectral->params[smode].ss_rpt_mode == 2) {
3804 			spectral->lb_edge_extrabins = 4;
3805 		}
3806 
3807 		if (spectral->is_rb_edge_extrabins_format &&
3808 		    spectral->params[smode].ss_rpt_mode == 2) {
3809 			spectral->rb_edge_extrabins = 4;
3810 		}
3811 
3812 		if (spectral->ch_width[smode] == CH_WIDTH_20MHZ) {
3813 			spectral->sc_spectral_20_40_mode = 0;
3814 
3815 			spectral->spectral_numbins =
3816 			    target_if_get_fft_bin_count(
3817 				spectral->params[smode].ss_fft_size);
3818 			spectral->spectral_fft_len =
3819 			    target_if_get_fft_bin_count(
3820 				spectral->params[smode].ss_fft_size);
3821 			spectral->spectral_data_len =
3822 			    target_if_get_fft_bin_count(
3823 				spectral->params[smode].ss_fft_size);
3824 			/*
3825 			 * Initialize classifier params to be sent to user
3826 			 * space classifier
3827 			 */
3828 			spectral->classifier_params.lower_chan_in_mhz =
3829 			    current_channel;
3830 			spectral->classifier_params.upper_chan_in_mhz = 0;
3831 
3832 		} else if (spectral->ch_width[smode] == CH_WIDTH_40MHZ) {
3833 			/* TODO : Remove this variable */
3834 			spectral->sc_spectral_20_40_mode = 1;
3835 			spectral->spectral_numbins =
3836 			    target_if_get_fft_bin_count(
3837 				spectral->params[smode].ss_fft_size);
3838 			spectral->spectral_fft_len =
3839 			    target_if_get_fft_bin_count(
3840 				spectral->params[smode].ss_fft_size);
3841 			spectral->spectral_data_len =
3842 			    target_if_get_fft_bin_count(
3843 				spectral->params[smode].ss_fft_size);
3844 
3845 			/*
3846 			 * Initialize classifier params to be sent to user
3847 			 * space classifier
3848 			 */
3849 			if (extension_channel < current_channel) {
3850 				spectral->classifier_params.lower_chan_in_mhz =
3851 				    extension_channel;
3852 				spectral->classifier_params.upper_chan_in_mhz =
3853 				    current_channel;
3854 			} else {
3855 				spectral->classifier_params.lower_chan_in_mhz =
3856 				    current_channel;
3857 				spectral->classifier_params.upper_chan_in_mhz =
3858 				    extension_channel;
3859 			}
3860 
3861 		} else if (spectral->ch_width[smode] == CH_WIDTH_80MHZ) {
3862 			/* Set the FFT Size */
3863 			/* TODO : Remove this variable */
3864 			spectral->sc_spectral_20_40_mode = 0;
3865 			spectral->spectral_numbins =
3866 			    target_if_get_fft_bin_count(
3867 				spectral->params[smode].ss_fft_size);
3868 			spectral->spectral_fft_len =
3869 			    target_if_get_fft_bin_count(
3870 				spectral->params[smode].ss_fft_size);
3871 			spectral->spectral_data_len =
3872 			    target_if_get_fft_bin_count(
3873 				spectral->params[smode].ss_fft_size);
3874 
3875 			/*
3876 			 * Initialize classifier params to be sent to user
3877 			 * space classifier
3878 			 */
3879 			spectral->classifier_params.lower_chan_in_mhz =
3880 			    current_channel;
3881 			spectral->classifier_params.upper_chan_in_mhz = 0;
3882 
3883 			/*
3884 			 * Initialize classifier params to be sent to user
3885 			 * space classifier
3886 			 */
3887 			if (extension_channel < current_channel) {
3888 				spectral->classifier_params.lower_chan_in_mhz =
3889 				    extension_channel;
3890 				spectral->classifier_params.upper_chan_in_mhz =
3891 				    current_channel;
3892 			} else {
3893 				spectral->classifier_params.lower_chan_in_mhz =
3894 				    current_channel;
3895 				spectral->classifier_params.upper_chan_in_mhz =
3896 				    extension_channel;
3897 			}
3898 
3899 		} else if (is_ch_width_160_or_80p80(
3900 			   spectral->ch_width[smode])) {
3901 			/* Set the FFT Size */
3902 
3903 			/* The below applies to both 160 and 80+80 cases */
3904 
3905 			/* TODO : Remove this variable */
3906 			spectral->sc_spectral_20_40_mode = 0;
3907 			spectral->spectral_numbins =
3908 			    target_if_get_fft_bin_count(
3909 				spectral->params[smode].ss_fft_size);
3910 			spectral->spectral_fft_len =
3911 			    target_if_get_fft_bin_count(
3912 				spectral->params[smode].ss_fft_size);
3913 			spectral->spectral_data_len =
3914 			    target_if_get_fft_bin_count(
3915 				spectral->params[smode].ss_fft_size);
3916 
3917 			/*
3918 			 * Initialize classifier params to be sent to user
3919 			 * space classifier
3920 			 */
3921 			spectral->classifier_params.lower_chan_in_mhz =
3922 			    current_channel;
3923 			spectral->classifier_params.upper_chan_in_mhz = 0;
3924 
3925 			/*
3926 			 * Initialize classifier params to be sent to user
3927 			 * space classifier
3928 			 */
3929 			if (extension_channel < current_channel) {
3930 				spectral->classifier_params.lower_chan_in_mhz =
3931 				    extension_channel;
3932 				spectral->classifier_params.upper_chan_in_mhz =
3933 				    current_channel;
3934 			} else {
3935 				spectral->classifier_params.lower_chan_in_mhz =
3936 				    current_channel;
3937 				spectral->classifier_params.upper_chan_in_mhz =
3938 				    extension_channel;
3939 			}
3940 		}
3941 
3942 		if (spectral->spectral_numbins) {
3943 			spectral->spectral_numbins +=
3944 			    spectral->lb_edge_extrabins;
3945 			spectral->spectral_numbins +=
3946 			    spectral->rb_edge_extrabins;
3947 		}
3948 
3949 		if (spectral->spectral_fft_len) {
3950 			spectral->spectral_fft_len +=
3951 			    spectral->lb_edge_extrabins;
3952 			spectral->spectral_fft_len +=
3953 			    spectral->rb_edge_extrabins;
3954 		}
3955 
3956 		if (spectral->spectral_data_len) {
3957 			spectral->spectral_data_len +=
3958 			    spectral->lb_edge_extrabins;
3959 			spectral->spectral_data_len +=
3960 			    spectral->rb_edge_extrabins;
3961 		}
3962 	} else {
3963 		/*
3964 		 * The decision to find 20/40 mode is found based on the
3965 		 * presence of extension channel
3966 		 * instead of channel width, as the channel width can
3967 		 * dynamically change
3968 		 */
3969 
3970 		if (extension_channel == 0) {
3971 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
3972 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
3973 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
3974 			spectral->spectral_data_len =
3975 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
3976 			/* only valid in 20-40 mode */
3977 			spectral->spectral_lower_max_index_offset = -1;
3978 			/* only valid in 20-40 mode */
3979 			spectral->spectral_upper_max_index_offset = -1;
3980 			spectral->spectral_max_index_offset =
3981 			    spectral->spectral_fft_len + 2;
3982 			spectral->sc_spectral_20_40_mode = 0;
3983 
3984 			/*
3985 			 * Initialize classifier params to be sent to user
3986 			 * space classifier
3987 			 */
3988 			spectral->classifier_params.lower_chan_in_mhz =
3989 			    current_channel;
3990 			spectral->classifier_params.upper_chan_in_mhz = 0;
3991 
3992 		} else {
3993 			spectral->spectral_numbins =
3994 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
3995 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
3996 			spectral->spectral_data_len =
3997 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
3998 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
3999 			/* only valid in 20 mode */
4000 			spectral->spectral_max_index_offset = -1;
4001 			spectral->spectral_lower_max_index_offset =
4002 			    spectral->spectral_fft_len + 2;
4003 			spectral->spectral_upper_max_index_offset =
4004 			    spectral->spectral_fft_len + 5;
4005 			spectral->sc_spectral_20_40_mode = 1;
4006 
4007 			/*
4008 			 * Initialize classifier params to be sent to user
4009 			 * space classifier
4010 			 */
4011 			if (extension_channel < current_channel) {
4012 				spectral->classifier_params.lower_chan_in_mhz =
4013 				    extension_channel;
4014 				spectral->classifier_params.upper_chan_in_mhz =
4015 				    current_channel;
4016 			} else {
4017 				spectral->classifier_params.lower_chan_in_mhz =
4018 				    current_channel;
4019 				spectral->classifier_params.upper_chan_in_mhz =
4020 				    extension_channel;
4021 			}
4022 		}
4023 	}
4024 
4025 	spectral->send_single_packet = 0;
4026 	spectral->classifier_params.spectral_20_40_mode =
4027 	    spectral->sc_spectral_20_40_mode;
4028 	spectral->classifier_params.spectral_dc_index =
4029 	    spectral->spectral_dc_index;
4030 	spectral->spectral_sent_msg = 0;
4031 	spectral->classify_scan = 0;
4032 	spectral->num_spectral_data = 0;
4033 
4034 	if (!p_sops->is_spectral_active(spectral, smode)) {
4035 		p_sops->configure_spectral(spectral, spectral_params, smode);
4036 		spectral->rparams.marker[smode].is_valid = false;
4037 
4038 		if (spectral->params[smode].ss_count) {
4039 			status = target_if_spectral_finite_scan_init(spectral,
4040 								     smode);
4041 			if (QDF_IS_STATUS_ERROR(status)) {
4042 				spectral_err("Failed to init finite scan");
4043 				return 1;
4044 			}
4045 		}
4046 		p_sops->start_spectral_scan(spectral, smode, err);
4047 		spectral->timestamp_war.timestamp_war_offset[smode] = 0;
4048 		spectral->timestamp_war.last_fft_timestamp[smode] = 0;
4049 	}
4050 
4051 	/* get current spectral configuration */
4052 	p_sops->get_spectral_config(spectral, &spectral->params[smode], smode);
4053 
4054 	target_if_init_upper_lower_flags(spectral, smode);
4055 
4056 	return 0;
4057 }
4058 
4059 /**
4060  * target_if_is_aspectral_prohibited_by_adfs() - Is Agile Spectral prohibited by
4061  * Agile DFS
4062  * @psoc: Pointer to psoc
4063  * @object: Pointer to pdev
4064  * @arg: Pointer to flag which indicates whether Agile Spectral is prohibited
4065  *
4066  * This API checks whether Agile DFS is running on any of the pdevs. If so, it
4067  * indicates that Agile Spectral scan is prohibited by Agile DFS.
4068  *
4069  * Return: void
4070  */
4071 static void
4072 target_if_is_aspectral_prohibited_by_adfs(struct wlan_objmgr_psoc *psoc,
4073 					  void *object, void *arg)
4074 {
4075 	bool *is_aspectral_prohibited = arg;
4076 	struct wlan_objmgr_pdev *cur_pdev = object;
4077 	bool is_agile_dfs_enabled_cur_pdev = false;
4078 	QDF_STATUS status;
4079 
4080 	qdf_assert_always(is_aspectral_prohibited);
4081 	if (*is_aspectral_prohibited)
4082 		return;
4083 
4084 	qdf_assert_always(psoc);
4085 	qdf_assert_always(cur_pdev);
4086 
4087 	status = ucfg_dfs_get_agile_precac_enable
4088 				(cur_pdev,
4089 				 &is_agile_dfs_enabled_cur_pdev);
4090 	if (QDF_IS_STATUS_ERROR(status)) {
4091 		spectral_err("Get agile precac failed, prohibiting aSpectral");
4092 		*is_aspectral_prohibited = true;
4093 		return;
4094 	}
4095 
4096 	if (is_agile_dfs_enabled_cur_pdev) {
4097 		spectral_err("aDFS is in progress on one of the pdevs");
4098 		*is_aspectral_prohibited = true;
4099 	}
4100 }
4101 
4102 /**
4103  * target_if_get_curr_band() - Get current operating band of pdev
4104  *
4105  * @pdev: pointer to pdev object
4106  *
4107  * API to get current operating band of a given pdev.
4108  *
4109  * Return: if success enum reg_wifi_band, REG_BAND_UNKNOWN in case of failure
4110  */
4111 static enum reg_wifi_band
4112 target_if_get_curr_band(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id)
4113 {
4114 	struct wlan_objmgr_vdev *vdev;
4115 	int16_t chan_freq;
4116 	enum reg_wifi_band cur_band;
4117 
4118 	if (!pdev) {
4119 		spectral_err("pdev is NULL");
4120 		return REG_BAND_UNKNOWN;
4121 	}
4122 
4123 	if (vdev_id == WLAN_INVALID_VDEV_ID)
4124 		vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID);
4125 	else
4126 		vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
4127 							    WLAN_SPECTRAL_ID);
4128 	if (!vdev) {
4129 		spectral_debug("vdev is NULL");
4130 		return REG_BAND_UNKNOWN;
4131 	}
4132 	chan_freq = target_if_vdev_get_chan_freq(vdev);
4133 	cur_band = wlan_reg_freq_to_band(chan_freq);
4134 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4135 
4136 	return cur_band;
4137 }
4138 
4139 /**
4140  * target_if_is_agile_scan_active_in_5g() - Is Agile Spectral scan active on
4141  * any of the 5G pdevs
4142  * @psoc: Pointer to psoc
4143  * @object: Pointer to pdev
4144  * @arg: Pointer to flag which indicates whether Agile Spectral scan is in
4145  *       progress in any 5G pdevs
4146  *
4147  * Return: void
4148  */
4149 static void
4150 target_if_is_agile_scan_active_in_5g(struct wlan_objmgr_psoc *psoc,
4151 				     void *object, void *arg)
4152 {
4153 	enum reg_wifi_band band;
4154 	bool *is_agile_scan_inprog_5g_pdev = arg;
4155 	struct target_if_spectral *spectral;
4156 	struct wlan_objmgr_pdev *cur_pdev = object;
4157 	struct target_if_spectral_ops *p_sops;
4158 
4159 	if (*is_agile_scan_inprog_5g_pdev)
4160 		return;
4161 
4162 	spectral = get_target_if_spectral_handle_from_pdev(cur_pdev);
4163 	if (!spectral) {
4164 		spectral_err("target if spectral handle is NULL");
4165 		return;
4166 	}
4167 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4168 
4169 	band = target_if_get_curr_band(
4170 			cur_pdev, spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE]);
4171 	if (band == REG_BAND_UNKNOWN) {
4172 		spectral_debug("Failed to get current band");
4173 		return;
4174 	}
4175 
4176 	if (band == REG_BAND_5G &&
4177 	    p_sops->is_spectral_active(spectral, SPECTRAL_SCAN_MODE_AGILE))
4178 		*is_agile_scan_inprog_5g_pdev = true;
4179 }
4180 
4181 /**
4182  * target_if_is_agile_supported_cur_chmask() - Is Agile Spectral scan supported
4183  * for current vdev rx chainmask.
4184  *
4185  * @spectral: Pointer to Spectral object
4186  * @is_supported: Pointer to is_supported
4187  *
4188  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4189  */
4190 static QDF_STATUS
4191 target_if_is_agile_supported_cur_chmask(struct target_if_spectral *spectral,
4192 					bool *is_supported)
4193 {
4194 	struct wlan_objmgr_vdev *vdev;
4195 	uint8_t vdev_rxchainmask;
4196 	struct wlan_objmgr_psoc *psoc;
4197 	struct wlan_objmgr_pdev *pdev;
4198 	struct target_psoc_info *tgt_psoc_info;
4199 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
4200 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr = NULL;
4201 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = NULL;
4202 	struct wlan_psoc_host_chainmask_table *table;
4203 	int j;
4204 	uint32_t table_id;
4205 	enum phy_ch_width ch_width;
4206 	uint8_t pdev_id;
4207 
4208 	if (!spectral) {
4209 		spectral_err("spectral target if object is null");
4210 		return QDF_STATUS_E_FAILURE;
4211 	}
4212 
4213 	if (!is_supported) {
4214 		spectral_err("is supported argument is null");
4215 		return QDF_STATUS_E_FAILURE;
4216 	}
4217 
4218 	if (spectral->spectral_gen <= SPECTRAL_GEN2) {
4219 		spectral_err("HW Agile mode is not supported up to gen 2");
4220 		return QDF_STATUS_E_FAILURE;
4221 	}
4222 
4223 	pdev = spectral->pdev_obj;
4224 	if (!pdev) {
4225 		spectral_err("pdev is null");
4226 		return QDF_STATUS_E_FAILURE;
4227 	}
4228 
4229 	psoc = wlan_pdev_get_psoc(pdev);
4230 	if (!psoc) {
4231 		spectral_err("psoc is null");
4232 		return QDF_STATUS_E_FAILURE;
4233 	}
4234 
4235 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
4236 	if (!vdev) {
4237 		spectral_err("First vdev is NULL");
4238 		return QDF_STATUS_E_FAILURE;
4239 	}
4240 
4241 	vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
4242 	if (!vdev_rxchainmask) {
4243 		spectral_err("vdev rx chainmask is zero");
4244 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4245 		return QDF_STATUS_E_FAILURE;
4246 	}
4247 
4248 	ch_width = target_if_vdev_get_ch_width(vdev);
4249 	if (ch_width == CH_WIDTH_INVALID) {
4250 		spectral_err("Invalid channel width");
4251 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4252 		return QDF_STATUS_E_FAILURE;
4253 	}
4254 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4255 
4256 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
4257 	if (!tgt_psoc_info) {
4258 		spectral_err("target_psoc_info is null");
4259 		return QDF_STATUS_E_FAILURE;
4260 	}
4261 
4262 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
4263 	if (!ext_svc_param) {
4264 		spectral_err("Extended service ready param null");
4265 		return QDF_STATUS_E_FAILURE;
4266 	}
4267 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
4268 
4269 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
4270 	if (!mac_phy_cap_arr) {
4271 		spectral_err("mac phy cap array is null");
4272 		return QDF_STATUS_E_FAILURE;
4273 	}
4274 
4275 	mac_phy_cap = &mac_phy_cap_arr[pdev_id];
4276 	if (!mac_phy_cap) {
4277 		spectral_err("mac phy cap is null");
4278 		return QDF_STATUS_E_FAILURE;
4279 	}
4280 
4281 	table_id = mac_phy_cap->chainmask_table_id;
4282 	table =  &ext_svc_param->chainmask_table[table_id];
4283 	if (!table) {
4284 		spectral_err("chainmask table not found");
4285 		return QDF_STATUS_E_FAILURE;
4286 	}
4287 
4288 	for (j = 0; j < table->num_valid_chainmasks; j++) {
4289 		if (table->cap_list[j].chainmask == vdev_rxchainmask) {
4290 			if (ch_width <= CH_WIDTH_80MHZ)
4291 				*is_supported =
4292 					table->cap_list[j].supports_aSpectral;
4293 			else
4294 				*is_supported =
4295 				      table->cap_list[j].supports_aSpectral_160;
4296 			break;
4297 		}
4298 	}
4299 
4300 	if (j == table->num_valid_chainmasks) {
4301 		spectral_err("vdev rx chainmask %u not found in table id = %u",
4302 			     vdev_rxchainmask, table_id);
4303 		return QDF_STATUS_E_FAILURE;
4304 	}
4305 
4306 	return QDF_STATUS_SUCCESS;
4307 }
4308 
4309 QDF_STATUS
4310 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev,
4311 			      uint8_t vdev_id,
4312 			      const enum spectral_scan_mode smode,
4313 			      enum spectral_cp_error_code *err)
4314 {
4315 	struct target_if_spectral_ops *p_sops;
4316 	struct target_if_spectral *spectral;
4317 	struct wlan_objmgr_psoc *psoc;
4318 	enum reg_wifi_band band;
4319 
4320 	if (!err) {
4321 		spectral_err("Error code argument is null");
4322 		QDF_ASSERT(0);
4323 		return QDF_STATUS_E_FAILURE;
4324 	}
4325 	*err = SPECTRAL_SCAN_ERR_INVALID;
4326 
4327 	if (!pdev) {
4328 		spectral_err("pdev object is NUll");
4329 		return QDF_STATUS_E_FAILURE;
4330 	}
4331 
4332 	psoc = wlan_pdev_get_psoc(pdev);
4333 	if (!psoc) {
4334 		spectral_err("psoc is null");
4335 		return QDF_STATUS_E_FAILURE;
4336 	}
4337 
4338 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4339 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4340 		spectral_err("Invalid Spectral mode %u", smode);
4341 		return QDF_STATUS_E_FAILURE;
4342 	}
4343 
4344 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4345 	if (!spectral) {
4346 		spectral_err("Spectral LMAC object is NUll");
4347 		return QDF_STATUS_E_FAILURE;
4348 	}
4349 
4350 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4351 	if (!p_sops) {
4352 		spectral_err("p_sops is null");
4353 		return QDF_STATUS_E_FAILURE;
4354 	}
4355 
4356 	if (p_sops->is_spectral_active(spectral, smode)) {
4357 		spectral_err("spectral in progress in current pdev, mode %d",
4358 			     smode);
4359 		return QDF_STATUS_E_FAILURE;
4360 	}
4361 	spectral->vdev_id[smode] = vdev_id;
4362 
4363 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
4364 		QDF_STATUS status;
4365 		bool is_supported = false;
4366 
4367 		status = target_if_is_agile_supported_cur_chmask(spectral,
4368 								 &is_supported);
4369 		if (QDF_IS_STATUS_ERROR(status)) {
4370 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4371 			return QDF_STATUS_E_FAILURE;
4372 		}
4373 
4374 		if (!is_supported) {
4375 			spectral_err("aSpectral unsupported for cur chainmask");
4376 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4377 			return QDF_STATUS_E_FAILURE;
4378 		}
4379 	}
4380 
4381 	band = target_if_get_curr_band(spectral->pdev_obj, vdev_id);
4382 	if (band == REG_BAND_UNKNOWN) {
4383 		spectral_err("Failed to get current band");
4384 		return QDF_STATUS_E_FAILURE;
4385 	}
4386 	if ((band == REG_BAND_5G) && (smode == SPECTRAL_SCAN_MODE_AGILE)) {
4387 		struct target_psoc_info *tgt_hdl;
4388 		enum wmi_host_hw_mode_config_type mode;
4389 		bool is_agile_scan_inprog_5g_pdev;
4390 
4391 		tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
4392 		if (!tgt_hdl) {
4393 			target_if_err("target_psoc_info is null");
4394 			return QDF_STATUS_E_FAILURE;
4395 		}
4396 
4397 		mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
4398 		switch (mode) {
4399 		case WMI_HOST_HW_MODE_SBS_PASSIVE:
4400 		case WMI_HOST_HW_MODE_SBS:
4401 		case WMI_HOST_HW_MODE_DBS_SBS:
4402 		case WMI_HOST_HW_MODE_DBS_OR_SBS:
4403 			is_agile_scan_inprog_5g_pdev = false;
4404 			wlan_objmgr_iterate_obj_list
4405 				(psoc, WLAN_PDEV_OP,
4406 				 target_if_is_agile_scan_active_in_5g,
4407 				 &is_agile_scan_inprog_5g_pdev, 0,
4408 				 WLAN_SPECTRAL_ID);
4409 			break;
4410 		default:
4411 			is_agile_scan_inprog_5g_pdev = false;
4412 			break;
4413 		}
4414 
4415 		if (is_agile_scan_inprog_5g_pdev) {
4416 			spectral_err("Agile Scan in progress in one of the SBS 5G pdev");
4417 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4418 			return QDF_STATUS_E_FAILURE;
4419 		}
4420 	}
4421 
4422 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
4423 		bool is_aspectral_prohibited = false;
4424 		QDF_STATUS status;
4425 
4426 		status = wlan_objmgr_iterate_obj_list
4427 				(psoc, WLAN_PDEV_OP,
4428 				 target_if_is_aspectral_prohibited_by_adfs,
4429 				 &is_aspectral_prohibited, 0,
4430 				 WLAN_SPECTRAL_ID);
4431 		if (QDF_IS_STATUS_ERROR(status)) {
4432 			spectral_err("Failed to iterate over pdevs");
4433 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4434 			return QDF_STATUS_E_FAILURE;
4435 		}
4436 
4437 		if (is_aspectral_prohibited) {
4438 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4439 			return QDF_STATUS_E_FAILURE;
4440 		}
4441 	}
4442 
4443 	if (!spectral->params_valid[smode]) {
4444 		target_if_spectral_info_read(spectral,
4445 					     smode,
4446 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
4447 					     &spectral->params[smode],
4448 					     sizeof(spectral->params[smode]));
4449 		spectral->params_valid[smode] = true;
4450 	}
4451 
4452 	qdf_spin_lock(&spectral->spectral_lock);
4453 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
4454 		QDF_STATUS status;
4455 		bool is_overlapping;
4456 		enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
4457 		enum spectral_scan_mode m;
4458 		enum phy_ch_width op_ch_width;
4459 		enum phy_ch_width agile_ch_width;
4460 
4461 		m = SPECTRAL_SCAN_MODE_NORMAL;
4462 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
4463 			ch_width[m] = CH_WIDTH_INVALID;
4464 		status = target_if_spectral_populate_chwidth
4465 			(spectral, ch_width, spectral->params
4466 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
4467 		if (QDF_IS_STATUS_ERROR(status)) {
4468 			qdf_spin_unlock(&spectral->spectral_lock);
4469 			spectral_err("Failed to populate channel width");
4470 			return QDF_STATUS_E_FAILURE;
4471 		}
4472 		op_ch_width = ch_width[SPECTRAL_SCAN_MODE_NORMAL];
4473 		agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
4474 
4475 		if (!spectral->params[smode].ss_frequency.cfreq1 ||
4476 		    (agile_ch_width == CH_WIDTH_80P80MHZ &&
4477 		    !spectral->params[smode].ss_frequency.cfreq2)) {
4478 			*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
4479 			qdf_spin_unlock(&spectral->spectral_lock);
4480 			return QDF_STATUS_E_FAILURE;
4481 		}
4482 
4483 		status = target_if_is_agile_span_overlap_with_operating_span
4484 				(spectral, ch_width,
4485 				 &spectral->params[smode].ss_frequency,
4486 				 &is_overlapping);
4487 		if (QDF_IS_STATUS_ERROR(status)) {
4488 			qdf_spin_unlock(&spectral->spectral_lock);
4489 			return QDF_STATUS_E_FAILURE;
4490 		}
4491 
4492 		if (is_overlapping) {
4493 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4494 			qdf_spin_unlock(&spectral->spectral_lock);
4495 			return QDF_STATUS_E_FAILURE;
4496 		}
4497 	}
4498 
4499 	target_if_spectral_scan_enable_params(spectral,
4500 					      &spectral->params[smode], smode,
4501 					      err);
4502 	qdf_spin_unlock(&spectral->spectral_lock);
4503 
4504 	return QDF_STATUS_SUCCESS;
4505 }
4506 
4507 QDF_STATUS
4508 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev,
4509 			     const enum spectral_scan_mode smode,
4510 			     enum spectral_cp_error_code *err)
4511 {
4512 	struct target_if_spectral_ops *p_sops;
4513 	struct target_if_spectral *spectral;
4514 
4515 	if (!err) {
4516 		spectral_err("Error code argument is null");
4517 		QDF_ASSERT(0);
4518 		return QDF_STATUS_E_FAILURE;
4519 	}
4520 	*err = SPECTRAL_SCAN_ERR_INVALID;
4521 
4522 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4523 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4524 		spectral_err("Invalid Spectral mode %u", smode);
4525 		return QDF_STATUS_E_FAILURE;
4526 	}
4527 
4528 	if (!pdev) {
4529 		spectral_err("pdev object is NUll ");
4530 		return QDF_STATUS_E_FAILURE;
4531 	}
4532 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4533 	if (!spectral) {
4534 		spectral_err("Spectral LMAC object is NUll ");
4535 		return QDF_STATUS_E_FAILURE;
4536 	}
4537 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4538 
4539 	qdf_spin_lock(&spectral->spectral_lock);
4540 	p_sops->stop_spectral_scan(spectral, smode);
4541 	if (spectral->classify_scan) {
4542 		/* TODO : Check if this logic is necessary */
4543 		spectral->detects_control_channel = 0;
4544 		spectral->detects_extension_channel = 0;
4545 		spectral->detects_above_dc = 0;
4546 		spectral->detects_below_dc = 0;
4547 		spectral->classify_scan = 0;
4548 	}
4549 
4550 	spectral->send_single_packet = 0;
4551 	spectral->sc_spectral_scan = 0;
4552 
4553 	qdf_spin_unlock(&spectral->spectral_lock);
4554 
4555 	return QDF_STATUS_SUCCESS;
4556 }
4557 
4558 /**
4559  * target_if_is_spectral_active() - Get whether Spectral is active
4560  * @pdev: Pointer to pdev object
4561  * @smode: Spectral scan mode
4562  *
4563  * API to get whether Spectral is active
4564  *
4565  * Return: True if Spectral is active, false if Spectral is not active
4566  */
4567 bool
4568 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev,
4569 			     const enum spectral_scan_mode smode)
4570 {
4571 	struct target_if_spectral *spectral = NULL;
4572 	struct target_if_spectral_ops *p_sops = NULL;
4573 
4574 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4575 
4576 	if (!spectral) {
4577 		spectral_err("SPECTRAL : Module doesn't exist");
4578 		return QDF_STATUS_E_FAILURE;
4579 	}
4580 
4581 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4582 
4583 	if (!p_sops) {
4584 		spectral_err("p_sops is null");
4585 		return QDF_STATUS_E_FAILURE;
4586 	}
4587 
4588 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4589 		spectral_err("Invalid Spectral mode %u", smode);
4590 		return QDF_STATUS_E_FAILURE;
4591 	}
4592 
4593 	return p_sops->is_spectral_active(spectral, smode);
4594 }
4595 
4596 /**
4597  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
4598  * @pdev: Pointer to pdev object
4599  * @smode: Spectral scan mode
4600  *
4601  * API to get whether Spectral is enabled
4602  *
4603  * Return: True if Spectral is enabled, false if Spectral is not enabled
4604  */
4605 bool
4606 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev,
4607 			      enum spectral_scan_mode smode)
4608 {
4609 	struct target_if_spectral *spectral = NULL;
4610 	struct target_if_spectral_ops *p_sops = NULL;
4611 
4612 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4613 
4614 	if (!spectral) {
4615 		spectral_err("SPECTRAL : Module doesn't exist");
4616 		return QDF_STATUS_E_FAILURE;
4617 	}
4618 
4619 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4620 
4621 	if (!p_sops) {
4622 		spectral_err("p_sops is null");
4623 		return QDF_STATUS_E_FAILURE;
4624 	}
4625 
4626 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4627 		spectral_err("Invalid Spectral mode %u", smode);
4628 		return QDF_STATUS_E_FAILURE;
4629 	}
4630 
4631 	return p_sops->is_spectral_enabled(spectral, smode);
4632 }
4633 
4634 #ifdef DIRECT_BUF_RX_DEBUG
4635 /**
4636  * target_if_spectral_do_dbr_ring_debug() - Start/Stop Spectral DMA ring debug
4637  * @pdev: Pointer to pdev object
4638  * @enable: Enable/Disable Spectral DMA ring debug
4639  *
4640  * Start/stop Spectral DMA ring debug based on @enable.
4641  * Also save the state for future use.
4642  *
4643  * Return: QDF_STATUS of operation
4644  */
4645 static QDF_STATUS
4646 target_if_spectral_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev, bool enable)
4647 {
4648 	struct target_if_spectral *spectral;
4649 	struct wlan_lmac_if_tx_ops *tx_ops;
4650 	struct wlan_objmgr_psoc *psoc;
4651 
4652 	if (!pdev)
4653 		return QDF_STATUS_E_FAILURE;
4654 
4655 	psoc = wlan_pdev_get_psoc(pdev);
4656 	if (!psoc) {
4657 		spectral_err("psoc is null");
4658 		return QDF_STATUS_E_INVAL;
4659 	}
4660 
4661 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
4662 	if (!tx_ops) {
4663 		spectral_err("tx_ops is NULL");
4664 		return QDF_STATUS_E_INVAL;
4665 	}
4666 
4667 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4668 	if (!spectral) {
4669 		spectral_err("Spectal LMAC object is NULL");
4670 		return QDF_STATUS_E_INVAL;
4671 	}
4672 
4673 	/* Save the state */
4674 	spectral->dbr_ring_debug = enable;
4675 
4676 	if (enable)
4677 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_ring_debug(
4678 				pdev, 0, SPECTRAL_DBR_RING_DEBUG_SIZE);
4679 	else
4680 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_ring_debug(
4681 				pdev, 0);
4682 
4683 	return QDF_STATUS_SUCCESS;
4684 }
4685 
4686 /**
4687  * target_if_spectral_do_dbr_buff_debug() - Start/Stop Spectral DMA buffer debug
4688  * @pdev: Pointer to pdev object
4689  * @enable: Enable/Disable Spectral DMA buffer debug
4690  *
4691  * Start/stop Spectral DMA buffer debug based on @enable.
4692  * Also save the state for future use.
4693  *
4694  * Return: QDF_STATUS of operation
4695  */
4696 static QDF_STATUS
4697 target_if_spectral_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev, bool enable)
4698 {
4699 	struct target_if_spectral *spectral;
4700 	struct wlan_lmac_if_tx_ops *tx_ops;
4701 	struct wlan_objmgr_psoc *psoc;
4702 
4703 	if (!pdev)
4704 		return QDF_STATUS_E_FAILURE;
4705 
4706 	psoc = wlan_pdev_get_psoc(pdev);
4707 	if (!psoc) {
4708 		spectral_err("psoc is null");
4709 		return QDF_STATUS_E_INVAL;
4710 	}
4711 
4712 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
4713 	if (!tx_ops) {
4714 		spectral_err("tx_ops is NULL");
4715 		return QDF_STATUS_E_INVAL;
4716 	}
4717 
4718 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4719 	if (!spectral) {
4720 		spectral_err("Spectal LMAC object is NULL");
4721 		return QDF_STATUS_E_INVAL;
4722 	}
4723 
4724 	/* Save the state */
4725 	spectral->dbr_buff_debug = enable;
4726 
4727 	if (enable)
4728 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_buffer_poisoning(
4729 				pdev, 0, MEM_POISON_SIGNATURE);
4730 	else
4731 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_buffer_poisoning(
4732 				pdev, 0);
4733 }
4734 
4735 /**
4736  * target_if_spectral_check_and_do_dbr_buff_debug() - Start/Stop Spectral buffer
4737  * debug based on the previous state
4738  * @pdev: Pointer to pdev object
4739  *
4740  * Return: QDF_STATUS of operation
4741  */
4742 static QDF_STATUS
4743 target_if_spectral_check_and_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev)
4744 {
4745 	struct target_if_spectral *spectral;
4746 
4747 	if (!pdev) {
4748 		spectral_err("pdev is NULL!");
4749 		return QDF_STATUS_E_FAILURE;
4750 	}
4751 
4752 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4753 	if (!spectral) {
4754 		spectral_err("Spectal LMAC object is NULL");
4755 		return QDF_STATUS_E_INVAL;
4756 	}
4757 
4758 	if (spectral->dbr_buff_debug)
4759 		return target_if_spectral_do_dbr_buff_debug(pdev, true);
4760 	else
4761 		return target_if_spectral_do_dbr_buff_debug(pdev, false);
4762 }
4763 
4764 /**
4765  * target_if_spectral_check_and_do_dbr_ring_debug() - Start/Stop Spectral ring
4766  * debug based on the previous state
4767  * @pdev: Pointer to pdev object
4768  *
4769  * Return: QDF_STATUS of operation
4770  */
4771 static QDF_STATUS
4772 target_if_spectral_check_and_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev)
4773 {
4774 	struct target_if_spectral *spectral;
4775 
4776 	if (!pdev) {
4777 		spectral_err("pdev is NULL!");
4778 		return QDF_STATUS_E_FAILURE;
4779 	}
4780 
4781 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4782 	if (!spectral) {
4783 		spectral_err("Spectal LMAC object is NULL");
4784 		return QDF_STATUS_E_INVAL;
4785 	}
4786 
4787 	if (spectral->dbr_ring_debug)
4788 		return target_if_spectral_do_dbr_ring_debug(pdev, true);
4789 	else
4790 		return target_if_spectral_do_dbr_ring_debug(pdev, false);
4791 }
4792 
4793 /**
4794  * target_if_spectral_set_dma_debug() - Set DMA debug for Spectral
4795  * @pdev: Pointer to pdev object
4796  * @dma_debug_type: Type of Spectral DMA debug i.e., ring or buffer debug
4797  * @debug_value: Value to be set for @dma_debug_type
4798  *
4799  * Set DMA debug for Spectral and start/stop Spectral DMA debug function
4800  * based on @debug_value
4801  *
4802  * Return: QDF_STATUS of operation
4803  */
4804 static QDF_STATUS
4805 target_if_spectral_set_dma_debug(
4806 	struct wlan_objmgr_pdev *pdev,
4807 	enum spectral_dma_debug dma_debug_type,
4808 	bool debug_value)
4809 {
4810 	struct target_if_spectral_ops *p_sops;
4811 	struct wlan_objmgr_psoc *psoc;
4812 	struct wlan_lmac_if_tx_ops *tx_ops;
4813 	struct target_if_spectral *spectral;
4814 
4815 	if (!pdev)
4816 		return QDF_STATUS_E_FAILURE;
4817 
4818 	psoc = wlan_pdev_get_psoc(pdev);
4819 	if (!psoc) {
4820 		spectral_err("psoc is null");
4821 		return QDF_STATUS_E_INVAL;
4822 	}
4823 
4824 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
4825 	if (!tx_ops) {
4826 		spectral_err("tx_ops is NULL");
4827 		return QDF_STATUS_E_FAILURE;
4828 	}
4829 
4830 	if (!tx_ops->target_tx_ops.tgt_get_tgt_type) {
4831 		spectral_err("Unable to fetch target type");
4832 		return QDF_STATUS_E_FAILURE;
4833 	}
4834 
4835 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4836 	if (!spectral) {
4837 		spectral_err("Spectal LMAC object is NULL");
4838 		return QDF_STATUS_E_INVAL;
4839 	}
4840 
4841 	if (spectral->direct_dma_support) {
4842 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4843 		if (p_sops->is_spectral_active(spectral,
4844 					       SPECTRAL_SCAN_MODE_NORMAL) ||
4845 		    p_sops->is_spectral_active(spectral,
4846 					       SPECTRAL_SCAN_MODE_AGILE)) {
4847 			spectral_err("Altering DBR debug config isn't allowed during an ongoing scan");
4848 			return QDF_STATUS_E_FAILURE;
4849 		}
4850 
4851 		switch (dma_debug_type) {
4852 		case SPECTRAL_DMA_RING_DEBUG:
4853 			target_if_spectral_do_dbr_ring_debug(pdev, debug_value);
4854 			break;
4855 
4856 		case SPECTRAL_DMA_BUFFER_DEBUG:
4857 			target_if_spectral_do_dbr_buff_debug(pdev, debug_value);
4858 			break;
4859 
4860 		default:
4861 			spectral_err("Unsupported DMA debug type : %d",
4862 				     dma_debug_type);
4863 			return QDF_STATUS_E_FAILURE;
4864 		}
4865 	}
4866 	return QDF_STATUS_SUCCESS;
4867 }
4868 #endif /* DIRECT_BUF_RX_DEBUG */
4869 
4870 /**
4871  * target_if_spectral_direct_dma_support() - Get Direct-DMA support
4872  * @pdev: Pointer to pdev object
4873  *
4874  * Return: Whether Direct-DMA is supported on this radio
4875  */
4876 static bool
4877 target_if_spectral_direct_dma_support(struct wlan_objmgr_pdev *pdev)
4878 {
4879 	struct target_if_spectral *spectral;
4880 
4881 	if (!pdev) {
4882 		spectral_err("pdev is NULL!");
4883 		return false;
4884 	}
4885 
4886 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4887 	if (!spectral) {
4888 		spectral_err("Spectral LMAC object is NULL");
4889 		return false;
4890 	}
4891 
4892 	return spectral->direct_dma_support;
4893 }
4894 
4895 /**
4896  * target_if_set_debug_level() - Set debug level for Spectral
4897  * @pdev: Pointer to pdev object
4898  * @debug_level: Debug level
4899  *
4900  * API to set the debug level for Spectral
4901  *
4902  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4903  */
4904 QDF_STATUS
4905 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
4906 {
4907 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
4908 
4909 	return QDF_STATUS_SUCCESS;
4910 }
4911 
4912 /**
4913  * target_if_get_debug_level() - Get debug level for Spectral
4914  * @pdev: Pointer to pdev object
4915  *
4916  * API to get the debug level for Spectral
4917  *
4918  * Return: Current debug level
4919  */
4920 uint32_t
4921 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
4922 {
4923 	return spectral_debug_level;
4924 }
4925 
4926 /**
4927  * target_if_get_spectral_capinfo() - Get Spectral capability information
4928  * @pdev: Pointer to pdev object
4929  * @scaps: Buffer into which data should be copied
4930  *
4931  * API to get the spectral capability information
4932  *
4933  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4934  */
4935 QDF_STATUS
4936 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev,
4937 			       struct spectral_caps *scaps)
4938 {
4939 	struct target_if_spectral *spectral = NULL;
4940 
4941 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4942 	if (!spectral) {
4943 		spectral_err("SPECTRAL : Module doesn't exist");
4944 		return QDF_STATUS_E_FAILURE;
4945 	}
4946 
4947 	qdf_mem_copy(scaps, &spectral->capability,
4948 		     sizeof(struct spectral_caps));
4949 
4950 	return QDF_STATUS_SUCCESS;
4951 }
4952 
4953 /**
4954  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
4955  * @pdev:  Pointer to pdev object
4956  * @stats: Buffer into which data should be copied
4957  *
4958  * API to get the spectral diagnostic statistics
4959  *
4960  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4961  */
4962 QDF_STATUS
4963 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev,
4964 				 struct spectral_diag_stats *stats)
4965 {
4966 	struct target_if_spectral *spectral = NULL;
4967 
4968 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4969 	if (!spectral) {
4970 		spectral_err("SPECTRAL : Module doesn't exist");
4971 		return QDF_STATUS_E_FAILURE;
4972 	}
4973 
4974 	qdf_mem_copy(stats, &spectral->diag_stats,
4975 		     sizeof(struct spectral_diag_stats));
4976 
4977 	return QDF_STATUS_SUCCESS;
4978 }
4979 
4980 /**
4981  * target_if_register_spectral_wmi_ops() - Register Spectral WMI operations
4982  * @psoc: Pointer to psoc object
4983  * @wmi_ops: Pointer to the structure having Spectral WMI operations
4984  *
4985  * API for registering Spectral WMI operations in
4986  * spectral internal data structure
4987  *
4988  * Return: QDF_STATUS
4989  */
4990 static QDF_STATUS
4991 target_if_register_spectral_wmi_ops(struct wlan_objmgr_psoc *psoc,
4992 				    struct spectral_wmi_ops *wmi_ops)
4993 {
4994 	struct target_if_psoc_spectral *psoc_spectral;
4995 
4996 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
4997 	if (!psoc_spectral) {
4998 		spectral_err("Spectral LMAC object is null");
4999 		return QDF_STATUS_E_INVAL;
5000 	}
5001 
5002 	psoc_spectral->wmi_ops = *wmi_ops;
5003 
5004 	return QDF_STATUS_SUCCESS;
5005 }
5006 
5007 /**
5008  * target_if_register_spectral_tgt_ops() - Register Spectral target operations
5009  * @psoc: Pointer to psoc object
5010  * @tgt_ops: Pointer to the structure having Spectral target operations
5011  *
5012  * API for registering Spectral target operations in
5013  * spectral internal data structure
5014  *
5015  * Return: QDF_STATUS
5016  */
5017 static QDF_STATUS
5018 target_if_register_spectral_tgt_ops(struct wlan_objmgr_psoc *psoc,
5019 				    struct spectral_tgt_ops *tgt_ops)
5020 {
5021 	if (!psoc) {
5022 		spectral_err("psoc is null");
5023 		return QDF_STATUS_E_INVAL;
5024 	}
5025 
5026 	ops_tgt = *tgt_ops;
5027 
5028 	return QDF_STATUS_SUCCESS;
5029 }
5030 
5031 /**
5032  * target_if_register_netlink_cb() - Register Netlink callbacks
5033  * @pdev: Pointer to pdev object
5034  * @nl_cb: Netlink callbacks to register
5035  *
5036  * Return: void
5037  */
5038 static void
5039 target_if_register_netlink_cb(
5040 	struct wlan_objmgr_pdev *pdev,
5041 	struct spectral_nl_cb *nl_cb)
5042 {
5043 	struct target_if_spectral *spectral = NULL;
5044 
5045 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5046 
5047 	if (!spectral) {
5048 		spectral_err("SPECTRAL : Module doesn't exist");
5049 		return;
5050 	}
5051 
5052 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
5053 
5054 	if (spectral->use_nl_bcast)
5055 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
5056 	else
5057 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
5058 }
5059 
5060 /**
5061  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
5062  * Netlink messages to the application layer
5063  * @pdev: Pointer to pdev object
5064  *
5065  * Return: true for broadcast, false for unicast
5066  */
5067 static bool
5068 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
5069 {
5070 	struct target_if_spectral *spectral = NULL;
5071 
5072 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5073 
5074 	if (!spectral) {
5075 		spectral_err("SPECTRAL : Module doesn't exist");
5076 		return false;
5077 	}
5078 
5079 	return spectral->use_nl_bcast;
5080 }
5081 
5082 /**
5083  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
5084  * @pdev: Pointer to pdev object
5085  *
5086  * Return: void
5087  */
5088 static void
5089 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
5090 {
5091 	struct target_if_spectral *spectral = NULL;
5092 
5093 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5094 	if (!spectral) {
5095 		spectral_err("SPECTRAL : Module doesn't exist");
5096 		return;
5097 	}
5098 
5099 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
5100 }
5101 
5102 static int
5103 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
5104 				  void *payload)
5105 {
5106 	struct target_if_spectral *spectral = NULL;
5107 	struct target_if_spectral_ops *p_sops = NULL;
5108 
5109 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5110 	if (!spectral) {
5111 		spectral_err("SPECTRAL : Module doesn't exist");
5112 		return -EPERM;
5113 	}
5114 
5115 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5116 
5117 	if (!p_sops) {
5118 		spectral_err("p_sops is null");
5119 		return -EPERM;
5120 	}
5121 
5122 	return p_sops->process_spectral_report(pdev, payload);
5123 }
5124 
5125 #ifdef DIRECT_BUF_RX_DEBUG
5126 static inline void
5127 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
5128 {
5129 	if (!tx_ops) {
5130 		spectral_err("tx_ops is NULL");
5131 		return;
5132 	}
5133 
5134 	tx_ops->sptrl_tx_ops.sptrlto_set_dma_debug =
5135 		target_if_spectral_set_dma_debug;
5136 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_ring_debug =
5137 		target_if_spectral_check_and_do_dbr_ring_debug;
5138 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_buff_debug =
5139 		target_if_spectral_check_and_do_dbr_buff_debug;
5140 }
5141 #else
5142 static inline void
5143 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
5144 {
5145 }
5146 #endif
5147 
5148 #if defined(WLAN_CONV_SPECTRAL_ENABLE) && defined(SPECTRAL_MODULIZED_ENABLE)
5149 /**
5150  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
5151  * register WMI event handler
5152  * @psoc: Pointer to psoc object
5153  * @event_id: Event id
5154  * @handler_func: Handler function
5155  * @rx_ctx: Context of WMI event processing
5156  *
5157  * Wrapper function to register WMI event handler
5158  *
5159  * Return: 0 for success else failure
5160  */
5161 static int
5162 target_if_spectral_wmi_unified_register_event_handler(
5163 				struct wlan_objmgr_psoc *psoc,
5164 				wmi_conv_event_id event_id,
5165 				wmi_unified_event_handler handler_func,
5166 				uint8_t rx_ctx)
5167 {
5168 	wmi_unified_t wmi_handle;
5169 	struct target_if_psoc_spectral *psoc_spectral;
5170 	QDF_STATUS ret;
5171 
5172 	if (!psoc) {
5173 		spectral_err("psoc is null");
5174 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5175 	}
5176 
5177 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5178 	if (!wmi_handle) {
5179 		spectral_err("WMI handle is null");
5180 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5181 	}
5182 
5183 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5184 	if (!psoc_spectral) {
5185 		spectral_err("spectral object is null");
5186 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5187 	}
5188 
5189 	ret = psoc_spectral->wmi_ops.wmi_unified_register_event_handler(
5190 			wmi_handle, event_id, handler_func, rx_ctx);
5191 
5192 	return qdf_status_to_os_return(ret);
5193 }
5194 
5195 /**
5196  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
5197  * to unregister WMI event handler
5198  * @psoc: Pointer to psoc object
5199  * @event_id: Event id
5200  *
5201  * Wrapper function to unregister WMI event handler
5202  *
5203  * Return: 0 for success else failure
5204  */
5205 static int
5206 target_if_spectral_wmi_unified_unregister_event_handler(
5207 				struct wlan_objmgr_psoc *psoc,
5208 				wmi_conv_event_id event_id)
5209 {
5210 	wmi_unified_t wmi_handle;
5211 	struct target_if_psoc_spectral *psoc_spectral;
5212 	QDF_STATUS ret;
5213 
5214 	if (!psoc) {
5215 		spectral_err("psoc is null");
5216 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5217 	}
5218 
5219 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5220 	if (!wmi_handle) {
5221 		spectral_err("WMI handle is null");
5222 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5223 	}
5224 
5225 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5226 	if (!psoc_spectral) {
5227 		spectral_err("spectral object is null");
5228 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5229 	}
5230 
5231 	ret = psoc_spectral->wmi_ops.wmi_unified_unregister_event_handler(
5232 					wmi_handle, event_id);
5233 
5234 	return qdf_status_to_os_return(ret);
5235 }
5236 
5237 /**
5238  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
5239  * function to extract fixed parameters from start scan response event
5240  * @psoc: Pointer to psoc object
5241  * @evt_buf: Event buffer
5242  * @param: Start scan response parameters
5243  *
5244  * Wrapper function to extract fixed parameters from start scan response event
5245  *
5246  * Return: QDF_STATUS
5247  */
5248 static QDF_STATUS
5249 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5250 			struct wlan_objmgr_psoc *psoc,
5251 			uint8_t *evt_buf,
5252 			struct spectral_startscan_resp_params *param)
5253 {
5254 	wmi_unified_t wmi_handle;
5255 	struct target_if_psoc_spectral *psoc_spectral;
5256 
5257 	if (!psoc) {
5258 		spectral_err("psoc is null");
5259 		return QDF_STATUS_E_INVAL;
5260 	}
5261 
5262 	if (!evt_buf) {
5263 		spectral_err("WMI event buffer is null");
5264 		return QDF_STATUS_E_INVAL;
5265 	}
5266 
5267 	if (!param) {
5268 		spectral_err("Spectral startscan response parameters is null");
5269 		return QDF_STATUS_E_INVAL;
5270 	}
5271 
5272 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5273 	if (!wmi_handle) {
5274 		spectral_err("WMI handle is null");
5275 		return QDF_STATUS_E_INVAL;
5276 	}
5277 
5278 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5279 	if (!psoc_spectral) {
5280 		spectral_err("spectral object is null");
5281 		return QDF_STATUS_E_FAILURE;
5282 	}
5283 
5284 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5285 			wmi_handle, evt_buf, param);
5286 }
5287 
5288 /**
5289  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
5290  * function to extract start and end indices of primary 80 MHz, 5 MHz and
5291  * secondary 80 MHz FFT bins
5292  * @psoc: Pointer to psoc object
5293  * @evt_buf: Event buffer
5294  * @param: FFT bin start and end indices
5295  *
5296  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
5297  * and secondary 80 MHz FFT bins
5298  *
5299  * Return: QDF_STATUS
5300  */
5301 static QDF_STATUS
5302 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
5303 			struct wlan_objmgr_psoc *psoc,
5304 			uint8_t *evt_buf,
5305 			struct spectral_fft_bin_markers_160_165mhz *param)
5306 {
5307 	wmi_unified_t wmi_handle;
5308 	struct target_if_psoc_spectral *psoc_spectral;
5309 
5310 	if (!psoc) {
5311 		spectral_err("psoc is null");
5312 		return QDF_STATUS_E_INVAL;
5313 	}
5314 
5315 	if (!evt_buf) {
5316 		spectral_err("WMI event buffer is null");
5317 		return QDF_STATUS_E_INVAL;
5318 	}
5319 
5320 	if (!param) {
5321 		spectral_err("Spectral FFT bin markers is null");
5322 		return QDF_STATUS_E_INVAL;
5323 	}
5324 
5325 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5326 	if (!wmi_handle) {
5327 		spectral_err("WMI handle is null");
5328 		return QDF_STATUS_E_INVAL;
5329 	}
5330 
5331 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5332 	if (!psoc_spectral) {
5333 		spectral_err("spectral object is null");
5334 		return QDF_STATUS_E_FAILURE;
5335 	}
5336 
5337 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fft_bin_index(
5338 			wmi_handle, evt_buf, param);
5339 }
5340 
5341 /**
5342  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
5343  * object from scn handle
5344  * @scn: scn handle
5345  *
5346  * Wrapper function to get psoc object from scn handle
5347  *
5348  * Return: Pointer to psoc object
5349  */
5350 static struct wlan_objmgr_psoc *
5351 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
5352 {
5353 	if (!scn) {
5354 		spectral_err("scn is null");
5355 		return NULL;
5356 	}
5357 
5358 	return ops_tgt.tgt_get_psoc_from_scn_hdl(scn);
5359 }
5360 #else
5361 /**
5362  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
5363  * register WMI event handler
5364  * @psoc: Pointer to psoc object
5365  * @event_id: Event id
5366  * @handler_func: Handler function
5367  * @rx_ctx: Context of WMI event processing
5368  *
5369  * Wrapper function to register WMI event handler
5370  *
5371  * Return: 0 for success else failure
5372  */
5373 static int
5374 target_if_spectral_wmi_unified_register_event_handler(
5375 				struct wlan_objmgr_psoc *psoc,
5376 				wmi_conv_event_id event_id,
5377 				wmi_unified_event_handler handler_func,
5378 				uint8_t rx_ctx)
5379 {
5380 	wmi_unified_t wmi_handle;
5381 	QDF_STATUS ret;
5382 
5383 	if (!psoc) {
5384 		spectral_err("psoc is null");
5385 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5386 	}
5387 
5388 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5389 	if (!wmi_handle) {
5390 		spectral_err("WMI handle is null");
5391 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5392 	}
5393 
5394 	ret = wmi_unified_register_event_handler(wmi_handle, event_id,
5395 						 handler_func, rx_ctx);
5396 
5397 	return qdf_status_to_os_return(ret);
5398 }
5399 
5400 /**
5401  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
5402  * to unregister WMI event handler
5403  * @psoc: Pointer to psoc object
5404  * @event_id: Event id
5405  *
5406  * Wrapper function to unregister WMI event handler
5407  *
5408  * Return: 0 for success else failure
5409  */
5410 static int
5411 target_if_spectral_wmi_unified_unregister_event_handler(
5412 				struct wlan_objmgr_psoc *psoc,
5413 				wmi_conv_event_id event_id)
5414 {
5415 	wmi_unified_t wmi_handle;
5416 	QDF_STATUS ret;
5417 
5418 	if (!psoc) {
5419 		spectral_err("psoc is null");
5420 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5421 	}
5422 
5423 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5424 	if (!wmi_handle) {
5425 		spectral_err("WMI handle is null");
5426 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5427 	}
5428 
5429 	ret = wmi_unified_unregister_event_handler(wmi_handle, event_id);
5430 
5431 	return qdf_status_to_os_return(ret);
5432 }
5433 
5434 /**
5435  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
5436  * function to extract fixed parameters from start scan response event
5437  * @psoc: Pointer to psoc object
5438  * @evt_buf: Event buffer
5439  * @param: Start scan response parameters
5440  *
5441  * Wrapper function to extract fixed parameters from start scan response event
5442  *
5443  * Return: QDF_STATUS
5444  */
5445 static QDF_STATUS
5446 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5447 			struct wlan_objmgr_psoc *psoc,
5448 			uint8_t *evt_buf,
5449 			struct spectral_startscan_resp_params *param)
5450 {
5451 	wmi_unified_t wmi_handle;
5452 
5453 	if (!psoc) {
5454 		spectral_err("psoc is null");
5455 		return QDF_STATUS_E_INVAL;
5456 	}
5457 
5458 	if (!evt_buf) {
5459 		spectral_err("WMI event buffer is null");
5460 		return QDF_STATUS_E_INVAL;
5461 	}
5462 
5463 	if (!param) {
5464 		spectral_err("Spectral startscan response parameters is null");
5465 		return QDF_STATUS_E_INVAL;
5466 	}
5467 
5468 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5469 	if (!wmi_handle) {
5470 		spectral_err("WMI handle is null");
5471 		return QDF_STATUS_E_INVAL;
5472 	}
5473 
5474 	return wmi_extract_pdev_sscan_fw_cmd_fixed_param(wmi_handle, evt_buf,
5475 							 param);
5476 }
5477 
5478 /**
5479  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
5480  * function to extract start and end indices of primary 80 MHz, 5 MHz and
5481  * secondary 80 MHz FFT bins
5482  * @psoc: Pointer to psoc object
5483  * @evt_buf: Event buffer
5484  * @param: FFT bin start and end indices
5485  *
5486  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
5487  * and secondary 80 MHz FFT bins
5488  *
5489  * Return: QDF_STATUS
5490  */
5491 static QDF_STATUS
5492 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
5493 			struct wlan_objmgr_psoc *psoc,
5494 			uint8_t *evt_buf,
5495 			struct spectral_fft_bin_markers_160_165mhz *param)
5496 {
5497 	wmi_unified_t wmi_handle;
5498 
5499 	if (!psoc) {
5500 		spectral_err("psoc is null");
5501 		return QDF_STATUS_E_INVAL;
5502 	}
5503 
5504 	if (!evt_buf) {
5505 		spectral_err("WMI event buffer is null");
5506 		return QDF_STATUS_E_INVAL;
5507 	}
5508 
5509 	if (!param) {
5510 		spectral_err("Spectral FFT bin markers is null");
5511 		return QDF_STATUS_E_INVAL;
5512 	}
5513 
5514 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5515 	if (!wmi_handle) {
5516 		spectral_err("WMI handle is null");
5517 		return QDF_STATUS_E_INVAL;
5518 	}
5519 
5520 	return wmi_extract_pdev_sscan_fft_bin_index(wmi_handle, evt_buf, param);
5521 }
5522 
5523 /**
5524  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
5525  * object from scn handle
5526  * @scn: scn handle
5527  *
5528  * Wrapper function to get psoc object from scn handle
5529  *
5530  * Return: Pointer to psoc object
5531  */
5532 static struct wlan_objmgr_psoc *
5533 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
5534 {
5535 	if (!scn) {
5536 		spectral_err("scn is null");
5537 		return NULL;
5538 	}
5539 
5540 	return target_if_get_psoc_from_scn_hdl(scn);
5541 }
5542 #endif
5543 
5544 /**
5545  * target_if_spectral_fw_param_event_handler() - WMI event handler to
5546  * process start scan response event
5547  * @scn: Pointer to scn object
5548  * @data_buf: Pointer to event buffer
5549  * @data_len: Length of event buffer
5550  *
5551  * Return: 0 for success, else failure
5552  */
5553 static int
5554 target_if_spectral_fw_param_event_handler(ol_scn_t scn, uint8_t *data_buf,
5555 					  uint32_t data_len)
5556 {
5557 	QDF_STATUS status;
5558 	struct wlan_objmgr_psoc *psoc;
5559 	struct wlan_objmgr_pdev *pdev;
5560 	struct wmi_unified *wmi_handle;
5561 	struct spectral_startscan_resp_params event_params = {0};
5562 	struct target_if_psoc_spectral *psoc_spectral;
5563 	struct target_if_spectral *spectral;
5564 
5565 	if (!scn) {
5566 		spectral_err("scn handle is null");
5567 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5568 	}
5569 
5570 	if (!data_buf) {
5571 		spectral_err("WMI event buffer null");
5572 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5573 	}
5574 
5575 	psoc = target_if_spectral_get_psoc_from_scn_handle(scn);
5576 	if (!psoc) {
5577 		spectral_err("psoc is null");
5578 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5579 	}
5580 
5581 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5582 	if (!psoc_spectral) {
5583 		spectral_err("spectral object is null");
5584 		return QDF_STATUS_E_FAILURE;
5585 	}
5586 
5587 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5588 	if (!wmi_handle) {
5589 		spectral_err("WMI handle is null");
5590 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5591 	}
5592 
5593 	status = target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5594 				psoc, data_buf, &event_params);
5595 	if (QDF_IS_STATUS_ERROR(status)) {
5596 		spectral_err("unable to extract sscan fw fixed params");
5597 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5598 	}
5599 
5600 	pdev = wlan_objmgr_get_pdev_by_id(psoc, event_params.pdev_id,
5601 					  WLAN_SPECTRAL_ID);
5602 	if (!pdev) {
5603 		spectral_err("pdev is null");
5604 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5605 	}
5606 
5607 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5608 	if (!spectral) {
5609 		spectral_err("spectral object is null");
5610 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
5611 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5612 	}
5613 
5614 	if (event_params.num_fft_bin_index == 1) {
5615 		status =
5616 			target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
5617 				psoc, data_buf,
5618 				&spectral->rparams.marker[event_params.smode]);
5619 		if (QDF_IS_STATUS_ERROR(status)) {
5620 			spectral_err("unable to extract sscan fw fixed params");
5621 			wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
5622 			return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5623 		}
5624 	} else {
5625 		spectral->rparams.marker[event_params.smode].is_valid = false;
5626 	}
5627 
5628 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
5629 
5630 	return qdf_status_to_os_return(QDF_STATUS_SUCCESS);
5631 }
5632 
5633 static QDF_STATUS
5634 target_if_spectral_register_events(struct wlan_objmgr_psoc *psoc)
5635 {
5636 	int ret;
5637 
5638 	if (!psoc) {
5639 		spectral_err("psoc is null");
5640 		return QDF_STATUS_E_INVAL;
5641 	}
5642 
5643 	ret = target_if_spectral_wmi_unified_register_event_handler(
5644 			psoc,
5645 			wmi_pdev_sscan_fw_param_eventid,
5646 			target_if_spectral_fw_param_event_handler,
5647 			WMI_RX_UMAC_CTX);
5648 
5649 	if (ret)
5650 		spectral_debug("event handler not supported, ret=%d", ret);
5651 
5652 	return QDF_STATUS_SUCCESS;
5653 }
5654 
5655 static QDF_STATUS
5656 target_if_spectral_unregister_events(struct wlan_objmgr_psoc *psoc)
5657 {
5658 	int ret;
5659 
5660 	if (!psoc) {
5661 		spectral_err("psoc is null");
5662 		return QDF_STATUS_E_INVAL;
5663 	}
5664 
5665 	ret = target_if_spectral_wmi_unified_unregister_event_handler(
5666 			psoc, wmi_pdev_sscan_fw_param_eventid);
5667 
5668 	if (ret)
5669 		spectral_debug("Unregister WMI event handler failed, ret = %d",
5670 			       ret);
5671 
5672 	return QDF_STATUS_SUCCESS;
5673 }
5674 
5675 void
5676 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
5677 {
5678 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
5679 	    target_if_pdev_spectral_init;
5680 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
5681 	    target_if_pdev_spectral_deinit;
5682 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_init =
5683 	    target_if_psoc_spectral_init;
5684 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_deinit =
5685 	    target_if_psoc_spectral_deinit;
5686 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
5687 	    target_if_set_spectral_config;
5688 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
5689 	    target_if_get_spectral_config;
5690 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
5691 	    target_if_start_spectral_scan;
5692 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
5693 	    target_if_stop_spectral_scan;
5694 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
5695 	    target_if_is_spectral_active;
5696 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
5697 	    target_if_is_spectral_enabled;
5698 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
5699 	    target_if_set_debug_level;
5700 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
5701 	    target_if_get_debug_level;
5702 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
5703 	    target_if_get_spectral_capinfo;
5704 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
5705 	    target_if_get_spectral_diagstats;
5706 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_wmi_ops =
5707 	    target_if_register_spectral_wmi_ops;
5708 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_tgt_ops =
5709 	    target_if_register_spectral_tgt_ops;
5710 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
5711 	    target_if_register_netlink_cb;
5712 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
5713 	    target_if_use_nl_bcast;
5714 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
5715 	    target_if_deregister_netlink_cb;
5716 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
5717 	    target_if_process_spectral_report;
5718 	tx_ops->sptrl_tx_ops.sptrlto_direct_dma_support =
5719 		target_if_spectral_direct_dma_support;
5720 	tx_ops->sptrl_tx_ops.sptrlto_register_events =
5721 		target_if_spectral_register_events;
5722 	tx_ops->sptrl_tx_ops.sptrlto_unregister_events =
5723 		target_if_spectral_unregister_events;
5724 
5725 	target_if_sptrl_debug_register_tx_ops(tx_ops);
5726 }
5727 qdf_export_symbol(target_if_sptrl_register_tx_ops);
5728 
5729 void
5730 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
5731 				       uint16_t cw_int, uint32_t dcs_enabled)
5732 {
5733 	struct spectral_samp_msg *msg = NULL;
5734 	struct target_if_spectral_ops *p_sops = NULL;
5735 	struct target_if_spectral *spectral = NULL;
5736 
5737 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5738 
5739 	if (!spectral) {
5740 		spectral_err("SPECTRAL : Module doesn't exist");
5741 		return;
5742 	}
5743 
5744 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5745 	if (!p_sops) {
5746 		spectral_err("p_sops is null");
5747 		return;
5748 	}
5749 
5750 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_sbuff(
5751 			spectral->pdev_obj,
5752 			SPECTRAL_MSG_INTERFERENCE_NOTIFICATION,
5753 			SPECTRAL_MSG_BUF_NEW);
5754 
5755 	if (msg) {
5756 		msg->int_type = cw_int ?
5757 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
5758 		msg->dcs_enabled = dcs_enabled;
5759 		msg->signature = SPECTRAL_SIGNATURE;
5760 		p_sops->get_mac_address(spectral, msg->macaddr);
5761 		if (spectral->send_phy_data
5762 				(pdev,
5763 				 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION) == 0)
5764 			spectral->spectral_sent_msg++;
5765 	}
5766 }
5767 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
5768 
5769 QDF_STATUS
5770 target_if_spectral_is_finite_scan(struct target_if_spectral *spectral,
5771 				  enum spectral_scan_mode smode,
5772 				  bool *finite_spectral_scan)
5773 {
5774 	struct target_if_finite_spectral_scan_params *finite_scan;
5775 
5776 	if (!spectral) {
5777 		spectral_err_rl("target if spectral object is null");
5778 		return QDF_STATUS_E_INVAL;
5779 	}
5780 
5781 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5782 		spectral_err_rl("invalid spectral mode %d", smode);
5783 		return QDF_STATUS_E_INVAL;
5784 	}
5785 
5786 	if (!finite_spectral_scan) {
5787 		spectral_err_rl("Invalid pointer");
5788 		return QDF_STATUS_E_INVAL;
5789 	}
5790 
5791 	finite_scan = &spectral->finite_scan[smode];
5792 	*finite_spectral_scan = finite_scan->finite_spectral_scan;
5793 
5794 	return QDF_STATUS_SUCCESS;
5795 }
5796 
5797 QDF_STATUS
5798 target_if_spectral_finite_scan_update(struct target_if_spectral *spectral,
5799 				      enum spectral_scan_mode smode)
5800 {
5801 	struct target_if_finite_spectral_scan_params *finite_scan;
5802 
5803 	if (!spectral) {
5804 		spectral_err_rl("target if spectral object is null");
5805 		return QDF_STATUS_E_INVAL;
5806 	}
5807 
5808 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5809 		spectral_err_rl("Invalid Spectral mode");
5810 		return QDF_STATUS_E_INVAL;
5811 	}
5812 
5813 	finite_scan = &spectral->finite_scan[smode];
5814 
5815 	if (!finite_scan->num_reports_expected) {
5816 		spectral_err_rl("Error, No reports expected");
5817 		return QDF_STATUS_E_FAILURE;
5818 	}
5819 
5820 	finite_scan->num_reports_expected--;
5821 	if (!finite_scan->num_reports_expected) {
5822 		QDF_STATUS status;
5823 		enum spectral_cp_error_code err;
5824 
5825 		/* received expected number of reports from target, stop scan */
5826 		status = target_if_stop_spectral_scan(spectral->pdev_obj, smode,
5827 						      &err);
5828 		if (QDF_IS_STATUS_ERROR(status)) {
5829 			spectral_err_rl("Failed to stop finite Spectral scan");
5830 			return QDF_STATUS_E_FAILURE;
5831 		}
5832 		finite_scan->finite_spectral_scan =  false;
5833 	}
5834 
5835 	return QDF_STATUS_SUCCESS;
5836 }
5837