From b95629d08b015e6923b3f4e22b3e671646ba18a0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 17 Sep 2025 19:42:24 +0300 Subject: [PATCH 1/9] ASoC: SOF: ipc4-topology: Remove dp_ from all module memory attributes Remove dp-prefix from all module instance's memory attributes and related data structures. The attributes are not anymore exclusively for Data Processing module instances, but generic for all module instances. However, the module init payload is still only for DP module instances. Signed-off-by: Jyri Sarha --- sound/soc/sof/ipc4-topology.c | 14 +++++++------- sound/soc/sof/sof-audio.h | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index c191e1bcc92960..7dca0c27e184b7 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -163,11 +163,11 @@ static const struct sof_topology_token comp_ext_tokens[] = { {SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain, offsetof(struct snd_sof_widget, comp_domain)}, {SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, dp_domain_id)}, + offsetof(struct snd_sof_widget, domain_id)}, {SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, dp_heap_bytes)}, + offsetof(struct snd_sof_widget, heap_bytes)}, {SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, dp_stack_bytes)}, + offsetof(struct snd_sof_widget, stack_bytes)}, }; static const struct sof_topology_token gain_tokens[] = { @@ -3138,7 +3138,7 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, /* Add object array objects after ext_init */ - /* Add dp_memory_data if comp_domain indicates DP */ + /* Add memory_data if comp_domain indicates DP */ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | @@ -3147,9 +3147,9 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, sizeof(u32))); ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32)); dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; - dp_mem_data->domain_id = swidget->dp_domain_id; - dp_mem_data->stack_bytes = swidget->dp_stack_bytes; - dp_mem_data->heap_bytes = swidget->dp_heap_bytes; + dp_mem_data->domain_id = swidget->domain_id; + dp_mem_data->stack_bytes = swidget->stack_bytes; + dp_mem_data->heap_bytes = swidget->heap_bytes; ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); } diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 7523081dddac15..13c498158c7b55 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -459,10 +459,10 @@ struct snd_sof_widget { /* Scheduling domain (enum sof_comp_domain), unset, Low Latency, or Data Processing */ u32 comp_domain; - /* The values below are added to mod_init pay load if comp_domain indicates DP component */ - u32 dp_domain_id; /* DP process userspace domain ID */ - u32 dp_stack_bytes; /* DP process stack size requirement in bytes */ - u32 dp_heap_bytes; /* DP process heap size requirement in bytes */ + /* Module instance's memory configuration. */ + u32 domain_id; /* Module instance's userspace domain ID */ + u32 stack_bytes; /* Module instance's stack size requirement */ + u32 heap_bytes; /* Module instance's heap size requirement */ struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ From a24efcfa8c0ff7da39fa01fe7b9f16ddc38abb3e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 7 Oct 2025 23:52:59 +0300 Subject: [PATCH 2/9] ASoC: sof: ipc4-topology: Fix SOF_TKN_COMP_STACK_BYTES_REQUIREMENT id The was inconsistency with SOF_TKN_COMP_STACK_BYTES_REQUIREMENT and SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT token ids in the Linux driver code with SOF FW topology code. This commit fixes the Linux side to match tools/topology/topology2/include/common/tokens.conf See https://github.com/thesofproject/sof/blob/788861804ed08485496e979dd9c467c1a21b30c5/tools/topology/topology2/include/common/tokens.conf#L30 Signed-off-by: Jyri Sarha --- include/uapi/sound/sof/tokens.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index f4a7baadb44da0..8956088b326003 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -111,8 +111,8 @@ #define SOF_TKN_COMP_SCHED_DOMAIN 418 #define SOF_TKN_COMP_DOMAIN_ID 419 -#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 420 -#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 421 +#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 420 +#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 421 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 From 6a1a878daeb0ed22d2f0f2f0eb6af68111fd271b Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 8 Oct 2025 00:35:09 +0300 Subject: [PATCH 3/9] ASoC: sof: ipc4-topology: Component tokens for lifetime and shared bytes Add token SOF_TKN_COMP_LIFETIME_HEAP_BYTES_REQUIREMENT for the amount of allocated memory a module instance needs for the whole of its life time from init to free, and SOF_TKN_COMP_SHARED_BYTES_REQUIREMENT for the amount of shared memory it needs to allocate. Also renames the SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT to SOF_TKN_COMP_INTERIM_HEAP_BYTES_REQUIREMENT to follow FW implementation terms. The interim heap is scratch memory needed for a short time and then freed, while lifetime heap remains allocated from init until the module instance is freed. Signed-off-by: Jyri Sarha --- include/uapi/sound/sof/tokens.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 8956088b326003..fa02192d27ff06 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -112,7 +112,9 @@ #define SOF_TKN_COMP_SCHED_DOMAIN 418 #define SOF_TKN_COMP_DOMAIN_ID 419 #define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 420 -#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 421 +#define SOF_TKN_COMP_INTERIM_HEAP_BYTES_REQUIREMENT 421 +#define SOF_TKN_COMP_LIFETIME_HEAP_BYTES_REQUIREMENT 422 +#define SOF_TKN_COMP_SHARED_BYTES_REQUIREMENT 423 /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 From 0922f6cfbba0f8ee97090d28155343055847d642 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 7 Oct 2025 23:23:02 +0300 Subject: [PATCH 4/9] ASoC: sof: Add lifetime_bytes and shared_bytes to snd_sof_widget Add to lifetime_bytes and shared_bytes snd_sof_widget. They are with SOF_TKN_COMP_LIFETIME_HEAP_BYTES_REQUIREMENT topology tokens and SOF_TKN_COMP_SHARED_BYTES_REQUIREMENT topology token's values. Also renames heap_bytes to interim_bytes to follow the term used in FW side implementation. Signed-off-by: Jyri Sarha --- sound/soc/sof/ipc4-topology.c | 8 ++++++-- sound/soc/sof/sof-audio.h | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 7dca0c27e184b7..a05c327ed9fdc9 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -164,10 +164,14 @@ static const struct sof_topology_token comp_ext_tokens[] = { offsetof(struct snd_sof_widget, comp_domain)}, {SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct snd_sof_widget, domain_id)}, - {SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct snd_sof_widget, heap_bytes)}, {SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct snd_sof_widget, stack_bytes)}, + {SOF_TKN_COMP_INTERIM_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_widget, interim_bytes)}, + {SOF_TKN_COMP_LIFETIME_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_widget, lifetime_bytes)}, + {SOF_TKN_COMP_SHARED_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_widget, shared_bytes)}, }; static const struct sof_topology_token gain_tokens[] = { diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 13c498158c7b55..5a4eece43bc9b0 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -462,7 +462,9 @@ struct snd_sof_widget { /* Module instance's memory configuration. */ u32 domain_id; /* Module instance's userspace domain ID */ u32 stack_bytes; /* Module instance's stack size requirement */ - u32 heap_bytes; /* Module instance's heap size requirement */ + u32 interim_bytes; /* Module instance's interim heap size requirement */ + u32 lifetime_bytes; /* Module instance's lifetime heap requirement */ + u32 shared_bytes; /* Module instance's shared memory requirement */ struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ From aef3116565b28384662edce49d4f3c4367a6cac8 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 23 Sep 2025 21:34:30 +0300 Subject: [PATCH 5/9] ASoC: ipc4: Add SOF_IPC4_GLB_CREATE_PIPELINE payload macros and structs Adds SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY macros to set extension bit in SOF_IPC4_GLB_CREATE_PIPELINE indicating presence of the payload, and all necessary macros and structs to create the payload. Signed-off-by: Jyri Sarha --- include/sound/sof/ipc4/header.h | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 5fd2486582cd49..01376c349b26eb 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -188,6 +188,10 @@ enum sof_ipc4_pipeline_state { #define SOF_IPC4_GLB_PIPE_EXT_CORE_ID_MASK GENMASK(23, 20) #define SOF_IPC4_GLB_PIPE_EXT_CORE_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_CORE_ID_SHIFT) +#define SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT 29 +#define SOF_IPC4_GLB_PIPE_PAYLOAD_MASK BIT(29) +#define SOF_IPC4_GLB_PIPE_PAYLOAD(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT) + /* pipeline set state ipc msg */ #define SOF_IPC4_GLB_PIPE_STATE_ID_SHIFT 16 #define SOF_IPC4_GLB_PIPE_STATE_ID_MASK GENMASK(23, 16) @@ -691,6 +695,78 @@ struct sof_ipc4_mod_init_ext_dp_memory_data { u32 heap_bytes; /* stack size in bytes, 0 means default size */ } __packed __aligned(4); +/* + * This set of macros are very similar to the set above, but these are + * for building payload to SOF_IPC4_GLB_CREATE_PIPELINE message. + * + * Macros for creating struct sof_ipc4_glb_pipe_payload payload with + * its associated data. ext_init payload should be the first piece of + * payload following SOF_IPC4_GLB_CREATE_PIPELINE msg, and its + * existence is indicated with SOF_IPC4_GLB_PIPE_PAYLOAD bit. + * + * The macros below apply to sof_ipc4_glb_pipe_payload.word0 + */ +#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT 0 +#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_MASK GENMASK(23, 0) +#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT) + +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT 24 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK BIT(24) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT) + +struct sof_ipc4_glb_pipe_payload { + u32 word0; + u32 rsvd1; + u32 rsvd2; +} __packed __aligned(4); + +/* + * SOF_IPC4_GLB_CREATE_PIPELINE payload may be followed by arbitrary + * number of object array objects. SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY-bit + * indicates that an array object follows struct + * sof_ipc4_glb_pipe_payload. + * + * The object header's SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST-bit in struct + * sof_ipc4_glb_pipe_ext_object indicates if the array is continued + * with another object. The header has also fields to identify the + * object, SOF_IPC4_GLB_PIPE_EXT_OBJ_ID, and to indicate the object's + * size in 32-bit words, SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS, not + * including the header itself. + * + * The macros below apply to sof_ipc4_glb_pipe_ext_object.header + */ +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT 0 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK BIT(0) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT) + +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT 1 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_MASK GENMASK(15, 1) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT) + +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT 16 +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_MASK GENMASK(31, 16) +#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT) + +struct sof_ipc4_glb_pipe_ext_object { + u32 header; + u32 data[]; +} __packed __aligned(4); + +enum sof_ipc4_glb_pipe_ext_obj_id { + SOF_IPC4_GLB_PIPE_DATA_ID_INVALID = 0, + SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA, + SOF_IPC4_GLB_PIPE_DATA_ID_MAX = SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA, +}; + +/* Pipeline memory configuration data object for ext_init object array */ +struct sof_ipc4_glb_pipe_ext_obj_memory_data { + u32 domain_id; /* userspace domain ID */ + u32 stack_bytes; /* stack size in bytes */ + u32 interim_heap_bytes; /* interim heap size in bytes */ + u32 lifetime_heap_bytes;/* lifetime heap size in bytes */ + u32 shared_bytes; /* shared size in bytes */ +} __packed __aligned(4); + /** @}*/ #endif From 2dec63154d3286d33a7ec0d8e2a6d611cccc4f13 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 17 Sep 2025 17:33:46 +0300 Subject: [PATCH 6/9] ASoC: SOF: ipc4-topology: Add payload to pipeline create messages Start adding payloads to pipeline create messages. The payload contains information for payload specific memory configuration. All non DP module instances within the same pipeline share the same memory attributes and access the same resources. The new logic sums interim, lifetime, and shared heap memory requirements together and picks the highest stack requirement of all module instances belonging to a pipeline. These pipeline specific attributes are sent as struct sof_ipc4_glb_pipe_payload payload in pipeline's create message. The idea is to pass common memory configuration for all the Low Latency modules in the pipeline in pipeline create message payload. The Data Processing module instances will still have an individual memory configuration in struct sof_ipc4_mod_init_ext_dp_memory_data payloads as before. In their payload everything is as it was before, all attributes are copied directly from their topology attributes. Signed-off-by: Jyri Sarha --- sound/soc/sof/ipc4-topology.c | 125 +++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index a05c327ed9fdc9..75153815f6e525 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1348,6 +1348,26 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget * pipeline = pipe_widget->private; pipeline->mem_usage += total; + /* + * If this is not a Data Processing module instance, add the + * required heap sizes to the sum of all modules instance's + * belonging to same pipeline and find the maximum stack + * requirement of all module instances belonging to the same + * pipeline. + */ + if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { + pipe_widget->interim_bytes += swidget->interim_bytes; + pipe_widget->lifetime_bytes += swidget->lifetime_bytes; + pipe_widget->shared_bytes += swidget->shared_bytes; + if (pipe_widget->stack_bytes < swidget->stack_bytes) + pipe_widget->stack_bytes = swidget->stack_bytes; + + dev_dbg(sdev->dev, "%s mem reqs to %s lifetime %u heap %u shared %u stack %u", + swidget->widget->name, pipe_widget->widget->name, + pipe_widget->lifetime_bytes, pipe_widget->interim_bytes, + pipe_widget->shared_bytes, pipe_widget->stack_bytes); + } + /* Update base_config->cpc from the module manifest */ sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config); @@ -1665,6 +1685,10 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) pipe_widget = swidget->spipe->pipe_widget; pipeline = pipe_widget->private; pipeline->mem_usage = 0; + pipe_widget->lifetime_bytes = 0; + pipe_widget->interim_bytes = 0; + pipe_widget->shared_bytes = 0; + pipe_widget->stack_bytes = 0; if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { if (pipeline->use_chain_dma) { @@ -3109,11 +3133,11 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr return 0; } -static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget, - struct sof_ipc4_msg *msg, - void *ipc_data, u32 ipc_size, - void **new_data) +static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + struct sof_ipc4_msg *msg, + void *ipc_data, u32 ipc_size, + void **new_data) { struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; struct sof_ipc4_module_init_ext_init *ext_init; @@ -3137,13 +3161,14 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, /* Add ext_init first and set objects array flag to 1 */ ext_init = (struct sof_ipc4_module_init_ext_init *)payload; - ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; ext_pos = DIV_ROUND_UP(sizeof(*ext_init), sizeof(u32)); /* Add object array objects after ext_init */ /* Add memory_data if comp_domain indicates DP */ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { + ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; + hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | @@ -3153,10 +3178,9 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; dp_mem_data->domain_id = swidget->domain_id; dp_mem_data->stack_bytes = swidget->stack_bytes; - dp_mem_data->heap_bytes = swidget->heap_bytes; + dp_mem_data->heap_bytes = swidget->interim_bytes; ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); } - /* If another array object is added, remember clear previous OBJ_LAST bit */ /* Calculate final size and check that it fits to max payload size */ @@ -3180,6 +3204,72 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev, return new_size; } +static void sof_ipc4_widget_pipe_ext_obj_memory_data(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u32 *payload, u32 *ext_pos, + struct sof_ipc4_glb_pipe_ext_object **hdr) +{ + struct sof_ipc4_glb_pipe_ext_obj_memory_data *mem_data; + + *hdr = (struct sof_ipc4_glb_pipe_ext_object *)&payload[*ext_pos]; + (*hdr)->header = + SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA) | + SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*mem_data), + sizeof(u32))); + *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32)); + mem_data = (struct sof_ipc4_glb_pipe_ext_obj_memory_data *)&payload[*ext_pos]; + mem_data->domain_id = swidget->domain_id; + mem_data->stack_bytes = swidget->stack_bytes; + mem_data->interim_heap_bytes = swidget->interim_bytes; + mem_data->lifetime_heap_bytes = swidget->lifetime_bytes; + mem_data->shared_bytes = swidget->shared_bytes; + *ext_pos += DIV_ROUND_UP(sizeof(*mem_data), sizeof(u32)); + + dev_dbg(sdev->dev, + "%s; domain_id %u stack %u interim %u lifetime %u shared %u bytes", + swidget->widget->name, mem_data->domain_id, mem_data->stack_bytes, + mem_data->interim_heap_bytes, mem_data->lifetime_heap_bytes, + mem_data->shared_bytes); +} + +static int sof_ipc4_widget_pipe_create_msg_payload(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + struct sof_ipc4_msg *msg, + void **new_data) +{ + struct sof_ipc4_glb_pipe_payload *payload_hdr; + struct sof_ipc4_glb_pipe_ext_object *hdr = NULL; + u32 *payload; + u32 ext_pos; + + payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + /* Add sof_ipc4_glb_pipe_payload and set array bit to 1 */ + payload_hdr = (struct sof_ipc4_glb_pipe_payload *)payload; + payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK; + ext_pos = DIV_ROUND_UP(sizeof(*payload_hdr), sizeof(u32)); + + sof_ipc4_widget_pipe_ext_obj_memory_data(sdev, swidget, payload, &ext_pos, &hdr); + /* Add following array objects here */ + + /* Mark end of object array */ + hdr->header |= SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK; + + /* Put total payload size in words to the payload header */ + payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(ext_pos); + *new_data = payload; + + /* Update msg extension bits according to the payload changes */ + msg->extension |= SOF_IPC4_GLB_PIPE_PAYLOAD_MASK; + + dev_dbg(sdev->dev, "%s: payload word0 %#x", swidget->widget->name, + payload_hdr->word0); + + return ext_pos * sizeof(int32_t); +} + static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; @@ -3333,8 +3423,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget swidget->widget->name, swidget->pipeline_id, module_id, swidget->instance_id, swidget->core); - ret = sof_ipc4_widget_setup_msg_payload(sdev, swidget, msg, ipc_data, ipc_size, - &ext_data); + ret = sof_ipc4_widget_mod_init_msg_payload(sdev, swidget, msg, ipc_data, ipc_size, + &ext_data); if (ret < 0) goto fail; @@ -3346,6 +3436,17 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n", swidget->widget->name, swidget->pipeline_id, swidget->instance_id, swidget->core); + + msg->extension &= ~SOF_IPC4_GLB_PIPE_PAYLOAD_MASK; + ret = sof_ipc4_widget_pipe_create_msg_payload(sdev, swidget, msg, + &ext_data); + if (ret < 0) + goto fail; + + if (ret > 0) { + ipc_size = ret; + ipc_data = ext_data; + } } msg->data_size = ipc_size; @@ -3403,6 +3504,10 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget swidget->widget->name); pipeline->mem_usage = 0; + swidget->lifetime_bytes = 0; + swidget->interim_bytes = 0; + swidget->shared_bytes = 0; + swidget->stack_bytes = 0; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; ida_free(&pipeline_ida, swidget->instance_id); swidget->instance_id = -EINVAL; From 98181898c332a49c8c56baca94286d08cb6e43e0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sun, 14 Dec 2025 22:57:43 +0200 Subject: [PATCH 7/9] ASoC: SOF: ipc4-topology: Change struct sof_ipc4_mod_init_ext_dp_memory_data Change struct sof_ipc4_mod_init_ext_dp_memory_data to what is required for the SOF FW userspace DP processing. The earlier version of the firmware (v2.14) did not use the contents of the struct for anything, and if it receives a struct that is larger than the original, the extra words are simply ignored, so there should not be any problem in changing the struct. The following FW versions will expect larger struct and ignore anything that is smaller. Signed-off-by: Jyri Sarha --- include/sound/sof/ipc4/header.h | 8 +++++--- sound/soc/sof/ipc4-topology.c | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h index 01376c349b26eb..60916b32db9074 100644 --- a/include/sound/sof/ipc4/header.h +++ b/include/sound/sof/ipc4/header.h @@ -690,9 +690,11 @@ enum sof_ipc4_mod_init_ext_obj_id { /* DP module memory configuration data object for ext_init object array */ struct sof_ipc4_mod_init_ext_dp_memory_data { - u32 domain_id; /* userspace domain ID */ - u32 stack_bytes; /* stack size in bytes, 0 means default size */ - u32 heap_bytes; /* stack size in bytes, 0 means default size */ + u32 domain_id; /* userspace domain ID */ + u32 stack_bytes; /* required stack size in bytes */ + u32 interim_heap_bytes; /* required interim heap size in bytes */ + u32 lifetime_heap_bytes; /* required lifetime heap size in bytes */ + u32 shared_bytes; /* required shared memory size in bytes */ } __packed __aligned(4); /* diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 75153815f6e525..636f2cf97ee977 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3178,7 +3178,9 @@ static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; dp_mem_data->domain_id = swidget->domain_id; dp_mem_data->stack_bytes = swidget->stack_bytes; - dp_mem_data->heap_bytes = swidget->interim_bytes; + dp_mem_data->interim_heap_bytes = swidget->interim_bytes; + dp_mem_data->lifetime_heap_bytes = swidget->lifetime_bytes; + dp_mem_data->shared_bytes = swidget->shared_bytes; ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); } /* If another array object is added, remember clear previous OBJ_LAST bit */ From bb00e25fec293ac17711885b754b848e0f6849ff Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 11 Feb 2026 18:54:31 +0200 Subject: [PATCH 8/9] ASoC: SOF: ipc4-topology: Refactor sof_ipc4_widget_mod_init_msg_payload() Refactor sof_ipc4_widget_mod_init_msg_payload() to be easier to extend. Signed-off-by: Jyri Sarha --- sound/soc/sof/ipc4-topology.c | 68 ++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 636f2cf97ee977..f6f978366a7a24 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3133,28 +3133,43 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr return 0; } +static void sof_ipc4_add_init_ext_dp_memory_data(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u32 *payload, u32 *ext_pos, + struct sof_ipc4_module_init_ext_object **hdr) +{ + /* Add memory_data if comp_domain indicates DP */ + if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { + struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; + + *hdr = (struct sof_ipc4_module_init_ext_object *)&payload[*ext_pos]; + (*hdr)->header = + SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | + SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), + sizeof(u32))); + *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32)); + dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[*ext_pos]; + dp_mem_data->domain_id = swidget->domain_id; + dp_mem_data->stack_bytes = swidget->stack_bytes; + dp_mem_data->interim_heap_bytes = swidget->interim_bytes; + dp_mem_data->lifetime_heap_bytes = swidget->lifetime_bytes; + dp_mem_data->shared_bytes = swidget->shared_bytes; + *ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); + } +} + static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg, void *ipc_data, u32 ipc_size, void **new_data) { - struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data; struct sof_ipc4_module_init_ext_init *ext_init; - struct sof_ipc4_module_init_ext_object *hdr; + struct sof_ipc4_module_init_ext_object *hdr = NULL; int new_size; u32 *payload; u32 ext_pos; - /* For the moment the only reason for adding init_ext_init payload is DP - * memory data. If both stack and heap size are 0 (= use default), then - * there is no need for init_ext_init payload. - */ - if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) { - msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK; - return 0; - } - payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); if (!payload) return -ENOMEM; @@ -3165,25 +3180,22 @@ static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, /* Add object array objects after ext_init */ - /* Add memory_data if comp_domain indicates DP */ - if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) { - ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; + sof_ipc4_add_init_ext_dp_memory_data(sdev, swidget, payload, &ext_pos, &hdr); - hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos]; - hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK | - SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) | - SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data), - sizeof(u32))); - ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32)); - dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos]; - dp_mem_data->domain_id = swidget->domain_id; - dp_mem_data->stack_bytes = swidget->stack_bytes; - dp_mem_data->interim_heap_bytes = swidget->interim_bytes; - dp_mem_data->lifetime_heap_bytes = swidget->lifetime_bytes; - dp_mem_data->shared_bytes = swidget->shared_bytes; - ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32)); + /* Add following object array items here */ + + if (!hdr) { + /* + * NOTE: Remove this early bail out, when struct + * sof_ipc4_module_init_ext_init alone has some + * function. + */ + kfree(payload); + return 0; } - /* If another array object is added, remember clear previous OBJ_LAST bit */ + + ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK; + hdr->header |= SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK; /* Calculate final size and check that it fits to max payload size */ new_size = ext_pos * sizeof(u32) + ipc_size; From 37f470e4529cf38bf15d74482ef3072883b3215a Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 16 Apr 2026 17:51:50 +0300 Subject: [PATCH 9/9] ASoC: SOF: ipc4-topology: Optimize sof_ipc4_widget_mod_init_msg_payload() Optimize sof_ipc4_widget_mod_init_msg_payload() so that it skips the payload allocation and rest of the function if no payload is needed. Signed-off-by: Jyri Sarha --- sound/soc/sof/ipc4-topology.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index f6f978366a7a24..a1045a5c5024f0 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -3170,6 +3170,13 @@ static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev, u32 *payload; u32 ext_pos; + /* + * Only DP widgets currently add init-ext objects here. Avoid allocating + * a max-sized payload buffer for widgets that will immediately return 0. + */ + if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) + return 0; + payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL); if (!payload) return -ENOMEM;