Commit c772cd72 authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Felix Fietkau
Browse files

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: 0762bdd3 ("wifi: mt76: mt7996: rework mt7996_mac_sta_rc_work to support MLO")
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250605-mt7996-sleep-while-atomic-v1-2-d46d15f9203c@kernel.org


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent a0c5eac9
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -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;

+49 −19
Original line number Diff line number Diff line
@@ -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
+4 −6
Original line number Diff line number Diff line
@@ -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);