* [PATCH 1/4] dmaengine: at_xdmac: handle numf > 1
2015-09-15 13:29 [PATCH 0/4] at_xdmac: improvment and fixes for the interleaved mode Ludovic Desroches
@ 2015-09-15 13:29 ` Ludovic Desroches
2015-09-15 13:36 ` [PATCH 2/4] dmaengine: at_xdmac: change block increment addressing mode Ludovic Desroches
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Ludovic Desroches @ 2015-09-15 13:29 UTC (permalink / raw)
To: vinod.koul, maxime.ripard
Cc: linux-arm-kernel, dmaengine, linux-kernel, nicolas.ferre,
Ludovic Desroches
From: Maxime Ripard <maxime.ripard@free-electrons.com>
Handle 'numf > 1' case for interleaved mode.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
drivers/dma/at_xdmac.c | 104 ++++++++++++++++++++++++-------------------------
1 file changed, 50 insertions(+), 54 deletions(-)
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index a165b4b..0190d1c 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -929,13 +929,19 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
{
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac_desc *prev = NULL, *first = NULL;
- struct data_chunk *chunk, *prev_chunk = NULL;
dma_addr_t dst_addr, src_addr;
- size_t dst_skip, src_skip, len = 0;
- size_t prev_dst_icg = 0, prev_src_icg = 0;
+ size_t src_skip = 0, dst_skip = 0, len = 0;
+ struct data_chunk *chunk;
int i;
- if (!xt || (xt->numf != 1) || (xt->dir != DMA_MEM_TO_MEM))
+ if (!xt || !xt->numf || (xt->dir != DMA_MEM_TO_MEM))
+ return NULL;
+
+ /*
+ * TODO: Handle the case where we have to repeat a chain of
+ * descriptors...
+ */
+ if ((xt->numf > 1) && (xt->frame_size > 1))
return NULL;
dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
@@ -945,66 +951,56 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
src_addr = xt->src_start;
dst_addr = xt->dst_start;
- for (i = 0; i < xt->frame_size; i++) {
- struct at_xdmac_desc *desc;
- size_t src_icg, dst_icg;
-
- chunk = xt->sgl + i;
+ if (xt->numf > 1) {
+ first = at_xdmac_interleaved_queue_desc(chan, atchan,
+ NULL,
+ src_addr, dst_addr,
+ xt, xt->sgl);
+ for (i = 0; i < xt->numf; i++)
+ at_xdmac_increment_block_count(chan, first);
+ } else {
+ for (i = 0; i < xt->frame_size; i++) {
+ size_t src_icg = 0, dst_icg = 0;
+ struct at_xdmac_desc *desc;
- dst_icg = dmaengine_get_dst_icg(xt, chunk);
- src_icg = dmaengine_get_src_icg(xt, chunk);
+ chunk = xt->sgl + i;
- src_skip = chunk->size + src_icg;
- dst_skip = chunk->size + dst_icg;
+ dst_icg = dmaengine_get_dst_icg(xt, chunk);
+ src_icg = dmaengine_get_src_icg(xt, chunk);
- dev_dbg(chan2dev(chan),
- "%s: chunk size=%d, src icg=%d, dst icg=%d\n",
- __func__, chunk->size, src_icg, dst_icg);
+ src_skip = chunk->size + src_icg;
+ dst_skip = chunk->size + dst_icg;
- /*
- * Handle the case where we just have the same
- * transfer to setup, we can just increase the
- * block number and reuse the same descriptor.
- */
- if (prev_chunk && prev &&
- (prev_chunk->size == chunk->size) &&
- (prev_src_icg == src_icg) &&
- (prev_dst_icg == dst_icg)) {
dev_dbg(chan2dev(chan),
- "%s: same configuration that the previous chunk, merging the descriptors...\n",
- __func__);
- at_xdmac_increment_block_count(chan, prev);
- continue;
- }
-
- desc = at_xdmac_interleaved_queue_desc(chan, atchan,
- prev,
- src_addr, dst_addr,
- xt, chunk);
- if (!desc) {
- list_splice_init(&first->descs_list,
- &atchan->free_descs_list);
- return NULL;
- }
+ "%s: chunk size=%d, src icg=%d, dst icg=%d\n",
+ __func__, chunk->size, src_icg, dst_icg);
+
+ desc = at_xdmac_interleaved_queue_desc(chan, atchan,
+ prev,
+ src_addr, dst_addr,
+ xt, chunk);
+ if (!desc) {
+ list_splice_init(&first->descs_list,
+ &atchan->free_descs_list);
+ return NULL;
+ }
- if (!first)
- first = desc;
+ if (!first)
+ first = desc;
- dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
- __func__, desc, first);
- list_add_tail(&desc->desc_node, &first->descs_list);
+ dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
+ __func__, desc, first);
+ list_add_tail(&desc->desc_node, &first->descs_list);
- if (xt->src_sgl)
- src_addr += src_skip;
+ if (xt->src_sgl)
+ src_addr += src_skip;
- if (xt->dst_sgl)
- dst_addr += dst_skip;
+ if (xt->dst_sgl)
+ dst_addr += dst_skip;
- len += chunk->size;
- prev_chunk = chunk;
- prev_dst_icg = dst_icg;
- prev_src_icg = src_icg;
- prev = desc;
+ len += chunk->size;
+ prev = desc;
+ }
}
first->tx_dma_desc.cookie = -EBUSY;
--
2.5.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/4] dmaengine: at_xdmac: fix memory leak in interleaved mode
2015-09-15 13:29 [PATCH 0/4] at_xdmac: improvment and fixes for the interleaved mode Ludovic Desroches
2015-09-15 13:29 ` [PATCH 1/4] dmaengine: at_xdmac: handle numf > 1 Ludovic Desroches
2015-09-15 13:36 ` [PATCH 2/4] dmaengine: at_xdmac: change block increment addressing mode Ludovic Desroches
@ 2015-09-15 13:38 ` Ludovic Desroches
2015-09-15 13:39 ` [PATCH 4/4] dmaengine: at_xdmac: clean used descriptor Ludovic Desroches
2015-10-01 2:01 ` [PATCH 0/4] at_xdmac: improvment and fixes for the interleaved mode Vinod Koul
4 siblings, 0 replies; 6+ messages in thread
From: Ludovic Desroches @ 2015-09-15 13:38 UTC (permalink / raw)
To: vinod.koul, maxime.ripard
Cc: linux-arm-kernel, dmaengine, linux-kernel, nicolas.ferre,
Ludovic Desroches
In interleaved mode, when numf > 1, we have only one descriptor for the
transfer but this descriptor has to be added to the descs_list. If not,
when doing remove_xfer, the descriptor won't be put back in the
free_descs_list.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
drivers/dma/at_xdmac.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 3952bff..fbd4093 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -958,6 +958,10 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
xt, xt->sgl);
for (i = 0; i < xt->numf; i++)
at_xdmac_increment_block_count(chan, first);
+
+ dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
+ __func__, first, first);
+ list_add_tail(&first->desc_node, &first->descs_list);
} else {
for (i = 0; i < xt->frame_size; i++) {
size_t src_icg = 0, dst_icg = 0;
--
2.5.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/4] dmaengine: at_xdmac: clean used descriptor
2015-09-15 13:29 [PATCH 0/4] at_xdmac: improvment and fixes for the interleaved mode Ludovic Desroches
` (2 preceding siblings ...)
2015-09-15 13:38 ` [PATCH 3/4] dmaengine: at_xdmac: fix memory leak in interleaved mode Ludovic Desroches
@ 2015-09-15 13:39 ` Ludovic Desroches
2015-10-01 2:01 ` [PATCH 0/4] at_xdmac: improvment and fixes for the interleaved mode Vinod Koul
4 siblings, 0 replies; 6+ messages in thread
From: Ludovic Desroches @ 2015-09-15 13:39 UTC (permalink / raw)
To: vinod.koul, maxime.ripard
Cc: linux-arm-kernel, dmaengine, linux-kernel, nicolas.ferre,
Ludovic Desroches
When putting back a descriptor to the free descs list, some fields are
not set to 0, it can cause bugs if someone uses it without having this
in mind.
Descriptor are not put back one by one so it is easier to clean
descriptors when we request them.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Cc: stable@vger.kernel.org #4.2
---
drivers/dma/at_xdmac.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index fbd4093..b5e132d 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -455,6 +455,15 @@ static struct at_xdmac_desc *at_xdmac_alloc_desc(struct dma_chan *chan,
return desc;
}
+void at_xdmac_init_used_desc(struct at_xdmac_desc *desc)
+{
+ memset(&desc->lld, 0, sizeof(desc->lld));
+ INIT_LIST_HEAD(&desc->descs_list);
+ desc->direction = DMA_TRANS_NONE;
+ desc->xfer_size = 0;
+ desc->active_xfer = false;
+}
+
/* Call must be protected by lock. */
static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan)
{
@@ -466,7 +475,7 @@ static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan)
desc = list_first_entry(&atchan->free_descs_list,
struct at_xdmac_desc, desc_node);
list_del(&desc->desc_node);
- desc->active_xfer = false;
+ at_xdmac_init_used_desc(desc);
}
return desc;
--
2.5.0
^ permalink raw reply related [flat|nested] 6+ messages in thread