/* * Copyright (c) 2015,2017-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef QCA_SUPPORT_SPECTRAL_SIMULATION #include "target_if_spectral.h" #include "target_if_spectral_sim.h" #include "target_if_spectral_sim_int.h" #include "_ieee80211.h" #include "ieee80211_api.h" #include "ieee80211_defines.h" #include "qdf_types.h" #include "ieee80211_var.h" #include #include /* Helper functions */ static int target_if_populate_report_static_gen2( struct spectralsim_report *report, enum phy_ch_width width, bool is_80_80); static int target_if_populate_report_static_gen3( struct spectralsim_report *report, enum phy_ch_width width, bool is_80_80); static void target_if_depopulate_report( struct spectralsim_report *report); static int target_if_populate_reportset_static( struct spectralsim_context *simctx, struct spectralsim_reportset *reportset, enum phy_ch_width width, bool is_80_80); static void target_if_depopulate_reportset( struct spectralsim_reportset * reportset); static int target_if_populate_simdata(struct spectralsim_context *simctx); static void target_if_depopulate_simdata(struct spectralsim_context *simctx); static OS_TIMER_FUNC(target_if_spectral_sim_phyerrdelivery_handler); /* * Static configuration. * For now, we will be having a single configuration per BW, and a single * report per configuration (since we need the data only for ensuring correct * format handling). * * Extend this for more functionality if required in the future. */ /** * target_if_populate_report_static_gen2() - Statically populate simulation * data for one report for generation 2 chipsets * @report: Pointer to spectral report data instance * @width : Channel bandwidth enumeration * * Statically populate simulation data for one report for generation 2 chipsets * * Return: 0 on success, negative error code on failure */ static int target_if_populate_report_static_gen2( struct spectralsim_report *report, enum phy_ch_width width) { if (!report) { spectral_err("report pointer is null."); goto bad; } switch (width) { case CH_WIDTH_20MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_20_gen2)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_20_gen2); qdf_mem_copy(report->data, reportdata_20_gen2, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_20, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_20, sizeof(report->chan_info)); break; case CH_WIDTH_40MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_40_gen2)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_40_gen2); qdf_mem_copy(report->data, reportdata_40_gen2, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_40, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_40, sizeof(report->chan_info)); break; case CH_WIDTH_80MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_80_gen2)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_80_gen2); qdf_mem_copy(report->data, reportdata_80_gen2, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_80, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_80, sizeof(report->chan_info)); break; case CH_WIDTH_80P80MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_80_80_gen2)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_80_80_gen2); qdf_mem_copy(report->data, reportdata_80_80_gen2, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_80_80, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_80_80, sizeof(report->chan_info)); break; case CH_WIDTH_160MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_160_gen2)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_160_gen2); qdf_mem_copy(report->data, reportdata_160_gen2, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_160, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_160, sizeof(report->chan_info)); break; default: spectral_err("Unhandled width enum: %d. Please correct.", width); goto bad; } return 0; bad: return -EPERM; } /** * target_if_populate_report_static_gen3() - Statically populate simulation * data for one report for generation 3 chipsets * @report: Pointer to spectral report data instance * @width : Channel bandwidth enumeration * * Statically populate simulation data for one report for generation 3 chipsets * * Return: 0 on success, negative error code on failure */ static int target_if_populate_report_static_gen3( struct spectralsim_report *report, enum phy_ch_width width) { if (!report) { spectral_err("report pointer is null"); goto bad; } switch (width) { case CH_WIDTH_20MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_20_gen3)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_20_gen3); qdf_mem_copy(report->data, reportdata_20_gen3, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_20, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_20, sizeof(report->chan_info)); break; case CH_WIDTH_40MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_40_gen3)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_40_gen3); qdf_mem_copy(report->data, reportdata_40_gen3, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_40, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_40, sizeof(report->chan_info)); break; case CH_WIDTH_80MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_80_gen3)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_80_gen3); qdf_mem_copy(report->data, reportdata_80_gen3, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_80, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_80, sizeof(report->chan_info)); break; case CH_WIDTH_80P80MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_80_80_gen3)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_80_80_gen3); qdf_mem_copy(report->data, reportdata_80_80_gen3, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_80_80, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_80_80, sizeof(report->chan_info)); break; case CH_WIDTH_160MHZ: report->data = NULL; report->data = (uint8_t *) qdf_mem_malloc(sizeof(reportdata_160_gen3)); if (!report->data) goto bad; report->datasize = sizeof(reportdata_160_gen3); qdf_mem_copy(report->data, reportdata_160_gen3, report->datasize); qdf_mem_copy(&report->rfqual_info, &rfqual_info_160, sizeof(report->rfqual_info)); qdf_mem_copy(&report->chan_info, &chan_info_160, sizeof(report->chan_info)); break; default: spectral_err("Unhandled width enum: %d. Please correct.", width); goto bad; } return 0; bad: return -EPERM; } /** * target_if_depopulate_report() - Free the given instances of * struct spectralsim_report * @report: instance of struct spectralsim_report * * Free the given instances of struct spectralsim_report * * Return: None */ static void target_if_depopulate_report( struct spectralsim_report *report) { if (!report) return; if (report->data) { qdf_mem_free(report->data); report->data = NULL; report->datasize = 0; } } /** * target_if_populate_reportset_static() - Statically populate simulation data * for a given configuration * @simctx: Pointer to struct spectralsim_context * @reportset: Set of spectral report data instances * @width : Channel bandwidth enumeration * * Statically populate simulation data for a given configuration * * Return: 0 on success, negative error code on failure */ static int target_if_populate_reportset_static( struct spectralsim_context *simctx, struct spectralsim_reportset *reportset, enum phy_ch_width width) { int ret = 0; struct spectralsim_report *report = NULL; if (!reportset) { spectral_err("reportset pointer is null."); goto bad; } reportset->headreport = NULL; reportset->curr_report = NULL; /* For now, we populate only one report */ report = (struct spectralsim_report *) qdf_mem_malloc(sizeof(struct spectralsim_report)); if (!report) goto bad; qdf_mem_zero(report, sizeof(*report)); switch (width) { case CH_WIDTH_20MHZ: qdf_mem_copy(&reportset->config, &config_20_1, sizeof(reportset->config)); ret = simctx->populate_report_static(report, CH_WIDTH_20MHZ); if (ret != 0) goto bad; report->next = NULL; reportset->headreport = report; break; case CH_WIDTH_40MHZ: qdf_mem_copy(&reportset->config, &config_40_1, sizeof(reportset->config)); ret = simctx->populate_report_static(report, CH_WIDTH_40MHZ); if (ret != 0) goto bad; report->next = NULL; reportset->headreport = report; break; case CH_WIDTH_80MHZ: qdf_mem_copy(&reportset->config, &config_80_1, sizeof(reportset->config)); ret = simctx->populate_report_static(report, CH_WIDTH_80MHZ); if (ret != 0) goto bad; report->next = NULL; reportset->headreport = report; break; case CH_WIDTH_80P80MHZ: qdf_mem_copy(&reportset->config, &config_80_80_1, sizeof(reportset->config)); ret = simctx->populate_report_static(report, CH_WIDTH_80P80MHZ); if (ret != 0) goto bad; report->next = NULL; reportset->headreport = report; break; case CH_WIDTH_160MHZ: qdf_mem_copy(&reportset->config, &config_160_1, sizeof(reportset->config)); ret = simctx->populate_report_static(report, CH_WIDTH_160MHZ); if (ret != 0) goto bad; report->next = NULL; reportset->headreport = report; break; default: spectral_err("Unhandled width enum: %d. Please correct.", width); goto bad; }; reportset->curr_report = reportset->headreport; return 0; bad: target_if_depopulate_reportset(reportset); return -EPERM; } /** * target_if_depopulate_reportset() - Free all the instances of * struct spectralsim_reportset * @reportset: head pointer to struct spectralsim_reportset linked list * * Free all the instances of struct spectralsim_reportset * * Return: None */ static void target_if_depopulate_reportset( struct spectralsim_reportset *reportset) { struct spectralsim_report *curr_report = NULL; struct spectralsim_report *next_report = NULL; if (!reportset) return; curr_report = reportset->headreport; while (curr_report) { next_report = curr_report->next; target_if_depopulate_report(curr_report); qdf_mem_free(curr_report); curr_report = next_report; } } /** * target_if_populate_simdata() - Populate simulation data * @simctx: Pointer to struct spectralsim_context * * Populate simulation data * * Return: 0 on success, negative error code on failure */ static int target_if_populate_simdata( struct spectralsim_context *simctx) { /* * For now, we use static population. Switch to loading from a file if * needed in the future. */ simctx->bw20_headreportset = NULL; SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx, simctx->bw20_headreportset, CH_WIDTH_20MHZ); simctx->bw40_headreportset = NULL; SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx, simctx->bw40_headreportset, CH_WIDTH_40MHZ); simctx->bw80_headreportset = NULL; SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx, simctx->bw80_headreportset, CH_WIDTH_80MHZ); simctx->bw160_headreportset = NULL; SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx, simctx->bw160_headreportset, CH_WIDTH_160MHZ); simctx->bw80_80_headreportset = NULL; SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx, simctx->bw80_80_headreportset, CH_WIDTH_80P80MHZ); simctx->curr_reportset = NULL; simctx->is_enabled = false; simctx->is_active = false; simctx->ssim_starting_tsf64 = 0; simctx->ssim_count = 0; simctx->ssim_period_ms = 0; return 0; } /** * target_if_depopulate_simdata() - De-populate simulation data * @simctx: Pointer to struct spectralsim_context * * De-populate simulation data * * Return: none */ static void target_if_depopulate_simdata( struct spectralsim_context *simctx) { if (!simctx) return; SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw20_headreportset); SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw40_headreportset); SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw80_headreportset); SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw160_headreportset); SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw80_80_headreportset); } /* * target_if_spectral_sim_phyerrdelivery_handler() - Phyerr delivery handler * * Return: none * * NB: kernel-doc script doesn't parse OS_TIMER_FUNC */ static OS_TIMER_FUNC(target_if_spectral_sim_phyerrdelivery_handler) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; struct spectralsim_reportset *curr_reportset = NULL; struct spectralsim_report *curr_report = NULL; struct target_if_spectral_acs_stats acs_stats; uint64_t curr_tsf64 = 0; struct target_if_spectral_ops *p_sops; OS_GET_TIMER_ARG(spectral, struct target_if_spectral *); if (!spectral) { spectral_err("spectral pointer is null."); return; } p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral); if (!p_sops) { spectral_err("p_sops pointer is null."); return; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("simctx pointer is null."); return; } if (!simctx->is_active) return; curr_reportset = simctx->curr_reportset; if (!curr_reportset) { spectral_err("curr_reportset pointer is null."); return; } curr_report = curr_reportset->curr_report; if (!curr_report) { spectral_err("curr_report pointer is null."); return; } if (!curr_reportset->headreport) { spectral_err("curr_reportset->headreport pointer is null."); return; } /* * We use a simulation TSF since in offload architectures we can't * expect to * get an accurate current TSF from HW. * In case of TSF wrap over, we'll use it as-is for now since the * simulation * is intended only for format verification. */ curr_tsf64 = simctx->ssim_starting_tsf64 + ((simctx->ssim_period_ms * simctx->ssim_count) * 1000); p_sops->spectral_process_phyerr(spectral, curr_report->data, curr_report->datasize, &curr_report->rfqual_info, &curr_report->chan_info, curr_tsf64, &acs_stats); simctx->ssim_count++; if (curr_report->next) curr_reportset->curr_report = curr_report->next; else curr_reportset->curr_report = curr_reportset->headreport; if (curr_reportset->config.ss_count != 0 && simctx->ssim_count == curr_reportset->config.ss_count) { target_if_spectral_sops_sim_stop_scan(spectral); } else { qdf_timer_start(&simctx->ssim_pherrdelivery_timer, simctx->ssim_period_ms); } } /* Module services */ int target_if_spectral_sim_attach(struct target_if_spectral *spectral) { struct spectralsim_context *simctx = NULL; if (!spectral) { spectral_err("Spectral simulation: spectral pointer is null.") return -EPERM; } simctx = (struct spectralsim_context *) qdf_mem_malloc(sizeof(struct spectralsim_context)); if (!simctx) return -EPERM; qdf_mem_zero(simctx, sizeof(*simctx)); spectral->simctx = simctx; if (spectral->spectral_gen == SPECTRAL_GEN2) simctx->populate_report_static = target_if_populate_report_static_gen2; else if (spectral->spectral_gen == SPECTRAL_GEN3) simctx->populate_report_static = target_if_populate_report_static_gen3; if (target_if_populate_simdata(simctx) != 0) { qdf_mem_free(simctx); spectral->simctx = NULL; spectral_err("Spectral simulation attach failed"); return -EPERM; } qdf_timer_init(NULL, &simctx->ssim_pherrdelivery_timer, target_if_spectral_sim_phyerrdelivery_handler, (void *)(spectral), QDF_TIMER_TYPE_WAKE_APPS); spectral_info("Spectral simulation attached"); return 0; } void target_if_spectral_sim_detach(struct target_if_spectral *spectral) { struct spectralsim_context *simctx = NULL; if (!spectral) { spectral_err("spectral pointer is null."); return; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("simctx pointer is null."); return; } qdf_timer_free(&simctx->ssim_pherrdelivery_timer); target_if_depopulate_simdata(simctx); qdf_mem_free(simctx); spectral->simctx = NULL; spectral_info("Spectral simulation detached"); } uint32_t target_if_spectral_sops_sim_is_active(void *arg) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; spectral = (struct target_if_spectral *)arg; if (!spectral) { spectral_err("Spectral simulation: spectral pointer is null"); return 0; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("Spectral simulation: simctx pointer is null"); return 0; } return simctx->is_active; } qdf_export_symbol(target_if_spectral_sops_sim_is_active); uint32_t target_if_spectral_sops_sim_is_enabled(void *arg) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; spectral = (struct target_if_spectral *)arg; if (!spectral) { spectral_err("Spectral simulation: spectral pointer is null"); return 0; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("Spectral simulation: simctx pointer is null"); return 0; } return simctx->is_enabled; } qdf_export_symbol(target_if_spectral_sops_sim_is_enabled); uint32_t target_if_spectral_sops_sim_start_scan(void *arg) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; spectral = (struct target_if_spectral *)arg; if (!spectral) { spectral_err("Spectral simulation: spectral pointer is null"); return 0; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("Spectral simulation: simctx pointer is null"); return 0; } if (!simctx->curr_reportset) { spectral_err("Spectral simulation: No current report set configured - unable to start simulated Spectral scan"); return 0; } if (!simctx->curr_reportset->curr_report) { spectral_err("Spectral simulation: No report data instances populated - unable to start simulated Spectral scan"); return 0; } if (!simctx->is_enabled) simctx->is_enabled = true; simctx->is_active = true; /* Hardcoding current time as zero since it is simulation */ simctx->ssim_starting_tsf64 = 0; simctx->ssim_count = 0; /* * TODO: Support high resolution timer in microseconds if required, so * that * we can support default periods such as ~200 us. For now, we use 1 * millisecond since the current use case for the simulation is to * validate * formats rather than have a time dependent classification. */ simctx->ssim_period_ms = 1; qdf_timer_start(&simctx->ssim_pherrdelivery_timer, simctx->ssim_period_ms); return 1; } qdf_export_symbol(target_if_spectral_sops_sim_start_scan); uint32_t target_if_spectral_sops_sim_stop_scan(void *arg) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; spectral = (struct target_if_spectral *)arg; if (!spectral) { spectral_err("Spectral simulation: spectral pointer is null"); return 0; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("Spectral simulation: simctx pointer is null"); return 0; } qdf_timer_stop(&simctx->ssim_pherrdelivery_timer); simctx->is_active = false; simctx->is_enabled = false; simctx->ssim_starting_tsf64 = 0; simctx->ssim_count = 0; simctx->ssim_period_ms = 0; return 1; } qdf_export_symbol(target_if_spectral_sops_sim_stop_scan); #ifdef SPECTRAL_SIM_DUMP_PARAM_DATA static void target_if_log_sim_spectral_params(struct spectral_config *params) { int i = 0; spectral_debug("\n"); 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", params->ss_fft_period, params->ss_period, params->ss_count, params->ss_short_report, params->radar_bin_thresh_sel, params->ss_spectral_pri, params->ss_fft_size, params->ss_gc_ena, params->ss_restart_ena, params->ss_noise_floor_ref, params->ss_init_delay, params->ss_nb_tone_thr, params->ss_str_bin_thr, params->ss_wb_rpt_mode, params->ss_rssi_rpt_mode, params->ss_rssi_thr, params->ss_pwr_format, params->ss_rpt_mode, params->ss_bin_scale, params->ss_dbm_adj, params->ss_chn_mask, params->ss_nf_temp_data); for (i = 0; i < AH_MAX_CHAINS * 2; i++) spectral_debug("ss_nf_cal[%d]=%hhd", i, params->ss_nf_cal[i]); for (i = 0; i < AH_MAX_CHAINS * 2; i++) spectral_debug("ss_nf_pwr[%d]=%hhd", i, params->ss_nf_pwr[i]); spectral_info("\n"); } #else static void target_if_log_sim_spectral_params(struct spectral_config *params) { } #endif /* SPECTRAL_SIM_DUMP_PARAM_DATA */ uint32_t target_if_spectral_sops_sim_configure_params( void *arg, struct spectral_config *params, enum spectral_scan_mode smode) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; enum wlan_phymode phymode; uint8_t bw; struct spectralsim_reportset *des_headreportset = NULL; struct spectralsim_reportset *temp_reportset = NULL; struct wlan_objmgr_vdev *vdev = NULL; if (!params) { spectral_err("Spectral simulation: params pointer is null.") return 0; } target_if_log_sim_spectral_params(params); spectral = (struct target_if_spectral *)arg; if (!spectral) { spectral_err("Spectral simulation: spectral pointer is null"); return 0; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("Spectral simulation: simctx pointer is null"); return 0; } vdev = target_if_spectral_get_vdev(spectral, smode); if (!vdev) { spectral_warn("Spectral simulation: No VAPs found - not proceeding with param config."); return 0; } bw = target_if_vdev_get_ch_width(vdev); switch (bw) { case CH_WIDTH_20MHZ: des_headreportset = simctx->bw20_headreportset; break; case CH_WIDTH_40MHZ: des_headreportset = simctx->bw40_headreportset; break; case CH_WIDTH_80MHZ: des_headreportset = simctx->bw80_headreportset; break; case CH_WIDTH_160MHZ: des_headreportset = simctx->bw160_headreportset; break; case CH_WIDTH_80P80MHZ: des_headreportset = simctx->bw80_80_headreportset; break; case CH_WIDTH_INVALID: default: spectral_err("Spectral simulation: Invalid width: %d configured - not proceeding with param config.", bw); wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); return 0; } wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); if (!des_headreportset) { spectral_warn("Spectral simulation: No simulation data present for configured bandwidth/PHY mode - unable to proceed with param config."); return 0; } simctx->curr_reportset = NULL; temp_reportset = des_headreportset; while (temp_reportset) { if (qdf_mem_cmp(&temp_reportset->config, params, sizeof(struct spectral_config)) == 0) { /* Found a matching config. We are done. */ simctx->curr_reportset = temp_reportset; break; } temp_reportset = temp_reportset->next; } if (!simctx->curr_reportset) { spectral_warn("Spectral simulation: No simulation data present for desired Spectral configuration - unable to proceed with param config."); return 0; } if (!simctx->curr_reportset->curr_report) { spectral_warn("Spectral simulation: No report data instances populated for desired Spectral configuration - unable to proceed with param config"); return 0; } return 1; } qdf_export_symbol(target_if_spectral_sops_sim_configure_params); uint32_t target_if_spectral_sops_sim_get_params( void *arg, struct spectral_config *params) { struct target_if_spectral *spectral = NULL; struct spectralsim_context *simctx = NULL; spectral = (struct target_if_spectral *)arg; if (!param || !spectral) { spectral_err("Spectral simulation: null params, param %pK, spectral %pK.", param, spectral); return 0; } simctx = (struct spectralsim_context *)spectral->simctx; if (!simctx) { spectral_err("Spectral simulation: simctx pointer is null."); return 0; } if (!simctx->curr_reportset) { spectral_warn("Spectral simulation: No configured reportset found."); return 0; } qdf_mem_copy(params, &simctx->curr_reportset->config, sizeof(*params)); return 1; } qdf_export_symbol(target_if_spectral_sops_sim_get_params); #endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */