]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mt76: mt7996: Enable HW RRO for MT7992 chipset
authorRex Lu <rex.lu@mediatek.com>
Tue, 9 Sep 2025 09:45:14 +0000 (11:45 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 15 Sep 2025 07:47:41 +0000 (09:47 +0200)
This is a preliminary patch to enable WED support for MT7992 Kite
chipset supported by 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-6-7d66f6eb7795@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/init.c
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
drivers/net/wireless/mediatek/mt76/mt7996/regs.h

index 21ac618d1c836aa997b12769cdbe386265b2b276..93144b5e9564792556153a1fad7bf8e4140a3385 100644 (file)
@@ -605,19 +605,21 @@ void mt7996_mac_init(struct mt7996_dev *dev)
        }
 
        /* rro module init */
-       if (is_mt7996(&dev->mt76))
-               mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
-       else
+       if (dev->hif2)
                mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE,
-                                  dev->hif2 ? 7 : 0);
+                                  is_mt7996(&dev->mt76) ? 2 : 7);
+       else
+               mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0);
 
        if (dev->has_rro) {
                u16 timeout;
 
                timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128;
                mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout);
-               mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1);
-               mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0);
+               mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE,
+                                  is_mt7996(&dev->mt76) ? 1 : 2);
+               mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH,
+                                  !is_mt7996(&dev->mt76));
        } else {
                mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
                mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
@@ -754,11 +756,95 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)
        msleep(20);
 }
 
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static void mt7996_rro_hw_init(struct mt7996_dev *dev)
+{
+       struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+       u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0;
+       int i;
+
+       if (!dev->has_rro)
+               return;
+
+       if (is_mt7992(&dev->mt76)) {
+               /* Set emul 3.0 function */
+               mt76_wr(dev, MT_RRO_3_0_EMU_CONF,
+                       MT_RRO_3_0_EMU_CONF_EN_MASK);
+               mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0,
+                       dev->wed_rro.addr_elem[0].phy_addr);
+       } else {
+               /* TODO: remove line after WM has set */
+               mt76_clear(dev, WF_RRO_AXI_MST_CFG,
+                          WF_RRO_AXI_MST_CFG_DIDX_OK);
+               /* setup BA bitmap cache address */
+               mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0,
+                       dev->wed_rro.ba_bitmap[0].phy_addr);
+               mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0);
+               mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0,
+                       dev->wed_rro.ba_bitmap[1].phy_addr);
+               mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0);
+
+               /* Setup Address element address */
+               for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+                       mt76_wr(dev, reg,
+                               dev->wed_rro.addr_elem[i].phy_addr >> 4);
+                       reg += 4;
+               }
+
+               /* Setup Address element address - separate address
+                * segment mode
+                */
+               mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
+                       MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
+       }
+       wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
+       if (is_mt7996(&dev->mt76))
+               wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION;
+       else
+               wed->wlan.ind_cmd.particular_sid = 1;
+       wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr;
+       wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN;
+       wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL;
+
+       mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00);
+       mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1,
+                MT_RRO_IND_CMD_SIGNATURE_BASE1_EN);
+
+       /* particular session configure */
+       /* use max session idx + 1 as particular session id */
+       mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr);
+
+       if (is_mt7992(&dev->mt76)) {
+               reg = MT_RRO_MSDU_PG_SEG_ADDR0;
+
+               mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG,
+                        MT_RRO_3_1_GLOBAL_CONFIG_INTERLEAVE_EN);
+
+               /* setup Msdu page address */
+               for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
+                       mt76_wr(dev, reg,
+                               dev->wed_rro.msdu_pg[i].phy_addr >> 4);
+                       reg += 4;
+               }
+               mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
+                       MT_RRO_PARTICULAR_CONFG_EN |
+                       FIELD_PREP(MT_RRO_PARTICULAR_SID, 1));
+       } else {
+               mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
+                       MT_RRO_PARTICULAR_CONFG_EN |
+                       FIELD_PREP(MT_RRO_PARTICULAR_SID,
+                                  MT7996_RRO_MAX_SESSION));
+       }
+       /* interrupt enable */
+       mt76_wr(dev, MT_RRO_HOST_INT_ENA,
+               MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
+}
+#endif
+
 static int mt7996_wed_rro_init(struct mt7996_dev *dev)
 {
 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
        struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
-       u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0;
        struct mt7996_wed_rro_addr *addr;
        void *ptr;
        int i;
@@ -804,6 +890,20 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
                        dev->wed_rro.addr_elem[i].phy_addr;
        }
 
+       for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
+               ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
+                                         MT7996_RRO_MSDU_PG_SIZE_PER_CR,
+                                         &dev->wed_rro.msdu_pg[i].phy_addr,
+                                         GFP_KERNEL);
+               if (!ptr)
+                       return -ENOMEM;
+
+               dev->wed_rro.msdu_pg[i].ptr = ptr;
+
+               memset(dev->wed_rro.msdu_pg[i].ptr, 0,
+                      MT7996_RRO_MSDU_PG_SIZE_PER_CR);
+       }
+
        ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
                                  MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr),
                                  &dev->wed_rro.session.phy_addr,
@@ -818,50 +918,8 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
                addr++;
        }
 
-       /* rro hw init */
-       /* TODO: remove line after WM has set */
-       mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK);
-
-       /* setup BA bitmap cache address */
-       mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0,
-               dev->wed_rro.ba_bitmap[0].phy_addr);
-       mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0);
-       mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0,
-               dev->wed_rro.ba_bitmap[1].phy_addr);
-       mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0);
-
-       /* setup Address element address */
-       for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
-               mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4);
-               reg += 4;
-       }
-
-       /* setup Address element address - separate address segment mode */
-       mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
-               MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
-
-       wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
-       wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION;
-       wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr;
-       wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN;
-       wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL;
-
-       mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00);
-       mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1,
-                MT_RRO_IND_CMD_SIGNATURE_BASE1_EN);
-
-       /* particular session configure */
-       /* use max session idx + 1 as particular session id */
-       mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr);
-       mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
-               MT_RRO_PARTICULAR_CONFG_EN |
-               FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION));
-
-       /* interrupt enable */
-       mt76_wr(dev, MT_RRO_HOST_INT_ENA,
-               MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
+       mt7996_rro_hw_init(dev);
 
-       /* rro ind cmd queue init */
        return mt7996_dma_rro_init(dev);
 #else
        return 0;
@@ -900,6 +958,16 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev)
                                   dev->wed_rro.addr_elem[i].phy_addr);
        }
 
+       for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
+               if (!dev->wed_rro.msdu_pg[i].ptr)
+                       continue;
+
+               dmam_free_coherent(dev->mt76.dma_dev,
+                                  MT7996_RRO_MSDU_PG_SIZE_PER_CR,
+                                  dev->wed_rro.msdu_pg[i].ptr,
+                                  dev->wed_rro.msdu_pg[i].phy_addr);
+       }
+
        if (!dev->wed_rro.session.ptr)
                return;
 
index c210dfd5e37a91ded70e09f51bca52406d7b9d53..094ea070369a8ac33a3aa692d5aaf9535c89d3d8 100644 (file)
 #define MT7996_CRIT_TEMP               110
 #define MT7996_MAX_TEMP                        120
 
+#define MT7996_RRO_MSDU_PG_HASH_SIZE   127
 #define MT7996_RRO_MAX_SESSION         1024
 #define MT7996_RRO_WINDOW_MAX_LEN      1024
 #define MT7996_RRO_ADDR_ELEM_LEN       128
 #define MT7996_RX_MSDU_PAGE_SIZE       (128 + \
                                         SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
+/* RRO 3.1 */
+#define MT7996_RRO_MSDU_PG_CR_CNT      8
+#define MT7996_RRO_MSDU_PG_SIZE_PER_CR 0x10000
+
 struct mt7996_vif;
 struct mt7996_sta;
 struct mt7996_dfs_pulse;
@@ -400,6 +405,10 @@ struct mt7996_dev {
                        void *ptr;
                        dma_addr_t phy_addr;
                } session;
+               struct {
+                       void *ptr;
+                       dma_addr_t phy_addr;
+               } msdu_pg[MT7996_RRO_MSDU_PG_CR_CNT];
 
                struct work_struct work;
                struct list_head poll_list;
index 4b8bc008ab3143dcf44cd40b17b9f09778cfd464..070cdebcd19d7713ebae1d74fdf0c6062eb7c925 100644 (file)
@@ -88,6 +88,8 @@ enum offs_rev {
 #define MT_RRO_BA_BITMAP_BASE1                 MT_RRO_TOP(0xC)
 #define WF_RRO_AXI_MST_CFG                     MT_RRO_TOP(0xB8)
 #define WF_RRO_AXI_MST_CFG_DIDX_OK             BIT(12)
+
+#define MT_RRO_ADDR_ARRAY_BASE0                        MT_RRO_TOP(0x30)
 #define MT_RRO_ADDR_ARRAY_BASE1                        MT_RRO_TOP(0x34)
 #define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE   BIT(31)
 
@@ -108,6 +110,14 @@ enum offs_rev {
 
 #define MT_RRO_ADDR_ELEM_SEG_ADDR0             MT_RRO_TOP(0x400)
 
+#define MT_RRO_3_0_EMU_CONF                    MT_RRO_TOP(0x600)
+#define MT_RRO_3_0_EMU_CONF_EN_MASK            BIT(11)
+
+#define MT_RRO_3_1_GLOBAL_CONFIG               MT_RRO_TOP(0x604)
+#define MT_RRO_3_1_GLOBAL_CONFIG_INTERLEAVE_EN BIT(0)
+
+#define MT_RRO_MSDU_PG_SEG_ADDR0               MT_RRO_TOP(0x620)
+
 #define MT_RRO_ACK_SN_CTRL                     MT_RRO_TOP(0x50)
 #define MT_RRO_ACK_SN_CTRL_SN_MASK             GENMASK(27, 16)
 #define MT_RRO_ACK_SN_CTRL_SESSION_MASK                GENMASK(11, 0)