Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: renesas: rz-ssi: Use proper dma_buffer_pos after resume

When the driver supports DMA, it enqueues four DMA descriptors per
substream before the substream is started. New descriptors are enqueued in
the DMA completion callback, and each time a new descriptor is queued, the
dma_buffer_pos is incremented.

During suspend, the DMA transactions are terminated. There might be cases
where the four extra enqueued DMA descriptors are not completed and are
instead canceled on suspend. However, the cancel operation does not take
into account that the dma_buffer_pos was already incremented.

Previously, the suspend code reinitialized dma_buffer_pos to zero, but this
is not always correct.

To avoid losing any audio periods during suspend/resume and to prevent
clip sound, save the completed DMA buffer position in the DMA callback and
reinitialize dma_buffer_pos on resume.

Cc: stable@vger.kernel.org
Fixes: 1fc778f7c833a ("ASoC: renesas: rz-ssi: Add suspend to RAM support")
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://patch.msgid.link/20251029141134.2556926-3-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Claudiu Beznea and committed by
Mark Brown
22897e56 45f5c9ee

+12 -13
+12 -13
sound/soc/renesas/rz-ssi.c
··· 85 85 struct snd_pcm_substream *substream; 86 86 int fifo_sample_size; /* sample capacity of SSI FIFO */ 87 87 int dma_buffer_pos; /* The address for the next DMA descriptor */ 88 + int completed_dma_buf_pos; /* The address of the last completed DMA descriptor. */ 88 89 int period_counter; /* for keeping track of periods transferred */ 89 90 int sample_width; 90 91 int buffer_pos; /* current frame position in the buffer */ ··· 216 215 rz_ssi_set_substream(strm, substream); 217 216 strm->sample_width = samples_to_bytes(runtime, 1); 218 217 strm->dma_buffer_pos = 0; 218 + strm->completed_dma_buf_pos = 0; 219 219 strm->period_counter = 0; 220 220 strm->buffer_pos = 0; 221 221 ··· 439 437 snd_pcm_period_elapsed(strm->substream); 440 438 strm->period_counter = current_period; 441 439 } 440 + 441 + strm->completed_dma_buf_pos += runtime->period_size; 442 + if (strm->completed_dma_buf_pos >= runtime->buffer_size) 443 + strm->completed_dma_buf_pos = 0; 442 444 } 443 445 444 446 static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) ··· 784 778 return -ENODEV; 785 779 } 786 780 787 - static int rz_ssi_trigger_resume(struct rz_ssi_priv *ssi) 781 + static int rz_ssi_trigger_resume(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) 788 782 { 783 + struct snd_pcm_substream *substream = strm->substream; 784 + struct snd_pcm_runtime *runtime = substream->runtime; 789 785 int ret; 786 + 787 + strm->dma_buffer_pos = strm->completed_dma_buf_pos + runtime->period_size; 790 788 791 789 if (rz_ssi_is_stream_running(&ssi->playback) || 792 790 rz_ssi_is_stream_running(&ssi->capture)) ··· 804 794 ssi->hw_params_cache.channels); 805 795 } 806 796 807 - static void rz_ssi_streams_suspend(struct rz_ssi_priv *ssi) 808 - { 809 - if (rz_ssi_is_stream_running(&ssi->playback) || 810 - rz_ssi_is_stream_running(&ssi->capture)) 811 - return; 812 - 813 - ssi->playback.dma_buffer_pos = 0; 814 - ssi->capture.dma_buffer_pos = 0; 815 - } 816 - 817 797 static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, 818 798 struct snd_soc_dai *dai) 819 799 { ··· 813 813 814 814 switch (cmd) { 815 815 case SNDRV_PCM_TRIGGER_RESUME: 816 - ret = rz_ssi_trigger_resume(ssi); 816 + ret = rz_ssi_trigger_resume(ssi, strm); 817 817 if (ret) 818 818 return ret; 819 819 ··· 852 852 853 853 case SNDRV_PCM_TRIGGER_SUSPEND: 854 854 rz_ssi_stop(ssi, strm); 855 - rz_ssi_streams_suspend(ssi); 856 855 break; 857 856 858 857 case SNDRV_PCM_TRIGGER_STOP: