diff --git a/os_if/linux/spectral/src/wlan_cfg80211_spectral.c b/os_if/linux/spectral/src/wlan_cfg80211_spectral.c index 7d512d5226..95191d89b9 100644 --- a/os_if/linux/spectral/src/wlan_cfg80211_spectral.c +++ b/os_if/linux/spectral/src/wlan_cfg80211_spectral.c @@ -91,6 +91,8 @@ const struct nla_policy spectral_scan_policy[ .type = NLA_U8}, [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DMA_BUFFER_DEBUG] = { .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH] = { + .type = NLA_U8}, }; const struct nla_policy spectral_scan_get_status_policy[ @@ -126,6 +128,7 @@ static void wlan_spectral_intit_config(struct spectral_config *config_req) config_req->ss_chn_mask = SPECTRAL_PHYERR_PARAM_NOVAL; config_req->ss_frequency.cfreq1 = SPECTRAL_PHYERR_PARAM_NOVAL; config_req->ss_frequency.cfreq2 = SPECTRAL_PHYERR_PARAM_NOVAL; + config_req->ss_bandwidth = SPECTRAL_PHYERR_PARAM_NOVAL; } /** @@ -369,6 +372,10 @@ int wlan_cfg80211_spectral_scan_config_and_start(struct wiphy *wiphy, config_req.ss_frequency.cfreq2 = nla_get_u32(tb [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY_2]); + if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH]) + config_req.ss_bandwidth = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH]); + if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]) { status = convert_spectral_mode_nl_to_internal(nla_get_u32(tb [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]), &sscan_mode); @@ -676,7 +683,10 @@ int wlan_cfg80211_spectral_scan_get_config(struct wiphy *wiphy, sconfig->ss_frequency.cfreq1) || nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY_2, - sconfig->ss_frequency.cfreq2)) + sconfig->ss_frequency.cfreq2) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH, + sconfig->ss_bandwidth)) goto fail; diff --git a/spectral/core/spectral_common.c b/spectral/core/spectral_common.c index ea78c3166b..035d73439f 100644 --- a/spectral/core/spectral_common.c +++ b/spectral/core/spectral_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011,2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2011,2017-2021 The Linux Foundation. All rights reserved. * * * Permission to use, copy, modify, and/or distribute this software for @@ -343,6 +343,15 @@ spectral_control_cmn(struct wlan_objmgr_pdev *pdev, goto bad; } + if (sp_in->ss_bandwidth != SPECTRAL_PHYERR_PARAM_NOVAL) { + param.id = SPECTRAL_PARAM_CHAN_WIDTH; + param.value = sp_in->ss_bandwidth; + ret = sc->sptrlc_set_spectral_config + (pdev, ¶m, smode, err); + if (QDF_IS_STATUS_ERROR(ret)) + goto bad; + } + break; case SPECTRAL_GET_CONFIG: @@ -373,6 +382,7 @@ spectral_control_cmn(struct wlan_objmgr_pdev *pdev, spectralparams->ss_dbm_adj = sp_out.ss_dbm_adj; spectralparams->ss_chn_mask = sp_out.ss_chn_mask; spectralparams->ss_frequency = sp_out.ss_frequency; + spectralparams->ss_bandwidth = sp_out.ss_bandwidth; break; case SPECTRAL_IS_ACTIVE: diff --git a/spectral/dispatcher/inc/spectral_ioctl.h b/spectral/dispatcher/inc/spectral_ioctl.h index 475fa8a0ae..2c8b5329b2 100644 --- a/spectral/dispatcher/inc/spectral_ioctl.h +++ b/spectral/dispatcher/inc/spectral_ioctl.h @@ -309,6 +309,7 @@ struct spectral_config_frequency { * span of interest or center frequency (in MHz) of * any WLAN channel in the secondary 80 MHz span of * interest. + * @ss_bandwidth: Spectral scan bandwidth */ struct spectral_config { uint16_t ss_fft_period; @@ -336,6 +337,7 @@ struct spectral_config { int8_t ss_nf_pwr[AH_MAX_CHAINS * 2]; int32_t ss_nf_temp_data; struct spectral_config_frequency ss_frequency; + uint16_t ss_bandwidth; }; /** diff --git a/target_if/spectral/target_if_spectral.c b/target_if/spectral/target_if_spectral.c index ae30c84c0b..0984f747db 100644 --- a/target_if/spectral/target_if_spectral.c +++ b/target_if/spectral/target_if_spectral.c @@ -525,7 +525,7 @@ target_if_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral, sparam.mode = smode; sparam.center_freq1 = param->ss_frequency.cfreq1; sparam.center_freq2 = param->ss_frequency.cfreq2; - sparam.chan_width = spectral->ch_width[smode]; + sparam.chan_width = param->ss_bandwidth; return psoc_spectral->wmi_ops.wmi_spectral_configure_cmd_send( GET_WMI_HDL_FROM_PDEV(pdev), &sparam); @@ -595,6 +595,240 @@ target_if_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral, GET_WMI_HDL_FROM_PDEV(pdev), ¶m); } +/** + * is_spectral_arch_beryllium() - Check whether the given target Spectral + * architecture is Beryllium + * @target_tpe: Target type + * + * Return: true if the spectral architecture is Beryllium, else false + */ +static inline bool is_spectral_arch_beryllium(uint32_t target_tpe) +{ + if (target_tpe == TARGET_TYPE_QCN9224) + return true; + + return false; +} + +/** + * List of supported sscan BWs. Make sure to maintain the array elements in the + * same order of BWs as that of struct spectral_supported_bws bitmap. + */ +static const enum phy_ch_width supported_sscan_bw_list[] = { + CH_WIDTH_5MHZ, + CH_WIDTH_10MHZ, + CH_WIDTH_20MHZ, + CH_WIDTH_40MHZ, + CH_WIDTH_80MHZ, + CH_WIDTH_160MHZ, + CH_WIDTH_80P80MHZ, +#ifdef WLAN_FEATURE_11BE + CH_WIDTH_320MHZ, +#endif +}; + +#define INVALID_SSCAN_BW_POS (-1) +int get_supported_sscan_bw_pos(enum phy_ch_width sscan_bw) +{ + int max_pos, pos; + + max_pos = QDF_ARRAY_SIZE(supported_sscan_bw_list); + for (pos = 0; pos < max_pos; pos++) { + if (supported_sscan_bw_list[pos] == sscan_bw) + return pos; + } + + return INVALID_SSCAN_BW_POS; +} + +/** + * target_if_is_sscan_bw_supported() - Check whether the given sscan_bw is + * supported + * @spectral: Spectral LMAC object + * @smode: Spectral scan mode + * @sscan_bw: Spectral scan bandwidth + * @op_bw: operating bandwidth + * @is_bw_supported: Pointer to the caller variable where this function + * populates whether @sscan_bw is supported + * @is_80_80_agile: Indicates an 80+80 agile Scan request + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS +target_if_is_sscan_bw_supported(struct target_if_spectral *spectral, + enum spectral_scan_mode smode, + enum phy_ch_width sscan_bw, + enum phy_ch_width op_bw, + bool *is_bw_supported, + bool is_80_80_agile) +{ + struct spectral_supported_bws *supported_bws; + + *is_bw_supported = false; + + if (op_bw >= CH_WIDTH_INVALID) { + spectral_err("Invalid channel width %d", op_bw); + return QDF_STATUS_E_INVAL; + } + + if ((is_80_80_agile && sscan_bw != CH_WIDTH_80P80MHZ) || + (!is_80_80_agile && sscan_bw == CH_WIDTH_80P80MHZ)) { + *is_bw_supported = false; + return QDF_STATUS_SUCCESS; + } + + /* Get the supported sscan bandwidths for this operating bandwidth */ + supported_bws = &spectral->supported_bws[smode][op_bw]; + *is_bw_supported = supported_bws->bandwidths & + (1 << get_supported_sscan_bw_pos(sscan_bw)); + + return QDF_STATUS_SUCCESS; +} + +/** + * get_max_sscan_bw() - Get the maximum sscan bandwidth for a given operating + * bandwidth + * @spectral: Spectral LMAC object + * @smode: Spectral scan mode + * @op_bw: operating bandwidth + * + * Return: Maximum sscan bandwidth for @op_bw on success, else CH_WIDTH_INVALID + */ +static enum phy_ch_width +get_max_sscan_bw(struct target_if_spectral *spectral, + enum spectral_scan_mode smode, + enum phy_ch_width op_bw) +{ + int op_bw_pos, pos; + struct spectral_supported_bws *supported_bws; + + supported_bws = &spectral->supported_bws[smode][op_bw]; + op_bw_pos = get_supported_sscan_bw_pos(op_bw); + + /** + * Start with operating bandwidth, and keep reducing the bandwidth until + * a supported sscan BW is found. + */ + for (pos = op_bw_pos; pos >= 0; pos--) { + if (supported_bws->bandwidths & (1 << pos)) + return supported_sscan_bw_list[pos]; + } + + return CH_WIDTH_INVALID; +} + +/* target_if_spectral_find_agile_width() - Given a channel width enum, find the + * corresponding translation for Agile channel width. + * @spectral: pointer to Spectral object + * @op_width: operating channel width + * @is_80_80_agile: Indicates an 80+80 agile Scan request + * + * Return: The translated channel width enum. + */ +static enum phy_ch_width +target_if_spectral_find_agile_width(struct target_if_spectral *spectral, + enum phy_ch_width op_bw, + bool is_80_80_agile) +{ + enum phy_ch_width agile_width; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + + if (!spectral) { + spectral_err("Spectral object is null"); + return CH_WIDTH_INVALID; + } + + pdev = spectral->pdev_obj; + if (!pdev) { + spectral_err("pdev is null"); + return CH_WIDTH_INVALID; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + spectral_err("psoc is null"); + return CH_WIDTH_INVALID; + } + + agile_width = get_max_sscan_bw(spectral, SPECTRAL_SCAN_MODE_AGILE, + op_bw); + + if (wlan_psoc_nif_fw_ext_cap_get(psoc, + WLAN_SOC_RESTRICTED_80P80_SUPPORT)) { + switch (op_bw) { + case CH_WIDTH_80P80MHZ: + if (!is_80_80_agile) + agile_width = CH_WIDTH_160MHZ; + else + agile_width = CH_WIDTH_80P80MHZ; + + break; + + case CH_WIDTH_160MHZ: + if (is_80_80_agile) + agile_width = CH_WIDTH_80P80MHZ; + else + agile_width = CH_WIDTH_160MHZ; + + break; + + default: + break; + } + } + + return agile_width; +} + +/** + * get_default_sscan_bw() - Get the default sscan bandwidth for a given + * operating bandwidth + * @spectral: Spectral LMAC object + * @smode: Spectral scan mode + * @is_80_80_agile: Indicates an 80+80 agile Scan request + * + * Return: Default sscan bandwidth for @op_bw on success, else CH_WIDTH_INVALID + */ +static enum phy_ch_width +get_default_sscan_bw(struct target_if_spectral *spectral, + enum spectral_scan_mode smode, + bool is_80_80_agile) +{ + struct wlan_objmgr_vdev *vdev; + enum phy_ch_width vdev_ch_width, sscan_width; + + vdev = target_if_spectral_get_vdev(spectral, smode); + if (!vdev) { + spectral_err("vdev is null"); + return CH_WIDTH_INVALID; + } + + vdev_ch_width = target_if_vdev_get_ch_width(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); + if (vdev_ch_width >= CH_WIDTH_INVALID) { + spectral_err("Invalid vdev channel width %d", vdev_ch_width); + return CH_WIDTH_INVALID; + } + + switch (smode) { + case SPECTRAL_SCAN_MODE_NORMAL: + sscan_width = get_max_sscan_bw(spectral, smode, vdev_ch_width); + break; + + case SPECTRAL_SCAN_MODE_AGILE: + sscan_width = target_if_spectral_find_agile_width( + spectral, vdev_ch_width, is_80_80_agile); + break; + + default: + sscan_width = CH_WIDTH_INVALID; + break; + } + + return sscan_width; +} + /** * target_if_spectral_info_init_defaults() - Helper function to load defaults * for Spectral information (parameters and state) into cache. @@ -613,6 +847,7 @@ target_if_spectral_info_init_defaults(struct target_if_spectral *spectral, { struct target_if_spectral_param_state_info *info; struct wlan_objmgr_vdev *vdev = NULL; + enum phy_ch_width sscan_bw; if (smode >= SPECTRAL_SCAN_MODE_MAX) { spectral_err("Invalid Spectral mode %u", smode); @@ -698,6 +933,13 @@ target_if_spectral_info_init_defaults(struct target_if_spectral *spectral, info->osps_cache.osc_params.ss_frequency.cfreq2 = SPECTRAL_SCAN_FREQUENCY_DEFAULT; + sscan_bw = get_default_sscan_bw(spectral, smode, false); + if (sscan_bw >= CH_WIDTH_INVALID) { + spectral_err("Invalid sscan BW %u", sscan_bw); + return QDF_STATUS_E_FAILURE; + } + info->osps_cache.osc_params.ss_bandwidth = sscan_bw; + /* The cache is now valid */ info->osps_cache.osc_is_valid = 1; @@ -1876,6 +2118,182 @@ target_if_init_spectral_param_properties(struct target_if_spectral *spectral) return QDF_STATUS_SUCCESS; } +/* Bandwidth to half bandwidth mapping */ +static const enum phy_ch_width half_bw_map[] = { +#ifdef WLAN_FEATURE_11BE + [CH_WIDTH_320MHZ] = CH_WIDTH_160MHZ, +#endif + [CH_WIDTH_80P80MHZ] = CH_WIDTH_80MHZ, + [CH_WIDTH_160MHZ] = CH_WIDTH_80MHZ, + [CH_WIDTH_80MHZ] = CH_WIDTH_40MHZ, + [CH_WIDTH_40MHZ] = CH_WIDTH_20MHZ, + [CH_WIDTH_20MHZ] = CH_WIDTH_10MHZ, + [CH_WIDTH_10MHZ] = CH_WIDTH_5MHZ, + [CH_WIDTH_5MHZ] = CH_WIDTH_INVALID +}; + +/** + * target_if_get_half_bandwidth() - Get half bandwidth for a given bandwidth + * @bw: bandwidth + * + * Return: Half bandwidth of @bw + */ +static enum phy_ch_width target_if_get_half_bandwidth(enum phy_ch_width bw) +{ + if (bw >= CH_WIDTH_INVALID) + return CH_WIDTH_INVALID; + + return half_bw_map[bw]; +} + +/** + * target_if_populate_supported_sscan_bws_be() - Populate supported spectral + * scan bandwidths for beryllium chipsets + * @spectral: Spectral LMAC object + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS +target_if_populate_supported_sscan_bws_be(struct target_if_spectral *spectral) +{ + enum phy_ch_width op_bw; + struct spectral_supported_bws *supported_bws; + QDF_STATUS status; + + qdf_assert_always(spectral); + + /* 20MHz */ + op_bw = CH_WIDTH_20MHZ; + supported_bws = &spectral->supported_bws + [SPECTRAL_SCAN_MODE_NORMAL][op_bw]; + supported_bws->bandwidths |= 1 << get_supported_sscan_bw_pos(op_bw); + supported_bws = &spectral->supported_bws + [SPECTRAL_SCAN_MODE_AGILE][op_bw]; + supported_bws->bandwidths |= 1 << get_supported_sscan_bw_pos(op_bw); + + for (op_bw = CH_WIDTH_40MHZ; op_bw < CH_WIDTH_MAX; op_bw++) { + bool is_supported; + enum phy_ch_width half_op_bw; + + status = wlan_reg_is_chwidth_supported(spectral->pdev_obj, + op_bw, &is_supported); + if (QDF_IS_STATUS_ERROR(status)) { + spectral_err("Unable to check if ch_width(%d) is supported", + op_bw); + return QDF_STATUS_E_FAILURE; + } + + if (!is_supported) + continue; + + spectral_debug("Updating supported bw for op_bw: %d", op_bw); + /* Normal mode */ + supported_bws = &spectral->supported_bws + [SPECTRAL_SCAN_MODE_NORMAL][op_bw]; + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos(op_bw); + + /* Agile mode */ + supported_bws = &spectral->supported_bws + [SPECTRAL_SCAN_MODE_AGILE][op_bw]; + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos(op_bw); + + half_op_bw = target_if_get_half_bandwidth(op_bw); + if (half_op_bw != CH_WIDTH_INVALID) + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos(half_op_bw); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_populate_supported_sscan_bws() - Populate supported spectral + * scan bandwidths + * @spectral: Spectral LMAC object + * @target_type: Target type + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS +target_if_populate_supported_sscan_bws(struct target_if_spectral *spectral, + uint32_t target_type) +{ + enum spectral_scan_mode smode; + enum phy_ch_width op_bw; + struct spectral_supported_bws *supported_bws; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + qdf_assert_always(spectral); + + if (is_spectral_arch_beryllium(target_type)) + return target_if_populate_supported_sscan_bws_be(spectral); + + psoc = wlan_pdev_get_psoc(spectral->pdev_obj); + if (!psoc) { + spectral_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + for (op_bw = CH_WIDTH_20MHZ; op_bw < CH_WIDTH_MAX; op_bw++) { + bool is_supported; + + status = wlan_reg_is_chwidth_supported(spectral->pdev_obj, + op_bw, &is_supported); + if (QDF_IS_STATUS_ERROR(status)) { + spectral_err("Unable to check if ch_width(%d) is supported", + op_bw); + return QDF_STATUS_E_FAILURE; + } + + if (!is_supported) + continue; + + spectral_debug("Updating supported bw for op_bw: %d", op_bw); + smode = SPECTRAL_SCAN_MODE_NORMAL; + for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) { + supported_bws = &spectral->supported_bws[smode][op_bw]; + + if (is_ch_width_160_or_80p80(op_bw) && + smode == SPECTRAL_SCAN_MODE_AGILE) { + /** + * If fragmentation is supported, then only 80Hz + * agile width is supported + */ + if (spectral->rparams.fragmentation_160[smode]) + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos( + CH_WIDTH_80MHZ); + + /** + * If restricted 80p80 is supported, then both + * 160 and 80p80 agile widths are supported for + * 160MHz, and only 160MHz agile width is + * supported for 80p80 + */ + if (wlan_psoc_nif_fw_ext_cap_get( + psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) { + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos( + CH_WIDTH_160MHZ); + if (op_bw == CH_WIDTH_160MHZ) + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos( + CH_WIDTH_80P80MHZ); + } + } else { + supported_bws->bandwidths |= + 1 << get_supported_sscan_bw_pos( + op_bw); + } + } + } + + return QDF_STATUS_SUCCESS; +} + QDF_STATUS target_if_init_spectral_capability(struct target_if_spectral *spectral, uint32_t target_type) @@ -1887,6 +2305,7 @@ target_if_init_spectral_capability(struct target_if_spectral *spectral, struct target_psoc_info *tgt_psoc_info; struct wlan_psoc_host_service_ext_param *ext_svc_param; struct spectral_caps *pcap = &spectral->capability; + QDF_STATUS status; pdev = spectral->pdev_obj; psoc = wlan_pdev_get_psoc(pdev); @@ -1955,6 +2374,12 @@ target_if_init_spectral_capability(struct target_if_spectral *spectral, pcap->num_detectors_80p80mhz = 2; } + status = target_if_populate_supported_sscan_bws(spectral, target_type); + if (QDF_IS_STATUS_ERROR(status)) { + spectral_err("Unable to populate supported sscan BWs"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; } @@ -3248,84 +3673,6 @@ fail: return psoc_spectral; } -/* target_if_spectral_find_agile_width() - Given a channel width enum, find the - * corresponding translation for Agile channel width. - * @spectral: pointer to Spectral object - * @chwidth: operating channel width - * @is_80_80_agile: Indicates an 80+80 agile Scan request - * - * Return: The translated channel width enum. - */ -static enum phy_ch_width -target_if_spectral_find_agile_width(struct target_if_spectral *spectral, - enum phy_ch_width chwidth, - bool is_80_80_agile) -{ - enum phy_ch_width agile_width; - struct wlan_objmgr_pdev *pdev; - struct wlan_objmgr_psoc *psoc; - - if (!spectral) { - spectral_err("Spectral object is null"); - return CH_WIDTH_INVALID; - } - - pdev = spectral->pdev_obj; - if (!pdev) { - spectral_err("pdev is null"); - return CH_WIDTH_INVALID; - } - - psoc = wlan_pdev_get_psoc(pdev); - if (!psoc) { - spectral_err("psoc is null"); - return CH_WIDTH_INVALID; - } - - switch (chwidth) { - case CH_WIDTH_20MHZ: - agile_width = CH_WIDTH_20MHZ; - break; - - case CH_WIDTH_40MHZ: - agile_width = CH_WIDTH_40MHZ; - break; - - case CH_WIDTH_80MHZ: - agile_width = CH_WIDTH_80MHZ; - break; - - case CH_WIDTH_80P80MHZ: - if (wlan_psoc_nif_fw_ext_cap_get(psoc, - WLAN_SOC_RESTRICTED_80P80_SUPPORT) && !is_80_80_agile) - agile_width = CH_WIDTH_160MHZ; - else - agile_width = CH_WIDTH_80P80MHZ; - - if (agile_width > spectral->rparams.max_agile_ch_width) - agile_width = spectral->rparams.max_agile_ch_width; - break; - - case CH_WIDTH_160MHZ: - if (wlan_psoc_nif_fw_ext_cap_get(psoc, - WLAN_SOC_RESTRICTED_80P80_SUPPORT) && is_80_80_agile) - agile_width = CH_WIDTH_80P80MHZ; - else - agile_width = CH_WIDTH_160MHZ; - - if (agile_width > spectral->rparams.max_agile_ch_width) - agile_width = spectral->rparams.max_agile_ch_width; - break; - - default: - spectral_err("Invalid channel width %d", chwidth); - agile_width = CH_WIDTH_INVALID; - break; - } - - return agile_width; -} - /** * target_if_calculate_center_freq() - Helper routine to * check whether given frequency is center frequency of a @@ -3708,38 +4055,30 @@ target_if_is_agile_span_overlap_with_operating_span static QDF_STATUS target_if_spectral_populate_chwidth(struct target_if_spectral *spectral, enum phy_ch_width *ch_width, - bool is_80_80_agile) { - struct wlan_objmgr_vdev *vdev; + bool is_80_80_agile) +{ enum spectral_scan_mode smode; - enum phy_ch_width vdev_ch_width; + + qdf_assert_always(spectral); smode = SPECTRAL_SCAN_MODE_NORMAL; - for (; smode < SPECTRAL_SCAN_MODE_MAX; smode++) - ch_width[smode] = CH_WIDTH_INVALID; - - if (!spectral) { - spectral_err("Spectral object is null"); - return QDF_STATUS_E_INVAL; + for (; smode < SPECTRAL_SCAN_MODE_MAX; ++smode) { + /* If user has configured sscan bandwidth, use it */ + if (spectral->sscan_width_configured[smode]) { + ch_width[smode] = spectral->params[smode].ss_bandwidth; + } else { + /* Otherwise, derive the default sscan bandwidth */ + ch_width[smode] = get_default_sscan_bw(spectral, smode, + is_80_80_agile); + if (ch_width[smode] >= CH_WIDTH_INVALID) { + spectral_err("Invalid sscan BW %u", + ch_width[smode]); + return QDF_STATUS_E_FAILURE; + } + spectral->params[smode].ss_bandwidth = ch_width[smode]; + } } - vdev = target_if_spectral_get_vdev(spectral, SPECTRAL_SCAN_MODE_NORMAL); - if (!vdev) { - spectral_err("vdev is null"); - return QDF_STATUS_E_FAILURE; - } - - vdev_ch_width = target_if_vdev_get_ch_width(vdev); - wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); - if (vdev_ch_width == CH_WIDTH_INVALID) { - spectral_err("Invalid channel width %d", vdev_ch_width); - return QDF_STATUS_E_FAILURE; - } - - ch_width[SPECTRAL_SCAN_MODE_NORMAL] = vdev_ch_width; - ch_width[SPECTRAL_SCAN_MODE_AGILE] = - target_if_spectral_find_agile_width(spectral, vdev_ch_width, - is_80_80_agile); - return QDF_STATUS_SUCCESS; } @@ -3839,6 +4178,9 @@ _target_if_set_spectral_config(struct target_if_spectral *spectral, enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX]; enum spectral_scan_mode m; struct spectral_config_frequency center_freq = {0}; + bool is_bw_supported; + struct wlan_objmgr_vdev *vdev; + enum phy_ch_width op_bw; if (!err) { spectral_err("Error code argument is null"); @@ -4081,6 +4423,44 @@ _target_if_set_spectral_config(struct target_if_spectral *spectral, sparams->ss_frequency.cfreq1 = center_freq.cfreq1; sparams->ss_frequency.cfreq2 = center_freq.cfreq2; + break; + + case SPECTRAL_PARAM_CHAN_WIDTH: + if (param->value >= CH_WIDTH_INVALID) { + spectral_err("invalid sscan width: %u", param->value); + *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; + return QDF_STATUS_E_FAILURE; + } + + vdev = target_if_spectral_get_vdev(spectral, smode); + if (!vdev) { + spectral_err("vdev is null"); + return QDF_STATUS_E_NULL_VALUE; + } + op_bw = target_if_vdev_get_ch_width(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); + + /* Validate the bandwidth */ + status = target_if_is_sscan_bw_supported( + spectral, smode, + param->value, op_bw, &is_bw_supported, + spectral->params[SPECTRAL_SCAN_MODE_AGILE]. + ss_frequency.cfreq2 > 0); + if (QDF_IS_STATUS_ERROR(status)) { + spectral_err("Unable to check if given sscan_bw is supported"); + return QDF_STATUS_E_FAILURE; + } + + if (!is_bw_supported) { + spectral_err("sscan bw(%u) is not supported for the current operating width(%u) and sscan mode(%u)", + param->value, op_bw, smode); + *err = SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE; + return QDF_STATUS_E_FAILURE; + } + + sparams->ss_bandwidth = param->value; + spectral->sscan_width_configured[smode] = true; + break; } @@ -5399,6 +5779,7 @@ target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev, &spectral->params[smode], smode, err); + spectral->sscan_width_configured[smode] = false; qdf_spin_unlock(&spectral->spectral_lock); return QDF_STATUS_SUCCESS; diff --git a/target_if/spectral/target_if_spectral.h b/target_if/spectral/target_if_spectral.h index 3b6a7254b5..a02394fecc 100644 --- a/target_if/spectral/target_if_spectral.h +++ b/target_if/spectral/target_if_spectral.h @@ -1083,6 +1083,37 @@ struct sscan_detector_list { uint8_t num_detectors; }; +/** + * struct spectral_supported_bws - Supported sscan bandwidths + * @bandwidths: bitmap of supported sscan bandwidths. Make sure to maintain this + * bitmap in the increasing order of bandwidths. + */ +struct spectral_supported_bws { + union { + struct { + uint32_t supports_sscan_bw_5:1, + supports_sscan_bw_10:1, + supports_sscan_bw_20:1, + supports_sscan_bw_40:1, + supports_sscan_bw_80:1, + supports_sscan_bw_160:1, + supports_sscan_bw_80_80:1, + supports_sscan_bw_320:1, + reserved:24; + }; + uint32_t bandwidths; + }; +}; + +/** + * get_supported_sscan_bw_pos() - Get the position of a given sscan_bw inside + * the supported sscan bandwidths bitmap + * @sscan_bw: Spectral scan bandwidth + * + * Return: bit position for a valid sscan bandwidth, else -1 + */ +int get_supported_sscan_bw_pos(enum phy_ch_width sscan_bw); + /** * struct target_if_spectral - main spectral structure * @pdev: Pointer to pdev @@ -1146,6 +1177,7 @@ struct sscan_detector_list { * @tsf64: Latest TSF Value * @param_info: Offload architecture Spectral parameter cache information * @ch_width: Indicates Channel Width 20/40/80/160 MHz for each Spectral mode + * @sscan_width_configured: Whether user has configured sscan bandwidth * @diag_stats: Diagnostic statistics * @is_160_format: Indicates whether information provided by HW is in altered * format for 802.11ac 160/80+80 MHz support (QCA9984 onwards) @@ -1186,6 +1218,8 @@ struct sscan_detector_list { * @session_det_map_lock: Lock to synchronize accesses to session detector map * @report_info: Per session info to be filled at report level in SAMP message * @session_report_info_lock: Lock to synchronize access to session report info + * @supported_bws: Supported sscan bandwidths for all sscan modes and + * operating widths */ struct target_if_spectral { struct wlan_objmgr_pdev *pdev_obj; @@ -1274,6 +1308,7 @@ struct target_if_spectral { param_info[SPECTRAL_SCAN_MODE_MAX]; #endif enum phy_ch_width ch_width[SPECTRAL_SCAN_MODE_MAX]; + bool sscan_width_configured[SPECTRAL_SCAN_MODE_MAX]; struct spectral_diag_stats diag_stats; bool is_160_format; bool is_lb_edge_extrabins_format; @@ -1314,6 +1349,8 @@ struct target_if_spectral { qdf_spinlock_t session_det_map_lock; struct per_session_report_info report_info[SPECTRAL_SCAN_MODE_MAX]; qdf_spinlock_t session_report_info_lock; + struct spectral_supported_bws + supported_bws[SPECTRAL_SCAN_MODE_MAX][CH_WIDTH_MAX]; }; /**