* [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
* 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
* [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
* 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
* [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
* 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
* [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
* 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
* [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 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
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®