wifi: mt76: Move RCU section in mt7996_mcu_set_fixed_field()

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: 0762bdd302 ("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>
This commit is contained in:
Lorenzo Bianconi
2025-06-05 13:14:17 +02:00
committed by Felix Fietkau
parent a0c5eac918
commit c772cd726e
4 changed files with 57 additions and 29 deletions

View 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);

View 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;

View 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

View 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);