QDMA
Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Userspace API for slash QDMA (Queue-based DMA) devices.
A QDMA device is a separate character device created for PF1, while the control device (ctldev) is created for PF2. Each PCI function gets at most one of each. Device nodes appear at /dev/slash_qdma_ctl0, /dev/slash_qdma_ctl1, etc.
Queue pair lifecycle:
slash_qdma_open() — open the QDMA device
slash_qdma_qpair_add() — create a queue pair (returns assigned qid)
slash_qdma_qpair_start() — activate for transfers
slash_qdma_qpair_get_fd() — obtain fd for data transfer
slash_qdma_qpair_stop() — deactivate
slash_qdma_qpair_del() — destroy
slash_qdma_close() — close the device
The fd from qpair_get_fd() is ioctl-only for data movement: create kernel buffers with slash_qdma_buffer_create() (or slash_qdma_qpair_buffer_create() through a queue-pair fd), then move them with slash_qdma_qpair_transfer() / slash_qdma_qpair_transfer_batch(). read(), write(), and poll() are not available for SLASH transfers.
Kernel buffers: For high-throughput transfers, the kernel allocates a DMA buffer once (pages + SGL + DMA mapping built at creation), returns a mappable fd, and userspace mmaps it for CPU access. Transfers reference the buffer by its fd instead of re-pinning per call. Closing the buffer fd (and unmapping) releases it.
Error conventions: int-returning functions return -1 with errno set. Pointer-returning functions return NULL with errno set.
Functions
-
struct slash_qdma *slash_qdma_open(const char *path)
Open a QDMA device.
- Parameters:
path – Path to the character device node. NULL returns NULL/EINVAL.
- Returns:
Heap-allocated handle on success, NULL on failure.
-
int slash_qdma_close(struct slash_qdma *qdma)
Close a QDMA device and free the handle.
- Parameters:
qdma – Handle from slash_qdma_open(), or NULL (returns -1/EINVAL).
- Returns:
0 on success, -1 on failure.
-
int slash_qdma_info_read(struct slash_qdma *qdma, struct slash_qdma_info *info)
Read QDMA device capabilities.
- Parameters:
qdma – Open QDMA handle.
info – Caller-allocated struct, filled in on success.
- Returns:
0 on success, -1 on failure.
-
int slash_qdma_qpair_add(struct slash_qdma *qdma, struct slash_qdma_qpair_add *req)
Create a new queue pair.
- Parameters:
qdma – Open QDMA handle.
req – In/out — caller sets configuration fields, kernel fills in the assigned queue id (and possibly other output fields).
- Returns:
0 on success, -1 on failure.
-
int slash_qdma_qpair_start(struct slash_qdma *qdma, uint32_t qid)
Activate a queue pair for transfers.
- Parameters:
qdma – Open QDMA handle.
qid – Queue pair id from slash_qdma_qpair_add().
- Returns:
0 on success, -1 on failure.
-
int slash_qdma_qpair_stop(struct slash_qdma *qdma, uint32_t qid)
Deactivate a queue pair.
- Parameters:
qdma – Open QDMA handle.
qid – Queue pair id.
- Returns:
0 on success, -1 on failure.
-
int slash_qdma_qpair_del(struct slash_qdma *qdma, uint32_t qid)
Destroy a queue pair.
The kernel implicitly stops the queue if it is still running, so a separate stop call is not required before del.
- Parameters:
qdma – Open QDMA handle.
qid – Queue pair id.
- Returns:
0 on success, -1 on failure.
-
int slash_qdma_qpair_get_fd(struct slash_qdma *qdma, uint32_t qid, int flags)
Obtain a file descriptor for data transfer.
The returned fd supports transfer and buffer-registration ioctls. It does not support read/write data movement; use slash_qdma_qpair_transfer().
- Parameters:
qdma – Open QDMA handle.
qid – Queue pair id (must be started).
flags – Only O_CLOEXEC is accepted; the kernel returns -EINVAL for any other bits.
- Returns:
Non-negative fd on success, -1 on failure.
-
int slash_qdma_qpair_get_fd_multi(struct slash_qdma *qdma, const uint32_t *qids, uint32_t qpair_count, int flags)
Obtain a transfer fd bound to one or more queue pairs.
Like slash_qdma_qpair_get_fd(), but the returned fd is a collection of up to SLASH_QDMA_FD_MAX_QPAIRS queue pairs. A transfer issued on the fd selects a bound queue pair by its index in @qids, so a single transfer can fan across both AXI-MM/NoC channels. Each bound queue pair keeps whatever per-qpair settings (mm_channel, ring sizes, directions) it was given at add time.
- Parameters:
qdma – Open QDMA handle.
qids – Array of @qpair_count queue pair IDs (must be started).
qpair_count – Number of entries in @qids (1..SLASH_QDMA_FD_MAX_QPAIRS).
flags – Only O_CLOEXEC is accepted.
- Returns:
Non-negative fd on success, -1 on failure (errno set).
-
int slash_qdma_buffer_create(struct slash_qdma *qdma, uint64_t length, struct slash_qdma_buffer *buf_out)
Create a kernel-owned DMA buffer and mmap it.
Allocates @length bytes of kernel memory (DMA-mapped once), returns a buffer fd, and mmaps it into @buf_out->addr for CPU access. The buffer is bound to @qdma’s device; transfers must use a queue-pair fd of the same device.
- Parameters:
qdma – Open QDMA handle.
length – Buffer length in bytes (non-zero multiple of the page size).
buf_out – [out] Receives the created buffer (fd, mapping, metadata).
- Returns:
0 on success, -1 on failure (errno set).
-
int slash_qdma_qpair_buffer_create(int qpair_fd, uint64_t length, struct slash_qdma_buffer *buf_out)
Create a kernel-owned DMA buffer through a queue-pair fd.
Same semantics as slash_qdma_buffer_create(), but issues the create ioctl on
qpair_fd. This is the preferred form for clients that received only qpair fds via SCM_RIGHTS (for example libvrtd clients).- Returns:
0 on success, -1 on failure (errno set).
-
int slash_qdma_buffer_destroy(struct slash_qdma_buffer *buf)
Release a buffer created with slash_qdma_buffer_create() or slash_qdma_qpair_buffer_create().
Unmaps @buf->addr and closes @buf->fd. Safe to call on a zeroed/partial buffer (fields are reset).
- Returns:
0 on success, -1 on failure (errno set).
-
ssize_t slash_qdma_qpair_transfer(int qpair_fd, int buf_fd, uint64_t buf_offset, uint64_t dev_addr, uint64_t length, uint32_t direction)
Perform a DMA transfer using a single buffer fd.
Convenience wrapper around slash_qdma_qpair_transfer_batch() for a single sub-transfer on qpair_index 0.
- Parameters:
qpair_fd – Queue-pair I/O fd from slash_qdma_qpair_get_fd().
buf_fd – Buffer fd (from slash_qdma_buffer_create()).
buf_offset – Byte offset within the buffer.
dev_addr – Device-side (endpoint) address.
length – Number of bytes to transfer.
direction – One of enum slash_qdma_transfer_dir (H2C or C2H).
- Returns:
Number of bytes transferred (>= 0) on success, -1 on failure (errno set).
-
ssize_t slash_qdma_qpair_transfer_batch(int qpair_fd, const struct slash_qdma_subxfer *xfers, uint32_t count)
Perform a batch of buffer DMA sub-transfers in one call.
Issues a single transfer ioctl carrying @count sub-transfers. The kernel runs sub-transfers that target distinct queue pairs concurrently, so one call can drive both NoC channels in parallel. Each sub-transfer names a bound queue pair by index (see slash_qdma_qpair_get_fd_multi()) and a buffer by its buf_fd.
- Parameters:
qpair_fd – Transfer fd from slash_qdma_qpair_get_fd[_multi]().
xfers – Array of @count sub-transfer descriptors.
count – Number of sub-transfers (1..SLASH_QDMA_FD_MAX_QPAIRS).
- Returns:
Total bytes transferred (>= 0) on success, -1 on failure (errno set).
-
struct slash_qdma
- #include <qdma.h>
Handle to an open QDMA device.
@priv is NULL for real hardware handles. When slash_qdma_open() is called with “\@mock”, it points to an internal slash_qdma_mock context; callers should treat it as opaque.
-
struct slash_qdma_buffer
- #include <qdma.h>
A kernel-owned DMA buffer and its CPU mapping.
Created by slash_qdma_buffer_create() / slash_qdma_qpair_buffer_create() and released by slash_qdma_buffer_destroy(). @addr is an mmap of the kernel buffer fd; write/read it from the CPU and move it with the transfer helpers, passing @fd as the sub-transfer’s buf_fd.