Thanks to visit codestin.com
Credit goes to github.com

Skip to content

dwc2: preserve EP0 status completion before SETUP#3634

Draft
Alex-Schaefer wants to merge 2 commits into
hathach:masterfrom
HKM-Messtechnik:fix/Dwc2Stm32U5
Draft

dwc2: preserve EP0 status completion before SETUP#3634
Alex-Schaefer wants to merge 2 commits into
hathach:masterfrom
HKM-Messtechnik:fix/Dwc2Stm32U5

Conversation

@Alex-Schaefer
Copy link
Copy Markdown

@Alex-Schaefer Alex-Schaefer commented May 9, 2026

Observed Problem

  • DWC2 can report EP0 OUT xfer_complete and setup_phase_done together.
  • TinyUSB previously processed SETUP first and returned, dropping the co-latched EP0 OUT status completion.
  • That lost the previous control-read OUT status ZLP ACK.
  • Observed DFU symptom: next DNLOAD SETUP arrived while DFU was still in DFU_DNLOAD_SYNC, causing LIBUSB_ERROR_PIPE.
  • A/B testing confirmed root cause: unpatched failed, patched passed, re-patched passed.

Implemented Fix

  • Queue EP0 OUT zero-length dcd_event_xfer_complete() before dcd_event_setup_received() when both are co-reported.
  • Added ep0_out_zlp_armed latch so the synthetic completion only fires if EP0 OUT ZLP was actually armed.
  • Latch is cleared on bus reset, synthetic completion, normal EP0 OUT completion, and superseding SETUP.

Remaining Upstream-Polish Question

  • dcd_edpt_xfer_fifo() does not update ep0_out_zlp_armed.
  • This does not affect our DFU/control path because EP0 control transfers go through dcd_edpt_xfer().

Current status

Hardware validated on STM32U5G9J custom PCB with USB CDC, USB DFU device and HS USB host for flash drives. Should be in accordance to ST RM0456 for STM32U5, section 73 USB on-the-go high-speed (OTG_HS).

No further tests/validation currently done.

More tests with STM32U5G9J-DK2 evalboard and reproducable examples are planned, but I don't have time for it now.

On STM32 DWC2, SETUP phase done and EP0 OUT transfer complete can be
reported together. Processing SETUP first can overwrite control state
before the previous zero-length OUT status stage is acknowledged, which
causes DFU DNLOAD/GETSTATUS traffic to lose the status ACK and stall.

Queue the EP0 OUT zero-length transfer completion before queuing the
SETUP event when the endpoint has no pending OUT data and total_len is
zero. This keeps TinyUSB control-transfer ordering intact for the
combined interrupt case.
Copilot AI review requested due to automatic review settings May 9, 2026 07:14
@Alex-Schaefer Alex-Schaefer marked this pull request as draft May 9, 2026 07:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the DWC2 (STM32) device controller driver to preserve TinyUSB control-transfer event ordering when DWC2 reports EP0 OUT transfer completion and SETUP phase done in the same interrupt, avoiding loss of the EP0 OUT status-stage ACK (notably impacting DFU DNLOAD/GETSTATUS sequences).

Changes:

  • Detect the combined setup_phase_done + xfer_complete interrupt case on EP0 OUT with zero total length.
  • Enqueue an EP0 OUT zero-length xfer_complete event before enqueuing the SETUP event (in both slave and DMA paths).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

static void handle_epout_slave(uint8_t rhport, uint8_t epnum, dwc2_doepint_t doepint_bm) {
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
const bool ep0_status_complete_before_setup = (epnum == 0) && doepint_bm.setup_phase_done &&
doepint_bm.xfer_complete &&
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, TUSB_DIR_OUT);
const bool ep0_status_complete_before_setup = (epnum == 0) && doepint_bm.setup_phase_done &&
doepint_bm.xfer_complete &&
Track when an EP0 OUT zero-length transfer is actually armed and require that state before synthesizing a status-stage completion ahead of a co-reported SETUP event.

This preserves the validated status-before-SETUP ordering fix while avoiding stale zero-length state from producing spurious EP0 OUT completions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants