Commit 137bd110 authored by Jon Medhurst's avatar Jon Medhurst Committed by Vinod Koul

dmaengine: pl330: Align DMA memcpy operations to MFIFO width

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. This failure may result in DMA transferring one too few MFIFO
entries (so too few bytes are copied) or the DMA trying to write one too
many MFIFO entries and hanging because this is never provided.

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

We work around these shortcomings by making sure we pick a burst size
and length which ensures no bursts straddle an MFIFO entry.
Signed-off-by: default avatarJon Medhurst <tixy@linaro.org>
[squashed linker error "undefined reference to `__aeabi_uldivmod]
Reported-by: default avatarkbuild test robot <fengguang.wu@intel.com>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
parent 1f9cd915
...@@ -2459,16 +2459,25 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, ...@@ -2459,16 +2459,25 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
/* Select max possible burst size */ /* Select max possible burst size */
burst = pl330->pcfg.data_bus_width / 8; burst = pl330->pcfg.data_bus_width / 8;
while (burst > 1) { /*
if (!(len % burst)) * Make sure we use a burst size that aligns with all the memcpy
break; * parameters because our DMA programming algorithm doesn't cope with
* transfers which straddle an entry in the DMA device's MFIFO.
*/
while ((src | dst | len) & (burst - 1))
burst /= 2; burst /= 2;
}
desc->rqcfg.brst_size = 0; desc->rqcfg.brst_size = 0;
while (burst != (1 << desc->rqcfg.brst_size)) while (burst != (1 << desc->rqcfg.brst_size))
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 < pl330->pcfg.data_bus_width)
desc->rqcfg.brst_len = 1;
desc->rqcfg.brst_len = get_burst_len(desc, len); desc->rqcfg.brst_len = get_burst_len(desc, len);
desc->txd.flags = flags; desc->txd.flags = flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment