Browse Source

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
Amith Ajith 3 years ago
parent
commit
c3bb3fb37a

+ 204 - 29
umac/regulatory/core/src/reg_opclass.c

@@ -1474,12 +1474,6 @@ static uint8_t reg_get_chan_or_chan_center(const struct
 				    idx,
 				    idx,
 				    NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN,
 				    NUM_20_MHZ_CHAN_IN_160_MHZ_CHAN,
 				    &center_chan);
 				    &center_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,
-				    &center_chan);
 	} else {
 	} else {
 		center_chan = op_class_tbl->channels[*idx];
 		center_chan = op_class_tbl->channels[*idx];
 		*idx = *idx + 1;
 		*idx = *idx + 1;
@@ -1488,6 +1482,200 @@ static uint8_t reg_get_chan_or_chan_center(const struct
 	return center_chan;
 	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
  * reg_get_channels_from_opclassmap()- Get channels from the opclass map
  * @pdev: Pointer to pdev
  * @pdev: Pointer to pdev
@@ -1509,32 +1697,19 @@ reg_get_channels_from_opclassmap(
 		const struct reg_dmn_op_class_map_t *op_class_tbl,
 		const struct reg_dmn_op_class_map_t *op_class_tbl,
 		bool *is_opclass_operable)
 		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 = &reg_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;
 		*is_opclass_operable = true;
 }
 }
 
 

+ 43 - 0
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

+ 10 - 0
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
 enum supported_6g_pwr_types
 reg_conv_6g_ap_type_to_supported_6g_pwr_types(enum reg_6g_ap_type ap_pwr_type);
 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
 #endif