How to fence a PCIe operation with the deadman

This guide shows you how to run a sequence that touches the PCIe bus without risking a host you cannot get back. It applies to anything that removes an endpoint, resets a bridge, rescans, holds runtime power management, or reprograms the fabric, not only to the obviously destructive steps.

The rule is short: arm a cancellable auto-reboot guard before any PCIe-touching sequence, and disarm it only after the health ladder passes.

Why it is not optional

A bus operation that hangs the host does not fail; it stops answering. The machine is up, the session is gone, and the only fix is a power cycle. A guard armed beforehand turns that into a wait: if nothing disarms it, the host reboots itself and comes back.

This has happened often enough that none of these sequences should be run by hand.

Use a composed plan, not a script

The dau-build hardware plans arm the guard around the destructive span, take the host lock, read the board’s access facts from its platform definition, and support a dry run. A bare script does none of that.

The plans this package’s smoke command is injected into cover the two common cases:

dau-cfg task=tasks/hardware/hardware-plan plan=plans/dpv1-validate-bitstream \
  platform=platforms/<vendor>/<board> \
  model.work_root=/srv/vivado-shell model.bitstream=artifacts/candidate.bit \
  plan.dau_core_root=/srv/checkouts/dau-core \
  plan.dau_driver_root=/srv/checkouts/dau-driver

Without model.execute=true this prints the step ladder and touches nothing. Read it before running it.

Endpoint removal, secondary-bus reset, rescan, and runtime-PM holds are steps of those plans, not scripts in this repository. Reach for plan=plans/recovery and the programming plans rather than reproducing the steps yourself.

Arm and disarm by hand only when you must

The guard is a dau-utils tool, not part of this package:

sudo python -m dau_utils.deadman arm --timeout <seconds>
sudo python -m dau_utils.deadman status
sudo python -m dau_utils.deadman disarm

dau-driver neither implements nor depends on it. dau_utils is a separate prerequisite on the bench host, and nothing here will tell you it is missing. Pair it with the host’s own hardware watchdog, so that a host hung too far for the timer to fire still recovers.

Choose the timeout from how long the span takes, with margin. Too short reboots a healthy host mid-programming; too long means a long wait after a hang you already know about.

Disarm only after the device answers

The ordering matters more than the arming does. A programmed board is not healthy because programming returned. It is healthy because the device it produced identified itself afterwards.

So the ladder is: arm, do the destructive span, discover the device, read the magic word, read back the identity block, compare it against what was built, and only then disarm.

Verification steps come before the disarm on purpose, so an uncaught exception in a verify step reboots the host. That is the intended behaviour. The alternative is the incident this ordering exists to prevent, where a plan saw an endpoint, disarmed, and reported success while the board kept running the previous design.

Verify the advertisement against the manifest that produced the bitstream:

dau-driver-verify-advertisement --manifest <output_root>/shell-build.artifacts.yaml

Add --require-build-id to fail, rather than warn, on a device whose build id does not match the manifest’s spec hash.

Next