[PATCH wireless] wifi: mt76: mt7921e: fix unregister deadlock
From: Devin Wittmayer
Date: Mon Nov 02 2026 - 18:37:12 EST
Removing the driver can hang forever when the chip stops answering.
Removal disables NAPI and only then waits for the reset work, which a
failing chip keeps queuing. That reset disables NAPI again and never
returns.
Do what mt7925e does: mark the device removed once it is unregistered,
so no new reset is queued, and cancel the reset work before disabling
NAPI.
Fixes: 3d78c46423c6 ("wifi: mt76: mt7921e: stop chip reset worker in unregister hook")
Reported-by: Matthew Wilcox <willy@xxxxxxxxxxxxx>
Closes: https://lore.kernel.org/all/aujjJPq-Qth7UyMp@xxxxxxxxxxxxxxxxxxxx/
Signed-off-by: Devin Wittmayer <lucid_duck@xxxxxxxxxxxxx>
---
Reproduced on an MT7922 by putting the chip in D3hot under the driver:
the same driver own and chip reset failures, then rmmod waiting in the
same stack while the reset work is stuck disabling NAPI.
dead chip, rmmod result
6.18.52, in-tree hangs
mt76 03dd150dbd36 returns
with this patch returns
75673ab3c0e4 reverted hangs
reverted, with this patch returns, 3 of 3
Since 75673ab3c0e4 the reset stops early when driver own fails, so
current mt76 gets through a fully dead chip. That commit is not in
v7.3, and any reset that gets as far as NAPI still hangs.
This needs the removed check in the reset helper from 79941e85f4b3. A
normal rmmod and a debugfs chip reset work as before.
Matthew, thanks for the stack trace.
drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index f87c44f2a8b6..1ff219005d14 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -52,11 +52,12 @@ static void mt7921e_unregister_device(struct mt792x_dev *dev)
cancel_work_sync(&dev->init_work);
mt76_unregister_device(&dev->mt76);
+ set_bit(MT76_REMOVED, &dev->mphy.state);
+ cancel_work_sync(&dev->reset_work);
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);
mt76_connac2_tx_token_put(&dev->mt76);
__mt792x_mcu_drv_pmctrl(dev);
@@ -460,7 +461,6 @@ static void mt7921_pci_remove(struct pci_dev *pdev)
device_init_wakeup(dev->mt76.dev, false);
mt7921e_unregister_device(dev);
- set_bit(MT76_REMOVED, &mdev->phy.state);
devm_free_irq(&pdev->dev, pdev->irq, dev);
mt76_free_device(&dev->mt76);
pci_free_irq_vectors(pdev);
--
2.56.0