Skip to content

usb walker (osinit): two hub-watcher bugs, fixed for xHCI only -- untried on a Pi 3, deliberately #679

Open

Description

@pdfinn

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-kbd 2–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 portstatus failures per pass in hubwatch.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions