[PATCH 5.4 111/129] dmaengine: dw-edma: Fix scatter-gather address calculation

From: Greg Kroah-Hartman
Date: Tue Sep 08 2020 - 15:05:22 EST


From: Gustavo Pimentel <Gustavo.Pimentel@xxxxxxxxxxxx>

commit 05655541c9503bfd01af4e6cbd7f5a29ac748e6c upstream.

Fix the source and destination physical address calculation of a
peripheral device on scatter-gather implementation.

This issue manifested during tests using a 64 bits architecture system.
The abnormal behavior wasn't visible before due to all previous tests
were done using 32 bits architecture system, that masked his effect.

Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Gustavo Pimentel <gustavo.pimentel@xxxxxxxxxxxx>
Link: https://lore.kernel.org/r/8d3ab7e2ba96563fe3495b32f60077fffb85307d.1597327623.git.gustavo.pimentel@xxxxxxxxxxxx
Signed-off-by: Vinod Koul <vkoul@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/dma/dw-edma/dw-edma-core.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -391,7 +391,7 @@ dw_edma_device_transfer(struct dw_edma_t
if (xfer->cyclic) {
burst->dar = xfer->xfer.cyclic.paddr;
} else {
- burst->dar = sg_dma_address(sg);
+ burst->dar = dst_addr;
/* Unlike the typical assumption by other
* drivers/IPs the peripheral memory isn't
* a FIFO memory, in this case, it's a
@@ -399,14 +399,13 @@ dw_edma_device_transfer(struct dw_edma_t
* and destination addresses are increased
* by the same portion (data length)
*/
- src_addr += sg_dma_len(sg);
}
} else {
burst->dar = dst_addr;
if (xfer->cyclic) {
burst->sar = xfer->xfer.cyclic.paddr;
} else {
- burst->sar = sg_dma_address(sg);
+ burst->sar = src_addr;
/* Unlike the typical assumption by other
* drivers/IPs the peripheral memory isn't
* a FIFO memory, in this case, it's a
@@ -414,12 +413,14 @@ dw_edma_device_transfer(struct dw_edma_t
* and destination addresses are increased
* by the same portion (data length)
*/
- dst_addr += sg_dma_len(sg);
}
}

- if (!xfer->cyclic)
+ if (!xfer->cyclic) {
+ src_addr += sg_dma_len(sg);
+ dst_addr += sg_dma_len(sg);
sg = sg_next(sg);
+ }
}

return vchan_tx_prep(&chan->vc, &desc->vd, xfer->flags);