From af17b7bc3f5e60cb14af5a3196fb95fbf37bbc2f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 2 Jul 2026 10:17:07 +0200 Subject: [PATCH 1/7] module: (cosmetic) fix two comments set_processing_mode() and get_processing_mode() methods of struct module_interface aren't unused, they are used by IADK. Fix respective comments. Signed-off-by: Guennadi Liakhovetski --- src/include/module/module/interface.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/module/module/interface.h b/src/include/module/module/interface.h index 26c176aee9b1..a968ab862028 100644 --- a/src/include/module/module/interface.h +++ b/src/include/module/module/interface.h @@ -239,13 +239,13 @@ struct module_interface { uint8_t *fragment, size_t fragment_size); /** - * (unused) Set processing mode for the module + * (IADK) Set processing mode for the module */ int (*set_processing_mode)(struct processing_module *mod, enum module_processing_mode mode); /** - * (unused) Get the current processing mode for the module + * (IADK) Get the current processing mode for the module */ enum module_processing_mode (*get_processing_mode)(struct processing_module *mod); From ad647b34b4cd28a6a4fe56dc3486432f829a2155 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 2 Jul 2026 14:00:23 +0200 Subject: [PATCH 2/7] schedule: userspace: DP also runs in userspace when possible scheduler_is_user() should return true for DP as well. Signed-off-by: Guennadi Liakhovetski --- src/schedule/schedule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schedule/schedule.c b/src/schedule/schedule.c index 231bba864856..6dc141834842 100644 --- a/src/schedule/schedule.c +++ b/src/schedule/schedule.c @@ -30,7 +30,7 @@ static inline bool scheduler_is_user(int type) * to user-space and only keep Zephyr scheduler logic in * kernel */ - return type == SOF_SCHEDULE_LL_TIMER; + return type == SOF_SCHEDULE_LL_TIMER || type == SOF_SCHEDULE_DP; } int schedule_task_init(struct task *task, From 6590ef51185c4f1d3d72b1b2a79af1b5b88c8028 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 2 Jul 2026 14:31:08 +0200 Subject: [PATCH 3/7] schedule: limit schedule_free() to testing only schedule_free() is only called from testbench and stand-alone ztest. Remove it and all scheduler .scheduler_free() methods for all other builds. Also fix memory leaks in the Zephyr LL version. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/schedule/schedule.h | 5 +++++ src/platform/library/schedule/edf_schedule.c | 4 ++++ src/platform/library/schedule/ll_schedule.c | 4 ++++ src/schedule/ll_schedule_xtos.c | 4 ++++ src/schedule/zephyr_ll.c | 15 ++++++++++----- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index 1e7d6b3842e9..03ce567dc9ea 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -140,6 +140,7 @@ struct scheduler_ops { */ int (*schedule_task_free)(void *data, struct task *task); +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY /** * Frees scheduler's resources. * @param data Private data of selected scheduler. @@ -149,6 +150,7 @@ struct scheduler_ops { * This operation is optional. */ void (*scheduler_free)(void *data, uint32_t flags); +#endif /** * Initializes context @@ -309,6 +311,8 @@ static inline int schedule_task_free(struct task *task) return sch->ops->schedule_task_free(sch->data, task); } +/* Only used in a stand-alone test and in a testbench test */ +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY /** See scheduler_ops::scheduler_free */ static inline void schedule_free(uint32_t flags) { @@ -322,6 +326,7 @@ static inline void schedule_free(uint32_t flags) sch->ops->scheduler_free(sch->data, flags); } } +#endif /** See scheduler_ops::scheduler_init_context */ static inline struct k_thread *scheduler_init_context(struct task *task) diff --git a/src/platform/library/schedule/edf_schedule.c b/src/platform/library/schedule/edf_schedule.c index 0c127c934e21..67c3a669c2f8 100644 --- a/src/platform/library/schedule/edf_schedule.c +++ b/src/platform/library/schedule/edf_schedule.c @@ -49,10 +49,12 @@ static int schedule_edf_task(void *data, struct task *task, uint64_t start, return 0; } +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY static void edf_scheduler_free(void *data, uint32_t flags) { free(data); } +#endif static int schedule_edf_task_cancel(void *data, struct task *task) { @@ -83,7 +85,9 @@ static struct scheduler_ops schedule_edf_ops = { .reschedule_task = NULL, .schedule_task_cancel = schedule_edf_task_cancel, .schedule_task_free = schedule_edf_task_free, +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY .scheduler_free = edf_scheduler_free, +#endif }; int schedule_task_init_edf(struct task *task, const struct sof_uuid_entry *uid, diff --git a/src/platform/library/schedule/ll_schedule.c b/src/platform/library/schedule/ll_schedule.c index 4cfd0a9d196c..1bfc378ffad2 100644 --- a/src/platform/library/schedule/ll_schedule.c +++ b/src/platform/library/schedule/ll_schedule.c @@ -66,10 +66,12 @@ static int schedule_ll_task(void *data, struct task *task, uint64_t start, return 0; } +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY static void ll_scheduler_free(void *data, uint32_t flags) { free(data); } +#endif /* TODO: scheduler free and cancel APIs can merge as part of Zephyr */ static int schedule_ll_task_cancel(void *data, struct task *task) @@ -96,7 +98,9 @@ static struct scheduler_ops schedule_ll_ops = { .reschedule_task = NULL, .schedule_task_cancel = schedule_ll_task_cancel, .schedule_task_free = schedule_ll_task_free, +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY .scheduler_free = ll_scheduler_free, +#endif }; int schedule_task_init_ll(struct task *task, diff --git a/src/schedule/ll_schedule_xtos.c b/src/schedule/ll_schedule_xtos.c index d0460b57a563..be24f3b34fd4 100644 --- a/src/schedule/ll_schedule_xtos.c +++ b/src/schedule/ll_schedule_xtos.c @@ -724,6 +724,7 @@ static int reschedule_ll_task(void *data, struct task *task, uint64_t start) } #endif +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY static void scheduler_free_ll(void *data, uint32_t flags) { struct ll_schedule_data *sch = data; @@ -739,6 +740,7 @@ static void scheduler_free_ll(void *data, uint32_t flags) irq_local_enable(irq_flags); } +#endif static void ll_scheduler_recalculate_tasks(struct ll_schedule_data *sch, struct clock_notify_data *clk_data) @@ -807,6 +809,8 @@ static const struct scheduler_ops schedule_ll_ops = { .schedule_task_free = schedule_ll_task_free, .schedule_task_cancel = schedule_ll_task_cancel, .reschedule_task = reschedule_ll_task, +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY .scheduler_free = scheduler_free_ll, +#endif .schedule_task_running = NULL, }; diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 79b85118b5d3..33d2d76014bd 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -546,17 +546,18 @@ static int zephyr_ll_task_cancel(void *data, struct task *task) return 0; } -/* - * Runs on secondary cores in their shutdown sequence. In theory tasks can still - * be active, but other schedulers ignore them too... And we don't need to free - * the scheduler data - it's allocated in the SYS zone. - */ +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY static void zephyr_ll_scheduler_free(void *data, uint32_t flags) { struct zephyr_ll *sch = data; zephyr_ll_assert_core(sch); +#if CONFIG_SOF_USERSPACE_LL + zephyr_ll_locks[sch->core] = NULL; + k_object_free(sch->lock); +#endif + if (sch->n_tasks) tr_err(&ll_tr, "%u tasks are still active!", sch->n_tasks); @@ -564,7 +565,9 @@ static void zephyr_ll_scheduler_free(void *data, uint32_t flags) #if CONFIG_SOF_USERSPACE_LL domain_thread_free(sch->ll_domain, sch->n_tasks); #endif + sof_heap_free(sch->heap, sch); } +#endif #if CONFIG_SOF_USERSPACE_LL struct k_thread *zephyr_ll_init_context(void *data, struct task *task) @@ -601,7 +604,9 @@ static const struct scheduler_ops zephyr_ll_ops = { .schedule_task_after = zephyr_ll_task_schedule_after, .schedule_task_free = zephyr_ll_task_free, .schedule_task_cancel = zephyr_ll_task_cancel, +#if CONFIG_SOF_BOOT_TEST_STANDALONE || CONFIG_LIBRARY .scheduler_free = zephyr_ll_scheduler_free, +#endif #if CONFIG_SOF_USERSPACE_LL .scheduler_init_context = zephyr_ll_init_context, #endif From e4c8e182a67d9e935ce3b7e828ac4297596ce720 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 2 Jul 2026 17:28:55 +0200 Subject: [PATCH 4/7] init: add a check for userspace schedulers When running the LL scheduler in userspace, it can happen that no kernel-mode schedulers get registered on a running secondary core. To recognise such cases add a check for userspace schedulers to check_restore(). Signed-off-by: Guennadi Liakhovetski --- src/init/init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/init/init.c b/src/init/init.c index 9a99c2d9c27b..c76b4842d88e 100644 --- a/src/init/init.c +++ b/src/init/init.c @@ -94,13 +94,15 @@ static bool check_restore(void) { struct idc *idc = *idc_get(); struct notify *notifier = *arch_notify_get(); - struct schedulers *schedulers = *arch_schedulers_get(); + struct schedulers **schedulers = arch_schedulers_get(); + struct schedulers **user_schedulers = arch_user_schedulers_get(); /* check whether basic core structures has been already allocated. If they * are available in memory, it means that this is not cold boot and memory * has not been powered off. */ - return !!idc && !!notifier && !!schedulers; + return !!idc && !!notifier && + ((schedulers && *schedulers) || (user_schedulers && *user_schedulers)); } static inline int secondary_core_restore(void) { return 0; }; From 125a25a72193450355018b87d6db260f36ffda93 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 2 Jul 2026 17:42:43 +0200 Subject: [PATCH 5/7] schedule: ll: make ll_sch_is_current() always available Make ll_sch_is_current() available for builds with CONFIG_COLD_STORE_EXECUTE_DEBUG unselected. Signed-off-by: Guennadi Liakhovetski --- zephyr/include/sof/lib/memory.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zephyr/include/sof/lib/memory.h b/zephyr/include/sof/lib/memory.h index 6fa6a8ef558d..a176ae9ac896 100644 --- a/zephyr/include/sof/lib/memory.h +++ b/zephyr/include/sof/lib/memory.h @@ -16,15 +16,15 @@ #define __cold_rodata #endif -#if CONFIG_COLD_STORE_EXECUTE_DEBUG -#include - #ifdef __ZEPHYR__ bool ll_sch_is_current(void); #else #define ll_sch_is_current() false #endif +#if CONFIG_COLD_STORE_EXECUTE_DEBUG +#include + void dbg_path_hot_start_watching(void); void dbg_path_hot_stop_watching(void); void dbg_path_hot_confirm(void); From be724505188b787e7374535b4e12b4cc40c39cd7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 8 Jul 2026 16:32:17 +0200 Subject: [PATCH 6/7] schedule: dp: don't use privileged instructions When LL runs in userspace, multiple DP functions are called in userspace mode too. They cannot use privileged instructions then. Signed-off-by: Guennadi Liakhovetski --- src/schedule/zephyr_dp_schedule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 1c6b94d3bb4c..8dacb0283450 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -255,7 +255,7 @@ static int scheduler_dp_task_stop(void *data, struct task *task) struct task_dp_pdata *pdata = task->priv_data; /* this is asyn cancel - mark the task as canceled and remove it from scheduling */ - lock_key = scheduler_dp_lock(cpu_get_id()); + lock_key = scheduler_dp_lock(task->core); task->state = SOF_TASK_STATE_CANCEL; list_item_del(&task->list); @@ -307,7 +307,7 @@ static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t sta struct task_dp_pdata *pdata = task->priv_data; unsigned int lock_key; - lock_key = scheduler_dp_lock(cpu_get_id()); + lock_key = scheduler_dp_lock(task->core); if (task_is_active(task)) { scheduler_dp_unlock(lock_key); From f0a81ebfbf19ff53b68b7433a58f842cd4a0ac37 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 10 Jul 2026 09:36:09 +0200 Subject: [PATCH 7/7] schedule: dp: zero-initialise private data pointer The LL tick task's .priv_data pointer has to be NULL for the check in zephyr_ll_task_init() to pass. Signed-off-by: Guennadi Liakhovetski --- src/schedule/zephyr_dp_schedule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 8dacb0283450..25fa8b319457 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -358,6 +358,7 @@ __cold int scheduler_dp_init(void) if (!dp_sch) return -ENOMEM; + dp_sch->ll_tick_src.priv_data = NULL; list_init(&dp_sch->tasks); scheduler_init(SOF_SCHEDULE_DP, &schedule_dp_ops, dp_sch);