mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 12:21:22 -05:00
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:
committed by
Mark Brown
parent
6eab703457
commit
169ec0a541
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user