2019-10-15 14:49:55

by Radhey Shyam Pandey

[permalink] [raw]
Subject: [PATCH v2 -next 0/7] dmaengine: xilinx_dma: AXI DMA driver improvements

This patchset adds callback result, descriptor residue
calculation and some regression fixes.

Changes for v2:
- Fix commenting style in 3/8 Introduce xilinx_dma_get_residue patch.
- Invoke get_residue for supported configuration and remove internal check.
- Remove residue from channel data in a new preparatory patch.
- Drop patch checking for idle state in axidma stop_transfer.
It need further debug.

Please refer to below link for more information:
https://www.spinics.net/lists/dmaengine/msg19480.html


Nicholas Graumann (5):
dmaengine: xilinx_dma: Merge get_callback and _invoke
dmaengine: xilinx_dma: Introduce xilinx_dma_get_residue
dmaengine: xilinx_dma: Add callback_result support
dmaengine: xilinx_dma: Print debug message when no free tx segments
dmaengine: xilinx_dma: Clear desc_pendingcount in xilinx_dma_reset

Radhey Shyam Pandey (2):
dmaengine: xilinx_dma: Remove desc_callback_valid check
dmaengine: xilinx_dma: Remove residue from channel data

drivers/dma/xilinx/xilinx_dma.c | 111 ++++++++++++++++++++++++++++++----------
1 file changed, 84 insertions(+), 27 deletions(-)

--
2.7.4


2019-10-15 14:50:02

by Radhey Shyam Pandey

[permalink] [raw]
Subject: [PATCH v2 -next 5/7] dmaengine: xilinx_dma: Add callback_result support

From: Nicholas Graumann <[email protected]>

Take advantage of dmaengine_desc_get_callback_invoke which allows either
a callback or callback_result to be specified. This can be useful when
using the AXI DMA transfer unknown quantities of data where the residue
contained in the result can be used to calculate the number of bytes
transferred.

Signed-off-by: Nicholas Graumann <[email protected]>
Signed-off-by: Radhey Shyam Pandey <[email protected]>
---
Changes for v2:
Invoke xilinx_dma_get_residue only for valid combination.
---
drivers/dma/xilinx/xilinx_dma.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 8c10686..932407a 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -303,12 +303,16 @@ struct xilinx_cdma_tx_segment {
* @segments: TX segments list
* @node: Node in the channel descriptors list
* @cyclic: Check for cyclic transfers.
+ * @err: Whether the descriptor has an error.
+ * @residue: Residue of the completed descriptor
*/
struct xilinx_dma_tx_descriptor {
struct dma_async_tx_descriptor async_tx;
struct list_head segments;
struct list_head node;
bool cyclic;
+ bool err;
+ u32 residue;
};

/**
@@ -859,6 +863,8 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
spin_lock_irqsave(&chan->lock, flags);

list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+ struct dmaengine_result result;
+
if (desc->cyclic) {
xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
break;
@@ -867,9 +873,20 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
/* Remove from the list of running transactions */
list_del(&desc->node);

+ if (unlikely(desc->err)) {
+ if (chan->direction == DMA_DEV_TO_MEM)
+ result.result = DMA_TRANS_READ_FAILED;
+ else
+ result.result = DMA_TRANS_WRITE_FAILED;
+ } else {
+ result.result = DMA_TRANS_NOERROR;
+ }
+
+ result.residue = desc->residue;
+
/* Run the link descriptor callback function */
spin_unlock_irqrestore(&chan->lock, flags);
- dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
+ dmaengine_desc_get_callback_invoke(&desc->async_tx, &result);
spin_lock_irqsave(&chan->lock, flags);

/* Run any dependencies, then free the descriptor */
@@ -1425,6 +1442,13 @@ static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
return;

list_for_each_entry_safe(desc, next, &chan->active_list, node) {
+ if (chan->has_sg && chan->xdev->dma_config->dmatype !=
+ XDMA_TYPE_VDMA)
+ desc->residue = xilinx_dma_get_residue(chan, desc);
+ else
+ desc->residue = 0;
+ desc->err = chan->err;
+
list_del(&desc->node);
if (!desc->cyclic)
dma_cookie_complete(&desc->async_tx);
--
2.7.4

2019-10-15 14:50:20

by Radhey Shyam Pandey

[permalink] [raw]
Subject: [PATCH v2 -next 7/7] dmaengine: xilinx_dma: Clear desc_pendingcount in xilinx_dma_reset

From: Nicholas Graumann <[email protected]>

Whenever we reset the channel, we need to clear desc_pendingcount
along with desc_submitcount. Otherwise when a new transaction is
submitted, the irq coalesce level could be programmed to an incorrect
value in the axidma case.

This behavior can be observed when terminating pending transactions
with xilinx_dma_terminate_all() and then submitting new transactions
without releasing and requesting the channel.

Signed-off-by: Nicholas Graumann <[email protected]>
Signed-off-by: Radhey Shyam Pandey <[email protected]>
---
Changes for v2:
None
---
drivers/dma/xilinx/xilinx_dma.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index b0d3aac..56a7317 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1486,6 +1486,7 @@ static int xilinx_dma_reset(struct xilinx_dma_chan *chan)

chan->err = false;
chan->idle = true;
+ chan->desc_pendingcount = 0;
chan->desc_submitcount = 0;

return err;
--
2.7.4

2019-10-15 14:50:35

by Radhey Shyam Pandey

[permalink] [raw]
Subject: [PATCH v2 -next 4/7] dmaengine: xilinx_dma: Introduce xilinx_dma_get_residue

From: Nicholas Graumann <[email protected]>

Introduce a function that can calculate residues for IPs that support it:
AXI DMA and CDMA.

Signed-off-by: Nicholas Graumann <[email protected]>
Signed-off-by: Radhey Shyam Pandey <[email protected]>
---
Changes for v2:
Fix merge failure due to changes in previous patch.
Invoke xilinx_dma_get_residue only for valid combination.
Fix multi-line comment style.
---
drivers/dma/xilinx/xilinx_dma.c | 71 +++++++++++++++++++++++++++++++----------
1 file changed, 54 insertions(+), 17 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 809e638..8c10686 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -788,6 +788,44 @@ static void xilinx_dma_free_chan_resources(struct dma_chan *dchan)
}

/**
+ * xilinx_dma_get_residue - Compute residue for a given descriptor
+ * @chan: Driver specific dma channel
+ * @desc: dma transaction descriptor
+ *
+ * Return: The number of residue bytes for the descriptor.
+ */
+static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
+ struct xilinx_dma_tx_descriptor *desc)
+{
+ struct xilinx_cdma_tx_segment *cdma_seg;
+ struct xilinx_axidma_tx_segment *axidma_seg;
+ struct xilinx_cdma_desc_hw *cdma_hw;
+ struct xilinx_axidma_desc_hw *axidma_hw;
+ struct list_head *entry;
+ u32 residue = 0;
+
+ list_for_each(entry, &desc->segments) {
+ if (chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
+ cdma_seg = list_entry(entry,
+ struct xilinx_cdma_tx_segment,
+ node);
+ cdma_hw = &cdma_seg->hw;
+ residue += (cdma_hw->control - cdma_hw->status) &
+ chan->xdev->max_buffer_len;
+ } else {
+ axidma_seg = list_entry(entry,
+ struct xilinx_axidma_tx_segment,
+ node);
+ axidma_hw = &axidma_seg->hw;
+ residue += (axidma_hw->control - axidma_hw->status) &
+ chan->xdev->max_buffer_len;
+ }
+ }
+
+ return residue;
+}
+
+/**
* xilinx_dma_chan_handle_cyclic - Cyclic dma callback
* @chan: Driver specific dma channel
* @desc: dma transaction descriptor
@@ -996,8 +1034,6 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
{
struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
struct xilinx_dma_tx_descriptor *desc;
- struct xilinx_axidma_tx_segment *segment;
- struct xilinx_axidma_desc_hw *hw;
enum dma_status ret;
unsigned long flags;
u32 residue = 0;
@@ -1006,22 +1042,20 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
if (ret == DMA_COMPLETE || !txstate)
return ret;

- if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
- spin_lock_irqsave(&chan->lock, flags);
+ spin_lock_irqsave(&chan->lock, flags);

- desc = list_last_entry(&chan->active_list,
- struct xilinx_dma_tx_descriptor, node);
- if (chan->has_sg) {
- list_for_each_entry(segment, &desc->segments, node) {
- hw = &segment->hw;
- residue += (hw->control - hw->status) &
- chan->xdev->max_buffer_len;
- }
- }
- spin_unlock_irqrestore(&chan->lock, flags);
+ desc = list_last_entry(&chan->active_list,
+ struct xilinx_dma_tx_descriptor, node);
+ /*
+ * VDMA and simple mode do not support residue reporting, so the
+ * residue field will always be 0.
+ */
+ if (chan->has_sg && chan->xdev->dma_config->dmatype != XDMA_TYPE_VDMA)
+ residue = xilinx_dma_get_residue(chan, desc);

- dma_set_residue(txstate, residue);
- }
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ dma_set_residue(txstate, residue);

return ret;
}
@@ -2713,12 +2747,15 @@ static int xilinx_dma_probe(struct platform_device *pdev)
xilinx_dma_prep_dma_cyclic;
xdev->common.device_prep_interleaved_dma =
xilinx_dma_prep_interleaved;
- /* Residue calculation is supported by only AXI DMA */
+ /* Residue calculation is supported by only AXI DMA and CDMA */
xdev->common.residue_granularity =
DMA_RESIDUE_GRANULARITY_SEGMENT;
} else if (xdev->dma_config->dmatype == XDMA_TYPE_CDMA) {
dma_cap_set(DMA_MEMCPY, xdev->common.cap_mask);
xdev->common.device_prep_dma_memcpy = xilinx_cdma_prep_memcpy;
+ /* Residue calculation is supported by only AXI DMA and CDMA */
+ xdev->common.residue_granularity =
+ DMA_RESIDUE_GRANULARITY_SEGMENT;
} else {
xdev->common.device_prep_interleaved_dma =
xilinx_vdma_dma_prep_interleaved;
--
2.7.4

2019-10-15 14:51:00

by Radhey Shyam Pandey

[permalink] [raw]
Subject: [PATCH v2 -next 2/7] dmaengine: xilinx_dma: Merge get_callback and _invoke

From: Nicholas Graumann <[email protected]>

The dma api provides a single interface to get the appropriate callback
and invoke it directly. Prefer using it.

Signed-off-by: Nicholas Graumann <[email protected]>
Signed-off-by: Radhey Shyam Pandey <[email protected]>
---
Changes for v2:
None
---
drivers/dma/xilinx/xilinx_dma.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index a3f8a2c..465dabc 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -823,8 +823,6 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
spin_lock_irqsave(&chan->lock, flags);

list_for_each_entry_safe(desc, next, &chan->done_list, node) {
- struct dmaengine_desc_callback cb;
-
if (desc->cyclic) {
xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
break;
@@ -834,9 +832,8 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
list_del(&desc->node);

/* Run the link descriptor callback function */
- dmaengine_desc_get_callback(&desc->async_tx, &cb);
spin_unlock_irqrestore(&chan->lock, flags);
- dmaengine_desc_callback_invoke(&cb, NULL);
+ dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
spin_lock_irqsave(&chan->lock, flags);

/* Run any dependencies, then free the descriptor */
--
2.7.4

2019-10-15 14:51:29

by Radhey Shyam Pandey

[permalink] [raw]
Subject: [PATCH v2 -next 1/7] dmaengine: xilinx_dma: Remove desc_callback_valid check

In descriptor cleanup the call to desc_callback_valid can be safely
removed as both callback pointers i.e callback_result and callback
are anyway checked in invoke(). There is no much benefit in having
redundant checks.

Signed-off-by: Radhey Shyam Pandey <[email protected]>
Signed-off-by: Nicholas Graumann <[email protected]>
Reviewed-by: Appana Durga Kedareswara rao <[email protected]>
---
Changes for v2:
None
---
drivers/dma/xilinx/xilinx_dma.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 440f2ce..a3f8a2c 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -835,11 +835,9 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)

/* Run the link descriptor callback function */
dmaengine_desc_get_callback(&desc->async_tx, &cb);
- if (dmaengine_desc_callback_valid(&cb)) {
- spin_unlock_irqrestore(&chan->lock, flags);
- dmaengine_desc_callback_invoke(&cb, NULL);
- spin_lock_irqsave(&chan->lock, flags);
- }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ dmaengine_desc_callback_invoke(&cb, NULL);
+ spin_lock_irqsave(&chan->lock, flags);

/* Run any dependencies, then free the descriptor */
dma_run_dependencies(&desc->async_tx);
--
2.7.4

2019-10-20 14:06:21

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH v2 -next 0/7] dmaengine: xilinx_dma: AXI DMA driver improvements

On 15-10-19, 20:18, Radhey Shyam Pandey wrote:
> This patchset adds callback result, descriptor residue
> calculation and some regression fixes.

Applied, thanks

--
~Vinod