xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2011,2017-2019 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 
45 static void target_if_spectral_get_firstvdev_pdev(struct wlan_objmgr_pdev *pdev,
46 						  void *obj, void *arg)
47 {
48 	struct wlan_objmgr_vdev *vdev = obj;
49 	struct wlan_objmgr_vdev **first_vdev = arg;
50 
51 	if (!(*first_vdev))
52 		*first_vdev = vdev;
53 }
54 
55 struct wlan_objmgr_vdev *
56 target_if_spectral_get_vdev(struct target_if_spectral *spectral)
57 {
58 	struct wlan_objmgr_pdev *pdev = NULL;
59 	struct wlan_objmgr_vdev *first_vdev = NULL;
60 
61 	qdf_assert_always(spectral);
62 	pdev = spectral->pdev_obj;
63 	qdf_assert_always(pdev);
64 
65 	if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_SPECTRAL_ID) !=
66 	    QDF_STATUS_SUCCESS) {
67 		spectral_err("Unable to get pdev reference.");
68 		return NULL;
69 	}
70 
71 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
72 					  target_if_spectral_get_firstvdev_pdev,
73 					  &first_vdev, 0, WLAN_SPECTRAL_ID);
74 
75 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
76 
77 	if (!first_vdev)
78 		return NULL;
79 
80 	if (wlan_objmgr_vdev_try_get_ref(first_vdev, WLAN_SPECTRAL_ID) !=
81 			QDF_STATUS_SUCCESS)
82 		first_vdev = NULL;
83 
84 
85 	return first_vdev;
86 }
87 
88 /**
89  * target_if_send_vdev_spectral_configure_cmd() - Send WMI command to configure
90  * spectral parameters
91  * @spectral: Pointer to Spectral target_if internal private data
92  * @param: Pointer to spectral_config giving the Spectral configuration
93  *
94  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
95  */
96 static int
97 target_if_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral,
98 					   struct spectral_config *param)
99 {
100 	struct vdev_spectral_configure_params sparam;
101 	struct wlan_objmgr_pdev *pdev = NULL;
102 	struct wlan_objmgr_vdev *vdev = NULL;
103 
104 	qdf_assert_always(spectral && param);
105 
106 	pdev = spectral->pdev_obj;
107 
108 	qdf_assert_always(pdev);
109 
110 	vdev = target_if_spectral_get_vdev(spectral);
111 	if (!vdev)
112 		return QDF_STATUS_E_NOENT;
113 
114 	qdf_mem_zero(&sparam, sizeof(sparam));
115 
116 	sparam.vdev_id = wlan_vdev_get_id(vdev);
117 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
118 
119 	sparam.count = param->ss_count;
120 	sparam.period = param->ss_period;
121 	sparam.spectral_pri = param->ss_spectral_pri;
122 	sparam.fft_size = param->ss_fft_size;
123 	sparam.gc_enable = param->ss_gc_ena;
124 	sparam.restart_enable = param->ss_restart_ena;
125 	sparam.noise_floor_ref = param->ss_noise_floor_ref;
126 	sparam.init_delay = param->ss_init_delay;
127 	sparam.nb_tone_thr = param->ss_nb_tone_thr;
128 	sparam.str_bin_thr = param->ss_str_bin_thr;
129 	sparam.wb_rpt_mode = param->ss_wb_rpt_mode;
130 	sparam.rssi_rpt_mode = param->ss_rssi_rpt_mode;
131 	sparam.rssi_thr = param->ss_rssi_thr;
132 	sparam.pwr_format = param->ss_pwr_format;
133 	sparam.rpt_mode = param->ss_rpt_mode;
134 	sparam.bin_scale = param->ss_bin_scale;
135 	sparam.dbm_adj = param->ss_dbm_adj;
136 	sparam.chn_mask = param->ss_chn_mask;
137 
138 	return spectral->param_wmi_cmd_ops.wmi_spectral_configure_cmd_send(
139 				GET_WMI_HDL_FROM_PDEV(pdev), &sparam);
140 }
141 
142 /**
143  * target_if_send_vdev_spectral_enable_cmd() - Send WMI command to
144  * enable/disable Spectral
145  * @spectral: Pointer to Spectral target_if internal private data
146  * @is_spectral_active_valid: Flag to indicate if spectral activate (trigger) is
147  * valid
148  * @is_spectral_active: Value of spectral activate
149  * @is_spectral_enabled_valid: Flag to indicate if spectral enable is valid
150  * @is_spectral_enabled: Value of spectral enable
151  *
152  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
153  */
154 static int
155 target_if_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral,
156 					uint8_t is_spectral_active_valid,
157 					uint8_t is_spectral_active,
158 					uint8_t is_spectral_enabled_valid,
159 					uint8_t is_spectral_enabled)
160 {
161 	struct vdev_spectral_enable_params param;
162 	struct wlan_objmgr_pdev *pdev = NULL;
163 	struct wlan_objmgr_vdev *vdev = NULL;
164 
165 	qdf_assert_always(spectral);
166 
167 	pdev = spectral->pdev_obj;
168 
169 	qdf_assert_always(pdev);
170 
171 	vdev = target_if_spectral_get_vdev(spectral);
172 	if (!vdev)
173 		return QDF_STATUS_E_NOENT;
174 
175 	qdf_mem_zero(&param, sizeof(param));
176 
177 	param.vdev_id = wlan_vdev_get_id(vdev);
178 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
179 
180 	param.active_valid = is_spectral_active_valid;
181 	param.enabled_valid = is_spectral_enabled_valid;
182 	param.active = is_spectral_active;
183 	param.enabled = is_spectral_enabled;
184 
185 	return spectral->param_wmi_cmd_ops.wmi_spectral_enable_cmd_send(
186 				GET_WMI_HDL_FROM_PDEV(pdev), &param);
187 }
188 
189 /**
190  * target_if_spectral_info_init_defaults() - Helper function to load defaults
191  * for Spectral information (parameters and state) into cache.
192  * @spectral: Pointer to Spectral target_if internal private data
193  * @smode: Spectral scan mode
194  *
195  * It is assumed that the caller has obtained the requisite lock if applicable.
196  * Note that this is currently treated as a temporary function.  Ideally, we
197  * would like to get defaults from the firmware.
198  *
199  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
200  */
201 static QDF_STATUS
202 target_if_spectral_info_init_defaults(struct target_if_spectral *spectral,
203 				      enum spectral_scan_mode smode)
204 {
205 	struct target_if_spectral_param_state_info *info;
206 	struct wlan_objmgr_vdev *vdev = NULL;
207 
208 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
209 		spectral_err("Invalid Spectral mode %u", smode);
210 		return QDF_STATUS_E_FAILURE;
211 	}
212 
213 	info = &spectral->param_info[smode];
214 
215 	/* State */
216 	info->osps_cache.osc_spectral_active = SPECTRAL_SCAN_ACTIVE_DEFAULT;
217 
218 	info->osps_cache.osc_spectral_enabled = SPECTRAL_SCAN_ENABLE_DEFAULT;
219 
220 	/* Parameters */
221 	info->osps_cache.osc_params.ss_count = SPECTRAL_SCAN_COUNT_DEFAULT;
222 
223 	if (spectral->spectral_gen == SPECTRAL_GEN3)
224 		info->osps_cache.osc_params.ss_period =
225 			SPECTRAL_SCAN_PERIOD_GEN_III_DEFAULT;
226 	else
227 		info->osps_cache.osc_params.ss_period =
228 			SPECTRAL_SCAN_PERIOD_GEN_II_DEFAULT;
229 
230 	info->osps_cache.osc_params.ss_spectral_pri =
231 	    SPECTRAL_SCAN_PRIORITY_DEFAULT;
232 
233 	info->osps_cache.osc_params.ss_fft_size =
234 	    SPECTRAL_SCAN_FFT_SIZE_DEFAULT;
235 
236 	info->osps_cache.osc_params.ss_gc_ena = SPECTRAL_SCAN_GC_ENA_DEFAULT;
237 
238 	info->osps_cache.osc_params.ss_restart_ena =
239 	    SPECTRAL_SCAN_RESTART_ENA_DEFAULT;
240 
241 	info->osps_cache.osc_params.ss_noise_floor_ref =
242 	    SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT;
243 
244 	info->osps_cache.osc_params.ss_init_delay =
245 	    SPECTRAL_SCAN_INIT_DELAY_DEFAULT;
246 
247 	info->osps_cache.osc_params.ss_nb_tone_thr =
248 	    SPECTRAL_SCAN_NB_TONE_THR_DEFAULT;
249 
250 	info->osps_cache.osc_params.ss_str_bin_thr =
251 	    SPECTRAL_SCAN_STR_BIN_THR_DEFAULT;
252 
253 	info->osps_cache.osc_params.ss_wb_rpt_mode =
254 	    SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT;
255 
256 	info->osps_cache.osc_params.ss_rssi_rpt_mode =
257 	    SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT;
258 
259 	info->osps_cache.osc_params.ss_rssi_thr =
260 	    SPECTRAL_SCAN_RSSI_THR_DEFAULT;
261 
262 	info->osps_cache.osc_params.ss_pwr_format =
263 	    SPECTRAL_SCAN_PWR_FORMAT_DEFAULT;
264 
265 	info->osps_cache.osc_params.ss_rpt_mode =
266 	    SPECTRAL_SCAN_RPT_MODE_DEFAULT;
267 
268 	info->osps_cache.osc_params.ss_bin_scale =
269 	    SPECTRAL_SCAN_BIN_SCALE_DEFAULT;
270 
271 	info->osps_cache.osc_params.ss_dbm_adj = SPECTRAL_SCAN_DBM_ADJ_DEFAULT;
272 
273 	vdev = target_if_spectral_get_vdev(spectral);
274 	if (!vdev)
275 		return QDF_STATUS_E_NOENT;
276 
277 	info->osps_cache.osc_params.ss_chn_mask =
278 	    wlan_vdev_mlme_get_rxchainmask(vdev);
279 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
280 
281 	info->osps_cache.osc_params.ss_short_report =
282 		SPECTRAL_SCAN_SHORT_REPORT_DEFAULT;
283 
284 	info->osps_cache.osc_params.ss_fft_period =
285 		SPECTRAL_SCAN_FFT_PERIOD_DEFAULT;
286 
287 	info->osps_cache.osc_params.ss_frequency =
288 		SPECTRAL_SCAN_FREQUENCY_DEFAULT;
289 
290 	/* The cache is now valid */
291 	info->osps_cache.osc_is_valid = 1;
292 
293 	return QDF_STATUS_SUCCESS;
294 }
295 
296 /**
297  * target_if_log_read_spectral_active() - Helper function to log whether
298  * spectral is active after reading cache
299  * @function_name: Function name
300  * @output: whether spectral is active or not
301  *
302  * Helper function to log whether spectral is active after reading cache
303  *
304  * Return: none
305  */
306 static void
307 target_if_log_read_spectral_active(
308 	const char *function_name,
309 	unsigned char output)
310 {
311 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE. Returning val=%u",
312 		       function_name, output);
313 }
314 
315 /**
316  * target_if_log_read_spectral_enabled() - Helper function to log whether
317  * spectral is enabled after reading cache
318  * @function_name: Function name
319  * @output: whether spectral is enabled or not
320  *
321  * Helper function to log whether spectral is enabled after reading cache
322  *
323  * Return: none
324  */
325 static void
326 target_if_log_read_spectral_enabled(
327 	const char *function_name,
328 	unsigned char output)
329 {
330 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED. Returning val=%u",
331 		       function_name, output);
332 }
333 
334 /**
335  * target_if_log_read_spectral_enabled() - Helper function to log spectral
336  * parameters after reading cache
337  * @function_name: Function name
338  * @pparam: Spectral parameters
339  *
340  * Helper function to log spectral parameters after reading cache
341  *
342  * Return: none
343  */
344 static void
345 target_if_log_read_spectral_params(
346 	const char *function_name,
347 	struct spectral_config *pparam)
348 {
349 	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_frequency=%u\n",
350 		       function_name,
351 		       pparam->ss_count,
352 		       pparam->ss_period,
353 		       pparam->ss_spectral_pri,
354 		       pparam->ss_fft_size,
355 		       pparam->ss_gc_ena,
356 		       pparam->ss_restart_ena,
357 		       (int8_t)pparam->ss_noise_floor_ref,
358 		       pparam->ss_init_delay,
359 		       pparam->ss_nb_tone_thr,
360 		       pparam->ss_str_bin_thr,
361 		       pparam->ss_wb_rpt_mode,
362 		       pparam->ss_rssi_rpt_mode,
363 		       (int8_t)pparam->ss_rssi_thr,
364 		       pparam->ss_pwr_format,
365 		       pparam->ss_rpt_mode,
366 		       pparam->ss_bin_scale,
367 		       pparam->ss_dbm_adj,
368 		       pparam->ss_chn_mask,
369 		       pparam->ss_frequency);
370 }
371 
372 /**
373  * target_if_log_read_spectral_active_catch_validate() - Helper function to
374  * log whether spectral is active after intializing the cache
375  * @function_name: Function name
376  * @output: whether spectral is active or not
377  *
378  * Helper function to log whether spectral is active after intializing cache
379  *
380  * Return: none
381  */
382 static void
383 target_if_log_read_spectral_active_catch_validate(
384 	const char *function_name,
385 	unsigned char output)
386 {
387 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE on initial cache validation\nReturning val=%u",
388 		       function_name, output);
389 }
390 
391 /**
392  * target_if_log_read_spectral_enabled_catch_validate() - Helper function to
393  * log whether spectral is enabled after intializing the cache
394  * @function_name: Function name
395  * @output: whether spectral is enabled or not
396  *
397  * Helper function to log whether spectral is enabled after intializing cache
398  *
399  * Return: none
400  */
401 static void
402 target_if_log_read_spectral_enabled_catch_validate(
403 	const char *function_name,
404 	unsigned char output)
405 {
406 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED on initial cache validation\nReturning val=%u\n",
407 		       function_name, output);
408 }
409 
410 /**
411  * target_if_log_read_spectral_params_catch_validate() - Helper function to
412  * log spectral parameters after intializing the cache
413  * @function_name: Function name
414  * @pparam: Spectral parameters
415  *
416  * Helper function to log spectral parameters after intializing the cache
417  *
418  * Return: none
419  */
420 static void
421 target_if_log_read_spectral_params_catch_validate(
422 	const char *function_name,
423 	struct spectral_config *pparam)
424 {
425 	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",
426 		       function_name,
427 		       pparam->ss_count,
428 		       pparam->ss_period,
429 		       pparam->ss_spectral_pri,
430 		       pparam->ss_fft_size,
431 		       pparam->ss_gc_ena,
432 		       pparam->ss_restart_ena,
433 		       (int8_t)pparam->ss_noise_floor_ref,
434 		       pparam->ss_init_delay,
435 		       pparam->ss_nb_tone_thr,
436 		       pparam->ss_str_bin_thr,
437 		       pparam->ss_wb_rpt_mode,
438 		       pparam->ss_rssi_rpt_mode,
439 		       (int8_t)pparam->ss_rssi_thr,
440 		       pparam->ss_pwr_format,
441 		       pparam->ss_rpt_mode,
442 		       pparam->ss_bin_scale,
443 		       pparam->ss_dbm_adj, pparam->ss_chn_mask);
444 }
445 
446 /**
447  * target_if_spectral_info_read() - Read spectral information from the cache.
448  * @spectral: Pointer to Spectral target_if internal private data
449  * @smode: Spectral scan mode
450  * @specifier: target_if_spectral_info enumeration specifying which
451  * information is required
452  * @output: Void output pointer into which the information will be read
453  * @output_len: size of object pointed to by output pointer
454  *
455  * Read spectral parameters or the desired state information from the cache.
456  *
457  * Return: 0 on success, negative error code on failure
458  */
459 static int
460 target_if_spectral_info_read(
461 	struct target_if_spectral *spectral,
462 	enum spectral_scan_mode smode,
463 	enum target_if_spectral_info specifier,
464 	void *output, int output_len)
465 {
466 	/*
467 	 * Note: This function is designed to be able to accommodate
468 	 * WMI reads for defaults, non-cacheable information, etc
469 	 * if required.
470 	 */
471 	struct target_if_spectral_param_state_info *info;
472 	int is_cacheable = 0;
473 	int init_def_retval = 0;
474 
475 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
476 		spectral_err("Invalid Spectral mode %u", smode);
477 		return -EINVAL;
478 	}
479 	info = &spectral->param_info[smode];
480 
481 	if (!output)
482 		return -EINVAL;
483 
484 	switch (specifier) {
485 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
486 		if (output_len != sizeof(info->osps_cache.osc_spectral_active))
487 			return -EINVAL;
488 		is_cacheable = 1;
489 		break;
490 
491 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
492 		if (output_len != sizeof(info->osps_cache.osc_spectral_enabled))
493 			return -EINVAL;
494 		is_cacheable = 1;
495 		break;
496 
497 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
498 		if (output_len != sizeof(info->osps_cache.osc_params))
499 			return -EINVAL;
500 		is_cacheable = 1;
501 		break;
502 
503 	default:
504 		spectral_err("Unknown target_if_spectral_info specifier");
505 		return -EINVAL;
506 	}
507 
508 	qdf_spin_lock(&info->osps_lock);
509 
510 	if (is_cacheable) {
511 		if (info->osps_cache.osc_is_valid) {
512 			switch (specifier) {
513 			case TARGET_IF_SPECTRAL_INFO_ACTIVE:
514 				qdf_mem_copy(
515 				  output,
516 				  &info->osps_cache.osc_spectral_active,
517 				  sizeof(info->osps_cache.osc_spectral_active));
518 
519 				target_if_log_read_spectral_active(
520 					__func__,
521 					*((unsigned char *)output));
522 				break;
523 
524 			case TARGET_IF_SPECTRAL_INFO_ENABLED:
525 				qdf_mem_copy(
526 				  output,
527 				  &info->osps_cache.osc_spectral_enabled,
528 				  sizeof(
529 					info->osps_cache.osc_spectral_enabled));
530 
531 				target_if_log_read_spectral_enabled(
532 					__func__,
533 					*((unsigned char *)output));
534 				break;
535 
536 			case TARGET_IF_SPECTRAL_INFO_PARAMS:
537 				qdf_mem_copy(
538 				  output,
539 				  &info->osps_cache.osc_params,
540 				  sizeof(info->osps_cache.osc_params));
541 
542 				target_if_log_read_spectral_params(
543 					__func__,
544 					(struct spectral_config *)output);
545 				break;
546 
547 			default:
548 				/* We can't reach this point */
549 				break;
550 			}
551 			qdf_spin_unlock(&info->osps_lock);
552 			return 0;
553 		}
554 	}
555 
556 	/* Cache is invalid */
557 
558 	/*
559 	 * If WMI Reads are implemented to fetch defaults/non-cacheable info,
560 	 * then the below implementation will change
561 	 */
562 	init_def_retval =
563 			target_if_spectral_info_init_defaults(spectral, smode);
564 	if (init_def_retval != QDF_STATUS_SUCCESS) {
565 		qdf_spin_unlock(&info->osps_lock);
566 		if (init_def_retval == QDF_STATUS_E_NOENT)
567 			return -ENOENT;
568 		else
569 			return -EINVAL;
570 	}
571 	/* target_if_spectral_info_init_defaults() has set cache to valid */
572 
573 	switch (specifier) {
574 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
575 		qdf_mem_copy(output,
576 			     &info->osps_cache.osc_spectral_active,
577 			     sizeof(info->osps_cache.osc_spectral_active));
578 
579 		target_if_log_read_spectral_active_catch_validate(
580 			__func__,
581 			*((unsigned char *)output));
582 		break;
583 
584 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
585 		qdf_mem_copy(output,
586 			     &info->osps_cache.osc_spectral_enabled,
587 			     sizeof(info->osps_cache.osc_spectral_enabled));
588 
589 		target_if_log_read_spectral_enabled_catch_validate(
590 			__func__,
591 			*((unsigned char *)output));
592 		break;
593 
594 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
595 		qdf_mem_copy(output,
596 			     &info->osps_cache.osc_params,
597 			     sizeof(info->osps_cache.osc_params));
598 
599 		target_if_log_read_spectral_params_catch_validate(
600 			__func__,
601 			(struct spectral_config *)output);
602 
603 		break;
604 
605 	default:
606 		/* We can't reach this point */
607 		break;
608 	}
609 
610 	qdf_spin_unlock(&info->osps_lock);
611 
612 	return 0;
613 }
614 
615 /**
616  * target_if_log_write_spectral_active() - Helper function to log inputs and
617  * return value of call to configure the Spectral 'active' configuration,
618  * TARGET_IF_SPECTRAL_INFO_ACTIVE into firmware
619  * @function_name: Function name in which this is called
620  * @pval: whether spectral is active or not
621  * @ret: return value of the firmware write function
622  *
623  * Return: none
624  */
625 static void
626 target_if_log_write_spectral_active(
627 	const char *function_name,
628 	uint8_t pval,
629 	int ret)
630 {
631 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE with val=%u status=%d",
632 		       function_name, pval, ret);
633 }
634 
635 /**
636  * target_if_log_write_spectral_enabled() - Helper function to log inputs and
637  * return value of call to configure the Spectral 'enabled' configuration,
638  * TARGET_IF_SPECTRAL_INFO_ENABLED into firmware
639  * @function_name: Function name in which this is called
640  * @pval: whether spectral is enabled or not
641  * @ret: return value of the firmware write function
642  *
643  * Return: none
644  */
645 static void
646 target_if_log_write_spectral_enabled(
647 	const char *function_name,
648 	uint8_t pval,
649 	int ret)
650 {
651 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED with val=%u status=%d",
652 		       function_name, pval, ret);
653 }
654 
655 /**
656  * target_if_log_write_spectral_params() - Helper function to log inputs and
657  * return value of call to configure Spectral parameters,
658  * TARGET_IF_SPECTRAL_INFO_PARAMS into firmware
659  * @param: Spectral parameters
660  * @function_name: Function name in which this is called
661  * @ret: return value of the firmware write function
662  *
663  * Return: none
664  */
665 static void
666 target_if_log_write_spectral_params(
667 	struct spectral_config *param,
668 	const char *function_name,
669 	int ret)
670 {
671 	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_frequency=%u\nstatus = %d",
672 		       function_name,
673 		       param->ss_count,
674 		       param->ss_period,
675 		       param->ss_spectral_pri,
676 		       param->ss_fft_size,
677 		       param->ss_gc_ena,
678 		       param->ss_restart_ena,
679 		       (int8_t)param->ss_noise_floor_ref,
680 		       param->ss_init_delay,
681 		       param->ss_nb_tone_thr,
682 		       param->ss_str_bin_thr,
683 		       param->ss_wb_rpt_mode,
684 		       param->ss_rssi_rpt_mode,
685 		       (int8_t)param->ss_rssi_thr,
686 		       param->ss_pwr_format,
687 		       param->ss_rpt_mode,
688 		       param->ss_bin_scale,
689 		       param->ss_dbm_adj,
690 		       param->ss_chn_mask,
691 		       param->ss_frequency,
692 		       ret);
693 }
694 
695 /**
696  * target_if_spectral_info_write() - Write Spectral information to the
697  * firmware, and update cache
698  * @spectral: Pointer to Spectral target_if internal private data
699  * @smode: Spectral scan mode
700  * @specifier: target_if_spectral_info enumeration specifying which
701  * information is involved
702  * @input: void input pointer containing the information to be written
703  * @input_len: size of object pointed to by input pointer
704  *
705  * Write Spectral parameters or the desired state information to
706  * the firmware, and update cache
707  *
708  * Return: 0 on success, negative error code on failure
709  */
710 static int
711 target_if_spectral_info_write(
712 	struct target_if_spectral *spectral,
713 	enum spectral_scan_mode smode,
714 	enum target_if_spectral_info specifier,
715 	void *input, int input_len)
716 {
717 	struct target_if_spectral_param_state_info *info;
718 	int ret;
719 	uint8_t *pval = NULL;
720 	struct spectral_config *param = NULL;
721 
722 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
723 		spectral_err("Invalid Spectral mode %u", smode);
724 		return -EINVAL;
725 	}
726 	info = &spectral->param_info[smode];
727 
728 	if (!input)
729 		return -EINVAL;
730 
731 	switch (specifier) {
732 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
733 		if (input_len != sizeof(info->osps_cache.osc_spectral_active))
734 			return -EINVAL;
735 
736 		pval = (uint8_t *)input;
737 
738 		qdf_spin_lock(&info->osps_lock);
739 		ret = target_if_send_vdev_spectral_enable_cmd(spectral,
740 							      1, *pval, 0, 0);
741 
742 		target_if_log_write_spectral_active(
743 			__func__,
744 			*pval,
745 			ret);
746 
747 		if (ret < 0) {
748 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
749 				     ret);
750 			qdf_spin_unlock(&info->osps_lock);
751 			return ret;
752 		}
753 
754 		info->osps_cache.osc_spectral_active = *pval;
755 
756 		/* The cache is now valid */
757 		info->osps_cache.osc_is_valid = 1;
758 
759 		qdf_spin_unlock(&info->osps_lock);
760 		break;
761 
762 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
763 		if (input_len != sizeof(info->osps_cache.osc_spectral_enabled))
764 			return -EINVAL;
765 
766 		pval = (uint8_t *)input;
767 
768 		qdf_spin_lock(&info->osps_lock);
769 		ret = target_if_send_vdev_spectral_enable_cmd(spectral,
770 							      0, 0, 1, *pval);
771 
772 		target_if_log_write_spectral_enabled(
773 			__func__,
774 			*pval,
775 			ret);
776 
777 		if (ret < 0) {
778 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
779 				     ret);
780 			qdf_spin_unlock(&info->osps_lock);
781 			return ret;
782 		}
783 
784 		info->osps_cache.osc_spectral_enabled = *pval;
785 
786 		/* The cache is now valid */
787 		info->osps_cache.osc_is_valid = 1;
788 
789 		qdf_spin_unlock(&info->osps_lock);
790 		break;
791 
792 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
793 		if (input_len != sizeof(info->osps_cache.osc_params))
794 			return -EINVAL;
795 
796 		param = (struct spectral_config *)input;
797 
798 		qdf_spin_lock(&info->osps_lock);
799 		ret = target_if_send_vdev_spectral_configure_cmd(spectral,
800 								 param);
801 
802 		target_if_log_write_spectral_params(
803 			param,
804 			__func__,
805 			ret);
806 
807 		if (ret < 0) {
808 			spectral_err("target_if_send_vdev_spectral_configure_cmd failed with error=%d",
809 				     ret);
810 			qdf_spin_unlock(&info->osps_lock);
811 			return ret;
812 		}
813 
814 		qdf_mem_copy(&info->osps_cache.osc_params,
815 			     param, sizeof(info->osps_cache.osc_params));
816 
817 		/* The cache is now valid */
818 		info->osps_cache.osc_is_valid = 1;
819 
820 		qdf_spin_unlock(&info->osps_lock);
821 		break;
822 
823 	default:
824 		spectral_err("Unknown target_if_spectral_info specifier");
825 		return -EINVAL;
826 	}
827 
828 	return 0;
829 }
830 
831 /**
832  * target_if_spectral_get_tsf64() - Function to get the TSF value
833  * @arg: Pointer to handle for Spectral target_if internal private data
834  *
835  * Get the last TSF received in WMI buffer
836  *
837  * Return: TSF value
838  */
839 static uint64_t
840 target_if_spectral_get_tsf64(void *arg)
841 {
842 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
843 
844 	return spectral->tsf64;
845 }
846 
847 /**
848  * target_if_spectral_get_capability() - Function to get whether a
849  * given Spectral hardware capability is available
850  * @arg: Pointer to handle for Spectral target_if internal private data
851  * @type: Spectral hardware capability type
852  *
853  * Get whether a given Spectral hardware capability is available
854  *
855  * Return: True if the capability is available, false if the capability is not
856  * available
857  */
858 uint32_t
859 target_if_spectral_get_capability(void *arg, enum spectral_capability_type type)
860 {
861 	int status = STATUS_FAIL;
862 
863 	switch (type) {
864 	case SPECTRAL_CAP_PHYDIAG:
865 	case SPECTRAL_CAP_RADAR:
866 	case SPECTRAL_CAP_SPECTRAL_SCAN:
867 	case SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN:
868 		status = STATUS_PASS;
869 		break;
870 	default:
871 		status = STATUS_FAIL;
872 	}
873 	return status;
874 }
875 
876 /**
877  * target_if_spectral_set_rxfilter() - Set the RX Filter before Spectral start
878  * @arg: Pointer to handle for Spectral target_if internal private data
879  * @rxfilter: Rx filter to be used
880  *
881  * Note: This is only a placeholder function. It is not currently required since
882  * FW should be taking care of setting the required filters.
883  *
884  * Return: 0
885  */
886 uint32_t
887 target_if_spectral_set_rxfilter(void *arg, int rxfilter)
888 {
889 	/*
890 	 * Will not be required since enabling of spectral in firmware
891 	 * will take care of this
892 	 */
893 	return 0;
894 }
895 
896 /**
897  * target_if_spectral_get_rxfilter() - Get the current RX Filter settings
898  * @arg: Pointer to handle for Spectral target_if internal private data
899  *
900  * Note: This is only a placeholder function. It is not currently required since
901  * FW should be taking care of setting the required filters.
902  *
903  * Return: 0
904  */
905 uint32_t
906 target_if_spectral_get_rxfilter(void *arg)
907 {
908 	/*
909 	 * Will not be required since enabling of spectral in firmware
910 	 * will take care of this
911 	 */
912 	return 0;
913 }
914 
915 /**
916  * target_if_sops_is_spectral_active() - Get whether Spectral is active
917  * @arg: Pointer to handle for Spectral target_if internal private data
918  * @smode: Spectral scan mode
919  *
920  * Function to check whether Spectral is active
921  *
922  * Return: True if Spectral is active, false if Spectral is not active
923  */
924 uint32_t
925 target_if_sops_is_spectral_active(void *arg, enum spectral_scan_mode smode)
926 {
927 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
928 	uint8_t val = 0;
929 	int ret;
930 
931 	ret = target_if_spectral_info_read(
932 		spectral,
933 		smode,
934 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
935 		&val, sizeof(val));
936 
937 	if (ret != 0) {
938 		/*
939 		 * Could not determine if Spectral is active.
940 		 * Return false as a safe value.
941 		 * XXX: Consider changing the function prototype
942 		 * to be able to indicate failure to fetch value.
943 		 */
944 		return 0;
945 	}
946 
947 	return val;
948 }
949 
950 /**
951  * target_if_sops_is_spectral_enabled() - Get whether Spectral is enabled
952  * @arg: Pointer to handle for Spectral target_if internal private data
953  * @smode: Spectral scan mode
954  *
955  * Function to check whether Spectral is enabled
956  *
957  * Return: True if Spectral is enabled, false if Spectral is not enabled
958  */
959 uint32_t
960 target_if_sops_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
961 {
962 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
963 	uint8_t val = 0;
964 	int ret;
965 
966 	ret = target_if_spectral_info_read(
967 		spectral,
968 		smode,
969 		TARGET_IF_SPECTRAL_INFO_ENABLED,
970 		&val, sizeof(val));
971 
972 	if (ret != 0) {
973 		/*
974 		 * Could not determine if Spectral is enabled.
975 		 * Return false as a safe value.
976 		 * XXX: Consider changing the function prototype
977 		 * to be able to indicate failure to fetch value.
978 		 */
979 		return 0;
980 	}
981 
982 	return val;
983 }
984 
985 /**
986  * target_if_sops_start_spectral_scan() - Start Spectral scan
987  * @arg: Pointer to handle for Spectral target_if internal private data
988  * @smode: Spectral scan mode
989  * @err: Spectral error code
990  *
991  * Function to start spectral scan
992  *
993  * Return: 0 on success else failure
994  */
995 uint32_t
996 target_if_sops_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
997 				   enum spectral_cp_error_code *err)
998 {
999 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1000 	uint8_t val = 1;
1001 	uint8_t enabled = 0;
1002 	int ret;
1003 
1004 	ret = target_if_spectral_info_read(
1005 		spectral,
1006 		smode,
1007 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1008 		&enabled, sizeof(enabled));
1009 
1010 	if (ret != 0) {
1011 		/*
1012 		 * Could not determine if Spectral is enabled. Assume we need
1013 		 * to enable it
1014 		 */
1015 		enabled = 0;
1016 	}
1017 
1018 	if (!enabled) {
1019 		ret = target_if_spectral_info_write(
1020 			spectral,
1021 			smode,
1022 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1023 			&val, sizeof(val));
1024 
1025 		if (ret != 0)
1026 			return ret;
1027 	}
1028 
1029 	ret = target_if_spectral_info_write(
1030 		spectral,
1031 		smode,
1032 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
1033 		&val, sizeof(val));
1034 
1035 	if (ret != 0)
1036 		return ret;
1037 
1038 	return 0;
1039 }
1040 
1041 /**
1042  * target_if_sops_stop_spectral_scan() - Stop Spectral scan
1043  * @arg: Pointer to handle for Spectral target_if internal private data
1044  * @smode: Spectral scan mode
1045  *
1046  * Function to stop spectral scan
1047  *
1048  * Return: 0 on success else failure
1049  */
1050 uint32_t
1051 target_if_sops_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
1052 {
1053 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1054 	uint8_t val = 0;
1055 	int tempret, ret = 0;
1056 	uint8_t enabled = 0;
1057 
1058 	tempret = target_if_spectral_info_read(
1059 		spectral,
1060 		smode,
1061 		TARGET_IF_SPECTRAL_INFO_ENABLED,
1062 		&enabled, sizeof(enabled));
1063 
1064 	if (tempret)
1065 		/*
1066 		 * Could not determine if Spectral is enabled. Assume scan is
1067 		 * not in progress
1068 		 */
1069 		enabled = 0;
1070 
1071 	/* if scan is not enabled, no need to send stop to FW */
1072 	if (!enabled)
1073 		return -EPERM;
1074 
1075 	tempret = target_if_spectral_info_write(
1076 			spectral,
1077 			smode,
1078 			TARGET_IF_SPECTRAL_INFO_ACTIVE,
1079 			&val, sizeof(val));
1080 
1081 	if (tempret != 0)
1082 		ret = tempret;
1083 
1084 	tempret = target_if_spectral_info_write(
1085 			spectral,
1086 			smode,
1087 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1088 			&val, sizeof(val));
1089 
1090 	if (tempret != 0)
1091 		ret = tempret;
1092 
1093 	return ret;
1094 }
1095 
1096 /**
1097  * target_if_spectral_get_extension_channel() - Get the Extension channel
1098  * @arg: Pointer to handle for Spectral target_if internal private data
1099  *
1100  * Function to get the current Extension channel (in MHz)
1101  *
1102  * Return: Current Extension channel (in MHz) on success, 0 on failure or if
1103  * extension channel is not present.
1104  */
1105 uint32_t
1106 target_if_spectral_get_extension_channel(void *arg)
1107 {
1108 	/*
1109 	 * XXX: Once we expand to use cases where Spectral could be activated
1110 	 * without a channel being set to VDEV, we need to consider returning a
1111 	 * negative value in case of failure and having all callers handle this.
1112 	 */
1113 
1114 	struct target_if_spectral *spectral = NULL;
1115 	struct wlan_objmgr_vdev *vdev = NULL;
1116 	uint16_t sec20chan_freq = 0;
1117 
1118 	qdf_assert_always(arg);
1119 	spectral = (struct target_if_spectral *)arg;
1120 
1121 	vdev = target_if_spectral_get_vdev(spectral);
1122 	if (!vdev)
1123 		return 0;
1124 
1125 	if (target_if_vdev_get_sec20chan_freq_mhz(vdev, &sec20chan_freq) < 0) {
1126 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1127 		return 0;
1128 	}
1129 
1130 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1131 
1132 	return sec20chan_freq;
1133 }
1134 
1135 /**
1136  * target_if_spectral_get_current_channel() - Get the current channel
1137  * @arg: Pointer to handle for Spectral target_if internal private data
1138  *
1139  * Function to get the current channel (in MHz)
1140  *
1141  * Return: Current channel (in MHz) on success, 0 on failure
1142  */
1143 uint32_t
1144 target_if_spectral_get_current_channel(void *arg)
1145 {
1146 	/*
1147 	 * XXX: Once we expand to use cases where Spectral could be activated
1148 	 * without a channel being set to VDEV, we need to consider returning a
1149 	 * negative value in case of failure and having all callers handle this.
1150 	 */
1151 
1152 	struct target_if_spectral *spectral = NULL;
1153 	int16_t chan_freq = 0;
1154 	struct wlan_objmgr_vdev *vdev = NULL;
1155 
1156 	qdf_assert_always(arg);
1157 	spectral = (struct target_if_spectral *)arg;
1158 
1159 	vdev = target_if_spectral_get_vdev(spectral);
1160 	if (!vdev)
1161 		return 0;
1162 
1163 	chan_freq = target_if_vdev_get_chan_freq(vdev);
1164 	if (chan_freq < 0) {
1165 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1166 		return 0;
1167 	}
1168 
1169 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1170 
1171 	return chan_freq;
1172 }
1173 
1174 /**
1175  * target_if_spectral_reset_hw() - Reset the hardware
1176  * @arg: Pointer to handle for Spectral target_if internal private data
1177  *
1178  * This is only a placeholder since it is not currently required in the offload
1179  * case.
1180  *
1181  * Return: 0
1182  */
1183 uint32_t
1184 target_if_spectral_reset_hw(void *arg)
1185 {
1186 	not_yet_implemented();
1187 	return 0;
1188 }
1189 
1190 /**
1191  * target_if_spectral_get_chain_noise_floor() - Get the Chain noise floor from
1192  * Noisefloor history buffer
1193  * @arg: Pointer to handle for Spectral target_if internal private data
1194  * @nf_buf: Pointer to buffer into which chain Noise Floor data should be copied
1195  *
1196  * This is only a placeholder since it is not currently required in the offload
1197  * case.
1198  *
1199  * Return: 0
1200  */
1201 uint32_t
1202 target_if_spectral_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1203 {
1204 	not_yet_implemented();
1205 	return 0;
1206 }
1207 
1208 /**
1209  * target_if_spectral_get_ext_noisefloor() - Get the extension channel
1210  * noisefloor
1211  * @arg: Pointer to handle for Spectral target_if internal private data
1212  *
1213  * This is only a placeholder since it is not currently required in the offload
1214  * case.
1215  *
1216  * Return: 0
1217  */
1218 int8_t
1219 target_if_spectral_get_ext_noisefloor(void *arg)
1220 {
1221 	not_yet_implemented();
1222 	return 0;
1223 }
1224 
1225 /**
1226  * target_if_spectral_get_ctl_noisefloor() - Get the control channel noisefloor
1227  * @arg: Pointer to handle for Spectral target_if internal private data
1228  *
1229  * This is only a placeholder since it is not currently required in the offload
1230  * case.
1231  *
1232  * Return: 0
1233  */
1234 int8_t
1235 target_if_spectral_get_ctl_noisefloor(void *arg)
1236 {
1237 	not_yet_implemented();
1238 	return 0;
1239 }
1240 
1241 /**
1242  * target_if_spectral_sops_configure_params() - Configure user supplied Spectral
1243  *                                         parameters
1244  * @arg: Pointer to handle for Spectral target_if internal private data
1245  * @params: Spectral parameters
1246  * @smode: Spectral scan mode
1247  *
1248  * Function to configure spectral parameters
1249  *
1250  * Return: 0 on success else failure
1251  */
1252 uint32_t
1253 target_if_spectral_sops_configure_params(
1254 	void *arg, struct spectral_config *params,
1255 	enum spectral_scan_mode smode)
1256 {
1257 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1258 
1259 	return target_if_spectral_info_write(
1260 		spectral,
1261 		smode,
1262 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1263 		params, sizeof(*params));
1264 }
1265 
1266 /**
1267  * target_if_spectral_sops_get_params() - Get user configured Spectral
1268  * parameters
1269  * @arg: Pointer to handle for Spectral target_if internal private data
1270  * @params: Pointer to buffer into which Spectral parameters should be copied
1271  * @smode: Spectral scan mode
1272  *
1273  * Function to get the configured spectral parameters
1274  *
1275  * Return: 0 on success else failure
1276  */
1277 uint32_t
1278 target_if_spectral_sops_get_params(void *arg, struct spectral_config *params,
1279 				   enum spectral_scan_mode smode)
1280 {
1281 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1282 
1283 	return target_if_spectral_info_read(
1284 		spectral,
1285 		smode,
1286 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1287 		params, sizeof(*params));
1288 }
1289 
1290 /**
1291  * target_if_spectral_get_ent_mask() - Get enterprise mask
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 static uint32_t
1300 target_if_spectral_get_ent_mask(void *arg)
1301 {
1302 	not_yet_implemented();
1303 	return 0;
1304 }
1305 
1306 /**
1307  * target_if_spectral_get_macaddr() - Get radio MAC address
1308  * @arg: Pointer to handle for Spectral target_if internal private data
1309  * @addr: Pointer to buffer into which MAC address should be copied
1310  *
1311  * Function to get the MAC address of the pdev
1312  *
1313  * Return: 0 on success, -1 on failure
1314  */
1315 static uint32_t
1316 target_if_spectral_get_macaddr(void *arg, char *addr)
1317 {
1318 	uint8_t *myaddr = NULL;
1319 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1320 	struct wlan_objmgr_pdev *pdev = NULL;
1321 
1322 	pdev = spectral->pdev_obj;
1323 
1324 	wlan_pdev_obj_lock(pdev);
1325 	myaddr = wlan_pdev_get_hw_macaddr(pdev);
1326 	wlan_pdev_obj_unlock(pdev);
1327 	qdf_mem_copy(addr, myaddr, QDF_MAC_ADDR_SIZE);
1328 
1329 	return 0;
1330 }
1331 
1332 /**
1333  * target_if_init_spectral_param_properties() - Initialize Spectral parameter
1334  *                                              properties
1335  * @spectral: Pointer to Spectral target_if internal private data
1336  *
1337  * Initialize Spectral parameter properties
1338  *
1339  * Return: QDF_STATUS
1340  */
1341 static QDF_STATUS
1342 target_if_init_spectral_param_properties(struct target_if_spectral *spectral)
1343 {
1344 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1345 	int param;
1346 
1347 	/* Initialize default values for properties.
1348 	 * Default values are supported for all the parameters for all modes
1349 	 * and allows different values for each mode for all the parameters .
1350 	 */
1351 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
1352 		for (param = 0; param < SPECTRAL_PARAM_MAX; param++) {
1353 			spectral->properties[smode][param].supported = true;
1354 			spectral->properties[smode][param].common_all_modes =
1355 									false;
1356 		}
1357 	}
1358 
1359 	return QDF_STATUS_SUCCESS;
1360 }
1361 
1362 /**
1363  * target_if_init_spectral_capability() - Initialize Spectral capability
1364  * @spectral: Pointer to Spectral target_if internal private data
1365  *
1366  * This is a workaround.
1367  *
1368  * Return: QDF_STATUS
1369  */
1370 QDF_STATUS
1371 target_if_init_spectral_capability(struct target_if_spectral *spectral)
1372 {
1373 	struct wlan_objmgr_psoc *psoc;
1374 	struct wlan_objmgr_pdev *pdev;
1375 	struct wlan_psoc_host_spectral_scaling_params *scaling_params;
1376 	uint8_t num_bin_scaling_params, param_idx, pdev_id;
1377 	struct target_psoc_info *tgt_psoc_info;
1378 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
1379 	struct spectral_caps *pcap = &spectral->capability;
1380 
1381 	pdev = spectral->pdev_obj;
1382 	psoc = wlan_pdev_get_psoc(pdev);
1383 	if (!psoc) {
1384 		spectral_err("psoc is null");
1385 		return QDF_STATUS_E_FAILURE;
1386 	}
1387 
1388 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
1389 	if (!tgt_psoc_info) {
1390 		spectral_err("target_psoc_info is null");
1391 		return QDF_STATUS_E_FAILURE;
1392 	}
1393 
1394 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
1395 	num_bin_scaling_params = ext_svc_param->num_bin_scaling_params;
1396 	scaling_params = target_psoc_get_spectral_scaling_params(tgt_psoc_info);
1397 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1398 
1399 	/* XXX : Workaround: Set Spectral capability */
1400 	pcap = &spectral->capability;
1401 	pcap->phydiag_cap = 1;
1402 	pcap->radar_cap = 1;
1403 	pcap->spectral_cap = 1;
1404 	pcap->advncd_spectral_cap = 1;
1405 	pcap->hw_gen = spectral->spectral_gen;
1406 
1407 	for (param_idx = 0; param_idx < num_bin_scaling_params; param_idx++) {
1408 		if (scaling_params[param_idx].pdev_id == pdev_id) {
1409 			pcap->is_scaling_params_populated = true;
1410 			pcap->formula_id = scaling_params[param_idx].formula_id;
1411 			pcap->low_level_offset =
1412 				scaling_params[param_idx].low_level_offset;
1413 			pcap->high_level_offset =
1414 				scaling_params[param_idx].high_level_offset;
1415 			pcap->rssi_thr = scaling_params[param_idx].rssi_thr;
1416 			pcap->default_agc_max_gain =
1417 				scaling_params[param_idx].default_agc_max_gain;
1418 			break;
1419 		}
1420 	}
1421 
1422 	return QDF_STATUS_SUCCESS;
1423 }
1424 
1425 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1426 /**
1427  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1428  * internal operations with functions related to spectral simulation
1429  * @p_sops: spectral low level ops table
1430  *
1431  * Initialize spectral target_if internal operations with functions
1432  * related to spectral simulation
1433  *
1434  * Return: None
1435  */
1436 static void
1437 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1438 {
1439 	/*
1440 	 * Spectral simulation is currently intended for platform transitions
1441 	 * where underlying HW support may not be available for some time.
1442 	 * Hence, we do not currently provide a runtime switch to turn the
1443 	 * simulation on or off.
1444 	 * In case of future requirements where runtime switches are required,
1445 	 * this can be added. But it is suggested to use application layer
1446 	 * simulation as far as possible in such cases, since the main
1447 	 * use of record and replay of samples would concern higher
1448 	 * level sample processing rather than lower level delivery.
1449 	 */
1450 	p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled;
1451 	p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active;
1452 	p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan;
1453 	p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan;
1454 	p_sops->configure_spectral =
1455 		target_if_spectral_sops_sim_configure_params;
1456 	p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params;
1457 }
1458 
1459 #else
1460 /**
1461  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1462  * internal operations
1463  * @p_sops: spectral low level ops table
1464  *
1465  * Return: None
1466  */
1467 static void
1468 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1469 {
1470 	p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled;
1471 	p_sops->is_spectral_active = target_if_sops_is_spectral_active;
1472 	p_sops->start_spectral_scan = target_if_sops_start_spectral_scan;
1473 	p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan;
1474 	p_sops->configure_spectral = target_if_spectral_sops_configure_params;
1475 	p_sops->get_spectral_config = target_if_spectral_sops_get_params;
1476 }
1477 #endif
1478 
1479 /**
1480  * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
1481  * operations common to all Spectral chipset generations
1482  *
1483  * Initializes target_if_spectral_ops common to all chipset generations
1484  *
1485  * Return: None
1486  */
1487 static void
1488 target_if_init_spectral_ops_common(void)
1489 {
1490 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1491 
1492 	p_sops->get_tsf64 = target_if_spectral_get_tsf64;
1493 	p_sops->get_capability = target_if_spectral_get_capability;
1494 	p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
1495 	p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
1496 
1497 	target_if_init_spectral_simulation_ops(p_sops);
1498 
1499 	p_sops->get_extension_channel =
1500 	    target_if_spectral_get_extension_channel;
1501 	p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor;
1502 	p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor;
1503 	p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
1504 	p_sops->get_mac_address = target_if_spectral_get_macaddr;
1505 	p_sops->get_current_channel = target_if_spectral_get_current_channel;
1506 	p_sops->reset_hw = target_if_spectral_reset_hw;
1507 	p_sops->get_chain_noise_floor =
1508 	    target_if_spectral_get_chain_noise_floor;
1509 }
1510 
1511 /**
1512  * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
1513  * operations specific to Spectral chipset generation 2.
1514  *
1515  * Initializes target_if_spectral_ops specific to Spectral chipset generation 2.
1516  *
1517  * Return: None
1518  */
1519 static void
1520 target_if_init_spectral_ops_gen2(void)
1521 {
1522 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1523 
1524 	p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2;
1525 }
1526 
1527 /**
1528  * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
1529  * operations specific to Spectral chipset generation 3.
1530  *
1531  * Initializes target_if_spectral_ops specific to Spectral chipset generation 3.
1532  *
1533  * Return: None
1534  */
1535 static void
1536 target_if_init_spectral_ops_gen3(void)
1537 {
1538 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1539 
1540 	p_sops->process_spectral_report =
1541 			target_if_spectral_process_report_gen3;
1542 	return;
1543 }
1544 
1545 /**
1546  * target_if_init_spectral_ops() - Initialize target_if internal Spectral
1547  * operations.
1548  * @spectral: Pointer to Spectral target_if internal private data
1549  *
1550  * Initializes all function pointers in target_if_spectral_ops for
1551  * all generations
1552  *
1553  * Return: None
1554  */
1555 static void
1556 target_if_init_spectral_ops(struct target_if_spectral *spectral)
1557 {
1558 	target_if_init_spectral_ops_common();
1559 	if (spectral->spectral_gen == SPECTRAL_GEN2)
1560 		target_if_init_spectral_ops_gen2();
1561 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
1562 		target_if_init_spectral_ops_gen3();
1563 	else
1564 		spectral_err("Invalid Spectral generation");
1565 }
1566 
1567 /*
1568  * Dummy Functions:
1569  * These functions are initially registered to avoid any crashes due to
1570  * invocation of spectral functions before they are registered.
1571  */
1572 
1573 static uint64_t
1574 null_get_tsf64(void *arg)
1575 {
1576 	spectral_ops_not_registered("get_tsf64");
1577 	return 0;
1578 }
1579 
1580 static uint32_t
1581 null_get_capability(void *arg, enum spectral_capability_type type)
1582 {
1583 	/*
1584 	 * TODO : We should have conditional compilation to get the capability
1585 	 *      : We have not yet attahced ATH layer here, so there is no
1586 	 *      : way to check the HAL capbalities
1587 	 */
1588 	spectral_ops_not_registered("get_capability");
1589 
1590 	/* TODO : For the time being, we are returning TRUE */
1591 	return true;
1592 }
1593 
1594 static uint32_t
1595 null_set_rxfilter(void *arg, int rxfilter)
1596 {
1597 	spectral_ops_not_registered("set_rxfilter");
1598 	return 1;
1599 }
1600 
1601 static uint32_t
1602 null_get_rxfilter(void *arg)
1603 {
1604 	spectral_ops_not_registered("get_rxfilter");
1605 	return 0;
1606 }
1607 
1608 static uint32_t
1609 null_is_spectral_active(void *arg, enum spectral_scan_mode smode)
1610 {
1611 	spectral_ops_not_registered("is_spectral_active");
1612 	return 1;
1613 }
1614 
1615 static uint32_t
1616 null_is_spectral_enabled(void *arg, enum spectral_scan_mode smode)
1617 {
1618 	spectral_ops_not_registered("is_spectral_enabled");
1619 	return 1;
1620 }
1621 
1622 static uint32_t
1623 null_start_spectral_scan(void *arg, enum spectral_scan_mode smode,
1624 			 enum spectral_cp_error_code *err)
1625 {
1626 	spectral_ops_not_registered("start_spectral_scan");
1627 	return 1;
1628 }
1629 
1630 static uint32_t
1631 null_stop_spectral_scan(void *arg, enum spectral_scan_mode smode)
1632 {
1633 	spectral_ops_not_registered("stop_spectral_scan");
1634 	return 1;
1635 }
1636 
1637 static uint32_t
1638 null_get_extension_channel(void *arg)
1639 {
1640 	spectral_ops_not_registered("get_extension_channel");
1641 	return 1;
1642 }
1643 
1644 static int8_t
1645 null_get_ctl_noisefloor(void *arg)
1646 {
1647 	spectral_ops_not_registered("get_ctl_noisefloor");
1648 	return 1;
1649 }
1650 
1651 static int8_t
1652 null_get_ext_noisefloor(void *arg)
1653 {
1654 	spectral_ops_not_registered("get_ext_noisefloor");
1655 	return 0;
1656 }
1657 
1658 static uint32_t
1659 null_configure_spectral(void *arg, struct spectral_config *params,
1660 			enum spectral_scan_mode smode)
1661 {
1662 	spectral_ops_not_registered("configure_spectral");
1663 	return 0;
1664 }
1665 
1666 static uint32_t
1667 null_get_spectral_config(void *arg, struct spectral_config *params,
1668 			 enum spectral_scan_mode smode)
1669 {
1670 	spectral_ops_not_registered("get_spectral_config");
1671 	return 0;
1672 }
1673 
1674 static uint32_t
1675 null_get_ent_spectral_mask(void *arg)
1676 {
1677 	spectral_ops_not_registered("get_ent_spectral_mask");
1678 	return 0;
1679 }
1680 
1681 static uint32_t
1682 null_get_mac_address(void *arg, char *addr)
1683 {
1684 	spectral_ops_not_registered("get_mac_address");
1685 	return 0;
1686 }
1687 
1688 static uint32_t
1689 null_get_current_channel(void *arg)
1690 {
1691 	spectral_ops_not_registered("get_current_channel");
1692 	return 0;
1693 }
1694 
1695 static uint32_t
1696 null_reset_hw(void *arg)
1697 {
1698 	spectral_ops_not_registered("get_current_channel");
1699 	return 0;
1700 }
1701 
1702 static uint32_t
1703 null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1704 {
1705 	spectral_ops_not_registered("get_chain_noise_floor");
1706 	return 0;
1707 }
1708 
1709 static int
1710 null_spectral_process_phyerr(struct target_if_spectral *spectral,
1711 			     uint8_t *data,
1712 			     uint32_t datalen,
1713 			     struct target_if_spectral_rfqual_info *p_rfqual,
1714 			     struct target_if_spectral_chan_info *p_chaninfo,
1715 			     uint64_t tsf64,
1716 			     struct target_if_spectral_acs_stats *acs_stats)
1717 {
1718 	spectral_ops_not_registered("spectral_process_phyerr");
1719 	return 0;
1720 }
1721 
1722 static int
1723 null_process_spectral_report(struct wlan_objmgr_pdev *pdev,
1724 			     void *payload)
1725 {
1726 	spectral_ops_not_registered("process_spectral_report");
1727 	return 0;
1728 }
1729 /**
1730  * target_if_spectral_init_dummy_function_table() -
1731  * Initialize target_if internal
1732  * Spectral operations to dummy functions
1733  * @ps: Pointer to Spectral target_if internal private data
1734  *
1735  * Initialize all the function pointers in target_if_spectral_ops with
1736  * dummy functions.
1737  *
1738  * Return: None
1739  */
1740 static void
1741 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps)
1742 {
1743 	struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps);
1744 
1745 	p_sops->get_tsf64 = null_get_tsf64;
1746 	p_sops->get_capability = null_get_capability;
1747 	p_sops->set_rxfilter = null_set_rxfilter;
1748 	p_sops->get_rxfilter = null_get_rxfilter;
1749 	p_sops->is_spectral_enabled = null_is_spectral_enabled;
1750 	p_sops->is_spectral_active = null_is_spectral_active;
1751 	p_sops->start_spectral_scan = null_start_spectral_scan;
1752 	p_sops->stop_spectral_scan = null_stop_spectral_scan;
1753 	p_sops->get_extension_channel = null_get_extension_channel;
1754 	p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
1755 	p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
1756 	p_sops->configure_spectral = null_configure_spectral;
1757 	p_sops->get_spectral_config = null_get_spectral_config;
1758 	p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
1759 	p_sops->get_mac_address = null_get_mac_address;
1760 	p_sops->get_current_channel = null_get_current_channel;
1761 	p_sops->reset_hw = null_reset_hw;
1762 	p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
1763 	p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
1764 	p_sops->process_spectral_report = null_process_spectral_report;
1765 }
1766 
1767 /**
1768  * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
1769  * operations
1770  * @spectral: Pointer to Spectral target_if internal private data
1771  * @p: Pointer to Spectral function table
1772  *
1773  * Return: None
1774  */
1775 static void
1776 target_if_spectral_register_funcs(struct target_if_spectral *spectral,
1777 				  struct target_if_spectral_ops *p)
1778 {
1779 	struct target_if_spectral_ops *p_sops =
1780 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1781 
1782 	p_sops->get_tsf64 = p->get_tsf64;
1783 	p_sops->get_capability = p->get_capability;
1784 	p_sops->set_rxfilter = p->set_rxfilter;
1785 	p_sops->get_rxfilter = p->get_rxfilter;
1786 	p_sops->is_spectral_enabled = p->is_spectral_enabled;
1787 	p_sops->is_spectral_active = p->is_spectral_active;
1788 	p_sops->start_spectral_scan = p->start_spectral_scan;
1789 	p_sops->stop_spectral_scan = p->stop_spectral_scan;
1790 	p_sops->get_extension_channel = p->get_extension_channel;
1791 	p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor;
1792 	p_sops->get_ext_noisefloor = p->get_ext_noisefloor;
1793 	p_sops->configure_spectral = p->configure_spectral;
1794 	p_sops->get_spectral_config = p->get_spectral_config;
1795 	p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask;
1796 	p_sops->get_mac_address = p->get_mac_address;
1797 	p_sops->get_current_channel = p->get_current_channel;
1798 	p_sops->reset_hw = p->reset_hw;
1799 	p_sops->get_chain_noise_floor = p->get_chain_noise_floor;
1800 	p_sops->spectral_process_phyerr = p->spectral_process_phyerr;
1801 	p_sops->process_spectral_report = p->process_spectral_report;
1802 }
1803 
1804 /**
1805  * target_if_spectral_clear_stats() - Clear Spectral stats
1806  * @spectral: Pointer to Spectral target_if internal private data
1807  *
1808  * Function to clear spectral stats
1809  *
1810  * Return: None
1811  */
1812 static void
1813 target_if_spectral_clear_stats(struct target_if_spectral *spectral)
1814 {
1815 	struct target_if_spectral_ops *p_sops =
1816 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1817 
1818 	qdf_mem_zero(&spectral->spectral_stats,
1819 		     sizeof(struct target_if_spectral_stats));
1820 	spectral->spectral_stats.last_reset_tstamp =
1821 	    p_sops->get_tsf64(spectral);
1822 }
1823 
1824 /**
1825  * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
1826  * @spectral: Pointer to Spectral target_if internal private data
1827  *
1828  * Function to check whether hardware supports spectral
1829  *
1830  * Return: True if HW supports Spectral, false if HW does not support Spectral
1831  */
1832 static int
1833 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
1834 {
1835 	struct target_if_spectral_ops *p_sops = NULL;
1836 	struct spectral_caps *pcap = NULL;
1837 	int is_spectral_supported = true;
1838 
1839 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1840 	pcap = &spectral->capability;
1841 
1842 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
1843 		is_spectral_supported = false;
1844 		spectral_info("SPECTRAL : No PHYDIAG support");
1845 		return is_spectral_supported;
1846 	}
1847 	pcap->phydiag_cap = 1;
1848 
1849 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
1850 		is_spectral_supported = false;
1851 		spectral_info("SPECTRAL : No RADAR support");
1852 		return is_spectral_supported;
1853 	}
1854 	pcap->radar_cap = 1;
1855 
1856 	if (p_sops->get_capability(spectral,
1857 				   SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
1858 		is_spectral_supported = false;
1859 		spectral_info("SPECTRAL : No SPECTRAL SUPPORT");
1860 		return is_spectral_supported;
1861 	}
1862 	pcap->spectral_cap = 1;
1863 
1864 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
1865 	    == false) {
1866 		spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT");
1867 	} else {
1868 		pcap->advncd_spectral_cap = 1;
1869 	}
1870 
1871 	return is_spectral_supported;
1872 }
1873 
1874 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1875 /**
1876  * target_if_spectral_detach_simulation() - De-initialize Spectral
1877  * Simulation functionality
1878  * @spectral: Pointer to Spectral target_if internal private data
1879  *
1880  * Function to de-initialize Spectral Simulation functionality
1881  *
1882  * Return: None
1883  */
1884 static void
1885 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
1886 {
1887 	target_if_spectral_sim_detach(spectral);
1888 }
1889 
1890 #else
1891 static void
1892 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
1893 {
1894 }
1895 #endif
1896 
1897 /**
1898  * target_if_spectral_detach() - De-initialize target_if Spectral
1899  * @pdev: Pointer to pdev object
1900  *
1901  * Function to detach target_if spectral
1902  *
1903  * Return: None
1904  */
1905 static void
1906 target_if_spectral_detach(struct target_if_spectral *spectral)
1907 {
1908 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1909 	spectral_info("spectral detach");
1910 
1911 	if (spectral) {
1912 		for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++)
1913 			qdf_spinlock_destroy
1914 				(&spectral->param_info[smode].osps_lock);
1915 
1916 		target_if_spectral_detach_simulation(spectral);
1917 
1918 		qdf_spinlock_destroy(&spectral->spectral_lock);
1919 		qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
1920 
1921 		qdf_mem_free(spectral);
1922 		spectral = NULL;
1923 	}
1924 }
1925 
1926 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1927 /**
1928  * target_if_spectral_attach_simulation() - Initialize Spectral Simulation
1929  * functionality
1930  * @spectral: Pointer to Spectral target_if internal private data
1931  *
1932  * Function to initialize spectral simulation functionality
1933  *
1934  * Return: 0 on success, negative error code on failure
1935  */
1936 static int
1937 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
1938 {
1939 	if (target_if_spectral_sim_attach(spectral)) {
1940 		qdf_mem_free(spectral);
1941 		return -EPERM;
1942 	}
1943 	return 0;
1944 }
1945 
1946 #else
1947 static int
1948 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
1949 {
1950 	return 0;
1951 }
1952 #endif
1953 
1954 /**
1955  * target_if_pdev_spectral_init() - Initialize target_if Spectral
1956  * functionality for the given pdev
1957  * @pdev: Pointer to pdev object
1958  *
1959  * Function to initialize pointer to spectral target_if internal private data
1960  *
1961  * Return: On success, pointer to Spectral target_if internal private data, on
1962  * failure, NULL
1963  */
1964 void *
1965 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
1966 {
1967 	struct target_if_spectral_ops *p_sops = NULL;
1968 	struct target_if_spectral *spectral = NULL;
1969 	uint32_t target_type;
1970 	uint32_t target_revision;
1971 	struct wlan_objmgr_psoc *psoc;
1972 	struct wlan_lmac_if_target_tx_ops *tx_ops;
1973 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1974 
1975 	if (!pdev) {
1976 		spectral_err("SPECTRAL: pdev is NULL!");
1977 		return NULL;
1978 	}
1979 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
1980 			sizeof(struct target_if_spectral));
1981 	if (!spectral)
1982 		return spectral;
1983 
1984 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
1985 	/* Store pdev in Spectral */
1986 	spectral->pdev_obj = pdev;
1987 
1988 	psoc = wlan_pdev_get_psoc(pdev);
1989 
1990 	tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops;
1991 
1992 	if (tx_ops->tgt_get_tgt_type) {
1993 		target_type = tx_ops->tgt_get_tgt_type(psoc);
1994 	} else {
1995 		qdf_mem_free(spectral);
1996 		return NULL;
1997 	}
1998 
1999 	if (tx_ops->tgt_get_tgt_revision) {
2000 		target_revision = tx_ops->tgt_get_tgt_revision(psoc);
2001 	} else {
2002 		qdf_mem_free(spectral);
2003 		return NULL;
2004 	}
2005 
2006 	/* init the function ptr table */
2007 	target_if_spectral_init_dummy_function_table(spectral);
2008 
2009 	/* get spectral function table */
2010 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2011 	/* TODO : Should this be called here of after ath_attach ? */
2012 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
2013 		spectral_info("HAL_CAP_PHYDIAG : Capable");
2014 
2015 	/* TODO: Need to fix the capablity check for RADAR */
2016 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
2017 		spectral_info("HAL_CAP_RADAR   : Capable");
2018 
2019 	/* TODO : Need to fix the capablity check for SPECTRAL */
2020 	/* TODO : Should this be called here of after ath_attach ? */
2021 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
2022 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
2023 
2024 	qdf_spinlock_create(&spectral->spectral_lock);
2025 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
2026 	target_if_spectral_clear_stats(spectral);
2027 
2028 	if (target_type == TARGET_TYPE_QCA8074V2)
2029 		spectral->fftbin_size_war =
2030 			SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE;
2031 	else if (target_type == TARGET_TYPE_QCA8074 ||
2032 		 target_type == TARGET_TYPE_QCA6018 ||
2033 		 target_type == TARGET_TYPE_QCA6390)
2034 		spectral->fftbin_size_war =
2035 			SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE;
2036 	else
2037 		spectral->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR;
2038 
2039 	if (target_type == TARGET_TYPE_QCA8074 ||
2040 	    target_type == TARGET_TYPE_QCA8074V2 ||
2041 	    target_type == TARGET_TYPE_QCA6018) {
2042 		spectral->inband_fftbin_size_adj = 1;
2043 		spectral->null_fftbin_adj = 1;
2044 	} else {
2045 		spectral->inband_fftbin_size_adj = 0;
2046 		spectral->null_fftbin_adj = 0;
2047 	}
2048 
2049 	if ((target_type == TARGET_TYPE_QCA8074) ||
2050 	    (target_type == TARGET_TYPE_QCA8074V2) ||
2051 	    (target_type == TARGET_TYPE_QCA6018) ||
2052 	    (target_type == TARGET_TYPE_QCN9000) ||
2053 	    (target_type == TARGET_TYPE_QCA6290) ||
2054 	    (target_type == TARGET_TYPE_QCA6390)) {
2055 		spectral->spectral_gen = SPECTRAL_GEN3;
2056 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
2057 		spectral->tag_sscan_summary_exp =
2058 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
2059 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
2060 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
2061 		spectral->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN3;
2062 		spectral->fft_size_max = SPECTRAL_PARAM_FFT_SIZE_MAX_GEN3;
2063 	} else {
2064 		spectral->spectral_gen = SPECTRAL_GEN2;
2065 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
2066 		spectral->tag_sscan_summary_exp =
2067 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
2068 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
2069 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
2070 		spectral->fft_size_min = SPECTRAL_PARAM_FFT_SIZE_MIN_GEN2;
2071 		spectral->fft_size_max = SPECTRAL_PARAM_FFT_SIZE_MAX_GEN2;
2072 	}
2073 
2074 	target_if_init_spectral_param_properties(spectral);
2075 	/* Init spectral capability */
2076 	if (target_if_init_spectral_capability(spectral) !=
2077 					QDF_STATUS_SUCCESS) {
2078 		qdf_mem_free(spectral);
2079 		return NULL;
2080 	}
2081 	if (target_if_spectral_attach_simulation(spectral) < 0)
2082 		return NULL;
2083 
2084 	target_if_init_spectral_ops(spectral);
2085 
2086 	/* Spectral mode specific init */
2087 	for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) {
2088 		spectral->last_fft_timestamp[smode] = 0;
2089 		spectral->timestamp_war_offset[smode] = 0;
2090 		spectral->params_valid[smode] = false;
2091 		qdf_spinlock_create(&spectral->param_info[smode].osps_lock);
2092 		spectral->param_info[smode].osps_cache.osc_is_valid = 0;
2093 	}
2094 
2095 	target_if_spectral_register_funcs(spectral, &spectral_ops);
2096 
2097 	if (target_if_spectral_check_hw_capability(spectral) == false) {
2098 		target_if_spectral_detach(spectral);
2099 		spectral = NULL;
2100 	} else {
2101 		/*
2102 		 * TODO: Once the driver architecture transitions to chipset
2103 		 * versioning based checks, reflect this here.
2104 		 */
2105 		spectral->is_160_format = false;
2106 		spectral->is_lb_edge_extrabins_format = false;
2107 		spectral->is_rb_edge_extrabins_format = false;
2108 
2109 		if (target_type == TARGET_TYPE_QCA9984 ||
2110 		    target_type == TARGET_TYPE_QCA9888) {
2111 			spectral->is_160_format = true;
2112 			spectral->is_lb_edge_extrabins_format = true;
2113 			spectral->is_rb_edge_extrabins_format = true;
2114 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
2115 			    (target_revision == AR900B_REV_2)) {
2116 			spectral->is_rb_edge_extrabins_format = true;
2117 		}
2118 
2119 		if (target_type == TARGET_TYPE_QCA9984 ||
2120 		    target_type == TARGET_TYPE_QCA9888)
2121 			spectral->is_sec80_rssi_war_required = true;
2122 
2123 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
2124 
2125 		if (spectral->spectral_gen == SPECTRAL_GEN3)
2126 			init_160mhz_delivery_state_machine(spectral);
2127 	}
2128 
2129 	return spectral;
2130 }
2131 
2132 /**
2133  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
2134  * functionality for the given pdev
2135  * @pdev: Pointer to pdev object
2136  *
2137  * Function to de-initialize pointer to spectral target_if internal private data
2138  *
2139  * Return: None
2140  */
2141 void
2142 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
2143 {
2144 	struct target_if_spectral *spectral = NULL;
2145 
2146 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2147 	if (!spectral) {
2148 		spectral_err("SPECTRAL : Module doesn't exist");
2149 		return;
2150 	}
2151 	target_if_spectral_detach(spectral);
2152 
2153 	return;
2154 }
2155 
2156 /* target_if_spectral_find_agile_width() - Given a channel width enum, find the
2157  *                          corresponding translation for Agile channel width.
2158  *                          Translation schema of different operating modes:
2159  *                          20 -> 20, 40 -> 40, (80 & 160 & 80_80) -> 80.
2160  * @chwidth: Channel width enum.
2161  *
2162  * Return: The translated channel width enum.
2163  */
2164 static enum phy_ch_width
2165 target_if_spectral_find_agile_width(enum phy_ch_width chwidth)
2166 {
2167 	switch (chwidth) {
2168 	case CH_WIDTH_20MHZ:
2169 		return CH_WIDTH_20MHZ;
2170 	case CH_WIDTH_40MHZ:
2171 		return CH_WIDTH_40MHZ;
2172 	case CH_WIDTH_80MHZ:
2173 	case CH_WIDTH_80P80MHZ:
2174 	case CH_WIDTH_160MHZ:
2175 		return CH_WIDTH_80MHZ;
2176 	default:
2177 		spectral_err("Invalid chwidth enum %d", chwidth);
2178 		return CH_WIDTH_INVALID;
2179 	}
2180 }
2181 
2182 /**
2183  * target_if_calculate_center_freq() - Helper routine to
2184  * check whether given frequency is center frequency of a
2185  * WLAN channel
2186  *
2187  * @spectral: Pointer to Spectral object
2188  * @chan_freq: Center frequency of a WLAN channel
2189  * @is_valid: Indicates whether given frequency is valid
2190  *
2191  * Return: QDF_STATUS
2192  */
2193 static QDF_STATUS
2194 target_if_is_center_freq_of_any_chan(struct wlan_objmgr_pdev *pdev,
2195 				     uint32_t chan_freq,
2196 				     bool *is_valid)
2197 {
2198 	struct regulatory_channel *cur_chan_list;
2199 	int i;
2200 
2201 	if (!pdev) {
2202 		spectral_err("pdev object is null");
2203 		return QDF_STATUS_E_FAILURE;
2204 	}
2205 
2206 	if (!is_valid) {
2207 		spectral_err("is valid argument is null");
2208 		return QDF_STATUS_E_FAILURE;
2209 	}
2210 
2211 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*cur_chan_list));
2212 	if (!cur_chan_list)
2213 		return QDF_STATUS_E_FAILURE;
2214 
2215 	if (wlan_reg_get_current_chan_list(
2216 			pdev, cur_chan_list) != QDF_STATUS_SUCCESS) {
2217 		spectral_err("Failed to get cur_chan list");
2218 		qdf_mem_free(cur_chan_list);
2219 		return QDF_STATUS_E_FAILURE;
2220 	}
2221 
2222 	*is_valid = false;
2223 	for (i = 0; i < NUM_CHANNELS; i++) {
2224 		uint32_t flags;
2225 		uint32_t center_freq;
2226 
2227 		flags = cur_chan_list[i].chan_flags;
2228 		center_freq = cur_chan_list[i].center_freq;
2229 
2230 		if (!(flags & REGULATORY_CHAN_DISABLED) &&
2231 		    (center_freq == chan_freq)) {
2232 			*is_valid = true;
2233 			break;
2234 		}
2235 	}
2236 
2237 	qdf_mem_free(cur_chan_list);
2238 
2239 	return QDF_STATUS_SUCCESS;
2240 }
2241 
2242 /**
2243  * target_if_calculate_center_freq() - Helper routine to
2244  * find the center frequency of the agile span from a
2245  * WLAN channel center frequency
2246  *
2247  * @spectral: Pointer to Spectral object
2248  * @chan_freq: Center frequency of a WLAN channel
2249  * @center_freq: Pointer to center frequency
2250  *
2251  * Return: QDF_STATUS
2252  */
2253 static QDF_STATUS
2254 target_if_calculate_center_freq(struct target_if_spectral *spectral,
2255 				uint16_t chan_freq,
2256 				uint16_t *center_freq)
2257 {
2258 	struct wlan_objmgr_vdev *vdev;
2259 	enum phy_ch_width ch_width;
2260 	enum phy_ch_width agile_ch_width;
2261 	uint16_t chan_num;
2262 
2263 	if (!spectral) {
2264 		spectral_err("spectral target if object is null");
2265 		return QDF_STATUS_E_FAILURE;
2266 	}
2267 
2268 	if (!center_freq) {
2269 		spectral_err("center_freq argument is null");
2270 		return QDF_STATUS_E_FAILURE;
2271 	}
2272 
2273 	chan_num = wlan_reg_freq_to_chan(spectral->pdev_obj, chan_freq);
2274 
2275 	vdev = target_if_spectral_get_vdev(spectral);
2276 	if (!vdev) {
2277 		spectral_err("vdev is NULL");
2278 		return QDF_STATUS_E_FAILURE;
2279 	}
2280 	ch_width = target_if_vdev_get_ch_width(vdev);
2281 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2282 	agile_ch_width = target_if_spectral_find_agile_width(ch_width);
2283 
2284 	if (agile_ch_width == CH_WIDTH_20MHZ) {
2285 		*center_freq = chan_freq;
2286 	} else {
2287 		uint16_t start_freq;
2288 		uint16_t end_freq;
2289 		const struct bonded_channel *bonded_chan_ptr = NULL;
2290 
2291 		wlan_reg_get_5g_bonded_channel_and_state
2292 			(spectral->pdev_obj, chan_num, agile_ch_width,
2293 			 &bonded_chan_ptr);
2294 		if (!bonded_chan_ptr) {
2295 			spectral_err("Bonded channel is not found");
2296 			return QDF_STATUS_E_FAILURE;
2297 		}
2298 		start_freq = wlan_reg_chan_to_freq(spectral->pdev_obj,
2299 						   bonded_chan_ptr->start_ch);
2300 		end_freq = wlan_reg_chan_to_freq(spectral->pdev_obj,
2301 						 bonded_chan_ptr->end_ch);
2302 		*center_freq = (start_freq + end_freq) >> 1;
2303 	}
2304 
2305 	return QDF_STATUS_SUCCESS;
2306 }
2307 
2308 /**
2309  * target_if_validate_center_freq() - Helper routine to
2310  * validate user provided agile center frequency
2311  *
2312  * @spectral: Pointer to Spectral object
2313  * @center_freq: User provided agile span center frequency
2314  * @is_valid: Indicates whether agile span center frequency is valid
2315  *
2316  * Return: QDF_STATUS
2317  */
2318 static QDF_STATUS
2319 target_if_validate_center_freq(struct target_if_spectral *spectral,
2320 			       uint16_t center_freq,
2321 			       bool *is_valid)
2322 {
2323 	struct wlan_objmgr_vdev *vdev;
2324 	enum phy_ch_width ch_width;
2325 	enum phy_ch_width agile_ch_width;
2326 	uint16_t chan_num;
2327 	struct wlan_objmgr_pdev *pdev;
2328 	QDF_STATUS status;
2329 
2330 	if (!spectral) {
2331 		spectral_err("spectral target if object is null");
2332 		return QDF_STATUS_E_FAILURE;
2333 	}
2334 
2335 	if (!is_valid) {
2336 		spectral_err("is_valid argument is null");
2337 		return QDF_STATUS_E_FAILURE;
2338 	}
2339 
2340 	pdev = spectral->pdev_obj;
2341 	vdev = target_if_spectral_get_vdev(spectral);
2342 	if (!vdev) {
2343 		spectral_err("vdev is NULL");
2344 		return QDF_STATUS_E_FAILURE;
2345 	}
2346 	ch_width = target_if_vdev_get_ch_width(vdev);
2347 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2348 	agile_ch_width = target_if_spectral_find_agile_width(ch_width);
2349 
2350 	if (agile_ch_width == CH_WIDTH_20MHZ) {
2351 		status = target_if_is_center_freq_of_any_chan
2352 				(pdev, center_freq, is_valid);
2353 		if (QDF_IS_STATUS_ERROR(status))
2354 			return QDF_STATUS_E_FAILURE;
2355 	} else {
2356 		uint16_t start_freq;
2357 		uint16_t end_freq;
2358 		const struct bonded_channel *bonded_chan_ptr = NULL;
2359 		bool is_chan;
2360 
2361 		status = target_if_is_center_freq_of_any_chan
2362 				(pdev, center_freq + 10, &is_chan);
2363 		if (QDF_IS_STATUS_ERROR(status))
2364 			return QDF_STATUS_E_FAILURE;
2365 
2366 		if (is_chan) {
2367 			uint32_t calulated_center_freq;
2368 
2369 			chan_num = wlan_reg_freq_to_chan(pdev,
2370 							 center_freq + 10);
2371 			wlan_reg_get_5g_bonded_channel_and_state
2372 				(pdev, chan_num, agile_ch_width,
2373 				 &bonded_chan_ptr);
2374 			if (!bonded_chan_ptr) {
2375 				spectral_err("Bonded channel is not found");
2376 				return QDF_STATUS_E_FAILURE;
2377 			}
2378 			start_freq = wlan_reg_chan_to_freq
2379 				(pdev, bonded_chan_ptr->start_ch);
2380 			end_freq = wlan_reg_chan_to_freq
2381 				(pdev, bonded_chan_ptr->end_ch);
2382 			calulated_center_freq = (start_freq + end_freq) >> 1;
2383 			*is_valid = (center_freq == calulated_center_freq);
2384 		} else {
2385 			*is_valid = false;
2386 		}
2387 	}
2388 
2389 	return QDF_STATUS_SUCCESS;
2390 }
2391 
2392 /**
2393  * target_if_is_agile_span_overlap_with_operating_span() - Helper routine to
2394  * check whether agile span overlaps with current operating band.
2395  *
2396  * @spectral: Pointer to Spectral object
2397  * @ss_frequency: Agile span center frequency
2398  * @is_overlapping: Indicates whether Agile span overlaps with operating span
2399  *
2400  * Helper routine to check whether agile span overlaps with current
2401  * operating band.
2402  *
2403  * Return: QDF_STATUS
2404  */
2405 static QDF_STATUS
2406 target_if_is_agile_span_overlap_with_operating_span
2407 			(struct target_if_spectral *spectral,
2408 			 uint32_t ss_frequency,
2409 			 bool *is_overlapping)
2410 {
2411 	uint32_t chan_num;
2412 	enum phy_ch_width ch_width;
2413 	enum phy_ch_width agile_ch_width;
2414 	const struct bonded_channel *bonded_chan_ptr = NULL;
2415 	struct wlan_objmgr_vdev *vdev;
2416 	struct wlan_objmgr_pdev *pdev;
2417 	int16_t chan_freq;
2418 	uint32_t op_start_freq;
2419 	uint32_t op_end_freq;
2420 	uint32_t agile_start_freq;
2421 	uint32_t agile_end_freq;
2422 	uint32_t cfreq2;
2423 
2424 	if (!spectral) {
2425 		spectral_err("Spectral object is NULL");
2426 		return QDF_STATUS_E_FAILURE;
2427 	}
2428 
2429 	pdev  = spectral->pdev_obj;
2430 	if (!pdev) {
2431 		spectral_err("pdev object is NULL");
2432 		return QDF_STATUS_E_FAILURE;
2433 	}
2434 
2435 	if (!is_overlapping) {
2436 		spectral_err("Argument(is_overlapping) is NULL");
2437 		return QDF_STATUS_E_FAILURE;
2438 	}
2439 
2440 	vdev = target_if_spectral_get_vdev(spectral);
2441 	if (!vdev) {
2442 		spectral_err("vdev is NULL");
2443 		return QDF_STATUS_E_FAILURE;
2444 	}
2445 	ch_width = target_if_vdev_get_ch_width(vdev);
2446 	chan_freq = target_if_vdev_get_chan_freq(vdev);
2447 	cfreq2 = target_if_vdev_get_chan_freq_seg2(vdev);
2448 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2449 	if (cfreq2 < 0)
2450 		return QDF_STATUS_E_FAILURE;
2451 
2452 	chan_num = wlan_reg_freq_to_chan(pdev, chan_freq);
2453 
2454 	if (ch_width == CH_WIDTH_20MHZ) {
2455 		op_start_freq = chan_freq - 10;
2456 		op_end_freq = chan_freq + 10;
2457 	} else {
2458 		wlan_reg_get_5g_bonded_channel_and_state
2459 			(pdev, chan_num, ch_width, &bonded_chan_ptr);
2460 		if (!bonded_chan_ptr) {
2461 			spectral_err("Bonded channel is not found");
2462 			return QDF_STATUS_E_FAILURE;
2463 		}
2464 		op_start_freq =
2465 			wlan_reg_chan_to_freq(pdev,
2466 					      bonded_chan_ptr->start_ch) - 10;
2467 		op_end_freq =
2468 			wlan_reg_chan_to_freq(pdev,
2469 					      bonded_chan_ptr->end_ch) + 10;
2470 	}
2471 
2472 	agile_ch_width = target_if_spectral_find_agile_width(ch_width);
2473 	if (agile_ch_width == CH_WIDTH_INVALID)
2474 		return QDF_STATUS_E_FAILURE;
2475 	agile_start_freq = ss_frequency -
2476 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
2477 	agile_end_freq = ss_frequency +
2478 				(wlan_reg_get_bw_value(agile_ch_width) >> 1);
2479 	if (agile_end_freq <= op_start_freq || op_end_freq <= agile_start_freq)
2480 		*is_overlapping = false;
2481 	else
2482 		*is_overlapping = true;
2483 
2484 	/* Use non zero cfreq2 to identify 80p80 */
2485 	if (cfreq2) {
2486 		uint32_t sec80_start_feq;
2487 		uint32_t sec80_end_freq;
2488 
2489 		sec80_start_feq = cfreq2 - 40;
2490 		sec80_end_freq = cfreq2 + 40;
2491 
2492 		if ((agile_end_freq > sec80_start_feq) &&
2493 		    (sec80_end_freq > agile_start_freq))
2494 			*is_overlapping = true;
2495 	}
2496 
2497 	return QDF_STATUS_SUCCESS;
2498 }
2499 
2500 /**
2501  * _target_if_set_spectral_config() - Set spectral config
2502  * @spectral:       Pointer to spectral object
2503  * @threshtype: config type
2504  * @value:      config value
2505  * @smode: Spectral scan mode
2506  * @err: Spectral error code
2507  *
2508  * API to set spectral configurations
2509  *
2510  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
2511  */
2512 static QDF_STATUS
2513 _target_if_set_spectral_config(struct target_if_spectral *spectral,
2514 			       const uint32_t threshtype, const uint32_t value,
2515 			       const enum spectral_scan_mode smode,
2516 			       enum spectral_cp_error_code *err)
2517 {
2518 	struct spectral_config params;
2519 	struct target_if_spectral_ops *p_sops;
2520 	struct spectral_config *sparams;
2521 	QDF_STATUS status;
2522 	bool is_overlapping;
2523 	uint16_t agile_cfreq;
2524 	bool is_valid_chan;
2525 
2526 	if (!err) {
2527 		spectral_err("Error code argument is null");
2528 		QDF_ASSERT(0);
2529 	}
2530 	*err = SPECTRAL_SCAN_ERR_INVALID;
2531 
2532 	if (!spectral) {
2533 		spectral_err("spectral object is NULL");
2534 		return QDF_STATUS_E_FAILURE;
2535 	}
2536 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2537 
2538 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2539 		spectral_err("Invalid Spectral mode %u", smode);
2540 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
2541 		return QDF_STATUS_E_FAILURE;
2542 	}
2543 
2544 	sparams = &spectral->params[smode];
2545 
2546 	if (!spectral->params_valid[smode]) {
2547 		target_if_spectral_info_read(spectral,
2548 					     smode,
2549 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
2550 					     &spectral->params[smode],
2551 					     sizeof(spectral->params[smode]));
2552 		spectral->params_valid[smode] = true;
2553 	}
2554 
2555 	switch (threshtype) {
2556 	case SPECTRAL_PARAM_FFT_PERIOD:
2557 		sparams->ss_fft_period = value;
2558 		break;
2559 	case SPECTRAL_PARAM_SCAN_PERIOD:
2560 		sparams->ss_period = value;
2561 		break;
2562 	case SPECTRAL_PARAM_SCAN_COUNT:
2563 		sparams->ss_count = value;
2564 		break;
2565 	case SPECTRAL_PARAM_SHORT_REPORT:
2566 		sparams->ss_short_report = (!!value) ? true : false;
2567 		break;
2568 	case SPECTRAL_PARAM_SPECT_PRI:
2569 		sparams->ss_spectral_pri = (!!value) ? true : false;
2570 		break;
2571 	case SPECTRAL_PARAM_FFT_SIZE:
2572 		if ((value < spectral->fft_size_min) ||
2573 		    (value > spectral->fft_size_max)) {
2574 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
2575 			return QDF_STATUS_E_FAILURE;
2576 		}
2577 		sparams->ss_fft_size = value;
2578 		break;
2579 	case SPECTRAL_PARAM_GC_ENA:
2580 		sparams->ss_gc_ena = !!value;
2581 		break;
2582 	case SPECTRAL_PARAM_RESTART_ENA:
2583 		sparams->ss_restart_ena = !!value;
2584 		break;
2585 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
2586 		sparams->ss_noise_floor_ref = value;
2587 		break;
2588 	case SPECTRAL_PARAM_INIT_DELAY:
2589 		sparams->ss_init_delay = value;
2590 		break;
2591 	case SPECTRAL_PARAM_NB_TONE_THR:
2592 		sparams->ss_nb_tone_thr = value;
2593 		break;
2594 	case SPECTRAL_PARAM_STR_BIN_THR:
2595 		sparams->ss_str_bin_thr = value;
2596 		break;
2597 	case SPECTRAL_PARAM_WB_RPT_MODE:
2598 		sparams->ss_wb_rpt_mode = !!value;
2599 		break;
2600 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
2601 		sparams->ss_rssi_rpt_mode = !!value;
2602 		break;
2603 	case SPECTRAL_PARAM_RSSI_THR:
2604 		sparams->ss_rssi_thr = value;
2605 		break;
2606 	case SPECTRAL_PARAM_PWR_FORMAT:
2607 		sparams->ss_pwr_format = !!value;
2608 		break;
2609 	case SPECTRAL_PARAM_RPT_MODE:
2610 		if ((value < SPECTRAL_PARAM_RPT_MODE_MIN) ||
2611 		    (value > SPECTRAL_PARAM_RPT_MODE_MAX)) {
2612 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
2613 			return QDF_STATUS_E_FAILURE;
2614 		}
2615 		sparams->ss_rpt_mode = value;
2616 		break;
2617 	case SPECTRAL_PARAM_BIN_SCALE:
2618 		sparams->ss_bin_scale = value;
2619 		break;
2620 	case SPECTRAL_PARAM_DBM_ADJ:
2621 		sparams->ss_dbm_adj = !!value;
2622 		break;
2623 	case SPECTRAL_PARAM_CHN_MASK:
2624 		sparams->ss_chn_mask = value;
2625 		break;
2626 	case SPECTRAL_PARAM_FREQUENCY:
2627 		status = target_if_is_center_freq_of_any_chan
2628 				(spectral->pdev_obj, value, &is_valid_chan);
2629 		if (QDF_IS_STATUS_ERROR(status))
2630 			return QDF_STATUS_E_FAILURE;
2631 
2632 		if (is_valid_chan) {
2633 			status = target_if_calculate_center_freq(spectral,
2634 								 value,
2635 								 &agile_cfreq);
2636 			if (QDF_IS_STATUS_ERROR(status)) {
2637 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
2638 				return QDF_STATUS_E_FAILURE;
2639 			}
2640 		} else {
2641 			bool is_valid_agile_cfreq;
2642 
2643 			status = target_if_validate_center_freq
2644 				(spectral, value, &is_valid_agile_cfreq);
2645 			if (QDF_IS_STATUS_ERROR(status))
2646 				return QDF_STATUS_E_FAILURE;
2647 
2648 			if (!is_valid_agile_cfreq) {
2649 				*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
2650 				spectral_err("Invalid agile center frequency");
2651 				return QDF_STATUS_E_FAILURE;
2652 			}
2653 
2654 			agile_cfreq = value;
2655 		}
2656 
2657 		status = target_if_is_agile_span_overlap_with_operating_span
2658 				(spectral, agile_cfreq, &is_overlapping);
2659 		if (QDF_IS_STATUS_ERROR(status))
2660 			return QDF_STATUS_E_FAILURE;
2661 
2662 		if (is_overlapping) {
2663 			spectral_err("Agile span overlapping with current BW");
2664 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
2665 			return QDF_STATUS_E_FAILURE;
2666 		}
2667 		sparams->ss_frequency = agile_cfreq;
2668 		break;
2669 	}
2670 
2671 	p_sops->configure_spectral(spectral, sparams, smode);
2672 	/* only to validate the writes */
2673 	p_sops->get_spectral_config(spectral, &params, smode);
2674 	return QDF_STATUS_SUCCESS;
2675 }
2676 
2677 QDF_STATUS
2678 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
2679 			      const uint32_t threshtype, const uint32_t value,
2680 			      const enum spectral_scan_mode smode,
2681 			      enum spectral_cp_error_code *err)
2682 {
2683 	enum spectral_scan_mode mode = SPECTRAL_SCAN_MODE_NORMAL;
2684 	struct target_if_spectral *spectral;
2685 	QDF_STATUS status;
2686 
2687 	if (!err) {
2688 		spectral_err("Error code argument is null");
2689 		QDF_ASSERT(0);
2690 	}
2691 	*err = SPECTRAL_SCAN_ERR_INVALID;
2692 
2693 	if (!pdev) {
2694 		spectral_err("pdev object is NULL");
2695 		return QDF_STATUS_E_FAILURE;
2696 	}
2697 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2698 	if (!spectral) {
2699 		spectral_err("spectral object is NULL");
2700 		return QDF_STATUS_E_FAILURE;
2701 	}
2702 
2703 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2704 		spectral_err("Invalid Spectral mode %u", smode);
2705 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
2706 		return QDF_STATUS_E_FAILURE;
2707 	}
2708 
2709 	if (!spectral->properties[smode][threshtype].supported) {
2710 		spectral_err("Spectral parameter(%u) unsupported for mode %u",
2711 			     threshtype, smode);
2712 		*err = SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED;
2713 		return QDF_STATUS_E_FAILURE;
2714 	}
2715 
2716 	if (spectral->properties[smode][threshtype].common_all_modes) {
2717 		spectral_warn("Setting Spectral parameter %u for all modes",
2718 			      threshtype);
2719 		for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) {
2720 			status = _target_if_set_spectral_config
2721 						(spectral, threshtype, value,
2722 						 mode, err);
2723 			if (QDF_IS_STATUS_ERROR(status))
2724 				return QDF_STATUS_E_FAILURE;
2725 		}
2726 		return QDF_STATUS_SUCCESS;
2727 	}
2728 
2729 	return _target_if_set_spectral_config(spectral, threshtype,
2730 					      value, smode, err);
2731 }
2732 
2733 /**
2734  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
2735  * @fft_len: FFT length
2736  * @pdev: Pointer to pdev object
2737  *
2738  * API to get fft bin count for a given fft length
2739  *
2740  * Return: FFt bin count
2741  */
2742 static int
2743 target_if_get_fft_bin_count(int fft_len)
2744 {
2745 	int bin_count = 0;
2746 
2747 	switch (fft_len) {
2748 	case 5:
2749 		bin_count = 16;
2750 		break;
2751 	case 6:
2752 		bin_count = 32;
2753 		break;
2754 	case 7:
2755 		bin_count = 64;
2756 		break;
2757 	case 8:
2758 		bin_count = 128;
2759 		break;
2760 	case 9:
2761 		bin_count = 256;
2762 		break;
2763 	default:
2764 		break;
2765 	}
2766 
2767 	return bin_count;
2768 }
2769 
2770 /**
2771  * target_if_init_upper_lower_flags() - Initializes control and extension
2772  * segment flags
2773  * @fft_len: FFT length
2774  * @pdev: Pointer to pdev object
2775  *
2776  * API to initialize the control and extension flags with the lower/upper
2777  * segment based on the HT mode
2778  *
2779  * Return: FFt bin count
2780  */
2781 static void
2782 target_if_init_upper_lower_flags(struct target_if_spectral *spectral)
2783 {
2784 	int current_channel = 0;
2785 	int ext_channel = 0;
2786 	struct target_if_spectral_ops *p_sops =
2787 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2788 
2789 	current_channel = p_sops->get_current_channel(spectral);
2790 	ext_channel = p_sops->get_extension_channel(spectral);
2791 
2792 	if ((current_channel == 0) || (ext_channel == 0))
2793 		return;
2794 
2795 	if (spectral->sc_spectral_20_40_mode) {
2796 		/* HT40 mode */
2797 		if (ext_channel < current_channel) {
2798 			spectral->lower_is_extension = 1;
2799 			spectral->upper_is_control = 1;
2800 			spectral->lower_is_control = 0;
2801 			spectral->upper_is_extension = 0;
2802 		} else {
2803 			spectral->lower_is_extension = 0;
2804 			spectral->upper_is_control = 0;
2805 			spectral->lower_is_control = 1;
2806 			spectral->upper_is_extension = 1;
2807 		}
2808 	} else {
2809 		/* HT20 mode, lower is always control */
2810 		spectral->lower_is_extension = 0;
2811 		spectral->upper_is_control = 0;
2812 		spectral->lower_is_control = 1;
2813 		spectral->upper_is_extension = 0;
2814 	}
2815 }
2816 
2817 /**
2818  * target_if_get_spectral_config() - Get spectral configuration
2819  * @pdev: Pointer to pdev object
2820  * @param: Pointer to spectral_config structure in which the configuration
2821  * should be returned
2822  * @smode: Spectral scan mode
2823  *
2824  * API to get the current spectral configuration
2825  *
2826  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
2827  */
2828 QDF_STATUS
2829 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
2830 			      struct spectral_config *param,
2831 			      enum spectral_scan_mode smode)
2832 {
2833 	struct target_if_spectral_ops *p_sops = NULL;
2834 	struct target_if_spectral *spectral = NULL;
2835 
2836 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2837 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2838 
2839 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2840 		spectral_err("Invalid Spectral mode %u", smode);
2841 		return QDF_STATUS_E_FAILURE;
2842 	}
2843 
2844 	qdf_mem_zero(param, sizeof(struct spectral_config));
2845 	p_sops->get_spectral_config(spectral, param, smode);
2846 
2847 	return QDF_STATUS_SUCCESS;
2848 }
2849 
2850 /**
2851  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
2852  *                                           parameters
2853  * @spectral: Pointer to Spectral target_if internal private data
2854  * @spectral_params: Pointer to Spectral parameters
2855  * @smode: Spectral scan mode
2856  * @err: Spectral error code
2857  *
2858  * Enable use of desired Spectral parameters by configuring them into HW, and
2859  * starting Spectral scan
2860  *
2861  * Return: 0 on success, 1 on failure
2862  */
2863 int
2864 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
2865 				      struct spectral_config *spectral_params,
2866 				      enum spectral_scan_mode smode,
2867 				      enum spectral_cp_error_code *err)
2868 {
2869 	int extension_channel = 0;
2870 	int current_channel = 0;
2871 	struct target_if_spectral_ops *p_sops = NULL;
2872 	struct wlan_objmgr_vdev *vdev = NULL;
2873 
2874 	if (!spectral) {
2875 		spectral_err("Spectral LMAC object is NULL");
2876 		return 1;
2877 	}
2878 
2879 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2880 		spectral_err("Invalid Spectral mode %u", smode);
2881 		return 1;
2882 	}
2883 
2884 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2885 
2886 	if (!p_sops) {
2887 		spectral_err("p_sops is NULL");
2888 		return 1;
2889 	}
2890 
2891 	spectral->sc_spectral_noise_pwr_cal =
2892 	    spectral_params->ss_spectral_pri ? 1 : 0;
2893 
2894 	/* check if extension channel is present */
2895 	extension_channel = p_sops->get_extension_channel(spectral);
2896 	current_channel = p_sops->get_current_channel(spectral);
2897 
2898 	vdev = target_if_spectral_get_vdev(spectral);
2899 	if (!vdev)
2900 		return 1;
2901 
2902 	spectral->ch_width = target_if_vdev_get_ch_width(vdev);
2903 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2904 
2905 	if (spectral->ch_width == CH_WIDTH_INVALID)
2906 		return 1;
2907 
2908 	if (spectral->capability.advncd_spectral_cap) {
2909 		spectral->lb_edge_extrabins = 0;
2910 		spectral->rb_edge_extrabins = 0;
2911 
2912 		if (spectral->is_lb_edge_extrabins_format &&
2913 		    spectral->params[smode].ss_rpt_mode == 2) {
2914 			spectral->lb_edge_extrabins = 4;
2915 		}
2916 
2917 		if (spectral->is_rb_edge_extrabins_format &&
2918 		    spectral->params[smode].ss_rpt_mode == 2) {
2919 			spectral->rb_edge_extrabins = 4;
2920 		}
2921 
2922 		if (spectral->ch_width == CH_WIDTH_20MHZ) {
2923 			spectral->sc_spectral_20_40_mode = 0;
2924 
2925 			spectral->spectral_numbins =
2926 			    target_if_get_fft_bin_count(
2927 				spectral->params[smode].ss_fft_size);
2928 			spectral->spectral_fft_len =
2929 			    target_if_get_fft_bin_count(
2930 				spectral->params[smode].ss_fft_size);
2931 			spectral->spectral_data_len =
2932 			    target_if_get_fft_bin_count(
2933 				spectral->params[smode].ss_fft_size);
2934 			/*
2935 			 * Initialize classifier params to be sent to user
2936 			 * space classifier
2937 			 */
2938 			spectral->classifier_params.lower_chan_in_mhz =
2939 			    current_channel;
2940 			spectral->classifier_params.upper_chan_in_mhz = 0;
2941 
2942 		} else if (spectral->ch_width == CH_WIDTH_40MHZ) {
2943 			/* TODO : Remove this variable */
2944 			spectral->sc_spectral_20_40_mode = 1;
2945 			spectral->spectral_numbins =
2946 			    target_if_get_fft_bin_count(
2947 				spectral->params[smode].ss_fft_size);
2948 			spectral->spectral_fft_len =
2949 			    target_if_get_fft_bin_count(
2950 				spectral->params[smode].ss_fft_size);
2951 			spectral->spectral_data_len =
2952 			    target_if_get_fft_bin_count(
2953 				spectral->params[smode].ss_fft_size);
2954 
2955 			/*
2956 			 * Initialize classifier params to be sent to user
2957 			 * space classifier
2958 			 */
2959 			if (extension_channel < current_channel) {
2960 				spectral->classifier_params.lower_chan_in_mhz =
2961 				    extension_channel;
2962 				spectral->classifier_params.upper_chan_in_mhz =
2963 				    current_channel;
2964 			} else {
2965 				spectral->classifier_params.lower_chan_in_mhz =
2966 				    current_channel;
2967 				spectral->classifier_params.upper_chan_in_mhz =
2968 				    extension_channel;
2969 			}
2970 
2971 		} else if (spectral->ch_width == CH_WIDTH_80MHZ) {
2972 			/* Set the FFT Size */
2973 			/* TODO : Remove this variable */
2974 			spectral->sc_spectral_20_40_mode = 0;
2975 			spectral->spectral_numbins =
2976 			    target_if_get_fft_bin_count(
2977 				spectral->params[smode].ss_fft_size);
2978 			spectral->spectral_fft_len =
2979 			    target_if_get_fft_bin_count(
2980 				spectral->params[smode].ss_fft_size);
2981 			spectral->spectral_data_len =
2982 			    target_if_get_fft_bin_count(
2983 				spectral->params[smode].ss_fft_size);
2984 
2985 			/*
2986 			 * Initialize classifier params to be sent to user
2987 			 * space classifier
2988 			 */
2989 			spectral->classifier_params.lower_chan_in_mhz =
2990 			    current_channel;
2991 			spectral->classifier_params.upper_chan_in_mhz = 0;
2992 
2993 			/*
2994 			 * Initialize classifier params to be sent to user
2995 			 * space classifier
2996 			 */
2997 			if (extension_channel < current_channel) {
2998 				spectral->classifier_params.lower_chan_in_mhz =
2999 				    extension_channel;
3000 				spectral->classifier_params.upper_chan_in_mhz =
3001 				    current_channel;
3002 			} else {
3003 				spectral->classifier_params.lower_chan_in_mhz =
3004 				    current_channel;
3005 				spectral->classifier_params.upper_chan_in_mhz =
3006 				    extension_channel;
3007 			}
3008 
3009 		} else if (spectral->ch_width == CH_WIDTH_160MHZ) {
3010 			/* Set the FFT Size */
3011 
3012 			/* The below applies to both 160 and 80+80 cases */
3013 
3014 			/* TODO : Remove this variable */
3015 			spectral->sc_spectral_20_40_mode = 0;
3016 			spectral->spectral_numbins =
3017 			    target_if_get_fft_bin_count(
3018 				spectral->params[smode].ss_fft_size);
3019 			spectral->spectral_fft_len =
3020 			    target_if_get_fft_bin_count(
3021 				spectral->params[smode].ss_fft_size);
3022 			spectral->spectral_data_len =
3023 			    target_if_get_fft_bin_count(
3024 				spectral->params[smode].ss_fft_size);
3025 
3026 			/*
3027 			 * Initialize classifier params to be sent to user
3028 			 * space classifier
3029 			 */
3030 			spectral->classifier_params.lower_chan_in_mhz =
3031 			    current_channel;
3032 			spectral->classifier_params.upper_chan_in_mhz = 0;
3033 
3034 			/*
3035 			 * Initialize classifier params to be sent to user
3036 			 * space classifier
3037 			 */
3038 			if (extension_channel < current_channel) {
3039 				spectral->classifier_params.lower_chan_in_mhz =
3040 				    extension_channel;
3041 				spectral->classifier_params.upper_chan_in_mhz =
3042 				    current_channel;
3043 			} else {
3044 				spectral->classifier_params.lower_chan_in_mhz =
3045 				    current_channel;
3046 				spectral->classifier_params.upper_chan_in_mhz =
3047 				    extension_channel;
3048 			}
3049 		}
3050 
3051 		if (spectral->spectral_numbins) {
3052 			spectral->spectral_numbins +=
3053 			    spectral->lb_edge_extrabins;
3054 			spectral->spectral_numbins +=
3055 			    spectral->rb_edge_extrabins;
3056 		}
3057 
3058 		if (spectral->spectral_fft_len) {
3059 			spectral->spectral_fft_len +=
3060 			    spectral->lb_edge_extrabins;
3061 			spectral->spectral_fft_len +=
3062 			    spectral->rb_edge_extrabins;
3063 		}
3064 
3065 		if (spectral->spectral_data_len) {
3066 			spectral->spectral_data_len +=
3067 			    spectral->lb_edge_extrabins;
3068 			spectral->spectral_data_len +=
3069 			    spectral->rb_edge_extrabins;
3070 		}
3071 	} else {
3072 		/*
3073 		 * The decision to find 20/40 mode is found based on the
3074 		 * presence of extension channel
3075 		 * instead of channel width, as the channel width can
3076 		 * dynamically change
3077 		 */
3078 
3079 		if (extension_channel == 0) {
3080 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
3081 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
3082 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
3083 			spectral->spectral_data_len =
3084 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
3085 			/* only valid in 20-40 mode */
3086 			spectral->spectral_lower_max_index_offset = -1;
3087 			/* only valid in 20-40 mode */
3088 			spectral->spectral_upper_max_index_offset = -1;
3089 			spectral->spectral_max_index_offset =
3090 			    spectral->spectral_fft_len + 2;
3091 			spectral->sc_spectral_20_40_mode = 0;
3092 
3093 			/*
3094 			 * Initialize classifier params to be sent to user
3095 			 * space classifier
3096 			 */
3097 			spectral->classifier_params.lower_chan_in_mhz =
3098 			    current_channel;
3099 			spectral->classifier_params.upper_chan_in_mhz = 0;
3100 
3101 		} else {
3102 			spectral->spectral_numbins =
3103 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
3104 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
3105 			spectral->spectral_data_len =
3106 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
3107 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
3108 			/* only valid in 20 mode */
3109 			spectral->spectral_max_index_offset = -1;
3110 			spectral->spectral_lower_max_index_offset =
3111 			    spectral->spectral_fft_len + 2;
3112 			spectral->spectral_upper_max_index_offset =
3113 			    spectral->spectral_fft_len + 5;
3114 			spectral->sc_spectral_20_40_mode = 1;
3115 
3116 			/*
3117 			 * Initialize classifier params to be sent to user
3118 			 * space classifier
3119 			 */
3120 			if (extension_channel < current_channel) {
3121 				spectral->classifier_params.lower_chan_in_mhz =
3122 				    extension_channel;
3123 				spectral->classifier_params.upper_chan_in_mhz =
3124 				    current_channel;
3125 			} else {
3126 				spectral->classifier_params.lower_chan_in_mhz =
3127 				    current_channel;
3128 				spectral->classifier_params.upper_chan_in_mhz =
3129 				    extension_channel;
3130 			}
3131 		}
3132 	}
3133 
3134 	spectral->send_single_packet = 0;
3135 	spectral->classifier_params.spectral_20_40_mode =
3136 	    spectral->sc_spectral_20_40_mode;
3137 	spectral->classifier_params.spectral_dc_index =
3138 	    spectral->spectral_dc_index;
3139 	spectral->spectral_sent_msg = 0;
3140 	spectral->classify_scan = 0;
3141 	spectral->num_spectral_data = 0;
3142 
3143 	if (!p_sops->is_spectral_active(spectral, smode)) {
3144 		p_sops->configure_spectral(spectral, spectral_params, smode);
3145 		p_sops->start_spectral_scan(spectral, smode, err);
3146 		spectral->timestamp_war_offset[smode] = 0;
3147 		spectral->last_fft_timestamp[smode] = 0;
3148 	}
3149 
3150 	/* get current spectral configuration */
3151 	p_sops->get_spectral_config(spectral, &spectral->params[smode], smode);
3152 
3153 	target_if_init_upper_lower_flags(spectral);
3154 
3155 	return 0;
3156 }
3157 
3158 /**
3159  * target_if_is_aspectral_prohibited_by_adfs() - Is Agile Spectral prohibited by
3160  * Agile DFS
3161  * @psoc: Pointer to psoc
3162  * @object: Pointer to pdev
3163  * @arg: Pointer to flag which indicates whether Agile Spectral is prohibited
3164  *
3165  * This API checks whether Agile DFS is running on any of the pdevs. If so, it
3166  * indicates that Agile Spectral scan is prohibited by Agile DFS.
3167  *
3168  * Return: void
3169  */
3170 static void
3171 target_if_is_aspectral_prohibited_by_adfs(struct wlan_objmgr_psoc *psoc,
3172 					  void *object, void *arg)
3173 {
3174 	bool *is_aspectral_prohibited = arg;
3175 	struct wlan_objmgr_pdev *cur_pdev = object;
3176 	bool is_agile_dfs_enabled_cur_pdev = false;
3177 	QDF_STATUS status;
3178 
3179 	qdf_assert_always(is_aspectral_prohibited);
3180 	if (*is_aspectral_prohibited)
3181 		return;
3182 
3183 	qdf_assert_always(psoc);
3184 	qdf_assert_always(cur_pdev);
3185 
3186 	status = ucfg_dfs_get_agile_precac_enable
3187 				(cur_pdev,
3188 				 &is_agile_dfs_enabled_cur_pdev);
3189 	if (QDF_IS_STATUS_ERROR(status)) {
3190 		spectral_err("Get agile precac failed, prohibiting aSpectral");
3191 		*is_aspectral_prohibited = true;
3192 		return;
3193 	}
3194 
3195 	if (is_agile_dfs_enabled_cur_pdev) {
3196 		spectral_err("aDFS is in progress on one of the pdevs");
3197 		*is_aspectral_prohibited = true;
3198 	}
3199 }
3200 
3201 /**
3202  * target_if_get_curr_band() - Get current operating band of pdev
3203  *
3204  * @spectral: pointer to spectral object
3205  *
3206  * API to get current operating band of a given pdev.
3207  *
3208  * Return: if success enum band_info, BAND_UNKNOWN in case of failure
3209  */
3210 static enum band_info
3211 target_if_get_curr_band(struct wlan_objmgr_pdev *pdev)
3212 {
3213 	struct wlan_objmgr_vdev *vdev;
3214 	int16_t chan_freq;
3215 	enum band_info cur_band;
3216 	uint32_t chan_num;
3217 
3218 	if (!pdev) {
3219 		spectral_err("pdev is NULL");
3220 		return BAND_UNKNOWN;
3221 	}
3222 
3223 	vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_SPECTRAL_ID);
3224 	if (!vdev) {
3225 		spectral_debug("vdev is NULL");
3226 		return BAND_UNKNOWN;
3227 	}
3228 	chan_freq = target_if_vdev_get_chan_freq(vdev);
3229 	chan_num = wlan_reg_freq_to_chan(pdev, chan_freq);
3230 	cur_band = wlan_reg_chan_to_band(chan_num);
3231 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3232 
3233 	return cur_band;
3234 }
3235 
3236 /**
3237  * target_if_is_agile_scan_active_in_5g() - Is Agile Spectral scan active on
3238  * any of the 5G pdevs
3239  * @psoc: Pointer to psoc
3240  * @object: Pointer to pdev
3241  * @arg: Pointer to flag which indicates whether Agile Spectral scan is in
3242  *       progress in any 5G pdevs
3243  *
3244  * Return: void
3245  */
3246 static void
3247 target_if_is_agile_scan_active_in_5g(struct wlan_objmgr_psoc *psoc,
3248 				     void *object, void *arg)
3249 {
3250 	enum band_info band;
3251 	bool *is_agile_scan_inprog_5g_pdev = arg;
3252 	struct target_if_spectral *spectral;
3253 	struct wlan_objmgr_pdev *cur_pdev = object;
3254 	struct target_if_spectral_ops *p_sops;
3255 
3256 	if (*is_agile_scan_inprog_5g_pdev)
3257 		return;
3258 
3259 	spectral = get_target_if_spectral_handle_from_pdev(cur_pdev);
3260 	if (!spectral) {
3261 		spectral_err("target if spectral handle is NULL");
3262 		return;
3263 	}
3264 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3265 
3266 	band = target_if_get_curr_band(cur_pdev);
3267 	if (band == BAND_UNKNOWN) {
3268 		spectral_debug("Failed to get current band");
3269 		return;
3270 	}
3271 
3272 	if (band == BAND_5G &&
3273 	    p_sops->is_spectral_active(spectral, SPECTRAL_SCAN_MODE_AGILE))
3274 		*is_agile_scan_inprog_5g_pdev = true;
3275 }
3276 
3277 QDF_STATUS
3278 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev,
3279 			      const enum spectral_scan_mode smode,
3280 			      enum spectral_cp_error_code *err)
3281 {
3282 	struct target_if_spectral_ops *p_sops;
3283 	struct target_if_spectral *spectral;
3284 	struct wlan_objmgr_psoc *psoc;
3285 	enum band_info band;
3286 
3287 	if (!err) {
3288 		spectral_err("Error code argument is null");
3289 		QDF_ASSERT(0);
3290 	}
3291 	*err = SPECTRAL_SCAN_ERR_INVALID;
3292 
3293 	psoc = wlan_pdev_get_psoc(pdev);
3294 	if (!psoc) {
3295 		spectral_err("psoc is null");
3296 		return QDF_STATUS_E_FAILURE;
3297 	}
3298 
3299 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3300 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3301 		spectral_err("Invalid Spectral mode %u", smode);
3302 		return QDF_STATUS_E_FAILURE;
3303 	}
3304 
3305 	if (!pdev) {
3306 		spectral_err("pdev object is NUll");
3307 		return QDF_STATUS_E_FAILURE;
3308 	}
3309 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3310 	if (!spectral) {
3311 		spectral_err("Spectral LMAC object is NUll");
3312 		return QDF_STATUS_E_FAILURE;
3313 	}
3314 
3315 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3316 
3317 	band = target_if_get_curr_band(spectral->pdev_obj);
3318 	if (band == BAND_UNKNOWN) {
3319 		spectral_err("Failed to get current band");
3320 		return QDF_STATUS_E_FAILURE;
3321 	}
3322 	if ((band == BAND_5G) && (smode == SPECTRAL_SCAN_MODE_AGILE)) {
3323 		struct target_psoc_info *tgt_hdl;
3324 		enum wmi_host_hw_mode_config_type mode;
3325 		bool is_agile_scan_inprog_5g_pdev;
3326 
3327 		if (p_sops->is_spectral_active(spectral,
3328 					       SPECTRAL_SCAN_MODE_AGILE)) {
3329 			spectral_err("Agile Scan in progress in current pdev");
3330 			return QDF_STATUS_E_FAILURE;
3331 		}
3332 
3333 		tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
3334 		if (!tgt_hdl) {
3335 			target_if_err("target_psoc_info is null");
3336 			return QDF_STATUS_E_FAILURE;
3337 		}
3338 
3339 		mode = target_psoc_get_preferred_hw_mode(tgt_hdl);
3340 		switch (mode) {
3341 		case WMI_HOST_HW_MODE_SBS_PASSIVE:
3342 		case WMI_HOST_HW_MODE_SBS:
3343 		case WMI_HOST_HW_MODE_DBS_SBS:
3344 		case WMI_HOST_HW_MODE_DBS_OR_SBS:
3345 			is_agile_scan_inprog_5g_pdev = false;
3346 			wlan_objmgr_iterate_obj_list
3347 				(psoc, WLAN_PDEV_OP,
3348 				 target_if_is_agile_scan_active_in_5g,
3349 				 &is_agile_scan_inprog_5g_pdev, 0,
3350 				 WLAN_SPECTRAL_ID);
3351 			break;
3352 		default:
3353 			is_agile_scan_inprog_5g_pdev = false;
3354 			break;
3355 		}
3356 
3357 		if (is_agile_scan_inprog_5g_pdev) {
3358 			spectral_err("Agile Scan in progress in one of the SBS 5G pdev");
3359 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3360 			return QDF_STATUS_E_FAILURE;
3361 		}
3362 	}
3363 
3364 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
3365 		bool is_aspectral_prohibited = false;
3366 		QDF_STATUS status;
3367 
3368 		status = wlan_objmgr_iterate_obj_list
3369 				(psoc, WLAN_PDEV_OP,
3370 				 target_if_is_aspectral_prohibited_by_adfs,
3371 				 &is_aspectral_prohibited, 0,
3372 				 WLAN_SPECTRAL_ID);
3373 		if (QDF_IS_STATUS_ERROR(status)) {
3374 			spectral_err("Failed to iterate over pdevs");
3375 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3376 			return QDF_STATUS_E_FAILURE;
3377 		}
3378 
3379 		if (is_aspectral_prohibited) {
3380 			*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3381 			return QDF_STATUS_E_FAILURE;
3382 		}
3383 	}
3384 
3385 	if (!spectral->params_valid[smode]) {
3386 		target_if_spectral_info_read(spectral,
3387 					     smode,
3388 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
3389 					     &spectral->params[smode],
3390 					     sizeof(spectral->params[smode]));
3391 		spectral->params_valid[smode] = true;
3392 	}
3393 
3394 	qdf_spin_lock(&spectral->spectral_lock);
3395 	if (smode == SPECTRAL_SCAN_MODE_AGILE &&
3396 	    !spectral->params[smode].ss_frequency) {
3397 		*err = SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
3398 		qdf_spin_unlock(&spectral->spectral_lock);
3399 		return QDF_STATUS_E_FAILURE;
3400 	}
3401 
3402 	if (smode == SPECTRAL_SCAN_MODE_AGILE) {
3403 		QDF_STATUS status;
3404 		bool is_overlapping;
3405 
3406 		status = target_if_is_agile_span_overlap_with_operating_span
3407 				(spectral,
3408 				 spectral->params[smode].ss_frequency,
3409 				 &is_overlapping);
3410 		if (QDF_IS_STATUS_ERROR(status)) {
3411 			qdf_spin_unlock(&spectral->spectral_lock);
3412 			return QDF_STATUS_E_FAILURE;
3413 		}
3414 
3415 		if (is_overlapping) {
3416 			*err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
3417 			qdf_spin_unlock(&spectral->spectral_lock);
3418 			return QDF_STATUS_E_FAILURE;
3419 		}
3420 	}
3421 
3422 	target_if_spectral_scan_enable_params(spectral,
3423 					      &spectral->params[smode], smode,
3424 					      err);
3425 	qdf_spin_unlock(&spectral->spectral_lock);
3426 
3427 	return QDF_STATUS_SUCCESS;
3428 }
3429 
3430 QDF_STATUS
3431 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev,
3432 			     const enum spectral_scan_mode smode,
3433 			     enum spectral_cp_error_code *err)
3434 {
3435 	struct target_if_spectral_ops *p_sops;
3436 	struct target_if_spectral *spectral;
3437 
3438 	if (!err) {
3439 		spectral_err("Error code argument is null");
3440 		QDF_ASSERT(0);
3441 	}
3442 	*err = SPECTRAL_SCAN_ERR_INVALID;
3443 
3444 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3445 		*err = SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
3446 		spectral_err("Invalid Spectral mode %u", smode);
3447 		return QDF_STATUS_E_FAILURE;
3448 	}
3449 
3450 	if (!pdev) {
3451 		spectral_err("pdev object is NUll ");
3452 		return QDF_STATUS_E_FAILURE;
3453 	}
3454 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3455 	if (!spectral) {
3456 		spectral_err("Spectral LMAC object is NUll ");
3457 		return QDF_STATUS_E_FAILURE;
3458 	}
3459 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3460 
3461 	qdf_spin_lock(&spectral->spectral_lock);
3462 	p_sops->stop_spectral_scan(spectral, smode);
3463 	if (spectral->classify_scan) {
3464 		/* TODO : Check if this logic is necessary */
3465 		spectral->detects_control_channel = 0;
3466 		spectral->detects_extension_channel = 0;
3467 		spectral->detects_above_dc = 0;
3468 		spectral->detects_below_dc = 0;
3469 		spectral->classify_scan = 0;
3470 	}
3471 
3472 	spectral->send_single_packet = 0;
3473 	spectral->sc_spectral_scan = 0;
3474 
3475 	qdf_spin_unlock(&spectral->spectral_lock);
3476 
3477 	return QDF_STATUS_SUCCESS;
3478 }
3479 
3480 /**
3481  * target_if_is_spectral_active() - Get whether Spectral is active
3482  * @pdev: Pointer to pdev object
3483  * @smode: Spectral scan mode
3484  *
3485  * API to get whether Spectral is active
3486  *
3487  * Return: True if Spectral is active, false if Spectral is not active
3488  */
3489 bool
3490 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev,
3491 			     const enum spectral_scan_mode smode)
3492 {
3493 	struct target_if_spectral *spectral = NULL;
3494 	struct target_if_spectral_ops *p_sops = NULL;
3495 
3496 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3497 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3498 
3499 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3500 		spectral_err("Invalid Spectral mode %u", smode);
3501 		return QDF_STATUS_E_FAILURE;
3502 	}
3503 
3504 	return p_sops->is_spectral_active(spectral, smode);
3505 }
3506 
3507 /**
3508  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
3509  * @pdev: Pointer to pdev object
3510  * @smode: Spectral scan mode
3511  *
3512  * API to get whether Spectral is enabled
3513  *
3514  * Return: True if Spectral is enabled, false if Spectral is not enabled
3515  */
3516 bool
3517 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev,
3518 			      enum spectral_scan_mode smode)
3519 {
3520 	struct target_if_spectral *spectral = NULL;
3521 	struct target_if_spectral_ops *p_sops = NULL;
3522 
3523 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3524 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3525 
3526 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
3527 		spectral_err("Invalid Spectral mode %u", smode);
3528 		return QDF_STATUS_E_FAILURE;
3529 	}
3530 
3531 	return p_sops->is_spectral_enabled(spectral, smode);
3532 }
3533 
3534 /**
3535  * target_if_set_debug_level() - Set debug level for Spectral
3536  * @pdev: Pointer to pdev object
3537  * @debug_level: Debug level
3538  *
3539  * API to set the debug level for Spectral
3540  *
3541  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3542  */
3543 QDF_STATUS
3544 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
3545 {
3546 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
3547 
3548 	return QDF_STATUS_SUCCESS;
3549 }
3550 
3551 /**
3552  * target_if_get_debug_level() - Get debug level for Spectral
3553  * @pdev: Pointer to pdev object
3554  *
3555  * API to get the debug level for Spectral
3556  *
3557  * Return: Current debug level
3558  */
3559 uint32_t
3560 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
3561 {
3562 	return spectral_debug_level;
3563 }
3564 
3565 /**
3566  * target_if_get_spectral_capinfo() - Get Spectral capability information
3567  * @pdev: Pointer to pdev object
3568  * @scaps: Buffer into which data should be copied
3569  *
3570  * API to get the spectral capability information
3571  *
3572  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3573  */
3574 QDF_STATUS
3575 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev,
3576 			       struct spectral_caps *scaps)
3577 {
3578 	struct target_if_spectral *spectral = NULL;
3579 
3580 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3581 	qdf_mem_copy(scaps, &spectral->capability,
3582 		     sizeof(struct spectral_caps));
3583 
3584 	return QDF_STATUS_SUCCESS;
3585 }
3586 
3587 /**
3588  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
3589  * @pdev:  Pointer to pdev object
3590  * @stats: Buffer into which data should be copied
3591  *
3592  * API to get the spectral diagnostic statistics
3593  *
3594  * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure
3595  */
3596 QDF_STATUS
3597 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev,
3598 				 struct spectral_diag_stats *stats)
3599 {
3600 	struct target_if_spectral *spectral = NULL;
3601 
3602 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3603 	qdf_mem_copy(stats, &spectral->diag_stats,
3604 		     sizeof(struct spectral_diag_stats));
3605 
3606 	return QDF_STATUS_SUCCESS;
3607 }
3608 
3609 /**
3610  * target_if_register_wmi_spectral_cmd_ops() - Register wmi_spectral_cmd_ops
3611  * @cmd_ops: Pointer to the structure having wmi_spectral_cmd function pointers
3612  * @pdev: Pointer to pdev object
3613  *
3614  * API for register wmi_spectral_cmd_ops in spectral internal data structure
3615  *
3616  * Return: void
3617  */
3618 void
3619 target_if_register_wmi_spectral_cmd_ops(struct wlan_objmgr_pdev *pdev,
3620 					struct wmi_spectral_cmd_ops *cmd_ops)
3621 {
3622 	struct target_if_spectral *spectral =
3623 		get_target_if_spectral_handle_from_pdev(pdev);
3624 
3625 	if (!spectral) {
3626 		spectral_err("Spectral LMAC object is null");
3627 		return;
3628 	}
3629 	spectral->param_wmi_cmd_ops = *cmd_ops;
3630 }
3631 
3632 /**
3633  * target_if_register_netlink_cb() - Register Netlink callbacks
3634  * @pdev: Pointer to pdev object
3635  * @nl_cb: Netlink callbacks to register
3636  *
3637  * Return: void
3638  */
3639 static void
3640 target_if_register_netlink_cb(
3641 	struct wlan_objmgr_pdev *pdev,
3642 	struct spectral_nl_cb *nl_cb)
3643 {
3644 	struct target_if_spectral *spectral = NULL;
3645 
3646 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3647 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
3648 
3649 	if (spectral->use_nl_bcast)
3650 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
3651 	else
3652 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
3653 }
3654 
3655 /**
3656  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
3657  * Netlink messages to the application layer
3658  * @pdev: Pointer to pdev object
3659  *
3660  * Return: true for broadcast, false for unicast
3661  */
3662 static bool
3663 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
3664 {
3665 	struct target_if_spectral *spectral = NULL;
3666 
3667 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3668 	return spectral->use_nl_bcast;
3669 }
3670 
3671 /**
3672  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
3673  * @pdev: Pointer to pdev object
3674  *
3675  * Return: void
3676  */
3677 static void
3678 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
3679 {
3680 	struct target_if_spectral *spectral = NULL;
3681 
3682 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3683 	if (!spectral) {
3684 		spectral_err("SPECTRAL : Module doesn't exist");
3685 		return;
3686 	}
3687 
3688 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
3689 }
3690 
3691 static int
3692 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
3693 				  void *payload)
3694 {
3695 	struct target_if_spectral *spectral = NULL;
3696 	struct target_if_spectral_ops *p_sops = NULL;
3697 
3698 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3699 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3700 
3701 	return p_sops->process_spectral_report(pdev, payload);
3702 }
3703 
3704 void
3705 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
3706 {
3707 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
3708 	    target_if_pdev_spectral_init;
3709 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
3710 	    target_if_pdev_spectral_deinit;
3711 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
3712 	    target_if_set_spectral_config;
3713 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
3714 	    target_if_get_spectral_config;
3715 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
3716 	    target_if_start_spectral_scan;
3717 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
3718 	    target_if_stop_spectral_scan;
3719 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
3720 	    target_if_is_spectral_active;
3721 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
3722 	    target_if_is_spectral_enabled;
3723 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
3724 	    target_if_set_debug_level;
3725 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
3726 	    target_if_get_debug_level;
3727 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
3728 	    target_if_get_spectral_capinfo;
3729 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
3730 	    target_if_get_spectral_diagstats;
3731 	tx_ops->sptrl_tx_ops.sptrlto_register_wmi_spectral_cmd_ops =
3732 	    target_if_register_wmi_spectral_cmd_ops;
3733 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
3734 	    target_if_register_netlink_cb;
3735 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
3736 	    target_if_use_nl_bcast;
3737 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
3738 	    target_if_deregister_netlink_cb;
3739 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
3740 		target_if_process_spectral_report;
3741 }
3742 qdf_export_symbol(target_if_sptrl_register_tx_ops);
3743 
3744 void
3745 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
3746 				       uint16_t cw_int, uint32_t dcs_enabled)
3747 {
3748 	struct spectral_samp_msg *msg = NULL;
3749 	struct target_if_spectral_ops *p_sops = NULL;
3750 	struct target_if_spectral *spectral = NULL;
3751 
3752 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
3753 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_sbuff(
3754 			spectral->pdev_obj,
3755 			SPECTRAL_MSG_INTERFERENCE_NOTIFICATION,
3756 			SPECTRAL_MSG_BUF_NEW);
3757 
3758 	if (msg) {
3759 		msg->int_type = cw_int ?
3760 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
3761 		msg->dcs_enabled = dcs_enabled;
3762 		msg->signature = SPECTRAL_SIGNATURE;
3763 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3764 		p_sops->get_mac_address(spectral, msg->macaddr);
3765 		if (spectral->send_phy_data
3766 				(pdev,
3767 				 SPECTRAL_MSG_INTERFERENCE_NOTIFICATION) == 0)
3768 			spectral->spectral_sent_msg++;
3769 	}
3770 }
3771 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
3772