From: JB Tsai <jb.tsai@mediatek.com>
To: <nbd@nbd.name>, <lorenzo@kernel.org>
Cc: <linux-wireless@vger.kernel.org>,
<linux-mediatek@lists.infradead.org>, <Sean.Wang@mediatek.com>,
<Quan.Zhou@mediatek.com>, <Ryder.Lee@mediatek.com>,
<Leon.Yen@mediatek.com>, <litien.chang@mediatek.com>,
<jb.tsai@mediatek.com>, Fei Shao <fshao@google.com>
Subject: [PATCH] wifi: mt76: mt7925: Fix unregister deadlock
Date: Tue, 30 Jun 2026 17:06:10 +0800 [thread overview]
Message-ID: <20260630090610.586954-1-jb.tsai@mediatek.com> (raw)
During device shutdown or removal, a deadlock can occur between the
PCIe remove path and the driver's asynchronous reset work.
The unregistration path calls napi_disable() before cancelling the
reset work. If the reset work runs concurrently, it may re-enable NAPI
and schedule it. Because the device is being unregistered, this can
lead to NAPI state corruption where NAPI is marked as scheduled but
never polled, causing subsequent napi_disable() calls to hang forever.
Fix this by:
1. Moving cancel_work_sync(&dev->reset_work) to the very start of
mt7925e_unregister_device(), ensuring it is stopped before NAPI
is disabled.
2. Setting the MT76_REMOVED flag early in the PCI remove path to
prevent new reset work from being queued.
3. Checking MT76_REMOVED in mt7925_mac_reset_work() and aborting the
reset early if the device is being removed.
Co-developed-by: Fei Shao <fshao@google.com>
Signed-off-by: JB Tsai <jb.tsai@mediatek.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 7 +++++++
drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 4 ++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 0641a7131d7c..1c6d43b162c0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1319,6 +1319,9 @@ void mt7925_mac_reset_work(struct work_struct *work)
cancel_work_sync(&pm->wake_work);
for (i = 0; i < 10; i++) {
+ if (test_bit(MT76_REMOVED, &dev->mt76.phy.state))
+ goto out;
+
mutex_lock(&dev->mt76.mutex);
ret = mt792x_dev_reset(dev);
mutex_unlock(&dev->mt76.mutex);
@@ -1338,8 +1341,12 @@ void mt7925_mac_reset_work(struct work_struct *work)
ieee80211_scan_completed(dev->mphy.hw, &info);
}
+out:
dev->hw_full_reset = false;
pm->suspended = false;
+ if (test_bit(MT76_REMOVED, &dev->mt76.phy.state))
+ return;
+
ieee80211_wake_queues(hw);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index ea64303283ed..978a3f08e080 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -43,13 +43,13 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN)
wiphy_rfkill_stop_polling(hw->wiphy);
+ cancel_work_sync(&dev->reset_work);
cancel_work_sync(&dev->init_work);
mt76_unregister_device(&dev->mt76);
mt76_for_each_q_rx(&dev->mt76, i)
napi_disable(&dev->mt76.napi[i]);
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
- cancel_work_sync(&dev->reset_work);
mt7925_tx_token_put(dev);
__mt792x_mcu_drv_pmctrl(dev);
@@ -498,8 +498,8 @@ static void mt7925_pci_remove(struct pci_dev *pdev)
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
- mt7925e_unregister_device(dev);
set_bit(MT76_REMOVED, &mdev->phy.state);
+ mt7925e_unregister_device(dev);
devm_free_irq(&pdev->dev, pdev->irq, dev);
mt76_free_device(&dev->mt76);
pci_free_irq_vectors(pdev);
--
2.45.2
reply other threads:[~2026-06-30 9:06 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260630090610.586954-1-jb.tsai@mediatek.com \
--to=jb.tsai@mediatek.com \
--cc=Leon.Yen@mediatek.com \
--cc=Quan.Zhou@mediatek.com \
--cc=Ryder.Lee@mediatek.com \
--cc=Sean.Wang@mediatek.com \
--cc=fshao@google.com \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-wireless@vger.kernel.org \
--cc=litien.chang@mediatek.com \
--cc=lorenzo@kernel.org \
--cc=nbd@nbd.name \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox