]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mt76: mt7996: Enable WED for MT7992 chipset
authorRex Lu <rex.lu@mediatek.com>
Tue, 9 Sep 2025 09:45:18 +0000 (11:45 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 15 Sep 2025 07:47:41 +0000 (09:47 +0200)
Introduce WED offload support for MT7992 chipset in MT7996 driver.

Co-developed-by: Sujuan Chen <sujuan.chen@mediatek.com>
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
Co-developed-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250909-mt7996-rro-rework-v5-10-7d66f6eb7795@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/dma.c
drivers/net/wireless/mediatek/mt76/mt7996/init.c
drivers/net/wireless/mediatek/mt76/mt7996/main.c
drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
drivers/net/wireless/mediatek/mt76/mt7996/pci.c
drivers/net/wireless/mediatek/mt76/mt7996/regs.h

index b3665bb0a433ae4cdbf02fa647d644961509d7aa..c5fd25acf9a1a60d4aaffe8ba6d2cf2aafe4fd87 100644 (file)
@@ -17,7 +17,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc,
                ring_base += MT_TXQ_ID(0) * MT_RING_SIZE;
                idx -= MT_TXQ_ID(0);
 
-               if (phy->mt76->band_idx == MT_BAND2)
+               if (wed == &dev->mt76.mmio.wed_hif2)
                        flags = MT_WED_Q_TX(0);
                else
                        flags = MT_WED_Q_TX(idx);
@@ -429,6 +429,30 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
                mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
                         MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
 
+               if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
+                   (dev->hif2->speed == PCIE_SPEED_5_0GT &&
+                    dev->hif2->width < PCIE_LNK_X2)) {
+                       mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
+                                WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+                                FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+                                           0x1));
+                       mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
+                                MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+                                FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+                                           0x1));
+               } else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
+                          (dev->hif2->speed == PCIE_SPEED_8_0GT &&
+                           dev->hif2->width < PCIE_LNK_X2)) {
+                       mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
+                                WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+                                FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+                                           0x2));
+                       mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
+                                MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+                                FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
+                                           0x2));
+               }
+
                /* WFDMA rx threshold */
                mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c);
                mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008);
index a472c9bd4fd8ae88a5213bda8225c91716423f6d..0104b50ce3f6d52d762dc2f87e5caa5d36ce69b8 100644 (file)
@@ -666,7 +666,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
        if (!mt7996_band_valid(dev, band))
                return 0;
 
-       if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) {
+       if (dev->hif2 &&
+           ((is_mt7996(&dev->mt76) && band == MT_BAND2) ||
+            (is_mt7992(&dev->mt76) && band == MT_BAND1))) {
                hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
                wed = &dev->mt76.mmio.wed_hif2;
        }
@@ -724,10 +726,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band)
                goto error;
 
        if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) {
-               u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2;
-
-               mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask);
-               mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask);
+               mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT);
+               mtk_wed_device_start(&dev->mt76.mmio.wed_hif2,
+                                    MT_INT_TX_RX_DONE_EXT);
        }
 
        return 0;
index 0d5866ac951f70895ec971dbee0146dd58f1abae..6adb7f7bdd6f26501f312e9abb28cf572a8583b7 100644 (file)
@@ -2158,9 +2158,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
        struct mt7996_dev *dev = mt7996_hw_dev(hw);
        struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
        struct mt7996_sta_link *msta_link;
-       struct mt7996_vif_link *link;
        struct mt76_vif_link *mlink;
-       struct mt7996_phy *phy;
 
        mlink = rcu_dereference(mvif->mt76.link[msta->deflink_id]);
        if (!mlink)
@@ -2173,12 +2171,9 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
        if (!msta_link->wcid.sta || msta_link->wcid.idx > MT7996_WTBL_STA)
                return -EIO;
 
-       link = (struct mt7996_vif_link *)mlink;
-       phy = mt7996_vif_link_phy(link);
-       if (!phy)
-               return -ENODEV;
-
-       if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2)
+       if (dev->hif2 &&
+           ((is_mt7996(&dev->mt76) && msta_link->wcid.phy_idx == MT_BAND2) ||
+            (is_mt7992(&dev->mt76) && msta_link->wcid.phy_idx == MT_BAND1)))
                wed = &dev->mt76.mmio.wed_hif2;
 
        if (!mtk_wed_device_active(wed))
@@ -2191,7 +2186,11 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
        path->mtk_wdma.queue = 0;
        path->mtk_wdma.wcid = msta_link->wcid.idx;
 
-       path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed);
+       if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU) &&
+           mtk_wed_is_amsdu_supported(wed))
+               path->mtk_wdma.amsdu = msta_link->wcid.amsdu;
+       else
+               path->mtk_wdma.amsdu = 0;
        ctx->dev = NULL;
 
        return 0;
index a8b4ef433c2bfdbbf79ae7f6aa54f33a5d5254ff..aa70e5fce98f005ef5c3f588203f61e179ff04e8 100644 (file)
@@ -459,14 +459,14 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
        struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
        struct pci_dev *pci_dev = pdev_ptr;
-       u32 hif1_ofs = 0;
+       u32 hif1_ofs;
 
        if (!wed_enable)
                return 0;
 
        dev->has_rro = true;
 
-       hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+       hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0;
 
        if (hif2)
                wed = &dev->mt76.mmio.wed_hif2;
@@ -491,10 +491,17 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
                                             MT_TXQ_RING_BASE(0) +
                                             MT7996_TXQ_BAND2 * MT_RING_SIZE;
                if (dev->has_rro) {
-                       wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
-                                                MT_RXQ_RING_BASE(0) +
-                                                MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
-                       wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
+                       if (is_mt7996(&dev->mt76)) {
+                               wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
+                               wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+                                                        MT_RXQ_RING_BASE(0) +
+                                                        MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
+                       } else {
+                               wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_BAND1_EXT) - 1;
+                               wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+                                                        MT_RXQ_RING_BASE(0) +
+                                                        MT7996_RXQ_MCU_WA_EXT * MT_RING_SIZE;
+                       }
                } else {
                        wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
                                                 MT_RXQ_RING_BASE(0) +
@@ -504,8 +511,8 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
 
                wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG;
                wed->wlan.wpdma_rx[0] = wed->wlan.phy_base + hif1_ofs +
-                                       MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) +
-                                       MT7996_RXQ_BAND0 * MT_RING_SIZE;
+                                       MT_RXQ_RING_BASE(MT7996_RXQ_BAND2) +
+                                       MT7996_RXQ_BAND2 * MT_RING_SIZE;
 
                wed->wlan.id = MT7996_DEVICE_ID_2;
                wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1;
@@ -525,9 +532,19 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
                wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base +
                                            MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) +
                                            MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE;
-               wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
-                                           MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) +
-                                           MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE;
+               if (is_mt7996(&dev->mt76)) {
+                       wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
+                                                   MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) +
+                                                   MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE;
+               } else {
+                       wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
+                                                   MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND1) +
+                                                   MT7996_RXQ_RRO_BAND1 * MT_RING_SIZE;
+                       wed->wlan.wpdma_rx[1] = wed->wlan.phy_base + hif1_ofs +
+                                               MT_RXQ_RING_BASE(MT7996_RXQ_BAND1) +
+                                               MT7996_RXQ_BAND1 * MT_RING_SIZE;
+               }
+
                wed->wlan.wpdma_rx_pg = wed->wlan.phy_base +
                                        MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) +
                                        MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE;
@@ -537,10 +554,14 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
                wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE);
 
                wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1;
-               wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1;
-
                wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1;
-               wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1;
+               if (is_mt7996(&dev->mt76)) {
+                       wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1;
+                       wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1;
+               } else {
+                       wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND1) - 1;
+                       wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND1) - 1;
+               }
 
                wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1;
                wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1;
@@ -548,16 +569,27 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
 
                wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1;
                wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1;
-               if (dev->has_rro) {
-                       wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
-                                                MT7996_RXQ_TXFREE0 * MT_RING_SIZE;
-                       wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1;
+               if (is_mt7996(&dev->mt76)) {
+                       if (dev->has_rro) {
+                               wed->wlan.wpdma_txfree = wed->wlan.phy_base +
+                                                        MT_RXQ_RING_BASE(0) +
+                                                        MT7996_RXQ_TXFREE0 * MT_RING_SIZE;
+                               wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1;
+                       } else {
+                               wed->wlan.wpdma_txfree = wed->wlan.phy_base +
+                                                        MT_RXQ_RING_BASE(0) +
+                                                        MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
+                               wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1;
+                       }
                } else {
                        wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1;
                        wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
                                                  MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
                }
                dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt;
+
+               if (dev->hif2 && is_mt7992(&dev->mt76))
+                       wed->wlan.id = 0x7992;
        }
 
        wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE;
@@ -576,8 +608,10 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
                wed->wlan.reset_complete = mt76_wed_reset_complete;
        }
 
-       if (mtk_wed_device_attach(wed))
+       if (mtk_wed_device_attach(wed)) {
+               dev->has_rro = false;
                return 0;
+       }
 
        *irq = wed->irq;
        dev->mt76.dma_dev = wed->dev;
index 9af3382003bcfecd2eed5d1384d57bdf65af7f82..f6dfd36a44c0bf587d3ac85a5a9d38e24deb14d4 100644 (file)
@@ -280,6 +280,9 @@ struct mt7996_hif {
        struct device *dev;
        void __iomem *regs;
        int irq;
+
+       enum pci_bus_speed speed;
+       enum pcie_link_width width;
 };
 
 struct mt7996_wed_rro_addr {
index f5ce50056ee94e2915fd189419905acc8cebd853..3f49bbbba3b9ccd100267f54775838ddef634766 100644 (file)
@@ -87,6 +87,7 @@ static int mt7996_pci_hif2_probe(struct pci_dev *pdev)
        hif->dev = &pdev->dev;
        hif->regs = pcim_iomap_table(pdev)[0];
        hif->irq = pdev->irq;
+       pcie_bandwidth_available(pdev, NULL, &hif->speed, &hif->width);
        spin_lock_bh(&hif_lock);
        list_add(&hif->list, &hif_list);
        spin_unlock_bh(&hif_lock);
index 070cdebcd19d7713ebae1d74fdf0c6062eb7c925..d239fa3f375f5e86f9cf650fda713a4e1e4b2f96 100644 (file)
@@ -442,6 +442,7 @@ enum offs_rev {
 #define MT_WFDMA0_PAUSE_RX_Q_RRO_TH            MT_WFDMA0(0x27c)
 
 #define WF_WFDMA0_GLO_CFG_EXT0                 MT_WFDMA0(0x2b0)
+#define WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK   GENMASK(27, 24)
 #define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD       BIT(18)
 #define WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE  BIT(14)
 
@@ -473,6 +474,9 @@ enum offs_rev {
 #define MT_WFDMA_AXI_R2A_CTRL                  MT_WFDMA_EXT_CSR(0x500)
 #define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK    GENMASK(4, 0)
 
+#define MT_WFDMA_AXI_R2A_CTRL2                 MT_WFDMA_EXT_CSR(0x508)
+#define MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK   GENMASK(31, 28)
+
 #define MT_PCIE_RECOG_ID                       0xd7090
 #define MT_PCIE_RECOG_ID_MASK                  GENMASK(30, 0)
 #define MT_PCIE_RECOG_ID_SEM                   BIT(31)