[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:41:27 PST 2025


Note, this is an update to the original patch I sent.

In this v2 patch, I moved mutex protection from inside
mt7925_roc_abort_sync() to the
call site in pci.c. The previous approach caused a self-deadlock when
roc_abort_sync was
called from the station remove path, which already holds the mutex.

I created a repo with all these patches if that makes it easier:
https://github.com/zbowling/mt7925

These bugs also exist in the mt7921 driver, which this mt7925 driver
seems to fork from.
These lock patterns match the much older mt7615 driver and other wifi drivers.

Zac Bowling

Zac Bowling


On Wed, Dec 31, 2025 at 4:23 PM Zac Bowling <zbowling at gmail.com> wrote:
>
> 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