Unverified Commit 169ec0a5 authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown
Browse files

ASoC: SOF: Relocate and rework functionality for PCM stream freeing



Move the sof_pcm_stream_free() from sof-audio.c to pcm.c as static function
and add wrapper to free all active stream, which is going to be used in
ipc3/4 topology code (removes duplicated code).

With this change most of the PCM stream related code is located in one
source file for easier lookup and simplified flow.

Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarLiam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20250206092828.7569-2-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6eab7034
Loading
Loading
Loading
Loading
+4 −16
Original line number Diff line number Diff line
@@ -2386,28 +2386,16 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
{
	struct snd_sof_widget *swidget;
	struct snd_sof_pcm *spcm;
	int dir, ret;
	int ret;

	/*
	 * free all PCMs and their associated DAPM widgets if their connected DAPM widget
	 * list is not NULL. This should only be true for paused streams at this point.
	 * This is equivalent to the handling of FE DAI suspend trigger for running streams.
	 */
	list_for_each_entry(spcm, &sdev->pcm_list, list) {
		for_each_pcm_streams(dir) {
			struct snd_pcm_substream *substream = spcm->stream[dir].substream;

			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
				continue;

			if (spcm->stream[dir].list) {
				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
				if (ret < 0)
	ret = sof_pcm_free_all_streams(sdev);
	if (ret)
		return ret;
			}
		}
	}

	/*
	 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger
+1 −17
Original line number Diff line number Diff line
@@ -3401,9 +3401,6 @@ static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *

static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
{
	struct snd_sof_pcm *spcm;
	int dir, ret;

	/*
	 * This function is called during system suspend, we need to make sure
	 * that all streams have been freed up.
@@ -3415,21 +3412,8 @@ static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
	 *
	 * This will also make sure that paused streams handled correctly.
	 */
	list_for_each_entry(spcm, &sdev->pcm_list, list) {
		for_each_pcm_streams(dir) {
			struct snd_pcm_substream *substream = spcm->stream[dir].substream;

			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
				continue;

			if (spcm->stream[dir].list) {
				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
				if (ret < 0)
					return ret;
			}
		}
	}
	return 0;
	return sof_pcm_free_all_streams(sdev);
}

static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
+78 −0
Original line number Diff line number Diff line
@@ -191,6 +191,84 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
	return 0;
}

static int sof_pcm_stream_free(struct snd_sof_dev *sdev,
			       struct snd_pcm_substream *substream,
			       struct snd_sof_pcm *spcm, int dir,
			       bool free_widget_list)
{
	const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
	int ret;
	int err = 0;

	if (spcm->prepared[substream->stream]) {
		/* stop DMA first if needed */
		if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
			snd_sof_pcm_platform_trigger(sdev, substream,
						     SNDRV_PCM_TRIGGER_STOP);

		/* free PCM in the DSP */
		if (pcm_ops && pcm_ops->hw_free) {
			ret = pcm_ops->hw_free(sdev->component, substream);
			if (ret < 0) {
				dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
					__func__, ret);
				err = ret;
			}
		}

		spcm->prepared[substream->stream] = false;
		spcm->pending_stop[substream->stream] = false;
	}

	/* reset the DMA */
	ret = snd_sof_pcm_platform_hw_free(sdev, substream);
	if (ret < 0) {
		dev_err(sdev->dev, "%s: platform hw free failed %d\n",
			__func__, ret);
		if (!err)
			err = ret;
	}

	/* free widget list */
	if (free_widget_list) {
		ret = sof_widget_list_free(sdev, spcm, dir);
		if (ret < 0) {
			dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
				__func__, ret);
			if (!err)
				err = ret;
		}
	}

	return err;
}

int sof_pcm_free_all_streams(struct snd_sof_dev *sdev)
{
	struct snd_pcm_substream *substream;
	struct snd_sof_pcm *spcm;
	int dir, ret;

	list_for_each_entry(spcm, &sdev->pcm_list, list) {
		for_each_pcm_streams(dir) {
			substream = spcm->stream[dir].substream;

			if (!substream || !substream->runtime ||
			    spcm->stream[dir].suspend_ignored)
				continue;

			if (spcm->stream[dir].list) {
				ret = sof_pcm_stream_free(sdev, substream, spcm,
							  dir, true);
				if (ret < 0)
					return ret;
			}
		}
	}

	return 0;
}

static int sof_pcm_hw_free(struct snd_soc_component *component,
			   struct snd_pcm_substream *substream)
{
+0 −49
Original line number Diff line number Diff line
@@ -829,55 +829,6 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
	return false;
}

int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
			struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
{
	const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
	int ret;
	int err = 0;

	if (spcm->prepared[substream->stream]) {
		/* stop DMA first if needed */
		if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
			snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);

		/* free PCM in the DSP */
		if (pcm_ops && pcm_ops->hw_free) {
			ret = pcm_ops->hw_free(sdev->component, substream);
			if (ret < 0) {
				dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
					__func__, ret);
				err = ret;
			}
		}

		spcm->prepared[substream->stream] = false;
		spcm->pending_stop[substream->stream] = false;
	}

	/* reset the DMA */
	ret = snd_sof_pcm_platform_hw_free(sdev, substream);
	if (ret < 0) {
		dev_err(sdev->dev, "%s: platform hw free failed %d\n",
			__func__, ret);
		if (!err)
			err = ret;
	}

	/* free widget list */
	if (free_widget_list) {
		ret = sof_widget_list_free(sdev, spcm, dir);
		if (ret < 0) {
			dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
				__func__, ret);
			if (!err)
				err = ret;
		}
	}

	return err;
}

/*
 * Generic object lookup APIs.
 */
+1 −2
Original line number Diff line number Diff line
@@ -649,8 +649,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);
int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev,
			 struct snd_sof_pcm *spcm);
int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
			struct snd_sof_pcm *spcm, int dir, bool free_widget_list);
int sof_pcm_free_all_streams(struct snd_sof_dev *sdev);
int get_token_u32(void *elem, void *object, u32 offset);
int get_token_u16(void *elem, void *object, u32 offset);
int get_token_comp_format(void *elem, void *object, u32 offset);