xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision d57e7836dc389f88871517cfeedfdd0f572e4b31)
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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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_QCA5018 ||
1421 		    target_type == TARGET_TYPE_QCA6490) {
1422 			param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
1423 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1424 			param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
1425 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1426 			param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
1427 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1428 			param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
1429 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_QCN9000;
1430 		} else {
1431 			param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
1432 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1433 			param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
1434 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1435 			param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
1436 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1437 			param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
1438 				SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3_DEFAULT;
1439 		}
1440 		break;
1441 
1442 	case SPECTRAL_GEN2:
1443 		param_min_max->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN2;
1444 		param_min_max->fft_size_max[CH_WIDTH_20MHZ] =
1445 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1446 		param_min_max->fft_size_max[CH_WIDTH_40MHZ] =
1447 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1448 		param_min_max->fft_size_max[CH_WIDTH_80MHZ] =
1449 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1450 		param_min_max->fft_size_max[CH_WIDTH_80P80MHZ] =
1451 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1452 		param_min_max->fft_size_max[CH_WIDTH_160MHZ] =
1453 					SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
1454 		break;
1455 
1456 	default:
1457 		spectral_err("Invalid spectral generation %d", gen);
1458 		return QDF_STATUS_E_INVAL;
1459 	}
1460 
1461 	return QDF_STATUS_SUCCESS;
1462 }
1463 
1464 /**
1465  * target_if_init_spectral_param_properties() - Initialize Spectral parameter
1466  *                                              properties
1467  * @spectral: Pointer to Spectral target_if internal private data
1468  *
1469  * Initialize Spectral parameter properties
1470  *
1471  * Return: QDF_STATUS
1472  */
1473 static QDF_STATUS
1474 target_if_init_spectral_param_properties(struct target_if_spectral *spectral)
1475 {
1476 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1477 	int param;
1478 
1479 	/* Initialize default values for properties.
1480 	 * Default values are supported for all the parameters for all modes
1481 	 * and allows different values for each mode for all the parameters .
1482 	 */
1483 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
1484 		for (param = 0; param < SPECTRAL_PARAM_MAX; param++) {
1485 			spectral->properties[smode][param].supported = true;
1486 			spectral->properties[smode][param].common_all_modes =
1487 									false;
1488 		}
1489 	}
1490 
1491 	/* Once FW advertisement is in place remove this hard coding */
1492 	smode = SPECTRAL_SCAN_MODE_NORMAL;
1493 	spectral->properties[SPECTRAL_SCAN_MODE_NORMAL]
1494 			[SPECTRAL_PARAM_FREQUENCY].supported = false;
1495 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
1496 		spectral->properties[smode]
1497 			[SPECTRAL_PARAM_SPECT_PRI].common_all_modes = true;
1498 		spectral->properties[smode]
1499 			[SPECTRAL_PARAM_SCAN_PERIOD].common_all_modes = true;
1500 		spectral->properties[smode]
1501 			[SPECTRAL_PARAM_INIT_DELAY].common_all_modes = true;
1502 	}
1503 
1504 	return QDF_STATUS_SUCCESS;
1505 }
1506 
1507 QDF_STATUS
1508 target_if_init_spectral_capability(struct target_if_spectral *spectral,
1509 				   uint32_t target_type)
1510 {
1511 	struct wlan_objmgr_psoc *psoc;
1512 	struct wlan_objmgr_pdev *pdev;
1513 	struct wlan_psoc_host_spectral_scaling_params *scaling_params;
1514 	uint8_t num_bin_scaling_params, param_idx, pdev_id;
1515 	struct target_psoc_info *tgt_psoc_info;
1516 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
1517 	struct spectral_caps *pcap = &spectral->capability;
1518 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr = NULL;
1519 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = NULL;
1520 	struct wlan_psoc_host_chainmask_table *table;
1521 	int j;
1522 	uint32_t table_id;
1523 
1524 	pdev = spectral->pdev_obj;
1525 	psoc = wlan_pdev_get_psoc(pdev);
1526 	if (!psoc) {
1527 		spectral_err("psoc is null");
1528 		return QDF_STATUS_E_FAILURE;
1529 	}
1530 
1531 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
1532 	if (!tgt_psoc_info) {
1533 		spectral_err("target_psoc_info is null");
1534 		return QDF_STATUS_E_FAILURE;
1535 	}
1536 
1537 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
1538 	num_bin_scaling_params = ext_svc_param->num_bin_scaling_params;
1539 	scaling_params = target_psoc_get_spectral_scaling_params(tgt_psoc_info);
1540 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1541 
1542 	/* XXX : Workaround: Set Spectral capability */
1543 	pcap = &spectral->capability;
1544 	pcap->phydiag_cap = 1;
1545 	pcap->radar_cap = 1;
1546 	pcap->spectral_cap = 1;
1547 	pcap->advncd_spectral_cap = 1;
1548 	pcap->hw_gen = spectral->spectral_gen;
1549 	if (spectral->spectral_gen >= SPECTRAL_GEN3) {
1550 		mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
1551 		if (!mac_phy_cap_arr) {
1552 			spectral_err("mac phy cap array is null");
1553 			return QDF_STATUS_E_FAILURE;
1554 		}
1555 
1556 		mac_phy_cap = &mac_phy_cap_arr[pdev_id];
1557 		if (!mac_phy_cap) {
1558 			spectral_err("mac phy cap is null");
1559 			return QDF_STATUS_E_FAILURE;
1560 		}
1561 
1562 		table_id = mac_phy_cap->chainmask_table_id;
1563 		table =  &ext_svc_param->chainmask_table[table_id];
1564 		if (!table) {
1565 			spectral_err("chainmask table not found");
1566 			return QDF_STATUS_E_FAILURE;
1567 		}
1568 
1569 		for (j = 0; j < table->num_valid_chainmasks; j++) {
1570 			pcap->agile_spectral_cap |=
1571 				table->cap_list[j].supports_aSpectral;
1572 			pcap->agile_spectral_cap_160 |=
1573 				table->cap_list[j].supports_aSpectral_160;
1574 		}
1575 		pcap->agile_spectral_cap_80p80 = pcap->agile_spectral_cap_160;
1576 	} else {
1577 		pcap->agile_spectral_cap = false;
1578 		pcap->agile_spectral_cap_160 = false;
1579 		pcap->agile_spectral_cap_80p80 = false;
1580 	}
1581 
1582 	if (scaling_params) {
1583 		for (param_idx = 0; param_idx < num_bin_scaling_params;
1584 		     param_idx++) {
1585 			if (scaling_params[param_idx].pdev_id == pdev_id) {
1586 				pcap->is_scaling_params_populated = true;
1587 				pcap->formula_id =
1588 				    scaling_params[param_idx].formula_id;
1589 				pcap->low_level_offset =
1590 				    scaling_params[param_idx].low_level_offset;
1591 				pcap->high_level_offset =
1592 				    scaling_params[param_idx].high_level_offset;
1593 				pcap->rssi_thr =
1594 				    scaling_params[param_idx].rssi_thr;
1595 				pcap->default_agc_max_gain =
1596 				 scaling_params[param_idx].default_agc_max_gain;
1597 				break;
1598 			}
1599 		}
1600 	}
1601 
1602 	pcap->num_detectors_20mhz = 1;
1603 	pcap->num_detectors_40mhz = 1;
1604 	pcap->num_detectors_80mhz = 1;
1605 	if (target_type == TARGET_TYPE_QCN9000 ||
1606 	    target_type == TARGET_TYPE_QCA6490) {
1607 		pcap->num_detectors_160mhz = 1;
1608 		pcap->num_detectors_80p80mhz = 1;
1609 	} else {
1610 		pcap->num_detectors_160mhz = 2;
1611 		pcap->num_detectors_80p80mhz = 2;
1612 	}
1613 
1614 	return QDF_STATUS_SUCCESS;
1615 }
1616 
1617 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1618 /**
1619  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1620  * internal operations with functions related to spectral simulation
1621  * @p_sops: spectral low level ops table
1622  *
1623  * Initialize spectral target_if internal operations with functions
1624  * related to spectral simulation
1625  *
1626  * Return: None
1627  */
1628 static void
1629 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1630 {
1631 	/*
1632 	 * Spectral simulation is currently intended for platform transitions
1633 	 * where underlying HW support may not be available for some time.
1634 	 * Hence, we do not currently provide a runtime switch to turn the
1635 	 * simulation on or off.
1636 	 * In case of future requirements where runtime switches are required,
1637 	 * this can be added. But it is suggested to use application layer
1638 	 * simulation as far as possible in such cases, since the main
1639 	 * use of record and replay of samples would concern higher
1640 	 * level sample processing rather than lower level delivery.
1641 	 */
1642 	p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled;
1643 	p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active;
1644 	p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan;
1645 	p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan;
1646 	p_sops->configure_spectral =
1647 		target_if_spectral_sops_sim_configure_params;
1648 	p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params;
1649 }
1650 
1651 #else
1652 /**
1653  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1654  * internal operations
1655  * @p_sops: spectral low level ops table
1656  *
1657  * Return: None
1658  */
1659 static void
1660 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1661 {
1662 	p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled;
1663 	p_sops->is_spectral_active = target_if_sops_is_spectral_active;
1664 	p_sops->start_spectral_scan = target_if_sops_start_spectral_scan;
1665 	p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan;
1666 	p_sops->configure_spectral = target_if_spectral_sops_configure_params;
1667 	p_sops->get_spectral_config = target_if_spectral_sops_get_params;
1668 }
1669 #endif
1670 
1671 /**
1672  * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
1673  * operations common to all Spectral chipset generations
1674  *
1675  * Initializes target_if_spectral_ops common to all chipset generations
1676  *
1677  * Return: None
1678  */
1679 static void
1680 target_if_init_spectral_ops_common(void)
1681 {
1682 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1683 
1684 	p_sops->get_tsf64 = target_if_spectral_get_tsf64;
1685 	p_sops->get_capability = target_if_spectral_get_capability;
1686 	p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
1687 	p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
1688 
1689 	target_if_init_spectral_simulation_ops(p_sops);
1690 
1691 	p_sops->get_extension_channel =
1692 	    target_if_spectral_get_extension_channel;
1693 	p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor;
1694 	p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor;
1695 	p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
1696 	p_sops->get_mac_address = target_if_spectral_get_macaddr;
1697 	p_sops->get_current_channel = target_if_spectral_get_current_channel;
1698 	p_sops->reset_hw = target_if_spectral_reset_hw;
1699 	p_sops->get_chain_noise_floor =
1700 	    target_if_spectral_get_chain_noise_floor;
1701 }
1702 
1703 /**
1704  * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
1705  * operations specific to Spectral chipset generation 2.
1706  *
1707  * Initializes target_if_spectral_ops specific to Spectral chipset generation 2.
1708  *
1709  * Return: None
1710  */
1711 static void
1712 target_if_init_spectral_ops_gen2(void)
1713 {
1714 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1715 
1716 	p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2;
1717 }
1718 
1719 /**
1720  * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
1721  * operations specific to Spectral chipset generation 3.
1722  *
1723  * Initializes target_if_spectral_ops specific to Spectral chipset generation 3.
1724  *
1725  * Return: None
1726  */
1727 static void
1728 target_if_init_spectral_ops_gen3(void)
1729 {
1730 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1731 
1732 	p_sops->process_spectral_report =
1733 			target_if_spectral_process_report_gen3;
1734 	return;
1735 }
1736 
1737 /**
1738  * target_if_init_spectral_ops() - Initialize target_if internal Spectral
1739  * operations.
1740  * @spectral: Pointer to Spectral target_if internal private data
1741  *
1742  * Initializes all function pointers in target_if_spectral_ops for
1743  * all generations
1744  *
1745  * Return: None
1746  */
1747 static void
1748 target_if_init_spectral_ops(struct target_if_spectral *spectral)
1749 {
1750 	target_if_init_spectral_ops_common();
1751 	if (spectral->spectral_gen == SPECTRAL_GEN2)
1752 		target_if_init_spectral_ops_gen2();
1753 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
1754 		target_if_init_spectral_ops_gen3();
1755 	else
1756 		spectral_err("Invalid Spectral generation");
1757 }
1758 
1759 /*
1760  * Dummy Functions:
1761  * These functions are initially registered to avoid any crashes due to
1762  * invocation of spectral functions before they are registered.
1763  */
1764 
1765 static uint64_t
1766 null_get_tsf64(void *arg)
1767 {
1768 	spectral_ops_not_registered("get_tsf64");
1769 	return 0;
1770 }
1771 
1772 static uint32_t
1773 null_get_capability(void *arg, enum spectral_capability_type type)
1774 {
1775 	/*
1776 	 * TODO : We should have conditional compilation to get the capability
1777 	 *      : We have not yet attahced ATH layer here, so there is no
1778 	 *      : way to check the HAL capbalities
1779 	 */
1780 	spectral_ops_not_registered("get_capability");
1781 
1782 	/* TODO : For the time being, we are returning TRUE */
1783 	return true;
1784 }
1785 
1786 static uint32_t
1787 null_set_rxfilter(void *arg, int rxfilter)
1788 {
1789 	spectral_ops_not_registered("set_rxfilter");
1790 	return 1;
1791 }
1792 
1793 static uint32_t
1794 null_get_rxfilter(void *arg)
1795 {
1796 	spectral_ops_not_registered("get_rxfilter");
1797 	return 0;
1798 }
1799 
1800 static uint32_t
1801 null_is_spectral_active(void *arg, enum spectral_scan_mode smode)
1802 {
1803 	spectral_ops_not_registered("is_spectral_active");
1804 	return 1;
1805 }
1806 
1807 static uint32_t
1808 null_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
1809 {
1810 	spectral_ops_not_registered("is_spectral_enabled");
1811 	return 1;
1812 }
1813 
1814 static uint32_t
1815 null_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
1816 			 enum spectral_cp_error_code *err)
1817 {
1818 	spectral_ops_not_registered("start_spectral_scan");
1819 	return 1;
1820 }
1821 
1822 static uint32_t
1823 null_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
1824 {
1825 	spectral_ops_not_registered("stop_spectral_scan");
1826 	return 1;
1827 }
1828 
1829 static uint32_t
1830 null_get_extension_channel(void *arg, enum spectral_scan_mode smode)
1831 {
1832 	spectral_ops_not_registered("get_extension_channel");
1833 	return 1;
1834 }
1835 
1836 static int8_t
1837 null_get_ctl_noisefloor(void *arg)
1838 {
1839 	spectral_ops_not_registered("get_ctl_noisefloor");
1840 	return 1;
1841 }
1842 
1843 static int8_t
1844 null_get_ext_noisefloor(void *arg)
1845 {
1846 	spectral_ops_not_registered("get_ext_noisefloor");
1847 	return 0;
1848 }
1849 
1850 static uint32_t
1851 null_configure_spectral(void *arg, struct spectral_config *params,
1852 			enum spectral_scan_mode smode)
1853 {
1854 	spectral_ops_not_registered("configure_spectral");
1855 	return 0;
1856 }
1857 
1858 static uint32_t
1859 null_get_spectral_config(void *arg, struct spectral_config *params,
1860 			 enum spectral_scan_mode smode)
1861 {
1862 	spectral_ops_not_registered("get_spectral_config");
1863 	return 0;
1864 }
1865 
1866 static uint32_t
1867 null_get_ent_spectral_mask(void *arg)
1868 {
1869 	spectral_ops_not_registered("get_ent_spectral_mask");
1870 	return 0;
1871 }
1872 
1873 static uint32_t
1874 null_get_mac_address(void *arg, char *addr)
1875 {
1876 	spectral_ops_not_registered("get_mac_address");
1877 	return 0;
1878 }
1879 
1880 static uint32_t
1881 null_get_current_channel(void *arg, enum spectral_scan_mode smode)
1882 {
1883 	spectral_ops_not_registered("get_current_channel");
1884 	return 0;
1885 }
1886 
1887 static uint32_t
1888 null_reset_hw(void *arg)
1889 {
1890 	spectral_ops_not_registered("get_current_channel");
1891 	return 0;
1892 }
1893 
1894 static uint32_t
1895 null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1896 {
1897 	spectral_ops_not_registered("get_chain_noise_floor");
1898 	return 0;
1899 }
1900 
1901 static int
1902 null_spectral_process_phyerr(struct target_if_spectral *spectral,
1903 			     uint8_t *data,
1904 			     uint32_t datalen,
1905 			     struct target_if_spectral_rfqual_info *p_rfqual,
1906 			     struct target_if_spectral_chan_info *p_chaninfo,
1907 			     uint64_t tsf64,
1908 			     struct target_if_spectral_acs_stats *acs_stats)
1909 {
1910 	spectral_ops_not_registered("spectral_process_phyerr");
1911 	return 0;
1912 }
1913 
1914 static int
1915 null_process_spectral_report(struct wlan_objmgr_pdev *pdev,
1916 			     void *payload)
1917 {
1918 	spectral_ops_not_registered("process_spectral_report");
1919 	return 0;
1920 }
1921 /**
1922  * target_if_spectral_init_dummy_function_table() -
1923  * Initialize target_if internal
1924  * Spectral operations to dummy functions
1925  * @ps: Pointer to Spectral target_if internal private data
1926  *
1927  * Initialize all the function pointers in target_if_spectral_ops with
1928  * dummy functions.
1929  *
1930  * Return: None
1931  */
1932 static void
1933 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps)
1934 {
1935 	struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps);
1936 
1937 	p_sops->get_tsf64 = null_get_tsf64;
1938 	p_sops->get_capability = null_get_capability;
1939 	p_sops->set_rxfilter = null_set_rxfilter;
1940 	p_sops->get_rxfilter = null_get_rxfilter;
1941 	p_sops->is_spectral_enabled = null_is_spectral_enabled;
1942 	p_sops->is_spectral_active = null_is_spectral_active;
1943 	p_sops->start_spectral_scan = null_start_spectral_scan;
1944 	p_sops->stop_spectral_scan = null_stop_spectral_scan;
1945 	p_sops->get_extension_channel = null_get_extension_channel;
1946 	p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
1947 	p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
1948 	p_sops->configure_spectral = null_configure_spectral;
1949 	p_sops->get_spectral_config = null_get_spectral_config;
1950 	p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
1951 	p_sops->get_mac_address = null_get_mac_address;
1952 	p_sops->get_current_channel = null_get_current_channel;
1953 	p_sops->reset_hw = null_reset_hw;
1954 	p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
1955 	p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
1956 	p_sops->process_spectral_report = null_process_spectral_report;
1957 }
1958 
1959 /**
1960  * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
1961  * operations
1962  * @spectral: Pointer to Spectral target_if internal private data
1963  * @p: Pointer to Spectral function table
1964  *
1965  * Return: None
1966  */
1967 static void
1968 target_if_spectral_register_funcs(struct target_if_spectral *spectral,
1969 				  struct target_if_spectral_ops *p)
1970 {
1971 	struct target_if_spectral_ops *p_sops =
1972 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1973 
1974 	p_sops->get_tsf64 = p->get_tsf64;
1975 	p_sops->get_capability = p->get_capability;
1976 	p_sops->set_rxfilter = p->set_rxfilter;
1977 	p_sops->get_rxfilter = p->get_rxfilter;
1978 	p_sops->is_spectral_enabled = p->is_spectral_enabled;
1979 	p_sops->is_spectral_active = p->is_spectral_active;
1980 	p_sops->start_spectral_scan = p->start_spectral_scan;
1981 	p_sops->stop_spectral_scan = p->stop_spectral_scan;
1982 	p_sops->get_extension_channel = p->get_extension_channel;
1983 	p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor;
1984 	p_sops->get_ext_noisefloor = p->get_ext_noisefloor;
1985 	p_sops->configure_spectral = p->configure_spectral;
1986 	p_sops->get_spectral_config = p->get_spectral_config;
1987 	p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask;
1988 	p_sops->get_mac_address = p->get_mac_address;
1989 	p_sops->get_current_channel = p->get_current_channel;
1990 	p_sops->reset_hw = p->reset_hw;
1991 	p_sops->get_chain_noise_floor = p->get_chain_noise_floor;
1992 	p_sops->spectral_process_phyerr = p->spectral_process_phyerr;
1993 	p_sops->process_spectral_report = p->process_spectral_report;
1994 }
1995 
1996 /**
1997  * target_if_spectral_clear_stats() - Clear Spectral stats
1998  * @spectral: Pointer to Spectral target_if internal private data
1999  *
2000  * Function to clear spectral stats
2001  *
2002  * Return: None
2003  */
2004 static void
2005 target_if_spectral_clear_stats(struct target_if_spectral *spectral)
2006 {
2007 	struct target_if_spectral_ops *p_sops =
2008 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2009 
2010 	qdf_mem_zero(&spectral->spectral_stats,
2011 		     sizeof(struct target_if_spectral_stats));
2012 	spectral->spectral_stats.last_reset_tstamp =
2013 	    p_sops->get_tsf64(spectral);
2014 }
2015 
2016 /**
2017  * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
2018  * @spectral: Pointer to Spectral target_if internal private data
2019  *
2020  * Function to check whether hardware supports spectral
2021  *
2022  * Return: True if HW supports Spectral, false if HW does not support Spectral
2023  */
2024 static int
2025 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
2026 {
2027 	struct target_if_spectral_ops *p_sops = NULL;
2028 	struct spectral_caps *pcap = NULL;
2029 	int is_spectral_supported = true;
2030 
2031 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2032 	pcap = &spectral->capability;
2033 
2034 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
2035 		is_spectral_supported = false;
2036 		spectral_info("SPECTRAL : No PHYDIAG support");
2037 		return is_spectral_supported;
2038 	}
2039 	pcap->phydiag_cap = 1;
2040 
2041 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
2042 		is_spectral_supported = false;
2043 		spectral_info("SPECTRAL : No RADAR support");
2044 		return is_spectral_supported;
2045 	}
2046 	pcap->radar_cap = 1;
2047 
2048 	if (p_sops->get_capability(spectral,
2049 				   SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
2050 		is_spectral_supported = false;
2051 		spectral_info("SPECTRAL : No SPECTRAL SUPPORT");
2052 		return is_spectral_supported;
2053 	}
2054 	pcap->spectral_cap = 1;
2055 
2056 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
2057 	    == false) {
2058 		spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT");
2059 	} else {
2060 		pcap->advncd_spectral_cap = 1;
2061 	}
2062 
2063 	return is_spectral_supported;
2064 }
2065 
2066 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
2067 /**
2068  * target_if_spectral_detach_simulation() - De-initialize Spectral
2069  * Simulation functionality
2070  * @spectral: Pointer to Spectral target_if internal private data
2071  *
2072  * Function to de-initialize Spectral Simulation functionality
2073  *
2074  * Return: None
2075  */
2076 static void
2077 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
2078 {
2079 	target_if_spectral_sim_detach(spectral);
2080 }
2081 
2082 #else
2083 static void
2084 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
2085 {
2086 }
2087 #endif
2088 
2089 /**
2090  * target_if_spectral_detach() - De-initialize target_if Spectral
2091  * @pdev: Pointer to pdev object
2092  *
2093  * Function to detach target_if spectral
2094  *
2095  * Return: None
2096  */
2097 static void
2098 target_if_spectral_detach(struct target_if_spectral *spectral)
2099 {
2100 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
2101 	spectral_info("spectral detach");
2102 
2103 	if (spectral) {
2104 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
2105 			qdf_spinlock_destroy
2106 				(&spectral->param_info[smode].osps_lock);
2107 
2108 		target_if_spectral_detach_simulation(spectral);
2109 
2110 		qdf_spinlock_destroy(&spectral->spectral_lock);
2111 		qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
2112 
2113 		qdf_mem_free(spectral);
2114 		spectral = NULL;
2115 	}
2116 }
2117 
2118 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
2119 /**
2120  * target_if_spectral_attach_simulation() - Initialize Spectral Simulation
2121  * functionality
2122  * @spectral: Pointer to Spectral target_if internal private data
2123  *
2124  * Function to initialize spectral simulation functionality
2125  *
2126  * Return: 0 on success, negative error code on failure
2127  */
2128 static int
2129 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
2130 {
2131 	if (target_if_spectral_sim_attach(spectral)) {
2132 		qdf_mem_free(spectral);
2133 		return -EPERM;
2134 	}
2135 	return 0;
2136 }
2137 
2138 #else
2139 static int
2140 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
2141 {
2142 	return 0;
2143 }
2144 #endif
2145 
2146 /**
2147  * target_if_spectral_len_adj_swar_init() - Initialize FFT bin length adjustment
2148  * related info
2149  * @swar: Pointer to Spectral FFT bin length adjustment SWAR params
2150  * @target_type: Target type
2151  *
2152  * Function to Initialize parameters related to Spectral FFT bin
2153  * length adjustment SWARs.
2154  *
2155  * Return: void
2156  */
2157 static void
2158 target_if_spectral_len_adj_swar_init(struct spectral_fft_bin_len_adj_swar *swar,
2159 				     uint32_t target_type)
2160 {
2161 	if (target_type == TARGET_TYPE_QCA8074V2 ||
2162 	    target_type == TARGET_TYPE_QCN9000 ||
2163 	    target_type == TARGET_TYPE_QCN9100 ||
2164 	    target_type == TARGET_TYPE_QCA5018 ||
2165 	    target_type == TARGET_TYPE_QCA6750 ||
2166 	    target_type == TARGET_TYPE_QCA6490)
2167 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE;
2168 	else if (target_type == TARGET_TYPE_QCA8074 ||
2169 		 target_type == TARGET_TYPE_QCA6018 ||
2170 		 target_type == TARGET_TYPE_QCA6390)
2171 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE;
2172 	else
2173 		swar->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR;
2174 
2175 	if (target_type == TARGET_TYPE_QCA8074 ||
2176 	    target_type == TARGET_TYPE_QCA8074V2 ||
2177 	    target_type == TARGET_TYPE_QCA6018 ||
2178 	    target_type == TARGET_TYPE_QCN9100 ||
2179 	    target_type == TARGET_TYPE_QCA5018 ||
2180 	    target_type == TARGET_TYPE_QCN9000 ||
2181 	    target_type == TARGET_TYPE_QCA6490) {
2182 		swar->inband_fftbin_size_adj = 1;
2183 		swar->null_fftbin_adj = 1;
2184 	} else {
2185 		swar->inband_fftbin_size_adj = 0;
2186 		swar->null_fftbin_adj = 0;
2187 	}
2188 
2189 	if ((target_type == TARGET_TYPE_QCA8074V2) ||
2190 	    (target_type == TARGET_TYPE_QCN9100))
2191 		swar->packmode_fftbin_size_adj = 1;
2192 	else
2193 		swar->packmode_fftbin_size_adj = 0;
2194 }
2195 
2196 /**
2197  * target_if_spectral_report_params_init() - Initialize parameters which
2198  * describes the structure of Spectral reports
2199  *
2200  * @rparams: Pointer to Spectral report parameter object
2201  * @target_type: target type
2202  *
2203  * Function to Initialize parameters related to the structure of Spectral
2204  * reports.
2205  *
2206  * Return: void
2207  */
2208 static void
2209 target_if_spectral_report_params_init(
2210 			struct spectral_report_params *rparams,
2211 			uint32_t target_type)
2212 {
2213 	enum spectral_scan_mode smode;
2214 
2215 	/* This entries are currently used by gen3 chipsets only. Hence
2216 	 * initialization is done for gen3 alone. In future if other generations
2217 	 * needs to use them they have to add proper initial values.
2218 	 */
2219 	if (target_type == TARGET_TYPE_QCN9000 ||
2220 	    target_type == TARGET_TYPE_QCA5018 ||
2221 	    target_type == TARGET_TYPE_QCA6750 ||
2222 	    target_type == TARGET_TYPE_QCA6490) {
2223 		rparams->version = SPECTRAL_REPORT_FORMAT_VERSION_2;
2224 		rparams->num_spectral_detectors =
2225 				NUM_SPECTRAL_DETECTORS_GEN3_V2;
2226 		smode = SPECTRAL_SCAN_MODE_NORMAL;
2227 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
2228 			rparams->fragmentation_160[smode] = false;
2229 		rparams->max_agile_ch_width = CH_WIDTH_80P80MHZ;
2230 	} else {
2231 		rparams->version = SPECTRAL_REPORT_FORMAT_VERSION_1;
2232 		rparams->num_spectral_detectors =
2233 				NUM_SPECTRAL_DETECTORS_GEN3_V1;
2234 		smode = SPECTRAL_SCAN_MODE_NORMAL;
2235 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
2236 			rparams->fragmentation_160[smode] = true;
2237 		rparams->max_agile_ch_width = CH_WIDTH_80MHZ;
2238 	}
2239 
2240 	switch (rparams->version) {
2241 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
2242 		rparams->ssumaary_padding_bytes =
2243 			NUM_PADDING_BYTES_SSCAN_SUMARY_REPORT_GEN3_V1;
2244 		rparams->fft_report_hdr_len =
2245 			FFT_REPORT_HEADER_LENGTH_GEN3_V1;
2246 		break;
2247 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
2248 		rparams->ssumaary_padding_bytes =
2249 			NUM_PADDING_BYTES_SSCAN_SUMARY_REPORT_GEN3_V2;
2250 		rparams->fft_report_hdr_len =
2251 			FFT_REPORT_HEADER_LENGTH_GEN3_V2;
2252 		break;
2253 	default:
2254 		qdf_assert_always(0);
2255 	}
2256 
2257 	rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_0] =
2258 						SPECTRAL_SCAN_MODE_NORMAL;
2259 	if (target_type == TARGET_TYPE_QCN9000 ||
2260 	    target_type == TARGET_TYPE_QCA6490) {
2261 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
2262 						SPECTRAL_SCAN_MODE_AGILE;
2263 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
2264 						SPECTRAL_SCAN_MODE_INVALID;
2265 	} else {
2266 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_1] =
2267 						SPECTRAL_SCAN_MODE_NORMAL;
2268 		rparams->detid_mode_table[SPECTRAL_DETECTOR_ID_2] =
2269 						SPECTRAL_SCAN_MODE_AGILE;
2270 	}
2271 }
2272 
2273 /**
2274  * target_if_spectral_timestamp_war_init() - Initialize Spectral timestamp WAR
2275  * related info
2276  * @twar: Pointer to Spectral timstamp WAR related info
2277  *
2278  * Function to Initialize parameters related to Spectral timestamp WAR
2279  *
2280  * Return: void
2281  */
2282 static void
2283 target_if_spectral_timestamp_war_init(struct spectral_timestamp_war *twar)
2284 {
2285 	enum spectral_scan_mode smode;
2286 
2287 	smode = SPECTRAL_SCAN_MODE_NORMAL;
2288 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2289 		twar->last_fft_timestamp[smode] = 0;
2290 		twar->timestamp_war_offset[smode] = 0;
2291 	}
2292 	twar->target_reset_count = 0;
2293 }
2294 
2295 /**
2296  * target_if_pdev_spectral_init() - Initialize target_if Spectral
2297  * functionality for the given pdev
2298  * @pdev: Pointer to pdev object
2299  *
2300  * Function to initialize pointer to spectral target_if internal private data
2301  *
2302  * Return: On success, pointer to Spectral target_if internal private data, on
2303  * failure, NULL
2304  */
2305 void *
2306 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
2307 {
2308 	struct target_if_spectral_ops *p_sops = NULL;
2309 	struct target_if_spectral *spectral = NULL;
2310 	uint32_t target_type;
2311 	uint32_t target_revision;
2312 	struct wlan_objmgr_psoc *psoc;
2313 	struct wlan_lmac_if_target_tx_ops *tgt_tx_ops;
2314 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
2315 	QDF_STATUS status;
2316 	struct wlan_lmac_if_tx_ops *tx_ops;
2317 
2318 	if (!pdev) {
2319 		spectral_err("SPECTRAL: pdev is NULL!");
2320 		return NULL;
2321 	}
2322 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
2323 			sizeof(struct target_if_spectral));
2324 	if (!spectral)
2325 		return spectral;
2326 
2327 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
2328 	/* Store pdev in Spectral */
2329 	spectral->pdev_obj = pdev;
2330 	spectral->vdev_id[SPECTRAL_SCAN_MODE_NORMAL] = WLAN_INVALID_VDEV_ID;
2331 	spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE] = WLAN_INVALID_VDEV_ID;
2332 
2333 	psoc = wlan_pdev_get_psoc(pdev);
2334 
2335 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
2336 	if (!tx_ops) {
2337 		spectral_err("tx_ops is NULL");
2338 		qdf_mem_free(spectral);
2339 		return NULL;
2340 	}
2341 
2342 	tgt_tx_ops = &tx_ops->target_tx_ops;
2343 
2344 	if (tgt_tx_ops->tgt_get_tgt_type) {
2345 		target_type = tgt_tx_ops->tgt_get_tgt_type(psoc);
2346 	} else {
2347 		qdf_mem_free(spectral);
2348 		return NULL;
2349 	}
2350 
2351 	if (tgt_tx_ops->tgt_get_tgt_revision) {
2352 		target_revision = tgt_tx_ops->tgt_get_tgt_revision(psoc);
2353 	} else {
2354 		qdf_mem_free(spectral);
2355 		return NULL;
2356 	}
2357 
2358 	/* init the function ptr table */
2359 	target_if_spectral_init_dummy_function_table(spectral);
2360 
2361 	/* get spectral function table */
2362 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2363 	/* TODO : Should this be called here of after ath_attach ? */
2364 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
2365 		spectral_info("HAL_CAP_PHYDIAG : Capable");
2366 
2367 	/* TODO: Need to fix the capablity check for RADAR */
2368 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
2369 		spectral_info("HAL_CAP_RADAR   : Capable");
2370 
2371 	/* TODO : Need to fix the capablity check for SPECTRAL */
2372 	/* TODO : Should this be called here of after ath_attach ? */
2373 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
2374 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
2375 
2376 	qdf_spinlock_create(&spectral->spectral_lock);
2377 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
2378 	target_if_spectral_clear_stats(spectral);
2379 
2380 	if (target_type == TARGET_TYPE_QCA8074 ||
2381 	    target_type == TARGET_TYPE_QCA8074V2 ||
2382 	    target_type == TARGET_TYPE_QCA6018 ||
2383 	    target_type == TARGET_TYPE_QCA5018 ||
2384 	    target_type == TARGET_TYPE_QCA6390 ||
2385 	    target_type == TARGET_TYPE_QCN9100 ||
2386 	    target_type == TARGET_TYPE_QCA6490 ||
2387 	    target_type == TARGET_TYPE_QCN9000 ||
2388 	    target_type == TARGET_TYPE_QCA6750)
2389 		spectral->direct_dma_support = true;
2390 
2391 	target_if_spectral_len_adj_swar_init(&spectral->len_adj_swar,
2392 					     target_type);
2393 	target_if_spectral_report_params_init(&spectral->rparams, target_type);
2394 
2395 	if ((target_type == TARGET_TYPE_QCA8074) ||
2396 	    (target_type == TARGET_TYPE_QCA8074V2) ||
2397 	    (target_type == TARGET_TYPE_QCA6018) ||
2398 	    (target_type == TARGET_TYPE_QCA5018) ||
2399 	    (target_type == TARGET_TYPE_QCN9100) ||
2400 	    (target_type == TARGET_TYPE_QCN9000) ||
2401 	    (target_type == TARGET_TYPE_QCA6290) ||
2402 	    (target_type == TARGET_TYPE_QCA6390) ||
2403 	    (target_type == TARGET_TYPE_QCA6490) ||
2404 	    (target_type == TARGET_TYPE_QCA6750)) {
2405 		spectral->spectral_gen = SPECTRAL_GEN3;
2406 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
2407 		spectral->tag_sscan_summary_exp =
2408 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
2409 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
2410 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
2411 	} else {
2412 		spectral->spectral_gen = SPECTRAL_GEN2;
2413 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
2414 		spectral->tag_sscan_summary_exp =
2415 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
2416 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
2417 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
2418 	}
2419 
2420 	status = target_if_init_spectral_param_min_max(
2421 					&spectral->param_min_max,
2422 					spectral->spectral_gen, target_type);
2423 	if (QDF_IS_STATUS_ERROR(status)) {
2424 		spectral_err("Failed to initialize parameter min max values");
2425 		goto fail;
2426 	}
2427 
2428 	target_if_init_spectral_param_properties(spectral);
2429 	/* Init spectral capability */
2430 	if (target_if_init_spectral_capability(spectral, target_type) !=
2431 					QDF_STATUS_SUCCESS) {
2432 		qdf_mem_free(spectral);
2433 		return NULL;
2434 	}
2435 	if (target_if_spectral_attach_simulation(spectral) < 0)
2436 		return NULL;
2437 
2438 	target_if_init_spectral_ops(spectral);
2439 	target_if_spectral_timestamp_war_init(&spectral->timestamp_war);
2440 
2441 	/* Spectral mode specific init */
2442 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2443 		spectral->params_valid[smode] = false;
2444 		qdf_spinlock_create(&spectral->param_info[smode].osps_lock);
2445 		spectral->param_info[smode].osps_cache.osc_is_valid = 0;
2446 	}
2447 
2448 	target_if_spectral_register_funcs(spectral, &spectral_ops);
2449 
2450 	if (target_if_spectral_check_hw_capability(spectral) == false) {
2451 		goto fail;
2452 	} else {
2453 		/*
2454 		 * TODO: Once the driver architecture transitions to chipset
2455 		 * versioning based checks, reflect this here.
2456 		 */
2457 		spectral->is_160_format = false;
2458 		spectral->is_lb_edge_extrabins_format = false;
2459 		spectral->is_rb_edge_extrabins_format = false;
2460 
2461 		if (target_type == TARGET_TYPE_QCA9984 ||
2462 		    target_type == TARGET_TYPE_QCA9888) {
2463 			spectral->is_160_format = true;
2464 			spectral->is_lb_edge_extrabins_format = true;
2465 			spectral->is_rb_edge_extrabins_format = true;
2466 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
2467 			    (target_revision == AR900B_REV_2)) {
2468 			spectral->is_rb_edge_extrabins_format = true;
2469 		}
2470 
2471 		if (target_type == TARGET_TYPE_QCA9984 ||
2472 		    target_type == TARGET_TYPE_QCA9888)
2473 			spectral->is_sec80_rssi_war_required = true;
2474 
2475 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
2476 
2477 		if (spectral->spectral_gen == SPECTRAL_GEN3)
2478 			init_160mhz_delivery_state_machine(spectral);
2479 	}
2480 
2481 	return spectral;
2482 
2483 fail:
2484 	target_if_spectral_detach(spectral);
2485 	return NULL;
2486 }
2487 
2488 /**
2489  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
2490  * functionality for the given pdev
2491  * @pdev: Pointer to pdev object
2492  *
2493  * Function to de-initialize pointer to spectral target_if internal private data
2494  *
2495  * Return: None
2496  */
2497 void
2498 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
2499 {
2500 	struct target_if_spectral *spectral = NULL;
2501 
2502 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2503 	if (!spectral) {
2504 		spectral_err("SPECTRAL : Module doesn't exist");
2505 		return;
2506 	}
2507 	target_if_spectral_detach(spectral);
2508 
2509 	return;
2510 }
2511 
2512 /**
2513  * target_if_psoc_spectral_deinit() - De-initialize target_if Spectral
2514  * functionality for the given psoc
2515  * @psoc: Pointer to psoc object
2516  *
2517  * Function to de-initialize pointer to psoc spectral target_if internal
2518  * private data
2519  *
2520  * Return: None
2521  */
2522 static void
2523 target_if_psoc_spectral_deinit(struct wlan_objmgr_psoc *psoc)
2524 {
2525 	struct target_if_psoc_spectral *psoc_spectral;
2526 
2527 	if (!psoc) {
2528 		spectral_err("psoc is null");
2529 		return;
2530 	}
2531 
2532 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
2533 	if (!psoc_spectral) {
2534 		spectral_err("Spectral target_if psoc object is null");
2535 		return;
2536 	}
2537 
2538 	qdf_mem_free(psoc_spectral);
2539 }
2540 
2541 /**
2542  * target_if_psoc_spectral_init() - Initialize target_if Spectral
2543  * functionality for the given psoc
2544  * @psoc: Pointer to psoc object
2545  *
2546  * Function to initialize pointer to psoc spectral target_if internal
2547  * private data
2548  *
2549  * Return: On success, pointer to Spectral psoc target_if internal
2550  * private data, on failure, NULL
2551  */
2552 static void *
2553 target_if_psoc_spectral_init(struct wlan_objmgr_psoc *psoc)
2554 {
2555 	struct target_if_psoc_spectral *psoc_spectral = NULL;
2556 
2557 	if (!psoc) {
2558 		spectral_err("psoc is null");
2559 		goto fail;
2560 	}
2561 
2562 	psoc_spectral = (struct target_if_psoc_spectral *)qdf_mem_malloc(
2563 			sizeof(struct target_if_psoc_spectral));
2564 	if (!psoc_spectral) {
2565 		spectral_err("Spectral lmac psoc object allocation failed");
2566 		goto fail;
2567 	}
2568 
2569 	psoc_spectral->psoc_obj = psoc;
2570 
2571 	return psoc_spectral;
2572 
2573 fail:
2574 	if (psoc_spectral)
2575 		target_if_psoc_spectral_deinit(psoc);
2576 
2577 	return psoc_spectral;
2578 }
2579 
2580 /* target_if_spectral_find_agile_width() - Given a channel width enum, find the
2581  * corresponding translation for Agile channel width.
2582  * @spectral: pointer to Spectral object
2583  * @chwidth: operating channel width
2584  * @is_80_80_agile: Indicates an 80+80 agile Scan request
2585  *
2586  * Return: The translated channel width enum.
2587  */
2588 static enum phy_ch_width
2589 target_if_spectral_find_agile_width(struct target_if_spectral *spectral,
2590 				    enum phy_ch_width chwidth,
2591 				    bool is_80_80_agile)
2592 {
2593 	enum phy_ch_width agile_width;
2594 	struct wlan_objmgr_pdev *pdev;
2595 	struct wlan_objmgr_psoc *psoc;
2596 
2597 	if (!spectral) {
2598 		spectral_err("Spectral object is null");
2599 		return CH_WIDTH_INVALID;
2600 	}
2601 
2602 	pdev =  spectral->pdev_obj;
2603 	if (!pdev) {
2604 		spectral_err("pdev is null");
2605 		return CH_WIDTH_INVALID;
2606 	}
2607 
2608 	psoc = wlan_pdev_get_psoc(pdev);
2609 	if (!psoc) {
2610 		spectral_err("psoc is null");
2611 		return CH_WIDTH_INVALID;
2612 	}
2613 
2614 	switch (chwidth) {
2615 	case CH_WIDTH_20MHZ:
2616 		agile_width = CH_WIDTH_20MHZ;
2617 		break;
2618 
2619 	case CH_WIDTH_40MHZ:
2620 		agile_width = CH_WIDTH_40MHZ;
2621 		break;
2622 
2623 	case CH_WIDTH_80MHZ:
2624 		agile_width = CH_WIDTH_80MHZ;
2625 		break;
2626 
2627 	case CH_WIDTH_80P80MHZ:
2628 		if (wlan_psoc_nif_fw_ext_cap_get(psoc,
2629 		    WLAN_SOC_RESTRICTED_80P80_SUPPORT) && !is_80_80_agile)
2630 			agile_width = CH_WIDTH_160MHZ;
2631 		else
2632 			agile_width = CH_WIDTH_80P80MHZ;
2633 
2634 		if (agile_width > spectral->rparams.max_agile_ch_width)
2635 			agile_width = spectral->rparams.max_agile_ch_width;
2636 		break;
2637 
2638 	case CH_WIDTH_160MHZ:
2639 		if (wlan_psoc_nif_fw_ext_cap_get(psoc,
2640 		    WLAN_SOC_RESTRICTED_80P80_SUPPORT) && is_80_80_agile)
2641 			agile_width = CH_WIDTH_80P80MHZ;
2642 		else
2643 			agile_width = CH_WIDTH_160MHZ;
2644 
2645 		if (agile_width > spectral->rparams.max_agile_ch_width)
2646 			agile_width = spectral->rparams.max_agile_ch_width;
2647 		break;
2648 
2649 	default:
2650 		spectral_err("Invalid channel width %d", chwidth);
2651 		agile_width = CH_WIDTH_INVALID;
2652 		break;
2653 	}
2654 
2655 	return agile_width;
2656 }
2657 
2658 /**
2659  * target_if_calculate_center_freq() - Helper routine to
2660  * check whether given frequency is center frequency of a
2661  * WLAN channel
2662  *
2663  * @spectral: Pointer to Spectral object
2664  * @chan_freq: Center frequency of a WLAN channel
2665  * @is_valid: Indicates whether given frequency is valid
2666  *
2667  * Return: QDF_STATUS
2668  */
2669 static QDF_STATUS
2670 target_if_is_center_freq_of_any_chan(struct wlan_objmgr_pdev *pdev,
2671 				     uint32_t chan_freq,
2672 				     bool *is_valid)
2673 {
2674 	struct regulatory_channel *cur_chan_list;
2675 	int i;
2676 
2677 	if (!pdev) {
2678 		spectral_err("pdev object is null");
2679 		return QDF_STATUS_E_FAILURE;
2680 	}
2681 
2682 	if (!is_valid) {
2683 		spectral_err("is valid argument is null");
2684 		return QDF_STATUS_E_FAILURE;
2685 	}
2686 
2687 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
2688 	if (!cur_chan_list)
2689 		return QDF_STATUS_E_FAILURE;
2690 
2691 	if (wlan_reg_get_current_chan_list(
2692 			pdev, cur_chan_list) != QDF_STATUS_SUCCESS) {
2693 		spectral_err("Failed to get cur_chan list");
2694 		qdf_mem_free(cur_chan_list);
2695 		return QDF_STATUS_E_FAILURE;
2696 	}
2697 
2698 	*is_valid = false;
2699 	for (i = 0; i < NUM_CHANNELS; i++) {
2700 		uint32_t flags;
2701 		uint32_t center_freq;
2702 
2703 		flags = cur_chan_list[i].chan_flags;
2704 		center_freq = cur_chan_list[i].center_freq;
2705 
2706 		if (!(flags & REGULATORY_CHAN_DISABLED) &&
2707 		    (center_freq == chan_freq)) {
2708 			*is_valid = true;
2709 			break;
2710 		}
2711 	}
2712 
2713 	qdf_mem_free(cur_chan_list);
2714 
2715 	return QDF_STATUS_SUCCESS;
2716 }
2717 
2718 /**
2719  * target_if_calculate_center_freq() - Helper routine to
2720  * find the center frequency of the agile span from a
2721  * WLAN channel center frequency
2722  *
2723  * @spectral: Pointer to Spectral object
2724  * @ch_width: Channel width array
2725  * @chan_freq: Center frequency of a WLAN channel
2726  * @center_freq: Pointer to center frequency
2727  *
2728  * Return: QDF_STATUS
2729  */
2730 static QDF_STATUS
2731 target_if_calculate_center_freq(struct target_if_spectral *spectral,
2732 				enum phy_ch_width *ch_width,
2733 				uint16_t chan_freq,
2734 				uint16_t *center_freq)
2735 {
2736 	enum phy_ch_width agile_ch_width;
2737 
2738 	if (!spectral) {
2739 		spectral_err("spectral target if object is null");
2740 		return QDF_STATUS_E_FAILURE;
2741 	}
2742 
2743 	if (!ch_width) {
2744 		spectral_err("Channel width array is null");
2745 		return QDF_STATUS_E_INVAL;
2746 	}
2747 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
2748 
2749 	if (!center_freq) {
2750 		spectral_err("center_freq argument is null");
2751 		return QDF_STATUS_E_FAILURE;
2752 	}
2753 
2754 	if (agile_ch_width == CH_WIDTH_20MHZ) {
2755 		*center_freq = chan_freq;
2756 	} else {
2757 		uint16_t start_freq;
2758 		uint16_t end_freq;
2759 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
2760 		enum channel_state state;
2761 
2762 		state = wlan_reg_get_5g_bonded_channel_and_state_for_freq
2763 			(spectral->pdev_obj, chan_freq, agile_ch_width,
2764 			 &bonded_chan_ptr);
2765 		if (state == CHANNEL_STATE_DISABLE ||
2766 		    state == CHANNEL_STATE_INVALID) {
2767 			spectral_err("Channel state is disable or invalid");
2768 			return QDF_STATUS_E_FAILURE;
2769 		}
2770 		if (!bonded_chan_ptr) {
2771 			spectral_err("Bonded channel is not found");
2772 			return QDF_STATUS_E_FAILURE;
2773 		}
2774 		start_freq = bonded_chan_ptr->start_freq;
2775 		end_freq = bonded_chan_ptr->end_freq;
2776 		*center_freq = (start_freq + end_freq) >> 1;
2777 	}
2778 
2779 	return QDF_STATUS_SUCCESS;
2780 }
2781 
2782 /**
2783  * target_if_validate_center_freq() - Helper routine to
2784  * validate user provided agile center frequency
2785  *
2786  * @spectral: Pointer to Spectral object
2787  * @ch_width: Channel width array
2788  * @center_freq: User provided agile span center frequency
2789  * @is_valid: Indicates whether agile span center frequency is valid
2790  *
2791  * Return: QDF_STATUS
2792  */
2793 static QDF_STATUS
2794 target_if_validate_center_freq(struct target_if_spectral *spectral,
2795 			       enum phy_ch_width *ch_width,
2796 			       uint16_t center_freq,
2797 			       bool *is_valid)
2798 {
2799 	enum phy_ch_width agile_ch_width;
2800 	struct wlan_objmgr_pdev *pdev;
2801 	QDF_STATUS status;
2802 
2803 	if (!spectral) {
2804 		spectral_err("spectral target if object is null");
2805 		return QDF_STATUS_E_FAILURE;
2806 	}
2807 
2808 	if (!ch_width) {
2809 		spectral_err("channel width array is null");
2810 		return QDF_STATUS_E_INVAL;
2811 	}
2812 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
2813 
2814 	if (!is_valid) {
2815 		spectral_err("is_valid argument is null");
2816 		return QDF_STATUS_E_FAILURE;
2817 	}
2818 
2819 	pdev = spectral->pdev_obj;
2820 
2821 	if (agile_ch_width == CH_WIDTH_20MHZ) {
2822 		status = target_if_is_center_freq_of_any_chan
2823 				(pdev, center_freq, is_valid);
2824 		if (QDF_IS_STATUS_ERROR(status))
2825 			return QDF_STATUS_E_FAILURE;
2826 	} else {
2827 		uint16_t start_freq;
2828 		uint16_t end_freq;
2829 		const struct bonded_channel_freq *bonded_chan_ptr = NULL;
2830 		bool is_chan;
2831 
2832 		status = target_if_is_center_freq_of_any_chan
2833 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
2834 				 &is_chan);
2835 		if (QDF_IS_STATUS_ERROR(status))
2836 			return QDF_STATUS_E_FAILURE;
2837 
2838 		if (is_chan) {
2839 			uint32_t calulated_center_freq;
2840 			enum channel_state st;
2841 
2842 			st = wlan_reg_get_5g_bonded_channel_and_state_for_freq
2843 				(pdev, center_freq + FREQ_OFFSET_10MHZ,
2844 				 agile_ch_width,
2845 				 &bonded_chan_ptr);
2846 			if (st == CHANNEL_STATE_DISABLE ||
2847 			    st == CHANNEL_STATE_INVALID) {
2848 				spectral_err("Channel state disable/invalid");
2849 				return QDF_STATUS_E_FAILURE;
2850 			}
2851 			if (!bonded_chan_ptr) {
2852 				spectral_err("Bonded channel is not found");
2853 				return QDF_STATUS_E_FAILURE;
2854 			}
2855 			start_freq = bonded_chan_ptr->start_freq;
2856 			end_freq = bonded_chan_ptr->end_freq;
2857 			calulated_center_freq = (start_freq + end_freq) >> 1;
2858 			*is_valid = (center_freq == calulated_center_freq);
2859 		} else {
2860 			*is_valid = false;
2861 		}
2862 	}
2863 
2864 	return QDF_STATUS_SUCCESS;
2865 }
2866 
2867 /**
2868  * target_if_is_agile_span_overlap_with_operating_span() - Helper routine to
2869  * check whether agile span overlaps with current operating band.
2870  *
2871  * @spectral: Pointer to Spectral object
2872  * @ch_width: Channel width array
2873  * @center_freq: Agile span center frequency
2874  * @is_overlapping: Indicates whether Agile span overlaps with operating span
2875  *
2876  * Helper routine to check whether agile span overlaps with current
2877  * operating band.
2878  *
2879  * Return: QDF_STATUS
2880  */
2881 static QDF_STATUS
2882 target_if_is_agile_span_overlap_with_operating_span
2883 			(struct target_if_spectral *spectral,
2884 			 enum phy_ch_width *ch_width,
2885 			 struct spectral_config_frequency *center_freq,
2886 			 bool *is_overlapping)
2887 {
2888 	enum phy_ch_width op_ch_width;
2889 	enum phy_ch_width agile_ch_width;
2890 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
2891 	struct wlan_objmgr_vdev *vdev;
2892 	struct wlan_objmgr_pdev *pdev;
2893 	int16_t chan_freq;
2894 	uint32_t op_start_freq;
2895 	uint32_t op_end_freq;
2896 	uint32_t agile_start_freq;
2897 	uint32_t agile_end_freq;
2898 	uint32_t cfreq2;
2899 
2900 	if (!spectral) {
2901 		spectral_err("Spectral object is NULL");
2902 		return QDF_STATUS_E_FAILURE;
2903 	}
2904 
2905 	pdev  = spectral->pdev_obj;
2906 	if (!pdev) {
2907 		spectral_err("pdev object is NULL");
2908 		return QDF_STATUS_E_FAILURE;
2909 	}
2910 
2911 	if (!ch_width) {
2912 		spectral_err("channel width array is null");
2913 		return QDF_STATUS_E_FAILURE;
2914 	}
2915 	op_ch_width = ch_width[SPECTRAL_SCAN_MODE_NORMAL];
2916 	if (op_ch_width == CH_WIDTH_INVALID) {
2917 		spectral_err("Invalid channel width");
2918 		return QDF_STATUS_E_INVAL;
2919 	}
2920 	agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
2921 	if (agile_ch_width == CH_WIDTH_INVALID) {
2922 		spectral_err("Invalid channel width");
2923 		return QDF_STATUS_E_INVAL;
2924 	}
2925 
2926 	if (!is_overlapping) {
2927 		spectral_err("Argument(is_overlapping) is NULL");
2928 		return QDF_STATUS_E_FAILURE;
2929 	}
2930 	*is_overlapping = false;
2931 
2932 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
2933 	if (!vdev) {
2934 		spectral_err("vdev is NULL");
2935 		return QDF_STATUS_E_FAILURE;
2936 	}
2937 	chan_freq = target_if_vdev_get_chan_freq(vdev);
2938 	cfreq2 = target_if_vdev_get_chan_freq_seg2(vdev);
2939 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2940 	if (cfreq2 < 0) {
2941 		spectral_err("cfreq2 is invalid");
2942 		return QDF_STATUS_E_FAILURE;
2943 	}
2944 
2945 	if (op_ch_width == CH_WIDTH_20MHZ) {
2946 		op_start_freq = chan_freq - FREQ_OFFSET_10MHZ;
2947 		op_end_freq = chan_freq + FREQ_OFFSET_10MHZ;
2948 	} else {
2949 		enum channel_state state;
2950 
2951 		state = wlan_reg_get_5g_bonded_channel_and_state_for_freq
2952 			(pdev, chan_freq, op_ch_width, &bonded_chan_ptr);
2953 		if (state == CHANNEL_STATE_DISABLE ||
2954 		    state == CHANNEL_STATE_INVALID) {
2955 			spectral_err("Channel state is disable or invalid");
2956 			return QDF_STATUS_E_FAILURE;
2957 		}
2958 		if (!bonded_chan_ptr) {
2959 			spectral_err("Bonded channel is not found");
2960 			return QDF_STATUS_E_FAILURE;
2961 		}
2962 		op_start_freq = bonded_chan_ptr->start_freq - FREQ_OFFSET_10MHZ;
2963 		op_end_freq = bonded_chan_ptr->end_freq - FREQ_OFFSET_10MHZ;
2964 	}
2965 
2966 	if (agile_ch_width == CH_WIDTH_80P80MHZ) {
2967 		agile_start_freq = center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
2968 		agile_end_freq = center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
2969 		if (agile_end_freq > op_start_freq &&
2970 		    op_end_freq > agile_start_freq)
2971 			*is_overlapping = true;
2972 
2973 		agile_start_freq = center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
2974 		agile_end_freq = center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
2975 		if (agile_end_freq > op_start_freq &&
2976 		    op_end_freq > agile_start_freq)
2977 			*is_overlapping = true;
2978 	} else {
2979 		agile_start_freq = center_freq->cfreq1 -
2980 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
2981 		agile_end_freq = center_freq->cfreq1 +
2982 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
2983 		if (agile_end_freq > op_start_freq &&
2984 		    op_end_freq > agile_start_freq)
2985 			*is_overlapping = true;
2986 	}
2987 
2988 	if (op_ch_width == CH_WIDTH_80P80MHZ) {
2989 		uint32_t sec80_start_feq;
2990 		uint32_t sec80_end_freq;
2991 
2992 		sec80_start_feq = cfreq2 - FREQ_OFFSET_40MHZ;
2993 		sec80_end_freq = cfreq2 + FREQ_OFFSET_40MHZ;
2994 
2995 		if (agile_ch_width == CH_WIDTH_80P80MHZ) {
2996 			agile_start_freq =
2997 					center_freq->cfreq1 - FREQ_OFFSET_40MHZ;
2998 			agile_end_freq =
2999 					center_freq->cfreq1 + FREQ_OFFSET_40MHZ;
3000 			if (agile_end_freq > sec80_start_feq &&
3001 			    sec80_end_freq > agile_start_freq)
3002 				*is_overlapping = true;
3003 
3004 			agile_start_freq =
3005 					center_freq->cfreq2 - FREQ_OFFSET_40MHZ;
3006 			agile_end_freq =
3007 					center_freq->cfreq2 + FREQ_OFFSET_40MHZ;
3008 			if (agile_end_freq > sec80_start_feq &&
3009 			    sec80_end_freq > agile_start_freq)
3010 				*is_overlapping = true;
3011 		} else {
3012 			agile_start_freq = center_freq->cfreq1 -
3013 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
3014 			agile_end_freq = center_freq->cfreq1 +
3015 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
3016 			if (agile_end_freq > sec80_start_feq &&
3017 			    sec80_end_freq > agile_start_freq)
3018 				*is_overlapping = true;
3019 		}
3020 	}
3021 
3022 	return QDF_STATUS_SUCCESS;
3023 }
3024 
3025 /**
3026  * target_if_spectral_populate_chwidth() - Helper routine to
3027  * populate channel width for different Spectral modes
3028  *
3029  * @spectral: Pointer to Spectral object
3030  * @ch_width: Channel width array
3031  * @is_80_80_agile: Indicates whether 80+80 agile scan is requested
3032  *
3033  * Helper routine to populate channel width for different Spectral modes
3034  *
3035  * Return: QDF_STATUS
3036  */
3037 static QDF_STATUS
3038 target_if_spectral_populate_chwidth(struct target_if_spectral *spectral,
3039 				    enum phy_ch_width *ch_width,
3040 				    bool is_80_80_agile) {
3041 	struct wlan_objmgr_vdev *vdev;
3042 	enum spectral_scan_mode smode;
3043 	enum phy_ch_width vdev_ch_width;
3044 
3045 	smode = SPECTRAL_SCAN_MODE_NORMAL;
3046 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
3047 		ch_width[smode] = CH_WIDTH_INVALID;
3048 
3049 	if (!spectral) {
3050 		spectral_err("Spectral object is null");
3051 		return QDF_STATUS_E_INVAL;
3052 	}
3053 
3054 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_NORMAL);
3055 	if (!vdev) {
3056 		spectral_err("vdev is null");
3057 		return QDF_STATUS_E_FAILURE;
3058 	}
3059 
3060 	vdev_ch_width = target_if_vdev_get_ch_width(vdev);
3061 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3062 	if (vdev_ch_width == CH_WIDTH_INVALID) {
3063 		spectral_err("Invalid channel width %d", vdev_ch_width);
3064 		return QDF_STATUS_E_FAILURE;
3065 	}
3066 
3067 	ch_width[SPECTRAL_SCAN_MODE_NORMAL] = vdev_ch_width;
3068 	ch_width[SPECTRAL_SCAN_MODE_AGILE] =
3069 		target_if_spectral_find_agile_width(spectral, vdev_ch_width,
3070 						    is_80_80_agile);
3071 
3072 	return QDF_STATUS_SUCCESS;
3073 }
3074 
3075 /**
3076  * target_if_spectral_is_valid_80p80_freq() - API to check whether given
3077  * (cfreq1, cfreq2) pair forms a valid 80+80 combination
3078  * @pdev: pointer to pdev
3079  * @cfreq1: center frequency 1
3080  * @cfreq2: center frequency 2
3081  *
3082  * API to check whether given (cfreq1, cfreq2) pair forms a valid 80+80
3083  * combination
3084  *
3085  * Return: true or false
3086  */
3087 static bool
3088 target_if_spectral_is_valid_80p80_freq(struct wlan_objmgr_pdev *pdev,
3089 				       uint32_t cfreq1, uint32_t cfreq2)
3090 {
3091 	struct ch_params ch_params;
3092 	enum channel_state chan_state1;
3093 	enum channel_state chan_state2;
3094 	struct wlan_objmgr_psoc *psoc;
3095 
3096 	qdf_assert_always(pdev);
3097 	psoc = wlan_pdev_get_psoc(pdev);
3098 	qdf_assert_always(psoc);
3099 
3100 	/* In restricted 80P80 MHz enabled, only one 80+80 MHz
3101 	 * channel is supported with cfreq=5690 and cfreq=5775.
3102 	 */
3103 	if (wlan_psoc_nif_fw_ext_cap_get(
3104 				psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT))
3105 		return CHAN_WITHIN_RESTRICTED_80P80(cfreq1, cfreq2);
3106 
3107 	ch_params.center_freq_seg1 = wlan_reg_freq_to_chan(pdev, cfreq2);
3108 	ch_params.mhz_freq_seg1 = cfreq2;
3109 	ch_params.ch_width = CH_WIDTH_80P80MHZ;
3110 	wlan_reg_set_channel_params_for_freq(pdev, cfreq1 - FREQ_OFFSET_10MHZ,
3111 					     0, &ch_params);
3112 
3113 	if (ch_params.ch_width != CH_WIDTH_80P80MHZ)
3114 		return false;
3115 
3116 	if (ch_params.mhz_freq_seg0 != cfreq1 ||
3117 	    ch_params.mhz_freq_seg1 != cfreq2)
3118 		return false;
3119 
3120 	chan_state1 = wlan_reg_get_5g_bonded_channel_state_for_freq(
3121 				pdev,
3122 				ch_params.mhz_freq_seg0 - FREQ_OFFSET_10MHZ,
3123 				CH_WIDTH_80MHZ);
3124 	if ((chan_state1 == CHANNEL_STATE_DISABLE) ||
3125 	    (chan_state1 == CHANNEL_STATE_INVALID))
3126 		return false;
3127 
3128 	chan_state2 = wlan_reg_get_5g_bonded_channel_state_for_freq(
3129 				pdev,
3130 				ch_params.mhz_freq_seg1 - FREQ_OFFSET_10MHZ,
3131 				CH_WIDTH_80MHZ);
3132 	if ((chan_state2 == CHANNEL_STATE_DISABLE) ||
3133 	    (chan_state2 == CHANNEL_STATE_INVALID))
3134 		return false;
3135 
3136 	if (abs(ch_params.mhz_freq_seg0 - ch_params.mhz_freq_seg1) <=
3137 	    FREQ_OFFSET_80MHZ)
3138 		return false;
3139 
3140 	return true;
3141 }
3142 
3143 /**
3144  * _target_if_set_spectral_config() - Set spectral config
3145  * @spectral:       Pointer to spectral object
3146  * @param: Spectral parameter id and value
3147  * @smode: Spectral scan mode
3148  * @err: Spectral error code
3149  *
3150  * API to set spectral configurations
3151  *
3152  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3153  */
3154 static QDF_STATUS
3155 _target_if_set_spectral_config(struct target_if_spectral *spectral,
3156 			       const struct spectral_cp_param *param,
3157 			       const enum spectral_scan_mode smode,
3158 			       enum spectral_cp_error_code *err)
3159 {
3160 	struct spectral_config params;
3161 	struct target_if_spectral_ops *p_sops;
3162 	struct spectral_config *sparams;
3163 	QDF_STATUS status;
3164 	bool is_overlapping;
3165 	uint16_t agile_cfreq;
3166 	bool is_valid_chan;
3167 	struct spectral_param_min_max *param_min_max;
3168 	enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
3169 	enum spectral_scan_mode m;
3170 	struct spectral_config_frequency center_freq = {0};
3171 
3172 	if (!err) {
3173 		spectral_err("Error code argument is null");
3174 		QDF_ASSERT(0);
3175 		return QDF_STATUS_E_FAILURE;
3176 	}
3177 	*err = SPECTRAL_SCAN_ERR_INVALID;
3178 
3179 	if (!param) {
3180 		spectral_err("Parameter object is null");
3181 		return QDF_STATUS_E_FAILURE;
3182 	}
3183 
3184 	if (!spectral) {
3185 		spectral_err("spectral object is NULL");
3186 		return QDF_STATUS_E_FAILURE;
3187 	}
3188 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3189 	param_min_max = &spectral->param_min_max;
3190 
3191 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3192 		spectral_err("Invalid Spectral mode %u", smode);
3193 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3194 		return QDF_STATUS_E_FAILURE;
3195 	}
3196 
3197 	sparams = &spectral->params[smode];
3198 	m = SPECTRAL_SCAN_MODE_NORMAL;
3199 	for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
3200 		ch_width[m] = CH_WIDTH_INVALID;
3201 
3202 	if (!spectral->params_valid[smode]) {
3203 		target_if_spectral_info_read(spectral,
3204 					     smode,
3205 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
3206 					     &spectral->params[smode],
3207 					     sizeof(spectral->params[smode]));
3208 		spectral->params_valid[smode] = true;
3209 	}
3210 
3211 	switch (param->id) {
3212 	case SPECTRAL_PARAM_FFT_PERIOD:
3213 		sparams->ss_fft_period = param->value;
3214 		break;
3215 	case SPECTRAL_PARAM_SCAN_PERIOD:
3216 		sparams->ss_period = param->value;
3217 		break;
3218 	case SPECTRAL_PARAM_SCAN_COUNT:
3219 		sparams->ss_count = param->value;
3220 		break;
3221 	case SPECTRAL_PARAM_SHORT_REPORT:
3222 		sparams->ss_short_report = (!!param->value) ? true : false;
3223 		break;
3224 	case SPECTRAL_PARAM_SPECT_PRI:
3225 		sparams->ss_spectral_pri = (!!param->value) ? true : false;
3226 		break;
3227 	case SPECTRAL_PARAM_FFT_SIZE:
3228 		status = target_if_spectral_populate_chwidth
3229 			(spectral, ch_width, spectral->params
3230 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
3231 		if (QDF_IS_STATUS_ERROR(status))
3232 			return QDF_STATUS_E_FAILURE;
3233 		if ((param->value < param_min_max->fft_size_min) ||
3234 		    (param->value > param_min_max->fft_size_max
3235 		    [ch_width[smode]])) {
3236 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3237 			return QDF_STATUS_E_FAILURE;
3238 		}
3239 		sparams->ss_fft_size = param->value;
3240 		break;
3241 	case SPECTRAL_PARAM_GC_ENA:
3242 		sparams->ss_gc_ena = !!param->value;
3243 		break;
3244 	case SPECTRAL_PARAM_RESTART_ENA:
3245 		sparams->ss_restart_ena = !!param->value;
3246 		break;
3247 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
3248 		sparams->ss_noise_floor_ref = param->value;
3249 		break;
3250 	case SPECTRAL_PARAM_INIT_DELAY:
3251 		sparams->ss_init_delay = param->value;
3252 		break;
3253 	case SPECTRAL_PARAM_NB_TONE_THR:
3254 		sparams->ss_nb_tone_thr = param->value;
3255 		break;
3256 	case SPECTRAL_PARAM_STR_BIN_THR:
3257 		sparams->ss_str_bin_thr = param->value;
3258 		break;
3259 	case SPECTRAL_PARAM_WB_RPT_MODE:
3260 		sparams->ss_wb_rpt_mode = !!param->value;
3261 		break;
3262 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
3263 		sparams->ss_rssi_rpt_mode = !!param->value;
3264 		break;
3265 	case SPECTRAL_PARAM_RSSI_THR:
3266 		sparams->ss_rssi_thr = param->value;
3267 		break;
3268 	case SPECTRAL_PARAM_PWR_FORMAT:
3269 		sparams->ss_pwr_format = !!param->value;
3270 		break;
3271 	case SPECTRAL_PARAM_RPT_MODE:
3272 		if ((param->value < SPECTRAL_PARAM_RPT_MODE_MIN) ||
3273 		    (param->value > SPECTRAL_PARAM_RPT_MODE_MAX)) {
3274 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3275 			return QDF_STATUS_E_FAILURE;
3276 		}
3277 		sparams->ss_rpt_mode = param->value;
3278 		break;
3279 	case SPECTRAL_PARAM_BIN_SCALE:
3280 		sparams->ss_bin_scale = param->value;
3281 		break;
3282 	case SPECTRAL_PARAM_DBM_ADJ:
3283 		sparams->ss_dbm_adj = !!param->value;
3284 		break;
3285 	case SPECTRAL_PARAM_CHN_MASK:
3286 		sparams->ss_chn_mask = param->value;
3287 		break;
3288 	case SPECTRAL_PARAM_FREQUENCY:
3289 		status = target_if_spectral_populate_chwidth(
3290 				spectral, ch_width, param->freq.cfreq2 > 0);
3291 		if (QDF_IS_STATUS_ERROR(status)) {
3292 			spectral_err("Failed to populate channel width");
3293 			return QDF_STATUS_E_FAILURE;
3294 		}
3295 
3296 		if (ch_width[smode] != CH_WIDTH_80P80MHZ &&
3297 		    param->freq.cfreq2) {
3298 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3299 			spectral_err("Non zero cfreq2 expected for 80p80 only");
3300 			return QDF_STATUS_E_INVAL;
3301 		}
3302 
3303 		if (ch_width[smode] == CH_WIDTH_80P80MHZ &&
3304 		    !param->freq.cfreq2) {
3305 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3306 			spectral_err("Non zero cfreq2 expected for 80p80");
3307 			return QDF_STATUS_E_INVAL;
3308 		}
3309 
3310 		status = target_if_is_center_freq_of_any_chan
3311 				(spectral->pdev_obj, param->freq.cfreq1,
3312 				 &is_valid_chan);
3313 		if (QDF_IS_STATUS_ERROR(status))
3314 			return QDF_STATUS_E_FAILURE;
3315 
3316 		if (is_valid_chan) {
3317 			status = target_if_calculate_center_freq(
3318 							spectral, ch_width,
3319 							param->freq.cfreq1,
3320 							&agile_cfreq);
3321 			if (QDF_IS_STATUS_ERROR(status)) {
3322 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3323 				return QDF_STATUS_E_FAILURE;
3324 			}
3325 		} else {
3326 			bool is_valid_agile_cfreq;
3327 
3328 			status = target_if_validate_center_freq
3329 				(spectral, ch_width, param->freq.cfreq1,
3330 				 &is_valid_agile_cfreq);
3331 			if (QDF_IS_STATUS_ERROR(status))
3332 				return QDF_STATUS_E_FAILURE;
3333 
3334 			if (!is_valid_agile_cfreq) {
3335 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3336 				spectral_err("Invalid agile center frequency");
3337 				return QDF_STATUS_E_FAILURE;
3338 			}
3339 
3340 			agile_cfreq = param->freq.cfreq1;
3341 		}
3342 		center_freq.cfreq1 = agile_cfreq;
3343 
3344 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
3345 			status = target_if_is_center_freq_of_any_chan
3346 					(spectral->pdev_obj, param->freq.cfreq2,
3347 					 &is_valid_chan);
3348 			if (QDF_IS_STATUS_ERROR(status))
3349 				return QDF_STATUS_E_FAILURE;
3350 
3351 			if (is_valid_chan) {
3352 				status = target_if_calculate_center_freq(
3353 						spectral, ch_width,
3354 						param->freq.cfreq2,
3355 						&agile_cfreq);
3356 				if (QDF_IS_STATUS_ERROR(status)) {
3357 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3358 					return QDF_STATUS_E_FAILURE;
3359 				}
3360 			} else {
3361 				bool is_valid_agile_cfreq;
3362 
3363 				status = target_if_validate_center_freq
3364 					(spectral, ch_width, param->freq.cfreq2,
3365 					 &is_valid_agile_cfreq);
3366 				if (QDF_IS_STATUS_ERROR(status))
3367 					return QDF_STATUS_E_FAILURE;
3368 
3369 				if (!is_valid_agile_cfreq) {
3370 					*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3371 					spectral_err("Invalid agile center frequency");
3372 					return QDF_STATUS_E_FAILURE;
3373 				}
3374 
3375 				agile_cfreq = param->freq.cfreq2;
3376 			}
3377 			center_freq.cfreq2 = agile_cfreq;
3378 		}
3379 
3380 		status = target_if_is_agile_span_overlap_with_operating_span
3381 				(spectral, ch_width,
3382 				 &center_freq, &is_overlapping);
3383 		if (QDF_IS_STATUS_ERROR(status))
3384 			return QDF_STATUS_E_FAILURE;
3385 
3386 		if (is_overlapping) {
3387 			spectral_err("Agile freq %u, %u overlaps with operating span",
3388 				     center_freq.cfreq1, center_freq.cfreq2);
3389 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3390 			return QDF_STATUS_E_FAILURE;
3391 		}
3392 
3393 		if (ch_width[smode] == CH_WIDTH_80P80MHZ) {
3394 			bool is_valid_80p80;
3395 
3396 			is_valid_80p80 = target_if_spectral_is_valid_80p80_freq(
3397 						spectral->pdev_obj,
3398 						center_freq.cfreq1,
3399 						center_freq.cfreq2);
3400 
3401 			if (!is_valid_80p80) {
3402 				spectral_err("Agile freq %u, %u is invalid 80+80 combination",
3403 					     center_freq.cfreq1,
3404 					     center_freq.cfreq2);
3405 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3406 				return QDF_STATUS_E_FAILURE;
3407 			}
3408 		}
3409 
3410 		sparams->ss_frequency.cfreq1 = center_freq.cfreq1;
3411 		sparams->ss_frequency.cfreq2 = center_freq.cfreq2;
3412 
3413 		break;
3414 	}
3415 
3416 	p_sops->configure_spectral(spectral, sparams, smode);
3417 	/* only to validate the writes */
3418 	p_sops->get_spectral_config(spectral, &params, smode);
3419 	return QDF_STATUS_SUCCESS;
3420 }
3421 
3422 QDF_STATUS
3423 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
3424 			      const struct spectral_cp_param *param,
3425 			      const enum spectral_scan_mode smode,
3426 			      enum spectral_cp_error_code *err)
3427 {
3428 	enum spectral_scan_mode mode = SPECTRAL_SCAN_MODE_NORMAL;
3429 	struct target_if_spectral *spectral;
3430 	QDF_STATUS status;
3431 
3432 	if (!err) {
3433 		spectral_err("Error code argument is null");
3434 		QDF_ASSERT(0);
3435 		return QDF_STATUS_E_FAILURE;
3436 	}
3437 	*err = SPECTRAL_SCAN_ERR_INVALID;
3438 
3439 	if (!pdev) {
3440 		spectral_err("pdev object is NULL");
3441 		return QDF_STATUS_E_FAILURE;
3442 	}
3443 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3444 	if (!spectral) {
3445 		spectral_err("spectral object is NULL");
3446 		return QDF_STATUS_E_FAILURE;
3447 	}
3448 
3449 	if (!param) {
3450 		spectral_err("parameter object is NULL");
3451 		return QDF_STATUS_E_FAILURE;
3452 	}
3453 
3454 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3455 		spectral_err("Invalid Spectral mode %u", smode);
3456 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3457 		return QDF_STATUS_E_FAILURE;
3458 	}
3459 
3460 	if (!spectral->properties[smode][param->id].supported) {
3461 		spectral_err("Spectral parameter(%u) unsupported for mode %u",
3462 			     param->id, smode);
3463 		*err = SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED;
3464 		return QDF_STATUS_E_FAILURE;
3465 	}
3466 
3467 	if (spectral->properties[smode][param->id].common_all_modes) {
3468 		spectral_warn("Setting Spectral parameter %u for all modes",
3469 			      param->id);
3470 		for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) {
3471 			status = _target_if_set_spectral_config
3472 						(spectral, param, mode, err);
3473 			if (QDF_IS_STATUS_ERROR(status))
3474 				return QDF_STATUS_E_FAILURE;
3475 		}
3476 		return QDF_STATUS_SUCCESS;
3477 	}
3478 
3479 	return _target_if_set_spectral_config(spectral, param, smode, err);
3480 }
3481 
3482 /**
3483  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
3484  * @fft_len: FFT length
3485  * @pdev: Pointer to pdev object
3486  *
3487  * API to get fft bin count for a given fft length
3488  *
3489  * Return: FFt bin count
3490  */
3491 static int
3492 target_if_get_fft_bin_count(int fft_len)
3493 {
3494 	int bin_count = 0;
3495 
3496 	switch (fft_len) {
3497 	case 5:
3498 		bin_count = 16;
3499 		break;
3500 	case 6:
3501 		bin_count = 32;
3502 		break;
3503 	case 7:
3504 		bin_count = 64;
3505 		break;
3506 	case 8:
3507 		bin_count = 128;
3508 		break;
3509 	case 9:
3510 		bin_count = 256;
3511 		break;
3512 	default:
3513 		break;
3514 	}
3515 
3516 	return bin_count;
3517 }
3518 
3519 /**
3520  * target_if_init_upper_lower_flags() - Initializes control and extension
3521  * segment flags
3522  * @spectral: pointer to target if spectral object
3523  * @smode: Spectral scan mode
3524  *
3525  * API to initialize the control and extension flags with the lower/upper
3526  * segment based on the HT mode
3527  *
3528  * Return: FFt bin count
3529  */
3530 static void
3531 target_if_init_upper_lower_flags(struct target_if_spectral *spectral,
3532 				 enum spectral_scan_mode smode)
3533 {
3534 	int current_channel = 0;
3535 	int ext_channel = 0;
3536 	struct target_if_spectral_ops *p_sops =
3537 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
3538 
3539 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3540 		spectral_err("Invalid Spectral mode %u", smode);
3541 		return;
3542 	}
3543 	current_channel = p_sops->get_current_channel(spectral, smode);
3544 	ext_channel = p_sops->get_extension_channel(spectral, smode);
3545 
3546 	if ((current_channel == 0) || (ext_channel == 0))
3547 		return;
3548 
3549 	if (spectral->sc_spectral_20_40_mode) {
3550 		/* HT40 mode */
3551 		if (ext_channel < current_channel) {
3552 			spectral->lower_is_extension = 1;
3553 			spectral->upper_is_control = 1;
3554 			spectral->lower_is_control = 0;
3555 			spectral->upper_is_extension = 0;
3556 		} else {
3557 			spectral->lower_is_extension = 0;
3558 			spectral->upper_is_control = 0;
3559 			spectral->lower_is_control = 1;
3560 			spectral->upper_is_extension = 1;
3561 		}
3562 	} else {
3563 		/* HT20 mode, lower is always control */
3564 		spectral->lower_is_extension = 0;
3565 		spectral->upper_is_control = 0;
3566 		spectral->lower_is_control = 1;
3567 		spectral->upper_is_extension = 0;
3568 	}
3569 }
3570 
3571 /**
3572  * target_if_get_spectral_config() - Get spectral configuration
3573  * @pdev: Pointer to pdev object
3574  * @param: Pointer to spectral_config structure in which the configuration
3575  * should be returned
3576  * @smode: Spectral scan mode
3577  *
3578  * API to get the current spectral configuration
3579  *
3580  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3581  */
3582 QDF_STATUS
3583 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
3584 			      struct spectral_config *param,
3585 			      enum spectral_scan_mode smode)
3586 {
3587 	struct target_if_spectral_ops *p_sops = NULL;
3588 	struct target_if_spectral *spectral = NULL;
3589 
3590 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3591 
3592 	if (!spectral) {
3593 		spectral_err("SPECTRAL : Module doesn't exist");
3594 		return QDF_STATUS_E_FAILURE;
3595 	}
3596 
3597 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3598 
3599 	if (!p_sops) {
3600 		spectral_err("p_sops is null");
3601 		return QDF_STATUS_E_FAILURE;
3602 	}
3603 
3604 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3605 		spectral_err("Invalid Spectral mode %u", smode);
3606 		return QDF_STATUS_E_FAILURE;
3607 	}
3608 
3609 	qdf_mem_zero(param, sizeof(struct spectral_config));
3610 	p_sops->get_spectral_config(spectral, param, smode);
3611 
3612 	return QDF_STATUS_SUCCESS;
3613 }
3614 
3615 /**
3616  * target_if_spectral_get_num_detectors() - Get number of Spectral detectors
3617  * @spectral: Pointer to target if Spectral object
3618  * @ch_width: channel width
3619  * @num_detectors: Pointer to the variable to store number of Spectral detectors
3620  *
3621  * API to get number of Spectral detectors used for scan in the given channel
3622  * width.
3623  *
3624  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_INVAL on failure
3625  */
3626 static QDF_STATUS
3627 target_if_spectral_get_num_detectors(struct target_if_spectral *spectral,
3628 				     enum phy_ch_width ch_width,
3629 				     uint32_t *num_detectors)
3630 {
3631 	if (!spectral) {
3632 		spectral_err("target if spectral object is null");
3633 		return QDF_STATUS_E_INVAL;
3634 	}
3635 
3636 	if (ch_width >= CH_WIDTH_INVALID) {
3637 		spectral_err("Invalid channel width %d", ch_width);
3638 		return QDF_STATUS_E_INVAL;
3639 	}
3640 
3641 	if (!num_detectors) {
3642 		spectral_err("Invalid argument, number of detectors");
3643 		return QDF_STATUS_E_INVAL;
3644 	}
3645 
3646 	switch (ch_width) {
3647 	case CH_WIDTH_20MHZ:
3648 		*num_detectors = spectral->capability.num_detectors_20mhz;
3649 		break;
3650 
3651 	case CH_WIDTH_40MHZ:
3652 		*num_detectors = spectral->capability.num_detectors_40mhz;
3653 		break;
3654 
3655 	case CH_WIDTH_80MHZ:
3656 		*num_detectors = spectral->capability.num_detectors_80mhz;
3657 		break;
3658 
3659 	case CH_WIDTH_160MHZ:
3660 		*num_detectors = spectral->capability.num_detectors_160mhz;
3661 		break;
3662 
3663 	case CH_WIDTH_80P80MHZ:
3664 		*num_detectors = spectral->capability.num_detectors_80p80mhz;
3665 		break;
3666 
3667 	default:
3668 		spectral_err("Unsupported channel width %d", ch_width);
3669 		return QDF_STATUS_E_INVAL;
3670 	}
3671 
3672 	return QDF_STATUS_SUCCESS;
3673 }
3674 
3675 /**
3676  * target_if_spectral_finite_scan_init() - Initializations required for finite
3677  * Spectral scan
3678  * @spectral: Pointer to target of Spctral object
3679  * @smode: Spectral scan mode
3680  *
3681  * This routine initializes the finite Spectral scan. Finite Spectral scan is
3682  * triggered by configuring a non zero scan count.
3683  *
3684  * Return: QDF_STATUS_SUCCESS on success
3685  */
3686 static QDF_STATUS
3687 target_if_spectral_finite_scan_init(struct target_if_spectral *spectral,
3688 				    enum spectral_scan_mode smode)
3689 {
3690 	struct target_if_finite_spectral_scan_params *finite_scan;
3691 	enum phy_ch_width ch_width;
3692 	uint32_t num_detectors;
3693 	QDF_STATUS status;
3694 	uint16_t sscan_count;
3695 
3696 	if (!spectral) {
3697 		spectral_err("target if spectral object is null");
3698 		return QDF_STATUS_E_INVAL;
3699 	}
3700 
3701 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3702 		spectral_err("Invalid Spectral mode");
3703 		return QDF_STATUS_E_INVAL;
3704 	}
3705 
3706 	ch_width = spectral->ch_width[smode];
3707 	status = target_if_spectral_get_num_detectors(spectral, ch_width,
3708 						      &num_detectors);
3709 
3710 	if (QDF_IS_STATUS_ERROR(status)) {
3711 		spectral_err("Failed to get number of detectors");
3712 		return QDF_STATUS_E_FAILURE;
3713 	}
3714 
3715 	finite_scan = &spectral->finite_scan[smode];
3716 	sscan_count =  spectral->params[smode].ss_count;
3717 
3718 	finite_scan->finite_spectral_scan =  true;
3719 	finite_scan->num_reports_expected = num_detectors * sscan_count;
3720 
3721 	return QDF_STATUS_SUCCESS;
3722 }
3723 
3724 /**
3725  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
3726  *                                           parameters
3727  * @spectral: Pointer to Spectral target_if internal private data
3728  * @spectral_params: Pointer to Spectral parameters
3729  * @smode: Spectral scan mode
3730  * @err: Spectral error code
3731  *
3732  * Enable use of desired Spectral parameters by configuring them into HW, and
3733  * starting Spectral scan
3734  *
3735  * Return: 0 on success, 1 on failure
3736  */
3737 int
3738 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
3739 				      struct spectral_config *spectral_params,
3740 				      enum spectral_scan_mode smode,
3741 				      enum spectral_cp_error_code *err)
3742 {
3743 	int extension_channel = 0;
3744 	int current_channel = 0;
3745 	struct target_if_spectral_ops *p_sops = NULL;
3746 	QDF_STATUS status;
3747 	struct wlan_objmgr_pdev *pdev;
3748 	struct wlan_objmgr_psoc *psoc;
3749 
3750 	if (!spectral) {
3751 		spectral_err("Spectral LMAC object is NULL");
3752 		return 1;
3753 	}
3754 
3755 	pdev =  spectral->pdev_obj;
3756 	if (!pdev) {
3757 		spectral_err("pdev is null");
3758 		return QDF_STATUS_E_INVAL;
3759 	}
3760 
3761 	psoc = wlan_pdev_get_psoc(pdev);
3762 	if (!psoc) {
3763 		spectral_err("psoc is null");
3764 		return QDF_STATUS_E_INVAL;
3765 	}
3766 
3767 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3768 		spectral_err("Invalid Spectral mode %u", smode);
3769 		return 1;
3770 	}
3771 
3772 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3773 
3774 	if (!p_sops) {
3775 		spectral_err("p_sops is NULL");
3776 		return 1;
3777 	}
3778 
3779 	spectral->sc_spectral_noise_pwr_cal =
3780 	    spectral_params->ss_spectral_pri ? 1 : 0;
3781 
3782 	/* check if extension channel is present */
3783 	extension_channel = p_sops->get_extension_channel(spectral, smode);
3784 	current_channel = p_sops->get_current_channel(spectral, smode);
3785 
3786 	status = target_if_spectral_populate_chwidth(
3787 			spectral, spectral->ch_width,
3788 			spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3789 			ss_frequency.cfreq2 > 0);
3790 	if (QDF_IS_STATUS_ERROR(status)) {
3791 		spectral_err("Failed to get channel widths");
3792 		return 1;
3793 	}
3794 
3795 	if (spectral->capability.advncd_spectral_cap) {
3796 		spectral->lb_edge_extrabins = 0;
3797 		spectral->rb_edge_extrabins = 0;
3798 
3799 		if (spectral->is_lb_edge_extrabins_format &&
3800 		    spectral->params[smode].ss_rpt_mode == 2) {
3801 			spectral->lb_edge_extrabins = 4;
3802 		}
3803 
3804 		if (spectral->is_rb_edge_extrabins_format &&
3805 		    spectral->params[smode].ss_rpt_mode == 2) {
3806 			spectral->rb_edge_extrabins = 4;
3807 		}
3808 
3809 		if (spectral->ch_width[smode] == CH_WIDTH_20MHZ) {
3810 			spectral->sc_spectral_20_40_mode = 0;
3811 
3812 			spectral->spectral_numbins =
3813 			    target_if_get_fft_bin_count(
3814 				spectral->params[smode].ss_fft_size);
3815 			spectral->spectral_fft_len =
3816 			    target_if_get_fft_bin_count(
3817 				spectral->params[smode].ss_fft_size);
3818 			spectral->spectral_data_len =
3819 			    target_if_get_fft_bin_count(
3820 				spectral->params[smode].ss_fft_size);
3821 			/*
3822 			 * Initialize classifier params to be sent to user
3823 			 * space classifier
3824 			 */
3825 			spectral->classifier_params.lower_chan_in_mhz =
3826 			    current_channel;
3827 			spectral->classifier_params.upper_chan_in_mhz = 0;
3828 
3829 		} else if (spectral->ch_width[smode] == CH_WIDTH_40MHZ) {
3830 			/* TODO : Remove this variable */
3831 			spectral->sc_spectral_20_40_mode = 1;
3832 			spectral->spectral_numbins =
3833 			    target_if_get_fft_bin_count(
3834 				spectral->params[smode].ss_fft_size);
3835 			spectral->spectral_fft_len =
3836 			    target_if_get_fft_bin_count(
3837 				spectral->params[smode].ss_fft_size);
3838 			spectral->spectral_data_len =
3839 			    target_if_get_fft_bin_count(
3840 				spectral->params[smode].ss_fft_size);
3841 
3842 			/*
3843 			 * Initialize classifier params to be sent to user
3844 			 * space classifier
3845 			 */
3846 			if (extension_channel < current_channel) {
3847 				spectral->classifier_params.lower_chan_in_mhz =
3848 				    extension_channel;
3849 				spectral->classifier_params.upper_chan_in_mhz =
3850 				    current_channel;
3851 			} else {
3852 				spectral->classifier_params.lower_chan_in_mhz =
3853 				    current_channel;
3854 				spectral->classifier_params.upper_chan_in_mhz =
3855 				    extension_channel;
3856 			}
3857 
3858 		} else if (spectral->ch_width[smode] == CH_WIDTH_80MHZ) {
3859 			/* Set the FFT Size */
3860 			/* TODO : Remove this variable */
3861 			spectral->sc_spectral_20_40_mode = 0;
3862 			spectral->spectral_numbins =
3863 			    target_if_get_fft_bin_count(
3864 				spectral->params[smode].ss_fft_size);
3865 			spectral->spectral_fft_len =
3866 			    target_if_get_fft_bin_count(
3867 				spectral->params[smode].ss_fft_size);
3868 			spectral->spectral_data_len =
3869 			    target_if_get_fft_bin_count(
3870 				spectral->params[smode].ss_fft_size);
3871 
3872 			/*
3873 			 * Initialize classifier params to be sent to user
3874 			 * space classifier
3875 			 */
3876 			spectral->classifier_params.lower_chan_in_mhz =
3877 			    current_channel;
3878 			spectral->classifier_params.upper_chan_in_mhz = 0;
3879 
3880 			/*
3881 			 * Initialize classifier params to be sent to user
3882 			 * space classifier
3883 			 */
3884 			if (extension_channel < current_channel) {
3885 				spectral->classifier_params.lower_chan_in_mhz =
3886 				    extension_channel;
3887 				spectral->classifier_params.upper_chan_in_mhz =
3888 				    current_channel;
3889 			} else {
3890 				spectral->classifier_params.lower_chan_in_mhz =
3891 				    current_channel;
3892 				spectral->classifier_params.upper_chan_in_mhz =
3893 				    extension_channel;
3894 			}
3895 
3896 		} else if (is_ch_width_160_or_80p80(
3897 			   spectral->ch_width[smode])) {
3898 			/* Set the FFT Size */
3899 
3900 			/* The below applies to both 160 and 80+80 cases */
3901 
3902 			/* TODO : Remove this variable */
3903 			spectral->sc_spectral_20_40_mode = 0;
3904 			spectral->spectral_numbins =
3905 			    target_if_get_fft_bin_count(
3906 				spectral->params[smode].ss_fft_size);
3907 			spectral->spectral_fft_len =
3908 			    target_if_get_fft_bin_count(
3909 				spectral->params[smode].ss_fft_size);
3910 			spectral->spectral_data_len =
3911 			    target_if_get_fft_bin_count(
3912 				spectral->params[smode].ss_fft_size);
3913 
3914 			/*
3915 			 * Initialize classifier params to be sent to user
3916 			 * space classifier
3917 			 */
3918 			spectral->classifier_params.lower_chan_in_mhz =
3919 			    current_channel;
3920 			spectral->classifier_params.upper_chan_in_mhz = 0;
3921 
3922 			/*
3923 			 * Initialize classifier params to be sent to user
3924 			 * space classifier
3925 			 */
3926 			if (extension_channel < current_channel) {
3927 				spectral->classifier_params.lower_chan_in_mhz =
3928 				    extension_channel;
3929 				spectral->classifier_params.upper_chan_in_mhz =
3930 				    current_channel;
3931 			} else {
3932 				spectral->classifier_params.lower_chan_in_mhz =
3933 				    current_channel;
3934 				spectral->classifier_params.upper_chan_in_mhz =
3935 				    extension_channel;
3936 			}
3937 		}
3938 
3939 		if (spectral->spectral_numbins) {
3940 			spectral->spectral_numbins +=
3941 			    spectral->lb_edge_extrabins;
3942 			spectral->spectral_numbins +=
3943 			    spectral->rb_edge_extrabins;
3944 		}
3945 
3946 		if (spectral->spectral_fft_len) {
3947 			spectral->spectral_fft_len +=
3948 			    spectral->lb_edge_extrabins;
3949 			spectral->spectral_fft_len +=
3950 			    spectral->rb_edge_extrabins;
3951 		}
3952 
3953 		if (spectral->spectral_data_len) {
3954 			spectral->spectral_data_len +=
3955 			    spectral->lb_edge_extrabins;
3956 			spectral->spectral_data_len +=
3957 			    spectral->rb_edge_extrabins;
3958 		}
3959 	} else {
3960 		/*
3961 		 * The decision to find 20/40 mode is found based on the
3962 		 * presence of extension channel
3963 		 * instead of channel width, as the channel width can
3964 		 * dynamically change
3965 		 */
3966 
3967 		if (extension_channel == 0) {
3968 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
3969 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
3970 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
3971 			spectral->spectral_data_len =
3972 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
3973 			/* only valid in 20-40 mode */
3974 			spectral->spectral_lower_max_index_offset = -1;
3975 			/* only valid in 20-40 mode */
3976 			spectral->spectral_upper_max_index_offset = -1;
3977 			spectral->spectral_max_index_offset =
3978 			    spectral->spectral_fft_len + 2;
3979 			spectral->sc_spectral_20_40_mode = 0;
3980 
3981 			/*
3982 			 * Initialize classifier params to be sent to user
3983 			 * space classifier
3984 			 */
3985 			spectral->classifier_params.lower_chan_in_mhz =
3986 			    current_channel;
3987 			spectral->classifier_params.upper_chan_in_mhz = 0;
3988 
3989 		} else {
3990 			spectral->spectral_numbins =
3991 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
3992 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
3993 			spectral->spectral_data_len =
3994 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
3995 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
3996 			/* only valid in 20 mode */
3997 			spectral->spectral_max_index_offset = -1;
3998 			spectral->spectral_lower_max_index_offset =
3999 			    spectral->spectral_fft_len + 2;
4000 			spectral->spectral_upper_max_index_offset =
4001 			    spectral->spectral_fft_len + 5;
4002 			spectral->sc_spectral_20_40_mode = 1;
4003 
4004 			/*
4005 			 * Initialize classifier params to be sent to user
4006 			 * space classifier
4007 			 */
4008 			if (extension_channel < current_channel) {
4009 				spectral->classifier_params.lower_chan_in_mhz =
4010 				    extension_channel;
4011 				spectral->classifier_params.upper_chan_in_mhz =
4012 				    current_channel;
4013 			} else {
4014 				spectral->classifier_params.lower_chan_in_mhz =
4015 				    current_channel;
4016 				spectral->classifier_params.upper_chan_in_mhz =
4017 				    extension_channel;
4018 			}
4019 		}
4020 	}
4021 
4022 	spectral->send_single_packet = 0;
4023 	spectral->classifier_params.spectral_20_40_mode =
4024 	    spectral->sc_spectral_20_40_mode;
4025 	spectral->classifier_params.spectral_dc_index =
4026 	    spectral->spectral_dc_index;
4027 	spectral->spectral_sent_msg = 0;
4028 	spectral->classify_scan = 0;
4029 	spectral->num_spectral_data = 0;
4030 
4031 	if (!p_sops->is_spectral_active(spectral, smode)) {
4032 		p_sops->configure_spectral(spectral, spectral_params, smode);
4033 		spectral->rparams.marker[smode].is_valid = false;
4034 
4035 		if (spectral->params[smode].ss_count) {
4036 			status = target_if_spectral_finite_scan_init(spectral,
4037 								     smode);
4038 			if (QDF_IS_STATUS_ERROR(status)) {
4039 				spectral_err("Failed to init finite scan");
4040 				return 1;
4041 			}
4042 		}
4043 		p_sops->start_spectral_scan(spectral, smode, err);
4044 		spectral->timestamp_war.timestamp_war_offset[smode] = 0;
4045 		spectral->timestamp_war.last_fft_timestamp[smode] = 0;
4046 	}
4047 
4048 	/* get current spectral configuration */
4049 	p_sops->get_spectral_config(spectral, &spectral->params[smode], smode);
4050 
4051 	target_if_init_upper_lower_flags(spectral, smode);
4052 
4053 	return 0;
4054 }
4055 
4056 /**
4057  * target_if_is_aspectral_prohibited_by_adfs() - Is Agile Spectral prohibited by
4058  * Agile DFS
4059  * @psoc: Pointer to psoc
4060  * @object: Pointer to pdev
4061  * @arg: Pointer to flag which indicates whether Agile Spectral is prohibited
4062  *
4063  * This API checks whether Agile DFS is running on any of the pdevs. If so, it
4064  * indicates that Agile Spectral scan is prohibited by Agile DFS.
4065  *
4066  * Return: void
4067  */
4068 static void
4069 target_if_is_aspectral_prohibited_by_adfs(struct wlan_objmgr_psoc *psoc,
4070 					  void *object, void *arg)
4071 {
4072 	bool *is_aspectral_prohibited = arg;
4073 	struct wlan_objmgr_pdev *cur_pdev = object;
4074 	bool is_agile_dfs_enabled_cur_pdev = false;
4075 	QDF_STATUS status;
4076 
4077 	qdf_assert_always(is_aspectral_prohibited);
4078 	if (*is_aspectral_prohibited)
4079 		return;
4080 
4081 	qdf_assert_always(psoc);
4082 	qdf_assert_always(cur_pdev);
4083 
4084 	status = ucfg_dfs_get_agile_precac_enable
4085 				(cur_pdev,
4086 				 &is_agile_dfs_enabled_cur_pdev);
4087 	if (QDF_IS_STATUS_ERROR(status)) {
4088 		spectral_err("Get agile precac failed, prohibiting aSpectral");
4089 		*is_aspectral_prohibited = true;
4090 		return;
4091 	}
4092 
4093 	if (is_agile_dfs_enabled_cur_pdev) {
4094 		spectral_err("aDFS is in progress on one of the pdevs");
4095 		*is_aspectral_prohibited = true;
4096 	}
4097 }
4098 
4099 /**
4100  * target_if_get_curr_band() - Get current operating band of pdev
4101  *
4102  * @pdev: pointer to pdev object
4103  *
4104  * API to get current operating band of a given pdev.
4105  *
4106  * Return: if success enum reg_wifi_band, REG_BAND_UNKNOWN in case of failure
4107  */
4108 static enum reg_wifi_band
4109 target_if_get_curr_band(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id)
4110 {
4111 	struct wlan_objmgr_vdev *vdev;
4112 	int16_t chan_freq;
4113 	enum reg_wifi_band cur_band;
4114 
4115 	if (!pdev) {
4116 		spectral_err("pdev is NULL");
4117 		return REG_BAND_UNKNOWN;
4118 	}
4119 
4120 	if (vdev_id == WLAN_INVALID_VDEV_ID)
4121 		vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID);
4122 	else
4123 		vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
4124 							    WLAN_SPECTRAL_ID);
4125 	if (!vdev) {
4126 		spectral_debug("vdev is NULL");
4127 		return REG_BAND_UNKNOWN;
4128 	}
4129 	chan_freq = target_if_vdev_get_chan_freq(vdev);
4130 	cur_band = wlan_reg_freq_to_band(chan_freq);
4131 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4132 
4133 	return cur_band;
4134 }
4135 
4136 /**
4137  * target_if_is_agile_scan_active_in_5g() - Is Agile Spectral scan active on
4138  * any of the 5G pdevs
4139  * @psoc: Pointer to psoc
4140  * @object: Pointer to pdev
4141  * @arg: Pointer to flag which indicates whether Agile Spectral scan is in
4142  *       progress in any 5G pdevs
4143  *
4144  * Return: void
4145  */
4146 static void
4147 target_if_is_agile_scan_active_in_5g(struct wlan_objmgr_psoc *psoc,
4148 				     void *object, void *arg)
4149 {
4150 	enum reg_wifi_band band;
4151 	bool *is_agile_scan_inprog_5g_pdev = arg;
4152 	struct target_if_spectral *spectral;
4153 	struct wlan_objmgr_pdev *cur_pdev = object;
4154 	struct target_if_spectral_ops *p_sops;
4155 
4156 	if (*is_agile_scan_inprog_5g_pdev)
4157 		return;
4158 
4159 	spectral = get_target_if_spectral_handle_from_pdev(cur_pdev);
4160 	if (!spectral) {
4161 		spectral_err("target if spectral handle is NULL");
4162 		return;
4163 	}
4164 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4165 
4166 	band = target_if_get_curr_band(
4167 			cur_pdev, spectral->vdev_id[SPECTRAL_SCAN_MODE_AGILE]);
4168 	if (band == REG_BAND_UNKNOWN) {
4169 		spectral_debug("Failed to get current band");
4170 		return;
4171 	}
4172 
4173 	if (band == REG_BAND_5G &&
4174 	    p_sops->is_spectral_active(spectral, SPECTRAL_SCAN_MODE_AGILE))
4175 		*is_agile_scan_inprog_5g_pdev = true;
4176 }
4177 
4178 /**
4179  * target_if_is_agile_supported_cur_chmask() - Is Agile Spectral scan supported
4180  * for current vdev rx chainmask.
4181  *
4182  * @spectral: Pointer to Spectral object
4183  * @is_supported: Pointer to is_supported
4184  *
4185  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4186  */
4187 static QDF_STATUS
4188 target_if_is_agile_supported_cur_chmask(struct target_if_spectral *spectral,
4189 					bool *is_supported)
4190 {
4191 	struct wlan_objmgr_vdev *vdev;
4192 	uint8_t vdev_rxchainmask;
4193 	struct wlan_objmgr_psoc *psoc;
4194 	struct wlan_objmgr_pdev *pdev;
4195 	struct target_psoc_info *tgt_psoc_info;
4196 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
4197 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr = NULL;
4198 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = NULL;
4199 	struct wlan_psoc_host_chainmask_table *table;
4200 	int j;
4201 	uint32_t table_id;
4202 	enum phy_ch_width ch_width;
4203 	uint8_t pdev_id;
4204 
4205 	if (!spectral) {
4206 		spectral_err("spectral target if object is null");
4207 		return QDF_STATUS_E_FAILURE;
4208 	}
4209 
4210 	if (!is_supported) {
4211 		spectral_err("is supported argument is null");
4212 		return QDF_STATUS_E_FAILURE;
4213 	}
4214 
4215 	if (spectral->spectral_gen <= SPECTRAL_GEN2) {
4216 		spectral_err("HW Agile mode is not supported up to gen 2");
4217 		return QDF_STATUS_E_FAILURE;
4218 	}
4219 
4220 	pdev = spectral->pdev_obj;
4221 	if (!pdev) {
4222 		spectral_err("pdev is null");
4223 		return QDF_STATUS_E_FAILURE;
4224 	}
4225 
4226 	psoc = wlan_pdev_get_psoc(pdev);
4227 	if (!psoc) {
4228 		spectral_err("psoc is null");
4229 		return QDF_STATUS_E_FAILURE;
4230 	}
4231 
4232 	vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_AGILE);
4233 	if (!vdev) {
4234 		spectral_err("First vdev is NULL");
4235 		return QDF_STATUS_E_FAILURE;
4236 	}
4237 
4238 	vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
4239 	if (!vdev_rxchainmask) {
4240 		spectral_err("vdev rx chainmask is zero");
4241 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4242 		return QDF_STATUS_E_FAILURE;
4243 	}
4244 
4245 	ch_width = target_if_vdev_get_ch_width(vdev);
4246 	if (ch_width == CH_WIDTH_INVALID) {
4247 		spectral_err("Invalid channel width");
4248 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4249 		return QDF_STATUS_E_FAILURE;
4250 	}
4251 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4252 
4253 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
4254 	if (!tgt_psoc_info) {
4255 		spectral_err("target_psoc_info is null");
4256 		return QDF_STATUS_E_FAILURE;
4257 	}
4258 
4259 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
4260 	if (!ext_svc_param) {
4261 		spectral_err("Extended service ready param null");
4262 		return QDF_STATUS_E_FAILURE;
4263 	}
4264 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
4265 
4266 	mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_psoc_info);
4267 	if (!mac_phy_cap_arr) {
4268 		spectral_err("mac phy cap array is null");
4269 		return QDF_STATUS_E_FAILURE;
4270 	}
4271 
4272 	mac_phy_cap = &mac_phy_cap_arr[pdev_id];
4273 	if (!mac_phy_cap) {
4274 		spectral_err("mac phy cap is null");
4275 		return QDF_STATUS_E_FAILURE;
4276 	}
4277 
4278 	table_id = mac_phy_cap->chainmask_table_id;
4279 	table =  &ext_svc_param->chainmask_table[table_id];
4280 	if (!table) {
4281 		spectral_err("chainmask table not found");
4282 		return QDF_STATUS_E_FAILURE;
4283 	}
4284 
4285 	for (j = 0; j < table->num_valid_chainmasks; j++) {
4286 		if (table->cap_list[j].chainmask == vdev_rxchainmask) {
4287 			if (ch_width <= CH_WIDTH_80MHZ)
4288 				*is_supported =
4289 					table->cap_list[j].supports_aSpectral;
4290 			else
4291 				*is_supported =
4292 				      table->cap_list[j].supports_aSpectral_160;
4293 			break;
4294 		}
4295 	}
4296 
4297 	if (j == table->num_valid_chainmasks) {
4298 		spectral_err("vdev rx chainmask %u not found in table id = %u",
4299 			     vdev_rxchainmask, table_id);
4300 		return QDF_STATUS_E_FAILURE;
4301 	}
4302 
4303 	return QDF_STATUS_SUCCESS;
4304 }
4305 
4306 QDF_STATUS
4307 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev,
4308 			      uint8_t vdev_id,
4309 			      const enum spectral_scan_mode smode,
4310 			      enum spectral_cp_error_code *err)
4311 {
4312 	struct target_if_spectral_ops *p_sops;
4313 	struct target_if_spectral *spectral;
4314 	struct wlan_objmgr_psoc *psoc;
4315 	enum reg_wifi_band band;
4316 
4317 	if (!err) {
4318 		spectral_err("Error code argument is null");
4319 		QDF_ASSERT(0);
4320 		return QDF_STATUS_E_FAILURE;
4321 	}
4322 	*err = SPECTRAL_SCAN_ERR_INVALID;
4323 
4324 	if (!pdev) {
4325 		spectral_err("pdev object is NUll");
4326 		return QDF_STATUS_E_FAILURE;
4327 	}
4328 
4329 	psoc = wlan_pdev_get_psoc(pdev);
4330 	if (!psoc) {
4331 		spectral_err("psoc is null");
4332 		return QDF_STATUS_E_FAILURE;
4333 	}
4334 
4335 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4336 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4337 		spectral_err("Invalid Spectral mode %u", smode);
4338 		return QDF_STATUS_E_FAILURE;
4339 	}
4340 
4341 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4342 	if (!spectral) {
4343 		spectral_err("Spectral LMAC object is NUll");
4344 		return QDF_STATUS_E_FAILURE;
4345 	}
4346 
4347 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4348 	if (!p_sops) {
4349 		spectral_err("p_sops is null");
4350 		return QDF_STATUS_E_FAILURE;
4351 	}
4352 
4353 	if (p_sops->is_spectral_active(spectral, smode)) {
4354 		spectral_err("spectral in progress in current pdev, mode %d",
4355 			     smode);
4356 		return QDF_STATUS_E_FAILURE;
4357 	}
4358 	spectral->vdev_id[smode] = vdev_id;
4359 
4360 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
4361 		QDF_STATUS status;
4362 		bool is_supported = false;
4363 
4364 		status = target_if_is_agile_supported_cur_chmask(spectral,
4365 								 &is_supported);
4366 		if (QDF_IS_STATUS_ERROR(status)) {
4367 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4368 			return QDF_STATUS_E_FAILURE;
4369 		}
4370 
4371 		if (!is_supported) {
4372 			spectral_err("aSpectral unsupported for cur chainmask");
4373 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4374 			return QDF_STATUS_E_FAILURE;
4375 		}
4376 	}
4377 
4378 	band = target_if_get_curr_band(spectral->pdev_obj, vdev_id);
4379 	if (band == REG_BAND_UNKNOWN) {
4380 		spectral_err("Failed to get current band");
4381 		return QDF_STATUS_E_FAILURE;
4382 	}
4383 	if ((band == REG_BAND_5G) && (smode == SPECTRAL_SCAN_MODE_AGILE)) {
4384 		struct target_psoc_info *tgt_hdl;
4385 		enum wmi_host_hw_mode_config_type mode;
4386 		bool is_agile_scan_inprog_5g_pdev;
4387 
4388 		tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
4389 		if (!tgt_hdl) {
4390 			target_if_err("target_psoc_info is null");
4391 			return QDF_STATUS_E_FAILURE;
4392 		}
4393 
4394 		mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
4395 		switch (mode) {
4396 		case WMI_HOST_HW_MODE_SBS_PASSIVE:
4397 		case WMI_HOST_HW_MODE_SBS:
4398 		case WMI_HOST_HW_MODE_DBS_SBS:
4399 		case WMI_HOST_HW_MODE_DBS_OR_SBS:
4400 			is_agile_scan_inprog_5g_pdev = false;
4401 			wlan_objmgr_iterate_obj_list
4402 				(psoc, WLAN_PDEV_OP,
4403 				 target_if_is_agile_scan_active_in_5g,
4404 				 &is_agile_scan_inprog_5g_pdev, 0,
4405 				 WLAN_SPECTRAL_ID);
4406 			break;
4407 		default:
4408 			is_agile_scan_inprog_5g_pdev = false;
4409 			break;
4410 		}
4411 
4412 		if (is_agile_scan_inprog_5g_pdev) {
4413 			spectral_err("Agile Scan in progress in one of the SBS 5G pdev");
4414 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4415 			return QDF_STATUS_E_FAILURE;
4416 		}
4417 	}
4418 
4419 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
4420 		bool is_aspectral_prohibited = false;
4421 		QDF_STATUS status;
4422 
4423 		status = wlan_objmgr_iterate_obj_list
4424 				(psoc, WLAN_PDEV_OP,
4425 				 target_if_is_aspectral_prohibited_by_adfs,
4426 				 &is_aspectral_prohibited, 0,
4427 				 WLAN_SPECTRAL_ID);
4428 		if (QDF_IS_STATUS_ERROR(status)) {
4429 			spectral_err("Failed to iterate over pdevs");
4430 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4431 			return QDF_STATUS_E_FAILURE;
4432 		}
4433 
4434 		if (is_aspectral_prohibited) {
4435 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4436 			return QDF_STATUS_E_FAILURE;
4437 		}
4438 	}
4439 
4440 	if (!spectral->params_valid[smode]) {
4441 		target_if_spectral_info_read(spectral,
4442 					     smode,
4443 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
4444 					     &spectral->params[smode],
4445 					     sizeof(spectral->params[smode]));
4446 		spectral->params_valid[smode] = true;
4447 	}
4448 
4449 	qdf_spin_lock(&spectral->spectral_lock);
4450 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
4451 		QDF_STATUS status;
4452 		bool is_overlapping;
4453 		enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX];
4454 		enum spectral_scan_mode m;
4455 		enum phy_ch_width op_ch_width;
4456 		enum phy_ch_width agile_ch_width;
4457 
4458 		m = SPECTRAL_SCAN_MODE_NORMAL;
4459 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
4460 			ch_width[m] = CH_WIDTH_INVALID;
4461 		status = target_if_spectral_populate_chwidth
4462 			(spectral, ch_width, spectral->params
4463 			 [SPECTRAL_SCAN_MODE_AGILE].ss_frequency.cfreq2 > 0);
4464 		if (QDF_IS_STATUS_ERROR(status)) {
4465 			qdf_spin_unlock(&spectral->spectral_lock);
4466 			spectral_err("Failed to populate channel width");
4467 			return QDF_STATUS_E_FAILURE;
4468 		}
4469 		op_ch_width = ch_width[SPECTRAL_SCAN_MODE_NORMAL];
4470 		agile_ch_width = ch_width[SPECTRAL_SCAN_MODE_AGILE];
4471 
4472 		if (!spectral->params[smode].ss_frequency.cfreq1 ||
4473 		    (agile_ch_width == CH_WIDTH_80P80MHZ &&
4474 		    !spectral->params[smode].ss_frequency.cfreq2)) {
4475 			*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
4476 			qdf_spin_unlock(&spectral->spectral_lock);
4477 			return QDF_STATUS_E_FAILURE;
4478 		}
4479 
4480 		status = target_if_is_agile_span_overlap_with_operating_span
4481 				(spectral, ch_width,
4482 				 &spectral->params[smode].ss_frequency,
4483 				 &is_overlapping);
4484 		if (QDF_IS_STATUS_ERROR(status)) {
4485 			qdf_spin_unlock(&spectral->spectral_lock);
4486 			return QDF_STATUS_E_FAILURE;
4487 		}
4488 
4489 		if (is_overlapping) {
4490 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
4491 			qdf_spin_unlock(&spectral->spectral_lock);
4492 			return QDF_STATUS_E_FAILURE;
4493 		}
4494 	}
4495 
4496 	target_if_spectral_scan_enable_params(spectral,
4497 					      &spectral->params[smode], smode,
4498 					      err);
4499 	qdf_spin_unlock(&spectral->spectral_lock);
4500 
4501 	return QDF_STATUS_SUCCESS;
4502 }
4503 
4504 QDF_STATUS
4505 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev,
4506 			     const enum spectral_scan_mode smode,
4507 			     enum spectral_cp_error_code *err)
4508 {
4509 	struct target_if_spectral_ops *p_sops;
4510 	struct target_if_spectral *spectral;
4511 
4512 	if (!err) {
4513 		spectral_err("Error code argument is null");
4514 		QDF_ASSERT(0);
4515 		return QDF_STATUS_E_FAILURE;
4516 	}
4517 	*err = SPECTRAL_SCAN_ERR_INVALID;
4518 
4519 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4520 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
4521 		spectral_err("Invalid Spectral mode %u", smode);
4522 		return QDF_STATUS_E_FAILURE;
4523 	}
4524 
4525 	if (!pdev) {
4526 		spectral_err("pdev object is NUll ");
4527 		return QDF_STATUS_E_FAILURE;
4528 	}
4529 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4530 	if (!spectral) {
4531 		spectral_err("Spectral LMAC object is NUll ");
4532 		return QDF_STATUS_E_FAILURE;
4533 	}
4534 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4535 
4536 	qdf_spin_lock(&spectral->spectral_lock);
4537 	p_sops->stop_spectral_scan(spectral, smode);
4538 	if (spectral->classify_scan) {
4539 		/* TODO : Check if this logic is necessary */
4540 		spectral->detects_control_channel = 0;
4541 		spectral->detects_extension_channel = 0;
4542 		spectral->detects_above_dc = 0;
4543 		spectral->detects_below_dc = 0;
4544 		spectral->classify_scan = 0;
4545 	}
4546 
4547 	spectral->send_single_packet = 0;
4548 	spectral->sc_spectral_scan = 0;
4549 	spectral->vdev_id[smode] = WLAN_INVALID_VDEV_ID;
4550 
4551 	qdf_spin_unlock(&spectral->spectral_lock);
4552 
4553 	return QDF_STATUS_SUCCESS;
4554 }
4555 
4556 /**
4557  * target_if_is_spectral_active() - Get whether Spectral is active
4558  * @pdev: Pointer to pdev object
4559  * @smode: Spectral scan mode
4560  *
4561  * API to get whether Spectral is active
4562  *
4563  * Return: True if Spectral is active, false if Spectral is not active
4564  */
4565 bool
4566 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev,
4567 			     const enum spectral_scan_mode smode)
4568 {
4569 	struct target_if_spectral *spectral = NULL;
4570 	struct target_if_spectral_ops *p_sops = NULL;
4571 
4572 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4573 
4574 	if (!spectral) {
4575 		spectral_err("SPECTRAL : Module doesn't exist");
4576 		return QDF_STATUS_E_FAILURE;
4577 	}
4578 
4579 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4580 
4581 	if (!p_sops) {
4582 		spectral_err("p_sops is null");
4583 		return QDF_STATUS_E_FAILURE;
4584 	}
4585 
4586 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4587 		spectral_err("Invalid Spectral mode %u", smode);
4588 		return QDF_STATUS_E_FAILURE;
4589 	}
4590 
4591 	return p_sops->is_spectral_active(spectral, smode);
4592 }
4593 
4594 /**
4595  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
4596  * @pdev: Pointer to pdev object
4597  * @smode: Spectral scan mode
4598  *
4599  * API to get whether Spectral is enabled
4600  *
4601  * Return: True if Spectral is enabled, false if Spectral is not enabled
4602  */
4603 bool
4604 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev,
4605 			      enum spectral_scan_mode smode)
4606 {
4607 	struct target_if_spectral *spectral = NULL;
4608 	struct target_if_spectral_ops *p_sops = NULL;
4609 
4610 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4611 
4612 	if (!spectral) {
4613 		spectral_err("SPECTRAL : Module doesn't exist");
4614 		return QDF_STATUS_E_FAILURE;
4615 	}
4616 
4617 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4618 
4619 	if (!p_sops) {
4620 		spectral_err("p_sops is null");
4621 		return QDF_STATUS_E_FAILURE;
4622 	}
4623 
4624 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
4625 		spectral_err("Invalid Spectral mode %u", smode);
4626 		return QDF_STATUS_E_FAILURE;
4627 	}
4628 
4629 	return p_sops->is_spectral_enabled(spectral, smode);
4630 }
4631 
4632 #ifdef DIRECT_BUF_RX_DEBUG
4633 /**
4634  * target_if_spectral_do_dbr_ring_debug() - Start/Stop Spectral DMA ring debug
4635  * @pdev: Pointer to pdev object
4636  * @enable: Enable/Disable Spectral DMA ring debug
4637  *
4638  * Start/stop Spectral DMA ring debug based on @enable.
4639  * Also save the state for future use.
4640  *
4641  * Return: QDF_STATUS of operation
4642  */
4643 static QDF_STATUS
4644 target_if_spectral_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev, bool enable)
4645 {
4646 	struct target_if_spectral *spectral;
4647 	struct wlan_lmac_if_tx_ops *tx_ops;
4648 	struct wlan_objmgr_psoc *psoc;
4649 
4650 	if (!pdev)
4651 		return QDF_STATUS_E_FAILURE;
4652 
4653 	psoc = wlan_pdev_get_psoc(pdev);
4654 	if (!psoc) {
4655 		spectral_err("psoc is null");
4656 		return QDF_STATUS_E_INVAL;
4657 	}
4658 
4659 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
4660 	if (!tx_ops) {
4661 		spectral_err("tx_ops is NULL");
4662 		return QDF_STATUS_E_INVAL;
4663 	}
4664 
4665 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4666 	if (!spectral) {
4667 		spectral_err("Spectal LMAC object is NULL");
4668 		return QDF_STATUS_E_INVAL;
4669 	}
4670 
4671 	/* Save the state */
4672 	spectral->dbr_ring_debug = enable;
4673 
4674 	if (enable)
4675 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_ring_debug(
4676 				pdev, 0, SPECTRAL_DBR_RING_DEBUG_SIZE);
4677 	else
4678 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_ring_debug(
4679 				pdev, 0);
4680 
4681 	return QDF_STATUS_SUCCESS;
4682 }
4683 
4684 /**
4685  * target_if_spectral_do_dbr_buff_debug() - Start/Stop Spectral DMA buffer debug
4686  * @pdev: Pointer to pdev object
4687  * @enable: Enable/Disable Spectral DMA buffer debug
4688  *
4689  * Start/stop Spectral DMA buffer debug based on @enable.
4690  * Also save the state for future use.
4691  *
4692  * Return: QDF_STATUS of operation
4693  */
4694 static QDF_STATUS
4695 target_if_spectral_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev, bool enable)
4696 {
4697 	struct target_if_spectral *spectral;
4698 	struct wlan_lmac_if_tx_ops *tx_ops;
4699 	struct wlan_objmgr_psoc *psoc;
4700 
4701 	if (!pdev)
4702 		return QDF_STATUS_E_FAILURE;
4703 
4704 	psoc = wlan_pdev_get_psoc(pdev);
4705 	if (!psoc) {
4706 		spectral_err("psoc is null");
4707 		return QDF_STATUS_E_INVAL;
4708 	}
4709 
4710 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
4711 	if (!tx_ops) {
4712 		spectral_err("tx_ops is NULL");
4713 		return QDF_STATUS_E_INVAL;
4714 	}
4715 
4716 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4717 	if (!spectral) {
4718 		spectral_err("Spectal LMAC object is NULL");
4719 		return QDF_STATUS_E_INVAL;
4720 	}
4721 
4722 	/* Save the state */
4723 	spectral->dbr_buff_debug = enable;
4724 
4725 	if (enable)
4726 		return tx_ops->dbr_tx_ops.direct_buf_rx_start_buffer_poisoning(
4727 				pdev, 0, MEM_POISON_SIGNATURE);
4728 	else
4729 		return tx_ops->dbr_tx_ops.direct_buf_rx_stop_buffer_poisoning(
4730 				pdev, 0);
4731 }
4732 
4733 /**
4734  * target_if_spectral_check_and_do_dbr_buff_debug() - Start/Stop Spectral buffer
4735  * debug based on the previous state
4736  * @pdev: Pointer to pdev object
4737  *
4738  * Return: QDF_STATUS of operation
4739  */
4740 static QDF_STATUS
4741 target_if_spectral_check_and_do_dbr_buff_debug(struct wlan_objmgr_pdev *pdev)
4742 {
4743 	struct target_if_spectral *spectral;
4744 
4745 	if (!pdev) {
4746 		spectral_err("pdev is NULL!");
4747 		return QDF_STATUS_E_FAILURE;
4748 	}
4749 
4750 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4751 	if (!spectral) {
4752 		spectral_err("Spectal LMAC object is NULL");
4753 		return QDF_STATUS_E_INVAL;
4754 	}
4755 
4756 	if (spectral->dbr_buff_debug)
4757 		return target_if_spectral_do_dbr_buff_debug(pdev, true);
4758 	else
4759 		return target_if_spectral_do_dbr_buff_debug(pdev, false);
4760 }
4761 
4762 /**
4763  * target_if_spectral_check_and_do_dbr_ring_debug() - Start/Stop Spectral ring
4764  * debug based on the previous state
4765  * @pdev: Pointer to pdev object
4766  *
4767  * Return: QDF_STATUS of operation
4768  */
4769 static QDF_STATUS
4770 target_if_spectral_check_and_do_dbr_ring_debug(struct wlan_objmgr_pdev *pdev)
4771 {
4772 	struct target_if_spectral *spectral;
4773 
4774 	if (!pdev) {
4775 		spectral_err("pdev is NULL!");
4776 		return QDF_STATUS_E_FAILURE;
4777 	}
4778 
4779 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4780 	if (!spectral) {
4781 		spectral_err("Spectal LMAC object is NULL");
4782 		return QDF_STATUS_E_INVAL;
4783 	}
4784 
4785 	if (spectral->dbr_ring_debug)
4786 		return target_if_spectral_do_dbr_ring_debug(pdev, true);
4787 	else
4788 		return target_if_spectral_do_dbr_ring_debug(pdev, false);
4789 }
4790 
4791 /**
4792  * target_if_spectral_set_dma_debug() - Set DMA debug for Spectral
4793  * @pdev: Pointer to pdev object
4794  * @dma_debug_type: Type of Spectral DMA debug i.e., ring or buffer debug
4795  * @debug_value: Value to be set for @dma_debug_type
4796  *
4797  * Set DMA debug for Spectral and start/stop Spectral DMA debug function
4798  * based on @debug_value
4799  *
4800  * Return: QDF_STATUS of operation
4801  */
4802 static QDF_STATUS
4803 target_if_spectral_set_dma_debug(
4804 	struct wlan_objmgr_pdev *pdev,
4805 	enum spectral_dma_debug dma_debug_type,
4806 	bool debug_value)
4807 {
4808 	struct target_if_spectral_ops *p_sops;
4809 	struct wlan_objmgr_psoc *psoc;
4810 	struct wlan_lmac_if_tx_ops *tx_ops;
4811 	struct target_if_spectral *spectral;
4812 
4813 	if (!pdev)
4814 		return QDF_STATUS_E_FAILURE;
4815 
4816 	psoc = wlan_pdev_get_psoc(pdev);
4817 	if (!psoc) {
4818 		spectral_err("psoc is null");
4819 		return QDF_STATUS_E_INVAL;
4820 	}
4821 
4822 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
4823 	if (!tx_ops) {
4824 		spectral_err("tx_ops is NULL");
4825 		return QDF_STATUS_E_FAILURE;
4826 	}
4827 
4828 	if (!tx_ops->target_tx_ops.tgt_get_tgt_type) {
4829 		spectral_err("Unable to fetch target type");
4830 		return QDF_STATUS_E_FAILURE;
4831 	}
4832 
4833 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4834 	if (!spectral) {
4835 		spectral_err("Spectal LMAC object is NULL");
4836 		return QDF_STATUS_E_INVAL;
4837 	}
4838 
4839 	if (spectral->direct_dma_support) {
4840 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
4841 		if (p_sops->is_spectral_active(spectral,
4842 					       SPECTRAL_SCAN_MODE_NORMAL) ||
4843 		    p_sops->is_spectral_active(spectral,
4844 					       SPECTRAL_SCAN_MODE_AGILE)) {
4845 			spectral_err("Altering DBR debug config isn't allowed during an ongoing scan");
4846 			return QDF_STATUS_E_FAILURE;
4847 		}
4848 
4849 		switch (dma_debug_type) {
4850 		case SPECTRAL_DMA_RING_DEBUG:
4851 			target_if_spectral_do_dbr_ring_debug(pdev, debug_value);
4852 			break;
4853 
4854 		case SPECTRAL_DMA_BUFFER_DEBUG:
4855 			target_if_spectral_do_dbr_buff_debug(pdev, debug_value);
4856 			break;
4857 
4858 		default:
4859 			spectral_err("Unsupported DMA debug type : %d",
4860 				     dma_debug_type);
4861 			return QDF_STATUS_E_FAILURE;
4862 		}
4863 	}
4864 	return QDF_STATUS_SUCCESS;
4865 }
4866 #endif /* DIRECT_BUF_RX_DEBUG */
4867 
4868 /**
4869  * target_if_spectral_direct_dma_support() - Get Direct-DMA support
4870  * @pdev: Pointer to pdev object
4871  *
4872  * Return: Whether Direct-DMA is supported on this radio
4873  */
4874 static bool
4875 target_if_spectral_direct_dma_support(struct wlan_objmgr_pdev *pdev)
4876 {
4877 	struct target_if_spectral *spectral;
4878 
4879 	if (!pdev) {
4880 		spectral_err("pdev is NULL!");
4881 		return false;
4882 	}
4883 
4884 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4885 	if (!spectral) {
4886 		spectral_err("Spectral LMAC object is NULL");
4887 		return false;
4888 	}
4889 
4890 	return spectral->direct_dma_support;
4891 }
4892 
4893 /**
4894  * target_if_set_debug_level() - Set debug level for Spectral
4895  * @pdev: Pointer to pdev object
4896  * @debug_level: Debug level
4897  *
4898  * API to set the debug level for Spectral
4899  *
4900  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4901  */
4902 QDF_STATUS
4903 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
4904 {
4905 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
4906 
4907 	return QDF_STATUS_SUCCESS;
4908 }
4909 
4910 /**
4911  * target_if_get_debug_level() - Get debug level for Spectral
4912  * @pdev: Pointer to pdev object
4913  *
4914  * API to get the debug level for Spectral
4915  *
4916  * Return: Current debug level
4917  */
4918 uint32_t
4919 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
4920 {
4921 	return spectral_debug_level;
4922 }
4923 
4924 /**
4925  * target_if_get_spectral_capinfo() - Get Spectral capability information
4926  * @pdev: Pointer to pdev object
4927  * @scaps: Buffer into which data should be copied
4928  *
4929  * API to get the spectral capability information
4930  *
4931  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4932  */
4933 QDF_STATUS
4934 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev,
4935 			       struct spectral_caps *scaps)
4936 {
4937 	struct target_if_spectral *spectral = NULL;
4938 
4939 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4940 	if (!spectral) {
4941 		spectral_err("SPECTRAL : Module doesn't exist");
4942 		return QDF_STATUS_E_FAILURE;
4943 	}
4944 
4945 	qdf_mem_copy(scaps, &spectral->capability,
4946 		     sizeof(struct spectral_caps));
4947 
4948 	return QDF_STATUS_SUCCESS;
4949 }
4950 
4951 /**
4952  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
4953  * @pdev:  Pointer to pdev object
4954  * @stats: Buffer into which data should be copied
4955  *
4956  * API to get the spectral diagnostic statistics
4957  *
4958  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
4959  */
4960 QDF_STATUS
4961 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev,
4962 				 struct spectral_diag_stats *stats)
4963 {
4964 	struct target_if_spectral *spectral = NULL;
4965 
4966 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4967 	if (!spectral) {
4968 		spectral_err("SPECTRAL : Module doesn't exist");
4969 		return QDF_STATUS_E_FAILURE;
4970 	}
4971 
4972 	qdf_mem_copy(stats, &spectral->diag_stats,
4973 		     sizeof(struct spectral_diag_stats));
4974 
4975 	return QDF_STATUS_SUCCESS;
4976 }
4977 
4978 /**
4979  * target_if_register_spectral_wmi_ops() - Register Spectral WMI operations
4980  * @psoc: Pointer to psoc object
4981  * @wmi_ops: Pointer to the structure having Spectral WMI operations
4982  *
4983  * API for registering Spectral WMI operations in
4984  * spectral internal data structure
4985  *
4986  * Return: QDF_STATUS
4987  */
4988 static QDF_STATUS
4989 target_if_register_spectral_wmi_ops(struct wlan_objmgr_psoc *psoc,
4990 				    struct spectral_wmi_ops *wmi_ops)
4991 {
4992 	struct target_if_psoc_spectral *psoc_spectral;
4993 
4994 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
4995 	if (!psoc_spectral) {
4996 		spectral_err("Spectral LMAC object is null");
4997 		return QDF_STATUS_E_INVAL;
4998 	}
4999 
5000 	psoc_spectral->wmi_ops = *wmi_ops;
5001 
5002 	return QDF_STATUS_SUCCESS;
5003 }
5004 
5005 /**
5006  * target_if_register_spectral_tgt_ops() - Register Spectral target operations
5007  * @psoc: Pointer to psoc object
5008  * @tgt_ops: Pointer to the structure having Spectral target operations
5009  *
5010  * API for registering Spectral target operations in
5011  * spectral internal data structure
5012  *
5013  * Return: QDF_STATUS
5014  */
5015 static QDF_STATUS
5016 target_if_register_spectral_tgt_ops(struct wlan_objmgr_psoc *psoc,
5017 				    struct spectral_tgt_ops *tgt_ops)
5018 {
5019 	if (!psoc) {
5020 		spectral_err("psoc is null");
5021 		return QDF_STATUS_E_INVAL;
5022 	}
5023 
5024 	ops_tgt = *tgt_ops;
5025 
5026 	return QDF_STATUS_SUCCESS;
5027 }
5028 
5029 /**
5030  * target_if_register_netlink_cb() - Register Netlink callbacks
5031  * @pdev: Pointer to pdev object
5032  * @nl_cb: Netlink callbacks to register
5033  *
5034  * Return: void
5035  */
5036 static void
5037 target_if_register_netlink_cb(
5038 	struct wlan_objmgr_pdev *pdev,
5039 	struct spectral_nl_cb *nl_cb)
5040 {
5041 	struct target_if_spectral *spectral = NULL;
5042 
5043 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5044 
5045 	if (!spectral) {
5046 		spectral_err("SPECTRAL : Module doesn't exist");
5047 		return;
5048 	}
5049 
5050 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
5051 
5052 	if (spectral->use_nl_bcast)
5053 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
5054 	else
5055 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
5056 }
5057 
5058 /**
5059  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
5060  * Netlink messages to the application layer
5061  * @pdev: Pointer to pdev object
5062  *
5063  * Return: true for broadcast, false for unicast
5064  */
5065 static bool
5066 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
5067 {
5068 	struct target_if_spectral *spectral = NULL;
5069 
5070 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5071 
5072 	if (!spectral) {
5073 		spectral_err("SPECTRAL : Module doesn't exist");
5074 		return false;
5075 	}
5076 
5077 	return spectral->use_nl_bcast;
5078 }
5079 
5080 /**
5081  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
5082  * @pdev: Pointer to pdev object
5083  *
5084  * Return: void
5085  */
5086 static void
5087 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
5088 {
5089 	struct target_if_spectral *spectral = NULL;
5090 
5091 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5092 	if (!spectral) {
5093 		spectral_err("SPECTRAL : Module doesn't exist");
5094 		return;
5095 	}
5096 
5097 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
5098 }
5099 
5100 static int
5101 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
5102 				  void *payload)
5103 {
5104 	struct target_if_spectral *spectral = NULL;
5105 	struct target_if_spectral_ops *p_sops = NULL;
5106 
5107 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5108 	if (!spectral) {
5109 		spectral_err("SPECTRAL : Module doesn't exist");
5110 		return -EPERM;
5111 	}
5112 
5113 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5114 
5115 	if (!p_sops) {
5116 		spectral_err("p_sops is null");
5117 		return -EPERM;
5118 	}
5119 
5120 	return p_sops->process_spectral_report(pdev, payload);
5121 }
5122 
5123 #ifdef DIRECT_BUF_RX_DEBUG
5124 static inline void
5125 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
5126 {
5127 	if (!tx_ops) {
5128 		spectral_err("tx_ops is NULL");
5129 		return;
5130 	}
5131 
5132 	tx_ops->sptrl_tx_ops.sptrlto_set_dma_debug =
5133 		target_if_spectral_set_dma_debug;
5134 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_ring_debug =
5135 		target_if_spectral_check_and_do_dbr_ring_debug;
5136 	tx_ops->sptrl_tx_ops.sptrlto_check_and_do_dbr_buff_debug =
5137 		target_if_spectral_check_and_do_dbr_buff_debug;
5138 }
5139 #else
5140 static inline void
5141 target_if_sptrl_debug_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
5142 {
5143 }
5144 #endif
5145 
5146 #if defined(WLAN_CONV_SPECTRAL_ENABLE) && defined(SPECTRAL_MODULIZED_ENABLE)
5147 /**
5148  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
5149  * register WMI event handler
5150  * @psoc: Pointer to psoc object
5151  * @event_id: Event id
5152  * @handler_func: Handler function
5153  * @rx_ctx: Context of WMI event processing
5154  *
5155  * Wrapper function to register WMI event handler
5156  *
5157  * Return: 0 for success else failure
5158  */
5159 static int
5160 target_if_spectral_wmi_unified_register_event_handler(
5161 				struct wlan_objmgr_psoc *psoc,
5162 				wmi_conv_event_id event_id,
5163 				wmi_unified_event_handler handler_func,
5164 				uint8_t rx_ctx)
5165 {
5166 	wmi_unified_t wmi_handle;
5167 	struct target_if_psoc_spectral *psoc_spectral;
5168 	QDF_STATUS ret;
5169 
5170 	if (!psoc) {
5171 		spectral_err("psoc is null");
5172 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5173 	}
5174 
5175 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5176 	if (!wmi_handle) {
5177 		spectral_err("WMI handle is null");
5178 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5179 	}
5180 
5181 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5182 	if (!psoc_spectral) {
5183 		spectral_err("spectral object is null");
5184 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5185 	}
5186 
5187 	ret = psoc_spectral->wmi_ops.wmi_unified_register_event_handler(
5188 			wmi_handle, event_id, handler_func, rx_ctx);
5189 
5190 	return qdf_status_to_os_return(ret);
5191 }
5192 
5193 /**
5194  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
5195  * to unregister WMI event handler
5196  * @psoc: Pointer to psoc object
5197  * @event_id: Event id
5198  *
5199  * Wrapper function to unregister WMI event handler
5200  *
5201  * Return: 0 for success else failure
5202  */
5203 static int
5204 target_if_spectral_wmi_unified_unregister_event_handler(
5205 				struct wlan_objmgr_psoc *psoc,
5206 				wmi_conv_event_id event_id)
5207 {
5208 	wmi_unified_t wmi_handle;
5209 	struct target_if_psoc_spectral *psoc_spectral;
5210 	QDF_STATUS ret;
5211 
5212 	if (!psoc) {
5213 		spectral_err("psoc is null");
5214 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5215 	}
5216 
5217 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5218 	if (!wmi_handle) {
5219 		spectral_err("WMI handle is null");
5220 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5221 	}
5222 
5223 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5224 	if (!psoc_spectral) {
5225 		spectral_err("spectral object is null");
5226 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5227 	}
5228 
5229 	ret = psoc_spectral->wmi_ops.wmi_unified_unregister_event_handler(
5230 					wmi_handle, event_id);
5231 
5232 	return qdf_status_to_os_return(ret);
5233 }
5234 
5235 /**
5236  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
5237  * function to extract fixed parameters from start scan response event
5238  * @psoc: Pointer to psoc object
5239  * @evt_buf: Event buffer
5240  * @param: Start scan response parameters
5241  *
5242  * Wrapper function to extract fixed parameters from start scan response event
5243  *
5244  * Return: QDF_STATUS
5245  */
5246 static QDF_STATUS
5247 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5248 			struct wlan_objmgr_psoc *psoc,
5249 			uint8_t *evt_buf,
5250 			struct spectral_startscan_resp_params *param)
5251 {
5252 	wmi_unified_t wmi_handle;
5253 	struct target_if_psoc_spectral *psoc_spectral;
5254 
5255 	if (!psoc) {
5256 		spectral_err("psoc is null");
5257 		return QDF_STATUS_E_INVAL;
5258 	}
5259 
5260 	if (!evt_buf) {
5261 		spectral_err("WMI event buffer is null");
5262 		return QDF_STATUS_E_INVAL;
5263 	}
5264 
5265 	if (!param) {
5266 		spectral_err("Spectral startscan response parameters is null");
5267 		return QDF_STATUS_E_INVAL;
5268 	}
5269 
5270 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5271 	if (!wmi_handle) {
5272 		spectral_err("WMI handle is null");
5273 		return QDF_STATUS_E_INVAL;
5274 	}
5275 
5276 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5277 	if (!psoc_spectral) {
5278 		spectral_err("spectral object is null");
5279 		return QDF_STATUS_E_FAILURE;
5280 	}
5281 
5282 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5283 			wmi_handle, evt_buf, param);
5284 }
5285 
5286 /**
5287  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
5288  * function to extract start and end indices of primary 80 MHz, 5 MHz and
5289  * secondary 80 MHz FFT bins
5290  * @psoc: Pointer to psoc object
5291  * @evt_buf: Event buffer
5292  * @param: FFT bin start and end indices
5293  *
5294  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
5295  * and secondary 80 MHz FFT bins
5296  *
5297  * Return: QDF_STATUS
5298  */
5299 static QDF_STATUS
5300 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
5301 			struct wlan_objmgr_psoc *psoc,
5302 			uint8_t *evt_buf,
5303 			struct spectral_fft_bin_markers_160_165mhz *param)
5304 {
5305 	wmi_unified_t wmi_handle;
5306 	struct target_if_psoc_spectral *psoc_spectral;
5307 
5308 	if (!psoc) {
5309 		spectral_err("psoc is null");
5310 		return QDF_STATUS_E_INVAL;
5311 	}
5312 
5313 	if (!evt_buf) {
5314 		spectral_err("WMI event buffer is null");
5315 		return QDF_STATUS_E_INVAL;
5316 	}
5317 
5318 	if (!param) {
5319 		spectral_err("Spectral FFT bin markers is null");
5320 		return QDF_STATUS_E_INVAL;
5321 	}
5322 
5323 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5324 	if (!wmi_handle) {
5325 		spectral_err("WMI handle is null");
5326 		return QDF_STATUS_E_INVAL;
5327 	}
5328 
5329 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5330 	if (!psoc_spectral) {
5331 		spectral_err("spectral object is null");
5332 		return QDF_STATUS_E_FAILURE;
5333 	}
5334 
5335 	return psoc_spectral->wmi_ops.wmi_extract_pdev_sscan_fft_bin_index(
5336 			wmi_handle, evt_buf, param);
5337 }
5338 
5339 /**
5340  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
5341  * object from scn handle
5342  * @scn: scn handle
5343  *
5344  * Wrapper function to get psoc object from scn handle
5345  *
5346  * Return: Pointer to psoc object
5347  */
5348 static struct wlan_objmgr_psoc *
5349 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
5350 {
5351 	if (!scn) {
5352 		spectral_err("scn is null");
5353 		return NULL;
5354 	}
5355 
5356 	return ops_tgt.tgt_get_psoc_from_scn_hdl(scn);
5357 }
5358 #else
5359 /**
5360  * target_if_spectral_wmi_unified_register_event_handler() - Wrapper function to
5361  * register WMI event handler
5362  * @psoc: Pointer to psoc object
5363  * @event_id: Event id
5364  * @handler_func: Handler function
5365  * @rx_ctx: Context of WMI event processing
5366  *
5367  * Wrapper function to register WMI event handler
5368  *
5369  * Return: 0 for success else failure
5370  */
5371 static int
5372 target_if_spectral_wmi_unified_register_event_handler(
5373 				struct wlan_objmgr_psoc *psoc,
5374 				wmi_conv_event_id event_id,
5375 				wmi_unified_event_handler handler_func,
5376 				uint8_t rx_ctx)
5377 {
5378 	wmi_unified_t wmi_handle;
5379 	QDF_STATUS ret;
5380 
5381 	if (!psoc) {
5382 		spectral_err("psoc is null");
5383 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5384 	}
5385 
5386 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5387 	if (!wmi_handle) {
5388 		spectral_err("WMI handle is null");
5389 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5390 	}
5391 
5392 	ret = wmi_unified_register_event_handler(wmi_handle, event_id,
5393 						 handler_func, rx_ctx);
5394 
5395 	return qdf_status_to_os_return(ret);
5396 }
5397 
5398 /**
5399  * target_if_spectral_wmi_unified_unregister_event_handler() - Wrapper function
5400  * to unregister WMI event handler
5401  * @psoc: Pointer to psoc object
5402  * @event_id: Event id
5403  *
5404  * Wrapper function to unregister WMI event handler
5405  *
5406  * Return: 0 for success else failure
5407  */
5408 static int
5409 target_if_spectral_wmi_unified_unregister_event_handler(
5410 				struct wlan_objmgr_psoc *psoc,
5411 				wmi_conv_event_id event_id)
5412 {
5413 	wmi_unified_t wmi_handle;
5414 	QDF_STATUS ret;
5415 
5416 	if (!psoc) {
5417 		spectral_err("psoc is null");
5418 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5419 	}
5420 
5421 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5422 	if (!wmi_handle) {
5423 		spectral_err("WMI handle is null");
5424 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5425 	}
5426 
5427 	ret = wmi_unified_unregister_event_handler(wmi_handle, event_id);
5428 
5429 	return qdf_status_to_os_return(ret);
5430 }
5431 
5432 /**
5433  * target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param() - Wrapper
5434  * function to extract fixed parameters from start scan response event
5435  * @psoc: Pointer to psoc object
5436  * @evt_buf: Event buffer
5437  * @param: Start scan response parameters
5438  *
5439  * Wrapper function to extract fixed parameters from start scan response event
5440  *
5441  * Return: QDF_STATUS
5442  */
5443 static QDF_STATUS
5444 target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5445 			struct wlan_objmgr_psoc *psoc,
5446 			uint8_t *evt_buf,
5447 			struct spectral_startscan_resp_params *param)
5448 {
5449 	wmi_unified_t wmi_handle;
5450 
5451 	if (!psoc) {
5452 		spectral_err("psoc is null");
5453 		return QDF_STATUS_E_INVAL;
5454 	}
5455 
5456 	if (!evt_buf) {
5457 		spectral_err("WMI event buffer is null");
5458 		return QDF_STATUS_E_INVAL;
5459 	}
5460 
5461 	if (!param) {
5462 		spectral_err("Spectral startscan response parameters is null");
5463 		return QDF_STATUS_E_INVAL;
5464 	}
5465 
5466 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5467 	if (!wmi_handle) {
5468 		spectral_err("WMI handle is null");
5469 		return QDF_STATUS_E_INVAL;
5470 	}
5471 
5472 	return wmi_extract_pdev_sscan_fw_cmd_fixed_param(wmi_handle, evt_buf,
5473 							 param);
5474 }
5475 
5476 /**
5477  * target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index() - Wrapper
5478  * function to extract start and end indices of primary 80 MHz, 5 MHz and
5479  * secondary 80 MHz FFT bins
5480  * @psoc: Pointer to psoc object
5481  * @evt_buf: Event buffer
5482  * @param: FFT bin start and end indices
5483  *
5484  * Wrapper function to extract start and end indices of primary 80 MHz, 5 MHz
5485  * and secondary 80 MHz FFT bins
5486  *
5487  * Return: QDF_STATUS
5488  */
5489 static QDF_STATUS
5490 target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
5491 			struct wlan_objmgr_psoc *psoc,
5492 			uint8_t *evt_buf,
5493 			struct spectral_fft_bin_markers_160_165mhz *param)
5494 {
5495 	wmi_unified_t wmi_handle;
5496 
5497 	if (!psoc) {
5498 		spectral_err("psoc is null");
5499 		return QDF_STATUS_E_INVAL;
5500 	}
5501 
5502 	if (!evt_buf) {
5503 		spectral_err("WMI event buffer is null");
5504 		return QDF_STATUS_E_INVAL;
5505 	}
5506 
5507 	if (!param) {
5508 		spectral_err("Spectral FFT bin markers is null");
5509 		return QDF_STATUS_E_INVAL;
5510 	}
5511 
5512 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5513 	if (!wmi_handle) {
5514 		spectral_err("WMI handle is null");
5515 		return QDF_STATUS_E_INVAL;
5516 	}
5517 
5518 	return wmi_extract_pdev_sscan_fft_bin_index(wmi_handle, evt_buf, param);
5519 }
5520 
5521 /**
5522  * target_if_spectral_get_psoc_from_scn_handle() - Wrapper function to get psoc
5523  * object from scn handle
5524  * @scn: scn handle
5525  *
5526  * Wrapper function to get psoc object from scn handle
5527  *
5528  * Return: Pointer to psoc object
5529  */
5530 static struct wlan_objmgr_psoc *
5531 target_if_spectral_get_psoc_from_scn_handle(ol_scn_t scn)
5532 {
5533 	if (!scn) {
5534 		spectral_err("scn is null");
5535 		return NULL;
5536 	}
5537 
5538 	return target_if_get_psoc_from_scn_hdl(scn);
5539 }
5540 #endif
5541 
5542 /**
5543  * target_if_spectral_fw_param_event_handler() - WMI event handler to
5544  * process start scan response event
5545  * @scn: Pointer to scn object
5546  * @data_buf: Pointer to event buffer
5547  * @data_len: Length of event buffer
5548  *
5549  * Return: 0 for success, else failure
5550  */
5551 static int
5552 target_if_spectral_fw_param_event_handler(ol_scn_t scn, uint8_t *data_buf,
5553 					  uint32_t data_len)
5554 {
5555 	QDF_STATUS status;
5556 	struct wlan_objmgr_psoc *psoc;
5557 	struct wlan_objmgr_pdev *pdev;
5558 	struct wmi_unified *wmi_handle;
5559 	struct spectral_startscan_resp_params event_params = {0};
5560 	struct target_if_psoc_spectral *psoc_spectral;
5561 	struct target_if_spectral *spectral;
5562 
5563 	if (!scn) {
5564 		spectral_err("scn handle is null");
5565 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5566 	}
5567 
5568 	if (!data_buf) {
5569 		spectral_err("WMI event buffer null");
5570 		return qdf_status_to_os_return(QDF_STATUS_E_INVAL);
5571 	}
5572 
5573 	psoc = target_if_spectral_get_psoc_from_scn_handle(scn);
5574 	if (!psoc) {
5575 		spectral_err("psoc is null");
5576 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5577 	}
5578 
5579 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
5580 	if (!psoc_spectral) {
5581 		spectral_err("spectral object is null");
5582 		return QDF_STATUS_E_FAILURE;
5583 	}
5584 
5585 	wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
5586 	if (!wmi_handle) {
5587 		spectral_err("WMI handle is null");
5588 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5589 	}
5590 
5591 	status = target_if_spectral_wmi_extract_pdev_sscan_fw_cmd_fixed_param(
5592 				psoc, data_buf, &event_params);
5593 	if (QDF_IS_STATUS_ERROR(status)) {
5594 		spectral_err("unable to extract sscan fw fixed params");
5595 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5596 	}
5597 
5598 	pdev = wlan_objmgr_get_pdev_by_id(psoc, event_params.pdev_id,
5599 					  WLAN_SPECTRAL_ID);
5600 	if (!pdev) {
5601 		spectral_err("pdev is null");
5602 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5603 	}
5604 
5605 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5606 	if (!spectral) {
5607 		spectral_err("spectral object is null");
5608 		wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
5609 		return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5610 	}
5611 
5612 	if (event_params.num_fft_bin_index == 1) {
5613 		status =
5614 			target_if_spectral_wmi_extract_pdev_sscan_fft_bin_index(
5615 				psoc, data_buf,
5616 				&spectral->rparams.marker[event_params.smode]);
5617 		if (QDF_IS_STATUS_ERROR(status)) {
5618 			spectral_err("unable to extract sscan fw fixed params");
5619 			wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
5620 			return qdf_status_to_os_return(QDF_STATUS_E_FAILURE);
5621 		}
5622 	} else {
5623 		spectral->rparams.marker[event_params.smode].is_valid = false;
5624 	}
5625 
5626 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
5627 
5628 	return qdf_status_to_os_return(QDF_STATUS_SUCCESS);
5629 }
5630 
5631 static QDF_STATUS
5632 target_if_spectral_register_events(struct wlan_objmgr_psoc *psoc)
5633 {
5634 	int ret;
5635 
5636 	if (!psoc) {
5637 		spectral_err("psoc is null");
5638 		return QDF_STATUS_E_INVAL;
5639 	}
5640 
5641 	ret = target_if_spectral_wmi_unified_register_event_handler(
5642 			psoc,
5643 			wmi_pdev_sscan_fw_param_eventid,
5644 			target_if_spectral_fw_param_event_handler,
5645 			WMI_RX_UMAC_CTX);
5646 
5647 	if (ret)
5648 		spectral_debug("event handler not supported, ret=%d", ret);
5649 
5650 	return QDF_STATUS_SUCCESS;
5651 }
5652 
5653 static QDF_STATUS
5654 target_if_spectral_unregister_events(struct wlan_objmgr_psoc *psoc)
5655 {
5656 	int ret;
5657 
5658 	if (!psoc) {
5659 		spectral_err("psoc is null");
5660 		return QDF_STATUS_E_INVAL;
5661 	}
5662 
5663 	ret = target_if_spectral_wmi_unified_unregister_event_handler(
5664 			psoc, wmi_pdev_sscan_fw_param_eventid);
5665 
5666 	if (ret)
5667 		spectral_debug("Unregister WMI event handler failed, ret = %d",
5668 			       ret);
5669 
5670 	return QDF_STATUS_SUCCESS;
5671 }
5672 
5673 void
5674 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
5675 {
5676 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
5677 	    target_if_pdev_spectral_init;
5678 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
5679 	    target_if_pdev_spectral_deinit;
5680 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_init =
5681 	    target_if_psoc_spectral_init;
5682 	tx_ops->sptrl_tx_ops.sptrlto_psoc_spectral_deinit =
5683 	    target_if_psoc_spectral_deinit;
5684 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
5685 	    target_if_set_spectral_config;
5686 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
5687 	    target_if_get_spectral_config;
5688 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
5689 	    target_if_start_spectral_scan;
5690 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
5691 	    target_if_stop_spectral_scan;
5692 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
5693 	    target_if_is_spectral_active;
5694 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
5695 	    target_if_is_spectral_enabled;
5696 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
5697 	    target_if_set_debug_level;
5698 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
5699 	    target_if_get_debug_level;
5700 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
5701 	    target_if_get_spectral_capinfo;
5702 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
5703 	    target_if_get_spectral_diagstats;
5704 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_wmi_ops =
5705 	    target_if_register_spectral_wmi_ops;
5706 	tx_ops->sptrl_tx_ops.sptrlto_register_spectral_tgt_ops =
5707 	    target_if_register_spectral_tgt_ops;
5708 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
5709 	    target_if_register_netlink_cb;
5710 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
5711 	    target_if_use_nl_bcast;
5712 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
5713 	    target_if_deregister_netlink_cb;
5714 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
5715 	    target_if_process_spectral_report;
5716 	tx_ops->sptrl_tx_ops.sptrlto_direct_dma_support =
5717 		target_if_spectral_direct_dma_support;
5718 	tx_ops->sptrl_tx_ops.sptrlto_register_events =
5719 		target_if_spectral_register_events;
5720 	tx_ops->sptrl_tx_ops.sptrlto_unregister_events =
5721 		target_if_spectral_unregister_events;
5722 
5723 	target_if_sptrl_debug_register_tx_ops(tx_ops);
5724 }
5725 qdf_export_symbol(target_if_sptrl_register_tx_ops);
5726 
5727 void
5728 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
5729 				       uint16_t cw_int, uint32_t dcs_enabled)
5730 {
5731 	struct spectral_samp_msg *msg = NULL;
5732 	struct target_if_spectral_ops *p_sops = NULL;
5733 	struct target_if_spectral *spectral = NULL;
5734 
5735 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
5736 
5737 	if (!spectral) {
5738 		spectral_err("SPECTRAL : Module doesn't exist");
5739 		return;
5740 	}
5741 
5742 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
5743 	if (!p_sops) {
5744 		spectral_err("p_sops is null");
5745 		return;
5746 	}
5747 
5748 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_sbuff(
5749 			spectral->pdev_obj,
5750 			SPECTRAL_MSG_INTERFERENCE_NOTIFICATION,
5751 			SPECTRAL_MSG_BUF_NEW);
5752 
5753 	if (msg) {
5754 		msg->int_type = cw_int ?
5755 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
5756 		msg->dcs_enabled = dcs_enabled;
5757 		msg->signature = SPECTRAL_SIGNATURE;
5758 		p_sops->get_mac_address(spectral, msg->macaddr);
5759 		if (spectral->send_phy_data
5760 				(pdev,
5761 				 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION) == 0)
5762 			spectral->spectral_sent_msg++;
5763 	}
5764 }
5765 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
5766 
5767 QDF_STATUS
5768 target_if_spectral_is_finite_scan(struct target_if_spectral *spectral,
5769 				  enum spectral_scan_mode smode,
5770 				  bool *finite_spectral_scan)
5771 {
5772 	struct target_if_finite_spectral_scan_params *finite_scan;
5773 
5774 	if (!spectral) {
5775 		spectral_err_rl("target if spectral object is null");
5776 		return QDF_STATUS_E_INVAL;
5777 	}
5778 
5779 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5780 		spectral_err_rl("invalid spectral mode %d", smode);
5781 		return QDF_STATUS_E_INVAL;
5782 	}
5783 
5784 	if (!finite_spectral_scan) {
5785 		spectral_err_rl("Invalid pointer");
5786 		return QDF_STATUS_E_INVAL;
5787 	}
5788 
5789 	finite_scan = &spectral->finite_scan[smode];
5790 	*finite_spectral_scan = finite_scan->finite_spectral_scan;
5791 
5792 	return QDF_STATUS_SUCCESS;
5793 }
5794 
5795 QDF_STATUS
5796 target_if_spectral_finite_scan_update(struct target_if_spectral *spectral,
5797 				      enum spectral_scan_mode smode)
5798 {
5799 	struct target_if_finite_spectral_scan_params *finite_scan;
5800 
5801 	if (!spectral) {
5802 		spectral_err_rl("target if spectral object is null");
5803 		return QDF_STATUS_E_INVAL;
5804 	}
5805 
5806 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
5807 		spectral_err_rl("Invalid Spectral mode");
5808 		return QDF_STATUS_E_INVAL;
5809 	}
5810 
5811 	finite_scan = &spectral->finite_scan[smode];
5812 
5813 	if (!finite_scan->num_reports_expected) {
5814 		spectral_err_rl("Error, No reports expected");
5815 		return QDF_STATUS_E_FAILURE;
5816 	}
5817 
5818 	finite_scan->num_reports_expected--;
5819 	if (!finite_scan->num_reports_expected) {
5820 		QDF_STATUS status;
5821 		enum spectral_cp_error_code err;
5822 
5823 		/* received expected number of reports from target, stop scan */
5824 		status = target_if_stop_spectral_scan(spectral->pdev_obj, smode,
5825 						      &err);
5826 		if (QDF_IS_STATUS_ERROR(status)) {
5827 			spectral_err_rl("Failed to stop finite Spectral scan");
5828 			return QDF_STATUS_E_FAILURE;
5829 		}
5830 		finite_scan->finite_spectral_scan =  false;
5831 	}
5832 
5833 	return QDF_STATUS_SUCCESS;
5834 }
5835