mirror of https://github.com/thesofproject/sof.git
ipc: fix logic for buffer free
A buffer should be prevented from being freed only if both the sink and the source widgets are active. In the case of dynamic pipeline loading, a buffer belonging to a pipeline will need to freed when that pipeline is no longer active but the other end of the buffer might still be active. So, change the logic to check if both the sink and source widget states are invalid to prevent the buffer from being freed. Also make sure that the buffer is disconnected from the active comp before it is freed. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
This commit is contained in:
parent
f7d0d89f9e
commit
6d67a9dce9
|
@ -136,6 +136,21 @@ int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void pipeline_disconnect(struct comp_dev *comp, struct comp_buffer *buffer, int dir)
|
||||
{
|
||||
uint32_t flags;
|
||||
|
||||
if (dir == PPL_CONN_DIR_COMP_TO_BUFFER)
|
||||
comp_info(comp, "disconnect buffer %d as sink", buffer->id);
|
||||
else
|
||||
comp_info(comp, "disconnect buffer %d as source", buffer->id);
|
||||
|
||||
irq_local_disable(flags);
|
||||
list_item_del(buffer_comp_list(buffer, dir));
|
||||
comp_writeback(comp);
|
||||
irq_local_enable(flags);
|
||||
}
|
||||
|
||||
struct pipeline_walk_context {
|
||||
int (*comp_func)(struct comp_dev *, struct comp_buffer *,
|
||||
struct pipeline_walk_context *, int);
|
||||
|
|
|
@ -221,9 +221,10 @@ struct pipeline *pipeline_new(struct sof_ipc_pipe_new *pipe_desc,
|
|||
struct comp_dev *cd);
|
||||
int pipeline_free(struct pipeline *p);
|
||||
|
||||
/* insert component in pipeline */
|
||||
/* insert/remove component in pipeline */
|
||||
int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer,
|
||||
int dir);
|
||||
void pipeline_disconnect(struct comp_dev *comp, struct comp_buffer *buffer, int dir);
|
||||
|
||||
/* complete the pipeline */
|
||||
int pipeline_complete(struct pipeline *p, struct comp_dev *source,
|
||||
|
|
|
@ -291,6 +291,9 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id)
|
|||
struct ipc_comp_dev *ibd;
|
||||
struct ipc_comp_dev *icd;
|
||||
struct list_item *clist;
|
||||
struct comp_dev *sink = NULL, *source = NULL;
|
||||
bool sink_active = false;
|
||||
bool source_active = false;
|
||||
|
||||
/* check whether buffer exists */
|
||||
ibd = ipc_get_comp_by_id(ipc, buffer_id);
|
||||
|
@ -309,13 +312,36 @@ int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id)
|
|||
|
||||
/* check comp state if sink and source are valid */
|
||||
if (ibd->cb->sink == icd->cd &&
|
||||
ibd->cb->sink->state != COMP_STATE_READY)
|
||||
return -EINVAL;
|
||||
ibd->cb->sink->state != COMP_STATE_READY) {
|
||||
sink = ibd->cb->sink;
|
||||
sink_active = true;
|
||||
}
|
||||
|
||||
if (ibd->cb->source == icd->cd &&
|
||||
ibd->cb->source->state != COMP_STATE_READY)
|
||||
return -EINVAL;
|
||||
ibd->cb->source->state != COMP_STATE_READY) {
|
||||
source = ibd->cb->source;
|
||||
source_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A buffer could be connected to 2 different pipelines. When one pipeline is freed, the
|
||||
* buffer comp that belongs in this pipeline will need to be freed even when the other
|
||||
* pipeline that the buffer is connected to is active. Check if both ends are active before
|
||||
* freeing the buffer.
|
||||
*/
|
||||
if (sink_active && source_active)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Disconnect the buffer from the active component before freeing it.
|
||||
*/
|
||||
if (sink)
|
||||
pipeline_disconnect(sink, ibd->cb, PPL_CONN_DIR_BUFFER_TO_COMP);
|
||||
|
||||
if (source)
|
||||
pipeline_disconnect(source, ibd->cb, PPL_CONN_DIR_COMP_TO_BUFFER);
|
||||
|
||||
/* free buffer and remove from list */
|
||||
buffer_free(ibd->cb);
|
||||
list_item_del(&ibd->list);
|
||||
|
|
Loading…
Reference in New Issue