]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mt76: Move RCU section in mt7996_mcu_set_fixed_field()
authorLorenzo Bianconi <lorenzo@kernel.org>
Thu, 5 Jun 2025 11:14:17 +0000 (13:14 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 7 Jul 2025 15:42:20 +0000 (17:42 +0200)
Since mt76_mcu_skb_send_msg() routine can't be executed in atomic context,
move RCU section in mt7996_mcu_set_fixed_field() and execute
mt76_mcu_skb_send_msg() in non-atomic context. This is a preliminary
patch to fix a 'sleep while atomic' issue in mt7996_mac_sta_rc_work().

Fixes: 0762bdd30279 ("wifi: mt76: mt7996: rework mt7996_mac_sta_rc_work to support MLO")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250605-mt7996-sleep-while-atomic-v1-2-d46d15f9203c@kernel.org
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/mac.c
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 0dbd4662bc842947abf09f9ae3aa4a1d4b86cba8..7444bd374b50bdfdcf7e1973993f496b740a1c51 100644 (file)
@@ -2405,11 +2405,10 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
                               IEEE80211_RC_BW_CHANGED))
                        mt7996_mcu_add_rate_ctrl(dev, vif, link_conf,
                                                 link_sta, link, msta_link,
-                                                true);
+                                                link_id, true);
 
                if (changed & IEEE80211_RC_SMPS_CHANGED)
-                       mt7996_mcu_set_fixed_field(dev, link_sta, link,
-                                                  msta_link, NULL,
+                       mt7996_mcu_set_fixed_field(dev, msta, NULL, link_id,
                                                   RATE_PARAM_MMPS_UPDATE);
 
                spin_lock_bh(&dev->mt76.sta_poll_lock);
index 78ae9f5cb1760ababc088fc21bfc3957cfe02506..a096b5bab001de8d4fe3270ab37b1a6dab702ab1 100644 (file)
@@ -1114,7 +1114,8 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
 
                        err = mt7996_mcu_add_rate_ctrl(dev, vif, link_conf,
                                                       link_sta, link,
-                                                      msta_link, false);
+                                                      msta_link, link_id,
+                                                      false);
                        if (err)
                                return err;
 
index f0adc0b4b8b6ccdc6ce11991a4d99b89500fe7a9..33c61e795b734e84af42fdea5ba33975e3e3365a 100644 (file)
@@ -1905,22 +1905,35 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
                                     MCU_WM_UNI_CMD(RA), true);
 }
 
-int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
-                              struct ieee80211_link_sta *link_sta,
-                              struct mt7996_vif_link *link,
-                              struct mt7996_sta_link *msta_link,
-                              void *data, u32 field)
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
+                              void *data, u8 link_id, u32 field)
 {
-       struct sta_phy_uni *phy = data;
+       struct mt7996_vif *mvif = msta->vif;
+       struct mt7996_sta_link *msta_link;
        struct sta_rec_ra_fixed_uni *ra;
+       struct sta_phy_uni *phy = data;
+       struct mt76_vif_link *mlink;
        struct sk_buff *skb;
+       int err = -ENODEV;
        struct tlv *tlv;
 
-       skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
+       rcu_read_lock();
+
+       mlink = rcu_dereference(mvif->mt76.link[link_id]);
+       if (!mlink)
+               goto error_unlock;
+
+       msta_link = rcu_dereference(msta->link[link_id]);
+       if (!msta_link)
+               goto error_unlock;
+
+       skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink,
                                              &msta_link->wcid,
                                              MT7996_STA_UPDATE_MAX_SIZE);
-       if (IS_ERR(skb))
-               return PTR_ERR(skb);
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               goto error_unlock;
+       }
 
        tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
        ra = (struct sta_rec_ra_fixed_uni *)tlv;
@@ -1935,27 +1948,45 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
                if (phy)
                        ra->phy = *phy;
                break;
-       case RATE_PARAM_MMPS_UPDATE:
+       case RATE_PARAM_MMPS_UPDATE: {
+               struct ieee80211_sta *sta = wcid_to_sta(&msta_link->wcid);
+               struct ieee80211_link_sta *link_sta;
+
+               link_sta = rcu_dereference(sta->link[link_id]);
+               if (!link_sta) {
+                       dev_kfree_skb(skb);
+                       goto error_unlock;
+               }
+
                ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);
                break;
+       }
        default:
                break;
        }
        ra->field = cpu_to_le32(field);
 
+       rcu_read_unlock();
+
        return mt76_mcu_skb_send_msg(&dev->mt76, skb,
                                     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+error_unlock:
+       rcu_read_unlock();
+
+       return err;
 }
 
 static int
 mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
                               struct ieee80211_link_sta *link_sta,
                               struct mt7996_vif_link *link,
-                              struct mt7996_sta_link *msta_link)
+                              struct mt7996_sta_link *msta_link,
+                              u8 link_id)
 {
        struct cfg80211_chan_def *chandef = &link->phy->mt76->chandef;
        struct cfg80211_bitrate_mask *mask = &link->bitrate_mask;
        enum nl80211_band band = chandef->chan->band;
+       struct mt7996_sta *msta = msta_link->sta;
        struct sta_phy_uni phy = {};
        int ret, nrates = 0;
 
@@ -1996,8 +2027,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
 
        /* fixed single rate */
        if (nrates == 1) {
-               ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
-                                                msta_link, &phy,
+               ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
                                                 RATE_PARAM_FIXED_MCS);
                if (ret)
                        return ret;
@@ -2018,8 +2048,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
                else
                        mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
 
-               ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
-                                                msta_link, &phy,
+               ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
                                                 RATE_PARAM_FIXED_GI);
                if (ret)
                        return ret;
@@ -2027,8 +2056,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
 
        /* fixed HE_LTF */
        if (mask->control[band].he_ltf != GENMASK(7, 0)) {
-               ret = mt7996_mcu_set_fixed_field(dev, link_sta, link,
-                                                msta_link, &phy,
+               ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
                                                 RATE_PARAM_FIXED_HE_LTF);
                if (ret)
                        return ret;
@@ -2150,7 +2178,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
                             struct ieee80211_bss_conf *link_conf,
                             struct ieee80211_link_sta *link_sta,
                             struct mt7996_vif_link *link,
-                            struct mt7996_sta_link *msta_link, bool changed)
+                            struct mt7996_sta_link *msta_link,
+                            u8 link_id, bool changed)
 {
        struct sk_buff *skb;
        int ret;
@@ -2178,7 +2207,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
        if (ret)
                return ret;
 
-       return mt7996_mcu_add_rate_ctrl_fixed(dev, link_sta, link, msta_link);
+       return mt7996_mcu_add_rate_ctrl_fixed(dev, link_sta, link, msta_link,
+                                             link_id);
 }
 
 static int
index 1ad6bc046f7c01d43452252ed46677d42e0c8850..a529c2bae7cbf83589650c593f033e6ec5e714a8 100644 (file)
@@ -625,18 +625,16 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
                             struct ieee80211_bss_conf *link_conf,
                             struct ieee80211_link_sta *link_sta,
                             struct mt7996_vif_link *link,
-                            struct mt7996_sta_link *msta_link, bool changed);
+                            struct mt7996_sta_link *msta_link,
+                            u8 link_id, bool changed);
 int mt7996_set_channel(struct mt76_phy *mphy);
 int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
 int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif,
                      struct ieee80211_bss_conf *link_conf);
 int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
                                   void *data, u16 version);
-int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
-                              struct ieee80211_link_sta *link_sta,
-                              struct mt7996_vif_link *link,
-                              struct mt7996_sta_link *msta_link,
-                              void *data, u32 field);
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
+                              void *data, u8 link_id, u32 field);
 int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
 int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len);
 int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);