[PATCH mt76 3/7] wifi: mt76: mt7996: set specific BSSINFO and STAREC commands after channel switch

Shayne Chen
2025-11-25T03:47:35Z

From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>

After channel switch, some tags of BSSINFO (rfch) and STAREC (bfer,
rate_ctrl) commands should also be updated. Otherwise, a BSS might not be
able to transmit with its peer using correct bandwidth.

Co-developed-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7996/main.c | 14 ++++-
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 59 +++++++++++++++++++
.../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +
3 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 18c6cdaae20b..afc0ca3f3939 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -962,12 +962,24 @@ mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper;
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band);
- int ret;
+ struct mt7996_vif_link *link;
+ int ret = -EINVAL;

mutex_lock(&dev->mt76.mutex);

+ link = mt7996_vif_conf_link(dev, vif, link_conf);
+ if (!link)
+ goto out;
+
+ ret = mt7996_mcu_update_bss_rfch(phy, link);
+ if (ret)
+ goto out;
+
+ ieee80211_iterate_stations_mtx(hw, mt7996_mcu_update_sta_rec_bw, link);
+
ret = mt7996_mcu_rdd_resume_tx(phy);

+out:
mutex_unlock(&dev->mt76.mutex);

return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index c18c809ac77a..8f2b3f4f25ab 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1231,6 +1231,22 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
}

+int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy, struct mt7996_vif_link *link)
+{
+ struct mt7996_dev *dev = phy->dev;
+ struct sk_buff *skb;
+
+ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76,
+ MT7996_BSS_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7996_mcu_bss_rfch_tlv(skb, phy);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+}
+
int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
@@ -2590,6 +2606,49 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}

+void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta)
+{
+ struct mt7996_vif_link *link = (struct mt7996_vif_link *)data;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_sta_link *msta_link;
+ struct mt7996_dev *dev;
+ struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_link_sta *link_sta;
+ struct ieee80211_vif *vif;
+ struct sk_buff *skb;
+ int link_id;
+
+ if (link->mt76.mvif != &msta->vif->mt76)
+ return;
+
+ dev = link->phy->dev;
+ link_id = link->msta_link.wcid.link_id;
+ link_sta = link_sta_dereference_protected(sta, link_id);
+ if (!link_sta)
+ return;
+
+ msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ if (!msta_link)
+ return;
+
+ vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
+ link_conf = link_conf_dereference_protected(vif, link_id);
+ if (!link_conf)
+ return;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
+ &msta_link->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return;
+
+ mt7996_mcu_sta_bfer_tlv(dev, skb, link_conf, link_sta, link);
+ mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link);
+
+ mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+}
+
static int
mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct sk_buff *skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index d31864f973cc..8f1043159f58 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -670,6 +670,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink,
struct mt7996_sta_link *msta_link, int enable);
+int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy,
+ struct mt7996_vif_link *link);
int mt7996_mcu_add_sta(struct mt7996_dev *dev,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_link_sta *link_sta,
@@ -679,6 +681,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev,
int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link);
+void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta);
int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
struct ieee80211_ampdu_params *params,
struct ieee80211_vif *vif, bool enable);
--
2.51.0