Skip to content

Commit

Permalink
ASoC: SOF: hda: fix link DMA config
Browse files Browse the repository at this point in the history
In ASoC, hda codec and SOF driver set the same stream tag to
hardware for a pcm stream and this stream tag should be restored
to hardware after resuming from system suspend. For this bug,
there are two capture pcm streams active before doing system
suspend and one is terminated by user for the stream is unused
and its stream tag is released. Later after doing system suspend
the stream tag for remained active stream is released by SOF driver.
After system resume, hda codec driver restores the stream tag for
the active pcm stream, but SOF restores another stream tag which is
allocated with a different stream tag, and this makes controller
don't get any capture data, then infinite XRUN happens in FW.

For stream tag is stored in both hda codec and SOF driver, it
shouldn't be released only in SOF driver. This patch just keeps the
stream information in dma data and checks whether there is a stored
DMA data for stream resuming from S3 and restores it. And it also
removes DMA data when the stream is released.

Tested on Whisky Lake platform.

GitHub issue: thesofproject/sof#1594
Signed-off-by: Rander Wang <rander.wang@linux.intel.com>
  • Loading branch information
RanderWang committed Jul 4, 2019
1 parent 6ec3295 commit 68b2f3c
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 12 deletions.
15 changes: 9 additions & 6 deletions sound/soc/sof/intel/hda-dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
int stream_tag;
int ret;

link_dev = hda_link_stream_assign(bus, substream);
if (!link_dev)
return -EBUSY;
/* get stored dma data if resuming from system suspend */
link_dev = snd_soc_dai_get_dma_data(dai, substream);
if (!link_dev) {
link_dev = hda_link_stream_assign(bus, substream);
if (!link_dev)
return -EBUSY;
}

stream_tag = hdac_stream(link_dev)->stream_tag;

Expand Down Expand Up @@ -318,7 +322,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
/*
* clear and release link DMA channel. It will be assigned when
* clear link DMA channel. It will be restored when
* hw_params is set up again after resume.
*/
ret = hda_link_config_ipc(hda_stream, dai->name,
Expand All @@ -327,8 +331,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
return ret;
stream_tag = hdac_stream(link_dev)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
snd_hdac_ext_stream_release(link_dev,
HDAC_EXT_STREAM_TYPE_LINK);

/* fallthrough */
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Expand Down Expand Up @@ -372,6 +374,7 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
stream_tag = hdac_stream(link_dev)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
snd_soc_dai_set_dma_data(dai, substream, NULL);
link_dev->link_prepared = 0;

/* free the host DMA channel reserved by hostless streams */
Expand Down
10 changes: 4 additions & 6 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,10 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
hda_stream->hw_params_upon_resume = 1;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
/*
* clear and release stream. This should already be taken care
* for running streams when the SUSPEND trigger is called.
* But paused streams do not get suspended, so this needs to be
* done explicitly during suspend.
* clear stream. This should already be taken care for running
* streams when the SUSPEND trigger is called. But paused
* streams do not get suspended, so this needs to be done
* explicitly during suspend.
*/
if (stream->link_substream) {
rtd = snd_pcm_substream_chip(stream->link_substream);
Expand All @@ -456,8 +456,6 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
return -EINVAL;
stream_tag = hdac_stream(stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
snd_hdac_ext_stream_release(stream,
HDAC_EXT_STREAM_TYPE_LINK);
}
#endif
}
Expand Down

0 comments on commit 68b2f3c

Please sign in to comment.