From 7211814f2adcf376b8db6321447a9725c33b6ae7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Apr 2024 14:00:36 +0300 Subject: ASoC: SOF: ipc4-pcm: Do not reset the ChainDMA if it has not been allocated The ChainDMA operation differs from normal pipelines that it is only created when the stream started, in fact a PCM using ChainDMA has no pipelines, modules. To reset a ChainDMA, it needs to be first allocated in firmware. When PulseAudio/PipeWire starts, they will probe the PCMs by opening them, check hw_params and then close the PCM without starting audio. Unconditionally resetting the ChainDMA can result the following error: ipc tx : 0xe040000|0x0: GLB_CHAIN_DMA ipc tx reply: 0x2e000007|0x0: GLB_CHAIN_DMA FW reported error: 7 - Unsupported operation requested ipc error for msg 0xe040000|0x0 sof_pcm_stream_free: pcm_ops hw_free failed -22 Add a new chain_dma_allocated flag to sof_ipc4_pcm_stream_priv to store the ChainDMA allocation state and use this flag to skip sending the reset if the ChainDMA is not allocated. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Link: https://msgid.link/r/20240409110036.9411-5-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/ipc4-pcm.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 34ce6bb7f37d..4594470ed08b 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -40,9 +40,12 @@ struct sof_ipc4_timestamp_info { /** * struct sof_ipc4_pcm_stream_priv - IPC4 specific private data * @time_info: pointer to time info struct if it is supported, otherwise NULL + * @chain_dma_allocated: indicates the ChainDMA allocation state */ struct sof_ipc4_pcm_stream_priv { struct sof_ipc4_timestamp_info *time_info; + + bool chain_dma_allocated; }; static inline struct sof_ipc4_timestamp_info * @@ -269,14 +272,17 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, */ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, - int direction, + struct snd_sof_pcm *spcm, int direction, struct snd_sof_pcm_stream_pipeline_list *pipeline_list, int state, int cmd) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; + struct sof_ipc4_pcm_stream_priv *stream_priv; bool allocate, enable, set_fifo_size; struct sof_ipc4_msg msg = {{ 0 }}; - int i; + int ret, i; + + stream_priv = spcm->stream[direction].private; switch (state) { case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */ @@ -297,6 +303,11 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, set_fifo_size = false; break; case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */ + + /* ChainDMA can only be reset if it has been allocated */ + if (!stream_priv->chain_dma_allocated) + return 0; + allocate = false; enable = false; set_fifo_size = false; @@ -354,7 +365,12 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, if (enable) msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK; - return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); + ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); + /* Update the ChainDMA allocation state */ + if (!ret) + stream_priv->chain_dma_allocated = allocate; + + return ret; } static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, @@ -394,7 +410,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, * trigger function that handles the rest for the substream. */ if (pipeline->use_chain_dma) - return sof_ipc4_chain_dma_trigger(sdev, substream->stream, + return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream, pipeline_list, state, cmd); /* allocate memory for the pipeline data */ -- cgit v1.2.3