1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019 Intel Corporation. All rights reserved.
4 //
5 // Author: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
6 
7 #include <sof/audio/component.h>
8 #include <sof/schedule/task.h>
9 #include <stdint.h>
10 #include <sof/schedule/edf_schedule.h>
11 #include <sof/lib/wait.h>
12 
13 #include <kernel.h>
14 #include <sys_clock.h>
15 
16 struct k_work_q edf_workq;
17 K_THREAD_STACK_DEFINE(edf_workq_stack, 8192);
18 
19 /*
20  * since only IPC is using the EDF scheduler - we schedule the work in the
21  * next timer_domain time slice
22  */
23 #define EDF_SCHEDULE_DELAY	0
24 
edf_work_handler(struct k_work * work)25 static void edf_work_handler(struct k_work *work)
26 {
27 	struct task *task = CONTAINER_OF(work, struct task, z_delayed_work);
28 
29 	task->state = SOF_TASK_STATE_RUNNING;
30 	task_run(task);
31 
32 	task_complete(task);
33 	task->state = SOF_TASK_STATE_COMPLETED;
34 }
35 
36 /* schedule task */
schedule_edf_task(void * data,struct task * task,uint64_t start,uint64_t period)37 static int schedule_edf_task(void *data, struct task *task, uint64_t start,
38 			     uint64_t period)
39 {
40 	/* start time is microseconds from now */
41 	k_timeout_t start_time = K_USEC(start + EDF_SCHEDULE_DELAY);
42 
43 	k_work_reschedule_for_queue(&edf_workq,
44 				       &task->z_delayed_work,
45 					   start_time);
46 
47 	task->state = SOF_TASK_STATE_QUEUED;
48 	return 0;
49 }
50 
schedule_edf_task_cancel(void * data,struct task * task)51 static int schedule_edf_task_cancel(void *data, struct task *task)
52 {
53 	if (task->state == SOF_TASK_STATE_QUEUED) {
54 		k_work_cancel_delayable(&task->z_delayed_work);
55 
56 		/* delete task */
57 		task->state = SOF_TASK_STATE_CANCEL;
58 	}
59 
60 	return 0;
61 }
62 
schedule_edf_task_complete(void * data,struct task * task)63 static int schedule_edf_task_complete(void *data, struct task *task)
64 {
65 	task_complete(task);
66 	return 0;
67 }
68 
schedule_edf_task_running(void * data,struct task * task)69 static int schedule_edf_task_running(void *data, struct task *task)
70 {
71 	task->state = SOF_TASK_STATE_RUNNING;
72 	return 0;
73 }
74 
schedule_edf_task_free(void * data,struct task * task)75 static int schedule_edf_task_free(void *data, struct task *task)
76 {
77 	task->state = SOF_TASK_STATE_FREE;
78 	task->ops.run = NULL;
79 	task->data = NULL;
80 
81 	return 0;
82 }
83 
84 static struct scheduler_ops schedule_edf_ops = {
85 	.schedule_task		= schedule_edf_task,
86 	.schedule_task_running	= schedule_edf_task_running,
87 	.schedule_task_complete = schedule_edf_task_complete,
88 	.schedule_task_cancel	= schedule_edf_task_cancel,
89 	.schedule_task_free	= schedule_edf_task_free,
90 };
91 
scheduler_init_edf(void)92 int scheduler_init_edf(void)
93 {
94 	struct k_thread *thread = &edf_workq.thread;
95 
96 	scheduler_init(SOF_SCHEDULE_EDF, &schedule_edf_ops, NULL);
97 
98 	k_work_queue_start(&edf_workq,
99 		       edf_workq_stack,
100 		       K_THREAD_STACK_SIZEOF(edf_workq_stack),
101 		       1, NULL);
102 
103 	k_thread_suspend(thread);
104 
105 	k_thread_cpu_mask_clear(thread);
106 	k_thread_cpu_mask_enable(thread, PLATFORM_PRIMARY_CORE_ID);
107 	k_thread_name_set(thread, "edf_workq");
108 
109 	k_thread_resume(thread);
110 
111 	return 0;
112 }
113 
schedule_task_init_edf(struct task * task,const struct sof_uuid_entry * uid,const struct task_ops * ops,void * data,uint16_t core,uint32_t flags)114 int schedule_task_init_edf(struct task *task, const struct sof_uuid_entry *uid,
115 			   const struct task_ops *ops,
116 			   void *data, uint16_t core, uint32_t flags)
117 {
118 	int ret;
119 
120 	ret = schedule_task_init(task, uid, SOF_SCHEDULE_EDF, 0, ops->run, data,
121 				 core, flags);
122 	if (ret < 0)
123 		return ret;
124 
125 	task->ops = *ops;
126 
127 	k_work_init_delayable(&task->z_delayed_work, edf_work_handler);
128 
129 	return 0;
130 }
131 
schedule_task_init_edf_with_budget(struct task * task,const struct sof_uuid_entry * uid,const struct task_ops * ops,void * data,uint16_t core,uint32_t flags,uint32_t cycles_budget)132 int schedule_task_init_edf_with_budget(struct task *task,
133 				       const struct sof_uuid_entry *uid,
134 				       const struct task_ops *ops,
135 				       void *data, uint16_t core,
136 				       uint32_t flags, uint32_t cycles_budget)
137 {
138 	return schedule_task_init_edf(task, uid, ops, data, core, flags);
139 }
140