* [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; 15+ 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] 15+ 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 9:18 ` sashiko-bot 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, 2 replies; 15+ 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 related [flat|nested] 15+ 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 9:18 ` sashiko-bot 2026-06-25 15:33 ` Frank Li 1 sibling, 0 replies; 15+ messages in thread From: sashiko-bot @ 2026-06-25 9:18 UTC (permalink / raw) To: Jean-Michel Hautbois; +Cc: vkoul, dmaengine, imx, Frank.Li Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [High] Unprotected write to channel status in the error handler causes a data race that can mask hardware errors and hang DMA clients. -- commit cc17ac4f2b0c85f5476ae3803d0c9e31bd371d29 Author: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org> dmaengine: fsl-edma: Move error handler out of header file This commit moves the fsl_edma_err_chan_handler function from an inline definition in the header file to the common C file. This prepares the driver for MCF ColdFire eDMA support, where the handler is called from a specific interrupt handler. > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c > index bb7531c456dfa..1b1a0496b5e6f 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; > +} > + [Severity: High] This is a pre-existing issue, but does this unlocked write to the channel status create a race condition that could mask hardware errors? If fsl_edma_tx_chan_handler() processes a completed transfer on CPU0, it calls fsl_edma_xfer_desc() to start the next pending transfer. This enables the hardware request and then assigns the channel status to DMA_IN_PROGRESS. If the new transfer immediately triggers a hardware error, the error interrupt fires on CPU1. CPU1 executes fsl_edma_err_chan_handler() and writes DMA_ERROR to fsl_chan->status without acquiring the vchan.lock. If CPU1's write occurs between the hardware request being enabled and CPU0's write to DMA_IN_PROGRESS, the DMA_ERROR state is overwritten. If the error is masked, the driver state remains DMA_IN_PROGRESS while the hardware is permanently halted. Could this cause DMA clients to hang indefinitely waiting for the failed transfer? [ ... ] -- Sashiko AI review · https://sashiko.dev/#/patchset/20260625-b4-edma-dmaengine-v3-0-44be00ace37d@yoseli.org?part=1 ^ permalink raw reply [flat|nested] 15+ 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 9:18 ` sashiko-bot @ 2026-06-25 15:33 ` Frank Li 1 sibling, 0 replies; 15+ 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] 15+ 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 9:20 ` sashiko-bot 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, 2 replies; 15+ 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 related [flat|nested] 15+ 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 9:20 ` sashiko-bot 2026-06-25 15:16 ` Frank Li 1 sibling, 0 replies; 15+ messages in thread From: sashiko-bot @ 2026-06-25 9:20 UTC (permalink / raw) To: Jean-Michel Hautbois; +Cc: dmaengine, vkoul, imx, Frank.Li Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [High] The patch correctly bypasses the XOR byte-lane adjustment for 8-bit registers on MCF eDMA via the FSL_EDMA_DRV_MCF flag, but fails to apply the same bypass for 16-bit registers written via edma_writew(). This will corrupt TCD 16-bit register writes on ColdFire platforms. -- commit e23a155133dba0ca56d6eea575c63bb35a8ef9ab Author: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org> dmaengine: fsl-edma: Add FSL_EDMA_DRV_MCF flag for ColdFire eDMA This commit adds a new flag FSL_EDMA_DRV_MCF for the ColdFire eDMA driver to bypass the XOR byte-lane adjustment for 8-bit registers, ensuring writes target the correct documented addresses. > diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h > index abc8f78055156..64b5375272917 100644 > --- a/drivers/dma/fsl-edma-common.h > +++ b/drivers/dma/fsl-edma-common.h [ ... ] > @@ -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); [Severity: High] This isn't a bug introduced by this patch, but should edma_writew() be updated to bypass the address adjustment as well? Looking at edma_writew() right below this function, it performs 16-bit writes and unconditionally applies the ^ 0x2 XOR offset adjustment for big-endian controllers: drivers/dma/fsl-edma-common.h:edma_writew() { /* swap the reg offset for these in big-endian mode */ if (edma->big_endian) iowrite16be(val, (void __iomem *)((unsigned long)addr ^ 0x2)); ... } Without checking FSL_EDMA_DRV_MCF here, wouldn't writing 16-bit TCD registers on native ColdFire platforms still apply the ^ 0x2 offset and incorrectly swap registers like soff and attr? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260625-b4-edma-dmaengine-v3-0-44be00ace37d@yoseli.org?part=2 ^ permalink raw reply [flat|nested] 15+ 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 9:20 ` sashiko-bot @ 2026-06-25 15:16 ` Frank Li 1 sibling, 0 replies; 15+ 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] 15+ 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; 15+ 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 related [flat|nested] 15+ 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; 15+ 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] 15+ 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 9:17 ` sashiko-bot 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, 2 replies; 15+ 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 related [flat|nested] 15+ 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 9:17 ` sashiko-bot 2026-06-25 15:23 ` Frank Li 1 sibling, 0 replies; 15+ messages in thread From: sashiko-bot @ 2026-06-25 9:17 UTC (permalink / raw) To: Jean-Michel Hautbois; +Cc: imx, dmaengine, vkoul, Frank.Li Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Pre-existing issues: - [High] Incomplete Fix / Hardware State Corruption: fsl_edma_disable_request() truncates channel IDs >= 32 when disabling error interrupts. -- commit 95f12f5cb94b6214f42fed40a0a6ec8cb8002d51 Author: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org> dmaengine: mcf-edma: Fix error handler for all 64 DMA channels This commit updates the DMA error interrupt handler to properly process errors on all 64 channels by iterating over a 64-bit mask with for_each_set_bit(). It also ensures both low and high channel groups consistently use fsl_edma_err_chan_handler() for error status reporting. > diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c > index 953b20f99f251..3dab5d475d1b4 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) [ ... ] > - 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]); [Severity: High] This is a pre-existing issue, but does fsl_edma_disable_request() properly handle channel IDs >= 32? Looking at fsl_edma_disable_request() in drivers/dma/fsl-edma-common.c, it uses the EDMA_CEEI_CEEI() macro to write to the ceei register: iowrite8(ch, regs->cerq); iowrite8(EDMA_CEEI_CEEI(ch), regs->ceei); However, EDMA_CEEI_CEEI(x) masks the channel ID to 5 bits using GENMASK(4, 0). When fsl_edma_disable_request() is called for high channels (32-63), the channel ID will be truncated. For instance, channel 33 would be truncated to 1. Could this truncation fail to disable the error interrupt for the intended high channel, leading to a continuous interrupt loop, while erroneously disabling the interrupt for an unrelated active low channel? > + iowrite8(EDMA_MASK_CH(ch), regs->cerr); > + fsl_edma_err_chan_handler(&mcf_edma->chans[ch]); > } > > return IRQ_HANDLED; -- Sashiko AI review · https://sashiko.dev/#/patchset/20260625-b4-edma-dmaengine-v3-0-44be00ace37d@yoseli.org?part=4 ^ permalink raw reply [flat|nested] 15+ 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 9:17 ` sashiko-bot @ 2026-06-25 15:23 ` Frank Li 1 sibling, 0 replies; 15+ 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] 15+ 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 9:21 ` sashiko-bot 2026-06-25 15:26 ` Frank Li 4 siblings, 2 replies; 15+ 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 related [flat|nested] 15+ 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 9:21 ` sashiko-bot 2026-06-25 15:26 ` Frank Li 1 sibling, 0 replies; 15+ messages in thread From: sashiko-bot @ 2026-06-25 9:21 UTC (permalink / raw) To: Jean-Michel Hautbois; +Cc: vkoul, Frank.Li, dmaengine, imx Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: New issues: - [High] Replacing explicit `free_irq()` with `devm_request_irq()` introduces a Use-After-Free race condition by deferring IRQ unregistration until after the virtual channels are torn down. Pre-existing issues: - [High] dma_async_device_unregister() fails to clean up channels because fsl_edma_cleanup_vchan() improperly empties the channel list beforehand, leading to a resource leak. -- commit 3174cb73d4f28e4270bffd2960b8600186152672 Author: Jean-Michel Hautbois <jeanmichel.hautbois@yoseli.org> dmaengine: mcf-edma: Use devm for per-channel IRQ registration This patch converts the eDMA transfer interrupt registration to use the managed devm_request_irq() API with per-channel names. It also adds logic in the remove path to manually quiesce the hardware since the interrupts are now freed later by devres. > diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c > --- a/drivers/dma/mcf-edma-main.c > +++ b/drivers/dma/mcf-edma-main.c [ ... ] > @@ -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); [Severity: High] Does deferring the IRQ unregistration until after the virtual channels are torn down introduce a use-after-free race? Since devm_request_irq() defers freeing the IRQ until after mcf_edma_remove() returns, the driver loses the synchronization barrier that previously waited for in-flight handlers. The manual hardware quiescence loop does not synchronize with already executing handlers. If an interrupt handler executes on another CPU, could it complete the transfer and call vchan_cookie_complete(), which executes tasklet_schedule()? If this happens after fsl_edma_cleanup_vchan() kills the tasklet: fsl_edma_cleanup_vchan() tasklet_kill(&chan->vchan.task); the tasklet could be placed back on the runqueue. After remove() completes, devres frees the IRQ and device memory, meaning the scheduled tasklet would execute on freed memory. > dma_async_device_unregister(&mcf_edma->dma_dev); [Severity: High] This isn't a bug introduced by this patch, but does the order of operations here leave dma_async_device_unregister() operating on an empty list? Looking at fsl_edma_cleanup_vchan(), it iterates over dmadev->channels and removes every channel from the list: fsl_edma_cleanup_vchan() { list_for_each_entry_safe(...) { list_del(&chan->vchan.chan.device_node); ... } } Immediately after, dma_async_device_unregister() is called, which relies on iterating over the exact same device->channels list to unregister the channels. Because the list was just emptied, the iteration does zero passes, skipping the core channel unregistration and permanently leaking sysfs entries and per-cpu memory. > } -- Sashiko AI review · https://sashiko.dev/#/patchset/20260625-b4-edma-dmaengine-v3-0-44be00ace37d@yoseli.org?part=5 ^ permalink raw reply [flat|nested] 15+ 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 9:21 ` sashiko-bot @ 2026-06-25 15:26 ` Frank Li 1 sibling, 0 replies; 15+ 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] 15+ messages in thread
end of thread, other threads:[~2026-06-25 15:34 UTC | newest] Thread overview: 15+ 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 9:18 ` sashiko-bot 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 9:20 ` sashiko-bot 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 9:17 ` sashiko-bot 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 9:21 ` sashiko-bot 2026-06-25 15:26 ` Frank Li
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.