]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: mt76: mt7996: set specific BSSINFO and STAREC commands after channel switch
authorStanleyYP Wang <StanleyYP.Wang@mediatek.com>
Mon, 15 Dec 2025 06:37:24 +0000 (14:37 +0800)
committerFelix Fietkau <nbd@nbd.name>
Mon, 23 Mar 2026 09:14:42 +0000 (09:14 +0000)
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>
Link: https://patch.msgid.link/20251215063728.3013365-3-shayne.chen@mediatek.com
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/main.c
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h

index fac50dbceae7645a766ee51220c6b029c46ce5bc..393823368bed2f51bbcdf877a81c4e5c7ede175e 100644 (file)
@@ -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;
index 6294704f78813886a5068fc8fa636d4392e5a6c9..5a634b71ed2a9a6a15f956d451cd88fec0984b39 100644 (file)
@@ -1231,6 +1231,22 @@ out:
                                     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,
index d31864f973cceb5649ac4b7357bcac79eb01d0d9..8f1043159f5870eba8f9c6a42440530a685898a0 100644 (file)
@@ -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);