Skip to content

Commit 3646b63

Browse files
ubiedanashif
authored andcommitted
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 <[email protected]>
1 parent 1f3a091 commit 3646b63

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

include/zephyr/rtio/work.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2024 Croxel Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_RTIO_WORKQ_H_
8+
#define ZEPHYR_INCLUDE_RTIO_WORKQ_H_
9+
10+
#include <stdint.h>
11+
#include <zephyr/device.h>
12+
#include <zephyr/rtio/rtio.h>
13+
#include <zephyr/sys/p4wq.h>
14+
15+
#ifdef __cplusplus
16+
extern "C" {
17+
#endif
18+
19+
/**
20+
* @brief Callback API to execute work operation.
21+
*
22+
* @param iodev_sqe Associated SQE operation.
23+
*/
24+
typedef void (*rtio_work_submit_t)(struct rtio_iodev_sqe *iodev_sqe);
25+
26+
/**
27+
* @brief RTIO Work request.
28+
*
29+
* This RTIO Work request to perform a work operation decoupled
30+
* from its submission in the RTIO work-queues.
31+
*/
32+
struct rtio_work_req {
33+
/** Work item used to submit unit of work. */
34+
struct k_p4wq_work work;
35+
36+
/** Handle to IODEV SQE containing the operation.
37+
* This is filled inside @ref rtio_work_req_submit.
38+
*/
39+
struct rtio_iodev_sqe *iodev_sqe;
40+
41+
/** Callback handler where synchronous operation may be executed.
42+
* This is filled inside @ref rtio_work_req_submit.
43+
*/
44+
rtio_work_submit_t handler;
45+
};
46+
47+
/**
48+
* @brief Allocate item to perform an RTIO work request.
49+
*
50+
* @details This allocation utilizes its internal memory slab with
51+
* pre-allocated elements.
52+
*
53+
* @return Pointer to allocated item if successful.
54+
* @return NULL if allocation failed.
55+
*/
56+
struct rtio_work_req *rtio_work_req_alloc(void);
57+
58+
/**
59+
* @brief Submit RTIO work request.
60+
*
61+
* @param req Item to fill with request information.
62+
* @param iodev_sqe RTIO Operation information.
63+
* @param handler Callback to handler where work operation is performed.
64+
*/
65+
void rtio_work_req_submit(struct rtio_work_req *req,
66+
struct rtio_iodev_sqe *iodev_sqe,
67+
rtio_work_submit_t handler);
68+
69+
/**
70+
* @brief Obtain number of currently used items from the pre-allocated pool.
71+
*
72+
* @return Number of used items.
73+
*/
74+
uint32_t rtio_work_req_used_count_get(void);
75+
76+
#ifdef __cplusplus
77+
}
78+
#endif
79+
80+
#endif /* ZEPHYR_INCLUDE_RTIO_WORKQ_H_ */

subsys/rtio/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ if(CONFIG_RTIO)
1212
zephyr_library_sources(rtio_init.c)
1313
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_handlers.c)
1414
endif()
15+
16+
zephyr_library_sources_ifdef(CONFIG_RTIO_WORKQ rtio_workq.c)

subsys/rtio/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ config RTIO_SYS_MEM_BLOCKS
3131
without a pre-allocated memory buffer. Instead the buffer will be taken
3232
from the allocated memory pool associated with the RTIO context.
3333

34+
rsource "Kconfig.workq"
35+
3436
module = RTIO
3537
module-str = RTIO
3638
module-help = Sets log level for RTIO support

subsys/rtio/Kconfig.workq

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright (c) 2024 Croxel Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config RTIO_WORKQ
5+
bool "RTIO Work-queues service to process Sync operations"
6+
select SCHED_DEADLINE
7+
select RTIO_CONSUME_SEM
8+
help
9+
Enable RTIO Work-queues to allow processing synchronous operations
10+
in an asynchronous non-blocking fashion.
11+
12+
if RTIO_WORKQ
13+
14+
config RTIO_WORKQ_PRIO_MED
15+
int "Medium Thread priority of RTIO Work-queues"
16+
default MAIN_THREAD_PRIORITY
17+
18+
config RTIO_WORKQ_STACK_SIZE
19+
int "Thread stack-size of RTIO Workqueues"
20+
default 2048
21+
22+
config RTIO_WORKQ_THREADS_POOL
23+
int "Number of threads to use for processing work-items"
24+
default 1
25+
26+
config RTIO_WORKQ_POOL_ITEMS
27+
int "Pool of work items to use with the RTIO Work-queues"
28+
default 4
29+
help
30+
Configure the Pool of work items appropriately to your
31+
application, the more simultaneous requests you expect
32+
to issue, the bigger this pool should be.
33+
34+
endif # RTIO_WORKQ

subsys/rtio/rtio_workq.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2024 Croxel Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/rtio/work.h>
8+
#include <zephyr/kernel.h>
9+
10+
#define RTIO_WORKQ_PRIO_MED CONFIG_RTIO_WORKQ_PRIO_MED
11+
#define RTIO_WORKQ_PRIO_HIGH RTIO_WORKQ_PRIO_MED - 1
12+
#define RTIO_WORKQ_PRIO_LOW RTIO_WORKQ_PRIO_MED + 1
13+
14+
K_P4WQ_DEFINE(rtio_workq,
15+
CONFIG_RTIO_WORKQ_THREADS_POOL,
16+
CONFIG_RTIO_WORKQ_STACK_SIZE);
17+
18+
K_MEM_SLAB_DEFINE_STATIC(rtio_work_items_slab,
19+
sizeof(struct rtio_work_req),
20+
CONFIG_RTIO_WORKQ_POOL_ITEMS,
21+
4);
22+
23+
static void rtio_work_handler(struct k_p4wq_work *work)
24+
{
25+
struct rtio_work_req *req = CONTAINER_OF(work,
26+
struct rtio_work_req,
27+
work);
28+
struct rtio_iodev_sqe *iodev_sqe = req->iodev_sqe;
29+
30+
req->handler(iodev_sqe);
31+
32+
k_mem_slab_free(&rtio_work_items_slab, req);
33+
}
34+
35+
struct rtio_work_req *rtio_work_req_alloc(void)
36+
{
37+
struct rtio_work_req *req;
38+
int err;
39+
40+
err = k_mem_slab_alloc(&rtio_work_items_slab, (void **)&req, K_NO_WAIT);
41+
if (err) {
42+
return NULL;
43+
}
44+
45+
(void)k_sem_init(&req->work.done_sem, 1, 1);
46+
47+
return req;
48+
}
49+
50+
void rtio_work_req_submit(struct rtio_work_req *req,
51+
struct rtio_iodev_sqe *iodev_sqe,
52+
rtio_work_submit_t handler)
53+
{
54+
if (!req) {
55+
return;
56+
}
57+
58+
if (!iodev_sqe || !handler) {
59+
k_mem_slab_free(&rtio_work_items_slab, req);
60+
return;
61+
}
62+
63+
struct k_p4wq_work *work = &req->work;
64+
struct rtio_sqe *sqe = &iodev_sqe->sqe;
65+
66+
/** Link the relevant info so that we can get it on the k_p4wq_work work item.
67+
*/
68+
req->iodev_sqe = iodev_sqe;
69+
req->handler = handler;
70+
71+
/** Set the required information to handle the action */
72+
work->handler = rtio_work_handler;
73+
work->deadline = 0;
74+
75+
if (sqe->prio == RTIO_PRIO_LOW) {
76+
work->priority = RTIO_WORKQ_PRIO_LOW;
77+
} else if (sqe->prio == RTIO_PRIO_HIGH) {
78+
work->priority = RTIO_WORKQ_PRIO_HIGH;
79+
} else {
80+
work->priority = RTIO_WORKQ_PRIO_MED;
81+
}
82+
83+
/** Decoupling action: Let the P4WQ execute the action. */
84+
k_p4wq_submit(&rtio_workq, work);
85+
}
86+
87+
uint32_t rtio_work_req_used_count_get(void)
88+
{
89+
return k_mem_slab_num_used_get(&rtio_work_items_slab);
90+
}

0 commit comments

Comments
 (0)