gizhw:amdxdna
AMD XDNA (the Ryzen AI NPU, driver amdxdna): its GET_INFO queries (the layouts of drm/amdxdna_accel.h) and the run of a kernel: a hardware context, a device heap that holds the buffers, a firmware image and control code loaded into it, and an ERT START_NPU packet (amdxdna_ctx.h) that starts one run. A request is an ioctl on a Handle of gizhw:device; the NPU's generic view is gizhw:npu.
import * as Amdxdna from "gizhw:amdxdna";Types
Firmware
type Firmware = { major: i64; minor: i64; patch: i64; build: i64; }The XDNA firmware's version and build.
major:i64minor:i64patch:i64build:i64
Aie
type Aie = { major: i64; minor: i64; }The AIE (the NPU's array) version.
major:i64minor:i64
Bo
type Bo = { handle: i64; at: u64; size: i64; offset: u64; host: u64; }A device buffer: its handle, its device address at, its size, and the offset its host mapping uses (a heap buffer's).
handle:i64at:u64size:i64offset:u64host:u64
Context
type Context = { h: Device.Handle; hwctx: i64; syncobj: i64; heap: u64; heapAt: u64; }An open hardware context: its handle, its timeline syncobj, and the device heap mapped at heap (device address heapAt).
h:M7.Handlehwctx:i64syncobj:i64heap:u64heapAt:u64
Kernel
type Kernel = { pdi: bytes; ctrl: bytes; }A kernel: its firmware image (PDI) and its control code: an instruction list (an xclbin's insts.bin) or an ELF whose
.ctrltext holds it (XRT's full-ELF kernels, such as its gemm).
pdi:bytesctrl:bytes
Command
type Command = { bo: Bo; at: u64; }A command buffer, mapped at at: it holds one run's packet from its submit until the run ends.
bo:M1.Boat:u64
Program
type Program = { ctx: Context; ctrl: Bo; size: i64; elf: bool; debug: Bo; cmd: Command; }A loaded kernel: its control code (size bytes; elf: from an ELF), the debug buffer it writes, and the command buffer
of its run.
ctx:M1.Contextctrl:M1.Bosize:i64elf:booldebug:M1.Bocmd:M1.Command
Txn
type Txn = { ops: bytes; count: i64; }AIE transaction (TXN) control code, the instruction list an MLIR-AIE kernel runs (the format of an xclbin's
insts.bin): a 4-word header for the whole NPU2 array (6 rows, 8 columns, one memory-tile row), then operations. A tile
is (row << 4) | column: row 0 is the shim (interface) tiles, row 1 the memory tiles, rows 2 to 5 the cores.
ops:bytescount:i64
Xclbin
type Xclbin = { pdis: Vec<bytes>; kernels: Vec<string>; }An xclbin's parts that an NPU run needs: the firmware images (PDIs) of its AIE partition and the names of its kernels.
pdis:Vec<bytes>kernels:Vec<string>
Functions
infoRequest
function infoRequest(param: i64, size: i64, buffer: u64): bytesThe request for amdxdna's GET_INFO: a query number, the reply's size, and the reply buffer at buffer.
Effects: fail.
query
function query(h: Device.Handle, param: i64, size: i64): bytes throws stringThe reply of query param: size bytes the kernel wrote for it.
Effects: fail, io.
parseAie
function parseAie(data: bytes): AieThe AIE version from its 8-byte reply.
Effects: fail.
parseFirmware
function parseFirmware(data: bytes): FirmwareThe firmware version from its 16-byte reply.
Effects: fail.
aie
function aie(h: Device.Handle): Aie throws stringThe AIE version of the NPU behind h.
Effects: fail, io.
firmware
function firmware(h: Device.Handle): Firmware throws stringThe firmware version of the NPU behind h.
Effects: fail, io.
createHwctxRequest
function createHwctxRequest(qos: u64): bytesThe request for CREATE_HWCTX: the QoS block at qos, the opcode limit and the tile count.
Effects: fail.
createBoRequest
function createBoRequest(size: i64, kind: i64): bytesThe request for CREATE_BO: a buffer of size bytes of kind kind.
Effects: fail.
configRequest
function configRequest(hwctx: i64, kind: i64, value: u64, size: i64): bytesThe request for CONFIG_HWCTX of hardware context hwctx: parameter kind, its value or address, and its size.
Effects: fail.
cuConfig
function cuConfig(pdi: i64): bytesThe CU configuration: one control unit (CU 0) that runs from the firmware image in buffer pdi.
Effects: fail.
syncRequest
function syncRequest(handle: i64, direction: i64, size: i64): bytesThe request for SYNC_BO of buffer handle, in direction (SYNC_TO_DEVICE or SYNC_FROM_DEVICE) over size bytes.
Effects: fail.
execRequest
function execRequest(hwctx: i64, cmd: i64, handles: u64 = 0u, count: i64 = 0): bytesThe request for EXEC_CMD on hardware context hwctx: one command, which is buffer cmd itself (the inline form), and
the count buffer handles (u32) at address handles that the run uses.
Effects: fail.
startPacket
function startPacket(ctrl: u64, size: i64, args: Vec<i64>): bytesThe NPU packet that runs control code at device address ctrl (size bytes) with the arguments args. The opcode is
args[0], and each buffer address is 64-bit. The size field counts 32-bit words, and the count is fixed at 16, as XRT writes
them; the driver reads a shorter packet at the wrong offsets.
Effects: fail.
npuPacket
function npuPacket(ctrl: u64, size: i64, args: Vec<i64>): bytesThe packet that runs an ELF's control code (startPacket's other form, as XRT sends it): the CU mask, the code's device
address ctrl, its size in bytes, no properties, then each argument in 64 bits; the count is the words after the header.
Effects: fail.
ctrlText
function ctrlText(data: bytes): Option<bytes>The .ctrltext section of a 32-bit ELF, or none when data is not an ELF.
Effects: fail.
txn
function txn(): TxnAn empty transaction.
tile
function tile(row: i64, column: i64): i64The tile at row and column.
Effects: fail.
xclbin
function xclbin(data: bytes): Xclbin throws stringParses xclbin data (XRT's axlf: a header, then 40-byte section headers from byte 456; the section count at 448). An
AIE_PARTITION holds an array of aie_pdi records (its size and offset at byte 120), each with its image's size and
offset at byte 16; an IP_LAYOUT holds 80-byte ip_data records from byte 8, each named at byte 16.
Effects: fail.
open
function open(h: Device.Handle): Context throws stringOpens a hardware context on the NPU behind h, with its device heap mapped into this process. The heap comes first:
the driver's hwctx init looks up the client's device heap and fails with ENOENT without it.
Effects: fail, io.
more
function more(c: Context): Context throws stringAnother hardware context on the NPU and device heap of c, for a second kernel that runs beside the first (a client
has one heap).
Effects: fail, io.
load
function load(c: Context, kernel: Kernel): Program throws stringLoads kernel into context c: the firmware and control code go to device buffers, the context is configured to run
them with a debug buffer, and a command buffer is mapped for the runs.
Effects: fail, io.
command
function command(c: Context): Command throws stringA command buffer of context c, for a run submitted while others are in flight.
Effects: fail, io.
code
function code(p: Program, ctrl: bytes): Program throws stringReplaces the control code of p with ctrl (an instruction list, such as Txn.code gives); its buffer grows when the
code does not fit.
Effects: fail, io.
another
function another(p: Program, ctrl: bytes): Program throws stringAnother program of the firmware and context of p, with its own control code ctrl (a kernel whose runs differ only
in their control code, such as each kind of a model's layers).
Effects: fail, io.
run
function run(p: Program, args: Vec<i64>, buffers: Vec<Bo> = []): void throws stringRuns the loaded kernel once with the arguments args (the buffers' device addresses among them) and waits for the run.
Effects: fail, io.
submit
function submit(p: Program, cmd: Command, args: Vec<i64>, buffers: Vec<Bo> = []): u64 throws stringQueues a run of p in command buffer cmd and returns its point on the context's timeline; the context runs its
commands in order. The run's buffers and its control code go with the command, as XRT sends them, so the driver holds
them for the run. Submitting the next run before this one ends saves the wait and the wake-up between them.
Effects: fail, io.
finish
function finish(c: Context, point: u64, commands: Vec<Command>): void throws stringWaits until context c reaches point (submit), then checks that each of commands completed.
Effects: fail, io.
debugOf
function debugOf(p: Program): bytes throws stringThe debug buffer of p as its runs left it.
Effects: fail, io.
close
function close(c: Context): voidCloses the context: the kernel releases its hardware context and buffers with the descriptor.
Effects: fail, io.
buffer
function buffer(c: Context, size: i64): Bo throws stringA device buffer of size zero bytes; a run reads and writes it by its device address at (its address in this
process). Each page is written here: the NPU reaches the buffer through this process's page tables, and its writes to a
page the process has not touched yet are lost (a run right after buffer wrote nothing; 20 ms later it did).
Effects: fail, io.
upload
function upload(c: Context, bo: Bo, data: bytes, at: i64 = 0): voidCopies data into buffer bo at byte at, before the run that reads it.
Effects: fail, io.
download
function download(c: Context, bo: Bo, size: i64, at: i64 = 0): bytesThe size bytes of buffer bo from byte at as the device left them after a run: the CPU caches over them are dropped
first, so the read fetches what the device wrote.
Effects: fail, io.
downloadInto
function downloadInto(c: Context, bo: Bo, into: mut bytes, at: i64 = 0): voidAs download, the into.length bytes from byte at copied into into (a loop that reuses one buffer).
Effects: fail, io.
Methods
Txn.write
function Txn.write(self: mut Txn, t: i64, address: i64, value: i64): voidWrites value to the register (or the core's memory word) at address of tile t, as a run-time parameter.
Effects: fail.
Txn.copy
function Txn.copy(self: mut Txn, arg: i64, direction: i64, t: i64, bd: i64, channel: i64, offset: i64, length: i64, packet: i64 = -1, token: bool = false, cache: i64 = 2): voidA linear shim DMA of length bytes of kernel argument arg from byte offset, on shim tile t, buffer descriptor
bd and channel, in direction (Txn.strided with one dimension).
Effects: fail.
Txn.strided
function Txn.strided(self: mut Txn, arg: i64, direction: i64, t: i64, bd: i64, channel: i64, offset: i64, sizes: Vec<i64>, strides: Vec<i64>, unit: i64, packet: i64 = -1, token: bool = false, cache: i64 = 2): voidA shim DMA of kernel argument arg from byte offset, on shim tile t, buffer descriptor bd and channel, in
direction: the descriptor, the firmware's patch of the buffer's address into it, the task-complete token (an S2MM
always issues one; token asks for one on an MM2S), and the descriptor pushed to the channel's queue. The data is
sizes (four, the outermost first; the first repeats the other three) by strides, in elements of unit bytes; the
innermost stride is 1, and the DMA moves whole 32-bit words. packet (0 to 31) sends the data as packets with that id.
Effects: fail.
Txn.wait
function Txn.wait(self: mut Txn, t: i64, direction: i64, channel: i64): voidWaits for the task-complete token of channel in direction on shim tile t.
Effects: fail.
Txn.code
function Txn.code(self: Txn): bytesThe control code: the header, then the operations.
Effects: fail.
Constants
DRIVER
const DRIVER = "amdxdna"The driver name the kernel binds to an XDNA NPU.
S2MM
const S2MM = 0The DMA directions: S2MM moves a stream into memory (the NPU writes the buffer), MM2S the other way.
MM2S
const MM2S = 1The DMA direction that moves memory into a stream (the NPU reads the buffer).
NO_CACHE
const NO_CACHE = 0x0The AXI cache attributes of a shim DMA's reads and writes.
NORMAL_CACHE
const NORMAL_CACHE = 0x2The AXI cache attribute of normal (cacheable) memory.
AGGRESSIVE_CACHE
const AGGRESSIVE_CACHE = 0xEThe AXI cache attribute that allows every kind of caching.