mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-24 04:42:20 +00:00
290 lines
8.9 KiB
Diff
290 lines
8.9 KiB
Diff
From dcf0ca8823813e47867ac0bf32c0907b9abc9f39 Mon Sep 17 00:00:00 2001
|
||
From: Wen Gong <quic_wgong@quicinc.com>
|
||
Date: Wed, 20 Oct 2021 15:03:25 +0530
|
||
Subject: [PATCH] ath11k: add parse of transmit power envelope element
|
||
|
||
The transmit power envelope element has some fields for power,
|
||
ath11k should parse it according to IEEE Std 802.11ax™‐2021.
|
||
This patch is to do it.
|
||
|
||
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
|
||
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
|
||
---
|
||
drivers/net/wireless/ath/ath11k/core.h | 38 +++++++
|
||
drivers/net/wireless/ath/ath11k/mac.c | 196 +++++++++++++++++++++++++++++++++
|
||
2 files changed, 234 insertions(+)
|
||
|
||
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
|
||
index 7bb27ef..47f885f 100644
|
||
--- a/drivers/net/wireless/ath/ath11k/core.h
|
||
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
||
@@ -246,6 +246,43 @@ struct ath11k_mac_filter {
|
||
u8 peer_mac[ETH_ALEN];
|
||
};
|
||
|
||
+/**
|
||
+ * 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_6g: 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 ath11k_reg_tpc_power_info {
|
||
+ bool is_psd_power;
|
||
+ u8 eirp_power;
|
||
+ enum wmi_reg_6g_ap_type power_type_6g;
|
||
+ 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 ath11k_vif {
|
||
u32 vdev_id;
|
||
enum wmi_vdev_type vdev_type;
|
||
@@ -298,6 +335,7 @@ struct ath11k_vif {
|
||
bool do_not_send_tmpl;
|
||
u32 vht_cap;
|
||
struct ieee80211_chanctx_conf chanctx;
|
||
+ struct ath11k_reg_tpc_power_info reg_tpc_info;
|
||
struct dentry *debugfs_twt;
|
||
struct ath11k_mgmt_frame_stats mgmt_stats;
|
||
/* protected by conf_mutex */
|
||
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
|
||
index 3ef2615..2894b50 100644
|
||
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||
@@ -7805,6 +7805,199 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
|
||
return 0;
|
||
}
|
||
|
||
+static u8 ath11k_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 ath11k_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 ath11k_mac_parse_tx_pwr_env(struct ath11k *ar,
|
||
+ struct ieee80211_vif *vif,
|
||
+ struct ieee80211_chanctx_conf *ctx)
|
||
+{
|
||
+ struct ath11k_base *ab = ar->ab;
|
||
+ struct ath11k_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) {
|
||
+ ath11k_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 =
|
||
+ ath11k_mac_get_tpe_count(pwr_interpret, pwr_count);
|
||
+ for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
|
||
+ ath11k_dbg(ab, ATH11K_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) {
|
||
+ ath11k_dbg(ab, ATH11K_DBG_MAC,
|
||
+ "TPE PSD power : %d\n", single_tpe->tx_power[0]);
|
||
+ arvif->reg_tpc_info.num_pwr_levels =
|
||
+ ath11k_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 =
|
||
+ ath11k_mac_get_tpe_count(pwr_interpret, pwr_count);
|
||
+ for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
|
||
+ ath11k_dbg(ab, ATH11K_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
|
||
ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
|
||
struct ieee80211_vif *vif,
|
||
@@ -7831,6 +8024,9 @@ ath11k_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)
|
||
+ ath11k_mac_parse_tx_pwr_env(ar, vif, ctx);
|
||
}
|
||
|
||
/* for QCA6390 bss peer must be created before vdev_start */
|
||
--
|
||
2.7.4
|
||
|