[PATCH] dmaengine: fsl_raid: fix 64-bit ring base address programming
From: Rosen Penev <hidden>
Date: 2026-09-10 20:17:22
Also in:
lkml
Subsystem:
dma generic offload engine subsystem, the rest · Maintainers:
Vinod Koul, Linus Torvalds
The driver claims a 40-bit DMA mask via dma_set_mask(40), but the
inbound/outbound ring base addresses were programmed by masking the
physical address with FSL_RE_ADDR_BIT_MASK (0xF) into the high register
and shifting it right by FSL_RE_ADDR_BIT_SHIFT (4) into the low register.
This truncates the upper address bits and, worse, places the lowest 4
bits of the address into the high register. For any ring allocated above
the 64 GB boundary the hardware reads/writes the wrong physical memory,
causing silent data corruption.
Program the registers correctly: the low register takes bits [31:0] and
the high register takes bits [39:32] of the 40-bit DMA address. Replace
the broken FSL_RE_ADDR_BIT_* macros with FSL_RE_ADDR_HIGH_MASK.
Fixes: ad80da658bbc ("dmaengine: Driver support for FSL RaidEngine device.")
Assisted-by: opencode:hy3-free
Signed-off-by: Rosen Penev <redacted>
---
drivers/dma/fsl_raid.c | 14 +++++++++-----
drivers/dma/fsl_raid.h | 3 +--
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
index befb4bb69d54..7343833b3b34 100644
--- a/drivers/dma/fsl_raid.c
+++ b/drivers/dma/fsl_raid.c@@ -715,15 +715,19 @@ static int fsl_re_chan_probe(struct platform_device *ofdev, goto err_free_1; } - /* Program the Inbound/Outbound ring base addresses and size */ + /* Program the Inbound/Outbound ring base addresses and size. + * The DMA rings are 64-bit addresses split into high/low registers. + * The driver supports a 40-bit DMA mask, so the low register holds + * bits [31:0] and the high register holds bits [39:32]. + */ out_be32(&chan->jrregs->inbring_base_h, - chan->inb_phys_addr & FSL_RE_ADDR_BIT_MASK); + upper_32_bits(chan->inb_phys_addr) & FSL_RE_ADDR_HIGH_MASK); out_be32(&chan->jrregs->oubring_base_h, - chan->oub_phys_addr & FSL_RE_ADDR_BIT_MASK); + upper_32_bits(chan->oub_phys_addr) & FSL_RE_ADDR_HIGH_MASK); out_be32(&chan->jrregs->inbring_base_l, - chan->inb_phys_addr >> FSL_RE_ADDR_BIT_SHIFT); + lower_32_bits(chan->inb_phys_addr)); out_be32(&chan->jrregs->oubring_base_l, - chan->oub_phys_addr >> FSL_RE_ADDR_BIT_SHIFT); + lower_32_bits(chan->oub_phys_addr)); out_be32(&chan->jrregs->inbring_size, FSL_RE_RING_SIZE << FSL_RE_RING_SIZE_SHIFT); out_be32(&chan->jrregs->oubring_size,
diff --git a/drivers/dma/fsl_raid.h b/drivers/dma/fsl_raid.h
index adbfede330a7..748047996bbc 100644
--- a/drivers/dma/fsl_raid.h
+++ b/drivers/dma/fsl_raid.h@@ -66,8 +66,7 @@ #define FSL_RE_RING_SIZE 0x400 #define FSL_RE_RING_SIZE_MASK (FSL_RE_RING_SIZE - 1) #define FSL_RE_RING_SIZE_SHIFT 8 -#define FSL_RE_ADDR_BIT_SHIFT 4 -#define FSL_RE_ADDR_BIT_MASK (BIT(FSL_RE_ADDR_BIT_SHIFT) - 1) +#define FSL_RE_ADDR_HIGH_MASK 0xFF #define FSL_RE_ERROR 0x40000000 #define FSL_RE_INTR 0x80000000 #define FSL_RE_CLR_INTR 0x80000000
--
2.55.0