wlan-ap-Telecominfraproject/feeds/ipq95xx/mac80211/patches/qca/624-0011-ath12k-add-support-to-select-all-6-GHZ-regulatory-rules.patch
John Crispin b9b03a6e38 ipq95xx: add Qualcomm wifi-7 support
Signed-off-by: John Crispin <john@phrozen.org>
2023-04-10 14:25:48 +02:00

354 lines
15 KiB
Diff

From e10cecf8cd3637074ab292b36f5c1c855398fe95 Mon Sep 17 00:00:00 2001
From: Aishwarya R <quic_aisr@quicinc.com>
Date: Mon, 11 Apr 2022 12:41:55 +0530
Subject: [PATCH] ath12k: add support to select all 6 GHZ regulatory rules
Currently, ath12k was only updating one type of 6 GHZ
regulatory rule based on wmi_vdev_type. However, during
AP + STA concurrency, it can not maintain two different
rules in one single reg rule space. Hence, this change is to
update and store all possible 6G reg rules in the regulatory
domain.
Subsequent patch will use one of this reg rules as per
its configured power mode and can update its rules accordingly.
Even during concurrency, two rules can be fetched and updated.
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/reg.c | 121 ++++++++++++++++++--------
drivers/net/wireless/ath/ath12k/reg.h | 1 -
drivers/net/wireless/ath/ath12k/wmi.c | 67 +++++++++-----
drivers/net/wireless/ath/ath12k/wmi.h | 1 -
4 files changed, 128 insertions(+), 62 deletions(-)
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -43,6 +43,40 @@ ath12k_ieee80211_ap_pwr_type_convert(enu
}
}
+static struct cur_reg_rule
+*ath12k_get_active_6g_reg_rule(struct cur_regulatory_info *reg_info,
+ u32 *max_bw_6g, int *max_elements)
+{
+ struct cur_reg_rule *reg_rule = NULL;
+ u8 i = 0, j = 0;
+
+ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
+ if (reg_info->num_6g_reg_rules_ap[i]) {
+ *max_elements = reg_info->num_6g_reg_rules_ap[i];
+ reg_rule = reg_info->reg_rules_6g_ap_ptr[i];
+ *max_bw_6g = reg_info->max_bw_6g_ap[i];
+ reg_info->num_6g_reg_rules_ap[i] = 0;
+ return reg_rule;
+ }
+ }
+
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
+ for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
+ if (reg_info->num_6g_reg_rules_cl[j][i]) {
+ *max_elements = reg_info->num_6g_reg_rules_cl
+ [j][i];
+ reg_rule = reg_info->reg_rules_6g_client_ptr
+ [j][i];
+ *max_bw_6g = reg_info->max_bw_6g_client[j][i];
+ reg_info->num_6g_reg_rules_cl[j][i] = 0;
+ return reg_rule;
+ }
+ }
+ }
+
+ return reg_rule;
+}
+
static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
{
const struct ieee80211_regdomain *regd;
@@ -586,49 +620,35 @@ ath12k_reg_update_weather_radar_band(str
struct ieee80211_regdomain *
ath12k_reg_build_regd(struct ath12k_base *ab,
struct cur_regulatory_info *reg_info, bool intersect,
- enum wmi_vdev_type vdev_type,
enum ieee80211_ap_reg_power power_type)
{
struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
struct cur_reg_rule *reg_rule, *reg_rule_6g;
- u8 i = 0, j = 0, k = 0;
+ u8 i = 0, j = 0, k = 0, max_elements = 0;
u8 num_rules;
u16 max_bw;
- u32 flags, reg_6g_number, max_bw_6g;
+ u32 flags, reg_6g_number = 0, max_bw_6g = 0;
char alpha2[3];
+ bool reg_6g_itr_set = false;
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.
+ /* FIXME: Currently updating all 9 possible regulatory rules for 6G.
+ * For space optimization, logic can be enhanced to store reg rules
+ * dynamically from power, AP and STA mode combination.
*/
if (reg_info->is_ext_reg_event) {
- if (vdev_type == WMI_VDEV_TYPE_STA) {
- enum wmi_reg_6g_ap_type ap_type;
-
- ap_type = ath12k_ieee80211_ap_pwr_type_convert(power_type);
-
- if (ap_type == WMI_REG_MAX_AP_TYPE)
- ap_type = WMI_REG_INDOOR_AP;
- reg_6g_number = reg_info->num_6g_reg_rules_cl
- [ap_type][WMI_REG_DEFAULT_CLIENT];
- if (reg_6g_number == 0) {
- ap_type = WMI_REG_INDOOR_AP;
- reg_6g_number = reg_info->num_6g_reg_rules_cl
- [ap_type][WMI_REG_DEFAULT_CLIENT];
- }
- reg_rule_6g = reg_info->reg_rules_6g_client_ptr
- [ap_type][WMI_REG_DEFAULT_CLIENT];
- max_bw_6g = reg_info->max_bw_6g_client
- [ap_type][WMI_REG_DEFAULT_CLIENT];
- } else {
- reg_6g_number = reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP];
- reg_rule_6g = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
- max_bw_6g = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
+ /* All 6G APs - (LP, SP, VLP) */
+ for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
+ reg_6g_number += reg_info->num_6g_reg_rules_ap[i];
+ /* All 6G STAs - (LP_DEF, LP_SUB, SP_DEF, SP_SUB, VLP_DEF, VLP_SUB) */
+ for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
+ for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
+ reg_6g_number += reg_info->num_6g_reg_rules_cl
+ [j][i];
}
- num_rules += reg_6g_number;
- }
+ }
+ num_rules += reg_6g_number;
if (!num_rules)
goto ret;
@@ -655,7 +675,7 @@ ath12k_reg_build_regd(struct ath12k_base
/* Update reg_rules[] below. Firmware is expected to
* send these rules in order(2G rules first and then 5G)
*/
- for (; i < num_rules; i++) {
+ for (i = 0, j = 0; i < num_rules; i++) {
if (reg_info->num_2g_reg_rules &&
(i < reg_info->num_2g_reg_rules)) {
reg_rule = reg_info->reg_rules_2g_ptr + i;
@@ -685,12 +705,39 @@ ath12k_reg_build_regd(struct ath12k_base
* per other BW rule flags we pass from here
*/
flags = NL80211_RRF_AUTO_BW | NL80211_RRF_NO_320MHZ;
- } else if (reg_info->is_ext_reg_event && reg_6g_number &&
- (k < reg_6g_number)) {
- reg_rule = reg_rule_6g + k++;
- max_bw = min_t(u16, reg_rule->max_bw, max_bw_6g);
- if (reg_rule->psd_flag)
- flags |= NL80211_RRF_PSD;
+ } else if (reg_info->is_ext_reg_event && reg_6g_number) {
+ if (!reg_6g_itr_set) {
+ reg_rule_6g = ath12k_get_active_6g_reg_rule(reg_info,
+ &max_bw_6g, &max_elements);
+
+ if (!reg_rule_6g) {
+ ath12k_warn(ab,
+ "\nFetching a valid reg_rule_6g_ptr failed."
+ "This shouldn't happen normally. Be carefull with"
+ "the regulatory domain settings\n");
+ break;
+ }
+ reg_6g_itr_set = true;
+ }
+ if (reg_6g_itr_set && k < max_elements) {
+ reg_rule = reg_rule_6g + k++;
+ max_bw = min_t(u16, reg_rule->max_bw, max_bw_6g);
+ flags = NL80211_RRF_AUTO_BW;
+
+ if (reg_rule->psd_flag)
+ flags |= NL80211_RRF_PSD;
+
+ ath12k_copy_reg_rule(&ab->reg_rule_6g, reg_rule);
+ }
+
+ if (reg_6g_itr_set && k >= max_elements) {
+ reg_6g_itr_set = false;
+ reg_rule_6g = NULL;
+ max_bw_6g = 0;
+ max_elements = 0;
+ k = 0;
+ }
+ reg_6g_number--;
#if 1 /*WAR*/
if ((reg_rule->start_freq == 6425) && (reg_rule->end_freq == 6525))
max_bw = 80;
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -32,7 +32,6 @@ void ath12k_regd_update_work(struct work
struct ieee80211_regdomain *
ath12k_reg_build_regd(struct ath12k_base *ab,
struct cur_regulatory_info *reg_info, bool intersect,
- enum wmi_vdev_type vdev_type,
enum ieee80211_ap_reg_power power_type);
enum wmi_reg_6g_ap_type
ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type);
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5084,6 +5084,27 @@ static void ath12k_print_reg_rule(struct
}
}
+static u8
+ath12k_invalid_5g_reg_ext_rules_from_wmi(u32 num_reg_rules,
+ struct wmi_regulatory_ext_rule_struct *wmi_reg_rule)
+{
+ u8 num_invalid_5g_rules = 0;
+ u32 count, start_freq, end_freq;
+
+ for (count = 0; count < num_reg_rules; count++) {
+ start_freq = FIELD_GET(REG_RULE_START_FREQ,
+ wmi_reg_rule[count].freq_info);
+ end_freq = FIELD_GET(REG_RULE_END_FREQ,
+ wmi_reg_rule[count].freq_info);
+
+ if (start_freq >= ATH12K_MIN_6G_FREQ &&
+ end_freq <= ATH12K_MAX_6G_FREQ)
+ num_invalid_5g_rules++;
+ }
+
+ return num_invalid_5g_rules;
+}
+
static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
struct sk_buff *skb,
struct cur_regulatory_info *reg_info)
@@ -5188,28 +5209,6 @@ static int ath12k_pull_reg_chan_list_ext
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) {
- ath12k_dbg(ab, ATH12K_DBG_WMI,
- "US 5g reg rules number %d from fw",
- reg_info->num_5g_reg_rules);
-
- if (reg_info->num_5g_reg_rules > REG_US_5G_NUM_REG_RULES)
- skip_6g_rules_in_5g_rules = reg_info->num_5g_reg_rules -
- REG_US_5G_NUM_REG_RULES;
-
- 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;
@@ -5329,6 +5328,28 @@ static int ath12k_pull_reg_chan_list_ext
}
ext_wmi_reg_rule += num_2g_reg_rules;
+ /* FIXME: Currently FW includes 6G reg rule also in 5G rule
+ * list for few countries.
+ * 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 logic 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.
+ */
+ skip_6g_rules_in_5g_rules = ath12k_invalid_5g_reg_ext_rules_from_wmi(num_5g_reg_rules,
+ ext_wmi_reg_rule);
+
+ if(skip_6g_rules_in_5g_rules) {
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "CC: %s 5g reg rules number %d from fw, %d number of invalid 5g rules",
+ reg_info->alpha2, reg_info->num_5g_reg_rules,
+ skip_6g_rules_in_5g_rules);
+
+ num_5g_reg_rules = num_5g_reg_rules - skip_6g_rules_in_5g_rules;
+ reg_info->num_5g_reg_rules = num_5g_reg_rules;
+ }
+
if (num_5g_reg_rules) {
reg_info->reg_rules_5g_ptr =
create_ext_reg_rules_from_wmi(num_5g_reg_rules,
@@ -6659,8 +6680,6 @@ static int ath12k_reg_handle_chan_list(s
int pdev_idx;
struct ath12k *ar;
- enum wmi_vdev_type vdev_type;
-
if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
/* In case of failure to set the requested ctry,
* fw retains the current regd. We print a failure info
@@ -6702,14 +6721,11 @@ static int ath12k_reg_handle_chan_list(s
!ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
intersect = true;
- ar = ab->pdevs[pdev_idx].ar;
- vdev_type = ath12k_mac_get_ar_vdev_type(ar);
-
ath12k_dbg(ab, ATH12K_DBG_WMI,
- "wmi handle chan list power type %d vdev type %d intersect %d\n",
- power_type, vdev_type, intersect);
+ "wmi handle chan list power type %d intersect %d\n",
+ power_type, intersect);
- regd = ath12k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type);
+ regd = ath12k_reg_build_regd(ab, reg_info, intersect, power_type);
if (!regd) {
ath12k_warn(ab, "failed to build regd from reg_info\n");
goto fallback;
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4310,7 +4310,6 @@ struct wmi_eht_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,
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -636,17 +636,6 @@ struct ath12k *ath12k_mac_get_ar_by_vdev
return NULL;
}
-enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar)
-{
- struct ath12k_vif *arvif;
-
- list_for_each_entry(arvif, &ar->arvifs, list) {
- return arvif->vdev_type;
- }
-
- return WMI_VDEV_TYPE_UNSPEC;
-}
-
struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
{
int i;
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -147,7 +147,6 @@ struct ath12k_vif *ath12k_mac_get_arvif_
u32 vdev_id);
struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id);
struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
-enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar);
void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
struct ieee80211_vif *vif,