All tasks of a stream share one pair and one set of DMA channels, and
get_caps() advertises a single fragment, but the compress core allows
up to 64 tasks. A second task requests the pair again and overwrites the
DMA channels. Freeing both tasks then releases the same channels twice
and leaves a stale asrc->pair[] entry after close.

Return -EBUSY from task_create() while a task exists, and clear the DMA
channel pointers once they are released.

Fixes: 24a01710f627 ("ASoC: fsl_asrc_m2m: Add memory to memory function")
Signed-off-by: Stefan Ghetu <[email protected]>
---
 sound/soc/fsl/fsl_asrc_m2m.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
index cadfebb12e7c..2e91073f14f9 100644
--- a/sound/soc/fsl/fsl_asrc_m2m.c
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -471,6 +471,10 @@ static int fsl_asrc_m2m_comp_task_create(struct 
snd_compr_stream *stream,
        struct dma_chan *tmp_chan;
        int ret;
 
+       /* All tasks share the pair and DMA channels: one task at a time */
+       if (pair->dma_chan[IN])
+               return -EBUSY;
+
        exp_info_in.ops = &fsl_asrc_m2m_dma_buf_ops;
        exp_info_in.size = ASRC_M2M_BUFFER_SIZE;
        exp_info_in.flags = O_RDWR;
@@ -527,6 +531,7 @@ static int fsl_asrc_m2m_comp_task_create(struct 
snd_compr_stream *stream,
 
 err_dma_channel_out:
        dma_release_channel(pair->dma_chan[IN]);
+       pair->dma_chan[IN] = NULL;
 err_dma_channel_in:
        if (asrc->m2m_unprepare)
                asrc->m2m_unprepare(pair);
@@ -571,6 +576,8 @@ static int fsl_asrc_m2m_comp_task_free(struct 
snd_compr_stream *stream,
                dma_release_channel(pair->dma_chan[IN]);
        if (pair->dma_chan[OUT])
                dma_release_channel(pair->dma_chan[OUT]);
+       pair->dma_chan[IN] = NULL;
+       pair->dma_chan[OUT] = NULL;
 
        return 0;
 }
-- 
2.53.0


Reply via email to