Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DMABUF API v3 #1035

Merged
merged 8 commits into from
Sep 27, 2024
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
1 change: 1 addition & 0 deletions README_BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Cmake Options | Default | Description |
`WITH_IIOD_NETWORK` | ON | Add network (TCP/IP) support |
`WITH_IIOD_SERIAL` | ON | Add serial (UART) support |
`WITH_IIOD_USBD` | ON | Add support for USB through FunctionFS within IIOD |
`WITH_IIOD_USB_DMABUF` | OFF | Enable DMABUF support on the USB stack |
`WITH_IIOD_V0_COMPAT` | ON | Add support for Libiio v0.x protocol and clients |
`WITH_LIBTINYIIOD` | OFF | Build libtinyiiod |
`WITH_AIO` | ON | Build IIOD with async. I/O support |
Expand Down
27 changes: 25 additions & 2 deletions block.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ struct iio_block {

struct iio_task_token *token;
size_t bytes_used;

int dmabuf_fd;
};

struct iio_block *
Expand All @@ -41,13 +43,19 @@ iio_buffer_create_block(struct iio_buffer *buf, size_t size)
if (!block)
return iio_ptr(-ENOMEM);

block->dmabuf_fd = -EINVAL;

if (ops->create_block) {
pdata = ops->create_block(buf->pdata, size, &block->data);
ret = iio_err(pdata);
if (!ret)
if (!ret) {
block->pdata = pdata;
else if (ret != -ENOSYS)

if (ops->get_dmabuf_fd)
block->dmabuf_fd = ops->get_dmabuf_fd(pdata);
} else if (ret != -ENOSYS) {
goto err_free_block;
}
}

if (!block->pdata) {
Expand Down Expand Up @@ -295,3 +303,18 @@ struct iio_buffer * iio_block_get_buffer(const struct iio_block *block)
{
return block->buffer;
}

int iio_block_get_dmabuf_fd(const struct iio_block *block)
{
return block->dmabuf_fd;
}

int iio_block_disable_cpu_access(struct iio_block *block, bool disable)
{
const struct iio_backend_ops *ops = block->buffer->dev->ctx->ops;

if (ops->disable_cpu_access)
return ops->disable_cpu_access(block->pdata, disable);

return -ENOSYS;
}
1 change: 1 addition & 0 deletions iio-config.h.cmakein
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#cmakedefine01 WITH_IIOD_NETWORK
#cmakedefine01 WITH_IIOD_USBD
#cmakedefine01 WITH_IIOD_SERIAL
#cmakedefine01 WITH_IIOD_USB_DMABUF
#cmakedefine01 WITH_IIOD_V0_COMPAT
#cmakedefine01 WITH_LOCAL_CONFIG
#cmakedefine01 WITH_LOCAL_DMABUF_API
Expand Down
6 changes: 6 additions & 0 deletions iiod/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ if (WITH_AIO)
endif()

target_sources(iiod PRIVATE usbd.c)


option(WITH_IIOD_USB_DMABUF "Enable DMABUF support on the USB stack" OFF)
if (WITH_IIOD_USB_DMABUF)
target_sources(iiod PRIVATE usb-dmabuf.c)
endif()
endif()

target_include_directories(iiod PRIVATE ${LIBAIO_INCLUDE_DIR})
Expand Down
8 changes: 8 additions & 0 deletions iiod/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct iio_mutex;
struct iio_task;
struct iiod_io;
struct pollfd;
struct parser_pdata;
struct thread_pool;
extern struct thread_pool *main_thread_pool;
struct DevEntry;
Expand All @@ -61,6 +62,8 @@ struct block_entry {
uint64_t bytes_used;
uint16_t idx;
bool cyclic;
int dmabuf_fd;
int ep_fd;
};

struct buffer_entry {
Expand All @@ -71,6 +74,7 @@ struct buffer_entry {
struct iio_task *enqueue_task, *dequeue_task;
uint32_t *words;
uint16_t idx;
bool is_tx;

SLIST_HEAD(BlockList, block_entry) blocklist;
struct iio_mutex *lock;
Expand Down Expand Up @@ -139,6 +143,10 @@ int start_network_daemon(struct iio_context *ctx,
struct thread_pool *pool, const void *xml_zstd,
size_t xml_zstd_len, uint16_t port);

int usb_attach_dmabuf(int ep_fd, int fd);
int usb_detach_dmabuf(int ep_fd, int fd);
int usb_transfer_dmabuf(int ep_fd, int fd, uint64_t size);

int binary_parse(struct parser_pdata *pdata);

void enable_binary(struct parser_pdata *pdata);
Expand Down
64 changes: 54 additions & 10 deletions iiod/responder.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,17 @@ static int buffer_dequeue_block(void *priv, void *d)
if (ret < 0)
goto out_send_response;

if (!iio_buffer_is_tx(buffer->buf)) {
if (!buffer->is_tx) {
if (WITH_IIOD_USB_DMABUF && entry->dmabuf_fd > 0) {
/* We need to send the error code before the data.
* If usb_transfer_dmabuf() fails, we're screwed... */
iiod_io_send_response_code(entry->io, entry->bytes_used);

return usb_transfer_dmabuf(buffer->pdata->fd_out,
entry->dmabuf_fd,
entry->bytes_used);
}

data.ptr = iio_block_start(entry->block);
data.size = iio_block_end(entry->block) - data.ptr;
nb_data++;
Expand Down Expand Up @@ -364,6 +374,8 @@ static void handle_create_buffer(struct parser_pdata *pdata,
goto err_send_response;
}

entry->pdata = pdata;

nb_channels = iio_device_get_channels_count(dev);
nb_words = (nb_channels + 31) / 32;

Expand Down Expand Up @@ -434,6 +446,8 @@ static void handle_create_buffer(struct parser_pdata *pdata,
entry->words[BIT_WORD(i)] &= ~BIT_MASK(i);
}

entry->is_tx = iio_buffer_is_tx(buf);

/* Success, destroy the temporary mask object */
iio_channels_mask_destroy(mask);

Expand Down Expand Up @@ -628,7 +642,7 @@ static void handle_create_block(struct parser_pdata *pdata,
struct iiod_buf data;
uint64_t block_size;
struct iiod_io *io;
int ret;
int ret, ep_fd;

io = iiod_command_create_io(cmd, cmd_data);
ret = iio_err(io);
Expand Down Expand Up @@ -674,6 +688,25 @@ static void handle_create_block(struct parser_pdata *pdata,
entry->io = io;
entry->idx = cmd->code >> 16;

if (WITH_IIOD_USB_DMABUF && pdata->is_usb) {
entry->dmabuf_fd = iio_block_get_dmabuf_fd(block);
if (entry->dmabuf_fd > 0) {
ep_fd = buf_entry->is_tx ? pdata->fd_in : pdata->fd_out;
entry->ep_fd = ep_fd;

ret = usb_attach_dmabuf(ep_fd, entry->dmabuf_fd);
if (!ret) {
/* We could attach to functionfs. Disable CPU
* access to the block as we won't need it. */
iio_block_disable_cpu_access(block, true);
} else {
/* If we can't attach - no problem. The
* data will be transferred the regular way. */
entry->dmabuf_fd = -ENOSYS;
}
}
}

/* Keep a reference to the iiod_io until the block is freed. */
iiod_io_ref(io);

Expand All @@ -695,7 +728,7 @@ static void handle_free_block(struct parser_pdata *pdata,
struct iio_buffer *buf;
struct iio_block *block;
struct iiod_io *io;
int ret;
int ret, ep_fd;

buf = get_iio_buffer(pdata, cmd, &buf_entry);
ret = iio_err(buf);
Expand All @@ -715,6 +748,9 @@ static void handle_free_block(struct parser_pdata *pdata,
if (entry->block != block)
continue;

if (WITH_IIOD_USB_DMABUF && entry->dmabuf_fd > 0)
usb_detach_dmabuf(entry->ep_fd, entry->dmabuf_fd);

SLIST_REMOVE(&buf_entry->blocklist, entry, block_entry, entry);

free_block_entry(entry);
Expand Down Expand Up @@ -779,13 +815,21 @@ static void handle_transfer_block(struct parser_pdata *pdata,
}

/* Read the data into the block if we are dealing with a TX buffer */
if (iio_buffer_is_tx(buf)) {
readbuf.ptr = iio_block_start(block);
readbuf.size = iio_block_end(block) - readbuf.ptr;

ret = iiod_command_data_read(cmd_data, &readbuf);
if (ret < 0)
goto out_send_response;
if (entry->is_tx) {
if (WITH_IIOD_USB_DMABUF && block_entry->dmabuf_fd > 0) {
ret = usb_transfer_dmabuf(pdata->fd_in,
block_entry->dmabuf_fd,
bytes_used);
if (ret)
goto out_send_response;
} else {
readbuf.ptr = iio_block_start(block);
readbuf.size = iio_block_end(block) - readbuf.ptr;

ret = iiod_command_data_read(cmd_data, &readbuf);
if (ret < 0)
goto out_send_response;
}
}

block_entry->bytes_used = bytes_used;
Expand Down
60 changes: 60 additions & 0 deletions iiod/usb-dmabuf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* libiio - Library for interfacing industrial I/O (IIO) devices
*
* Copyright (C) 2023 Analog Devices, Inc.
* Author: Paul Cercueil <[email protected]>
*/

#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/ioctl.h>

#define IIO_FFS_DMABUF_ATTACH _IOW('g', 131, int)
#define IIO_FFS_DMABUF_DETACH _IOW('g', 132, int)
#define IIO_FFS_DMABUF_TRANSFER _IOW('g', 133, struct iio_ffs_dmabuf_transfer)

struct iio_ffs_dmabuf_transfer {
int fd;
uint32_t flags;
uint64_t length;
};

int usb_attach_dmabuf(int ep_fd, int fd)
{
int ret;

ret = ioctl(ep_fd, IIO_FFS_DMABUF_ATTACH, &fd);
if (ret == -1)
return -errno;

return 0;
}

int usb_detach_dmabuf(int ep_fd, int fd)
{
int ret;

ret = ioctl(ep_fd, IIO_FFS_DMABUF_DETACH, &fd);
if (ret == -1)
return -errno;

return 0;
}

int usb_transfer_dmabuf(int ep_fd, int fd, uint64_t size)
{
struct iio_ffs_dmabuf_transfer req;
int ret;

req.fd = fd;
req.length = size;
req.flags = 0;

ret = ioctl(ep_fd, IIO_FFS_DMABUF_TRANSFER, &req);
if (ret == -1)
return -errno;

return 0;
}
1 change: 1 addition & 0 deletions include/iio/iio-backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct iio_backend_ops {
int (*dequeue_block)(struct iio_block_pdata *pdata, bool nonblock);

int (*get_dmabuf_fd)(struct iio_block_pdata *pdata);
int (*disable_cpu_access)(struct iio_block_pdata *pdata, bool disable);

struct iio_event_stream_pdata *(*open_ev)(const struct iio_device *dev);
void (*close_ev)(struct iio_event_stream_pdata *pdata);
Expand Down
19 changes: 19 additions & 0 deletions include/iio/iio.h
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,25 @@ iio_buffer_create_block(struct iio_buffer *buffer, size_t size);
__api void iio_block_destroy(struct iio_block *block);


/** @brief Get the file descriptor of the underlying DMABUF object
* @param block A pointer to an iio_block structure
* @return The file descriptor of the underlying DMABUF object.
* If the iio_block is not backed by a DMABUF object, -EINVAL is returned.
* Otherwise, the file descriptor will be valid until the block is destroyed. */
__api __check_ret int iio_block_get_dmabuf_fd(const struct iio_block *block);


/** @brief Disable CPU access of a given block
* @param block A pointer to an iio_block structure
* @param disable Whether or not to disable CPU access
*
* <b>NOTE:</b>Disabling CPU access is useful when manipulating DMABUF objects.
* If CPU access is disabled, the block's internal buffer of samples should not
* be accessed. Therefore, the following functions should not be called:
* iio_block_start, iio_block_first, iio_block_end, iio_block_foreach_sample. */
__api int iio_block_disable_cpu_access(struct iio_block *block, bool disable);


/** @brief Get the start address of the block
* @param block A pointer to an iio_block structure
* @return A pointer corresponding to the start address of the block */
Expand Down
Loading
Loading