mt76: mt7915: add Wireless Ethernet Dispatch support
authorFelix Fietkau <nbd@nbd.name>
Mon, 6 Dec 2021 12:45:54 +0000 (13:45 +0100)
committerFelix Fietkau <nbd@nbd.name>
Fri, 13 May 2022 07:39:35 +0000 (09:39 +0200)
This is used to support hardware flow offloading from Ethernet to WLAN

Signed-off-by: Felix Fietkau <nbd@nbd.name>
18 files changed:
drivers/net/wireless/mediatek/mt76/dma.c
drivers/net/wireless/mediatek/mt76/mac80211.c
drivers/net/wireless/mediatek/mt76/mmio.c
drivers/net/wireless/mediatek/mt76/mt76.h
drivers/net/wireless/mediatek/mt76/mt7603/dma.c
drivers/net/wireless/mediatek/mt76/mt7615/dma.c
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
drivers/net/wireless/mediatek/mt76/mt7915/dma.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.h
drivers/net/wireless/mediatek/mt76/mt7915/main.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
drivers/net/wireless/mediatek/mt76/mt7915/pci.c
drivers/net/wireless/mediatek/mt76/mt7915/regs.h
drivers/net/wireless/mediatek/mt76/mt7921/dma.c
drivers/net/wireless/mediatek/mt76/tx.c

index 83787fc01e4e2e0f6b39d85b48ee641d346fcf53..30de8be4aac1631706d8283450e52fea00dd6735 100644 (file)
@@ -7,9 +7,36 @@
 #include "mt76.h"
 #include "dma.h"
 
-#define Q_READ(_dev, _q, _field)               readl(&(_q)->regs->_field)
-#define Q_WRITE(_dev, _q, _field, _val)                writel(_val, &(_q)->regs->_field)
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
+
+#define Q_READ(_dev, _q, _field) ({                                    \
+       u32 _offset = offsetof(struct mt76_queue_regs, _field);         \
+       u32 _val;                                                       \
+       if ((_q)->flags & MT_QFLAG_WED)                                 \
+               _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed,       \
+                                              ((_q)->wed_regs +        \
+                                               _offset));              \
+       else                                                            \
+               _val = readl(&(_q)->regs->_field);                      \
+       _val;                                                           \
+})
+
+#define Q_WRITE(_dev, _q, _field, _val)        do {                            \
+       u32 _offset = offsetof(struct mt76_queue_regs, _field);         \
+       if ((_q)->flags & MT_QFLAG_WED)                                 \
+               mtk_wed_device_reg_write(&(_dev)->mmio.wed,             \
+                                        ((_q)->wed_regs + _offset),    \
+                                        _val);                         \
+       else                                                            \
+               writel(_val, &(_q)->regs->_field);                      \
+} while (0)
+
+#else
+
+#define Q_READ(_dev, _q, _field)       readl(&(_q)->regs->_field)
+#define Q_WRITE(_dev, _q, _field, _val)        writel(_val, &(_q)->regs->_field)
 
+#endif
 
 static struct mt76_txwi_cache *
 mt76_alloc_txwi(struct mt76_dev *dev)
@@ -111,36 +138,6 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
        mt76_dma_sync_idx(dev, q);
 }
 
-static int
-mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
-                    int idx, int n_desc, int bufsize,
-                    u32 ring_base)
-{
-       int size;
-
-       spin_lock_init(&q->lock);
-       spin_lock_init(&q->cleanup_lock);
-
-       q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
-       q->ndesc = n_desc;
-       q->buf_size = bufsize;
-       q->hw_idx = idx;
-
-       size = q->ndesc * sizeof(struct mt76_desc);
-       q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL);
-       if (!q->desc)
-               return -ENOMEM;
-
-       size = q->ndesc * sizeof(*q->entry);
-       q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
-       if (!q->entry)
-               return -ENOMEM;
-
-       mt76_dma_queue_reset(dev, q);
-
-       return 0;
-}
-
 static int
 mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
                 struct mt76_queue_buf *buf, int nbufs, u32 info,
@@ -486,6 +483,85 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
        return frames;
 }
 
+static int
+mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+       struct mtk_wed_device *wed = &dev->mmio.wed;
+       int ret, type, ring;
+       u8 flags = q->flags;
+
+       if (!mtk_wed_device_active(wed))
+               q->flags &= ~MT_QFLAG_WED;
+
+       if (!(q->flags & MT_QFLAG_WED))
+               return 0;
+
+       type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags);
+       ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags);
+
+       switch (type) {
+       case MT76_WED_Q_TX:
+               ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs);
+               if (!ret)
+                       q->wed_regs = wed->tx_ring[ring].reg_base;
+               break;
+       case MT76_WED_Q_TXFREE:
+               /* WED txfree queue needs ring to be initialized before setup */
+               q->flags = 0;
+               mt76_dma_queue_reset(dev, q);
+               mt76_dma_rx_fill(dev, q);
+               q->flags = flags;
+
+               ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
+               if (!ret)
+                       q->wed_regs = wed->txfree_ring.reg_base;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+#else
+       return 0;
+#endif
+}
+
+static int
+mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+                    int idx, int n_desc, int bufsize,
+                    u32 ring_base)
+{
+       int ret, size;
+
+       spin_lock_init(&q->lock);
+       spin_lock_init(&q->cleanup_lock);
+
+       q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
+       q->ndesc = n_desc;
+       q->buf_size = bufsize;
+       q->hw_idx = idx;
+
+       size = q->ndesc * sizeof(struct mt76_desc);
+       q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL);
+       if (!q->desc)
+               return -ENOMEM;
+
+       size = q->ndesc * sizeof(*q->entry);
+       q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
+       if (!q->entry)
+               return -ENOMEM;
+
+       ret = mt76_dma_wed_setup(dev, q);
+       if (ret)
+               return ret;
+
+       if (q->flags != MT_WED_Q_TXFREE)
+               mt76_dma_queue_reset(dev, q);
+
+       return 0;
+}
+
 static void
 mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
 {
@@ -567,14 +643,29 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
 static int
 mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
 {
-       int len, data_len, done = 0;
+       int len, data_len, done = 0, dma_idx;
        struct sk_buff *skb;
        unsigned char *data;
+       bool check_ddone = false;
        bool more;
 
+       if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
+           q->flags == MT_WED_Q_TXFREE) {
+               dma_idx = Q_READ(dev, q, dma_idx);
+               check_ddone = true;
+       }
+
        while (done < budget) {
                u32 info;
 
+               if (check_ddone) {
+                       if (q->tail == dma_idx)
+                               dma_idx = Q_READ(dev, q, dma_idx);
+
+                       if (q->tail == dma_idx)
+                               break;
+               }
+
                data = mt76_dma_dequeue(dev, q, false, &len, &info, &more);
                if (!data)
                        break;
@@ -715,5 +806,8 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
        }
 
        mt76_free_pending_txwi(dev);
+
+       if (mtk_wed_device_active(&dev->mmio.wed))
+               mtk_wed_device_detach(&dev->mmio.wed);
 }
 EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
index 9056d09d6c337a9fe956b652f434ab5286517a51..18b5de55334c8339bdfd60f6aeece1b382858d56 100644 (file)
@@ -1582,7 +1582,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna);
 
 struct mt76_queue *
 mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
-               int ring_base)
+               int ring_base, u32 flags)
 {
        struct mt76_queue *hwq;
        int err;
@@ -1591,6 +1591,8 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
        if (!hwq)
                return ERR_PTR(-ENOMEM);
 
+       hwq->flags = flags;
+
        err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
        if (err < 0)
                return ERR_PTR(err);
index 26353b6bce976f797896c42edbc669d0ffac482c..86e3d2ac4d0db22d7af39999c7caec5757fb3c90 100644 (file)
@@ -73,8 +73,13 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
        spin_lock_irqsave(&dev->mmio.irq_lock, flags);
        dev->mmio.irqmask &= ~clear;
        dev->mmio.irqmask |= set;
-       if (addr)
-               mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
+       if (addr) {
+               if (mtk_wed_device_active(&dev->mmio.wed))
+                       mtk_wed_device_irq_set_mask(&dev->mmio.wed,
+                                                   dev->mmio.irqmask);
+               else
+                       mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
+       }
        spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
 }
 EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
index dce86846e6481e73d72b23241afd452b4b2dbcea..dc0f1b0aa34a27bdcf15c5d330d380cebf5eca57 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/leds.h>
 #include <linux/usb.h>
 #include <linux/average.h>
+#include <linux/soc/mediatek/mtk_wed.h>
 #include <net/mac80211.h>
 #include "util.h"
 #include "testmode.h"
 
 #define MT76_TOKEN_FREE_THR    64
 
+#define MT_QFLAG_WED_RING      GENMASK(1, 0)
+#define MT_QFLAG_WED_TYPE      GENMASK(3, 2)
+#define MT_QFLAG_WED           BIT(4)
+
+#define __MT_WED_Q(_type, _n)  (MT_QFLAG_WED | \
+                                FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \
+                                FIELD_PREP(MT_QFLAG_WED_RING, _n))
+#define MT_WED_Q_TX(_n)                __MT_WED_Q(MT76_WED_Q_TX, _n)
+#define MT_WED_Q_TXFREE                __MT_WED_Q(MT76_WED_Q_TXFREE, 0)
+
 struct mt76_dev;
 struct mt76_phy;
 struct mt76_wcid;
@@ -42,6 +53,11 @@ enum mt76_bus_type {
        MT76_BUS_SDIO,
 };
 
+enum mt76_wed_type {
+       MT76_WED_Q_TX,
+       MT76_WED_Q_TXFREE,
+};
+
 struct mt76_bus_ops {
        u32 (*rr)(struct mt76_dev *dev, u32 offset);
        void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
@@ -170,6 +186,9 @@ struct mt76_queue {
        u8 buf_offset;
        u8 hw_idx;
        u8 qid;
+       u8 flags;
+
+       u32 wed_regs;
 
        dma_addr_t desc_dma;
        struct sk_buff *rx_head;
@@ -537,6 +556,8 @@ struct mt76_mmio {
        void __iomem *regs;
        spinlock_t irq_lock;
        u32 irqmask;
+
+       struct mtk_wed_device wed;
 };
 
 struct mt76_rx_status {
@@ -719,6 +740,7 @@ struct mt76_dev {
 
        spinlock_t token_lock;
        struct idr token;
+       u16 wed_token_count;
        u16 token_count;
        u16 token_size;
 
@@ -944,14 +966,14 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len);
 
 struct mt76_queue *
 mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
-               int ring_base);
+               int ring_base, u32 flags);
 u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx);
 static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx,
-                                    int n_desc, int ring_base)
+                                    int n_desc, int ring_base, u32 flags)
 {
        struct mt76_queue *q;
 
-       q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base);
+       q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags);
        if (IS_ERR(q))
                return PTR_ERR(q);
 
@@ -966,7 +988,7 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx,
 {
        struct mt76_queue *q;
 
-       q = mt76_init_queue(dev, qid, idx, n_desc, ring_base);
+       q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0);
        if (IS_ERR(q))
                return PTR_ERR(q);
 
index 2c1c79dc7fda0e4fd3aba2fcdcadc9556461e78a..f9e5857850e71443224533d32fad38409e8817c1 100644 (file)
@@ -173,13 +173,13 @@ int mt7603_dma_init(struct mt7603_dev *dev)
 
        for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
                ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
-                                        MT7603_TX_RING_SIZE, MT_TX_RING_BASE);
+                                        MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0);
                if (ret)
                        return ret;
        }
 
        ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
-                                MT7603_PSD_RING_SIZE, MT_TX_RING_BASE);
+                                MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0);
        if (ret)
                return ret;
 
@@ -189,12 +189,12 @@ int mt7603_dma_init(struct mt7603_dev *dev)
                return ret;
 
        ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN,
-                                MT_MCU_RING_SIZE, MT_TX_RING_BASE);
+                                MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0);
        if (ret)
                return ret;
 
        ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC,
-                                MT_MCU_RING_SIZE, MT_TX_RING_BASE);
+                                MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0);
        if (ret)
                return ret;
 
index 95dbb413678afbe274ecf4cd693bc61fed077b26..ce19f57de475810ce3ecb5268cdf90e644b0c802 100644 (file)
@@ -26,14 +26,14 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
        for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
                ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
                                         MT7615_TX_RING_SIZE / 2,
-                                        MT_TX_RING_BASE);
+                                        MT_TX_RING_BASE, 0);
                if (ret)
                        return ret;
        }
 
        ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT,
                                 MT7615_TX_MGMT_RING_SIZE,
-                                MT_TX_RING_BASE);
+                                MT_TX_RING_BASE, 0);
        if (ret)
                return ret;
 
@@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
                return mt7622_init_tx_queues_multi(dev);
 
        ret = mt76_init_tx_queue(&dev->mphy, 0, 0, MT7615_TX_RING_SIZE,
-                                MT_TX_RING_BASE);
+                                MT_TX_RING_BASE, 0);
        if (ret)
                return ret;
 
index 23d2864d37fb1e45eafc67c41bc4d2787bd50007..96ec96df6a3cfcd9d0ef4e9e3998f7f54d0889c9 100644 (file)
@@ -191,13 +191,13 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
        for (i = 0; i < IEEE80211_NUM_ACS; i++) {
                ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i),
                                         MT76x02_TX_RING_SIZE,
-                                        MT_TX_RING_BASE);
+                                        MT_TX_RING_BASE, 0);
                if (ret)
                        return ret;
        }
 
        ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
-                                MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE);
+                                MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0);
        if (ret)
                return ret;
 
index dad5225e223e001ad4117aa6c3f1cb9d7f249d8f..f3d608d2d3b2c52cea8179e84af9ddedc86a3ed5 100644 (file)
@@ -8,9 +8,16 @@
 static int
 mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base)
 {
+       struct mt7915_dev *dev = phy->dev;
        int i, err;
 
-       err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, ring_base);
+       if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
+               ring_base = MT_WED_TX_RING_BASE;
+               idx -= MT_TXQ_ID(0);
+       }
+
+       err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, ring_base,
+                                MT_WED_Q_TX(idx));
        if (err < 0)
                return err;
 
@@ -319,6 +326,14 @@ static int mt7915_dma_enable(struct mt7915_dev *dev)
        if (dev->dbdc_support || dev->phy.band_idx)
                irq_mask |= MT_INT_BAND1_RX_DONE;
 
+       if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+               u32 wed_irq_mask = irq_mask;
+
+               wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1;
+               mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask);
+               mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask);
+       }
+
        mt7915_irq_enable(dev, irq_mask);
 
        return 0;
@@ -327,6 +342,7 @@ static int mt7915_dma_enable(struct mt7915_dev *dev)
 int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
 {
        struct mt76_dev *mdev = &dev->mt76;
+       u32 wa_rx_base, wa_rx_idx;
        u32 hif1_ofs = 0;
        int ret;
 
@@ -339,6 +355,17 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
 
        mt7915_dma_disable(dev, true);
 
+       if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+               mt76_set(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_WED);
+
+               mt76_wr(dev, MT_WFDMA_WED_RING_CONTROL,
+                       FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX0, 18) |
+                       FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX1, 19) |
+                       FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_RX1, 1));
+       } else {
+               mt76_clear(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_WED);
+       }
+
        /* init tx queue */
        ret = mt7915_init_tx_queues(&dev->phy,
                                    MT_TXQ_ID(dev->phy.band_idx),
@@ -390,11 +417,17 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
                return ret;
 
        /* event from WA */
+       if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+               wa_rx_base = MT_WED_RX_RING_BASE;
+               wa_rx_idx = MT7915_RXQ_MCU_WA;
+               dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE;
+       } else {
+               wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA);
+               wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA);
+       }
        ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
-                              MT_RXQ_ID(MT_RXQ_MCU_WA),
-                              MT7915_RX_MCU_RING_SIZE,
-                              MT_RX_BUF_SIZE,
-                              MT_RXQ_RING_BASE(MT_RXQ_MCU_WA));
+                              wa_rx_idx, MT7915_RX_MCU_RING_SIZE,
+                              MT_RX_BUF_SIZE, wa_rx_base);
        if (ret)
                return ret;
 
index cc796693ced9be669cd5b50abec1d4e07fff1a03..a493162b4e8c0ff2ab3ab8a6660f51137a51ac30 100644 (file)
@@ -1348,6 +1348,29 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
        return 0;
 }
 
+u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
+{
+       struct mt7915_txp *txp = ptr + MT_TXD_SIZE;
+       __le32 *txwi = ptr;
+       u32 val;
+
+       memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp));
+
+       val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) |
+             FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT);
+       txwi[0] = cpu_to_le32(val);
+
+       val = MT_TXD1_LONG_FORMAT |
+             FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3);
+       txwi[1] = cpu_to_le32(val);
+
+       txp->token = cpu_to_le16(token_id);
+       txp->nbuf = 1;
+       txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp));
+
+       return MT_TXD_SIZE + sizeof(*txp);
+}
+
 static void
 mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
 {
@@ -1381,7 +1404,7 @@ mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
 
        txp = mt7915_txwi_to_txp(dev, t);
        for (i = 0; i < txp->nbuf; i++)
-               dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
+               dma_unmap_single(dev->dma_dev, le32_to_cpu(txp->buf[i]),
                                 le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
 }
 
@@ -1390,6 +1413,7 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
                 struct ieee80211_sta *sta, struct list_head *free_list)
 {
        struct mt76_dev *mdev = &dev->mt76;
+       struct mt7915_sta *msta;
        struct mt76_wcid *wcid;
        __le32 *txwi;
        u16 wcid_idx;
@@ -1402,13 +1426,24 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
        if (sta) {
                wcid = (struct mt76_wcid *)sta->drv_priv;
                wcid_idx = wcid->idx;
-
-               if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
-                       mt7915_tx_check_aggr(sta, txwi);
        } else {
                wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
+               wcid = rcu_dereference(dev->mt76.wcid[wcid_idx]);
+
+               if (wcid && wcid->sta) {
+                       msta = container_of(wcid, struct mt7915_sta, wcid);
+                       sta = container_of((void *)msta, struct ieee80211_sta,
+                                         drv_priv);
+                       spin_lock_bh(&dev->sta_poll_lock);
+                       if (list_empty(&msta->poll_list))
+                               list_add_tail(&msta->poll_list, &dev->sta_poll_list);
+                       spin_unlock_bh(&dev->sta_poll_lock);
+               }
        }
 
+       if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+               mt7915_tx_check_aggr(sta, txwi);
+
        __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
 
 out:
@@ -1416,29 +1451,55 @@ out:
        mt76_put_txwi(mdev, t);
 }
 
+static void
+mt7915_mac_tx_free_prepare(struct mt7915_dev *dev)
+{
+       struct mt76_dev *mdev = &dev->mt76;
+       struct mt76_phy *mphy_ext = mdev->phy2;
+
+       /* clean DMA queues and unmap buffers first */
+       mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
+       mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
+       if (mphy_ext) {
+               mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false);
+               mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false);
+       }
+}
+
+static void
+mt7915_mac_tx_free_done(struct mt7915_dev *dev,
+                       struct list_head *free_list, bool wake)
+{
+       struct sk_buff *skb, *tmp;
+
+       mt7915_mac_sta_poll(dev);
+
+       if (wake)
+               mt76_set_tx_blocked(&dev->mt76, false);
+
+       mt76_worker_schedule(&dev->mt76.tx_worker);
+
+       list_for_each_entry_safe(skb, tmp, free_list, list) {
+               skb_list_del_init(skb);
+               napi_consume_skb(skb, 1);
+       }
+}
+
 static void
 mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
 {
        struct mt7915_tx_free *free = (struct mt7915_tx_free *)data;
        struct mt76_dev *mdev = &dev->mt76;
-       struct mt76_phy *mphy_ext = mdev->phy2;
        struct mt76_txwi_cache *txwi;
        struct ieee80211_sta *sta = NULL;
        LIST_HEAD(free_list);
-       struct sk_buff *skb, *tmp;
        void *end = data + len;
        bool v3, wake = false;
        u16 total, count = 0;
        u32 txd = le32_to_cpu(free->txd);
        __le32 *cur_info;
 
-       /* clean DMA queues and unmap buffers first */
-       mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
-       mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
-       if (mphy_ext) {
-               mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false);
-               mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false);
-       }
+       mt7915_mac_tx_free_prepare(dev);
 
        total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT);
        v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4);
@@ -1492,17 +1553,38 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
                }
        }
 
-       mt7915_mac_sta_poll(dev);
+       mt7915_mac_tx_free_done(dev, &free_list, wake);
+}
 
-       if (wake)
-               mt76_set_tx_blocked(&dev->mt76, false);
+static void
+mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len)
+{
+       struct mt7915_tx_free *free = (struct mt7915_tx_free *)data;
+       struct mt76_dev *mdev = &dev->mt76;
+       __le16 *info = (__le16 *)free->info;
+       void *end = data + len;
+       LIST_HEAD(free_list);
+       bool wake = false;
+       u8 i, count;
 
-       mt76_worker_schedule(&dev->mt76.tx_worker);
+       mt7915_mac_tx_free_prepare(dev);
 
-       list_for_each_entry_safe(skb, tmp, &free_list, list) {
-               skb_list_del_init(skb);
-               napi_consume_skb(skb, 1);
+       count = FIELD_GET(MT_TX_FREE_MSDU_CNT_V0, le16_to_cpu(free->ctrl));
+       if (WARN_ON_ONCE((void *)&info[count] > end))
+               return;
+
+       for (i = 0; i < count; i++) {
+               struct mt76_txwi_cache *txwi;
+               u16 msdu = le16_to_cpu(info[i]);
+
+               txwi = mt76_token_release(mdev, msdu, &wake);
+               if (!txwi)
+                       continue;
+
+               mt7915_txwi_free(dev, txwi, NULL, &free_list);
        }
+
+       mt7915_mac_tx_free_done(dev, &free_list, wake);
 }
 
 static bool
@@ -1682,6 +1764,9 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
        case PKT_TYPE_TXRX_NOTIFY:
                mt7915_mac_tx_free(dev, data, len);
                return false;
+       case PKT_TYPE_TXRX_NOTIFY_V0:
+               mt7915_mac_tx_free_v0(dev, data, len);
+               return false;
        case PKT_TYPE_TXS:
                for (rxd += 2; rxd + 8 <= end; rxd += 8)
                    mt7915_mac_add_txs(dev, rxd);
@@ -1709,6 +1794,10 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
                mt7915_mac_tx_free(dev, skb->data, skb->len);
                napi_consume_skb(skb, 1);
                break;
+       case PKT_TYPE_TXRX_NOTIFY_V0:
+               mt7915_mac_tx_free_v0(dev, skb->data, skb->len);
+               napi_consume_skb(skb, 1);
+               break;
        case PKT_TYPE_RX_EVENT:
                mt7915_mcu_rx_event(dev, skb);
                break;
index 5add1dd36dbead583df8f5c3f38d73e14bfdc1c3..c5fd1a618ae7c6dea314ae609d91e5ea3eb205c7 100644 (file)
@@ -24,6 +24,7 @@ enum rx_pkt_type {
        PKT_TYPE_TXRX_NOTIFY,
        PKT_TYPE_RX_EVENT,
        PKT_TYPE_RX_FW_MONITOR = 0x0c,
+       PKT_TYPE_TXRX_NOTIFY_V0 = 0x18,
 };
 
 /* RXD DW1 */
@@ -311,6 +312,7 @@ struct mt7915_tx_free {
 
 #define MT_TX_FREE_VER                 GENMASK(18, 16)
 #define MT_TX_FREE_MSDU_CNT            GENMASK(9, 0)
+#define MT_TX_FREE_MSDU_CNT_V0 GENMASK(6, 0)
 #define MT_TX_FREE_WLAN_ID             GENMASK(23, 14)
 #define MT_TX_FREE_LATENCY             GENMASK(12, 0)
 /* 0: success, others: dropped */
index 5177b19f915488d148281817d88b41aaa693c96b..78bf5ffa75766f67faa988eff8fdb4510409647a 100644 (file)
@@ -1373,6 +1373,39 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static int
+mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_sta *sta,
+                            struct net_device_path_ctx *ctx,
+                            struct net_device_path *path)
+{
+       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+       struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+       struct mt7915_dev *dev = mt7915_hw_dev(hw);
+       struct mt7915_phy *phy = mt7915_hw_phy(hw);
+       struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+
+       if (!mtk_wed_device_active(wed))
+               return -ENODEV;
+
+       if (msta->wcid.idx > 0xff)
+               return -EIO;
+
+       path->type = DEV_PATH_MTK_WDMA;
+       path->dev = ctx->dev;
+       path->mtk_wdma.wdma_idx = wed->wdma_idx;
+       path->mtk_wdma.bss = mvif->mt76.idx;
+       path->mtk_wdma.wcid = msta->wcid.idx;
+       path->mtk_wdma.queue = phy != &dev->phy;
+
+       ctx->dev = NULL;
+
+       return 0;
+}
+#endif
+
 const struct ieee80211_ops mt7915_ops = {
        .tx = mt7915_tx,
        .start = mt7915_start,
@@ -1420,4 +1453,7 @@ const struct ieee80211_ops mt7915_ops = {
        .sta_add_debugfs = mt7915_sta_add_debugfs,
 #endif
        .set_radar_background = mt7915_set_radar_background,
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+       .net_fill_forward_path = mt7915_net_fill_forward_path,
+#endif
 };
index 7594c2b44fe1a76a55e00f66262cd29e7b4498b4..07c1a15e735d53e2d8a0c18a52aebb1595e9cccb 100644 (file)
@@ -2496,6 +2496,9 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
        if (ret)
                return ret;
 
+       if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+               mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
+
        ret = mt7915_mcu_set_mwds(dev, 1);
        if (ret)
                return ret;
index 3c55d4cebbf2e9026eedc4b9d29c177e73d2cfb2..c6446757ad4a572411ebac3db60dd7966058116e 100644 (file)
@@ -550,15 +550,21 @@ static void mt7915_rx_poll_complete(struct mt76_dev *mdev,
 static void mt7915_irq_tasklet(struct tasklet_struct *t)
 {
        struct mt7915_dev *dev = from_tasklet(dev, t, irq_tasklet);
+       struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
        u32 intr, intr1, mask;
 
-       mt76_wr(dev, MT_INT_MASK_CSR, 0);
-       if (dev->hif2)
-               mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+       if (mtk_wed_device_active(wed)) {
+               mtk_wed_device_irq_set_mask(wed, 0);
+               intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask);
+       } else {
+               mt76_wr(dev, MT_INT_MASK_CSR, 0);
+               if (dev->hif2)
+                       mt76_wr(dev, MT_INT1_MASK_CSR, 0);
 
-       intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
-       intr &= dev->mt76.mmio.irqmask;
-       mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
+               intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+               intr &= dev->mt76.mmio.irqmask;
+               mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
+       }
 
        if (dev->hif2) {
                intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR);
@@ -613,10 +619,15 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
 irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
 {
        struct mt7915_dev *dev = dev_instance;
+       struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
 
-       mt76_wr(dev, MT_INT_MASK_CSR, 0);
-       if (dev->hif2)
-               mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+       if (mtk_wed_device_active(wed)) {
+               mtk_wed_device_irq_set_mask(wed, 0);
+       } else {
+               mt76_wr(dev, MT_INT_MASK_CSR, 0);
+               if (dev->hif2)
+                       mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+       }
 
        if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
                return IRQ_NONE;
index fbb5dde588a84d91be3ddc325fe7f22a3d8ce76f..fdd989f0bb992941530addb881cd603129788ca7 100644 (file)
@@ -435,6 +435,8 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev,
 void mt7915_wfsys_reset(struct mt7915_dev *dev);
 irqreturn_t mt7915_irq_handler(int irq, void *dev_instance);
 u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif);
+u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
+
 int mt7915_register_device(struct mt7915_dev *dev);
 void mt7915_unregister_device(struct mt7915_dev *dev);
 int mt7915_eeprom_init(struct mt7915_dev *dev);
index 7cea49f23941a0a24462b0653b68c7c7bb5c6406..d74f609775d3bbb23eecb8d04b294bf5eb1d323e 100644 (file)
@@ -12,6 +12,9 @@
 #include "mac.h"
 #include "../trace.h"
 
+static bool wed_enable = false;
+module_param(wed_enable, bool, 0644);
+
 static LIST_HEAD(hif_list);
 static DEFINE_SPINLOCK(hif_lock);
 static u32 hif_idx;
@@ -92,12 +95,79 @@ static int mt7915_pci_hif2_probe(struct pci_dev *pdev)
        return 0;
 }
 
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static int mt7915_wed_offload_enable(struct mtk_wed_device *wed)
+{
+       struct mt7915_dev *dev;
+       int ret;
+
+       dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
+
+       spin_lock_bh(&dev->mt76.token_lock);
+       dev->mt76.token_size = wed->wlan.token_start;
+       spin_unlock_bh(&dev->mt76.token_lock);
+
+       ret = wait_event_timeout(dev->mt76.tx_wait,
+                                !dev->mt76.wed_token_count, HZ);
+       if (!ret)
+               return -EAGAIN;
+
+       return 0;
+}
+
+static void mt7915_wed_offload_disable(struct mtk_wed_device *wed)
+{
+       struct mt7915_dev *dev;
+
+       dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
+
+       spin_lock_bh(&dev->mt76.token_lock);
+       dev->mt76.token_size = MT7915_TOKEN_SIZE;
+       spin_unlock_bh(&dev->mt76.token_lock);
+}
+#endif
+
+static int
+mt7915_pci_wed_init(struct mt7915_dev *dev, struct pci_dev *pdev, int *irq)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+       struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+       int ret;
+
+       if (!wed_enable)
+               return 0;
+
+       wed->wlan.pci_dev = pdev;
+       wed->wlan.wpdma_phys = pci_resource_start(pdev, 0) +
+                              MT_WFDMA_EXT_CSR_BASE;
+       wed->wlan.nbuf = 4096;
+       wed->wlan.token_start = MT7915_TOKEN_SIZE - wed->wlan.nbuf;
+       wed->wlan.init_buf = mt7915_wed_init_buf;
+       wed->wlan.offload_enable = mt7915_wed_offload_enable;
+       wed->wlan.offload_disable = mt7915_wed_offload_disable;
+
+       if (mtk_wed_device_attach(wed) != 0)
+               return 0;
+
+       *irq = wed->irq;
+       dev->mt76.dma_dev = wed->dev;
+
+       ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
+
+       return 1;
+#else
+       return 0;
+#endif
+}
+
 static int mt7915_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *id)
 {
+       struct mt7915_hif *hif2 = NULL;
        struct mt7915_dev *dev;
        struct mt76_dev *mdev;
-       struct mt7915_hif *hif2;
        int irq;
        int ret;
 
@@ -129,15 +199,24 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
        mt7915_wfsys_reset(dev);
        hif2 = mt7915_pci_init_hif2(pdev);
 
-       ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+       ret = mt7915_pci_wed_init(dev, pdev, &irq);
        if (ret < 0)
-               goto free_device;
+               goto free_wed_or_irq_vector;
+
+       if (!ret) {
+               hif2 = mt7915_pci_init_hif2(pdev);
+
+               ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+               if (ret < 0)
+                       goto free_device;
+
+               irq = pdev->irq;
+       }
 
-       irq = pdev->irq;
        ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler,
                               IRQF_SHARED, KBUILD_MODNAME, dev);
        if (ret)
-               goto free_irq_vector;
+               goto free_wed_or_irq_vector;
 
        /* master switch of PCIe tnterrupt enable */
        mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
@@ -172,8 +251,11 @@ free_hif2:
        if (dev->hif2)
                put_device(dev->hif2->dev);
        devm_free_irq(mdev->dev, irq, dev);
-free_irq_vector:
-       pci_free_irq_vectors(pdev);
+free_wed_or_irq_vector:
+       if (mtk_wed_device_active(&mdev->mmio.wed))
+               mtk_wed_device_detach(&mdev->mmio.wed);
+       else
+               pci_free_irq_vectors(pdev);
 free_device:
        mt76_free_device(&dev->mt76);
 
index 66c60e60e9214299e24b4897227721a8361e3dad..31dffb9c949c7863b185f03ad3fc89238805258c 100644 (file)
@@ -577,18 +577,31 @@ enum offs_rev {
 
 /* WFDMA CSR */
 #define MT_WFDMA_EXT_CSR_BASE          __REG(WFDMA_EXT_CSR_ADDR)
+#define MT_WFDMA_EXT_CSR_PHYS_BASE     0x18027000
 #define MT_WFDMA_EXT_CSR(ofs)          (MT_WFDMA_EXT_CSR_BASE + (ofs))
+#define MT_WFDMA_EXT_CSR_PHYS(ofs)     (MT_WFDMA_EXT_CSR_PHYS_BASE + (ofs))
 
-#define MT_WFDMA_HOST_CONFIG           MT_WFDMA_EXT_CSR(0x30)
+#define MT_WFDMA_HOST_CONFIG           MT_WFDMA_EXT_CSR_PHYS(0x30)
 #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0)
+#define MT_WFDMA_HOST_CONFIG_WED       BIT(1)
 
-#define MT_WFDMA_EXT_CSR_HIF_MISC      MT_WFDMA_EXT_CSR(0x44)
+#define MT_WFDMA_WED_RING_CONTROL      MT_WFDMA_EXT_CSR_PHYS(0x34)
+#define MT_WFDMA_WED_RING_CONTROL_TX0  GENMASK(4, 0)
+#define MT_WFDMA_WED_RING_CONTROL_TX1  GENMASK(12, 8)
+#define MT_WFDMA_WED_RING_CONTROL_RX1  GENMASK(20, 16)
+
+#define MT_WFDMA_EXT_CSR_HIF_MISC      MT_WFDMA_EXT_CSR_PHYS(0x44)
 #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
 
 #define MT_PCIE_RECOG_ID               0xd7090
 #define MT_PCIE_RECOG_ID_MASK          GENMASK(30, 0)
 #define MT_PCIE_RECOG_ID_SEM           BIT(31)
 
+#define MT_INT_WED_MASK_CSR            MT_WFDMA_EXT_CSR(0x204)
+
+#define MT_WED_TX_RING_BASE            MT_WFDMA_EXT_CSR(0x300)
+#define MT_WED_RX_RING_BASE            MT_WFDMA_EXT_CSR(0x400)
+
 /* WFDMA0 PCIE1 */
 #define MT_WFDMA0_PCIE1_BASE           __REG(WFDMA0_PCIE1_ADDR)
 #define MT_WFDMA0_PCIE1(ofs)           (MT_WFDMA0_PCIE1_BASE + (ofs))
index 34b3effe14f3b1d0b29314c822a7baa8baa3c38a..3a6b158b779ec6ed4255d38d58e8b5e2d840af72 100644 (file)
@@ -9,7 +9,7 @@ static int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc)
 {
        int i, err;
 
-       err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, MT_TX_RING_BASE);
+       err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, MT_TX_RING_BASE, 0);
        if (err < 0)
                return err;
 
index 84fa922c977a9740133d3e7c741ef107b5a63b08..02067edca95e0d157e7296b4b3bd9ec0fca6576d 100644 (file)
@@ -726,6 +726,12 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
        if (token >= 0)
                dev->token_count++;
 
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+       if (mtk_wed_device_active(&dev->mmio.wed) &&
+           token >= dev->mmio.wed.wlan.token_start)
+               dev->wed_token_count++;
+#endif
+
        if (dev->token_count >= dev->token_size - MT76_TOKEN_FREE_THR)
                __mt76_set_tx_blocked(dev, true);
 
@@ -743,9 +749,17 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
        spin_lock_bh(&dev->token_lock);
 
        txwi = idr_remove(&dev->token, token);
-       if (txwi)
+       if (txwi) {
                dev->token_count--;
 
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+               if (mtk_wed_device_active(&dev->mmio.wed) &&
+                   token >= dev->mmio.wed.wlan.token_start &&
+                   --dev->wed_token_count == 0)
+                       wake_up(&dev->tx_wait);
+#endif
+       }
+
        if (dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR &&
            dev->phy.q_tx[0]->blocked)
                *wake = true;