1 /*
2  * Copyright (c) 2024 Croxel Inc.
3  * Copyright (c) 2025 Croxel Inc.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/rtio/work.h>
9 #include <zephyr/kernel.h>
10 
11 K_MEM_SLAB_DEFINE_STATIC(rtio_work_items_slab,
12 			 sizeof(struct rtio_work_req),
13 			 CONFIG_RTIO_WORKQ_POOL_ITEMS,
14 			 4);
15 static K_THREAD_STACK_ARRAY_DEFINE(rtio_workq_threads_stack,
16 				   CONFIG_RTIO_WORKQ_THREADS_POOL,
17 				   CONFIG_RTIO_WORKQ_THREADS_POOL_STACK_SIZE);
18 static struct k_thread rtio_work_threads[CONFIG_RTIO_WORKQ_THREADS_POOL];
19 static K_QUEUE_DEFINE(rtio_workq);
20 
rtio_work_req_alloc(void)21 struct rtio_work_req *rtio_work_req_alloc(void)
22 {
23 	struct rtio_work_req *req;
24 	int err;
25 
26 	err = k_mem_slab_alloc(&rtio_work_items_slab, (void **)&req, K_NO_WAIT);
27 	if (err) {
28 		return NULL;
29 	}
30 
31 	return req;
32 }
33 
rtio_work_req_submit(struct rtio_work_req * req,struct rtio_iodev_sqe * iodev_sqe,rtio_work_submit_t handler)34 void rtio_work_req_submit(struct rtio_work_req *req,
35 			  struct rtio_iodev_sqe *iodev_sqe,
36 			  rtio_work_submit_t handler)
37 {
38 	if (!req) {
39 		return;
40 	}
41 
42 	if (!iodev_sqe || !handler) {
43 		k_mem_slab_free(&rtio_work_items_slab, req);
44 		return;
45 	}
46 
47 	req->iodev_sqe = iodev_sqe;
48 	req->handler = handler;
49 
50 	/** For now we're simply treating this as a FIFO queue. It may be
51 	 * desirable to expand this to handle queue ordering based on RTIO
52 	 * SQE priority.
53 	 */
54 	k_queue_append(&rtio_workq, req);
55 }
56 
rtio_work_req_used_count_get(void)57 uint32_t rtio_work_req_used_count_get(void)
58 {
59 	return k_mem_slab_num_used_get(&rtio_work_items_slab);
60 }
61 
rtio_workq_thread_fn(void * arg1,void * arg2,void * arg3)62 static void rtio_workq_thread_fn(void *arg1, void *arg2, void *arg3)
63 {
64 	ARG_UNUSED(arg1);
65 	ARG_UNUSED(arg2);
66 	ARG_UNUSED(arg3);
67 
68 	while (true) {
69 		struct rtio_work_req *req = k_queue_get(&rtio_workq, K_FOREVER);
70 
71 		if (req != NULL) {
72 			req->handler(req->iodev_sqe);
73 
74 			k_mem_slab_free(&rtio_work_items_slab, req);
75 		}
76 	}
77 }
78 
static_init(void)79 static int static_init(void)
80 {
81 	for (size_t i = 0 ; i < ARRAY_SIZE(rtio_work_threads) ; i++) {
82 		k_thread_create(&rtio_work_threads[i],
83 				rtio_workq_threads_stack[i],
84 				CONFIG_RTIO_WORKQ_THREADS_POOL_STACK_SIZE,
85 				rtio_workq_thread_fn,
86 				NULL, NULL, NULL,
87 				CONFIG_RTIO_WORKQ_THREADS_POOL_PRIO,
88 				0,
89 				K_NO_WAIT);
90 	}
91 
92 	return 0;
93 }
94 
95 SYS_INIT(static_init, POST_KERNEL, 1);
96