aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIra Snyder <iws@ovro.caltech.edu>2010-09-30 07:46:45 -0400
committerDan Williams <dan.j.williams@intel.com>2010-10-07 17:41:41 -0400
commitc14330417ef2050f4bf38ac20e125785fea14351 (patch)
tree0b8352bd377d873feff3ec684c0c027f89aa7b14 /drivers
parenta86ee03ce6f279ebe581a7a8c0c4393eaeb789ee (diff)
fsldma: implement support for scatterlist to scatterlist copy
Now that the DMAEngine API has support for scatterlist to scatterlist copy, implement support for the Freescale DMA controller. Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dma/fsldma.c128
1 files changed, 125 insertions, 3 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index cea08bed9cf9..1ed29d10a5fa 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -38,6 +38,8 @@
38#include <asm/fsldma.h> 38#include <asm/fsldma.h>
39#include "fsldma.h" 39#include "fsldma.h"
40 40
41static const char msg_ld_oom[] = "No free memory for link descriptor\n";
42
41static void dma_init(struct fsldma_chan *chan) 43static void dma_init(struct fsldma_chan *chan)
42{ 44{
43 /* Reset the channel */ 45 /* Reset the channel */
@@ -499,7 +501,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
499 501
500 new = fsl_dma_alloc_descriptor(chan); 502 new = fsl_dma_alloc_descriptor(chan);
501 if (!new) { 503 if (!new) {
502 dev_err(chan->dev, "No free memory for link descriptor\n"); 504 dev_err(chan->dev, msg_ld_oom);
503 return NULL; 505 return NULL;
504 } 506 }
505 507
@@ -536,8 +538,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
536 /* Allocate the link descriptor from DMA pool */ 538 /* Allocate the link descriptor from DMA pool */
537 new = fsl_dma_alloc_descriptor(chan); 539 new = fsl_dma_alloc_descriptor(chan);
538 if (!new) { 540 if (!new) {
539 dev_err(chan->dev, 541 dev_err(chan->dev, msg_ld_oom);
540 "No free memory for link descriptor\n");
541 goto fail; 542 goto fail;
542 } 543 }
543#ifdef FSL_DMA_LD_DEBUG 544#ifdef FSL_DMA_LD_DEBUG
@@ -583,6 +584,125 @@ fail:
583 return NULL; 584 return NULL;
584} 585}
585 586
587static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
588 struct scatterlist *dst_sg, unsigned int dst_nents,
589 struct scatterlist *src_sg, unsigned int src_nents,
590 unsigned long flags)
591{
592 struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
593 struct fsldma_chan *chan = to_fsl_chan(dchan);
594 size_t dst_avail, src_avail;
595 dma_addr_t dst, src;
596 size_t len;
597
598 /* basic sanity checks */
599 if (dst_nents == 0 || src_nents == 0)
600 return NULL;
601
602 if (dst_sg == NULL || src_sg == NULL)
603 return NULL;
604
605 /*
606 * TODO: should we check that both scatterlists have the same
607 * TODO: number of bytes in total? Is that really an error?
608 */
609
610 /* get prepared for the loop */
611 dst_avail = sg_dma_len(dst_sg);
612 src_avail = sg_dma_len(src_sg);
613
614 /* run until we are out of scatterlist entries */
615 while (true) {
616
617 /* create the largest transaction possible */
618 len = min_t(size_t, src_avail, dst_avail);
619 len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT);
620 if (len == 0)
621 goto fetch;
622
623 dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail;
624 src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail;
625
626 /* allocate and populate the descriptor */
627 new = fsl_dma_alloc_descriptor(chan);
628 if (!new) {
629 dev_err(chan->dev, msg_ld_oom);
630 goto fail;
631 }
632#ifdef FSL_DMA_LD_DEBUG
633 dev_dbg(chan->dev, "new link desc alloc %p\n", new);
634#endif
635
636 set_desc_cnt(chan, &new->hw, len);
637 set_desc_src(chan, &new->hw, src);
638 set_desc_dst(chan, &new->hw, dst);
639
640 if (!first)
641 first = new;
642 else
643 set_desc_next(chan, &prev->hw, new->async_tx.phys);
644
645 new->async_tx.cookie = 0;
646 async_tx_ack(&new->async_tx);
647 prev = new;
648
649 /* Insert the link descriptor to the LD ring */
650 list_add_tail(&new->node, &first->tx_list);
651
652 /* update metadata */
653 dst_avail -= len;
654 src_avail -= len;
655
656fetch:
657 /* fetch the next dst scatterlist entry */
658 if (dst_avail == 0) {
659
660 /* no more entries: we're done */
661 if (dst_nents == 0)
662 break;
663
664 /* fetch the next entry: if there are no more: done */
665 dst_sg = sg_next(dst_sg);
666 if (dst_sg == NULL)
667 break;
668
669 dst_nents--;
670 dst_avail = sg_dma_len(dst_sg);
671 }
672
673 /* fetch the next src scatterlist entry */
674 if (src_avail == 0) {
675
676 /* no more entries: we're done */
677 if (src_nents == 0)
678 break;
679
680 /* fetch the next entry: if there are no more: done */
681 src_sg = sg_next(src_sg);
682 if (src_sg == NULL)
683 break;
684
685 src_nents--;
686 src_avail = sg_dma_len(src_sg);
687 }
688 }
689
690 new->async_tx.flags = flags; /* client is in control of this ack */
691 new->async_tx.cookie = -EBUSY;
692
693 /* Set End-of-link to the last link descriptor of new list */
694 set_ld_eol(chan, new);
695
696 return &first->async_tx;
697
698fail:
699 if (!first)
700 return NULL;
701
702 fsldma_free_desc_list_reverse(chan, &first->tx_list);
703 return NULL;
704}
705
586/** 706/**
587 * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction 707 * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
588 * @chan: DMA channel 708 * @chan: DMA channel
@@ -1327,11 +1447,13 @@ static int __devinit fsldma_of_probe(struct platform_device *op,
1327 1447
1328 dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask); 1448 dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
1329 dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask); 1449 dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
1450 dma_cap_set(DMA_SG, fdev->common.cap_mask);
1330 dma_cap_set(DMA_SLAVE, fdev->common.cap_mask); 1451 dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
1331 fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources; 1452 fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
1332 fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources; 1453 fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
1333 fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt; 1454 fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
1334 fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy; 1455 fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
1456 fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
1335 fdev->common.device_tx_status = fsl_tx_status; 1457 fdev->common.device_tx_status = fsl_tx_status;
1336 fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending; 1458 fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
1337 fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg; 1459 fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;