dmaengine: stm32-dma: fix residue in case of MDMA chaining
authorAmelie Delaunay <amelie.delaunay@foss.st.com>
Wed, 4 Oct 2023 15:50:24 +0000 (17:50 +0200)
committerVinod Koul <vkoul@kernel.org>
Mon, 9 Oct 2023 05:40:58 +0000 (11:10 +0530)
In case of MDMA chaining, DMA is configured in Double-Buffer Mode (DBM)
with two periods, but if transfer has been prepared with _prep_slave_sg(),
the transfer is not marked cyclic (=!chan->desc->cyclic). However, as DBM
is activated for MDMA chaining, residue computation must take into account
cyclic constraints.

With only two periods in MDMA chaining, and no update due to Transfer
Complete interrupt masked, n_sg is always 0. If DMA current memory address
(depending on SxCR.CT and SxM0AR/SxM1AR) does not correspond, it means n_sg
should be increased.
Then, the residue of the current period is the one read from SxNDTR and
should not be overwritten with the full period length.

Fixes: 723795173ce1 ("dmaengine: stm32-dma: add support to trigger STM32 MDMA")
Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20231004155024.2609531-2-amelie.delaunay@foss.st.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/stm32-dma.c

index 7427acc..0b30151 100644 (file)
@@ -1389,11 +1389,12 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
 
        residue = stm32_dma_get_remaining_bytes(chan);
 
-       if (chan->desc->cyclic && !stm32_dma_is_current_sg(chan)) {
+       if ((chan->desc->cyclic || chan->trig_mdma) && !stm32_dma_is_current_sg(chan)) {
                n_sg++;
                if (n_sg == chan->desc->num_sgs)
                        n_sg = 0;
-               residue = sg_req->len;
+               if (!chan->trig_mdma)
+                       residue = sg_req->len;
        }
 
        /*
@@ -1403,7 +1404,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
         * residue = remaining bytes from NDTR + remaining
         * periods/sg to be transferred
         */
-       if (!chan->desc->cyclic || n_sg != 0)
+       if ((!chan->desc->cyclic && !chan->trig_mdma) || n_sg != 0)
                for (i = n_sg; i < desc->num_sgs; i++)
                        residue += desc->sg_req[i].len;