mac80211: minstrel_ht: support ieee80211_rate_status

This patch adds support for the new struct ieee80211_rate_status and its
annotation in struct ieee80211_tx_status in minstrel_ht.

In minstrel_ht_tx_status, a check for the presence of instances of the
new struct in ieee80211_tx_status is added. Based on this, minstrel_ht
then gets and updates internal rate stats with either struct
ieee80211_rate_status or ieee80211_tx_info->status.rates.
Adjusted variants of minstrel_ht_txstat_valid, minstrel_ht_get_stats,
minstrel_{ht/vht}_get_group_idx are added which use struct
ieee80211_rate_status and struct rate_info instead of the legacy structs.

struct rate_info from cfg80211.h does not provide whether short preamble
was used for the transmission. So we retrieve this information from VIF
and STA configuration and cache it in a new flag in struct minstrel_ht_sta
per rate control instance.

Compile-Tested: current wireless-next tree with all flags on
Tested-on: Xiaomi 4A Gigabit (MediaTek MT7603E, MT7612E) with OpenWrt
                Linux 5.10.113

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Link: https://lore.kernel.org/r/20220509173958.1398201-3-jelonek.jonas@gmail.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Jonas Jelonek 2022-05-09 19:39:58 +02:00 коммит произвёл Johannes Berg
Родитель 44fa75f207
Коммит 569cf386ec
2 изменённых файлов: 133 добавлений и 9 удалений

Просмотреть файл

@ -333,6 +333,17 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
!!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
} }
/*
* Look up an MCS group index based on new cfg80211 rate_info.
*/
static int
minstrel_ht_ri_get_group_idx(struct rate_info *rate)
{
return GROUP_IDX((rate->mcs / 8) + 1,
!!(rate->flags & RATE_INFO_FLAGS_SHORT_GI),
!!(rate->bw & RATE_INFO_BW_40));
}
static int static int
minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate) minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate)
{ {
@ -342,6 +353,18 @@ minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate)
2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)); 2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH));
} }
/*
* Look up an MCS group index based on new cfg80211 rate_info.
*/
static int
minstrel_vht_ri_get_group_idx(struct rate_info *rate)
{
return VHT_GROUP_IDX(rate->nss,
!!(rate->flags & RATE_INFO_FLAGS_SHORT_GI),
!!(rate->bw & RATE_INFO_BW_40) +
2*!!(rate->bw & RATE_INFO_BW_80));
}
static struct minstrel_rate_stats * static struct minstrel_rate_stats *
minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
struct ieee80211_tx_rate *rate) struct ieee80211_tx_rate *rate)
@ -385,6 +408,50 @@ out:
return &mi->groups[group].rates[idx]; return &mi->groups[group].rates[idx];
} }
/*
* Get the minstrel rate statistics for specified STA and rate info.
*/
static struct minstrel_rate_stats *
minstrel_ht_ri_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
struct ieee80211_rate_status *rate_status)
{
int group, idx;
struct rate_info *rate = &rate_status->rate_idx;
if (rate->flags & RATE_INFO_FLAGS_MCS) {
group = minstrel_ht_ri_get_group_idx(rate);
idx = rate->mcs % 8;
goto out;
}
if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) {
group = minstrel_vht_ri_get_group_idx(rate);
idx = rate->mcs;
goto out;
}
group = MINSTREL_CCK_GROUP;
for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) {
if (rate->legacy != minstrel_cck_bitrates[ mp->cck_rates[idx] ])
continue;
/* short preamble */
if ((mi->supported[group] & BIT(idx + 4)) &&
mi->use_short_preamble)
idx += 4;
goto out;
}
group = MINSTREL_OFDM_GROUP;
for (idx = 0; idx < ARRAY_SIZE(mp->ofdm_rates[0]); idx++)
if (rate->legacy == minstrel_ofdm_bitrates[ mp->ofdm_rates[mi->band][idx] ])
goto out;
idx = 0;
out:
return &mi->groups[group].rates[idx];
}
static inline struct minstrel_rate_stats * static inline struct minstrel_rate_stats *
minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
{ {
@ -1152,6 +1219,40 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
return false; return false;
} }
/*
* Check whether rate_status contains valid information.
*/
static bool
minstrel_ht_ri_txstat_valid(struct minstrel_priv *mp,
struct minstrel_ht_sta *mi,
struct ieee80211_rate_status *rate_status)
{
int i;
if (!rate_status)
return false;
if (!rate_status->try_count)
return false;
if (rate_status->rate_idx.flags & RATE_INFO_FLAGS_MCS ||
rate_status->rate_idx.flags & RATE_INFO_FLAGS_VHT_MCS)
return true;
for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++) {
if (rate_status->rate_idx.legacy ==
minstrel_cck_bitrates[ mp->cck_rates[i] ])
return true;
}
for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates); i++) {
if (rate_status->rate_idx.legacy ==
minstrel_ofdm_bitrates[ mp->ofdm_rates[mi->band][i] ])
return true;
}
return false;
}
static void static void
minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
{ {
@ -1217,16 +1318,34 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
mi->ampdu_packets++; mi->ampdu_packets++;
mi->ampdu_len += info->status.ampdu_len; mi->ampdu_len += info->status.ampdu_len;
last = !minstrel_ht_txstat_valid(mp, mi, &ar[0]); if (st->rates && st->n_rates) {
for (i = 0; !last; i++) { last = !minstrel_ht_ri_txstat_valid(mp, mi, &(st->rates[0]));
last = (i == IEEE80211_TX_MAX_RATES - 1) || for (i = 0; !last; i++) {
!minstrel_ht_txstat_valid(mp, mi, &ar[i + 1]); last = (i == st->n_rates - 1) ||
!minstrel_ht_ri_txstat_valid(mp, mi,
&(st->rates[i + 1]));
rate = minstrel_ht_get_stats(mp, mi, &ar[i]); rate = minstrel_ht_ri_get_stats(mp, mi,
if (last) &(st->rates[i]));
rate->success += info->status.ampdu_ack_len;
rate->attempts += ar[i].count * info->status.ampdu_len; if (last)
rate->success += info->status.ampdu_ack_len;
rate->attempts += st->rates[i].try_count *
info->status.ampdu_len;
}
} else {
last = !minstrel_ht_txstat_valid(mp, mi, &ar[0]);
for (i = 0; !last; i++) {
last = (i == IEEE80211_TX_MAX_RATES - 1) ||
!minstrel_ht_txstat_valid(mp, mi, &ar[i + 1]);
rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
if (last)
rate->success += info->status.ampdu_ack_len;
rate->attempts += ar[i].count * info->status.ampdu_len;
}
} }
if (mp->hw->max_rates > 1) { if (mp->hw->max_rates > 1) {
@ -1583,6 +1702,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
u16 ht_cap = sta->deflink.ht_cap.cap; u16 ht_cap = sta->deflink.ht_cap.cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
const struct ieee80211_rate *ctl_rate; const struct ieee80211_rate *ctl_rate;
struct sta_info *sta_info;
bool ldpc, erp; bool ldpc, erp;
int use_vht; int use_vht;
int n_supported = 0; int n_supported = 0;
@ -1701,6 +1821,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
n_supported++; n_supported++;
} }
sta_info = container_of(sta, struct sta_info, sta);
mi->use_short_preamble = test_sta_flag(sta_info, WLAN_STA_SHORT_PREAMBLE) &&
sta_info->sdata->vif.bss_conf.use_short_preamble;
minstrel_ht_update_cck(mp, mi, sband, sta); minstrel_ht_update_cck(mp, mi, sband, sta);
minstrel_ht_update_ofdm(mp, mi, sband, sta); minstrel_ht_update_ofdm(mp, mi, sband, sta);

Просмотреть файл

@ -180,7 +180,7 @@ struct minstrel_ht_sta {
/* tx flags to add for frames for this sta */ /* tx flags to add for frames for this sta */
u32 tx_flags; u32 tx_flags;
bool use_short_preamble;
u8 band; u8 band;
u8 sample_seq; u8 sample_seq;