Sound Open Firmware
Loading...
Searching...
No Matches
ll_schedule_domain.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2019 Intel Corporation. All rights reserved.
4 *
5 * Author: Tomasz Lauda <tomasz.lauda@linux.intel.com>
6 */
7
8#ifndef __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__
9#define __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__
10
11#include <rtos/atomic.h>
12#include <rtos/panic.h>
13#include <rtos/alloc.h>
14#include <sof/lib/cpu.h>
15#include <rtos/clk.h>
16#include <sof/lib/memory.h>
17#include <rtos/sof.h>
18#include <rtos/spinlock.h>
19#include <sof/trace/trace.h>
20#include <ipc/topology.h>
21#include <user/trace.h>
22#include <stdbool.h>
23#include <stdint.h>
24
25#if defined(CONFIG_AMD)
26#define LL_TIMER_PERIOD_US 500ULL /* 500us period for AMD ACP platforms */
27#else
28#define LL_TIMER_PERIOD_US 1000ULL /* default period in microseconds */
29#endif
30
31/* Default ll watchdog timeout in microseconds.
32 * It was decided to have a timeout of two periods to give a safe margin of time between the start
33 * of the watchdog and its first feeding.
34 */
35#define LL_WATCHDOG_TIMEOUT_US (2 * LL_TIMER_PERIOD_US)
36
37
38struct dma;
40struct task;
41struct timer;
42struct comp_dev;
43
45 int (*domain_register)(struct ll_schedule_domain *domain,
46 struct task *task,
47 void (*handler)(void *arg), void *arg);
49 struct task *task, uint32_t num_tasks);
50#if CONFIG_SOF_USERSPACE_LL
51 /*
52 * Initialize the scheduling thread and perform all privileged setup
53 * (thread creation, timer init, access grants). Called once from
54 * kernel context before any user-space domain_register() calls.
55 */
56 int (*domain_thread_init)(struct ll_schedule_domain *domain,
57 struct task *task);
58 /* Free resources acquired by domain_thread_init(). Called from
59 * kernel context when the scheduling context is being torn down.
60 */
61 void (*domain_thread_free)(struct ll_schedule_domain *domain,
62 uint32_t num_tasks);
63#endif
64 void (*domain_enable)(struct ll_schedule_domain *domain, int core);
65 void (*domain_disable)(struct ll_schedule_domain *domain, int core);
66#if CONFIG_CROSS_CORE_STREAM
67 /*
68 * Unlike domain_disable(), these are intended to temporary block LL from
69 * starting its next cycle. Triggering (e.g., by means of timer interrupt)
70 * is still enabled and registered but execution of next cycle is blocked.
71 * Once unblocked, if triggering were previously registered in a blocked
72 * state -- next cycle execution could start immediately.
73 */
74 void (*domain_block)(struct ll_schedule_domain *domain);
75 void (*domain_unblock)(struct ll_schedule_domain *domain);
76#endif
77 void (*domain_set)(struct ll_schedule_domain *domain, uint64_t start);
78 void (*domain_clear)(struct ll_schedule_domain *domain);
79 bool (*domain_is_pending)(struct ll_schedule_domain *domain,
80 struct task *task, struct comp_dev **comp);
81 void (*domain_task_cancel)(struct ll_schedule_domain *domain, struct task *task);
82};
83
85 uint64_t next_tick;
86 uint64_t new_target_tick;
87#ifdef CONFIG_SOF_USERSPACE_LL
88 struct k_mutex *lock;
89#else
90 struct k_spinlock lock;
91#endif
92 atomic_t total_num_tasks;
93 atomic_t enabled_cores;
94 uint32_t ticks_per_ms;
95 int type;
96 int clk;
98 bool full_sync;
99 void *priv_data;
100 bool enabled[CONFIG_CORE_COUNT];
102};
103
104#define ll_sch_domain_set_pdata(domain, data) ((domain)->priv_data = (data))
105
106#define ll_sch_domain_get_pdata(domain) ((domain)->priv_data)
107
108static inline struct ll_schedule_domain *timer_domain_get(void)
109{
111}
112
113static inline struct ll_schedule_domain *dma_domain_get(void)
114{
116}
117
118#ifdef CONFIG_SOF_USERSPACE_LL
119struct task *zephyr_ll_task_alloc(void);
120struct k_heap *zephyr_ll_user_heap(void);
121bool zephyr_ll_user_heap_verify(struct k_heap *heap);
122void zephyr_ll_user_resources_init(void);
123void user_ll_grant_access(struct k_thread *thread, int core);
124void user_ll_lock_sched(int core);
125void user_ll_unlock_sched(int core);
126#ifdef CONFIG_ASSERT
127/* Assert that the calling context already holds the LL lock for 'core'. */
128void user_ll_assert_locked(int core);
129#else
130static inline void user_ll_assert_locked(int core) { ARG_UNUSED(core); }
131#endif
132#endif /* CONFIG_SOF_USERSPACE_LL */
133
134static inline struct ll_schedule_domain *domain_init
135 (int type, int clk, bool synchronous,
136 const struct ll_schedule_domain_ops *ops)
137{
138 struct ll_schedule_domain *domain;
139
140#ifdef CONFIG_SOF_USERSPACE_LL
141 domain = sof_heap_alloc(zephyr_ll_user_heap(), SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT,
142 sizeof(*domain), sizeof(void *));
143 if (domain)
144 memset(domain, 0, sizeof(*domain));
145#else
146 domain = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*domain));
147#endif
148 if (!domain)
149 return NULL;
150 domain->type = type;
151 domain->clk = clk;
152 domain->synchronous = synchronous;
153 domain->full_sync = false;
154#ifdef __ZEPHYR__
155 domain->ticks_per_ms = k_ms_to_cyc_ceil64(1);
156#else
157 domain->ticks_per_ms = clock_ms_to_ticks(clk, 1);
158#endif
159 domain->ops = ops;
160 /* maximum value means no tick has been set to timer */
161 domain->next_tick = UINT64_MAX;
162 domain->new_target_tick = UINT64_MAX;
163
164#ifdef CONFIG_SOF_USERSPACE_LL
165 /* Allocate mutex dynamically for userspace access */
166 domain->lock = k_object_alloc(K_OBJ_MUTEX);
167 if (!domain->lock) {
168 sof_heap_free(zephyr_ll_user_heap(), domain);
169 return NULL;
170 }
171 k_mutex_init(domain->lock);
172#else
173 k_spinlock_init(&domain->lock);
174#endif
175 atomic_init(&domain->total_num_tasks, 0);
176 atomic_init(&domain->enabled_cores, 0);
177
178 return domain;
179}
180
181/* configure the next interrupt for domain */
182static inline void domain_set(struct ll_schedule_domain *domain, uint64_t start)
183{
184 if (domain->ops->domain_set)
185 domain->ops->domain_set(domain, start);
186 else
187 domain->next_tick = start;
188}
189
190/* clear the interrupt for domain */
191static inline void domain_clear(struct ll_schedule_domain *domain)
192{
193 if (domain->ops->domain_clear)
194 domain->ops->domain_clear(domain);
195
196 /* reset to denote no tick/interrupt is set */
197 domain->next_tick = UINT64_MAX;
198}
199
200/* let the domain know that a task has been cancelled */
201static inline void domain_task_cancel(struct ll_schedule_domain *domain,
202 struct task *task)
203{
204 if (domain->ops->domain_task_cancel)
205 domain->ops->domain_task_cancel(domain, task);
206}
207
208#if CONFIG_SOF_USERSPACE_LL
209/*
210 * Initialize the scheduling thread and do all privileged setup.
211 * Must be called from kernel context before user-space tasks register.
212 */
213static inline int domain_thread_init(struct ll_schedule_domain *domain,
214 struct task *task)
215{
216 assert(domain->ops->domain_thread_init);
217
218 return domain->ops->domain_thread_init(domain, task);
219}
220
221/*
222 * Free resources acquired by domain_thread_init().
223 * Must be called from kernel context.
224 */
225static inline void domain_thread_free(struct ll_schedule_domain *domain,
226 uint32_t num_tasks)
227{
228 if (domain->ops->domain_thread_free)
229 domain->ops->domain_thread_free(domain, num_tasks);
230}
231#endif
232
233static inline int domain_register(struct ll_schedule_domain *domain,
234 struct task *task,
235 void (*handler)(void *arg), void *arg)
236{
237 int ret;
238
239 assert(domain->ops->domain_register);
240
241 ret = domain->ops->domain_register(domain, task, handler, arg);
242
243 if (!ret)
244 /* registered one more task, increase the count */
245 atomic_add(&domain->total_num_tasks, 1);
246
247 return ret;
248}
249
250static inline void domain_unregister(struct ll_schedule_domain *domain,
251 struct task *task, uint32_t num_tasks)
252{
253 int ret;
254
255 assert(domain->ops->domain_unregister);
256
257 /* unregistering a task, decrement the count */
258 if (task)
259 atomic_sub(&domain->total_num_tasks, 1);
260
261 /*
262 * In some cases .domain_unregister() might not return, terminating the
263 * current thread, that's why we had to update state before calling it.
264 */
265 ret = domain->ops->domain_unregister(domain, task, num_tasks);
266 if (ret < 0 && task)
267 /* Failed to unregister the domain, restore state */
268 atomic_add(&domain->total_num_tasks, 1);
269}
270
271static inline void domain_enable(struct ll_schedule_domain *domain, int core)
272{
273 if (!domain->enabled[core] && domain->ops->domain_enable) {
274 domain->ops->domain_enable(domain, core);
275 domain->enabled[core] = true;
276 atomic_add(&domain->enabled_cores, 1);
277 }
278}
279
280static inline void domain_disable(struct ll_schedule_domain *domain, int core)
281{
282 if (domain->enabled[core] && domain->ops->domain_disable) {
283 domain->ops->domain_disable(domain, core);
284 domain->enabled[core] = false;
285 atomic_sub(&domain->enabled_cores, 1);
286 }
287}
288
289#if CONFIG_CROSS_CORE_STREAM
290static inline void domain_block(struct ll_schedule_domain *domain)
291{
292 if (domain->ops->domain_block)
293 domain->ops->domain_block(domain);
294}
295
296static inline void domain_unblock(struct ll_schedule_domain *domain)
297{
298 if (domain->ops->domain_unblock)
299 domain->ops->domain_unblock(domain);
300}
301#endif
302
303static inline bool domain_is_pending(struct ll_schedule_domain *domain,
304 struct task *task, struct comp_dev **comp)
305{
306 bool ret;
307
308 assert(domain->ops->domain_is_pending);
309
310 ret = domain->ops->domain_is_pending(domain, task, comp);
311
312 return ret;
313}
314
315
316#ifndef __ZEPHYR__
317struct ll_schedule_domain *timer_domain_init(struct timer *timer, int clk);
318#else
319#if CONFIG_DMA_DOMAIN
320#define dma_multi_chan_domain_init(dma_array, num_dma, clk, aggregated_irq)\
321 zephyr_dma_domain_init(dma_array, num_dma, clk)
322struct ll_schedule_domain *zephyr_dma_domain_init(struct dma *dma_array,
323 uint32_t num_dma,
324 int clk);
325#endif /* CONFIG_DMA_DOMAIN */
326struct ll_schedule_domain *zephyr_ll_domain(void);
327struct ll_schedule_domain *zephyr_domain_init(int clk);
328#define timer_domain_init(timer, clk) zephyr_domain_init(clk)
329#ifdef CONFIG_SOF_USERSPACE_LL
330struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain);
331struct k_thread *zephyr_domain_thread_tid_for_core(int core);
332struct k_mem_domain *zephyr_ll_mem_domain(void);
333#endif /* CONFIG_SOF_USERSPACE_LL */
334#ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION
335__syscall int zephyr_ll_task_sem_alloc(struct task *task);
336__syscall int zephyr_ll_task_sem_free(struct task *task);
337#include <zephyr/syscalls/ll_schedule_domain.h>
338#else
339int z_impl_zephyr_ll_task_sem_alloc(struct task *task);
340int z_impl_zephyr_ll_task_sem_free(struct task *task);
341#define zephyr_ll_task_sem_alloc z_impl_zephyr_ll_task_sem_alloc
342#define zephyr_ll_task_sem_free z_impl_zephyr_ll_task_sem_free
343#endif /* CONFIG_SOF_FULL_ZEPHYR_APPLICATION */
344#endif /* __ZEPHYR__ */
345
347 uint32_t num_dma, int clk,
348 bool aggregated_irq);
349
351 uint32_t num_dma,
352 int clk);
353
354#endif /* __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__ */
#define atomic_init(p, v)
Definition atomic.h:18
CPU header file.
void * rzalloc(uint32_t flags, size_t bytes)
Similar to rmalloc(), guarantees that returned block is zeroed.
void * sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, size_t alignment)
#define SOF_MEM_FLAG_USER
Allocate user memory address.
Definition alloc.h:45
#define SOF_MEM_FLAG_KERNEL
Allocate kernel memory address.
Definition alloc.h:43
#define SOF_MEM_FLAG_COHERENT
Allocate uncached address.
Definition alloc.h:37
void sof_heap_free(struct k_heap *heap, void *addr)
static void domain_task_cancel(struct ll_schedule_domain *domain, struct task *task)
Definition ll_schedule_domain.h:201
static void domain_unregister(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks)
Definition ll_schedule_domain.h:250
static void domain_disable(struct ll_schedule_domain *domain, int core)
Definition ll_schedule_domain.h:280
static struct ll_schedule_domain * dma_domain_get(void)
Definition ll_schedule_domain.h:113
struct ll_schedule_domain * timer_domain_init(struct timer *timer, int clk)
struct ll_schedule_domain * dma_multi_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk, bool aggregated_irq)
struct ll_schedule_domain * dma_single_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk)
static void domain_clear(struct ll_schedule_domain *domain)
Definition ll_schedule_domain.h:191
static struct ll_schedule_domain * domain_init(int type, int clk, bool synchronous, const struct ll_schedule_domain_ops *ops)
Definition ll_schedule_domain.h:135
static bool domain_is_pending(struct ll_schedule_domain *domain, struct task *task, struct comp_dev **comp)
Definition ll_schedule_domain.h:303
static void domain_enable(struct ll_schedule_domain *domain, int core)
Definition ll_schedule_domain.h:271
static struct ll_schedule_domain * timer_domain_get(void)
Definition ll_schedule_domain.h:108
static int domain_register(struct ll_schedule_domain *domain, struct task *task, void(*handler)(void *arg), void *arg)
Definition ll_schedule_domain.h:233
static void domain_set(struct ll_schedule_domain *domain, uint64_t start)
Definition ll_schedule_domain.h:182
#define assert(x)
Definition panic.h:19
struct sof * sof_get(void)
static void k_spinlock_init(struct k_spinlock *lock)
Definition spinlock.h:13
Audio component base device "class".
Definition component.h:645
Definition dma.h:209
Definition ll_schedule_domain.h:44
void(* domain_task_cancel)(struct ll_schedule_domain *domain, struct task *task)
Definition ll_schedule_domain.h:81
bool(* domain_is_pending)(struct ll_schedule_domain *domain, struct task *task, struct comp_dev **comp)
Definition ll_schedule_domain.h:79
void(* domain_clear)(struct ll_schedule_domain *domain)
Definition ll_schedule_domain.h:78
void(* domain_disable)(struct ll_schedule_domain *domain, int core)
Definition ll_schedule_domain.h:65
int(* domain_register)(struct ll_schedule_domain *domain, struct task *task, void(*handler)(void *arg), void *arg)
Definition ll_schedule_domain.h:45
int(* domain_unregister)(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks)
Definition ll_schedule_domain.h:48
void(* domain_set)(struct ll_schedule_domain *domain, uint64_t start)
Definition ll_schedule_domain.h:77
void(* domain_enable)(struct ll_schedule_domain *domain, int core)
Definition ll_schedule_domain.h:64
Definition ll_schedule_domain.h:84
atomic_t enabled_cores
number of enabled cores
Definition ll_schedule_domain.h:93
uint32_t ticks_per_ms
number of clock ticks per ms
Definition ll_schedule_domain.h:94
bool full_sync
tasks should be full synchronous, no time dependent
Definition ll_schedule_domain.h:98
bool synchronous
are tasks should be synchronous
Definition ll_schedule_domain.h:97
atomic_t total_num_tasks
total number of registered tasks
Definition ll_schedule_domain.h:92
struct k_spinlock lock
standard lock
Definition ll_schedule_domain.h:90
void * priv_data
pointer to private data
Definition ll_schedule_domain.h:99
int type
domain type
Definition ll_schedule_domain.h:95
bool enabled[CONFIG_CORE_COUNT]
enabled cores
Definition ll_schedule_domain.h:100
uint64_t next_tick
ticks just set for next run
Definition ll_schedule_domain.h:85
int clk
source clock
Definition ll_schedule_domain.h:96
const struct ll_schedule_domain_ops * ops
domain ops
Definition ll_schedule_domain.h:101
uint64_t new_target_tick
for the next set, used during the reschedule stage
Definition ll_schedule_domain.h:86
struct ll_schedule_domain * platform_timer_domain
Definition sof.h:67
struct ll_schedule_domain * platform_dma_domain
Definition sof.h:70
Task used by schedulers.
Definition task.h:56
uint32_t type
Definition tlv.h:0