mt76u_resume_rx() returns as soon as submitting the RX buffers fails, so the mt76_worker_enable() at the end of the function is never reached and the RX worker stays parked. The mt792x USB reset path relies on mt76u_stop_rx() and mt76u_resume_rx() being a balanced park/unpark pair: if firmware download fails, mt7925_init_hardware() retries up to ten times and calls mt792xu_init_reset() again, which parks the already parked RX worker. kthread_park() then hits its WARN_ON_ONCE() and returns -EBUSY: WARNING: kernel/kthread.c:710 at kthread_park+0x17b/0x1b0 Workqueue: events mt7925_init_work Call Trace: mt76_worker_disable drivers/net/wireless/mediatek/mt76/util.h:93 [inline] mt76u_stop_rx+0x5b/0x2f0 drivers/net/wireless/mediatek/mt76/usb.c:757 mt792xu_init_reset+0x52/0x80 drivers/net/wireless/mediatek/mt76/mt792x_usb.c:477 mt7925_init_hardware drivers/net/wireless/mediatek/mt76/mt7925/init.c:152 [inline] mt7925_init_work+0x49b/0x7e0 drivers/net/wireless/mediatek/mt76/mt7925/init.c:196 The early return is unbalanced with the URBs as well: mt76u_stop_rx() poisons every URB of every RX queue, while mt76u_resume_rx() would only unpoison the queues it reached. If MT_RXQ_MAIN fails to submit, the URBs of MT_RXQ_MCU keep urb->reject raised, the next stop/resume pair moves it further away from zero instead of back to zero, and every later submission on that queue fails with -EPERM. A stalled RX endpoint makes usb_submit_urb() return -EPIPE, which is the failure that leaves the MCU unresponsive and triggers the retry loop. Unpoison and resubmit every RX queue, keep the first error, and always re-enable the worker so that both pairs stay balanced. Fixes: 0d2afe09fad5 ("mt76: mt7921: add mt7921u driver") Cc: stable@vger.kernel.org Co-developed-by: Bin Yu Signed-off-by: Bin Yu Co-developed-by: Cheng Wen Signed-off-by: Cheng Wen Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn> --- v2: - Unpoison and resubmit every RX queue instead of breaking out of the loop at the first failure, so that a failing MT_RXQ_MAIN no longer leaves the MT_RXQ_MCU URBs poisoned across reset retries, and the queue indices are reset for every queue before the worker runs again. Yes on both counts, thank you for the review. mt76u_stop_rx() poisons the URBs of every RX queue unconditionally, so mt76u_resume_rx() has to unpoison that same set of URBs for urb->reject to return to zero. The previous version only fixed the park/unpark pair: MT_RXQ_MAIN is queue 0 and MT_RXQ_MCU is queue 1, so a submission failure on the main queue left all MCU URBs poisoned. The next mt792xu_init_reset() then raised reject to 2 and the following resume lowered it back to 1, and usb_hcd_link_urb_to_ep() keeps rejecting every submission on that queue with -EPERM because reject is non-zero. The skipped queue also kept its old q->head, q->tail and q->queued, since mt76u_submit_rx_buffers() is what clears them, while the worker had already been re-enabled. v2 walks all RX queues, unpoisons and resubmits each of them, keeps the first error and still always re-enables the worker. The error is still returned to the caller, so the firmware retry loop behaves as before. --- drivers/net/wireless/mediatek/mt76/usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index a9af3aa6b80a..252a18dc3cb2 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -775,23 +775,23 @@ EXPORT_SYMBOL_GPL(mt76u_stop_rx); int mt76u_resume_rx(struct mt76_dev *dev) { - int i; + int i, err = 0; mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; - int err, j; + int ret, j; for (j = 0; j < q->ndesc; j++) usb_unpoison_urb(q->entry[j].urb); - err = mt76u_submit_rx_buffers(dev, i); - if (err < 0) - return err; + ret = mt76u_submit_rx_buffers(dev, i); + if (ret < 0 && !err) + err = ret; } mt76_worker_enable(&dev->usb.rx_worker); - return 0; + return err; } EXPORT_SYMBOL_GPL(mt76u_resume_rx); -- 2.34.1