ソースを参照

qcacmn: 802.11BE 5G 240MHZ regulatory changes

Firmware sends the following reg rule to build 5G 240MHZ channels
240MHZ reg rule:
start: 5490, end: 5730, max_bw: 240.
However, 240MHZ is not one of the standard IEEE channel width.
Hence the channel finding APIs will fail to find a channel of 240MHZ BW.

240MHZ is considered as a punctured 320MHZ channel (320 - 80).
Hence convert the max bw of 240MHZ reg rule to 320MHZ within the host
so that channel can be built.

Also, change the 5G 240MHZ bonded pair's end freq to 5720. Since there is a
5MHZ bandwidth gap between channel 144 and 149, the bonded pair is
restricted to 5720MHZ on 5G.

Change-Id: Iee8dad0317f7ecb95843faa3d0779b854b8f48fa
CRs-Fixed: 3106866
Priyadarshnee Srinivasan 3 年 前
コミット
d0b50dd6b8

+ 52 - 0
target_if/regulatory/src/target_if_reg.c

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -1029,6 +1030,55 @@ tgt_if_regulatory_is_upper_6g_edge_ch_disabled(struct wlan_objmgr_psoc *psoc)
 }
 #endif
 
+/**
+ * tgt_if_reg_is_chip_11be_cap() - Finds out if the hardware is capable
+ * of 11BE. The capability bit is read from mac_phy_cap populated by the
+ * FW per pdev.
+ * @psoc: Pointer to psoc
+ * @phy_id: phy_id
+ *
+ * Return: True if chip is 11BE capable, false otherwise.
+ */
+#ifdef WLAN_FEATURE_11BE
+static bool tgt_if_reg_is_chip_11be_cap(struct wlan_objmgr_psoc *psoc,
+					uint16_t phy_id)
+{
+	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap_arr, *mac_phy_cap;
+	struct target_psoc_info *tgt_hdl;
+	uint8_t pdev_id;
+	struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
+
+	reg_tx_ops = target_if_regulatory_get_tx_ops(psoc);
+
+	if (!reg_tx_ops) {
+		target_if_err("reg_tx_ops is NULL");
+		return false;
+	}
+
+	if (reg_tx_ops->get_pdev_id_from_phy_id)
+		reg_tx_ops->get_pdev_id_from_phy_id(psoc, phy_id, &pdev_id);
+	else
+		pdev_id = phy_id;
+
+	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
+	if (tgt_hdl) {
+		mac_phy_cap_arr = target_psoc_get_mac_phy_cap(tgt_hdl);
+		if (!mac_phy_cap_arr)
+			return false;
+		mac_phy_cap = &mac_phy_cap_arr[pdev_id];
+		if (mac_phy_cap && mac_phy_cap->supports_11be)
+			return true;
+	}
+	return false;
+}
+#else
+static bool tgt_if_reg_is_chip_11be_cap(struct wlan_objmgr_psoc *psoc,
+					uint16_t phy_id)
+{
+	return false;
+}
+#endif
+
 QDF_STATUS target_if_register_regulatory_tx_ops(
 		struct wlan_lmac_if_tx_ops *tx_ops)
 {
@@ -1086,5 +1136,7 @@ QDF_STATUS target_if_register_regulatory_tx_ops(
 
 	tgt_if_register_afc_callback(reg_ops);
 
+	reg_ops->is_chip_11be = tgt_if_reg_is_chip_11be_cap;
+
 	return QDF_STATUS_SUCCESS;
 }

+ 2 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -1033,6 +1033,8 @@ struct wlan_lmac_if_reg_tx_ops {
 				(struct wlan_objmgr_psoc *psoc, void *arg);
 	QDF_STATUS (*trigger_acs_for_afc)(struct wlan_objmgr_pdev *pdev);
 #endif
+	bool (*is_chip_11be)(struct wlan_objmgr_psoc *psoc,
+			     uint16_t phy_id);
 };
 
 /**

+ 120 - 1
umac/regulatory/core/src/reg_build_chan_list.c

@@ -2818,6 +2818,122 @@ static void reg_store_regulatory_ext_info_to_socpriv(
 	}
 }
 
+#ifdef WLAN_FEATURE_11BE
+static bool
+reg_is_bonded_ch_subset_of_regrule(struct cur_reg_rule *cur_rule_ptr,
+				   const struct bonded_channel_freq
+				   *bonded_ch_ptr)
+{
+	if (bonded_ch_ptr->start_freq >= cur_rule_ptr->start_freq &&
+	    bonded_ch_ptr->end_freq <= cur_rule_ptr->end_freq)
+		return true;
+
+	return false;
+}
+#endif
+
+/**
+ * reg_is_5g_240chan_in_rule() - Determine if the given reg rule supports
+ * 5g 240MHZ chan [100 - 144] and the BW of the rule is greater than 160MHZ.
+ * @cur_rule_ptr: Pointer to struct cur_reg_rule
+ * @bonded_ch_ptr: Pointer to  const struct bonded_channel_freq
+ *
+ * Return -True if 240 chan rule is found, false otherwise.
+ */
+#ifdef WLAN_FEATURE_11BE
+static bool
+reg_is_5g_240chan_in_rule(struct cur_reg_rule *cur_rule_ptr,
+			  const struct bonded_channel_freq *bonded_ch_ptr)
+{
+	if (!bonded_ch_ptr)
+		return false;
+
+	if (reg_is_bonded_ch_subset_of_regrule(cur_rule_ptr, bonded_ch_ptr) &&
+	    cur_rule_ptr->max_bw > BW_160_MHZ)
+		return true;
+
+	return false;
+}
+#endif
+
+/**
+ * reg_is_chip_cc_11be_cap() - Determine if country supports a max BW
+ * greater than 160MHZ and if chip is 11BE capable.
+ * @psoc: Pointer to struct wlan_objmgr_psoc
+ * @phy_id: Phy-id
+ * @max_cc_bw: Maximum 5g BW supported by the country
+ *
+ * Return - True if cc_max is greater than 160MHZ and chip is 11BE cap,
+ * false otherwise.
+ */
+#ifdef WLAN_FEATURE_11BE
+static bool reg_is_chip_cc_11be_cap(struct wlan_objmgr_psoc *psoc,
+				    uint16_t phy_id,
+				    uint16_t max_cc_bw)
+{
+	struct wlan_lmac_if_reg_tx_ops *tx_ops;
+
+	tx_ops = reg_get_psoc_tx_ops(psoc);
+	if (!tx_ops)
+		return false;
+
+	if (max_cc_bw > BW_160_MHZ && tx_ops->is_chip_11be(psoc, phy_id))
+		return true;
+
+	return false;
+}
+#endif
+
+/**
+ * reg_modify_max_bw_for_240mhz_5g_chans() - Manually update the bandwidh
+ * of the 240MHz channels in 5GHz band [IEEE channels 100 - 144 support 240MHz
+ * bandwidth using puncturing; 240MHz = 320MHz - 80Mhz(punctured)].
+ * The max bandwidth for these channels should be 320MHz.
+ *
+ * Modify reg rule BW of 100 - 144 channels to 320 if
+ * a) Chip supports 11BE
+ * b) Country supports 320MHZ BW.
+ * c) Reg rule BW advertised by FW is 240MHZ.
+ * d) Channel is between 5500 and 5720.
+ *
+ * @regulat_info: Pointer to struct cur_regulatory_info
+ * @reg_rule_5g: Pointer to  struct cur_reg_rule
+ */
+#ifdef WLAN_FEATURE_11BE
+static void
+reg_modify_max_bw_for_240mhz_5g_chans(struct cur_regulatory_info *regulat_info,
+				      struct cur_reg_rule *reg_rule_5g)
+
+{
+#define FREQ_5500_MHZ  5500
+
+	uint16_t num_5g_reg_rules = regulat_info->num_5g_reg_rules;
+	uint16_t rule_num;
+	struct cur_reg_rule *cur_rule_ptr;
+	const struct bonded_channel_freq *bonded_ch_ptr;
+
+	bonded_ch_ptr = reg_get_bonded_chan_entry(FREQ_5500_MHZ,
+						  CH_WIDTH_320MHZ);
+	if (!reg_is_chip_cc_11be_cap(regulat_info->psoc,
+				     regulat_info->phy_id,
+				     regulat_info->max_bw_5g))
+		return;
+
+	for (rule_num = 0, cur_rule_ptr = reg_rule_5g;
+	     rule_num < num_5g_reg_rules; cur_rule_ptr++, rule_num++) {
+		if (reg_is_5g_240chan_in_rule(cur_rule_ptr, bonded_ch_ptr)) {
+			cur_rule_ptr->max_bw = BW_320_MHZ;
+			break;
+		}
+	}
+}
+#else
+static void
+reg_modify_max_bw_for_240mhz_5g_chans(struct cur_regulatory_info *regulat_info,
+				      struct cur_reg_rule *reg_rule_5g)
+{
+}
+#endif
 /**
  * reg_fill_master_channels() - Fill the master channel lists based on the
  *	regulatory rules
@@ -2920,11 +3036,14 @@ reg_fill_master_channels(struct cur_regulatory_info *regulat_info,
 				     reg_rule_2g, num_2g_reg_rules *
 				     sizeof(struct cur_reg_rule));
 		curr_reg_rule_location = num_2g_reg_rules;
-		if (num_5g_reg_rules)
+		if (num_5g_reg_rules) {
+			reg_modify_max_bw_for_240mhz_5g_chans(regulat_info,
+							      reg_rule_5g);
 			qdf_mem_copy(reg_rules->reg_rules +
 				     curr_reg_rule_location, reg_rule_5g,
 				     num_5g_reg_rules *
 				     sizeof(struct cur_reg_rule));
+		}
 	}
 
 	for (i = 0; i < REG_CURRENT_MAX_AP_TYPE; i++) {

+ 59 - 19
umac/regulatory/core/src/reg_services_common.c

@@ -146,7 +146,7 @@ static const struct bonded_channel_freq bonded_chan_160mhz_list_freq[] = {
 #ifdef WLAN_FEATURE_11BE
 /* bonded_chan_320mhz_list_freq - List of 320MHz bonnded channel frequencies */
 static const struct bonded_channel_freq bonded_chan_320mhz_list_freq[] = {
-	{5500, 5800}, /* center freq: 5650 */
+	{5500, 5720}, /* center freq: 5650: The 5Ghz 240MHz chan */
 #ifdef CONFIG_BAND_6GHZ
 	{5955, 6255}, /* center freq: 6105 */
 	{6115, 6415}, /* center freq: 6265 */
@@ -3653,6 +3653,12 @@ reg_get_2g_bonded_channel_state_for_freq(struct wlan_objmgr_pdev *pdev,
 }
 
 #ifdef WLAN_FEATURE_11BE
+static inline qdf_freq_t
+reg_get_band_cen_from_bandstart(uint16_t bw, qdf_freq_t bandstart)
+{
+	return bandstart - BW_10_MHZ + bw / 2;
+}
+
 /**
  * reg_get_320_bonded_chan_array() - Fetches a list of bonded channel pointers
  * for the given bonded channel array. If 320 band center is specified,
@@ -3696,9 +3702,11 @@ reg_get_320_bonded_chan_array(struct wlan_objmgr_pdev *pdev,
 	} else {
 		/* Fetch the bonded channel pointer for the given band_center */
 		for (i = 0; i < array_size; i++) {
-			if (((bonded_chan_ar[i].start_freq +
-			      bonded_chan_ar[i].end_freq) / 2) ==
-				band_center_320) {
+			qdf_freq_t bandstart = bonded_chan_ar[i].start_freq;
+
+			if (band_center_320 ==
+			    reg_get_band_cen_from_bandstart(BW_320_MHZ,
+							    bandstart)) {
 				bonded_chan_ptr[num_bonded_pairs] =
 					&bonded_chan_ar[i];
 				num_bonded_pairs++;
@@ -3729,6 +3737,15 @@ reg_get_320_bonded_chan_array(struct wlan_objmgr_pdev *pdev,
 #define REG_IS_PRIMARY_CHAN_NOT_ALLOWED(_x, _y) \
 	(!reg_is_state_allowed(reg_get_channel_state_for_freq((_x), (_y))))
 
+static inline qdf_freq_t
+reg_get_endchan_cen_from_bandstart(qdf_freq_t band_start,
+				   uint16_t bw)
+{
+	uint16_t left_edge_freq = band_start - BW_10_MHZ;
+
+	return left_edge_freq + bw - BW_10_MHZ;
+}
+
 static enum channel_state
 reg_get_320_bonded_channel_state(struct wlan_objmgr_pdev *pdev,
 				 qdf_freq_t freq,
@@ -3739,7 +3756,7 @@ reg_get_320_bonded_channel_state(struct wlan_objmgr_pdev *pdev,
 {
 	enum channel_state chan_state = CHANNEL_STATE_INVALID;
 	enum channel_state temp_chan_state;
-	uint16_t chan_cfreq;
+	uint16_t startchan_cfreq, endchan_cfreq;
 	uint16_t max_cont_bw, i;
 
 	*out_punc_bitmap = ALL_SCHANS_PUNC;
@@ -3747,14 +3764,17 @@ reg_get_320_bonded_channel_state(struct wlan_objmgr_pdev *pdev,
 	if (!bonded_chan_ptr)
 		return chan_state;
 
-	chan_cfreq =  bonded_chan_ptr->start_freq;
-
+	startchan_cfreq =  bonded_chan_ptr->start_freq;
+	endchan_cfreq =
+		reg_get_endchan_cen_from_bandstart(startchan_cfreq,
+						   BW_320_MHZ);
 	max_cont_bw = 0;
 	i = 0;
 
-	while (chan_cfreq <= bonded_chan_ptr->end_freq) {
-		temp_chan_state = reg_get_channel_state_for_freq(pdev,
-								 chan_cfreq);
+	while (startchan_cfreq <= endchan_cfreq) {
+		temp_chan_state =
+			reg_get_channel_state_for_freq(pdev,
+						       startchan_cfreq);
 		if (reg_is_state_allowed(temp_chan_state)) {
 			max_cont_bw += SUB_CHAN_BW;
 			*out_punc_bitmap &= ~BIT(i);
@@ -3763,7 +3783,7 @@ reg_get_320_bonded_channel_state(struct wlan_objmgr_pdev *pdev,
 		if (temp_chan_state < chan_state)
 			chan_state = temp_chan_state;
 
-		chan_cfreq = chan_cfreq + SUB_CHAN_BW;
+		startchan_cfreq = startchan_cfreq + SUB_CHAN_BW;
 		i++;
 	}
 
@@ -3785,9 +3805,15 @@ reg_get_320_bonded_channel_state(struct wlan_objmgr_pdev *pdev,
 		return CHANNEL_STATE_ENABLE;
 }
 
+static inline bool reg_is_pri_within_240mhz_chan(qdf_freq_t freq)
+{
+	return (freq >= CHAN_FREQ_5660 && freq <= CHAN_FREQ_5720);
+}
+
 /**
- * reg_fill_primary_160mhz_centers() - Fill the primary 160MHz segment centers
- * for a 320MHz channel in the given channel param.
+ * reg_fill_chan320mhz_seg0_center() - Fill the primary segment center
+ * for a 320MHz channel in the given channel param. Primary segment center
+ * of a 320MHZ is the 160MHZ segment center of the given freq.
  * @pdev: Pointer to struct wlan_objmgr_pdev.
  * @ch_param: channel params to be filled.
  * @freq: Input primary frequency in MHZ.
@@ -3795,7 +3821,7 @@ reg_get_320_bonded_channel_state(struct wlan_objmgr_pdev *pdev,
  * Return: void.
  */
 static void
-reg_fill_primary_160mhz_centers(struct wlan_objmgr_pdev *pdev,
+reg_fill_chan320mhz_seg0_center(struct wlan_objmgr_pdev *pdev,
 				struct ch_params *ch_param, qdf_freq_t freq)
 {
 	const struct bonded_channel_freq *t_bonded_ch_ptr;
@@ -3809,8 +3835,21 @@ reg_fill_primary_160mhz_centers(struct wlan_objmgr_pdev *pdev,
 			reg_freq_to_chan(pdev,
 					 ch_param->mhz_freq_seg0);
 	} else {
-		reg_err("Cannot find 160Mhz centers for freq %d", freq);
-		ch_param->ch_width = CH_WIDTH_INVALID;
+		/**
+		 * If we do not find a 160Mhz  bonded  pair, since it is
+		 * for a 320Mhz channel we need to also see if we can find a
+		 * pseudo 160Mhz channel for the special case of
+		 * 5Ghz 240Mhz channel.
+		 */
+		if (reg_is_pri_within_240mhz_chan(freq)) {
+			ch_param->mhz_freq_seg0 =
+				PRIM_SEG_FREQ_CENTER_240MHZ_5G_CHAN;
+			ch_param->center_freq_seg0 =
+				PRIM_SEG_IEEE_CENTER_240MHZ_5G_CHAN;
+		} else {
+			ch_param->ch_width = CH_WIDTH_INVALID;
+			reg_err("Cannot find 160Mhz centers for freq %d", freq);
+		}
 	}
 }
 
@@ -3913,17 +3952,18 @@ reg_fill_channel_list_for_320(struct wlan_objmgr_pdev *pdev,
 		if (chan_state == CHANNEL_STATE_ENABLE) {
 			struct ch_params *t_chan_param =
 			    &chan_list->chan_param[num_ch_params];
+			qdf_freq_t start_freq = bonded_ch_ptr[i]->start_freq;
 
 			t_chan_param->mhz_freq_seg1 =
-				(bonded_ch_ptr[i]->start_freq +
-				 bonded_ch_ptr[i]->end_freq) / 2;
+				reg_get_band_cen_from_bandstart(BW_320_MHZ,
+								start_freq);
 			t_chan_param->center_freq_seg1 =
 				reg_freq_to_chan(pdev,
 						 t_chan_param->mhz_freq_seg1);
 			t_chan_param->ch_width = *in_ch_width;
 			t_chan_param->reg_punc_bitmap = out_punc_bitmap;
 
-			reg_fill_primary_160mhz_centers(pdev,
+			reg_fill_chan320mhz_seg0_center(pdev,
 							t_chan_param,
 							freq);
 			num_ch_params++;

+ 6 - 0
umac/regulatory/core/src/reg_services_common.h

@@ -158,6 +158,12 @@ extern const struct chan_map channel_map_global[];
 #define ALL_SCHANS_PUNC 0xFFFF /* all subchannels punctured */
 #endif
 
+#define CHAN_FREQ_5660 5660
+#define CHAN_FREQ_5720 5720
+
+#define PRIM_SEG_IEEE_CENTER_240MHZ_5G_CHAN 146
+#define PRIM_SEG_FREQ_CENTER_240MHZ_5G_CHAN 5730
+
 #ifdef CONFIG_AFC_SUPPORT
 /**
  * struct afc_cb_handler - defines structure for afc request received  event