From 13971b58df52bc29de97632295fcae43aeade5c9 Mon Sep 17 00:00:00 2001 From: HiFiPHile Date: Thu, 27 Aug 2026 14:49:47 +0200 Subject: fix(dwc2): drain host RX status before channel IRQ Popping an IN transfer-completion entry from GRXSTSP asserts HCINT.XferCompl. Drain the receive FIFO first, then read the live masked global status so the newly asserted channel completion is handled without waiting for another interrupt. --- src/portable/synopsys/dwc2/hcd_dwc2.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 05efacbee..ca16eec70 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -1574,21 +1574,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { handle_hprt_irq(rhport, in_isr); } - if (gintsts & GINTSTS_HCINT) { - // Host Channel interrupt: source is cleared in HCINT register - // must be handled after TX FIFO empty - handle_channel_irq(rhport, in_isr); - } - - if (gintsts & GINTSTS_DISCINT) { - // Device disconnected - dwc2->gintsts = GINTSTS_DISCINT; - - if (0 == (dwc2->hprt & HPRT_CONN_STATUS)) { - hcd_event_device_remove(rhport, in_isr); - } - } - #if CFG_TUH_DWC2_SLAVE_ENABLE // RxFIFO non-empty interrupt handling if (gintsts & GINTSTS_RXFLVL) { @@ -1620,6 +1605,21 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { } } #endif + + // Draining the RxFIFO completion status can assert HCINT.XferCompl. Read + // the live status here so the completion is handled in this ISR invocation. + if ((dwc2->gintsts & dwc2->gintmsk) & GINTSTS_HCINT) { + handle_channel_irq(rhport, in_isr); + } + + if (gintsts & GINTSTS_DISCINT) { + // Device disconnected + dwc2->gintsts = GINTSTS_DISCINT; + + if (0 == (dwc2->hprt & HPRT_CONN_STATUS)) { + hcd_event_device_remove(rhport, in_isr); + } + } } #endif -- cgit v1.3.1