ipc4: helper: Fix module free

When 2 modules are bound together, they are bound with a buffer between
them with the connection like this : source_module->buffer->sink_module.

So, what this means is that there is only one connection going from a
module to the buffer. So, calling pipeline_disconnect() from the same
module to the same buffer in both directions makes no sense.

Consider the following pipeline:
host_copier->gain->mixin

With the current logic, while iterating through the list of modules, if
mixin goes first for freeing, we'd end up freeing the buffer between the
mixin and gain before it is disconnected from the gain.

The right way to free a module would be first disconnect the module from
the sink buffer, then check if the sink buffer has been disconnected
from its sink module. If so, the buffer should be freed. Otherwise the
buffer will be freed whenever the sink module is disconnected from it.
The same thing must be repeated for the module's source buffer as well.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
This commit is contained in:
Ranjani Sridharan 2022-10-19 12:45:44 -07:00 committed by Kai Vehmanen
parent 56b4773884
commit 0b7b3a5c7e
1 changed files with 29 additions and 8 deletions

View File

@ -183,18 +183,39 @@ static int ipc_pipeline_module_free(uint32_t pipeline_id)
icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_COMPONENT, pipeline_id); icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_COMPONENT, pipeline_id);
while (icd) { while (icd) {
struct comp_buffer *sink; struct list_item *list, *_list;
struct list_item *sink_list; struct comp_buffer *buffer;
struct list_item *tmp_list;
/* free sink buffer allocated by current component in bind function */ /* free sink buffer allocated by current component in bind function */
list_for_item_safe(sink_list, tmp_list, &icd->cd->bsink_list) { list_for_item_safe(list, _list, &icd->cd->bsink_list) {
sink = container_of(sink_list, struct comp_buffer, source_list); struct comp_buffer __sparse_cache *buffer_c;
struct comp_dev *sink;
pipeline_disconnect(icd->cd, sink, PPL_CONN_DIR_COMP_TO_BUFFER); buffer = container_of(list, struct comp_buffer, source_list);
pipeline_disconnect(icd->cd, sink, PPL_CONN_DIR_BUFFER_TO_COMP); pipeline_disconnect(icd->cd, buffer, PPL_CONN_DIR_COMP_TO_BUFFER);
buffer_c = buffer_acquire(buffer);
sink = buffer_c->sink;
buffer_release(buffer_c);
buffer_free(sink); /* free the buffer only when the sink module has also been disconnected */
if (!sink)
buffer_free(buffer);
}
/* free source buffer allocated by current component in bind function */
list_for_item_safe(list, _list, &icd->cd->bsource_list) {
struct comp_buffer __sparse_cache *buffer_c;
struct comp_dev *source;
buffer = container_of(list, struct comp_buffer, sink_list);
pipeline_disconnect(icd->cd, buffer, PPL_CONN_DIR_BUFFER_TO_COMP);
buffer_c = buffer_acquire(buffer);
source = buffer_c->source;
buffer_release(buffer_c);
/* free the buffer only when the source module has also been disconnected */
if (!source)
buffer_free(buffer);
} }
ret = ipc_comp_free(ipc, icd->id); ret = ipc_comp_free(ipc, icd->id);