[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260101062535.186356-1-zbowling@gmail.com>
Date: Wed, 31 Dec 2025 22:25:35 -0800
From: Zac Bowling <zbowling@...il.com>
To: linux-wireless@...r.kernel.org
Cc: linux-mediatek@...ts.infradead.org,
linux-kernel@...r.kernel.org,
kvalo@...nel.org,
lorenzo@...nel.org,
nbd@....name,
sean.wang@...iatek.com,
deren.wu@...iatek.com,
ryder.lee@...iatek.com
Subject: [PATCH] wifi: mt76: mt7921: fix missing mutex protection in multiple paths
From: Zac Bowling <zac@...bowling.com>
The MT7921 driver has the same mutex protection bugs as MT7925 - they were
inherited when MT7925 was forked from MT7921. Several code paths iterate
over active interfaces and call MCU functions without proper mutex protection.
Add mutex protection in the following locations:
1. mt7921_set_runtime_pm() in main.c:
Called when runtime PM settings change. The callback
mt7921_pm_interface_iter() calls MCU functions that require
the device mutex to be held.
2. mt7921_regd_set_6ghz_power_type() in main.c:
Called during VIF add/remove for 6GHz power type determination.
Uses ieee80211_iterate_active_interfaces() without mutex.
3. mt7921_mac_reset_work() in mac.c:
After firmware recovery, iterates interfaces to reconnect them.
The mt7921_vif_connect_iter() callback calls MCU functions.
4. PCI/SDIO suspend paths (pci.c, sdio.c):
The mt7921_roc_abort_sync() call iterates interfaces without
mutex protection.
These bugs can cause system hangs during:
- Power management state transitions
- WiFi reset/recovery
- Suspend/resume cycles
- 6GHz regulatory power type changes
The fix follows the same pattern used in the MT7925 patches.
Signed-off-by: Zac Bowling <zac@...bowling.com>
---
drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 ++
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 4 ++++
drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 ++
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c | 2 ++
4 files changed, 10 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 03b4960db73f..f5c882e45bbe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -693,9 +693,11 @@ void mt7921_mac_reset_work(struct work_struct *work)
clear_bit(MT76_RESET, &dev->mphy.state);
pm->suspended = false;
ieee80211_wake_queues(hw);
+ mt792x_mutex_acquire(dev);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_vif_connect_iter, NULL);
+ mt792x_mutex_release(dev);
mt76_connac_power_save_sched(&dev->mt76.phy, pm);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 5fae9a6e273c..05793a786644 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -619,9 +619,11 @@ void mt7921_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,
mt7921_pm_interface_iter, dev);
+ mt792x_mutex_release(dev);
pm->ds_enable = pm->ds_enable_user && !monitor;
mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
}
@@ -765,9 +767,11 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add)
struct mt792x_dev *dev = phy->dev;
u32 valid_vif_num = 0;
+ mt792x_mutex_acquire(dev);
ieee80211_iterate_active_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_calc_vif_num, &valid_vif_num);
+ mt792x_mutex_release(dev);
if (valid_vif_num > 1) {
phy->power_type = MT_AP_DEFAULT;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index ec9686183251..9f76b334b93d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -426,7 +426,9 @@ static int mt7921_pci_suspend(struct device *device)
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
+ mt792x_mutex_acquire(dev);
mt7921_roc_abort_sync(dev);
+ mt792x_mutex_release(dev);
err = mt792x_mcu_drv_pmctrl(dev);
if (err < 0)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
index 3421e53dc948..92ea2811816f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -219,7 +219,9 @@ static int mt7921s_suspend(struct device *__dev)
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
+ mt792x_mutex_acquire(dev);
mt7921_roc_abort_sync(dev);
+ mt792x_mutex_release(dev);
err = mt792x_mcu_drv_pmctrl(dev);
if (err < 0)
--
2.51.0
Powered by blists - more mailing lists