<feed xmlns='http://www.w3.org/2005/Atom'>
<title>tinyusb.git/src/portable/chipidea, branch hil-report</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.</subtitle>
<id>http://cgit.235523.xyz/tinyusb.git/atom/src/portable/chipidea?h=hil-report</id>
<link rel='self' href='http://cgit.235523.xyz/tinyusb.git/atom/src/portable/chipidea?h=hil-report'/>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/'/>
<updated>2026-08-19T10:40:48Z</updated>
<entry>
<title>dcd(ci_hs): stage the device address before priming the status stage</title>
<updated>2026-08-19T10:40:48Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-19T05:29:45Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=75a01f561438c16677b48f3a59fda80a2b096ad8'/>
<id>urn:sha1:75a01f561438c16677b48f3a59fda80a2b096ad8</id>
<content type='text'>
IMXRT1060RM 42.7.23 and UM10503 Table 478 both ask for the DEVICEADDR write
with USBADRA=1 to happen after the SET_ADDRESS data phase and before the
prime of the status stage, so the controller loads USBADR from its holding
register when the status stage is ACKed. The driver did it the other way
round, leaving a window between the ENDPTPRIME store and the DEVICEADDR
store: an IN answered inside that window ACKs with USBADRA still 0, so the
holding register is never consulted and the device keeps answering on
address 0 while the host has moved to the new one. Instruction timing alone
cannot open that window, but dcd_set_address() runs in task context, so any
interrupt landing between the two stores stretches it past a microframe.

Hardware discards a staged address on a SETUP or OUT to endpoint 0 and
zeroes USBADR on a bus reset, which covers a superseded SET_ADDRESS. What
it cannot cover is a SETUP latched before this write and still unconsumed
after the full CI_HS_BUSY_SPIN spin, which refuses the prime: condition 2
already fired for that earlier SETUP, so the stage would survive and load
USBADR on the next EP0 IN ACK of an unrelated transfer. USB 2.0 9.4.6 is
explicit that "the USB device does not change its device address until
after the Status stage of this request is completed successfully", so the
refused-prime path restores the previous USBADR rather than leaving a stage
armed. Restoring the previous value rather than writing zero keeps 9.4.6's
Address-state row correct, where a device already at a non-zero address
must stay there; on Linux that write is always a no-op, since hub_set_address
only issues SET_ADDRESS from USB_STATE_DEFAULT.

Cast dev_addr before the shift: it is uint8_t, promoted to int, so an
address of 64 or more reached the sign bit of a 32-bit int.

No errata applies: IMXRT1060CE_A Rev 1.3 lists only ERR050101 and ERR010661
for USB, IMXRT1060CE_B Rev 1.1 only ERR010661.

Validated on mimxrt1064_evk: 18/19 device+host tests, 6x usbtest 30/30, and
a 100-iteration forced re-enumeration A/B that is clean on both this change
and its parent (0/100 each). All 19 ci_hs boards build; unit tests 63/63;
PVS drops one diagnostic (the sign-bit shift) and adds none.
</content>
</entry>
<entry>
<title>dcd(ci_hs): rework bus reset handling and bound the register waits</title>
<updated>2026-08-18T15:07:49Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-16T18:01:54Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=2fda873fa5f6ef0c893f4f138b5c54e49c24e0a9'/>
<id>urn:sha1:2fda873fa5f6ef0c893f4f138b5c54e49c24e0a9</id>
<content type='text'>
A bus reset was detected only from the port change that ends it, which is late:
the manual asks the DCD to clear the endpoint semaphores, cancel every prime and
free the dTDs while the reset is still being driven. Enable the reset interrupt
and do all of that there, in the manual's order (IMXRT1060RM 42.5.6.2.1,
p.2394), including the two steps that were missing - confirming the port is
still being reset, and freeing the dTDs. A failed check means the cleanup
arrived late and the controller may be in an undefined state, so the manual's
remedy is carried out rather than noted: a controller reset, followed by the
full re-initialisation it then requires, since the reset detaches the device.

The port change that ends the reset is left with what the manual gives it, the
negotiated speed, which the new BUS_RESET_END event carries. A port change is
classified by the interrupt that preceded it: a suspend raises no port change of
its own, the resume that ends it does.

Every unbounded register spin is now bounded. They waited on bits the hardware
clears within a frame, but each could hang an interrupt handler outright on a
controller that had stopped responding. The endpoint flush follows all three
steps of IMXRT1060RM 42.5.6.6.5 (p.2413), repeating a flush the controller
refuses while a packet is in progress - previously reported as success.

EP0 setup handling is hardened alongside: the payload is copied out of the queue
head through the volatile qualifier before ENDPTSETUPSTAT is cleared, since that
clear releases the setup lockout and a back-to-back setup can overwrite the
buffer immediately after, and C orders volatile accesses only against each
other, so a plain memcpy may legally be sunk past the store.

There is deliberately no unplug detection. IMXRT1060RM 42.7.31 (p.2470) states a
zero Current Connect Status means the device "did not attach successfully or was
forcibly disconnected by the software writing a zero to the Run bit ... It does
not state the device being disconnected or suspended", so a cable pull raises no
port change at all; VBUS via OTGSC is the manual's disconnect indicator and is
board dependent.

Verified on mimxrt1064_evk: 30 forced bus resets each re-enumerating at high
speed with no descriptor errors, plus repeated full usbtest batteries at 30/30
across the series.
</content>
</entry>
<entry>
<title>portable/chipidea: name SBUSCFG in ci_hs_regs_t, unify AHB burst hook</title>
<updated>2026-08-17T05:12:08Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-08-13T07:35:01Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=8ccd0d549798c66d484e5a4b4c57edf49e8bb097'/>
<id>urn:sha1:8ccd0d549798c66d484e5a4b4c57edf49e8bb097</id>
<content type='text'>
Replace the duplicated per-MCU dispatch in dcd_init/hcd_init and the two
helper flavors (USB_Type access on iMX RT, raw offset 0x90 on LPC18/43)
with one SBUSCFG register field plus a per-header CI_HS_SET_AHB_BURST()
hook, compiled only where defined. The LPC USB0-only policy is now
visible at the macro definition.
</content>
</entry>
<entry>
<title>portable/chipidea: configure i.MX RT AHB bursts</title>
<updated>2026-07-27T12:58:13Z</updated>
<author>
<name>Zixun LI</name>
<email>admin@hifiphile.com</email>
</author>
<published>2026-07-27T12:58:13Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=f0a8a1483bd4e89ab3adf40d8c61777a5ddadc7f'/>
<id>urn:sha1:f0a8a1483bd4e89ab3adf40d8c61777a5ddadc7f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>portable/chipidea: configure LPC USB0 AHB bursts</title>
<updated>2026-07-27T12:39:02Z</updated>
<author>
<name>Zixun LI</name>
<email>admin@hifiphile.com</email>
</author>
<published>2026-07-27T12:39:02Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=a2f4786865e85f9cfe7f58c86fbb9355bbd2d701'/>
<id>urn:sha1:a2f4786865e85f9cfe7f58c86fbb9355bbd2d701</id>
<content type='text'>
</content>
</entry>
<entry>
<title>fix(ci_fs): address code-review findings in host/device drivers</title>
<updated>2026-07-17T17:18:27Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-17T17:18:27Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=4782770e7f5f4a726f9739d940c110196807f15c'/>
<id>urn:sha1:4782770e7f5f4a726f9739d940c110196807f15c</id>
<content type='text'>
Host (hcd_ci_fs.c):
- Release the speculatively-armed sibling BDT on the NAK path (IN only) as
  well as on completion, so a NAKed multi-packet IN no longer leaks a BDT
  that stays own=1 and blocks every same-direction pipe. Both paths now go
  through a single release_sibling_bd() helper (was a copy-pasted disarm).
- Clear the ENTIRE shared BDT (both directions) on bus reset; clearing only
  the IN half left a stale OUT/SETUP descriptor after a disconnect mid-OUT,
  blocking the first control transfer on re-enumeration.
- Size bda[] to span the whole BDT (2*2*4) so STAT-indexed access is within
  the declared array bounds (was out-of-declared-bounds, benign via union).

Shared (ci_fs_type.h):
- Hoist buffer_descriptor_t and the TOK_PID enum out of the device and host
  drivers into the shared header so the identical definitions cannot drift.

Board (kinetis_k):
- Drop a redundant local in board_get_unique_id.

Build-verified: host + kinetis k/kl/k32l + MCX. HIL: frdm_k64f host 2/2
(cdc_msc_hid + device_info); frdm_kl25z device core suite green with the
relocated definitions.
</content>
</entry>
<entry>
<title>fix(ci_fs host): release stale sibling BDT on multi-packet completion</title>
<updated>2026-07-17T10:26:05Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-10T02:15:22Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=7d7444bd8924fce9e60364893265bd2451e115e7'/>
<id>urn:sha1:7d7444bd8924fce9e60364893265bd2451e115e7</id>
<content type='text'>
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 &gt; 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) &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
</content>
</entry>
<entry>
<title>dcd_ci_fs: disarm sibling BDT on short-packet OUT completion</title>
<updated>2026-07-17T10:26:03Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-09T17:17:52Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=439a60a87f4039beba5a1d202b7ff6f9d93745dc'/>
<id>urn:sha1:439a60a87f4039beba5a1d202b7ff6f9d93745dc</id>
<content type='text'>
A multi-packet OUT transfer speculatively arms both even/odd BDTs to avoid
NAK. When the host ends the transfer early with a short packet, the sibling
BDT was left armed (own=1), desyncing the even/odd ping-pong so the next OUT
packet landed at buffer+max_packet_size instead of buffer and the stack read
stale data. Disarm the sibling on completion.

Fixes device/mtp on Kinetis (GetDeviceInfo command was received into the wrong
buffer half -&gt; hang). Pre-existing (MSC only arms single-packet command
receives so it never hit the double-buffer path). HIL: frdm_kl25z &amp; frdm_k64f
device 13/13.

Co-Authored-By: Claude Opus 4.8 (1M context) &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
</content>
</entry>
<entry>
<title>migrate NXP Kinetis khci to chipidea ci_fs driver (device + host)</title>
<updated>2026-07-17T10:26:02Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-09T17:17:18Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=fa1fee0a5f82b5a78ace26ee1722c1d636c5b32a'/>
<id>urn:sha1:fa1fee0a5f82b5a78ace26ee1722c1d636c5b32a</id>
<content type='text'>
Complete the khci -&gt; chipidea ci_fs migration that was started for device
(commit d70403f1f "host is not yet"):

- device: switch kinetis_k/kl/k32l (Makefiles + k32l CMake) to dcd_ci_fs.c
- host: add hcd_ci_fs.c (port of hcd_khci.c onto ci_fs_regs_t) and switch all
  Kinetis families to it; remove src/portable/nxp/khci entirely
- enable host examples (device_info, cdc_msc_hid) for mcu:KINETIS_K
- README: merge the KL and K32L2 rows into a single "KL, K32L" ci_fs row

hcd_ci_fs.c also fixes two pre-existing host bugs found via HIL on frdm_k64f
(present in the old hcd_khci.c too):
- data toggle was flipped on a NAK in suspend_transfer; a NAK transfers no
  data so the toggle must be preserved, else the retried bulk packet is
  silently discarded by the device (MSC CBW/CSW hang). See comment in file.
- prepare_packets asserted and dropped a transfer when the single shared BDT
  was still owned by an in-flight transfer under concurrent activity; now it
  returns busy and resume_transfer defers/retries on the next SOF.

HIL verified on frdm_k64f: device 13/13, host cdc_msc_hid (CDC mount + echo +
MSC mount, through a hub).

Co-Authored-By: Claude Opus 4.8 (1M context) &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01ExGPLP5eU43LR7o6yYLpNi
</content>
</entry>
<entry>
<title>dcd(ci_hs): stale overlay fix; run usbtest on lpcxpresso43s67</title>
<updated>2026-07-14T08:23:07Z</updated>
<author>
<name>hathach</name>
<email>thach@tinyusb.org</email>
</author>
<published>2026-07-14T08:23:07Z</published>
<link rel='alternate' type='text/html' href='http://cgit.235523.xyz/tinyusb.git/commit/?id=ca402a0e781eb4d5580030f713377552b72eddda'/>
<id>urn:sha1:ca402a0e781eb4d5580030f713377552b72eddda</id>
<content type='text'>
- dcd_edpt_stall flushes the primed buffer (ENDPTFLUSH), but the aborted
  transfer's dQH overlay can be left ACTIVE with mid-transfer state; the
  next prime after clear-halt then resumes the stale overlay instead of
  loading the fresh qtd, so post-halt IN reads return mid-buffer data
  (usbtest case 13 'buf[32] = 56 (not 0)', with case 18 failing
  downstream of the same corruption in the full battery). qhd_start_xfer
  now clears overlay.active alongside overlay.halted before linking the
  new qtd.
- test/hil(hfp): drop lpcxpresso43s67's device/usbtest skip - the
  historical first-case wedge no longer reproduces on this branch, and
  with the overlay fix the board runs 30/30 on its Fresco xHCI host
  (previously 28/30 with deterministic case 13/18 failures).
  mimxrt1064_evk (imxrt dcache path) 30/30 regression-clean.
- docs(hil skill): document the external hifiphile rig - pool
  test/hil/hfp.json, SSH-reachable from htpc/ci with no outbound SSH,
  exercised by the CI hil-tinyusb (hfp.json) job; never run HIL against
  it during development unless the user explicitly asks.

Co-Authored-By: Claude Fable 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_017TQZrFfU3K4Y198aLsUpBC
</content>
</entry>
</feed>
