[PATCH 3/3] wifi: mt76: mt7925: fix missing mutex protection in runtime PM and MLO PM
Zac Bowling
zbowling at gmail.com
Wed Dec 31 16:23:21 PST 2025
From: Zac Bowling <zac at zacbowling.com>
Two additional code paths were identified that iterate over active
interfaces and call MCU functions without proper mutex protection:
1. mt7925_set_runtime_pm(): Called when runtime PM settings change.
The callback mt7925_pm_interface_iter() calls mt7925_mcu_set_beacon_filter()
which in turn calls mt7925_mcu_set_rxfilter(). These MCU functions require
the device mutex to be held.
2. mt7925_mlo_pm_work(): A workqueue function for MLO power management.
The callback mt7925_mlo_pm_iter() was acquiring mutex internally, which
is inconsistent with the rest of the driver where the caller holds the
mutex during interface iteration. Move the mutex to the caller for
consistency and to prevent potential race conditions.
The impact of these bugs:
- mt7925_set_runtime_pm(): Can cause deadlocks when power management
settings are changed while WiFi is active
- mt7925_mlo_pm_work(): Can cause race conditions during MLO power save
state transitions
Note: Similar bugs exist in the mt7921 driver and should be fixed in a
separate patch series.
Reported-by: Zac Bowling <zac at zacbowling.com>
Tested-by: Zac Bowling <zac at zacbowling.com>
Signed-off-by: Zac Bowling <zac at zacbowling.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 3001a62a8b67..9f17b21aef1c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -751,9 +751,11 @@ void mt7925_set_runtime_pm(struct mt792x_dev *dev)
bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
pm->enable = pm->enable_user && !monitor;
+ mt792x_mutex_acquire(dev);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_pm_interface_iter, dev);
+ mt792x_mutex_release(dev);
pm->ds_enable = pm->ds_enable_user && !monitor;
mt7925_mcu_set_deep_sleep(dev, pm->ds_enable);
}
@@ -1301,14 +1303,12 @@ mt7925_mlo_pm_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
if (mvif->mlo_pm_state != MT792x_MLO_CHANGED_PS)
return;
- mt792x_mutex_acquire(dev);
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
bss_conf = mt792x_vif_to_bss_conf(vif, i);
if (!bss_conf)
continue;
mt7925_mcu_uni_bss_ps(dev, bss_conf);
}
- mt792x_mutex_release(dev);
}
void mt7925_mlo_pm_work(struct work_struct *work)
@@ -1317,9 +1317,11 @@ void mt7925_mlo_pm_work(struct work_struct *work)
mlo_pm_work.work);
struct ieee80211_hw *hw = mt76_hw(dev);
+ mt792x_mutex_acquire(dev);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_mlo_pm_iter, dev);
+ mt792x_mutex_release(dev);
}
void mt7925_scan_work(struct work_struct *work)
--
2.51.0
More information about the Linux-mediatek
mailing list