xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision 8ddef7dd9a290d4a9b1efd5d3efacf51d78a1a0d)
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 <reg_services_public_struct.h>
31 #include <target_if_spectral_sim.h>
32 #include <target_if.h>
33 #include <qdf_module.h>
34 
35 /**
36  * @spectral_ops - Spectral function table, holds the Spectral functions that
37  * depend on whether the architecture is Direct Attach or Offload. This is used
38  * to populate the actual Spectral function table present in the Spectral
39  * module.
40  */
41 struct target_if_spectral_ops spectral_ops;
42 int spectral_debug_level = DEBUG_SPECTRAL;
43 
44 static void target_if_spectral_get_firstvdev_pdev(struct wlan_objmgr_pdev *pdev,
45 						  void *obj, void *arg)
46 {
47 	struct wlan_objmgr_vdev *vdev = obj;
48 	struct wlan_objmgr_vdev **first_vdev = arg;
49 
50 	if (!(*first_vdev))
51 		*first_vdev = vdev;
52 }
53 
54 struct wlan_objmgr_vdev *
55 target_if_spectral_get_vdev(struct target_if_spectral *spectral)
56 {
57 	struct wlan_objmgr_pdev *pdev = NULL;
58 	struct wlan_objmgr_vdev *first_vdev = NULL;
59 
60 	qdf_assert_always(spectral);
61 	pdev = spectral->pdev_obj;
62 	qdf_assert_always(pdev);
63 
64 	if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_SPECTRAL_ID) !=
65 	    QDF_STATUS_SUCCESS) {
66 		spectral_err("Unable to get pdev reference.");
67 		return NULL;
68 	}
69 
70 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
71 					  target_if_spectral_get_firstvdev_pdev,
72 					  &first_vdev, 0, WLAN_SPECTRAL_ID);
73 
74 	wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
75 
76 	if (!first_vdev)
77 		return NULL;
78 
79 	if (wlan_objmgr_vdev_try_get_ref(first_vdev, WLAN_SPECTRAL_ID) !=
80 			QDF_STATUS_SUCCESS)
81 		first_vdev = NULL;
82 
83 
84 	return first_vdev;
85 }
86 
87 /**
88  * target_if_send_vdev_spectral_configure_cmd() - Send WMI command to configure
89  * spectral parameters
90  * @spectral: Pointer to Spectral target_if internal private data
91  * @param: Pointer to spectral_config giving the Spectral configuration
92  *
93  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
94  */
95 static int
96 target_if_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral,
97 					   struct spectral_config *param)
98 {
99 	struct vdev_spectral_configure_params sparam;
100 	struct wlan_objmgr_pdev *pdev = NULL;
101 	struct wlan_objmgr_vdev *vdev = NULL;
102 
103 	qdf_assert_always(spectral && param);
104 
105 	pdev = spectral->pdev_obj;
106 
107 	qdf_assert_always(pdev);
108 
109 	vdev = target_if_spectral_get_vdev(spectral);
110 	if (!vdev)
111 		return QDF_STATUS_E_NOENT;
112 
113 	qdf_mem_zero(&sparam, sizeof(sparam));
114 
115 	sparam.vdev_id = wlan_vdev_get_id(vdev);
116 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
117 
118 	sparam.count = param->ss_count;
119 	sparam.period = param->ss_period;
120 	sparam.spectral_pri = param->ss_spectral_pri;
121 	sparam.fft_size = param->ss_fft_size;
122 	sparam.gc_enable = param->ss_gc_ena;
123 	sparam.restart_enable = param->ss_restart_ena;
124 	sparam.noise_floor_ref = param->ss_noise_floor_ref;
125 	sparam.init_delay = param->ss_init_delay;
126 	sparam.nb_tone_thr = param->ss_nb_tone_thr;
127 	sparam.str_bin_thr = param->ss_str_bin_thr;
128 	sparam.wb_rpt_mode = param->ss_wb_rpt_mode;
129 	sparam.rssi_rpt_mode = param->ss_rssi_rpt_mode;
130 	sparam.rssi_thr = param->ss_rssi_thr;
131 	sparam.pwr_format = param->ss_pwr_format;
132 	sparam.rpt_mode = param->ss_rpt_mode;
133 	sparam.bin_scale = param->ss_bin_scale;
134 	sparam.dbm_adj = param->ss_dbm_adj;
135 	sparam.chn_mask = param->ss_chn_mask;
136 
137 	return spectral->param_wmi_cmd_ops.wmi_spectral_configure_cmd_send(
138 				GET_WMI_HDL_FROM_PDEV(pdev), &sparam);
139 }
140 
141 /**
142  * target_if_send_vdev_spectral_enable_cmd() - Send WMI command to
143  * enable/disable Spectral
144  * @spectral: Pointer to Spectral target_if internal private data
145  * @is_spectral_active_valid: Flag to indicate if spectral activate (trigger) is
146  * valid
147  * @is_spectral_active: Value of spectral activate
148  * @is_spectral_enabled_valid: Flag to indicate if spectral enable is valid
149  * @is_spectral_enabled: Value of spectral enable
150  *
151  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
152  */
153 static int
154 target_if_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral,
155 					uint8_t is_spectral_active_valid,
156 					uint8_t is_spectral_active,
157 					uint8_t is_spectral_enabled_valid,
158 					uint8_t is_spectral_enabled)
159 {
160 	struct vdev_spectral_enable_params param;
161 	struct wlan_objmgr_pdev *pdev = NULL;
162 	struct wlan_objmgr_vdev *vdev = NULL;
163 
164 	qdf_assert_always(spectral);
165 
166 	pdev = spectral->pdev_obj;
167 
168 	qdf_assert_always(pdev);
169 
170 	vdev = target_if_spectral_get_vdev(spectral);
171 	if (!vdev)
172 		return QDF_STATUS_E_NOENT;
173 
174 	qdf_mem_zero(&param, sizeof(param));
175 
176 	param.vdev_id = wlan_vdev_get_id(vdev);
177 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
178 
179 	param.active_valid = is_spectral_active_valid;
180 	param.enabled_valid = is_spectral_enabled_valid;
181 	param.active = is_spectral_active;
182 	param.enabled = is_spectral_enabled;
183 
184 	return spectral->param_wmi_cmd_ops.wmi_spectral_enable_cmd_send(
185 				GET_WMI_HDL_FROM_PDEV(pdev), &param);
186 }
187 
188 /**
189  * target_if_spectral_info_init_defaults() - Helper function to load defaults
190  * for Spectral information (parameters and state) into cache.
191  * @spectral: Pointer to Spectral target_if internal private data
192  *
193  * It is assumed that the caller has obtained the requisite lock if applicable.
194  * Note that this is currently treated as a temporary function.  Ideally, we
195  * would like to get defaults from the firmware.
196  *
197  * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
198  */
199 static int
200 target_if_spectral_info_init_defaults(struct target_if_spectral *spectral)
201 {
202 	struct target_if_spectral_param_state_info *info =
203 		&spectral->param_info;
204 	struct wlan_objmgr_vdev *vdev = NULL;
205 
206 	/* State */
207 	info->osps_cache.osc_spectral_active = SPECTRAL_SCAN_ACTIVE_DEFAULT;
208 
209 	info->osps_cache.osc_spectral_enabled = SPECTRAL_SCAN_ENABLE_DEFAULT;
210 
211 	/* Parameters */
212 	info->osps_cache.osc_params.ss_count = SPECTRAL_SCAN_COUNT_DEFAULT;
213 
214 	if (spectral->spectral_gen == SPECTRAL_GEN3)
215 		info->osps_cache.osc_params.ss_period =
216 			SPECTRAL_SCAN_PERIOD_GEN_III_DEFAULT;
217 	else
218 		info->osps_cache.osc_params.ss_period =
219 			SPECTRAL_SCAN_PERIOD_GEN_II_DEFAULT;
220 
221 	info->osps_cache.osc_params.ss_spectral_pri =
222 	    SPECTRAL_SCAN_PRIORITY_DEFAULT;
223 
224 	info->osps_cache.osc_params.ss_fft_size =
225 	    SPECTRAL_SCAN_FFT_SIZE_DEFAULT;
226 
227 	info->osps_cache.osc_params.ss_gc_ena = SPECTRAL_SCAN_GC_ENA_DEFAULT;
228 
229 	info->osps_cache.osc_params.ss_restart_ena =
230 	    SPECTRAL_SCAN_RESTART_ENA_DEFAULT;
231 
232 	info->osps_cache.osc_params.ss_noise_floor_ref =
233 	    SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT;
234 
235 	info->osps_cache.osc_params.ss_init_delay =
236 	    SPECTRAL_SCAN_INIT_DELAY_DEFAULT;
237 
238 	info->osps_cache.osc_params.ss_nb_tone_thr =
239 	    SPECTRAL_SCAN_NB_TONE_THR_DEFAULT;
240 
241 	info->osps_cache.osc_params.ss_str_bin_thr =
242 	    SPECTRAL_SCAN_STR_BIN_THR_DEFAULT;
243 
244 	info->osps_cache.osc_params.ss_wb_rpt_mode =
245 	    SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT;
246 
247 	info->osps_cache.osc_params.ss_rssi_rpt_mode =
248 	    SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT;
249 
250 	info->osps_cache.osc_params.ss_rssi_thr =
251 	    SPECTRAL_SCAN_RSSI_THR_DEFAULT;
252 
253 	info->osps_cache.osc_params.ss_pwr_format =
254 	    SPECTRAL_SCAN_PWR_FORMAT_DEFAULT;
255 
256 	info->osps_cache.osc_params.ss_rpt_mode =
257 	    SPECTRAL_SCAN_RPT_MODE_DEFAULT;
258 
259 	info->osps_cache.osc_params.ss_bin_scale =
260 	    SPECTRAL_SCAN_BIN_SCALE_DEFAULT;
261 
262 	info->osps_cache.osc_params.ss_dbm_adj = SPECTRAL_SCAN_DBM_ADJ_DEFAULT;
263 
264 	vdev = target_if_spectral_get_vdev(spectral);
265 	if (!vdev)
266 		return QDF_STATUS_E_NOENT;
267 
268 	info->osps_cache.osc_params.ss_chn_mask =
269 	    wlan_vdev_mlme_get_rxchainmask(vdev);
270 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
271 
272 	info->osps_cache.osc_params.ss_short_report =
273 		SPECTRAL_SCAN_SHORT_REPORT_DEFAULT;
274 
275 	info->osps_cache.osc_params.ss_fft_period =
276 		SPECTRAL_SCAN_FFT_PERIOD_DEFAULT;
277 
278 	/* The cache is now valid */
279 	info->osps_cache.osc_is_valid = 1;
280 
281 	return QDF_STATUS_SUCCESS;
282 }
283 
284 /**
285  * target_if_log_read_spectral_active() - Helper function to log whether
286  * spectral is active after reading cache
287  * @function_name: Function name
288  * @output: whether spectral is active or not
289  *
290  * Helper function to log whether spectral is active after reading cache
291  *
292  * Return: none
293  */
294 static void
295 target_if_log_read_spectral_active(
296 	const char *function_name,
297 	unsigned char output)
298 {
299 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE. Returning val=%u",
300 		       function_name, output);
301 }
302 
303 /**
304  * target_if_log_read_spectral_enabled() - Helper function to log whether
305  * spectral is enabled after reading cache
306  * @function_name: Function name
307  * @output: whether spectral is enabled or not
308  *
309  * Helper function to log whether spectral is enabled after reading cache
310  *
311  * Return: none
312  */
313 static void
314 target_if_log_read_spectral_enabled(
315 	const char *function_name,
316 	unsigned char output)
317 {
318 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED. Returning val=%u",
319 		       function_name, output);
320 }
321 
322 /**
323  * target_if_log_read_spectral_enabled() - Helper function to log spectral
324  * parameters after reading cache
325  * @function_name: Function name
326  * @pparam: Spectral parameters
327  *
328  * Helper function to log spectral parameters after reading cache
329  *
330  * Return: none
331  */
332 static void
333 target_if_log_read_spectral_params(
334 	const char *function_name,
335 	struct spectral_config *pparam)
336 {
337 	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\n",
338 		       function_name,
339 		       pparam->ss_count,
340 		       pparam->ss_period,
341 		       pparam->ss_spectral_pri,
342 		       pparam->ss_fft_size,
343 		       pparam->ss_gc_ena,
344 		       pparam->ss_restart_ena,
345 		       (int8_t)pparam->ss_noise_floor_ref,
346 		       pparam->ss_init_delay,
347 		       pparam->ss_nb_tone_thr,
348 		       pparam->ss_str_bin_thr,
349 		       pparam->ss_wb_rpt_mode,
350 		       pparam->ss_rssi_rpt_mode,
351 		       (int8_t)pparam->ss_rssi_thr,
352 		       pparam->ss_pwr_format,
353 		       pparam->ss_rpt_mode,
354 		       pparam->ss_bin_scale,
355 		       pparam->ss_dbm_adj,
356 		       pparam->ss_chn_mask);
357 }
358 
359 /**
360  * target_if_log_read_spectral_active_catch_validate() - Helper function to
361  * log whether spectral is active after intializing the cache
362  * @function_name: Function name
363  * @output: whether spectral is active or not
364  *
365  * Helper function to log whether spectral is active after intializing cache
366  *
367  * Return: none
368  */
369 static void
370 target_if_log_read_spectral_active_catch_validate(
371 	const char *function_name,
372 	unsigned char output)
373 {
374 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE on initial cache validation\nReturning val=%u",
375 		       function_name, output);
376 }
377 
378 /**
379  * target_if_log_read_spectral_enabled_catch_validate() - Helper function to
380  * log whether spectral is enabled after intializing the cache
381  * @function_name: Function name
382  * @output: whether spectral is enabled or not
383  *
384  * Helper function to log whether spectral is enabled after intializing cache
385  *
386  * Return: none
387  */
388 static void
389 target_if_log_read_spectral_enabled_catch_validate(
390 	const char *function_name,
391 	unsigned char output)
392 {
393 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED on initial cache validation\nReturning val=%u\n",
394 		       function_name, output);
395 }
396 
397 /**
398  * target_if_log_read_spectral_params_catch_validate() - Helper function to
399  * log spectral parameters after intializing the cache
400  * @function_name: Function name
401  * @pparam: Spectral parameters
402  *
403  * Helper function to log spectral parameters after intializing the cache
404  *
405  * Return: none
406  */
407 static void
408 target_if_log_read_spectral_params_catch_validate(
409 	const char *function_name,
410 	struct spectral_config *pparam)
411 {
412 	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",
413 		       function_name,
414 		       pparam->ss_count,
415 		       pparam->ss_period,
416 		       pparam->ss_spectral_pri,
417 		       pparam->ss_fft_size,
418 		       pparam->ss_gc_ena,
419 		       pparam->ss_restart_ena,
420 		       (int8_t)pparam->ss_noise_floor_ref,
421 		       pparam->ss_init_delay,
422 		       pparam->ss_nb_tone_thr,
423 		       pparam->ss_str_bin_thr,
424 		       pparam->ss_wb_rpt_mode,
425 		       pparam->ss_rssi_rpt_mode,
426 		       (int8_t)pparam->ss_rssi_thr,
427 		       pparam->ss_pwr_format,
428 		       pparam->ss_rpt_mode,
429 		       pparam->ss_bin_scale,
430 		       pparam->ss_dbm_adj, pparam->ss_chn_mask);
431 }
432 
433 /**
434  * target_if_spectral_info_read() - Read spectral information from the cache.
435  * @spectral: Pointer to Spectral target_if internal private data
436  * @specifier: target_if_spectral_info enumeration specifying which
437  * information is required
438  * @output: Void output pointer into which the information will be read
439  * @output_len: size of object pointed to by output pointer
440  *
441  * Read spectral parameters or the desired state information from the cache.
442  *
443  * Return: 0 on success, negative error code on failure
444  */
445 static int
446 target_if_spectral_info_read(
447 	struct target_if_spectral *spectral,
448 	enum target_if_spectral_info specifier,
449 	void *output, int output_len)
450 {
451 	/*
452 	 * Note: This function is designed to be able to accommodate
453 	 * WMI reads for defaults, non-cacheable information, etc
454 	 * if required.
455 	 */
456 	struct target_if_spectral_param_state_info *info =
457 		&spectral->param_info;
458 	int is_cacheable = 0;
459 	int init_def_retval = 0;
460 
461 	if (!output)
462 		return -EINVAL;
463 
464 	switch (specifier) {
465 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
466 		if (output_len != sizeof(info->osps_cache.osc_spectral_active))
467 			return -EINVAL;
468 		is_cacheable = 1;
469 		break;
470 
471 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
472 		if (output_len != sizeof(info->osps_cache.osc_spectral_enabled))
473 			return -EINVAL;
474 		is_cacheable = 1;
475 		break;
476 
477 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
478 		if (output_len != sizeof(info->osps_cache.osc_params))
479 			return -EINVAL;
480 		is_cacheable = 1;
481 		break;
482 
483 	default:
484 		spectral_err("Unknown target_if_spectral_info specifier");
485 		return -EINVAL;
486 	}
487 
488 	qdf_spin_lock(&info->osps_lock);
489 
490 	if (is_cacheable) {
491 		if (info->osps_cache.osc_is_valid) {
492 			switch (specifier) {
493 			case TARGET_IF_SPECTRAL_INFO_ACTIVE:
494 				qdf_mem_copy(
495 				  output,
496 				  &info->osps_cache.osc_spectral_active,
497 				  sizeof(info->osps_cache.osc_spectral_active));
498 
499 				target_if_log_read_spectral_active(
500 					__func__,
501 					*((unsigned char *)output));
502 				break;
503 
504 			case TARGET_IF_SPECTRAL_INFO_ENABLED:
505 				qdf_mem_copy(
506 				  output,
507 				  &info->osps_cache.osc_spectral_enabled,
508 				  sizeof(
509 					info->osps_cache.osc_spectral_enabled));
510 
511 				target_if_log_read_spectral_enabled(
512 					__func__,
513 					*((unsigned char *)output));
514 				break;
515 
516 			case TARGET_IF_SPECTRAL_INFO_PARAMS:
517 				qdf_mem_copy(
518 				  output,
519 				  &info->osps_cache.osc_params,
520 				  sizeof(info->osps_cache.osc_params));
521 
522 				target_if_log_read_spectral_params(
523 					__func__,
524 					(struct spectral_config *)output);
525 				break;
526 
527 			default:
528 				/* We can't reach this point */
529 				break;
530 			}
531 			qdf_spin_unlock(&info->osps_lock);
532 			return 0;
533 		}
534 	}
535 
536 	/* Cache is invalid */
537 
538 	/*
539 	 * If WMI Reads are implemented to fetch defaults/non-cacheable info,
540 	 * then the below implementation will change
541 	 */
542 	init_def_retval = target_if_spectral_info_init_defaults(spectral);
543 	if (init_def_retval != QDF_STATUS_SUCCESS) {
544 		qdf_spin_unlock(&info->osps_lock);
545 		if (init_def_retval == QDF_STATUS_E_NOENT)
546 			return -ENOENT;
547 		else
548 			return -EINVAL;
549 	}
550 	/* target_if_spectral_info_init_defaults() has set cache to valid */
551 
552 	switch (specifier) {
553 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
554 		qdf_mem_copy(output,
555 			     &info->osps_cache.osc_spectral_active,
556 			     sizeof(info->osps_cache.osc_spectral_active));
557 
558 		target_if_log_read_spectral_active_catch_validate(
559 			__func__,
560 			*((unsigned char *)output));
561 		break;
562 
563 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
564 		qdf_mem_copy(output,
565 			     &info->osps_cache.osc_spectral_enabled,
566 			     sizeof(info->osps_cache.osc_spectral_enabled));
567 
568 		target_if_log_read_spectral_enabled_catch_validate(
569 			__func__,
570 			*((unsigned char *)output));
571 		break;
572 
573 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
574 		qdf_mem_copy(output,
575 			     &info->osps_cache.osc_params,
576 			     sizeof(info->osps_cache.osc_params));
577 
578 		target_if_log_read_spectral_params_catch_validate(
579 			__func__,
580 			(struct spectral_config *)output);
581 
582 		break;
583 
584 	default:
585 		/* We can't reach this point */
586 		break;
587 	}
588 
589 	qdf_spin_unlock(&info->osps_lock);
590 
591 	return 0;
592 }
593 
594 /**
595  * target_if_log_write_spectral_active() - Helper function to log inputs and
596  * return value of call to configure the Spectral 'active' configuration,
597  * TARGET_IF_SPECTRAL_INFO_ACTIVE into firmware
598  * @function_name: Function name in which this is called
599  * @pval: whether spectral is active or not
600  * @ret: return value of the firmware write function
601  *
602  * Return: none
603  */
604 static void
605 target_if_log_write_spectral_active(
606 	const char *function_name,
607 	uint8_t pval,
608 	int ret)
609 {
610 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ACTIVE with val=%u status=%d",
611 		       function_name, pval, ret);
612 }
613 
614 /**
615  * target_if_log_write_spectral_enabled() - Helper function to log inputs and
616  * return value of call to configure the Spectral 'enabled' configuration,
617  * TARGET_IF_SPECTRAL_INFO_ENABLED into firmware
618  * @function_name: Function name in which this is called
619  * @pval: whether spectral is enabled or not
620  * @ret: return value of the firmware write function
621  *
622  * Return: none
623  */
624 static void
625 target_if_log_write_spectral_enabled(
626 	const char *function_name,
627 	uint8_t pval,
628 	int ret)
629 {
630 	spectral_debug("%s: TARGET_IF_SPECTRAL_INFO_ENABLED with val=%u status=%d",
631 		       function_name, pval, ret);
632 }
633 
634 /**
635  * target_if_log_write_spectral_params() - Helper function to log inputs and
636  * return value of call to configure Spectral parameters,
637  * TARGET_IF_SPECTRAL_INFO_PARAMS into firmware
638  * @param: Spectral parameters
639  * @function_name: Function name in which this is called
640  * @ret: return value of the firmware write function
641  *
642  * Return: none
643  */
644 static void
645 target_if_log_write_spectral_params(
646 	struct spectral_config *param,
647 	const char *function_name,
648 	int ret)
649 {
650 	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\nstatus = %d",
651 		       function_name,
652 		       param->ss_count,
653 		       param->ss_period,
654 		       param->ss_spectral_pri,
655 		       param->ss_fft_size,
656 		       param->ss_gc_ena,
657 		       param->ss_restart_ena,
658 		       (int8_t)param->ss_noise_floor_ref,
659 		       param->ss_init_delay,
660 		       param->ss_nb_tone_thr,
661 		       param->ss_str_bin_thr,
662 		       param->ss_wb_rpt_mode,
663 		       param->ss_rssi_rpt_mode,
664 		       (int8_t)param->ss_rssi_thr,
665 		       param->ss_pwr_format,
666 		       param->ss_rpt_mode,
667 		       param->ss_bin_scale,
668 		       param->ss_dbm_adj, param->ss_chn_mask, ret);
669 }
670 
671 /**
672  * target_if_spectral_info_write() - Write Spectral information to the
673  * firmware, and update cache
674  * @spectral: Pointer to Spectral target_if internal private data
675  * @specifier: target_if_spectral_info enumeration specifying which
676  * information is involved
677  * @input: void input pointer containing the information to be written
678  * @input_len: size of object pointed to by input pointer
679  *
680  * Write Spectral parameters or the desired state information to
681  * the firmware, and update cache
682  *
683  * Return: 0 on success, negative error code on failure
684  */
685 static int
686 target_if_spectral_info_write(
687 	struct target_if_spectral *spectral,
688 	enum target_if_spectral_info specifier,
689 	void *input, int input_len)
690 {
691 	struct target_if_spectral_param_state_info *info =
692 		&spectral->param_info;
693 	int ret;
694 	uint8_t *pval = NULL;
695 	struct spectral_config *param = NULL;
696 
697 	if (!input)
698 		return -EINVAL;
699 
700 	switch (specifier) {
701 	case TARGET_IF_SPECTRAL_INFO_ACTIVE:
702 		if (input_len != sizeof(info->osps_cache.osc_spectral_active))
703 			return -EINVAL;
704 
705 		pval = (uint8_t *)input;
706 
707 		qdf_spin_lock(&info->osps_lock);
708 		ret = target_if_send_vdev_spectral_enable_cmd(spectral,
709 							      1, *pval, 0, 0);
710 
711 		target_if_log_write_spectral_active(
712 			__func__,
713 			*pval,
714 			ret);
715 
716 		if (ret < 0) {
717 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
718 				     ret);
719 			qdf_spin_unlock(&info->osps_lock);
720 			return ret;
721 		}
722 
723 		info->osps_cache.osc_spectral_active = *pval;
724 
725 		/* The cache is now valid */
726 		info->osps_cache.osc_is_valid = 1;
727 
728 		qdf_spin_unlock(&info->osps_lock);
729 		break;
730 
731 	case TARGET_IF_SPECTRAL_INFO_ENABLED:
732 		if (input_len != sizeof(info->osps_cache.osc_spectral_enabled))
733 			return -EINVAL;
734 
735 		pval = (uint8_t *)input;
736 
737 		qdf_spin_lock(&info->osps_lock);
738 		ret = target_if_send_vdev_spectral_enable_cmd(spectral,
739 							      0, 0, 1, *pval);
740 
741 		target_if_log_write_spectral_enabled(
742 			__func__,
743 			*pval,
744 			ret);
745 
746 		if (ret < 0) {
747 			spectral_err("target_if_send_vdev_spectral_enable_cmd failed with error=%d",
748 				     ret);
749 			qdf_spin_unlock(&info->osps_lock);
750 			return ret;
751 		}
752 
753 		info->osps_cache.osc_spectral_enabled = *pval;
754 
755 		/* The cache is now valid */
756 		info->osps_cache.osc_is_valid = 1;
757 
758 		qdf_spin_unlock(&info->osps_lock);
759 		break;
760 
761 	case TARGET_IF_SPECTRAL_INFO_PARAMS:
762 		if (input_len != sizeof(info->osps_cache.osc_params))
763 			return -EINVAL;
764 
765 		param = (struct spectral_config *)input;
766 
767 		qdf_spin_lock(&info->osps_lock);
768 		ret = target_if_send_vdev_spectral_configure_cmd(spectral,
769 								 param);
770 
771 		target_if_log_write_spectral_params(
772 			param,
773 			__func__,
774 			ret);
775 
776 		if (ret < 0) {
777 			spectral_err("target_if_send_vdev_spectral_configure_cmd failed with error=%d",
778 				     ret);
779 			qdf_spin_unlock(&info->osps_lock);
780 			return ret;
781 		}
782 
783 		qdf_mem_copy(&info->osps_cache.osc_params,
784 			     param, sizeof(info->osps_cache.osc_params));
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 	default:
793 		spectral_err("Unknown target_if_spectral_info specifier");
794 		return -EINVAL;
795 	}
796 
797 	return 0;
798 }
799 
800 /**
801  * target_if_spectral_get_tsf64() - Function to get the TSF value
802  * @arg: Pointer to handle for Spectral target_if internal private data
803  *
804  * Get the last TSF received in WMI buffer
805  *
806  * Return: TSF value
807  */
808 static uint64_t
809 target_if_spectral_get_tsf64(void *arg)
810 {
811 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
812 
813 	return spectral->tsf64;
814 }
815 
816 /**
817  * target_if_spectral_get_capability() - Function to get whether a
818  * given Spectral hardware capability is available
819  * @arg: Pointer to handle for Spectral target_if internal private data
820  * @type: Spectral hardware capability type
821  *
822  * Get whether a given Spectral hardware capability is available
823  *
824  * Return: True if the capability is available, false if the capability is not
825  * available
826  */
827 uint32_t
828 target_if_spectral_get_capability(void *arg, enum spectral_capability_type type)
829 {
830 	int status = STATUS_FAIL;
831 
832 	switch (type) {
833 	case SPECTRAL_CAP_PHYDIAG:
834 	case SPECTRAL_CAP_RADAR:
835 	case SPECTRAL_CAP_SPECTRAL_SCAN:
836 	case SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN:
837 		status = STATUS_PASS;
838 		break;
839 	default:
840 		status = STATUS_FAIL;
841 	}
842 	return status;
843 }
844 
845 /**
846  * target_if_spectral_set_rxfilter() - Set the RX Filter before Spectral start
847  * @arg: Pointer to handle for Spectral target_if internal private data
848  * @rxfilter: Rx filter to be used
849  *
850  * Note: This is only a placeholder function. It is not currently required since
851  * FW should be taking care of setting the required filters.
852  *
853  * Return: 0
854  */
855 uint32_t
856 target_if_spectral_set_rxfilter(void *arg, int rxfilter)
857 {
858 	/*
859 	 * Will not be required since enabling of spectral in firmware
860 	 * will take care of this
861 	 */
862 	return 0;
863 }
864 
865 /**
866  * target_if_spectral_get_rxfilter() - Get the current RX Filter settings
867  * @arg: Pointer to handle for Spectral target_if internal private data
868  *
869  * Note: This is only a placeholder function. It is not currently required since
870  * FW should be taking care of setting the required filters.
871  *
872  * Return: 0
873  */
874 uint32_t
875 target_if_spectral_get_rxfilter(void *arg)
876 {
877 	/*
878 	 * Will not be required since enabling of spectral in firmware
879 	 * will take care of this
880 	 */
881 	return 0;
882 }
883 
884 /**
885  * target_if_sops_is_spectral_active() - Get whether Spectral is active
886  * @arg: Pointer to handle for Spectral target_if internal private data
887  *
888  * Function to check whether Spectral is active
889  *
890  * Return: True if Spectral is active, false if Spectral is not active
891  */
892 uint32_t
893 target_if_sops_is_spectral_active(void *arg)
894 {
895 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
896 	uint8_t val = 0;
897 	int ret;
898 
899 	ret = target_if_spectral_info_read(
900 		spectral,
901 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
902 		&val, sizeof(val));
903 
904 	if (ret != 0) {
905 		/*
906 		 * Could not determine if Spectral is active.
907 		 * Return false as a safe value.
908 		 * XXX: Consider changing the function prototype
909 		 * to be able to indicate failure to fetch value.
910 		 */
911 		return 0;
912 	}
913 
914 	return val;
915 }
916 
917 /**
918  * target_if_sops_is_spectral_enabled() - Get whether Spectral is enabled
919  * @arg: Pointer to handle for Spectral target_if internal private data
920  *
921  * Function to check whether Spectral is enabled
922  *
923  * Return: True if Spectral is enabled, false if Spectral is not enabled
924  */
925 uint32_t
926 target_if_sops_is_spectral_enabled(void *arg)
927 {
928 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
929 	uint8_t val = 0;
930 	int ret;
931 
932 	ret = target_if_spectral_info_read(
933 		spectral,
934 		TARGET_IF_SPECTRAL_INFO_ENABLED,
935 		&val, sizeof(val));
936 
937 	if (ret != 0) {
938 		/*
939 		 * Could not determine if Spectral is enabled.
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_start_spectral_scan() - Start Spectral scan
952  * @arg: Pointer to handle for Spectral target_if internal private data
953  *
954  * Function to start spectral scan
955  *
956  * Return: 0 on success else failure
957  */
958 uint32_t
959 target_if_sops_start_spectral_scan(void *arg)
960 {
961 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
962 	uint8_t val = 1;
963 	uint8_t enabled = 0;
964 	int ret;
965 
966 	ret = target_if_spectral_info_read(
967 		spectral,
968 		TARGET_IF_SPECTRAL_INFO_ENABLED,
969 		&enabled, sizeof(enabled));
970 
971 	if (ret != 0) {
972 		/*
973 		 * Could not determine if Spectral is enabled. Assume we need
974 		 * to enable it
975 		 */
976 		enabled = 0;
977 	}
978 
979 	if (!enabled) {
980 		ret = target_if_spectral_info_write(
981 			spectral,
982 			TARGET_IF_SPECTRAL_INFO_ENABLED,
983 			&val, sizeof(val));
984 
985 		if (ret != 0)
986 			return ret;
987 	}
988 
989 	ret = target_if_spectral_info_write(
990 		spectral,
991 		TARGET_IF_SPECTRAL_INFO_ACTIVE,
992 		&val, sizeof(val));
993 
994 	if (ret != 0)
995 		return ret;
996 
997 	return 0;
998 }
999 
1000 /**
1001  * target_if_sops_stop_spectral_scan() - Stop Spectral scan
1002  * @arg: Pointer to handle for Spectral target_if internal private data
1003  *
1004  * Function to stop spectral scan
1005  *
1006  * Return: 0 on success else failure
1007  */
1008 uint32_t
1009 target_if_sops_stop_spectral_scan(void *arg)
1010 {
1011 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1012 	uint8_t val = 0;
1013 	int tempret, ret = 0;
1014 
1015 	tempret = target_if_spectral_info_write(
1016 			spectral,
1017 			TARGET_IF_SPECTRAL_INFO_ACTIVE,
1018 			&val, sizeof(val));
1019 
1020 	if (tempret != 0)
1021 		ret = tempret;
1022 
1023 	tempret = target_if_spectral_info_write(
1024 			spectral,
1025 			TARGET_IF_SPECTRAL_INFO_ENABLED,
1026 			&val, sizeof(val));
1027 
1028 	if (tempret != 0)
1029 		ret = tempret;
1030 
1031 	return ret;
1032 }
1033 
1034 /**
1035  * target_if_spectral_get_extension_channel() - Get the Extension channel
1036  * @arg: Pointer to handle for Spectral target_if internal private data
1037  *
1038  * Function to get the current Extension channel (in MHz)
1039  *
1040  * Return: Current Extension channel (in MHz) on success, 0 on failure or if
1041  * extension channel is not present.
1042  */
1043 uint32_t
1044 target_if_spectral_get_extension_channel(void *arg)
1045 {
1046 	/*
1047 	 * XXX: Once we expand to use cases where Spectral could be activated
1048 	 * without a channel being set to VDEV, we need to consider returning a
1049 	 * negative value in case of failure and having all callers handle this.
1050 	 */
1051 
1052 	struct target_if_spectral *spectral = NULL;
1053 	struct wlan_objmgr_vdev *vdev = NULL;
1054 	uint16_t sec20chan_freq = 0;
1055 
1056 	qdf_assert_always(arg);
1057 	spectral = (struct target_if_spectral *)arg;
1058 
1059 	vdev = target_if_spectral_get_vdev(spectral);
1060 	if (!vdev)
1061 		return 0;
1062 
1063 	if (target_if_vdev_get_sec20chan_freq_mhz(vdev, &sec20chan_freq) < 0) {
1064 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1065 		return 0;
1066 	}
1067 
1068 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1069 
1070 	return sec20chan_freq;
1071 }
1072 
1073 /**
1074  * target_if_spectral_get_current_channel() - Get the current channel
1075  * @arg: Pointer to handle for Spectral target_if internal private data
1076  *
1077  * Function to get the current channel (in MHz)
1078  *
1079  * Return: Current channel (in MHz) on success, 0 on failure
1080  */
1081 uint32_t
1082 target_if_spectral_get_current_channel(void *arg)
1083 {
1084 	/*
1085 	 * XXX: Once we expand to use cases where Spectral could be activated
1086 	 * without a channel being set to VDEV, we need to consider returning a
1087 	 * negative value in case of failure and having all callers handle this.
1088 	 */
1089 
1090 	struct target_if_spectral *spectral = NULL;
1091 	int16_t chan_freq = 0;
1092 	struct wlan_objmgr_vdev *vdev = NULL;
1093 
1094 	qdf_assert_always(arg);
1095 	spectral = (struct target_if_spectral *)arg;
1096 
1097 	vdev = target_if_spectral_get_vdev(spectral);
1098 	if (!vdev)
1099 		return 0;
1100 
1101 	chan_freq = target_if_vdev_get_chan_freq(vdev);
1102 	if (chan_freq < 0) {
1103 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1104 		return 0;
1105 	}
1106 
1107 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1108 
1109 	return chan_freq;
1110 }
1111 
1112 /**
1113  * target_if_spectral_reset_hw() - Reset the hardware
1114  * @arg: Pointer to handle for Spectral target_if internal private data
1115  *
1116  * This is only a placeholder since it is not currently required in the offload
1117  * case.
1118  *
1119  * Return: 0
1120  */
1121 uint32_t
1122 target_if_spectral_reset_hw(void *arg)
1123 {
1124 	not_yet_implemented();
1125 	return 0;
1126 }
1127 
1128 /**
1129  * target_if_spectral_get_chain_noise_floor() - Get the Chain noise floor from
1130  * Noisefloor history buffer
1131  * @arg: Pointer to handle for Spectral target_if internal private data
1132  * @nf_buf: Pointer to buffer into which chain Noise Floor data should be copied
1133  *
1134  * This is only a placeholder since it is not currently required in the offload
1135  * case.
1136  *
1137  * Return: 0
1138  */
1139 uint32_t
1140 target_if_spectral_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1141 {
1142 	not_yet_implemented();
1143 	return 0;
1144 }
1145 
1146 /**
1147  * target_if_spectral_get_ext_noisefloor() - Get the extension channel
1148  * noisefloor
1149  * @arg: Pointer to handle for Spectral target_if internal private data
1150  *
1151  * This is only a placeholder since it is not currently required in the offload
1152  * case.
1153  *
1154  * Return: 0
1155  */
1156 int8_t
1157 target_if_spectral_get_ext_noisefloor(void *arg)
1158 {
1159 	not_yet_implemented();
1160 	return 0;
1161 }
1162 
1163 /**
1164  * target_if_spectral_get_ctl_noisefloor() - Get the control channel noisefloor
1165  * @arg: Pointer to handle for Spectral target_if internal private data
1166  *
1167  * This is only a placeholder since it is not currently required in the offload
1168  * case.
1169  *
1170  * Return: 0
1171  */
1172 int8_t
1173 target_if_spectral_get_ctl_noisefloor(void *arg)
1174 {
1175 	not_yet_implemented();
1176 	return 0;
1177 }
1178 
1179 /**
1180  * target_if_spectral_sops_configure_params() - Configure user supplied Spectral
1181  *                                         parameters
1182  * @arg: Pointer to handle for Spectral target_if internal private data
1183  * @params: Spectral parameters
1184  *
1185  * Function to configure spectral parameters
1186  *
1187  * Return: 0 on success else failure
1188  */
1189 uint32_t
1190 target_if_spectral_sops_configure_params(
1191 	void *arg, struct spectral_config *params)
1192 {
1193 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1194 
1195 	return target_if_spectral_info_write(
1196 		spectral,
1197 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1198 		params, sizeof(*params));
1199 }
1200 
1201 /**
1202  * target_if_spectral_sops_get_params() - Get user configured Spectral
1203  * parameters
1204  * @arg: Pointer to handle for Spectral target_if internal private data
1205  * @params: Pointer to buffer into which Spectral parameters should be copied
1206  *
1207  * Function to get the configured spectral parameters
1208  *
1209  * Return: 0 on success else failure
1210  */
1211 uint32_t
1212 target_if_spectral_sops_get_params(void *arg, struct spectral_config *params)
1213 {
1214 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1215 
1216 	return target_if_spectral_info_read(
1217 		spectral,
1218 		TARGET_IF_SPECTRAL_INFO_PARAMS,
1219 		params, sizeof(*params));
1220 }
1221 
1222 /**
1223  * target_if_spectral_get_ent_mask() - Get enterprise mask
1224  * @arg: Pointer to handle for Spectral target_if internal private data
1225  *
1226  * This is only a placeholder since it is not currently required in the offload
1227  * case.
1228  *
1229  * Return: 0
1230  */
1231 static uint32_t
1232 target_if_spectral_get_ent_mask(void *arg)
1233 {
1234 	not_yet_implemented();
1235 	return 0;
1236 }
1237 
1238 /**
1239  * target_if_spectral_get_macaddr() - Get radio MAC address
1240  * @arg: Pointer to handle for Spectral target_if internal private data
1241  * @addr: Pointer to buffer into which MAC address should be copied
1242  *
1243  * Function to get the MAC address of the pdev
1244  *
1245  * Return: 0 on success, -1 on failure
1246  */
1247 static uint32_t
1248 target_if_spectral_get_macaddr(void *arg, char *addr)
1249 {
1250 	uint8_t *myaddr = NULL;
1251 	struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
1252 	struct wlan_objmgr_pdev *pdev = NULL;
1253 
1254 	pdev = spectral->pdev_obj;
1255 
1256 	wlan_pdev_obj_lock(pdev);
1257 	myaddr = wlan_pdev_get_hw_macaddr(pdev);
1258 	wlan_pdev_obj_unlock(pdev);
1259 	qdf_mem_copy(addr, myaddr, IEEE80211_ADDR_LEN);
1260 
1261 	return 0;
1262 }
1263 
1264 /**
1265  * target_if_init_spectral_capability() - Initialize Spectral capability
1266  * @spectral: Pointer to Spectral target_if internal private data
1267  *
1268  * This is a workaround.
1269  *
1270  * Return: QDF_STATUS
1271  */
1272 QDF_STATUS
1273 target_if_init_spectral_capability(struct target_if_spectral *spectral)
1274 {
1275 	struct wlan_objmgr_psoc *psoc;
1276 	struct wlan_objmgr_pdev *pdev;
1277 	struct wlan_psoc_host_spectral_scaling_params *scaling_params;
1278 	uint8_t num_bin_scaling_params, param_idx, pdev_id;
1279 	struct target_psoc_info *tgt_psoc_info;
1280 	struct wlan_psoc_host_service_ext_param *ext_svc_param;
1281 	struct spectral_caps *pcap = &spectral->capability;
1282 
1283 	pdev = spectral->pdev_obj;
1284 	psoc = wlan_pdev_get_psoc(pdev);
1285 	if (!psoc) {
1286 		spectral_err("psoc is null");
1287 		return QDF_STATUS_E_FAILURE;
1288 	}
1289 
1290 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
1291 	if (!tgt_psoc_info) {
1292 		spectral_err("target_psoc_info is null");
1293 		return QDF_STATUS_E_FAILURE;
1294 	}
1295 
1296 	ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info);
1297 	num_bin_scaling_params = ext_svc_param->num_bin_scaling_params;
1298 	scaling_params = target_psoc_get_spectral_scaling_params(tgt_psoc_info);
1299 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
1300 
1301 	/* XXX : Workaround: Set Spectral capability */
1302 	pcap = &spectral->capability;
1303 	pcap->phydiag_cap = 1;
1304 	pcap->radar_cap = 1;
1305 	pcap->spectral_cap = 1;
1306 	pcap->advncd_spectral_cap = 1;
1307 	pcap->hw_gen = spectral->spectral_gen;
1308 
1309 	for (param_idx = 0; param_idx < num_bin_scaling_params; param_idx++) {
1310 		if (scaling_params[param_idx].pdev_id == pdev_id) {
1311 			pcap->is_scaling_params_populated = true;
1312 			pcap->formula_id = scaling_params[param_idx].formula_id;
1313 			pcap->low_level_offset =
1314 				scaling_params[param_idx].low_level_offset;
1315 			pcap->high_level_offset =
1316 				scaling_params[param_idx].high_level_offset;
1317 			pcap->rssi_thr = scaling_params[param_idx].rssi_thr;
1318 			pcap->default_agc_max_gain =
1319 				scaling_params[param_idx].default_agc_max_gain;
1320 			break;
1321 		}
1322 	}
1323 
1324 	return QDF_STATUS_SUCCESS;
1325 }
1326 
1327 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1328 /**
1329  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1330  * internal operations with functions related to spectral simulation
1331  * @p_sops: spectral low level ops table
1332  *
1333  * Initialize spectral target_if internal operations with functions
1334  * related to spectral simulation
1335  *
1336  * Return: None
1337  */
1338 static void
1339 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1340 {
1341 	/*
1342 	 * Spectral simulation is currently intended for platform transitions
1343 	 * where underlying HW support may not be available for some time.
1344 	 * Hence, we do not currently provide a runtime switch to turn the
1345 	 * simulation on or off.
1346 	 * In case of future requirements where runtime switches are required,
1347 	 * this can be added. But it is suggested to use application layer
1348 	 * simulation as far as possible in such cases, since the main
1349 	 * use of record and replay of samples would concern higher
1350 	 * level sample processing rather than lower level delivery.
1351 	 */
1352 	p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled;
1353 	p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active;
1354 	p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan;
1355 	p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan;
1356 	p_sops->configure_spectral =
1357 		target_if_spectral_sops_sim_configure_params;
1358 	p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params;
1359 }
1360 
1361 #else
1362 /**
1363  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1364  * internal operations
1365  * @p_sops: spectral low level ops table
1366  *
1367  * Return: None
1368  */
1369 static void
1370 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1371 {
1372 	p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled;
1373 	p_sops->is_spectral_active = target_if_sops_is_spectral_active;
1374 	p_sops->start_spectral_scan = target_if_sops_start_spectral_scan;
1375 	p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan;
1376 	p_sops->configure_spectral = target_if_spectral_sops_configure_params;
1377 	p_sops->get_spectral_config = target_if_spectral_sops_get_params;
1378 }
1379 #endif
1380 
1381 /**
1382  * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
1383  * operations common to all Spectral chipset generations
1384  *
1385  * Initializes target_if_spectral_ops common to all chipset generations
1386  *
1387  * Return: None
1388  */
1389 static void
1390 target_if_init_spectral_ops_common(void)
1391 {
1392 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1393 
1394 	p_sops->get_tsf64 = target_if_spectral_get_tsf64;
1395 	p_sops->get_capability = target_if_spectral_get_capability;
1396 	p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
1397 	p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
1398 
1399 	target_if_init_spectral_simulation_ops(p_sops);
1400 
1401 	p_sops->get_extension_channel =
1402 	    target_if_spectral_get_extension_channel;
1403 	p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor;
1404 	p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor;
1405 	p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
1406 	p_sops->get_mac_address = target_if_spectral_get_macaddr;
1407 	p_sops->get_current_channel = target_if_spectral_get_current_channel;
1408 	p_sops->reset_hw = target_if_spectral_reset_hw;
1409 	p_sops->get_chain_noise_floor =
1410 	    target_if_spectral_get_chain_noise_floor;
1411 }
1412 
1413 /**
1414  * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
1415  * operations specific to Spectral chipset generation 2.
1416  *
1417  * Initializes target_if_spectral_ops specific to Spectral chipset generation 2.
1418  *
1419  * Return: None
1420  */
1421 static void
1422 target_if_init_spectral_ops_gen2(void)
1423 {
1424 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1425 
1426 	p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2;
1427 }
1428 
1429 /**
1430  * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
1431  * operations specific to Spectral chipset generation 3.
1432  *
1433  * Initializes target_if_spectral_ops specific to Spectral chipset generation 3.
1434  *
1435  * Return: None
1436  */
1437 static void
1438 target_if_init_spectral_ops_gen3(void)
1439 {
1440 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1441 
1442 	p_sops->process_spectral_report =
1443 			target_if_spectral_process_report_gen3;
1444 	return;
1445 }
1446 
1447 /**
1448  * target_if_init_spectral_ops() - Initialize target_if internal Spectral
1449  * operations.
1450  * @spectral: Pointer to Spectral target_if internal private data
1451  *
1452  * Initializes all function pointers in target_if_spectral_ops for
1453  * all generations
1454  *
1455  * Return: None
1456  */
1457 static void
1458 target_if_init_spectral_ops(struct target_if_spectral *spectral)
1459 {
1460 	target_if_init_spectral_ops_common();
1461 	if (spectral->spectral_gen == SPECTRAL_GEN2)
1462 		target_if_init_spectral_ops_gen2();
1463 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
1464 		target_if_init_spectral_ops_gen3();
1465 	else
1466 		spectral_err("Invalid Spectral generation");
1467 }
1468 
1469 /*
1470  * Dummy Functions:
1471  * These functions are initially registered to avoid any crashes due to
1472  * invocation of spectral functions before they are registered.
1473  */
1474 
1475 static uint64_t
1476 null_get_tsf64(void *arg)
1477 {
1478 	spectral_ops_not_registered("get_tsf64");
1479 	return 0;
1480 }
1481 
1482 static uint32_t
1483 null_get_capability(void *arg, enum spectral_capability_type type)
1484 {
1485 	/*
1486 	 * TODO : We should have conditional compilation to get the capability
1487 	 *      : We have not yet attahced ATH layer here, so there is no
1488 	 *      : way to check the HAL capbalities
1489 	 */
1490 	spectral_ops_not_registered("get_capability");
1491 
1492 	/* TODO : For the time being, we are returning TRUE */
1493 	return true;
1494 }
1495 
1496 static uint32_t
1497 null_set_rxfilter(void *arg, int rxfilter)
1498 {
1499 	spectral_ops_not_registered("set_rxfilter");
1500 	return 1;
1501 }
1502 
1503 static uint32_t
1504 null_get_rxfilter(void *arg)
1505 {
1506 	spectral_ops_not_registered("get_rxfilter");
1507 	return 0;
1508 }
1509 
1510 static uint32_t
1511 null_is_spectral_active(void *arg)
1512 {
1513 	spectral_ops_not_registered("is_spectral_active");
1514 	return 1;
1515 }
1516 
1517 static uint32_t
1518 null_is_spectral_enabled(void *arg)
1519 {
1520 	spectral_ops_not_registered("is_spectral_enabled");
1521 	return 1;
1522 }
1523 
1524 static uint32_t
1525 null_start_spectral_scan(void *arg)
1526 {
1527 	spectral_ops_not_registered("start_spectral_scan");
1528 	return 1;
1529 }
1530 
1531 static uint32_t
1532 null_stop_spectral_scan(void *arg)
1533 {
1534 	spectral_ops_not_registered("stop_spectral_scan");
1535 	return 1;
1536 }
1537 
1538 static uint32_t
1539 null_get_extension_channel(void *arg)
1540 {
1541 	spectral_ops_not_registered("get_extension_channel");
1542 	return 1;
1543 }
1544 
1545 static int8_t
1546 null_get_ctl_noisefloor(void *arg)
1547 {
1548 	spectral_ops_not_registered("get_ctl_noisefloor");
1549 	return 1;
1550 }
1551 
1552 static int8_t
1553 null_get_ext_noisefloor(void *arg)
1554 {
1555 	spectral_ops_not_registered("get_ext_noisefloor");
1556 	return 0;
1557 }
1558 
1559 static uint32_t
1560 null_configure_spectral(void *arg, struct spectral_config *params)
1561 {
1562 	spectral_ops_not_registered("configure_spectral");
1563 	return 0;
1564 }
1565 
1566 static uint32_t
1567 null_get_spectral_config(void *arg, struct spectral_config *params)
1568 {
1569 	spectral_ops_not_registered("get_spectral_config");
1570 	return 0;
1571 }
1572 
1573 static uint32_t
1574 null_get_ent_spectral_mask(void *arg)
1575 {
1576 	spectral_ops_not_registered("get_ent_spectral_mask");
1577 	return 0;
1578 }
1579 
1580 static uint32_t
1581 null_get_mac_address(void *arg, char *addr)
1582 {
1583 	spectral_ops_not_registered("get_mac_address");
1584 	return 0;
1585 }
1586 
1587 static uint32_t
1588 null_get_current_channel(void *arg)
1589 {
1590 	spectral_ops_not_registered("get_current_channel");
1591 	return 0;
1592 }
1593 
1594 static uint32_t
1595 null_reset_hw(void *arg)
1596 {
1597 	spectral_ops_not_registered("get_current_channel");
1598 	return 0;
1599 }
1600 
1601 static uint32_t
1602 null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1603 {
1604 	spectral_ops_not_registered("get_chain_noise_floor");
1605 	return 0;
1606 }
1607 
1608 static int
1609 null_spectral_process_phyerr(struct target_if_spectral *spectral,
1610 			     uint8_t *data,
1611 			     uint32_t datalen,
1612 			     struct target_if_spectral_rfqual_info *p_rfqual,
1613 			     struct target_if_spectral_chan_info *p_chaninfo,
1614 			     uint64_t tsf64,
1615 			     struct target_if_spectral_acs_stats *acs_stats)
1616 {
1617 	spectral_ops_not_registered("spectral_process_phyerr");
1618 	return 0;
1619 }
1620 
1621 static int
1622 null_process_spectral_report(struct wlan_objmgr_pdev *pdev,
1623 			     void *payload)
1624 {
1625 	spectral_ops_not_registered("process_spectral_report");
1626 	return 0;
1627 }
1628 /**
1629  * target_if_spectral_init_dummy_function_table() -
1630  * Initialize target_if internal
1631  * Spectral operations to dummy functions
1632  * @ps: Pointer to Spectral target_if internal private data
1633  *
1634  * Initialize all the function pointers in target_if_spectral_ops with
1635  * dummy functions.
1636  *
1637  * Return: None
1638  */
1639 static void
1640 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps)
1641 {
1642 	struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps);
1643 
1644 	p_sops->get_tsf64 = null_get_tsf64;
1645 	p_sops->get_capability = null_get_capability;
1646 	p_sops->set_rxfilter = null_set_rxfilter;
1647 	p_sops->get_rxfilter = null_get_rxfilter;
1648 	p_sops->is_spectral_enabled = null_is_spectral_enabled;
1649 	p_sops->is_spectral_active = null_is_spectral_active;
1650 	p_sops->start_spectral_scan = null_start_spectral_scan;
1651 	p_sops->stop_spectral_scan = null_stop_spectral_scan;
1652 	p_sops->get_extension_channel = null_get_extension_channel;
1653 	p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
1654 	p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
1655 	p_sops->configure_spectral = null_configure_spectral;
1656 	p_sops->get_spectral_config = null_get_spectral_config;
1657 	p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
1658 	p_sops->get_mac_address = null_get_mac_address;
1659 	p_sops->get_current_channel = null_get_current_channel;
1660 	p_sops->reset_hw = null_reset_hw;
1661 	p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
1662 	p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
1663 	p_sops->process_spectral_report = null_process_spectral_report;
1664 }
1665 
1666 /**
1667  * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
1668  * operations
1669  * @spectral: Pointer to Spectral target_if internal private data
1670  * @p: Pointer to Spectral function table
1671  *
1672  * Return: None
1673  */
1674 static void
1675 target_if_spectral_register_funcs(struct target_if_spectral *spectral,
1676 				  struct target_if_spectral_ops *p)
1677 {
1678 	struct target_if_spectral_ops *p_sops =
1679 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1680 
1681 	p_sops->get_tsf64 = p->get_tsf64;
1682 	p_sops->get_capability = p->get_capability;
1683 	p_sops->set_rxfilter = p->set_rxfilter;
1684 	p_sops->get_rxfilter = p->get_rxfilter;
1685 	p_sops->is_spectral_enabled = p->is_spectral_enabled;
1686 	p_sops->is_spectral_active = p->is_spectral_active;
1687 	p_sops->start_spectral_scan = p->start_spectral_scan;
1688 	p_sops->stop_spectral_scan = p->stop_spectral_scan;
1689 	p_sops->get_extension_channel = p->get_extension_channel;
1690 	p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor;
1691 	p_sops->get_ext_noisefloor = p->get_ext_noisefloor;
1692 	p_sops->configure_spectral = p->configure_spectral;
1693 	p_sops->get_spectral_config = p->get_spectral_config;
1694 	p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask;
1695 	p_sops->get_mac_address = p->get_mac_address;
1696 	p_sops->get_current_channel = p->get_current_channel;
1697 	p_sops->reset_hw = p->reset_hw;
1698 	p_sops->get_chain_noise_floor = p->get_chain_noise_floor;
1699 	p_sops->spectral_process_phyerr = p->spectral_process_phyerr;
1700 	p_sops->process_spectral_report = p->process_spectral_report;
1701 }
1702 
1703 /**
1704  * target_if_spectral_clear_stats() - Clear Spectral stats
1705  * @spectral: Pointer to Spectral target_if internal private data
1706  *
1707  * Function to clear spectral stats
1708  *
1709  * Return: None
1710  */
1711 static void
1712 target_if_spectral_clear_stats(struct target_if_spectral *spectral)
1713 {
1714 	struct target_if_spectral_ops *p_sops =
1715 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1716 
1717 	qdf_mem_zero(&spectral->spectral_stats,
1718 		     sizeof(struct target_if_spectral_stats));
1719 	spectral->spectral_stats.last_reset_tstamp =
1720 	    p_sops->get_tsf64(spectral);
1721 }
1722 
1723 /**
1724  * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
1725  * @spectral: Pointer to Spectral target_if internal private data
1726  *
1727  * Function to check whether hardware supports spectral
1728  *
1729  * Return: True if HW supports Spectral, false if HW does not support Spectral
1730  */
1731 static int
1732 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
1733 {
1734 	struct target_if_spectral_ops *p_sops = NULL;
1735 	struct spectral_caps *pcap = NULL;
1736 	int is_spectral_supported = true;
1737 
1738 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1739 	pcap = &spectral->capability;
1740 
1741 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
1742 		is_spectral_supported = false;
1743 		spectral_info("SPECTRAL : No PHYDIAG support");
1744 		return is_spectral_supported;
1745 	}
1746 	pcap->phydiag_cap = 1;
1747 
1748 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
1749 		is_spectral_supported = false;
1750 		spectral_info("SPECTRAL : No RADAR support");
1751 		return is_spectral_supported;
1752 	}
1753 	pcap->radar_cap = 1;
1754 
1755 	if (p_sops->get_capability(spectral,
1756 				   SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
1757 		is_spectral_supported = false;
1758 		spectral_info("SPECTRAL : No SPECTRAL SUPPORT");
1759 		return is_spectral_supported;
1760 	}
1761 	pcap->spectral_cap = 1;
1762 
1763 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
1764 	    == false) {
1765 		spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT");
1766 	} else {
1767 		pcap->advncd_spectral_cap = 1;
1768 	}
1769 
1770 	return is_spectral_supported;
1771 }
1772 
1773 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1774 /**
1775  * target_if_spectral_detach_simulation() - De-initialize Spectral
1776  * Simulation functionality
1777  * @spectral: Pointer to Spectral target_if internal private data
1778  *
1779  * Function to de-initialize Spectral Simulation functionality
1780  *
1781  * Return: None
1782  */
1783 static void
1784 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
1785 {
1786 	target_if_spectral_sim_detach(spectral);
1787 }
1788 
1789 #else
1790 static void
1791 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
1792 {
1793 }
1794 #endif
1795 
1796 /**
1797  * target_if_spectral_detach() - De-initialize target_if Spectral
1798  * @pdev: Pointer to pdev object
1799  *
1800  * Function to detach target_if spectral
1801  *
1802  * Return: None
1803  */
1804 static void
1805 target_if_spectral_detach(struct target_if_spectral *spectral)
1806 {
1807 	spectral_info("spectral detach");
1808 
1809 	if (spectral) {
1810 		if (spectral->spectral_gen == SPECTRAL_GEN3)
1811 			deinit_160mhz_delivery_state_machine(spectral);
1812 		qdf_spinlock_destroy(&spectral->param_info.osps_lock);
1813 
1814 		target_if_spectral_detach_simulation(spectral);
1815 
1816 		qdf_spinlock_destroy(&spectral->spectral_lock);
1817 		qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
1818 
1819 		qdf_mem_free(spectral);
1820 		spectral = NULL;
1821 	}
1822 }
1823 
1824 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1825 /**
1826  * target_if_spectral_attach_simulation() - Initialize Spectral Simulation
1827  * functionality
1828  * @spectral: Pointer to Spectral target_if internal private data
1829  *
1830  * Function to initialize spectral simulation functionality
1831  *
1832  * Return: 0 on success, negative error code on failure
1833  */
1834 static int
1835 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
1836 {
1837 	if (target_if_spectral_sim_attach(spectral)) {
1838 		qdf_mem_free(spectral);
1839 		return -EPERM;
1840 	}
1841 	return 0;
1842 }
1843 
1844 #else
1845 static int
1846 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
1847 {
1848 	return 0;
1849 }
1850 #endif
1851 
1852 /**
1853  * target_if_pdev_spectral_init() - Initialize target_if Spectral
1854  * functionality for the given pdev
1855  * @pdev: Pointer to pdev object
1856  *
1857  * Function to initialize pointer to spectral target_if internal private data
1858  *
1859  * Return: On success, pointer to Spectral target_if internal private data, on
1860  * failure, NULL
1861  */
1862 void *
1863 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
1864 {
1865 	struct target_if_spectral_ops *p_sops = NULL;
1866 	struct target_if_spectral *spectral = NULL;
1867 	uint32_t target_type;
1868 	uint32_t target_revision;
1869 	struct wlan_objmgr_psoc *psoc;
1870 	struct wlan_lmac_if_target_tx_ops *tx_ops;
1871 
1872 	if (!pdev) {
1873 		spectral_err("SPECTRAL: pdev is NULL!");
1874 		return NULL;
1875 	}
1876 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
1877 			sizeof(struct target_if_spectral));
1878 	if (!spectral)
1879 		return spectral;
1880 
1881 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
1882 	/* Store pdev in Spectral */
1883 	spectral->pdev_obj = pdev;
1884 
1885 	psoc = wlan_pdev_get_psoc(pdev);
1886 
1887 	tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops;
1888 
1889 	if (tx_ops->tgt_get_tgt_type) {
1890 		target_type = tx_ops->tgt_get_tgt_type(psoc);
1891 	} else {
1892 		qdf_mem_free(spectral);
1893 		return NULL;
1894 	}
1895 
1896 	if (tx_ops->tgt_get_tgt_revision) {
1897 		target_revision = tx_ops->tgt_get_tgt_revision(psoc);
1898 	} else {
1899 		qdf_mem_free(spectral);
1900 		return NULL;
1901 	}
1902 
1903 	/* init the function ptr table */
1904 	target_if_spectral_init_dummy_function_table(spectral);
1905 
1906 	/* get spectral function table */
1907 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1908 	/* TODO : Should this be called here of after ath_attach ? */
1909 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
1910 		spectral_info("HAL_CAP_PHYDIAG : Capable");
1911 
1912 	/* TODO: Need to fix the capablity check for RADAR */
1913 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
1914 		spectral_info("HAL_CAP_RADAR   : Capable");
1915 
1916 	/* TODO : Need to fix the capablity check for SPECTRAL */
1917 	/* TODO : Should this be called here of after ath_attach ? */
1918 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
1919 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
1920 
1921 	qdf_spinlock_create(&spectral->spectral_lock);
1922 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
1923 	target_if_spectral_clear_stats(spectral);
1924 
1925 	if (target_type == TARGET_TYPE_QCA8074V2 ||
1926 	    target_type == TARGET_TYPE_QCA6018)
1927 		spectral->fftbin_size_war =
1928 			SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE;
1929 	else if (target_type == TARGET_TYPE_QCA8074)
1930 		spectral->fftbin_size_war =
1931 			SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE;
1932 	else
1933 		spectral->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR;
1934 
1935 	if (target_type == TARGET_TYPE_QCA8074 ||
1936 	    target_type == TARGET_TYPE_QCA8074V2 ||
1937 	    target_type == TARGET_TYPE_QCA6018) {
1938 		spectral->inband_fftbin_size_adj = 1;
1939 		spectral->null_fftbin_adj = 1;
1940 	} else {
1941 		spectral->inband_fftbin_size_adj = 0;
1942 		spectral->null_fftbin_adj = 0;
1943 	}
1944 	spectral->last_fft_timestamp = 0;
1945 	spectral->timestamp_war_offset = 0;
1946 
1947 	if ((target_type == TARGET_TYPE_QCA8074) ||
1948 	    (target_type == TARGET_TYPE_QCA8074V2) ||
1949 	    (target_type == TARGET_TYPE_QCA6018) ||
1950 	    (target_type == TARGET_TYPE_QCA6290)) {
1951 		spectral->spectral_gen = SPECTRAL_GEN3;
1952 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
1953 		spectral->tag_sscan_summary_exp =
1954 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
1955 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
1956 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
1957 	} else {
1958 		spectral->spectral_gen = SPECTRAL_GEN2;
1959 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
1960 		spectral->tag_sscan_summary_exp =
1961 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
1962 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
1963 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
1964 	}
1965 
1966 	spectral->params_valid = false;
1967 	/* Init spectral capability */
1968 	if (target_if_init_spectral_capability(spectral) !=
1969 					QDF_STATUS_SUCCESS) {
1970 		qdf_mem_free(spectral);
1971 		return NULL;
1972 	}
1973 	if (target_if_spectral_attach_simulation(spectral) < 0)
1974 		return NULL;
1975 
1976 	target_if_init_spectral_ops(spectral);
1977 
1978 	qdf_spinlock_create(&spectral->param_info.osps_lock);
1979 	spectral->param_info.osps_cache.osc_is_valid = 0;
1980 
1981 	target_if_spectral_register_funcs(spectral, &spectral_ops);
1982 
1983 	if (target_if_spectral_check_hw_capability(spectral) == false) {
1984 		target_if_spectral_detach(spectral);
1985 		spectral = NULL;
1986 	} else {
1987 		/*
1988 		 * TODO: Once the driver architecture transitions to chipset
1989 		 * versioning based checks, reflect this here.
1990 		 */
1991 		spectral->is_160_format = false;
1992 		spectral->is_lb_edge_extrabins_format = false;
1993 		spectral->is_rb_edge_extrabins_format = false;
1994 
1995 		if (target_type == TARGET_TYPE_QCA9984 ||
1996 		    target_type == TARGET_TYPE_QCA9888) {
1997 			spectral->is_160_format = true;
1998 			spectral->is_lb_edge_extrabins_format = true;
1999 			spectral->is_rb_edge_extrabins_format = true;
2000 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
2001 			    (target_revision == AR900B_REV_2)) {
2002 			spectral->is_rb_edge_extrabins_format = true;
2003 		}
2004 
2005 		if (target_type == TARGET_TYPE_QCA9984 ||
2006 		    target_type == TARGET_TYPE_QCA9888)
2007 			spectral->is_sec80_rssi_war_required = true;
2008 
2009 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
2010 
2011 		if (spectral->spectral_gen == SPECTRAL_GEN3)
2012 			init_160mhz_delivery_state_machine(spectral);
2013 	}
2014 
2015 	return spectral;
2016 }
2017 
2018 /**
2019  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
2020  * functionality for the given pdev
2021  * @pdev: Pointer to pdev object
2022  *
2023  * Function to de-initialize pointer to spectral target_if internal private data
2024  *
2025  * Return: None
2026  */
2027 void
2028 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
2029 {
2030 	struct target_if_spectral *spectral = NULL;
2031 
2032 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2033 	if (!spectral) {
2034 		spectral_err("SPECTRAL : Module doesn't exist");
2035 		return;
2036 	}
2037 	target_if_spectral_detach(spectral);
2038 
2039 	return;
2040 }
2041 
2042 /**
2043  * target_if_set_spectral_config() - Set spectral config
2044  * @pdev:       Pointer to pdev object
2045  * @threshtype: config type
2046  * @value:      config value
2047  *
2048  * API to set spectral configurations
2049  *
2050  * Return: 0 on success else failure
2051  */
2052 int
2053 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
2054 			      const uint32_t threshtype, const uint32_t value)
2055 {
2056 	struct spectral_config params;
2057 	struct target_if_spectral_ops *p_sops = NULL;
2058 	struct target_if_spectral *spectral = NULL;
2059 
2060 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2061 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2062 	if (!spectral) {
2063 		spectral_err("spectral object is NULL");
2064 		return -EPERM;
2065 	}
2066 
2067 	if (!spectral->params_valid) {
2068 		target_if_spectral_info_read(spectral,
2069 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
2070 					     &spectral->params,
2071 					     sizeof(spectral->params));
2072 		spectral->params_valid = true;
2073 	}
2074 
2075 	switch (threshtype) {
2076 	case SPECTRAL_PARAM_FFT_PERIOD:
2077 		spectral->params.ss_fft_period = value;
2078 		break;
2079 	case SPECTRAL_PARAM_SCAN_PERIOD:
2080 		spectral->params.ss_period = value;
2081 		break;
2082 	case SPECTRAL_PARAM_SCAN_COUNT:
2083 		spectral->params.ss_count = value;
2084 		break;
2085 	case SPECTRAL_PARAM_SHORT_REPORT:
2086 		spectral->params.ss_short_report = (!!value) ? true : false;
2087 		break;
2088 	case SPECTRAL_PARAM_SPECT_PRI:
2089 		spectral->params.ss_spectral_pri = (!!value) ? true : false;
2090 		break;
2091 	case SPECTRAL_PARAM_FFT_SIZE:
2092 		spectral->params.ss_fft_size = value;
2093 		break;
2094 	case SPECTRAL_PARAM_GC_ENA:
2095 		spectral->params.ss_gc_ena = !!value;
2096 		break;
2097 	case SPECTRAL_PARAM_RESTART_ENA:
2098 		spectral->params.ss_restart_ena = !!value;
2099 		break;
2100 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
2101 		spectral->params.ss_noise_floor_ref = value;
2102 		break;
2103 	case SPECTRAL_PARAM_INIT_DELAY:
2104 		spectral->params.ss_init_delay = value;
2105 		break;
2106 	case SPECTRAL_PARAM_NB_TONE_THR:
2107 		spectral->params.ss_nb_tone_thr = value;
2108 		break;
2109 	case SPECTRAL_PARAM_STR_BIN_THR:
2110 		spectral->params.ss_str_bin_thr = value;
2111 		break;
2112 	case SPECTRAL_PARAM_WB_RPT_MODE:
2113 		spectral->params.ss_wb_rpt_mode = !!value;
2114 		break;
2115 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
2116 		spectral->params.ss_rssi_rpt_mode = !!value;
2117 		break;
2118 	case SPECTRAL_PARAM_RSSI_THR:
2119 		spectral->params.ss_rssi_thr = value;
2120 		break;
2121 	case SPECTRAL_PARAM_PWR_FORMAT:
2122 		spectral->params.ss_pwr_format = !!value;
2123 		break;
2124 	case SPECTRAL_PARAM_RPT_MODE:
2125 		spectral->params.ss_rpt_mode = value;
2126 		break;
2127 	case SPECTRAL_PARAM_BIN_SCALE:
2128 		spectral->params.ss_bin_scale = value;
2129 		break;
2130 	case SPECTRAL_PARAM_DBM_ADJ:
2131 		spectral->params.ss_dbm_adj = !!value;
2132 		break;
2133 	case SPECTRAL_PARAM_CHN_MASK:
2134 		spectral->params.ss_chn_mask = value;
2135 		break;
2136 	}
2137 
2138 	p_sops->configure_spectral(spectral, &spectral->params);
2139 	/* only to validate the writes */
2140 	p_sops->get_spectral_config(spectral, &params);
2141 	return 0;
2142 }
2143 
2144 /**
2145  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
2146  * @fft_len: FFT length
2147  * @pdev: Pointer to pdev object
2148  *
2149  * API to get fft bin count for a given fft length
2150  *
2151  * Return: FFt bin count
2152  */
2153 static int
2154 target_if_get_fft_bin_count(int fft_len)
2155 {
2156 	int bin_count = 0;
2157 
2158 	switch (fft_len) {
2159 	case 5:
2160 		bin_count = 16;
2161 		break;
2162 	case 6:
2163 		bin_count = 32;
2164 		break;
2165 	case 7:
2166 		bin_count = 64;
2167 		break;
2168 	case 8:
2169 		bin_count = 128;
2170 		break;
2171 	case 9:
2172 		bin_count = 256;
2173 		break;
2174 	default:
2175 		break;
2176 	}
2177 
2178 	return bin_count;
2179 }
2180 
2181 /**
2182  * target_if_init_upper_lower_flags() - Initializes control and extension
2183  * segment flags
2184  * @fft_len: FFT length
2185  * @pdev: Pointer to pdev object
2186  *
2187  * API to initialize the control and extension flags with the lower/upper
2188  * segment based on the HT mode
2189  *
2190  * Return: FFt bin count
2191  */
2192 static void
2193 target_if_init_upper_lower_flags(struct target_if_spectral *spectral)
2194 {
2195 	int current_channel = 0;
2196 	int ext_channel = 0;
2197 	struct target_if_spectral_ops *p_sops =
2198 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2199 
2200 	current_channel = p_sops->get_current_channel(spectral);
2201 	ext_channel = p_sops->get_extension_channel(spectral);
2202 
2203 	if ((current_channel == 0) || (ext_channel == 0))
2204 		return;
2205 
2206 	if (spectral->sc_spectral_20_40_mode) {
2207 		/* HT40 mode */
2208 		if (ext_channel < current_channel) {
2209 			spectral->lower_is_extension = 1;
2210 			spectral->upper_is_control = 1;
2211 			spectral->lower_is_control = 0;
2212 			spectral->upper_is_extension = 0;
2213 		} else {
2214 			spectral->lower_is_extension = 0;
2215 			spectral->upper_is_control = 0;
2216 			spectral->lower_is_control = 1;
2217 			spectral->upper_is_extension = 1;
2218 		}
2219 	} else {
2220 		/* HT20 mode, lower is always control */
2221 		spectral->lower_is_extension = 0;
2222 		spectral->upper_is_control = 0;
2223 		spectral->lower_is_control = 1;
2224 		spectral->upper_is_extension = 0;
2225 	}
2226 }
2227 
2228 /**
2229  * target_if_get_spectral_config() - Get spectral configuration
2230  * @pdev: Pointer to pdev object
2231  * @param: Pointer to spectral_config structure in which the configuration
2232  * should be returned
2233  *
2234  * API to get the current spectral configuration
2235  *
2236  * Return: None
2237  */
2238 void
2239 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
2240 			      struct spectral_config *param)
2241 {
2242 	struct target_if_spectral_ops *p_sops = NULL;
2243 	struct target_if_spectral *spectral = NULL;
2244 
2245 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2246 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2247 
2248 	qdf_mem_zero(param, sizeof(struct spectral_config));
2249 	p_sops->get_spectral_config(spectral, param);
2250 }
2251 
2252 /**
2253  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
2254  *                                           parameters
2255  * @spectral: Pointer to Spectral target_if internal private data
2256  * @spectral_params: Pointer to Spectral parameters
2257  *
2258  * Enable use of desired Spectral parameters by configuring them into HW, and
2259  * starting Spectral scan
2260  *
2261  * Return: 0 on success, 1 on failure
2262  */
2263 int
2264 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
2265 				      struct spectral_config *spectral_params)
2266 {
2267 	int extension_channel = 0;
2268 	int current_channel = 0;
2269 	struct target_if_spectral_ops *p_sops = NULL;
2270 	struct wlan_objmgr_vdev *vdev = NULL;
2271 
2272 	if (!spectral) {
2273 		spectral_err("SPECTRAL : Spectral is NULL");
2274 		return 1;
2275 	}
2276 
2277 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2278 
2279 	if (!p_sops) {
2280 		spectral_err("SPECTRAL : p_sops is NULL");
2281 		return 1;
2282 	}
2283 
2284 	spectral->sc_spectral_noise_pwr_cal =
2285 	    spectral_params->ss_spectral_pri ? 1 : 0;
2286 
2287 	/* check if extension channel is present */
2288 	extension_channel = p_sops->get_extension_channel(spectral);
2289 	current_channel = p_sops->get_current_channel(spectral);
2290 
2291 	vdev = target_if_spectral_get_vdev(spectral);
2292 	if (!vdev)
2293 		return 1;
2294 
2295 	spectral->ch_width = target_if_vdev_get_ch_width(vdev);
2296 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2297 
2298 	if (spectral->ch_width == CH_WIDTH_INVALID)
2299 		return 1;
2300 
2301 	if (spectral->capability.advncd_spectral_cap) {
2302 		spectral->lb_edge_extrabins = 0;
2303 		spectral->rb_edge_extrabins = 0;
2304 
2305 		if (spectral->is_lb_edge_extrabins_format &&
2306 		    spectral->params.ss_rpt_mode == 2) {
2307 			spectral->lb_edge_extrabins = 4;
2308 		}
2309 
2310 		if (spectral->is_rb_edge_extrabins_format &&
2311 		    spectral->params.ss_rpt_mode == 2) {
2312 			spectral->rb_edge_extrabins = 4;
2313 		}
2314 
2315 		if (spectral->ch_width == CH_WIDTH_20MHZ) {
2316 			spectral->sc_spectral_20_40_mode = 0;
2317 
2318 			spectral->spectral_numbins =
2319 			    target_if_get_fft_bin_count(
2320 				spectral->params.ss_fft_size);
2321 			spectral->spectral_fft_len =
2322 			    target_if_get_fft_bin_count(
2323 				spectral->params.ss_fft_size);
2324 			spectral->spectral_data_len =
2325 			    target_if_get_fft_bin_count(
2326 				spectral->params.ss_fft_size);
2327 			/*
2328 			 * Initialize classifier params to be sent to user
2329 			 * space classifier
2330 			 */
2331 			spectral->classifier_params.lower_chan_in_mhz =
2332 			    current_channel;
2333 			spectral->classifier_params.upper_chan_in_mhz = 0;
2334 
2335 		} else if (spectral->ch_width == CH_WIDTH_40MHZ) {
2336 			/* TODO : Remove this variable */
2337 			spectral->sc_spectral_20_40_mode = 1;
2338 			spectral->spectral_numbins =
2339 			    target_if_get_fft_bin_count(
2340 				spectral->params.ss_fft_size);
2341 			spectral->spectral_fft_len =
2342 			    target_if_get_fft_bin_count(
2343 				spectral->params.ss_fft_size);
2344 			spectral->spectral_data_len =
2345 			    target_if_get_fft_bin_count(
2346 				spectral->params.ss_fft_size);
2347 
2348 			/*
2349 			 * Initialize classifier params to be sent to user
2350 			 * space classifier
2351 			 */
2352 			if (extension_channel < current_channel) {
2353 				spectral->classifier_params.lower_chan_in_mhz =
2354 				    extension_channel;
2355 				spectral->classifier_params.upper_chan_in_mhz =
2356 				    current_channel;
2357 			} else {
2358 				spectral->classifier_params.lower_chan_in_mhz =
2359 				    current_channel;
2360 				spectral->classifier_params.upper_chan_in_mhz =
2361 				    extension_channel;
2362 			}
2363 
2364 		} else if (spectral->ch_width == CH_WIDTH_80MHZ) {
2365 			/* Set the FFT Size */
2366 			/* TODO : Remove this variable */
2367 			spectral->sc_spectral_20_40_mode = 0;
2368 			spectral->spectral_numbins =
2369 			    target_if_get_fft_bin_count(
2370 				spectral->params.ss_fft_size);
2371 			spectral->spectral_fft_len =
2372 			    target_if_get_fft_bin_count(
2373 				spectral->params.ss_fft_size);
2374 			spectral->spectral_data_len =
2375 			    target_if_get_fft_bin_count(
2376 				spectral->params.ss_fft_size);
2377 
2378 			/*
2379 			 * Initialize classifier params to be sent to user
2380 			 * space classifier
2381 			 */
2382 			spectral->classifier_params.lower_chan_in_mhz =
2383 			    current_channel;
2384 			spectral->classifier_params.upper_chan_in_mhz = 0;
2385 
2386 			/*
2387 			 * Initialize classifier params to be sent to user
2388 			 * space classifier
2389 			 */
2390 			if (extension_channel < current_channel) {
2391 				spectral->classifier_params.lower_chan_in_mhz =
2392 				    extension_channel;
2393 				spectral->classifier_params.upper_chan_in_mhz =
2394 				    current_channel;
2395 			} else {
2396 				spectral->classifier_params.lower_chan_in_mhz =
2397 				    current_channel;
2398 				spectral->classifier_params.upper_chan_in_mhz =
2399 				    extension_channel;
2400 			}
2401 
2402 		} else if (spectral->ch_width == CH_WIDTH_160MHZ) {
2403 			/* Set the FFT Size */
2404 
2405 			/* The below applies to both 160 and 80+80 cases */
2406 
2407 			/* TODO : Remove this variable */
2408 			spectral->sc_spectral_20_40_mode = 0;
2409 			spectral->spectral_numbins =
2410 			    target_if_get_fft_bin_count(
2411 				spectral->params.ss_fft_size);
2412 			spectral->spectral_fft_len =
2413 			    target_if_get_fft_bin_count(
2414 				spectral->params.ss_fft_size);
2415 			spectral->spectral_data_len =
2416 			    target_if_get_fft_bin_count(
2417 				spectral->params.ss_fft_size);
2418 
2419 			/*
2420 			 * Initialize classifier params to be sent to user
2421 			 * space classifier
2422 			 */
2423 			spectral->classifier_params.lower_chan_in_mhz =
2424 			    current_channel;
2425 			spectral->classifier_params.upper_chan_in_mhz = 0;
2426 
2427 			/*
2428 			 * Initialize classifier params to be sent to user
2429 			 * space classifier
2430 			 */
2431 			if (extension_channel < current_channel) {
2432 				spectral->classifier_params.lower_chan_in_mhz =
2433 				    extension_channel;
2434 				spectral->classifier_params.upper_chan_in_mhz =
2435 				    current_channel;
2436 			} else {
2437 				spectral->classifier_params.lower_chan_in_mhz =
2438 				    current_channel;
2439 				spectral->classifier_params.upper_chan_in_mhz =
2440 				    extension_channel;
2441 			}
2442 		}
2443 
2444 		if (spectral->spectral_numbins) {
2445 			spectral->spectral_numbins +=
2446 			    spectral->lb_edge_extrabins;
2447 			spectral->spectral_numbins +=
2448 			    spectral->rb_edge_extrabins;
2449 		}
2450 
2451 		if (spectral->spectral_fft_len) {
2452 			spectral->spectral_fft_len +=
2453 			    spectral->lb_edge_extrabins;
2454 			spectral->spectral_fft_len +=
2455 			    spectral->rb_edge_extrabins;
2456 		}
2457 
2458 		if (spectral->spectral_data_len) {
2459 			spectral->spectral_data_len +=
2460 			    spectral->lb_edge_extrabins;
2461 			spectral->spectral_data_len +=
2462 			    spectral->rb_edge_extrabins;
2463 		}
2464 	} else {
2465 		/*
2466 		 * The decision to find 20/40 mode is found based on the
2467 		 * presence of extension channel
2468 		 * instead of channel width, as the channel width can
2469 		 * dynamically change
2470 		 */
2471 
2472 		if (extension_channel == 0) {
2473 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
2474 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
2475 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
2476 			spectral->spectral_data_len =
2477 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
2478 			/* only valid in 20-40 mode */
2479 			spectral->spectral_lower_max_index_offset = -1;
2480 			/* only valid in 20-40 mode */
2481 			spectral->spectral_upper_max_index_offset = -1;
2482 			spectral->spectral_max_index_offset =
2483 			    spectral->spectral_fft_len + 2;
2484 			spectral->sc_spectral_20_40_mode = 0;
2485 
2486 			/*
2487 			 * Initialize classifier params to be sent to user
2488 			 * space classifier
2489 			 */
2490 			spectral->classifier_params.lower_chan_in_mhz =
2491 			    current_channel;
2492 			spectral->classifier_params.upper_chan_in_mhz = 0;
2493 
2494 		} else {
2495 			spectral->spectral_numbins =
2496 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
2497 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
2498 			spectral->spectral_data_len =
2499 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
2500 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
2501 			/* only valid in 20 mode */
2502 			spectral->spectral_max_index_offset = -1;
2503 			spectral->spectral_lower_max_index_offset =
2504 			    spectral->spectral_fft_len + 2;
2505 			spectral->spectral_upper_max_index_offset =
2506 			    spectral->spectral_fft_len + 5;
2507 			spectral->sc_spectral_20_40_mode = 1;
2508 
2509 			/*
2510 			 * Initialize classifier params to be sent to user
2511 			 * space classifier
2512 			 */
2513 			if (extension_channel < current_channel) {
2514 				spectral->classifier_params.lower_chan_in_mhz =
2515 				    extension_channel;
2516 				spectral->classifier_params.upper_chan_in_mhz =
2517 				    current_channel;
2518 			} else {
2519 				spectral->classifier_params.lower_chan_in_mhz =
2520 				    current_channel;
2521 				spectral->classifier_params.upper_chan_in_mhz =
2522 				    extension_channel;
2523 			}
2524 		}
2525 	}
2526 
2527 	spectral->send_single_packet = 0;
2528 	spectral->classifier_params.spectral_20_40_mode =
2529 	    spectral->sc_spectral_20_40_mode;
2530 	spectral->classifier_params.spectral_dc_index =
2531 	    spectral->spectral_dc_index;
2532 	spectral->spectral_sent_msg = 0;
2533 	spectral->classify_scan = 0;
2534 	spectral->num_spectral_data = 0;
2535 
2536 	if (!p_sops->is_spectral_active(spectral)) {
2537 		p_sops->configure_spectral(spectral, spectral_params);
2538 		p_sops->start_spectral_scan(spectral);
2539 		spectral->timestamp_war_offset = 0;
2540 		spectral->last_fft_timestamp = 0;
2541 	} else {
2542 	}
2543 
2544 	/* get current spectral configuration */
2545 	p_sops->get_spectral_config(spectral, &spectral->params);
2546 
2547 	target_if_init_upper_lower_flags(spectral);
2548 
2549 	return 0;
2550 }
2551 
2552 /**
2553  * target_if_start_spectral_scan() - Start spectral scan
2554  * @pdev: Pointer to pdev object
2555  *
2556  * API to start spectral scan
2557  *
2558  * Return: 0 in case of success, -1 on failure
2559  */
2560 int
2561 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev)
2562 {
2563 	struct target_if_spectral_ops *p_sops = NULL;
2564 	struct target_if_spectral *spectral = NULL;
2565 
2566 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2567 	if (!spectral) {
2568 		spectral_err("SPECTRAL : Spectral LMAC object is NUll");
2569 		return -EPERM;
2570 	}
2571 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2572 
2573 	if (!spectral->params_valid) {
2574 		target_if_spectral_info_read(spectral,
2575 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
2576 					     &spectral->params,
2577 					     sizeof(spectral->params));
2578 		spectral->params_valid = true;
2579 	}
2580 
2581 	qdf_spin_lock(&spectral->spectral_lock);
2582 	target_if_spectral_scan_enable_params(spectral, &spectral->params);
2583 	qdf_spin_unlock(&spectral->spectral_lock);
2584 
2585 	return 0;
2586 }
2587 
2588 void
2589 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev)
2590 {
2591 	struct target_if_spectral_ops *p_sops = NULL;
2592 	struct target_if_spectral *spectral = NULL;
2593 
2594 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2595 	if (!spectral) {
2596 		spectral_err("SPECTRAL : Spectral LMAC object is NUll ");
2597 		return;
2598 	}
2599 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2600 
2601 	qdf_spin_lock(&spectral->spectral_lock);
2602 	p_sops->stop_spectral_scan(spectral);
2603 	if (spectral->classify_scan) {
2604 		/* TODO : Check if this logic is necessary */
2605 		spectral->detects_control_channel = 0;
2606 		spectral->detects_extension_channel = 0;
2607 		spectral->detects_above_dc = 0;
2608 		spectral->detects_below_dc = 0;
2609 		spectral->classify_scan = 0;
2610 	}
2611 
2612 	spectral->send_single_packet = 0;
2613 	spectral->sc_spectral_scan = 0;
2614 
2615 	qdf_spin_unlock(&spectral->spectral_lock);
2616 }
2617 
2618 /**
2619  * target_if_is_spectral_active() - Get whether Spectral is active
2620  * @pdev: Pointer to pdev object
2621  *
2622  * API to get whether Spectral is active
2623  *
2624  * Return: True if Spectral is active, false if Spectral is not active
2625  */
2626 bool
2627 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev)
2628 {
2629 	struct target_if_spectral *spectral = NULL;
2630 	struct target_if_spectral_ops *p_sops = NULL;
2631 
2632 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2633 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2634 	return p_sops->is_spectral_active(spectral);
2635 }
2636 
2637 /**
2638  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
2639  * @pdev: Pointer to pdev object
2640  *
2641  * API to get whether Spectral is enabled
2642  *
2643  * Return: True if Spectral is enabled, false if Spectral is not enabled
2644  */
2645 bool
2646 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev)
2647 {
2648 	struct target_if_spectral *spectral = NULL;
2649 	struct target_if_spectral_ops *p_sops = NULL;
2650 
2651 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2652 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2653 	return p_sops->is_spectral_enabled(spectral);
2654 }
2655 
2656 /**
2657  * target_if_set_debug_level() - Set debug level for Spectral
2658  * @pdev: Pointer to pdev object
2659  * @debug_level: Debug level
2660  *
2661  * API to set the debug level for Spectral
2662  *
2663  * Return: 0 in case of success
2664  */
2665 int
2666 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
2667 {
2668 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
2669 	return 0;
2670 }
2671 
2672 /**
2673  * target_if_get_debug_level() - Get debug level for Spectral
2674  * @pdev: Pointer to pdev object
2675  *
2676  * API to get the debug level for Spectral
2677  *
2678  * Return: Current debug level
2679  */
2680 uint32_t
2681 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
2682 {
2683 	return spectral_debug_level;
2684 }
2685 
2686 /**
2687  * target_if_get_spectral_capinfo() - Get Spectral capability information
2688  * @pdev: Pointer to pdev object
2689  * @outdata: Buffer into which data should be copied
2690  *
2691  * API to get the spectral capability information
2692  *
2693  * Return: void
2694  */
2695 void
2696 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev, void *outdata)
2697 {
2698 	struct target_if_spectral *spectral = NULL;
2699 
2700 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2701 	qdf_mem_copy(outdata, &spectral->capability,
2702 		     sizeof(struct spectral_caps));
2703 }
2704 
2705 /**
2706  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
2707  * @pdev:  Pointer to pdev object
2708  * @outdata: Buffer into which data should be copied
2709  *
2710  * API to get the spectral diagnostic statistics
2711  *
2712  * Return: void
2713  */
2714 void
2715 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev, void *outdata)
2716 {
2717 	struct target_if_spectral *spectral = NULL;
2718 
2719 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2720 	qdf_mem_copy(outdata, &spectral->diag_stats,
2721 		     sizeof(struct spectral_diag_stats));
2722 }
2723 
2724 /**
2725  * target_if_register_wmi_spectral_cmd_ops() - Register wmi_spectral_cmd_ops
2726  * @cmd_ops: Pointer to the structure having wmi_spectral_cmd function pointers
2727  * @pdev: Pointer to pdev object
2728  *
2729  * API for register wmi_spectral_cmd_ops in spectral internal data structure
2730  *
2731  * Return: void
2732  */
2733 void
2734 target_if_register_wmi_spectral_cmd_ops(struct wlan_objmgr_pdev *pdev,
2735 					struct wmi_spectral_cmd_ops *cmd_ops)
2736 {
2737 	struct target_if_spectral *spectral = NULL;
2738 
2739 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2740 	spectral->param_wmi_cmd_ops.wmi_spectral_configure_cmd_send =
2741 	    cmd_ops->wmi_spectral_configure_cmd_send;
2742 	spectral->param_wmi_cmd_ops.wmi_spectral_enable_cmd_send =
2743 	    cmd_ops->wmi_spectral_enable_cmd_send;
2744 }
2745 
2746 /**
2747  * target_if_register_netlink_cb() - Register Netlink callbacks
2748  * @pdev: Pointer to pdev object
2749  * @nl_cb: Netlink callbacks to register
2750  *
2751  * Return: void
2752  */
2753 static void
2754 target_if_register_netlink_cb(
2755 	struct wlan_objmgr_pdev *pdev,
2756 	struct spectral_nl_cb *nl_cb)
2757 {
2758 	struct target_if_spectral *spectral = NULL;
2759 
2760 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2761 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
2762 
2763 	if (spectral->use_nl_bcast)
2764 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
2765 	else
2766 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
2767 }
2768 
2769 /**
2770  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
2771  * Netlink messages to the application layer
2772  * @pdev: Pointer to pdev object
2773  *
2774  * Return: true for broadcast, false for unicast
2775  */
2776 static bool
2777 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
2778 {
2779 	struct target_if_spectral *spectral = NULL;
2780 
2781 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2782 	return spectral->use_nl_bcast;
2783 }
2784 
2785 /**
2786  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
2787  * @pdev: Pointer to pdev object
2788  *
2789  * Return: void
2790  */
2791 static void
2792 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
2793 {
2794 	struct target_if_spectral *spectral = NULL;
2795 
2796 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2797 	if (!spectral) {
2798 		spectral_err("SPECTRAL : Module doesn't exist");
2799 		return;
2800 	}
2801 
2802 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
2803 }
2804 
2805 static int
2806 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
2807 				  void *payload)
2808 {
2809 	struct target_if_spectral *spectral = NULL;
2810 	struct target_if_spectral_ops *p_sops = NULL;
2811 
2812 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2813 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2814 
2815 	return p_sops->process_spectral_report(pdev, payload);
2816 }
2817 
2818 void
2819 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
2820 {
2821 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
2822 	    target_if_pdev_spectral_init;
2823 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
2824 	    target_if_pdev_spectral_deinit;
2825 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
2826 	    target_if_set_spectral_config;
2827 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
2828 	    target_if_get_spectral_config;
2829 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
2830 	    target_if_start_spectral_scan;
2831 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
2832 	    target_if_stop_spectral_scan;
2833 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
2834 	    target_if_is_spectral_active;
2835 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
2836 	    target_if_is_spectral_enabled;
2837 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
2838 	    target_if_set_debug_level;
2839 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
2840 	    target_if_get_debug_level;
2841 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
2842 	    target_if_get_spectral_capinfo;
2843 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
2844 	    target_if_get_spectral_diagstats;
2845 	tx_ops->sptrl_tx_ops.sptrlto_register_wmi_spectral_cmd_ops =
2846 	    target_if_register_wmi_spectral_cmd_ops;
2847 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
2848 	    target_if_register_netlink_cb;
2849 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
2850 	    target_if_use_nl_bcast;
2851 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
2852 	    target_if_deregister_netlink_cb;
2853 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
2854 		target_if_process_spectral_report;
2855 }
2856 qdf_export_symbol(target_if_sptrl_register_tx_ops);
2857 
2858 void
2859 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
2860 				       uint16_t cw_int, uint32_t dcs_enabled)
2861 {
2862 	struct spectral_samp_msg *msg = NULL;
2863 	struct target_if_spectral_ops *p_sops = NULL;
2864 	struct target_if_spectral *spectral = NULL;
2865 
2866 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2867 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_nbuff(
2868 			spectral->pdev_obj);
2869 
2870 	if (msg) {
2871 		msg->int_type = cw_int ?
2872 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
2873 		msg->dcs_enabled = dcs_enabled;
2874 		msg->signature = SPECTRAL_SIGNATURE;
2875 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2876 		p_sops->get_mac_address(spectral, msg->macaddr);
2877 		if (spectral->send_phy_data(pdev) == 0)
2878 			spectral->spectral_sent_msg++;
2879 	}
2880 }
2881 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
2882