ath10k: report tx rate using ieee80211_tx_rate_update()
Mesh path metric needs tx rate information from ieee80211_tx_status() call but in ath10k there is no mechanism to report tx rate information via ieee80211_tx_status(), the tx rate is only accessible via sta_statiscs() op. Per peer tx stats has tx rate info available, Tx rate is available to ath10k driver after every 4 PPDU sent in the air. For each PPDU, ath10k driver updates rate informattion to mac80211 using ieee80211_tx_rate_update(). Per peer txrate information is updated through per peer statistics and is available for QCA9888/QCA9984/QCA4019/QCA998X only Tested on QCA9984 with firmware-5.bin_10.4-3.5.3-00053 Tested on QCA998X with firmware-5.bin_10.2.4-1.0-00036 Signed-off-by: Anilkumar Kolli <akolli@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
85bd0107c6
commit
9a9cf0e63f
|
@ -494,6 +494,7 @@ struct ath10k_sta {
|
|||
u32 smps;
|
||||
u16 peer_id;
|
||||
struct rate_info txrate;
|
||||
struct ieee80211_tx_info tx_info;
|
||||
|
||||
struct work_struct update_wk;
|
||||
u64 rx_duration;
|
||||
|
|
|
@ -2811,7 +2811,7 @@ void ath10k_htt_htc_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
|||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
static inline int ath10k_get_legacy_rate_idx(struct ath10k *ar, u8 rate)
|
||||
static inline s8 ath10k_get_legacy_rate_idx(struct ath10k *ar, u8 rate)
|
||||
{
|
||||
static const u8 legacy_rates[] = {1, 2, 5, 11, 6, 9, 12,
|
||||
18, 24, 36, 48, 54};
|
||||
|
@ -2830,7 +2830,7 @@ static void
|
|||
ath10k_accumulate_per_peer_tx_stats(struct ath10k *ar,
|
||||
struct ath10k_sta *arsta,
|
||||
struct ath10k_per_peer_tx_stats *pstats,
|
||||
u8 legacy_rate_idx)
|
||||
s8 legacy_rate_idx)
|
||||
{
|
||||
struct rate_info *txrate = &arsta->txrate;
|
||||
struct ath10k_htt_tx_stats *tx_stats;
|
||||
|
@ -2950,8 +2950,10 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
|
|||
struct ath10k_per_peer_tx_stats *peer_stats)
|
||||
{
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ieee80211_chanctx_conf *conf = NULL;
|
||||
u8 rate = 0, sgi;
|
||||
s8 rate_idx = 0;
|
||||
bool skip_auto_rate;
|
||||
struct rate_info txrate;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
@ -2961,6 +2963,13 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
|
|||
txrate.nss = ATH10K_HW_NSS(peer_stats->ratecode);
|
||||
txrate.mcs = ATH10K_HW_MCS_RATE(peer_stats->ratecode);
|
||||
sgi = ATH10K_HW_GI(peer_stats->flags);
|
||||
skip_auto_rate = ATH10K_FW_SKIPPED_RATE_CTRL(peer_stats->flags);
|
||||
|
||||
/* Firmware's rate control skips broadcast/management frames,
|
||||
* if host has configure fixed rates and in some other special cases.
|
||||
*/
|
||||
if (skip_auto_rate)
|
||||
return;
|
||||
|
||||
if (txrate.flags == WMI_RATE_PREAMBLE_VHT && txrate.mcs > 9) {
|
||||
ath10k_warn(ar, "Invalid VHT mcs %hhd peer stats", txrate.mcs);
|
||||
|
@ -2975,7 +2984,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
|
|||
}
|
||||
|
||||
memset(&arsta->txrate, 0, sizeof(arsta->txrate));
|
||||
|
||||
memset(&arsta->tx_info.status, 0, sizeof(arsta->tx_info.status));
|
||||
if (txrate.flags == WMI_RATE_PREAMBLE_CCK ||
|
||||
txrate.flags == WMI_RATE_PREAMBLE_OFDM) {
|
||||
rate = ATH10K_HW_LEGACY_RATE(peer_stats->ratecode);
|
||||
|
@ -2994,11 +3003,59 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar,
|
|||
arsta->txrate.mcs = txrate.mcs;
|
||||
}
|
||||
|
||||
if (sgi)
|
||||
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
switch (txrate.flags) {
|
||||
case WMI_RATE_PREAMBLE_OFDM:
|
||||
if (arsta->arvif && arsta->arvif->vif)
|
||||
conf = rcu_dereference(arsta->arvif->vif->chanctx_conf);
|
||||
if (conf && conf->def.chan->band == NL80211_BAND_5GHZ)
|
||||
arsta->tx_info.status.rates[0].idx = rate_idx - 4;
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_CCK:
|
||||
arsta->tx_info.status.rates[0].idx = rate_idx;
|
||||
if (sgi)
|
||||
arsta->tx_info.status.rates[0].flags |=
|
||||
(IEEE80211_TX_RC_USE_SHORT_PREAMBLE |
|
||||
IEEE80211_TX_RC_SHORT_GI);
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_HT:
|
||||
arsta->tx_info.status.rates[0].idx =
|
||||
txrate.mcs + ((txrate.nss - 1) * 8);
|
||||
if (sgi)
|
||||
arsta->tx_info.status.rates[0].flags |=
|
||||
IEEE80211_TX_RC_SHORT_GI;
|
||||
arsta->tx_info.status.rates[0].flags |= IEEE80211_TX_RC_MCS;
|
||||
break;
|
||||
case WMI_RATE_PREAMBLE_VHT:
|
||||
ieee80211_rate_set_vht(&arsta->tx_info.status.rates[0],
|
||||
txrate.mcs, txrate.nss);
|
||||
if (sgi)
|
||||
arsta->tx_info.status.rates[0].flags |=
|
||||
IEEE80211_TX_RC_SHORT_GI;
|
||||
arsta->tx_info.status.rates[0].flags |= IEEE80211_TX_RC_VHT_MCS;
|
||||
break;
|
||||
}
|
||||
|
||||
arsta->txrate.nss = txrate.nss;
|
||||
arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw);
|
||||
if (sgi)
|
||||
arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
|
||||
|
||||
switch (arsta->txrate.bw) {
|
||||
case RATE_INFO_BW_40:
|
||||
arsta->tx_info.status.rates[0].flags |=
|
||||
IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||
break;
|
||||
case RATE_INFO_BW_80:
|
||||
arsta->tx_info.status.rates[0].flags |=
|
||||
IEEE80211_TX_RC_80_MHZ_WIDTH;
|
||||
break;
|
||||
}
|
||||
|
||||
if (peer_stats->succ_pkts) {
|
||||
arsta->tx_info.flags = IEEE80211_TX_STAT_ACK;
|
||||
arsta->tx_info.status.rates[0].count = 1;
|
||||
ieee80211_tx_rate_update(ar->hw, sta, &arsta->tx_info);
|
||||
}
|
||||
|
||||
if (ath10k_debug_is_extd_tx_stats_enabled(ar))
|
||||
ath10k_accumulate_per_peer_tx_stats(ar, arsta, peer_stats,
|
||||
|
|
|
@ -4984,6 +4984,7 @@ enum wmi_rate_preamble {
|
|||
(((preamble) << 6) | ((nss) << 4) | (rate))
|
||||
#define ATH10K_HW_AMPDU(flags) ((flags) & 0x1)
|
||||
#define ATH10K_HW_BA_FAIL(flags) (((flags) >> 1) & 0x3)
|
||||
#define ATH10K_FW_SKIPPED_RATE_CTRL(flags) (((flags) >> 6) & 0x1)
|
||||
|
||||
#define ATH10K_VHT_MCS_NUM 10
|
||||
#define ATH10K_BW_NUM 4
|
||||
|
|
Loading…
Reference in New Issue