linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
@ 2025-04-12  9:49 Shengyu Qu
  0 siblings, 0 replies; 8+ messages in thread
From: Shengyu Qu @ 2025-04-12  9:49 UTC (permalink / raw)
  To: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, matthias.bgg,
	angelogioacchino.delregno, johannes.berg, miriam.rachel.korenblit,
	nicolas.cavallari, christophe.jaillet, benjamin-jw.lin,
	StanleyYP.Wang, quic_adisi, deren.wu, chui-hao.chiu, bo.jiao,
	gustavoars, razvan.grigore, linux-wireless, linux-kernel,
	linux-arm-kernel, linux-mediatek
  Cc: Shengyu Qu, Ping-Ke Shih, Sujuan Chen

The current WED only supports 256 wcid, whereas mt7986 can support up to
512 entries, so firmware provides a rule to get sta_info by DA when wcid
is set to 0x3ff by txd. Also, WED provides a register to overwrite txd
wcid, that is, wcid[9:8] can be overwritten by 0x3 and wcid[7:0] is set
to 0xff by host driver.

However, firmware is unable to get sta_info from DA as DA != RA for
4addr cases, so firmware and wifi host driver both use wcid (256 - 271)
and (768 ~ 783) for sync up to get correct sta_info.

Currently WDS+WED config is completely broken on MT7986/7981 devices if
without this patch.

Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
Tested-by: Sujuan Chen <sujuan.chen@mediatek.com>
Co-developed-by: Bo Jiao <bo.jiao@mediatek.com>
Signed-off-by: Bo Jiao <bo.jiao@mediatek.com>
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
---
Changes since v1:
 - Drop duplicate setting in mmio
 - Reduce the patch size by redefining mt76_wcid_alloc
Changes since v2:
 - Rework wds wcid getting flow
Changes since v3:
 - Rebase to next-20240703
 - Sync with downstream patch
Changes since v4:
 - Rebase to next-20240802
Changes since v5:
 - Fixed build test error reported by robot
 - Rebase to next-20240805
Changes since v6:
 - Fix potential race conditions on tx/rx packets during the transition
 - Rebase to Felix's newest codebase
Changes since v7:
 - Fix build fail
Changes since v8:
 - Changed code as Shih advised
Changes since v9:
 - Changed code as Shih advised
 - Moved mt76_wcid_alloc to mt76.h
---
 drivers/net/wireless/mediatek/mt76/mt76.h     | 15 ++++++
 .../net/wireless/mediatek/mt76/mt7915/main.c  | 53 +++++++++++++++++--
 .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 18 +++++--
 .../net/wireless/mediatek/mt76/mt7915/mcu.h   |  1 +
 drivers/net/wireless/mediatek/mt76/util.c     | 37 +++++++++++--
 drivers/net/wireless/mediatek/mt76/util.h     |  2 +-
 6 files changed, 115 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index d7cd467b812f..7f590854959e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -28,6 +28,9 @@
 
 #define MT76_TOKEN_FREE_THR	64
 
+#define MT76_WED_WDS_MIN    256
+#define MT76_WED_WDS_MAX    272
+
 #define MT_QFLAG_WED_RING	GENMASK(1, 0)
 #define MT_QFLAG_WED_TYPE	GENMASK(4, 2)
 #define MT_QFLAG_WED		BIT(5)
@@ -73,6 +76,12 @@ enum mt76_wed_type {
 	MT76_WED_RRO_Q_IND,
 };
 
+enum mt76_wed_state {
+	MT76_WED_DEFAULT,
+	MT76_WED_ACTIVE,
+	MT76_WED_WDS_ACTIVE,
+};
+
 struct mt76_bus_ops {
 	u32 (*rr)(struct mt76_dev *dev, u32 offset);
 	void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
@@ -1169,6 +1178,12 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
 int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			  struct net_device *netdev, enum tc_setup_type type,
 			  void *type_data);
+
+static inline int mt76_wcid_alloc(u32 *mask, int size)
+{
+	return __mt76_wcid_alloc(mask, size, MT76_WED_DEFAULT);
+}
+
 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
 u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
 int mt76_wed_offload_enable(struct mtk_wed_device *wed);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 3aa31c5cefa6..fcbf4f971026 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -744,9 +744,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 	bool ext_phy = mvif->phy != &dev->phy;
+	u8 flags = MT76_WED_DEFAULT;
 	int idx;
 
-	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+	    !is_mt7915(&dev->mt76)) {
+		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
+		       MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
+	}
+
+	idx = __mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA, flags);
 	if (idx < 0)
 		return -ENOSPC;
 
@@ -1271,6 +1278,11 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
 {
 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+	int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
+	struct ieee80211_sta *pre_sta;
+	struct mt7915_sta *pre_msta;
+	u8 flags = MT76_WED_DEFAULT;
+	int tmp_idx;
 
 	if (enabled)
 		set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
@@ -1280,6 +1292,37 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
 	if (!msta->wcid.sta)
 		return;
 
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+	    !is_mt7915(&dev->mt76) &&
+	    (msta->wcid.idx < min || msta->wcid.idx > max - 1)) {
+		pre_sta = kmemdup(sta, sizeof(*sta) + sizeof(*msta), GFP_KERNEL | __GFP_ZERO);
+		if (!pre_sta)
+			goto error_alloc;
+		pre_msta = (struct mt7915_sta *)pre_sta->drv_priv;
+
+		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
+			MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
+
+		tmp_idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA, flags);
+		if (tmp_idx < 0)
+			goto error_wcid;
+		pre_msta->wcid.idx = (u16)tmp_idx;
+		mt7915_mac_sta_add(&dev->mt76, vif, pre_sta);
+		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], &msta->wcid);
+
+		tmp_idx = msta->wcid.idx;
+		msta->wcid.idx = pre_msta->wcid.idx;
+		pre_msta->wcid.idx = (u16)tmp_idx;
+		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], NULL);
+
+		synchronize_rcu();
+		mt7915_mac_sta_remove(&dev->mt76, vif, pre_sta);
+
+error_wcid:
+		kfree(pre_sta);
+	}
+
+error_alloc:
 	mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
 }
 
@@ -1726,15 +1769,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
 	if (!mtk_wed_device_active(wed))
 		return -ENODEV;
 
-	if (msta->wcid.idx > 0xff)
+	if (msta->wcid.idx > MT7915_WTBL_STA)
 		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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
 	path->mtk_wdma.queue = phy != &dev->phy;
+	if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
+	    is_mt7915(&dev->mt76))
+		path->mtk_wdma.wcid = msta->wcid.idx;
+	else
+		path->mtk_wdma.wcid = 0x3ff;
 
 	ctx->dev = NULL;
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 427542777abc..61a854d2c416 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -2403,10 +2403,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
 
 	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
 
-	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
-	     is_mt7915(&dev->mt76)) ||
-	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
-		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+		if (is_mt7915(&dev->mt76) ||
+		    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
+			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
+						0, 0, 0);
+		else
+			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
+						MCU_WA_PARAM_WED_VERSION,
+						dev->mt76.mmio.wed.rev_id, 0);
+		if (ret)
+			return ret;
+	}
+#endif
 
 	ret = mt7915_mcu_set_mwds(dev, 1);
 	if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 086ad89ecd91..989f24cb49eb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -278,6 +278,7 @@ enum {
 	MCU_WA_PARAM_PDMA_RX = 0x04,
 	MCU_WA_PARAM_CPU_UTIL = 0x0b,
 	MCU_WA_PARAM_RED = 0x0e,
+	MCU_WA_PARAM_WED_VERSION = 0x32,
 	MCU_WA_PARAM_RED_SETTING = 0x40,
 };
 
diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
index 95b3dc96e4c4..e80bef2b33a1 100644
--- a/drivers/net/wireless/mediatek/mt76/util.c
+++ b/drivers/net/wireless/mediatek/mt76/util.c
@@ -42,8 +42,10 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
 }
 EXPORT_SYMBOL_GPL(____mt76_poll_msec);
 
-int mt76_wcid_alloc(u32 *mask, int size)
+int __mt76_wcid_alloc(u32 *mask, int size, u8 flag)
 {
+	int max = MT76_WED_WDS_MAX;
+	int min = MT76_WED_WDS_MIN;
 	int i, idx = 0, cur;
 
 	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
@@ -53,16 +55,45 @@ int mt76_wcid_alloc(u32 *mask, int size)
 
 		idx--;
 		cur = i * 32 + idx;
-		if (cur >= size)
+
+		switch (flag) {
+		case MT76_WED_ACTIVE:
+			if (cur >= min && cur < max)
+				continue;
+
+			if (cur >= size) {
+				u32 end = max - min - 1;
+
+				i = min / 32;
+				idx = ffs(~mask[i] & GENMASK(end, 0));
+				if (!idx)
+					goto error;
+				idx--;
+				cur = min + idx;
+			}
+
 			break;
+		case MT76_WED_WDS_ACTIVE:
+			if (cur < min)
+				continue;
+			if (cur >= max)
+				goto error;
+
+			break;
+		default:
+			if (cur >= size)
+				goto error;
+			break;
+		}
 
 		mask[i] |= BIT(idx);
 		return cur;
 	}
 
+error:
 	return -1;
 }
-EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
+EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
 
 int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
 {
diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
index 260965dde94c..fe95a847182e 100644
--- a/drivers/net/wireless/mediatek/mt76/util.h
+++ b/drivers/net/wireless/mediatek/mt76/util.h
@@ -27,7 +27,7 @@ enum {
 #define MT76_INCR(_var, _size) \
 	(_var = (((_var) + 1) % (_size)))
 
-int mt76_wcid_alloc(u32 *mask, int size);
+int __mt76_wcid_alloc(u32 *mask, int size, u8 flags);
 
 static inline void
 mt76_wcid_mask_set(u32 *mask, int idx)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
@ 2025-04-21 14:04 Shengyu Qu
  2025-05-18 14:41 ` Shengyu Qu
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Shengyu Qu @ 2025-04-21 14:04 UTC (permalink / raw)
  To: nbd, pkshih, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno, johannes.berg,
	miriam.rachel.korenblit, christophe.jaillet, greearb,
	howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: Shengyu Qu, Sujuan Chen, Bo Jiao

The current WED only supports 256 wcid, whereas mt7986 can support up to
512 entries, so firmware provides a rule to get sta_info by DA when wcid
is set to 0x3ff by txd. Also, WED provides a register to overwrite txd
wcid, that is, wcid[9:8] can be overwritten by 0x3 and wcid[7:0] is set
to 0xff by host driver.

However, firmware is unable to get sta_info from DA as DA != RA for
4addr cases, so firmware and wifi host driver both use wcid (256 - 271)
and (768 ~ 783) for sync up to get correct sta_info.

Currently WDS+WED config is completely broken on MT7986/7981 devices if
without this patch.

Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
Tested-by: Sujuan Chen <sujuan.chen@mediatek.com>
Co-developed-by: Bo Jiao <bo.jiao@mediatek.com>
Signed-off-by: Bo Jiao <bo.jiao@mediatek.com>
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
---
Changes since v1:
 - Drop duplicate setting in mmio
 - Reduce the patch size by redefining mt76_wcid_alloc
Changes since v2:
 - Rework wds wcid getting flow
Changes since v3:
 - Rebase to next-20240703
 - Sync with downstream patch
Changes since v4:
 - Rebase to next-20240802
Changes since v5:
 - Fixed build test error reported by robot
 - Rebase to next-20240805
Changes since v6:
 - Fix potential race conditions on tx/rx packets during the transition
 - Rebase to Felix's newest codebase
Changes since v7:
 - Fix build fail
Changes since v8:
 - Changed code as Shih advised
Changes since v9:
 - Changed code as Shih advised
 - Moved mt76_wcid_alloc to mt76.h
---
 drivers/net/wireless/mediatek/mt76/mt76.h     | 15 ++++++
 .../net/wireless/mediatek/mt76/mt7915/main.c  | 53 +++++++++++++++++--
 .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 18 +++++--
 .../net/wireless/mediatek/mt76/mt7915/mcu.h   |  1 +
 drivers/net/wireless/mediatek/mt76/util.c     | 37 +++++++++++--
 drivers/net/wireless/mediatek/mt76/util.h     |  2 +-
 6 files changed, 115 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index d7cd467b812f..7f590854959e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -28,6 +28,9 @@
 
 #define MT76_TOKEN_FREE_THR	64
 
+#define MT76_WED_WDS_MIN    256
+#define MT76_WED_WDS_MAX    272
+
 #define MT_QFLAG_WED_RING	GENMASK(1, 0)
 #define MT_QFLAG_WED_TYPE	GENMASK(4, 2)
 #define MT_QFLAG_WED		BIT(5)
@@ -73,6 +76,12 @@ enum mt76_wed_type {
 	MT76_WED_RRO_Q_IND,
 };
 
+enum mt76_wed_state {
+	MT76_WED_DEFAULT,
+	MT76_WED_ACTIVE,
+	MT76_WED_WDS_ACTIVE,
+};
+
 struct mt76_bus_ops {
 	u32 (*rr)(struct mt76_dev *dev, u32 offset);
 	void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
@@ -1169,6 +1178,12 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
 int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			  struct net_device *netdev, enum tc_setup_type type,
 			  void *type_data);
+
+static inline int mt76_wcid_alloc(u32 *mask, int size)
+{
+	return __mt76_wcid_alloc(mask, size, MT76_WED_DEFAULT);
+}
+
 #ifdef CONFIG_NET_MEDIATEK_SOC_WED
 u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
 int mt76_wed_offload_enable(struct mtk_wed_device *wed);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 3aa31c5cefa6..fcbf4f971026 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -744,9 +744,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 	bool ext_phy = mvif->phy != &dev->phy;
+	u8 flags = MT76_WED_DEFAULT;
 	int idx;
 
-	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+	    !is_mt7915(&dev->mt76)) {
+		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
+		       MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
+	}
+
+	idx = __mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA, flags);
 	if (idx < 0)
 		return -ENOSPC;
 
@@ -1271,6 +1278,11 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
 {
 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+	int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
+	struct ieee80211_sta *pre_sta;
+	struct mt7915_sta *pre_msta;
+	u8 flags = MT76_WED_DEFAULT;
+	int tmp_idx;
 
 	if (enabled)
 		set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
@@ -1280,6 +1292,37 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
 	if (!msta->wcid.sta)
 		return;
 
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+	    !is_mt7915(&dev->mt76) &&
+	    (msta->wcid.idx < min || msta->wcid.idx > max - 1)) {
+		pre_sta = kmemdup(sta, sizeof(*sta) + sizeof(*msta), GFP_KERNEL | __GFP_ZERO);
+		if (!pre_sta)
+			goto error_alloc;
+		pre_msta = (struct mt7915_sta *)pre_sta->drv_priv;
+
+		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
+			MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
+
+		tmp_idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA, flags);
+		if (tmp_idx < 0)
+			goto error_wcid;
+		pre_msta->wcid.idx = (u16)tmp_idx;
+		mt7915_mac_sta_add(&dev->mt76, vif, pre_sta);
+		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], &msta->wcid);
+
+		tmp_idx = msta->wcid.idx;
+		msta->wcid.idx = pre_msta->wcid.idx;
+		pre_msta->wcid.idx = (u16)tmp_idx;
+		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], NULL);
+
+		synchronize_rcu();
+		mt7915_mac_sta_remove(&dev->mt76, vif, pre_sta);
+
+error_wcid:
+		kfree(pre_sta);
+	}
+
+error_alloc:
 	mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
 }
 
@@ -1726,15 +1769,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
 	if (!mtk_wed_device_active(wed))
 		return -ENODEV;
 
-	if (msta->wcid.idx > 0xff)
+	if (msta->wcid.idx > MT7915_WTBL_STA)
 		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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
 	path->mtk_wdma.queue = phy != &dev->phy;
+	if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
+	    is_mt7915(&dev->mt76))
+		path->mtk_wdma.wcid = msta->wcid.idx;
+	else
+		path->mtk_wdma.wcid = 0x3ff;
 
 	ctx->dev = NULL;
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 427542777abc..61a854d2c416 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -2403,10 +2403,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
 
 	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
 
-	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
-	     is_mt7915(&dev->mt76)) ||
-	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
-		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+		if (is_mt7915(&dev->mt76) ||
+		    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
+			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
+						0, 0, 0);
+		else
+			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
+						MCU_WA_PARAM_WED_VERSION,
+						dev->mt76.mmio.wed.rev_id, 0);
+		if (ret)
+			return ret;
+	}
+#endif
 
 	ret = mt7915_mcu_set_mwds(dev, 1);
 	if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 086ad89ecd91..989f24cb49eb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -278,6 +278,7 @@ enum {
 	MCU_WA_PARAM_PDMA_RX = 0x04,
 	MCU_WA_PARAM_CPU_UTIL = 0x0b,
 	MCU_WA_PARAM_RED = 0x0e,
+	MCU_WA_PARAM_WED_VERSION = 0x32,
 	MCU_WA_PARAM_RED_SETTING = 0x40,
 };
 
diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
index 95b3dc96e4c4..e80bef2b33a1 100644
--- a/drivers/net/wireless/mediatek/mt76/util.c
+++ b/drivers/net/wireless/mediatek/mt76/util.c
@@ -42,8 +42,10 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
 }
 EXPORT_SYMBOL_GPL(____mt76_poll_msec);
 
-int mt76_wcid_alloc(u32 *mask, int size)
+int __mt76_wcid_alloc(u32 *mask, int size, u8 flag)
 {
+	int max = MT76_WED_WDS_MAX;
+	int min = MT76_WED_WDS_MIN;
 	int i, idx = 0, cur;
 
 	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
@@ -53,16 +55,45 @@ int mt76_wcid_alloc(u32 *mask, int size)
 
 		idx--;
 		cur = i * 32 + idx;
-		if (cur >= size)
+
+		switch (flag) {
+		case MT76_WED_ACTIVE:
+			if (cur >= min && cur < max)
+				continue;
+
+			if (cur >= size) {
+				u32 end = max - min - 1;
+
+				i = min / 32;
+				idx = ffs(~mask[i] & GENMASK(end, 0));
+				if (!idx)
+					goto error;
+				idx--;
+				cur = min + idx;
+			}
+
 			break;
+		case MT76_WED_WDS_ACTIVE:
+			if (cur < min)
+				continue;
+			if (cur >= max)
+				goto error;
+
+			break;
+		default:
+			if (cur >= size)
+				goto error;
+			break;
+		}
 
 		mask[i] |= BIT(idx);
 		return cur;
 	}
 
+error:
 	return -1;
 }
-EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
+EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
 
 int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
 {
diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
index 260965dde94c..fe95a847182e 100644
--- a/drivers/net/wireless/mediatek/mt76/util.h
+++ b/drivers/net/wireless/mediatek/mt76/util.h
@@ -27,7 +27,7 @@ enum {
 #define MT76_INCR(_var, _size) \
 	(_var = (((_var) + 1) % (_size)))
 
-int mt76_wcid_alloc(u32 *mask, int size);
+int __mt76_wcid_alloc(u32 *mask, int size, u8 flags);
 
 static inline void
 mt76_wcid_mask_set(u32 *mask, int idx)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
  2025-04-21 14:04 [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled Shengyu Qu
@ 2025-05-18 14:41 ` Shengyu Qu
  2025-05-25 13:42 ` Shengyu Qu
  2025-06-24 14:11 ` Shengyu Qu
  2 siblings, 0 replies; 8+ messages in thread
From: Shengyu Qu @ 2025-05-18 14:41 UTC (permalink / raw)
  To: nbd
  Cc: wiagn233, Sujuan Chen, Bo Jiao, pkshih, lorenzo, ryder.lee,
	shayne.chen, sean.wang, matthias.bgg, angelogioacchino.delregno,
	johannes.berg, miriam.rachel.korenblit, christophe.jaillet,
	greearb, howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek


[-- Attachment #1.1.1: Type: text/plain, Size: 11032 bytes --]

Hi Felix,

Do you think this patch is ok to merge?

Best regards,
Shengyu

在 2025/4/21 22:04, Shengyu Qu 写道:
> The current WED only supports 256 wcid, whereas mt7986 can support up to
> 512 entries, so firmware provides a rule to get sta_info by DA when wcid
> is set to 0x3ff by txd. Also, WED provides a register to overwrite txd
> wcid, that is, wcid[9:8] can be overwritten by 0x3 and wcid[7:0] is set
> to 0xff by host driver.
> 
> However, firmware is unable to get sta_info from DA as DA != RA for
> 4addr cases, so firmware and wifi host driver both use wcid (256 - 271)
> and (768 ~ 783) for sync up to get correct sta_info.
> 
> Currently WDS+WED config is completely broken on MT7986/7981 devices if
> without this patch.
> 
> Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
> Tested-by: Sujuan Chen <sujuan.chen@mediatek.com>
> Co-developed-by: Bo Jiao <bo.jiao@mediatek.com>
> Signed-off-by: Bo Jiao <bo.jiao@mediatek.com>
> Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
> Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
> ---
> Changes since v1:
>   - Drop duplicate setting in mmio
>   - Reduce the patch size by redefining mt76_wcid_alloc
> Changes since v2:
>   - Rework wds wcid getting flow
> Changes since v3:
>   - Rebase to next-20240703
>   - Sync with downstream patch
> Changes since v4:
>   - Rebase to next-20240802
> Changes since v5:
>   - Fixed build test error reported by robot
>   - Rebase to next-20240805
> Changes since v6:
>   - Fix potential race conditions on tx/rx packets during the transition
>   - Rebase to Felix's newest codebase
> Changes since v7:
>   - Fix build fail
> Changes since v8:
>   - Changed code as Shih advised
> Changes since v9:
>   - Changed code as Shih advised
>   - Moved mt76_wcid_alloc to mt76.h
> ---
>   drivers/net/wireless/mediatek/mt76/mt76.h     | 15 ++++++
>   .../net/wireless/mediatek/mt76/mt7915/main.c  | 53 +++++++++++++++++--
>   .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 18 +++++--
>   .../net/wireless/mediatek/mt76/mt7915/mcu.h   |  1 +
>   drivers/net/wireless/mediatek/mt76/util.c     | 37 +++++++++++--
>   drivers/net/wireless/mediatek/mt76/util.h     |  2 +-
>   6 files changed, 115 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index d7cd467b812f..7f590854959e 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -28,6 +28,9 @@
>   
>   #define MT76_TOKEN_FREE_THR	64
>   
> +#define MT76_WED_WDS_MIN    256
> +#define MT76_WED_WDS_MAX    272
> +
>   #define MT_QFLAG_WED_RING	GENMASK(1, 0)
>   #define MT_QFLAG_WED_TYPE	GENMASK(4, 2)
>   #define MT_QFLAG_WED		BIT(5)
> @@ -73,6 +76,12 @@ enum mt76_wed_type {
>   	MT76_WED_RRO_Q_IND,
>   };
>   
> +enum mt76_wed_state {
> +	MT76_WED_DEFAULT,
> +	MT76_WED_ACTIVE,
> +	MT76_WED_WDS_ACTIVE,
> +};
> +
>   struct mt76_bus_ops {
>   	u32 (*rr)(struct mt76_dev *dev, u32 offset);
>   	void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
> @@ -1169,6 +1178,12 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
>   int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>   			  struct net_device *netdev, enum tc_setup_type type,
>   			  void *type_data);
> +
> +static inline int mt76_wcid_alloc(u32 *mask, int size)
> +{
> +	return __mt76_wcid_alloc(mask, size, MT76_WED_DEFAULT);
> +}
> +
>   #ifdef CONFIG_NET_MEDIATEK_SOC_WED
>   u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
>   int mt76_wed_offload_enable(struct mtk_wed_device *wed);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> index 3aa31c5cefa6..fcbf4f971026 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> @@ -744,9 +744,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
>   	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
>   	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
>   	bool ext_phy = mvif->phy != &dev->phy;
> +	u8 flags = MT76_WED_DEFAULT;
>   	int idx;
>   
> -	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +	    !is_mt7915(&dev->mt76)) {
> +		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
> +		       MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
> +	}
> +
> +	idx = __mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA, flags);
>   	if (idx < 0)
>   		return -ENOSPC;
>   
> @@ -1271,6 +1278,11 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>   {
>   	struct mt7915_dev *dev = mt7915_hw_dev(hw);
>   	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
> +	int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
> +	struct ieee80211_sta *pre_sta;
> +	struct mt7915_sta *pre_msta;
> +	u8 flags = MT76_WED_DEFAULT;
> +	int tmp_idx;
>   
>   	if (enabled)
>   		set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
> @@ -1280,6 +1292,37 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>   	if (!msta->wcid.sta)
>   		return;
>   
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +	    !is_mt7915(&dev->mt76) &&
> +	    (msta->wcid.idx < min || msta->wcid.idx > max - 1)) {
> +		pre_sta = kmemdup(sta, sizeof(*sta) + sizeof(*msta), GFP_KERNEL | __GFP_ZERO);
> +		if (!pre_sta)
> +			goto error_alloc;
> +		pre_msta = (struct mt7915_sta *)pre_sta->drv_priv;
> +
> +		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
> +			MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
> +
> +		tmp_idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA, flags);
> +		if (tmp_idx < 0)
> +			goto error_wcid;
> +		pre_msta->wcid.idx = (u16)tmp_idx;
> +		mt7915_mac_sta_add(&dev->mt76, vif, pre_sta);
> +		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], &msta->wcid);
> +
> +		tmp_idx = msta->wcid.idx;
> +		msta->wcid.idx = pre_msta->wcid.idx;
> +		pre_msta->wcid.idx = (u16)tmp_idx;
> +		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], NULL);
> +
> +		synchronize_rcu();
> +		mt7915_mac_sta_remove(&dev->mt76, vif, pre_sta);
> +
> +error_wcid:
> +		kfree(pre_sta);
> +	}
> +
> +error_alloc:
>   	mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
>   }
>   
> @@ -1726,15 +1769,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
>   	if (!mtk_wed_device_active(wed))
>   		return -ENODEV;
>   
> -	if (msta->wcid.idx > 0xff)
> +	if (msta->wcid.idx > MT7915_WTBL_STA)
>   		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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
>   	path->mtk_wdma.queue = phy != &dev->phy;
> +	if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
> +	    is_mt7915(&dev->mt76))
> +		path->mtk_wdma.wcid = msta->wcid.idx;
> +	else
> +		path->mtk_wdma.wcid = 0x3ff;
>   
>   	ctx->dev = NULL;
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> index 427542777abc..61a854d2c416 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> @@ -2403,10 +2403,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
>   
>   	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
>   
> -	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> -	     is_mt7915(&dev->mt76)) ||
> -	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> -		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
> +#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
> +		if (is_mt7915(&dev->mt76) ||
> +		    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> +			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
> +						0, 0, 0);
> +		else
> +			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
> +						MCU_WA_PARAM_WED_VERSION,
> +						dev->mt76.mmio.wed.rev_id, 0);
> +		if (ret)
> +			return ret;
> +	}
> +#endif
>   
>   	ret = mt7915_mcu_set_mwds(dev, 1);
>   	if (ret)
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> index 086ad89ecd91..989f24cb49eb 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> @@ -278,6 +278,7 @@ enum {
>   	MCU_WA_PARAM_PDMA_RX = 0x04,
>   	MCU_WA_PARAM_CPU_UTIL = 0x0b,
>   	MCU_WA_PARAM_RED = 0x0e,
> +	MCU_WA_PARAM_WED_VERSION = 0x32,
>   	MCU_WA_PARAM_RED_SETTING = 0x40,
>   };
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
> index 95b3dc96e4c4..e80bef2b33a1 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.c
> +++ b/drivers/net/wireless/mediatek/mt76/util.c
> @@ -42,8 +42,10 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
>   }
>   EXPORT_SYMBOL_GPL(____mt76_poll_msec);
>   
> -int mt76_wcid_alloc(u32 *mask, int size)
> +int __mt76_wcid_alloc(u32 *mask, int size, u8 flag)
>   {
> +	int max = MT76_WED_WDS_MAX;
> +	int min = MT76_WED_WDS_MIN;
>   	int i, idx = 0, cur;
>   
>   	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
> @@ -53,16 +55,45 @@ int mt76_wcid_alloc(u32 *mask, int size)
>   
>   		idx--;
>   		cur = i * 32 + idx;
> -		if (cur >= size)
> +
> +		switch (flag) {
> +		case MT76_WED_ACTIVE:
> +			if (cur >= min && cur < max)
> +				continue;
> +
> +			if (cur >= size) {
> +				u32 end = max - min - 1;
> +
> +				i = min / 32;
> +				idx = ffs(~mask[i] & GENMASK(end, 0));
> +				if (!idx)
> +					goto error;
> +				idx--;
> +				cur = min + idx;
> +			}
> +
>   			break;
> +		case MT76_WED_WDS_ACTIVE:
> +			if (cur < min)
> +				continue;
> +			if (cur >= max)
> +				goto error;
> +
> +			break;
> +		default:
> +			if (cur >= size)
> +				goto error;
> +			break;
> +		}
>   
>   		mask[i] |= BIT(idx);
>   		return cur;
>   	}
>   
> +error:
>   	return -1;
>   }
> -EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
> +EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
>   
>   int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
>   {
> diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
> index 260965dde94c..fe95a847182e 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.h
> +++ b/drivers/net/wireless/mediatek/mt76/util.h
> @@ -27,7 +27,7 @@ enum {
>   #define MT76_INCR(_var, _size) \
>   	(_var = (((_var) + 1) % (_size)))
>   
> -int mt76_wcid_alloc(u32 *mask, int size);
> +int __mt76_wcid_alloc(u32 *mask, int size, u8 flags);
>   
>   static inline void
>   mt76_wcid_mask_set(u32 *mask, int idx)


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 6977 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
  2025-04-21 14:04 [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled Shengyu Qu
  2025-05-18 14:41 ` Shengyu Qu
@ 2025-05-25 13:42 ` Shengyu Qu
  2025-06-24 14:11 ` Shengyu Qu
  2 siblings, 0 replies; 8+ messages in thread
From: Shengyu Qu @ 2025-05-25 13:42 UTC (permalink / raw)
  To: nbd, pkshih, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno, johannes.berg,
	miriam.rachel.korenblit, christophe.jaillet, greearb,
	howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: wiagn233, Sujuan Chen, Bo Jiao


[-- Attachment #1.1.1: Type: text/plain, Size: 10965 bytes --]

Ping again.

在 2025/4/21 22:04, Shengyu Qu 写道:
> The current WED only supports 256 wcid, whereas mt7986 can support up to
> 512 entries, so firmware provides a rule to get sta_info by DA when wcid
> is set to 0x3ff by txd. Also, WED provides a register to overwrite txd
> wcid, that is, wcid[9:8] can be overwritten by 0x3 and wcid[7:0] is set
> to 0xff by host driver.
> 
> However, firmware is unable to get sta_info from DA as DA != RA for
> 4addr cases, so firmware and wifi host driver both use wcid (256 - 271)
> and (768 ~ 783) for sync up to get correct sta_info.
> 
> Currently WDS+WED config is completely broken on MT7986/7981 devices if
> without this patch.
> 
> Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
> Tested-by: Sujuan Chen <sujuan.chen@mediatek.com>
> Co-developed-by: Bo Jiao <bo.jiao@mediatek.com>
> Signed-off-by: Bo Jiao <bo.jiao@mediatek.com>
> Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
> Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
> ---
> Changes since v1:
>   - Drop duplicate setting in mmio
>   - Reduce the patch size by redefining mt76_wcid_alloc
> Changes since v2:
>   - Rework wds wcid getting flow
> Changes since v3:
>   - Rebase to next-20240703
>   - Sync with downstream patch
> Changes since v4:
>   - Rebase to next-20240802
> Changes since v5:
>   - Fixed build test error reported by robot
>   - Rebase to next-20240805
> Changes since v6:
>   - Fix potential race conditions on tx/rx packets during the transition
>   - Rebase to Felix's newest codebase
> Changes since v7:
>   - Fix build fail
> Changes since v8:
>   - Changed code as Shih advised
> Changes since v9:
>   - Changed code as Shih advised
>   - Moved mt76_wcid_alloc to mt76.h
> ---
>   drivers/net/wireless/mediatek/mt76/mt76.h     | 15 ++++++
>   .../net/wireless/mediatek/mt76/mt7915/main.c  | 53 +++++++++++++++++--
>   .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 18 +++++--
>   .../net/wireless/mediatek/mt76/mt7915/mcu.h   |  1 +
>   drivers/net/wireless/mediatek/mt76/util.c     | 37 +++++++++++--
>   drivers/net/wireless/mediatek/mt76/util.h     |  2 +-
>   6 files changed, 115 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index d7cd467b812f..7f590854959e 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -28,6 +28,9 @@
>   
>   #define MT76_TOKEN_FREE_THR	64
>   
> +#define MT76_WED_WDS_MIN    256
> +#define MT76_WED_WDS_MAX    272
> +
>   #define MT_QFLAG_WED_RING	GENMASK(1, 0)
>   #define MT_QFLAG_WED_TYPE	GENMASK(4, 2)
>   #define MT_QFLAG_WED		BIT(5)
> @@ -73,6 +76,12 @@ enum mt76_wed_type {
>   	MT76_WED_RRO_Q_IND,
>   };
>   
> +enum mt76_wed_state {
> +	MT76_WED_DEFAULT,
> +	MT76_WED_ACTIVE,
> +	MT76_WED_WDS_ACTIVE,
> +};
> +
>   struct mt76_bus_ops {
>   	u32 (*rr)(struct mt76_dev *dev, u32 offset);
>   	void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
> @@ -1169,6 +1178,12 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
>   int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>   			  struct net_device *netdev, enum tc_setup_type type,
>   			  void *type_data);
> +
> +static inline int mt76_wcid_alloc(u32 *mask, int size)
> +{
> +	return __mt76_wcid_alloc(mask, size, MT76_WED_DEFAULT);
> +}
> +
>   #ifdef CONFIG_NET_MEDIATEK_SOC_WED
>   u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
>   int mt76_wed_offload_enable(struct mtk_wed_device *wed);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> index 3aa31c5cefa6..fcbf4f971026 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> @@ -744,9 +744,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
>   	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
>   	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
>   	bool ext_phy = mvif->phy != &dev->phy;
> +	u8 flags = MT76_WED_DEFAULT;
>   	int idx;
>   
> -	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +	    !is_mt7915(&dev->mt76)) {
> +		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
> +		       MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
> +	}
> +
> +	idx = __mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA, flags);
>   	if (idx < 0)
>   		return -ENOSPC;
>   
> @@ -1271,6 +1278,11 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>   {
>   	struct mt7915_dev *dev = mt7915_hw_dev(hw);
>   	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
> +	int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
> +	struct ieee80211_sta *pre_sta;
> +	struct mt7915_sta *pre_msta;
> +	u8 flags = MT76_WED_DEFAULT;
> +	int tmp_idx;
>   
>   	if (enabled)
>   		set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
> @@ -1280,6 +1292,37 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>   	if (!msta->wcid.sta)
>   		return;
>   
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +	    !is_mt7915(&dev->mt76) &&
> +	    (msta->wcid.idx < min || msta->wcid.idx > max - 1)) {
> +		pre_sta = kmemdup(sta, sizeof(*sta) + sizeof(*msta), GFP_KERNEL | __GFP_ZERO);
> +		if (!pre_sta)
> +			goto error_alloc;
> +		pre_msta = (struct mt7915_sta *)pre_sta->drv_priv;
> +
> +		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
> +			MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
> +
> +		tmp_idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA, flags);
> +		if (tmp_idx < 0)
> +			goto error_wcid;
> +		pre_msta->wcid.idx = (u16)tmp_idx;
> +		mt7915_mac_sta_add(&dev->mt76, vif, pre_sta);
> +		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], &msta->wcid);
> +
> +		tmp_idx = msta->wcid.idx;
> +		msta->wcid.idx = pre_msta->wcid.idx;
> +		pre_msta->wcid.idx = (u16)tmp_idx;
> +		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], NULL);
> +
> +		synchronize_rcu();
> +		mt7915_mac_sta_remove(&dev->mt76, vif, pre_sta);
> +
> +error_wcid:
> +		kfree(pre_sta);
> +	}
> +
> +error_alloc:
>   	mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
>   }
>   
> @@ -1726,15 +1769,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
>   	if (!mtk_wed_device_active(wed))
>   		return -ENODEV;
>   
> -	if (msta->wcid.idx > 0xff)
> +	if (msta->wcid.idx > MT7915_WTBL_STA)
>   		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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
>   	path->mtk_wdma.queue = phy != &dev->phy;
> +	if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
> +	    is_mt7915(&dev->mt76))
> +		path->mtk_wdma.wcid = msta->wcid.idx;
> +	else
> +		path->mtk_wdma.wcid = 0x3ff;
>   
>   	ctx->dev = NULL;
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> index 427542777abc..61a854d2c416 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> @@ -2403,10 +2403,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
>   
>   	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
>   
> -	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> -	     is_mt7915(&dev->mt76)) ||
> -	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> -		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
> +#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
> +		if (is_mt7915(&dev->mt76) ||
> +		    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> +			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
> +						0, 0, 0);
> +		else
> +			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
> +						MCU_WA_PARAM_WED_VERSION,
> +						dev->mt76.mmio.wed.rev_id, 0);
> +		if (ret)
> +			return ret;
> +	}
> +#endif
>   
>   	ret = mt7915_mcu_set_mwds(dev, 1);
>   	if (ret)
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> index 086ad89ecd91..989f24cb49eb 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> @@ -278,6 +278,7 @@ enum {
>   	MCU_WA_PARAM_PDMA_RX = 0x04,
>   	MCU_WA_PARAM_CPU_UTIL = 0x0b,
>   	MCU_WA_PARAM_RED = 0x0e,
> +	MCU_WA_PARAM_WED_VERSION = 0x32,
>   	MCU_WA_PARAM_RED_SETTING = 0x40,
>   };
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
> index 95b3dc96e4c4..e80bef2b33a1 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.c
> +++ b/drivers/net/wireless/mediatek/mt76/util.c
> @@ -42,8 +42,10 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
>   }
>   EXPORT_SYMBOL_GPL(____mt76_poll_msec);
>   
> -int mt76_wcid_alloc(u32 *mask, int size)
> +int __mt76_wcid_alloc(u32 *mask, int size, u8 flag)
>   {
> +	int max = MT76_WED_WDS_MAX;
> +	int min = MT76_WED_WDS_MIN;
>   	int i, idx = 0, cur;
>   
>   	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
> @@ -53,16 +55,45 @@ int mt76_wcid_alloc(u32 *mask, int size)
>   
>   		idx--;
>   		cur = i * 32 + idx;
> -		if (cur >= size)
> +
> +		switch (flag) {
> +		case MT76_WED_ACTIVE:
> +			if (cur >= min && cur < max)
> +				continue;
> +
> +			if (cur >= size) {
> +				u32 end = max - min - 1;
> +
> +				i = min / 32;
> +				idx = ffs(~mask[i] & GENMASK(end, 0));
> +				if (!idx)
> +					goto error;
> +				idx--;
> +				cur = min + idx;
> +			}
> +
>   			break;
> +		case MT76_WED_WDS_ACTIVE:
> +			if (cur < min)
> +				continue;
> +			if (cur >= max)
> +				goto error;
> +
> +			break;
> +		default:
> +			if (cur >= size)
> +				goto error;
> +			break;
> +		}
>   
>   		mask[i] |= BIT(idx);
>   		return cur;
>   	}
>   
> +error:
>   	return -1;
>   }
> -EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
> +EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
>   
>   int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
>   {
> diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
> index 260965dde94c..fe95a847182e 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.h
> +++ b/drivers/net/wireless/mediatek/mt76/util.h
> @@ -27,7 +27,7 @@ enum {
>   #define MT76_INCR(_var, _size) \
>   	(_var = (((_var) + 1) % (_size)))
>   
> -int mt76_wcid_alloc(u32 *mask, int size);
> +int __mt76_wcid_alloc(u32 *mask, int size, u8 flags);
>   
>   static inline void
>   mt76_wcid_mask_set(u32 *mask, int idx)


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 6977 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
  2025-04-21 14:04 [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled Shengyu Qu
  2025-05-18 14:41 ` Shengyu Qu
  2025-05-25 13:42 ` Shengyu Qu
@ 2025-06-24 14:11 ` Shengyu Qu
  2025-06-25 10:18   ` Felix Fietkau
  2 siblings, 1 reply; 8+ messages in thread
From: Shengyu Qu @ 2025-06-24 14:11 UTC (permalink / raw)
  To: nbd, pkshih, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno, johannes.berg,
	miriam.rachel.korenblit, christophe.jaillet, greearb,
	howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: wiagn233, Sujuan Chen, Bo Jiao


[-- Attachment #1.1.1: Type: text/plain, Size: 11197 bytes --]

Hi Felix,

Please, tell me if this patch needs any polishing. I really don't know
why this patch still not get merged after such a long time(and 2x
resend), especially it already got a Reviewed-by and is a bugfix.

Best regards,
Shengyu

在 2025/4/21 22:04, Shengyu Qu 写道:
> The current WED only supports 256 wcid, whereas mt7986 can support up to
> 512 entries, so firmware provides a rule to get sta_info by DA when wcid
> is set to 0x3ff by txd. Also, WED provides a register to overwrite txd
> wcid, that is, wcid[9:8] can be overwritten by 0x3 and wcid[7:0] is set
> to 0xff by host driver.
> 
> However, firmware is unable to get sta_info from DA as DA != RA for
> 4addr cases, so firmware and wifi host driver both use wcid (256 - 271)
> and (768 ~ 783) for sync up to get correct sta_info.
> 
> Currently WDS+WED config is completely broken on MT7986/7981 devices if
> without this patch.
> 
> Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
> Tested-by: Sujuan Chen <sujuan.chen@mediatek.com>
> Co-developed-by: Bo Jiao <bo.jiao@mediatek.com>
> Signed-off-by: Bo Jiao <bo.jiao@mediatek.com>
> Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
> Signed-off-by: Shengyu Qu <wiagn233@outlook.com>
> ---
> Changes since v1:
>   - Drop duplicate setting in mmio
>   - Reduce the patch size by redefining mt76_wcid_alloc
> Changes since v2:
>   - Rework wds wcid getting flow
> Changes since v3:
>   - Rebase to next-20240703
>   - Sync with downstream patch
> Changes since v4:
>   - Rebase to next-20240802
> Changes since v5:
>   - Fixed build test error reported by robot
>   - Rebase to next-20240805
> Changes since v6:
>   - Fix potential race conditions on tx/rx packets during the transition
>   - Rebase to Felix's newest codebase
> Changes since v7:
>   - Fix build fail
> Changes since v8:
>   - Changed code as Shih advised
> Changes since v9:
>   - Changed code as Shih advised
>   - Moved mt76_wcid_alloc to mt76.h
> ---
>   drivers/net/wireless/mediatek/mt76/mt76.h     | 15 ++++++
>   .../net/wireless/mediatek/mt76/mt7915/main.c  | 53 +++++++++++++++++--
>   .../net/wireless/mediatek/mt76/mt7915/mcu.c   | 18 +++++--
>   .../net/wireless/mediatek/mt76/mt7915/mcu.h   |  1 +
>   drivers/net/wireless/mediatek/mt76/util.c     | 37 +++++++++++--
>   drivers/net/wireless/mediatek/mt76/util.h     |  2 +-
>   6 files changed, 115 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
> index d7cd467b812f..7f590854959e 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -28,6 +28,9 @@
>   
>   #define MT76_TOKEN_FREE_THR	64
>   
> +#define MT76_WED_WDS_MIN    256
> +#define MT76_WED_WDS_MAX    272
> +
>   #define MT_QFLAG_WED_RING	GENMASK(1, 0)
>   #define MT_QFLAG_WED_TYPE	GENMASK(4, 2)
>   #define MT_QFLAG_WED		BIT(5)
> @@ -73,6 +76,12 @@ enum mt76_wed_type {
>   	MT76_WED_RRO_Q_IND,
>   };
>   
> +enum mt76_wed_state {
> +	MT76_WED_DEFAULT,
> +	MT76_WED_ACTIVE,
> +	MT76_WED_WDS_ACTIVE,
> +};
> +
>   struct mt76_bus_ops {
>   	u32 (*rr)(struct mt76_dev *dev, u32 offset);
>   	void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
> @@ -1169,6 +1178,12 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
>   int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>   			  struct net_device *netdev, enum tc_setup_type type,
>   			  void *type_data);
> +
> +static inline int mt76_wcid_alloc(u32 *mask, int size)
> +{
> +	return __mt76_wcid_alloc(mask, size, MT76_WED_DEFAULT);
> +}
> +
>   #ifdef CONFIG_NET_MEDIATEK_SOC_WED
>   u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
>   int mt76_wed_offload_enable(struct mtk_wed_device *wed);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> index 3aa31c5cefa6..fcbf4f971026 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> @@ -744,9 +744,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
>   	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
>   	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
>   	bool ext_phy = mvif->phy != &dev->phy;
> +	u8 flags = MT76_WED_DEFAULT;
>   	int idx;
>   
> -	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +	    !is_mt7915(&dev->mt76)) {
> +		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
> +		       MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
> +	}
> +
> +	idx = __mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA, flags);
>   	if (idx < 0)
>   		return -ENOSPC;
>   
> @@ -1271,6 +1278,11 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>   {
>   	struct mt7915_dev *dev = mt7915_hw_dev(hw);
>   	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
> +	int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
> +	struct ieee80211_sta *pre_sta;
> +	struct mt7915_sta *pre_msta;
> +	u8 flags = MT76_WED_DEFAULT;
> +	int tmp_idx;
>   
>   	if (enabled)
>   		set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
> @@ -1280,6 +1292,37 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>   	if (!msta->wcid.sta)
>   		return;
>   
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +	    !is_mt7915(&dev->mt76) &&
> +	    (msta->wcid.idx < min || msta->wcid.idx > max - 1)) {
> +		pre_sta = kmemdup(sta, sizeof(*sta) + sizeof(*msta), GFP_KERNEL | __GFP_ZERO);
> +		if (!pre_sta)
> +			goto error_alloc;
> +		pre_msta = (struct mt7915_sta *)pre_sta->drv_priv;
> +
> +		flags = test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ?
> +			MT76_WED_WDS_ACTIVE : MT76_WED_ACTIVE;
> +
> +		tmp_idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA, flags);
> +		if (tmp_idx < 0)
> +			goto error_wcid;
> +		pre_msta->wcid.idx = (u16)tmp_idx;
> +		mt7915_mac_sta_add(&dev->mt76, vif, pre_sta);
> +		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], &msta->wcid);
> +
> +		tmp_idx = msta->wcid.idx;
> +		msta->wcid.idx = pre_msta->wcid.idx;
> +		pre_msta->wcid.idx = (u16)tmp_idx;
> +		rcu_assign_pointer(dev->mt76.wcid[tmp_idx], NULL);
> +
> +		synchronize_rcu();
> +		mt7915_mac_sta_remove(&dev->mt76, vif, pre_sta);
> +
> +error_wcid:
> +		kfree(pre_sta);
> +	}
> +
> +error_alloc:
>   	mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta);
>   }
>   
> @@ -1726,15 +1769,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
>   	if (!mtk_wed_device_active(wed))
>   		return -ENODEV;
>   
> -	if (msta->wcid.idx > 0xff)
> +	if (msta->wcid.idx > MT7915_WTBL_STA)
>   		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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
>   	path->mtk_wdma.queue = phy != &dev->phy;
> +	if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
> +	    is_mt7915(&dev->mt76))
> +		path->mtk_wdma.wcid = msta->wcid.idx;
> +	else
> +		path->mtk_wdma.wcid = 0x3ff;
>   
>   	ctx->dev = NULL;
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> index 427542777abc..61a854d2c416 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> @@ -2403,10 +2403,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
>   
>   	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
>   
> -	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> -	     is_mt7915(&dev->mt76)) ||
> -	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> -		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
> +#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
> +	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
> +		if (is_mt7915(&dev->mt76) ||
> +		    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> +			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
> +						0, 0, 0);
> +		else
> +			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
> +						MCU_WA_PARAM_WED_VERSION,
> +						dev->mt76.mmio.wed.rev_id, 0);
> +		if (ret)
> +			return ret;
> +	}
> +#endif
>   
>   	ret = mt7915_mcu_set_mwds(dev, 1);
>   	if (ret)
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> index 086ad89ecd91..989f24cb49eb 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> @@ -278,6 +278,7 @@ enum {
>   	MCU_WA_PARAM_PDMA_RX = 0x04,
>   	MCU_WA_PARAM_CPU_UTIL = 0x0b,
>   	MCU_WA_PARAM_RED = 0x0e,
> +	MCU_WA_PARAM_WED_VERSION = 0x32,
>   	MCU_WA_PARAM_RED_SETTING = 0x40,
>   };
>   
> diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
> index 95b3dc96e4c4..e80bef2b33a1 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.c
> +++ b/drivers/net/wireless/mediatek/mt76/util.c
> @@ -42,8 +42,10 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
>   }
>   EXPORT_SYMBOL_GPL(____mt76_poll_msec);
>   
> -int mt76_wcid_alloc(u32 *mask, int size)
> +int __mt76_wcid_alloc(u32 *mask, int size, u8 flag)
>   {
> +	int max = MT76_WED_WDS_MAX;
> +	int min = MT76_WED_WDS_MIN;
>   	int i, idx = 0, cur;
>   
>   	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
> @@ -53,16 +55,45 @@ int mt76_wcid_alloc(u32 *mask, int size)
>   
>   		idx--;
>   		cur = i * 32 + idx;
> -		if (cur >= size)
> +
> +		switch (flag) {
> +		case MT76_WED_ACTIVE:
> +			if (cur >= min && cur < max)
> +				continue;
> +
> +			if (cur >= size) {
> +				u32 end = max - min - 1;
> +
> +				i = min / 32;
> +				idx = ffs(~mask[i] & GENMASK(end, 0));
> +				if (!idx)
> +					goto error;
> +				idx--;
> +				cur = min + idx;
> +			}
> +
>   			break;
> +		case MT76_WED_WDS_ACTIVE:
> +			if (cur < min)
> +				continue;
> +			if (cur >= max)
> +				goto error;
> +
> +			break;
> +		default:
> +			if (cur >= size)
> +				goto error;
> +			break;
> +		}
>   
>   		mask[i] |= BIT(idx);
>   		return cur;
>   	}
>   
> +error:
>   	return -1;
>   }
> -EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
> +EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
>   
>   int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
>   {
> diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
> index 260965dde94c..fe95a847182e 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.h
> +++ b/drivers/net/wireless/mediatek/mt76/util.h
> @@ -27,7 +27,7 @@ enum {
>   #define MT76_INCR(_var, _size) \
>   	(_var = (((_var) + 1) % (_size)))
>   
> -int mt76_wcid_alloc(u32 *mask, int size);
> +int __mt76_wcid_alloc(u32 *mask, int size, u8 flags);
>   
>   static inline void
>   mt76_wcid_mask_set(u32 *mask, int idx)


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 6977 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
  2025-06-24 14:11 ` Shengyu Qu
@ 2025-06-25 10:18   ` Felix Fietkau
  2025-06-25 11:00     ` Felix Fietkau
  0 siblings, 1 reply; 8+ messages in thread
From: Felix Fietkau @ 2025-06-25 10:18 UTC (permalink / raw)
  To: Shengyu Qu, pkshih, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno, johannes.berg,
	miriam.rachel.korenblit, christophe.jaillet, greearb,
	howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: Sujuan Chen, Bo Jiao

On 24.06.25 16:11, Shengyu Qu wrote:
> Hi Felix,
> 
> Please, tell me if this patch needs any polishing. I really don't know
> why this patch still not get merged after such a long time(and 2x
> resend), especially it already got a Reviewed-by and is a bugfix.

Hi Shengyu,

sorry it took such a long time for me to take a look at this patch.
I don't see how it can even work properly in its current form, because 
of at least one bug:

When switching from non-wds to wds mode, the code calls 
mt7915_mac_sta_add in order to create the new sta. However, after 
changes that I made a while back, this function does not actually upload 
the station to the MCU anymore, since it is called on the NOTEXIST->NONE 
transition before assoc. Without corresponding ASSOC/AUTHORIZE events 
(handled by mt7915_mac_sta_event), the firmware doesn't get any data for 
the new wcid.

That said, I finally got around to starting to rework your patch myself. 
I will let you know when I have something ready for testing, hopefully 
later today.

- Felix

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
  2025-06-25 10:18   ` Felix Fietkau
@ 2025-06-25 11:00     ` Felix Fietkau
  2025-06-25 17:25       ` Shengyu Qu
  0 siblings, 1 reply; 8+ messages in thread
From: Felix Fietkau @ 2025-06-25 11:00 UTC (permalink / raw)
  To: Shengyu Qu, pkshih, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno, johannes.berg,
	miriam.rachel.korenblit, christophe.jaillet, greearb,
	howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: Sujuan Chen, Bo Jiao

On 25.06.25 12:18, Felix Fietkau wrote:
> On 24.06.25 16:11, Shengyu Qu wrote:
>> Hi Felix,
>> 
>> Please, tell me if this patch needs any polishing. I really don't know
>> why this patch still not get merged after such a long time(and 2x
>> resend), especially it already got a Reviewed-by and is a bugfix.
> 
> Hi Shengyu,
> 
> sorry it took such a long time for me to take a look at this patch.
> I don't see how it can even work properly in its current form, because
> of at least one bug:
> 
> When switching from non-wds to wds mode, the code calls
> mt7915_mac_sta_add in order to create the new sta. However, after
> changes that I made a while back, this function does not actually upload
> the station to the MCU anymore, since it is called on the NOTEXIST->NONE
> transition before assoc. Without corresponding ASSOC/AUTHORIZE events
> (handled by mt7915_mac_sta_event), the firmware doesn't get any data for
> the new wcid.
> 
> That said, I finally got around to starting to rework your patch myself.
> I will let you know when I have something ready for testing, hopefully
> later today.

Here's my first draft:

---
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 14927a92f9d1..f1d1b0ebd074 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -28,6 +28,9 @@
  
  #define MT76_TOKEN_FREE_THR	64
  
+#define MT76_WED_WDS_MIN    256
+#define MT76_WED_WDS_MAX    272
+
  #define MT_QFLAG_WED_RING	GENMASK(1, 0)
  #define MT_QFLAG_WED_TYPE	GENMASK(4, 2)
  #define MT_QFLAG_WED		BIT(5)
@@ -1181,6 +1184,7 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
  int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  			  struct net_device *netdev, enum tc_setup_type type,
  			  void *type_data);
+
  #ifdef CONFIG_NET_MEDIATEK_SOC_WED
  u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
  int mt76_wed_offload_enable(struct mtk_wed_device *wed);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index b287b7d9394e..ec2287459587 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -1385,7 +1385,7 @@ static ssize_t mt7915_sta_fixed_rate_set(struct file *file,
  
  out:
  	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
-	ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);
+	ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &msta->wcid, &phy, field);
  	if (ret)
  		return -EFAULT;
  
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 9400e4af2a04..e3e65848a17f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -1991,7 +1991,7 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
  		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
  			       IEEE80211_RC_NSS_CHANGED |
  			       IEEE80211_RC_BW_CHANGED))
-			mt7915_mcu_add_rate_ctrl(dev, vif, sta, true);
+			mt7915_mcu_add_rate_ctrl(dev, vif, sta, &msta->wcid, true);
  
  		if (changed & IEEE80211_RC_SMPS_CHANGED)
  			mt7915_mcu_add_smps(dev, vif, sta);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index fe0639c14bf9..0227ea8665f1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -747,7 +747,13 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
  	bool ext_phy = mvif->phy != &dev->phy;
  	int idx;
  
-	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+	    !is_mt7915(&dev->mt76) &&
+	    test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags))
+		idx = __mt76_wcid_alloc(mdev->wcid_mask, MT76_WED_WDS_MIN,
+					MT76_WED_WDS_MAX);
+	else
+		idx = mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA);
  	if (idx < 0)
  		return -ENOSPC;
  
@@ -836,7 +842,7 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
  		addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 30);
  		mt76_rmw_field(dev, addr, GENMASK(7, 0), 0xa0);
  
-		ret = mt7915_mcu_add_rate_ctrl(dev, vif, sta, false);
+		ret = mt7915_mcu_add_rate_ctrl(dev, vif, sta, &msta->wcid, false);
  		if (ret)
  			return ret;
  
@@ -1267,6 +1273,40 @@ mt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  	return 0;
  }
  
+static void mt7915_sta_wed_set_4addr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+				     struct ieee80211_sta *sta)
+{
+	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+	int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
+	int idx, prev_idx = msta->wcid.idx;
+	struct mt76_wcid wcid = msta->wcid;
+	int state;
+
+	if (!is_mt7915(&dev->mt76))
+		return;
+
+	if (msta->wcid.idx >= min && msta->wcid.idx < max)
+		return;
+
+	idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, min, max);
+	if (idx < 0)
+		return;
+
+	wcid.idx = idx;
+	state = msta->wcid.sta ? CONN_STATE_PORT_SECURE : CONN_STATE_DISCONNECT;
+	__mt7915_mcu_add_sta(dev, vif, sta, &wcid, state, true);
+	mt7915_mcu_add_rate_ctrl(dev, vif, sta, &wcid, false);
+	rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid);
+	msta->wcid.idx = idx;
+
+	synchronize_rcu();
+
+	rcu_assign_pointer(dev->mt76.wcid[prev_idx], NULL);
+	mt76_wcid_mask_clear(dev->mt76.wcid_mask, prev_idx);
+	wcid.idx = prev_idx;
+	__mt7915_mcu_add_sta(dev, vif, sta, &wcid, CONN_STATE_DISCONNECT, false);
+}
+
  static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
  				 struct ieee80211_vif *vif,
  				 struct ieee80211_sta *sta,
@@ -1280,6 +1320,9 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
  	else
  		clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
  
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) && enabled)
+		mt7915_sta_wed_set_4addr(dev, vif, sta);
+
  	if (!msta->wcid.sta)
  		return;
  
@@ -1729,15 +1772,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
  	if (!mtk_wed_device_active(wed))
  		return -ENODEV;
  
-	if (msta->wcid.idx > 0xff)
+	if (msta->wcid.idx > MT7915_WTBL_STA)
  		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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
  	path->mtk_wdma.queue = phy != &dev->phy;
+	if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
+	    is_mt7915(&dev->mt76))
+		path->mtk_wdma.wcid = msta->wcid.idx;
+	else
+		path->mtk_wdma.wcid = 0x3ff;
  
  	ctx->dev = NULL;
  
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index cf948628e588..26497b580eb6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -1359,6 +1359,7 @@ mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
  int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
  				   struct ieee80211_vif *vif,
  				   struct ieee80211_sta *sta,
+				   struct mt76_wcid *wcid,
  				   void *data, u32 field)
  {
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
@@ -1430,7 +1431,7 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  	if (ret)
  		return ret;
  
-	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL,
+	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &msta->wcid, NULL,
  					      RATE_PARAM_MMPS_UPDATE);
  }
  
@@ -1439,17 +1440,19 @@ mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  		       struct ieee80211_sta *sta)
  {
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
  	struct mt76_phy *mphy = mvif->phy->mt76;
  	u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
  
-	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
-					      RATE_PARAM_SPE_UPDATE);
+	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &msta->wcid,
+					      &spe_idx, RATE_PARAM_SPE_UPDATE);
  }
  
  static int
  mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  			       struct ieee80211_vif *vif,
-			       struct ieee80211_sta *sta)
+			       struct ieee80211_sta *sta,
+			       struct mt76_wcid *wcid)
  {
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
  	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
@@ -1497,7 +1500,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  
  	/* fixed single rate */
  	if (nrates == 1) {
-		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
+		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, wcid, &phy,
  						     RATE_PARAM_FIXED_MCS);
  		if (ret)
  			return ret;
@@ -1519,7 +1522,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  		else
  			mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
  
-		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
+		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, wcid, &phy,
  						     RATE_PARAM_FIXED_GI);
  		if (ret)
  			return ret;
@@ -1527,7 +1530,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  
  	/* fixed HE_LTF */
  	if (mask->control[band].he_ltf != GENMASK(7, 0)) {
-		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
+		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, wcid, &phy,
  						     RATE_PARAM_FIXED_HE_LTF);
  		if (ret)
  			return ret;
@@ -1640,15 +1643,14 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
  }
  
  int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
-			     struct ieee80211_sta *sta, bool changed)
+			     struct ieee80211_sta *sta, struct mt76_wcid *wcid,
+			     bool changed)
  {
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
-	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
  	struct sk_buff *skb;
  	int ret;
  
-	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
-					    &msta->wcid);
+	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, wcid);
  	if (IS_ERR(skb))
  		return PTR_ERR(skb);
  
@@ -1673,7 +1675,7 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  	 * and updates as peer fixed rate parameters, which overrides
  	 * sta_rec_ra and firmware rate control algorithm.
  	 */
-	return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
+	return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta, wcid);
  }
  
  static int
@@ -1704,8 +1706,9 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  				 sizeof(req), true);
  }
  
-int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta, int conn_state, bool newly)
+int __mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+			 struct ieee80211_sta *sta,  struct mt76_wcid *wcid,
+			 int conn_state, bool newly)
  {
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
  	struct ieee80211_link_sta *link_sta;
@@ -1715,9 +1718,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  
  	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
  	link_sta = sta ? &sta->deflink : NULL;
+	if (!wcid)
+		wcid = &msta->wcid;
  
-	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
-					    &msta->wcid);
+	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, wcid);
  	if (IS_ERR(skb))
  		return PTR_ERR(skb);
  
@@ -2413,10 +2417,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
  
  	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
  
-	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
-	     is_mt7915(&dev->mt76)) ||
-	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
-		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
+	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+		if (is_mt7915(&dev->mt76) ||
+		    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
+			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
+						0, 0, 0);
+		else
+			ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
+						MCU_WA_PARAM_WED_VERSION,
+						dev->mt76.mmio.wed.rev_id, 0);
+		if (ret)
+			return ret;
+	}
+#endif
  
  	ret = mt7915_mcu_set_mwds(dev, 1);
  	if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 086ad89ecd91..989f24cb49eb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -278,6 +278,7 @@ enum {
  	MCU_WA_PARAM_PDMA_RX = 0x04,
  	MCU_WA_PARAM_CPU_UTIL = 0x0b,
  	MCU_WA_PARAM_RED = 0x0e,
+	MCU_WA_PARAM_WED_VERSION = 0x32,
  	MCU_WA_PARAM_RED_SETTING = 0x40,
  };
  
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index 2e94347c46d6..c781058a416f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -455,8 +455,16 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
  			    struct ieee80211_vif *vif, bool enable);
  int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
  			    struct ieee80211_vif *vif, int enable);
-int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
-		       struct ieee80211_sta *sta, int conn_state, bool newly);
+int __mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+			 struct ieee80211_sta *sta, struct mt76_wcid *wcid,
+			 int conn_state, bool newly);
+static inline int
+mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta, int conn_state, bool newly)
+{
+    return __mt7915_mcu_add_sta(dev, vif, sta, NULL, conn_state, newly);
+}
+
  int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
  			 struct ieee80211_ampdu_params *params,
  			 bool add);
@@ -472,7 +480,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
  			    struct ieee80211_he_obss_pd *he_obss_pd);
  int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
-			     struct ieee80211_sta *sta, bool changed);
+			     struct ieee80211_sta *sta, struct mt76_wcid *wcid,
+			     bool changed);
  int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  			struct ieee80211_sta *sta);
  int mt7915_set_channel(struct mt76_phy *mphy);
@@ -482,6 +491,7 @@ int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *req);
  int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
  				   struct ieee80211_vif *vif,
  				   struct ieee80211_sta *sta,
+				   struct mt76_wcid *wcid,
  				   void *data, u32 field);
  int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
  int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf);
diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
index 95b3dc96e4c4..9fa60d380ede 100644
--- a/drivers/net/wireless/mediatek/mt76/util.c
+++ b/drivers/net/wireless/mediatek/mt76/util.c
@@ -42,12 +42,19 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
  }
  EXPORT_SYMBOL_GPL(____mt76_poll_msec);
  
-int mt76_wcid_alloc(u32 *mask, int size)
+int __mt76_wcid_alloc(u32 *mask, int min, int size)
  {
+	u32 min_mask = ~0;
  	int i, idx = 0, cur;
  
+	mask += min / 32;
+	min %= 32;
+	if (min > 0)
+		min_mask = ~((1 << min) - 1);
+
  	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
-		idx = ffs(~mask[i]);
+		idx = ffs(~mask[i] & min_mask);
+		min_mask = ~0;
  		if (!idx)
  			continue;
  
@@ -62,7 +69,7 @@ int mt76_wcid_alloc(u32 *mask, int size)
  
  	return -1;
  }
-EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
+EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
  
  int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
  {
diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
index 260965dde94c..bca2893f980e 100644
--- a/drivers/net/wireless/mediatek/mt76/util.h
+++ b/drivers/net/wireless/mediatek/mt76/util.h
@@ -27,7 +27,12 @@ enum {
  #define MT76_INCR(_var, _size) \
  	(_var = (((_var) + 1) % (_size)))
  
-int mt76_wcid_alloc(u32 *mask, int size);
+int __mt76_wcid_alloc(u32 *mask, int min, int size);
+
+static inline int mt76_wcid_alloc(u32 *mask, int size)
+{
+	return __mt76_wcid_alloc(mask, 0, size);
+}
  
  static inline void
  mt76_wcid_mask_set(u32 *mask, int idx)
-- 
2.49.0



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled
  2025-06-25 11:00     ` Felix Fietkau
@ 2025-06-25 17:25       ` Shengyu Qu
  0 siblings, 0 replies; 8+ messages in thread
From: Shengyu Qu @ 2025-06-25 17:25 UTC (permalink / raw)
  To: Felix Fietkau, pkshih, lorenzo, ryder.lee, shayne.chen, sean.wang,
	matthias.bgg, angelogioacchino.delregno, johannes.berg,
	miriam.rachel.korenblit, christophe.jaillet, greearb,
	howard-yh.hsu, StanleyYP.Wang, deren.wu, chui-hao.chiu,
	quic_adisi, gustavoars, razvan.grigore, linux-wireless,
	linux-kernel, linux-arm-kernel, linux-mediatek
  Cc: wiagn233, Sujuan Chen, Bo Jiao


[-- Attachment #1.1.1: Type: text/plain, Size: 21543 bytes --]

Hi Felix,

Thanks for reply. Sadly I don't have time to test this patch either. But
I think you can find someone to help testing it here:
https://github.com/openwrt/openwrt/issues/14680

Best regards,
Shengyu

在 2025/6/25 19:00, Felix Fietkau 写道:
> On 25.06.25 12:18, Felix Fietkau wrote:
>> On 24.06.25 16:11, Shengyu Qu wrote:
>>> Hi Felix,
>>>
>>> Please, tell me if this patch needs any polishing. I really don't know
>>> why this patch still not get merged after such a long time(and 2x
>>> resend), especially it already got a Reviewed-by and is a bugfix.
>>
>> Hi Shengyu,
>>
>> sorry it took such a long time for me to take a look at this patch.
>> I don't see how it can even work properly in its current form, because
>> of at least one bug:
>>
>> When switching from non-wds to wds mode, the code calls
>> mt7915_mac_sta_add in order to create the new sta. However, after
>> changes that I made a while back, this function does not actually upload
>> the station to the MCU anymore, since it is called on the NOTEXIST->NONE
>> transition before assoc. Without corresponding ASSOC/AUTHORIZE events
>> (handled by mt7915_mac_sta_event), the firmware doesn't get any data for
>> the new wcid.
>>
>> That said, I finally got around to starting to rework your patch myself.
>> I will let you know when I have something ready for testing, hopefully
>> later today.
> 
> Here's my first draft:
> 
> ---
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/ 
> wireless/mediatek/mt76/mt76.h
> index 14927a92f9d1..f1d1b0ebd074 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt76.h
> @@ -28,6 +28,9 @@
> 
>   #define MT76_TOKEN_FREE_THR    64
> 
> +#define MT76_WED_WDS_MIN    256
> +#define MT76_WED_WDS_MAX    272
> +
>   #define MT_QFLAG_WED_RING    GENMASK(1, 0)
>   #define MT_QFLAG_WED_TYPE    GENMASK(4, 2)
>   #define MT_QFLAG_WED        BIT(5)
> @@ -1181,6 +1184,7 @@ void mt76_wed_dma_reset(struct mt76_dev *dev);
>   int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct 
> ieee80211_vif *vif,
>                 struct net_device *netdev, enum tc_setup_type type,
>                 void *type_data);
> +
>   #ifdef CONFIG_NET_MEDIATEK_SOC_WED
>   u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
>   int mt76_wed_offload_enable(struct mtk_wed_device *wed);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/ 
> drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
> index b287b7d9394e..ec2287459587 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
> @@ -1385,7 +1385,7 @@ static ssize_t mt7915_sta_fixed_rate_set(struct 
> file *file,
> 
>   out:
>       vif = container_of((void *)msta->vif, struct ieee80211_vif, 
> drv_priv);
> -    ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field);
> +    ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &msta->wcid, 
> &phy, field);
>       if (ret)
>           return -EFAULT;
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/ 
> net/wireless/mediatek/mt76/mt7915/mac.c
> index 9400e4af2a04..e3e65848a17f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
> @@ -1991,7 +1991,7 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
>           if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
>                      IEEE80211_RC_NSS_CHANGED |
>                      IEEE80211_RC_BW_CHANGED))
> -            mt7915_mcu_add_rate_ctrl(dev, vif, sta, true);
> +            mt7915_mcu_add_rate_ctrl(dev, vif, sta, &msta->wcid, true);
> 
>           if (changed & IEEE80211_RC_SMPS_CHANGED)
>               mt7915_mcu_add_smps(dev, vif, sta);
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/ 
> net/wireless/mediatek/mt76/mt7915/main.c
> index fe0639c14bf9..0227ea8665f1 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
> @@ -747,7 +747,13 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, 
> struct ieee80211_vif *vif,
>       bool ext_phy = mvif->phy != &dev->phy;
>       int idx;
> 
> -    idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
> +    if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> +        !is_mt7915(&dev->mt76) &&
> +        test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags))
> +        idx = __mt76_wcid_alloc(mdev->wcid_mask, MT76_WED_WDS_MIN,
> +                    MT76_WED_WDS_MAX);
> +    else
> +        idx = mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA);
>       if (idx < 0)
>           return -ENOSPC;
> 
> @@ -836,7 +842,7 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, 
> struct ieee80211_vif *vif,
>           addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 30);
>           mt76_rmw_field(dev, addr, GENMASK(7, 0), 0xa0);
> 
> -        ret = mt7915_mcu_add_rate_ctrl(dev, vif, sta, false);
> +        ret = mt7915_mcu_add_rate_ctrl(dev, vif, sta, &msta->wcid, false);
>           if (ret)
>               return ret;
> 
> @@ -1267,6 +1273,40 @@ mt7915_set_bitrate_mask(struct ieee80211_hw *hw, 
> struct ieee80211_vif *vif,
>       return 0;
>   }
> 
> +static void mt7915_sta_wed_set_4addr(struct mt7915_dev *dev, struct 
> ieee80211_vif *vif,
> +                     struct ieee80211_sta *sta)
> +{
> +    struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
> +    int min = MT76_WED_WDS_MIN, max = MT76_WED_WDS_MAX;
> +    int idx, prev_idx = msta->wcid.idx;
> +    struct mt76_wcid wcid = msta->wcid;
> +    int state;
> +
> +    if (!is_mt7915(&dev->mt76))
> +        return;
> +
> +    if (msta->wcid.idx >= min && msta->wcid.idx < max)
> +        return;
> +
> +    idx = __mt76_wcid_alloc(dev->mt76.wcid_mask, min, max);
> +    if (idx < 0)
> +        return;
> +
> +    wcid.idx = idx;
> +    state = msta->wcid.sta ? CONN_STATE_PORT_SECURE : 
> CONN_STATE_DISCONNECT;
> +    __mt7915_mcu_add_sta(dev, vif, sta, &wcid, state, true);
> +    mt7915_mcu_add_rate_ctrl(dev, vif, sta, &wcid, false);
> +    rcu_assign_pointer(dev->mt76.wcid[idx], &msta->wcid);
> +    msta->wcid.idx = idx;
> +
> +    synchronize_rcu();
> +
> +    rcu_assign_pointer(dev->mt76.wcid[prev_idx], NULL);
> +    mt76_wcid_mask_clear(dev->mt76.wcid_mask, prev_idx);
> +    wcid.idx = prev_idx;
> +    __mt7915_mcu_add_sta(dev, vif, sta, &wcid, CONN_STATE_DISCONNECT, 
> false);
> +}
> +
>   static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
>                    struct ieee80211_vif *vif,
>                    struct ieee80211_sta *sta,
> @@ -1280,6 +1320,9 @@ static void mt7915_sta_set_4addr(struct 
> ieee80211_hw *hw,
>       else
>           clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
> 
> +    if (mtk_wed_device_active(&dev->mt76.mmio.wed) && enabled)
> +        mt7915_sta_wed_set_4addr(dev, vif, sta);
> +
>       if (!msta->wcid.sta)
>           return;
> 
> @@ -1729,15 +1772,19 @@ mt7915_net_fill_forward_path(struct ieee80211_hw 
> *hw,
>       if (!mtk_wed_device_active(wed))
>           return -ENODEV;
> 
> -    if (msta->wcid.idx > 0xff)
> +    if (msta->wcid.idx > MT7915_WTBL_STA)
>           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 = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff;
>       path->mtk_wdma.queue = phy != &dev->phy;
> +    if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags) ||
> +        is_mt7915(&dev->mt76))
> +        path->mtk_wdma.wcid = msta->wcid.idx;
> +    else
> +        path->mtk_wdma.wcid = 0x3ff;
> 
>       ctx->dev = NULL;
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/ 
> net/wireless/mediatek/mt76/mt7915/mcu.c
> index cf948628e588..26497b580eb6 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
> @@ -1359,6 +1359,7 @@ mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode 
> smps)
>   int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
>                      struct ieee80211_vif *vif,
>                      struct ieee80211_sta *sta,
> +                   struct mt76_wcid *wcid,
>                      void *data, u32 field)
>   {
>       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
> @@ -1430,7 +1431,7 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, 
> struct ieee80211_vif *vif,
>       if (ret)
>           return ret;
> 
> -    return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL,
> +    return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &msta->wcid, 
> NULL,
>                             RATE_PARAM_MMPS_UPDATE);
>   }
> 
> @@ -1439,17 +1440,19 @@ mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, 
> struct ieee80211_vif *vif,
>                  struct ieee80211_sta *sta)
>   {
>       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
> +    struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
>       struct mt76_phy *mphy = mvif->phy->mt76;
>       u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
> 
> -    return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
> -                          RATE_PARAM_SPE_UPDATE);
> +    return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &msta->wcid,
> +                          &spe_idx, RATE_PARAM_SPE_UPDATE);
>   }
> 
>   static int
>   mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
>                      struct ieee80211_vif *vif,
> -                   struct ieee80211_sta *sta)
> +                   struct ieee80211_sta *sta,
> +                   struct mt76_wcid *wcid)
>   {
>       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
>       struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
> @@ -1497,7 +1500,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev 
> *dev,
> 
>       /* fixed single rate */
>       if (nrates == 1) {
> -        ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
> +        ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, wcid, &phy,
>                                RATE_PARAM_FIXED_MCS);
>           if (ret)
>               return ret;
> @@ -1519,7 +1522,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev 
> *dev,
>           else
>               mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
> 
> -        ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
> +        ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, wcid, &phy,
>                                RATE_PARAM_FIXED_GI);
>           if (ret)
>               return ret;
> @@ -1527,7 +1530,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev 
> *dev,
> 
>       /* fixed HE_LTF */
>       if (mask->control[band].he_ltf != GENMASK(7, 0)) {
> -        ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
> +        ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, wcid, &phy,
>                                RATE_PARAM_FIXED_HE_LTF);
>           if (ret)
>               return ret;
> @@ -1640,15 +1643,14 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff 
> *skb, struct mt7915_dev *dev,
>   }
> 
>   int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct 
> ieee80211_vif *vif,
> -                 struct ieee80211_sta *sta, bool changed)
> +                 struct ieee80211_sta *sta, struct mt76_wcid *wcid,
> +                 bool changed)
>   {
>       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
> -    struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
>       struct sk_buff *skb;
>       int ret;
> 
> -    skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
> -                        &msta->wcid);
> +    skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, wcid);
>       if (IS_ERR(skb))
>           return PTR_ERR(skb);
> 
> @@ -1673,7 +1675,7 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev 
> *dev, struct ieee80211_vif *vif,
>        * and updates as peer fixed rate parameters, which overrides
>        * sta_rec_ra and firmware rate control algorithm.
>        */
> -    return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
> +    return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta, wcid);
>   }
> 
>   static int
> @@ -1704,8 +1706,9 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, 
> struct ieee80211_vif *vif,
>                    sizeof(req), true);
>   }
> 
> -int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
> -               struct ieee80211_sta *sta, int conn_state, bool newly)
> +int __mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif 
> *vif,
> +             struct ieee80211_sta *sta,  struct mt76_wcid *wcid,
> +             int conn_state, bool newly)
>   {
>       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
>       struct ieee80211_link_sta *link_sta;
> @@ -1715,9 +1718,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, 
> struct ieee80211_vif *vif,
> 
>       msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
>       link_sta = sta ? &sta->deflink : NULL;
> +    if (!wcid)
> +        wcid = &msta->wcid;
> 
> -    skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
> -                        &msta->wcid);
> +    skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, wcid);
>       if (IS_ERR(skb))
>           return PTR_ERR(skb);
> 
> @@ -2413,10 +2417,20 @@ int mt7915_mcu_init_firmware(struct mt7915_dev 
> *dev)
> 
>       mt76_connac_mcu_del_wtbl_all(&dev->mt76);
> 
> -    if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
> -         is_mt7915(&dev->mt76)) ||
> -        !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> -        mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
> +#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
> +    if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
> +        if (is_mt7915(&dev->mt76) ||
> +            !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
> +            ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY),
> +                        0, 0, 0);
> +        else
> +            ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
> +                        MCU_WA_PARAM_WED_VERSION,
> +                        dev->mt76.mmio.wed.rev_id, 0);
> +        if (ret)
> +            return ret;
> +    }
> +#endif
> 
>       ret = mt7915_mcu_set_mwds(dev, 1);
>       if (ret)
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/ 
> net/wireless/mediatek/mt76/mt7915/mcu.h
> index 086ad89ecd91..989f24cb49eb 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
> @@ -278,6 +278,7 @@ enum {
>       MCU_WA_PARAM_PDMA_RX = 0x04,
>       MCU_WA_PARAM_CPU_UTIL = 0x0b,
>       MCU_WA_PARAM_RED = 0x0e,
> +    MCU_WA_PARAM_WED_VERSION = 0x32,
>       MCU_WA_PARAM_RED_SETTING = 0x40,
>   };
> 
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/ 
> drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
> index 2e94347c46d6..c781058a416f 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
> +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
> @@ -455,8 +455,16 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
>                   struct ieee80211_vif *vif, bool enable);
>   int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
>                   struct ieee80211_vif *vif, int enable);
> -int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
> -               struct ieee80211_sta *sta, int conn_state, bool newly);
> +int __mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif 
> *vif,
> +             struct ieee80211_sta *sta, struct mt76_wcid *wcid,
> +             int conn_state, bool newly);
> +static inline int
> +mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
> +           struct ieee80211_sta *sta, int conn_state, bool newly)
> +{
> +    return __mt7915_mcu_add_sta(dev, vif, sta, NULL, conn_state, newly);
> +}
> +
>   int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
>                struct ieee80211_ampdu_params *params,
>                bool add);
> @@ -472,7 +480,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, 
> struct ieee80211_vif *vif,
>   int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct 
> ieee80211_vif *vif,
>                   struct ieee80211_he_obss_pd *he_obss_pd);
>   int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct 
> ieee80211_vif *vif,
> -                 struct ieee80211_sta *sta, bool changed);
> +                 struct ieee80211_sta *sta, struct mt76_wcid *wcid,
> +                 bool changed);
>   int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif 
> *vif,
>               struct ieee80211_sta *sta);
>   int mt7915_set_channel(struct mt76_phy *mphy);
> @@ -482,6 +491,7 @@ int mt7915_mcu_update_edca(struct mt7915_dev *dev, 
> void *req);
>   int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
>                      struct ieee80211_vif *vif,
>                      struct ieee80211_sta *sta,
> +                   struct mt76_wcid *wcid,
>                      void *data, u32 field);
>   int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
>   int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 
> *read_buf);
> diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/ 
> wireless/mediatek/mt76/util.c
> index 95b3dc96e4c4..9fa60d380ede 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.c
> +++ b/drivers/net/wireless/mediatek/mt76/util.c
> @@ -42,12 +42,19 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 
> offset, u32 mask, u32 val,
>   }
>   EXPORT_SYMBOL_GPL(____mt76_poll_msec);
> 
> -int mt76_wcid_alloc(u32 *mask, int size)
> +int __mt76_wcid_alloc(u32 *mask, int min, int size)
>   {
> +    u32 min_mask = ~0;
>       int i, idx = 0, cur;
> 
> +    mask += min / 32;
> +    min %= 32;
> +    if (min > 0)
> +        min_mask = ~((1 << min) - 1);
> +
>       for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
> -        idx = ffs(~mask[i]);
> +        idx = ffs(~mask[i] & min_mask);
> +        min_mask = ~0;
>           if (!idx)
>               continue;
> 
> @@ -62,7 +69,7 @@ int mt76_wcid_alloc(u32 *mask, int size)
> 
>       return -1;
>   }
> -EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
> +EXPORT_SYMBOL_GPL(__mt76_wcid_alloc);
> 
>   int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx)
>   {
> diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/ 
> wireless/mediatek/mt76/util.h
> index 260965dde94c..bca2893f980e 100644
> --- a/drivers/net/wireless/mediatek/mt76/util.h
> +++ b/drivers/net/wireless/mediatek/mt76/util.h
> @@ -27,7 +27,12 @@ enum {
>   #define MT76_INCR(_var, _size) \
>       (_var = (((_var) + 1) % (_size)))
> 
> -int mt76_wcid_alloc(u32 *mask, int size);
> +int __mt76_wcid_alloc(u32 *mask, int min, int size);
> +
> +static inline int mt76_wcid_alloc(u32 *mask, int size)
> +{
> +    return __mt76_wcid_alloc(mask, 0, size);
> +}
> 
>   static inline void
>   mt76_wcid_mask_set(u32 *mask, int idx)


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 6977 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-06-25 17:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-21 14:04 [PATCH v10 RESEND] wifi: mt76: mt7915: add wds support when wed is enabled Shengyu Qu
2025-05-18 14:41 ` Shengyu Qu
2025-05-25 13:42 ` Shengyu Qu
2025-06-24 14:11 ` Shengyu Qu
2025-06-25 10:18   ` Felix Fietkau
2025-06-25 11:00     ` Felix Fietkau
2025-06-25 17:25       ` Shengyu Qu
  -- strict thread matches above, loose matches on Subject: below --
2025-04-12  9:49 Shengyu Qu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).