mt76: mt7915: stop queues when running out of tx tokens
authorFelix Fietkau <nbd@nbd.name>
Sat, 21 Nov 2020 15:00:14 +0000 (16:00 +0100)
committerFelix Fietkau <nbd@nbd.name>
Fri, 4 Dec 2020 13:31:16 +0000 (14:31 +0100)
Avoids packet drops under load with lots of stations

Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/init.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h

index ff29a80..ed4635b 100644 (file)
@@ -690,6 +690,7 @@ void mt7915_unregister_device(struct mt7915_dev *dev)
                        ieee80211_free_txskb(hw, txwi->skb);
                }
                mt76_put_txwi(&dev->mt76, txwi);
+               dev->token_count--;
        }
        spin_unlock_bh(&dev->token_lock);
        idr_destroy(&dev->token);
index b509269..f504eeb 100644 (file)
@@ -906,6 +906,26 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
                mt7915_mac_write_txwi_tm(dev, mphy, txwi, skb);
 }
 
+static void
+mt7915_set_tx_blocked(struct mt7915_dev *dev, bool blocked)
+{
+       struct mt76_phy *mphy = &dev->mphy, *mphy2 = dev->mt76.phy2;
+       struct mt76_queue *q, *q2 = NULL;
+
+       q = mphy->q_tx[0];
+       if (blocked == q->blocked)
+               return;
+
+       q->blocked = blocked;
+       if (mphy2) {
+               q2 = mphy2->q_tx[0];
+               q2->blocked = blocked;
+       }
+
+       if (!blocked)
+               mt76_worker_schedule(&dev->mt76.tx_worker);
+}
+
 int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
                          enum mt76_txq_id qid, struct mt76_wcid *wcid,
                          struct ieee80211_sta *sta,
@@ -962,7 +982,13 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 
        spin_lock_bh(&dev->token_lock);
        id = idr_alloc(&dev->token, t, 0, MT7915_TOKEN_SIZE, GFP_ATOMIC);
+       if (id >= 0)
+               dev->token_count++;
+
+       if (dev->token_count >= MT7915_TOKEN_SIZE - MT7915_TOKEN_FREE_THR)
+               mt7915_set_tx_blocked(dev, true);
        spin_unlock_bh(&dev->token_lock);
+
        if (id < 0)
                return id;
 
@@ -1071,6 +1097,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
        LIST_HEAD(free_list);
        struct sk_buff *tmp;
        u8 i, count;
+       bool wake = false;
 
        /* clean DMA queues and unmap buffers first */
        mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
@@ -1123,6 +1150,11 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
 
                spin_lock_bh(&dev->token_lock);
                txwi = idr_remove(&dev->token, msdu);
+               if (txwi)
+                       dev->token_count--;
+               if (dev->token_count < MT7915_TOKEN_SIZE - MT7915_TOKEN_FREE_THR &&
+                   dev->mphy.q_tx[0]->blocked)
+                       wake = true;
                spin_unlock_bh(&dev->token_lock);
 
                if (!txwi)
@@ -1153,6 +1185,13 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
        }
 
        mt7915_mac_sta_poll(dev);
+
+       if (wake) {
+               spin_lock_bh(&dev->token_lock);
+               mt7915_set_tx_blocked(dev, false);
+               spin_unlock_bh(&dev->token_lock);
+       }
+
        mt76_worker_schedule(&dev->mt76.tx_worker);
 
        napi_consume_skb(skb, 1);
index 30e53a0..0339abf 100644 (file)
@@ -32,6 +32,7 @@
 
 #define MT7915_EEPROM_SIZE             3584
 #define MT7915_TOKEN_SIZE              8192
+#define MT7915_TOKEN_FREE_THR          64
 
 #define MT7915_CFEND_RATE_DEFAULT      0x49    /* OFDM 24M */
 #define MT7915_CFEND_RATE_11B          0x03    /* 11B LP, 11M */
@@ -161,6 +162,7 @@ struct mt7915_dev {
        u32 hw_pattern;
 
        spinlock_t token_lock;
+       int token_count;
        struct idr token;
 
        s8 **rate_power; /* TODO: use mt76_rate_power */