]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dmaengine: xilinx: xilinx_dma: Fix unmasked residue subtraction
authorMarek Vasut <marex@nabladev.com>
Mon, 16 Mar 2026 22:25:24 +0000 (23:25 +0100)
committerVinod Koul <vkoul@kernel.org>
Tue, 17 Mar 2026 10:44:34 +0000 (16:14 +0530)
The segment .control and .status fields both contain top bits which are
not part of the buffer size, the buffer size is located only in the bottom
max_buffer_len bits. To avoid interference from those top bits, mask out
the size using max_buffer_len first, and only then subtract the values.

Fixes: a575d0b4e663 ("dmaengine: xilinx_dma: Introduce xilinx_dma_get_residue")
Signed-off-by: Marek Vasut <marex@nabladev.com>
Link: https://patch.msgid.link/20260316222530.163815-1-marex@nabladev.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/xilinx/xilinx_dma.c

index 9dd5d7388e1d24828601cf9ed0457c76ca691113..969343342e86c42edfb8112f2dcff4ba63d967af 100644 (file)
@@ -997,16 +997,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
                                              struct xilinx_cdma_tx_segment,
                                              node);
                        cdma_hw = &cdma_seg->hw;
-                       residue += (cdma_hw->control - cdma_hw->status) &
-                                  chan->xdev->max_buffer_len;
+                       residue += (cdma_hw->control & chan->xdev->max_buffer_len) -
+                                  (cdma_hw->status & chan->xdev->max_buffer_len);
                } else if (chan->xdev->dma_config->dmatype ==
                           XDMA_TYPE_AXIDMA) {
                        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;
+                       residue += (axidma_hw->control & chan->xdev->max_buffer_len) -
+                                  (axidma_hw->status & chan->xdev->max_buffer_len);
                } else {
                        aximcdma_seg =
                                list_entry(entry,
@@ -1014,8 +1014,8 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan,
                                           node);
                        aximcdma_hw = &aximcdma_seg->hw;
                        residue +=
-                               (aximcdma_hw->control - aximcdma_hw->status) &
-                               chan->xdev->max_buffer_len;
+                               (aximcdma_hw->control & chan->xdev->max_buffer_len) -
+                               (aximcdma_hw->status & chan->xdev->max_buffer_len);
                }
        }