Skip to content

Commit 6f4e235

Browse files
Wen Gongkvalo
authored andcommitted
wifi: 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. 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
1 parent 28f64d3 commit 6f4e235

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed

drivers/net/wireless/ath/ath11k/core.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,43 @@ struct ath11k_rekey_data {
314314
bool enable_offload;
315315
};
316316

317+
/**
318+
* struct ath11k_chan_power_info - TPE containing power info per channel chunk
319+
* @chan_cfreq: channel center freq (MHz)
320+
* e.g.
321+
* channel 37/20 MHz, it is 6135
322+
* channel 37/40 MHz, it is 6125
323+
* channel 37/80 MHz, it is 6145
324+
* channel 37/160 MHz, it is 6185
325+
* @tx_power: transmit power (dBm)
326+
*/
327+
struct ath11k_chan_power_info {
328+
u16 chan_cfreq;
329+
s8 tx_power;
330+
};
331+
332+
/**
333+
* struct ath11k_reg_tpc_power_info - regulatory TPC power info
334+
* @is_psd_power: is PSD power or not
335+
* @eirp_power: Maximum EIRP power (dBm), valid only if power is PSD
336+
* @ap_power_type: type of power (SP/LPI/VLP)
337+
* @num_pwr_levels: number of power levels
338+
* @reg_max: Array of maximum TX power (dBm) per PSD value
339+
* @ap_constraint_power: AP constraint power (dBm)
340+
* @tpe: TPE values processed from TPE IE
341+
* @chan_power_info: power info to send to firmware
342+
*/
343+
struct ath11k_reg_tpc_power_info {
344+
bool is_psd_power;
345+
u8 eirp_power;
346+
enum wmi_reg_6ghz_ap_type ap_power_type;
347+
u8 num_pwr_levels;
348+
u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL];
349+
u8 ap_constraint_power;
350+
s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL];
351+
struct ath11k_chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL];
352+
};
353+
317354
struct ath11k_vif {
318355
u32 vdev_id;
319356
enum wmi_vdev_type vdev_type;
@@ -369,6 +406,8 @@ struct ath11k_vif {
369406
struct ath11k_arp_ns_offload arp_ns_offload;
370407
struct ath11k_rekey_data rekey_data;
371408

409+
struct ath11k_reg_tpc_power_info reg_tpc_info;
410+
372411
#ifdef CONFIG_ATH11K_DEBUGFS
373412
struct dentry *debugfs_twt;
374413
#endif /* CONFIG_ATH11K_DEBUGFS */

drivers/net/wireless/ath/ath11k/mac.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7608,6 +7608,192 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
76087608
return 0;
76097609
}
76107610

7611+
static u8 ath11k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt)
7612+
{
7613+
switch (txpwr_intrprt) {
7614+
/* Refer "Table 9-276-Meaning of Maximum Transmit Power Count subfield
7615+
* if the Maximum Transmit Power Interpretation subfield is 0 or 2" of
7616+
* "IEEE Std 802.11ax 2021".
7617+
*/
7618+
case IEEE80211_TPE_LOCAL_EIRP:
7619+
case IEEE80211_TPE_REG_CLIENT_EIRP:
7620+
txpwr_cnt = txpwr_cnt <= 3 ? txpwr_cnt : 3;
7621+
txpwr_cnt = txpwr_cnt + 1;
7622+
break;
7623+
/* Refer "Table 9-277-Meaning of Maximum Transmit Power Count subfield
7624+
* if Maximum Transmit Power Interpretation subfield is 1 or 3" of
7625+
* "IEEE Std 802.11ax 2021".
7626+
*/
7627+
case IEEE80211_TPE_LOCAL_EIRP_PSD:
7628+
case IEEE80211_TPE_REG_CLIENT_EIRP_PSD:
7629+
txpwr_cnt = txpwr_cnt <= 4 ? txpwr_cnt : 4;
7630+
txpwr_cnt = txpwr_cnt ? (BIT(txpwr_cnt - 1)) : 1;
7631+
break;
7632+
}
7633+
7634+
return txpwr_cnt;
7635+
}
7636+
7637+
static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
7638+
{
7639+
if (chan_def->chan->flags & IEEE80211_CHAN_PSD) {
7640+
switch (chan_def->width) {
7641+
case NL80211_CHAN_WIDTH_20:
7642+
return 1;
7643+
case NL80211_CHAN_WIDTH_40:
7644+
return 2;
7645+
case NL80211_CHAN_WIDTH_80:
7646+
return 4;
7647+
case NL80211_CHAN_WIDTH_80P80:
7648+
case NL80211_CHAN_WIDTH_160:
7649+
return 8;
7650+
default:
7651+
return 1;
7652+
}
7653+
} else {
7654+
switch (chan_def->width) {
7655+
case NL80211_CHAN_WIDTH_20:
7656+
return 1;
7657+
case NL80211_CHAN_WIDTH_40:
7658+
return 2;
7659+
case NL80211_CHAN_WIDTH_80:
7660+
return 3;
7661+
case NL80211_CHAN_WIDTH_80P80:
7662+
case NL80211_CHAN_WIDTH_160:
7663+
return 4;
7664+
default:
7665+
return 1;
7666+
}
7667+
}
7668+
}
7669+
7670+
static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar,
7671+
struct ieee80211_vif *vif,
7672+
struct ieee80211_chanctx_conf *ctx)
7673+
{
7674+
struct ath11k_base *ab = ar->ab;
7675+
struct ath11k_vif *arvif = (void *)vif->drv_priv;
7676+
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
7677+
struct ieee80211_tx_pwr_env *single_tpe;
7678+
enum wmi_reg_6ghz_client_type client_type;
7679+
struct cur_regulatory_info *reg_info;
7680+
int i;
7681+
u8 pwr_count, pwr_interpret, pwr_category;
7682+
u8 psd_index = 0, non_psd_index = 0, local_tpe_count = 0, reg_tpe_count = 0;
7683+
bool use_local_tpe, non_psd_set = false, psd_set = false;
7684+
7685+
reg_info = &ab->reg_info_store[ar->pdev_idx];
7686+
client_type = reg_info->client_type;
7687+
7688+
for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
7689+
single_tpe = &bss_conf->tx_pwr_env[i];
7690+
pwr_category = u8_get_bits(single_tpe->tx_power_info,
7691+
IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
7692+
pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
7693+
IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
7694+
7695+
if (pwr_category == client_type) {
7696+
if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP ||
7697+
pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD)
7698+
local_tpe_count++;
7699+
else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP ||
7700+
pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD)
7701+
reg_tpe_count++;
7702+
}
7703+
}
7704+
7705+
if (!reg_tpe_count && !local_tpe_count) {
7706+
ath11k_warn(ab,
7707+
"no transmit power envelope match client power type %d\n",
7708+
client_type);
7709+
return;
7710+
} else if (!reg_tpe_count) {
7711+
use_local_tpe = true;
7712+
} else {
7713+
use_local_tpe = false;
7714+
}
7715+
7716+
for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
7717+
single_tpe = &bss_conf->tx_pwr_env[i];
7718+
pwr_category = u8_get_bits(single_tpe->tx_power_info,
7719+
IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
7720+
pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
7721+
IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
7722+
7723+
if (pwr_category != client_type)
7724+
continue;
7725+
7726+
/* get local transmit power envelope */
7727+
if (use_local_tpe) {
7728+
if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP) {
7729+
non_psd_index = i;
7730+
non_psd_set = true;
7731+
} else if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) {
7732+
psd_index = i;
7733+
psd_set = true;
7734+
}
7735+
/* get regulatory transmit power envelope */
7736+
} else {
7737+
if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP) {
7738+
non_psd_index = i;
7739+
non_psd_set = true;
7740+
} else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) {
7741+
psd_index = i;
7742+
psd_set = true;
7743+
}
7744+
}
7745+
}
7746+
7747+
if (non_psd_set && !psd_set) {
7748+
single_tpe = &bss_conf->tx_pwr_env[non_psd_index];
7749+
pwr_count = u8_get_bits(single_tpe->tx_power_info,
7750+
IEEE80211_TX_PWR_ENV_INFO_COUNT);
7751+
pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
7752+
IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
7753+
arvif->reg_tpc_info.is_psd_power = false;
7754+
arvif->reg_tpc_info.eirp_power = 0;
7755+
7756+
arvif->reg_tpc_info.num_pwr_levels =
7757+
ath11k_mac_get_tpe_count(pwr_interpret, pwr_count);
7758+
7759+
for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
7760+
ath11k_dbg(ab, ATH11K_DBG_MAC,
7761+
"non PSD power[%d] : %d\n",
7762+
i, single_tpe->tx_power[i]);
7763+
arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
7764+
}
7765+
}
7766+
7767+
if (psd_set) {
7768+
single_tpe = &bss_conf->tx_pwr_env[psd_index];
7769+
pwr_count = u8_get_bits(single_tpe->tx_power_info,
7770+
IEEE80211_TX_PWR_ENV_INFO_COUNT);
7771+
pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
7772+
IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
7773+
arvif->reg_tpc_info.is_psd_power = true;
7774+
7775+
if (pwr_count == 0) {
7776+
ath11k_dbg(ab, ATH11K_DBG_MAC,
7777+
"TPE PSD power : %d\n", single_tpe->tx_power[0]);
7778+
arvif->reg_tpc_info.num_pwr_levels =
7779+
ath11k_mac_get_num_pwr_levels(&ctx->def);
7780+
7781+
for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++)
7782+
arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[0] / 2;
7783+
} else {
7784+
arvif->reg_tpc_info.num_pwr_levels =
7785+
ath11k_mac_get_tpe_count(pwr_interpret, pwr_count);
7786+
7787+
for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
7788+
ath11k_dbg(ab, ATH11K_DBG_MAC,
7789+
"TPE PSD power[%d] : %d\n",
7790+
i, single_tpe->tx_power[i]);
7791+
arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
7792+
}
7793+
}
7794+
}
7795+
}
7796+
76117797
static int
76127798
ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
76137799
struct ieee80211_vif *vif,
@@ -7642,6 +7828,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
76427828
}
76437829

76447830
ath11k_reg_handle_chan_list(ab, reg_info, power_type);
7831+
7832+
ath11k_mac_parse_tx_pwr_env(ar, vif, ctx);
76457833
}
76467834

76477835
/* for QCA6390 bss peer must be created before vdev_start */

0 commit comments

Comments
 (0)