]> git.baikalelectronics.ru Git - kernel.git/commitdiff
mt76: mt76x02: fix tx status reporting issues
authorFelix Fietkau <nbd@nbd.name>
Wed, 5 Jun 2019 18:50:52 +0000 (20:50 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 27 Jun 2019 10:58:13 +0000 (12:58 +0200)
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 <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c

index fc4169c83e764c1c55f8199d1b03d9392d037cd3..907bec9d5e4c13c58570bf1a026d65d201eaaa3f 100644 (file)
@@ -258,10 +258,11 @@ struct mt76_rx_tid {
 #define MT_TX_CB_TXS_DONE              BIT(1)
 #define MT_TX_CB_TXS_FAILED            BIT(2)
 
-#define MT_PACKET_ID_MASK              GENMASK(7, 0)
+#define MT_PACKET_ID_MASK              GENMASK(6, 0)
 #define MT_PACKET_ID_NO_ACK            0
 #define MT_PACKET_ID_NO_SKB            1
 #define MT_PACKET_ID_FIRST             2
+#define MT_PACKET_ID_HAS_RATE          BIT(7)
 
 #define MT_TX_STATUS_SKB_TIMEOUT       HZ
 
@@ -689,6 +690,14 @@ static inline void mt76_insert_hdr_pad(struct sk_buff *skb)
        skb->data[len + 1] = 0;
 }
 
+static inline bool mt76_is_skb_pktid(u8 pktid)
+{
+       if (pktid & MT_PACKET_ID_HAS_RATE)
+               return false;
+
+       return pktid >= MT_PACKET_ID_FIRST;
+}
+
 void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
 void mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta,
             struct mt76_wcid *wcid, struct sk_buff *skb);
index ee4a86971be74668f58948791d5147de5e663741..82bafb5ac32658326a8414eb4279df7baedbb55e 100644 (file)
@@ -420,30 +420,92 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
 EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
 
 static void
-mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev,
+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 mt76x02_sta *msta,
                           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,
+       phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
+
+       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);
+       } else if (rate[0].idx < 0) {
+               if (!msta)
+                       return;
+
+               mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
+                                           dev->mt76.chandef.chan->band);
+       }
+
+       mt76x02_mac_process_tx_rate(&last_rate, st->rate,
                                    dev->mt76.chandef.chan->band);
-       if (last_rate < IEEE80211_TX_MAX_RATES - 1)
-               rate[last_rate + 1].idx = -1;
-
-       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;
+
+       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 +551,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;
 
@@ -512,14 +580,14 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
                        return;
                }
 
-               mt76x02_mac_fill_tx_status(dev, status.info, &msta->status,
-                                          msta->n_frames);
+               mt76x02_mac_fill_tx_status(dev, msta, status.info,
+                                          &msta->status, msta->n_frames);
 
                msta->status = *stat;
                msta->n_frames = 1;
                *update = 0;
        } else {
-               mt76x02_mac_fill_tx_status(dev, status.info, stat, 1);
+               mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
                *update = 1;
        }
 
index cf7abd9b7d2ea11c3a0acb2e401566d8dc1ea1d3..7a1164a07ee75c8dd14970d4a57df2afbbbbbe47 100644 (file)
@@ -164,9 +164,15 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
        mt76x02_mac_write_txwi(dev, txwi, tx_info->skb, wcid, sta, len);
 
        pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+
+       /* encode packet rate for no-skb packet id to fix up status reporting */
+       if (pid == MT_PACKET_ID_NO_SKB)
+               pid = MT_PACKET_ID_HAS_RATE |
+                     (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
+
        txwi->pktid = pid;
 
-       if (pid >= MT_PACKET_ID_FIRST)
+       if (mt76_is_skb_pktid(pid))
                qsel = MT_QSEL_MGMT;
 
        tx_info->info = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
index 6b89f7eab26c9ebbe53859880a753943e9fdb03b..47386ca713cc9c75a6cbb141e4d2a9f56175fe2a 100644 (file)
@@ -89,9 +89,15 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
        skb_push(tx_info->skb, sizeof(*txwi));
 
        pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+
+       /* encode packet rate for no-skb packet id to fix up status reporting */
+       if (pid == MT_PACKET_ID_NO_SKB)
+               pid = MT_PACKET_ID_HAS_RATE |
+                     (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
+
        txwi->pktid = pid;
 
-       if (pid >= MT_PACKET_ID_FIRST || ep == MT_EP_OUT_HCCA)
+       if (mt76_is_skb_pktid(pid) || ep == MT_EP_OUT_HCCA)
                qsel = MT_QSEL_MGMT;
        else
                qsel = MT_QSEL_EDCA;