Hardware CI
The Hardware Tests workflow in .github/workflows/hardware-test.yml
selects hardware through the labgrid coordinator. See
Release hardware validation for the completed release qualification and
Runtime JESD overlay validation for the required overlay kernels.
Discovery and test selection
The workflow calls the reusable hw-matrix.yml workflow from
tfcollins/labgrid-plugins with dynamic_mode: true. Coordinator place
metadata supplies the runner routing; .github/supported-boards.yml filters
supported daughter-board tags. The current allowlist contains ad9081,
adrv9371, adrv9009, adrv9009zu11eg, and daq3. An allowlist entry
is not proof that matching hardware is available or validated.
Runs are triggered manually, on pushes to main, nightly at 08:00 UTC,
and for pull requests carrying the hw-test label. The reusable workflow
owns discovery and scheduling. This repository does not define separate
hw-direct and hw-coord jobs or route jobs using a static node manifest.
Each selected leg receives BOARD, CARRIER, LG_ENV, and
LG_COORDINATOR. Its test command selects:
Full-DTB tests matching
test/hw/*${BOARD}*${CARRIER}*_hw.py.Overlay tests matching
test/hw/xsa/test_*${BOARD}*${CARRIER}*_overlay.py.
PetaLinux tests are excluded from this workflow’s selection. An empty selection
fails. After pytest, check_hardware_results.py requires passing JUnit
results without failures or errors; an all-skipped run cannot qualify hardware.
Runner preparation
Register the self-hosted runner and give it the label selected by the place’s
coordinator runner tag. It needs access to the coordinator and exporter,
the board’s boot artifacts, and the appropriate FPGA tools.
.github/scripts/install-adidt-venv.sh installs the checkout with dev
extras into ~/.cache/adidt-ci/adidt-venv. It also installs the AD9371
clock-model requirements and exposes the supported Vivado 2025.1 sdtgen
launcher in that environment. Missing tools or imports fail setup before
hardware acquisition.
.github/scripts/prepare-hardware-env.sh then:
Loads optional board-specific artifact settings from
~/.config/pyadi-dt/hardware/$BOARD-$CARRIER.env. Override the directory withADIDT_HARDWARE_CONFIG_DIR.Sanitizes
PATHand verifies GNUas, labgrid, pytest, andsdtgen.Prepares a private labgrid environment from the live place tags. TFTP deployment disables SD autoboot; ZynqMP deployment registers the pinned production JTAG strategy and accepts either Ethernet port.
Keep operational labgrid environments private. The workflow passes
PYADI_BUILD_TOKEN for private dependency access. Optional Prism upload is
controlled by PRISM_UPLOAD_ENABLED and uses the explicitly passed
PRISM_EMAIL and PRISM_PASSWORD secrets. These values are not test
artifacts.
Exporter service
Exporters publish the serial, power, JTAG, and other resources used by the
coordinator. The repository’s installation convention uses one
labgrid-exporter.service per host and /etc/labgrid/exporter.yaml.
See Labgrid exporter systemd service for installation and service operation.
Generated-DTB deployment
A successful stock-image boot does not qualify a generated tree. Tests stamp the generated DTB and verify its unique marker in Linux. TFTP tests require a strategy that consumes the staged files; recovery strategies that boot only the existing SD tree are unsuitable for those tests.
The ZU11EG test uses production JTAG bootstrap followed by U-Boot’s serial S-record loader. It verifies the complete RAM payload CRC, the marker in both U-Boot and Linux, four online CPUs, both PHYs, JESD DATA, and RX DMA. See Release hardware validation for prerequisites and a local test command.
For runtime overlays, use the matching modular kernels, module bundles, and
base trees described in Runtime JESD overlay validation. Installing
pyadi-dt does not update a board’s kernel. Overlay tests verify live-tree
application and removal as well as JESD and DMA on each reload.
Local runs and evidence
Use the same checkout and prepared environment as CI. From a Bash shell at the
repository root, set LG_ENV to an existing private configuration for the
selected place, then run:
export VENV_DIR="$HOME/.cache/adidt-ci/adidt-venv"
export LG_COORDINATOR=10.0.0.41:20408
export BOARD=adrv9009 CARRIER=zc706
source .github/scripts/prepare-hardware-env.sh
"$VENV_DIR/bin/labgrid-client" -p nemo acquire
trap '"$VENV_DIR/bin/labgrid-client" -p nemo release' EXIT
"$VENV_DIR/bin/python" -m pytest -p no:genalyzer -v -s \
test/hw/xsa/test_adrv9009_zc706_overlay.py \
--junitxml=/tmp/adrv9009-overlay.xml
"$VENV_DIR/bin/python" .github/scripts/check_hardware_results.py \
/tmp/adrv9009-overlay.xml
The shared board fixture powers down the board on teardown, including failed boots. Retain failed reports as well as passing evidence. The workflow collects generated DTS/DTB/DTBO files, kernel and serial logs, and JUnit reports. Record the tested commit and artifact checksums alongside those results.
Local DT-emission parity
Run the System-API parity checks before deploying changed device wiring:
python -m pytest test/devices/test_system_adrv9371_zc706_dts_parity.py \
test/devices/test_system_ad9081_dts_parity.py
Reference fixtures live under test/devices/fixtures. Refresh a fixture only
from a reviewed reference or verified generated tree; a parity comparison
alone does not establish live hardware coverage.
Troubleshooting
No matching leg: inspect the reusable workflow’s discovery output, coordinator daughter-board/carrier tags, runner routing, and the allowlist.
Empty or skipped-only test results: check filename selection, pytest feature markers, and missing prerequisites. Do not treat this as a pass.
Wrong tree after boot: inspect the prepared strategy and staged-file consumption, and retain the marker mismatch. Do not substitute a stock boot.
ZU11EG JTAG reaches the wrong host: verify exporter resolution.
ADIDT_JTAG_HOSToverrides JTAG resource hosts for the test process and restores them during teardown.Overlay rejected or modules busy: check the kernel/module match and topology teardown sequence. The harness does not force module removal or bypass the JESD notifier.
FMCDAQ3 serial command truncation: the BootFabric fixture paces writes at a minimum of 2 ms per byte to accommodate UART Lite’s receive FIFO.