mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-24 21:02:35 +00:00
354 lines
15 KiB
Diff
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,
|