Unverified Commit 7211814f authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown
Browse files

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: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://msgid.link/r/20240409110036.9411-5-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 551af328
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -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 */