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: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20250206092828.7569-2-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Peter Ujfalusi
2025-02-06 11:28:25 +02:00
committed by Mark Brown
parent 6eab703457
commit 169ec0a541
5 changed files with 84 additions and 84 deletions

View File

@@ -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)
return ret;
}
}
}
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

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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.
*/

View File

@@ -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);