From: pratyush.anand@st.com (Pratyush Anand)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] dmaengine/dw_dmac: Add support for device_prep_dma_sg
Date: Tue, 13 Dec 2011 14:17:44 +0530 [thread overview]
Message-ID: <1323766064-13425-1-git-send-email-pratyush.anand@st.com> (raw)
Memory to memory copy with scatter gather option has been implemented in
this patch. Driver can manage even if number of nodes in src and dst
list is different.
Signed-off-by: Pratyush Anand <pratyush.anand@st.com>
---
drivers/dma/dw_dmac.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 135 insertions(+), 0 deletions(-)
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 96b2750..c1c78c1 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -729,6 +729,140 @@ err_desc_get:
}
static struct dma_async_tx_descriptor *
+dwc_prep_dma_sg(struct dma_chan *chan,
+ struct scatterlist *dsgl, unsigned int dst_nents,
+ struct scatterlist *ssgl, unsigned int src_nents,
+ unsigned long flags)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dw_desc *desc;
+ struct dw_desc *first;
+ struct dw_desc *prev;
+ size_t xfer_count;
+ size_t offset;
+ unsigned int src_width;
+ unsigned int dst_width;
+ u32 ctllo;
+ struct scatterlist *dsg, *ssg;
+ dma_addr_t src = 0, dst = 0;
+ unsigned int slen = 0, dlen = 0, total_len = 0;
+ unsigned int i, nents, len = 0, incs, si = 0, di = 0;
+
+ if (unlikely(!src_nents))
+ return NULL;
+
+ if (unlikely(!dst_nents))
+ return NULL;
+
+ prev = first = NULL;
+
+ dsg = dsgl;
+ ssg = ssgl;
+ nents = max(src_nents, dst_nents);
+
+ if (nents == src_nents)
+ incs = true;
+ else
+ incs = false;
+
+ for (i = 0; i < nents;) {
+ if (!slen) {
+ src = sg_dma_address(ssg);
+ slen = sg_dma_len(ssg);
+ ssg = sg_next(ssg);
+ if (!ssg && si < src_nents - 1)
+ goto err_sg_len;
+ si++;
+ } else
+ src += len;
+
+ if (!dlen) {
+ dst = sg_dma_address(dsg);
+ dlen = sg_dma_len(dsg);
+ dsg = sg_next(dsg);
+ if (!dsg && di < dst_nents - 1)
+ goto err_sg_len;
+ di++;
+ } else
+ dst += len;
+
+ if (incs)
+ i = si;
+ else
+ i = di;
+ len = min(slen, dlen);
+ slen -= len;
+ dlen -= len;
+
+ if (!((src | dst | len) & 7))
+ src_width = dst_width = 3;
+ else if (!((src | dst | len) & 3))
+ src_width = dst_width = 2;
+ else if (!((src | dst | len) & 1))
+ src_width = dst_width = 1;
+ else
+ src_width = dst_width = 0;
+
+ ctllo = DWC_DEFAULT_CTLLO(chan->private)
+ | DWC_CTLL_DST_WIDTH(dst_width)
+ | DWC_CTLL_SRC_WIDTH(src_width)
+ | DWC_CTLL_DST_INC
+ | DWC_CTLL_SRC_INC
+ | DWC_CTLL_FC_M2M;
+
+ offset = 0;
+ while ((len - offset) > 0) {
+
+ xfer_count = min_t(size_t, (len - offset) >> dst_width,
+ DWC_MAX_COUNT);
+
+ desc = dwc_desc_get(dwc);
+ if (!desc)
+ goto err_desc_get;
+
+ desc->lli.sar = src + offset;
+ desc->lli.dar = dst + offset;
+ desc->lli.ctllo = ctllo;
+ desc->lli.ctlhi = xfer_count;
+
+ if (!first) {
+ first = desc;
+ } else {
+ prev->lli.llp = desc->txd.phys;
+ dma_sync_single_for_device(chan2parent(chan),
+ prev->txd.phys,
+ sizeof(prev->lli),
+ DMA_TO_DEVICE);
+ list_add_tail(&desc->desc_node,
+ &first->tx_list);
+ }
+ prev = desc;
+ offset += xfer_count << dst_width;
+ }
+ total_len += len;
+ }
+
+ if (flags & DMA_PREP_INTERRUPT)
+ /* Trigger interrupt after last block */
+ prev->lli.ctllo |= DWC_CTLL_INT_EN;
+
+ prev->lli.llp = 0;
+ dma_sync_single_for_device(chan2parent(chan),
+ prev->txd.phys, sizeof(prev->lli),
+ DMA_TO_DEVICE);
+
+ first->txd.flags = flags;
+ first->len = total_len;
+
+ return &first->txd;
+
+err_sg_len:
+err_desc_get:
+ dwc_desc_put(dwc, first);
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *
dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction direction,
unsigned long flags)
@@ -1471,6 +1605,7 @@ static int __init dw_probe(struct platform_device *pdev)
dw->dma.device_free_chan_resources = dwc_free_chan_resources;
dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy;
+ dw->dma.device_prep_dma_sg = dwc_prep_dma_sg;
dw->dma.device_prep_slave_sg = dwc_prep_slave_sg;
dw->dma.device_control = dwc_control;
--
1.7.2.2
next reply other threads:[~2011-12-13 8:47 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-13 8:47 Pratyush Anand [this message]
2011-12-13 11:54 ` [PATCH] dmaengine/dw_dmac: Add support for device_prep_dma_sg Linus Walleij
2011-12-23 15:58 ` Vinod Koul
2012-01-02 11:20 ` Pratyush Anand
2012-01-02 11:25 ` Vinod Koul
2012-01-03 9:40 ` Russell King - ARM Linux
2012-01-03 13:03 ` Vinod Koul
2012-01-03 13:43 ` Russell King - ARM Linux
2012-01-04 13:47 ` Vinod Koul
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1323766064-13425-1-git-send-email-pratyush.anand@st.com \
--to=pratyush.anand@st.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).