diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2014-07-16 17:15:48 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2014-12-23 04:13:02 -0500 |
commit | ccadee9b1e90dc6d3d97a20ac96cb1a82e0d5a1d (patch) | |
tree | f0ea642c3e287ddbd274789216e8234bf788885f | |
parent | 87244fe5abdf1dbaf4e438d80cf641bf3c01d5cf (diff) |
dmaengine: rcar-dmac: Implement support for hardware descriptor lists
The DMAC supports hardware-based auto-configuration from descriptor
lists. This reduces the number of interrupts required for processing a
DMA transfer. Support that mode in the driver.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
-rw-r--r-- | drivers/dma/sh/rcar-dmac.c | 304 |
1 files changed, 253 insertions, 51 deletions
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 89d40f9730ba..6e7cdab61827 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/dma-mapping.h> | ||
13 | #include <linux/dmaengine.h> | 14 | #include <linux/dmaengine.h> |
14 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
15 | #include <linux/list.h> | 16 | #include <linux/list.h> |
@@ -41,6 +42,19 @@ struct rcar_dmac_xfer_chunk { | |||
41 | }; | 42 | }; |
42 | 43 | ||
43 | /* | 44 | /* |
45 | * struct rcar_dmac_hw_desc - Hardware descriptor for a transfer chunk | ||
46 | * @sar: value of the SAR register (source address) | ||
47 | * @dar: value of the DAR register (destination address) | ||
48 | * @tcr: value of the TCR register (transfer count) | ||
49 | */ | ||
50 | struct rcar_dmac_hw_desc { | ||
51 | u32 sar; | ||
52 | u32 dar; | ||
53 | u32 tcr; | ||
54 | u32 reserved; | ||
55 | } __attribute__((__packed__)); | ||
56 | |||
57 | /* | ||
44 | * struct rcar_dmac_desc - R-Car Gen2 DMA Transfer Descriptor | 58 | * struct rcar_dmac_desc - R-Car Gen2 DMA Transfer Descriptor |
45 | * @async_tx: base DMA asynchronous transaction descriptor | 59 | * @async_tx: base DMA asynchronous transaction descriptor |
46 | * @direction: direction of the DMA transfer | 60 | * @direction: direction of the DMA transfer |
@@ -49,6 +63,10 @@ struct rcar_dmac_xfer_chunk { | |||
49 | * @node: entry in the channel's descriptors lists | 63 | * @node: entry in the channel's descriptors lists |
50 | * @chunks: list of transfer chunks for this transfer | 64 | * @chunks: list of transfer chunks for this transfer |
51 | * @running: the transfer chunk being currently processed | 65 | * @running: the transfer chunk being currently processed |
66 | * @nchunks: number of transfer chunks for this transfer | ||
67 | * @hwdescs.mem: hardware descriptors memory for the transfer | ||
68 | * @hwdescs.dma: device address of the hardware descriptors memory | ||
69 | * @hwdescs.size: size of the hardware descriptors in bytes | ||
52 | * @size: transfer size in bytes | 70 | * @size: transfer size in bytes |
53 | * @cyclic: when set indicates that the DMA transfer is cyclic | 71 | * @cyclic: when set indicates that the DMA transfer is cyclic |
54 | */ | 72 | */ |
@@ -61,6 +79,13 @@ struct rcar_dmac_desc { | |||
61 | struct list_head node; | 79 | struct list_head node; |
62 | struct list_head chunks; | 80 | struct list_head chunks; |
63 | struct rcar_dmac_xfer_chunk *running; | 81 | struct rcar_dmac_xfer_chunk *running; |
82 | unsigned int nchunks; | ||
83 | |||
84 | struct { | ||
85 | struct rcar_dmac_hw_desc *mem; | ||
86 | dma_addr_t dma; | ||
87 | size_t size; | ||
88 | } hwdescs; | ||
64 | 89 | ||
65 | unsigned int size; | 90 | unsigned int size; |
66 | bool cyclic; | 91 | bool cyclic; |
@@ -217,7 +242,8 @@ struct rcar_dmac { | |||
217 | #define RCAR_DMATSRB 0x0038 | 242 | #define RCAR_DMATSRB 0x0038 |
218 | #define RCAR_DMACHCRB 0x001c | 243 | #define RCAR_DMACHCRB 0x001c |
219 | #define RCAR_DMACHCRB_DCNT(n) ((n) << 24) | 244 | #define RCAR_DMACHCRB_DCNT(n) ((n) << 24) |
220 | #define RCAR_DMACHCRB_DPTR(n) ((n) << 16) | 245 | #define RCAR_DMACHCRB_DPTR_MASK (0xff << 16) |
246 | #define RCAR_DMACHCRB_DPTR_SHIFT 16 | ||
221 | #define RCAR_DMACHCRB_DRST (1 << 15) | 247 | #define RCAR_DMACHCRB_DRST (1 << 15) |
222 | #define RCAR_DMACHCRB_DTS (1 << 8) | 248 | #define RCAR_DMACHCRB_DTS (1 << 8) |
223 | #define RCAR_DMACHCRB_SLM_NORMAL (0 << 4) | 249 | #define RCAR_DMACHCRB_SLM_NORMAL (0 << 4) |
@@ -289,30 +315,81 @@ static bool rcar_dmac_chan_is_busy(struct rcar_dmac_chan *chan) | |||
289 | static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan) | 315 | static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan) |
290 | { | 316 | { |
291 | struct rcar_dmac_desc *desc = chan->desc.running; | 317 | struct rcar_dmac_desc *desc = chan->desc.running; |
292 | struct rcar_dmac_xfer_chunk *chunk = desc->running; | 318 | u32 chcr = desc->chcr; |
293 | |||
294 | dev_dbg(chan->chan.device->dev, | ||
295 | "chan%u: queue chunk %p: %u@%pad -> %pad\n", | ||
296 | chan->index, chunk, chunk->size, &chunk->src_addr, | ||
297 | &chunk->dst_addr); | ||
298 | 319 | ||
299 | WARN_ON_ONCE(rcar_dmac_chan_is_busy(chan)); | 320 | WARN_ON_ONCE(rcar_dmac_chan_is_busy(chan)); |
300 | 321 | ||
322 | if (chan->mid_rid >= 0) | ||
323 | rcar_dmac_chan_write(chan, RCAR_DMARS, chan->mid_rid); | ||
324 | |||
325 | if (desc->hwdescs.mem) { | ||
326 | dev_dbg(chan->chan.device->dev, | ||
327 | "chan%u: queue desc %p: %u@%pad\n", | ||
328 | chan->index, desc, desc->nchunks, &desc->hwdescs.dma); | ||
329 | |||
301 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | 330 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT |
302 | rcar_dmac_chan_write(chan, RCAR_DMAFIXSAR, chunk->src_addr >> 32); | 331 | rcar_dmac_chan_write(chan, RCAR_DMAFIXDPBASE, |
303 | rcar_dmac_chan_write(chan, RCAR_DMAFIXDAR, chunk->dst_addr >> 32); | 332 | desc->hwdescs.dma >> 32); |
304 | #endif | 333 | #endif |
305 | rcar_dmac_chan_write(chan, RCAR_DMASAR, chunk->src_addr & 0xffffffff); | 334 | rcar_dmac_chan_write(chan, RCAR_DMADPBASE, |
306 | rcar_dmac_chan_write(chan, RCAR_DMADAR, chunk->dst_addr & 0xffffffff); | 335 | (desc->hwdescs.dma & 0xfffffff0) | |
336 | RCAR_DMADPBASE_SEL); | ||
337 | rcar_dmac_chan_write(chan, RCAR_DMACHCRB, | ||
338 | RCAR_DMACHCRB_DCNT(desc->nchunks - 1) | | ||
339 | RCAR_DMACHCRB_DRST); | ||
307 | 340 | ||
308 | if (chan->mid_rid >= 0) | 341 | /* |
309 | rcar_dmac_chan_write(chan, RCAR_DMARS, chan->mid_rid); | 342 | * Program the descriptor stage interrupt to occur after the end |
343 | * of the first stage. | ||
344 | */ | ||
345 | rcar_dmac_chan_write(chan, RCAR_DMADPCR, RCAR_DMADPCR_DIPT(1)); | ||
346 | |||
347 | chcr |= RCAR_DMACHCR_RPT_SAR | RCAR_DMACHCR_RPT_DAR | ||
348 | | RCAR_DMACHCR_RPT_TCR | RCAR_DMACHCR_DPB; | ||
349 | |||
350 | /* | ||
351 | * If the descriptor isn't cyclic enable normal descriptor mode | ||
352 | * and the transfer completion interrupt. | ||
353 | */ | ||
354 | if (!desc->cyclic) | ||
355 | chcr |= RCAR_DMACHCR_DPM_ENABLED | RCAR_DMACHCR_IE; | ||
356 | /* | ||
357 | * If the descriptor is cyclic and has a callback enable the | ||
358 | * descriptor stage interrupt in infinite repeat mode. | ||
359 | */ | ||
360 | else if (desc->async_tx.callback) | ||
361 | chcr |= RCAR_DMACHCR_DPM_INFINITE | RCAR_DMACHCR_DSIE; | ||
362 | /* | ||
363 | * Otherwise just select infinite repeat mode without any | ||
364 | * interrupt. | ||
365 | */ | ||
366 | else | ||
367 | chcr |= RCAR_DMACHCR_DPM_INFINITE; | ||
368 | } else { | ||
369 | struct rcar_dmac_xfer_chunk *chunk = desc->running; | ||
310 | 370 | ||
311 | rcar_dmac_chan_write(chan, RCAR_DMATCR, | 371 | dev_dbg(chan->chan.device->dev, |
312 | chunk->size >> desc->xfer_shift); | 372 | "chan%u: queue chunk %p: %u@%pad -> %pad\n", |
373 | chan->index, chunk, chunk->size, &chunk->src_addr, | ||
374 | &chunk->dst_addr); | ||
313 | 375 | ||
314 | rcar_dmac_chan_write(chan, RCAR_DMACHCR, desc->chcr | RCAR_DMACHCR_DE | | 376 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT |
315 | RCAR_DMACHCR_IE); | 377 | rcar_dmac_chan_write(chan, RCAR_DMAFIXSAR, |
378 | chunk->src_addr >> 32); | ||
379 | rcar_dmac_chan_write(chan, RCAR_DMAFIXDAR, | ||
380 | chunk->dst_addr >> 32); | ||
381 | #endif | ||
382 | rcar_dmac_chan_write(chan, RCAR_DMASAR, | ||
383 | chunk->src_addr & 0xffffffff); | ||
384 | rcar_dmac_chan_write(chan, RCAR_DMADAR, | ||
385 | chunk->dst_addr & 0xffffffff); | ||
386 | rcar_dmac_chan_write(chan, RCAR_DMATCR, | ||
387 | chunk->size >> desc->xfer_shift); | ||
388 | |||
389 | chcr |= RCAR_DMACHCR_DPM_DISABLED | RCAR_DMACHCR_IE; | ||
390 | } | ||
391 | |||
392 | rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr | RCAR_DMACHCR_DE); | ||
316 | } | 393 | } |
317 | 394 | ||
318 | static int rcar_dmac_init(struct rcar_dmac *dmac) | 395 | static int rcar_dmac_init(struct rcar_dmac *dmac) |
@@ -403,31 +480,58 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp) | |||
403 | * @desc: the descriptor | 480 | * @desc: the descriptor |
404 | * | 481 | * |
405 | * Put the descriptor and its transfer chunk descriptors back in the channel's | 482 | * Put the descriptor and its transfer chunk descriptors back in the channel's |
406 | * free descriptors lists. The descriptor's chunk will be reinitialized to an | 483 | * free descriptors lists, and free the hardware descriptors list memory. The |
407 | * empty list as a result. | 484 | * descriptor's chunks list will be reinitialized to an empty list as a result. |
408 | * | 485 | * |
409 | * The descriptor must have been removed from the channel's done list before | 486 | * The descriptor must have been removed from the channel's lists before calling |
410 | * calling this function. | 487 | * this function. |
411 | * | 488 | * |
412 | * Locking: Must be called with the channel lock held. | 489 | * Locking: Must be called in non-atomic context. |
413 | */ | 490 | */ |
414 | static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan, | 491 | static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan, |
415 | struct rcar_dmac_desc *desc) | 492 | struct rcar_dmac_desc *desc) |
416 | { | 493 | { |
494 | if (desc->hwdescs.mem) { | ||
495 | dma_free_coherent(NULL, desc->hwdescs.size, desc->hwdescs.mem, | ||
496 | desc->hwdescs.dma); | ||
497 | desc->hwdescs.mem = NULL; | ||
498 | } | ||
499 | |||
500 | spin_lock_irq(&chan->lock); | ||
417 | list_splice_tail_init(&desc->chunks, &chan->desc.chunks_free); | 501 | list_splice_tail_init(&desc->chunks, &chan->desc.chunks_free); |
418 | list_add_tail(&desc->node, &chan->desc.free); | 502 | list_add_tail(&desc->node, &chan->desc.free); |
503 | spin_unlock_irq(&chan->lock); | ||
419 | } | 504 | } |
420 | 505 | ||
421 | static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) | 506 | static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan) |
422 | { | 507 | { |
423 | struct rcar_dmac_desc *desc, *_desc; | 508 | struct rcar_dmac_desc *desc, *_desc; |
509 | LIST_HEAD(list); | ||
424 | 510 | ||
425 | list_for_each_entry_safe(desc, _desc, &chan->desc.wait, node) { | 511 | /* |
512 | * We have to temporarily move all descriptors from the wait list to a | ||
513 | * local list as iterating over the wait list, even with | ||
514 | * list_for_each_entry_safe, isn't safe if we release the channel lock | ||
515 | * around the rcar_dmac_desc_put() call. | ||
516 | */ | ||
517 | spin_lock_irq(&chan->lock); | ||
518 | list_splice_init(&chan->desc.wait, &list); | ||
519 | spin_unlock_irq(&chan->lock); | ||
520 | |||
521 | list_for_each_entry_safe(desc, _desc, &list, node) { | ||
426 | if (async_tx_test_ack(&desc->async_tx)) { | 522 | if (async_tx_test_ack(&desc->async_tx)) { |
427 | list_del(&desc->node); | 523 | list_del(&desc->node); |
428 | rcar_dmac_desc_put(chan, desc); | 524 | rcar_dmac_desc_put(chan, desc); |
429 | } | 525 | } |
430 | } | 526 | } |
527 | |||
528 | if (list_empty(&list)) | ||
529 | return; | ||
530 | |||
531 | /* Put the remaining descriptors back in the wait list. */ | ||
532 | spin_lock_irq(&chan->lock); | ||
533 | list_splice(&list, &chan->desc.wait); | ||
534 | spin_unlock_irq(&chan->lock); | ||
431 | } | 535 | } |
432 | 536 | ||
433 | /* | 537 | /* |
@@ -444,11 +548,11 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan) | |||
444 | struct rcar_dmac_desc *desc; | 548 | struct rcar_dmac_desc *desc; |
445 | int ret; | 549 | int ret; |
446 | 550 | ||
447 | spin_lock_irq(&chan->lock); | ||
448 | |||
449 | /* Recycle acked descriptors before attempting allocation. */ | 551 | /* Recycle acked descriptors before attempting allocation. */ |
450 | rcar_dmac_desc_recycle_acked(chan); | 552 | rcar_dmac_desc_recycle_acked(chan); |
451 | 553 | ||
554 | spin_lock_irq(&chan->lock); | ||
555 | |||
452 | do { | 556 | do { |
453 | if (list_empty(&chan->desc.free)) { | 557 | if (list_empty(&chan->desc.free)) { |
454 | /* | 558 | /* |
@@ -547,6 +651,28 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan) | |||
547 | return chunk; | 651 | return chunk; |
548 | } | 652 | } |
549 | 653 | ||
654 | static void rcar_dmac_alloc_hwdesc(struct rcar_dmac_chan *chan, | ||
655 | struct rcar_dmac_desc *desc) | ||
656 | { | ||
657 | struct rcar_dmac_xfer_chunk *chunk; | ||
658 | struct rcar_dmac_hw_desc *hwdesc; | ||
659 | size_t size = desc->nchunks * sizeof(*hwdesc); | ||
660 | |||
661 | hwdesc = dma_alloc_coherent(NULL, size, &desc->hwdescs.dma, GFP_NOWAIT); | ||
662 | if (!hwdesc) | ||
663 | return; | ||
664 | |||
665 | desc->hwdescs.mem = hwdesc; | ||
666 | desc->hwdescs.size = size; | ||
667 | |||
668 | list_for_each_entry(chunk, &desc->chunks, node) { | ||
669 | hwdesc->sar = chunk->src_addr; | ||
670 | hwdesc->dar = chunk->dst_addr; | ||
671 | hwdesc->tcr = chunk->size >> desc->xfer_shift; | ||
672 | hwdesc++; | ||
673 | } | ||
674 | } | ||
675 | |||
550 | /* ----------------------------------------------------------------------------- | 676 | /* ----------------------------------------------------------------------------- |
551 | * Stop and reset | 677 | * Stop and reset |
552 | */ | 678 | */ |
@@ -555,7 +681,8 @@ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan) | |||
555 | { | 681 | { |
556 | u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR); | 682 | u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR); |
557 | 683 | ||
558 | chcr &= ~(RCAR_DMACHCR_IE | RCAR_DMACHCR_TE | RCAR_DMACHCR_DE); | 684 | chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE | |
685 | RCAR_DMACHCR_TE | RCAR_DMACHCR_DE); | ||
559 | rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr); | 686 | rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr); |
560 | } | 687 | } |
561 | 688 | ||
@@ -666,8 +793,10 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, | |||
666 | struct rcar_dmac_xfer_chunk *chunk; | 793 | struct rcar_dmac_xfer_chunk *chunk; |
667 | struct rcar_dmac_desc *desc; | 794 | struct rcar_dmac_desc *desc; |
668 | struct scatterlist *sg; | 795 | struct scatterlist *sg; |
796 | unsigned int nchunks = 0; | ||
669 | unsigned int max_chunk_size; | 797 | unsigned int max_chunk_size; |
670 | unsigned int full_size = 0; | 798 | unsigned int full_size = 0; |
799 | bool highmem = false; | ||
671 | unsigned int i; | 800 | unsigned int i; |
672 | 801 | ||
673 | desc = rcar_dmac_desc_get(chan); | 802 | desc = rcar_dmac_desc_get(chan); |
@@ -706,6 +835,14 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, | |||
706 | size = ALIGN(dev_addr, 1ULL << 32) - dev_addr; | 835 | size = ALIGN(dev_addr, 1ULL << 32) - dev_addr; |
707 | if (mem_addr >> 32 != (mem_addr + size - 1) >> 32) | 836 | if (mem_addr >> 32 != (mem_addr + size - 1) >> 32) |
708 | size = ALIGN(mem_addr, 1ULL << 32) - mem_addr; | 837 | size = ALIGN(mem_addr, 1ULL << 32) - mem_addr; |
838 | |||
839 | /* | ||
840 | * Check if either of the source or destination address | ||
841 | * can't be expressed in 32 bits. If so we can't use | ||
842 | * hardware descriptor lists. | ||
843 | */ | ||
844 | if (dev_addr >> 32 || mem_addr >> 32) | ||
845 | highmem = true; | ||
709 | #endif | 846 | #endif |
710 | 847 | ||
711 | chunk = rcar_dmac_xfer_chunk_get(chan); | 848 | chunk = rcar_dmac_xfer_chunk_get(chan); |
@@ -736,11 +873,26 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl, | |||
736 | len -= size; | 873 | len -= size; |
737 | 874 | ||
738 | list_add_tail(&chunk->node, &desc->chunks); | 875 | list_add_tail(&chunk->node, &desc->chunks); |
876 | nchunks++; | ||
739 | } | 877 | } |
740 | } | 878 | } |
741 | 879 | ||
880 | desc->nchunks = nchunks; | ||
742 | desc->size = full_size; | 881 | desc->size = full_size; |
743 | 882 | ||
883 | /* | ||
884 | * Use hardware descriptor lists if possible when more than one chunk | ||
885 | * needs to be transferred (otherwise they don't make much sense). | ||
886 | * | ||
887 | * The highmem check currently covers the whole transfer. As an | ||
888 | * optimization we could use descriptor lists for consecutive lowmem | ||
889 | * chunks and direct manual mode for highmem chunks. Whether the | ||
890 | * performance improvement would be significant enough compared to the | ||
891 | * additional complexity remains to be investigated. | ||
892 | */ | ||
893 | if (!highmem && nchunks > 1) | ||
894 | rcar_dmac_alloc_hwdesc(chan, desc); | ||
895 | |||
744 | return &desc->async_tx; | 896 | return &desc->async_tx; |
745 | } | 897 | } |
746 | 898 | ||
@@ -940,8 +1092,10 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, | |||
940 | dma_cookie_t cookie) | 1092 | dma_cookie_t cookie) |
941 | { | 1093 | { |
942 | struct rcar_dmac_desc *desc = chan->desc.running; | 1094 | struct rcar_dmac_desc *desc = chan->desc.running; |
1095 | struct rcar_dmac_xfer_chunk *running = NULL; | ||
943 | struct rcar_dmac_xfer_chunk *chunk; | 1096 | struct rcar_dmac_xfer_chunk *chunk; |
944 | unsigned int residue = 0; | 1097 | unsigned int residue = 0; |
1098 | unsigned int dptr = 0; | ||
945 | 1099 | ||
946 | if (!desc) | 1100 | if (!desc) |
947 | return 0; | 1101 | return 0; |
@@ -954,9 +1108,23 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan, | |||
954 | if (cookie != desc->async_tx.cookie) | 1108 | if (cookie != desc->async_tx.cookie) |
955 | return desc->size; | 1109 | return desc->size; |
956 | 1110 | ||
1111 | /* | ||
1112 | * In descriptor mode the descriptor running pointer is not maintained | ||
1113 | * by the interrupt handler, find the running descriptor from the | ||
1114 | * descriptor pointer field in the CHCRB register. In non-descriptor | ||
1115 | * mode just use the running descriptor pointer. | ||
1116 | */ | ||
1117 | if (desc->hwdescs.mem) { | ||
1118 | dptr = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) & | ||
1119 | RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT; | ||
1120 | WARN_ON(dptr >= desc->nchunks); | ||
1121 | } else { | ||
1122 | running = desc->running; | ||
1123 | } | ||
1124 | |||
957 | /* Compute the size of all chunks still to be transferred. */ | 1125 | /* Compute the size of all chunks still to be transferred. */ |
958 | list_for_each_entry_reverse(chunk, &desc->chunks, node) { | 1126 | list_for_each_entry_reverse(chunk, &desc->chunks, node) { |
959 | if (chunk == desc->running) | 1127 | if (chunk == running || ++dptr == desc->nchunks) |
960 | break; | 1128 | break; |
961 | 1129 | ||
962 | residue += chunk->size; | 1130 | residue += chunk->size; |
@@ -1025,42 +1193,71 @@ done: | |||
1025 | * IRQ handling | 1193 | * IRQ handling |
1026 | */ | 1194 | */ |
1027 | 1195 | ||
1196 | static irqreturn_t rcar_dmac_isr_desc_stage_end(struct rcar_dmac_chan *chan) | ||
1197 | { | ||
1198 | struct rcar_dmac_desc *desc = chan->desc.running; | ||
1199 | unsigned int stage; | ||
1200 | |||
1201 | if (WARN_ON(!desc || !desc->cyclic)) { | ||
1202 | /* | ||
1203 | * This should never happen, there should always be a running | ||
1204 | * cyclic descriptor when a descriptor stage end interrupt is | ||
1205 | * triggered. Warn and return. | ||
1206 | */ | ||
1207 | return IRQ_NONE; | ||
1208 | } | ||
1209 | |||
1210 | /* Program the interrupt pointer to the next stage. */ | ||
1211 | stage = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) & | ||
1212 | RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT; | ||
1213 | rcar_dmac_chan_write(chan, RCAR_DMADPCR, RCAR_DMADPCR_DIPT(stage)); | ||
1214 | |||
1215 | return IRQ_WAKE_THREAD; | ||
1216 | } | ||
1217 | |||
1028 | static irqreturn_t rcar_dmac_isr_transfer_end(struct rcar_dmac_chan *chan) | 1218 | static irqreturn_t rcar_dmac_isr_transfer_end(struct rcar_dmac_chan *chan) |
1029 | { | 1219 | { |
1030 | struct rcar_dmac_desc *desc = chan->desc.running; | 1220 | struct rcar_dmac_desc *desc = chan->desc.running; |
1031 | struct rcar_dmac_xfer_chunk *chunk; | ||
1032 | irqreturn_t ret = IRQ_WAKE_THREAD; | 1221 | irqreturn_t ret = IRQ_WAKE_THREAD; |
1033 | 1222 | ||
1034 | if (WARN_ON_ONCE(!desc)) { | 1223 | if (WARN_ON_ONCE(!desc)) { |
1035 | /* | 1224 | /* |
1036 | * This should never happen, there should always be | 1225 | * This should never happen, there should always be a running |
1037 | * a running descriptor when a transfer ends. Warn and | 1226 | * descriptor when a transfer end interrupt is triggered. Warn |
1038 | * return. | 1227 | * and return. |
1039 | */ | 1228 | */ |
1040 | return IRQ_NONE; | 1229 | return IRQ_NONE; |
1041 | } | 1230 | } |
1042 | 1231 | ||
1043 | /* | 1232 | /* |
1044 | * If we haven't completed the last transfer chunk simply move to the | 1233 | * The transfer end interrupt isn't generated for each chunk when using |
1045 | * next one. Only wake the IRQ thread if the transfer is cyclic. | 1234 | * descriptor mode. Only update the running chunk pointer in |
1235 | * non-descriptor mode. | ||
1046 | */ | 1236 | */ |
1047 | chunk = desc->running; | 1237 | if (!desc->hwdescs.mem) { |
1048 | if (!list_is_last(&chunk->node, &desc->chunks)) { | 1238 | /* |
1049 | desc->running = list_next_entry(chunk, node); | 1239 | * If we haven't completed the last transfer chunk simply move |
1050 | if (!desc->cyclic) | 1240 | * to the next one. Only wake the IRQ thread if the transfer is |
1051 | ret = IRQ_HANDLED; | 1241 | * cyclic. |
1052 | goto done; | 1242 | */ |
1053 | } | 1243 | if (!list_is_last(&desc->running->node, &desc->chunks)) { |
1244 | desc->running = list_next_entry(desc->running, node); | ||
1245 | if (!desc->cyclic) | ||
1246 | ret = IRQ_HANDLED; | ||
1247 | goto done; | ||
1248 | } | ||
1054 | 1249 | ||
1055 | /* | 1250 | /* |
1056 | * We've completed the last transfer chunk. If the transfer is cyclic, | 1251 | * We've completed the last transfer chunk. If the transfer is |
1057 | * move back to the first one. | 1252 | * cyclic, move back to the first one. |
1058 | */ | 1253 | */ |
1059 | if (desc->cyclic) { | 1254 | if (desc->cyclic) { |
1060 | desc->running = list_first_entry(&desc->chunks, | 1255 | desc->running = |
1256 | list_first_entry(&desc->chunks, | ||
1061 | struct rcar_dmac_xfer_chunk, | 1257 | struct rcar_dmac_xfer_chunk, |
1062 | node); | 1258 | node); |
1063 | goto done; | 1259 | goto done; |
1260 | } | ||
1064 | } | 1261 | } |
1065 | 1262 | ||
1066 | /* The descriptor is complete, move it to the done list. */ | 1263 | /* The descriptor is complete, move it to the done list. */ |
@@ -1083,6 +1280,7 @@ done: | |||
1083 | 1280 | ||
1084 | static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev) | 1281 | static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev) |
1085 | { | 1282 | { |
1283 | u32 mask = RCAR_DMACHCR_DSE | RCAR_DMACHCR_TE; | ||
1086 | struct rcar_dmac_chan *chan = dev; | 1284 | struct rcar_dmac_chan *chan = dev; |
1087 | irqreturn_t ret = IRQ_NONE; | 1285 | irqreturn_t ret = IRQ_NONE; |
1088 | u32 chcr; | 1286 | u32 chcr; |
@@ -1090,8 +1288,12 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev) | |||
1090 | spin_lock(&chan->lock); | 1288 | spin_lock(&chan->lock); |
1091 | 1289 | ||
1092 | chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR); | 1290 | chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR); |
1093 | rcar_dmac_chan_write(chan, RCAR_DMACHCR, | 1291 | if (chcr & RCAR_DMACHCR_TE) |
1094 | chcr & ~(RCAR_DMACHCR_TE | RCAR_DMACHCR_DE)); | 1292 | mask |= RCAR_DMACHCR_DE; |
1293 | rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask); | ||
1294 | |||
1295 | if (chcr & RCAR_DMACHCR_DSE) | ||
1296 | ret |= rcar_dmac_isr_desc_stage_end(chan); | ||
1095 | 1297 | ||
1096 | if (chcr & RCAR_DMACHCR_TE) | 1298 | if (chcr & RCAR_DMACHCR_TE) |
1097 | ret |= rcar_dmac_isr_transfer_end(chan); | 1299 | ret |= rcar_dmac_isr_transfer_end(chan); |
@@ -1148,11 +1350,11 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev) | |||
1148 | list_add_tail(&desc->node, &chan->desc.wait); | 1350 | list_add_tail(&desc->node, &chan->desc.wait); |
1149 | } | 1351 | } |
1150 | 1352 | ||
1353 | spin_unlock_irq(&chan->lock); | ||
1354 | |||
1151 | /* Recycle all acked descriptors. */ | 1355 | /* Recycle all acked descriptors. */ |
1152 | rcar_dmac_desc_recycle_acked(chan); | 1356 | rcar_dmac_desc_recycle_acked(chan); |
1153 | 1357 | ||
1154 | spin_unlock_irq(&chan->lock); | ||
1155 | |||
1156 | return IRQ_HANDLED; | 1358 | return IRQ_HANDLED; |
1157 | } | 1359 | } |
1158 | 1360 | ||