Skip to content

Commit 80a0bdb

Browse files
committed
rtio: Introduce OP_DELAY as a valid SQE operation
SQE items with this OP will take the specified amount of time (asynchronously) before completing. This allows to serve as an asynchronous delay in between SQE items (e.g: A sensor measurement requested, which requires 50-ms before having the result available). Signed-off-by: Luis Ubieda <[email protected]>
1 parent f922014 commit 80a0bdb

File tree

5 files changed

+138
-1
lines changed

5 files changed

+138
-1
lines changed

include/zephyr/rtio/rtio.h

+24-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <zephyr/sys/atomic.h>
3636
#include <zephyr/sys/mem_blocks.h>
3737
#include <zephyr/sys/util.h>
38+
#include <zephyr/sys_clock.h>
3839
#include <zephyr/sys/iterable_sections.h>
3940
#include <zephyr/sys/mpsc_lockfree.h>
4041

@@ -336,6 +337,13 @@ struct rtio_sqe {
336337
uint8_t *rx_buf; /**< Buffer to read into */
337338
} txrx;
338339

340+
/** OP_DELAY */
341+
struct {
342+
k_timeout_t timeout; /**< Delay timeout. */
343+
k_timepoint_t deadline; /**< Absolute deadline. Used internally. */
344+
sys_snode_t node; /**< Slist node. Used internally */
345+
} delay;
346+
339347
/** OP_I2C_CONFIGURE */
340348
uint32_t i2c_config;
341349

@@ -540,8 +548,11 @@ struct rtio_iodev {
540548
/** An operation that transceives (reads and writes simultaneously) */
541549
#define RTIO_OP_TXRX (RTIO_OP_CALLBACK+1)
542550

551+
/** An operation that takes a specified amount of time (asynchronously) before completing */
552+
#define RTIO_OP_DELAY (RTIO_OP_TXRX+1)
553+
543554
/** An operation to recover I2C buses */
544-
#define RTIO_OP_I2C_RECOVER (RTIO_OP_TXRX+1)
555+
#define RTIO_OP_I2C_RECOVER (RTIO_OP_DELAY+1)
545556

546557
/** An operation to configure I2C buses */
547558
#define RTIO_OP_I2C_CONFIGURE (RTIO_OP_I2C_RECOVER+1)
@@ -717,6 +728,18 @@ static inline void rtio_sqe_prep_transceive(struct rtio_sqe *sqe,
717728
sqe->userdata = userdata;
718729
}
719730

731+
static inline void rtio_sqe_prep_delay(struct rtio_sqe *sqe,
732+
k_timeout_t timeout,
733+
void *userdata)
734+
{
735+
memset(sqe, 0, sizeof(struct rtio_sqe));
736+
sqe->op = RTIO_OP_DELAY;
737+
sqe->prio = 0;
738+
sqe->iodev = NULL;
739+
sqe->delay.timeout = timeout;
740+
sqe->userdata = userdata;
741+
}
742+
720743
static inline struct rtio_iodev_sqe *rtio_sqe_pool_alloc(struct rtio_sqe_pool *pool)
721744
{
722745
struct mpsc_node *node = mpsc_pop(&pool->free_q);

subsys/rtio/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ if(CONFIG_RTIO)
1010

1111
zephyr_library_sources(rtio_executor.c)
1212
zephyr_library_sources(rtio_init.c)
13+
zephyr_library_sources(rtio_sched.c)
1314
zephyr_library_sources_ifdef(CONFIG_USERSPACE rtio_handlers.c)
1415
endif()
1516

subsys/rtio/rtio_executor.c

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <zephyr/rtio/rtio.h>
88
#include <zephyr/kernel.h>
99

10+
#include "rtio_sched.h"
11+
1012
#include <zephyr/logging/log.h>
1113
LOG_MODULE_REGISTER(rtio_executor, CONFIG_RTIO_LOG_LEVEL);
1214

@@ -22,6 +24,9 @@ static void rtio_executor_op(struct rtio_iodev_sqe *iodev_sqe)
2224
sqe->callback.callback(iodev_sqe->r, sqe, sqe->callback.arg0);
2325
rtio_iodev_sqe_ok(iodev_sqe, 0);
2426
break;
27+
case RTIO_OP_DELAY:
28+
rtio_sched_alarm(iodev_sqe, sqe->delay.timeout);
29+
break;
2530
default:
2631
rtio_iodev_sqe_err(iodev_sqe, -EINVAL);
2732
}

subsys/rtio/rtio_sched.c

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2025 Croxel Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/rtio/rtio.h>
9+
#include <zephyr/spinlock.h>
10+
#include "rtio_sched.h"
11+
12+
static struct k_spinlock rio_sched_lock;
13+
static sys_slist_t rtio_sched_list = SYS_SLIST_STATIC_INIT(&rtio_sched_list);
14+
15+
static inline void add_alarm_to_list(struct rtio_sqe *sqe)
16+
{
17+
struct rtio_sqe *curr_sqe, *prev_sqe = NULL;
18+
19+
/** We assume we have a sorted list: earlier alarms go first */
20+
SYS_SLIST_FOR_EACH_CONTAINER(&rtio_sched_list, curr_sqe, delay.node) {
21+
if (sys_timepoint_cmp(sqe->delay.deadline, curr_sqe->delay.deadline) <= 0) {
22+
sys_slist_insert(&rtio_sched_list,
23+
(prev_sqe ? &prev_sqe->delay.node : NULL),
24+
&sqe->delay.node);
25+
return;
26+
}
27+
prev_sqe = curr_sqe;
28+
}
29+
30+
sys_slist_append(&rtio_sched_list, &sqe->delay.node);
31+
}
32+
33+
static inline void remove_alarm_from_list(struct rtio_sqe *sqe)
34+
{
35+
sys_slist_find_and_remove(&rtio_sched_list, &sqe->delay.node);
36+
}
37+
38+
static inline struct rtio_sqe *get_next_alarm_from_list(void)
39+
{
40+
sys_snode_t *node = sys_slist_peek_head(&rtio_sched_list);
41+
42+
if (node == NULL) {
43+
return NULL;
44+
}
45+
46+
struct rtio_sqe *sqe = CONTAINER_OF(node, struct rtio_sqe, delay.node);
47+
48+
return sqe;
49+
}
50+
51+
static void rtio_sched_alarm_expired(struct k_timer *timer)
52+
{
53+
struct rtio_iodev_sqe *iodev_sqe;
54+
55+
K_SPINLOCK(&rio_sched_lock) {
56+
struct rtio_sqe *sqe = get_next_alarm_from_list();
57+
58+
iodev_sqe = CONTAINER_OF(sqe, struct rtio_iodev_sqe, sqe);
59+
60+
remove_alarm_from_list(sqe);
61+
62+
sqe = get_next_alarm_from_list();
63+
if (sqe != NULL) {
64+
k_timer_start(timer,
65+
sys_timepoint_timeout(sqe->delay.deadline),
66+
K_NO_WAIT);
67+
}
68+
}
69+
70+
rtio_iodev_sqe_ok(iodev_sqe, 0);
71+
}
72+
73+
static K_TIMER_DEFINE(rtio_delay_timer, rtio_sched_alarm_expired, NULL);
74+
75+
void rtio_sched_alarm(struct rtio_iodev_sqe *iodev_sqe, k_timeout_t timeout)
76+
{
77+
struct rtio_sqe *sqe = &iodev_sqe->sqe;
78+
k_timepoint_t *sqe_deadline = &sqe->delay.deadline;
79+
80+
*sqe_deadline = sys_timepoint_calc(timeout);
81+
82+
K_SPINLOCK(&rio_sched_lock) {
83+
struct rtio_sqe *next_sqe;
84+
85+
add_alarm_to_list(sqe);
86+
87+
next_sqe = get_next_alarm_from_list();
88+
89+
/** We assume we have an alarm to schedule, since we just added a new one */
90+
k_timer_start(&rtio_delay_timer,
91+
sys_timepoint_timeout(next_sqe->delay.deadline),
92+
K_NO_WAIT);
93+
}
94+
}

subsys/rtio/rtio_sched.h

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright (c) 2025 Croxel Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
9+
#ifndef ZEPHYR_SUBSYS_RTIO_SCHED_H_
10+
#define ZEPHYR_SUBSYS_RTIO_SCHED_H_
11+
12+
void rtio_sched_alarm(struct rtio_iodev_sqe *iodev_sqe, k_timeout_t timeout);
13+
14+
#endif /* ZEPHYR_SUBSYS_RTIO_SCHED_H_ */

0 commit comments

Comments
 (0)