zephyr/subsys/rtio/rtio_executor_simple.c

149 lines
3.5 KiB
C
Raw Normal View History

rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
/*
* Copyright (c) 2022 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "rtio_executor_common.h"
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
#include <zephyr/rtio/rtio_executor_simple.h>
#include <zephyr/rtio/rtio.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(rtio_executor_simple, CONFIG_RTIO_LOG_LEVEL);
/**
* @brief Submit submissions to simple executor
*
* The simple executor provides no concurrency instead
* execution each submission chain one after the next.
*
* @param r RTIO context
*
* @retval 0 Always succeeds
*/
int rtio_simple_submit(struct rtio *r)
{
struct rtio_simple_executor *exc = (struct rtio_simple_executor *)r->executor;
/* Task is already running */
if (exc->task.sqe != NULL) {
return 0;
}
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
struct rtio_sqe *sqe = rtio_spsc_consume(r->sq);
if (sqe == NULL) {
return 0;
}
/* Some validation on the sqe to ensure no programming errors were
* made so assumptions in ok and err are valid.
*/
#ifdef CONFIG_ASSERT
__ASSERT(sqe != NULL, "Expected a valid sqe on submit call");
bool transaction = sqe->flags & RTIO_SQE_TRANSACTION;
bool chained = sqe->flags & RTIO_SQE_CHAINED;
if (transaction || chained) {
struct rtio_sqe *next = rtio_spsc_next(r->sq, sqe);
__ASSERT(next != NULL,
"sqe %p flagged as transaction (%d) or chained (%d) without subsequent sqe in queue",
sqe, transaction, chained);
}
__ASSERT(!(chained && transaction),
"sqe %p flagged as both being transaction and chained, only one is allowed",
sqe);
#endif
exc->task.sqe = sqe;
exc->task.r = r;
rtio_executor_submit(&exc->task);
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
return 0;
}
/**
* @brief Callback from an iodev describing success
*/
void rtio_simple_ok(struct rtio_iodev_sqe *iodev_sqe, int result)
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
{
struct rtio *r = iodev_sqe->r;
const struct rtio_sqe *sqe = iodev_sqe->sqe;
#ifdef CONFIG_ASSERT
struct rtio_simple_executor *exc =
(struct rtio_simple_executor *)r->executor;
__ASSERT_NO_MSG(iodev_sqe == &exc->task);
#endif
bool transaction = sqe->flags & RTIO_SQE_TRANSACTION;
while (transaction) {
rtio_spsc_release(r->sq);
sqe = rtio_spsc_consume(r->sq);
__ASSERT_NO_MSG(sqe != NULL);
transaction = sqe->flags & RTIO_SQE_TRANSACTION;
}
void *userdata = sqe->userdata;
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
rtio_spsc_release(r->sq);
iodev_sqe->sqe = NULL;
rtio_cqe_submit(r, result, userdata);
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
rtio_simple_submit(r);
}
/**
* @brief Callback from an iodev describing error
*
* Some assumptions are made and should have been validated on rtio_submit
* - a sqe marked as chained or transaction has a next sqe
* - a sqe is marked either chained or transaction but not both
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
*/
void rtio_simple_err(struct rtio_iodev_sqe *iodev_sqe, int result)
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
{
const struct rtio_sqe *sqe = iodev_sqe->sqe;
struct rtio *r = iodev_sqe->r;
void *userdata = sqe->userdata;
bool chained = sqe->flags & RTIO_SQE_CHAINED;
bool transaction = sqe->flags & RTIO_SQE_TRANSACTION;
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
#ifdef CONFIG_ASSERT
struct rtio_simple_executor *exc =
(struct rtio_simple_executor *)r->executor;
__ASSERT_NO_MSG(iodev_sqe == &exc->task);
#endif
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
rtio_spsc_release(r->sq);
iodev_sqe->sqe = NULL;
if (!transaction) {
rtio_cqe_submit(r, result, userdata);
}
while (chained | transaction) {
sqe = rtio_spsc_consume(r->sq);
chained = sqe->flags & RTIO_SQE_CHAINED;
transaction = sqe->flags & RTIO_SQE_TRANSACTION;
userdata = sqe->userdata;
rtio_spsc_release(r->sq);
if (!transaction) {
rtio_cqe_submit(r, result, userdata);
} else {
rtio_cqe_submit(r, -ECANCELED, userdata);
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
}
}
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
iodev_sqe->sqe = rtio_spsc_consume(r->sq);
if (iodev_sqe->sqe != NULL) {
rtio_executor_submit(iodev_sqe);
rtio: Real-Time Input/Output Stream A DMA friendly Stream API for zephyr. Based on ideas from io_uring and iio, a queue based API for I/O operations. Provides a pair of fixed length ringbuffer backed queues for submitting I/O requests and recieving I/O completions. The requests may be chained together to ensure the next operation does not start until the current one is complete. Requests target an abstract rtio_iodev which is expected to wrap all the hardware particulars of how to perform the operation. For example with a SPI bus device, a description of what a read, and write mean can be decided by the iodev wrapping a particular device hanging off of a SPI controller. The queue pair are submitted to an executor which may be a simple inplace looping executor done in the callers execution context (thread/stack) but other executors are expected. A threadpool executor might for example allow for concurrent request chains to execute in parallel. A DMA executor, in conjunction with DMA aware iodevs would allow for hardware offloading of operations going so far as to schedule with priority using hardware arbitration. Both the iodev and executor are definable by a particular SoC, meaning they can work in conjuction to perform IO operations using a particular DMA controller or methodology if desired. The application decides entirely how large the queues are, where the buffers to read/write come from (some executors may have particular demands!), and which executor to submit requests to. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
2019-06-26 17:17:18 +02:00
}
}