From c3bb3fb37a5b043cb997311919d421223149c826 Mon Sep 17 00:00:00 2001 From: Amith Ajith Date: Wed, 9 Mar 2022 06:34:28 +0530 Subject: [PATCH] qcacmn: Fix incorrect 6g supported channels reported for opclass 133 & 134 API reg_get_channels_from_opclassmap populates channels from opclass map to reg_ap_cap as supported and non-supported channels. But for 6g opclass 133 and 134, non-supported channels were also getting reported as supported channels. This was due to an error in the logic of reg_get_channels_from_opclassmap API for opclass 133 and 134. The 20Mhz channels towards the end of the channel list in the op_class_tbl were causing the issue. To address this issue, add a logic to get the supported and non-supported channels from the cfi list object of op_class_tbl for 6GHz in the reg_get_channels_from_opclassmap API. Also remove the 40MHz centre channel calculation condition for 6GHz in reg_get_chan_or_chan_center API as it is being handled in the new API. CRs-Fixed: 3133022 Change-Id: If6ea18f79786c8549a1c75c557adffa178dd5c71 --- umac/regulatory/core/src/reg_opclass.c | 233 +++++++++++++++--- .../regulatory/core/src/reg_services_common.c | 43 ++++ .../regulatory/core/src/reg_services_common.h | 10 + 3 files changed, 257 insertions(+), 29 deletions(-) diff --git a/umac/regulatory/core/src/reg_opclass.c b/umac/regulatory/core/src/reg_opclass.c index 8bcada0494..da516c7ca0 100644 --- a/umac/regulatory/core/src/reg_opclass.c +++ b/umac/regulatory/core/src/reg_opclass.c @@ -1474,12 +1474,6 @@ static uint8_t reg_get_chan_or_chan_center(const struct idx, NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN, ¢er_chan); - } else if ((op_class_tbl->op_class == BW_40_MHZ) && - (op_class_tbl->op_class == OPCLS_132)) { - reg_get_channel_cen(op_class_tbl, - idx, - NUM_20_MHZ_CHAN_IN_40_MHZ_CHAN, - ¢er_chan); } else { center_chan = op_class_tbl->channels[*idx]; *idx = *idx + 1; @@ -1488,6 +1482,200 @@ static uint8_t reg_get_chan_or_chan_center(const struct return center_chan; } +static inline qdf_freq_t reg_get_nearest_primary_freq(uint16_t bw, + qdf_freq_t cfi_freq, + uint8_t op_class) +{ + qdf_freq_t pri_freq; + + if (bw <= BW_40_MHZ && op_class != OPCLS_132) { + pri_freq = cfi_freq; + } else { + if (cfi_freq >= BW_10_MHZ) + pri_freq = cfi_freq - BW_10_MHZ; + else + pri_freq = 0; + } + + return pri_freq; +} + +#ifdef WLAN_FEATURE_11BE +/** + * reg_is_chan_supported()- Check if given channel is supported based on its + * freq provided + * @pdev: Pointer to pdev + * @pri_freq: Primary frequency of the input channel + * @cfi_freq: cfi frequency of the input channel + * @ch_width: Input channel width + * + * Return: True if the channel is supported, else false + */ +static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, + qdf_freq_t pri_freq, + qdf_freq_t cfi_freq, + enum phy_ch_width ch_width) +{ + struct reg_channel_list chan_list; + qdf_freq_t center_320; + struct ch_params ch_params; + + center_320 = (ch_width == CH_WIDTH_320MHZ) ? cfi_freq : 0; + reg_fill_channel_list(pdev, + pri_freq, + 0, + ch_width, + center_320, + &chan_list); + ch_params = chan_list.chan_param[0]; + + if (ch_params.ch_width == ch_width) + return true; + + return false; +} +#else +static bool reg_is_chan_supported(struct wlan_objmgr_pdev *pdev, + qdf_freq_t pri_freq, + qdf_freq_t cfi_freq, + enum phy_ch_width ch_width) +{ + struct ch_params ch_params; + + ch_params.ch_width = ch_width; + reg_set_channel_params_for_freq(pdev, pri_freq, 0, &ch_params); + if (ch_params.ch_width == ch_width) + return true; + + return false; +} +#endif + +/** + * reg_is_cfi_supported()- Check if given cfi is supported + * @pdev: Pointer to pdev + * @cfi_freq: cfi frequency + * @bw: bandwidth + * + * Return: True if the cfi is supported, else false + */ +static bool reg_is_cfi_supported(struct wlan_objmgr_pdev *pdev, + qdf_freq_t cfi_freq, + uint16_t bw, + uint8_t op_class) +{ + enum phy_ch_width ch_width; + qdf_freq_t pri_freq; + bool is_cfi_supported; + + ch_width = reg_find_chwidth_from_bw(bw); + pri_freq = reg_get_nearest_primary_freq(bw, cfi_freq, op_class); + is_cfi_supported = reg_is_chan_supported(pdev, + pri_freq, + cfi_freq, + ch_width); + + return is_cfi_supported; +} + +/** + * reg_get_cfis_from_opclassmap_for_6g()- Get channels from the opclass map + * for 6GHz + * @pdev: Pointer to pdev + * @cap: Pointer to regdmn_ap_cap_opclass_t + * @op_class_tbl: Pointer to op_class_tbl + * + * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported + * and non-supported channels for 6Ghz. + * + * Return: void. + */ +static void reg_get_cfis_from_opclassmap_for_6g( + struct wlan_objmgr_pdev *pdev, + struct regdmn_ap_cap_opclass_t *cap, + const struct reg_dmn_op_class_map_t *op_class_tbl) +{ + uint8_t n_sup_chans = 0, n_unsup_chans = 0, j; + const struct c_freq_lst *p_cfi_lst = op_class_tbl->p_cfi_lst_obj; + qdf_freq_t cfi_freq; + qdf_freq_t start_freq = op_class_tbl->start_freq; + uint16_t bw = op_class_tbl->chan_spacing; + + for (j = 0; j < p_cfi_lst->num_cfis; j++) { + uint8_t cfi = p_cfi_lst->p_cfis_arr[j]; + bool is_cfi_supported; + + cfi_freq = start_freq + FREQ_TO_CHAN_SCALE * cfi; + is_cfi_supported = reg_is_cfi_supported(pdev, + cfi_freq, + bw, + op_class_tbl->op_class); + if (is_cfi_supported) { + cap->sup_chan_list[n_sup_chans++] = cfi; + cap->num_supported_chan++; + } else { + cap->non_sup_chan_list[n_unsup_chans++] = cfi; + cap->num_non_supported_chan++; + } + } +} + +static uint16_t reg_find_nearest_ieee_bw(uint16_t spacing) +{ + #define SMALLEST_BW 20 + return (spacing / SMALLEST_BW) * SMALLEST_BW; +} + +/** + * reg_get_cfis_from_opclassmap_for_non6g()- Get channels from the opclass map + * for non-6GHz + * @pdev: Pointer to pdev + * @cap: Pointer to regdmn_ap_cap_opclass_t + * @op_class_tbl: Pointer to op_class_tbl + * + * Populate channels from opclass map to regdmn_ap_cap_opclass_t as supported + * and non-supported channels for non-6Ghz. + * + * Return: void. + */ +static void reg_get_cfis_from_opclassmap_for_non6g( + struct wlan_objmgr_pdev *pdev, + struct regdmn_ap_cap_opclass_t *cap, + const struct reg_dmn_op_class_map_t *op_class_tbl) +{ + qdf_freq_t start_freq = op_class_tbl->start_freq; + uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0; + + while (op_class_tbl->channels[chan_idx]) { + uint8_t op_cls_chan; + qdf_freq_t pri_freq; + enum phy_ch_width ch_width; + bool is_supported; + uint16_t opcls_bw; + + op_cls_chan = reg_get_chan_or_chan_center(op_class_tbl, + &chan_idx); + pri_freq = start_freq + FREQ_TO_CHAN_SCALE * op_cls_chan; + opcls_bw = reg_find_nearest_ieee_bw(op_class_tbl->chan_spacing); + ch_width = reg_find_chwidth_from_bw(opcls_bw); + pri_freq = reg_get_nearest_primary_freq(opcls_bw, + pri_freq, + op_class_tbl->op_class); + is_supported = reg_is_chan_supported(pdev, + pri_freq, + 0, + ch_width); + + if (!is_supported) { + cap->non_sup_chan_list[n_unsup_chans++] = op_cls_chan; + cap->num_non_supported_chan++; + } else { + cap->sup_chan_list[n_sup_chans++] = op_cls_chan; + cap->num_supported_chan++; + } + } +} + /** * reg_get_channels_from_opclassmap()- Get channels from the opclass map * @pdev: Pointer to pdev @@ -1509,32 +1697,19 @@ reg_get_channels_from_opclassmap( const struct reg_dmn_op_class_map_t *op_class_tbl, bool *is_opclass_operable) { - uint8_t op_cls_chan; - qdf_freq_t search_freq; - bool is_freq_present; - uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0; + struct regdmn_ap_cap_opclass_t *cap = ®_ap_cap[index]; - while (op_class_tbl->channels[chan_idx]) { - op_cls_chan = op_class_tbl->channels[chan_idx]; - search_freq = op_class_tbl->start_freq + - (FREQ_TO_CHAN_SCALE * op_cls_chan); - is_freq_present = - reg_is_freq_present_in_cur_chan_list(pdev, search_freq); - - if (!is_freq_present) { - reg_ap_cap[index].non_sup_chan_list[n_unsup_chans++] = - reg_get_chan_or_chan_center(op_class_tbl, - &chan_idx); - reg_ap_cap[index].num_non_supported_chan++; - } else { - reg_ap_cap[index].sup_chan_list[n_sup_chans++] = - reg_get_chan_or_chan_center(op_class_tbl, - &chan_idx); - reg_ap_cap[index].num_supported_chan++; - } + if (reg_is_6ghz_op_class(pdev, op_class_tbl->op_class)) { + reg_get_cfis_from_opclassmap_for_6g(pdev, + cap, + op_class_tbl); + } else { + reg_get_cfis_from_opclassmap_for_non6g(pdev, + cap, + op_class_tbl); } - if (reg_ap_cap[index].num_supported_chan >= 1) + if (cap->num_supported_chan >= 1) *is_opclass_operable = true; } diff --git a/umac/regulatory/core/src/reg_services_common.c b/umac/regulatory/core/src/reg_services_common.c index 3663a6c38d..9de0d432b9 100644 --- a/umac/regulatory/core/src/reg_services_common.c +++ b/umac/regulatory/core/src/reg_services_common.c @@ -8118,3 +8118,46 @@ bool reg_is_freq_idx_enabled(struct wlan_objmgr_pdev *pdev, } } +#ifdef WLAN_FEATURE_11BE +enum phy_ch_width reg_find_chwidth_from_bw(uint16_t bw) +{ + switch (bw) { + case BW_5_MHZ: + return CH_WIDTH_5MHZ; + case BW_10_MHZ: + return CH_WIDTH_10MHZ; + case BW_20_MHZ: + return CH_WIDTH_20MHZ; + case BW_40_MHZ: + return CH_WIDTH_40MHZ; + case BW_80_MHZ: + return CH_WIDTH_80MHZ; + case BW_160_MHZ: + return CH_WIDTH_160MHZ; + case BW_320_MHZ: + return CH_WIDTH_320MHZ; + default: + return CH_WIDTH_INVALID; + } +} +#else +enum phy_ch_width reg_find_chwidth_from_bw(uint16_t bw) +{ + switch (bw) { + case BW_5_MHZ: + return CH_WIDTH_5MHZ; + case BW_10_MHZ: + return CH_WIDTH_10MHZ; + case BW_20_MHZ: + return CH_WIDTH_20MHZ; + case BW_40_MHZ: + return CH_WIDTH_40MHZ; + case BW_80_MHZ: + return CH_WIDTH_80MHZ; + case BW_160_MHZ: + return CH_WIDTH_160MHZ; + default: + return CH_WIDTH_INVALID; + } +} +#endif diff --git a/umac/regulatory/core/src/reg_services_common.h b/umac/regulatory/core/src/reg_services_common.h index 80fa65d776..28ca0d2b83 100644 --- a/umac/regulatory/core/src/reg_services_common.h +++ b/umac/regulatory/core/src/reg_services_common.h @@ -2217,4 +2217,14 @@ reg_get_best_6g_pwr_type(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq); */ enum supported_6g_pwr_types reg_conv_6g_ap_type_to_supported_6g_pwr_types(enum reg_6g_ap_type ap_pwr_type); + +/** + * reg_find_chwidth_from_bw () - Gets channel width for given + * bandwidth + * @bw: Bandwidth + * + * Return: phy_ch_width + */ +enum phy_ch_width reg_find_chwidth_from_bw(uint16_t bw); + #endif