| From 561b09f674330399473432d80a51a4e13926b17f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 16 Mar 2026 23:18:57 +0100 |
| Subject: dmaengine: xilinx: xilinx_dma: Fix residue calculation for cyclic DMA |
| |
| From: Marek Vasut <marex@nabladev.com> |
| |
| [ Upstream commit f61d145999d61948a23cd436ebbfa4c3b9ab8987 ] |
| |
| The cyclic DMA calculation is currently entirely broken and reports |
| residue only for the first segment. The problem is twofold. |
| |
| First, when the first descriptor finishes, it is moved from active_list |
| to done_list, but it is never returned back into the active_list. The |
| xilinx_dma_tx_status() expects the descriptor to be in the active_list |
| to report any meaningful residue information, which never happens after |
| the first descriptor finishes. Fix this up in xilinx_dma_start_transfer() |
| and if the descriptor is cyclic, lift it from done_list and place it back |
| into active_list list. |
| |
| Second, the segment .status fields of the descriptor remain dirty. Once |
| the DMA did one pass on the descriptor, the .status fields are populated |
| with data by the DMA, but the .status fields are not cleared before reuse |
| during the next cyclic DMA round. The xilinx_dma_get_residue() recognizes |
| that as if the descriptor was complete and had 0 residue, which is bogus. |
| Reinitialize the status field before placing the descriptor back into the |
| active_list. |
| |
| Fixes: c0bba3a99f07 ("dmaengine: vdma: Add Support for Xilinx AXI Direct Memory Access Engine") |
| Signed-off-by: Marek Vasut <marex@nabladev.com> |
| Link: https://patch.msgid.link/20260316221943.160375-1-marex@nabladev.com |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/dma/xilinx/xilinx_dma.c | 23 ++++++++++++++++++++++- |
| 1 file changed, 22 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c |
| index e2adc33631ca3..948093a47d9f9 100644 |
| --- a/drivers/dma/xilinx/xilinx_dma.c |
| +++ b/drivers/dma/xilinx/xilinx_dma.c |
| @@ -1513,8 +1513,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) |
| if (chan->err) |
| return; |
| |
| - if (list_empty(&chan->pending_list)) |
| + if (list_empty(&chan->pending_list)) { |
| + if (chan->cyclic) { |
| + struct xilinx_dma_tx_descriptor *desc; |
| + struct list_head *entry; |
| + |
| + desc = list_last_entry(&chan->done_list, |
| + struct xilinx_dma_tx_descriptor, node); |
| + list_for_each(entry, &desc->segments) { |
| + struct xilinx_axidma_tx_segment *axidma_seg; |
| + struct xilinx_axidma_desc_hw *axidma_hw; |
| + axidma_seg = list_entry(entry, |
| + struct xilinx_axidma_tx_segment, |
| + node); |
| + axidma_hw = &axidma_seg->hw; |
| + axidma_hw->status = 0; |
| + } |
| + |
| + list_splice_tail_init(&chan->done_list, &chan->active_list); |
| + chan->desc_pendingcount = 0; |
| + chan->idle = false; |
| + } |
| return; |
| + } |
| |
| if (!chan->idle) |
| return; |
| -- |
| 2.53.0 |
| |