asrc_read_last_fifo() checks the FIFO fill level, a number of frames,
against a length in bytes, and ignores the frames already drained by
previous iterations of its retry loop. With an output length close to
the 512 KiB buffer size, which userspace controls through the task input
size and formats, the drain writes past the end of the output buffer:
312 bytes for 10 channels of S24_LE with 8 frames left in the FIFO.
8-bit formats are also stored as 3 bytes per sample.

Check the space needed by all drained frames in bytes, and add a 1-byte
path for 8-bit formats.

Fixes: 24a01710f627 ("ASoC: fsl_asrc_m2m: Add memory to memory function")
Signed-off-by: Stefan Ghetu <[email protected]>
---
 sound/soc/fsl/fsl_asrc_m2m.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
index 58101ce07c9f..cadfebb12e7c 100644
--- a/sound/soc/fsl/fsl_asrc_m2m.c
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -53,21 +53,26 @@ static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, 
void *dma_vaddr, u32
 {
        struct fsl_asrc *asrc = pair->asrc;
        enum asrc_pair_index index = pair->index;
-       u32 i, reg, size, t_size = 0, width;
+       u32 i, reg, size, t_size = 0, width, frame_bytes;
        u32 *reg32 = NULL;
        u16 *reg16 = NULL;
        u8  *reg24 = NULL;
+       u8  *reg8 = NULL;
 
        width = snd_pcm_format_physical_width(pair->sample_format[OUT]);
        if (width == 32)
                reg32 = dma_vaddr + *length;
        else if (width == 16)
                reg16 = dma_vaddr + *length;
+       else if (width == 8)
+               reg8 = dma_vaddr + *length;
        else
                reg24 = dma_vaddr + *length;
+
+       frame_bytes = pair->channels * width / 8;
 retry:
        size = asrc->get_output_fifo_size(pair);
-       if (size + *length > ASRC_M2M_BUFFER_SIZE)
+       if (*length + (t_size + size) * frame_bytes > ASRC_M2M_BUFFER_SIZE)
                goto end;
 
        for (i = 0; i < size * pair->channels; i++) {
@@ -76,6 +81,8 @@ static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, 
void *dma_vaddr, u32
                        *reg32++ = reg;
                } else if (reg16) {
                        *reg16++ = (u16)reg;
+               } else if (reg8) {
+                       *reg8++ = (u8)reg;
                } else {
                        *reg24++ = (u8)reg;
                        *reg24++ = (u8)(reg >> 8);
@@ -89,12 +96,7 @@ static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, 
void *dma_vaddr, u32
                goto retry;
 end:
        /* Update payload length */
-       if (reg32)
-               *length += t_size * pair->channels * 4;
-       else if (reg16)
-               *length += t_size * pair->channels * 2;
-       else
-               *length += t_size * pair->channels * 3;
+       *length += t_size * frame_bytes;
 }
 
 /* config dma channel */
-- 
2.53.0


Reply via email to