diff options
| author | Shengjiu Wang <shengjiu.wang@nxp.com> | 2024-06-20 10:40:18 +0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2024-07-27 10:40:20 +0200 |
| commit | 8acf8801f3d9d864d0ab79a1b5f3f768bb80cc97 (patch) | |
| tree | 27e9f91075b29cb2fe5b2a1ae287a51d0832a0f9 | |
| parent | 2a28531dd0167a298befe90d946e34da8bb1b579 (diff) | |
| download | linux-8acf8801f3d9d864d0ab79a1b5f3f768bb80cc97.tar.gz linux-8acf8801f3d9d864d0ab79a1b5f3f768bb80cc97.tar.bz2 linux-8acf8801f3d9d864d0ab79a1b5f3f768bb80cc97.zip | |
ALSA: dmaengine_pcm: terminate dmaengine before synchronize
[ Upstream commit 6a7db25aad8ce6512b366d2ce1d0e60bac00a09d ]
When dmaengine supports pause function, in suspend state,
dmaengine_pause() is called instead of dmaengine_terminate_async(),
In end of playback stream, the runtime->state will go to
SNDRV_PCM_STATE_DRAINING, if system suspend & resume happen
at this time, application will not resume playback stream, the
stream will be closed directly, the dmaengine_terminate_async()
will not be called before the dmaengine_synchronize(), which
violates the call sequence for dmaengine_synchronize().
This behavior also happens for capture streams, but there is no
SNDRV_PCM_STATE_DRAINING state for capture. So use
dmaengine_tx_status() to check the DMA status if the status is
DMA_PAUSED, then call dmaengine_terminate_async() to terminate
dmaengine before dmaengine_synchronize().
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Link: https://patch.msgid.link/1718851218-27803-1-git-send-email-shengjiu.wang@nxp.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | sound/core/pcm_dmaengine.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index db2229445256..a7e2e6955e51 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -359,6 +359,12 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_sync_stop); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); + if (status == DMA_PAUSED) + dmaengine_terminate_async(prtd->dma_chan); dmaengine_synchronize(prtd->dma_chan); kfree(prtd); @@ -377,6 +383,12 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream) { struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); + if (status == DMA_PAUSED) + dmaengine_terminate_async(prtd->dma_chan); dmaengine_synchronize(prtd->dma_chan); dma_release_channel(prtd->dma_chan); |
