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_MEM_SLAB_DEFINE_STATIC(rtio_work_items_slab,
15 			 sizeof(struct rtio_work_req),
16 			 CONFIG_RTIO_WORKQ_POOL_ITEMS,
17 			 4);
18 
rtio_work_req_done_handler(struct k_p4wq_work * work)19 static void rtio_work_req_done_handler(struct k_p4wq_work *work)
20 {
21 	struct rtio_work_req *req = CONTAINER_OF(work,
22 						 struct rtio_work_req,
23 						 work);
24 	k_mem_slab_free(&rtio_work_items_slab, req);
25 }
26 
27 K_P4WQ_DEFINE_WITH_DONE_HANDLER(rtio_workq,
28 	      CONFIG_RTIO_WORKQ_THREADS_POOL,
29 	      CONFIG_RTIO_WORKQ_STACK_SIZE,
30 		  rtio_work_req_done_handler);
31 
rtio_work_handler(struct k_p4wq_work * work)32 static void rtio_work_handler(struct k_p4wq_work *work)
33 {
34 	struct rtio_work_req *req = CONTAINER_OF(work,
35 						 struct rtio_work_req,
36 						 work);
37 	struct rtio_iodev_sqe *iodev_sqe = req->iodev_sqe;
38 
39 	req->handler(iodev_sqe);
40 }
41 
rtio_work_req_alloc(void)42 struct rtio_work_req *rtio_work_req_alloc(void)
43 {
44 	struct rtio_work_req *req;
45 	int err;
46 
47 	err = k_mem_slab_alloc(&rtio_work_items_slab, (void **)&req, K_NO_WAIT);
48 	if (err) {
49 		return NULL;
50 	}
51 
52 	/** Initialize work item before using it as it comes
53 	 * from a Memory slab (no-init region).
54 	 */
55 	req->work.thread = NULL;
56 	(void)k_sem_init(&req->work.done_sem, 1, 1);
57 
58 	return req;
59 }
60 
rtio_work_req_submit(struct rtio_work_req * req,struct rtio_iodev_sqe * iodev_sqe,rtio_work_submit_t handler)61 void rtio_work_req_submit(struct rtio_work_req *req,
62 			  struct rtio_iodev_sqe *iodev_sqe,
63 			  rtio_work_submit_t handler)
64 {
65 	if (!req) {
66 		return;
67 	}
68 
69 	if (!iodev_sqe || !handler) {
70 		k_mem_slab_free(&rtio_work_items_slab, req);
71 		return;
72 	}
73 
74 	struct k_p4wq_work *work = &req->work;
75 	struct rtio_sqe *sqe = &iodev_sqe->sqe;
76 
77 	/** Link the relevant info so that we can get it on the k_p4wq_work work item.
78 	 */
79 	req->iodev_sqe = iodev_sqe;
80 	req->handler = handler;
81 
82 	/** Set the required information to handle the action */
83 	work->handler = rtio_work_handler;
84 	work->deadline = 0;
85 
86 	if (sqe->prio == RTIO_PRIO_LOW) {
87 		work->priority = RTIO_WORKQ_PRIO_LOW;
88 	} else if (sqe->prio == RTIO_PRIO_HIGH) {
89 		work->priority = RTIO_WORKQ_PRIO_HIGH;
90 	} else {
91 		work->priority = RTIO_WORKQ_PRIO_MED;
92 	}
93 
94 	/** Decoupling action: Let the P4WQ execute the action. */
95 	k_p4wq_submit(&rtio_workq, work);
96 }
97 
rtio_work_req_used_count_get(void)98 uint32_t rtio_work_req_used_count_get(void)
99 {
100 	return k_mem_slab_num_used_get(&rtio_work_items_slab);
101 }
102