xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral_sim.c (revision 2cc88020a1e82db5820e620eab19c7309891304c)
1 /*
2  * Copyright (c) 2015,2017-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
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 #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION
21 #include "target_if_spectral.h"
22 #include "target_if_spectral_sim.h"
23 #include "target_if_spectral_sim_int.h"
24 #include "_ieee80211.h"
25 #include "ieee80211_api.h"
26 #include "ieee80211_defines.h"
27 #include "qdf_types.h"
28 #include "ieee80211_var.h"
29 #include <wlan_mlme_dispatcher.h>
30 #include <qdf_module.h>
31 
32 /* Helper functions */
33 
34 static int target_if_populate_report_static_gen2(
35 	struct spectralsim_report *report,
36 	enum phy_ch_width width, bool is_80_80);
37 static int target_if_populate_report_static_gen3(
38 	struct spectralsim_report *report,
39 	enum phy_ch_width width, bool is_80_80);
40 static void target_if_depopulate_report(
41 	struct spectralsim_report *report);
42 
43 static int target_if_populate_reportset_static(
44 	struct spectralsim_context *simctx,
45 	struct spectralsim_reportset *reportset,
46 	enum phy_ch_width width, bool is_80_80);
47 static void target_if_depopulate_reportset(
48 	struct spectralsim_reportset *
49 	reportset);
50 
51 static int target_if_populate_simdata(struct spectralsim_context *simctx);
52 static void target_if_depopulate_simdata(struct spectralsim_context *simctx);
53 static OS_TIMER_FUNC(target_if_spectral_sim_phyerrdelivery_handler);
54 
55 /*
56  * Static configuration.
57  * For now, we will be having a single configuration per BW, and a single
58  * report per configuration (since we need the data only for ensuring correct
59  * format handling).
60  *
61  * Extend this for more functionality if required in the future.
62  */
63 
64 /**
65  * target_if_populate_report_static_gen2() - Statically populate simulation
66  * data for one report for generation 2 chipsets
67  * @report: Pointer to spectral report data instance
68  * @width : Channel bandwidth enumeration
69  *
70  * Statically populate simulation data for one report for generation 2 chipsets
71  *
72  * Return: 0 on success, negative error code on failure
73  */
74 static int
75 target_if_populate_report_static_gen2(
76 	struct spectralsim_report *report,
77 	enum phy_ch_width width)
78 {
79 	if (!report) {
80 		spectral_err("report pointer is null.");
81 		goto bad;
82 	}
83 
84 	switch (width) {
85 	case CH_WIDTH_20MHZ:
86 		report->data = NULL;
87 		report->data = (uint8_t *)
88 		    qdf_mem_malloc(sizeof(reportdata_20_gen2));
89 
90 		if (!report->data)
91 			goto bad;
92 
93 		report->datasize = sizeof(reportdata_20_gen2);
94 		qdf_mem_copy(report->data,
95 			     reportdata_20_gen2, report->datasize);
96 
97 		qdf_mem_copy(&report->rfqual_info,
98 			     &rfqual_info_20, sizeof(report->rfqual_info));
99 
100 		qdf_mem_copy(&report->chan_info,
101 			     &chan_info_20, sizeof(report->chan_info));
102 
103 		break;
104 	case CH_WIDTH_40MHZ:
105 		report->data = NULL;
106 		report->data = (uint8_t *)
107 		    qdf_mem_malloc(sizeof(reportdata_40_gen2));
108 
109 		if (!report->data)
110 			goto bad;
111 
112 		report->datasize = sizeof(reportdata_40_gen2);
113 		qdf_mem_copy(report->data,
114 			     reportdata_40_gen2, report->datasize);
115 
116 		qdf_mem_copy(&report->rfqual_info,
117 			     &rfqual_info_40, sizeof(report->rfqual_info));
118 
119 		qdf_mem_copy(&report->chan_info,
120 			     &chan_info_40, sizeof(report->chan_info));
121 
122 		break;
123 	case CH_WIDTH_80MHZ:
124 		report->data = NULL;
125 		report->data = (uint8_t *)
126 		    qdf_mem_malloc(sizeof(reportdata_80_gen2));
127 
128 		if (!report->data)
129 			goto bad;
130 
131 		report->datasize = sizeof(reportdata_80_gen2);
132 		qdf_mem_copy(report->data,
133 			     reportdata_80_gen2, report->datasize);
134 
135 		qdf_mem_copy(&report->rfqual_info,
136 			     &rfqual_info_80, sizeof(report->rfqual_info));
137 
138 		qdf_mem_copy(&report->chan_info,
139 			     &chan_info_80, sizeof(report->chan_info));
140 
141 		break;
142 	case CH_WIDTH_80P80MHZ:
143 		report->data = NULL;
144 		report->data = (uint8_t *)
145 		    qdf_mem_malloc(sizeof(reportdata_80_80_gen2));
146 
147 		if (!report->data)
148 			goto bad;
149 
150 		report->datasize = sizeof(reportdata_80_80_gen2);
151 		qdf_mem_copy(report->data,
152 			     reportdata_80_80_gen2, report->datasize);
153 
154 		qdf_mem_copy(&report->rfqual_info,
155 			     &rfqual_info_80_80,
156 			     sizeof(report->rfqual_info));
157 
158 		qdf_mem_copy(&report->chan_info,
159 			     &chan_info_80_80,
160 			     sizeof(report->chan_info));
161 		break;
162 
163 	case CH_WIDTH_160MHZ:
164 		report->data = NULL;
165 		report->data = (uint8_t *)
166 		    qdf_mem_malloc(sizeof(reportdata_160_gen2));
167 
168 		if (!report->data)
169 			goto bad;
170 
171 		report->datasize = sizeof(reportdata_160_gen2);
172 		qdf_mem_copy(report->data,
173 			     reportdata_160_gen2, report->datasize);
174 
175 		qdf_mem_copy(&report->rfqual_info,
176 			     &rfqual_info_160,
177 			     sizeof(report->rfqual_info));
178 
179 		qdf_mem_copy(&report->chan_info,
180 			     &chan_info_160, sizeof(report->chan_info));
181 		break;
182 
183 	default:
184 		spectral_err("Unhandled width enum: %d. Please correct.",
185 			     width);
186 		goto bad;
187 	}
188 
189 	return 0;
190 
191  bad:
192 	return -EPERM;
193 }
194 
195 /**
196  * target_if_populate_report_static_gen3() - Statically populate simulation
197  * data for one report for generation 3 chipsets
198  * @report: Pointer to spectral report data instance
199  * @width : Channel bandwidth enumeration
200  *
201  * Statically populate simulation data for one report for generation 3 chipsets
202  *
203  * Return: 0 on success, negative error code on failure
204  */
205 static int
206 target_if_populate_report_static_gen3(
207 	struct spectralsim_report *report,
208 	enum phy_ch_width width)
209 {
210 	if (!report) {
211 		spectral_err("report pointer is null");
212 		goto bad;
213 	}
214 	switch (width) {
215 	case CH_WIDTH_20MHZ:
216 		report->data = NULL;
217 		report->data = (uint8_t *)
218 		    qdf_mem_malloc(sizeof(reportdata_20_gen3));
219 
220 		if (!report->data)
221 			goto bad;
222 
223 		report->datasize = sizeof(reportdata_20_gen3);
224 		qdf_mem_copy(report->data,
225 			     reportdata_20_gen3, report->datasize);
226 
227 		qdf_mem_copy(&report->rfqual_info,
228 			     &rfqual_info_20, sizeof(report->rfqual_info));
229 
230 		qdf_mem_copy(&report->chan_info,
231 			     &chan_info_20, sizeof(report->chan_info));
232 
233 		break;
234 	case CH_WIDTH_40MHZ:
235 		report->data = NULL;
236 		report->data = (uint8_t *)
237 		    qdf_mem_malloc(sizeof(reportdata_40_gen3));
238 
239 		if (!report->data)
240 			goto bad;
241 
242 		report->datasize = sizeof(reportdata_40_gen3);
243 		qdf_mem_copy(report->data,
244 			     reportdata_40_gen3, report->datasize);
245 
246 		qdf_mem_copy(&report->rfqual_info,
247 			     &rfqual_info_40, sizeof(report->rfqual_info));
248 
249 		qdf_mem_copy(&report->chan_info,
250 			     &chan_info_40, sizeof(report->chan_info));
251 
252 		break;
253 	case CH_WIDTH_80MHZ:
254 		report->data = NULL;
255 		report->data = (uint8_t *)
256 		    qdf_mem_malloc(sizeof(reportdata_80_gen3));
257 
258 		if (!report->data)
259 			goto bad;
260 
261 		report->datasize = sizeof(reportdata_80_gen3);
262 		qdf_mem_copy(report->data,
263 			     reportdata_80_gen3, report->datasize);
264 
265 		qdf_mem_copy(&report->rfqual_info,
266 			     &rfqual_info_80, sizeof(report->rfqual_info));
267 
268 		qdf_mem_copy(&report->chan_info,
269 			     &chan_info_80, sizeof(report->chan_info));
270 
271 		break;
272 
273 	case CH_WIDTH_80P80MHZ:
274 		report->data = NULL;
275 		report->data = (uint8_t *)
276 		    qdf_mem_malloc(sizeof(reportdata_80_80_gen3));
277 
278 		if (!report->data)
279 			goto bad;
280 
281 		report->datasize = sizeof(reportdata_80_80_gen3);
282 		qdf_mem_copy(report->data,
283 			     reportdata_80_80_gen3, report->datasize);
284 
285 		qdf_mem_copy(&report->rfqual_info,
286 			     &rfqual_info_80_80,
287 			     sizeof(report->rfqual_info));
288 
289 		qdf_mem_copy(&report->chan_info,
290 			     &chan_info_80_80,
291 			     sizeof(report->chan_info));
292 		break;
293 
294 	case CH_WIDTH_160MHZ:
295 		report->data = NULL;
296 		report->data = (uint8_t *)
297 		    qdf_mem_malloc(sizeof(reportdata_160_gen3));
298 
299 		if (!report->data)
300 			goto bad;
301 
302 		report->datasize = sizeof(reportdata_160_gen3);
303 		qdf_mem_copy(report->data,
304 			     reportdata_160_gen3, report->datasize);
305 
306 		qdf_mem_copy(&report->rfqual_info,
307 			     &rfqual_info_160,
308 			     sizeof(report->rfqual_info));
309 
310 		qdf_mem_copy(&report->chan_info,
311 			     &chan_info_160, sizeof(report->chan_info));
312 		break;
313 
314 	default:
315 		spectral_err("Unhandled width enum: %d. Please correct.",
316 			     width);
317 		goto bad;
318 	}
319 
320 	return 0;
321 
322  bad:
323 	return -EPERM;
324 }
325 
326 /**
327  * target_if_depopulate_report() - Free the given instances of
328  * struct spectralsim_report
329  * @report: instance of struct spectralsim_report
330  *
331  * Free the given instances of struct spectralsim_report
332  *
333  * Return: None
334  */
335 static void
336 target_if_depopulate_report(
337 	struct spectralsim_report *report)
338 {
339 	if (!report)
340 		return;
341 
342 	if (report->data) {
343 		qdf_mem_free(report->data);
344 		report->data = NULL;
345 		report->datasize = 0;
346 	}
347 }
348 
349 /**
350  * target_if_populate_reportset_static() - Statically populate simulation data
351  * for a given configuration
352  * @simctx: Pointer to struct spectralsim_context
353  * @reportset: Set of spectral report data instances
354  * @width : Channel bandwidth enumeration
355  *
356  * Statically populate simulation data for a given configuration
357  *
358  * Return: 0 on success, negative error code on failure
359  */
360 static int
361 target_if_populate_reportset_static(
362 	struct spectralsim_context *simctx,
363 	struct spectralsim_reportset *reportset,
364 	enum phy_ch_width width)
365 {
366 	int ret = 0;
367 	struct spectralsim_report *report = NULL;
368 
369 	if (!reportset) {
370 		spectral_err("reportset pointer is null.");
371 		goto bad;
372 	}
373 
374 	reportset->headreport = NULL;
375 	reportset->curr_report = NULL;
376 
377 	/* For now, we populate only one report */
378 	report = (struct spectralsim_report *)
379 	    qdf_mem_malloc(sizeof(struct spectralsim_report));
380 
381 	if (!report)
382 		goto bad;
383 
384 	qdf_mem_zero(report, sizeof(*report));
385 
386 	switch (width) {
387 	case CH_WIDTH_20MHZ:
388 		qdf_mem_copy(&reportset->config,
389 			     &config_20_1, sizeof(reportset->config));
390 
391 		ret = simctx->populate_report_static(report, CH_WIDTH_20MHZ);
392 		if (ret != 0)
393 			goto bad;
394 
395 		report->next = NULL;
396 		reportset->headreport = report;
397 		break;
398 	case CH_WIDTH_40MHZ:
399 		qdf_mem_copy(&reportset->config,
400 			     &config_40_1, sizeof(reportset->config));
401 
402 		ret = simctx->populate_report_static(report, CH_WIDTH_40MHZ);
403 		if (ret != 0)
404 			goto bad;
405 
406 		report->next = NULL;
407 		reportset->headreport = report;
408 		break;
409 	case CH_WIDTH_80MHZ:
410 		qdf_mem_copy(&reportset->config,
411 			     &config_80_1, sizeof(reportset->config));
412 
413 		ret = simctx->populate_report_static(report, CH_WIDTH_80MHZ);
414 		if (ret != 0)
415 			goto bad;
416 
417 		report->next = NULL;
418 		reportset->headreport = report;
419 		break;
420 
421 	case CH_WIDTH_80P80MHZ:
422 		qdf_mem_copy(&reportset->config,
423 			     &config_80_80_1,
424 			     sizeof(reportset->config));
425 
426 		ret = simctx->populate_report_static(report,
427 						     CH_WIDTH_80P80MHZ);
428 		if (ret != 0)
429 			goto bad;
430 
431 		report->next = NULL;
432 		reportset->headreport = report;
433 		break;
434 
435 	case CH_WIDTH_160MHZ:
436 		qdf_mem_copy(&reportset->config,
437 			     &config_160_1, sizeof(reportset->config));
438 
439 		ret = simctx->populate_report_static(report,
440 						     CH_WIDTH_160MHZ);
441 		if (ret != 0)
442 			goto bad;
443 
444 		report->next = NULL;
445 		reportset->headreport = report;
446 		break;
447 
448 	default:
449 		spectral_err("Unhandled width enum: %d. Please correct.",
450 			     width);
451 		goto bad;
452 	};
453 
454 	reportset->curr_report = reportset->headreport;
455 
456 	return 0;
457 
458  bad:
459 	target_if_depopulate_reportset(reportset);
460 	return -EPERM;
461 }
462 
463 /**
464  * target_if_depopulate_reportset() - Free all the instances of
465  * struct spectralsim_reportset
466  * @reportset: head pointer to struct spectralsim_reportset linked list
467  *
468  * Free all the instances of struct spectralsim_reportset
469  *
470  * Return: None
471  */
472 static void
473 target_if_depopulate_reportset(
474 	struct spectralsim_reportset *reportset)
475 {
476 	struct spectralsim_report *curr_report = NULL;
477 	struct spectralsim_report *next_report = NULL;
478 
479 	if (!reportset)
480 		return;
481 
482 	curr_report = reportset->headreport;
483 
484 	while (curr_report) {
485 		next_report = curr_report->next;
486 		target_if_depopulate_report(curr_report);
487 		qdf_mem_free(curr_report);
488 		curr_report = next_report;
489 	}
490 }
491 
492 /**
493  * target_if_populate_simdata() - Populate simulation data
494  * @simctx: Pointer to struct spectralsim_context
495  *
496  * Populate simulation data
497  *
498  * Return: 0 on success, negative error code on failure
499  */
500 static int
501 target_if_populate_simdata(
502 	struct spectralsim_context *simctx)
503 {
504 	/*
505 	 * For now, we use static population. Switch to loading from a file if
506 	 * needed in the future.
507 	 */
508 
509 	simctx->bw20_headreportset = NULL;
510 	SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
511 						simctx->bw20_headreportset,
512 						CH_WIDTH_20MHZ);
513 
514 	simctx->bw40_headreportset = NULL;
515 	SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
516 						simctx->bw40_headreportset,
517 						CH_WIDTH_40MHZ);
518 
519 	simctx->bw80_headreportset = NULL;
520 	SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
521 						simctx->bw80_headreportset,
522 						CH_WIDTH_80MHZ);
523 
524 	simctx->bw160_headreportset = NULL;
525 	SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
526 						simctx->bw160_headreportset,
527 						CH_WIDTH_160MHZ);
528 
529 	simctx->bw80_80_headreportset = NULL;
530 	SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
531 						simctx->bw80_80_headreportset,
532 						CH_WIDTH_80P80MHZ);
533 
534 	simctx->curr_reportset = NULL;
535 
536 	simctx->is_enabled = false;
537 	simctx->is_active = false;
538 
539 	simctx->ssim_starting_tsf64 = 0;
540 	simctx->ssim_count = 0;
541 	simctx->ssim_period_ms = 0;
542 
543 	return 0;
544 }
545 
546 /**
547  * target_if_depopulate_simdata() - De-populate simulation data
548  * @simctx: Pointer to struct spectralsim_context
549  *
550  * De-populate simulation data
551  *
552  * Return: none
553  */
554 static void
555 target_if_depopulate_simdata(
556 	struct spectralsim_context *simctx)
557 {
558 	if (!simctx)
559 		return;
560 
561 	SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw20_headreportset);
562 	SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw40_headreportset);
563 	SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw80_headreportset);
564 	SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw160_headreportset);
565 	SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw80_80_headreportset);
566 }
567 
568 /*
569  * target_if_spectral_sim_phyerrdelivery_handler() - Phyerr delivery handler
570  *
571  * Return: none
572  *
573  * NB: kernel-doc script doesn't parse OS_TIMER_FUNC
574  */
575 static
576 OS_TIMER_FUNC(target_if_spectral_sim_phyerrdelivery_handler)
577 {
578 	struct target_if_spectral *spectral = NULL;
579 	struct spectralsim_context *simctx = NULL;
580 	struct spectralsim_reportset *curr_reportset = NULL;
581 	struct spectralsim_report *curr_report = NULL;
582 	struct target_if_spectral_acs_stats acs_stats;
583 	uint64_t curr_tsf64 = 0;
584 	struct target_if_spectral_ops *p_sops;
585 
586 	OS_GET_TIMER_ARG(spectral, struct target_if_spectral *);
587 	if (!spectral) {
588 		spectral_err("spectral pointer is null.");
589 		return;
590 	}
591 
592 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
593 	if (!p_sops) {
594 		spectral_err("p_sops pointer is null.");
595 		return;
596 	}
597 
598 	simctx = (struct spectralsim_context *)spectral->simctx;
599 	if (!simctx) {
600 		spectral_err("simctx pointer is null.");
601 		return;
602 	}
603 
604 	if (!simctx->is_active)
605 		return;
606 
607 	curr_reportset = simctx->curr_reportset;
608 	if (!curr_reportset) {
609 		spectral_err("curr_reportset pointer is null.");
610 		return;
611 	}
612 
613 	curr_report = curr_reportset->curr_report;
614 	if (!curr_report) {
615 		spectral_err("curr_report pointer is null.");
616 		return;
617 	}
618 
619 	if (!curr_reportset->headreport) {
620 		spectral_err("curr_reportset->headreport pointer is null.");
621 		return;
622 	}
623 
624 	/*
625 	 * We use a simulation TSF since in offload architectures we can't
626 	 * expect to
627 	 * get an accurate current TSF from HW.
628 	 * In case of TSF wrap over, we'll use it as-is for now since the
629 	 * simulation
630 	 * is intended only for format verification.
631 	 */
632 	curr_tsf64 = simctx->ssim_starting_tsf64 +
633 	    ((simctx->ssim_period_ms * simctx->ssim_count) * 1000);
634 
635 	p_sops->spectral_process_phyerr(spectral,
636 					curr_report->data,
637 					curr_report->datasize,
638 					&curr_report->rfqual_info,
639 					&curr_report->chan_info,
640 					curr_tsf64, &acs_stats);
641 
642 	simctx->ssim_count++;
643 
644 	if (curr_report->next)
645 		curr_reportset->curr_report = curr_report->next;
646 	else
647 		curr_reportset->curr_report = curr_reportset->headreport;
648 
649 	if (curr_reportset->config.ss_count != 0 &&
650 	    simctx->ssim_count == curr_reportset->config.ss_count) {
651 		target_if_spectral_sops_sim_stop_scan(spectral);
652 	} else {
653 		qdf_timer_start(&simctx->ssim_pherrdelivery_timer,
654 				simctx->ssim_period_ms);
655 	}
656 }
657 
658 /* Module services */
659 
660 int
661 target_if_spectral_sim_attach(struct target_if_spectral *spectral)
662 {
663 	struct spectralsim_context *simctx = NULL;
664 
665 	if (!spectral) {
666 		spectral_err("Spectral simulation: spectral pointer is null.")
667 		return -EPERM;
668 	}
669 
670 	simctx = (struct spectralsim_context *)
671 	    qdf_mem_malloc(sizeof(struct spectralsim_context));
672 
673 	if (!simctx)
674 		return -EPERM;
675 
676 	qdf_mem_zero(simctx, sizeof(*simctx));
677 
678 	spectral->simctx = simctx;
679 
680 	if (spectral->spectral_gen == SPECTRAL_GEN2)
681 		simctx->populate_report_static =
682 			target_if_populate_report_static_gen2;
683 	else if (spectral->spectral_gen == SPECTRAL_GEN3)
684 		simctx->populate_report_static =
685 			target_if_populate_report_static_gen3;
686 
687 	if (target_if_populate_simdata(simctx) != 0) {
688 		qdf_mem_free(simctx);
689 		spectral->simctx = NULL;
690 		spectral_err("Spectral simulation attach failed");
691 		return -EPERM;
692 	}
693 
694 	qdf_timer_init(NULL,
695 		       &simctx->ssim_pherrdelivery_timer,
696 		       target_if_spectral_sim_phyerrdelivery_handler,
697 		       (void *)(spectral), QDF_TIMER_TYPE_WAKE_APPS);
698 
699 	spectral_info("Spectral simulation attached");
700 
701 	return 0;
702 }
703 
704 void
705 target_if_spectral_sim_detach(struct target_if_spectral *spectral)
706 {
707 	struct spectralsim_context *simctx = NULL;
708 
709 	if (!spectral) {
710 		spectral_err("spectral pointer is null.");
711 		return;
712 	}
713 
714 	simctx = (struct spectralsim_context *)spectral->simctx;
715 	if (!simctx) {
716 		spectral_err("simctx pointer is null.");
717 		return;
718 	}
719 
720 	qdf_timer_free(&simctx->ssim_pherrdelivery_timer);
721 
722 	target_if_depopulate_simdata(simctx);
723 	qdf_mem_free(simctx);
724 	spectral->simctx = NULL;
725 
726 	spectral_info("Spectral simulation detached");
727 }
728 
729 uint32_t
730 target_if_spectral_sops_sim_is_active(void *arg)
731 {
732 	struct target_if_spectral *spectral = NULL;
733 	struct spectralsim_context *simctx = NULL;
734 
735 	spectral = (struct target_if_spectral *)arg;
736 	if (!spectral) {
737 		spectral_err("Spectral simulation: spectral pointer is null");
738 		return 0;
739 	}
740 	simctx = (struct spectralsim_context *)spectral->simctx;
741 	if (!simctx) {
742 		spectral_err("Spectral simulation: simctx pointer is null");
743 		return 0;
744 	}
745 
746 	return simctx->is_active;
747 }
748 qdf_export_symbol(target_if_spectral_sops_sim_is_active);
749 
750 uint32_t
751 target_if_spectral_sops_sim_is_enabled(void *arg)
752 {
753 	struct target_if_spectral *spectral = NULL;
754 	struct spectralsim_context *simctx = NULL;
755 
756 	spectral = (struct target_if_spectral *)arg;
757 	if (!spectral) {
758 		spectral_err("Spectral simulation: spectral pointer is null");
759 		return 0;
760 	}
761 	simctx = (struct spectralsim_context *)spectral->simctx;
762 	if (!simctx) {
763 		spectral_err("Spectral simulation: simctx pointer is null");
764 		return 0;
765 	}
766 
767 	return simctx->is_enabled;
768 }
769 qdf_export_symbol(target_if_spectral_sops_sim_is_enabled);
770 
771 uint32_t
772 target_if_spectral_sops_sim_start_scan(void *arg)
773 {
774 	struct target_if_spectral *spectral = NULL;
775 	struct spectralsim_context *simctx = NULL;
776 
777 	spectral = (struct target_if_spectral *)arg;
778 	if (!spectral) {
779 		spectral_err("Spectral simulation: spectral pointer is null");
780 		return 0;
781 	}
782 	simctx = (struct spectralsim_context *)spectral->simctx;
783 	if (!simctx) {
784 		spectral_err("Spectral simulation: simctx pointer is null");
785 		return 0;
786 	}
787 
788 	if (!simctx->curr_reportset) {
789 		spectral_err("Spectral simulation: No current report set configured  - unable to start simulated Spectral scan");
790 		return 0;
791 	}
792 
793 	if (!simctx->curr_reportset->curr_report) {
794 		spectral_err("Spectral simulation: No report data instances populated - unable to start simulated Spectral scan");
795 		return 0;
796 	}
797 
798 	if (!simctx->is_enabled)
799 		simctx->is_enabled = true;
800 
801 	simctx->is_active = true;
802 
803 	/* Hardcoding current time as zero since it is simulation */
804 	simctx->ssim_starting_tsf64 = 0;
805 	simctx->ssim_count = 0;
806 
807 	/*
808 	 * TODO: Support high resolution timer in microseconds if required, so
809 	 * that
810 	 * we can support default periods such as ~200 us.  For now, we use 1
811 	 * millisecond since the current use case for the simulation is to
812 	 * validate
813 	 * formats rather than have a time dependent classification.
814 	 */
815 	simctx->ssim_period_ms = 1;
816 
817 	qdf_timer_start(&simctx->ssim_pherrdelivery_timer,
818 			simctx->ssim_period_ms);
819 
820 	return 1;
821 }
822 qdf_export_symbol(target_if_spectral_sops_sim_start_scan);
823 
824 uint32_t
825 target_if_spectral_sops_sim_stop_scan(void *arg)
826 {
827 	struct target_if_spectral *spectral = NULL;
828 	struct spectralsim_context *simctx = NULL;
829 
830 	spectral = (struct target_if_spectral *)arg;
831 	if (!spectral) {
832 		spectral_err("Spectral simulation: spectral pointer is null");
833 		return 0;
834 	}
835 	simctx = (struct spectralsim_context *)spectral->simctx;
836 	if (!simctx) {
837 		spectral_err("Spectral simulation: simctx pointer is null");
838 		return 0;
839 	}
840 
841 	qdf_timer_stop(&simctx->ssim_pherrdelivery_timer);
842 
843 	simctx->is_active = false;
844 	simctx->is_enabled = false;
845 
846 	simctx->ssim_starting_tsf64 = 0;
847 	simctx->ssim_count = 0;
848 	simctx->ssim_period_ms = 0;
849 
850 	return 1;
851 }
852 qdf_export_symbol(target_if_spectral_sops_sim_stop_scan);
853 
854 #ifdef SPECTRAL_SIM_DUMP_PARAM_DATA
855 static void
856 target_if_log_sim_spectral_params(struct spectral_config *params)
857 {
858 	int i = 0;
859 
860 	spectral_debug("\n");
861 
862 	spectral_debug("Spectral simulation: Param data dump:\nss_fft_period=%hu\nss_period=%hu\nss_count=%hu\nss_short_report=%hu\nradar_bin_thresh_sel=%hhu\nss_spectral_pri=%hu\nss_fft_size=%hu\nss_gc_ena=%hu\nss_restart_ena=%hu\nss_noise_floor_ref=%hu\nss_init_delay=%hu\nss_nb_tone_thr=%hu\nss_str_bin_thr=%hu\nss_wb_rpt_mode=%hu\nss_rssi_rpt_mode=%hu\nss_rssi_thr=%hu\nss_pwr_format=%hu\nss_rpt_mode=%hu\nss_bin_scale=%hu\nss_dbm_adj=%hu\nss_chn_mask=%hu\nss_nf_temp_data=%d",
863 		       params->ss_fft_period,
864 		       params->ss_period,
865 		       params->ss_count,
866 		       params->ss_short_report,
867 		       params->radar_bin_thresh_sel,
868 		       params->ss_spectral_pri,
869 		       params->ss_fft_size,
870 		       params->ss_gc_ena,
871 		       params->ss_restart_ena,
872 		       params->ss_noise_floor_ref,
873 		       params->ss_init_delay,
874 		       params->ss_nb_tone_thr,
875 		       params->ss_str_bin_thr,
876 		       params->ss_wb_rpt_mode,
877 		       params->ss_rssi_rpt_mode,
878 		       params->ss_rssi_thr,
879 		       params->ss_pwr_format,
880 		       params->ss_rpt_mode,
881 		       params->ss_bin_scale,
882 		       params->ss_dbm_adj,
883 		       params->ss_chn_mask, params->ss_nf_temp_data);
884 
885 	for (i = 0; i < AH_MAX_CHAINS * 2; i++)
886 		spectral_debug("ss_nf_cal[%d]=%hhd", i, params->ss_nf_cal[i]);
887 
888 	for (i = 0; i < AH_MAX_CHAINS * 2; i++)
889 		spectral_debug("ss_nf_pwr[%d]=%hhd", i, params->ss_nf_pwr[i]);
890 
891 	spectral_info("\n");
892 }
893 #else
894 
895 static void
896 target_if_log_sim_spectral_params(struct spectral_config *params)
897 {
898 }
899 #endif				/* SPECTRAL_SIM_DUMP_PARAM_DATA */
900 
901 uint32_t
902 target_if_spectral_sops_sim_configure_params(
903 	void *arg,
904 	struct spectral_config *params,
905 	enum spectral_scan_mode smode)
906 {
907 	struct target_if_spectral *spectral = NULL;
908 	struct spectralsim_context *simctx = NULL;
909 	enum wlan_phymode phymode;
910 	uint8_t bw;
911 	struct spectralsim_reportset *des_headreportset = NULL;
912 	struct spectralsim_reportset *temp_reportset = NULL;
913 	struct wlan_objmgr_vdev *vdev = NULL;
914 
915 	if (!params) {
916 		spectral_err("Spectral simulation: params pointer is null.")
917 		return 0;
918 	}
919 	target_if_log_sim_spectral_params(params);
920 
921 	spectral = (struct target_if_spectral *)arg;
922 	if (!spectral) {
923 		spectral_err("Spectral simulation: spectral pointer is null");
924 		return 0;
925 	}
926 	simctx = (struct spectralsim_context *)spectral->simctx;
927 	if (!simctx) {
928 		spectral_err("Spectral simulation: simctx pointer is null");
929 		return 0;
930 	}
931 
932 	vdev = target_if_spectral_get_vdev(spectral, smode);
933 	if (!vdev) {
934 		spectral_warn("Spectral simulation: No VAPs found - not proceeding with param config.");
935 		return 0;
936 	}
937 
938 	bw = target_if_vdev_get_ch_width(vdev);
939 
940 	switch (bw) {
941 	case CH_WIDTH_20MHZ:
942 		des_headreportset = simctx->bw20_headreportset;
943 		break;
944 	case CH_WIDTH_40MHZ:
945 		des_headreportset = simctx->bw40_headreportset;
946 		break;
947 	case CH_WIDTH_80MHZ:
948 		des_headreportset = simctx->bw80_headreportset;
949 		break;
950 	case CH_WIDTH_160MHZ:
951 		des_headreportset = simctx->bw160_headreportset;
952 		break;
953 	case CH_WIDTH_80P80MHZ:
954 		des_headreportset = simctx->bw80_80_headreportset;
955 		break;
956 	case CH_WIDTH_INVALID:
957 	default:
958 		spectral_err("Spectral simulation: Invalid width: %d configured - not proceeding with param config.",
959 			     bw);
960 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
961 		return 0;
962 	}
963 
964 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
965 
966 	if (!des_headreportset) {
967 		spectral_warn("Spectral simulation: No simulation data present for configured bandwidth/PHY mode - unable to proceed  with param config.");
968 		return 0;
969 	}
970 
971 	simctx->curr_reportset = NULL;
972 	temp_reportset = des_headreportset;
973 
974 	while (temp_reportset) {
975 		if (qdf_mem_cmp(&temp_reportset->config,
976 				params, sizeof(struct spectral_config)) == 0) {
977 			/* Found a matching config. We are done. */
978 			simctx->curr_reportset = temp_reportset;
979 			break;
980 		}
981 
982 		temp_reportset = temp_reportset->next;
983 	}
984 
985 	if (!simctx->curr_reportset) {
986 		spectral_warn("Spectral simulation: No simulation data present for desired Spectral configuration - unable to proceed with param config.");
987 		return 0;
988 	}
989 
990 	if (!simctx->curr_reportset->curr_report) {
991 		spectral_warn("Spectral simulation: No report data instances populated for desired Spectral configuration - unable to proceed with param config");
992 		return 0;
993 	}
994 
995 	return 1;
996 }
997 qdf_export_symbol(target_if_spectral_sops_sim_configure_params);
998 
999 uint32_t
1000 target_if_spectral_sops_sim_get_params(
1001 	void *arg, struct spectral_config *params)
1002 {
1003 	struct target_if_spectral *spectral = NULL;
1004 	struct spectralsim_context *simctx = NULL;
1005 	spectral = (struct target_if_spectral *)arg;
1006 
1007 	if (!param || !spectral) {
1008 		spectral_err("Spectral simulation: null params, param %pK, spectral %pK.",
1009 			     param, spectral);
1010 		return 0;
1011 	}
1012 
1013 	simctx = (struct spectralsim_context *)spectral->simctx;
1014 	if (!simctx) {
1015 		spectral_err("Spectral simulation: simctx pointer is null.");
1016 		return 0;
1017 	}
1018 
1019 	if (!simctx->curr_reportset) {
1020 		spectral_warn("Spectral simulation: No configured reportset found.");
1021 		return 0;
1022 	}
1023 
1024 	qdf_mem_copy(params, &simctx->curr_reportset->config, sizeof(*params));
1025 
1026 	return 1;
1027 }
1028 qdf_export_symbol(target_if_spectral_sops_sim_get_params);
1029 
1030 #endif				/* QCA_SUPPORT_SPECTRAL_SIMULATION */
1031