rtio: Add RTIO Work-queues service
Adds ability to process synchronous requests in an asynchronous fashion, relying on dedicated P4WQ's and pre-allocated work items. Signed-off-by: Luis Ubieda <luisf@croxel.com>
This commit is contained in:
parent
1f3a0910d7
commit
3646b63217
5 changed files with 208 additions and 0 deletions
80
include/zephyr/rtio/work.h
Normal file
80
include/zephyr/rtio/work.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Croxel Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_RTIO_WORKQ_H_
|
||||||
|
#define ZEPHYR_INCLUDE_RTIO_WORKQ_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/rtio/rtio.h>
|
||||||
|
#include <zephyr/sys/p4wq.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback API to execute work operation.
|
||||||
|
*
|
||||||
|
* @param iodev_sqe Associated SQE operation.
|
||||||
|
*/
|
||||||
|
typedef void (*rtio_work_submit_t)(struct rtio_iodev_sqe *iodev_sqe);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief RTIO Work request.
|
||||||
|
*
|
||||||
|
* This RTIO Work request to perform a work operation decoupled
|
||||||
|
* from its submission in the RTIO work-queues.
|
||||||
|
*/
|
||||||
|
struct rtio_work_req {
|
||||||
|
/** Work item used to submit unit of work. */
|
||||||
|
struct k_p4wq_work work;
|
||||||
|
|
||||||
|
/** Handle to IODEV SQE containing the operation.
|
||||||
|
* This is filled inside @ref rtio_work_req_submit.
|
||||||
|
*/
|
||||||
|
struct rtio_iodev_sqe *iodev_sqe;
|
||||||
|
|
||||||
|
/** Callback handler where synchronous operation may be executed.
|
||||||
|
* This is filled inside @ref rtio_work_req_submit.
|
||||||
|
*/
|
||||||
|
rtio_work_submit_t handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate item to perform an RTIO work request.
|
||||||
|
*
|
||||||
|
* @details This allocation utilizes its internal memory slab with
|
||||||
|
* pre-allocated elements.
|
||||||
|
*
|
||||||
|
* @return Pointer to allocated item if successful.
|
||||||
|
* @return NULL if allocation failed.
|
||||||
|
*/
|
||||||
|
struct rtio_work_req *rtio_work_req_alloc(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Submit RTIO work request.
|
||||||
|
*
|
||||||
|
* @param req Item to fill with request information.
|
||||||
|
* @param iodev_sqe RTIO Operation information.
|
||||||
|
* @param handler Callback to handler where work operation is performed.
|
||||||
|
*/
|
||||||
|
void rtio_work_req_submit(struct rtio_work_req *req,
|
||||||
|
struct rtio_iodev_sqe *iodev_sqe,
|
||||||
|
rtio_work_submit_t handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtain number of currently used items from the pre-allocated pool.
|
||||||
|
*
|
||||||
|
* @return Number of used items.
|
||||||
|
*/
|
||||||
|
uint32_t rtio_work_req_used_count_get(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_RTIO_WORKQ_H_ */
|
|
@ -12,3 +12,5 @@ if(CONFIG_RTIO)
|
||||||
zephyr_library_sources(rtio_init.c)
|
zephyr_library_sources(rtio_init.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_handlers.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_handlers.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_RTIO_WORKQ rtio_workq.c)
|
||||||
|
|
|
@ -31,6 +31,8 @@ config RTIO_SYS_MEM_BLOCKS
|
||||||
without a pre-allocated memory buffer. Instead the buffer will be taken
|
without a pre-allocated memory buffer. Instead the buffer will be taken
|
||||||
from the allocated memory pool associated with the RTIO context.
|
from the allocated memory pool associated with the RTIO context.
|
||||||
|
|
||||||
|
rsource "Kconfig.workq"
|
||||||
|
|
||||||
module = RTIO
|
module = RTIO
|
||||||
module-str = RTIO
|
module-str = RTIO
|
||||||
module-help = Sets log level for RTIO support
|
module-help = Sets log level for RTIO support
|
||||||
|
|
34
subsys/rtio/Kconfig.workq
Normal file
34
subsys/rtio/Kconfig.workq
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Copyright (c) 2024 Croxel Inc.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config RTIO_WORKQ
|
||||||
|
bool "RTIO Work-queues service to process Sync operations"
|
||||||
|
select SCHED_DEADLINE
|
||||||
|
select RTIO_CONSUME_SEM
|
||||||
|
help
|
||||||
|
Enable RTIO Work-queues to allow processing synchronous operations
|
||||||
|
in an asynchronous non-blocking fashion.
|
||||||
|
|
||||||
|
if RTIO_WORKQ
|
||||||
|
|
||||||
|
config RTIO_WORKQ_PRIO_MED
|
||||||
|
int "Medium Thread priority of RTIO Work-queues"
|
||||||
|
default MAIN_THREAD_PRIORITY
|
||||||
|
|
||||||
|
config RTIO_WORKQ_STACK_SIZE
|
||||||
|
int "Thread stack-size of RTIO Workqueues"
|
||||||
|
default 2048
|
||||||
|
|
||||||
|
config RTIO_WORKQ_THREADS_POOL
|
||||||
|
int "Number of threads to use for processing work-items"
|
||||||
|
default 1
|
||||||
|
|
||||||
|
config RTIO_WORKQ_POOL_ITEMS
|
||||||
|
int "Pool of work items to use with the RTIO Work-queues"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
Configure the Pool of work items appropriately to your
|
||||||
|
application, the more simultaneous requests you expect
|
||||||
|
to issue, the bigger this pool should be.
|
||||||
|
|
||||||
|
endif # RTIO_WORKQ
|
90
subsys/rtio/rtio_workq.c
Normal file
90
subsys/rtio/rtio_workq.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Croxel Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/rtio/work.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#define RTIO_WORKQ_PRIO_MED CONFIG_RTIO_WORKQ_PRIO_MED
|
||||||
|
#define RTIO_WORKQ_PRIO_HIGH RTIO_WORKQ_PRIO_MED - 1
|
||||||
|
#define RTIO_WORKQ_PRIO_LOW RTIO_WORKQ_PRIO_MED + 1
|
||||||
|
|
||||||
|
K_P4WQ_DEFINE(rtio_workq,
|
||||||
|
CONFIG_RTIO_WORKQ_THREADS_POOL,
|
||||||
|
CONFIG_RTIO_WORKQ_STACK_SIZE);
|
||||||
|
|
||||||
|
K_MEM_SLAB_DEFINE_STATIC(rtio_work_items_slab,
|
||||||
|
sizeof(struct rtio_work_req),
|
||||||
|
CONFIG_RTIO_WORKQ_POOL_ITEMS,
|
||||||
|
4);
|
||||||
|
|
||||||
|
static void rtio_work_handler(struct k_p4wq_work *work)
|
||||||
|
{
|
||||||
|
struct rtio_work_req *req = CONTAINER_OF(work,
|
||||||
|
struct rtio_work_req,
|
||||||
|
work);
|
||||||
|
struct rtio_iodev_sqe *iodev_sqe = req->iodev_sqe;
|
||||||
|
|
||||||
|
req->handler(iodev_sqe);
|
||||||
|
|
||||||
|
k_mem_slab_free(&rtio_work_items_slab, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rtio_work_req *rtio_work_req_alloc(void)
|
||||||
|
{
|
||||||
|
struct rtio_work_req *req;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = k_mem_slab_alloc(&rtio_work_items_slab, (void **)&req, K_NO_WAIT);
|
||||||
|
if (err) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)k_sem_init(&req->work.done_sem, 1, 1);
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtio_work_req_submit(struct rtio_work_req *req,
|
||||||
|
struct rtio_iodev_sqe *iodev_sqe,
|
||||||
|
rtio_work_submit_t handler)
|
||||||
|
{
|
||||||
|
if (!req) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iodev_sqe || !handler) {
|
||||||
|
k_mem_slab_free(&rtio_work_items_slab, req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct k_p4wq_work *work = &req->work;
|
||||||
|
struct rtio_sqe *sqe = &iodev_sqe->sqe;
|
||||||
|
|
||||||
|
/** Link the relevant info so that we can get it on the k_p4wq_work work item.
|
||||||
|
*/
|
||||||
|
req->iodev_sqe = iodev_sqe;
|
||||||
|
req->handler = handler;
|
||||||
|
|
||||||
|
/** Set the required information to handle the action */
|
||||||
|
work->handler = rtio_work_handler;
|
||||||
|
work->deadline = 0;
|
||||||
|
|
||||||
|
if (sqe->prio == RTIO_PRIO_LOW) {
|
||||||
|
work->priority = RTIO_WORKQ_PRIO_LOW;
|
||||||
|
} else if (sqe->prio == RTIO_PRIO_HIGH) {
|
||||||
|
work->priority = RTIO_WORKQ_PRIO_HIGH;
|
||||||
|
} else {
|
||||||
|
work->priority = RTIO_WORKQ_PRIO_MED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decoupling action: Let the P4WQ execute the action. */
|
||||||
|
k_p4wq_submit(&rtio_workq, work);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rtio_work_req_used_count_get(void)
|
||||||
|
{
|
||||||
|
return k_mem_slab_num_used_get(&rtio_work_items_slab);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue