Skip to content

gk7205v200: flip dwc3 to host before unbinding xhci (otg) - #114

Merged
widgetii merged 1 commit into
masterfrom
gk7205v200-otg-halt-xhci-before-unbind
Jul 31, 2026
Merged

gk7205v200: flip dwc3 to host before unbinding xhci (otg)#114
widgetii merged 1 commit into
masterfrom
gk7205v200-otg-halt-xhci-before-unbind

Conversation

@widgetii

Copy link
Copy Markdown
Member

Booting the otg profile with /etc/usbmode = device made S72usbmode's usb-mode device log, on every boot:

xhci-hcd xhci-hcd.0.auto: Host not halted after 16000 microseconds.
xhci-hcd xhci-hcd.0.auto: Host controller not halted, aborting reset.

Cause

dwc3_core_init() leaves GCTL.PRTCAPDIR = OTG(3), and this 4.9 dwc3 never moves off OTG on its own — the same fact S72usbmode's header already documents. xhci-hcd binds and registers both buses on top of that anyway, but it is not actually driving the port. Unbinding straight from OTG therefore asks xhci_halt() to halt a host that was never really running, and it times out.

The gadget composed regardless, so this was cosmetic in practice — but it left the host controller un-halted, which is precisely the live-DMA-engine state the unbind exists to avoid.

This is not a probe/timing race. Confirmed by whiting out S72usbmode and rebooting so nothing touched the controller:

dwc3 PRTCAPDIR : OTG     <- never leaves its power-on state
xhci bound     : yes     <- binds on top of it regardless
halt warnings  : 0       <- no unbind attempted, so no warning

Then echo host > mode followed by a manual unbind → still 0 warnings. That isolates the trigger to unbind-while-OTG.

Fix

Flip the controller to host before unbinding, so the already-bound xHCI is genuinely running and the unbind halts cleanly. A runtime switch from host is already in that state, so only boot pays for the extra flip.

Testing

On a gk7205v200 (Xiongmai IPC_GK7205V200_50H20AI_S38) running gk7205v200_otg_generic:

before after
cold boots warning 5/5 0/5
runtime round trips warning 0 0

All 5 boots come up role=device, gadget bound to 10030000.dwc3, /dev/video0 present. Two runtime hostdevice round trips stay clean, still ~0.35s, with no reboot and no majestic restart.

Note for reviewers

An earlier attempt treated this as a probe race and polled for xHCI to settle before unbinding. It changed nothing — the wait succeeded and the halt still failed — which is what refuted the race hypothesis. That approach is deliberately not in this PR.

Relatedly, do not gate such a wait on "every root hub has its hub interface driver bound": on this SoC the USB3 root hub never gets a driver (hub 2-0:1.0: hub can't support USB3.0), so that condition can never be satisfied.

🤖 Generated with Claude Code

Booting the otg profile with /etc/usbmode = device made S72usbmode's
`usb-mode device` log, on every single boot:

    xhci-hcd xhci-hcd.0.auto: Host not halted after 16000 microseconds.
    xhci-hcd xhci-hcd.0.auto: Host controller not halted, aborting reset.

dwc3_core_init() leaves GCTL.PRTCAPDIR = OTG(3) and this 4.9 dwc3 never
moves off OTG on its own. xhci-hcd binds and registers both buses on top
of that anyway, but it is not actually driving the port -- so unbinding
straight from OTG asks xhci_halt() to halt a host that was never really
running, and it times out.

The gadget composed regardless, so this was cosmetic in practice, but it
left the host controller un-halted: exactly the live-DMA-engine state the
unbind is there to avoid.

Flip the controller to host before unbinding, so the already-bound xHCI
is genuinely running and the unbind halts cleanly. A switch from host is
already in that state, so only boot pays for the extra flip.

Measured on gk7205v200 (Xiongmai IPC_GK7205V200_50H20AI_S38): 5/5 cold
boots warned before, 0/5 after. Runtime host<->device round trips stay
clean and still take ~0.35s, with no reboot and no majestic restart.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

gk7205v200: Ensure DWC3 host mode before xHCI unbind on OTG boot

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Force DWC3 into host mode before unbinding xHCI when switching to device.
• Prevent xHCI halt timeouts caused by unbind while PRTCAPDIR remains OTG.
• Ensure host controller is cleanly halted before composing the UVC gadget.
Diagram

graph TD
  A["Init: usb-mode (to_device)"] --> B["debugfs: dwc3 mode file"] --> C["Set mode: host (if not already)"] --> D["sysfs: unbind xhci-hcd"] --> E["Set mode: device"] --> F["configfs: compose UVC gadget"] --> G["UDC: bind gadget"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Fix in kernel DWC3 driver (leave OTG on init)
  • ➕ Addresses root cause globally (PRTCAPDIR staying OTG in 4.9)
  • ➕ Avoids userspace needing OTG-specific sequencing knowledge
  • ➖ Much higher risk and validation burden on an older kernel
  • ➖ Could impact other boards/profiles relying on current behavior
2. Skip unbind when PRTCAPDIR is OTG (or poll for host-ready)
  • ➕ Avoids extra role flip on boot
  • ➕ Keeps script changes localized to decision logic
  • ➖ Leaves xHCI potentially un-halted (live DMA) during role switch
  • ➖ Polling doesn’t help if OTG never transitions without an explicit flip

Recommendation: Keep the PR’s approach: explicitly flipping to host before unbinding is the smallest, most deterministic way to ensure xHCI is actually running and can halt cleanly, preserving the safety goal of the unbind (stopping DMA) without taking on kernel-level risk.

Files changed (1) +14 / -0

Bug fix (1) +14 / -0
usb-modeForce host mode before xHCI unbind when switching to device +14/-0

Force host mode before xHCI unbind when switching to device

• In the 'to_device()' path, ensures the DWC3 debugfs mode is set to 'host' before unbinding the already-bound 'xhci-hcd' driver. This avoids xHCI halt timeouts when boot leaves PRTCAPDIR in OTG and makes the unbind reliably stop the host DMA engine.

devices/gk7205v200_otg_generic/general/overlay/usr/bin/usb-mode

@widgetii
widgetii merged commit 94cce13 into master Jul 31, 2026
@widgetii
widgetii deleted the gk7205v200-otg-halt-xhci-before-unbind branch July 31, 2026 15:21
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

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.

1 participant