* [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup
@ 2026-06-25 8:59 Jean-Michel Hautbois
2026-06-25 8:59 ` [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file Jean-Michel Hautbois
` (4 more replies)
0 siblings, 5 replies; 11+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-25 8:59 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Angelo Dureghello
Cc: Frank Li, imx, dmaengine, linux-kernel, Jean-Michel Hautbois
The MCF54418 ColdFire SoC integrates an enhanced DMA controller (eDMA)
with 64 DMA channels. The current mcf-edma interrupt and error handlers
only deal correctly with the first 32 channels: they test the status
bits with BIT(ch) on an "unsigned long", which is 32-bit on ColdFire, so
any access to a channel >= 32 is undefined behaviour and the
corresponding completions/errors are mishandled.
This series fixes the 64-channel handling and tidies up the related
code:
- move the shared eDMA error handler out of the header file so it can
be reused by the mcf-edma glue;
- add an FSL_EDMA_DRV_MCF driver flag to describe the ColdFire
specifics;
- fix the completion and error interrupt handlers to iterate over all
64 channels using a proper bitmap;
- register the per-channel interrupts with devm, which also fixes the
IRQ leak on the probe error path and quiesces the controller on
remove().
The two interrupt-handler fixes carry Fixes: tags and are candidates for
stable.
This work was previously posted as a single series together with the
ColdFire/m68k platform enablement. As the driver changes and the
arch/m68k/ enablement are independent and target different trees, they
are now sent separately.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
Changes in v3:
- Rename the patch subject prefix dma: -> dmaengine: (Vinod Koul).
- Split the ColdFire/m68k enablement into its own series targeting the
m68k tree; this series now contains only the drivers/dma/ changes.
- Add Fixes: tags to the two 64-channel interrupt-handler fixes.
- Replace the "Add per-channel IRQ naming" change with a devm-based
per-channel IRQ registration that also fixes the probe-failure IRQ
leak and quiesces the controller on remove().
- Link to v2: https://lore.kernel.org/dmaengine/20251126-dma-coldfire-v2-0-5b1e4544d609@yoseli.org
---
Jean-Michel Hautbois (5):
dmaengine: fsl-edma: Move error handler out of header file
dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA
dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels
dmaengine: mcf-edma: Fix error handler for all 64 DMA channels
dmaengine: mcf-edma: Use devm for per-channel IRQ registration
drivers/dma/fsl-edma-common.c | 5 ++
drivers/dma/fsl-edma-common.h | 11 ++--
drivers/dma/mcf-edma-main.c | 133 ++++++++++++++++++++----------------------
3 files changed, 72 insertions(+), 77 deletions(-)
---
base-commit: ab9de95c9cf952332ab79453b4b5d1bfca8e514f
change-id: 20260625-b4-edma-dmaengine-281c71664da7
Best regards,
--
Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file
2026-06-25 8:59 [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup Jean-Michel Hautbois
@ 2026-06-25 8:59 ` Jean-Michel Hautbois
2026-06-25 15:33 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 2/5] dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA Jean-Michel Hautbois
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-25 8:59 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Angelo Dureghello
Cc: Frank Li, imx, dmaengine, linux-kernel, Jean-Michel Hautbois
Move fsl_edma_err_chan_handler from an inline function in the header
to a proper function in fsl-edma-common.c. This prepares for MCF
ColdFire eDMA support where the error handler needs to be called from
the MCF-specific error interrupt handler.
No functional change for existing users.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
drivers/dma/fsl-edma-common.c | 5 +++++
drivers/dma/fsl-edma-common.h | 6 +-----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index bb7531c456df..1b1a0496b5e6 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -44,6 +44,11 @@
#define EDMA64_ERRH 0x28
#define EDMA64_ERRL 0x2c
+void fsl_edma_err_chan_handler(struct fsl_edma_chan *fsl_chan)
+{
+ fsl_chan->status = DMA_ERROR;
+}
+
void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan)
{
spin_lock(&fsl_chan->vchan.lock);
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index 205a96489094..abc8f7805515 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -475,11 +475,7 @@ static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
return container_of(vd, struct fsl_edma_desc, vdesc);
}
-static inline void fsl_edma_err_chan_handler(struct fsl_edma_chan *fsl_chan)
-{
- fsl_chan->status = DMA_ERROR;
-}
-
+void fsl_edma_err_chan_handler(struct fsl_edma_chan *fsl_chan);
void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan);
void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan);
void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 2/5] dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA
2026-06-25 8:59 [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup Jean-Michel Hautbois
2026-06-25 8:59 ` [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file Jean-Michel Hautbois
@ 2026-06-25 8:59 ` Jean-Michel Hautbois
2026-06-25 15:16 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 3/5] dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels Jean-Michel Hautbois
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-25 8:59 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Angelo Dureghello
Cc: Frank Li, imx, dmaengine, linux-kernel, Jean-Michel Hautbois
Add FSL_EDMA_DRV_MCF driver flag to identify MCF ColdFire eDMA
controllers which have a native M68K register layout.
The edma_writeb() function applies an XOR ^ 0x3 byte-lane adjustment for
big-endian eDMA controllers where byte registers within a 32-bit word
need address correction due to endianness differences between the CPU
and hardware IP block.
However, the MCF54418 eDMA is native to the ColdFire architecture and
its 8-bit registers (SERQ, CERQ, SEEI, CEEI, CINT, CERR, SSRT, CDNE) are
located at sequential byte addresses (0x4018-0x401F) as documented in
the MCF54418 Reference Manual Table 19-2. No byte-lane adjustment is
needed - applying the XOR causes writes to target incorrect registers
(e.g., writing to CERR at 0x401D would actually access SSRT at 0x401E).
Set this flag in the MCF eDMA driver to bypass the XOR adjustment and
access registers at their documented addresses.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
drivers/dma/fsl-edma-common.h | 5 ++++-
drivers/dma/mcf-edma-main.c | 2 +-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
index abc8f7805515..64b537527291 100644
--- a/drivers/dma/fsl-edma-common.h
+++ b/drivers/dma/fsl-edma-common.h
@@ -225,6 +225,8 @@ struct fsl_edma_desc {
#define FSL_EDMA_DRV_TCD64 BIT(15)
/* All channel ERR IRQ share one IRQ line */
#define FSL_EDMA_DRV_ERRIRQ_SHARE BIT(16)
+/* MCF eDMA: Different register layout, no XOR for byte access */
+#define FSL_EDMA_DRV_MCF BIT(17)
#define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
@@ -419,7 +421,8 @@ static inline void edma_writeb(struct fsl_edma_engine *edma,
u8 val, void __iomem *addr)
{
/* swap the reg offset for these in big-endian mode */
- if (edma->big_endian)
+ /* MCF eDMA has different register layout, no XOR needed */
+ if (edma->big_endian && !(edma->drvdata->flags & FSL_EDMA_DRV_MCF))
iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
else
iowrite8(val, addr);
diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
index 9e1c6400c77b..f95114829d80 100644
--- a/drivers/dma/mcf-edma-main.c
+++ b/drivers/dma/mcf-edma-main.c
@@ -145,7 +145,7 @@ static void mcf_edma_irq_free(struct platform_device *pdev,
}
static struct fsl_edma_drvdata mcf_data = {
- .flags = FSL_EDMA_DRV_EDMA64,
+ .flags = FSL_EDMA_DRV_EDMA64 | FSL_EDMA_DRV_MCF,
.setup_irq = mcf_edma_irq_init,
};
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 3/5] dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels
2026-06-25 8:59 [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup Jean-Michel Hautbois
2026-06-25 8:59 ` [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file Jean-Michel Hautbois
2026-06-25 8:59 ` [PATCH v3 2/5] dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA Jean-Michel Hautbois
@ 2026-06-25 8:59 ` Jean-Michel Hautbois
2026-06-25 15:30 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 4/5] dmaengine: mcf-edma: Fix error handler for all " Jean-Michel Hautbois
2026-06-25 8:59 ` [PATCH v3 5/5] dmaengine: mcf-edma: Use devm for per-channel IRQ registration Jean-Michel Hautbois
4 siblings, 1 reply; 11+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-25 8:59 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Angelo Dureghello
Cc: Frank Li, imx, dmaengine, linux-kernel, Jean-Michel Hautbois
Fix the DMA completion interrupt handler to properly handle all 64
channels on MCF54418 ColdFire processors.
The previous code used BIT(ch) to test interrupt status bits, which
causes undefined behavior on 32-bit architectures when ch >= 32 because
unsigned long is 32 bits and the shift would exceed the type width.
Replace with bitmap_from_u64() and for_each_set_bit() which correctly
handle 64-bit values on 32-bit systems by using a proper bitmap
representation.
Fixes: e7a3ff92eaf1 ("dmaengine: fsl-edma: add ColdFire mcf5441x edma support")
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
drivers/dma/mcf-edma-main.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
index f95114829d80..953b20f99f25 100644
--- a/drivers/dma/mcf-edma-main.c
+++ b/drivers/dma/mcf-edma-main.c
@@ -18,7 +18,8 @@ static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
{
struct fsl_edma_engine *mcf_edma = dev_id;
struct edma_regs *regs = &mcf_edma->regs;
- unsigned int ch;
+ unsigned long ch;
+ DECLARE_BITMAP(status_mask, 64);
u64 intmap;
intmap = ioread32(regs->inth);
@@ -27,11 +28,11 @@ static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
if (!intmap)
return IRQ_NONE;
- for (ch = 0; ch < mcf_edma->n_chans; ch++) {
- if (intmap & BIT(ch)) {
- iowrite8(EDMA_MASK_CH(ch), regs->cint);
- fsl_edma_tx_chan_handler(&mcf_edma->chans[ch]);
- }
+ bitmap_from_u64(status_mask, intmap);
+
+ for_each_set_bit(ch, status_mask, mcf_edma->n_chans) {
+ iowrite8(EDMA_MASK_CH(ch), regs->cint);
+ fsl_edma_tx_chan_handler(&mcf_edma->chans[ch]);
}
return IRQ_HANDLED;
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 4/5] dmaengine: mcf-edma: Fix error handler for all 64 DMA channels
2026-06-25 8:59 [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup Jean-Michel Hautbois
` (2 preceding siblings ...)
2026-06-25 8:59 ` [PATCH v3 3/5] dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels Jean-Michel Hautbois
@ 2026-06-25 8:59 ` Jean-Michel Hautbois
2026-06-25 15:23 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 5/5] dmaengine: mcf-edma: Use devm for per-channel IRQ registration Jean-Michel Hautbois
4 siblings, 1 reply; 11+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-25 8:59 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Angelo Dureghello
Cc: Frank Li, imx, dmaengine, linux-kernel, Jean-Michel Hautbois
Fix the DMA error interrupt handler to properly handle errors on all
64 channels. The previous implementation had several issues:
1. Returned IRQ_NONE if low channels had no errors, even if high
channels did
2. Used direct status assignment instead of fsl_edma_err_chan_handler()
for high channels
Split the error handling into two separate loops for the low (0-31)
and high (32-63) channel groups, using for_each_set_bit() for cleaner
iteration. Both groups now consistently use fsl_edma_err_chan_handler()
for proper error status reporting.
Fixes: e7a3ff92eaf1 ("dmaengine: fsl-edma: add ColdFire mcf5441x edma support")
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
drivers/dma/mcf-edma-main.c | 32 ++++++++++++--------------------
1 file changed, 12 insertions(+), 20 deletions(-)
diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
index 953b20f99f25..3dab5d475d1b 100644
--- a/drivers/dma/mcf-edma-main.c
+++ b/drivers/dma/mcf-edma-main.c
@@ -42,30 +42,22 @@ static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
{
struct fsl_edma_engine *mcf_edma = dev_id;
struct edma_regs *regs = &mcf_edma->regs;
- unsigned int err, ch;
+ unsigned long ch;
+ DECLARE_BITMAP(err_mask, 64);
+ u64 errmap;
- err = ioread32(regs->errl);
- if (!err)
+ errmap = ioread32(regs->errh);
+ errmap <<= 32;
+ errmap |= ioread32(regs->errl);
+ if (!errmap)
return IRQ_NONE;
- for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
- if (err & BIT(ch)) {
- fsl_edma_disable_request(&mcf_edma->chans[ch]);
- iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
- fsl_edma_err_chan_handler(&mcf_edma->chans[ch]);
- }
- }
-
- err = ioread32(regs->errh);
- if (!err)
- return IRQ_NONE;
+ bitmap_from_u64(err_mask, errmap);
- for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
- if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
- fsl_edma_disable_request(&mcf_edma->chans[ch]);
- iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
- mcf_edma->chans[ch].status = DMA_ERROR;
- }
+ for_each_set_bit(ch, err_mask, mcf_edma->n_chans) {
+ fsl_edma_disable_request(&mcf_edma->chans[ch]);
+ iowrite8(EDMA_MASK_CH(ch), regs->cerr);
+ fsl_edma_err_chan_handler(&mcf_edma->chans[ch]);
}
return IRQ_HANDLED;
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 5/5] dmaengine: mcf-edma: Use devm for per-channel IRQ registration
2026-06-25 8:59 [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup Jean-Michel Hautbois
` (3 preceding siblings ...)
2026-06-25 8:59 ` [PATCH v3 4/5] dmaengine: mcf-edma: Fix error handler for all " Jean-Michel Hautbois
@ 2026-06-25 8:59 ` Jean-Michel Hautbois
2026-06-25 15:26 ` Frank Li
4 siblings, 1 reply; 11+ messages in thread
From: Jean-Michel Hautbois @ 2026-06-25 8:59 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Angelo Dureghello
Cc: Frank Li, imx, dmaengine, linux-kernel, Jean-Michel Hautbois
Register each eDMA transfer interrupt with a per-channel name
("eDMA-<n>") so /proc/interrupts and debugging tools can identify the
channel behind each line, and switch the whole IRQ setup to
devm_request_irq().
Using the managed API lets devres release the handlers on probe
failure or device removal, which removes the manual mcf_edma_irq_free()
teardown and the IRQ leak / dangling irqaction that the previous error
paths left behind. The devm_kasprintf() result is now checked for NULL
before being used as the IRQ name.
Because devres only frees the handlers after mcf_edma_remove() returns,
the controller must be quiesced at the start of remove(): disable every
channel's request and acknowledge any pending interrupt before tearing
down the virtual channels. Otherwise an interrupt could fire into a
partially torn-down state while the handlers are still registered.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
---
drivers/dma/mcf-edma-main.c | 84 ++++++++++++++++++++++-----------------------
1 file changed, 41 insertions(+), 43 deletions(-)
diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
index 3dab5d475d1b..119d49c829fb 100644
--- a/drivers/dma/mcf-edma-main.c
+++ b/drivers/dma/mcf-edma-main.c
@@ -66,7 +66,7 @@ static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
static int mcf_edma_irq_init(struct platform_device *pdev,
struct fsl_edma_engine *mcf_edma)
{
- int ret = 0, i;
+ int ret, i, chan = 0;
struct resource *res;
res = platform_get_resource_byname(pdev,
@@ -74,33 +74,47 @@ static int mcf_edma_irq_init(struct platform_device *pdev,
if (!res)
return -1;
- for (ret = 0, i = res->start; i <= res->end; ++i)
- ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
- if (ret)
- return ret;
+ for (i = res->start; i <= res->end; ++i) {
+ char *irq_name;
+
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "eDMA-%d", chan++);
+ if (!irq_name)
+ return -ENOMEM;
+ ret = devm_request_irq(&pdev->dev, i, mcf_edma_tx_handler, 0,
+ irq_name, mcf_edma);
+ if (ret)
+ return ret;
+ }
res = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "edma-tx-16-55");
if (!res)
return -1;
- for (ret = 0, i = res->start; i <= res->end; ++i)
- ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
- if (ret)
- return ret;
+ for (i = res->start; i <= res->end; ++i) {
+ char *irq_name;
+
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "eDMA-%d", chan++);
+ if (!irq_name)
+ return -ENOMEM;
+ ret = devm_request_irq(&pdev->dev, i, mcf_edma_tx_handler, 0,
+ irq_name, mcf_edma);
+ if (ret)
+ return ret;
+ }
ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
if (ret != -ENXIO) {
- ret = request_irq(ret, mcf_edma_tx_handler,
- 0, "eDMA", mcf_edma);
+ ret = devm_request_irq(&pdev->dev, ret, mcf_edma_tx_handler, 0,
+ "eDMA-tx-56-63", mcf_edma);
if (ret)
return ret;
}
ret = platform_get_irq_byname(pdev, "edma-err");
if (ret != -ENXIO) {
- ret = request_irq(ret, mcf_edma_err_handler,
- 0, "eDMA", mcf_edma);
+ ret = devm_request_irq(&pdev->dev, ret, mcf_edma_err_handler, 0,
+ "eDMA-err", mcf_edma);
if (ret)
return ret;
}
@@ -108,35 +122,6 @@ static int mcf_edma_irq_init(struct platform_device *pdev,
return 0;
}
-static void mcf_edma_irq_free(struct platform_device *pdev,
- struct fsl_edma_engine *mcf_edma)
-{
- int irq;
- struct resource *res;
-
- res = platform_get_resource_byname(pdev,
- IORESOURCE_IRQ, "edma-tx-00-15");
- if (res) {
- for (irq = res->start; irq <= res->end; irq++)
- free_irq(irq, mcf_edma);
- }
-
- res = platform_get_resource_byname(pdev,
- IORESOURCE_IRQ, "edma-tx-16-55");
- if (res) {
- for (irq = res->start; irq <= res->end; irq++)
- free_irq(irq, mcf_edma);
- }
-
- irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
- if (irq != -ENXIO)
- free_irq(irq, mcf_edma);
-
- irq = platform_get_irq_byname(pdev, "edma-err");
- if (irq != -ENXIO)
- free_irq(irq, mcf_edma);
-}
-
static struct fsl_edma_drvdata mcf_data = {
.flags = FSL_EDMA_DRV_EDMA64 | FSL_EDMA_DRV_MCF,
.setup_irq = mcf_edma_irq_init,
@@ -249,8 +234,21 @@ static int mcf_edma_probe(struct platform_device *pdev)
static void mcf_edma_remove(struct platform_device *pdev)
{
struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
+ struct edma_regs *regs = &mcf_edma->regs;
+ int i;
+
+ /*
+ * The per-channel interrupts are requested with devm and are only
+ * freed after this function returns. Quiesce the controller first so
+ * that no interrupt can fire while the virtual channels are torn down:
+ * disable every channel's request and acknowledge any pending
+ * interrupt.
+ */
+ for (i = 0; i < mcf_edma->n_chans; i++)
+ fsl_edma_disable_request(&mcf_edma->chans[i]);
+ iowrite32(~0, regs->inth);
+ iowrite32(~0, regs->intl);
- mcf_edma_irq_free(pdev, mcf_edma);
fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
dma_async_device_unregister(&mcf_edma->dma_dev);
}
--
2.39.5
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 2/5] dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA
2026-06-25 8:59 ` [PATCH v3 2/5] dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA Jean-Michel Hautbois
@ 2026-06-25 15:16 ` Frank Li
0 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-06-25 15:16 UTC (permalink / raw)
To: Jean-Michel Hautbois
Cc: Frank Li, Vinod Koul, Angelo Dureghello, Frank Li, imx,
dmaengine, linux-kernel
On Thu, Jun 25, 2026 at 10:59:38AM +0200, Jean-Michel Hautbois wrote:
> Add FSL_EDMA_DRV_MCF driver flag to identify MCF ColdFire eDMA
> controllers which have a native M68K register layout.
>
> The edma_writeb() function applies an XOR ^ 0x3 byte-lane adjustment for
> big-endian eDMA controllers where byte registers within a 32-bit word
> need address correction due to endianness differences between the CPU
> and hardware IP block.
>
> However, the MCF54418 eDMA is native to the ColdFire architecture and
> its 8-bit registers (SERQ, CERQ, SEEI, CEEI, CINT, CERR, SSRT, CDNE) are
> located at sequential byte addresses (0x4018-0x401F) as documented in
> the MCF54418 Reference Manual Table 19-2. No byte-lane adjustment is
> needed - applying the XOR causes writes to target incorrect registers
> (e.g., writing to CERR at 0x401D would actually access SSRT at 0x401E).
>
> Set this flag in the MCF eDMA driver to bypass the XOR adjustment and
> access registers at their documented addresses.
>
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
> ---
> drivers/dma/fsl-edma-common.h | 5 ++++-
> drivers/dma/mcf-edma-main.c | 2 +-
> 2 files changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
> index abc8f7805515..64b537527291 100644
> --- a/drivers/dma/fsl-edma-common.h
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -225,6 +225,8 @@ struct fsl_edma_desc {
> #define FSL_EDMA_DRV_TCD64 BIT(15)
> /* All channel ERR IRQ share one IRQ line */
> #define FSL_EDMA_DRV_ERRIRQ_SHARE BIT(16)
> +/* MCF eDMA: Different register layout, no XOR for byte access */
> +#define FSL_EDMA_DRV_MCF BIT(17)
>
>
> #define FSL_EDMA_DRV_EDMA3 (FSL_EDMA_DRV_SPLIT_REG | \
> @@ -419,7 +421,8 @@ static inline void edma_writeb(struct fsl_edma_engine *edma,
> u8 val, void __iomem *addr)
> {
> /* swap the reg offset for these in big-endian mode */
> - if (edma->big_endian)
I think native endian, needn't set big_endian. Does it work if don't
set big_endian for MCF54418?
Frank
> + /* MCF eDMA has different register layout, no XOR needed */
> + if (edma->big_endian && !(edma->drvdata->flags & FSL_EDMA_DRV_MCF))
> iowrite8(val, (void __iomem *)((unsigned long)addr ^ 0x3));
> else
> iowrite8(val, addr);
> diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
> index 9e1c6400c77b..f95114829d80 100644
> --- a/drivers/dma/mcf-edma-main.c
> +++ b/drivers/dma/mcf-edma-main.c
> @@ -145,7 +145,7 @@ static void mcf_edma_irq_free(struct platform_device *pdev,
> }
>
> static struct fsl_edma_drvdata mcf_data = {
> - .flags = FSL_EDMA_DRV_EDMA64,
> + .flags = FSL_EDMA_DRV_EDMA64 | FSL_EDMA_DRV_MCF,
> .setup_irq = mcf_edma_irq_init,
> };
>
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 4/5] dmaengine: mcf-edma: Fix error handler for all 64 DMA channels
2026-06-25 8:59 ` [PATCH v3 4/5] dmaengine: mcf-edma: Fix error handler for all " Jean-Michel Hautbois
@ 2026-06-25 15:23 ` Frank Li
0 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-06-25 15:23 UTC (permalink / raw)
To: Jean-Michel Hautbois
Cc: Frank Li, Vinod Koul, Angelo Dureghello, Frank Li, imx,
dmaengine, linux-kernel
On Thu, Jun 25, 2026 at 10:59:40AM +0200, Jean-Michel Hautbois wrote:
> Fix the DMA error interrupt handler to properly handle errors on all
> 64 channels. The previous implementation had several issues:
>
> 1. Returned IRQ_NONE if low channels had no errors, even if high
> channels did
> 2. Used direct status assignment instead of fsl_edma_err_chan_handler()
> for high channels
>
> Split the error handling into two separate loops for the low (0-31)
> and high (32-63) channel groups, using for_each_set_bit() for cleaner
> iteration. Both groups now consistently use fsl_edma_err_chan_handler()
> for proper error status reporting.
>
> Fixes: e7a3ff92eaf1 ("dmaengine: fsl-edma: add ColdFire mcf5441x edma support")
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/dma/mcf-edma-main.c | 32 ++++++++++++--------------------
> 1 file changed, 12 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
> index 953b20f99f25..3dab5d475d1b 100644
> --- a/drivers/dma/mcf-edma-main.c
> +++ b/drivers/dma/mcf-edma-main.c
> @@ -42,30 +42,22 @@ static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
> {
> struct fsl_edma_engine *mcf_edma = dev_id;
> struct edma_regs *regs = &mcf_edma->regs;
> - unsigned int err, ch;
> + unsigned long ch;
> + DECLARE_BITMAP(err_mask, 64);
> + u64 errmap;
>
> - err = ioread32(regs->errl);
> - if (!err)
> + errmap = ioread32(regs->errh);
> + errmap <<= 32;
> + errmap |= ioread32(regs->errl);
> + if (!errmap)
> return IRQ_NONE;
>
> - for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
> - if (err & BIT(ch)) {
> - fsl_edma_disable_request(&mcf_edma->chans[ch]);
> - iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
> - fsl_edma_err_chan_handler(&mcf_edma->chans[ch]);
> - }
> - }
> -
> - err = ioread32(regs->errh);
> - if (!err)
> - return IRQ_NONE;
> + bitmap_from_u64(err_mask, errmap);
>
> - for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
> - if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
> - fsl_edma_disable_request(&mcf_edma->chans[ch]);
> - iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
> - mcf_edma->chans[ch].status = DMA_ERROR;
> - }
> + for_each_set_bit(ch, err_mask, mcf_edma->n_chans) {
> + fsl_edma_disable_request(&mcf_edma->chans[ch]);
> + iowrite8(EDMA_MASK_CH(ch), regs->cerr);
> + fsl_edma_err_chan_handler(&mcf_edma->chans[ch]);
> }
>
> return IRQ_HANDLED;
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 5/5] dmaengine: mcf-edma: Use devm for per-channel IRQ registration
2026-06-25 8:59 ` [PATCH v3 5/5] dmaengine: mcf-edma: Use devm for per-channel IRQ registration Jean-Michel Hautbois
@ 2026-06-25 15:26 ` Frank Li
0 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-06-25 15:26 UTC (permalink / raw)
To: Jean-Michel Hautbois
Cc: Frank Li, Vinod Koul, Angelo Dureghello, Frank Li, imx,
dmaengine, linux-kernel
On Thu, Jun 25, 2026 at 10:59:41AM +0200, Jean-Michel Hautbois wrote:
> Register each eDMA transfer interrupt with a per-channel name
> ("eDMA-<n>") so /proc/interrupts and debugging tools can identify the
> channel behind each line, and switch the whole IRQ setup to
> devm_request_irq().
>
> Using the managed API lets devres release the handlers on probe
> failure or device removal, which removes the manual mcf_edma_irq_free()
> teardown and the IRQ leak / dangling irqaction that the previous error
> paths left behind. The devm_kasprintf() result is now checked for NULL
> before being used as the IRQ name.
>
> Because devres only frees the handlers after mcf_edma_remove() returns,
> the controller must be quiesced at the start of remove(): disable every
> channel's request and acknowledge any pending interrupt before tearing
> down the virtual channels. Otherwise an interrupt could fire into a
> partially torn-down state while the handlers are still registered.
>
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/dma/mcf-edma-main.c | 84 ++++++++++++++++++++++-----------------------
> 1 file changed, 41 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
> index 3dab5d475d1b..119d49c829fb 100644
> --- a/drivers/dma/mcf-edma-main.c
> +++ b/drivers/dma/mcf-edma-main.c
> @@ -66,7 +66,7 @@ static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
> static int mcf_edma_irq_init(struct platform_device *pdev,
> struct fsl_edma_engine *mcf_edma)
> {
> - int ret = 0, i;
> + int ret, i, chan = 0;
> struct resource *res;
>
> res = platform_get_resource_byname(pdev,
> @@ -74,33 +74,47 @@ static int mcf_edma_irq_init(struct platform_device *pdev,
> if (!res)
> return -1;
>
> - for (ret = 0, i = res->start; i <= res->end; ++i)
> - ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
> - if (ret)
> - return ret;
> + for (i = res->start; i <= res->end; ++i) {
> + char *irq_name;
> +
> + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "eDMA-%d", chan++);
> + if (!irq_name)
> + return -ENOMEM;
> + ret = devm_request_irq(&pdev->dev, i, mcf_edma_tx_handler, 0,
> + irq_name, mcf_edma);
> + if (ret)
> + return ret;
> + }
>
> res = platform_get_resource_byname(pdev,
> IORESOURCE_IRQ, "edma-tx-16-55");
> if (!res)
> return -1;
>
> - for (ret = 0, i = res->start; i <= res->end; ++i)
> - ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
> - if (ret)
> - return ret;
> + for (i = res->start; i <= res->end; ++i) {
> + char *irq_name;
> +
> + irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "eDMA-%d", chan++);
> + if (!irq_name)
> + return -ENOMEM;
> + ret = devm_request_irq(&pdev->dev, i, mcf_edma_tx_handler, 0,
> + irq_name, mcf_edma);
> + if (ret)
> + return ret;
> + }
>
> ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
> if (ret != -ENXIO) {
> - ret = request_irq(ret, mcf_edma_tx_handler,
> - 0, "eDMA", mcf_edma);
> + ret = devm_request_irq(&pdev->dev, ret, mcf_edma_tx_handler, 0,
> + "eDMA-tx-56-63", mcf_edma);
> if (ret)
> return ret;
> }
>
> ret = platform_get_irq_byname(pdev, "edma-err");
> if (ret != -ENXIO) {
> - ret = request_irq(ret, mcf_edma_err_handler,
> - 0, "eDMA", mcf_edma);
> + ret = devm_request_irq(&pdev->dev, ret, mcf_edma_err_handler, 0,
> + "eDMA-err", mcf_edma);
> if (ret)
> return ret;
> }
> @@ -108,35 +122,6 @@ static int mcf_edma_irq_init(struct platform_device *pdev,
> return 0;
> }
>
> -static void mcf_edma_irq_free(struct platform_device *pdev,
> - struct fsl_edma_engine *mcf_edma)
> -{
> - int irq;
> - struct resource *res;
> -
> - res = platform_get_resource_byname(pdev,
> - IORESOURCE_IRQ, "edma-tx-00-15");
> - if (res) {
> - for (irq = res->start; irq <= res->end; irq++)
> - free_irq(irq, mcf_edma);
> - }
> -
> - res = platform_get_resource_byname(pdev,
> - IORESOURCE_IRQ, "edma-tx-16-55");
> - if (res) {
> - for (irq = res->start; irq <= res->end; irq++)
> - free_irq(irq, mcf_edma);
> - }
> -
> - irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
> - if (irq != -ENXIO)
> - free_irq(irq, mcf_edma);
> -
> - irq = platform_get_irq_byname(pdev, "edma-err");
> - if (irq != -ENXIO)
> - free_irq(irq, mcf_edma);
> -}
> -
> static struct fsl_edma_drvdata mcf_data = {
> .flags = FSL_EDMA_DRV_EDMA64 | FSL_EDMA_DRV_MCF,
> .setup_irq = mcf_edma_irq_init,
> @@ -249,8 +234,21 @@ static int mcf_edma_probe(struct platform_device *pdev)
> static void mcf_edma_remove(struct platform_device *pdev)
> {
> struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
> + struct edma_regs *regs = &mcf_edma->regs;
> + int i;
> +
> + /*
> + * The per-channel interrupts are requested with devm and are only
> + * freed after this function returns. Quiesce the controller first so
> + * that no interrupt can fire while the virtual channels are torn down:
> + * disable every channel's request and acknowledge any pending
> + * interrupt.
> + */
> + for (i = 0; i < mcf_edma->n_chans; i++)
> + fsl_edma_disable_request(&mcf_edma->chans[i]);
> + iowrite32(~0, regs->inth);
> + iowrite32(~0, regs->intl);
>
> - mcf_edma_irq_free(pdev, mcf_edma);
> fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
> dma_async_device_unregister(&mcf_edma->dma_dev);
> }
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 3/5] dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels
2026-06-25 8:59 ` [PATCH v3 3/5] dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels Jean-Michel Hautbois
@ 2026-06-25 15:30 ` Frank Li
0 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-06-25 15:30 UTC (permalink / raw)
To: Jean-Michel Hautbois
Cc: Frank Li, Vinod Koul, Angelo Dureghello, Frank Li, imx,
dmaengine, linux-kernel
On Thu, Jun 25, 2026 at 10:59:39AM +0200, Jean-Michel Hautbois wrote:
> Fix the DMA completion interrupt handler to properly handle all 64
> channels on MCF54418 ColdFire processors.
>
> The previous code used BIT(ch) to test interrupt status bits, which
> causes undefined behavior on 32-bit architectures when ch >= 32 because
> unsigned long is 32 bits and the shift would exceed the type width.
>
> Replace with bitmap_from_u64() and for_each_set_bit() which correctly
> handle 64-bit values on 32-bit systems by using a proper bitmap
> representation.
>
> Fixes: e7a3ff92eaf1 ("dmaengine: fsl-edma: add ColdFire mcf5441x edma support")
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/dma/mcf-edma-main.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c
> index f95114829d80..953b20f99f25 100644
> --- a/drivers/dma/mcf-edma-main.c
> +++ b/drivers/dma/mcf-edma-main.c
> @@ -18,7 +18,8 @@ static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
> {
> struct fsl_edma_engine *mcf_edma = dev_id;
> struct edma_regs *regs = &mcf_edma->regs;
> - unsigned int ch;
> + unsigned long ch;
> + DECLARE_BITMAP(status_mask, 64);
> u64 intmap;
>
> intmap = ioread32(regs->inth);
> @@ -27,11 +28,11 @@ static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
> if (!intmap)
> return IRQ_NONE;
>
> - for (ch = 0; ch < mcf_edma->n_chans; ch++) {
> - if (intmap & BIT(ch)) {
> - iowrite8(EDMA_MASK_CH(ch), regs->cint);
> - fsl_edma_tx_chan_handler(&mcf_edma->chans[ch]);
> - }
> + bitmap_from_u64(status_mask, intmap);
> +
> + for_each_set_bit(ch, status_mask, mcf_edma->n_chans) {
> + iowrite8(EDMA_MASK_CH(ch), regs->cint);
> + fsl_edma_tx_chan_handler(&mcf_edma->chans[ch]);
> }
>
> return IRQ_HANDLED;
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file
2026-06-25 8:59 ` [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file Jean-Michel Hautbois
@ 2026-06-25 15:33 ` Frank Li
0 siblings, 0 replies; 11+ messages in thread
From: Frank Li @ 2026-06-25 15:33 UTC (permalink / raw)
To: Jean-Michel Hautbois
Cc: Frank Li, Vinod Koul, Angelo Dureghello, Frank Li, imx,
dmaengine, linux-kernel
On Thu, Jun 25, 2026 at 10:59:37AM +0200, Jean-Michel Hautbois wrote:
> Move fsl_edma_err_chan_handler from an inline function in the header
> to a proper function in fsl-edma-common.c. This prepares for MCF
> ColdFire eDMA support where the error handler needs to be called from
> the MCF-specific error interrupt handler.
why need this move? not difference between call inline function and extern
function
Frank
>
> No functional change for existing users.
>
> Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org>
> ---
> drivers/dma/fsl-edma-common.c | 5 +++++
> drivers/dma/fsl-edma-common.h | 6 +-----
> 2 files changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
> index bb7531c456df..1b1a0496b5e6 100644
> --- a/drivers/dma/fsl-edma-common.c
> +++ b/drivers/dma/fsl-edma-common.c
> @@ -44,6 +44,11 @@
> #define EDMA64_ERRH 0x28
> #define EDMA64_ERRL 0x2c
>
> +void fsl_edma_err_chan_handler(struct fsl_edma_chan *fsl_chan)
> +{
> + fsl_chan->status = DMA_ERROR;
> +}
> +
> void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan)
> {
> spin_lock(&fsl_chan->vchan.lock);
> diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h
> index 205a96489094..abc8f7805515 100644
> --- a/drivers/dma/fsl-edma-common.h
> +++ b/drivers/dma/fsl-edma-common.h
> @@ -475,11 +475,7 @@ static inline struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
> return container_of(vd, struct fsl_edma_desc, vdesc);
> }
>
> -static inline void fsl_edma_err_chan_handler(struct fsl_edma_chan *fsl_chan)
> -{
> - fsl_chan->status = DMA_ERROR;
> -}
> -
> +void fsl_edma_err_chan_handler(struct fsl_edma_chan *fsl_chan);
> void fsl_edma_tx_chan_handler(struct fsl_edma_chan *fsl_chan);
> void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan);
> void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-06-25 15:34 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-25 8:59 [PATCH v3 0/5] dmaengine: mcf-edma: fix 64-channel handling and modernize IRQ setup Jean-Michel Hautbois
2026-06-25 8:59 ` [PATCH v3 1/5] dmaengine: fsl-edma: Move error handler out of header file Jean-Michel Hautbois
2026-06-25 15:33 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 2/5] dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA Jean-Michel Hautbois
2026-06-25 15:16 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 3/5] dmaengine: mcf-edma: Fix interrupt handler for 64 DMA channels Jean-Michel Hautbois
2026-06-25 15:30 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 4/5] dmaengine: mcf-edma: Fix error handler for all " Jean-Michel Hautbois
2026-06-25 15:23 ` Frank Li
2026-06-25 8:59 ` [PATCH v3 5/5] dmaengine: mcf-edma: Use devm for per-channel IRQ registration Jean-Michel Hautbois
2026-06-25 15:26 ` Frank Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®