]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: sof ipc4: Add sof_ipc4_widget_setup_msg_payload() and call it
authorJyri Sarha <jyri.sarha@linux.intel.com>
Mon, 12 Jan 2026 11:32:21 +0000 (13:32 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 12 Jan 2026 11:48:39 +0000 (11:48 +0000)
Add of_ipc4_widget_setup_msg_payload() for adding struct
sof_ipc4_module_init_ext_init payload with associated objects. The
function allocates memory for the additional payload, sets up the
payload according to data collected from topology, and copies
pre-encoded module specific payload after the ext_init payload. The
function is called in sof_ipc4_widget_setup().

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://patch.msgid.link/20260112113221.4442-5-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/ipc4-topology.c

index a14023c4c3e785b49770232d0cbcdd981ff77bed..f997b95d9cec3e003ae2629dbd52738fdfa4e967 100644 (file)
@@ -2974,6 +2974,77 @@ 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)
+{
+       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;
+       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;
+
+       /* 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));
+       }
+
+       /* If another array object is added, remember clear previous OBJ_LAST bit */
+
+       /* Calculate final size and check that it fits to max payload size */
+       new_size = ext_pos * sizeof(u32) + ipc_size;
+       if (new_size > sdev->ipc->max_payload_size) {
+               dev_err(sdev->dev, "Max ipc payload size %zu exceeded: %u",
+                       sdev->ipc->max_payload_size, new_size);
+               kfree(payload);
+               return -EINVAL;
+       }
+       *new_data = payload;
+
+       /* Copy module specific ipc_payload to end */
+       memcpy(&payload[ext_pos], ipc_data, ipc_size);
+
+       /* Update msg extension bits according to the payload changes */
+       msg->extension |= SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK;
+       msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
+       msg->extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(DIV_ROUND_UP(new_size, sizeof(u32)));
+
+       return new_size;
+}
+
 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;
@@ -2981,6 +3052,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
        struct sof_ipc4_pipeline *pipeline;
        struct sof_ipc4_msg *msg;
        void *ipc_data = NULL;
+       void *ext_data = NULL;
        u32 ipc_size = 0;
        int ret;
 
@@ -3125,6 +3197,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
                dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n",
                        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);
+               if (ret < 0)
+                       goto fail;
+
+               if (ret > 0) {
+                       ipc_size = ret;
+                       ipc_data = ext_data;
+               }
        } else {
                dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
                        swidget->widget->name, swidget->pipeline_id,
@@ -3135,6 +3217,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
        msg->data_ptr = ipc_data;
 
        ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, ipc_size);
+
+fail:
        if (ret < 0) {
                dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name);
 
@@ -3147,6 +3231,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
                }
        }
 
+       kfree(ext_data);
        return ret;
 }