ASoC: SOF: ipc4-topology: Update the memory data building

Peter Ujfalusi <peter.ujfalusi@linux.intel.com> says:

This series fixes some issues left to the first version
sof_ipc4_mod_init_ext_dp_memory_data payload building code. The
payload to specify memory requirements of Data Processing components,
running as independent processes in SOF firmware.

But more importantly it adds a payload of similar purpose to the
pipeline create message, e.g. sof_ipc4_glb_pipe_payload. It sums up
the memory requirements of individual Low Latency components in the
pipeline and sends the summed up values in pipeline create message.

Link: https://patch.msgid.link/20260730104141.14817-1-peter.ujfalusi@linux.intel.com
This commit is contained in:
Mark Brown
2026-07-31 15:44:40 +01:00
4 changed files with 229 additions and 42 deletions
+77 -3
View File
@@ -187,6 +187,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)
@@ -705,11 +709,81 @@ enum sof_ipc4_mod_init_ext_obj_id {
SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA,
};
/* DP module memory configuration data object for ext_init object array */
/* DP module memory configuration data object for object array */
struct sof_ipc4_mod_init_ext_dp_memory_data {
u32 domain_id; /* userspace domain ID */
u32 stack_bytes; /* required stack size in bytes */
u32 heap_bytes; /* required heap size in bytes */
} __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. struct sof_ipc4_glb_pipe_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, 0 means default size */
u32 heap_bytes; /* stack size in bytes, 0 means default size */
u32 stack_bytes; /* stack size in bytes */
u32 heap_bytes; /* heap size in bytes */
} __packed __aligned(4);
/** @}*/
+2 -2
View File
@@ -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
+146 -33
View File
@@ -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[] = {
@@ -1371,6 +1371,22 @@ 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 module instances belonging
* to the same pipeline, and find the maximum stack requirement
* among all module instances belonging to the same pipeline.
*/
if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) {
pipe_widget->heap_bytes += swidget->heap_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 heap %u stack %u",
swidget->widget->name, pipe_widget->widget->name,
pipe_widget->heap_bytes, pipe_widget->stack_bytes);
}
/* Update base_config->cpc from the module manifest */
sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
@@ -1688,6 +1704,8 @@ 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->heap_bytes = 0;
pipe_widget->stack_bytes = 0;
if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
if (pipeline->use_chain_dma) {
@@ -3085,27 +3103,47 @@ 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 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->heap_bytes = swidget->heap_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.
/*
* 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) {
msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK;
if (swidget->comp_domain != SOF_COMP_DOMAIN_DP)
return 0;
}
payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL);
if (!payload)
@@ -3113,27 +3151,26 @@ 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 dp_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 |
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->dp_domain_id;
dp_mem_data->stack_bytes = swidget->dp_stack_bytes;
dp_mem_data->heap_bytes = swidget->dp_heap_bytes;
ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32));
sof_ipc4_add_init_ext_dp_memory_data(sdev, swidget, payload, &ext_pos, &hdr);
/* 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;
@@ -3156,6 +3193,69 @@ 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->heap_bytes = swidget->heap_bytes;
*ext_pos += DIV_ROUND_UP(sizeof(*mem_data), sizeof(u32));
dev_dbg(sdev->dev,
"%s; domain_id %u stack %u heap %u bytes",
swidget->widget->name, mem_data->domain_id, mem_data->stack_bytes,
mem_data->heap_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;
@@ -3309,8 +3409,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;
@@ -3322,6 +3422,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;
@@ -3379,6 +3490,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
swidget->widget->name);
pipeline->mem_usage = 0;
swidget->heap_bytes = 0;
swidget->stack_bytes = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
ida_free(&pipeline_ida, swidget->instance_id);
swidget->instance_id = -EINVAL;
+4 -4
View File
@@ -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 */