summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-10 09:15:22 +0700
committerhathach <[email protected]>2026-07-17 17:26:05 +0700
commit7d7444bd8924fce9e60364893265bd2451e115e7 (patch)
treefac077306ab92aecdc8998de0b49c0de8f9ef9b9
parentd155273ce44f6bcf72494cce396188c90279c6a1 (diff)
fix(ci_fs host): release stale sibling BDT on multi-packet completion
hcd_ci_fs shares a single BDT set across all pipes. prepare_packets() speculatively arms the sibling (odd^1) BDT of a multi-packet transfer so it can ping-pong without NAKs. When such a transfer ends early (a short IN packet) or fails, the still-owned sibling was never released, permanently blocking the shared BDT for every other pipe. This deadlocked a 2nd device enumerating behind a hub while another device issued descriptor reads (host/device_info with CDC+MSC): the MSC's control transfers could never acquire the BDT, so it never got Set Address. Release the sibling in process_tokdne()'s completion path, but ONLY for a multi-packet transfer (length > max_packet_size): a single-packet transfer never arms a sibling, so that BDT slot may legitimately belong to another pipe's in-flight transfer and must not be disturbed (doing so unconditionally corrupts concurrent transfers, e.g. the CDC bulk-IN vs MSC enum in host/cdc_msc_hid). Mirrors the equivalent device-side fix in dcd_ci_fs.c; the host needs the multi-packet guard because its BDT set is shared across pipes. Verified on frdm_k64f (HIL): host/device_info now enumerates both CDC+MSC behind a hub, host/cdc_msc_hid still mounts the MSC (no regression). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
-rw-r--r--src/portable/chipidea/ci_fs/hcd_ci_fs.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/src/portable/chipidea/ci_fs/hcd_ci_fs.c b/src/portable/chipidea/ci_fs/hcd_ci_fs.c
index 44a68a8d6..5c5d81521 100644
--- a/src/portable/chipidea/ci_fs/hcd_ci_fs.c
+++ b/src/portable/chipidea/ci_fs/hcd_ci_fs.c
@@ -331,6 +331,16 @@ static void process_tokdne(uint8_t rhport)
}
_hcd.in_progress &= ~TU_BIT(pipenum);
pipe_state_t *pipe = &_hcd.pipe[ep->pipenum];
+ /* A multi-packet transfer speculatively arms the sibling (odd^1) BDT (see
+ * prepare_packets) to ping-pong without NAKs. When it ends early (a short IN packet)
+ * or fails, that sibling is still owned by the SIE; since the host shares a single
+ * BDT set across all pipes, a leftover armed sibling blocks every other pipe forever
+ * (e.g. a 2nd device stuck enumerating behind a hub). Release it - but ONLY for a
+ * multi-packet transfer: a single-packet transfer never armed a sibling, so that
+ * BDT slot may legitimately belong to another pipe's in-flight transfer. */
+ if (pipe->length > pipe->max_packet_size) {
+ ((buffer_descriptor_t *)&_hcd.bda[s ^ USB_STAT_ODD_MASK])->own = 0;
+ }
hcd_event_xfer_complete(pipe->dev_addr,
tu_edpt_addr(CI_REG->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
pipe->length - pipe->remaining,