Skip to content

Commit

Permalink
ASoC: SOF: Intel: hda: reset dma_sata during suspend
Browse files Browse the repository at this point in the history
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: thesofproject/sof#4779
Signed-off-by: Ranjani Sridharan <[email protected]>
  • Loading branch information
ranj063 committed Sep 18, 2021
1 parent 78a8ed4 commit 1328342
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 8 deletions.
16 changes: 10 additions & 6 deletions sound/soc/sof/intel/hda-dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);

Expand Down
12 changes: 10 additions & 2 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down

0 comments on commit 1328342

Please sign in to comment.