Commit 91fa00fa authored by Aditya Kumar Singh's avatar Aditya Kumar Singh Committed by Kalle Valo
Browse files

wifi: ath11k: add support to parse new WMI event for 6 GHz



In order to support different power levels of 6 GHz AP and client,
new WMI event for regulatory - WMI_REG_CHAN_LIST_CC_EXT_EVENTID is
added in firmware. This event provides new parameters required for
6 GHz regulatory rules.

Add support for parsing 2.4 GHz, 5 GHz and 6 GHz reg rules and other
parameters from WMI_REG_CHAN_LIST_CC_EXT_EVENTID.

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1

Signed-off-by: default avatarLavanya Suresh <quic_lavaks@quicinc.com>
Signed-off-by: default avatarWen Gong <quic_wgong@quicinc.com>
Signed-off-by: default avatarAditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230110121024.14051-3-quic_adisi@quicinc.com
parent 25e289e1
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -613,7 +613,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
{
	struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
	struct cur_reg_rule *reg_rule;
	u8 i = 0, j = 0;
	u8 i = 0, j = 0, k = 0;
	u8 num_rules;
	u16 max_bw;
	u32 flags;
@@ -621,6 +621,12 @@ ath11k_reg_build_regd(struct ath11k_base *ab,

	num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules;

	/* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list.
	 * This can be updated after complete 6 GHz regulatory support is added.
	 */
	if (reg_info->is_ext_reg_event)
		num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];

	if (!num_rules)
		goto ret;

@@ -666,6 +672,14 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
			 * per other BW rule flags we pass from here
			 */
			flags = NL80211_RRF_AUTO_BW;
		} else if (reg_info->is_ext_reg_event &&
			   reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] &&
			   (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) {
			reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] +
				   k++;
			max_bw = min_t(u16, reg_rule->max_bw,
				       reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]);
			flags = NL80211_RRF_AUTO_BW;
		} else {
			break;
		}
@@ -693,6 +707,14 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
			continue;
		}

		if (reg_info->is_ext_reg_event) {
			ath11k_dbg(ab, ATH11K_DBG_REG,
				   "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n",
				   i + 1, reg_rule->start_freq, reg_rule->end_freq,
				   max_bw, reg_rule->ant_gain, reg_rule->reg_power,
				   tmp_regd->reg_rules[i].dfs_cac_ms, flags,
				   reg_rule->psd_flag, reg_rule->psd_eirp);
		} else {
			ath11k_dbg(ab, ATH11K_DBG_REG,
				   "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
				   i + 1, reg_rule->start_freq, reg_rule->end_freq,
@@ -700,6 +722,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
				   tmp_regd->reg_rules[i].dfs_cac_ms,
				   flags);
		}
	}

	tmp_regd->n_reg_rules = i;

+402 −16
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = {
		= { .min_len = sizeof(struct wmi_vdev_stopped_event) },
	[WMI_TAG_REG_CHAN_LIST_CC_EVENT]
		= { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) },
	[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]
		= { .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) },
	[WMI_TAG_MGMT_RX_HDR]
		= { .min_len = sizeof(struct wmi_mgmt_rx_hdr) },
	[WMI_TAG_MGMT_TX_COMPL_EVENT]
@@ -3974,6 +3976,10 @@ ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg,
	wmi_cfg->sched_params = tg_cfg->sched_params;
	wmi_cfg->twt_ap_pdev_count = tg_cfg->twt_ap_pdev_count;
	wmi_cfg->twt_ap_sta_count = tg_cfg->twt_ap_sta_count;
	wmi_cfg->host_service_flags &=
		~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
	wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported <<
					WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT);
}

static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
@@ -4192,6 +4198,10 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab)

	ab->hw_params.hw_ops->wmi_init_config(ab, &config);

	if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,
		     ab->wmi_ab.svc_map))
		config.is_reg_cc_ext_event_supported = 1;

	memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config));

	init_param.res_cfg = &wmi_sc->wlan_resource_config;
@@ -4995,18 +5005,11 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
	reg_info->phy_id = chan_list_event_hdr->phy_id;
	reg_info->ctry_code = chan_list_event_hdr->country_id;
	reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code;
	if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_PASS)
		reg_info->status_code = REG_SET_CC_STATUS_PASS;
	else if (chan_list_event_hdr->status_code == WMI_REG_CURRENT_ALPHA2_NOT_FOUND)
		reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND;
	else if (chan_list_event_hdr->status_code == WMI_REG_INIT_ALPHA2_NOT_FOUND)
		reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND;
	else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_CHANGE_NOT_ALLOWED)
		reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED;
	else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_NO_MEMORY)
		reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY;
	else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL)
		reg_info->status_code = REG_SET_CC_STATUS_FAIL;

	reg_info->status_code =
		ath11k_wmi_cc_setting_code_to_reg(chan_list_event_hdr->status_code);

	reg_info->is_ext_reg_event = false;

	reg_info->min_bw_2ghz = chan_list_event_hdr->min_bw_2ghz;
	reg_info->max_bw_2ghz = chan_list_event_hdr->max_bw_2ghz;
@@ -5060,6 +5063,372 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
	return 0;
}

static struct cur_reg_rule
*create_ext_reg_rules_from_wmi(u32 num_reg_rules,
			       struct wmi_regulatory_ext_rule *wmi_reg_rule)
{
	struct cur_reg_rule *reg_rule_ptr;
	u32 count;

	reg_rule_ptr =  kcalloc(num_reg_rules, sizeof(*reg_rule_ptr), GFP_ATOMIC);

	if (!reg_rule_ptr)
		return NULL;

	for (count = 0; count < num_reg_rules; count++) {
		reg_rule_ptr[count].start_freq =
			u32_get_bits(wmi_reg_rule[count].freq_info,
				     REG_RULE_START_FREQ);
		reg_rule_ptr[count].end_freq =
			u32_get_bits(wmi_reg_rule[count].freq_info,
				     REG_RULE_END_FREQ);
		reg_rule_ptr[count].max_bw =
			u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
				     REG_RULE_MAX_BW);
		reg_rule_ptr[count].reg_power =
			u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
				     REG_RULE_REG_PWR);
		reg_rule_ptr[count].ant_gain =
			u32_get_bits(wmi_reg_rule[count].bw_pwr_info,
				     REG_RULE_ANT_GAIN);
		reg_rule_ptr[count].flags =
			u32_get_bits(wmi_reg_rule[count].flag_info,
				     REG_RULE_FLAGS);
		reg_rule_ptr[count].psd_flag =
			u32_get_bits(wmi_reg_rule[count].psd_power_info,
				     REG_RULE_PSD_INFO);
		reg_rule_ptr[count].psd_eirp =
			u32_get_bits(wmi_reg_rule[count].psd_power_info,
				     REG_RULE_PSD_EIRP);
	}

	return reg_rule_ptr;
}

static u8
ath11k_invalid_5ghz_reg_ext_rules_from_wmi(u32 num_reg_rules,
					   const struct wmi_regulatory_ext_rule *rule)
{
	u8 num_invalid_5ghz_rules = 0;
	u32 count, start_freq;

	for (count = 0; count < num_reg_rules; count++) {
		start_freq = u32_get_bits(rule[count].freq_info,
					  REG_RULE_START_FREQ);

		if (start_freq >= ATH11K_MIN_6G_FREQ)
			num_invalid_5ghz_rules++;
	}

	return num_invalid_5ghz_rules;
}

static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab,
						   struct sk_buff *skb,
						   struct cur_regulatory_info *reg_info)
{
	const void **tb;
	const struct wmi_reg_chan_list_cc_ext_event *ext_chan_list_event_hdr;
	struct wmi_regulatory_ext_rule *ext_wmi_reg_rule;
	u32 num_2ghz_reg_rules, num_5ghz_reg_rules;
	u32 num_6ghz_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
	u32 num_6ghz_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
	u32 total_reg_rules = 0;
	int ret, i, j, num_invalid_5ghz_ext_rules = 0;

	ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n");

	tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
	if (IS_ERR(tb)) {
		ret = PTR_ERR(tb);
		ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
		return ret;
	}

	ext_chan_list_event_hdr = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
	if (!ext_chan_list_event_hdr) {
		ath11k_warn(ab, "failed to fetch reg chan list ext update ev\n");
		kfree(tb);
		return -EPROTO;
	}

	reg_info->num_2ghz_reg_rules =
			ext_chan_list_event_hdr->num_2ghz_reg_rules;
	reg_info->num_5ghz_reg_rules =
			ext_chan_list_event_hdr->num_5ghz_reg_rules;
	reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] =
			ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_lpi;
	reg_info->num_6ghz_rules_ap[WMI_REG_STANDARD_POWER_AP] =
			ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_sp;
	reg_info->num_6ghz_rules_ap[WMI_REG_VERY_LOW_POWER_AP] =
			ext_chan_list_event_hdr->num_6ghz_reg_rules_ap_vlp;

	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
		reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i] =
			ext_chan_list_event_hdr->num_6ghz_reg_rules_client_lpi[i];
		reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i] =
			ext_chan_list_event_hdr->num_6ghz_reg_rules_client_sp[i];
		reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] =
			ext_chan_list_event_hdr->num_6ghz_reg_rules_client_vlp[i];
	}

	num_2ghz_reg_rules = reg_info->num_2ghz_reg_rules;
	num_5ghz_reg_rules = reg_info->num_5ghz_reg_rules;

	total_reg_rules += num_2ghz_reg_rules;
	total_reg_rules += num_5ghz_reg_rules;

	if ((num_2ghz_reg_rules > MAX_REG_RULES) ||
	    (num_5ghz_reg_rules > MAX_REG_RULES)) {
		ath11k_warn(ab, "Num reg rules for 2.4 GHz/5 GHz exceeds max limit (num_2ghz_reg_rules: %d num_5ghz_reg_rules: %d max_rules: %d)\n",
			    num_2ghz_reg_rules, num_5ghz_reg_rules, MAX_REG_RULES);
		kfree(tb);
		return -EINVAL;
	}

	for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
		num_6ghz_reg_rules_ap[i] = reg_info->num_6ghz_rules_ap[i];

		if (num_6ghz_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) {
			ath11k_warn(ab, "Num 6 GHz reg rules for AP mode(%d) exceeds max limit (num_6ghz_reg_rules_ap: %d, max_rules: %d)\n",
				    i, num_6ghz_reg_rules_ap[i], MAX_6GHZ_REG_RULES);
			kfree(tb);
			return -EINVAL;
		}

		total_reg_rules += num_6ghz_reg_rules_ap[i];
	}

	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
		num_6ghz_client[WMI_REG_INDOOR_AP][i] =
			reg_info->num_6ghz_rules_client[WMI_REG_INDOOR_AP][i];
		total_reg_rules += num_6ghz_client[WMI_REG_INDOOR_AP][i];

		num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
			reg_info->num_6ghz_rules_client[WMI_REG_STANDARD_POWER_AP][i];
		total_reg_rules += num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i];

		num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
			reg_info->num_6ghz_rules_client[WMI_REG_VERY_LOW_POWER_AP][i];
		total_reg_rules += num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i];

		if ((num_6ghz_client[WMI_REG_INDOOR_AP][i] > MAX_6GHZ_REG_RULES) ||
		    (num_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] >
							     MAX_6GHZ_REG_RULES) ||
		    (num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] >
							     MAX_6GHZ_REG_RULES)) {
			ath11k_warn(ab,
				    "Num 6 GHz client reg rules exceeds max limit, for client(type: %d)\n",
				    i);
			kfree(tb);
			return -EINVAL;
		}
	}

	if (!total_reg_rules) {
		ath11k_warn(ab, "No reg rules available\n");
		kfree(tb);
		return -EINVAL;
	}

	memcpy(reg_info->alpha2, &ext_chan_list_event_hdr->alpha2,
	       REG_ALPHA2_LEN);

	reg_info->dfs_region = ext_chan_list_event_hdr->dfs_region;
	reg_info->phybitmap = ext_chan_list_event_hdr->phybitmap;
	reg_info->num_phy = ext_chan_list_event_hdr->num_phy;
	reg_info->phy_id = ext_chan_list_event_hdr->phy_id;
	reg_info->ctry_code = ext_chan_list_event_hdr->country_id;
	reg_info->reg_dmn_pair = ext_chan_list_event_hdr->domain_code;

	reg_info->status_code =
		ath11k_wmi_cc_setting_code_to_reg(ext_chan_list_event_hdr->status_code);

	reg_info->is_ext_reg_event = true;

	reg_info->min_bw_2ghz = ext_chan_list_event_hdr->min_bw_2ghz;
	reg_info->max_bw_2ghz = ext_chan_list_event_hdr->max_bw_2ghz;
	reg_info->min_bw_5ghz = ext_chan_list_event_hdr->min_bw_5ghz;
	reg_info->max_bw_5ghz = ext_chan_list_event_hdr->max_bw_5ghz;

	reg_info->min_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
			ext_chan_list_event_hdr->min_bw_6ghz_ap_lpi;
	reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP] =
			 ext_chan_list_event_hdr->max_bw_6ghz_ap_lpi;
	reg_info->min_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
			ext_chan_list_event_hdr->min_bw_6ghz_ap_sp;
	reg_info->max_bw_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
			ext_chan_list_event_hdr->max_bw_6ghz_ap_sp;
	reg_info->min_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
			ext_chan_list_event_hdr->min_bw_6ghz_ap_vlp;
	reg_info->max_bw_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
			ext_chan_list_event_hdr->max_bw_6ghz_ap_vlp;

	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
		reg_info->min_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
				ext_chan_list_event_hdr->min_bw_6ghz_client_lpi[i];
		reg_info->max_bw_6ghz_client[WMI_REG_INDOOR_AP][i] =
				ext_chan_list_event_hdr->max_bw_6ghz_client_lpi[i];
		reg_info->min_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
				ext_chan_list_event_hdr->min_bw_6ghz_client_sp[i];
		reg_info->max_bw_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
				ext_chan_list_event_hdr->max_bw_6ghz_client_sp[i];
		reg_info->min_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
				ext_chan_list_event_hdr->min_bw_6ghz_client_vlp[i];
		reg_info->max_bw_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
				ext_chan_list_event_hdr->max_bw_6ghz_client_vlp[i];
	}

	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "%s:cc_ext %s dsf %d BW: min_2ghz %d max_2ghz %d min_5ghz %d max_5ghz %d",
		   __func__, reg_info->alpha2, reg_info->dfs_region,
		   reg_info->min_bw_2ghz, reg_info->max_bw_2ghz,
		   reg_info->min_bw_5ghz, reg_info->max_bw_5ghz);

	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "num_2ghz_reg_rules %d num_5ghz_reg_rules %d",
		   num_2ghz_reg_rules, num_5ghz_reg_rules);

	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "num_6ghz_reg_rules_ap_lpi: %d num_6ghz_reg_rules_ap_sp: %d num_6ghz_reg_rules_ap_vlp: %d",
		   num_6ghz_reg_rules_ap[WMI_REG_INDOOR_AP],
		   num_6ghz_reg_rules_ap[WMI_REG_STANDARD_POWER_AP],
		   num_6ghz_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP]);

	j = WMI_REG_DEFAULT_CLIENT;
	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "6 GHz Regular client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d",
		   num_6ghz_client[WMI_REG_INDOOR_AP][j],
		   num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j],
		   num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);

	j = WMI_REG_SUBORDINATE_CLIENT;
	ath11k_dbg(ab, ATH11K_DBG_WMI,
		   "6 GHz Subordinate client: num_6ghz_reg_rules_lpi: %d num_6ghz_reg_rules_sp: %d num_6ghz_reg_rules_vlp: %d",
		   num_6ghz_client[WMI_REG_INDOOR_AP][j],
		   num_6ghz_client[WMI_REG_STANDARD_POWER_AP][j],
		   num_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][j]);

	ext_wmi_reg_rule =
		(struct wmi_regulatory_ext_rule *)((u8 *)ext_chan_list_event_hdr
						   + sizeof(*ext_chan_list_event_hdr)
						   + sizeof(struct wmi_tlv));
	if (num_2ghz_reg_rules) {
		reg_info->reg_rules_2ghz_ptr =
			create_ext_reg_rules_from_wmi(num_2ghz_reg_rules,
						      ext_wmi_reg_rule);

		if (!reg_info->reg_rules_2ghz_ptr) {
			kfree(tb);
			ath11k_warn(ab, "Unable to Allocate memory for 2 GHz rules\n");
			return -ENOMEM;
		}
	}

	ext_wmi_reg_rule += num_2ghz_reg_rules;

	/* Firmware might include 6 GHz reg rule in 5 GHz rule list
	 * for few countries along with separate 6 GHz rule.
	 * Having same 6 GHz reg rule in 5 GHz and 6 GHz rules list
	 * causes intersect check to be true, and same rules will be
	 * shown multiple times in iw cmd.
	 * Hence, avoid parsing 6 GHz rule from 5 GHz reg rule list
	 */
	num_invalid_5ghz_ext_rules =
		ath11k_invalid_5ghz_reg_ext_rules_from_wmi(num_5ghz_reg_rules,
							   ext_wmi_reg_rule);

	if (num_invalid_5ghz_ext_rules) {
		ath11k_dbg(ab, ATH11K_DBG_WMI,
			   "CC: %s 5 GHz reg rules number %d from fw, %d number of invalid 5 GHz rules",
			   reg_info->alpha2, reg_info->num_5ghz_reg_rules,
			   num_invalid_5ghz_ext_rules);

		num_5ghz_reg_rules = num_5ghz_reg_rules - num_invalid_5ghz_ext_rules;
		reg_info->num_5ghz_reg_rules = num_5ghz_reg_rules;
	}

	if (num_5ghz_reg_rules) {
		reg_info->reg_rules_5ghz_ptr =
			create_ext_reg_rules_from_wmi(num_5ghz_reg_rules,
						      ext_wmi_reg_rule);

		if (!reg_info->reg_rules_5ghz_ptr) {
			kfree(tb);
			ath11k_warn(ab, "Unable to Allocate memory for 5 GHz rules\n");
			return -ENOMEM;
		}
	}

	/* We have adjusted the number of 5 GHz reg rules above. But still those
	 * many rules needs to be adjusted in ext_wmi_reg_rule.
	 *
	 * NOTE: num_invalid_5ghz_ext_rules will be 0 for rest other cases.
	 */
	ext_wmi_reg_rule += (num_5ghz_reg_rules + num_invalid_5ghz_ext_rules);

	for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
		reg_info->reg_rules_6ghz_ap_ptr[i] =
			create_ext_reg_rules_from_wmi(num_6ghz_reg_rules_ap[i],
						      ext_wmi_reg_rule);

		if (!reg_info->reg_rules_6ghz_ap_ptr[i]) {
			kfree(tb);
			ath11k_warn(ab, "Unable to Allocate memory for 6 GHz AP rules\n");
			return -ENOMEM;
		}

		ext_wmi_reg_rule += num_6ghz_reg_rules_ap[i];
	}

	for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
		for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
			reg_info->reg_rules_6ghz_client_ptr[j][i] =
				create_ext_reg_rules_from_wmi(num_6ghz_client[j][i],
							      ext_wmi_reg_rule);

			if (!reg_info->reg_rules_6ghz_client_ptr[j][i]) {
				kfree(tb);
				ath11k_warn(ab, "Unable to Allocate memory for 6 GHz client rules\n");
				return -ENOMEM;
			}

			ext_wmi_reg_rule += num_6ghz_client[j][i];
		}
	}

	reg_info->client_type = ext_chan_list_event_hdr->client_type;
	reg_info->rnr_tpe_usable = ext_chan_list_event_hdr->rnr_tpe_usable;
	reg_info->unspecified_ap_usable =
			ext_chan_list_event_hdr->unspecified_ap_usable;
	reg_info->domain_code_6ghz_ap[WMI_REG_INDOOR_AP] =
			ext_chan_list_event_hdr->domain_code_6ghz_ap_lpi;
	reg_info->domain_code_6ghz_ap[WMI_REG_STANDARD_POWER_AP] =
			ext_chan_list_event_hdr->domain_code_6ghz_ap_sp;
	reg_info->domain_code_6ghz_ap[WMI_REG_VERY_LOW_POWER_AP] =
			ext_chan_list_event_hdr->domain_code_6ghz_ap_vlp;

	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
		reg_info->domain_code_6ghz_client[WMI_REG_INDOOR_AP][i] =
				ext_chan_list_event_hdr->domain_code_6ghz_client_lpi[i];
		reg_info->domain_code_6ghz_client[WMI_REG_STANDARD_POWER_AP][i] =
				ext_chan_list_event_hdr->domain_code_6ghz_client_sp[i];
		reg_info->domain_code_6ghz_client[WMI_REG_VERY_LOW_POWER_AP][i] =
				ext_chan_list_event_hdr->domain_code_6ghz_client_vlp[i];
	}

	reg_info->domain_code_6ghz_super_id =
			ext_chan_list_event_hdr->domain_code_6ghz_super_id;

	ath11k_dbg(ab, ATH11K_DBG_WMI, "6 GHz client_type: %d domain_code_6ghz_super_id: %d",
		   reg_info->client_type, reg_info->domain_code_6ghz_super_id);

	ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory ext channel list\n");

	kfree(tb);
	return 0;
}

static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *skb,
					struct wmi_peer_delete_resp_event *peer_del_resp)
{
@@ -6507,12 +6876,14 @@ static bool ath11k_reg_is_world_alpha(char *alpha)
	return false;
}

static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb)
static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
				      struct sk_buff *skb,
				      enum wmi_reg_chan_list_cmd_type id)
{
	struct cur_regulatory_info *reg_info = NULL;
	struct ieee80211_regdomain *regd = NULL;
	bool intersect = false;
	int ret = 0, pdev_idx;
	int ret = 0, pdev_idx, i, j;
	struct ath11k *ar;

	reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
@@ -6521,7 +6892,11 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
		goto fallback;
	}

	if (id == WMI_REG_CHAN_LIST_CC_ID)
		ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
	else
		ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);

	if (ret) {
		ath11k_warn(ab, "failed to extract regulatory info from received event\n");
		goto fallback;
@@ -6623,6 +6998,14 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
	if (reg_info) {
		kfree(reg_info->reg_rules_2ghz_ptr);
		kfree(reg_info->reg_rules_5ghz_ptr);
		if (reg_info->is_ext_reg_event) {
			for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
				kfree(reg_info->reg_rules_6ghz_ap_ptr[i]);

			for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
				for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)
					kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]);
		}
		kfree(reg_info);
	}
	return ret;
@@ -8054,7 +8437,10 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
		ath11k_service_ready_ext2_event(ab, skb);
		break;
	case WMI_REG_CHAN_LIST_CC_EVENTID:
		ath11k_reg_chan_list_event(ab, skb);
		ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_ID);
		break;
	case WMI_REG_CHAN_LIST_CC_EXT_EVENTID:
		ath11k_reg_chan_list_event(ab, skb, WMI_REG_CHAN_LIST_CC_EXT_ID);
		break;
	case WMI_READY_EVENTID:
		ath11k_ready_event(ab, skb);
+152 −11

File changed.

Preview size limit exceeded, changes collapsed.