mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-19 10:23:03 +00:00
729 lines
26 KiB
Diff
729 lines
26 KiB
Diff
From 3d0653d618e62e969ecb5f3bf8c35a2c5b64d531 Mon Sep 17 00:00:00 2001
|
|
From: Lavanya Suresh <lavaks@codeaurora.org>
|
|
Date: Thu, 25 Mar 2021 23:23:50 +0530
|
|
Subject: [PATCH] ath11k: Add support to parse new wmi event for 6G regulatory
|
|
|
|
In order to support different power levels of 6G AP and client, new
|
|
wmi event for regulatory is added in FW (WMI_REG_CHAN_LIST_CC_EXT_EVENTID)
|
|
to provide new parameters required for 6G regulatory rules.
|
|
|
|
FW advertises its capability of handling new event in wmi service ready
|
|
event. Based on that, host needs to set host_service_flags in wmi init
|
|
command to indicate that host supports processing of new wmi event.
|
|
Based on advertised host capability, FW decides to send old event
|
|
(WMI_REG_CHAN_LIST_CC_EVENTID) or new event(WMI_REG_CHAN_LIST_CC_EXT_EVENTID).
|
|
|
|
Added support for parsing 2G/5G/6G reg rules and other parameters from
|
|
WMI_REG_CHAN_LIST_CC_EXT_EVENTID, to populate the channel lists.
|
|
Since 6G requires additional power value fields(PSD info), reg rule parsing
|
|
function is updated accordingly to handle it.
|
|
|
|
Signed-off-by: Lavanya Suresh <lavaks@codeaurora.org>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/reg.c | 36 +++-
|
|
drivers/net/wireless/ath/ath11k/wmi.c | 361 +++++++++++++++++++++++++++++++++-
|
|
drivers/net/wireless/ath/ath11k/wmi.h | 101 ++++++++++
|
|
3 files changed, 487 insertions(+), 11 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/reg.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/reg.c
|
|
@@ -513,7 +513,7 @@ ath11k_reg_build_regd(struct ath11k_base
|
|
{
|
|
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;
|
|
@@ -521,6 +521,13 @@ ath11k_reg_build_regd(struct ath11k_base
|
|
|
|
num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
|
|
|
|
+ /* FIXME: Currently taking reg rules for 6G only from Indoor AP mode list.
|
|
+ * This can be updated to choose the combination dynamically based on AP
|
|
+ * type and client type, after complete 6G regulatory support is added.
|
|
+ */
|
|
+ if (reg_info->is_ext_reg_event)
|
|
+ num_rules += reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP];
|
|
+
|
|
if (!num_rules)
|
|
goto ret;
|
|
|
|
@@ -566,6 +573,12 @@ ath11k_reg_build_regd(struct ath11k_base
|
|
* 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_6g_reg_rules_ap[WMI_REG_INDOOR_AP] &&
|
|
+ (k < reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP])) {
|
|
+ reg_rule = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP] + k++;
|
|
+ max_bw = min_t(u16, reg_rule->max_bw,
|
|
+ reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP]);
|
|
+ flags = NL80211_RRF_AUTO_BW;
|
|
} else {
|
|
break;
|
|
}
|
|
@@ -593,12 +606,21 @@ ath11k_reg_build_regd(struct ath11k_base
|
|
continue;
|
|
}
|
|
|
|
- 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,
|
|
- max_bw, reg_rule->ant_gain, reg_rule->reg_power,
|
|
- tmp_regd->reg_rules[i].dfs_cac_ms,
|
|
- flags);
|
|
+ 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,
|
|
+ max_bw, reg_rule->ant_gain, reg_rule->reg_power,
|
|
+ tmp_regd->reg_rules[i].dfs_cac_ms,
|
|
+ flags);
|
|
+ }
|
|
}
|
|
|
|
tmp_regd->n_reg_rules = i;
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
|
@@ -101,6 +101,8 @@ static const struct wmi_tlv_policy wmi_t
|
|
= { .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]
|
|
@@ -4371,6 +4373,9 @@ ath11k_wmi_copy_resource_config(struct w
|
|
wmi_cfg->ema_max_vap_cnt = tg_cfg->ema_max_vap_cnt;
|
|
wmi_cfg->ema_max_profile_period = tg_cfg->ema_max_profile_period;
|
|
wmi_cfg->max_num_group_keys = tg_cfg->max_num_group_keys;
|
|
+ wmi_cfg->host_service_flags &= ~(1 << WMI_RSRC_CFG_HOST_SERVICE_FLAG_REG_CC_EXT_SUPPORT_BIT);
|
|
+ wmi_cfg->host_service_flags |= tg_cfg->is_reg_cc_ext_event_supported <<
|
|
+ WMI_RSRC_CFG_HOST_SERVICE_FLAG_REG_CC_EXT_SUPPORT_BIT;
|
|
}
|
|
|
|
static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
|
|
@@ -4591,6 +4596,9 @@ int ath11k_wmi_cmd_init(struct ath11k_ba
|
|
config.ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD;
|
|
config.beacon_tx_offload_max_vdev += config.ema_max_vap_cnt;
|
|
|
|
+ if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, ab->wmi_ab.svc_map))
|
|
+ config.is_reg_cc_ext_event_supported = 1;
|
|
+
|
|
if (ab->nss.enabled)
|
|
config.max_num_group_keys = ATH11K_GROUP_KEYS_NUM_MAX;
|
|
|
|
@@ -5414,6 +5422,8 @@ static int ath11k_pull_reg_chan_list_upd
|
|
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->is_ext_reg_event = false;
|
|
+
|
|
reg_info->min_bw_2g = chan_list_event_hdr->min_bw_2g;
|
|
reg_info->max_bw_2g = chan_list_event_hdr->max_bw_2g;
|
|
reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g;
|
|
@@ -5464,6 +5474,347 @@ static int ath11k_pull_reg_chan_list_upd
|
|
return 0;
|
|
}
|
|
|
|
+static struct cur_reg_rule
|
|
+*create_ext_reg_rules_from_wmi(u32 num_reg_rules,
|
|
+ struct wmi_regulatory_ext_rule_struct *wmi_reg_rule)
|
|
+{
|
|
+ struct cur_reg_rule *reg_rule_ptr;
|
|
+ u32 count;
|
|
+
|
|
+ reg_rule_ptr = kzalloc((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 =
|
|
+ FIELD_GET(REG_RULE_START_FREQ,
|
|
+ wmi_reg_rule[count].freq_info);
|
|
+ reg_rule_ptr[count].end_freq =
|
|
+ FIELD_GET(REG_RULE_END_FREQ,
|
|
+ wmi_reg_rule[count].freq_info);
|
|
+ reg_rule_ptr[count].max_bw =
|
|
+ FIELD_GET(REG_RULE_MAX_BW,
|
|
+ wmi_reg_rule[count].bw_pwr_info);
|
|
+ reg_rule_ptr[count].reg_power =
|
|
+ FIELD_GET(REG_RULE_REG_PWR,
|
|
+ wmi_reg_rule[count].bw_pwr_info);
|
|
+ reg_rule_ptr[count].ant_gain =
|
|
+ FIELD_GET(REG_RULE_ANT_GAIN,
|
|
+ wmi_reg_rule[count].bw_pwr_info);
|
|
+ reg_rule_ptr[count].flags =
|
|
+ FIELD_GET(REG_RULE_FLAGS,
|
|
+ wmi_reg_rule[count].flag_info);
|
|
+ reg_rule_ptr[count].psd_flag =
|
|
+ FIELD_GET(REG_RULE_PSD_INFO,
|
|
+ wmi_reg_rule[count].psd_power_info);
|
|
+ reg_rule_ptr[count].psd_eirp =
|
|
+ FIELD_GET(REG_RULE_PSD_EIRP,
|
|
+ wmi_reg_rule[count].psd_power_info);
|
|
+ }
|
|
+
|
|
+ return reg_rule_ptr;
|
|
+}
|
|
+
|
|
+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_struct *ext_wmi_reg_rule;
|
|
+ u32 num_2g_reg_rules, num_5g_reg_rules;
|
|
+ u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
|
|
+ u32 num_6g_reg_rules_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
|
|
+ u32 total_reg_rules = 0;
|
|
+ int ret, i, j;
|
|
+
|
|
+ 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_2g_reg_rules = ext_chan_list_event_hdr->num_2g_reg_rules;
|
|
+ reg_info->num_5g_reg_rules = ext_chan_list_event_hdr->num_5g_reg_rules;
|
|
+ reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] =
|
|
+ ext_chan_list_event_hdr->num_6g_reg_rules_ap_lpi;
|
|
+ reg_info->num_6g_reg_rules_ap[WMI_REG_STANDARD_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->num_6g_reg_rules_ap_sp;
|
|
+ reg_info->num_6g_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->num_6g_reg_rules_ap_vlp;
|
|
+
|
|
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
|
|
+ reg_info->num_6g_reg_rules_client[WMI_REG_INDOOR_AP][i] =
|
|
+ ext_chan_list_event_hdr->num_6g_reg_rules_client_lpi[i];
|
|
+ reg_info->num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->num_6g_reg_rules_client_sp[i];
|
|
+ reg_info->num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->num_6g_reg_rules_client_vlp[i];
|
|
+ }
|
|
+
|
|
+ num_2g_reg_rules = reg_info->num_2g_reg_rules;
|
|
+ total_reg_rules += num_2g_reg_rules;
|
|
+ num_5g_reg_rules = reg_info->num_5g_reg_rules;
|
|
+ total_reg_rules += num_5g_reg_rules;
|
|
+
|
|
+ if ((num_2g_reg_rules > MAX_REG_RULES) || (num_5g_reg_rules > MAX_REG_RULES)) {
|
|
+ ath11k_warn(ab, "Num reg rules for 2G/5G exceeds max limit (num_2g_reg_rules: %d num_5g_reg_rules: %d max_rules: %d)\n",
|
|
+ num_2g_reg_rules, num_5g_reg_rules, MAX_REG_RULES);
|
|
+ kfree(tb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
|
|
+ num_6g_reg_rules_ap[i] = reg_info->num_6g_reg_rules_ap[i];
|
|
+
|
|
+ if (num_6g_reg_rules_ap[i] > MAX_6G_REG_RULES) {
|
|
+ ath11k_warn(ab, "Num 6G reg rules for AP mode(%d) exceeds max limit (num_6g_reg_rules_ap: %d, max_rules: %d)\n",
|
|
+ i, num_6g_reg_rules_ap[i], MAX_6G_REG_RULES);
|
|
+ kfree(tb);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ total_reg_rules += num_6g_reg_rules_ap[i];
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
|
|
+ num_6g_reg_rules_client[WMI_REG_INDOOR_AP][i] =
|
|
+ reg_info->num_6g_reg_rules_client[WMI_REG_INDOOR_AP][i];
|
|
+ total_reg_rules += num_6g_reg_rules_client[WMI_REG_INDOOR_AP][i];
|
|
+
|
|
+ num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][i] =
|
|
+ reg_info->num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][i];
|
|
+ total_reg_rules += num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][i];
|
|
+
|
|
+ num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] =
|
|
+ reg_info->num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][i];
|
|
+ total_reg_rules += num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][i];
|
|
+
|
|
+ if ((num_6g_reg_rules_client[WMI_REG_INDOOR_AP][i] > MAX_6G_REG_RULES) ||
|
|
+ (num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][i] > MAX_6G_REG_RULES) ||
|
|
+ (num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][i] > MAX_6G_REG_RULES)) {
|
|
+ ath11k_warn(ab, "Num 6g 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);
|
|
+
|
|
+ /* FIXME: Currently FW includes 6G reg rule also in 5G rule
|
|
+ * list for country US.
|
|
+ * Having same 6G reg rule in 5G and 6G rules list causes
|
|
+ * intersect check to be true, and same rules will be shown
|
|
+ * multiple times in iw cmd. So added hack below to avoid
|
|
+ * parsing 6G rule from 5G reg rule list, and this can be
|
|
+ * removed later, after FW updates to remove 6G reg rule
|
|
+ * from 5G rules list.
|
|
+ */
|
|
+ if (memcmp(reg_info->alpha2, "US", 2) == 0) {
|
|
+ reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;
|
|
+ num_5g_reg_rules = reg_info->num_5g_reg_rules;
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+
|
|
+ switch(ext_chan_list_event_hdr->status_code) {
|
|
+ case WMI_REG_SET_CC_STATUS_PASS:
|
|
+ reg_info->status_code = REG_SET_CC_STATUS_PASS;
|
|
+ break;
|
|
+ case WMI_REG_CURRENT_ALPHA2_NOT_FOUND:
|
|
+ reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND;
|
|
+ break;
|
|
+ case WMI_REG_INIT_ALPHA2_NOT_FOUND:
|
|
+ reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND;
|
|
+ break;
|
|
+ case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED:
|
|
+ reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED;
|
|
+ break;
|
|
+ case WMI_REG_SET_CC_STATUS_NO_MEMORY:
|
|
+ reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY;
|
|
+ break;
|
|
+ case WMI_REG_SET_CC_STATUS_FAIL:
|
|
+ reg_info->status_code = REG_SET_CC_STATUS_FAIL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ reg_info->is_ext_reg_event = true;
|
|
+
|
|
+ reg_info->min_bw_2g = ext_chan_list_event_hdr->min_bw_2g;
|
|
+ reg_info->max_bw_2g = ext_chan_list_event_hdr->max_bw_2g;
|
|
+ reg_info->min_bw_5g = ext_chan_list_event_hdr->min_bw_5g;
|
|
+ reg_info->max_bw_5g = ext_chan_list_event_hdr->max_bw_5g;
|
|
+ reg_info->min_bw_6g_ap[WMI_REG_INDOOR_AP] =
|
|
+ ext_chan_list_event_hdr->min_bw_6g_ap_lpi;
|
|
+ reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP] =
|
|
+ ext_chan_list_event_hdr->max_bw_6g_ap_lpi;
|
|
+ reg_info->min_bw_6g_ap[WMI_REG_STANDARD_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->min_bw_6g_ap_sp;
|
|
+ reg_info->max_bw_6g_ap[WMI_REG_STANDARD_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->max_bw_6g_ap_sp;
|
|
+ reg_info->min_bw_6g_ap[WMI_REG_VERY_LOW_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->min_bw_6g_ap_vlp;
|
|
+ reg_info->max_bw_6g_ap[WMI_REG_VERY_LOW_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->max_bw_6g_ap_vlp;
|
|
+
|
|
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
|
|
+ reg_info->min_bw_6g_client[WMI_REG_INDOOR_AP][i] =
|
|
+ ext_chan_list_event_hdr->min_bw_6g_client_lpi[i];
|
|
+ reg_info->max_bw_6g_client[WMI_REG_INDOOR_AP][i] =
|
|
+ ext_chan_list_event_hdr->max_bw_6g_client_lpi[i];
|
|
+ reg_info->min_bw_6g_client[WMI_REG_STANDARD_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->min_bw_6g_client_sp[i];
|
|
+ reg_info->max_bw_6g_client[WMI_REG_STANDARD_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->max_bw_6g_client_sp[i];
|
|
+ reg_info->min_bw_6g_client[WMI_REG_VERY_LOW_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->min_bw_6g_client_vlp[i];
|
|
+ reg_info->max_bw_6g_client[WMI_REG_VERY_LOW_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->max_bw_6g_client_vlp[i];
|
|
+ }
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "%s:cc_ext %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
|
|
+ __func__, reg_info->alpha2, reg_info->dfs_region,
|
|
+ reg_info->min_bw_2g, reg_info->max_bw_2g,
|
|
+ reg_info->min_bw_5g, reg_info->max_bw_5g);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "num_2g_reg_rules %d num_5g_reg_rules %d",
|
|
+ num_2g_reg_rules, num_5g_reg_rules);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "num_6g_reg_rules_ap_lpi: %d num_6g_reg_rules_ap_sp: %d num_6g_reg_rules_ap_vlp: %d",
|
|
+ num_6g_reg_rules_ap[WMI_REG_INDOOR_AP], num_6g_reg_rules_ap[WMI_REG_STANDARD_POWER_AP],
|
|
+ num_6g_reg_rules_ap[WMI_REG_VERY_LOW_POWER_AP]);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "6g Regular client: num_6g_reg_rules_lpi: %d num_6g_reg_rules_sp: %d num_6g_reg_rules_vlp: %d",
|
|
+ num_6g_reg_rules_client[WMI_REG_INDOOR_AP][WMI_REG_DEFAULT_CLIENT],
|
|
+ num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][WMI_REG_DEFAULT_CLIENT],
|
|
+ num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][WMI_REG_DEFAULT_CLIENT]);
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "6g Subordinate client: num_6g_reg_rules_lpi: %d num_6g_reg_rules_sp: %d num_6g_reg_rules_vlp: %d",
|
|
+ num_6g_reg_rules_client[WMI_REG_INDOOR_AP][WMI_REG_SUBORDINATE_CLIENT],
|
|
+ num_6g_reg_rules_client[WMI_REG_STANDARD_POWER_AP][WMI_REG_SUBORDINATE_CLIENT],
|
|
+ num_6g_reg_rules_client[WMI_REG_VERY_LOW_POWER_AP][WMI_REG_SUBORDINATE_CLIENT]);
|
|
+
|
|
+ ext_wmi_reg_rule =
|
|
+ (struct wmi_regulatory_rule_ext_struct *)((u8 *)ext_chan_list_event_hdr
|
|
+ + sizeof(*ext_chan_list_event_hdr)
|
|
+ + sizeof(struct wmi_tlv));
|
|
+
|
|
+ if (num_2g_reg_rules) {
|
|
+ reg_info->reg_rules_2g_ptr = create_ext_reg_rules_from_wmi(num_2g_reg_rules,
|
|
+ ext_wmi_reg_rule);
|
|
+
|
|
+ if (!reg_info->reg_rules_2g_ptr) {
|
|
+ kfree(tb);
|
|
+ ath11k_warn(ab, "Unable to Allocate memory for 2g rules\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (num_5g_reg_rules) {
|
|
+ ext_wmi_reg_rule += num_2g_reg_rules;
|
|
+ reg_info->reg_rules_5g_ptr = create_ext_reg_rules_from_wmi(num_5g_reg_rules,
|
|
+ ext_wmi_reg_rule);
|
|
+
|
|
+ if (!reg_info->reg_rules_5g_ptr) {
|
|
+ kfree(tb);
|
|
+ ath11k_warn(ab, "Unable to Allocate memory for 5g rules\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ext_wmi_reg_rule += num_5g_reg_rules;
|
|
+
|
|
+ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
|
|
+ reg_info->reg_rules_6g_ap_ptr[i] =
|
|
+ create_ext_reg_rules_from_wmi(num_6g_reg_rules_ap[i],
|
|
+ ext_wmi_reg_rule);
|
|
+
|
|
+ if (!reg_info->reg_rules_6g_ap_ptr[i]) {
|
|
+ kfree(tb);
|
|
+ ath11k_warn(ab, "Unable to Allocate memory for 6g ap rules\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ ext_wmi_reg_rule += num_6g_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_6g_client_ptr[j][i] =
|
|
+ create_ext_reg_rules_from_wmi(num_6g_reg_rules_client[j][i],
|
|
+ ext_wmi_reg_rule);
|
|
+
|
|
+ if (!reg_info->reg_rules_6g_client_ptr[j][i]) {
|
|
+ kfree(tb);
|
|
+ ath11k_warn(ab, "Unable to Allocate memory for 6g client rules\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ ext_wmi_reg_rule += num_6g_reg_rules_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_6g_ap[WMI_REG_INDOOR_AP] =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_ap_lpi;
|
|
+ reg_info->domain_code_6g_ap[WMI_REG_STANDARD_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_ap_sp;
|
|
+ reg_info->domain_code_6g_ap[WMI_REG_VERY_LOW_POWER_AP] =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_ap_vlp;
|
|
+
|
|
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
|
|
+ reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_client_lpi[i];
|
|
+ reg_info->domain_code_6g_client[WMI_REG_STANDARD_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_client_sp[i];
|
|
+ reg_info->domain_code_6g_client[WMI_REG_VERY_LOW_POWER_AP][i] =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_client_vlp[i];
|
|
+ }
|
|
+
|
|
+ reg_info->domain_code_6g_super_id =
|
|
+ ext_chan_list_event_hdr->domain_code_6g_super_id;
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
|
|
+ reg_info->client_type, reg_info->domain_code_6g_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)
|
|
{
|
|
@@ -6782,12 +7133,12 @@ static bool ath11k_reg_is_world_alpha(ch
|
|
return alpha[0] == '0' && alpha[1] == '0';
|
|
}
|
|
|
|
-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);
|
|
@@ -6796,7 +7147,11 @@ static int ath11k_reg_chan_list_event(st
|
|
goto fallback;
|
|
}
|
|
|
|
- ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
|
|
+ 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;
|
|
@@ -6898,6 +7253,14 @@ mem_free:
|
|
if (reg_info) {
|
|
kfree(reg_info->reg_rules_2g_ptr);
|
|
kfree(reg_info->reg_rules_5g_ptr);
|
|
+ if (reg_info->is_ext_reg_event) {
|
|
+ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
|
|
+ kfree(reg_info->reg_rules_6g_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_6g_client_ptr[j][i]);
|
|
+ }
|
|
kfree(reg_info);
|
|
}
|
|
return ret;
|
|
@@ -9146,7 +9509,10 @@ static void ath11k_wmi_tlv_op_rx(struct
|
|
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);
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
|
@@ -815,6 +815,7 @@ enum wmi_tlv_event_id {
|
|
WMI_RMC_NEW_LEADER_EVENTID = WMI_TLV_CMD(WMI_GRP_RMC),
|
|
WMI_REG_CHAN_LIST_CC_EVENTID = WMI_TLV_CMD(WMI_GRP_REGULATORY),
|
|
WMI_11D_NEW_COUNTRY_EVENTID,
|
|
+ WMI_REG_CHAN_LIST_CC_EXT_EVENTID,
|
|
WMI_NDI_CAP_RSP_EVENTID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE),
|
|
WMI_NDP_INITIATOR_RSP_EVENTID,
|
|
WMI_NDP_RESPONDER_RSP_EVENTID,
|
|
@@ -1903,6 +1904,9 @@ enum wmi_tlv_tag {
|
|
/* TODO add all the missing cmds */
|
|
WMI_TAG_QOS_NULL_FRAME_TX_SEND = 0x3A6,
|
|
WMI_TAG_QOS_NULL_FRAME_TX_STATUS,
|
|
+ WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
|
|
+ WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
|
|
+
|
|
WMI_CTRL_PATH_CAL_STATS = 0x3BC,
|
|
|
|
WMI_TAG_MAX
|
|
@@ -2175,6 +2179,7 @@ enum wmi_tlv_service {
|
|
WMI_TLV_SERVICE_FSE_CMEM_ALLOC_SUPPORT = 262,
|
|
WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263,
|
|
WMI_TLV_SERVICE_QOS_NULL_FRAME_TX_OVER_WMI = 264,
|
|
+ WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
|
|
|
|
WMI_MAX_EXT2_SERVICE
|
|
};
|
|
@@ -2386,6 +2391,7 @@ struct wmi_init_cmd {
|
|
|
|
#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
|
|
#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
|
|
+#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_REG_CC_EXT_SUPPORT_BIT 4
|
|
|
|
struct wmi_resource_config {
|
|
u32 tlv_header;
|
|
@@ -2968,6 +2974,8 @@ struct rx_reorder_queue_remove_params {
|
|
#define REG_RULE_MAX_BW 0x0000ffff
|
|
#define REG_RULE_REG_PWR 0x00ff0000
|
|
#define REG_RULE_ANT_GAIN 0xff000000
|
|
+#define REG_RULE_PSD_INFO BIT(2)
|
|
+#define REG_RULE_PSD_EIRP 0xffff0000
|
|
|
|
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
|
|
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
|
|
@@ -4300,6 +4308,8 @@ struct wmi_he_rate_set {
|
|
|
|
#define MAX_REG_RULES 10
|
|
#define REG_ALPHA2_LEN 2
|
|
+#define MAX_6G_REG_RULES 5
|
|
+#define REG_US_5G_NUM_REG_RULES 4
|
|
|
|
enum wmi_start_event_param {
|
|
WMI_VDEV_START_RESP_EVENT = 0,
|
|
@@ -4362,6 +4372,21 @@ enum {
|
|
WMI_REG_SET_CC_STATUS_FAIL = 5,
|
|
};
|
|
|
|
+enum wmi_reg_6g_ap_type {
|
|
+ WMI_REG_INDOOR_AP = 0,
|
|
+ WMI_REG_STANDARD_POWER_AP = 1,
|
|
+ WMI_REG_VERY_LOW_POWER_AP = 2,
|
|
+ WMI_REG_CURRENT_MAX_AP_TYPE,
|
|
+ WMI_REG_MAX_SUPP_AP_TYPE = WMI_REG_VERY_LOW_POWER_AP,
|
|
+ WMI_REG_MAX_AP_TYPE = 7,
|
|
+};
|
|
+
|
|
+enum wmi_reg_6g_client_type {
|
|
+ WMI_REG_DEFAULT_CLIENT = 0,
|
|
+ WMI_REG_SUBORDINATE_CLIENT = 1,
|
|
+ WMI_REG_MAX_CLIENT_TYPE = 2,
|
|
+};
|
|
+
|
|
struct cur_reg_rule {
|
|
u16 start_freq;
|
|
u16 end_freq;
|
|
@@ -4369,6 +4394,8 @@ struct cur_reg_rule {
|
|
u8 reg_power;
|
|
u8 ant_gain;
|
|
u16 flags;
|
|
+ bool psd_flag;
|
|
+ u16 psd_eirp;
|
|
};
|
|
|
|
struct cur_regulatory_info {
|
|
@@ -4380,6 +4407,7 @@ struct cur_regulatory_info {
|
|
u8 alpha2[REG_ALPHA2_LEN + 1];
|
|
u32 dfs_region;
|
|
u32 phybitmap;
|
|
+ bool is_ext_reg_event;
|
|
u32 min_bw_2g;
|
|
u32 max_bw_2g;
|
|
u32 min_bw_5g;
|
|
@@ -4388,6 +4416,28 @@ struct cur_regulatory_info {
|
|
u32 num_5g_reg_rules;
|
|
struct cur_reg_rule *reg_rules_2g_ptr;
|
|
struct cur_reg_rule *reg_rules_5g_ptr;
|
|
+ enum wmi_reg_6g_client_type client_type;
|
|
+ bool rnr_tpe_usable;
|
|
+ bool unspecified_ap_usable;
|
|
+ /* TODO: All 6G related info can be stored only for required
|
|
+ * combination instead of all types, to optimize memory usage.
|
|
+ */
|
|
+ u8 domain_code_6g_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
|
|
+ u8 domain_code_6g_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
|
|
+ u32 domain_code_6g_super_id;
|
|
+ u32 min_bw_6g_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
|
|
+ u32 max_bw_6g_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
|
|
+ u32 min_bw_6g_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
|
|
+ u32 max_bw_6g_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
|
|
+ u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
|
|
+ u32 num_6g_reg_rules_client[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
|
|
+ struct cur_reg_rule *reg_rules_6g_ap_ptr[WMI_REG_CURRENT_MAX_AP_TYPE];
|
|
+ struct cur_reg_rule *reg_rules_6g_client_ptr[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
|
|
+};
|
|
+
|
|
+enum wmi_reg_chan_list_cmd_type {
|
|
+ WMI_REG_CHAN_LIST_CC_ID = 0,
|
|
+ WMI_REG_CHAN_LIST_CC_EXT_ID = 1,
|
|
};
|
|
|
|
struct wmi_reg_chan_list_cc_event {
|
|
@@ -4418,6 +4468,61 @@ struct wmi_vdev_delete_resp_event {
|
|
u32 vdev_id;
|
|
} __packed;
|
|
|
|
+#define WMI_REG_CLIENT_MAX 4
|
|
+
|
|
+struct wmi_reg_chan_list_cc_ext_event {
|
|
+ u32 status_code;
|
|
+ u32 phy_id;
|
|
+ u32 alpha2;
|
|
+ u32 num_phy;
|
|
+ u32 country_id;
|
|
+ u32 domain_code;
|
|
+ u32 dfs_region;
|
|
+ u32 phybitmap;
|
|
+ u32 min_bw_2g;
|
|
+ u32 max_bw_2g;
|
|
+ u32 min_bw_5g;
|
|
+ u32 max_bw_5g;
|
|
+ u32 num_2g_reg_rules;
|
|
+ u32 num_5g_reg_rules;
|
|
+ u32 client_type;
|
|
+ u32 rnr_tpe_usable;
|
|
+ u32 unspecified_ap_usable;
|
|
+ u32 domain_code_6g_ap_lpi;
|
|
+ u32 domain_code_6g_ap_sp;
|
|
+ u32 domain_code_6g_ap_vlp;
|
|
+ u32 domain_code_6g_client_lpi[WMI_REG_CLIENT_MAX];
|
|
+ u32 domain_code_6g_client_sp[WMI_REG_CLIENT_MAX];
|
|
+ u32 domain_code_6g_client_vlp[WMI_REG_CLIENT_MAX];
|
|
+ u32 domain_code_6g_super_id;
|
|
+ u32 min_bw_6g_ap_sp;
|
|
+ u32 max_bw_6g_ap_sp;
|
|
+ u32 min_bw_6g_ap_lpi;
|
|
+ u32 max_bw_6g_ap_lpi;
|
|
+ u32 min_bw_6g_ap_vlp;
|
|
+ u32 max_bw_6g_ap_vlp;
|
|
+ u32 min_bw_6g_client_sp[WMI_REG_CLIENT_MAX];
|
|
+ u32 max_bw_6g_client_sp[WMI_REG_CLIENT_MAX];
|
|
+ u32 min_bw_6g_client_lpi[WMI_REG_CLIENT_MAX];
|
|
+ u32 max_bw_6g_client_lpi[WMI_REG_CLIENT_MAX];
|
|
+ u32 min_bw_6g_client_vlp[WMI_REG_CLIENT_MAX];
|
|
+ u32 max_bw_6g_client_vlp[WMI_REG_CLIENT_MAX];
|
|
+ u32 num_6g_reg_rules_ap_sp;
|
|
+ u32 num_6g_reg_rules_ap_lpi;
|
|
+ u32 num_6g_reg_rules_ap_vlp;
|
|
+ u32 num_6g_reg_rules_client_sp[WMI_REG_CLIENT_MAX];
|
|
+ u32 num_6g_reg_rules_client_lpi[WMI_REG_CLIENT_MAX];
|
|
+ u32 num_6g_reg_rules_client_vlp[WMI_REG_CLIENT_MAX];
|
|
+} __packed;
|
|
+
|
|
+struct wmi_regulatory_ext_rule_struct {
|
|
+ u32 tlv_header;
|
|
+ u32 freq_info;
|
|
+ u32 bw_pwr_info;
|
|
+ u32 flag_info;
|
|
+ u32 psd_power_info;
|
|
+};
|
|
+
|
|
struct wmi_peer_delete_resp_event {
|
|
u32 vdev_id;
|
|
struct wmi_mac_addr peer_macaddr;
|
|
@@ -6010,6 +6115,7 @@ struct target_resource_config {
|
|
u32 twt_ap_sta_count;
|
|
u32 ema_max_vap_cnt;
|
|
u32 ema_max_profile_period;
|
|
+ bool is_reg_cc_ext_event_supported;
|
|
};
|
|
|
|
enum wmi_tpc_pream_bw {
|