From 3bb2f4b040a34d634117bd4a9efd0f64309ed963 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 17 Sep 2021 14:14:13 -0700 Subject: [PATCH 1/3] ASoC: SOF: trace: no need to wake_up() after stopping DMA trace has been stopped and released at this point, so a wake_up() is not needed anymore. Fixes: 2291b8c29a77 ("ASoC: SOF: force end-of-file for debugfs trace at suspend") Signed-off-by: Ranjani Sridharan --- sound/soc/sof/trace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index e3afc3dac7d17a..5303338e71a739 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -556,7 +556,6 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev) sdev->dtrace_is_enabled = false; sdev->dtrace_draining = true; - wake_up(&sdev->trace_sleep); } EXPORT_SYMBOL(snd_sof_release_trace); From 78a8ed446e176a9ebeefe5d1748fc3d9f868f8c0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 17 Sep 2021 14:24:32 -0700 Subject: [PATCH 2/3] ASoC: SOF: trace: release trace when suspending to D0i3 Trace must be stopped when the DSP suspends to a D0 substate. Move the call to snd_sof_release_trace() so that it can be released for all D0 substates and add the call to re-init trace when resuming from a low-power D0 substate. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index e65f4f4d6df943..15fa2b00907e26 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -114,13 +114,16 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } - /* - * Nothing further to be done for platforms that support the low power - * D0 substate. - */ + /* Only resume trace when resuming from low-power D0 substate */ if (!runtime_resume && sof_ops(sdev)->set_power_state && - old_state == SOF_DSP_PM_D0) + old_state == SOF_DSP_PM_D0) { + /* this is not fatal */ + ret = snd_sof_init_trace_ipc(sdev); + if (ret < 0) + dev_warn(sdev->dev, "failed to init trace after resume %d\n", ret); + return 0; + } sdev->fw_state = SOF_FW_BOOT_PREPARE; @@ -204,15 +207,15 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) target_state = snd_sof_dsp_power_target(sdev); + /* release trace */ + snd_sof_release_trace(sdev); + /* Skip to platform-specific suspend if DSP is entering D0 */ if (target_state == SOF_DSP_PM_D0) goto suspend; sof_tear_down_pipelines(sdev, false); - /* release trace */ - snd_sof_release_trace(sdev); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* cache debugfs contents during runtime suspend */ if (runtime_suspend) From 132834240e4d848ad26a32b54c55131cc6d54ea5 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sat, 18 Sep 2021 15:44:10 -0700 Subject: [PATCH 3/3] ASoC: SOF: Intel: hda: reset dma_sata during suspend When the stream is cleared during the suspend trigger, the dma_data must be set to NULL and snd_hdac_ext_stream_release() must be called to release the link dev. Without this, some platforms run into issues with triggering the host DMA during system resume. Add the missing sequences to both hda_link_pcm_trigger() to handle all streams that get suspended and to hda_dsp_set_hw_params_upon_resume() to handle paused streams that are reset during system suspend. Also, because the dma_data is set to NULL during suspend, add the checks to ensure link_dev is not NULL during hw_params and hw_free to prevent NULL pointer dereferences. BugLink: https://github.com/thesofproject/sof/issues/4779 Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 16 ++++++++++------ sound/soc/sof/intel/hda-dsp.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index d71165fb6fad38..b44843116543c1 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -279,7 +279,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); int stream = substream->stream; - if (link_dev->link_prepared) + if (link_dev && link_dev->link_prepared) return 0; dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream); @@ -306,6 +306,10 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, bus = hstream->bus; rtd = asoc_substream_to_rtd(substream); + /* when paused streams are never released after system resume, link_dev would be NULL. */ + if (!link_dev) + return 0; + link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name); if (!link) return -EINVAL; @@ -347,7 +351,10 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, snd_hdac_ext_link_clear_stream_id(link, stream_tag); } + snd_soc_dai_set_dma_data(dai, substream, NULL); + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; + hda_stream->host_reserved = 0; fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -377,11 +384,8 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, rtd = asoc_substream_to_rtd(substream); link_dev = snd_soc_dai_get_dma_data(dai, substream); - if (!link_dev) { - dev_dbg(dai->dev, - "%s: link_dev is not assigned\n", __func__); - return -EINVAL; - } + if (!link_dev) + return 0; hda_stream = hstream_to_sof_hda_stream(link_dev); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index e03bb455f82a16..d65354125dabc4 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -904,6 +904,7 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_stream *hda_stream; struct snd_soc_pcm_runtime *rtd; struct hdac_ext_stream *stream; struct hdac_ext_link *link; @@ -922,16 +923,23 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) * explicitly during suspend. */ if (stream->link_substream) { + struct snd_soc_dai *cpu_dai; + rtd = asoc_substream_to_rtd(stream->link_substream); + cpu_dai = asoc_rtd_to_cpu(rtd, 0); name = asoc_rtd_to_codec(rtd, 0)->component->name; link = snd_hdac_ext_bus_get_link(bus, name); if (!link) return -EINVAL; + snd_soc_dai_set_dma_data(cpu_dai, stream->link_substream, NULL); + snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_LINK); stream->link_prepared = 0; - if (hdac_stream(stream)->direction == - SNDRV_PCM_STREAM_CAPTURE) + hda_stream = hstream_to_sof_hda_stream(stream); + hda_stream->host_reserved = 0; + + if (hdac_stream(stream)->direction == SNDRV_PCM_STREAM_CAPTURE) continue; stream_tag = hdac_stream(stream)->stream_tag;