dmaengine: jz4780: Fall back on smaller transfer sizes where necessary

For some reason the controller does not support 8 byte transfers (but
does support all other powers of 2 up to 128). In this case fall back
to 4 bytes. In addition, fall back to 128 bytes when any larger power
of 2 would be possible within the alignment constraints, as this is
the maximum supported.

It makes no sense to outright reject 8 or >128 bytes just because the
alignment constraints make those the maximum possible size given the
parameters for the transaction. For instance, this can result in a DMA
from/to an 8 byte aligned address failing.

It is perfectly safe to fall back to smaller transfer sizes, the only
consequence is reduced transfer efficiency, which is far better than
not allowing the transfer at all.

Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Cc: dmaengine@vger.kernel.org
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
Alex Smith 2015-07-24 17:24:21 +01:00 committed by Vinod Koul
parent 46fa516869
commit dc578f314e

View File

@ -214,11 +214,25 @@ static void jz4780_dma_desc_free(struct virt_dma_desc *vdesc)
kfree(desc); kfree(desc);
} }
static uint32_t jz4780_dma_transfer_size(unsigned long val, int *ord) static uint32_t jz4780_dma_transfer_size(unsigned long val, uint32_t *shift)
{ {
*ord = ffs(val) - 1; int ord = ffs(val) - 1;
switch (*ord) { /*
* 8 byte transfer sizes unsupported so fall back on 4. If it's larger
* than the maximum, just limit it. It is perfectly safe to fall back
* in this way since we won't exceed the maximum burst size supported
* by the device, the only effect is reduced efficiency. This is better
* than refusing to perform the request at all.
*/
if (ord == 3)
ord = 2;
else if (ord > 7)
ord = 7;
*shift = ord;
switch (ord) {
case 0: case 0:
return JZ_DMA_SIZE_1_BYTE; return JZ_DMA_SIZE_1_BYTE;
case 1: case 1:
@ -231,10 +245,8 @@ static uint32_t jz4780_dma_transfer_size(unsigned long val, int *ord)
return JZ_DMA_SIZE_32_BYTE; return JZ_DMA_SIZE_32_BYTE;
case 6: case 6:
return JZ_DMA_SIZE_64_BYTE; return JZ_DMA_SIZE_64_BYTE;
case 7:
return JZ_DMA_SIZE_128_BYTE;
default: default:
return -EINVAL; return JZ_DMA_SIZE_128_BYTE;
} }
} }
@ -244,7 +256,6 @@ static uint32_t jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
{ {
struct dma_slave_config *config = &jzchan->config; struct dma_slave_config *config = &jzchan->config;
uint32_t width, maxburst, tsz; uint32_t width, maxburst, tsz;
int ord;
if (direction == DMA_MEM_TO_DEV) { if (direction == DMA_MEM_TO_DEV) {
desc->dcm = JZ_DMA_DCM_SAI; desc->dcm = JZ_DMA_DCM_SAI;
@ -271,8 +282,8 @@ static uint32_t jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
* divisible by the transfer size, and we must not use more than the * divisible by the transfer size, and we must not use more than the
* maximum burst specified by the user. * maximum burst specified by the user.
*/ */
tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst), &ord); tsz = jz4780_dma_transfer_size(addr | len | (width * maxburst),
jzchan->transfer_shift = ord; &jzchan->transfer_shift);
switch (width) { switch (width) {
case DMA_SLAVE_BUSWIDTH_1_BYTE: case DMA_SLAVE_BUSWIDTH_1_BYTE:
@ -289,7 +300,7 @@ static uint32_t jz4780_dma_setup_hwdesc(struct jz4780_dma_chan *jzchan,
desc->dcm |= width << JZ_DMA_DCM_SP_SHIFT; desc->dcm |= width << JZ_DMA_DCM_SP_SHIFT;
desc->dcm |= width << JZ_DMA_DCM_DP_SHIFT; desc->dcm |= width << JZ_DMA_DCM_DP_SHIFT;
desc->dtc = len >> ord; desc->dtc = len >> jzchan->transfer_shift;
} }
static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg( static struct dma_async_tx_descriptor *jz4780_dma_prep_slave_sg(
@ -391,15 +402,13 @@ struct dma_async_tx_descriptor *jz4780_dma_prep_dma_memcpy(
struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan); struct jz4780_dma_chan *jzchan = to_jz4780_dma_chan(chan);
struct jz4780_dma_desc *desc; struct jz4780_dma_desc *desc;
uint32_t tsz; uint32_t tsz;
int ord;
desc = jz4780_dma_desc_alloc(jzchan, 1, DMA_MEMCPY); desc = jz4780_dma_desc_alloc(jzchan, 1, DMA_MEMCPY);
if (!desc) if (!desc)
return NULL; return NULL;
tsz = jz4780_dma_transfer_size(dest | src | len, &ord); tsz = jz4780_dma_transfer_size(dest | src | len,
if (tsz < 0) &jzchan->transfer_shift);
return ERR_PTR(tsz);
desc->desc[0].dsa = src; desc->desc[0].dsa = src;
desc->desc[0].dta = dest; desc->desc[0].dta = dest;