wifi: mt76: mt7996: Enable HW RRO for MT7992 chipset

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>
This commit is contained in:
Rex Lu 2025-09-09 11:45:14 +02:00 committed by Felix Fietkau
parent 3bc2f02f5c
commit eedb427eb2
3 changed files with 137 additions and 50 deletions

View File

@ -605,19 +605,21 @@ void mt7996_mac_init(struct mt7996_dev *dev)
} }
/* rro module init */ /* rro module init */
if (is_mt7996(&dev->mt76)) if (dev->hif2)
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
else
mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 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) { if (dev->has_rro) {
u16 timeout; u16 timeout;
timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128; 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_FLUSH_TIMEOUT, timeout);
mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE,
mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); is_mt7996(&dev->mt76) ? 1 : 2);
mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH,
!is_mt7996(&dev->mt76));
} else { } else {
mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); 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); 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) static int mt7996_wed_rro_init(struct mt7996_dev *dev)
{ {
#ifdef CONFIG_NET_MEDIATEK_SOC_WED #ifdef CONFIG_NET_MEDIATEK_SOC_WED
struct mtk_wed_device *wed = &dev->mt76.mmio.wed; struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0;
struct mt7996_wed_rro_addr *addr; struct mt7996_wed_rro_addr *addr;
void *ptr; void *ptr;
int i; int i;
@ -804,6 +890,20 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
dev->wed_rro.addr_elem[i].phy_addr; 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, ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr), MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr),
&dev->wed_rro.session.phy_addr, &dev->wed_rro.session.phy_addr,
@ -818,50 +918,8 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
addr++; addr++;
} }
/* rro hw init */ mt7996_rro_hw_init(dev);
/* 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);
/* rro ind cmd queue init */
return mt7996_dma_rro_init(dev); return mt7996_dma_rro_init(dev);
#else #else
return 0; return 0;
@ -900,6 +958,16 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev)
dev->wed_rro.addr_elem[i].phy_addr); 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) if (!dev->wed_rro.session.ptr)
return; return;

View File

@ -112,6 +112,7 @@
#define MT7996_CRIT_TEMP 110 #define MT7996_CRIT_TEMP 110
#define MT7996_MAX_TEMP 120 #define MT7996_MAX_TEMP 120
#define MT7996_RRO_MSDU_PG_HASH_SIZE 127
#define MT7996_RRO_MAX_SESSION 1024 #define MT7996_RRO_MAX_SESSION 1024
#define MT7996_RRO_WINDOW_MAX_LEN 1024 #define MT7996_RRO_WINDOW_MAX_LEN 1024
#define MT7996_RRO_ADDR_ELEM_LEN 128 #define MT7996_RRO_ADDR_ELEM_LEN 128
@ -128,6 +129,10 @@
#define MT7996_RX_MSDU_PAGE_SIZE (128 + \ #define MT7996_RX_MSDU_PAGE_SIZE (128 + \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) 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_vif;
struct mt7996_sta; struct mt7996_sta;
struct mt7996_dfs_pulse; struct mt7996_dfs_pulse;
@ -400,6 +405,10 @@ struct mt7996_dev {
void *ptr; void *ptr;
dma_addr_t phy_addr; dma_addr_t phy_addr;
} session; } session;
struct {
void *ptr;
dma_addr_t phy_addr;
} msdu_pg[MT7996_RRO_MSDU_PG_CR_CNT];
struct work_struct work; struct work_struct work;
struct list_head poll_list; struct list_head poll_list;

View File

@ -88,6 +88,8 @@ enum offs_rev {
#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) #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 MT_RRO_TOP(0xB8)
#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) #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_BASE1 MT_RRO_TOP(0x34)
#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) #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_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 MT_RRO_TOP(0x50)
#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) #define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16)
#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) #define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0)