[PATCH wireless] wifi: mt76: mt792x: defer the MCU shutdown past unregister on USB

Devin Wittmayer lucid_duck at justthetip.ca
Wed Sep 23 10:24:24 PDT 2026


The USB disconnect path abandons the MCU before it unregisters, so the
teardown commands that follow cannot be answered. The response parser
reads the silence as a timeout and starts a chip reset for each one,
queueing the work that was cancelled nine lines earlier and reloading
firmware onto a device being removed.

Shut the MCU down after unregister instead. MT7921AU on a Pi 5, eight
unload cycles per arm:

    unload         5.67 s -> 2.81 s
    MCU timeouts   8      -> 0
    reset queued   8/8    -> 0/8

Deauthorizing the port with the link up, to cover a surprise removal,
goes from 3.21 s to 0.33 s.

Fixes: 7910bd565d8b ("wifi: mt76: mt792x: quiesce USB paths on disconnect")
Tested-by: Eason Lai <eason.lai at mediatek.com>
Signed-off-by: Devin Wittmayer <lucid_duck at justthetip.ca>
---
 drivers/net/wireless/mediatek/mt76/mt792x_usb.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 850f6b2cfc4a..5e19e64a9a00 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -502,21 +502,26 @@ void mt792xu_disconnect(struct usb_interface *usb_intf)
 		return;
 
 	set_bit(MT76_RESET, &dev->mphy.state);
-	set_bit(MT76_MCU_RESET, &dev->mphy.state);
 	clear_bit(MT76_STATE_RUNNING, &dev->mphy.state);
-	wake_up(&dev->mt76.mcu.wait);
-	skb_queue_purge(&dev->mt76.mcu.res_q);
 
-	cancel_work_sync(&dev->reset_work);
 	cancel_work_sync(&dev->init_work);
 	mt76_worker_disable(&dev->mt76.tx_worker);
 	mt792xu_reset_work_cleanup(dev);
 	if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) {
+		set_bit(MT76_MCU_RESET, &dev->mphy.state);
+		wake_up(&dev->mt76.mcu.wait);
+		skb_queue_purge(&dev->mt76.mcu.res_q);
+		cancel_work_sync(&dev->reset_work);
 		set_bit(MT76_REMOVED, &dev->mphy.state);
 		return;
 	}
 
 	mt76_unregister_device(&dev->mt76);
+
+	set_bit(MT76_MCU_RESET, &dev->mphy.state);
+	wake_up(&dev->mt76.mcu.wait);
+	skb_queue_purge(&dev->mt76.mcu.res_q);
+	cancel_work_sync(&dev->reset_work);
 	mt792xu_cleanup(dev);
 	set_bit(MT76_REMOVED, &dev->mphy.state);
 
-- 
2.55.0




More information about the Linux-mediatek mailing list