diff --git a/src/audio/module_adapter/README.md b/src/audio/module_adapter/README.md index 9bc4f2b01695..f59ad2b7a41b 100644 --- a/src/audio/module_adapter/README.md +++ b/src/audio/module_adapter/README.md @@ -51,6 +51,8 @@ sequenceDiagram Connection establishes buffer relationships (`comp_buffer`) connecting the component sources and sinks to the rest of the generic pipeline graph. +Each connected buffer takes a slot in `mod->sinks[]` or `mod->sources[]`, which hold `CONFIG_MODULE_MAX_CONNECTIONS` entries each. A bind (IPC4) or prepare (IPC3) that would need more slots fails with `-EINVAL`. + ```mermaid sequenceDiagram participant Pipe as Pipeline diff --git a/src/audio/module_adapter/module_adapter_ipc3.c b/src/audio/module_adapter/module_adapter_ipc3.c index ab3a5db627c2..08625f38061f 100644 --- a/src/audio/module_adapter/module_adapter_ipc3.c +++ b/src/audio/module_adapter/module_adapter_ipc3.c @@ -320,6 +320,11 @@ int module_adapter_sink_src_prepare(struct comp_dev *dev) /* acquire all sink and source buffers, get handlers to sink/source API */ i = 0; comp_dev_for_each_consumer(dev, sink_buffer) { + if (i == CONFIG_MODULE_MAX_CONNECTIONS) { + comp_err(dev, "more than %d sinks connected", + CONFIG_MODULE_MAX_CONNECTIONS); + return -EINVAL; + } mod->sinks[i] = audio_buffer_get_sink(&sink_buffer->audio_buffer); i++; } @@ -327,6 +332,11 @@ int module_adapter_sink_src_prepare(struct comp_dev *dev) i = 0; comp_dev_for_each_producer(dev, source_buffer) { + if (i == CONFIG_MODULE_MAX_CONNECTIONS) { + comp_err(dev, "more than %d sources connected", + CONFIG_MODULE_MAX_CONNECTIONS); + return -EINVAL; + } mod->sources[i] = audio_buffer_get_source(&source_buffer->audio_buffer); i++; } diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index 6b66c89a8257..00eaa8380bc6 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -471,10 +471,29 @@ __cold static int module_update_source_buffer_params(struct processing_module *m __cold int module_adapter_bind(struct comp_dev *dev, const struct bind_info *bind_data) { struct processing_module *mod = comp_mod(dev); + struct comp_buffer *buffer; + unsigned int count = 0; int ret; assert_can_be_cold(); + /* + * The buffer is already connected here and every connected buffer + * takes a slot in mod->sinks[] or mod->sources[]. + */ + if (bind_data->bind_type == COMP_BIND_TYPE_SINK) { + comp_dev_for_each_consumer(dev, buffer) + count++; + } else { + comp_dev_for_each_producer(dev, buffer) + count++; + } + + if (count > CONFIG_MODULE_MAX_CONNECTIONS) { + comp_err(dev, "%u connections exceed max %d", count, CONFIG_MODULE_MAX_CONNECTIONS); + return -EINVAL; + } + ret = module_update_source_buffer_params(mod, bind_data); if (ret < 0) return ret; diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index d5a0e095b3f4..e5c61f6b3ea5 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1058,10 +1058,17 @@ __cold int ipc4_comp_connect(struct ipc *ipc, const struct ipc4_module_bind_unbi return IPC4_SUCCESS; e_sink_bind: - /* sink bind was already called */ + /* + * The source is already bound. Disconnect first, as + * ipc4_comp_disconnect() does, so its unbind does not keep the + * buffer in the source's sinks[]. + */ + pipeline_disconnect(sink, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); + pipeline_disconnect(source, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); bind_data.bind_type = COMP_BIND_TYPE_SINK; bind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); comp_unbind(source, &bind_data); + goto free; e_src_bind: pipeline_disconnect(sink, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); e_sink_connect: