Skip to content

Commit

Permalink
dmaengine: pl330: Align DMA memcpy operations to MFIFO width
Browse files Browse the repository at this point in the history
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: Jon Medhurst <tixy@linaro.org>
[squashed linker error "undefined reference to `__aeabi_uldivmod]
Reported-by: kbuild test robot <fengguang.wu@intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
  • Loading branch information
Jon Medhurst authored and Vinod Koul committed Nov 17, 2014
1 parent 1f9cd91 commit 137bd11
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions drivers/dma/pl330.c
Original file line number Diff line number Diff line change
Expand Up @@ -2459,16 +2459,25 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
/* Select max possible burst size */
burst = pl330->pcfg.data_bus_width / 8;

while (burst > 1) {
if (!(len % burst))
break;
/*
* 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 ((src | dst | len) & (burst - 1))
burst /= 2;
}

desc->rqcfg.brst_size = 0;
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 < pl330->pcfg.data_bus_width)
desc->rqcfg.brst_len = 1;

desc->rqcfg.brst_len = get_burst_len(desc, len);

desc->txd.flags = flags;
Expand Down

0 comments on commit 137bd11

Please sign in to comment.