All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes
@ 2023-09-19  7:17 ` Aishwarya R
  0 siblings, 0 replies; 34+ messages in thread
From: Aishwarya R @ 2023-09-19  7:17 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Aishwarya R

Add support for 6 GHz for various modes. Supports various power type of
AP(STANDARD_POWER_AP, INDOOR_AP, VERY_LOW_POWER_AP), power type of
STATION(DEFAULT_CLIENT, SUBORDINATE_CLIENT) and Power Spectral Density(PSD).

Implement the new rules for 6 GHz band in ath12k.
ath12k parse the transmit power envelope element in beacon of AP
and then set new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID to firmware
when connect to 6 GHz AP, also support backward compatibility with
firmware which not support new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID.

Aishwarya R (7):
  wifi: ath12k: add support to select 6 GHz Regulatory type
  wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
  wifi: ath12k: get 6 GHz power type from HE operation element
  wifi: ath12k: save power spectral density(PSD) of regulatory rule
  wifi: ath12k: add parse of transmit power envelope element
  wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
  wifi: ath12k: send TPC power to firmware for 6 GHz VDEV

 drivers/net/wireless/ath/ath12k/core.h |  39 ++
 drivers/net/wireless/ath/ath12k/mac.c  | 515 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   4 +
 drivers/net/wireless/ath/ath12k/reg.c  |  79 +++-
 drivers/net/wireless/ath/ath12k/reg.h  |   6 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 320 +++++++++++++--
 drivers/net/wireless/ath/ath12k/wmi.h  |  94 ++++-
 7 files changed, 1003 insertions(+), 54 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes
@ 2023-09-19  7:17 ` Aishwarya R
  0 siblings, 0 replies; 34+ messages in thread
From: Aishwarya R @ 2023-09-19  7:17 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Aishwarya R

Add support for 6 GHz for various modes. Supports various power type of
AP(STANDARD_POWER_AP, INDOOR_AP, VERY_LOW_POWER_AP), power type of
STATION(DEFAULT_CLIENT, SUBORDINATE_CLIENT) and Power Spectral Density(PSD).

Implement the new rules for 6 GHz band in ath12k.
ath12k parse the transmit power envelope element in beacon of AP
and then set new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID to firmware
when connect to 6 GHz AP, also support backward compatibility with
firmware which not support new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID.

Aishwarya R (7):
  wifi: ath12k: add support to select 6 GHz Regulatory type
  wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
  wifi: ath12k: get 6 GHz power type from HE operation element
  wifi: ath12k: save power spectral density(PSD) of regulatory rule
  wifi: ath12k: add parse of transmit power envelope element
  wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
  wifi: ath12k: send TPC power to firmware for 6 GHz VDEV

 drivers/net/wireless/ath/ath12k/core.h |  39 ++
 drivers/net/wireless/ath/ath12k/mac.c  | 515 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   4 +
 drivers/net/wireless/ath/ath12k/reg.c  |  79 +++-
 drivers/net/wireless/ath/ath12k/reg.h  |   6 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 320 +++++++++++++--
 drivers/net/wireless/ath/ath12k/wmi.h  |  94 ++++-
 7 files changed, 1003 insertions(+), 54 deletions(-)

-- 
2.17.1


-- 
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
  2023-09-19  7:17 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
@ 2023-09-19  7:17   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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] 34+ 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 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply related	[flat|nested] 34+ 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   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
  2023-09-19  7:17 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
@ 2023-09-19  7:17   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH 4/7] wifi: ath12k: save power spectral density(PSD) of regulatory rule
  2023-09-19  7:17 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 4/7] wifi: ath12k: save power spectral density(PSD) of regulatory rule
@ 2023-09-19  7:17   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH 5/7] wifi: ath12k: add parse of transmit power envelope element
  2023-09-19  7:17 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 5/7] wifi: ath12k: add parse of transmit power envelope element
@ 2023-09-19  7:17   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
  2023-09-19  7:17 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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,
+								   &center_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,
+								  &center_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,
+								   &center_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,
+								  &center_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,
+							   &center_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,
+							  &center_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


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
@ 2023-09-19  7:17   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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,
+								   &center_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,
+								  &center_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,
+								   &center_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,
+								  &center_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,
+							   &center_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,
+							  &center_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] 34+ messages in thread

* [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
  2023-09-19  7:17 ` Aishwarya R
@ 2023-09-19  7:17   ` Aishwarya R
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
@ 2023-09-19  7:17   ` Aishwarya R
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
  2023-09-19  7:17   ` Aishwarya R
@ 2023-09-19 17:47     ` Jeff Johnson
  -1 siblings, 0 replies; 34+ 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 {


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
@ 2023-09-19 17:47     ` Jeff Johnson
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
  2023-09-19  7:17   ` Aishwarya R
@ 2023-09-19 19:57     ` Jeff Johnson
  -1 siblings, 0 replies; 34+ messages in thread
From: Jeff Johnson @ 2023-09-19 19:57 UTC (permalink / raw)
  To: Aishwarya R, ath12k; +Cc: linux-wireless

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> 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.

what is "it"?

> 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.

Again what is "it"?

I'm having trouble discerning what is existing behavior and what is new 
behavior.

That distinction should be clear.  In the past the following template 
has been suggested:
   " Current code does (A), this has a problem when (B).
     We can improve this doing (C), because (D)."
<http://www.spinics.net/lists/kernel/msg1633438.html>

Obviously that exact format isn't required, but you should at least 
describe, if it isn't obvious:
1) what does the current code do
2) what is wrong with that code
3) what should be done to the code to fix the issue

I don't actually have an code patch comments


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
@ 2023-09-19 19:57     ` Jeff Johnson
  0 siblings, 0 replies; 34+ messages in thread
From: Jeff Johnson @ 2023-09-19 19:57 UTC (permalink / raw)
  To: Aishwarya R, ath12k; +Cc: linux-wireless

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> 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.

what is "it"?

> 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.

Again what is "it"?

I'm having trouble discerning what is existing behavior and what is new 
behavior.

That distinction should be clear.  In the past the following template 
has been suggested:
   " Current code does (A), this has a problem when (B).
     We can improve this doing (C), because (D)."
<http://www.spinics.net/lists/kernel/msg1633438.html>

Obviously that exact format isn't required, but you should at least 
describe, if it isn't obvious:
1) what does the current code do
2) what is wrong with that code
3) what should be done to the code to fix the issue

I don't actually have an code patch comments


-- 
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
  2023-09-19  7:17   ` Aishwarya R
@ 2023-09-19 19:59     ` Jeff Johnson
  -1 siblings, 0 replies; 34+ 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 &&


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
@ 2023-09-19 19:59     ` Jeff Johnson
  0 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
  2023-09-19  7:17   ` Aishwarya R
@ 2023-09-19 20:09     ` Jeff Johnson
  -1 siblings, 0 replies; 34+ 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,
> +								   &center_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,
> +								  &center_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,
> +								   &center_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,
> +								  &center_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,
> +							   &center_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,
> +							  &center_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 */


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
@ 2023-09-19 20:09     ` Jeff Johnson
  0 siblings, 0 replies; 34+ 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,
> +								   &center_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,
> +								  &center_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,
> +								   &center_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,
> +								  &center_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,
> +							   &center_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,
> +							  &center_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] 34+ messages in thread

* Re: [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
  2023-09-19  7:17   ` Aishwarya R
@ 2023-09-19 20:21     ` Jeff Johnson
  -1 siblings, 0 replies; 34+ 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


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
@ 2023-09-19 20:21     ` Jeff Johnson
  0 siblings, 0 replies; 34+ 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] 34+ 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
  -1 siblings, 0 replies; 34+ 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

[...]


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
@ 2023-09-20  2:10       ` Wen Gong
  0 siblings, 0 replies; 34+ 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] 34+ 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  5:48       ` Aishwarya R (QUIC)
  -1 siblings, 0 replies; 34+ messages in thread
From: Aishwarya R (QUIC) @ 2023-09-20  5:48 UTC (permalink / raw)
  To: Jeff Johnson (QUIC), ath12k; +Cc: linux-wireless, 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 

^ permalink raw reply	[flat|nested] 34+ messages in thread

* RE: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
@ 2023-09-20  5:48       ` Aishwarya R (QUIC)
  0 siblings, 0 replies; 34+ messages in thread
From: Aishwarya R (QUIC) @ 2023-09-20  5:48 UTC (permalink / raw)
  To: Jeff Johnson (QUIC), ath12k; +Cc: linux-wireless, 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] 34+ messages in thread

* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
  2023-09-20  5:48       ` Aishwarya R (QUIC)
@ 2023-09-20 13:34         ` Kalle Valo
  -1 siblings, 0 replies; 34+ messages in thread
From: Kalle Valo @ 2023-09-20 13:34 UTC (permalink / raw)
  To: Aishwarya R (QUIC)
  Cc: Jeff Johnson (QUIC), ath12k, linux-wireless, Wen Gong (QUIC)

"Aishwarya R (QUIC)" <quic_aisr@quicinc.com> writes:

[deleting ~500 lines of unnecessary quotes]

> Thanks for your review. I will address all your comments in next revision.

Please edit your quotes and only include the necessary information in
your reply. These kind of huge mails make use of patchwork very
difficult:

https://patchwork.kernel.org/project/linux-wireless/patch/20230919071724.15505-2-quic_aisr@quicinc.com/

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

-- 
ath12k mailing list
ath12k@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/ath12k

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
@ 2023-09-20 13:34         ` Kalle Valo
  0 siblings, 0 replies; 34+ messages in thread
From: Kalle Valo @ 2023-09-20 13:34 UTC (permalink / raw)
  To: Aishwarya R (QUIC)
  Cc: Jeff Johnson (QUIC), ath12k, linux-wireless, Wen Gong (QUIC)

"Aishwarya R (QUIC)" <quic_aisr@quicinc.com> writes:

[deleting ~500 lines of unnecessary quotes]

> Thanks for your review. I will address all your comments in next revision.

Please edit your quotes and only include the necessary information in
your reply. These kind of huge mails make use of patchwork very
difficult:

https://patchwork.kernel.org/project/linux-wireless/patch/20230919071724.15505-2-quic_aisr@quicinc.com/

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 34+ 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
  -1 siblings, 0 replies; 34+ 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] 34+ messages in thread

* Re: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
@ 2023-09-20 18:09         ` Jeff Johnson
  0 siblings, 0 replies; 34+ 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


^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2023-09-20 18:09 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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  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 17:47   ` Jeff Johnson
2023-09-19 17:47     ` Jeff Johnson
2023-09-20  2:10     ` Wen Gong
2023-09-20  2:10       ` Wen Gong
2023-09-20 18:09       ` Jeff Johnson
2023-09-20 18:09         ` Jeff Johnson
2023-09-20  5:48     ` Aishwarya R (QUIC)
2023-09-20  5:48       ` Aishwarya R (QUIC)
2023-09-20 13:34       ` Kalle Valo
2023-09-20 13:34         ` Kalle Valo
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:57   ` Jeff Johnson
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
2023-09-19  7:17   ` Aishwarya R
2023-09-19 19:59   ` Jeff Johnson
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
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
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   ` Aishwarya R
2023-09-19 20:09   ` Jeff Johnson
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
2023-09-19  7:17   ` Aishwarya R
2023-09-19 20:21   ` Jeff Johnson
2023-09-19 20:21     ` Jeff Johnson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.