dwc2: preserve EP0 status completion before SETUP#3634
Draft
Alex-Schaefer wants to merge 2 commits into
Draft
Conversation
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.
Contributor
There was a problem hiding this comment.
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_completeinterrupt case on EP0 OUT with zero total length. - Enqueue an EP0 OUT zero-length
xfer_completeevent 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Observed Problem
xfer_completeandsetup_phase_donetogether.DNLOADSETUP arrived while DFU was still inDFU_DNLOAD_SYNC, causingLIBUSB_ERROR_PIPE.Implemented Fix
dcd_event_xfer_complete()beforedcd_event_setup_received()when both are co-reported.ep0_out_zlp_armedlatch so the synthetic completion only fires if EP0 OUT ZLP was actually armed.Remaining Upstream-Polish Question
dcd_edpt_xfer_fifo()does not updateep0_out_zlp_armed.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
RM0456for STM32U5, section73 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.