From a7b30818957ecdde6709e3efd412f9bef971f6da Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 5 Mar 2026 21:49:22 +0200 Subject: [PATCH 1/4] module-adapter: Move pipeline_comp_dp_task_init() after mod struct inits Move pipeline_comp_dp_task_init() call after module private data initializations so that the struct module_config is available already at pipeline_comp_dp_task_init() init time. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module_adapter.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 3da4079d757e..d62b8736e015 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -244,6 +244,17 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, struct comp_dev *dev = mod->dev; + dst = &mod->priv.cfg; + /* + * NOTE: dst->ext_data points to stack variable and contains + * pointers to IPC payload mailbox, so its only valid in + * functions that called from this function. This why + * the pointer is set NULL before this function exits. + */ +#if CONFIG_IPC_MAJOR_4 + dst->ext_data = &ext_data; +#endif + #if CONFIG_ZEPHYR_DP_SCHEDULER /* create a task for DP processing */ if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) { @@ -256,16 +267,6 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, } #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ - dst = &mod->priv.cfg; - /* - * NOTE: dst->ext_data points to stack variable and contains - * pointers to IPC payload mailbox, so its only valid in - * functions that called from this function. This why - * the pointer is set NULL before this function exits. - */ -#if CONFIG_IPC_MAJOR_4 - dst->ext_data = &ext_data; -#endif ret = module_adapter_init_data(dev, dst, config, &spec); if (ret) { comp_err(dev, "%d: module init data failed", From 30e2ec5f0b8576d816b7e0177dc99af82f4b1e3d Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 25 Jun 2026 15:40:32 +0300 Subject: [PATCH 2/4] module-adapter: module_adapter_dp_heap_new() remove heap_size parameter Remove unused heap_size parameter from module_adapter_dp_heap_new() function. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module_adapter.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index d62b8736e015..8c5c1783f291 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -58,8 +58,7 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, #define PAGE_SZ HOST_PAGE_SIZE #endif -static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config, - size_t *heap_size) +static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config) { /* src-lite with 8 channels has been seen allocating 14k in one go */ /* FIXME: the size will be derived from configuration */ @@ -84,11 +83,10 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv */ uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER; - size_t heap_size; if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) && IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) { - mod_vreg = module_adapter_dp_heap_new(config, &heap_size); + mod_vreg = module_adapter_dp_heap_new(config); if (!mod_vreg) { comp_cl_err(drv, "Failed to allocate DP module heap / vregion"); return NULL; @@ -101,7 +99,6 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv #else mod_heap = drv->user_heap; #endif - heap_size = 0; mod_vreg = NULL; } From bef5f96516111712822c4a625126b84f8ef859bd Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 5 Mar 2026 19:53:46 +0200 Subject: [PATCH 3/4] module-adapter: Size DP heap from IPC ext init data Use IPC module init extended data (the dp_data) to determine DP module heap size when available. Add Kconfig option SOF_USERSPACE_DP_DEFAULT_HEAP_SIZE (default 20480) as fallback when extended init data is not present or does not provide heap sizes. Sanity-check the requested sizes (reject values above 64 MB) and log the allocated heap size. Also pass ext_init through module_adapter_mem_alloc() to module_adapter_dp_heap_new() and fix a minor comment typo. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module_adapter.c | 47 ++++++++++++++++++----- zephyr/Kconfig | 9 +++++ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 8c5c1783f291..835bc6ea86ee 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -58,17 +58,39 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, #define PAGE_SZ HOST_PAGE_SIZE #endif -static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config) +static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config, + const struct module_ext_init_data *ext_init) { /* src-lite with 8 channels has been seen allocating 14k in one go */ - /* FIXME: the size will be derived from configuration */ - const size_t buf_size = 28 * 1024; + size_t buf_size = CONFIG_SOF_USERSPACE_DP_DEFAULT_HEAP_SIZE; +#if CONFIG_IPC_MAJOR_4 + if (config->ipc_extended_init && ext_init && ext_init->dp_data && + ext_init->dp_data->heap_bytes > 0) { + if (ext_init->dp_data->heap_bytes > MB(64)) { + LOG_ERR("Bad heap size %u bytes for %#x", + ext_init->dp_data->heap_bytes, config->id); + return NULL; + } + + buf_size = ext_init->dp_data->heap_bytes; + + LOG_INF("%zu byte heap size requested in IPC for %#x", buf_size, config->id); + } +#endif + /* + * A 1-to-1 replacement of the original heap implementation would be to + * have "lifetime size" equal to 0. But (1) this is invalid for + * vregion_create() and (2) we gradually move objects, that are simple + * to move to the lifetime buffer. Make it 4k for the beginning. + */ return vregion_create(buf_size); } -static struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, - const struct comp_ipc_config *config) +static +struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, + const struct comp_ipc_config *config, + const struct module_ext_init_data *ext_init) { struct k_heap *mod_heap; struct vregion *mod_vreg; @@ -86,7 +108,7 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) && IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) { - mod_vreg = module_adapter_dp_heap_new(config); + mod_vreg = module_adapter_dp_heap_new(config, ext_init); if (!mod_vreg) { comp_cl_err(drv, "Failed to allocate DP module heap / vregion"); return NULL; @@ -227,8 +249,14 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, return NULL; } #endif + const struct module_ext_init_data *ext_init = +#if CONFIG_IPC_MAJOR_4 + &ext_data; +#else + NULL; +#endif - struct processing_module *mod = module_adapter_mem_alloc(drv, config); + struct processing_module *mod = module_adapter_mem_alloc(drv, config, ext_init); if (!mod) return NULL; @@ -245,8 +273,9 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, /* * NOTE: dst->ext_data points to stack variable and contains * pointers to IPC payload mailbox, so its only valid in - * functions that called from this function. This why - * the pointer is set NULL before this function exits. + * functions that are called from this function. This is + * why the pointer is set to NULL before this function + * exits. */ #if CONFIG_IPC_MAJOR_4 dst->ext_data = &ext_data; diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 27f37d829b4e..5d2743fe56ae 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -69,6 +69,15 @@ config SOF_ZEPHYR_HEAP_SIZE NOTE: Keep in mind that the heap size should not be greater than the physical memory size of the system defined in DT (and this includes baseFW text/data). +config SOF_USERSPACE_DP_DEFAULT_HEAP_SIZE + int "Default heap size for DP userspace threads" + default 20480 + help + Defines the default heap size for userspace DP processing + threads. The value can be overridden with IPC module init + ext_init module payload. The default is derived from what is + required for SRC module to produce all supported conversions. + config SOF_USERSPACE_USE_SHARED_HEAP bool "Use shared heap for SOF userspace modules" depends on USERSPACE From 5e259b990904042fe6305b38e44179cfd8b12eb6 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 5 Mar 2026 21:35:41 +0200 Subject: [PATCH 4/4] pipeline: Use dp_data stack size for DP task Use IPC module init extended data (dp_data stack_bytes) to set the DP processing thread stack size when available. Fall back to TASK_DP_STACK_SIZE when ext init data is not present or does not provide a stack size. Add Kconfig option ZEPHYR_DP_SCHEDULER_MIN_STACK_SIZE (default 2048) to enforce a minimum stack size regardless of what the IPC payload requests. Signed-off-by: Jyri Sarha --- src/audio/pipeline/pipeline-schedule.c | 12 +++++++++++- zephyr/Kconfig | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index cb4ec8fd3c62..70ae1186b2a2 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -398,6 +398,7 @@ int pipeline_comp_dp_task_init(struct comp_dev *comp) { /* DP tasks are guaranteed to have a module_adapter */ struct processing_module *mod = comp_mod(comp); + size_t stack_size = TASK_DP_STACK_SIZE; struct task_ops ops = { .run = dp_task_run, .get_deadline = NULL, @@ -413,8 +414,17 @@ int pipeline_comp_dp_task_init(struct comp_dev *comp) unsigned int flags = IS_ENABLED(CONFIG_USERSPACE) ? K_USER : 0; #endif + if (mod->priv.cfg.ext_data && mod->priv.cfg.ext_data->dp_data && + mod->priv.cfg.ext_data->dp_data->stack_bytes > 0) { + stack_size = MAX(mod->priv.cfg.ext_data->dp_data->stack_bytes, + CONFIG_ZEPHYR_DP_SCHEDULER_MIN_STACK_SIZE); + comp_info(comp, "stack size set to %zu, %zu requested, min allowed %zu", + stack_size, mod->priv.cfg.ext_data->dp_data->stack_bytes, + CONFIG_ZEPHYR_DP_SCHEDULER_MIN_STACK_SIZE); + } + return scheduler_dp_task_init(&comp->task, SOF_UUID(dp_task_uuid), &ops, mod, - comp->ipc_config.core, TASK_DP_STACK_SIZE, flags); + comp->ipc_config.core, stack_size, flags); } #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 5d2743fe56ae..603e52aafebd 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -241,6 +241,15 @@ config ZEPHYR_DP_SCHEDULER DP modules can be located in dieffrent cores than LL pipeline modules, may have different tick (i.e. 300ms for speech reccognition, etc.) +config ZEPHYR_DP_SCHEDULER_MIN_STACK_SIZE + int "Minimum stack size for DP processing thread" + default 512 + help + Defines the minimum stack size allowed for DP processing + threads despite what is requested in the module init IPC + ext_init payload. If the stack size requested in the IPC is + smaller than this, then the value defined here takes over. + config CROSS_CORE_STREAM bool "Enable cross-core connected pipelines" default y if IPC_MAJOR_4