* [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 17:47 ` Jeff Johnson
2023-09-19 7:17 ` [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type Aishwarya R
` (5 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
There are 3 types of regulatory rules for AP mode and 6 types for
STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
to select the exact reg rules.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/reg.c | 62 +++++++--
drivers/net/wireless/ath/ath12k/reg.h | 6 +-
drivers/net/wireless/ath/ath12k/wmi.c | 182 +++++++++++++++++++++++++-
drivers/net/wireless/ath/ath12k/wmi.h | 27 +++-
4 files changed, 257 insertions(+), 20 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 6ede91ebc8e1..8501f77eee55 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -28,6 +28,21 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
}
};
+enum wmi_reg_6g_ap_type
+ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type)
+{
+ switch (power_type) {
+ case IEEE80211_REG_LPI_AP:
+ return WMI_REG_INDOOR_AP;
+ case IEEE80211_REG_SP_AP:
+ return WMI_REG_STD_POWER_AP;
+ case IEEE80211_REG_VLP_AP:
+ return WMI_REG_VLP_AP;
+ default:
+ return WMI_REG_MAX_AP_TYPE;
+ }
+}
+
static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
{
const struct ieee80211_regdomain *regd;
@@ -562,14 +577,16 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
struct ieee80211_regdomain *
ath12k_reg_build_regd(struct ath12k_base *ab,
- struct ath12k_reg_info *reg_info, bool intersect)
+ struct ath12k_reg_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 ath12k_reg_rule *reg_rule;
+ struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
u8 i = 0, j = 0, k = 0;
u8 num_rules;
u16 max_bw;
- u32 flags;
+ u32 flags, reg_6ghz_number, max_bw_6ghz;
char alpha2[3];
num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
@@ -578,8 +595,33 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
* 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 (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_6ghz_number = reg_info->num_6g_reg_rules_cl
+ [ap_type][WMI_REG_DEFAULT_CLIENT];
+ if (reg_6ghz_number == 0) {
+ ap_type = WMI_REG_INDOOR_AP;
+ reg_6ghz_number = reg_info->num_6g_reg_rules_cl
+ [ap_type][WMI_REG_DEFAULT_CLIENT];
+ }
+ reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
+ [ap_type][WMI_REG_DEFAULT_CLIENT];
+ max_bw_6ghz = reg_info->max_bw_6g_client
+ [ap_type][WMI_REG_DEFAULT_CLIENT];
+ } else {
+ reg_6ghz_number = reg_info->num_6g_reg_rules_ap
+ [WMI_REG_INDOOR_AP];
+ reg_rule_6ghz = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
+ max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
+ }
+ num_rules += reg_6ghz_number;
+ }
if (!num_rules)
goto ret;
@@ -626,12 +668,10 @@ ath12k_reg_build_regd(struct ath12k_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_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]);
+ } else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
+ (k < reg_6ghz_number)) {
+ reg_rule = reg_rule_6ghz + k++;
+ max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
flags = NL80211_RRF_AUTO_BW;
} else {
break;
diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
index 56d009a47234..56324e30a358 100644
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -88,7 +88,11 @@ void ath12k_reg_free(struct ath12k_base *ab);
void ath12k_regd_update_work(struct work_struct *work);
struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
struct ath12k_reg_info *reg_info,
- bool intersect);
+ 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);
int ath12k_regd_update(struct ath12k *ar, bool init);
int ath12k_reg_update_chan_list(struct ath12k *ar);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index af910296c41e..1b9ce9a2ae96 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -4152,6 +4152,119 @@ static struct ath12k_reg_rule
return reg_rule_ptr;
}
+static char *ath12k_cc_status_to_str(enum ath12k_reg_cc_code code)
+{
+ switch (code) {
+ case REG_SET_CC_STATUS_PASS:
+ return "REG_SET_CC_STATUS_PASS";
+ case REG_CURRENT_ALPHA2_NOT_FOUND:
+ return "REG_CURRENT_ALPHA2_NOT_FOUND";
+ case REG_INIT_ALPHA2_NOT_FOUND:
+ return "REG_INIT_ALPHA2_NOT_FOUND";
+ case REG_SET_CC_CHANGE_NOT_ALLOWED:
+ return "REG_SET_CC_CHANGE_NOT_ALLOWED";
+ case REG_SET_CC_STATUS_NO_MEMORY:
+ return "REG_SET_CC_STATUS_NO_MEMORY";
+ case REG_SET_CC_STATUS_FAIL:
+ return "REG_SET_CC_STATUS_FAIL";
+ default:
+ return "unknown cc status";
+ }
+};
+
+static char *ath12k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id)
+{
+ switch (domain_id) {
+ case FCC1_6GHZ:
+ return "FCC1_6GHZ";
+ case ETSI1_6GHZ:
+ return "ETSI1_6GHZ";
+ case ETSI2_6GHZ:
+ return "ETSI2_6GHZ";
+ case APL1_6GHZ:
+ return "APL1_6GHZ";
+ case FCC1_6GHZ_CL:
+ return "FCC1_6GHZ_CL";
+ default:
+ return "unknown domain id";
+ }
+}
+
+static char *ath12k_6ghz_client_type_to_str(enum wmi_reg_6g_client_type type)
+{
+ switch (type) {
+ case WMI_REG_DEFAULT_CLIENT:
+ return "DEFAULT CLIENT";
+ case WMI_REG_SUBORDINATE_CLIENT:
+ return "SUBORDINATE CLIENT";
+ default:
+ return "unknown client type";
+ }
+}
+
+static char *ath12k_6ghz_ap_type_to_str(enum wmi_reg_6g_ap_type type)
+{
+ switch (type) {
+ case WMI_REG_INDOOR_AP:
+ return "INDOOR AP";
+ case WMI_REG_STD_POWER_AP:
+ return "STANDARD POWER AP";
+ case WMI_REG_VLP_AP:
+ return "VERY LOW POWER AP";
+ default:
+ return "unknown AP type";
+ }
+}
+
+static char *ath12k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id)
+{
+ switch (sub_id) {
+ case FCC1_CLIENT_LPI_REGULAR_6GHZ:
+ return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
+ case FCC1_CLIENT_SP_6GHZ:
+ return "FCC1_CLIENT_SP_6GHZ";
+ case FCC1_AP_LPI_6GHZ:
+ return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
+ case FCC1_AP_SP_6GHZ:
+ return "FCC1_AP_SP_6GHZ";
+ case ETSI1_LPI_6GHZ:
+ return "ETSI1_LPI_6GHZ";
+ case ETSI1_VLP_6GHZ:
+ return "ETSI1_VLP_6GHZ";
+ case ETSI2_LPI_6GHZ:
+ return "ETSI2_LPI_6GHZ";
+ case ETSI2_VLP_6GHZ:
+ return "ETSI2_VLP_6GHZ";
+ case APL1_LPI_6GHZ:
+ return "APL1_LPI_6GHZ";
+ case APL1_VLP_6GHZ:
+ return "APL1_VLP_6GHZ";
+ case EMPTY_6GHZ:
+ return "N/A";
+ default:
+ return "unknown sub reg id";
+ }
+}
+
+static void ath12k_print_reg_rule(struct ath12k_base *ab, char *prev,
+ u32 num_reg_rules,
+ struct ath12k_reg_rule *reg_rule_ptr)
+{
+ struct ath12k_reg_rule *reg_rule = reg_rule_ptr;
+ u32 count;
+
+ ath12k_dbg(ab, ATH12K_DBG_WMI, "%s reg rules number %d\n", prev, num_reg_rules);
+
+ for (count = 0; count < num_reg_rules; count++) {
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d) (psd flag %d EIRP %d dB/MHz)\n",
+ count + 1, reg_rule->start_freq, reg_rule->end_freq,
+ reg_rule->max_bw, reg_rule->ant_gain, reg_rule->reg_power,
+ reg_rule->flags, reg_rule->psd_flag, reg_rule->psd_eirp);
+ reg_rule++;
+ }
+}
+
static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
struct sk_buff *skb,
struct ath12k_reg_info *reg_info)
@@ -4163,7 +4276,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
u32 total_reg_rules = 0;
- int ret, i, j;
+ int ret, i, j, skip_6ghz_rules_in_5ghz_rules = 0;
ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
@@ -4265,6 +4378,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
* from 5G rules list.
*/
if (memcmp(reg_info->alpha2, "US", 2) == 0) {
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "US 5 GHz 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_6ghz_rules_in_5ghz_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;
}
@@ -4297,6 +4417,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
break;
}
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "%s: status_code %s", __func__,
+ ath12k_cc_status_to_str(reg_info->status_code));
+
reg_info->is_ext_reg_event = true;
reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g);
@@ -4325,6 +4449,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
le32_to_cpu(ev->max_bw_6g_client_vlp[i]);
}
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "%s: status_code %s", __func__,
+ ath12k_cc_status_to_str(reg_info->status_code));
+
ath12k_dbg(ab, ATH12K_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,
@@ -4368,10 +4496,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
return -ENOMEM;
}
+ ath12k_print_reg_rule(ab, "2 GHz",
+ num_2g_reg_rules,
+ reg_info->reg_rules_2g_ptr);
}
+ ext_wmi_reg_rule += num_2g_reg_rules;
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);
@@ -4381,9 +4512,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
return -ENOMEM;
}
+ ath12k_print_reg_rule(ab, "5 GHz",
+ num_5g_reg_rules,
+ reg_info->reg_rules_5g_ptr);
}
- ext_wmi_reg_rule += num_5g_reg_rules;
+ /* We have adjusted the number of 5 GHz reg rules via the hack above.
+ * Here, we adjust that many extra rules which came with 5g reg rules
+ * (for cc: US)
+ *
+ * NOTE: skip_6ghz_rules_in_5ghz_rules will be 0 for rest other cases.
+ */
+ ext_wmi_reg_rule += num_5g_reg_rules + skip_6ghz_rules_in_5ghz_rules;
for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
reg_info->reg_rules_6g_ap_ptr[i] =
@@ -4396,10 +4536,17 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
return -ENOMEM;
}
+ ath12k_print_reg_rule(ab, ath12k_6ghz_ap_type_to_str(i),
+ num_6g_reg_rules_ap[i],
+ reg_info->reg_rules_6g_ap_ptr[i]);
+
ext_wmi_reg_rule += num_6g_reg_rules_ap[i];
}
for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "AP type %s", ath12k_6ghz_ap_type_to_str(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_cl[j][i],
@@ -4411,6 +4558,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
return -ENOMEM;
}
+ ath12k_print_reg_rule(ab, ath12k_6ghz_client_type_to_str(i),
+ num_6g_reg_rules_cl[j][i],
+ reg_info->reg_rules_6g_client_ptr[j][i]);
+
ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];
}
}
@@ -4425,6 +4576,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =
le32_to_cpu(ev->domain_code_6g_ap_vlp);
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s , sp %s , vlp %s\n",
+ ath12k_6ghz_client_type_to_str(reg_info->client_type),
+ reg_info->rnr_tpe_usable,
+ reg_info->unspecified_ap_usable,
+ ath12k_sub_reg_6ghz_to_str
+ (le32_to_cpu(ev->domain_code_6g_ap_lpi)),
+ ath12k_sub_reg_6ghz_to_str
+ (le32_to_cpu(ev->domain_code_6g_ap_sp)),
+ ath12k_sub_reg_6ghz_to_str
+ (le32_to_cpu(ev->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] =
le32_to_cpu(ev->domain_code_6g_client_lpi[i]);
@@ -4432,12 +4595,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
le32_to_cpu(ev->domain_code_6g_client_sp[i]);
reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =
le32_to_cpu(ev->domain_code_6g_client_vlp[i]);
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "6 GHz AP BW: lpi %d - %d sp %d - %d vlp %d - %d\n",
+ ev->min_bw_6g_ap_lpi, ev->max_bw_6g_ap_lpi,
+ ev->min_bw_6g_ap_sp, ev->max_bw_6g_ap_sp,
+ ev->min_bw_6g_ap_vlp, ev->max_bw_6g_ap_vlp);
}
reg_info->domain_code_6g_super_id = le32_to_cpu(ev->domain_code_6g_super_id);
- ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
- reg_info->client_type, reg_info->domain_code_6g_super_id);
+ ath12k_dbg(ab, ATH12K_DBG_WMI, "6 GHz client_type: %s 6 GHz super domain %s",
+ ath12k_6ghz_client_type_to_str(reg_info->client_type),
+ ath12k_super_reg_6ghz_to_str(reg_info->domain_code_6g_super_id));
ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
@@ -5192,7 +5361,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
!ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
intersect = true;
- regd = ath12k_reg_build_regd(ab, reg_info, intersect);
+ regd = ath12k_reg_build_regd(ab, reg_info, intersect,
+ WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
if (!regd) {
ath12k_warn(ab, "failed to build regd from reg_info\n");
goto fallback;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 08a8c9e0f59f..966e6ba4e162 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2832,8 +2832,8 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg {
#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 REG_RULE_PSD_INFO BIT(0)
+#define REG_RULE_PSD_EIRP 0xff0000
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
@@ -3844,6 +3844,29 @@ enum {
WMI_REG_SET_CC_STATUS_FAIL = 5,
};
+enum reg_subdomains_6ghz {
+ EMPTY_6GHZ = 0x0,
+ FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
+ FCC1_CLIENT_SP_6GHZ = 0x02,
+ FCC1_AP_LPI_6GHZ = 0x03,
+ FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
+ FCC1_AP_SP_6GHZ = 0x04,
+ ETSI1_LPI_6GHZ = 0x10,
+ ETSI1_VLP_6GHZ = 0x11,
+ ETSI2_LPI_6GHZ = 0x12,
+ ETSI2_VLP_6GHZ = 0x13,
+ APL1_LPI_6GHZ = 0x20,
+ APL1_VLP_6GHZ = 0x21,
+};
+
+enum reg_super_domain_6ghz {
+ FCC1_6GHZ = 0x01,
+ ETSI1_6GHZ = 0x02,
+ ETSI2_6GHZ = 0x03,
+ APL1_6GHZ = 0x04,
+ FCC1_6GHZ_CL = 0x05,
+};
+
#define WMI_REG_CLIENT_MAX 4
struct wmi_reg_chan_list_cc_ext_event {
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
2023-09-19 7:17 ` [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type Aishwarya R
@ 2023-09-19 17:47 ` Jeff Johnson
2023-09-20 2:10 ` Wen Gong
2023-09-20 5:48 ` Aishwarya R (QUIC)
0 siblings, 2 replies; 17+ messages in thread
From: Jeff Johnson @ 2023-09-19 17:47 UTC (permalink / raw)
To: Aishwarya R, ath12k; +Cc: linux-wireless, Wen Gong
On 9/19/2023 12:17 AM, Aishwarya R wrote:
> There are 3 types of regulatory rules for AP mode and 6 types for
> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
> to select the exact reg rules.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Wen,
Can you provide a "Tested-on: WCN7850" tag for this series?
>
> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
> ---
> drivers/net/wireless/ath/ath12k/reg.c | 62 +++++++--
> drivers/net/wireless/ath/ath12k/reg.h | 6 +-
> drivers/net/wireless/ath/ath12k/wmi.c | 182 +++++++++++++++++++++++++-
> drivers/net/wireless/ath/ath12k/wmi.h | 27 +++-
> 4 files changed, 257 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
> index 6ede91ebc8e1..8501f77eee55 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.c
> +++ b/drivers/net/wireless/ath/ath12k/reg.c
> @@ -28,6 +28,21 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
> }
> };
>
> +enum wmi_reg_6g_ap_type
> +ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type)
> +{
> + switch (power_type) {
> + case IEEE80211_REG_LPI_AP:
> + return WMI_REG_INDOOR_AP;
> + case IEEE80211_REG_SP_AP:
> + return WMI_REG_STD_POWER_AP;
> + case IEEE80211_REG_VLP_AP:
> + return WMI_REG_VLP_AP;
> + default:
> + return WMI_REG_MAX_AP_TYPE;
> + }
> +}
> +
> static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
> {
> const struct ieee80211_regdomain *regd;
> @@ -562,14 +577,16 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
>
> struct ieee80211_regdomain *
> ath12k_reg_build_regd(struct ath12k_base *ab,
> - struct ath12k_reg_info *reg_info, bool intersect)
> + struct ath12k_reg_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 ath12k_reg_rule *reg_rule;
> + struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
> u8 i = 0, j = 0, k = 0;
> u8 num_rules;
> u16 max_bw;
> - u32 flags;
> + u32 flags, reg_6ghz_number, max_bw_6ghz;
> char alpha2[3];
>
> num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
> @@ -578,8 +595,33 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
> * 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 (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;
where is power_type coming from and can it be tainted?
if we always expect a valid value then why not just have the conversion
function set the default to WMI_REG_INDOOR_AP?
Are there places in upcoming patches that actually perform error
handling if the conversion function returns MAX?
> + reg_6ghz_number = reg_info->num_6g_reg_rules_cl
> + [ap_type][WMI_REG_DEFAULT_CLIENT];
please avoid splitting lines in the middle of a variable reference; that
decreases the readability of the code. It is better to exceed some
arbitrary line length guideline. you can use a client_type =
WMI_REG_DEFAULT_CLIENT assignment to help reduce the length.
if the line is still exceedingly long, split the lines after =
repeat for all cases that follow
> + if (reg_6ghz_number == 0) {
> + ap_type = WMI_REG_INDOOR_AP;
> + reg_6ghz_number = reg_info->num_6g_reg_rules_cl
> + [ap_type][WMI_REG_DEFAULT_CLIENT];
> + }
> + reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
> + [ap_type][WMI_REG_DEFAULT_CLIENT];
> + max_bw_6ghz = reg_info->max_bw_6g_client
> + [ap_type][WMI_REG_DEFAULT_CLIENT];
> + } else {
> + reg_6ghz_number = reg_info->num_6g_reg_rules_ap
> + [WMI_REG_INDOOR_AP];
> + reg_rule_6ghz = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
> + max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
> + }
> + num_rules += reg_6ghz_number;
> + }
>
> if (!num_rules)
> goto ret;
> @@ -626,12 +668,10 @@ ath12k_reg_build_regd(struct ath12k_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_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]);
> + } else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
> + (k < reg_6ghz_number)) {
> + reg_rule = reg_rule_6ghz + k++;
> + max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
> flags = NL80211_RRF_AUTO_BW;
> } else {
> break;
> diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
> index 56d009a47234..56324e30a358 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.h
> +++ b/drivers/net/wireless/ath/ath12k/reg.h
> @@ -88,7 +88,11 @@ void ath12k_reg_free(struct ath12k_base *ab);
> void ath12k_regd_update_work(struct work_struct *work);
> struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
> struct ath12k_reg_info *reg_info,
> - bool intersect);
> + 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);
> int ath12k_regd_update(struct ath12k *ar, bool init);
> int ath12k_reg_update_chan_list(struct ath12k *ar);
>
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index af910296c41e..1b9ce9a2ae96 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -4152,6 +4152,119 @@ static struct ath12k_reg_rule
> return reg_rule_ptr;
> }
>
> +static char *ath12k_cc_status_to_str(enum ath12k_reg_cc_code code)
all of these *_str() functions should return const char *
> +{
> + switch (code) {
> + case REG_SET_CC_STATUS_PASS:
> + return "REG_SET_CC_STATUS_PASS";
> + case REG_CURRENT_ALPHA2_NOT_FOUND:
> + return "REG_CURRENT_ALPHA2_NOT_FOUND";
> + case REG_INIT_ALPHA2_NOT_FOUND:
> + return "REG_INIT_ALPHA2_NOT_FOUND";
> + case REG_SET_CC_CHANGE_NOT_ALLOWED:
> + return "REG_SET_CC_CHANGE_NOT_ALLOWED";
> + case REG_SET_CC_STATUS_NO_MEMORY:
> + return "REG_SET_CC_STATUS_NO_MEMORY";
> + case REG_SET_CC_STATUS_FAIL:
> + return "REG_SET_CC_STATUS_FAIL";
> + default:
> + return "unknown cc status";
> + }
> +};
> +
> +static char *ath12k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id)
> +{
> + switch (domain_id) {
> + case FCC1_6GHZ:
> + return "FCC1_6GHZ";
> + case ETSI1_6GHZ:
> + return "ETSI1_6GHZ";
> + case ETSI2_6GHZ:
> + return "ETSI2_6GHZ";
> + case APL1_6GHZ:
> + return "APL1_6GHZ";
> + case FCC1_6GHZ_CL:
> + return "FCC1_6GHZ_CL";
> + default:
> + return "unknown domain id";
> + }
> +}
> +
> +static char *ath12k_6ghz_client_type_to_str(enum wmi_reg_6g_client_type type)
> +{
> + switch (type) {
> + case WMI_REG_DEFAULT_CLIENT:
> + return "DEFAULT CLIENT";
> + case WMI_REG_SUBORDINATE_CLIENT:
> + return "SUBORDINATE CLIENT";
> + default:
> + return "unknown client type";
> + }
> +}
> +
> +static char *ath12k_6ghz_ap_type_to_str(enum wmi_reg_6g_ap_type type)
> +{
> + switch (type) {
> + case WMI_REG_INDOOR_AP:
> + return "INDOOR AP";
> + case WMI_REG_STD_POWER_AP:
> + return "STANDARD POWER AP";
> + case WMI_REG_VLP_AP:
> + return "VERY LOW POWER AP";
> + default:
> + return "unknown AP type";
> + }
> +}
> +
> +static char *ath12k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id)
> +{
> + switch (sub_id) {
> + case FCC1_CLIENT_LPI_REGULAR_6GHZ:
> + return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
> + case FCC1_CLIENT_SP_6GHZ:
> + return "FCC1_CLIENT_SP_6GHZ";
> + case FCC1_AP_LPI_6GHZ:
> + return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
> + case FCC1_AP_SP_6GHZ:
> + return "FCC1_AP_SP_6GHZ";
> + case ETSI1_LPI_6GHZ:
> + return "ETSI1_LPI_6GHZ";
> + case ETSI1_VLP_6GHZ:
> + return "ETSI1_VLP_6GHZ";
> + case ETSI2_LPI_6GHZ:
> + return "ETSI2_LPI_6GHZ";
> + case ETSI2_VLP_6GHZ:
> + return "ETSI2_VLP_6GHZ";
> + case APL1_LPI_6GHZ:
> + return "APL1_LPI_6GHZ";
> + case APL1_VLP_6GHZ:
> + return "APL1_VLP_6GHZ";
> + case EMPTY_6GHZ:
> + return "N/A";
> + default:
> + return "unknown sub reg id";
> + }
> +}
> +
> +static void ath12k_print_reg_rule(struct ath12k_base *ab, char *prev,
> + u32 num_reg_rules,
> + struct ath12k_reg_rule *reg_rule_ptr)
> +{
> + struct ath12k_reg_rule *reg_rule = reg_rule_ptr;
> + u32 count;
> +
> + ath12k_dbg(ab, ATH12K_DBG_WMI, "%s reg rules number %d\n", prev, num_reg_rules);
> +
> + for (count = 0; count < num_reg_rules; count++) {
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d) (psd flag %d EIRP %d dB/MHz)\n",
> + count + 1, reg_rule->start_freq, reg_rule->end_freq,
> + reg_rule->max_bw, reg_rule->ant_gain, reg_rule->reg_power,
> + reg_rule->flags, reg_rule->psd_flag, reg_rule->psd_eirp);
> + reg_rule++;
> + }
> +}
> +
> static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> struct sk_buff *skb,
> struct ath12k_reg_info *reg_info)
> @@ -4163,7 +4276,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
> u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
> u32 total_reg_rules = 0;
> - int ret, i, j;
> + int ret, i, j, skip_6ghz_rules_in_5ghz_rules = 0;
>
> ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
>
> @@ -4265,6 +4378,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> * from 5G rules list.
> */
> if (memcmp(reg_info->alpha2, "US", 2) == 0) {
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "US 5 GHz 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_6ghz_rules_in_5ghz_rules = reg_info->num_5g_reg_rules -
> + REG_US_5G_NUM_REG_RULES;
I'd split this line after = instead of in the middle of the expression
> reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;
> num_5g_reg_rules = reg_info->num_5g_reg_rules;
> }
> @@ -4297,6 +4417,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> break;
> }
>
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "%s: status_code %s", __func__,
> + ath12k_cc_status_to_str(reg_info->status_code));
> +
> reg_info->is_ext_reg_event = true;
>
> reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g);
> @@ -4325,6 +4449,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> le32_to_cpu(ev->max_bw_6g_client_vlp[i]);
> }
>
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "%s: status_code %s", __func__,
> + ath12k_cc_status_to_str(reg_info->status_code));
> +
> ath12k_dbg(ab, ATH12K_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,
> @@ -4368,10 +4496,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
> return -ENOMEM;
> }
> + ath12k_print_reg_rule(ab, "2 GHz",
> + num_2g_reg_rules,
> + reg_info->reg_rules_2g_ptr);
> }
> + ext_wmi_reg_rule += num_2g_reg_rules;
>
> 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);
> @@ -4381,9 +4512,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
> return -ENOMEM;
> }
> + ath12k_print_reg_rule(ab, "5 GHz",
> + num_5g_reg_rules,
> + reg_info->reg_rules_5g_ptr);
> }
>
> - ext_wmi_reg_rule += num_5g_reg_rules;
> + /* We have adjusted the number of 5 GHz reg rules via the hack above.
> + * Here, we adjust that many extra rules which came with 5g reg rules
> + * (for cc: US)
> + *
> + * NOTE: skip_6ghz_rules_in_5ghz_rules will be 0 for rest other cases.
> + */
> + ext_wmi_reg_rule += num_5g_reg_rules + skip_6ghz_rules_in_5ghz_rules;
>
> for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
> reg_info->reg_rules_6g_ap_ptr[i] =
> @@ -4396,10 +4536,17 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> return -ENOMEM;
> }
>
> + ath12k_print_reg_rule(ab, ath12k_6ghz_ap_type_to_str(i),
> + num_6g_reg_rules_ap[i],
> + reg_info->reg_rules_6g_ap_ptr[i]);
> +
> ext_wmi_reg_rule += num_6g_reg_rules_ap[i];
> }
>
> for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "AP type %s", ath12k_6ghz_ap_type_to_str(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_cl[j][i],
> @@ -4411,6 +4558,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> return -ENOMEM;
> }
>
> + ath12k_print_reg_rule(ab, ath12k_6ghz_client_type_to_str(i),
> + num_6g_reg_rules_cl[j][i],
> + reg_info->reg_rules_6g_client_ptr[j][i]);
> +
> ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];
> }
> }
> @@ -4425,6 +4576,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =
> le32_to_cpu(ev->domain_code_6g_ap_vlp);
>
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s , sp %s , vlp %s\n",
> + ath12k_6ghz_client_type_to_str(reg_info->client_type),
> + reg_info->rnr_tpe_usable,
> + reg_info->unspecified_ap_usable,
> + ath12k_sub_reg_6ghz_to_str
> + (le32_to_cpu(ev->domain_code_6g_ap_lpi)),
> + ath12k_sub_reg_6ghz_to_str
> + (le32_to_cpu(ev->domain_code_6g_ap_sp)),
> + ath12k_sub_reg_6ghz_to_str
> + (le32_to_cpu(ev->domain_code_6g_ap_vlp)));
avoid splitting the line between a function and it's parameters.
it is ok to split in the middle of a parameter list, but the first
parameter should almost always be on the same line as the function
> +
> for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
> reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =
> le32_to_cpu(ev->domain_code_6g_client_lpi[i]);
> @@ -4432,12 +4595,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
> le32_to_cpu(ev->domain_code_6g_client_sp[i]);
> reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =
> le32_to_cpu(ev->domain_code_6g_client_vlp[i]);
> + ath12k_dbg(ab, ATH12K_DBG_WMI,
> + "6 GHz AP BW: lpi %d - %d sp %d - %d vlp %d - %d\n",
> + ev->min_bw_6g_ap_lpi, ev->max_bw_6g_ap_lpi,
> + ev->min_bw_6g_ap_sp, ev->max_bw_6g_ap_sp,
> + ev->min_bw_6g_ap_vlp, ev->max_bw_6g_ap_vlp);
> }
>
> reg_info->domain_code_6g_super_id = le32_to_cpu(ev->domain_code_6g_super_id);
>
> - ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
> - reg_info->client_type, reg_info->domain_code_6g_super_id);
> + ath12k_dbg(ab, ATH12K_DBG_WMI, "6 GHz client_type: %s 6 GHz super domain %s",
> + ath12k_6ghz_client_type_to_str(reg_info->client_type),
> + ath12k_super_reg_6ghz_to_str(reg_info->domain_code_6g_super_id));
>
> ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
>
> @@ -5192,7 +5361,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
> !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
> intersect = true;
>
> - regd = ath12k_reg_build_regd(ab, reg_info, intersect);
> + regd = ath12k_reg_build_regd(ab, reg_info, intersect,
> + WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
why is this forced to AP?
where is logic for client?
> if (!regd) {
> ath12k_warn(ab, "failed to build regd from reg_info\n");
> goto fallback;
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 08a8c9e0f59f..966e6ba4e162 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -2832,8 +2832,8 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg {
> #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 REG_RULE_PSD_INFO BIT(0)
> +#define REG_RULE_PSD_EIRP 0xff0000
>
> #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
> #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
> @@ -3844,6 +3844,29 @@ enum {
> WMI_REG_SET_CC_STATUS_FAIL = 5,
> };
>
> +enum reg_subdomains_6ghz {
> + EMPTY_6GHZ = 0x0,
> + FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
> + FCC1_CLIENT_SP_6GHZ = 0x02,
> + FCC1_AP_LPI_6GHZ = 0x03,
> + FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
> + FCC1_AP_SP_6GHZ = 0x04,
> + ETSI1_LPI_6GHZ = 0x10,
> + ETSI1_VLP_6GHZ = 0x11,
> + ETSI2_LPI_6GHZ = 0x12,
> + ETSI2_VLP_6GHZ = 0x13,
> + APL1_LPI_6GHZ = 0x20,
> + APL1_VLP_6GHZ = 0x21,
> +};
> +
> +enum reg_super_domain_6ghz {
> + FCC1_6GHZ = 0x01,
> + ETSI1_6GHZ = 0x02,
> + ETSI2_6GHZ = 0x03,
> + APL1_6GHZ = 0x04,
> + FCC1_6GHZ_CL = 0x05,
> +};
> +
> #define WMI_REG_CLIENT_MAX 4
>
> struct wmi_reg_chan_list_cc_ext_event {
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
2023-09-19 17:47 ` Jeff Johnson
@ 2023-09-20 2:10 ` Wen Gong
2023-09-20 18:09 ` Jeff Johnson
2023-09-20 5:48 ` Aishwarya R (QUIC)
1 sibling, 1 reply; 17+ messages in thread
From: Wen Gong @ 2023-09-20 2:10 UTC (permalink / raw)
To: Jeff Johnson, Aishwarya R, ath12k; +Cc: linux-wireless
On 9/20/2023 1:47 AM, Jeff Johnson wrote:
> On 9/19/2023 12:17 AM, Aishwarya R wrote:
>> There are 3 types of regulatory rules for AP mode and 6 types for
>> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
>> to select the exact reg rules.
>>
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Wen,
> Can you provide a "Tested-on: WCN7850" tag for this series?
>
Jeff, it is this tag below.
I have not tested this serials on WCN7850.
Should I test this serials on WCN7850?
Tested-on: WCN7850 hw2.0 PCI
WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
[...]
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
2023-09-20 2:10 ` Wen Gong
@ 2023-09-20 18:09 ` Jeff Johnson
0 siblings, 0 replies; 17+ messages in thread
From: Jeff Johnson @ 2023-09-20 18:09 UTC (permalink / raw)
To: Wen Gong, Aishwarya R, ath12k; +Cc: linux-wireless
On 9/19/2023 7:10 PM, Wen Gong wrote:
> On 9/20/2023 1:47 AM, Jeff Johnson wrote:
>> On 9/19/2023 12:17 AM, Aishwarya R wrote:
>>> There are 3 types of regulatory rules for AP mode and 6 types for
>>> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
>>> to select the exact reg rules.
>>>
>>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>>
>> Wen,
>> Can you provide a "Tested-on: WCN7850" tag for this series?
>>
> Jeff, it is this tag below.
>
> I have not tested this serials on WCN7850.
>
> Should I test this serials on WCN7850?
For a large, non-trivial patchset such as this I'd like to be sure that
both AP-focused and STA-focused products are tested before merge.
/jeff
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread
* RE: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
2023-09-19 17:47 ` Jeff Johnson
2023-09-20 2:10 ` Wen Gong
@ 2023-09-20 5:48 ` Aishwarya R (QUIC)
2023-09-20 13:34 ` Kalle Valo
1 sibling, 1 reply; 17+ messages in thread
From: Aishwarya R (QUIC) @ 2023-09-20 5:48 UTC (permalink / raw)
To: Jeff Johnson (QUIC), ath12k@lists.infradead.org
Cc: linux-wireless@vger.kernel.org, Wen Gong (QUIC)
On 9/19/2023 12:17 AM, Aishwarya R wrote:
>> There are 3 types of regulatory rules for AP mode and 6 types for
>> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
>> to select the exact reg rules.
>>
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Wen,
> Can you provide a "Tested-on: WCN7850" tag for this series?
>>
>> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
>> ---
>> drivers/net/wireless/ath/ath12k/reg.c | 62 +++++++--
>> drivers/net/wireless/ath/ath12k/reg.h | 6 +-
>> drivers/net/wireless/ath/ath12k/wmi.c | 182 +++++++++++++++++++++++++-
>> drivers/net/wireless/ath/ath12k/wmi.h | 27 +++-
>> 4 files changed, 257 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath12k/reg.c
>> b/drivers/net/wireless/ath/ath12k/reg.c
>> index 6ede91ebc8e1..8501f77eee55 100644
>> --- a/drivers/net/wireless/ath/ath12k/reg.c
>> +++ b/drivers/net/wireless/ath/ath12k/reg.c
>> @@ -28,6 +28,21 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
>> }
>> };
>>
>> +enum wmi_reg_6g_ap_type
>> +ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power
>> +power_type) {
>> + switch (power_type) {
>> + case IEEE80211_REG_LPI_AP:
>> + return WMI_REG_INDOOR_AP;
>> + case IEEE80211_REG_SP_AP:
>> + return WMI_REG_STD_POWER_AP;
>> + case IEEE80211_REG_VLP_AP:
>> + return WMI_REG_VLP_AP;
>> + default:
>> + return WMI_REG_MAX_AP_TYPE;
>> + }
>> +}
>> +
>> static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
>> {
>> const struct ieee80211_regdomain *regd; @@ -562,14 +577,16 @@
>> ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
>>
>> struct ieee80211_regdomain *
>> ath12k_reg_build_regd(struct ath12k_base *ab,
>> - struct ath12k_reg_info *reg_info, bool intersect)
>> + struct ath12k_reg_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 ath12k_reg_rule *reg_rule;
>> + struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
>> u8 i = 0, j = 0, k = 0;
>> u8 num_rules;
>> u16 max_bw;
>> - u32 flags;
>> + u32 flags, reg_6ghz_number, max_bw_6ghz;
>> char alpha2[3];
>>
>> num_rules = reg_info->num_5g_reg_rules +
>> reg_info->num_2g_reg_rules; @@ -578,8 +595,33 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
>> * 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 (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;
> where is power_type coming from and can it be tainted?
> if we always expect a valid value then why not just have the conversion function set the default to WMI_REG_INDOOR_AP?
> Are there places in upcoming patches that actually perform error handling if the conversion function returns MAX?
>> + reg_6ghz_number = reg_info->num_6g_reg_rules_cl
>> + [ap_type][WMI_REG_DEFAULT_CLIENT];
> please avoid splitting lines in the middle of a variable reference; that decreases the readability of the code. It is better to exceed some arbitrary line length guideline. you can use a client_type = WMI_REG_DEFAULT_CLIENT assignment to help reduce the length.
> if the line is still exceedingly long, split the lines after =
> repeat for all cases that follow
>> + if (reg_6ghz_number == 0) {
>> + ap_type = WMI_REG_INDOOR_AP;
>> + reg_6ghz_number = reg_info->num_6g_reg_rules_cl
>> + [ap_type][WMI_REG_DEFAULT_CLIENT];
>> + }
>> + reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
>> + [ap_type][WMI_REG_DEFAULT_CLIENT];
>> + max_bw_6ghz = reg_info->max_bw_6g_client
>> + [ap_type][WMI_REG_DEFAULT_CLIENT];
>> + } else {
>> + reg_6ghz_number = reg_info->num_6g_reg_rules_ap
>> + [WMI_REG_INDOOR_AP];
>> + reg_rule_6ghz = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
>> + max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
>> + }
>> + num_rules += reg_6ghz_number;
>> + }
>>
>> if (!num_rules)
>> goto ret;
>> @@ -626,12 +668,10 @@ ath12k_reg_build_regd(struct ath12k_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_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]);
>> + } else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
>> + (k < reg_6ghz_number)) {
>> + reg_rule = reg_rule_6ghz + k++;
>> + max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
>> flags = NL80211_RRF_AUTO_BW;
>> } else {
>> break;
>> diff --git a/drivers/net/wireless/ath/ath12k/reg.h
>> b/drivers/net/wireless/ath/ath12k/reg.h
>> index 56d009a47234..56324e30a358 100644
>> --- a/drivers/net/wireless/ath/ath12k/reg.h
>> +++ b/drivers/net/wireless/ath/ath12k/reg.h
>> @@ -88,7 +88,11 @@ void ath12k_reg_free(struct ath12k_base *ab);
>> void ath12k_regd_update_work(struct work_struct *work);
>> struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
>> struct ath12k_reg_info *reg_info,
>> - bool intersect);
>> + 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);
>> int ath12k_regd_update(struct ath12k *ar, bool init);
>> int ath12k_reg_update_chan_list(struct ath12k *ar);
>>
>> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c
>> b/drivers/net/wireless/ath/ath12k/wmi.c
>> index af910296c41e..1b9ce9a2ae96 100644
>> --- a/drivers/net/wireless/ath/ath12k/wmi.c
>> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
>> @@ -4152,6 +4152,119 @@ static struct ath12k_reg_rule
>> return reg_rule_ptr;
>> }
>>
>> +static char *ath12k_cc_status_to_str(enum ath12k_reg_cc_code code)
> all of these *_str() functions should return const char *
>> +{
>> + switch (code) {
>> + case REG_SET_CC_STATUS_PASS:
>> + return "REG_SET_CC_STATUS_PASS";
>> + case REG_CURRENT_ALPHA2_NOT_FOUND:
>> + return "REG_CURRENT_ALPHA2_NOT_FOUND";
>> + case REG_INIT_ALPHA2_NOT_FOUND:
>> + return "REG_INIT_ALPHA2_NOT_FOUND";
>> + case REG_SET_CC_CHANGE_NOT_ALLOWED:
>> + return "REG_SET_CC_CHANGE_NOT_ALLOWED";
>> + case REG_SET_CC_STATUS_NO_MEMORY:
>> + return "REG_SET_CC_STATUS_NO_MEMORY";
>> + case REG_SET_CC_STATUS_FAIL:
>> + return "REG_SET_CC_STATUS_FAIL";
>> + default:
>> + return "unknown cc status";
>> + }
>> +};
>> +
>> +static char *ath12k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz
>> +domain_id) {
>> + switch (domain_id) {
>> + case FCC1_6GHZ:
>> + return "FCC1_6GHZ";
>> + case ETSI1_6GHZ:
>> + return "ETSI1_6GHZ";
>> + case ETSI2_6GHZ:
>> + return "ETSI2_6GHZ";
>> + case APL1_6GHZ:
>> + return "APL1_6GHZ";
>> + case FCC1_6GHZ_CL:
>> + return "FCC1_6GHZ_CL";
>> + default:
>> + return "unknown domain id";
>> + }
>> +}
>> +
>> +static char *ath12k_6ghz_client_type_to_str(enum
>> +wmi_reg_6g_client_type type) {
>> + switch (type) {
>> + case WMI_REG_DEFAULT_CLIENT:
>> + return "DEFAULT CLIENT";
>> + case WMI_REG_SUBORDINATE_CLIENT:
>> + return "SUBORDINATE CLIENT";
>> + default:
>> + return "unknown client type";
>> + }
>> +}
>> +
>> +static char *ath12k_6ghz_ap_type_to_str(enum wmi_reg_6g_ap_type type)
>> +{
>> + switch (type) {
>> + case WMI_REG_INDOOR_AP:
>> + return "INDOOR AP";
>> + case WMI_REG_STD_POWER_AP:
>> + return "STANDARD POWER AP";
>> + case WMI_REG_VLP_AP:
>> + return "VERY LOW POWER AP";
>> + default:
>> + return "unknown AP type";
>> + }
>> +}
>> +
>> +static char *ath12k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz
>> +sub_id) {
>> + switch (sub_id) {
>> + case FCC1_CLIENT_LPI_REGULAR_6GHZ:
>> + return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
>> + case FCC1_CLIENT_SP_6GHZ:
>> + return "FCC1_CLIENT_SP_6GHZ";
>> + case FCC1_AP_LPI_6GHZ:
>> + return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
>> + case FCC1_AP_SP_6GHZ:
>> + return "FCC1_AP_SP_6GHZ";
>> + case ETSI1_LPI_6GHZ:
>> + return "ETSI1_LPI_6GHZ";
>> + case ETSI1_VLP_6GHZ:
>> + return "ETSI1_VLP_6GHZ";
>> + case ETSI2_LPI_6GHZ:
>> + return "ETSI2_LPI_6GHZ";
>> + case ETSI2_VLP_6GHZ:
>> + return "ETSI2_VLP_6GHZ";
>> + case APL1_LPI_6GHZ:
>> + return "APL1_LPI_6GHZ";
>> + case APL1_VLP_6GHZ:
>> + return "APL1_VLP_6GHZ";
>> + case EMPTY_6GHZ:
>> + return "N/A";
>> + default:
>> + return "unknown sub reg id";
>> + }
>> +}
>> +
>> +static void ath12k_print_reg_rule(struct ath12k_base *ab, char *prev,
>> + u32 num_reg_rules,
>> + struct ath12k_reg_rule *reg_rule_ptr) {
>> + struct ath12k_reg_rule *reg_rule = reg_rule_ptr;
>> + u32 count;
>> +
>> + ath12k_dbg(ab, ATH12K_DBG_WMI, "%s reg rules number %d\n", prev,
>> +num_reg_rules);
>> +
>> + for (count = 0; count < num_reg_rules; count++) {
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d) (psd flag %d EIRP %d dB/MHz)\n",
>> + count + 1, reg_rule->start_freq, reg_rule->end_freq,
>> + reg_rule->max_bw, reg_rule->ant_gain, reg_rule->reg_power,
>> + reg_rule->flags, reg_rule->psd_flag, reg_rule->psd_eirp);
>> + reg_rule++;
>> + }
>> +}
>> +
>> static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> struct sk_buff *skb,
>> struct ath12k_reg_info *reg_info) @@ -4163,7 +4276,7 @@
>> static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
>> u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
>> u32 total_reg_rules = 0;
>> - int ret, i, j;
>> + int ret, i, j, skip_6ghz_rules_in_5ghz_rules = 0;
>>
>> ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel
>> list\n");
>>
>> @@ -4265,6 +4378,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> * from 5G rules list.
>> */
>> if (memcmp(reg_info->alpha2, "US", 2) == 0) {
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "US 5 GHz 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_6ghz_rules_in_5ghz_rules = reg_info->num_5g_reg_rules -
>> + REG_US_5G_NUM_REG_RULES;
> I'd split this line after = instead of in the middle of the expression
>> reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;
>> num_5g_reg_rules = reg_info->num_5g_reg_rules;
>> }
>> @@ -4297,6 +4417,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> break;
>> }
>>
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "%s: status_code %s", __func__,
>> + ath12k_cc_status_to_str(reg_info->status_code));
>> +
>> reg_info->is_ext_reg_event = true;
>>
>> reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g); @@ -4325,6
>> +4449,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> le32_to_cpu(ev->max_bw_6g_client_vlp[i]);
>> }
>>
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "%s: status_code %s", __func__,
>> + ath12k_cc_status_to_str(reg_info->status_code));
>> +
>> ath12k_dbg(ab, ATH12K_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, @@ -4368,10
>> +4496,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
>> return -ENOMEM;
>> }
>> + ath12k_print_reg_rule(ab, "2 GHz",
>> + num_2g_reg_rules,
>> + reg_info->reg_rules_2g_ptr);
>> }
>> + ext_wmi_reg_rule += num_2g_reg_rules;
>>
>> 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);
>> @@ -4381,9 +4512,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
>> return -ENOMEM;
>> }
>> + ath12k_print_reg_rule(ab, "5 GHz",
>> + num_5g_reg_rules,
>> + reg_info->reg_rules_5g_ptr);
>> }
>>
>> - ext_wmi_reg_rule += num_5g_reg_rules;
>> + /* We have adjusted the number of 5 GHz reg rules via the hack above.
>> + * Here, we adjust that many extra rules which came with 5g reg rules
>> + * (for cc: US)
>> + *
>> + * NOTE: skip_6ghz_rules_in_5ghz_rules will be 0 for rest other cases.
>> + */
>> + ext_wmi_reg_rule += num_5g_reg_rules +
>> +skip_6ghz_rules_in_5ghz_rules;
>>
>> for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
>> reg_info->reg_rules_6g_ap_ptr[i] = @@ -4396,10 +4536,17 @@ static
>> int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> return -ENOMEM;
>> }
>>
>> + ath12k_print_reg_rule(ab, ath12k_6ghz_ap_type_to_str(i),
>> + num_6g_reg_rules_ap[i],
>> + reg_info->reg_rules_6g_ap_ptr[i]);
>> +
>> ext_wmi_reg_rule += num_6g_reg_rules_ap[i];
>> }
>>
>> for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "AP type %s", ath12k_6ghz_ap_type_to_str(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_cl[j][i],
>> @@ -4411,6 +4558,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> return -ENOMEM;
>> }
>>
>> + ath12k_print_reg_rule(ab, ath12k_6ghz_client_type_to_str(i),
>> + num_6g_reg_rules_cl[j][i],
>> + reg_info->reg_rules_6g_client_ptr[j][i]);
>> +
>> ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];
>> }
>> }
>> @@ -4425,6 +4576,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =
>> le32_to_cpu(ev->domain_code_6g_ap_vlp);
>>
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s , sp %s , vlp %s\n",
>> + ath12k_6ghz_client_type_to_str(reg_info->client_type),
>> + reg_info->rnr_tpe_usable,
>> + reg_info->unspecified_ap_usable,
>> + ath12k_sub_reg_6ghz_to_str
>> + (le32_to_cpu(ev->domain_code_6g_ap_lpi)),
>> + ath12k_sub_reg_6ghz_to_str
>> + (le32_to_cpu(ev->domain_code_6g_ap_sp)),
>> + ath12k_sub_reg_6ghz_to_str
>> + (le32_to_cpu(ev->domain_code_6g_ap_vlp)));
> avoid splitting the line between a function and it's parameters.
> it is ok to split in the middle of a parameter list, but the first parameter should almost always be on the same line as the function
>> +
>> for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
>> reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =
>> le32_to_cpu(ev->domain_code_6g_client_lpi[i]);
>> @@ -4432,12 +4595,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>> le32_to_cpu(ev->domain_code_6g_client_sp[i]);
>> reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =
>> le32_to_cpu(ev->domain_code_6g_client_vlp[i]);
>> + ath12k_dbg(ab, ATH12K_DBG_WMI,
>> + "6 GHz AP BW: lpi %d - %d sp %d - %d vlp %d - %d\n",
>> + ev->min_bw_6g_ap_lpi, ev->max_bw_6g_ap_lpi,
>> + ev->min_bw_6g_ap_sp, ev->max_bw_6g_ap_sp,
>> + ev->min_bw_6g_ap_vlp, ev->max_bw_6g_ap_vlp);
>> }
>>
>> reg_info->domain_code_6g_super_id =
>> le32_to_cpu(ev->domain_code_6g_super_id);
>>
>> - ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
>> - reg_info->client_type, reg_info->domain_code_6g_super_id);
>> + ath12k_dbg(ab, ATH12K_DBG_WMI, "6 GHz client_type: %s 6 GHz super domain %s",
>> + ath12k_6ghz_client_type_to_str(reg_info->client_type),
>> +
>> +ath12k_super_reg_6ghz_to_str(reg_info->domain_code_6g_super_id));
>>
>> ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel
>> list\n");
>>
>> @@ -5192,7 +5361,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
>> !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
>> intersect = true;
>>
>> - regd = ath12k_reg_build_regd(ab, reg_info, intersect);
>> + regd = ath12k_reg_build_regd(ab, reg_info, intersect,
>> + WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
> why is this forced to AP?
> where is logic for client?
>> if (!regd) {
>> ath12k_warn(ab, "failed to build regd from reg_info\n");
>> goto fallback;
>> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h
>> b/drivers/net/wireless/ath/ath12k/wmi.h
>> index 08a8c9e0f59f..966e6ba4e162 100644
>> --- a/drivers/net/wireless/ath/ath12k/wmi.h
>> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
>> @@ -2832,8 +2832,8 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg {
>> #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 REG_RULE_PSD_INFO BIT(0)
>> +#define REG_RULE_PSD_EIRP 0xff0000
>>
>> #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
>> #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) @@ -3844,6 +3844,29 @@
>> enum {
>> WMI_REG_SET_CC_STATUS_FAIL = 5,
>> };
>>
>> +enum reg_subdomains_6ghz {
>> + EMPTY_6GHZ = 0x0,
>> + FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
>> + FCC1_CLIENT_SP_6GHZ = 0x02,
>> + FCC1_AP_LPI_6GHZ = 0x03,
>> + FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
>> + FCC1_AP_SP_6GHZ = 0x04,
>> + ETSI1_LPI_6GHZ = 0x10,
>> + ETSI1_VLP_6GHZ = 0x11,
>> + ETSI2_LPI_6GHZ = 0x12,
>> + ETSI2_VLP_6GHZ = 0x13,
>> + APL1_LPI_6GHZ = 0x20,
>> + APL1_VLP_6GHZ = 0x21,
>> +};
>> +
>> +enum reg_super_domain_6ghz {
>> + FCC1_6GHZ = 0x01,
>> + ETSI1_6GHZ = 0x02,
>> + ETSI2_6GHZ = 0x03,
>> + APL1_6GHZ = 0x04,
>> + FCC1_6GHZ_CL = 0x05,
>> +};
>> +
>> #define WMI_REG_CLIENT_MAX 4
>>
>> struct wmi_reg_chan_list_cc_ext_event {
Thanks for your review. I will address all your comments in next revision.
Aishwarya
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
2023-09-19 7:17 ` [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 19:57 ` Jeff Johnson
2023-09-19 7:17 ` [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element Aishwarya R
` (4 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
During bootup, WMI_REG_CHAN_LIST_CC_EXT_EVENTID event sent from firmware
at an early stage and it expects the 6 GHz power type for 6 GHz reg rules.
As power mode is not defined at this point host selects IEEE80211_REG_UNSET_AP
as default mode.
When interface is created, it updates regd rules accordingly.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 11 ++++
drivers/net/wireless/ath/ath12k/mac.h | 1 +
drivers/net/wireless/ath/ath12k/wmi.c | 75 ++++++++++++++++-----------
drivers/net/wireless/ath/ath12k/wmi.h | 1 +
4 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index ee792822b411..5b9af264d305 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -563,6 +563,17 @@ struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id)
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;
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 57f4295420bb..82f590004d05 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -66,6 +66,7 @@ struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
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_drain_tx(struct ath12k *ar);
void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 1b9ce9a2ae96..211bdb915173 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5299,26 +5299,15 @@ static bool ath12k_reg_is_world_alpha(char *alpha)
return alpha[0] == '0' && alpha[1] == '0';
}
-static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
+static int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
+ struct ath12k_reg_info *reg_info,
+ enum ieee80211_ap_reg_power power_type)
{
- struct ath12k_reg_info *reg_info = NULL;
- struct ieee80211_regdomain *regd = NULL;
+ struct ieee80211_regdomain *regd;
bool intersect = false;
- int ret = 0, pdev_idx, i, j;
+ int pdev_idx;
struct ath12k *ar;
-
- reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
- if (!reg_info) {
- ret = -ENOMEM;
- goto fallback;
- }
-
- ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
-
- if (ret) {
- ath12k_warn(ab, "failed to extract regulatory info from received event\n");
- goto fallback;
- }
+ 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,
@@ -5326,7 +5315,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
* and return from here.
*/
ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");
- goto mem_free;
+ return -EINVAL;
}
pdev_idx = reg_info->phy_id;
@@ -5338,9 +5327,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
*/
if (ab->hw_params->single_pdev_only &&
pdev_idx < ab->hw_params->num_rxmda_per_pdev)
- goto mem_free;
- else
- goto fallback;
+ return -EINVAL;
+ goto fallback;
}
/* Avoid multiple overwrites to default regd, during core
@@ -5349,7 +5337,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
!memcmp(ab->default_regd[pdev_idx]->alpha2,
reg_info->alpha2, 2))
- goto mem_free;
+ return -EINVAL;
/* Intersect new rules with default regd if a new country setting was
* requested, i.e a default regd was already set during initialization
@@ -5361,8 +5349,13 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
!ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
intersect = true;
- regd = ath12k_reg_build_regd(ab, reg_info, intersect,
- WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
+ 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);
+
+ regd = ath12k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type);
if (!regd) {
ath12k_warn(ab, "failed to build regd from reg_info\n");
goto fallback;
@@ -5394,7 +5387,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
ab->dfs_region = reg_info->dfs_region;
spin_unlock(&ab->base_lock);
- goto mem_free;
+ return 0;
fallback:
/* Fallback to older reg (by sending previous country setting
@@ -5406,17 +5399,39 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
*/
/* TODO: This is rare, but still should also be handled */
WARN_ON(1);
+ return -EINVAL;
+}
+
+static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+ struct ath12k_reg_info *reg_info;
+ int ret, i, j;
+
+ reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
+ if (!reg_info)
+ return -ENOMEM;
+
+ ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
+
+ if (ret) {
+ ath12k_warn(ab, "failed to extract regulatory info from received event\n");
+ goto mem_free;
+ }
+
+ ret = ath12k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP);
+ if (ret)
+ ath12k_warn(ab, "failed to process regulatory info from received event\n");
+
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++)
+ 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]);
+ for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++)
+ kfree(reg_info->reg_rules_6g_client_ptr[i][j]);
+ }
}
kfree(reg_info);
}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 966e6ba4e162..c3b110af1272 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4161,6 +4161,7 @@ struct ath12k_wmi_target_cap_arg {
};
enum wmi_vdev_type {
+ WMI_VDEV_TYPE_UNSPEC = 0,
WMI_VDEV_TYPE_AP = 1,
WMI_VDEV_TYPE_STA = 2,
WMI_VDEV_TYPE_IBSS = 3,
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
2023-09-19 7:17 ` [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type Aishwarya R
2023-09-19 7:17 ` [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 19:59 ` Jeff Johnson
2023-09-19 7:17 ` [PATCH 4/7] wifi: ath12k: save power spectral density(PSD) of regulatory rule Aishwarya R
` (3 subsequent siblings)
6 siblings, 1 reply; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
When 6 GHz AP or STA is assigned a channel ctx, it needs to
extract the power type from HE operation element.
If unset power type is present, by default IEEE80211_REG_LPI_AP
power mode will be used.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 5b9af264d305..01f81b087fa2 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5823,6 +5823,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ath12k_vif *arvif = (void *)vif->drv_priv;
int ret;
struct ath12k_wmi_peer_create_arg param;
+ enum ieee80211_ap_reg_power power_type;
mutex_lock(&ar->conf_mutex);
@@ -5830,6 +5831,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
"mac chanctx assign ptr %pK vdev_id %i\n",
ctx, arvif->vdev_id);
+ if (ar->supports_6ghz && ctx->def.chan->band == NL80211_BAND_6GHZ &&
+ (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+ arvif->vdev_type == WMI_VDEV_TYPE_AP)) {
+ power_type = vif->bss_conf.power_type;
+ ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx power type %d\n",
+ power_type);
+ if (power_type == IEEE80211_REG_UNSET_AP)
+ power_type = IEEE80211_REG_LPI_AP;
+ }
+
/* for some targets bss peer must be created before vdev_start */
if (ab->hw_params->vdev_start_delay &&
arvif->vdev_type != WMI_VDEV_TYPE_AP &&
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
2023-09-19 7:17 ` [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element Aishwarya R
@ 2023-09-19 19:59 ` Jeff Johnson
0 siblings, 0 replies; 17+ messages in thread
From: Jeff Johnson @ 2023-09-19 19:59 UTC (permalink / raw)
To: Aishwarya R, ath12k; +Cc: linux-wireless
On 9/19/2023 12:17 AM, Aishwarya R wrote:
> When 6 GHz AP or STA is assigned a channel ctx, it needs to
here again, what is "it"?
and why does "it" need the power type?
> extract the power type from HE operation element.
> If unset power type is present, by default IEEE80211_REG_LPI_AP
> power mode will be used.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
> ---
> drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 5b9af264d305..01f81b087fa2 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5823,6 +5823,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
> struct ath12k_vif *arvif = (void *)vif->drv_priv;
> int ret;
> struct ath12k_wmi_peer_create_arg param;
> + enum ieee80211_ap_reg_power power_type;
>
> mutex_lock(&ar->conf_mutex);
>
> @@ -5830,6 +5831,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
> "mac chanctx assign ptr %pK vdev_id %i\n",
> ctx, arvif->vdev_id);
>
> + if (ar->supports_6ghz && ctx->def.chan->band == NL80211_BAND_6GHZ &&
> + (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> + arvif->vdev_type == WMI_VDEV_TYPE_AP)) {
> + power_type = vif->bss_conf.power_type;
> + ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx power type %d\n",
> + power_type);
> + if (power_type == IEEE80211_REG_UNSET_AP)
> + power_type = IEEE80211_REG_LPI_AP;
> + }
> +
> /* for some targets bss peer must be created before vdev_start */
> if (ab->hw_params->vdev_start_delay &&
> arvif->vdev_type != WMI_VDEV_TYPE_AP &&
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 4/7] wifi: ath12k: save power spectral density(PSD) of regulatory rule
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
` (2 preceding siblings ...)
2023-09-19 7:17 ` [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 7:17 ` [PATCH 5/7] wifi: ath12k: add parse of transmit power envelope element Aishwarya R
` (2 subsequent siblings)
6 siblings, 0 replies; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
Save the Power Spectral Density(PSD) report from firmware
to struct ieee80211_reg_rule. 6 GHz regulatory domains
introduces PSD. The PSD value of the regulatory rule should
be taken into effect for the ieee80211_channels falling into
that particular regulatory rule.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/reg.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 8501f77eee55..19681474026f 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -390,6 +390,10 @@ static void ath12k_reg_intersect_rules(struct ieee80211_reg_rule *rule1,
/* Use the flags of both the rules */
new_rule->flags = rule1->flags | rule2->flags;
+ if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD))
+ new_rule->psd = min_t(s8, rule1->psd, rule2->psd);
+ else
+ new_rule->flags &= ~NL80211_RRF_PSD;
/* To be safe, lts use the max cac timeout of both rules */
new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms,
@@ -488,13 +492,14 @@ ath12k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw)
static void
ath12k_reg_update_rule(struct ieee80211_reg_rule *reg_rule, u32 start_freq,
u32 end_freq, u32 bw, u32 ant_gain, u32 reg_pwr,
- u32 reg_flags)
+ s8 psd, u32 reg_flags)
{
reg_rule->freq_range.start_freq_khz = MHZ_TO_KHZ(start_freq);
reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(end_freq);
reg_rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw);
reg_rule->power_rule.max_antenna_gain = DBI_TO_MBI(ant_gain);
reg_rule->power_rule.max_eirp = DBM_TO_MBM(reg_pwr);
+ reg_rule->psd = psd;
reg_rule->flags = reg_flags;
}
@@ -516,7 +521,7 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
ath12k_reg_update_rule(regd->reg_rules + i, reg_rule->start_freq,
ETSI_WEATHER_RADAR_BAND_LOW, bw,
reg_rule->ant_gain, reg_rule->reg_power,
- flags);
+ reg_rule->psd_eirp, flags);
ath12k_dbg(ab, ATH12K_DBG_REG,
"\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
@@ -538,7 +543,7 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
ath12k_reg_update_rule(regd->reg_rules + i,
ETSI_WEATHER_RADAR_BAND_LOW, end_freq, bw,
reg_rule->ant_gain, reg_rule->reg_power,
- flags);
+ reg_rule->psd_eirp, flags);
regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT;
@@ -563,7 +568,7 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
ath12k_reg_update_rule(regd->reg_rules + i, ETSI_WEATHER_RADAR_BAND_HIGH,
reg_rule->end_freq, bw,
reg_rule->ant_gain, reg_rule->reg_power,
- flags);
+ reg_rule->psd_eirp, flags);
ath12k_dbg(ab, ATH12K_DBG_REG,
"\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
@@ -673,6 +678,8 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
reg_rule = reg_rule_6ghz + k++;
max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
flags = NL80211_RRF_AUTO_BW;
+ if (reg_rule->psd_flag)
+ flags |= NL80211_RRF_PSD;
} else {
break;
}
@@ -683,7 +690,7 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
reg_rule->start_freq,
reg_rule->end_freq, max_bw,
reg_rule->ant_gain, reg_rule->reg_power,
- flags);
+ reg_rule->psd_eirp, flags);
/* Update dfs cac timeout if the dfs domain is ETSI and the
* new rule covers weather radar band.
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 5/7] wifi: ath12k: add parse of transmit power envelope element
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
` (3 preceding siblings ...)
2023-09-19 7:17 ` [PATCH 4/7] wifi: ath12k: save power spectral density(PSD) of regulatory rule Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 7:17 ` [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command Aishwarya R
2023-09-19 7:17 ` [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV Aishwarya R
6 siblings, 0 replies; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
The transmit power envelope element has some fields for power, ath12k
should parse it according to IEEE Std 802.11ax™‐2021.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.h | 38 +++++
drivers/net/wireless/ath/ath12k/mac.c | 194 +++++++++++++++++++++++++
2 files changed, 232 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 9439052a652e..01768fe79bd6 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -187,6 +187,43 @@ enum ath12k_monitor_flags {
ATH12K_FLAG_MONITOR_ENABLED,
};
+/**
+ * struct chan_power_info - TPE containing power info per channel chunk
+ * @chan_cfreq: channel center freq (MHz)
+ * e.g.
+ * channel 37/20MHz, it is 6135
+ * channel 37/40MHz, it is 6125
+ * channel 37/80MHz, it is 6145
+ * channel 37/160MHz, it is 6185
+ * @tx_power: transmit power (dBm)
+ */
+struct chan_power_info {
+ u16 chan_cfreq;
+ s8 tx_power;
+};
+
+/**
+ * struct reg_tpc_power_info - regulatory TPC power info
+ * @is_psd_power: is PSD power or not
+ * @eirp_power: Maximum EIRP power (dBm), valid only if power is PSD
+ * @power_type_6ghz: type of power (SP/LPI/VLP)
+ * @num_pwr_levels: number of power levels
+ * @reg_max: Array of maximum TX power (dBm) per PSD value
+ * @ap_constraint_power: AP constraint power (dBm)
+ * @tpe: TPE values processed from TPE IE
+ * @chan_power_info: power info to send to FW
+ */
+struct ath12k_reg_tpc_power_info {
+ bool is_psd_power;
+ u8 eirp_power;
+ enum wmi_reg_6g_ap_type power_type_6ghz;
+ u8 num_pwr_levels;
+ u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL];
+ u8 ap_constraint_power;
+ s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL];
+ struct chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL];
+};
+
struct ath12k_vif {
u32 vdev_id;
enum wmi_vdev_type vdev_type;
@@ -235,6 +272,7 @@ struct ath12k_vif {
bool rsnie_present;
bool wpaie_present;
struct ieee80211_chanctx_conf chanctx;
+ struct ath12k_reg_tpc_power_info reg_tpc_info;
u32 key_cipher;
u8 tx_encap_type;
u8 vdev_stats_id;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 01f81b087fa2..0683b22137b0 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5812,6 +5812,197 @@ static int ath12k_start_vdev_delay(struct ieee80211_hw *hw,
return 0;
}
+static u8 ath12k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt)
+{
+ switch (txpwr_intrprt) {
+ /* Refer "Table 9-276-Meaning of Maximum Transmit Power Count subfield
+ * if the Maximum Transmit Power Interpretation subfield is 0 or 2" of
+ * "IEEE Std 802.11ax 2021".
+ */
+ case IEEE80211_TPE_LOCAL_EIRP:
+ case IEEE80211_TPE_REG_CLIENT_EIRP:
+ txpwr_cnt = txpwr_cnt <= 3 ? txpwr_cnt : 3;
+ txpwr_cnt = txpwr_cnt + 1;
+ break;
+ /* Refer "Table 9-277-Meaning of Maximum Transmit Power Count subfield
+ * if Maximum Transmit Power Interpretation subfield is 1 or 3" of
+ * "IEEE Std 802.11ax 2021".
+ */
+ case IEEE80211_TPE_LOCAL_EIRP_PSD:
+ case IEEE80211_TPE_REG_CLIENT_EIRP_PSD:
+ txpwr_cnt = txpwr_cnt <= 4 ? txpwr_cnt : 4;
+ txpwr_cnt = txpwr_cnt ? (BIT(txpwr_cnt - 1)) : 1;
+ break;
+ }
+
+ return txpwr_cnt;
+}
+
+static u8 ath12k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
+{
+ u8 num_pwr_levels;
+
+ if (chan_def->chan->flags & IEEE80211_CHAN_PSD) {
+ switch (chan_def->width) {
+ case NL80211_CHAN_WIDTH_20:
+ num_pwr_levels = 1;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ num_pwr_levels = 2;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ num_pwr_levels = 4;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ num_pwr_levels = 8;
+ break;
+ default:
+ return 1;
+ }
+ } else {
+ switch (chan_def->width) {
+ case NL80211_CHAN_WIDTH_20:
+ num_pwr_levels = 1;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ num_pwr_levels = 2;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ num_pwr_levels = 3;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ num_pwr_levels = 4;
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ return num_pwr_levels;
+}
+
+static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_vif *arvif = (void *)vif->drv_priv;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ieee80211_tx_pwr_env *single_tpe;
+ enum wmi_reg_6g_client_type client_type;
+ int i;
+ u8 pwr_count, pwr_interpret, pwr_category;
+ u8 psd_index = 0, non_psd_index = 0, local_tpe_count = 0, reg_tpe_count = 0;
+ bool use_local_tpe, non_psd_set = false, psd_set = false;
+
+ client_type = WMI_REG_DEFAULT_CLIENT;
+
+ for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
+ single_tpe = &bss_conf->tx_pwr_env[i];
+ pwr_category = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
+ pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+
+ if (pwr_category == client_type) {
+ if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP ||
+ pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD)
+ local_tpe_count++;
+ else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP ||
+ pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD)
+ reg_tpe_count++;
+ }
+ }
+
+ if (!reg_tpe_count && !local_tpe_count) {
+ ath12k_warn(ab,
+ "no transmit power envelope match client power type %d\n",
+ client_type);
+ return;
+ } else if (!reg_tpe_count) {
+ use_local_tpe = true;
+ } else {
+ use_local_tpe = false;
+ }
+ for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
+ single_tpe = &bss_conf->tx_pwr_env[i];
+ pwr_category = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
+ pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+
+ if (pwr_category != client_type)
+ continue;
+
+ /* get local transmit power envelope */
+ if (use_local_tpe) {
+ if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP) {
+ non_psd_index = i;
+ non_psd_set = true;
+ } else if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) {
+ psd_index = i;
+ psd_set = true;
+ }
+ /* get regulatory transmit power envelope */
+ } else {
+ if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP) {
+ non_psd_index = i;
+ non_psd_set = true;
+ } else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) {
+ psd_index = i;
+ psd_set = true;
+ }
+ }
+ }
+
+ if (non_psd_set && !psd_set) {
+ single_tpe = &bss_conf->tx_pwr_env[non_psd_index];
+ pwr_count = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_COUNT);
+ pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+ arvif->reg_tpc_info.is_psd_power = false;
+ arvif->reg_tpc_info.eirp_power = 0;
+
+ arvif->reg_tpc_info.num_pwr_levels =
+ ath12k_mac_get_tpe_count(pwr_interpret, pwr_count);
+ for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
+ "non PSD power[%d] : %d\n",
+ i, single_tpe->tx_power[i]);
+ arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
+ }
+ }
+ if (psd_set) {
+ single_tpe = &bss_conf->tx_pwr_env[psd_index];
+ pwr_count = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_COUNT);
+ pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+ IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+ arvif->reg_tpc_info.is_psd_power = true;
+
+ if (pwr_count == 0) {
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
+ "TPE PSD power : %d\n", single_tpe->tx_power[0]);
+ arvif->reg_tpc_info.num_pwr_levels =
+ ath12k_mac_get_num_pwr_levels(&ctx->def);
+ for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++)
+ arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[0] / 2;
+ } else {
+ arvif->reg_tpc_info.num_pwr_levels =
+ ath12k_mac_get_tpe_count(pwr_interpret, pwr_count);
+ for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
+ "TPE PSD power[%d] : %d\n",
+ i, single_tpe->tx_power[i]);
+ arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
+ }
+ }
+ }
+}
+
static int
ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -5839,6 +6030,9 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
power_type);
if (power_type == IEEE80211_REG_UNSET_AP)
power_type = IEEE80211_REG_LPI_AP;
+
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
+ ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
}
/* for some targets bss peer must be created before vdev_start */
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
` (4 preceding siblings ...)
2023-09-19 7:17 ` [PATCH 5/7] wifi: ath12k: add parse of transmit power envelope element Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 20:09 ` Jeff Johnson
2023-09-19 7:17 ` [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV Aishwarya R
6 siblings, 1 reply; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
Prepare the parameters which is needed for wmi cmd
vdev_set_tpc_power.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/core.h | 1 +
drivers/net/wireless/ath/ath12k/mac.c | 273 +++++++++++++++++++++++++
drivers/net/wireless/ath/ath12k/mac.h | 3 +
drivers/net/wireless/ath/ath12k/wmi.c | 1 +
drivers/net/wireless/ath/ath12k/wmi.h | 1 +
5 files changed, 279 insertions(+)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 01768fe79bd6..e9bf87f740cd 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -606,6 +606,7 @@ struct ath12k {
bool monitor_vdev_created;
bool monitor_started;
int monitor_vdev_id;
+ s8 max_allowed_tx_power;
};
struct ath12k_band_cap {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0683b22137b0..35bd472267c1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5883,6 +5883,279 @@ static u8 ath12k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
return num_pwr_levels;
}
+static u16 ath12k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def)
+{
+ u16 diff_seq;
+
+ /* It is to get the lowest channel number's center frequency of the chan.
+ * For example,
+ * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1
+ * with center frequency 5955, its diff is 5965 - 5955 = 10.
+ * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1
+ * with center frequency 5955, its diff is 5985 - 5955 = 30.
+ * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1
+ * with center frequency 5955, its diff is 6025 - 5955 = 70.
+ */
+ switch (chan_def->width) {
+ case NL80211_CHAN_WIDTH_160:
+ diff_seq = 70;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ diff_seq = 30;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ diff_seq = 10;
+ break;
+ default:
+ diff_seq = 0;
+ }
+
+ return chan_def->center_freq1 - diff_seq;
+}
+
+static u16 ath12k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def,
+ u16 start_seq, u8 seq)
+{
+ u16 seg_seq;
+
+ /* It is to get the center frequency of the specific bandwidth.
+ * start_seq means the lowest channel number's center frequency.
+ * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz & 80P80.
+ * For example,
+ * lowest channel is 1, its center frequency 5955,
+ * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0.
+ * lowest channel is 1, its center frequency 5955,
+ * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10.
+ * lowest channel is 1, its center frequency 5955,
+ * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30.
+ * lowest channel is 1, its center frequency 5955,
+ * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70.
+ */
+ if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3)
+ return chan_def->center_freq2;
+
+ seg_seq = 10 * (BIT(seq) - 1);
+ return seg_seq + start_seq;
+}
+
+static void ath12k_mac_get_psd_channel(struct ath12k *ar,
+ u16 step_freq,
+ u16 *start_freq,
+ u16 *center_freq,
+ u8 i,
+ struct ieee80211_channel **temp_chan,
+ s8 *tx_power)
+{
+ /* It is to get the center frequency for each 20 MHz.
+ * For example, if the chan is 160 MHz and center frequency is 6025,
+ * then it include 8 channels, they are 1/5/9/13/17/21/25/29,
+ * channel number 1's center frequency is 5955, it is parameter start_freq.
+ * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels.
+ * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7,
+ * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095,
+ * the gap is 20 for each channel, parameter step_freq means the gap.
+ * after get the center frequency of each channel, it is easy to find the
+ * struct ieee80211_channel of it and get the max_reg_power.
+ */
+ *center_freq = *start_freq + i * step_freq;
+ *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
+ *tx_power = (*temp_chan)->max_reg_power;
+}
+
+static void ath12k_mac_get_eirp_power(struct ath12k *ar,
+ u16 *start_freq,
+ u16 *center_freq,
+ u8 i,
+ struct ieee80211_channel **temp_chan,
+ struct cfg80211_chan_def *def,
+ s8 *tx_power)
+{
+ /* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/
+ * 160 MHz & 80P80 bandwidth, and then plus 10 to the center frequency,
+ * it is the center frequency of a channel number.
+ * For example, when configured channel number is 1.
+ * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975,
+ * then it is channel number 5.
+ * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995,
+ * then it is channel number 9.
+ * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035,
+ * then it is channel number 17.
+ * after get the center frequency of each channel, it is easy to find the
+ * struct ieee80211_channel of it and get the max_reg_power.
+ */
+ *center_freq = ath12k_mac_get_seg_freq(def, *start_freq, i);
+ *center_freq += 10;
+ *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
+ *tx_power = (*temp_chan)->max_reg_power;
+}
+
+void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
+ struct ieee80211_vif *vif,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct ath12k_base *ab = ar->ab;
+ struct ath12k_vif *arvif = (void *)vif->drv_priv;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath12k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info;
+ struct ieee80211_channel *chan, *temp_chan;
+ u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
+ bool is_psd_power = false, is_tpe_present = false;
+ s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
+ psd_power, tx_power = 0, eirp_power = 0;
+ u16 start_freq = 0, center_freq = 0;
+
+ chan = ctx->def.chan;
+ start_freq = ath12k_mac_get_6ghz_start_frequency(&ctx->def);
+ pwr_reduction = bss_conf->pwr_reduction;
+
+ if (arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+ arvif->reg_tpc_info.num_pwr_levels) {
+ is_tpe_present = true;
+ num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels;
+ } else {
+ num_pwr_levels = ath12k_mac_get_num_pwr_levels(&ctx->def);
+ }
+
+ for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) {
+ /* STA received TPE IE*/
+ if (is_tpe_present) {
+ /* local power is PSD power*/
+ if (chan->flags & IEEE80211_CHAN_PSD) {
+ /* Connecting AP is psd power */
+ if (reg_tpc_info->is_psd_power) {
+ is_psd_power = true;
+ ath12k_mac_get_psd_channel(ar, 20,
+ &start_freq,
+ ¢er_freq,
+ pwr_lvl_idx,
+ &temp_chan,
+ &tx_power);
+ psd_power = temp_chan->psd;
+ eirp_power = tx_power;
+ max_tx_power[pwr_lvl_idx] =
+ min_t(s8,
+ psd_power,
+ reg_tpc_info->tpe[pwr_lvl_idx]);
+ /* Connecting AP is not psd power */
+ } else {
+ ath12k_mac_get_eirp_power(ar,
+ &start_freq,
+ ¢er_freq,
+ pwr_lvl_idx,
+ &temp_chan,
+ &ctx->def,
+ &tx_power);
+ psd_power = temp_chan->psd;
+ /* convert psd power to EIRP power based
+ * on channel width
+ */
+ tx_power =
+ min_t(s8, tx_power,
+ psd_power + 13 + pwr_lvl_idx * 3);
+ max_tx_power[pwr_lvl_idx] =
+ min_t(s8,
+ tx_power,
+ reg_tpc_info->tpe[pwr_lvl_idx]);
+ }
+ /* local power is not PSD power */
+ } else {
+ /* Connecting AP is psd power */
+ if (reg_tpc_info->is_psd_power) {
+ is_psd_power = true;
+ ath12k_mac_get_psd_channel(ar, 20,
+ &start_freq,
+ ¢er_freq,
+ pwr_lvl_idx,
+ &temp_chan,
+ &tx_power);
+ eirp_power = tx_power;
+ max_tx_power[pwr_lvl_idx] =
+ reg_tpc_info->tpe[pwr_lvl_idx];
+ /* Connecting AP is not psd power */
+ } else {
+ ath12k_mac_get_eirp_power(ar,
+ &start_freq,
+ ¢er_freq,
+ pwr_lvl_idx,
+ &temp_chan,
+ &ctx->def,
+ &tx_power);
+ max_tx_power[pwr_lvl_idx] =
+ min_t(s8,
+ tx_power,
+ reg_tpc_info->tpe[pwr_lvl_idx]);
+ }
+ }
+ /* STA not received TPE IE */
+ } else {
+ /* local power is PSD power*/
+ if (chan->flags & IEEE80211_CHAN_PSD) {
+ is_psd_power = true;
+ ath12k_mac_get_psd_channel(ar, 20,
+ &start_freq,
+ ¢er_freq,
+ pwr_lvl_idx,
+ &temp_chan,
+ &tx_power);
+ psd_power = temp_chan->psd;
+ eirp_power = tx_power;
+ max_tx_power[pwr_lvl_idx] = psd_power;
+ } else {
+ ath12k_mac_get_eirp_power(ar,
+ &start_freq,
+ ¢er_freq,
+ pwr_lvl_idx,
+ &temp_chan,
+ &ctx->def,
+ &tx_power);
+ max_tx_power[pwr_lvl_idx] = tx_power;
+ }
+ }
+
+ if (is_psd_power) {
+ /* If AP local power constraint is present */
+ if (pwr_reduction)
+ eirp_power = eirp_power - pwr_reduction;
+
+ /* If FW updated max tx power is non zero, then take the min of
+ * firmware updated ap tx power
+ * and max power derived from above mentioned parameters.
+ */
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
+ "eirp power : %d firmware report power : %d\n",
+ eirp_power, ar->max_allowed_tx_power);
+ if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
+ eirp_power = min_t(s8,
+ eirp_power,
+ ar->max_allowed_tx_power);
+ } else {
+ /* If AP local power constraint is present */
+ if (pwr_reduction)
+ max_tx_power[pwr_lvl_idx] =
+ max_tx_power[pwr_lvl_idx] - pwr_reduction;
+ /* If FW updated max tx power is non zero, then take the min of
+ * firmware updated ap tx power
+ * and max power derived from above mentioned parameters.
+ */
+ if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
+ max_tx_power[pwr_lvl_idx] =
+ min_t(s8,
+ max_tx_power[pwr_lvl_idx],
+ ar->max_allowed_tx_power);
+ }
+ reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq;
+ reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power =
+ max_tx_power[pwr_lvl_idx];
+ }
+
+ reg_tpc_info->num_pwr_levels = num_pwr_levels;
+ reg_tpc_info->is_psd_power = is_psd_power;
+ reg_tpc_info->eirp_power = eirp_power;
+ reg_tpc_info->power_type_6ghz =
+ ath12k_ieee80211_ap_pwr_type_convert(vif->bss_conf.power_type);
+}
+
static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
struct ieee80211_vif *vif,
struct ieee80211_chanctx_conf *ctx)
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 82f590004d05..ce2ce7f324d7 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -68,6 +68,9 @@ 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,
+ struct ieee80211_chanctx_conf *ctx);
void ath12k_mac_drain_tx(struct ath12k *ar);
void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 211bdb915173..5bfca2513730 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5588,6 +5588,7 @@ static void ath12k_vdev_start_resp_event(struct ath12k_base *ab, struct sk_buff
}
ar->last_wmi_vdev_start_status = 0;
+ ar->max_allowed_tx_power = le32_to_cpu(vdev_start_resp.max_allowed_tx_power);
status = le32_to_cpu(vdev_start_resp.status);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c3b110af1272..9f24f8ded52f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3796,6 +3796,7 @@ struct wmi_vdev_start_resp_event {
};
__le32 cfgd_tx_streams;
__le32 cfgd_rx_streams;
+ __le32 max_allowed_tx_power;
} __packed;
/* VDEV start response status codes */
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
2023-09-19 7:17 ` [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command Aishwarya R
@ 2023-09-19 20:09 ` Jeff Johnson
0 siblings, 0 replies; 17+ messages in thread
From: Jeff Johnson @ 2023-09-19 20:09 UTC (permalink / raw)
To: Aishwarya R, ath12k; +Cc: linux-wireless
On 9/19/2023 12:17 AM, Aishwarya R wrote:
> Prepare the parameters which is needed for wmi cmd
> vdev_set_tpc_power.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
> ---
> drivers/net/wireless/ath/ath12k/core.h | 1 +
> drivers/net/wireless/ath/ath12k/mac.c | 273 +++++++++++++++++++++++++
> drivers/net/wireless/ath/ath12k/mac.h | 3 +
> drivers/net/wireless/ath/ath12k/wmi.c | 1 +
> drivers/net/wireless/ath/ath12k/wmi.h | 1 +
> 5 files changed, 279 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 01768fe79bd6..e9bf87f740cd 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -606,6 +606,7 @@ struct ath12k {
> bool monitor_vdev_created;
> bool monitor_started;
> int monitor_vdev_id;
> + s8 max_allowed_tx_power;
> };
>
> struct ath12k_band_cap {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 0683b22137b0..35bd472267c1 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5883,6 +5883,279 @@ static u8 ath12k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
> return num_pwr_levels;
> }
>
> +static u16 ath12k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def)
> +{
> + u16 diff_seq;
> +
> + /* It is to get the lowest channel number's center frequency of the chan.
s/It is to //
also suggest any function documentation should appear before the
function, and if the function requires documentation, that kernel-doc
format be used
same guidance applies to the functions that follow
> + * For example,
> + * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1
> + * with center frequency 5955, its diff is 5965 - 5955 = 10.
> + * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1
> + * with center frequency 5955, its diff is 5985 - 5955 = 30.
> + * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1
> + * with center frequency 5955, its diff is 6025 - 5955 = 70.
> + */
> + switch (chan_def->width) {
> + case NL80211_CHAN_WIDTH_160:
> + diff_seq = 70;
> + break;
> + case NL80211_CHAN_WIDTH_80:
> + case NL80211_CHAN_WIDTH_80P80:
> + diff_seq = 30;
> + break;
> + case NL80211_CHAN_WIDTH_40:
> + diff_seq = 10;
> + break;
> + default:
> + diff_seq = 0;
> + }
> +
> + return chan_def->center_freq1 - diff_seq;
> +}
> +
> +static u16 ath12k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def,
> + u16 start_seq, u8 seq)
> +{
> + u16 seg_seq;
> +
> + /* It is to get the center frequency of the specific bandwidth.
> + * start_seq means the lowest channel number's center frequency.
> + * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz & 80P80.
> + * For example,
> + * lowest channel is 1, its center frequency 5955,
> + * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0.
> + * lowest channel is 1, its center frequency 5955,
> + * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10.
> + * lowest channel is 1, its center frequency 5955,
> + * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30.
> + * lowest channel is 1, its center frequency 5955,
> + * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70.
> + */
> + if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3)
> + return chan_def->center_freq2;
> +
> + seg_seq = 10 * (BIT(seq) - 1);
> + return seg_seq + start_seq;
> +}
> +
> +static void ath12k_mac_get_psd_channel(struct ath12k *ar,
> + u16 step_freq,
> + u16 *start_freq,
> + u16 *center_freq,
> + u8 i,
> + struct ieee80211_channel **temp_chan,
> + s8 *tx_power)
> +{
> + /* It is to get the center frequency for each 20 MHz.
> + * For example, if the chan is 160 MHz and center frequency is 6025,
> + * then it include 8 channels, they are 1/5/9/13/17/21/25/29,
> + * channel number 1's center frequency is 5955, it is parameter start_freq.
> + * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels.
> + * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7,
> + * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095,
> + * the gap is 20 for each channel, parameter step_freq means the gap.
> + * after get the center frequency of each channel, it is easy to find the
> + * struct ieee80211_channel of it and get the max_reg_power.
> + */
> + *center_freq = *start_freq + i * step_freq;
> + *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
> + *tx_power = (*temp_chan)->max_reg_power;
> +}
> +
> +static void ath12k_mac_get_eirp_power(struct ath12k *ar,
> + u16 *start_freq,
> + u16 *center_freq,
> + u8 i,
> + struct ieee80211_channel **temp_chan,
> + struct cfg80211_chan_def *def,
> + s8 *tx_power)
> +{
> + /* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/
> + * 160 MHz & 80P80 bandwidth, and then plus 10 to the center frequency,
> + * it is the center frequency of a channel number.
> + * For example, when configured channel number is 1.
> + * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975,
> + * then it is channel number 5.
> + * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995,
> + * then it is channel number 9.
> + * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035,
> + * then it is channel number 17.
> + * after get the center frequency of each channel, it is easy to find the
> + * struct ieee80211_channel of it and get the max_reg_power.
> + */
> + *center_freq = ath12k_mac_get_seg_freq(def, *start_freq, i);
> + *center_freq += 10;
> + *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
> + *tx_power = (*temp_chan)->max_reg_power;
> +}
> +
> +void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
> + struct ieee80211_vif *vif,
> + struct ieee80211_chanctx_conf *ctx)
> +{
> + struct ath12k_base *ab = ar->ab;
> + struct ath12k_vif *arvif = (void *)vif->drv_priv;
> + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
> + struct ath12k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info;
> + struct ieee80211_channel *chan, *temp_chan;
> + u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
> + bool is_psd_power = false, is_tpe_present = false;
> + s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
> + psd_power, tx_power = 0, eirp_power = 0;
> + u16 start_freq = 0, center_freq = 0;
> +
> + chan = ctx->def.chan;
> + start_freq = ath12k_mac_get_6ghz_start_frequency(&ctx->def);
> + pwr_reduction = bss_conf->pwr_reduction;
> +
> + if (arvif->vdev_type == WMI_VDEV_TYPE_STA &&
> + arvif->reg_tpc_info.num_pwr_levels) {
> + is_tpe_present = true;
> + num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels;
> + } else {
> + num_pwr_levels = ath12k_mac_get_num_pwr_levels(&ctx->def);
> + }
> +
> + for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) {
> + /* STA received TPE IE*/
> + if (is_tpe_present) {
> + /* local power is PSD power*/
> + if (chan->flags & IEEE80211_CHAN_PSD) {
> + /* Connecting AP is psd power */
> + if (reg_tpc_info->is_psd_power) {
> + is_psd_power = true;
> + ath12k_mac_get_psd_channel(ar, 20,
> + &start_freq,
> + ¢er_freq,
> + pwr_lvl_idx,
> + &temp_chan,
> + &tx_power);
> + psd_power = temp_chan->psd;
> + eirp_power = tx_power;
> + max_tx_power[pwr_lvl_idx] =
> + min_t(s8,
> + psd_power,
> + reg_tpc_info->tpe[pwr_lvl_idx]);
> + /* Connecting AP is not psd power */
> + } else {
> + ath12k_mac_get_eirp_power(ar,
> + &start_freq,
> + ¢er_freq,
> + pwr_lvl_idx,
> + &temp_chan,
> + &ctx->def,
> + &tx_power);
> + psd_power = temp_chan->psd;
> + /* convert psd power to EIRP power based
> + * on channel width
> + */
> + tx_power =
> + min_t(s8, tx_power,
> + psd_power + 13 + pwr_lvl_idx * 3);
> + max_tx_power[pwr_lvl_idx] =
> + min_t(s8,
> + tx_power,
> + reg_tpc_info->tpe[pwr_lvl_idx]);
> + }
bad brace placement?
> + /* local power is not PSD power */
> + } else {
> + /* Connecting AP is psd power */
> + if (reg_tpc_info->is_psd_power) {
> + is_psd_power = true;
> + ath12k_mac_get_psd_channel(ar, 20,
> + &start_freq,
> + ¢er_freq,
> + pwr_lvl_idx,
> + &temp_chan,
> + &tx_power);
> + eirp_power = tx_power;
> + max_tx_power[pwr_lvl_idx] =
> + reg_tpc_info->tpe[pwr_lvl_idx];
> + /* Connecting AP is not psd power */
> + } else {
> + ath12k_mac_get_eirp_power(ar,
> + &start_freq,
> + ¢er_freq,
> + pwr_lvl_idx,
> + &temp_chan,
> + &ctx->def,
> + &tx_power);
> + max_tx_power[pwr_lvl_idx] =
> + min_t(s8,
> + tx_power,
> + reg_tpc_info->tpe[pwr_lvl_idx]);
> + }
> + }
bad brace placement?
> + /* STA not received TPE IE */
> + } else {
> + /* local power is PSD power*/
> + if (chan->flags & IEEE80211_CHAN_PSD) {
> + is_psd_power = true;
> + ath12k_mac_get_psd_channel(ar, 20,
> + &start_freq,
> + ¢er_freq,
> + pwr_lvl_idx,
> + &temp_chan,
> + &tx_power);
> + psd_power = temp_chan->psd;
> + eirp_power = tx_power;
> + max_tx_power[pwr_lvl_idx] = psd_power;
> + } else {
> + ath12k_mac_get_eirp_power(ar,
> + &start_freq,
> + ¢er_freq,
> + pwr_lvl_idx,
> + &temp_chan,
> + &ctx->def,
> + &tx_power);
> + max_tx_power[pwr_lvl_idx] = tx_power;
> + }
> + }
> +
> + if (is_psd_power) {
> + /* If AP local power constraint is present */
> + if (pwr_reduction)
> + eirp_power = eirp_power - pwr_reduction;
> +
> + /* If FW updated max tx power is non zero, then take the min of
> + * firmware updated ap tx power
> + * and max power derived from above mentioned parameters.
> + */
> + ath12k_dbg(ab, ATH12K_DBG_MAC,
> + "eirp power : %d firmware report power : %d\n",
> + eirp_power, ar->max_allowed_tx_power);
> + if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
> + eirp_power = min_t(s8,
> + eirp_power,
> + ar->max_allowed_tx_power);
> + } else {
> + /* If AP local power constraint is present */
> + if (pwr_reduction)
> + max_tx_power[pwr_lvl_idx] =
> + max_tx_power[pwr_lvl_idx] - pwr_reduction;
> + /* If FW updated max tx power is non zero, then take the min of
> + * firmware updated ap tx power
> + * and max power derived from above mentioned parameters.
> + */
> + if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
> + max_tx_power[pwr_lvl_idx] =
> + min_t(s8,
> + max_tx_power[pwr_lvl_idx],
> + ar->max_allowed_tx_power);
> + }
> + reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq;
> + reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power =
> + max_tx_power[pwr_lvl_idx];
> + }
> +
> + reg_tpc_info->num_pwr_levels = num_pwr_levels;
> + reg_tpc_info->is_psd_power = is_psd_power;
> + reg_tpc_info->eirp_power = eirp_power;
> + reg_tpc_info->power_type_6ghz =
> + ath12k_ieee80211_ap_pwr_type_convert(vif->bss_conf.power_type);
> +}
> +
> static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
> struct ieee80211_vif *vif,
> struct ieee80211_chanctx_conf *ctx)
> diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
> index 82f590004d05..ce2ce7f324d7 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.h
> +++ b/drivers/net/wireless/ath/ath12k/mac.h
> @@ -68,6 +68,9 @@ 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,
> + struct ieee80211_chanctx_conf *ctx);
> void ath12k_mac_drain_tx(struct ath12k *ar);
> void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
> int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 211bdb915173..5bfca2513730 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -5588,6 +5588,7 @@ static void ath12k_vdev_start_resp_event(struct ath12k_base *ab, struct sk_buff
> }
>
> ar->last_wmi_vdev_start_status = 0;
> + ar->max_allowed_tx_power = le32_to_cpu(vdev_start_resp.max_allowed_tx_power);
>
> status = le32_to_cpu(vdev_start_resp.status);
>
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c3b110af1272..9f24f8ded52f 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -3796,6 +3796,7 @@ struct wmi_vdev_start_resp_event {
> };
> __le32 cfgd_tx_streams;
> __le32 cfgd_rx_streams;
> + __le32 max_allowed_tx_power;
> } __packed;
>
> /* VDEV start response status codes */
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
2023-09-19 7:17 [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes Aishwarya R
` (5 preceding siblings ...)
2023-09-19 7:17 ` [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command Aishwarya R
@ 2023-09-19 7:17 ` Aishwarya R
2023-09-19 20:21 ` Jeff Johnson
6 siblings, 1 reply; 17+ messages in thread
From: Aishwarya R @ 2023-09-19 7:17 UTC (permalink / raw)
To: ath12k; +Cc: linux-wireless, Aishwarya R
When STATION is connected to a 6 GHz AP, or when AP boots up, it has
2 ways to configure the power limit to firmware. Currently it
sends 2 wmi command WMI_PDEV_PARAM_TXPOWER_LIMIT2G/
WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware.
Add support to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which
include more parameters for power control. When firmware support
SERVICE_EXT_TPC_REG, it means firmware support this feature, then ath12k
discard BSS_CHANGED_TXPOWER flag from mac80211 which is used to the first
way for 6 GHz band.
The second way is to prepare the parameter for wmi command
WMI_VDEV_SET_TPC_POWER_CMDID and send the firmware after vdev start
response success from firmware.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 25 +++++++++-
drivers/net/wireless/ath/ath12k/wmi.c | 67 +++++++++++++++++++++++++++
drivers/net/wireless/ath/ath12k/wmi.h | 36 +++++++++++++-
3 files changed, 125 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 35bd472267c1..5505f933a4e1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2467,8 +2467,18 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev_id %i txpower %d\n",
arvif->vdev_id, info->txpower);
- arvif->txpower = info->txpower;
- ath12k_mac_txpower_recalc(ar);
+ if (ar->supports_6ghz && info->chandef.chan &&
+ info->chandef.chan->band == NL80211_BAND_6GHZ &&
+ (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+ arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
+ test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT,
+ ar->ab->wmi_ab.svc_map)) {
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+ "discard tx power, change to set TPC power\n");
+ } else {
+ arvif->txpower = info->txpower;
+ ath12k_mac_txpower_recalc(ar);
+ }
}
if (changed & BSS_CHANGED_MCAST_RATE &&
@@ -5519,6 +5529,16 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
return ret;
}
+ if (ar->supports_6ghz &&
+ chandef->chan->band == NL80211_BAND_6GHZ &&
+ (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+ arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
+ test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) {
+ ath12k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
+ ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
+ &arvif->reg_tpc_info);
+ }
+
ar->num_started_vdevs++;
ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n",
arvif->vif->addr, arvif->vdev_id);
@@ -6304,6 +6324,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
if (power_type == IEEE80211_REG_UNSET_AP)
power_type = IEEE80211_REG_LPI_AP;
+ arvif->chanctx = *ctx;
if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 5bfca2513730..582c7e80c76b 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2311,6 +2311,73 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
return ret;
}
+int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
+ u32 vdev_id,
+ struct ath12k_reg_tpc_power_info *param)
+{
+ struct ath12k_wmi_pdev *wmi = ar->wmi;
+ struct wmi_vdev_set_tpc_power_cmd *cmd;
+ struct wmi_vdev_ch_power_info_params *ch;
+ struct sk_buff *skb;
+ struct wmi_tlv *tlv;
+ u8 *ptr;
+ int i, ret, len;
+
+ len = sizeof(*cmd) + TLV_HDR_SIZE;
+ len += (sizeof(*ch) * param->num_pwr_levels);
+
+ skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
+ if (!skb)
+ return -ENOMEM;
+
+ ptr = skb->data;
+
+ cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr;
+ cmd->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
+ WMI_TAG_VDEV_SET_TPC_POWER_CMD) |
+ FIELD_PREP(WMI_TLV_LEN,
+ sizeof(*cmd) - TLV_HDR_SIZE));
+ cmd->vdev_id = cpu_to_le32(vdev_id);
+ cmd->psd_power = cpu_to_le32(param->is_psd_power);
+ cmd->eirp_power = cpu_to_le32(param->eirp_power);
+ cmd->power_type_6ghz = cpu_to_le32(param->power_type_6ghz);
+ ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+ "wmi TPC vdev_id: %d is_psd_power: %d eirp_power: %d power_type_6ghz: %d\n",
+ vdev_id, param->is_psd_power, param->eirp_power,
+ param->power_type_6ghz);
+
+ ptr += sizeof(*cmd);
+ tlv = (struct wmi_tlv *)ptr;
+ tlv->header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+ FIELD_PREP(WMI_TLV_LEN,
+ param->num_pwr_levels * sizeof(*ch)));
+
+ ptr += TLV_HDR_SIZE;
+ ch = (struct wmi_vdev_ch_power_info_params *)ptr;
+
+ for (i = 0; i < param->num_pwr_levels; i++, ch++) {
+ ch->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
+ WMI_TAG_VDEV_CH_POWER_INFO) |
+ FIELD_PREP(WMI_TLV_LEN,
+ sizeof(*ch) - TLV_HDR_SIZE));
+
+ ch->chan_cfreq = cpu_to_le32(param->chan_power_info[i].chan_cfreq);
+ ch->tx_power = cpu_to_le32(param->chan_power_info[i].tx_power);
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+ "wmi TPC chan_cfreq: %d , tx_power: %d\n",
+ ch->chan_cfreq, ch->tx_power);
+ }
+
+ ret = ath12k_wmi_cmd_send(wmi, skb,
+ WMI_VDEV_SET_TPC_POWER_CMDID);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
+ dev_kfree_skb(skb);
+ }
+ return ret;
+}
+
int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar,
struct ath12k_wmi_scan_cancel_arg *arg)
{
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 9f24f8ded52f..a97eb2544ab0 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -24,6 +24,7 @@
struct ath12k_base;
struct ath12k;
+struct ath12k_reg_tpc_power_info;
/* There is no signed version of __le32, so for a temporary solution come
* up with our own version. The idea is from fs/ntfs/endian.h.
@@ -388,6 +389,7 @@ enum wmi_tlv_cmd_id {
WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
+ WMI_VDEV_SET_TPC_POWER_CMDID,
WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
WMI_PEER_DELETE_CMDID,
WMI_PEER_FLUSH_TIDS_CMDID,
@@ -1924,6 +1926,8 @@ enum wmi_tlv_tag {
WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
+ WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
+ WMI_TAG_VDEV_CH_POWER_INFO,
WMI_TAG_MAX
};
@@ -2148,7 +2152,8 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
WMI_TLV_SERVICE_EXT2_MSG = 220,
- WMI_MAX_EXT_SERVICE
+ WMI_MAX_EXT_SERVICE,
+ WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280,
};
enum {
@@ -3037,6 +3042,32 @@ struct ath12k_wmi_element_info_arg {
u8 *ptr;
};
+struct wmi_vdev_ch_power_info_params {
+ __le32 tlv_header;
+ __le32 chan_cfreq; /* Channel center frequency (MHz) */
+ /* Unit: dBm, either PSD/EIRP power for this frequency or
+ * incremental for non-PSD BW
+ */
+ __le32 tx_power;
+} __packed;
+
+struct wmi_vdev_set_tpc_power_cmd {
+ __le32 tlv_header;
+ __le32 vdev_id;
+ __le32 psd_power; /* Value: 0 or 1, is PSD power or not */
+ __le32 eirp_power;
+ /* Maximum EIRP power (dBm units), valid only if power is PSD */
+ __le32 power_type_6ghz; /* Type: WMI_6 GHz_REG_TYPE, used for halphy CTL lookup */
+ /* This fixed_param TLV is followed by the below TLVs:
+ * num_pwr_levels of wmi_vdev_ch_power_info
+ * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks).
+ * For non-psd power, the power values are for 20, 40, and till
+ * BSS BW power levels.
+ * The num_pwr_levels will be checked by sw how many elements present
+ * in the variable-length array.
+ */
+} __packed;
+
#define WMI_IE_BITMAP_SIZE 8
#define WMI_SCAN_MAX_NUM_SSID 0x0A
@@ -4824,5 +4855,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
struct sk_buff *tmpl);
int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
enum wmi_host_hw_mode_config_type mode);
+int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
+ u32 vdev_id,
+ struct ath12k_reg_tpc_power_info *param);
#endif
--
2.17.1
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply related [flat|nested] 17+ messages in thread* Re: [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
2023-09-19 7:17 ` [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV Aishwarya R
@ 2023-09-19 20:21 ` Jeff Johnson
0 siblings, 0 replies; 17+ messages in thread
From: Jeff Johnson @ 2023-09-19 20:21 UTC (permalink / raw)
To: Aishwarya R, ath12k; +Cc: linux-wireless
On 9/19/2023 12:17 AM, Aishwarya R wrote:
> When STATION is connected to a 6 GHz AP, or when AP boots up, it has
what is "it"?
> 2 ways to configure the power limit to firmware. Currently it
> sends 2 wmi command WMI_PDEV_PARAM_TXPOWER_LIMIT2G/
> WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware.
>
> Add support to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which
> include more parameters for power control. When firmware support
> SERVICE_EXT_TPC_REG, it means firmware support this feature, then ath12k
> discard BSS_CHANGED_TXPOWER flag from mac80211 which is used to the first
> way for 6 GHz band.
I'm not parsing this last sentence. s I mentioned in a previous patch,
it will be easier to understand if you break it down:
what the current code does
what is wrong with the current code
how to fix the current code
>
> The second way is to prepare the parameter for wmi command
> WMI_VDEV_SET_TPC_POWER_CMDID and send the firmware after vdev start
> response success from firmware.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
> ---
> drivers/net/wireless/ath/ath12k/mac.c | 25 +++++++++-
> drivers/net/wireless/ath/ath12k/wmi.c | 67 +++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath12k/wmi.h | 36 +++++++++++++-
> 3 files changed, 125 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 35bd472267c1..5505f933a4e1 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -2467,8 +2467,18 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
> ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev_id %i txpower %d\n",
> arvif->vdev_id, info->txpower);
>
> - arvif->txpower = info->txpower;
> - ath12k_mac_txpower_recalc(ar);
> + if (ar->supports_6ghz && info->chandef.chan &&
> + info->chandef.chan->band == NL80211_BAND_6GHZ &&
> + (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> + arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
> + test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT,
> + ar->ab->wmi_ab.svc_map)) {
> + ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> + "discard tx power, change to set TPC power\n");
> + } else {
> + arvif->txpower = info->txpower;
> + ath12k_mac_txpower_recalc(ar);
> + }
> }
>
> if (changed & BSS_CHANGED_MCAST_RATE &&
> @@ -5519,6 +5529,16 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
> return ret;
> }
>
> + if (ar->supports_6ghz &&
> + chandef->chan->band == NL80211_BAND_6GHZ &&
> + (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> + arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
> + test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) {
this complex test occurs in two places. can it be refactored into a
well-named bool imperative function?
> + ath12k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
> + ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
> + &arvif->reg_tpc_info);
> + }
> +
> ar->num_started_vdevs++;
> ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n",
> arvif->vif->addr, arvif->vdev_id);
> @@ -6304,6 +6324,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
> if (power_type == IEEE80211_REG_UNSET_AP)
> power_type = IEEE80211_REG_LPI_AP;
>
> + arvif->chanctx = *ctx;
> if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
> ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
> }
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 5bfca2513730..582c7e80c76b 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2311,6 +2311,73 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
> return ret;
> }
>
> +int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
> + u32 vdev_id,
> + struct ath12k_reg_tpc_power_info *param)
> +{
> + struct ath12k_wmi_pdev *wmi = ar->wmi;
> + struct wmi_vdev_set_tpc_power_cmd *cmd;
> + struct wmi_vdev_ch_power_info_params *ch;
> + struct sk_buff *skb;
> + struct wmi_tlv *tlv;
> + u8 *ptr;
> + int i, ret, len;
> +
> + len = sizeof(*cmd) + TLV_HDR_SIZE;
> + len += (sizeof(*ch) * param->num_pwr_levels);
> +
> + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
> + if (!skb)
> + return -ENOMEM;
> +
> + ptr = skb->data;
> +
> + cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr;
> + cmd->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
> + WMI_TAG_VDEV_SET_TPC_POWER_CMD) |
> + FIELD_PREP(WMI_TLV_LEN,
> + sizeof(*cmd) - TLV_HDR_SIZE));
use ath12k_wmi_tlv_cmd_hdr() everywhere you are creating a TLV header
> + cmd->vdev_id = cpu_to_le32(vdev_id);
> + cmd->psd_power = cpu_to_le32(param->is_psd_power);
> + cmd->eirp_power = cpu_to_le32(param->eirp_power);
> + cmd->power_type_6ghz = cpu_to_le32(param->power_type_6ghz);
> + ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> + "wmi TPC vdev_id: %d is_psd_power: %d eirp_power: %d power_type_6ghz: %d\n",
> + vdev_id, param->is_psd_power, param->eirp_power,
> + param->power_type_6ghz);
> +
> + ptr += sizeof(*cmd);
> + tlv = (struct wmi_tlv *)ptr;
> + tlv->header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
> + FIELD_PREP(WMI_TLV_LEN,
> + param->num_pwr_levels * sizeof(*ch)));
> +
> + ptr += TLV_HDR_SIZE;
> + ch = (struct wmi_vdev_ch_power_info_params *)ptr;
> +
> + for (i = 0; i < param->num_pwr_levels; i++, ch++) {
> + ch->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
> + WMI_TAG_VDEV_CH_POWER_INFO) |
> + FIELD_PREP(WMI_TLV_LEN,
> + sizeof(*ch) - TLV_HDR_SIZE));
> +
> + ch->chan_cfreq = cpu_to_le32(param->chan_power_info[i].chan_cfreq);
> + ch->tx_power = cpu_to_le32(param->chan_power_info[i].tx_power);
> +
> + ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> + "wmi TPC chan_cfreq: %d , tx_power: %d\n",
> + ch->chan_cfreq, ch->tx_power);
> + }
> +
> + ret = ath12k_wmi_cmd_send(wmi, skb,
> + WMI_VDEV_SET_TPC_POWER_CMDID);
> + if (ret) {
> + ath12k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
> + dev_kfree_skb(skb);
> + }
> + return ret;
> +}
> +
> int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar,
> struct ath12k_wmi_scan_cancel_arg *arg)
> {
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 9f24f8ded52f..a97eb2544ab0 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -24,6 +24,7 @@
>
> struct ath12k_base;
> struct ath12k;
> +struct ath12k_reg_tpc_power_info;
>
> /* There is no signed version of __le32, so for a temporary solution come
> * up with our own version. The idea is from fs/ntfs/endian.h.
> @@ -388,6 +389,7 @@ enum wmi_tlv_cmd_id {
> WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
> WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
> WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
> + WMI_VDEV_SET_TPC_POWER_CMDID,
> WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
> WMI_PEER_DELETE_CMDID,
> WMI_PEER_FLUSH_TIDS_CMDID,
> @@ -1924,6 +1926,8 @@ enum wmi_tlv_tag {
> WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
> WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
> WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
> + WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
> + WMI_TAG_VDEV_CH_POWER_INFO,
> WMI_TAG_MAX
> };
>
> @@ -2148,7 +2152,8 @@ enum wmi_tlv_service {
> WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
> WMI_TLV_SERVICE_EXT2_MSG = 220,
>
> - WMI_MAX_EXT_SERVICE
> + WMI_MAX_EXT_SERVICE,
> + WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280,
> };
>
> enum {
> @@ -3037,6 +3042,32 @@ struct ath12k_wmi_element_info_arg {
> u8 *ptr;
> };
>
> +struct wmi_vdev_ch_power_info_params {
> + __le32 tlv_header;
> + __le32 chan_cfreq; /* Channel center frequency (MHz) */
> + /* Unit: dBm, either PSD/EIRP power for this frequency or
> + * incremental for non-PSD BW
> + */
> + __le32 tx_power;
> +} __packed;
> +
> +struct wmi_vdev_set_tpc_power_cmd {
> + __le32 tlv_header;
> + __le32 vdev_id;
> + __le32 psd_power; /* Value: 0 or 1, is PSD power or not */
> + __le32 eirp_power;
> + /* Maximum EIRP power (dBm units), valid only if power is PSD */
> + __le32 power_type_6ghz; /* Type: WMI_6 GHz_REG_TYPE, used for halphy CTL lookup */
> + /* This fixed_param TLV is followed by the below TLVs:
> + * num_pwr_levels of wmi_vdev_ch_power_info
> + * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks).
> + * For non-psd power, the power values are for 20, 40, and till
> + * BSS BW power levels.
> + * The num_pwr_levels will be checked by sw how many elements present
> + * in the variable-length array.
> + */
> +} __packed;
> +
> #define WMI_IE_BITMAP_SIZE 8
>
> #define WMI_SCAN_MAX_NUM_SSID 0x0A
> @@ -4824,5 +4855,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
> struct sk_buff *tmpl);
> int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
> enum wmi_host_hw_mode_config_type mode);
> +int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
> + u32 vdev_id,
> + struct ath12k_reg_tpc_power_info *param);
>
> #endif
--
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k
^ permalink raw reply [flat|nested] 17+ messages in thread