diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-21 19:24:27 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-11-21 19:24:27 -0500 |
| commit | 4ec69c7ebc2cb8df1f33b26f4492481c452fef66 (patch) | |
| tree | be991a02923758c2afe09a13fe61650686bac8df | |
| parent | e6a588d086a75dc20afb8ffbcbe23a50d4a1ca37 (diff) | |
| parent | 1f0a5cbf61a54504236bbbe2c98b58e85f90e650 (diff) | |
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
| -rw-r--r-- | drivers/dma/pl330.c | 23 | ||||
| -rw-r--r-- | drivers/dma/sun6i-dma.c | 61 |
2 files changed, 46 insertions, 38 deletions
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 4839bfa74a10..19a99743cf52 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c | |||
| @@ -271,7 +271,7 @@ struct pl330_config { | |||
| 271 | #define DMAC_MODE_NS (1 << 0) | 271 | #define DMAC_MODE_NS (1 << 0) |
| 272 | unsigned int mode; | 272 | unsigned int mode; |
| 273 | unsigned int data_bus_width:10; /* In number of bits */ | 273 | unsigned int data_bus_width:10; /* In number of bits */ |
| 274 | unsigned int data_buf_dep:10; | 274 | unsigned int data_buf_dep:11; |
| 275 | unsigned int num_chan:4; | 275 | unsigned int num_chan:4; |
| 276 | unsigned int num_peri:6; | 276 | unsigned int num_peri:6; |
| 277 | u32 peri_ns; | 277 | u32 peri_ns; |
| @@ -2336,7 +2336,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) | |||
| 2336 | int burst_len; | 2336 | int burst_len; |
| 2337 | 2337 | ||
| 2338 | burst_len = pl330->pcfg.data_bus_width / 8; | 2338 | burst_len = pl330->pcfg.data_bus_width / 8; |
| 2339 | burst_len *= pl330->pcfg.data_buf_dep; | 2339 | burst_len *= pl330->pcfg.data_buf_dep / pl330->pcfg.num_chan; |
| 2340 | burst_len >>= desc->rqcfg.brst_size; | 2340 | burst_len >>= desc->rqcfg.brst_size; |
| 2341 | 2341 | ||
| 2342 | /* src/dst_burst_len can't be more than 16 */ | 2342 | /* 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 | /* Select max possible burst size */ | 2459 | /* Select max possible burst size */ |
| 2460 | burst = pl330->pcfg.data_bus_width / 8; | 2460 | burst = pl330->pcfg.data_bus_width / 8; |
| 2461 | 2461 | ||
| 2462 | while (burst > 1) { | 2462 | /* |
| 2463 | if (!(len % burst)) | 2463 | * Make sure we use a burst size that aligns with all the memcpy |
| 2464 | break; | 2464 | * parameters because our DMA programming algorithm doesn't cope with |
| 2465 | * transfers which straddle an entry in the DMA device's MFIFO. | ||
| 2466 | */ | ||
| 2467 | while ((src | dst | len) & (burst - 1)) | ||
| 2465 | burst /= 2; | 2468 | burst /= 2; |
| 2466 | } | ||
| 2467 | 2469 | ||
| 2468 | desc->rqcfg.brst_size = 0; | 2470 | desc->rqcfg.brst_size = 0; |
| 2469 | while (burst != (1 << desc->rqcfg.brst_size)) | 2471 | while (burst != (1 << desc->rqcfg.brst_size)) |
| 2470 | desc->rqcfg.brst_size++; | 2472 | desc->rqcfg.brst_size++; |
| 2471 | 2473 | ||
| 2474 | /* | ||
| 2475 | * If burst size is smaller than bus width then make sure we only | ||
| 2476 | * transfer one at a time to avoid a burst stradling an MFIFO entry. | ||
| 2477 | */ | ||
| 2478 | if (desc->rqcfg.brst_size * 8 < pl330->pcfg.data_bus_width) | ||
| 2479 | desc->rqcfg.brst_len = 1; | ||
| 2480 | |||
| 2472 | desc->rqcfg.brst_len = get_burst_len(desc, len); | 2481 | desc->rqcfg.brst_len = get_burst_len(desc, len); |
| 2473 | 2482 | ||
| 2474 | desc->txd.flags = flags; | 2483 | desc->txd.flags = flags; |
| @@ -2732,7 +2741,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) | |||
| 2732 | 2741 | ||
| 2733 | 2742 | ||
| 2734 | dev_info(&adev->dev, | 2743 | dev_info(&adev->dev, |
| 2735 | "Loaded driver for PL330 DMAC-%d\n", adev->periphid); | 2744 | "Loaded driver for PL330 DMAC-%x\n", adev->periphid); |
| 2736 | dev_info(&adev->dev, | 2745 | dev_info(&adev->dev, |
| 2737 | "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n", | 2746 | "\tDBUFF-%ux%ubytes Num_Chans-%u Num_Peri-%u Num_Events-%u\n", |
| 2738 | pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, | 2747 | pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, |
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 3aa10b328254..91292f5513ff 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c | |||
| @@ -230,30 +230,25 @@ static inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev, | |||
| 230 | readl(pchan->base + DMA_CHAN_CUR_PARA)); | 230 | readl(pchan->base + DMA_CHAN_CUR_PARA)); |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | static inline int convert_burst(u32 maxburst, u8 *burst) | 233 | static inline s8 convert_burst(u32 maxburst) |
| 234 | { | 234 | { |
| 235 | switch (maxburst) { | 235 | switch (maxburst) { |
| 236 | case 1: | 236 | case 1: |
| 237 | *burst = 0; | 237 | return 0; |
| 238 | break; | ||
| 239 | case 8: | 238 | case 8: |
| 240 | *burst = 2; | 239 | return 2; |
| 241 | break; | ||
| 242 | default: | 240 | default: |
| 243 | return -EINVAL; | 241 | return -EINVAL; |
| 244 | } | 242 | } |
| 245 | |||
| 246 | return 0; | ||
| 247 | } | 243 | } |
| 248 | 244 | ||
| 249 | static inline int convert_buswidth(enum dma_slave_buswidth addr_width, u8 *width) | 245 | static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width) |
| 250 | { | 246 | { |
| 251 | if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) || | 247 | if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) || |
| 252 | (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)) | 248 | (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)) |
| 253 | return -EINVAL; | 249 | return -EINVAL; |
| 254 | 250 | ||
| 255 | *width = addr_width >> 1; | 251 | return addr_width >> 1; |
| 256 | return 0; | ||
| 257 | } | 252 | } |
| 258 | 253 | ||
| 259 | static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev, | 254 | 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 | struct dma_slave_config *config) | 279 | struct dma_slave_config *config) |
| 285 | { | 280 | { |
| 286 | u8 src_width, dst_width, src_burst, dst_burst; | 281 | u8 src_width, dst_width, src_burst, dst_burst; |
| 287 | int ret; | ||
| 288 | 282 | ||
| 289 | if (!config) | 283 | if (!config) |
| 290 | return -EINVAL; | 284 | return -EINVAL; |
| 291 | 285 | ||
| 292 | ret = convert_burst(config->src_maxburst, &src_burst); | 286 | src_burst = convert_burst(config->src_maxburst); |
| 293 | if (ret) | 287 | if (src_burst) |
| 294 | return ret; | 288 | return src_burst; |
| 295 | 289 | ||
| 296 | ret = convert_burst(config->dst_maxburst, &dst_burst); | 290 | dst_burst = convert_burst(config->dst_maxburst); |
| 297 | if (ret) | 291 | if (dst_burst) |
| 298 | return ret; | 292 | return dst_burst; |
| 299 | 293 | ||
| 300 | ret = convert_buswidth(config->src_addr_width, &src_width); | 294 | src_width = convert_buswidth(config->src_addr_width); |
| 301 | if (ret) | 295 | if (src_width) |
| 302 | return ret; | 296 | return src_width; |
| 303 | 297 | ||
| 304 | ret = convert_buswidth(config->dst_addr_width, &dst_width); | 298 | dst_width = convert_buswidth(config->dst_addr_width); |
| 305 | if (ret) | 299 | if (dst_width) |
| 306 | return ret; | 300 | return dst_width; |
| 307 | 301 | ||
| 308 | lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) | | 302 | lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) | |
| 309 | DMA_CHAN_CFG_SRC_WIDTH(src_width) | | 303 | DMA_CHAN_CFG_SRC_WIDTH(src_width) | |
| @@ -542,11 +536,10 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( | |||
| 542 | { | 536 | { |
| 543 | struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); | 537 | struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); |
| 544 | struct sun6i_vchan *vchan = to_sun6i_vchan(chan); | 538 | struct sun6i_vchan *vchan = to_sun6i_vchan(chan); |
| 545 | struct dma_slave_config *sconfig = &vchan->cfg; | ||
| 546 | struct sun6i_dma_lli *v_lli; | 539 | struct sun6i_dma_lli *v_lli; |
| 547 | struct sun6i_desc *txd; | 540 | struct sun6i_desc *txd; |
| 548 | dma_addr_t p_lli; | 541 | dma_addr_t p_lli; |
| 549 | int ret; | 542 | s8 burst, width; |
| 550 | 543 | ||
| 551 | dev_dbg(chan2dev(chan), | 544 | dev_dbg(chan2dev(chan), |
| 552 | "%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n", | 545 | "%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 | goto err_txd_free; | 558 | goto err_txd_free; |
| 566 | } | 559 | } |
| 567 | 560 | ||
| 568 | ret = sun6i_dma_cfg_lli(v_lli, src, dest, len, sconfig); | 561 | v_lli->src = src; |
| 569 | if (ret) | 562 | v_lli->dst = dest; |
| 570 | goto err_dma_free; | 563 | v_lli->len = len; |
| 564 | v_lli->para = NORMAL_WAIT; | ||
| 571 | 565 | ||
| 566 | burst = convert_burst(8); | ||
| 567 | width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES); | ||
| 572 | v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) | | 568 | v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) | |
