* [PATCH mt76 1/5] wifi: mt76: Assume __mt76_connac_mcu_alloc_sta_req runs in atomic context
2025-06-05 11:14 [PATCH mt76 0/5] mt76: mt7996: Fix 'sleep while atomic' in mt7996_mac_sta_rc_work() Lorenzo Bianconi
@ 2025-06-05 11:14 ` Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 2/5] wifi: mt76: Move RCU section in mt7996_mcu_set_fixed_field() Lorenzo Bianconi
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 11:14 UTC (permalink / raw)
To: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu
Cc: linux-wireless, linux-arm-kernel, linux-mediatek, Ben Greear,
Lorenzo Bianconi
Rely on GFP_ATOMIC flag in __mt76_connac_mcu_alloc_sta_req since it can
run in 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>
---
drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index cb13d0a768789af956f810e5af19507e436a449a..fa08e952dffa9d6e623a1f6819f136be3a5a0c76 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -287,7 +287,7 @@ __mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif
mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo,
&hdr.wlan_idx_hi);
- skb = mt76_mcu_msg_alloc(dev, NULL, len);
+ skb = __mt76_mcu_msg_alloc(dev, NULL, len, len, GFP_ATOMIC);
if (!skb)
return ERR_PTR(-ENOMEM);
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH mt76 2/5] wifi: mt76: Move RCU section in mt7996_mcu_set_fixed_field()
2025-06-05 11:14 [PATCH mt76 0/5] mt76: mt7996: Fix 'sleep while atomic' in mt7996_mac_sta_rc_work() Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 1/5] wifi: mt76: Assume __mt76_connac_mcu_alloc_sta_req runs in atomic context Lorenzo Bianconi
@ 2025-06-05 11:14 ` Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 3/5] wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl_fixed() Lorenzo Bianconi
` (2 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 11:14 UTC (permalink / raw)
To: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu
Cc: linux-wireless, linux-arm-kernel, linux-mediatek, Ben Greear,
Lorenzo Bianconi
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>
---
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 5 +-
drivers/net/wireless/mediatek/mt76/mt7996/main.c | 3 +-
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 68 ++++++++++++++++------
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 10 ++--
4 files changed, 57 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 0dbd4662bc842947abf09f9ae3aa4a1d4b86cba8..7444bd374b50bdfdcf7e1973993f496b740a1c51 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 78ae9f5cb1760ababc088fc21bfc3957cfe02506..a096b5bab001de8d4fe3270ab37b1a6dab702ab1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -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;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index f0adc0b4b8b6ccdc6ce11991a4d99b89500fe7a9..33c61e795b734e84af42fdea5ba33975e3e3365a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -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
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 1ad6bc046f7c01d43452252ed46677d42e0c8850..a529c2bae7cbf83589650c593f033e6ec5e714a8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -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);
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH mt76 3/5] wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl_fixed()
2025-06-05 11:14 [PATCH mt76 0/5] mt76: mt7996: Fix 'sleep while atomic' in mt7996_mac_sta_rc_work() Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 1/5] wifi: mt76: Assume __mt76_connac_mcu_alloc_sta_req runs in atomic context Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 2/5] wifi: mt76: Move RCU section in mt7996_mcu_set_fixed_field() Lorenzo Bianconi
@ 2025-06-05 11:14 ` Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 4/5] wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl() Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work() Lorenzo Bianconi
4 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 11:14 UTC (permalink / raw)
To: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu
Cc: linux-wireless, linux-arm-kernel, linux-mediatek, Ben Greear,
Lorenzo Bianconi
Since mt7996_mcu_set_fixed_field() can't be executed in a RCU critical
section, move RCU section in mt7996_mcu_add_rate_ctrl_fixed() and run
mt7996_mcu_set_fixed_field() 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>
---
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 86 ++++++++++++++++---------
1 file changed, 57 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 33c61e795b734e84af42fdea5ba33975e3e3365a..742497ba2a6bcd73e3660e626e4a756d79a467bf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1977,51 +1977,74 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
}
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,
- u8 link_id)
+mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ struct ieee80211_vif *vif, 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 ieee80211_link_sta *link_sta;
+ struct cfg80211_bitrate_mask mask;
+ struct mt7996_sta_link *msta_link;
+ struct mt7996_vif_link *link;
struct sta_phy_uni phy = {};
- int ret, nrates = 0;
+ struct ieee80211_sta *sta;
+ int ret, nrates = 0, idx;
+ enum nl80211_band band;
+ bool has_he;
#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \
do { \
- u8 i, gi = mask->control[band]._gi; \
+ u8 i, gi = mask.control[band]._gi; \
gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \
phy.sgi = gi; \
- phy.he_ltf = mask->control[band].he_ltf; \
- for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \
- if (!mask->control[band]._mcs[i]) \
+ phy.he_ltf = mask.control[band].he_ltf; \
+ for (i = 0; i < ARRAY_SIZE(mask.control[band]._mcs); i++) { \
+ if (!mask.control[band]._mcs[i]) \
continue; \
- nrates += hweight16(mask->control[band]._mcs[i]); \
- phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \
+ nrates += hweight16(mask.control[band]._mcs[i]); \
+ phy.mcs = ffs(mask.control[band]._mcs[i]) - 1; \
if (_ht) \
phy.mcs += 8 * i; \
} \
} while (0)
- if (link_sta->he_cap.has_he) {
+ rcu_read_lock();
+
+ link = mt7996_vif_link(dev, vif, link_id);
+ if (!link)
+ goto error_unlock;
+
+ msta_link = rcu_dereference(msta->link[link_id]);
+ if (!msta_link)
+ goto error_unlock;
+
+ sta = wcid_to_sta(&msta_link->wcid);
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
+ goto error_unlock;
+
+ band = link->phy->mt76->chandef.chan->band;
+ has_he = link_sta->he_cap.has_he;
+ mask = link->bitrate_mask;
+ idx = msta_link->wcid.idx;
+
+ if (has_he) {
__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
} else if (link_sta->vht_cap.vht_supported) {
__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
} else if (link_sta->ht_cap.ht_supported) {
__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
} else {
- nrates = hweight32(mask->control[band].legacy);
- phy.mcs = ffs(mask->control[band].legacy) - 1;
+ nrates = hweight32(mask.control[band].legacy);
+ phy.mcs = ffs(mask.control[band].legacy) - 1;
}
+
+ rcu_read_unlock();
+
#undef __sta_phy_bitrate_mask_check
/* fall back to auto rate control */
- if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
- mask->control[band].he_gi == GENMASK(7, 0) &&
- mask->control[band].he_ltf == GENMASK(7, 0) &&
+ if (mask.control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
+ mask.control[band].he_gi == GENMASK(7, 0) &&
+ mask.control[band].he_ltf == GENMASK(7, 0) &&
nrates != 1)
return 0;
@@ -2034,16 +2057,16 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
}
/* fixed GI */
- if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
- mask->control[band].he_gi != GENMASK(7, 0)) {
+ if (mask.control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
+ mask.control[band].he_gi != GENMASK(7, 0)) {
u32 addr;
/* firmware updates only TXCMD but doesn't take WTBL into
* account, so driver should update here to reflect the
* actual txrate hardware sends out.
*/
- addr = mt7996_mac_wtbl_lmac_addr(dev, msta_link->wcid.idx, 7);
- if (link_sta->he_cap.has_he)
+ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 7);
+ if (has_he)
mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
else
mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
@@ -2055,7 +2078,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
}
/* fixed HE_LTF */
- if (mask->control[band].he_ltf != GENMASK(7, 0)) {
+ if (mask.control[band].he_ltf != GENMASK(7, 0)) {
ret = mt7996_mcu_set_fixed_field(dev, msta, &phy, link_id,
RATE_PARAM_FIXED_HE_LTF);
if (ret)
@@ -2063,6 +2086,11 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
}
return 0;
+
+error_unlock:
+ rcu_read_unlock();
+
+ return -ENODEV;
}
static void
@@ -2181,6 +2209,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link,
u8 link_id, bool changed)
{
+ struct mt7996_sta *msta = msta_link->sta;
struct sk_buff *skb;
int ret;
@@ -2207,8 +2236,7 @@ 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,
- link_id);
+ return mt7996_mcu_add_rate_ctrl_fixed(dev, msta, vif, link_id);
}
static int
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH mt76 4/5] wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl()
2025-06-05 11:14 [PATCH mt76 0/5] mt76: mt7996: Fix 'sleep while atomic' in mt7996_mac_sta_rc_work() Lorenzo Bianconi
` (2 preceding siblings ...)
2025-06-05 11:14 ` [PATCH mt76 3/5] wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl_fixed() Lorenzo Bianconi
@ 2025-06-05 11:14 ` Lorenzo Bianconi
2025-06-05 11:14 ` [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work() Lorenzo Bianconi
4 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 11:14 UTC (permalink / raw)
To: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu
Cc: linux-wireless, linux-arm-kernel, linux-mediatek, Ben Greear,
Lorenzo Bianconi
Since mt76_mcu_skb_send_msg() routine can't be executed in atomic context,
move RCU section in mt7996_mcu_add_rate_ctrl() 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>
---
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 3 +-
drivers/net/wireless/mediatek/mt76/mt7996/main.c | 6 +--
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 50 +++++++++++++++++-----
drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 10 ++---
4 files changed, 45 insertions(+), 24 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 7444bd374b50bdfdcf7e1973993f496b740a1c51..5561b1098e3fb0d25551fde3cfdb3057217395fd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2403,8 +2403,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
IEEE80211_RC_NSS_CHANGED |
IEEE80211_RC_BW_CHANGED))
- mt7996_mcu_add_rate_ctrl(dev, vif, link_conf,
- link_sta, link, msta_link,
+ mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif,
link_id, true);
if (changed & IEEE80211_RC_SMPS_CHANGED)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index a096b5bab001de8d4fe3270ab37b1a6dab702ab1..07dd75ce94a5f204dcd4d659a777151bb9fcf8d2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -1112,10 +1112,8 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
if (err)
return err;
- err = mt7996_mcu_add_rate_ctrl(dev, vif, link_conf,
- link_sta, link,
- msta_link, link_id,
- false);
+ err = mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif,
+ link_id, false);
if (err)
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 742497ba2a6bcd73e3660e626e4a756d79a467bf..77ab1f4854a43643c296f6ed28c08da99bfdcb04 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -2201,23 +2201,44 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi));
}
-int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_link_sta *link_sta,
- struct mt7996_vif_link *link,
- struct mt7996_sta_link *msta_link,
- u8 link_id, bool changed)
+int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ struct ieee80211_vif *vif, u8 link_id,
+ bool changed)
{
- struct mt7996_sta *msta = msta_link->sta;
+ struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_link_sta *link_sta;
+ struct mt7996_sta_link *msta_link;
+ struct mt7996_vif_link *link;
+ struct ieee80211_sta *sta;
struct sk_buff *skb;
- int ret;
+ int ret = -ENODEV;
+
+ rcu_read_lock();
+
+ link = mt7996_vif_link(dev, vif, link_id);
+ if (!link)
+ goto error_unlock;
+
+ msta_link = rcu_dereference(msta->link[link_id]);
+ if (!msta_link)
+ goto error_unlock;
+
+ sta = wcid_to_sta(&msta_link->wcid);
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
+ goto error_unlock;
+
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ if (!link_conf)
+ goto error_unlock;
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
&msta_link->wcid,
MT7996_STA_UPDATE_MAX_SIZE);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
+ if (IS_ERR(skb)) {
+ ret = PTR_ERR(skb);
+ goto error_unlock;
+ }
/* firmware rc algorithm refers to sta_rec_he for HE control.
* once dev->rc_work changes the settings driver should also
@@ -2231,12 +2252,19 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
*/
mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link);
+ rcu_read_unlock();
+
ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
if (ret)
return ret;
return mt7996_mcu_add_rate_ctrl_fixed(dev, msta, vif, link_id);
+
+error_unlock:
+ rcu_read_unlock();
+
+ return ret;
}
static int
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index a529c2bae7cbf83589650c593f033e6ec5e714a8..33ac16b64ef113eff3f7749963e34a49b3c67ac3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -620,13 +620,9 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy,
struct mt7996_vif_link *link,
struct ieee80211_he_obss_pd *he_obss_pd);
-int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *link_conf,
- struct ieee80211_link_sta *link_sta,
- struct mt7996_vif_link *link,
- struct mt7996_sta_link *msta_link,
- u8 link_id, bool changed);
+int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ struct ieee80211_vif *vif, 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,
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
2025-06-05 11:14 [PATCH mt76 0/5] mt76: mt7996: Fix 'sleep while atomic' in mt7996_mac_sta_rc_work() Lorenzo Bianconi
` (3 preceding siblings ...)
2025-06-05 11:14 ` [PATCH mt76 4/5] wifi: mt76: Move RCU section in mt7996_mcu_add_rate_ctrl() Lorenzo Bianconi
@ 2025-06-05 11:14 ` Lorenzo Bianconi
2025-06-05 16:50 ` Ben Greear
4 siblings, 1 reply; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 11:14 UTC (permalink / raw)
To: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu
Cc: linux-wireless, linux-arm-kernel, linux-mediatek, Ben Greear,
Lorenzo Bianconi
Since mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field() can't
run in atomic context, move RCU critical section in
mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field(). This patch
fixes 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>
---
drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 38 +++++--------------------
1 file changed, 7 insertions(+), 31 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 5561b1098e3fb0d25551fde3cfdb3057217395fd..445fe149ac0d7e194497a2dc884a599b9546c9ef 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2353,20 +2353,12 @@ void mt7996_mac_update_stats(struct mt7996_phy *phy)
void mt7996_mac_sta_rc_work(struct work_struct *work)
{
struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
- struct ieee80211_bss_conf *link_conf;
- struct ieee80211_link_sta *link_sta;
struct mt7996_sta_link *msta_link;
- struct mt7996_vif_link *link;
- struct mt76_vif_link *mlink;
- struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
- struct mt7996_sta *msta;
struct mt7996_vif *mvif;
LIST_HEAD(list);
u32 changed;
- u8 link_id;
- rcu_read_lock();
spin_lock_bh(&dev->mt76.sta_poll_lock);
list_splice_init(&dev->sta_rc_list, &list);
@@ -2377,44 +2369,28 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
changed = msta_link->changed;
msta_link->changed = 0;
-
- sta = wcid_to_sta(&msta_link->wcid);
- link_id = msta_link->wcid.link_id;
- msta = msta_link->sta;
- mvif = msta->vif;
- vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
-
- mlink = rcu_dereference(mvif->mt76.link[link_id]);
- if (!mlink)
- continue;
-
- link_sta = rcu_dereference(sta->link[link_id]);
- if (!link_sta)
- continue;
-
- link_conf = rcu_dereference(vif->link_conf[link_id]);
- if (!link_conf)
- continue;
+ mvif = msta_link->sta->vif;
+ vif = container_of((void *)mvif, struct ieee80211_vif,
+ drv_priv);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
- link = (struct mt7996_vif_link *)mlink;
-
if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
IEEE80211_RC_NSS_CHANGED |
IEEE80211_RC_BW_CHANGED))
mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif,
- link_id, true);
+ msta_link->wcid.link_id,
+ true);
if (changed & IEEE80211_RC_SMPS_CHANGED)
- mt7996_mcu_set_fixed_field(dev, msta, NULL, link_id,
+ mt7996_mcu_set_fixed_field(dev, msta_link->sta, NULL,
+ msta_link->wcid.link_id,
RATE_PARAM_MMPS_UPDATE);
spin_lock_bh(&dev->mt76.sta_poll_lock);
}
spin_unlock_bh(&dev->mt76.sta_poll_lock);
- rcu_read_unlock();
}
void mt7996_mac_work(struct work_struct *work)
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
2025-06-05 11:14 ` [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work() Lorenzo Bianconi
@ 2025-06-05 16:50 ` Ben Greear
2025-06-05 16:57 ` Lorenzo Bianconi
0 siblings, 1 reply; 11+ messages in thread
From: Ben Greear @ 2025-06-05 16:50 UTC (permalink / raw)
To: Lorenzo Bianconi, Felix Fietkau, Ryder Lee, Shayne Chen,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao,
Peter Chiu
Cc: linux-wireless, linux-arm-kernel, linux-mediatek
On 6/5/25 04:14, Lorenzo Bianconi wrote:
> Since mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field() can't
> run in atomic context, move RCU critical section in
> mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field(). This patch
> fixes 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>
Thanks for the quick fix on this, it appears to solve the problems we
saw related to this.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
2025-06-05 16:50 ` Ben Greear
@ 2025-06-05 16:57 ` Lorenzo Bianconi
2025-06-05 17:13 ` Ben Greear
0 siblings, 1 reply; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 16:57 UTC (permalink / raw)
To: Ben Greear
Cc: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu,
linux-wireless, linux-arm-kernel, linux-mediatek
[-- Attachment #1: Type: text/plain, Size: 810 bytes --]
> On 6/5/25 04:14, Lorenzo Bianconi wrote:
> > Since mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field() can't
> > run in atomic context, move RCU critical section in
> > mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field(). This patch
> > fixes 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>
>
> Thanks for the quick fix on this, it appears to solve the problems we
> saw related to this.
ack, thx. Can you please add your 'tested-by' tag in this case?
Regards,
Lorenzo
>
> Thanks,
> Ben
>
> --
> Ben Greear <greearb@candelatech.com>
> Candela Technologies Inc http://www.candelatech.com
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
2025-06-05 16:57 ` Lorenzo Bianconi
@ 2025-06-05 17:13 ` Ben Greear
2025-06-05 17:15 ` Lorenzo Bianconi
0 siblings, 1 reply; 11+ messages in thread
From: Ben Greear @ 2025-06-05 17:13 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu,
linux-wireless, linux-arm-kernel, linux-mediatek
On 6/5/25 09:57, Lorenzo Bianconi wrote:
>> On 6/5/25 04:14, Lorenzo Bianconi wrote:
>>> Since mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field() can't
>>> run in atomic context, move RCU critical section in
>>> mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field(). This patch
>>> fixes 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>
>>
>> Thanks for the quick fix on this, it appears to solve the problems we
>> saw related to this.
>
> ack, thx. Can you please add your 'tested-by' tag in this case?
Tested-by: Ben Greear <greearb@candelatech.com>
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
2025-06-05 17:13 ` Ben Greear
@ 2025-06-05 17:15 ` Lorenzo Bianconi
2025-06-05 17:17 ` Ben Greear
0 siblings, 1 reply; 11+ messages in thread
From: Lorenzo Bianconi @ 2025-06-05 17:15 UTC (permalink / raw)
To: Ben Greear
Cc: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu,
linux-wireless, linux-arm-kernel, linux-mediatek
[-- Attachment #1: Type: text/plain, Size: 1039 bytes --]
On Jun 05, Ben Greear wrote:
> On 6/5/25 09:57, Lorenzo Bianconi wrote:
> > > On 6/5/25 04:14, Lorenzo Bianconi wrote:
> > > > Since mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field() can't
> > > > run in atomic context, move RCU critical section in
> > > > mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field(). This patch
> > > > fixes 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>
> > >
> > > Thanks for the quick fix on this, it appears to solve the problems we
> > > saw related to this.
> >
> > ack, thx. Can you please add your 'tested-by' tag in this case?
>
> Tested-by: Ben Greear <greearb@candelatech.com>
I am assuming this is for the full series ;)
Regards,
Lorenzo
>
> Thanks,
> Ben
>
> --
> Ben Greear <greearb@candelatech.com>
> Candela Technologies Inc http://www.candelatech.com
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH mt76 5/5] wifi: mt76: Remove RCU section in mt7996_mac_sta_rc_work()
2025-06-05 17:15 ` Lorenzo Bianconi
@ 2025-06-05 17:17 ` Ben Greear
0 siblings, 0 replies; 11+ messages in thread
From: Ben Greear @ 2025-06-05 17:17 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Bo Jiao, Peter Chiu,
linux-wireless, linux-arm-kernel, linux-mediatek
On 6/5/25 10:15, Lorenzo Bianconi wrote:
> On Jun 05, Ben Greear wrote:
>> On 6/5/25 09:57, Lorenzo Bianconi wrote:
>>>> On 6/5/25 04:14, Lorenzo Bianconi wrote:
>>>>> Since mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field() can't
>>>>> run in atomic context, move RCU critical section in
>>>>> mt7996_mcu_add_rate_ctrl() and mt7996_mcu_set_fixed_field(). This patch
>>>>> fixes 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>
>>>>
>>>> Thanks for the quick fix on this, it appears to solve the problems we
>>>> saw related to this.
>>>
>>> ack, thx. Can you please add your 'tested-by' tag in this case?
>>
>> Tested-by: Ben Greear <greearb@candelatech.com>
>
> I am assuming this is for the full series ;)
Yes, and to be clear, I had to re-work the patches a bit to get them into my tree,
but that was just because I have a lot of mtk upstream patches and my own hacks
in this code. I still think the tested-by is valid though.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply [flat|nested] 11+ messages in thread