Pārlūkot izejas kodu

qcacmn: Add support to store and use fcc rules sent by firmware

When set_fcc_channel is set, host driver sets tx_power info about
channels 12, 13 to hardcoded values. Now firmware sends information
about channels 12, 13 to host driver and currently there is no
support to extract and store this information and use it to
modify tx_power of channels 12, 13 in host driver.

Add support to store the tx_power of channels 12, 13 received
from firmware and use this to modify tx_power of fcc channels.

Change-Id: Ie7b20a75bb09956a70b7b133ce7ce9beb8db138b
CRs-Fixed: 3270676
Asutosh Mohapatra 2 gadi atpakaļ
vecāks
revīzija
c70f8eec91

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

@@ -357,6 +357,22 @@ static QDF_STATUS tgt_if_regulatory_unregister_master_list_handler(
 }
 
 #ifdef CONFIG_BAND_6GHZ
+#ifdef CONFIG_REG_CLIENT
+/**
+ * tgt_mem_free_fcc_rules() - Free regulatory fcc rules
+ * @reg_info: Pointer to regulatory info
+ *
+ */
+static void tgt_reg_mem_free_fcc_rules(struct cur_regulatory_info *reg_info)
+{
+	qdf_mem_free(reg_info->fcc_rules_ptr);
+}
+#else
+static void tgt_reg_mem_free_fcc_rules(struct cur_regulatory_info *reg_info)
+{
+}
+#endif
+
 /**
  * tgt_reg_chan_list_ext_update_handler() - Extended channel list update handler
  * @handle: scn handle
@@ -433,6 +449,7 @@ static int tgt_reg_chan_list_ext_update_handler(ol_scn_t handle,
 clean:
 	qdf_mem_free(reg_info->reg_rules_2g_ptr);
 	qdf_mem_free(reg_info->reg_rules_5g_ptr);
+	tgt_reg_mem_free_fcc_rules(reg_info);
 
 	for (i = 0; i < REG_CURRENT_MAX_AP_TYPE; i++) {
 		qdf_mem_free(reg_info->reg_rules_6g_ap_ptr[i]);

+ 130 - 13
umac/regulatory/core/src/reg_build_chan_list.c

@@ -642,29 +642,70 @@ static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list,
 
 }
 
+#ifdef CONFIG_REG_CLIENT
+/**
+ * reg_get_tx_power_for_fcc_channel() - Set FCC txpower received from firmware
+ * @chan_list: Regulatory channel to be updated
+ * @fcc_rule: Pointer to current fcc rule array
+ *
+ * Return: true if regulatory channel is present in current fcc rules array
+ */
+static bool reg_get_tx_power_for_fcc_channel(
+		struct regulatory_channel *chan_list,
+		struct cur_fcc_rule *fcc_rule)
+{
+	int index = 0;
+
+	if (!chan_list || !fcc_rule)
+		return false;
+
+	for (index = 0; index < MAX_NUM_FCC_RULES; index++) {
+		if (chan_list->center_freq == fcc_rule[index].center_freq) {
+			chan_list->tx_power = fcc_rule[index].tx_power;
+			return true;
+		}
+	}
+
+	return false;
+}
+
 /**
  * reg_modify_chan_list_for_fcc_channel() - Set maximum FCC txpower for channel
  * 12 and 13 if set_fcc_channel flag is set to true.
- * @chan_list: Pointer to regulatory channel list.
- * @set_fcc_channel: If this flag is set to true, then set the max FCC txpower
- * for channel 12 and 13.
+ * @pdev_priv_obj: Pointer to pdev private object.
  */
 static void reg_modify_chan_list_for_fcc_channel(
-		struct regulatory_channel *chan_list, bool set_fcc_channel)
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
 {
-	enum channel_enum chan_enum;
+	struct regulatory_channel *chan_list = pdev_priv_obj->cur_chan_list;
+	struct cur_fcc_rule *fcc_rules = pdev_priv_obj->fcc_rules_ptr;
 
-	if (!set_fcc_channel)
+	if (!pdev_priv_obj->set_fcc_channel)
 		return;
 
-	for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++) {
-		if (chan_list[chan_enum].center_freq == CHAN_12_CENT_FREQ)
-			chan_list[chan_enum].tx_power = MAX_PWR_FCC_CHAN_12;
+	if (!chan_list || !fcc_rules)
+		return;
 
-		if (chan_list[chan_enum].center_freq == CHAN_13_CENT_FREQ)
-			chan_list[chan_enum].tx_power = MAX_PWR_FCC_CHAN_13;
+	if (!reg_get_tx_power_for_fcc_channel(
+			&chan_list[CHAN_ENUM_2467], fcc_rules)) {
+		chan_list[CHAN_ENUM_2467].tx_power = MAX_PWR_FCC_CHAN_12;
+		reg_debug("Channel 12 not found from BDF");
+	}
+	if (!reg_get_tx_power_for_fcc_channel(
+			&chan_list[CHAN_ENUM_2472], fcc_rules)) {
+		chan_list[CHAN_ENUM_2472].tx_power = MAX_PWR_FCC_CHAN_13;
+		reg_debug("Channel 13 not found from BDF");
 	}
+	reg_debug("Channel 12 tx_power = %d, 13 tx_power = %d",
+		  chan_list[CHAN_ENUM_2467].tx_power,
+		  chan_list[CHAN_ENUM_2472].tx_power);
+}
+#else
+static inline void reg_modify_chan_list_for_fcc_channel(
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
 }
+#endif
 
 /**
  * reg_modify_chan_list_for_chan_144() - Disable channel 144 if en_chan_144 flag
@@ -2596,8 +2637,7 @@ void reg_compute_pdev_current_chan_list(struct wlan_regulatory_pdev_priv_obj
 
 	reg_modify_chan_list_for_indoor_channels(pdev_priv_obj);
 
-	reg_modify_chan_list_for_fcc_channel(pdev_priv_obj->cur_chan_list,
-					     pdev_priv_obj->set_fcc_channel);
+	reg_modify_chan_list_for_fcc_channel(pdev_priv_obj);
 
 	reg_modify_chan_list_for_chan_144(pdev_priv_obj->cur_chan_list,
 					  pdev_priv_obj->en_chan_144);
@@ -2809,6 +2849,40 @@ void reg_save_reg_rules_to_pdev(struct reg_rule_info *psoc_reg_rules,
 	qdf_spin_unlock_bh(&pdev_priv_obj->reg_rules_lock);
 }
 
+#ifdef CONFIG_REG_CLIENT
+/**
+ * reg_set_pdev_fcc_rules - Set pdev fcc rules array
+ * @psoc_priv_obj - PSOC private object pointer
+ * @pdev_priv_obj - PDEV private object pointer
+ *
+ */
+
+static void reg_set_pdev_fcc_rules(
+		struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj,
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+	if (!psoc_priv_obj) {
+		reg_err("psoc priv obj is NULL");
+		return;
+	}
+
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("reg pdev priv obj is NULL");
+		return;
+	}
+
+	qdf_mem_copy(pdev_priv_obj->fcc_rules_ptr,
+		     psoc_priv_obj->fcc_rules_ptr,
+		     sizeof(struct cur_fcc_rule) * MAX_NUM_FCC_RULES);
+}
+#else
+static void reg_set_pdev_fcc_rules(
+		struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj,
+		struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+}
+#endif
+
 void reg_propagate_mas_chan_list_to_pdev(struct wlan_objmgr_psoc *psoc,
 					 void *object, void *arg)
 {
@@ -2845,6 +2919,7 @@ void reg_propagate_mas_chan_list_to_pdev(struct wlan_objmgr_psoc *psoc,
 	else
 		phy_id = pdev_id;
 
+	reg_set_pdev_fcc_rules(psoc_priv_obj, pdev_priv_obj);
 	reg_init_pdev_mas_chan_list(
 			pdev_priv_obj,
 			&psoc_priv_obj->mas_chan_params[phy_id]);
@@ -3187,6 +3262,40 @@ static void reg_init_legacy_master_chan(struct regulatory_channel *dst_list,
 	reg_init_chan(dst_list, 0, NUM_CHANNELS - 1, 0, soc_reg);
 }
 
+#ifdef CONFIG_REG_CLIENT
+/**
+ * reg_set_psoc_fcc_rules - Set PSOC fcc rules array
+ * @soc_reg - PSOC private object pointer
+ * @regulat_info - Regulatory info pointer
+ *
+ * Return - QDF_STATUS
+ */
+static QDF_STATUS reg_set_psoc_fcc_rules(
+		struct wlan_regulatory_psoc_priv_obj *soc_reg,
+		struct cur_regulatory_info *regulat_info)
+{
+	if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
+		reg_err("psoc reg component is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (regulat_info->num_fcc_rules)
+		qdf_mem_copy(soc_reg->fcc_rules_ptr,
+			     regulat_info->fcc_rules_ptr,
+			     sizeof(struct cur_fcc_rule) *
+			     regulat_info->num_fcc_rules);
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static inline QDF_STATUS reg_set_psoc_fcc_rules(
+		struct wlan_regulatory_psoc_priv_obj *soc_reg,
+		struct cur_regulatory_info *regulat_info)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 #ifdef CONFIG_BAND_6GHZ
 static void reg_init_2g_5g_master_chan(struct regulatory_channel *dst_list,
 				struct wlan_regulatory_psoc_priv_obj *soc_reg)
@@ -3747,6 +3856,10 @@ QDF_STATUS reg_process_master_chan_list_ext(
 
 	reg_set_socpriv_vars(soc_reg, regulat_info, psoc, phy_id);
 
+	status = reg_set_psoc_fcc_rules(soc_reg, regulat_info);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		return status;
+
 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbg_id);
 	if (pdev) {
 		reg_propagate_mas_chan_list_to_pdev(psoc, pdev, &dir);
@@ -4696,6 +4809,10 @@ QDF_STATUS reg_process_master_chan_list(
 		}
 	}
 
+	status = reg_set_psoc_fcc_rules(soc_reg, regulat_info);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		return status;
+
 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbg_id);
 	if (pdev) {
 		reg_propagate_mas_chan_list_to_pdev(psoc, pdev, &dir);

+ 10 - 0
umac/regulatory/core/src/reg_priv_objs.h

@@ -121,6 +121,8 @@ struct chan_change_cbk_entry {
  * unsafe channels list
  * @reg_afc_dev_type: AFC device deployment type from BDF
  * @sta_sap_scc_on_indoor_channel: Value of sap+sta scc on indoor support
+ * @fcc_rules_ptr : Value of fcc channel frequency and tx_power list received
+ * from firmware
  */
 struct wlan_regulatory_psoc_priv_obj {
 	struct mas_chan_params mas_chan_params[PSOC_MAX_PHY_REG_CAP];
@@ -192,6 +194,9 @@ struct wlan_regulatory_psoc_priv_obj {
 	enum reg_afc_dev_deploy_type reg_afc_dev_type;
 #endif
 	bool sta_sap_scc_on_indoor_channel;
+#ifdef CONFIG_REG_CLIENT
+	struct cur_fcc_rule fcc_rules_ptr[MAX_NUM_FCC_RULES];
+#endif
 };
 
 /**
@@ -240,6 +245,8 @@ struct wlan_regulatory_psoc_priv_obj {
  * priority during channel selection by upper layer
  * @reg_afc_dev_deployment_type: AFC device deployment type from BDF
  * @sta_sap_scc_on_indoor_channel: Value of sap+sta scc on indoor support
+ * @fcc_rules_ptr : Value of fcc channel frequency and tx_power list received
+ * from firmware
  */
 struct wlan_regulatory_pdev_priv_obj {
 	struct regulatory_channel cur_chan_list[NUM_CHANNELS];
@@ -316,6 +323,9 @@ struct wlan_regulatory_pdev_priv_obj {
 	enum reg_afc_dev_deploy_type reg_afc_dev_deployment_type;
 #endif
 	bool sta_sap_scc_on_indoor_channel;
+#ifdef CONFIG_REG_CLIENT
+	struct cur_fcc_rule fcc_rules_ptr[MAX_NUM_FCC_RULES];
+#endif
 };
 
 /**

+ 22 - 0
umac/regulatory/dispatcher/inc/reg_services_public_struct.h

@@ -92,6 +92,10 @@
 
 #define MAX_NUM_PWR_LEVEL 16
 
+#ifdef CONFIG_REG_CLIENT
+#define MAX_NUM_FCC_RULES 2
+#endif
+
 /**
  * enum dfs_reg - DFS region
  * @DFS_UNINIT_REGION: un-initialized region
@@ -1165,6 +1169,18 @@ struct cur_reg_rule {
 	uint16_t psd_eirp;
 };
 
+#ifdef CONFIG_REG_CLIENT
+/**
+ * struct cur_fcc_rule
+ * @center_freq: center frequency
+ * @tx_power: transmission power
+ */
+struct cur_fcc_rule {
+	uint16_t center_freq;
+	uint8_t tx_power;
+};
+#endif
+
 /**
  * struct cur_regulatory_info
  * @psoc: psoc ptr
@@ -1201,6 +1217,8 @@ struct cur_reg_rule {
  * @num_6g_reg_rules_client: list of number of 6G reg rules for client
  * @reg_rules_6g_ap_ptr: ptr to 6G AP reg rules
  * @reg_rules_6g_client_ptr: list of ptr to 6G client reg rules
+ * @fcc_rules_ptr: ptr to fcc rules
+ * @num_fcc_rules: Number of fcc rules sent by firmware
  */
 struct cur_regulatory_info {
 	struct wlan_objmgr_psoc *psoc;
@@ -1236,6 +1254,10 @@ struct cur_regulatory_info {
 	uint32_t num_6g_reg_rules_client[REG_CURRENT_MAX_AP_TYPE][REG_MAX_CLIENT_TYPE];
 	struct cur_reg_rule *reg_rules_6g_ap_ptr[REG_CURRENT_MAX_AP_TYPE];
 	struct cur_reg_rule *reg_rules_6g_client_ptr[REG_CURRENT_MAX_AP_TYPE][REG_MAX_CLIENT_TYPE];
+#ifdef CONFIG_REG_CLIENT
+	struct cur_fcc_rule *fcc_rules_ptr;
+	uint32_t num_fcc_rules;
+#endif
 };
 
 #if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_BAND_6GHZ)

+ 127 - 0
wmi/src/wmi_unified_tlv.c

@@ -15001,6 +15001,42 @@ static uint16_t wmi_set_htc_tx_tag_tlv(wmi_unified_t wmi_handle,
 }
 
 #ifdef CONFIG_BAND_6GHZ
+#ifdef CONFIG_REG_CLIENT
+/**
+ * extract_ext_fcc_rules_from_wmi - extract fcc rules from WMI TLV
+ * @num_fcc_rules: Number of FCC rules
+ * @wmi_fcc_rule:  WMI FCC rules TLV
+ *
+ * Return fcc_rule_ptr
+ */
+static struct cur_fcc_rule
+*extract_ext_fcc_rules_from_wmi(uint32_t num_fcc_rules,
+		wmi_regulatory_fcc_rule_struct *wmi_fcc_rule)
+{
+	struct cur_fcc_rule *fcc_rule_ptr;
+	uint32_t count;
+
+	if (!wmi_fcc_rule)
+		return NULL;
+
+	fcc_rule_ptr = qdf_mem_malloc(num_fcc_rules *
+				      sizeof(*fcc_rule_ptr));
+	if (!fcc_rule_ptr)
+		return NULL;
+
+	for (count = 0; count < num_fcc_rules; count++) {
+		fcc_rule_ptr[count].center_freq =
+			WMI_REG_FCC_RULE_CHAN_FREQ_GET(
+					wmi_fcc_rule[count].freq_info);
+		fcc_rule_ptr[count].tx_power =
+			WMI_REG_FCC_RULE_FCC_TX_POWER_GET(
+					wmi_fcc_rule[count].freq_info);
+	}
+
+	return fcc_rule_ptr;
+}
+#endif
+
 static struct cur_reg_rule
 *create_ext_reg_rules_from_wmi(uint32_t num_reg_rules,
 		wmi_regulatory_rule_ext_struct *wmi_reg_rule)
@@ -15109,6 +15145,90 @@ static enum cc_setting_code wmi_reg_status_to_reg_status(
 }
 
 #ifdef CONFIG_BAND_6GHZ
+
+#ifdef CONFIG_REG_CLIENT
+#define MAX_NUM_FCC_RULES 2
+
+/**
+ * extract_reg_fcc_rules_tlv - Extract reg fcc rules TLV
+ * @param_buf - Pointer to WMI params TLV
+ * @ext_chan_list_event_hdr - Pointer to REG CHAN LIST CC EXT EVENT Fixed
+ *			      Params TLV
+ * @ext_wmi_reg_rule - Pointer to REG CHAN LIST CC EXT EVENT Reg Rules TLV
+ * @ext_wmi_chan_priority - Pointer to REG CHAN LIST CC EXT EVENT Chan
+ *			    Priority TLV
+ * @evt_buf - Pointer to REG CHAN LIST CC EXT EVENT event buffer
+ * @reg_info - Pointer to Regulatory Info
+ * @len - Length of REG CHAN LIST CC EXT EVENT buffer
+ *
+ * Return - QDF_STATUS
+ */
+static QDF_STATUS extract_reg_fcc_rules_tlv(
+	WMI_REG_CHAN_LIST_CC_EXT_EVENTID_param_tlvs *param_buf,
+	wmi_reg_chan_list_cc_event_ext_fixed_param *ext_chan_list_event_hdr,
+	wmi_regulatory_rule_ext_struct *ext_wmi_reg_rule,
+	wmi_regulatory_chan_priority_struct *ext_wmi_chan_priority,
+	uint8_t *evt_buf,
+	struct cur_regulatory_info *reg_info,
+	uint32_t len)
+{
+	int i;
+	wmi_regulatory_fcc_rule_struct *ext_wmi_fcc_rule;
+
+	if (!param_buf) {
+		wmi_err("invalid channel list event buf");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	reg_info->num_fcc_rules = 0;
+	if (param_buf->reg_fcc_rule) {
+		if (param_buf->num_reg_fcc_rule > MAX_NUM_FCC_RULES) {
+			wmi_err("Number of fcc rules is greater than MAX_NUM_FCC_RULES");
+			return QDF_STATUS_E_INVAL;
+		}
+
+		ext_wmi_fcc_rule =
+			(wmi_regulatory_fcc_rule_struct *)
+			((uint8_t *)ext_chan_list_event_hdr +
+			sizeof(wmi_reg_chan_list_cc_event_ext_fixed_param) +
+			WMI_TLV_HDR_SIZE +
+			sizeof(wmi_regulatory_rule_ext_struct) *
+			param_buf->num_reg_rule_array +
+			WMI_TLV_HDR_SIZE +
+			sizeof(wmi_regulatory_chan_priority_struct) *
+			param_buf->num_reg_chan_priority +
+			WMI_TLV_HDR_SIZE);
+
+		reg_info->fcc_rules_ptr = extract_ext_fcc_rules_from_wmi(
+						param_buf->num_reg_fcc_rule,
+						ext_wmi_fcc_rule);
+
+		reg_info->num_fcc_rules = param_buf->num_reg_fcc_rule;
+	}
+
+	if (reg_info->fcc_rules_ptr) {
+		for (i = 0; i < reg_info->num_fcc_rules; i++) {
+			wmi_debug("FCC rule %d center_freq %d tx_power %d",
+				  i, reg_info->fcc_rules_ptr[i].center_freq,
+				  reg_info->fcc_rules_ptr[i].tx_power);
+		}
+	}
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS extract_reg_fcc_rules_tlv(
+	WMI_REG_CHAN_LIST_CC_EXT_EVENTID_param_tlvs *param_buf,
+	wmi_reg_chan_list_cc_event_ext_fixed_param *ext_chan_list_event_hdr,
+	wmi_regulatory_rule_ext_struct *ext_wmi_reg_rule,
+	wmi_regulatory_chan_priority_struct *ext_wmi_chan_priority,
+	uint8_t *evt_buf,
+	struct cur_regulatory_info *reg_info,
+	uint32_t len)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 static QDF_STATUS extract_reg_chan_list_ext_update_event_tlv(
 	wmi_unified_t wmi_handle, uint8_t *evt_buf,
 	struct cur_regulatory_info *reg_info, uint32_t len)
@@ -15122,6 +15242,7 @@ static QDF_STATUS extract_reg_chan_list_ext_update_event_tlv(
 	uint32_t num_6g_reg_rules_ap[REG_CURRENT_MAX_AP_TYPE];
 	uint32_t *num_6g_reg_rules_client[REG_CURRENT_MAX_AP_TYPE];
 	uint32_t total_reg_rules = 0;
+	QDF_STATUS status;
 
 	param_buf = (WMI_REG_CHAN_LIST_CC_EXT_EVENTID_param_tlvs *)evt_buf;
 	if (!param_buf) {
@@ -15431,6 +15552,12 @@ static QDF_STATUS extract_reg_chan_list_ext_update_event_tlv(
 	reg_info->domain_code_6g_super_id =
 		ext_chan_list_event_hdr->domain_code_6g_super_id;
 
+	status = extract_reg_fcc_rules_tlv(param_buf, ext_chan_list_event_hdr,
+				  ext_wmi_reg_rule, ext_wmi_chan_priority,
+				  evt_buf, reg_info, len);
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
 	wmi_debug("processed regulatory extended channel list");
 
 	return QDF_STATUS_SUCCESS;