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
rtio_work_handler(struct k_p4wq_work * work)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
rtio_work_req_alloc(void)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 /** Initialize work item before using it as it comes
46 * from a Memory slab (no-init region).
47 */
48 req->work.thread = NULL;
49 (void)k_sem_init(&req->work.done_sem, 1, 1);
50
51 return req;
52 }
53
rtio_work_req_submit(struct rtio_work_req * req,struct rtio_iodev_sqe * iodev_sqe,rtio_work_submit_t handler)54 void rtio_work_req_submit(struct rtio_work_req *req,
55 struct rtio_iodev_sqe *iodev_sqe,
56 rtio_work_submit_t handler)
57 {
58 if (!req) {
59 return;
60 }
61
62 if (!iodev_sqe || !handler) {
63 k_mem_slab_free(&rtio_work_items_slab, req);
64 return;
65 }
66
67 struct k_p4wq_work *work = &req->work;
68 struct rtio_sqe *sqe = &iodev_sqe->sqe;
69
70 /** Link the relevant info so that we can get it on the k_p4wq_work work item.
71 */
72 req->iodev_sqe = iodev_sqe;
73 req->handler = handler;
74
75 /** Set the required information to handle the action */
76 work->handler = rtio_work_handler;
77 work->deadline = 0;
78
79 if (sqe->prio == RTIO_PRIO_LOW) {
80 work->priority = RTIO_WORKQ_PRIO_LOW;
81 } else if (sqe->prio == RTIO_PRIO_HIGH) {
82 work->priority = RTIO_WORKQ_PRIO_HIGH;
83 } else {
84 work->priority = RTIO_WORKQ_PRIO_MED;
85 }
86
87 /** Decoupling action: Let the P4WQ execute the action. */
88 k_p4wq_submit(&rtio_workq, work);
89 }
90
rtio_work_req_used_count_get(void)91 uint32_t rtio_work_req_used_count_get(void)
92 {
93 return k_mem_slab_num_used_get(&rtio_work_items_slab);
94 }
95