diff options
author | Kai Vehmanen <kai.vehmanen@linux.intel.com> | 2019-09-27 16:05:30 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-10-01 13:31:06 -0400 |
commit | e66e52c5b7422824cedf0084c0766602dea7e8a7 (patch) | |
tree | d7f5ab4eee5f8a3364650eba36312a0aea2463a4 /sound/soc/sof | |
parent | 2e305a074061121220a2828f97a57d315cf8efba (diff) |
ASoC: SOF: pcm: fix resource leak in hw_free
Fix a bug in sof_pcm_hw_free() where some cleanup actions were
skipped if STREAM_PCM_FREE IPC was already successfully sent to
DSP when the stream was stopped or suspended. This is incorrect
as hw_free should clean up also other resources, including pcm
lib page allocations, period elapsed work queue and call to
platform hw_free.
Fixes: c29d96c3b9b4 ("ASoC: SOF: reset DMA state in prepare")
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20190927200538.660-6-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sof')
-rw-r--r-- | sound/soc/sof/pcm.c | 20 |
1 files changed, 10 insertions, 10 deletions
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index e3f6a6dc0f36..fa7769dd825c 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c | |||
@@ -244,7 +244,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) | |||
244 | snd_soc_rtdcom_lookup(rtd, DRV_NAME); | 244 | snd_soc_rtdcom_lookup(rtd, DRV_NAME); |
245 | struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); | 245 | struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); |
246 | struct snd_sof_pcm *spcm; | 246 | struct snd_sof_pcm *spcm; |
247 | int ret; | 247 | int ret, err = 0; |
248 | 248 | ||
249 | /* nothing to do for BE */ | 249 | /* nothing to do for BE */ |
250 | if (rtd->dai_link->no_pcm) | 250 | if (rtd->dai_link->no_pcm) |
@@ -254,26 +254,26 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) | |||
254 | if (!spcm) | 254 | if (!spcm) |
255 | return -EINVAL; | 255 | return -EINVAL; |
256 | 256 | ||
257 | if (!spcm->prepared[substream->stream]) | ||
258 | return 0; | ||
259 | |||
260 | dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, | 257 | dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, |
261 | substream->stream); | 258 | substream->stream); |
262 | 259 | ||
263 | ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); | 260 | if (spcm->prepared[substream->stream]) { |
261 | ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); | ||
262 | if (ret < 0) | ||
263 | err = ret; | ||
264 | } | ||
264 | 265 | ||
265 | snd_pcm_lib_free_pages(substream); | 266 | snd_pcm_lib_free_pages(substream); |
266 | 267 | ||
267 | cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); | 268 | cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); |
268 | 269 | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | |||
272 | ret = snd_sof_pcm_platform_hw_free(sdev, substream); | 270 | ret = snd_sof_pcm_platform_hw_free(sdev, substream); |
273 | if (ret < 0) | 271 | if (ret < 0) { |
274 | dev_err(sdev->dev, "error: platform hw free failed\n"); | 272 | dev_err(sdev->dev, "error: platform hw free failed\n"); |
273 | err = ret; | ||
274 | } | ||
275 | 275 | ||
276 | return ret; | 276 | return err; |
277 | } | 277 | } |
278 | 278 | ||
279 | static int sof_pcm_prepare(struct snd_pcm_substream *substream) | 279 | static int sof_pcm_prepare(struct snd_pcm_substream *substream) |