Skip to content

Commit

Permalink
wifi: ath11k: add parse of transmit power envelope element
Browse files Browse the repository at this point in the history
The transmit power envelope element has some fields for power, ath11k
should parse it according to IEEE Std 802.11ax™‐2021.

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23

Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20231218085844.2658-8-quic_bqiang@quicinc.com
  • Loading branch information
Wen Gong authored and Kalle Valo committed Jan 14, 2024
1 parent 28f64d3 commit 6f4e235
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 0 deletions.
39 changes: 39 additions & 0 deletions drivers/net/wireless/ath/ath11k/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,43 @@ struct ath11k_rekey_data {
bool enable_offload;
};

/**
* struct ath11k_chan_power_info - TPE containing power info per channel chunk
* @chan_cfreq: channel center freq (MHz)
* e.g.
* channel 37/20 MHz, it is 6135
* channel 37/40 MHz, it is 6125
* channel 37/80 MHz, it is 6145
* channel 37/160 MHz, it is 6185
* @tx_power: transmit power (dBm)
*/
struct ath11k_chan_power_info {
u16 chan_cfreq;
s8 tx_power;
};

/**
* struct ath11k_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
* @ap_power_type: 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 firmware
*/
struct ath11k_reg_tpc_power_info {
bool is_psd_power;
u8 eirp_power;
enum wmi_reg_6ghz_ap_type ap_power_type;
u8 num_pwr_levels;
u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL];
u8 ap_constraint_power;
s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL];
struct ath11k_chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL];
};

struct ath11k_vif {
u32 vdev_id;
enum wmi_vdev_type vdev_type;
Expand Down Expand Up @@ -369,6 +406,8 @@ struct ath11k_vif {
struct ath11k_arp_ns_offload arp_ns_offload;
struct ath11k_rekey_data rekey_data;

struct ath11k_reg_tpc_power_info reg_tpc_info;

#ifdef CONFIG_ATH11K_DEBUGFS
struct dentry *debugfs_twt;
#endif /* CONFIG_ATH11K_DEBUGFS */
Expand Down
188 changes: 188 additions & 0 deletions drivers/net/wireless/ath/ath11k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -7608,6 +7608,192 @@ 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)
{
if (chan_def->chan->flags & IEEE80211_CHAN_PSD) {
switch (chan_def->width) {
case NL80211_CHAN_WIDTH_20:
return 1;
case NL80211_CHAN_WIDTH_40:
return 2;
case NL80211_CHAN_WIDTH_80:
return 4;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
return 8;
default:
return 1;
}
} else {
switch (chan_def->width) {
case NL80211_CHAN_WIDTH_20:
return 1;
case NL80211_CHAN_WIDTH_40:
return 2;
case NL80211_CHAN_WIDTH_80:
return 3;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
return 4;
default:
return 1;
}
}
}

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_6ghz_client_type client_type;
struct cur_regulatory_info *reg_info;
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;

reg_info = &ab->reg_info_store[ar->pdev_idx];
client_type = reg_info->client_type;

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,
Expand Down Expand Up @@ -7642,6 +7828,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
}

ath11k_reg_handle_chan_list(ab, reg_info, power_type);

ath11k_mac_parse_tx_pwr_env(ar, vif, ctx);
}

/* for QCA6390 bss peer must be created before vdev_start */
Expand Down

0 comments on commit 6f4e235

Please sign in to comment.