xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral.c (revision 1f55ed1a9f5050d8da228aa8dd3fff7c0242aa71)
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_set(&sparam, sizeof(sparam), 0);
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_set(&param, sizeof(param), 0);
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: None
1271  */
1272 void
1273 target_if_init_spectral_capability(struct target_if_spectral *spectral)
1274 {
1275 	struct spectral_caps *pcap = &spectral->capability;
1276 
1277 	/* XXX : Workaround: Set Spectral capability */
1278 	pcap = &spectral->capability;
1279 	pcap->phydiag_cap = 1;
1280 	pcap->radar_cap = 1;
1281 	pcap->spectral_cap = 1;
1282 	pcap->advncd_spectral_cap = 1;
1283 	pcap->hw_gen = spectral->spectral_gen;
1284 }
1285 
1286 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1287 /**
1288  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1289  * internal operations with functions related to spectral simulation
1290  * @p_sops: spectral low level ops table
1291  *
1292  * Initialize spectral target_if internal operations with functions
1293  * related to spectral simulation
1294  *
1295  * Return: None
1296  */
1297 static void
1298 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1299 {
1300 	/*
1301 	 * Spectral simulation is currently intended for platform transitions
1302 	 * where underlying HW support may not be available for some time.
1303 	 * Hence, we do not currently provide a runtime switch to turn the
1304 	 * simulation on or off.
1305 	 * In case of future requirements where runtime switches are required,
1306 	 * this can be added. But it is suggested to use application layer
1307 	 * simulation as far as possible in such cases, since the main
1308 	 * use of record and replay of samples would concern higher
1309 	 * level sample processing rather than lower level delivery.
1310 	 */
1311 	p_sops->is_spectral_enabled = target_if_spectral_sops_sim_is_enabled;
1312 	p_sops->is_spectral_active = target_if_spectral_sops_sim_is_active;
1313 	p_sops->start_spectral_scan = target_if_spectral_sops_sim_start_scan;
1314 	p_sops->stop_spectral_scan = target_if_spectral_sops_sim_stop_scan;
1315 	p_sops->configure_spectral =
1316 		target_if_spectral_sops_sim_configure_params;
1317 	p_sops->get_spectral_config = target_if_spectral_sops_sim_get_params;
1318 }
1319 
1320 #else
1321 /**
1322  * target_if_init_spectral_simulation_ops() - Initialize spectral target_if
1323  * internal operations
1324  * @p_sops: spectral low level ops table
1325  *
1326  * Return: None
1327  */
1328 static void
1329 target_if_init_spectral_simulation_ops(struct target_if_spectral_ops *p_sops)
1330 {
1331 	p_sops->is_spectral_enabled = target_if_sops_is_spectral_enabled;
1332 	p_sops->is_spectral_active = target_if_sops_is_spectral_active;
1333 	p_sops->start_spectral_scan = target_if_sops_start_spectral_scan;
1334 	p_sops->stop_spectral_scan = target_if_sops_stop_spectral_scan;
1335 	p_sops->configure_spectral = target_if_spectral_sops_configure_params;
1336 	p_sops->get_spectral_config = target_if_spectral_sops_get_params;
1337 }
1338 #endif
1339 
1340 /**
1341  * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
1342  * operations common to all Spectral chipset generations
1343  *
1344  * Initializes target_if_spectral_ops common to all chipset generations
1345  *
1346  * Return: None
1347  */
1348 static void
1349 target_if_init_spectral_ops_common(void)
1350 {
1351 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1352 
1353 	p_sops->get_tsf64 = target_if_spectral_get_tsf64;
1354 	p_sops->get_capability = target_if_spectral_get_capability;
1355 	p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
1356 	p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
1357 
1358 	target_if_init_spectral_simulation_ops(p_sops);
1359 
1360 	p_sops->get_extension_channel =
1361 	    target_if_spectral_get_extension_channel;
1362 	p_sops->get_ctl_noisefloor = target_if_spectral_get_ctl_noisefloor;
1363 	p_sops->get_ext_noisefloor = target_if_spectral_get_ext_noisefloor;
1364 	p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
1365 	p_sops->get_mac_address = target_if_spectral_get_macaddr;
1366 	p_sops->get_current_channel = target_if_spectral_get_current_channel;
1367 	p_sops->reset_hw = target_if_spectral_reset_hw;
1368 	p_sops->get_chain_noise_floor =
1369 	    target_if_spectral_get_chain_noise_floor;
1370 }
1371 
1372 /**
1373  * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
1374  * operations specific to Spectral chipset generation 2.
1375  *
1376  * Initializes target_if_spectral_ops specific to Spectral chipset generation 2.
1377  *
1378  * Return: None
1379  */
1380 static void
1381 target_if_init_spectral_ops_gen2(void)
1382 {
1383 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1384 
1385 	p_sops->spectral_process_phyerr = target_if_process_phyerr_gen2;
1386 }
1387 
1388 /**
1389  * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
1390  * operations specific to Spectral chipset generation 3.
1391  *
1392  * Initializes target_if_spectral_ops specific to Spectral chipset generation 3.
1393  *
1394  * Return: None
1395  */
1396 static void
1397 target_if_init_spectral_ops_gen3(void)
1398 {
1399 	struct target_if_spectral_ops *p_sops = &spectral_ops;
1400 
1401 	p_sops->process_spectral_report =
1402 			target_if_spectral_process_report_gen3;
1403 	return;
1404 }
1405 
1406 /**
1407  * target_if_init_spectral_ops() - Initialize target_if internal Spectral
1408  * operations.
1409  * @spectral: Pointer to Spectral target_if internal private data
1410  *
1411  * Initializes all function pointers in target_if_spectral_ops for
1412  * all generations
1413  *
1414  * Return: None
1415  */
1416 static void
1417 target_if_init_spectral_ops(struct target_if_spectral *spectral)
1418 {
1419 	target_if_init_spectral_ops_common();
1420 	if (spectral->spectral_gen == SPECTRAL_GEN2)
1421 		target_if_init_spectral_ops_gen2();
1422 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
1423 		target_if_init_spectral_ops_gen3();
1424 	else
1425 		spectral_err("Invalid Spectral generation");
1426 }
1427 
1428 /*
1429  * Dummy Functions:
1430  * These functions are initially registered to avoid any crashes due to
1431  * invocation of spectral functions before they are registered.
1432  */
1433 
1434 static uint64_t
1435 null_get_tsf64(void *arg)
1436 {
1437 	spectral_ops_not_registered("get_tsf64");
1438 	return 0;
1439 }
1440 
1441 static uint32_t
1442 null_get_capability(void *arg, enum spectral_capability_type type)
1443 {
1444 	/*
1445 	 * TODO : We should have conditional compilation to get the capability
1446 	 *      : We have not yet attahced ATH layer here, so there is no
1447 	 *      : way to check the HAL capbalities
1448 	 */
1449 	spectral_ops_not_registered("get_capability");
1450 
1451 	/* TODO : For the time being, we are returning TRUE */
1452 	return true;
1453 }
1454 
1455 static uint32_t
1456 null_set_rxfilter(void *arg, int rxfilter)
1457 {
1458 	spectral_ops_not_registered("set_rxfilter");
1459 	return 1;
1460 }
1461 
1462 static uint32_t
1463 null_get_rxfilter(void *arg)
1464 {
1465 	spectral_ops_not_registered("get_rxfilter");
1466 	return 0;
1467 }
1468 
1469 static uint32_t
1470 null_is_spectral_active(void *arg)
1471 {
1472 	spectral_ops_not_registered("is_spectral_active");
1473 	return 1;
1474 }
1475 
1476 static uint32_t
1477 null_is_spectral_enabled(void *arg)
1478 {
1479 	spectral_ops_not_registered("is_spectral_enabled");
1480 	return 1;
1481 }
1482 
1483 static uint32_t
1484 null_start_spectral_scan(void *arg)
1485 {
1486 	spectral_ops_not_registered("start_spectral_scan");
1487 	return 1;
1488 }
1489 
1490 static uint32_t
1491 null_stop_spectral_scan(void *arg)
1492 {
1493 	spectral_ops_not_registered("stop_spectral_scan");
1494 	return 1;
1495 }
1496 
1497 static uint32_t
1498 null_get_extension_channel(void *arg)
1499 {
1500 	spectral_ops_not_registered("get_extension_channel");
1501 	return 1;
1502 }
1503 
1504 static int8_t
1505 null_get_ctl_noisefloor(void *arg)
1506 {
1507 	spectral_ops_not_registered("get_ctl_noisefloor");
1508 	return 1;
1509 }
1510 
1511 static int8_t
1512 null_get_ext_noisefloor(void *arg)
1513 {
1514 	spectral_ops_not_registered("get_ext_noisefloor");
1515 	return 0;
1516 }
1517 
1518 static uint32_t
1519 null_configure_spectral(void *arg, struct spectral_config *params)
1520 {
1521 	spectral_ops_not_registered("configure_spectral");
1522 	return 0;
1523 }
1524 
1525 static uint32_t
1526 null_get_spectral_config(void *arg, struct spectral_config *params)
1527 {
1528 	spectral_ops_not_registered("get_spectral_config");
1529 	return 0;
1530 }
1531 
1532 static uint32_t
1533 null_get_ent_spectral_mask(void *arg)
1534 {
1535 	spectral_ops_not_registered("get_ent_spectral_mask");
1536 	return 0;
1537 }
1538 
1539 static uint32_t
1540 null_get_mac_address(void *arg, char *addr)
1541 {
1542 	spectral_ops_not_registered("get_mac_address");
1543 	return 0;
1544 }
1545 
1546 static uint32_t
1547 null_get_current_channel(void *arg)
1548 {
1549 	spectral_ops_not_registered("get_current_channel");
1550 	return 0;
1551 }
1552 
1553 static uint32_t
1554 null_reset_hw(void *arg)
1555 {
1556 	spectral_ops_not_registered("get_current_channel");
1557 	return 0;
1558 }
1559 
1560 static uint32_t
1561 null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
1562 {
1563 	spectral_ops_not_registered("get_chain_noise_floor");
1564 	return 0;
1565 }
1566 
1567 static int
1568 null_spectral_process_phyerr(struct target_if_spectral *spectral,
1569 			     uint8_t *data,
1570 			     uint32_t datalen,
1571 			     struct target_if_spectral_rfqual_info *p_rfqual,
1572 			     struct target_if_spectral_chan_info *p_chaninfo,
1573 			     uint64_t tsf64,
1574 			     struct target_if_spectral_acs_stats *acs_stats)
1575 {
1576 	spectral_ops_not_registered("spectral_process_phyerr");
1577 	return 0;
1578 }
1579 
1580 static int
1581 null_process_spectral_report(struct wlan_objmgr_pdev *pdev,
1582 			     void *payload)
1583 {
1584 	spectral_ops_not_registered("process_spectral_report");
1585 	return 0;
1586 }
1587 /**
1588  * target_if_spectral_init_dummy_function_table() -
1589  * Initialize target_if internal
1590  * Spectral operations to dummy functions
1591  * @ps: Pointer to Spectral target_if internal private data
1592  *
1593  * Initialize all the function pointers in target_if_spectral_ops with
1594  * dummy functions.
1595  *
1596  * Return: None
1597  */
1598 static void
1599 target_if_spectral_init_dummy_function_table(struct target_if_spectral *ps)
1600 {
1601 	struct target_if_spectral_ops *p_sops = GET_TARGET_IF_SPECTRAL_OPS(ps);
1602 
1603 	p_sops->get_tsf64 = null_get_tsf64;
1604 	p_sops->get_capability = null_get_capability;
1605 	p_sops->set_rxfilter = null_set_rxfilter;
1606 	p_sops->get_rxfilter = null_get_rxfilter;
1607 	p_sops->is_spectral_enabled = null_is_spectral_enabled;
1608 	p_sops->is_spectral_active = null_is_spectral_active;
1609 	p_sops->start_spectral_scan = null_start_spectral_scan;
1610 	p_sops->stop_spectral_scan = null_stop_spectral_scan;
1611 	p_sops->get_extension_channel = null_get_extension_channel;
1612 	p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
1613 	p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
1614 	p_sops->configure_spectral = null_configure_spectral;
1615 	p_sops->get_spectral_config = null_get_spectral_config;
1616 	p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
1617 	p_sops->get_mac_address = null_get_mac_address;
1618 	p_sops->get_current_channel = null_get_current_channel;
1619 	p_sops->reset_hw = null_reset_hw;
1620 	p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
1621 	p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
1622 	p_sops->process_spectral_report = null_process_spectral_report;
1623 }
1624 
1625 /**
1626  * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
1627  * operations
1628  * @spectral: Pointer to Spectral target_if internal private data
1629  * @p: Pointer to Spectral function table
1630  *
1631  * Return: None
1632  */
1633 static void
1634 target_if_spectral_register_funcs(struct target_if_spectral *spectral,
1635 				  struct target_if_spectral_ops *p)
1636 {
1637 	struct target_if_spectral_ops *p_sops =
1638 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1639 
1640 	p_sops->get_tsf64 = p->get_tsf64;
1641 	p_sops->get_capability = p->get_capability;
1642 	p_sops->set_rxfilter = p->set_rxfilter;
1643 	p_sops->get_rxfilter = p->get_rxfilter;
1644 	p_sops->is_spectral_enabled = p->is_spectral_enabled;
1645 	p_sops->is_spectral_active = p->is_spectral_active;
1646 	p_sops->start_spectral_scan = p->start_spectral_scan;
1647 	p_sops->stop_spectral_scan = p->stop_spectral_scan;
1648 	p_sops->get_extension_channel = p->get_extension_channel;
1649 	p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor;
1650 	p_sops->get_ext_noisefloor = p->get_ext_noisefloor;
1651 	p_sops->configure_spectral = p->configure_spectral;
1652 	p_sops->get_spectral_config = p->get_spectral_config;
1653 	p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask;
1654 	p_sops->get_mac_address = p->get_mac_address;
1655 	p_sops->get_current_channel = p->get_current_channel;
1656 	p_sops->reset_hw = p->reset_hw;
1657 	p_sops->get_chain_noise_floor = p->get_chain_noise_floor;
1658 	p_sops->spectral_process_phyerr = p->spectral_process_phyerr;
1659 	p_sops->process_spectral_report = p->process_spectral_report;
1660 }
1661 
1662 /**
1663  * target_if_spectral_clear_stats() - Clear Spectral stats
1664  * @spectral: Pointer to Spectral target_if internal private data
1665  *
1666  * Function to clear spectral stats
1667  *
1668  * Return: None
1669  */
1670 static void
1671 target_if_spectral_clear_stats(struct target_if_spectral *spectral)
1672 {
1673 	struct target_if_spectral_ops *p_sops =
1674 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1675 
1676 	qdf_mem_zero(&spectral->spectral_stats,
1677 		     sizeof(struct target_if_spectral_stats));
1678 	spectral->spectral_stats.last_reset_tstamp =
1679 	    p_sops->get_tsf64(spectral);
1680 }
1681 
1682 /**
1683  * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
1684  * @spectral: Pointer to Spectral target_if internal private data
1685  *
1686  * Function to check whether hardware supports spectral
1687  *
1688  * Return: True if HW supports Spectral, false if HW does not support Spectral
1689  */
1690 static int
1691 target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
1692 {
1693 	struct target_if_spectral_ops *p_sops = NULL;
1694 	struct spectral_caps *pcap = NULL;
1695 	int is_spectral_supported = true;
1696 
1697 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1698 	pcap = &spectral->capability;
1699 
1700 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
1701 		is_spectral_supported = false;
1702 		spectral_info("SPECTRAL : No PHYDIAG support");
1703 		return is_spectral_supported;
1704 	}
1705 	pcap->phydiag_cap = 1;
1706 
1707 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
1708 		is_spectral_supported = false;
1709 		spectral_info("SPECTRAL : No RADAR support");
1710 		return is_spectral_supported;
1711 	}
1712 	pcap->radar_cap = 1;
1713 
1714 	if (p_sops->get_capability(spectral,
1715 				   SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
1716 		is_spectral_supported = false;
1717 		spectral_info("SPECTRAL : No SPECTRAL SUPPORT");
1718 		return is_spectral_supported;
1719 	}
1720 	pcap->spectral_cap = 1;
1721 
1722 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
1723 	    == false) {
1724 		spectral_info("SPECTRAL : No ADVANCED SPECTRAL SUPPORT");
1725 	} else {
1726 		pcap->advncd_spectral_cap = 1;
1727 	}
1728 
1729 	return is_spectral_supported;
1730 }
1731 
1732 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1733 /**
1734  * target_if_spectral_detach_simulation() - De-initialize Spectral
1735  * Simulation functionality
1736  * @spectral: Pointer to Spectral target_if internal private data
1737  *
1738  * Function to de-initialize Spectral Simulation functionality
1739  *
1740  * Return: None
1741  */
1742 static void
1743 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
1744 {
1745 	target_if_spectral_sim_detach(spectral);
1746 }
1747 
1748 #else
1749 static void
1750 target_if_spectral_detach_simulation(struct target_if_spectral *spectral)
1751 {
1752 }
1753 #endif
1754 
1755 /**
1756  * target_if_spectral_detach() - De-initialize target_if Spectral
1757  * @pdev: Pointer to pdev object
1758  *
1759  * Function to detach target_if spectral
1760  *
1761  * Return: None
1762  */
1763 static void
1764 target_if_spectral_detach(struct target_if_spectral *spectral)
1765 {
1766 	spectral_info("spectral detach");
1767 
1768 	if (spectral) {
1769 		if (spectral->spectral_gen == SPECTRAL_GEN3)
1770 			deinit_160mhz_delivery_state_machine(spectral);
1771 		qdf_spinlock_destroy(&spectral->param_info.osps_lock);
1772 
1773 		target_if_spectral_detach_simulation(spectral);
1774 
1775 		qdf_spinlock_destroy(&spectral->spectral_lock);
1776 		qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
1777 
1778 		qdf_mem_free(spectral);
1779 		spectral = NULL;
1780 	}
1781 }
1782 
1783 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
1784 /**
1785  * target_if_spectral_attach_simulation() - Initialize Spectral Simulation
1786  * functionality
1787  * @spectral: Pointer to Spectral target_if internal private data
1788  *
1789  * Function to initialize spectral simulation functionality
1790  *
1791  * Return: 0 on success, negative error code on failure
1792  */
1793 static int
1794 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
1795 {
1796 	if (target_if_spectral_sim_attach(spectral)) {
1797 		qdf_mem_free(spectral);
1798 		return -EPERM;
1799 	}
1800 	return 0;
1801 }
1802 
1803 #else
1804 static int
1805 target_if_spectral_attach_simulation(struct target_if_spectral *spectral)
1806 {
1807 	return 0;
1808 }
1809 #endif
1810 
1811 /**
1812  * target_if_pdev_spectral_init() - Initialize target_if Spectral
1813  * functionality for the given pdev
1814  * @pdev: Pointer to pdev object
1815  *
1816  * Function to initialize pointer to spectral target_if internal private data
1817  *
1818  * Return: On success, pointer to Spectral target_if internal private data, on
1819  * failure, NULL
1820  */
1821 void *
1822 target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
1823 {
1824 	struct target_if_spectral_ops *p_sops = NULL;
1825 	struct target_if_spectral *spectral = NULL;
1826 	uint32_t target_type;
1827 	uint32_t target_revision;
1828 	struct wlan_objmgr_psoc *psoc;
1829 	struct wlan_lmac_if_target_tx_ops *tx_ops;
1830 
1831 	if (!pdev) {
1832 		spectral_err("SPECTRAL: pdev is NULL!");
1833 		return NULL;
1834 	}
1835 	spectral = (struct target_if_spectral *)qdf_mem_malloc(
1836 			sizeof(struct target_if_spectral));
1837 	if (!spectral) {
1838 		spectral_err("SPECTRAL : Memory allocation failed");
1839 		return spectral;
1840 	}
1841 	qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
1842 	/* Store pdev in Spectral */
1843 	spectral->pdev_obj = pdev;
1844 
1845 	psoc = wlan_pdev_get_psoc(pdev);
1846 
1847 	tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops;
1848 
1849 	if (tx_ops->tgt_get_tgt_type) {
1850 		target_type = tx_ops->tgt_get_tgt_type(psoc);
1851 	} else {
1852 		qdf_mem_free(spectral);
1853 		return NULL;
1854 	}
1855 
1856 	if (tx_ops->tgt_get_tgt_revision) {
1857 		target_revision = tx_ops->tgt_get_tgt_revision(psoc);
1858 	} else {
1859 		qdf_mem_free(spectral);
1860 		return NULL;
1861 	}
1862 
1863 	/* init the function ptr table */
1864 	target_if_spectral_init_dummy_function_table(spectral);
1865 
1866 	/* get spectral function table */
1867 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1868 	/* TODO : Should this be called here of after ath_attach ? */
1869 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
1870 		spectral_info("HAL_CAP_PHYDIAG : Capable");
1871 
1872 	/* TODO: Need to fix the capablity check for RADAR */
1873 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
1874 		spectral_info("HAL_CAP_RADAR   : Capable");
1875 
1876 	/* TODO : Need to fix the capablity check for SPECTRAL */
1877 	/* TODO : Should this be called here of after ath_attach ? */
1878 	if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
1879 		spectral_info("HAL_CAP_SPECTRAL_SCAN : Capable");
1880 
1881 	qdf_spinlock_create(&spectral->spectral_lock);
1882 	qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
1883 	target_if_spectral_clear_stats(spectral);
1884 
1885 	if (target_type == TARGET_TYPE_QCA8074V2 ||
1886 	    target_type == TARGET_TYPE_QCA6018)
1887 		spectral->fftbin_size_war =
1888 			SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE;
1889 	else if (target_type == TARGET_TYPE_QCA8074)
1890 		spectral->fftbin_size_war =
1891 			SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE;
1892 	else
1893 		spectral->fftbin_size_war = SPECTRAL_FFTBIN_SIZE_NO_WAR;
1894 
1895 	if (target_type == TARGET_TYPE_QCA8074 ||
1896 	    target_type == TARGET_TYPE_QCA8074V2 ||
1897 	    target_type == TARGET_TYPE_QCA6018) {
1898 		spectral->inband_fftbin_size_adj = 1;
1899 		spectral->null_fftbin_adj = 1;
1900 	} else {
1901 		spectral->inband_fftbin_size_adj = 0;
1902 		spectral->null_fftbin_adj = 0;
1903 	}
1904 	spectral->last_fft_timestamp = 0;
1905 	spectral->timestamp_war_offset = 0;
1906 
1907 	if ((target_type == TARGET_TYPE_QCA8074) ||
1908 	    (target_type == TARGET_TYPE_QCA8074V2) ||
1909 	    (target_type == TARGET_TYPE_QCA6018) ||
1910 	    (target_type == TARGET_TYPE_QCA6290)) {
1911 		spectral->spectral_gen = SPECTRAL_GEN3;
1912 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
1913 		spectral->tag_sscan_summary_exp =
1914 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
1915 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
1916 		spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
1917 	} else {
1918 		spectral->spectral_gen = SPECTRAL_GEN2;
1919 		spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
1920 		spectral->tag_sscan_summary_exp =
1921 		    TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
1922 		spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
1923 		spectral->tlvhdr_size = sizeof(struct spectral_phyerr_tlv_gen2);
1924 	}
1925 
1926 	spectral->params_valid = false;
1927 	/* Init spectral capability */
1928 	target_if_init_spectral_capability(spectral);
1929 	if (target_if_spectral_attach_simulation(spectral) < 0)
1930 		return NULL;
1931 
1932 	target_if_init_spectral_ops(spectral);
1933 
1934 	qdf_spinlock_create(&spectral->param_info.osps_lock);
1935 	spectral->param_info.osps_cache.osc_is_valid = 0;
1936 
1937 	target_if_spectral_register_funcs(spectral, &spectral_ops);
1938 
1939 	if (target_if_spectral_check_hw_capability(spectral) == false) {
1940 		target_if_spectral_detach(spectral);
1941 		spectral = NULL;
1942 	} else {
1943 		/*
1944 		 * TODO: Once the driver architecture transitions to chipset
1945 		 * versioning based checks, reflect this here.
1946 		 */
1947 		spectral->is_160_format = false;
1948 		spectral->is_lb_edge_extrabins_format = false;
1949 		spectral->is_rb_edge_extrabins_format = false;
1950 
1951 		if (target_type == TARGET_TYPE_QCA9984 ||
1952 		    target_type == TARGET_TYPE_QCA9888) {
1953 			spectral->is_160_format = true;
1954 			spectral->is_lb_edge_extrabins_format = true;
1955 			spectral->is_rb_edge_extrabins_format = true;
1956 		} else  if ((target_type == TARGET_TYPE_AR900B) &&
1957 			    (target_revision == AR900B_REV_2)) {
1958 			spectral->is_rb_edge_extrabins_format = true;
1959 		}
1960 
1961 		if (target_type == TARGET_TYPE_QCA9984 ||
1962 		    target_type == TARGET_TYPE_QCA9888)
1963 			spectral->is_sec80_rssi_war_required = true;
1964 
1965 		spectral->use_nl_bcast = SPECTRAL_USE_NL_BCAST;
1966 
1967 		if (spectral->spectral_gen == SPECTRAL_GEN3)
1968 			init_160mhz_delivery_state_machine(spectral);
1969 	}
1970 
1971 	return spectral;
1972 }
1973 
1974 /**
1975  * target_if_pdev_spectral_deinit() - De-initialize target_if Spectral
1976  * functionality for the given pdev
1977  * @pdev: Pointer to pdev object
1978  *
1979  * Function to de-initialize pointer to spectral target_if internal private data
1980  *
1981  * Return: None
1982  */
1983 void
1984 target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
1985 {
1986 	struct target_if_spectral *spectral = NULL;
1987 
1988 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
1989 	if (!spectral) {
1990 		spectral_err("SPECTRAL : Module doesn't exist");
1991 		return;
1992 	}
1993 	target_if_spectral_detach(spectral);
1994 
1995 	return;
1996 }
1997 
1998 /**
1999  * target_if_set_spectral_config() - Set spectral config
2000  * @pdev:       Pointer to pdev object
2001  * @threshtype: config type
2002  * @value:      config value
2003  *
2004  * API to set spectral configurations
2005  *
2006  * Return: 0 on success else failure
2007  */
2008 int
2009 target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
2010 			      const uint32_t threshtype, const uint32_t value)
2011 {
2012 	struct spectral_config params;
2013 	struct target_if_spectral_ops *p_sops = NULL;
2014 	struct target_if_spectral *spectral = NULL;
2015 
2016 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2017 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2018 	if (!spectral) {
2019 		spectral_err("spectral object is NULL");
2020 		return -EPERM;
2021 	}
2022 
2023 	if (!spectral->params_valid) {
2024 		target_if_spectral_info_read(spectral,
2025 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
2026 					     &spectral->params,
2027 					     sizeof(spectral->params));
2028 		spectral->params_valid = true;
2029 	}
2030 
2031 	switch (threshtype) {
2032 	case SPECTRAL_PARAM_FFT_PERIOD:
2033 		spectral->params.ss_fft_period = value;
2034 		break;
2035 	case SPECTRAL_PARAM_SCAN_PERIOD:
2036 		spectral->params.ss_period = value;
2037 		break;
2038 	case SPECTRAL_PARAM_SCAN_COUNT:
2039 		spectral->params.ss_count = value;
2040 		break;
2041 	case SPECTRAL_PARAM_SHORT_REPORT:
2042 		spectral->params.ss_short_report = (!!value) ? true : false;
2043 		break;
2044 	case SPECTRAL_PARAM_SPECT_PRI:
2045 		spectral->params.ss_spectral_pri = (!!value) ? true : false;
2046 		break;
2047 	case SPECTRAL_PARAM_FFT_SIZE:
2048 		spectral->params.ss_fft_size = value;
2049 		break;
2050 	case SPECTRAL_PARAM_GC_ENA:
2051 		spectral->params.ss_gc_ena = !!value;
2052 		break;
2053 	case SPECTRAL_PARAM_RESTART_ENA:
2054 		spectral->params.ss_restart_ena = !!value;
2055 		break;
2056 	case SPECTRAL_PARAM_NOISE_FLOOR_REF:
2057 		spectral->params.ss_noise_floor_ref = value;
2058 		break;
2059 	case SPECTRAL_PARAM_INIT_DELAY:
2060 		spectral->params.ss_init_delay = value;
2061 		break;
2062 	case SPECTRAL_PARAM_NB_TONE_THR:
2063 		spectral->params.ss_nb_tone_thr = value;
2064 		break;
2065 	case SPECTRAL_PARAM_STR_BIN_THR:
2066 		spectral->params.ss_str_bin_thr = value;
2067 		break;
2068 	case SPECTRAL_PARAM_WB_RPT_MODE:
2069 		spectral->params.ss_wb_rpt_mode = !!value;
2070 		break;
2071 	case SPECTRAL_PARAM_RSSI_RPT_MODE:
2072 		spectral->params.ss_rssi_rpt_mode = !!value;
2073 		break;
2074 	case SPECTRAL_PARAM_RSSI_THR:
2075 		spectral->params.ss_rssi_thr = value;
2076 		break;
2077 	case SPECTRAL_PARAM_PWR_FORMAT:
2078 		spectral->params.ss_pwr_format = !!value;
2079 		break;
2080 	case SPECTRAL_PARAM_RPT_MODE:
2081 		spectral->params.ss_rpt_mode = value;
2082 		break;
2083 	case SPECTRAL_PARAM_BIN_SCALE:
2084 		spectral->params.ss_bin_scale = value;
2085 		break;
2086 	case SPECTRAL_PARAM_DBM_ADJ:
2087 		spectral->params.ss_dbm_adj = !!value;
2088 		break;
2089 	case SPECTRAL_PARAM_CHN_MASK:
2090 		spectral->params.ss_chn_mask = value;
2091 		break;
2092 	}
2093 
2094 	p_sops->configure_spectral(spectral, &spectral->params);
2095 	/* only to validate the writes */
2096 	p_sops->get_spectral_config(spectral, &params);
2097 	return 0;
2098 }
2099 
2100 /**
2101  * target_if_get_fft_bin_count() - Get fft bin count for a given fft length
2102  * @fft_len: FFT length
2103  * @pdev: Pointer to pdev object
2104  *
2105  * API to get fft bin count for a given fft length
2106  *
2107  * Return: FFt bin count
2108  */
2109 static int
2110 target_if_get_fft_bin_count(int fft_len)
2111 {
2112 	int bin_count = 0;
2113 
2114 	switch (fft_len) {
2115 	case 5:
2116 		bin_count = 16;
2117 		break;
2118 	case 6:
2119 		bin_count = 32;
2120 		break;
2121 	case 7:
2122 		bin_count = 64;
2123 		break;
2124 	case 8:
2125 		bin_count = 128;
2126 		break;
2127 	case 9:
2128 		bin_count = 256;
2129 		break;
2130 	default:
2131 		break;
2132 	}
2133 
2134 	return bin_count;
2135 }
2136 
2137 /**
2138  * target_if_init_upper_lower_flags() - Initializes control and extension
2139  * segment flags
2140  * @fft_len: FFT length
2141  * @pdev: Pointer to pdev object
2142  *
2143  * API to initialize the control and extension flags with the lower/upper
2144  * segment based on the HT mode
2145  *
2146  * Return: FFt bin count
2147  */
2148 static void
2149 target_if_init_upper_lower_flags(struct target_if_spectral *spectral)
2150 {
2151 	int current_channel = 0;
2152 	int ext_channel = 0;
2153 	struct target_if_spectral_ops *p_sops =
2154 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
2155 
2156 	current_channel = p_sops->get_current_channel(spectral);
2157 	ext_channel = p_sops->get_extension_channel(spectral);
2158 
2159 	if ((current_channel == 0) || (ext_channel == 0))
2160 		return;
2161 
2162 	if (spectral->sc_spectral_20_40_mode) {
2163 		/* HT40 mode */
2164 		if (ext_channel < current_channel) {
2165 			spectral->lower_is_extension = 1;
2166 			spectral->upper_is_control = 1;
2167 			spectral->lower_is_control = 0;
2168 			spectral->upper_is_extension = 0;
2169 		} else {
2170 			spectral->lower_is_extension = 0;
2171 			spectral->upper_is_control = 0;
2172 			spectral->lower_is_control = 1;
2173 			spectral->upper_is_extension = 1;
2174 		}
2175 	} else {
2176 		/* HT20 mode, lower is always control */
2177 		spectral->lower_is_extension = 0;
2178 		spectral->upper_is_control = 0;
2179 		spectral->lower_is_control = 1;
2180 		spectral->upper_is_extension = 0;
2181 	}
2182 }
2183 
2184 /**
2185  * target_if_get_spectral_config() - Get spectral configuration
2186  * @pdev: Pointer to pdev object
2187  * @param: Pointer to spectral_config structure in which the configuration
2188  * should be returned
2189  *
2190  * API to get the current spectral configuration
2191  *
2192  * Return: None
2193  */
2194 void
2195 target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
2196 			      struct spectral_config *param)
2197 {
2198 	struct target_if_spectral_ops *p_sops = NULL;
2199 	struct target_if_spectral *spectral = NULL;
2200 
2201 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2202 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2203 
2204 	qdf_mem_zero(param, sizeof(struct spectral_config));
2205 	p_sops->get_spectral_config(spectral, param);
2206 }
2207 
2208 /**
2209  * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
2210  *                                           parameters
2211  * @spectral: Pointer to Spectral target_if internal private data
2212  * @spectral_params: Pointer to Spectral parameters
2213  *
2214  * Enable use of desired Spectral parameters by configuring them into HW, and
2215  * starting Spectral scan
2216  *
2217  * Return: 0 on success, 1 on failure
2218  */
2219 int
2220 target_if_spectral_scan_enable_params(struct target_if_spectral *spectral,
2221 				      struct spectral_config *spectral_params)
2222 {
2223 	int extension_channel = 0;
2224 	int current_channel = 0;
2225 	struct target_if_spectral_ops *p_sops = NULL;
2226 	struct wlan_objmgr_vdev *vdev = NULL;
2227 
2228 	if (!spectral) {
2229 		spectral_err("SPECTRAL : Spectral is NULL");
2230 		return 1;
2231 	}
2232 
2233 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2234 
2235 	if (!p_sops) {
2236 		spectral_err("SPECTRAL : p_sops is NULL");
2237 		return 1;
2238 	}
2239 
2240 	spectral->sc_spectral_noise_pwr_cal =
2241 	    spectral_params->ss_spectral_pri ? 1 : 0;
2242 
2243 	/* check if extension channel is present */
2244 	extension_channel = p_sops->get_extension_channel(spectral);
2245 	current_channel = p_sops->get_current_channel(spectral);
2246 
2247 	vdev = target_if_spectral_get_vdev(spectral);
2248 	if (!vdev)
2249 		return 1;
2250 
2251 	spectral->ch_width = target_if_vdev_get_ch_width(vdev);
2252 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2253 
2254 	if (spectral->ch_width == CH_WIDTH_INVALID)
2255 		return 1;
2256 
2257 	if (spectral->capability.advncd_spectral_cap) {
2258 		spectral->lb_edge_extrabins = 0;
2259 		spectral->rb_edge_extrabins = 0;
2260 
2261 		if (spectral->is_lb_edge_extrabins_format &&
2262 		    spectral->params.ss_rpt_mode == 2) {
2263 			spectral->lb_edge_extrabins = 4;
2264 		}
2265 
2266 		if (spectral->is_rb_edge_extrabins_format &&
2267 		    spectral->params.ss_rpt_mode == 2) {
2268 			spectral->rb_edge_extrabins = 4;
2269 		}
2270 
2271 		if (spectral->ch_width == CH_WIDTH_20MHZ) {
2272 			spectral->sc_spectral_20_40_mode = 0;
2273 
2274 			spectral->spectral_numbins =
2275 			    target_if_get_fft_bin_count(
2276 				spectral->params.ss_fft_size);
2277 			spectral->spectral_fft_len =
2278 			    target_if_get_fft_bin_count(
2279 				spectral->params.ss_fft_size);
2280 			spectral->spectral_data_len =
2281 			    target_if_get_fft_bin_count(
2282 				spectral->params.ss_fft_size);
2283 			/*
2284 			 * Initialize classifier params to be sent to user
2285 			 * space classifier
2286 			 */
2287 			spectral->classifier_params.lower_chan_in_mhz =
2288 			    current_channel;
2289 			spectral->classifier_params.upper_chan_in_mhz = 0;
2290 
2291 		} else if (spectral->ch_width == CH_WIDTH_40MHZ) {
2292 			/* TODO : Remove this variable */
2293 			spectral->sc_spectral_20_40_mode = 1;
2294 			spectral->spectral_numbins =
2295 			    target_if_get_fft_bin_count(
2296 				spectral->params.ss_fft_size);
2297 			spectral->spectral_fft_len =
2298 			    target_if_get_fft_bin_count(
2299 				spectral->params.ss_fft_size);
2300 			spectral->spectral_data_len =
2301 			    target_if_get_fft_bin_count(
2302 				spectral->params.ss_fft_size);
2303 
2304 			/*
2305 			 * Initialize classifier params to be sent to user
2306 			 * space classifier
2307 			 */
2308 			if (extension_channel < current_channel) {
2309 				spectral->classifier_params.lower_chan_in_mhz =
2310 				    extension_channel;
2311 				spectral->classifier_params.upper_chan_in_mhz =
2312 				    current_channel;
2313 			} else {
2314 				spectral->classifier_params.lower_chan_in_mhz =
2315 				    current_channel;
2316 				spectral->classifier_params.upper_chan_in_mhz =
2317 				    extension_channel;
2318 			}
2319 
2320 		} else if (spectral->ch_width == CH_WIDTH_80MHZ) {
2321 			/* Set the FFT Size */
2322 			/* TODO : Remove this variable */
2323 			spectral->sc_spectral_20_40_mode = 0;
2324 			spectral->spectral_numbins =
2325 			    target_if_get_fft_bin_count(
2326 				spectral->params.ss_fft_size);
2327 			spectral->spectral_fft_len =
2328 			    target_if_get_fft_bin_count(
2329 				spectral->params.ss_fft_size);
2330 			spectral->spectral_data_len =
2331 			    target_if_get_fft_bin_count(
2332 				spectral->params.ss_fft_size);
2333 
2334 			/*
2335 			 * Initialize classifier params to be sent to user
2336 			 * space classifier
2337 			 */
2338 			spectral->classifier_params.lower_chan_in_mhz =
2339 			    current_channel;
2340 			spectral->classifier_params.upper_chan_in_mhz = 0;
2341 
2342 			/*
2343 			 * Initialize classifier params to be sent to user
2344 			 * space classifier
2345 			 */
2346 			if (extension_channel < current_channel) {
2347 				spectral->classifier_params.lower_chan_in_mhz =
2348 				    extension_channel;
2349 				spectral->classifier_params.upper_chan_in_mhz =
2350 				    current_channel;
2351 			} else {
2352 				spectral->classifier_params.lower_chan_in_mhz =
2353 				    current_channel;
2354 				spectral->classifier_params.upper_chan_in_mhz =
2355 				    extension_channel;
2356 			}
2357 
2358 		} else if (spectral->ch_width == CH_WIDTH_160MHZ) {
2359 			/* Set the FFT Size */
2360 
2361 			/* The below applies to both 160 and 80+80 cases */
2362 
2363 			/* TODO : Remove this variable */
2364 			spectral->sc_spectral_20_40_mode = 0;
2365 			spectral->spectral_numbins =
2366 			    target_if_get_fft_bin_count(
2367 				spectral->params.ss_fft_size);
2368 			spectral->spectral_fft_len =
2369 			    target_if_get_fft_bin_count(
2370 				spectral->params.ss_fft_size);
2371 			spectral->spectral_data_len =
2372 			    target_if_get_fft_bin_count(
2373 				spectral->params.ss_fft_size);
2374 
2375 			/*
2376 			 * Initialize classifier params to be sent to user
2377 			 * space classifier
2378 			 */
2379 			spectral->classifier_params.lower_chan_in_mhz =
2380 			    current_channel;
2381 			spectral->classifier_params.upper_chan_in_mhz = 0;
2382 
2383 			/*
2384 			 * Initialize classifier params to be sent to user
2385 			 * space classifier
2386 			 */
2387 			if (extension_channel < current_channel) {
2388 				spectral->classifier_params.lower_chan_in_mhz =
2389 				    extension_channel;
2390 				spectral->classifier_params.upper_chan_in_mhz =
2391 				    current_channel;
2392 			} else {
2393 				spectral->classifier_params.lower_chan_in_mhz =
2394 				    current_channel;
2395 				spectral->classifier_params.upper_chan_in_mhz =
2396 				    extension_channel;
2397 			}
2398 		}
2399 
2400 		if (spectral->spectral_numbins) {
2401 			spectral->spectral_numbins +=
2402 			    spectral->lb_edge_extrabins;
2403 			spectral->spectral_numbins +=
2404 			    spectral->rb_edge_extrabins;
2405 		}
2406 
2407 		if (spectral->spectral_fft_len) {
2408 			spectral->spectral_fft_len +=
2409 			    spectral->lb_edge_extrabins;
2410 			spectral->spectral_fft_len +=
2411 			    spectral->rb_edge_extrabins;
2412 		}
2413 
2414 		if (spectral->spectral_data_len) {
2415 			spectral->spectral_data_len +=
2416 			    spectral->lb_edge_extrabins;
2417 			spectral->spectral_data_len +=
2418 			    spectral->rb_edge_extrabins;
2419 		}
2420 	} else {
2421 		/*
2422 		 * The decision to find 20/40 mode is found based on the
2423 		 * presence of extension channel
2424 		 * instead of channel width, as the channel width can
2425 		 * dynamically change
2426 		 */
2427 
2428 		if (extension_channel == 0) {
2429 			spectral->spectral_numbins = SPECTRAL_HT20_NUM_BINS;
2430 			spectral->spectral_dc_index = SPECTRAL_HT20_DC_INDEX;
2431 			spectral->spectral_fft_len = SPECTRAL_HT20_FFT_LEN;
2432 			spectral->spectral_data_len =
2433 			    SPECTRAL_HT20_TOTAL_DATA_LEN;
2434 			/* only valid in 20-40 mode */
2435 			spectral->spectral_lower_max_index_offset = -1;
2436 			/* only valid in 20-40 mode */
2437 			spectral->spectral_upper_max_index_offset = -1;
2438 			spectral->spectral_max_index_offset =
2439 			    spectral->spectral_fft_len + 2;
2440 			spectral->sc_spectral_20_40_mode = 0;
2441 
2442 			/*
2443 			 * Initialize classifier params to be sent to user
2444 			 * space classifier
2445 			 */
2446 			spectral->classifier_params.lower_chan_in_mhz =
2447 			    current_channel;
2448 			spectral->classifier_params.upper_chan_in_mhz = 0;
2449 
2450 		} else {
2451 			spectral->spectral_numbins =
2452 			    SPECTRAL_HT40_TOTAL_NUM_BINS;
2453 			spectral->spectral_fft_len = SPECTRAL_HT40_FFT_LEN;
2454 			spectral->spectral_data_len =
2455 			    SPECTRAL_HT40_TOTAL_DATA_LEN;
2456 			spectral->spectral_dc_index = SPECTRAL_HT40_DC_INDEX;
2457 			/* only valid in 20 mode */
2458 			spectral->spectral_max_index_offset = -1;
2459 			spectral->spectral_lower_max_index_offset =
2460 			    spectral->spectral_fft_len + 2;
2461 			spectral->spectral_upper_max_index_offset =
2462 			    spectral->spectral_fft_len + 5;
2463 			spectral->sc_spectral_20_40_mode = 1;
2464 
2465 			/*
2466 			 * Initialize classifier params to be sent to user
2467 			 * space classifier
2468 			 */
2469 			if (extension_channel < current_channel) {
2470 				spectral->classifier_params.lower_chan_in_mhz =
2471 				    extension_channel;
2472 				spectral->classifier_params.upper_chan_in_mhz =
2473 				    current_channel;
2474 			} else {
2475 				spectral->classifier_params.lower_chan_in_mhz =
2476 				    current_channel;
2477 				spectral->classifier_params.upper_chan_in_mhz =
2478 				    extension_channel;
2479 			}
2480 		}
2481 	}
2482 
2483 	spectral->send_single_packet = 0;
2484 	spectral->classifier_params.spectral_20_40_mode =
2485 	    spectral->sc_spectral_20_40_mode;
2486 	spectral->classifier_params.spectral_dc_index =
2487 	    spectral->spectral_dc_index;
2488 	spectral->spectral_sent_msg = 0;
2489 	spectral->classify_scan = 0;
2490 	spectral->num_spectral_data = 0;
2491 
2492 	if (!p_sops->is_spectral_active(spectral)) {
2493 		p_sops->configure_spectral(spectral, spectral_params);
2494 		p_sops->start_spectral_scan(spectral);
2495 		spectral->timestamp_war_offset = 0;
2496 		spectral->last_fft_timestamp = 0;
2497 	} else {
2498 	}
2499 
2500 	/* get current spectral configuration */
2501 	p_sops->get_spectral_config(spectral, &spectral->params);
2502 
2503 	target_if_init_upper_lower_flags(spectral);
2504 
2505 	return 0;
2506 }
2507 
2508 /**
2509  * target_if_start_spectral_scan() - Start spectral scan
2510  * @pdev: Pointer to pdev object
2511  *
2512  * API to start spectral scan
2513  *
2514  * Return: 0 in case of success, -1 on failure
2515  */
2516 int
2517 target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev)
2518 {
2519 	struct target_if_spectral_ops *p_sops = NULL;
2520 	struct target_if_spectral *spectral = NULL;
2521 
2522 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2523 	if (!spectral) {
2524 		spectral_err("SPECTRAL : Spectral LMAC object is NUll");
2525 		return -EPERM;
2526 	}
2527 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2528 
2529 	if (!spectral->params_valid) {
2530 		target_if_spectral_info_read(spectral,
2531 					     TARGET_IF_SPECTRAL_INFO_PARAMS,
2532 					     &spectral->params,
2533 					     sizeof(spectral->params));
2534 		spectral->params_valid = true;
2535 	}
2536 
2537 	qdf_spin_lock(&spectral->spectral_lock);
2538 	target_if_spectral_scan_enable_params(spectral, &spectral->params);
2539 	qdf_spin_unlock(&spectral->spectral_lock);
2540 
2541 	return 0;
2542 }
2543 
2544 void
2545 target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev)
2546 {
2547 	struct target_if_spectral_ops *p_sops = NULL;
2548 	struct target_if_spectral *spectral = NULL;
2549 
2550 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2551 	if (!spectral) {
2552 		spectral_err("SPECTRAL : Spectral LMAC object is NUll ");
2553 		return;
2554 	}
2555 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2556 
2557 	qdf_spin_lock(&spectral->spectral_lock);
2558 	p_sops->stop_spectral_scan(spectral);
2559 	if (spectral->classify_scan) {
2560 		/* TODO : Check if this logic is necessary */
2561 		spectral->detects_control_channel = 0;
2562 		spectral->detects_extension_channel = 0;
2563 		spectral->detects_above_dc = 0;
2564 		spectral->detects_below_dc = 0;
2565 		spectral->classify_scan = 0;
2566 	}
2567 
2568 	spectral->send_single_packet = 0;
2569 	spectral->sc_spectral_scan = 0;
2570 
2571 	qdf_spin_unlock(&spectral->spectral_lock);
2572 }
2573 
2574 /**
2575  * target_if_is_spectral_active() - Get whether Spectral is active
2576  * @pdev: Pointer to pdev object
2577  *
2578  * API to get whether Spectral is active
2579  *
2580  * Return: True if Spectral is active, false if Spectral is not active
2581  */
2582 bool
2583 target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev)
2584 {
2585 	struct target_if_spectral *spectral = NULL;
2586 	struct target_if_spectral_ops *p_sops = NULL;
2587 
2588 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2589 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2590 	return p_sops->is_spectral_active(spectral);
2591 }
2592 
2593 /**
2594  * target_if_is_spectral_enabled() - Get whether Spectral is enabled
2595  * @pdev: Pointer to pdev object
2596  *
2597  * API to get whether Spectral is enabled
2598  *
2599  * Return: True if Spectral is enabled, false if Spectral is not enabled
2600  */
2601 bool
2602 target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev)
2603 {
2604 	struct target_if_spectral *spectral = NULL;
2605 	struct target_if_spectral_ops *p_sops = NULL;
2606 
2607 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2608 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2609 	return p_sops->is_spectral_enabled(spectral);
2610 }
2611 
2612 /**
2613  * target_if_set_debug_level() - Set debug level for Spectral
2614  * @pdev: Pointer to pdev object
2615  * @debug_level: Debug level
2616  *
2617  * API to set the debug level for Spectral
2618  *
2619  * Return: 0 in case of success
2620  */
2621 int
2622 target_if_set_debug_level(struct wlan_objmgr_pdev *pdev, uint32_t debug_level)
2623 {
2624 	spectral_debug_level = (DEBUG_SPECTRAL << debug_level);
2625 	return 0;
2626 }
2627 
2628 /**
2629  * target_if_get_debug_level() - Get debug level for Spectral
2630  * @pdev: Pointer to pdev object
2631  *
2632  * API to get the debug level for Spectral
2633  *
2634  * Return: Current debug level
2635  */
2636 uint32_t
2637 target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
2638 {
2639 	return spectral_debug_level;
2640 }
2641 
2642 /**
2643  * target_if_get_spectral_capinfo() - Get Spectral capability information
2644  * @pdev: Pointer to pdev object
2645  * @outdata: Buffer into which data should be copied
2646  *
2647  * API to get the spectral capability information
2648  *
2649  * Return: void
2650  */
2651 void
2652 target_if_get_spectral_capinfo(struct wlan_objmgr_pdev *pdev, void *outdata)
2653 {
2654 	struct target_if_spectral *spectral = NULL;
2655 
2656 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2657 	qdf_mem_copy(outdata, &spectral->capability,
2658 		     sizeof(struct spectral_caps));
2659 }
2660 
2661 /**
2662  * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
2663  * @pdev:  Pointer to pdev object
2664  * @outdata: Buffer into which data should be copied
2665  *
2666  * API to get the spectral diagnostic statistics
2667  *
2668  * Return: void
2669  */
2670 void
2671 target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev, void *outdata)
2672 {
2673 	struct target_if_spectral *spectral = NULL;
2674 
2675 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2676 	qdf_mem_copy(outdata, &spectral->diag_stats,
2677 		     sizeof(struct spectral_diag_stats));
2678 }
2679 
2680 /**
2681  * target_if_register_wmi_spectral_cmd_ops() - Register wmi_spectral_cmd_ops
2682  * @cmd_ops: Pointer to the structure having wmi_spectral_cmd function pointers
2683  * @pdev: Pointer to pdev object
2684  *
2685  * API for register wmi_spectral_cmd_ops in spectral internal data structure
2686  *
2687  * Return: void
2688  */
2689 void
2690 target_if_register_wmi_spectral_cmd_ops(struct wlan_objmgr_pdev *pdev,
2691 					struct wmi_spectral_cmd_ops *cmd_ops)
2692 {
2693 	struct target_if_spectral *spectral = NULL;
2694 
2695 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2696 	spectral->param_wmi_cmd_ops.wmi_spectral_configure_cmd_send =
2697 	    cmd_ops->wmi_spectral_configure_cmd_send;
2698 	spectral->param_wmi_cmd_ops.wmi_spectral_enable_cmd_send =
2699 	    cmd_ops->wmi_spectral_enable_cmd_send;
2700 }
2701 
2702 /**
2703  * target_if_register_netlink_cb() - Register Netlink callbacks
2704  * @pdev: Pointer to pdev object
2705  * @nl_cb: Netlink callbacks to register
2706  *
2707  * Return: void
2708  */
2709 static void
2710 target_if_register_netlink_cb(
2711 	struct wlan_objmgr_pdev *pdev,
2712 	struct spectral_nl_cb *nl_cb)
2713 {
2714 	struct target_if_spectral *spectral = NULL;
2715 
2716 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2717 	qdf_mem_copy(&spectral->nl_cb, nl_cb, sizeof(struct spectral_nl_cb));
2718 
2719 	if (spectral->use_nl_bcast)
2720 		spectral->send_phy_data = spectral->nl_cb.send_nl_bcast;
2721 	else
2722 		spectral->send_phy_data = spectral->nl_cb.send_nl_unicast;
2723 }
2724 
2725 /**
2726  * target_if_use_nl_bcast() - Get whether to use broadcast/unicast while sending
2727  * Netlink messages to the application layer
2728  * @pdev: Pointer to pdev object
2729  *
2730  * Return: true for broadcast, false for unicast
2731  */
2732 static bool
2733 target_if_use_nl_bcast(struct wlan_objmgr_pdev *pdev)
2734 {
2735 	struct target_if_spectral *spectral = NULL;
2736 
2737 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2738 	return spectral->use_nl_bcast;
2739 }
2740 
2741 /**
2742  * target_if_deregister_netlink_cb() - De-register Netlink callbacks
2743  * @pdev: Pointer to pdev object
2744  *
2745  * Return: void
2746  */
2747 static void
2748 target_if_deregister_netlink_cb(struct wlan_objmgr_pdev *pdev)
2749 {
2750 	struct target_if_spectral *spectral = NULL;
2751 
2752 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2753 	if (!spectral) {
2754 		spectral_err("SPECTRAL : Module doesn't exist");
2755 		return;
2756 	}
2757 
2758 	qdf_mem_zero(&spectral->nl_cb, sizeof(struct spectral_nl_cb));
2759 }
2760 
2761 static int
2762 target_if_process_spectral_report(struct wlan_objmgr_pdev *pdev,
2763 				  void *payload)
2764 {
2765 	struct target_if_spectral *spectral = NULL;
2766 	struct target_if_spectral_ops *p_sops = NULL;
2767 
2768 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2769 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2770 
2771 	return p_sops->process_spectral_report(pdev, payload);
2772 }
2773 
2774 void
2775 target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
2776 {
2777 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
2778 	    target_if_pdev_spectral_init;
2779 	tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
2780 	    target_if_pdev_spectral_deinit;
2781 	tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
2782 	    target_if_set_spectral_config;
2783 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
2784 	    target_if_get_spectral_config;
2785 	tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
2786 	    target_if_start_spectral_scan;
2787 	tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
2788 	    target_if_stop_spectral_scan;
2789 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
2790 	    target_if_is_spectral_active;
2791 	tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
2792 	    target_if_is_spectral_enabled;
2793 	tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
2794 	    target_if_set_debug_level;
2795 	tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
2796 	    target_if_get_debug_level;
2797 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
2798 	    target_if_get_spectral_capinfo;
2799 	tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
2800 	    target_if_get_spectral_diagstats;
2801 	tx_ops->sptrl_tx_ops.sptrlto_register_wmi_spectral_cmd_ops =
2802 	    target_if_register_wmi_spectral_cmd_ops;
2803 	tx_ops->sptrl_tx_ops.sptrlto_register_netlink_cb =
2804 	    target_if_register_netlink_cb;
2805 	tx_ops->sptrl_tx_ops.sptrlto_use_nl_bcast =
2806 	    target_if_use_nl_bcast;
2807 	tx_ops->sptrl_tx_ops.sptrlto_deregister_netlink_cb =
2808 	    target_if_deregister_netlink_cb;
2809 	tx_ops->sptrl_tx_ops.sptrlto_process_spectral_report =
2810 		target_if_process_spectral_report;
2811 }
2812 qdf_export_symbol(target_if_sptrl_register_tx_ops);
2813 
2814 void
2815 target_if_spectral_send_intf_found_msg(struct wlan_objmgr_pdev *pdev,
2816 				       uint16_t cw_int, uint32_t dcs_enabled)
2817 {
2818 	struct spectral_samp_msg *msg = NULL;
2819 	struct target_if_spectral_ops *p_sops = NULL;
2820 	struct target_if_spectral *spectral = NULL;
2821 
2822 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2823 	msg  = (struct spectral_samp_msg *)spectral->nl_cb.get_nbuff(
2824 			spectral->pdev_obj);
2825 
2826 	if (msg) {
2827 		msg->int_type = cw_int ?
2828 		    SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
2829 		msg->dcs_enabled = dcs_enabled;
2830 		msg->signature = SPECTRAL_SIGNATURE;
2831 		p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
2832 		p_sops->get_mac_address(spectral, msg->macaddr);
2833 		if (spectral->send_phy_data(pdev) == 0)
2834 			spectral->spectral_sent_msg++;
2835 	}
2836 }
2837 qdf_export_symbol(target_if_spectral_send_intf_found_msg);
2838