| Age | Commit message (Collapse) | Author |
|
Pure cleanup, no behavior change:
- Extract the EP0 control-transfer state into a named pipe0_state_t
typedef instead of an anonymous nested struct, and access it through
a local pipe0_state_t* in the functions that touch it repeatedly.
- Group the pipe0 fields so the two bools sit together and the larger
tusb_control_request_t deferred_setup is last.
- Reword the deferral comments: "coalesced" -> "combined".
Note: separating the edpt0_xfer DATA_IN/DATA_OUT case (dispatch on
state instead of dir_in) was attempted and reverted — it breaks ADI
MUSB enumeration. usbd can arm the opposite-direction status while
pipe0 is still in a DATA state, and only dir-dispatch routes that
correctly; a comment on the combined case records this.
Verified: HIL pass on ek_tm4c123gxl and max32666fthr (13/13 each).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
The actual-STALL path (no deferred SETUP) forced EP0 to IDLE but left
rxrdy_consumed set if the aborted transfer had parked RXRDY via NAK flow
control (e.g. a rejected OUT-data request in DATA_OUT). A subsequent
SETUP IRQ would then hit the parked-gate early return and be ignored,
relying on SentStall/SetupEnd to clear the flag first. Clear it here
so recovery never depends on that ordering.
Addresses Copilot review on #3699.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
dcd_edpt_stall(EP0 OUT) discarded the deferred SETUP and armed
SendStall. A deferred SETUP can only exist once the old transfer's
status stage was seen on the wire, so the request usbd is rejecting
(class callback failing at CONTROL_STAGE_DATA) already succeeded
host-side and the hardware already ACKed the next SETUP - the STALL
would land on that innocent request, which then fails host-side
without any tud callback ever seeing it. Skip the stall and replay
the deferred SETUP; the rejected transfer needs no wire-level stall
since it is already over.
Review follow-up for #3643 (dcd_musb.c l.860 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
The deferral path drains the SETUP but leaves RxPktRdy set, and the
SETUP's IRQ latches after the ISR's clear-on-read intr_tx read - so a
second process_ep0 pass (same ISR, via the intr_tx re-read merge) is
guaranteed and misreads the leftovers: count0==0 fires a spurious
DATA OUT completion, the replay's RXRDYC write turns the second pass
into a phantom csrl==0 DATA IN completion, and a zero-length replay
re-enters the deferral case on a drained FIFO (count0 assert or
garbage saved as a SETUP). The registers cannot expose the staleness:
RxPktRdy and count0 read unchanged until ServicedRxPktRdy is written.
Track it in software: rxrdy_consumed means "RxPktRdy is set in hw but
its packet was already consumed". Set wherever a drained packet's
RXRDY is intentionally left set (OUT/zero-length flow-control parks,
every DATA OUT drain awaiting the next arm, the deferral path);
cleared at every RXRDYC write site (edpt0_xfer arms, dcd_set_address,
STALLED/SETEND recovery, bus reset). The RXRDY block returns early
while parked. Replayed IN requests skip the RXRDYC in
pipe0_start_setup and keep the packet parked until the
edpt0_xfer(DATA IN) arm acks it (before loading the shared FIFO), so
the stale pass sees RXRDY+parked instead of csrl==0. The normal IDLE
path is unchanged - master never re-entered these windows because the
single SETUP edge was always consumed by the pass that parked it; the
deferral is what introduced a pending second pass.
Review follow-up for #3643 (dcd_musb.c l.516 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
STATUS_OUT_PENDING conflated "edpt0_xfer(STATUS OUT) called, awaiting
confirm IRQ" with "confirm IRQ seen, awaiting edpt0_xfer". The
deferral path completed the status and replayed the saved SETUP from
the ISR in both flavors; in the IRQ-first one, usbd's still-
outstanding edpt0_xfer(STATUS OUT) for the old transfer (queued via
status_stage_xact) then landed in the replayed transfer's state and
corrupted it: NULL pipe0.buf armed plus RXRDYC, so the host's next
DATA OUT drained through a NULL pointer. usbd processes EP0
XFER_COMPLETE events unconditionally, so nothing downstream defuses
it.
Split the state into STATUS_OUT_PENDING_XFER / _IRQ. The deferral
completes and replays only in PENDING_XFER (old transfer already
retired); in PENDING_IRQ it only holds the SETUP and the usbd-driven
edpt0_xfer fires the completion and replays. The DATA_IN deferral now
synthesizes PENDING_IRQ (its remain==0 invariant asserted: a SETUP
before DataEnd raises SetupEnd instead), which also makes the old
deferred-promotion in the csrl==0 DATA_IN case unreachable - dropped.
Assert the drain buffer before the DATA OUT FIFO read as a cheap
backstop for this corruption class.
Review follow-up for #3643 (dcd_musb.c l.503 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
MUSBMHDRC 21.1.5 requires the EP0 service routine to check SentStall
and SetupEnd first; the early DATAEND return ran before both, and
SentStall is most likely to fire exactly while DataEnd may still read
back set (auto-STALL after DataEnd, 21.1.7), which would skip the
recovery. The guard also moves below the RXRDY block so a coalesced
DATAEND|RXRDY read cannot swallow a SETUP on cores where the
CPU-set-only DataEnd bit reads back 1; the comment documents the
vendor-dependent read-back.
Review follow-up for #3643 (dcd_musb.c l.445 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
The goto jumped into the csrl==0 completion switch with RXRDY still
set, making its "When CSRL0 is zero" guard comment untrue on that
path. Handle each deferral state in a self-contained switch instead;
the csrl==0 switch is now only reached with csrl==0 and its comment
is truthful again. Behavior unchanged.
Review follow-up for #3643 (dcd_musb.c l.523 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
The pre-existing comment explaining why the OUT branch does not ack
RxPktRdy was dropped when the SETUP handling moved into
pipe0_start_setup(). It is load-bearing: acking before edpt0_xfer()
arms the drain buffer would let the host send data with nowhere to
put it. Restore it with the databook-deviation rationale so the
branches don't get "unified" later.
Review follow-up for #3643 (dcd_musb.c l.116 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
The 8-byte EP0 SETUP drain (count0 assert + two FIFO word reads via a
union) was duplicated verbatim between the IDLE case and the deferral
case; a future fix applied to one copy but not the other would only
show up on the rare deferred-race path. Share one helper. count0 is
now read inside the only remaining user (DATA OUT drain).
Review follow-up for #3643 (dcd_musb.c l.507 finding).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
# Conflicts:
# test/hil/hil_test.py
|
|
# Conflicts:
# README.rst
|
|
split-IN NAK storm (#3677)
Fix stm32f723disco host HIL: UART RX starvation + DWC2 split bulk NAK/XactErr handling (#3677)
stm32f7 BSP — UART RX starvation
- The host console USART shared interrupt priority with the USB OTG ISR, so a long
OTG interrupt could starve RXNE and drop received bytes. Raise the USART RX IRQ
above OTG_FS/OTG_HS in both the bare-metal and FreeRTOS init paths, guarded by
#ifdef UART_ID so boards without a UART console keep the default OTG priority.
dwc2 host — split NAK/XactErr handling
- Slave mode: a persistently-NAKing split bulk/control IN poll re-armed the
start-split immediately, storming the ISR and starving task context. Throttle by
disabling the channel and re-arming on the resulting halt (no frame deferral).
- Buffer-DMA mode: a pure split bulk-OUT NAK was unhandled, leaving the channel
halted and stalling the transfer — the dominant cause of CDC echo truncation.
Handle it by rewinding the buffer pointers and retrying the start-split
(Programming Guide v4.20a 5.1.4.2).
- Buffer-DMA mode: a split bulk-OUT XactErr was retried immediately, exhausting
HCD_XFER_ERROR_MAX before the transient cleared. Throttle via channel_disable +
re-arm to give the hub TT a recovery gap, mirroring slave mode.
- All three are scoped to split transfers (hcsplt.split_en); non-split NAK/XactErr
keep the core-handled / immediate-retry behavior. The OUT XactErr throttle also
excludes periodic split, where channel_disable() is a no-op and would wedge the
channel. The nak_disabled flag is generalized to retry_disabled and honors
xfer->closing so an endpoint close during a throttled retry tears down cleanly.
Verified on stm32f723disco HIL (slave + CFG_TUH_DWC2_DMA_ENABLE): host/cdc_msc_hid,
msc_file_explorer, and device_info all pass on both variants; DMA CDC echo went
from ~15-25% raw failure to 10/10 clean.
|
|
Cast DOEPDMA0 through uintptr_t and use sizeof(tusb_control_request_t)
instead of the magic constant 8, matching project convention. Add a
reference to Programming Guide v4.20a 9.1.2.1 for the DOEPDMAn-8 rule.
Addresses Copilot review comment; no functional change.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
|
|
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
core v3.10a (STM32L476)
DWC2 core rev 3.10a pushes an extra EP0 RX_COMPLETE (RXFLVL PKTSTS 0x3)
that is not a real OUT data completion, in two cases flagged on DOEPINT:
- STPKTRX (Setup Packet Received): between SETUP_RX and SETUP_DONE
- STSPHSRX (Status Phase Received, control write): after the OUT data
stage when the host starts the IN status phase
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
To avoid STATUS IN completion of previous control transfer treated as next DATA IN when IRQ latency is high.
Signed-off-by: HiFiPhile <[email protected]>
|
|
|
|
- GRXSTSP register has internal FIFO, receiving events won't mix up (STATUS OUT & next SETUP)
- Improve efficiency, remove 2nd IRQ overhead
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Fix issue in the stall handling:
- dcd_edpt_stall() for an IN endpoint cleared EP_TX_LEN(0) instead of
EP_TX_LEN(ep_num), clobbering endpoint 0's transmit length register
when stalling any other IN endpoint.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Refactor the driver to follow USBFS style for easier maintenance.
Replace the old packet/response helpers with explicit queue and update paths for IN and OUT transfers.
Introduce transfer validity tracking and per-endpoint data toggle state.
Reset toggle state on init, close-all, endpoint close, clear-stall, and bus reset.
Initialize endpoint controls consistently in NAK + TOG_0 mode.
Tighten EP0 setup/status handling and route transfer IRQ processing through the transfer-flag path.
Stop enabling ISO_ACT in INT_EN and clear unhandled interrupt flags explicitly.
Signed-off-by: HiFiPhile <[email protected]>
|
|
It would casue race condition, SETUP packet is always acked.
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
OUT is still buggy
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
|
|
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
instead of DATA1
hcd_edpt_xfer() previously reset ep->next_pid to 1 only when the control
endpoint direction changed between stages. That handled IN-data control
transfers (e.g. GET_REPORT, GET_DESCRIPTOR) where SETUP is OUT and DATA is
IN, but not OUT-data class requests like SET_REPORT, where SETUP and DATA
are both OUT and the direction-change check is false. ep->next_pid was
left at 0 from hcd_edpt_open(), so the DATA stage went on the wire as
DATA0 when the device expected DATA1. Strict devices (observed: Elgato
Stream Deck) treat this as a protocol violation and disconnect.
Key off "endpoint 0" instead of "direction changed", restoring the
previous behavior. Interrupt/bulk endpoints take the ep->interrupt_num > 0
branch above and never reach this code, so they are unaffected.
|
|
Handle cases where a new SETUP arrives before the previous control transfer fully completes by buffering the SETUP and replaying it after status completion. Split EP0 DATA state into DATA_IN/DATA_OUT and finalize pending status-out completion before processing deferred SETUP.
Signed-off-by: HiFiPhile <[email protected]>
|
|
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
|
|
hcd/dwc2: fix txfifo full check
|
|
Signed-off-by: HiFiPHile <[email protected]>
|
|
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.
|
|
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.
|