diff options
| author | HiFiPHile <[email protected]> | 2026-09-01 03:46:15 +0200 |
|---|---|---|
| committer | HiFiPHile <[email protected]> | 2026-09-02 10:50:03 +0200 |
| commit | c023de98f44a6c0563e8addc2be3864887aa1d41 (patch) | |
| tree | 51ef2b37edd50dcc9156b90e7435e847a9ad8056 | |
| parent | ee92fa7607c8eacac0ea44ffa09ece2d4e67a6f0 (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.c | 5 |
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) { |
