[PATCH v2] wifi: mt76: usb: re-enable the rx worker when resuming fails
YuanZhe Liu
25031212351 at stu.xidian.edu.cn
Sat Oct 31 09:51:03 PDT 2026
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 at vger.kernel.org
Co-developed-by: Bin Yu <byu at xidian.edu.cn>
Signed-off-by: Bin Yu <byu at xidian.edu.cn>
Co-developed-by: Cheng Wen <wencheng at xidian.edu.cn>
Signed-off-by: Cheng Wen <wencheng at xidian.edu.cn>
Signed-off-by: YuanZhe Liu <25031212351 at 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
More information about the Linux-mediatek
mailing list