AXB35-02 (Bosgame BeyondMax): the rear USB-A and Type-C ports#
Status: fix merged, mechanism verified on the board, functional plug test still outstanding. engine#823.
On this board, stock boots leave three of the four xHCI functions in D3cold, so the rear USB-A ports and both Type-C ports never
enumerate; only the controller that carries the front USB-A (and Bluetooth, and the JetKVM) stays in D0. Windows drives every
port, the board's ACPI exposes no UCSI (USBC000/PNP0CA0), and ec_su_axb35 has no USB controls — so a Windows-only port-power
path has always been the standing hypothesis, and the shipped answer is to keep the controllers awake rather than to find that
path.
What ships#
os/v3/puppy/embed/etc/udev/rules.d/91-1bit-xhci-keepawake.rules, gated so it can only ever bind on this machine:
ACTION=="add|bind", SUBSYSTEM=="pci", DRIVER=="xhci_hcd", ATTR{[dmi/id]board_name}=="AXB35-02",
ATTR{vendor}=="0x1022", ATTR{device}=="0x1587|0x1588|0x1589|0x158b", TEST=="power/control", ATTR{power/control}="on"
How to tell whether it applies to the machine in front of you#
tools/xhci_keepawake_check.sh # read-only: DMI match, per-controller state, verdict
tools/xhci_keepawake_check.sh --require-awake # exit 1 unless every controller the rule matches is in D0
Read-only by default. --apply / --revert perform the rule's own single action (power/control = on|auto) and need root; they
exist so the mechanism can be checked without a reboot, and --revert is the documented way back. --sysfs-root checks a tree
other than /sys, which is how tests/xhci_keepawake_check_test.py exercises every verdict on a machine that is not the board.
The verdict is one of four, and only one of them is "go ahead and plug":
| verdict | meaning |
|---|---|
NOT THIS BOARD |
the DMI gate does not match; nothing about #823 can be concluded from this machine |
would bind nothing |
the board matches but no xHCI function carries the rule's device ids (a BIOS that moved them) |
N asleep |
the rule is absent (a non-1bit boot) or not applied; a plug test here would test nothing |
all awake |
a plug into a rear USB-A or a Type-C port is a valid test of #823 |
Measured on the board (2026-11-08, kernel 7.4.0-rc1-1bit)#
== machine: board_name='AXB35-02' bios='1.09' product='BeyondMax Series'
function vendor device driver power control
0000:c5:00.4 0x1022 0x1587 xhci_hcd D3cold auto <- the rule matches this function
0000:c7:00.0 0x1022 0x1588 xhci_hcd D0 auto <- the rule matches this function
0000:c7:00.3 0x1022 0x1589 xhci_hcd D3cold auto <- the rule matches this function
0000:c7:00.4 0x1022 0x158b xhci_hcd D3cold auto <- the rule matches this function
== verdict: 4 controller(s) match the rule; 3 of them are NOT in D0
That is a stock Ubuntu dev boot, i.e. without the rule: the premise of #823 still holds on the current kernel, so the fix is not
addressing something a newer kernel had already fixed. Forcing power/control=on on those three (exactly the rule's action) moves
them D3cold → D0 and their root hubs' ports appear in /sys/bus/usb/devices; --revert puts them back. So the mechanism works
on this kernel; what has not happened is the plug.
The two halves of this issue have different fixes, and the rule covers one#
Measured on the board 2026-11-10, BIOS 1.10, a dev boot with the rule not installed:
0000:c5:00.4 0x1587 xhci_hcd D3cold <- rule matches
0000:c7:00.0 0x1588 xhci_hcd D0 <- rule matches
0000:c7:00.3 0x1589 xhci_hcd D3cold <- rule matches
0000:c7:00.4 0x158b xhci_hcd D3cold <- rule matches
0000:c7:00.5 0x158d thunderbolt D3cold <- the rule does NOT match this
0000:c7:00.6 0x158e thunderbolt D3cold <- the rule does NOT match this
The rear USB-A ports hang off the four xHCI functions the rule matches. The Type-C ports hang off the two USB4 host routers
(0x158d/0x158e), which the rule's device list does not contain, and which are in D3cold with the thunderbolt driver bound and
four live IRQs. So:
| half of engine#823 | what has to be awake | does the shipped rule cover it |
|---|---|---|
| rear USB-A | one of 0x1587/0x1588/0x1589/0x158b |
yes |
| Type-C | 0x158d/0x158e (USB4 host routers) |
no |
A suspended USB4 host router with no partner attached is normal, so this is not evidence that the routers are broken - it is evidence
that one plug test cannot test both halves: a plug into a rear USB-A exercises the rule, a plug into Type-C exercises a path no change
in this repository has touched. Record the router ids with the capture (tools/xhci_boot_capture.sh already records power_state per
controller; the two thunderbolt functions are worth reading the same way) so a "Type-C still dead" result is read as "the router half is
untested" rather than "the keepawake fix failed".
Two things a 2026-11-10 audit added, both read-only (sysfs and source; no root, no plug)#
engine#823's thread carried the audit in full; the two facts that move the next attempt:
ec_su_axb35carries no USB control, in source. The driver binds on this box (refcount 0) and its register map is fans only (0x20/0x21/0x23/0x25modes,0x30/0x31/0x35…tachometers). So "the EC path is not exposed to Linux" is narrower than it reads: the EC driver exists, and nothing in it addresses a Type-C or port-power register. A software fix is therefore not a matter of loading the right module, and a search for an EC-side switcher should start from0x38upwards, where nothing is known.- One silent controller had a stale resume in that boot:
0000:c5:00.4readruntime_status=resumingwithpower_state=D3coldwhile the other three xHCI functions wereactive/D0. A controller whose resume never completed cannot report a connect on its ports, so when a plug test is next run, readruntime_statusas well aspower_state— aresumingthat persists is a different fault from an autosuspended controller, and the keep-awake write may be landing during a transition that never settles.
Also worth knowing for the same next attempt: the three silent controllers have taken exactly 0 interrupts since boot while the awake one has
taken 155,139, and both USB4 host routers are up (gen=4, authorized=1, ~1.6k interrupts each) with no trained downstream link — so the
USB4 side is alive at PCI level and the missing thing is below it.
What is still owed#
One device into a rear USB-A or a Type-C port on a 1bit-OS boot, checked with --require-awake first. If a port is then still
dead the next diagnostic is the one no one has run: compare _DSM on the xHCI/USB4 ACPI nodes against what Windows sends. Until
that plug, the honest row is "fix merged and its mechanism verified on the board; functional confirmation pending" — which is what
the release notes should say rather than leaving users to discover it.
What a capture on BIOS 1.10 shows (measured 2026-11-08, after the owner's reflash)#
The owner's 1.10 (11/04/2026) does not change the software-side picture, and one thing about it is worth recording because it settles a hypothesis in engine#823:
bios-version: 1.10
bios-release-date: 11/04/2026
baseboard-product-name: AXB35-02
0000:c5:00.4 control=auto power_state=D3cold runtime_status=suspended
0000:c7:00.0 control=auto power_state=D0 runtime_status=active
0000:c7:00.3 control=auto power_state=D3cold runtime_status=suspended
0000:c7:00.4 control=auto power_state=D3cold runtime_status=suspended
Three of four controllers still autosuspend to D3cold on 1.10 - the same shape engine#823 reported on 1.09. What is new is that the state is software-controllable, which the issue's hypothesis doubted:
$ for d in c5:00.4 c7:00.3 c7:00.4; do echo on > /sys/bus/pci/devices/0000:$d/power/control; done
c5:00.4 D3cold -> D0 c7:00.3 D3cold -> D0 c7:00.4 D3cold -> D0
$ for d in c5:00.4 c7:00.3 c7:00.4; do echo auto > /sys/bus/pci/devices/0000:$d/power/control; done
all three back to D3cold (so the transition is reversible in both directions)
So the controller power gating is not behind a Windows-only driver or an EC/PD path that Linux cannot
reach: writing the same value the image's 91-1bit-xhci-keepawake.rules writes moves the controllers to
D0. What that does not prove is that a device plugged into a woken controller enumerates - that is the
part only a plug can answer, and it is why the capture below reports per-port connect state rather than
controller power alone.
tools/xhci_boot_capture.sh - one bundle from a boot, for the owner's next stick run#
tools/xhci_boot_capture.sh [outdir] # root; writes /data/xhci-capture-<stamp> when /data is writable
It records the firmware next to the claim it supports (BIOS version/date, board), then per controller
power/control, power_state and runtime_status, then per port connect or not from lsusb -v on
each root hub - the distinction that matters, because "nothing is plugged in" and "plugged in and not
enumerated" are indistinguishable in every other view. It also keeps the udev rule's presence, the
interrupt counts, lspci -vv, the full and filtered dmesg, and the repo's own
xhci_keepawake_check.sh verdict when the stick carries it, then prints a one-screen VERDICT.txt.
Deliberate limits: it needs root (per-port status and PCI config space), it does not assume
/sys/kernel/debug/usb (this kernel does not expose xhci/*/ports/*/portsc), and it lists which of
dmidecode/lsusb/lspci/dmesg/tar the stick actually had - an empty section then means "no tool"
rather than "no problem". When it escalates through sudo it hands the bundle back to the invoking user,
because a capture that needs sudo to read is a capture that does not get sent.