Run it as root, after hot-plugging the enclosure and before any CUDA workload (full workflow: the eGPU setup guide).
What this page answers: what each block of the recovered eGPU startup script does, and how far each rationale is verified — captured on the machine or stated in the recovery notes.
Provenance and evidence labels
The script below was recovered from the host’s file library and reproduced verbatim. For every “why”, this page labels the source:
- (captured) — stated in a comment in the recovered script, or measured on the machine.
- (author-stated, assumed) — the rationale recorded with the recovery notes; no without-test has been run to prove the failure it prevents.
The script
#!/usr/bin/env bash
set -euo pipefail
GPU="${GPU:-0000:63:00.0}"
AUDIO="${AUDIO:-0000:63:00.1}"
POWER_LIMIT="${POWER_LIMIT:-275}"
PCIE_PATH=("0000:00:01.2" "0000:61:00.0" "0000:62:00.0" "$GPU" "$AUDIO")
SHORT_PCIE_SETPCI=("00:01.2" "61:00.0" "62:00.0" "63:00.0")
# Detection and verification
lspci -nn -s "$GPU"
lspci -nn -s "$AUDIO" || true
# Runtime power and link behavior
for dev in "${PCIE_PATH[@]}"; do echo on | sudo tee "/sys/bus/pci/devices/$dev/power/control"; done
for dev in "${SHORT_PCIE_SETPCI[@]}"; do sudo setpci -s "$dev" CAP_EXP+30.w=0020:0020; done
sudo nvidia-smi -pm 1
sudo nvidia-smi -pl "$POWER_LIMIT"
# Optional compute-focused cleanup
if [[ -e "/sys/bus/pci/devices/$AUDIO/driver/unbind" ]]; then
echo "$AUDIO" | sudo tee "/sys/bus/pci/devices/$AUDIO/driver/unbind"
fi
nvidia-smi
lspci -vv -s "$GPU" | grep -Ei "LnkCap|LnkSta|LnkCtl" || true
Block by block
1. Parameters with recovered defaults (not dynamic discovery)
GPU="${GPU:-0000:63:00.0}"
AUDIO="${AUDIO:-0000:63:00.1}"
POWER_LIMIT="${POWER_LIMIT:-275}"The script is parameterized, not auto-discovering: defaults are aibox1’s
recovered addresses and power cap, overridable via environment. The GPU BDF
was found with lspci -nn | grep -Ei "10de|nvidia|vga|3d|display"; the audio
function is its sibling (63:00.1, PCI ID 10de:22e8 on this card). To use
the pattern elsewhere, set GPU/AUDIO to your own values first.
2. Detection gate (fails fast if the eGPU isn’t there)
lspci -nn -s "$GPU"
lspci -nn -s "$AUDIO" || trueUnder set -euo pipefail, a missing GPU aborts the script immediately — so
running it while the enclosure is unplugged is a safe, fast error instead of
a silent mis-configuration. The audio check tolerates absence. (captured)
3. Runtime power control = on, across the whole path
PCIE_PATH=("0000:00:01.2" "0000:61:00.0" "0000:62:00.0" "$GPU" "$AUDIO")
for dev in "${PCIE_PATH[@]}"; do echo on | sudo tee "/sys/bus/pci/devices/$dev/power/control"; doneSets sysfs power/control to on on five devices: the host Thunderbolt
root port (00:01.2), the Sonnet’s upstream “Barlow Ridge” bridge
(61:00.0), the downstream bridge to the slot (62:00.0), the GPU and its
audio function — keeping the entire chain out of PCI runtime autosuspend
while CUDA workloads are prepared. (author-stated, assumed) No without-test
has recorded what exactly degrades when this is skipped.
4. Link Control 2 poke on four devices
SHORT_PCIE_SETPCI=("00:01.2" "61:00.0" "62:00.0" "63:00.0")
for dev in "${SHORT_PCIE_SETPCI[@]}"; do sudo setpci -s "$dev" CAP_EXP+30.w=0020:0020; doneCAP_EXP+30.w is the PCIe Link Control 2 register (offset 0x30); the
write sets bit 5 (value 0x0020, mask 0x0020) on the root port, both
bridges and the GPU itself — not just the downstream bridge. Per the recovery
notes this is the same workaround seen in RTX PRO 6000 eGPU reports: it
disables problematic link-speed auto behavior while still allowing the GPU to
ramp under load. (author-stated, assumed; cross-referenced with PRO 6000
eGPU reports) No without-test has recorded the concrete symptom it prevents.
5. Persistence mode
sudo nvidia-smi -pm 1Keeps the NVIDIA driver initialized between CUDA workloads, reducing reinitialization time and hot-plug sensitivity. (author-stated, assumed)
6. Power cap at 275 W
POWER_LIMIT="${POWER_LIMIT:-275}"
sudo nvidia-smi -pl "$POWER_LIMIT"Deliberately below the RTX PRO 5000 Blackwell’s 300 W default class, to
keep the eGPU enclosure and transient behavior conservative. The stock
default is confirmed by nvidia-smi on a directly attached 48 GB card (the
aibox2 baseline: current/requested 250 W idle, default 300 W). Callers can
pass POWER_LIMIT=... to experiment. (captured: 275 < 300 W stock; the
“conservative for enclosure” rationale is author-stated)
7. Unbind the GPU audio function (conditional)
if [[ -e "/sys/bus/pci/devices/$AUDIO/driver/unbind" ]]; then
echo "$AUDIO" | sudo tee "/sys/bus/pci/devices/$AUDIO/driver/unbind"
fiThe HDMI/DP audio endpoint is not needed for compute and can complicate
suspend/hot-plug behavior, so the script unbinds it — but only when a bound
driver is actually present (the -e guard makes the step conditional rather
than fatal). (author-stated, assumed) The exact failure this prevents has
not been recorded.
8. Verify before workloads
nvidia-smi
lspci -vv -s "$GPU" | grep -Ei "LnkCap|LnkSta|LnkCtl" || trueHealthy state: nvidia-smi lists the card with the cap applied, and the
link lines show the negotiated speed/width. Note the idle expectation on this
chain: LnkCap 32GT/s x16 (Gen5-capable) but LnkSta 2.5GT/s x4 at idle
— idle downshifts are normal; verify under load, not from a cold snapshot.
(captured: the link values)
Notes on running it
- Workflow (recovered): boot with the Sonnet disconnected → log in → hot-plug the enclosure → run this script before any CUDA workload. It is a manual step, not a systemd unit, in everything recovered so far.
- Re-running after re-plug: the script reapplies all state from scratch (power control, link poke, persistence, cap, audio unbind), so running it again after an unplug/re-plug cycle is the expected flow; observed unplug behavior has not been recorded separately.
- The full script is reproduced above from the recovery document
(
notes/aibox-egpu-recovery-guide-updated.docxin the project notes); keep any edits to the on-host copy and this page in sync.
Sources and upstream documentation
- bolt — the Thunderbolt host service the workflow depends on.
- setpci(8) — the register-level command used for the Link Control 2 workaround.
- nvidia-smi documentation — power-limit and persistence-mode fields the script sets.