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