[PATCH] dma: improve scatterlist to scatterlist transfer

From: Ira W . Snyder
Date: Fri Sep 24 2010 - 17:18:09 EST


This is an improved algorithm to improve support on the Intel I/OAT
driver.

Signed-off-by: Ira W. Snyder <iws@xxxxxxxxxxxxxxxx>
---
drivers/dma/dmaengine.c | 52 +++++++++++++++++++++-----------------------
include/linux/dmaengine.h | 3 --
2 files changed, 25 insertions(+), 30 deletions(-)

diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 57ec1e5..cde775c 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -983,10 +983,13 @@ dma_async_memcpy_sg_to_sg(struct dma_chan *chan,
struct dma_async_tx_descriptor *tx;
dma_cookie_t cookie = -ENOMEM;
size_t dst_avail, src_avail;
- struct list_head tx_list;
+ struct scatterlist *sg;
size_t transferred = 0;
+ size_t dst_total = 0;
+ size_t src_total = 0;
dma_addr_t dst, src;
size_t len;
+ int i;

if (dst_nents == 0 || src_nents == 0)
return -EINVAL;
@@ -994,12 +997,17 @@ dma_async_memcpy_sg_to_sg(struct dma_chan *chan,
if (dst_sg == NULL || src_sg == NULL)
return -EINVAL;

+ /* get the total count of bytes in each scatterlist */
+ for_each_sg(dst_sg, sg, dst_nents, i)
+ dst_total += sg_dma_len(sg);
+
+ for_each_sg(src_sg, sg, src_nents, i)
+ src_total += sg_dma_len(sg);
+
/* get prepared for the loop */
dst_avail = sg_dma_len(dst_sg);
src_avail = sg_dma_len(src_sg);

- INIT_LIST_HEAD(&tx_list);
-
/* run until we are out of descriptors */
while (true) {

@@ -1018,14 +1026,24 @@ dma_async_memcpy_sg_to_sg(struct dma_chan *chan,
return -ENOMEM;
}

- /* keep track of the tx for later */
- list_add_tail(&tx->entry, &tx_list);
-
/* update metadata */
transferred += len;
dst_avail -= len;
src_avail -= len;

+ /* if this is the last transfer, setup the callback */
+ if (dst_total == transferred || src_total == transferred) {
+ tx->callback = cb;
+ tx->callback_param = cb_param;
+ }
+
+ /* submit the transaction */
+ cookie = tx->tx_submit(tx);
+ if (dma_submit_error(cookie)) {
+ dev_err(dev->dev, "failed to submit desc\n");
+ return cookie;
+ }
+
fetch:
/* fetch the next dst scatterlist entry */
if (dst_avail == 0) {
@@ -1060,30 +1078,13 @@ fetch:
}
}

- /* loop through the list of descriptors and submit them */
- list_for_each_entry(tx, &tx_list, entry) {
-
- /* this is the last descriptor: add the callback */
- if (list_is_last(&tx->entry, &tx_list)) {
- tx->callback = cb;
- tx->callback_param = cb_param;
- }
-
- /* submit the transaction */
- cookie = tx->tx_submit(tx);
- if (dma_submit_error(cookie)) {
- dev_err(dev->dev, "failed to submit desc\n");
- return cookie;
- }
- }
-
/* update counters */
preempt_disable();
__this_cpu_add(chan->local->bytes_transferred, transferred);
__this_cpu_inc(chan->local->memcpy_count);
preempt_enable();

- return cookie;
+ return 0;
}
EXPORT_SYMBOL(dma_async_memcpy_sg_to_sg);
#endif
@@ -1092,9 +1093,6 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
struct dma_chan *chan)
{
tx->chan = chan;
- #ifdef CONFIG_DMAENGINE_SG_TO_SG
- INIT_LIST_HEAD(&tx->entry);
- #endif
#ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
spin_lock_init(&tx->lock);
#endif
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 5507f4c..26f2712 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -317,9 +317,6 @@ struct dma_async_tx_descriptor {
dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
dma_async_tx_callback callback;
void *callback_param;
-#ifdef CONFIG_DMAENGINE_SG_TO_SG
- struct list_head entry;
-#endif
#ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
struct dma_async_tx_descriptor *next;
struct dma_async_tx_descriptor *parent;
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/