dma: pl330: Align DMA memcpy operations to MFIFO width
authorJon Medhurst <tixy@linaro.org>
Tue, 15 Apr 2014 16:18:15 +0000 (17:18 +0100)
committerLiviu Dudau <Liviu.Dudau@arm.com>
Fri, 31 Oct 2014 12:22:14 +0000 (12:22 +0000)
The algorithm used for programming the DMA Controller doesn't take into
consideration the requirements of transfers that are not aligned to the
bus width. Work around this by making sure we pick a bust size and
length which ensures no bursts straddle an MFIFO entry.

See "MFIFO Usage Overview" chapter in the the TRM for "CoreLink DMA
Controller DMA-330", Revision r1p1.

Signed-off-by: Jon Medhurst <tixy@linaro.org>
drivers/dma/pl330.c

index 2e147cb75dd9e5b3ae39ac8da170dc9f0ebd3081..56ad8e68dd2e9302de3b3acc5e4c9061026cd06b 100644 (file)
@@ -2759,8 +2759,13 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        /* Select max possible burst size */
        burst = pi->pcfg.data_bus_width / 8;
 
+       /*
+        * Make sure we use a burst size that aligns with all the memcpy
+        * parameters because our DMA programming algorithm doesn't cope with
+        * transfers which straddle an entry in the DMA device's MFIFO.
+        */
        while (burst > 1) {
-               if (!(len % burst))
+               if (!((src | dst | len) % burst))
                        break;
                burst /= 2;
        }
@@ -2769,6 +2774,13 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        while (burst != (1 << desc->rqcfg.brst_size))
                desc->rqcfg.brst_size++;
 
+       /*
+        * If burst size is smaller than bus width then make sure we only
+        * transfer one at a time to avoid a burst stradling an MFIFO entry.
+        */
+       if (desc->rqcfg.brst_size * 8 < pi->pcfg.data_bus_width)
+               desc->rqcfg.brst_len = 1;
+
        desc->rqcfg.brst_len = get_burst_len(desc, len);
 
        desc->txd.flags = flags;