summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiFiPHile <[email protected]>2026-09-01 03:46:15 +0200
committerHiFiPHile <[email protected]>2026-09-02 10:50:03 +0200
commitc023de98f44a6c0563e8addc2be3864887aa1d41 (patch)
tree51ef2b37edd50dcc9156b90e7435e847a9ad8056
parentee92fa7607c8eacac0ea44ffa09ece2d4e67a6f0 (diff)
fix(dwc2): preserve simultaneous slave channel halt
Slave-mode channel handlers process one interrupt cause per pass, but the dispatcher acknowledged every HCINT bit before invoking them. When ChHltd arrived together with another cause, the handler consumed the other cause and the halt was lost. A subsequent disable could then leave CHENA|CHDIS asserted with HCINT and HAINT clear, so the submitted periodic transfer never completed. When a slave channel reports ChHltd with another cause, acknowledge only the non-halt causes and leave ChHltd pending for the next channel-IRQ pass. DMA handlers retain their existing combined-cause behavior. The uninstrumented negative capture reproduced the lost terminal state with HCCHAR=0xe044881c, HCTSIZ=0x0008001c, HCINT=0, and XFER_RESULT_INVALID.
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index 45add6c7f..9f6fc1469 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -1389,7 +1389,10 @@ static void handle_channel_irq(uint8_t rhport, bool in_isr) {
dwc2_channel_char_t hcchar = {.value = channel->hcchar};
const uint32_t hcint = channel->hcint;
- channel->hcint = hcint; // clear interrupt
+ // Slave handlers process one cause per pass. If ChHltd arrived with
+ // another cause, leave it pending so the next pass retires the halt.
+ const uint32_t hcint_clear = (!is_dma && (hcint & ~HCINT_HALTED)) ? (hcint & ~HCINT_HALTED) : hcint;
+ channel->hcint = hcint_clear;
bool is_done = false;
if (is_dma) {