diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.cindex 049223df9beb1..dc4d87e004a0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c@@ -745,8 +745,15 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,bool ext_phy = mvif->phy != &dev->phy; int ret, idx; u32 addr; + 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;I'd prefer to replace the mt76_wcid_alloc flags argument with an explicit start offset argument.
Hi Felix, I'm not really familiar with mt76 code, just a enthusiast that wants to make WDS+WED working. So I'm not sure how to do this correctly... Maybe it's better for you to take over this patch, sorry.
@@ -1201,12 +1208,27 @@ static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,In order to update the code based on my latest changes and to fix potential race conditions on tx/rx packets during the transition, please change to this order:{ 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; if (enabled) set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + !is_mt7915(&dev->mt76) && + (msta->wcid.idx < min || msta->wcid.idx > max - 1)) { + struct ieee80211_sta *pre_sta; + + pre_sta = kzalloc(sizeof(*sta) + sizeof(*msta), GFP_KERNEL); + mt76_sta_pre_rcu_remove(hw, vif, sta); + memmove(pre_sta, sta, sizeof(*sta) + sizeof(*msta)); + mt7915_sta_add(hw, vif, sta); + synchronize_rcu(); + mt7915_sta_remove(hw, vif, pre_sta); + kfree(pre_sta); + } + mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); }1. copy the sta 2. allocate a new wcid 3. change the wcid index in the copied sta to the newly allocated wcid 4. call mcu functions on the duplicate sta for creating the new sta entry. 5. use rcu_assign_pointer to point dev->wcid[new_idx] at &msta->wcid 6. swap wcid index between real sta and duplicated sta 7. rcu_assign_pointer(dev->wcid[orig_idx], NULL) 8. synchronize_rcu()9. call mcu functions to delete the duplicate sta's entry (points to old wcid after the swap)10. free the duplicated sta
Now, the mt7915_sta_set_4addr function looks like this(__mt76_wcid_alloc not modified), do you think it's acceptable? static void mt7915_sta_set_4addr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { 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; u8 flags = MT76_WED_DEFAULT; int temp_idx; if (enabled) set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 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 = kzalloc(sizeof(*sta) + sizeof(*msta), GFP_KERNEL); memmove(pre_sta, sta, sizeof(*sta) + sizeof(*msta)); 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; } temp_idx = __mt76_wcid_alloc(mdev->wcid_mask, MT7915_WTBL_STA, flags); ((struct mt7915_sta *)pre_sta->drv_priv)->wcid.idx = temp_idx; mt7915_sta_add(hw, vif, pre_sta); rcu_assign_pointer(dev->mt76.wcid[temp_idx], &msta->wcid); temp_idx = msta->wcid.idx; msta->wcid.idx = ((struct mt7915_sta *)pre_sta->drv_priv)->wcid.idx; ((struct mt7915_sta *)pre_sta->drv_priv)->wcid.idx = temp_idx; rcu_assign_pointer(dev->mt76.wcid[temp_idx], NULL); synchronize_rcu(); mt7915_sta_remove(hw, vif, pre_sta); kfree(pre_sta); } mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } Best regards, Shengyu
This should allow mgmt tx/rx to work while the sta is being migrated to the new wcid entry.- Felix
Attachment:
OpenPGP_0xE3520CC91929C8E7.asc
Description: OpenPGP public key
Attachment:
OpenPGP_signature.asc
Description: OpenPGP digital signature