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 Tested-by: Sujuan Chen <sujuan.chen@xxxxxxxxxxxx> Co-developed-by: Bo Jiao <bo.jiao@xxxxxxxxxxxx> Signed-off-by: Bo Jiao <bo.jiao@xxxxxxxxxxxx> Signed-off-by: Sujuan Chen <sujuan.chen@xxxxxxxxxxxx> --- v2: - drop duplicate settings - reduce the patch size by redefining mt76_wcid_alloc --- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++ .../net/wireless/mediatek/mt76/mt7915/main.c | 24 +++++++++-- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 13 +++++- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/util.c | 40 +++++++++++++++++-- drivers/net/wireless/mediatek/mt76/util.h | 7 +++- 6 files changed, 82 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 32a77a0ae9da..4726378fd0ad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -60,6 +60,12 @@ enum mt76_wed_type { MT76_WED_Q_RX, }; +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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index c40b6098f19a..46a9e4f0396e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -660,8 +660,15 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; bool ext_phy = mvif->phy != &dev->phy; int ret, idx; + u8 flags = MT76_WED_DEFAULT; - 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; @@ -1115,6 +1122,13 @@ 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) && + !is_mt7915(&dev->mt76)) { + mt7915_sta_remove(hw, vif, sta); + mt76_sta_pre_rcu_remove(hw, vif, sta); + mt7915_sta_add(hw, vif, sta); + } + mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } @@ -1479,15 +1493,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 9e479d41eab5..3e73a95ff029 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2307,8 +2307,17 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev) if (ret) return ret; - if (mtk_wed_device_active(&dev->mt76.mmio.wed) && is_mt7915(&dev->mt76)) - mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + if (is_mt7915(&dev->mt76)) + 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; + } 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 46c517e50ae4..b0e5c0e9fa67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -271,6 +271,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, }; enum mcu_mmps_mode { diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index 581964425468..5cd5ede0438f 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -42,9 +42,14 @@ 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) { +#define MT76_WED_WDS_MIN 256 +#define MT76_WED_WDS_CNT 16 + int i, idx = 0, cur; + int min = MT76_WED_WDS_MIN; + int max = min + MT76_WED_WDS_CNT; for (i = 0; i < DIV_ROUND_UP(size, 32); i++) { idx = ffs(~mask[i]); @@ -53,16 +58,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 = MT76_WED_WDS_CNT - 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, bool ext_phy) { diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h index 260965dde94c..99b7263c0a20 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 size, u8 flags); + +static inline int mt76_wcid_alloc(u32 *mask, int size) +{ + return __mt76_wcid_alloc(mask, size, 0); +} static inline void mt76_wcid_mask_set(u32 *mask, int idx) -- 2.18.0