Commit 4ec69c7e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'fixes' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine fixes from Vinod Koul:
 "We have couple of fixes for dmaengine queued up:
   - dma mempcy fix for dma configuration of sun6i by Maxime
   - pl330 fixes: First the fixing allocation for data buffers by Liviu
     and then Jon's fixe for fifo width and usage"

* 'fixes' of git://git.infradead.org/users/vkoul/slave-dma:
  dmaengine: Fix allocation size for PL330 data buffer depth.
  dmaengine: pl330: Limit MFIFO usage for memcpy to avoid exhausting entries
  dmaengine: pl330: Align DMA memcpy operations to MFIFO width
  dmaengine: sun6i: Fix memcpy operation
parents e6a588d0 1f0a5cbf
...@@ -271,7 +271,7 @@ struct pl330_config { ...@@ -271,7 +271,7 @@ struct pl330_config {
#define DMAC_MODE_NS (1 << 0) #define DMAC_MODE_NS (1 << 0)
unsigned int mode; unsigned int mode;
unsigned int data_bus_width:10; /* In number of bits */ unsigned int data_bus_width:10; /* In number of bits */
unsigned int data_buf_dep:10; unsigned int data_buf_dep:11;
unsigned int num_chan:4; unsigned int num_chan:4;
unsigned int num_peri:6; unsigned int num_peri:6;
u32 peri_ns; u32 peri_ns;
...@@ -2336,7 +2336,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) ...@@ -2336,7 +2336,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
int burst_len; int burst_len;
burst_len = pl330->pcfg.data_bus_width / 8; burst_len = pl330->pcfg.data_bus_width / 8;
burst_len *= pl330->pcfg.data_buf_dep; burst_len *= pl330->pcfg.data_buf_dep / pl330->pcfg.num_chan;
burst_len >>= desc->rqcfg.brst_size; burst_len >>= desc->rqcfg.brst_size;
/* src/dst_burst_len can't be more than 16 */ /* src/dst_burst_len can't be more than 16 */
...@@ -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;
...@@ -2732,7 +2741,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -2732,7 +2741,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
dev_info(&adev->dev, dev_info(&adev->dev,
"Loaded driver for PL330 DMAC-%d\n", adev->periphid); "Loaded driver for PL330 DMAC-%x\n", adev->periphid);
dev_info(&adev->dev, dev_info(&adev->dev,
"\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n", "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n",
pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
......
...@@ -230,30 +230,25 @@ static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev, ...@@ -230,30 +230,25 @@ static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev,
readl(pchan->base + DMA_CHAN_CUR_PARA)); readl(pchan->base + DMA_CHAN_CUR_PARA));
} }
static inline int convert_burst(u32 maxburst, u8 *burst) static inline s8 convert_burst(u32 maxburst)
{ {
switch (maxburst) { switch (maxburst) {
case 1: case 1:
*burst = 0; return 0;
break;
case 8: case 8:
*burst = 2; return 2;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
return 0;
} }
static inline int convert_buswidth(enum dma_slave_buswidth addr_width, u8 *width) static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width)
{ {
if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) || if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) ||
(addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)) (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES))
return -EINVAL; return -EINVAL;
*width = addr_width >> 1; return addr_width >> 1;
return 0;
} }
static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev, static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
...@@ -284,26 +279,25 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli, ...@@ -284,26 +279,25 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
struct dma_slave_config *config) struct dma_slave_config *config)
{ {
u8 src_width, dst_width, src_burst, dst_burst; u8 src_width, dst_width, src_burst, dst_burst;
int ret;
if (!config) if (!config)
return -EINVAL; return -EINVAL;
ret = convert_burst(config->src_maxburst, &src_burst); src_burst = convert_burst(config->src_maxburst);
if (ret) if (src_burst)
return ret; return src_burst;
ret = convert_burst(config->dst_maxburst, &dst_burst); dst_burst = convert_burst(config->dst_maxburst);
if (ret) if (dst_burst)
return ret; return dst_burst;
ret = convert_buswidth(config->src_addr_width, &src_width); src_width = convert_buswidth(config->src_addr_width);
if (ret) if (src_width)
return ret; return src_width;
ret = convert_buswidth(config->dst_addr_width, &dst_width); dst_width = convert_buswidth(config->dst_addr_width);
if (ret) if (dst_width)
return ret; return dst_width;
lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) | lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
DMA_CHAN_CFG_SRC_WIDTH(src_width) | DMA_CHAN_CFG_SRC_WIDTH(src_width) |
...@@ -542,11 +536,10 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( ...@@ -542,11 +536,10 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
{ {
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
struct sun6i_vchan *vchan = to_sun6i_vchan(chan); struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
struct dma_slave_config *sconfig = &vchan->cfg;
struct sun6i_dma_lli *v_lli; struct sun6i_dma_lli *v_lli;
struct sun6i_desc *txd; struct sun6i_desc *txd;
dma_addr_t p_lli; dma_addr_t p_lli;
int ret; s8 burst, width;
dev_dbg(chan2dev(chan), dev_dbg(chan2dev(chan),
"%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n", "%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n",
...@@ -565,14 +558,21 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( ...@@ -565,14 +558,21 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
goto err_txd_free; goto err_txd_free;
} }
ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig); v_lli->src = src;
if (ret) v_lli->dst = dest;
goto err_dma_free; v_lli->len = len;
v_lli->para = NORMAL_WAIT;
burst = convert_burst(8);
width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) | v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) | DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
DMA_CHAN_CFG_DST_LINEAR_MODE | DMA_CHAN_CFG_DST_LINEAR_MODE |
DMA_CHAN_CFG_SRC_LINEAR_MODE; DMA_CHAN_CFG_SRC_LINEAR_MODE |
DMA_CHAN_CFG_SRC_BURST(burst) |
DMA_CHAN_CFG_SRC_WIDTH(width) |
DMA_CHAN_CFG_DST_BURST(burst) |
DMA_CHAN_CFG_DST_WIDTH(width);
sun6i_dma_lli_add(NULL, v_lli, p_lli, txd); sun6i_dma_lli_add(NULL, v_lli, p_lli, txd);
...@@ -580,8 +580,6 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( ...@@ -580,8 +580,6 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
return vchan_tx_prep(&vchan->vc, &txd->vd, flags); return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
err_dma_free:
dma_pool_free(sdev->pool, v_lli, p_lli);
err_txd_free: err_txd_free:
kfree(txd); kfree(txd);
return NULL; return NULL;
...@@ -915,6 +913,7 @@ static int sun6i_dma_probe(struct platform_device *pdev) ...@@ -915,6 +913,7 @@ static int sun6i_dma_probe(struct platform_device *pdev)
sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy; sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy;
sdc->slave.device_control = sun6i_dma_control; sdc->slave.device_control = sun6i_dma_control;
sdc->slave.chancnt = NR_MAX_VCHANS; sdc->slave.chancnt = NR_MAX_VCHANS;
sdc->slave.copy_align = 4;
sdc->slave.dev = &pdev->dev; sdc->slave.dev = &pdev->dev;
......
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