Repository navigation
Description
Found while hot-plug testing the xHCI driver on QEMU's virt machine (PR to follow). Both are in os/init/osinit.b's hub walker, which the Pi 3's kernel shares, and both are as true of a Pi 3 in principle. Neither fix is applied on a machine without an xHCI controller, because the Pi 3 is in production on the behaviour it has and there is no evidence from a board. This issue is so that the decision to try them there is made on purpose, by someone with the board.
1. A device plugged in while a hub is being walked at boot is never enumerated
hubwalk looks at each port once, in order, then spawns hubwatch, whose first act is a fresh look at every port to initialise was[]. A device that appears after the walk has passed its port but before that fresh look is recorded as "present, as before" — not a change — and is never enumerated, however long it stays plugged in.
- Reproduced under QEMU (
virt+qemu-xhci, cold hub,device_add usb-kbd2–4 s after the shell starts): 0 of 3 claimed before, 3 of 3 after. - Fix: the watcher starts from what the walk saw (
seen[]), not a fresh look. - Risk on a Pi 3: low — the difference is only the window between walk and watcher — but nonzero, and unmeasured.
2. A pulled hub's watcher never exits
When a hub is unplugged, whoever watches its parent port detaches it; from then on every portstatus on it fails, and hubwatch does continue for ever. It holds the hub's ep0 open (so the hub's Udev — and on xHCI its slot — is never released), and the devices that were plugged into the hub are never detached, so their drivers are never told.
- Reproduced under QEMU: pull a hub with a keyboard in it; the keyboard's endpoints stay
busy, slots leak. - Fix: after three consecutive passes in which every port read fails, detach the hub's children and exit.
- Risk on a Pi 3: real. This detaches devices on the strength of failed status reads. On a 3B+ the hub it would be judging is the LAN7515 — the one the Ethernet is on. If a live hub's status reads can fail for ~3 s (bus load? a NAK storm? the DWC's channel scheduling?), this turns a harmless hiccup into losing the network. Nobody has measured how often those reads fail on the board. The soak's logs could answer that without changing anything: count
portstatusfailures per pass inhubwatch.
How it is gated
roothubs() sets havexhci if any controller in #u/usb/ctl says xhci. With it clear, hubwatch takes the fresh look and never gives up — the code path a Pi 3 has always run. Checked: bcm2837 harness 260/0/0 before and after.
To try on a board
Set havexhci = 1 unconditionally in a test kernel, run tests/acceptance USB batteries and a soak, and look for has gone; so has what was on it in the log when nothing was unplugged.
Refs: INFR-404
Activity
xHCI hot-plug: four leaks and a controller reset, found by pulling a …
osinit: a USB device that fell off the bus and came back is set up again
osinit: a USB device that fell off the bus and came back is set up again