From f7f9c3ad6aa9f218456abdb149ba64ef0d2290dd Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 26 Aug 2021 07:16:24 -0700 Subject: [PATCH 1/3] ASoC: SOF: pm: fix a stale comment There is no restore_stream flag anymmore. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index c9e46f13b1f438..e65f4f4d6df943 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -191,7 +191,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) if (sdev->fw_state != SOF_FW_BOOT_COMPLETE) goto suspend; - /* set restore_stream for all streams during system suspend */ + /* prepare for streams to be resumed properly upon resume */ if (!runtime_suspend) { ret = sof_set_hw_params_upon_resume(sdev->dev); if (ret < 0) { From 2ac6502c36a152689c3210f367e03fa5b9bfa3e7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 25 Aug 2021 17:07:00 -0700 Subject: [PATCH 2/3] ASoC: SOF: handle paused streams during system suspend During system suspend, paused streams do not get suspended. Therefore, we need to explicitly free these PCMs in the DSP and free the associated DAPM widgets so that they can be set up again during resume. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 5 ++- sound/soc/sof/sof-audio.c | 65 +++++++++++++++++++++++++++++++++++++-- sound/soc/sof/sof-audio.h | 2 ++ 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index cde3f65c43780b..56db927390c98b 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -100,9 +100,8 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) } EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); -static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, - struct snd_sof_dev *sdev, - struct snd_sof_pcm *spcm) +int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm) { struct sof_ipc_stream stream; struct sof_ipc_reply reply; diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index a870c72461f212..fb7b5f9b9a9eea 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -718,6 +718,55 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) return 0; } +/* + * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that + * did not get suspended(ex: paused streams) so the widgets can be set up again during resume. + */ +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; + + /* + * 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) + continue; + + if (spcm->stream[dir].list) { + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (ret < 0) + return ret; + + ret = sof_widget_list_free(sdev, spcm, dir); + if (ret < 0) { + dev_err(sdev->dev, "failed to free widgets during suspend\n"); + return ret; + } + } + } + + /* + * free any left over DAI widgets. This is equivalent to the handling of suspend trigger + * for the BE DAI for running streams. + */ + list_for_each_entry(swidget, &sdev->widget_list, list) + if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) { + ret = sof_widget_free(sdev, swidget); + if (ret < 0) + return ret; + } + + return 0; +} + /* * For older firmware, this function doesn't free widgets for static pipelines during suspend. * It only resets use_count for all widgets. @@ -732,8 +781,8 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) /* * This function is called during suspend and for one-time topology verification during * first boot. In both cases, there is no need to protect swidget->use_count and - * sroute->setup because during suspend all streams are suspended and during topology - * loading the sound card unavailable to open PCMs. + * sroute->setup because during suspend all running streams are suspended and during + * topology loading the sound card unavailable to open PCMs. */ list_for_each_entry(swidget, &sdev->widget_list, list) { if (swidget->dynamic_pipeline_widget) @@ -752,6 +801,18 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) return ret; } + /* + * Tear down all pipelines associated with PCMs that did not get suspended + * and unset the prepare flag so that they can be set up again during resume. + */ + if (!verify) { + ret = sof_tear_down_left_over_pipelines(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to tear down paused pipelines\n"); + return ret; + } + } + list_for_each_entry(sroute, &sdev->route_list, list) sroute->setup = false; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 389d56ac3aba52..1c4f59d347177a 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -265,4 +265,6 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); /* PCM */ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); 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); #endif From 9e4ce70a7167aaa236c3135013d8643fb8ddea23 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 26 Aug 2021 16:48:38 -0700 Subject: [PATCH 3/3] ASoC: SOF: hda: reset DAI widget before reconfiguring it It is not unusual for ALSA/ASoC hw_params callbacks to be invoked multiple times. Reset and free the DAI widget before reconfiguring it to keep the DAI widget use_count balanced. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 8d9d40145ad02c..fe656d29f772a1 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -58,6 +58,13 @@ int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w) return -EINVAL; } + /* DAI already configured, reset it before reconfiguring it */ + if (sof_dai->configured) { + ret = hda_ctrl_dai_widget_free(w); + if (ret < 0) + return ret; + } + config = &sof_dai->dai_config[sof_dai->current_config]; /*