[PATCH wireless] wifi: mt76: mt7615: avoid waiting for mac work under the mt76 mutex
Runyu Xiao
runyu.xiao at seu.edu.cn
Thu Jun 11 21:13:31 PDT 2026
mt7615_suspend() takes the mt76 mutex and then waits for mac_work with
cancel_delayed_work_sync(). mt7615_mac_work() takes the same mutex at
the top of the worker, so the suspend path can deadlock against the
delayed work it is trying to flush.
This issue was found by our static analysis tool and then manually
reviewed against the current tree.
The grounded PoC kept the mt7615_suspend() ->
cancel_delayed_work_sync(&phy->mt76->mac_work) path and the
mt7615_mac_work() -> mt7615_mutex_acquire() edge. Lockdep reported:
WARNING: possible circular locking dependency detected
mt7615_mac_work+0x1b/0x29 [vuln_msv]
__cancel_work_timer
*** DEADLOCK ***
Stop queueing mac_work while the mutex is held, drop the mutex, and then
flush the delayed work from the sleepable post-unlock path.
Fixes: c6bf20109a3f ("mt76: mt7615: add WoW support")
Cc: stable at vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao at seu.edu.cn>
---
Notes:
- Validated with a grounded Lockdep PoC that preserves the
mt7615_suspend() -> cancel_delayed_work_sync(&phy->mt76->mac_work)
path and the mt7615_mac_work() -> mt7615_mutex_acquire() edge.
- checkpatch.pl --strict: clean.
- Not tested on mt7615 hardware.
drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 15fe155ac3f3..fcb619c0f6cf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -1242,7 +1242,8 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
cancel_delayed_work_sync(&phy->scan_work);
- cancel_delayed_work_sync(&phy->mt76->mac_work);
+ /* mac_work re-enters the mt76 mutex, so flush it after unlock. */
+ cancel_delayed_work(&phy->mt76->mac_work);
set_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
@@ -1254,6 +1255,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true);
mt7615_mutex_release(dev);
+ cancel_delayed_work_sync(&phy->mt76->mac_work);
return err;
}
--
2.34.1
More information about the linux-arm-kernel
mailing list