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
14#ifndef __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__
15#define __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__
16
17#include <rtos/atomic.h>
18#include <rtos/panic.h>
19#include <rtos/alloc.h>
20#include <sof/lib/cpu.h>
21#include <rtos/clk.h>
22#include <sof/lib/memory.h>
23#include <rtos/sof.h>
24#include <rtos/spinlock.h>
25#include <sof/trace/trace.h>
26#include <ipc/topology.h>
27#include <user/trace.h>
28#include <stdbool.h>
29#include <stdint.h>
30
35#if defined(CONFIG_AMD)
37#define LL_TIMER_PERIOD_US 500ULL
38#else
40#define LL_TIMER_PERIOD_US 1000ULL
41#endif
42
49#define LL_WATCHDOG_TIMEOUT_US (2 * LL_TIMER_PERIOD_US)
50
51struct dma;
53struct task;
54struct timer;
55struct comp_dev;
56
71 int (*domain_register)(struct ll_schedule_domain *domain,
72 struct task *task,
73 void (*handler)(void *arg), void *arg);
74
83 struct task *task, uint32_t num_tasks);
84
85#if CONFIG_SOF_USERSPACE_LL
94 int (*domain_thread_init)(struct ll_schedule_domain *domain,
95 struct task *task);
96
102 void (*domain_thread_free)(struct ll_schedule_domain *domain,
103 uint32_t num_tasks);
104#endif
105
111 void (*domain_enable)(struct ll_schedule_domain *domain, int core);
112
118 void (*domain_disable)(struct ll_schedule_domain *domain, int core);
119
120#if CONFIG_CROSS_CORE_STREAM
125 void (*domain_block)(struct ll_schedule_domain *domain);
126
131 void (*domain_unblock)(struct ll_schedule_domain *domain);
132#endif
133
139 void (*domain_set)(struct ll_schedule_domain *domain, uint64_t start);
140
145 void (*domain_clear)(struct ll_schedule_domain *domain);
146
154 bool (*domain_is_pending)(struct ll_schedule_domain *domain,
155 struct task *task, struct comp_dev **comp);
156
162 void (*domain_task_cancel)(struct ll_schedule_domain *domain, struct task *task);
163};
164
169 uint64_t next_tick;
171#ifdef CONFIG_SOF_USERSPACE_LL
172 struct k_mutex *lock;
173#else
174 struct k_spinlock lock;
175#endif
177 atomic_t enabled_cores;
178 uint32_t ticks_per_ms;
179 int type;
180 int clk;
183 void *priv_data;
184 bool enabled[CONFIG_CORE_COUNT];
186};
187
193#define ll_sch_domain_set_pdata(domain, data) ((domain)->priv_data = (data))
194
200#define ll_sch_domain_get_pdata(domain) ((domain)->priv_data)
201
206static inline struct ll_schedule_domain *timer_domain_get(void)
207{
209}
210
215static inline struct ll_schedule_domain *dma_domain_get(void)
216{
218}
219
220#ifdef CONFIG_SOF_USERSPACE_LL
225struct task *zephyr_ll_task_alloc(void);
226
231struct k_heap *zephyr_ll_user_heap(void);
232
238bool zephyr_ll_user_heap_verify(struct k_heap *heap);
239
243void zephyr_ll_user_resources_init(void);
244
250void user_ll_grant_access(struct k_thread *thread, int core);
251
256void user_ll_lock_sched(int core);
257
262void user_ll_unlock_sched(int core);
263
264#ifdef CONFIG_ASSERT
269void user_ll_assert_locked(int core);
270#else
271static inline void user_ll_assert_locked(int core) { ARG_UNUSED(core); }
272#endif
273#endif /* CONFIG_SOF_USERSPACE_LL */
274
287static inline struct ll_schedule_domain *domain_init
288 (int type, int clk, bool synchronous,
289 const struct ll_schedule_domain_ops *ops)
290{
291 struct ll_schedule_domain *domain;
292
293#ifdef CONFIG_SOF_USERSPACE_LL
294 domain = sof_heap_alloc(zephyr_ll_user_heap(), SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT,
295 sizeof(*domain), sizeof(void *));
296 if (domain)
297 memset(domain, 0, sizeof(*domain));
298#else
299 domain = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*domain));
300#endif
301 if (!domain)
302 return NULL;
303 domain->type = type;
304 domain->clk = clk;
305 domain->synchronous = synchronous;
306 domain->full_sync = false;
307#ifdef __ZEPHYR__
308 domain->ticks_per_ms = k_ms_to_cyc_ceil64(1);
309#else
310 domain->ticks_per_ms = clock_ms_to_ticks(clk, 1);
311#endif
312 domain->ops = ops;
313 /* maximum value means no tick has been set to timer */
314 domain->next_tick = UINT64_MAX;
315 domain->new_target_tick = UINT64_MAX;
316
317#ifdef CONFIG_SOF_USERSPACE_LL
318 /* Allocate mutex dynamically for userspace access */
319 domain->lock = k_object_alloc(K_OBJ_MUTEX);
320 if (!domain->lock) {
321 sof_heap_free(zephyr_ll_user_heap(), domain);
322 return NULL;
323 }
324 k_mutex_init(domain->lock);
325#else
326 k_spinlock_init(&domain->lock);
327#endif
328 atomic_init(&domain->total_num_tasks, 0);
329 atomic_init(&domain->enabled_cores, 0);
330
331 return domain;
332}
333
339static inline void domain_set(struct ll_schedule_domain *domain, uint64_t start)
340{
341 if (domain->ops->domain_set)
342 domain->ops->domain_set(domain, start);
343 else
344 domain->next_tick = start;
345}
346
351static inline void domain_clear(struct ll_schedule_domain *domain)
352{
353 if (domain->ops->domain_clear)
354 domain->ops->domain_clear(domain);
355
356 /* reset to denote no tick/interrupt is set */
357 domain->next_tick = UINT64_MAX;
358}
359
365static inline void domain_task_cancel(struct ll_schedule_domain *domain,
366 struct task *task)
367{
368 if (domain->ops->domain_task_cancel)
369 domain->ops->domain_task_cancel(domain, task);
370}
371
372#if CONFIG_SOF_USERSPACE_LL
382static inline int domain_thread_init(struct ll_schedule_domain *domain,
383 struct task *task)
384{
385 assert(domain->ops->domain_thread_init);
386
387 return domain->ops->domain_thread_init(domain, task);
388}
389
398static inline void domain_thread_free(struct ll_schedule_domain *domain,
399 uint32_t num_tasks)
400{
401 if (domain->ops->domain_thread_free)
402 domain->ops->domain_thread_free(domain, num_tasks);
403}
404#endif
405
414static inline int domain_register(struct ll_schedule_domain *domain,
415 struct task *task,
416 void (*handler)(void *arg), void *arg)
417{
418 int ret;
419
420 assert(domain->ops->domain_register);
421
422 ret = domain->ops->domain_register(domain, task, handler, arg);
423
424 if (!ret)
425 /* registered one more task, increase the count */
426 atomic_add(&domain->total_num_tasks, 1);
427
428 return ret;
429}
430
437static inline void domain_unregister(struct ll_schedule_domain *domain,
438 struct task *task, uint32_t num_tasks)
439{
440 int ret;
441
442 assert(domain->ops->domain_unregister);
443
444 /* unregistering a task, decrement the count */
445 if (task)
446 atomic_sub(&domain->total_num_tasks, 1);
447
448 /*
449 * In some cases .domain_unregister() might not return, terminating the
450 * current thread, that's why we had to update state before calling it.
451 */
452 ret = domain->ops->domain_unregister(domain, task, num_tasks);
453 if (ret < 0 && task)
454 /* Failed to unregister the domain, restore state */
455 atomic_add(&domain->total_num_tasks, 1);
456}
457
463static inline void domain_enable(struct ll_schedule_domain *domain, int core)
464{
465 if (!domain->enabled[core] && domain->ops->domain_enable) {
466 domain->ops->domain_enable(domain, core);
467 domain->enabled[core] = true;
468 atomic_add(&domain->enabled_cores, 1);
469 }
470}
471
477static inline void domain_disable(struct ll_schedule_domain *domain, int core)
478{
479 if (domain->enabled[core] && domain->ops->domain_disable) {
480 domain->ops->domain_disable(domain, core);
481 domain->enabled[core] = false;
482 atomic_sub(&domain->enabled_cores, 1);
483 }
484}
485
486#if CONFIG_CROSS_CORE_STREAM
491static inline void domain_block(struct ll_schedule_domain *domain)
492{
493 if (domain->ops->domain_block)
494 domain->ops->domain_block(domain);
495}
496
501static inline void domain_unblock(struct ll_schedule_domain *domain)
502{
503 if (domain->ops->domain_unblock)
504 domain->ops->domain_unblock(domain);
505}
506#endif
507
515static inline bool domain_is_pending(struct ll_schedule_domain *domain,
516 struct task *task, struct comp_dev **comp)
517{
518 bool ret;
519
520 assert(domain->ops->domain_is_pending);
521
522 ret = domain->ops->domain_is_pending(domain, task, comp);
523
524 return ret;
525}
526
527
528#ifndef __ZEPHYR__
535struct ll_schedule_domain *timer_domain_init(struct timer *timer, int clk);
536#else
537#if CONFIG_DMA_DOMAIN
538#define dma_multi_chan_domain_init(dma_array, num_dma, clk, aggregated_irq)\
539 zephyr_dma_domain_init(dma_array, num_dma, clk)
547struct ll_schedule_domain *zephyr_dma_domain_init(struct dma *dma_array,
548 uint32_t num_dma,
549 int clk);
550#endif /* CONFIG_DMA_DOMAIN */
551
557
564
565#define timer_domain_init(timer, clk) zephyr_domain_init(clk)
566
567#ifdef CONFIG_SOF_USERSPACE_LL
573struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain);
574
580struct k_thread *zephyr_domain_thread_tid_for_core(int core);
581
586struct k_mem_domain *zephyr_ll_mem_domain(void);
587
592struct k_thread *zephyr_ll_domain_thread(void);
593#endif /* CONFIG_SOF_USERSPACE_LL */
594
595#ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION
601__syscall int zephyr_ll_task_sem_alloc(struct task *task);
602
608__syscall int zephyr_ll_task_sem_free(struct task *task);
609#include <zephyr/syscalls/ll_schedule_domain.h>
610#else
611int z_impl_zephyr_ll_task_sem_alloc(struct task *task);
612int z_impl_zephyr_ll_task_sem_free(struct task *task);
613#define zephyr_ll_task_sem_alloc z_impl_zephyr_ll_task_sem_alloc
614#define zephyr_ll_task_sem_free z_impl_zephyr_ll_task_sem_free
615#endif /* CONFIG_SOF_FULL_ZEPHYR_APPLICATION */
616#endif /* __ZEPHYR__ */
617
627 uint32_t num_dma, int clk,
628 bool aggregated_irq);
629
638 uint32_t num_dma,
639 int clk);
640
643#endif /* __SOF_SCHEDULE_LL_SCHEDULE_DOMAIN_H__ */
Memory allocation API, zones, heaps, and alignment utilities.
#define atomic_init(p, v)
Definition atomic.h:18
RTOS DSP clock frequency management and notification interfaces.
CPU header file.
void * rzalloc(uint32_t flags, size_t bytes)
Allocate zero-initialized memory block with default natural alignment.
void * sof_heap_alloc(struct k_heap *heap, uint32_t flags, size_t bytes, size_t alignment)
Allocate memory from a specified Zephyr heap or default system heap.
#define SOF_MEM_FLAG_USER
Base allocation flag denoting memory allocated for user-space threads and module execution.
Definition alloc.h:69
#define SOF_MEM_FLAG_KERNEL
Base allocation flag denoting memory allocated for kernel-space data structures.
Definition alloc.h:67
#define SOF_MEM_FLAG_COHERENT
Allocate uncached / coherent memory address.
Definition alloc.h:53
void sof_heap_free(struct k_heap *heap, void *addr)
Free memory allocated via sof_heap_alloc().
struct ll_schedule_domain * zephyr_ll_domain(void)
Retrieve the global Low-Latency timer scheduling domain descriptor on Zephyr.
static void domain_task_cancel(struct ll_schedule_domain *domain, struct task *task)
Notify the domain that a task has been cancelled.
Definition ll_schedule_domain.h:365
int zephyr_ll_task_sem_alloc(struct task *task)
Allocate a completion semaphore for a Low-Latency task.
static void domain_unregister(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks)
Unregister a real-time task from the scheduling domain.
Definition ll_schedule_domain.h:437
struct ll_schedule_domain * zephyr_domain_init(int clk)
Initialize the primary timer-driven Low-Latency scheduling domain on Zephyr.
static void domain_disable(struct ll_schedule_domain *domain, int core)
Disable Low-Latency scheduling domain execution on the specified core.
Definition ll_schedule_domain.h:477
static struct ll_schedule_domain * dma_domain_get(void)
Get the primary platform DMA scheduling domain.
Definition ll_schedule_domain.h:215
struct ll_schedule_domain * dma_multi_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk, bool aggregated_irq)
Initialize multi-channel DMA scheduling domain.
struct ll_schedule_domain * dma_single_chan_domain_init(struct dma *dma_array, uint32_t num_dma, int clk)
Initialize single-channel DMA scheduling domain.
static void domain_clear(struct ll_schedule_domain *domain)
Clear/disarm the interrupt tick for the domain.
Definition ll_schedule_domain.h:351
#define timer_domain_init(timer, clk)
Definition ll_schedule_domain.h:565
static struct ll_schedule_domain * domain_init(int type, int clk, bool synchronous, const struct ll_schedule_domain_ops *ops)
Initialize a Low-Latency scheduling domain descriptor.
Definition ll_schedule_domain.h:288
int zephyr_ll_task_sem_free(struct task *task)
Free a completion semaphore for a Low-Latency task.
static bool domain_is_pending(struct ll_schedule_domain *domain, struct task *task, struct comp_dev **comp)
Query whether a task in the domain has pending execution work.
Definition ll_schedule_domain.h:515
static void domain_enable(struct ll_schedule_domain *domain, int core)
Enable Low-Latency scheduling domain execution on the specified core.
Definition ll_schedule_domain.h:463
static struct ll_schedule_domain * timer_domain_get(void)
Get the primary platform timer scheduling domain.
Definition ll_schedule_domain.h:206
static int domain_register(struct ll_schedule_domain *domain, struct task *task, void(*handler)(void *arg), void *arg)
Register a real-time task with the scheduling domain.
Definition ll_schedule_domain.h:414
static void domain_set(struct ll_schedule_domain *domain, uint64_t start)
Configure the next interrupt or tick timestamp for the domain.
Definition ll_schedule_domain.h:339
uint32_t type
Message type, symmetric to the incoming request.
Definition header.h:8
Memory attributes, cold/hot execution paths, and platform memory inclusions.
#define assert(x)
Definition panic.h:19
Sound Open Firmware global runtime context.
struct sof * sof_get(void)
Get the global Sound Open Firmware runtime instance pointer.
RTOS spinlock primitives and initialization.
static void k_spinlock_init(struct k_spinlock *lock)
Initialize a spinlock structure to the unlocked state.
Definition spinlock.h:25
User-space ABI log levels and binary trace packet header definitions.
Audio component base device "class" used by all other component types.
Definition component.h:587
Definition dma.h:209
Low-Latency schedule domain operations table.
Definition ll_schedule_domain.h:62
void(* domain_task_cancel)(struct ll_schedule_domain *domain, struct task *task)
Notification hook invoked when a task within the domain is cancelled.
Definition ll_schedule_domain.h:162
bool(* domain_is_pending)(struct ll_schedule_domain *domain, struct task *task, struct comp_dev **comp)
Query whether a task in the domain has pending execution work.
Definition ll_schedule_domain.h:154
void(* domain_clear)(struct ll_schedule_domain *domain)
Clear scheduled domain interrupt / tick timer.
Definition ll_schedule_domain.h:145
void(* domain_disable)(struct ll_schedule_domain *domain, int core)
Disable domain interrupts/triggers on the specified core.
Definition ll_schedule_domain.h:118
int(* domain_register)(struct ll_schedule_domain *domain, struct task *task, void(*handler)(void *arg), void *arg)
Register a real-time task with the domain.
Definition ll_schedule_domain.h:71
int(* domain_unregister)(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks)
Unregister a task from the domain.
Definition ll_schedule_domain.h:82
void(* domain_set)(struct ll_schedule_domain *domain, uint64_t start)
Set the next tick timestamp for the domain.
Definition ll_schedule_domain.h:139
void(* domain_enable)(struct ll_schedule_domain *domain, int core)
Enable domain interrupts/triggers on the specified core.
Definition ll_schedule_domain.h:111
Low-Latency scheduling domain instance descriptor.
Definition ll_schedule_domain.h:168
atomic_t enabled_cores
Number of currently enabled cores.
Definition ll_schedule_domain.h:177
uint32_t ticks_per_ms
Number of clock ticks per millisecond.
Definition ll_schedule_domain.h:178
bool full_sync
True if tasks are fully synchronous with no time dependency.
Definition ll_schedule_domain.h:182
bool synchronous
True if tasks in this domain execute synchronously.
Definition ll_schedule_domain.h:181
atomic_t total_num_tasks
Total number of registered tasks across all cores.
Definition ll_schedule_domain.h:176
struct k_spinlock lock
Standard spinlock.
Definition ll_schedule_domain.h:174
void * priv_data
Pointer to private domain driver data.
Definition ll_schedule_domain.h:183
int type
Domain type (SOF_SCHEDULE_LL_TIMER or SOF_SCHEDULE_LL_DMA).
Definition ll_schedule_domain.h:179
bool enabled[CONFIG_CORE_COUNT]
Per-core enablement flags.
Definition ll_schedule_domain.h:184
uint64_t next_tick
Ticks just set for next run.
Definition ll_schedule_domain.h:169
int clk
Source clock identifier.
Definition ll_schedule_domain.h:180
const struct ll_schedule_domain_ops * ops
Domain operations table.
Definition ll_schedule_domain.h:185
uint64_t new_target_tick
For the next set, used during the reschedule stage.
Definition ll_schedule_domain.h:170
struct ll_schedule_domain * platform_timer_domain
Definition sof.h:73
struct ll_schedule_domain * platform_dma_domain
Definition sof.h:76
Core task structure managed by SOF schedulers.
Definition task.h:81