Skip to content

Commit e8d0ba1

Browse files
ujfalusibroonie
authored andcommitted
ASoC: SOF: Intel: hda-dai: Do not release the link DMA on STOP
The linkDMA should not be released on stop trigger since a stream re-start might happen without closing of the stream. This leaves a short time for other streams to 'steal' the linkDMA since it has been released. This issue is not easy to reproduce under normal conditions as usually after stop the stream is closed, or the same stream is restarted, but if another stream got in between the stop and start, like this: aplay -Dhw:0,3 -c2 -r48000 -fS32_LE /dev/zero -d 120 CTRL+z aplay -Dhw:0,0 -c2 -r48000 -fS32_LE /dev/zero -d 120 then the link DMA channels will be mixed up, resulting firmware error or crash. Fixes: ab55937 ("ASoC: SOF: Intel: hda: Always clean up link DMA during stop") Cc: stable@vger.kernel.org Closes: thesofproject/sof#9695 Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://patch.msgid.link/20241217091019.31798-1-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 001a3d5 commit e8d0ba1

File tree

2 files changed

+19
-8
lines changed

2 files changed

+19
-8
lines changed

sound/soc/sof/intel/hda-dai.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,10 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
103103
return sdai->platform_private;
104104
}
105105

106-
int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
107-
struct snd_soc_dai *cpu_dai)
106+
static int
107+
hda_link_dma_cleanup(struct snd_pcm_substream *substream,
108+
struct hdac_ext_stream *hext_stream,
109+
struct snd_soc_dai *cpu_dai, bool release)
108110
{
109111
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
110112
struct sof_intel_hda_stream *hda_stream;
@@ -128,6 +130,17 @@ int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_st
128130
snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
129131
}
130132

133+
if (!release) {
134+
/*
135+
* Force stream reconfiguration without releasing the channel on
136+
* subsequent stream restart (without free), including LinkDMA
137+
* reset.
138+
* The stream is released via hda_dai_hw_free()
139+
*/
140+
hext_stream->link_prepared = 0;
141+
return 0;
142+
}
143+
131144
if (ops->release_hext_stream)
132145
ops->release_hext_stream(sdev, cpu_dai, substream);
133146

@@ -211,7 +224,7 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
211224
if (!hext_stream)
212225
return 0;
213226

214-
return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
227+
return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, true);
215228
}
216229

217230
static int __maybe_unused hda_dai_hw_params_data(struct snd_pcm_substream *substream,
@@ -304,7 +317,8 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
304317
switch (cmd) {
305318
case SNDRV_PCM_TRIGGER_STOP:
306319
case SNDRV_PCM_TRIGGER_SUSPEND:
307-
ret = hda_link_dma_cleanup(substream, hext_stream, dai);
320+
ret = hda_link_dma_cleanup(substream, hext_stream, dai,
321+
cmd == SNDRV_PCM_TRIGGER_STOP ? false : true);
308322
if (ret < 0) {
309323
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
310324
return ret;
@@ -660,8 +674,7 @@ static int hda_dai_suspend(struct hdac_bus *bus)
660674
}
661675

662676
ret = hda_link_dma_cleanup(hext_stream->link_substream,
663-
hext_stream,
664-
cpu_dai);
677+
hext_stream, cpu_dai, true);
665678
if (ret < 0)
666679
return ret;
667680
}

sound/soc/sof/intel/hda.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,8 +1038,6 @@ const struct hda_dai_widget_dma_ops *
10381038
hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
10391039
int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
10401040
struct snd_sof_dai_config_data *data);
1041-
int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
1042-
struct snd_soc_dai *cpu_dai);
10431041

10441042
static inline struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
10451043
{

0 commit comments

Comments
 (0)