Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/workflows/bump-xdna.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Keep third_party/xdna-driver on upstream amd/xdna-driver main (docs/npu.md,
# "The XDNA stack"): when upstream moves, open a PR here moving the submodule.
# It pins XRT too (xdna-driver's own xrt submodule). GitHub-hosted CI has no
# NPU; build with scripts/build-xdna.sh and run tests/npu_lane_e2e.sh on Strix
# Halo before merging.
#
# Uses the secret HRX_BUMP_TOKEN (Contents and Pull requests read/write on
# 1bit-MONSTER/engine): a PR opened with the default GITHUB_TOKEN would not
# start CI.
name: bump-xdna

on:
schedule:
- cron: "41 6 * * *"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: bump-xdna
cancel-in-progress: false

jobs:
bump:
runs-on: ubuntu-latest
steps:
- name: Require the token
env:
HRX_BUMP_TOKEN: ${{ secrets.HRX_BUMP_TOKEN }}
run: |
if [ -z "$HRX_BUMP_TOKEN" ]; then
echo "::error::secret HRX_BUMP_TOKEN is not set (see the header of this workflow)"
exit 1
fi

- uses: actions/checkout@v4
with:
token: ${{ secrets.HRX_BUMP_TOKEN }}

- name: Compare with upstream
id: pins
env:
GH_TOKEN: ${{ secrets.HRX_BUMP_TOKEN }}
run: |
set -euo pipefail
upstream=$(gh api repos/amd/xdna-driver/commits/main --jq .sha)
upstream_xrt=$(gh api "repos/amd/xdna-driver/contents/xrt?ref=$upstream" --jq .sha)
ours=$(git ls-tree HEAD third_party/xdna-driver | awk '{print $3}')
echo "upstream $upstream (xrt $upstream_xrt), ours $ours"
{
echo "upstream=$upstream"; echo "upstream_xrt=$upstream_xrt"; echo "ours=$ours"
if [ "$upstream" = "$ours" ]; then echo "changed=false"; else echo "changed=true"; fi
} >> "$GITHUB_OUTPUT"

- name: Open the bump PR
if: steps.pins.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.HRX_BUMP_TOKEN }}
UPSTREAM: ${{ steps.pins.outputs.upstream }}
UPSTREAM_XRT: ${{ steps.pins.outputs.upstream_xrt }}
OURS: ${{ steps.pins.outputs.ours }}
run: |
set -euo pipefail
branch="bump-xdna/${UPSTREAM:0:12}"
if git ls-remote --exit-code origin "refs/heads/$branch" > /dev/null; then
echo "$branch already exists"; exit 0
fi
log=$(gh api "repos/amd/xdna-driver/compare/${OURS}...${UPSTREAM}" \
--jq '.commits[-30:][] | "- \(.sha[0:9]) \(.commit.message | split("\n")[0])"' || true)
git config user.name "xdna-bump"
git config user.email "xdna-bump@users.noreply.github.com"
git switch -c "$branch"
git update-index --cacheinfo "160000,$UPSTREAM,third_party/xdna-driver"
git commit -q -m "Bump XDNA: amd/xdna-driver ${UPSTREAM:0:12} (XRT ${UPSTREAM_XRT:0:12})"
git push -q origin "$branch"
gh pr create --base main --head "$branch" \
--title "Bump XDNA: amd/xdna-driver ${UPSTREAM:0:12}" \
--body "Moves third_party/xdna-driver from \`${OURS:0:12}\` to upstream main \`${UPSTREAM:0:12}\` (its XRT submodule: \`${UPSTREAM_XRT:0:12}\`).

Upstream commits (last 30):
${log}

CI here has no NPU. Before merging, on Strix Halo:
\`scripts/build-xdna.sh ~/.cache/xdna-pin/prefix && cmake -B build -G Ninja -DONEBIT_NPU=ON -DONEBIT_XRT_ROOT=\$HOME/.cache/xdna-pin/prefix && cmake --build build --target onebit && tests/npu_lane_e2e.sh ...\`"
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@
url = https://github.com/1bit-MONSTER/llama.cpp.git
branch = 1bit/hrx-vulkan
shallow = true
[submodule "third_party/xdna-driver"]
path = third_party/xdna-driver
url = https://github.com/amd/xdna-driver.git
branch = main
28 changes: 28 additions & 0 deletions docs/npu.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,34 @@ The `1bit` binary links only `libxrt_coreutil`: no xclbin, no FastFlowLM library
greedy.
- Requests are served one at a time: the lane has one KV cache.

## The XDNA stack

The lane runs on XRT and the XDNA shim plugin (`libxrt_driver_xdna`), which XRT loads at run
time. Both are pinned: `third_party/xdna-driver` is upstream
[amd/xdna-driver](https://github.com/amd/xdna-driver), and its own `xrt` submodule pins XRT.

- **The kernel driver is not built from this pin.** `amdxdna` ships in the kernel
(`drivers/accel/amdxdna`), and Strix Halo runs the kernel's copy.
- **Building the pinned stack:** `scripts/build-xdna.sh <prefix>` builds XRT (the NPU package)
and then the shim, staged under `<prefix>/root`. Nothing is installed system-wide: XRT hard-codes
`/etc/OpenCL/vendors`, so both installs use `DESTDIR`. The engine then builds against it:

```
scripts/build-xdna.sh ~/.cache/xdna-pin/prefix
cmake -B build -G Ninja -DONEBIT_NPU=ON -DONEBIT_XRT_ROOT=$HOME/.cache/xdna-pin/prefix/root/opt/xilinx/xrt
```
- **XRT's OpenCL layer (`xocl`) is excluded** (`XRT_EXCLUDE_SUB_DIRECTORY`). The NPU does not use
it, and it fails to compile where the distro's `ocl_icd.h` is newer than XRT's bundled OpenCL
1.2 headers.
- **Keeping current:** `.github/workflows/bump-xdna.yml` runs daily and opens a PR whenever
upstream `main` moves (secret `HRX_BUMP_TOKEN`). CI has no NPU, so run the check below on
Strix Halo before merging.

Verified on 2026-09-23 with xdna-driver `5d302c9` and XRT `d8ececf`, in place of the system's
XRT 2.21.75. Both `libxrt_core` and `libxrt_driver_xdna` were loaded from the pinned prefix
(strace). `tests/npu_lane_e2e.sh` gave logits bit-identical to the reference lane on 24/24 steps,
at 10.8 ms/token (92.6 tok/s), with a 327 ms warm load.

## Open: where the kernel artifacts come from

CONTRIBUTING rule 4 requires NPU kernels to be built from source. The layer kernel and
Expand Down
56 changes: 56 additions & 0 deletions scripts/build-xdna.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# build-xdna.sh <prefix> [jobs]
#
# Builds the XDNA userspace stack pinned in third_party/xdna-driver (upstream
# amd/xdna-driver and its xrt submodule) into <prefix>: XRT, then the XDNA shim
# plugin (libxrt_driver_xdna). It installs nothing system-wide: both are staged
# with DESTDIR=<prefix>/root (XRT hard-codes /etc/OpenCL/vendors), so the XRT
# root is <prefix>/root/opt/xilinx/xrt. Point the engine at it with
# -DONEBIT_XRT_ROOT=<prefix>/root/opt/xilinx/xrt (docs/npu.md, "The XDNA stack").
#
# The kernel driver is not built: amdxdna ships in the kernel (drivers/accel).
# Build dependencies come from upstream's third_party/xdna-driver/tools/amdxdna_deps.sh.
set -euo pipefail
prefix=${1:?usage: build-xdna.sh <prefix> [jobs]}
jobs=${2:-$(nproc)}
root=$(cd "$(dirname "$0")/.." && pwd)
src=$root/third_party/xdna-driver
mkdir -p "$prefix"
prefix=$(cd "$prefix" && pwd)

[ -f "$src/build/build.sh" ] || { echo "third_party/xdna-driver is empty: git submodule update --init third_party/xdna-driver"; exit 1; }
git -C "$src" submodule update --init --recursive --depth 1

# XRT, NPU package. Its OpenCL layer (xocl) is left out: the NPU does not use
# it, and it fails to compile where the distro's ocl_icd.h is newer than XRT's
# bundled OpenCL 1.2 headers.
(cd "$src/xrt/build" && ./build.sh -npu -opt -noctest -j "$jobs" \
-cmake-flags "-DXRT_EXCLUDE_SUB_DIRECTORY=src/runtime_src/xocl")
stage=$prefix/root
xrt=$stage/opt/xilinx/xrt
DESTDIR=$stage cmake --install "$src/xrt/build/Release"

# The XDNA shim plugin, against that XRT; no kernel module.
(cd "$src/build" && XILINX_XRT="$xrt" ./build.sh -release -nokmod -j "$jobs")
DESTDIR=$stage cmake --install "$src/build/Release"
# XRT loads device plugins from its own lib directory; the shim installs under
# its build's prefix, so put it next to XRT.
find "$stage" -name 'libxrt_driver_xdna.so*' -not -path "$xrt/*" -exec cp -a {} "$xrt/lib/" \;

echo "XDNA stack (XRT root): $xrt"
ls "$xrt"/lib*/libxrt_coreutil.so* "$xrt"/lib*/libxrt_driver_xdna.so* 2>/dev/null
1 change: 1 addition & 0 deletions third_party/xdna-driver
Submodule xdna-driver added at 5d302c
Loading