ath11k: report tx bitrate for iw wlan station dump

HTT_T2H_MSG_TYPE_PPDU_STATS_IND is a message which include the ppdu
info, currently it is not report from firmware for ath11k, then the
tx bitrate of "iw wlan0 station dump" always show an invalid value
"tx bitrate: 6.0 MBit/s".

To address the issue, this is to parse the info of tx complete report
from firmware and indicate the tx rate to mac80211.

After that, "iw wlan0 station dump" show the correct tx bit rate such
as:
tx bitrate: 78.0 MBit/s MCS 12
tx bitrate: 144.4 MBit/s VHT-MCS 7 short GI VHT-NSS 2
tx bitrate: 286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0
tx bitrate: 1921.5 MBit/s 160MHz HE-MCS 9 HE-NSS 2 HE-GI 0 HE-DCM 0

Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1

Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20211217093722.5739-1-quic_wgong@quicinc.com
This commit is contained in:
Wen Gong 2021-12-20 18:11:09 +02:00 committed by Kalle Valo
parent 6ce708f54c
commit 1b8bb94c06
10 changed files with 210 additions and 133 deletions

View File

@ -382,6 +382,7 @@ struct ath11k_sta {
struct work_struct update_wk;
struct work_struct set_4addr_wk;
struct rate_info txrate;
u32 peer_nss;
struct rate_info last_txrate;
u64 rx_duration;
u64 tx_duration;

View File

@ -126,85 +126,9 @@ void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
}
void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
struct sk_buff *msdu,
struct hal_tx_status *ts)
{
struct ath11k_base *ab = ar->ab;
struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
enum hal_tx_rate_stats_pkt_type pkt_type;
enum hal_tx_rate_stats_sgi sgi;
enum hal_tx_rate_stats_bw bw;
struct ath11k_peer *peer;
struct ath11k_sta *arsta;
struct ieee80211_sta *sta;
u16 rate;
u8 rate_idx = 0;
int ret;
u8 mcs;
rcu_read_lock();
spin_lock_bh(&ab->base_lock);
peer = ath11k_peer_find_by_id(ab, ts->peer_id);
if (!peer || !peer->sta) {
ath11k_warn(ab, "failed to find the peer\n");
spin_unlock_bh(&ab->base_lock);
rcu_read_unlock();
return;
}
sta = peer->sta;
arsta = (struct ath11k_sta *)sta->drv_priv;
memset(&arsta->txrate, 0, sizeof(arsta->txrate));
pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
ts->rate_stats);
mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
ts->rate_stats);
sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
ts->rate_stats);
bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);
if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
pkt_type,
&rate_idx,
&rate);
if (ret < 0)
goto err_out;
arsta->txrate.legacy = rate;
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
if (mcs > 7) {
ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);
goto err_out;
}
arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1);
arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
if (sgi)
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
if (mcs > 9) {
ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);
goto err_out;
}
arsta->txrate.mcs = mcs;
arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
if (sgi)
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
/* TODO */
}
arsta->txrate.nss = arsta->last_txrate.nss;
arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
err_out:
spin_unlock_bh(&ab->base_lock);
rcu_read_unlock();
ath11k_dp_tx_update_txcompl(ar, ts);
}
static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,

View File

@ -19,7 +19,6 @@ void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
struct ath11k_per_peer_tx_stats *peer_stats,
u8 legacy_rate_idx);
void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
struct sk_buff *msdu,
struct hal_tx_status *ts);
#else /* CONFIG_ATH11K_DEBUGFS */
@ -34,7 +33,6 @@ ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
}
static inline void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
struct sk_buff *msdu,
struct hal_tx_status *ts)
{
}

View File

@ -1360,25 +1360,6 @@ int ath11k_dp_htt_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len,
return 0;
}
static inline u32 ath11k_he_gi_to_nl80211_he_gi(u8 sgi)
{
u32 ret = 0;
switch (sgi) {
case RX_MSDU_START_SGI_0_8_US:
ret = NL80211_RATE_INFO_HE_GI_0_8;
break;
case RX_MSDU_START_SGI_1_6_US:
ret = NL80211_RATE_INFO_HE_GI_1_6;
break;
case RX_MSDU_START_SGI_3_2_US:
ret = NL80211_RATE_INFO_HE_GI_3_2;
break;
}
return ret;
}
static void
ath11k_update_per_peer_tx_stats(struct ath11k *ar,
struct htt_ppdu_stats *ppdu_stats, u8 user)
@ -1497,14 +1478,15 @@ ath11k_update_per_peer_tx_stats(struct ath11k *ar,
arsta->txrate.mcs = mcs;
arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
arsta->txrate.he_dcm = dcm;
arsta->txrate.he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi);
arsta->txrate.he_ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(
(user_rate->ru_end -
arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi);
arsta->txrate.he_ru_alloc = ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc
((user_rate->ru_end -
user_rate->ru_start) + 1);
break;
}
arsta->txrate.nss = nss;
arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
arsta->tx_duration += tx_duration;
memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info));
@ -2384,7 +2366,7 @@ static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
}
rx_status->encoding = RX_ENC_HE;
rx_status->nss = nss;
rx_status->he_gi = ath11k_he_gi_to_nl80211_he_gi(sgi);
rx_status->he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi);
rx_status->bw = ath11k_mac_bw_to_mac80211_bw(bw);
break;
}

View File

@ -415,6 +415,105 @@ static void ath11k_dp_tx_cache_peer_stats(struct ath11k *ar,
}
}
void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts)
{
struct ath11k_base *ab = ar->ab;
struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
enum hal_tx_rate_stats_pkt_type pkt_type;
enum hal_tx_rate_stats_sgi sgi;
enum hal_tx_rate_stats_bw bw;
struct ath11k_peer *peer;
struct ath11k_sta *arsta;
struct ieee80211_sta *sta;
u16 rate, ru_tones;
u8 mcs, rate_idx, ofdma;
int ret;
spin_lock_bh(&ab->base_lock);
peer = ath11k_peer_find_by_id(ab, ts->peer_id);
if (!peer || !peer->sta) {
ath11k_dbg(ab, ATH11K_DBG_DP_TX,
"failed to find the peer by id %u\n", ts->peer_id);
goto err_out;
}
sta = peer->sta;
arsta = (struct ath11k_sta *)sta->drv_priv;
memset(&arsta->txrate, 0, sizeof(arsta->txrate));
pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
ts->rate_stats);
mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
ts->rate_stats);
sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
ts->rate_stats);
bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);
ru_tones = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU, ts->rate_stats);
ofdma = FIELD_GET(HAL_TX_RATE_STATS_INFO0_OFDMA_TX, ts->rate_stats);
/* This is to prefer choose the real NSS value arsta->last_txrate.nss,
* if it is invalid, then choose the NSS value while assoc.
*/
if (arsta->last_txrate.nss)
arsta->txrate.nss = arsta->last_txrate.nss;
else
arsta->txrate.nss = arsta->peer_nss;
if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
pkt_type,
&rate_idx,
&rate);
if (ret < 0)
goto err_out;
arsta->txrate.legacy = rate;
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
if (mcs > 7) {
ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);
goto err_out;
}
if (arsta->txrate.nss != 0)
arsta->txrate.mcs = mcs + 8 * (arsta->txrate.nss - 1);
arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
if (sgi)
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
if (mcs > 9) {
ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);
goto err_out;
}
arsta->txrate.mcs = mcs;
arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
if (sgi)
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
if (mcs > 11) {
ath11k_warn(ab, "Invalid HE mcs index %d\n", mcs);
goto err_out;
}
arsta->txrate.mcs = mcs;
arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi);
}
arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
if (ofdma && pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
arsta->txrate.bw = RATE_INFO_BW_HE_RU;
arsta->txrate.he_ru_alloc =
ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);
}
if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
err_out:
spin_unlock_bh(&ab->base_lock);
}
static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
struct sk_buff *msdu,
struct hal_tx_status *ts)
@ -460,7 +559,8 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar))) {
if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar)) ||
ab->hw_params.single_pdev_only) {
if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) {
if (ar->last_ppdu_id == 0) {
ar->last_ppdu_id = ts->ppdu_id;
@ -468,12 +568,12 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
ar->cached_ppdu_id == ar->last_ppdu_id) {
ar->cached_ppdu_id = ar->last_ppdu_id;
ar->cached_stats.is_ampdu = true;
ath11k_debugfs_sta_update_txcompl(ar, msdu, ts);
ath11k_dp_tx_update_txcompl(ar, ts);
memset(&ar->cached_stats, 0,
sizeof(struct ath11k_per_peer_tx_stats));
} else {
ar->cached_stats.is_ampdu = false;
ath11k_debugfs_sta_update_txcompl(ar, msdu, ts);
ath11k_dp_tx_update_txcompl(ar, ts);
memset(&ar->cached_stats, 0,
sizeof(struct ath11k_per_peer_tx_stats));
}

View File

@ -15,6 +15,7 @@ struct ath11k_dp_htt_wbm_tx_status {
int ack_rssi;
};
void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts);
int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab);
int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
struct ath11k_sta *arsta, struct sk_buff *skb);

View File

@ -1038,7 +1038,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab,
ru_tones = FIELD_GET(HAL_RX_HE_SIG_B1_MU_INFO_INFO0_RU_ALLOCATION,
info0);
ppdu_info->ru_alloc = ath11k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);
ppdu_info->ru_alloc =
ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(ru_tones);
ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
break;
}

View File

@ -363,33 +363,6 @@ ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab,
struct hal_rx_mon_ppdu_info *ppdu_info,
struct sk_buff *skb);
static inline u32 ath11k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones)
{
u32 ret = 0;
switch (ru_tones) {
case RU_26:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_26;
break;
case RU_52:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_52;
break;
case RU_106:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_106;
break;
case RU_242:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_242;
break;
case RU_484:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_484;
break;
case RU_996:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_996;
break;
}
return ret;
}
#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0 0xDDBEEF
#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1 0xADBEEF
#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2 0xBDBEEF

View File

@ -246,6 +246,93 @@ static const u32 ath11k_smps_map[] = {
static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy)
{
enum nl80211_he_ru_alloc ret;
switch (ru_phy) {
case RU_26:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_26;
break;
case RU_52:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_52;
break;
case RU_106:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_106;
break;
case RU_242:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_242;
break;
case RU_484:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_484;
break;
case RU_996:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_996;
break;
default:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_26;
break;
}
return ret;
}
enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones)
{
enum nl80211_he_ru_alloc ret;
switch (ru_tones) {
case 26:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_26;
break;
case 52:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_52;
break;
case 106:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_106;
break;
case 242:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_242;
break;
case 484:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_484;
break;
case 996:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_996;
break;
case (996 * 2):
ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
break;
default:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_26;
break;
}
return ret;
}
enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi)
{
enum nl80211_he_gi ret;
switch (sgi) {
case RX_MSDU_START_SGI_0_8_US:
ret = NL80211_RATE_INFO_HE_GI_0_8;
break;
case RX_MSDU_START_SGI_1_6_US:
ret = NL80211_RATE_INFO_HE_GI_1_6;
break;
case RX_MSDU_START_SGI_3_2_US:
ret = NL80211_RATE_INFO_HE_GI_3_2;
break;
default:
ret = NL80211_RATE_INFO_HE_GI_0_8;
break;
}
return ret;
}
u8 ath11k_mac_bw_to_mac80211_bw(u8 bw)
{
u8 ret = 0;
@ -2541,8 +2628,12 @@ static void ath11k_peer_assoc_prepare(struct ath11k *ar,
struct peer_assoc_params *arg,
bool reassoc)
{
struct ath11k_sta *arsta;
lockdep_assert_held(&ar->conf_mutex);
arsta = (struct ath11k_sta *)sta->drv_priv;
memset(arg, 0, sizeof(*arg));
reinit_completion(&ar->peer_assoc_done);
@ -2559,6 +2650,8 @@ static void ath11k_peer_assoc_prepare(struct ath11k *ar,
ath11k_peer_assoc_h_qos(ar, vif, sta, arg);
ath11k_peer_assoc_h_smps(sta, arg);
arsta->peer_nss = arg->peer_nss;
/* TODO: amsdu_disable req? */
}

View File

@ -162,6 +162,9 @@ void ath11k_mac_drain_tx(struct ath11k *ar);
void ath11k_mac_peer_cleanup_all(struct ath11k *ar);
int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
u8 ath11k_mac_bw_to_mac80211_bw(u8 bw);
u32 ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi);
enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy);
enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones);
enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw);
enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher);
void ath11k_mac_handle_beacon(struct ath11k *ar, struct sk_buff *skb);