mt76: mt76x02: fix tx status reporting issues

When the hardware falls back to lower rates for a transmit attempt, only the
first status report will show the number of retries correctly. The frames
that follow will report the correct final rate, but number of retries set to 0.
This can cause the rate control module to vastly underestimate the number of
retransmissions per rate.

To fix this, we need to keep track of the initial requested tx rate per packet
and pass it to the status information.
For frames with tx status requested, this is simple: use the rate configured
in info->control.rates[0] as reference.
For no-skb tx status information, we have to encode the requested tx rate in
the packet id (and make it possible to distinguish it from real packet ids).

To do that, reduce the packet id field size by one bit, and use that bit to
indicate packet id vs rate.

This change also improves reporting by filling the status rate array with
rates from first rate to final rate, taking the same steps as the hardware
fallback table. This matters in corner cases like MCS8 on HT, where the
fallback target is MCS0, not MCS7.

Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Felix Fietkau
2019-06-05 21:03:59 +02:00
parent 77d0e3378b
commit f575da2f01
4 changed files with 97 additions and 16 deletions
+75 -13
View File
@@ -419,31 +419,87 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
}
EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
static void
mt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy)
{
u8 mcs, nss;
if (!idx)
return;
rates += idx - 1;
rates[1] = rates[0];
switch (phy) {
case MT_PHY_TYPE_VHT:
mcs = ieee80211_rate_get_vht_mcs(rates);
nss = ieee80211_rate_get_vht_nss(rates);
if (mcs == 0)
nss = max_t(int, nss - 1, 1);
else
mcs--;
ieee80211_rate_set_vht(rates + 1, mcs, nss);
break;
case MT_PHY_TYPE_HT_GF:
case MT_PHY_TYPE_HT:
/* MCS 8 falls back to MCS 0 */
if (rates[0].idx == 8) {
rates[1].idx = 0;
break;
}
/* fall through */
default:
rates[1].idx = max_t(int, rates[0].idx - 1, 0);
break;
}
}
static void
mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev,
struct ieee80211_tx_info *info,
struct mt76x02_tx_status *st, int n_frames)
{
struct ieee80211_tx_rate *rate = info->status.rates;
int cur_idx, last_rate;
struct ieee80211_tx_rate last_rate;
u16 first_rate;
int retry = st->retry;
int phy;
int i;
if (!n_frames)
return;
last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate,
dev->mt76.chandef.chan->band);
if (last_rate < IEEE80211_TX_MAX_RATES - 1)
rate[last_rate + 1].idx = -1;
phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
cur_idx = rate[last_rate].idx + last_rate;
for (i = 0; i <= last_rate; i++) {
rate[i].flags = rate[last_rate].flags;
rate[i].idx = max_t(int, 0, cur_idx - i);
rate[i].count = 1;
if (st->pktid & MT_PACKET_ID_HAS_RATE) {
first_rate = st->rate & ~MT_RXWI_RATE_INDEX;
first_rate |= st->pktid & MT_RXWI_RATE_INDEX;
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
dev->mt76.chandef.chan->band);
}
mt76x02_mac_process_tx_rate(&last_rate, st->rate,
dev->mt76.chandef.chan->band);
for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
retry--;
if (i + 1 == ARRAY_SIZE(info->status.rates)) {
info->status.rates[i] = last_rate;
info->status.rates[i].count = max_t(int, retry, 1);
break;
}
mt76x02_tx_rate_fallback(info->status.rates, i, phy);
if (info->status.rates[i].idx == last_rate.idx)
break;
}
if (i + 1 < ARRAY_SIZE(info->status.rates)) {
info->status.rates[i + 1].idx = -1;
info->status.rates[i + 1].count = 0;
}
rate[last_rate].count = st->retry + 1 - last_rate;
info->status.ampdu_len = n_frames;
info->status.ampdu_ack_len = st->success ? n_frames : 0;
@@ -489,13 +545,19 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
mt76_tx_status_lock(mdev, &list);
if (wcid) {
if (stat->pktid >= MT_PACKET_ID_FIRST)
if (mt76_is_skb_pktid(stat->pktid))
status.skb = mt76_tx_status_skb_get(mdev, wcid,
stat->pktid, &list);
if (status.skb)
status.info = IEEE80211_SKB_CB(status.skb);
}
if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
mt76_tx_status_unlock(mdev, &list);
rcu_read_unlock();
return;
}
if (msta && stat->aggr && !status.skb) {
u32 stat_val, stat_cache;