* [PATCH 0/2] dmaengine: fsl-edma: add per-channel IOMMU support
@ 2026-09-16 15:55 Peng Fan (OSS)
2026-09-16 15:55 ` [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property Peng Fan (OSS)
2026-09-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS)
0 siblings, 2 replies; 8+ messages in thread
From: Peng Fan (OSS) @ 2026-09-16 15:55 UTC (permalink / raw)
To: Frank Li, Vinod Koul, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Frank Li, imx, dmaengine, devicetree, linux-kernel, Peng Fan
Add iommu-map support to the fsl-edma driver to enable per-channel IOMMU
stream ID mapping for eDMA controllers.
On i.MX95, eDMA channels are assigned individual stream IDs by the
SMMU, with paired channels (e.g. TX/RX) sharing the same SID. The
standard iommu-map devicetree property is used to describe this
mapping, following the same pattern used by PCI controllers.
Patch 1 adds the iommu-map property to the fsl,edma dt-binding schema
and includes an fsl,imx95-edma5 example demonstrating per-channel
mappings.
Patch 2 implements the driver support: at probe time, per-channel
devices are prepared with DMA masks and bus pointers; at xlate time,
the channel index is looked up in iommu-map to attach the appropriate
IOMMU domain. Channels without a matching entry operate in bypass
mode.
To test this patch on i.MX95 for channels using shared SID, needs:
https://lore.kernel.org/linux-iommu/20260916-smmu-shared-sid-v1-0-517384504aee@nxp.com/T/#t
If only test channels that not needs shared SID, no need above patchset.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Peng Fan (2):
dt-bindings: dma: fsl,edma: add iommu-map property
dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map
.../devicetree/bindings/dma/fsl,edma.yaml | 89 ++++++++++++++++++++++
drivers/dma/fsl-edma-common.c | 6 +-
drivers/dma/fsl-edma-common.h | 1 +
drivers/dma/fsl-edma-main.c | 76 +++++++++++++++++-
4 files changed, 169 insertions(+), 3 deletions(-)
---
base-commit: e6e35979777d646fe3c7c94dca7dd32fb25d45f4
change-id: 20260916-edma-iommu-d5b8d0b515dd
Best regards,
--
Peng Fan <peng.fan@nxp.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property 2026-09-16 15:55 [PATCH 0/2] dmaengine: fsl-edma: add per-channel IOMMU support Peng Fan (OSS) @ 2026-09-16 15:55 ` Peng Fan (OSS) 2026-09-16 16:46 ` Frank Li 2026-09-24 21:56 ` Rob Herring (Arm) 2026-09-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS) 1 sibling, 2 replies; 8+ messages in thread From: Peng Fan (OSS) @ 2026-09-16 15:55 UTC (permalink / raw) To: Frank Li, Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Frank Li, imx, dmaengine, devicetree, linux-kernel, Peng Fan From: Peng Fan <peng.fan@nxp.com> Add the iommu-map property to the fsl,edma binding to allow per-channel IOMMU stream ID mapping. This enables IOMMU translation for individual eDMA channels, where paired channels can share the same stream ID and channels without an entry operate in bypass mode. Also add a new example using fsl,imx95-edma5 that demonstrates the iommu-map usage with per-channel mappings. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Peng Fan <peng.fan@nxp.com> --- .../devicetree/bindings/dma/fsl,edma.yaml | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml index f609038e35ae1..cb8c650a5bb90 100644 --- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml +++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml @@ -104,6 +104,15 @@ properties: Bit semantics: 0 means channel available, 1 means channel unavailable default: 0 + iommu-map: + description: + Maps DMA channel numbers to IOMMU stream IDs. Each entry maps one + or more channels to a contiguous range of stream IDs. Paired channels + may share the same stream ID. Channels without an entry operate in + bypass mode. + minItems: 1 + maxItems: 64 + required: - "#dma-cells" - compatible @@ -351,3 +360,83 @@ examples: <&pd IMX_SC_R_DMA_3_CH6>, <&pd IMX_SC_R_DMA_3_CH7>; }; + + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + dma-controller@42000000 { + compatible = "fsl,imx95-edma5"; + reg = <0x42000000 0x210000>; + #dma-cells = <3>; + dma-channels = <64>; + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk 0>; + clock-names = "dma"; + /* + * Per-channel IOMMU mapping. Each channel + * occupies one entry; paired channels share + * the same SID. Channels without an entry + * operate in bypass mode. + */ + iommu-map = <2 &smmu 0x30 1>, + <3 &smmu 0x30 1>, + <4 &smmu 0x31 1>, + <5 &smmu 0x31 1>, + <6 &smmu 0x32 1>, + <7 &smmu 0x32 1>, + <8 &smmu 0x33 1>, + <9 &smmu 0x33 1>, + <10 &smmu 0x34 1>, + <11 &smmu 0x34 1>, + <12 &smmu 0x35 1>, + <13 &smmu 0x35 1>, + <14 &smmu 0x36 1>, + <15 &smmu 0x36 1>, + <16 &smmu 0x37 1>, + <17 &smmu 0x37 1>, + <18 &smmu 0x38 1>, + <19 &smmu 0x38 1>; + }; -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property 2026-09-16 15:55 ` [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property Peng Fan (OSS) @ 2026-09-16 16:46 ` Frank Li 2026-09-24 21:56 ` Rob Herring (Arm) 1 sibling, 0 replies; 8+ messages in thread From: Frank Li @ 2026-09-16 16:46 UTC (permalink / raw) To: Peng Fan (OSS) Cc: Frank Li, Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li, imx, dmaengine, devicetree, linux-kernel, Peng Fan On Wed, Sep 16, 2026 at 11:55:25PM +0800, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@nxp.com> > > Add the iommu-map property to the fsl,edma binding to allow per-channel > IOMMU stream ID mapping. This enables IOMMU translation for individual > eDMA channels, where paired channels can share the same stream ID and > channels without an entry operate in bypass mode. > > Also add a new example using fsl,imx95-edma5 that demonstrates the > iommu-map usage with per-channel mappings. > > Assisted-by: Claude:claude-opus-4-6 > Signed-off-by: Peng Fan <peng.fan@nxp.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > .../devicetree/bindings/dma/fsl,edma.yaml | 89 ++++++++++++++++++++++ > 1 file changed, 89 insertions(+) > > diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml > index f609038e35ae1..cb8c650a5bb90 100644 > --- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml > +++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml > @@ -104,6 +104,15 @@ properties: > Bit semantics: 0 means channel available, 1 means channel unavailable > default: 0 > > + iommu-map: > + description: > + Maps DMA channel numbers to IOMMU stream IDs. Each entry maps one > + or more channels to a contiguous range of stream IDs. Paired channels > + may share the same stream ID. Channels without an entry operate in > + bypass mode. > + minItems: 1 > + maxItems: 64 > + > required: > - "#dma-cells" > - compatible > @@ -351,3 +360,83 @@ examples: > <&pd IMX_SC_R_DMA_3_CH6>, > <&pd IMX_SC_R_DMA_3_CH7>; > }; > + > + - | > + #include <dt-bindings/interrupt-controller/arm-gic.h> > + > + dma-controller@42000000 { > + compatible = "fsl,imx95-edma5"; > + reg = <0x42000000 0x210000>; > + #dma-cells = <3>; > + dma-channels = <64>; > + interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>; > + clocks = <&clk 0>; > + clock-names = "dma"; > + /* > + * Per-channel IOMMU mapping. Each channel > + * occupies one entry; paired channels share > + * the same SID. Channels without an entry > + * operate in bypass mode. > + */ > + iommu-map = <2 &smmu 0x30 1>, > + <3 &smmu 0x30 1>, > + <4 &smmu 0x31 1>, > + <5 &smmu 0x31 1>, > + <6 &smmu 0x32 1>, > + <7 &smmu 0x32 1>, > + <8 &smmu 0x33 1>, > + <9 &smmu 0x33 1>, > + <10 &smmu 0x34 1>, > + <11 &smmu 0x34 1>, > + <12 &smmu 0x35 1>, > + <13 &smmu 0x35 1>, > + <14 &smmu 0x36 1>, > + <15 &smmu 0x36 1>, > + <16 &smmu 0x37 1>, > + <17 &smmu 0x37 1>, > + <18 &smmu 0x38 1>, > + <19 &smmu 0x38 1>; > + }; > > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property 2026-09-16 15:55 ` [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property Peng Fan (OSS) 2026-09-16 16:46 ` Frank Li @ 2026-09-24 21:56 ` Rob Herring (Arm) 2026-09-25 1:43 ` Peng Fan 1 sibling, 1 reply; 8+ messages in thread From: Rob Herring (Arm) @ 2026-09-24 21:56 UTC (permalink / raw) To: Peng Fan (OSS) Cc: Frank Li, linux-kernel, Krzysztof Kozlowski, Conor Dooley, imx, devicetree, Peng Fan, dmaengine, Vinod Koul, Frank Li On Wed, 16 Sep 2026 23:55:25 +0800, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@nxp.com> > > Add the iommu-map property to the fsl,edma binding to allow per-channel > IOMMU stream ID mapping. This enables IOMMU translation for individual > eDMA channels, where paired channels can share the same stream ID and > channels without an entry operate in bypass mode. > > Also add a new example using fsl,imx95-edma5 that demonstrates the > iommu-map usage with per-channel mappings. > > Assisted-by: Claude:claude-opus-4-6 > Signed-off-by: Peng Fan <peng.fan@nxp.com> > --- > .../devicetree/bindings/dma/fsl,edma.yaml | 89 ++++++++++++++++++++++ > 1 file changed, 89 insertions(+) > Reviewed-by: Rob Herring (Arm) <robh@kernel.org> ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property 2026-09-24 21:56 ` Rob Herring (Arm) @ 2026-09-25 1:43 ` Peng Fan 0 siblings, 0 replies; 8+ messages in thread From: Peng Fan @ 2026-09-25 1:43 UTC (permalink / raw) To: Rob Herring (Arm) Cc: Frank Li, linux-kernel, Krzysztof Kozlowski, Conor Dooley, imx, devicetree, Peng Fan, dmaengine, Vinod Koul, Frank Li Hi Rob, Frank, On Thu, Sep 24, 2026 at 04:56:26PM -0500, Rob Herring (Arm) wrote: > >On Wed, 16 Sep 2026 23:55:25 +0800, Peng Fan (OSS) wrote: >> From: Peng Fan <peng.fan@nxp.com> >> >> Add the iommu-map property to the fsl,edma binding to allow per-channel >> IOMMU stream ID mapping. This enables IOMMU translation for individual >> eDMA channels, where paired channels can share the same stream ID and >> channels without an entry operate in bypass mode. >> >> Also add a new example using fsl,imx95-edma5 that demonstrates the >> iommu-map usage with per-channel mappings. >> >> Assisted-by: Claude:claude-opus-4-6 >> Signed-off-by: Peng Fan <peng.fan@nxp.com> >> --- >> .../devicetree/bindings/dma/fsl,edma.yaml | 89 ++++++++++++++++++++++ >> 1 file changed, 89 insertions(+) >> > >Reviewed-by: Rob Herring (Arm) <robh@kernel.org> Thanks for reviewing this patchset. I think I need to drop this patchset and use the other method. in https://lore.kernel.org/all/20260917144804.GI3196566@ziepe.ca/, Jason Gunthorpe does not agree to use iommu-map for eDMA channels. "The DT modeling for devices that have multiple stream-IDs is to list them all in iommus list." More comments about QCOM VPU in https://lore.kernel.org/linux-iommu/20260618151745.GD231643@ziepe.ca/ " In Linux if you use DT iommus the SW sets things up so every stream shares the same translation. If your driver/device doesn't like that there is no SW way to opt out of sharing. I think that is the first core issue that VPU was struggling with. If you have one "device" then I would argue the DT should describe all its streams using iommus in the normal way. The introduction of iommu-map for VPU is only being done because that is a convenient hack to allow Linux to unbundle the streams. It would be much harder to unbunble the streams directly from the DT iommus property, but that would probably be the cleanest, software agnostic, DT modeling. So, if we are going to do a hack in DT to accomodate Linux, I argue to choose explicit child devices so VPU does not need to create a special bus, call of_dma_configue, or hack in new DMA API things that only it will ever use. Then the explicit children can properly describe how the HW decodes IOVA into each streams in the DT (which sounds very much like a HW property to me) so that Linux produces IOVA that the HW mangling properly routes to the expected stream. Then the VPU driver just has to assemble itself from many struct devices, which I admit is also a troublesome task. " Thanks Peng > > ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map 2026-09-16 15:55 [PATCH 0/2] dmaengine: fsl-edma: add per-channel IOMMU support Peng Fan (OSS) 2026-09-16 15:55 ` [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property Peng Fan (OSS) @ 2026-09-16 15:55 ` Peng Fan (OSS) 2026-09-16 16:06 ` sashiko-bot 2026-09-16 18:23 ` Frank Li 1 sibling, 2 replies; 8+ messages in thread From: Peng Fan (OSS) @ 2026-09-16 15:55 UTC (permalink / raw) To: Frank Li, Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley Cc: Frank Li, imx, dmaengine, devicetree, linux-kernel, Peng Fan From: Peng Fan <peng.fan@nxp.com> Add iommu-map support so that each eDMA channel can be individually mapped to an IOMMU stream ID. At probe time, fsl_edma_init_chan_iommu() prepares per-channel devices by initializing DMA masks and bus pointers so of_dma_configure_id() can be called later. At xlate time, fsl_edma_chan_configure_iommu() looks up the allocated channel index in iommu-map. If an entry exists, it calls of_dma_configure_id() to attach the IOMMU domain and sets chan_dma_dev so dmaengine_get_dma_device() returns the per-channel device. Channels without a matching entry operate in bypass mode. Also switch fsl_edma_prep_slave_dma() and fsl_edma_unprep_slave_dma() to use dmaengine_get_dma_device() for DMA resource mapping. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Peng Fan <peng.fan@nxp.com> --- drivers/dma/fsl-edma-common.c | 6 ++-- drivers/dma/fsl-edma-common.h | 1 + drivers/dma/fsl-edma-main.c | 76 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index bb7531c456dfa..58a92ff4ddbe7 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -283,8 +283,10 @@ int fsl_edma_resume(struct dma_chan *chan) static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan) { + struct device *dev = dmaengine_get_dma_device(&fsl_chan->vchan.chan); + if (fsl_chan->dma_dir != DMA_NONE) - dma_unmap_resource(fsl_chan->vchan.chan.device->dev, + dma_unmap_resource(dev, fsl_chan->dma_dev_addr, fsl_chan->dma_dev_size, fsl_chan->dma_dir, 0); @@ -294,7 +296,7 @@ static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan) static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan, enum dma_transfer_direction dir) { - struct device *dev = fsl_chan->vchan.chan.device->dev; + struct device *dev = dmaengine_get_dma_device(&fsl_chan->vchan.chan); enum dma_data_direction dma_dir; phys_addr_t addr = 0; u32 size = 0; diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 205a964890948..85487763e05ab 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -264,6 +264,7 @@ struct fsl_edma_engine { int txirq_16_31; int errirq; bool big_endian; + bool has_iommu_map; struct edma_regs regs; u64 chan_masked; struct fsl_edma_chan chans[] __counted_by(n_chans); diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index d9fb717b5b53c..eabb0086fc9de 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -16,6 +16,7 @@ #include <linux/interrupt.h> #include <linux/clk.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> @@ -24,6 +25,7 @@ #include "fsl-edma-common.h" +static int fsl_edma_chan_configure_iommu(struct fsl_edma_chan *fsl_chan); static void fsl_edma_synchronize(struct dma_chan *chan) { struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); @@ -298,7 +300,7 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, struct dma_chan *chan, *_chan; struct fsl_edma_chan *fsl_chan; bool b_chmux; - int i; + int i, ret; if (dma_spec->args_count != 3) return NULL; @@ -332,6 +334,12 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; + if (fsl_edma->has_iommu_map) { + ret = fsl_edma_chan_configure_iommu(fsl_chan); + if (ret) + return NULL; + } + chan = dma_get_slave_channel(chan); chan->device->privatecnt++; return chan; @@ -695,6 +703,70 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng return -EINVAL; } +/** + * fsl_edma_init_chan_iommu - prepare per-channel devices for IOMMU + * @pdev: the eDMA platform device + * @fsl_edma: the eDMA engine instance + * + * Must be called after dmaenginem_async_device_register() so that each + * channel's chan->dev->device is already registered. + * + * Initialize DMA mask and bus on each channel device so that + * of_dma_configure_id() can be called later at xlate time. + */ +static void fsl_edma_init_chan_iommu(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma) +{ + int i; + + if (!of_property_present(pdev->dev.of_node, "iommu-map")) + return; + + for (i = 0; i < fsl_edma->n_chans; i++) { + struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i]; + struct device *dev; + + if (fsl_edma->chan_masked & BIT(i)) + continue; + + dev = &fsl_chan->vchan.chan.dev->device; + dev->coherent_dma_mask = pdev->dev.coherent_dma_mask; + dev->dma_mask = &dev->coherent_dma_mask; + dev->bus = pdev->dev.bus; + } + + fsl_edma->has_iommu_map = true; +} + +static int fsl_edma_chan_configure_iommu(struct fsl_edma_chan *fsl_chan) +{ + struct device *dev = &fsl_chan->vchan.chan.dev->device; + struct device_node *np = fsl_chan->edma->dma_dev.dev->of_node; + struct of_phandle_args iommu_spec = {}; + u32 chan_id = fsl_chan - fsl_chan->edma->chans; + int ret; + + if (fsl_chan->vchan.chan.dev->chan_dma_dev) + return 0; + + ret = of_map_iommu_id(np, chan_id, &iommu_spec); + if (ret || !iommu_spec.np) + return 0; + of_node_put(iommu_spec.np); + + ret = of_dma_configure_id(dev, np, true, &chan_id); + if (ret) { + dev_err(dev, "DMA configure failed for ch%u: %d\n", + chan_id, ret); + return ret; + } + + fsl_chan->vchan.chan.dev->chan_dma_dev = true; + dev_dbg(dev, "ch%u: IOMMU domain configured\n", chan_id); + + return 0; +} + static int fsl_edma_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -882,6 +954,8 @@ static int fsl_edma_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, ret, "Can't register Freescale eDMA engine.\n"); + fsl_edma_init_chan_iommu(pdev, fsl_edma); + ret = devm_of_dma_controller_register(&pdev->dev, np, drvdata->dmamuxs ? fsl_edma_xlate : fsl_edma3_xlate, fsl_edma); -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map 2026-09-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS) @ 2026-09-16 16:06 ` sashiko-bot 2026-09-16 18:23 ` Frank Li 1 sibling, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-09-16 16:06 UTC (permalink / raw) To: Peng Fan (OSS) Cc: dmaengine, robh, Frank.Li, imx, conor+dt, devicetree, vkoul Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: - [High] dmaengine: fsl-edma: TCD pool mapped to parent device causing IOMMU faults - [High] dmaengine: fsl-edma: masking -EPROBE_DEFER in xlate breaks deferred probe - [High] dmaengine: fsl-edma: late modification of dev->bus causes refcount underflow - [High] dmaengine: fsl-edma: DMA_MEMCPY channels bypass IOMMU configuration - [High] dmaengine: fsl-edma: missing IOMMU configuration in fsl_edma_xlate - [High] dmaengine: fsl-edma: dirty srcid state on error path blocks future requests -- commit 94975a647e48c96637ca91c3ba2539ad15656ede Author: Peng Fan <peng.fan@nxp.com> dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map This patch adds iommu-map support so each eDMA channel can be individually mapped to an IOMMU stream ID. At probe time, per-channel devices are initialized, and at xlate time the IOMMU domain is configured. > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c > index bb7531c456dfa..58a92ff4ddbe7 100644 > --- a/drivers/dma/fsl-edma-common.c > +++ b/drivers/dma/fsl-edma-common.c > @@ -283,8 +283,10 @@ int fsl_edma_resume(struct dma_chan *chan) > > static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan) > { [ ... ] > @@ -294,7 +296,7 @@ static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan) > static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan, > enum dma_transfer_direction dir) > { > - struct device *dev = fsl_chan->vchan.chan.device->dev; > + struct device *dev = dmaengine_get_dma_device(&fsl_chan->vchan.chan); > enum dma_data_direction dma_dir; > phys_addr_t addr = 0; > u32 size = 0; [Severity: High] Since the new per-channel IOMMU feature maps channel devices differently from the parent controller, does the hardware TCD pool allocation in fsl_edma_alloc_chan_resources() also need to be updated? It currently maps the TCD pool using the parent controller device: fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev, ... If the pool uses the parent device, won't its DMA addresses be invalid in the channel's hardware IOMMU domain, causing translation faults when fetching the TCDs? > diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c > index d9fb717b5b53c..eabb0086fc9de 100644 > --- a/drivers/dma/fsl-edma-main.c > +++ b/drivers/dma/fsl-edma-main.c [ ... ] > @@ -332,6 +334,12 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, > fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; > fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; > > + if (fsl_edma->has_iommu_map) { > + ret = fsl_edma_chan_configure_iommu(fsl_chan); > + if (ret) > + return NULL; > + } > + [Severity: High] If fsl_edma_chan_configure_iommu() fails and returns -EPROBE_DEFER because the IOMMU driver is not yet probed, this drops the valid error code and returns NULL. Will this mislead the core DMA engine (which treats NULL as 'channel not found') and break deferred probing for client devices? [Severity: High] If fsl_edma_chan_configure_iommu() fails and returns an error, returning NULL here does not roll back the state assignments made just above (e.g., fsl_chan->srcid = dma_spec->args[0]). Because the channel wasn't successfully allocated, fsl_edma_free_chan_resources() will never be called to clear it. Will this leave a dirty srcid state that permanently locks out future client requests for this hardware signal due to fsl_edma_srcid_in_use()? [Severity: High] Because this IOMMU configuration logic is placed exclusively inside the DT xlate function, does it completely bypass non-DT channel allocations? If a client driver requests a channel for DMA_MEMCPY, memory will be mapped using the parent controller device while the channel hardware fetches using its hardwired Stream ID. Won't this cause IOMMU translation faults for non-DT channels? > chan = dma_get_slave_channel(chan); > chan->device->privatecnt++; > return chan; [ ... ] > +static void fsl_edma_init_chan_iommu(struct platform_device *pdev, > + struct fsl_edma_engine *fsl_edma) > +{ [ ... ] > + for (i = 0; i < fsl_edma->n_chans; i++) { > + struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i]; > + struct device *dev; > + > + if (fsl_edma->chan_masked & BIT(i)) > + continue; > + > + dev = &fsl_chan->vchan.chan.dev->device; > + dev->coherent_dma_mask = pdev->dev.coherent_dma_mask; > + dev->dma_mask = &dev->coherent_dma_mask; > + dev->bus = pdev->dev.bus; [Severity: High] Does this illegally modify the bus type of an already-registered device? This is executed after dmaenginem_async_device_register() has already called device_add(). Since bus_add_device() is never executed, won't device_del() invoke bus_remove_device() during driver unbinding or removal, causing a fatal reference count underflow and use-after-free on the global platform_bus_type subsystem? > + } > + > + fsl_edma->has_iommu_map = true; > +} [ ... ] > @@ -882,6 +954,8 @@ static int fsl_edma_probe(struct platform_device *pdev) > return dev_err_probe(&pdev->dev, ret, > "Can't register Freescale eDMA engine.\n"); > > + fsl_edma_init_chan_iommu(pdev, fsl_edma); > + > ret = devm_of_dma_controller_register(&pdev->dev, np, > drvdata->dmamuxs ? fsl_edma_xlate : fsl_edma3_xlate, > fsl_edma); [Severity: High] Since the per-channel IOMMU configuration was only added to fsl_edma3_xlate(), does this entirely omit configuration for hardware variants relying on fsl_edma_xlate()? Will controller variants using fsl_edma_xlate bypass the IOMMU configuration and cause hardware translation faults? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260916-edma-iommu-v1-0-e1731968081e@nxp.com?part=2 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map 2026-09-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS) 2026-09-16 16:06 ` sashiko-bot @ 2026-09-16 18:23 ` Frank Li 1 sibling, 0 replies; 8+ messages in thread From: Frank Li @ 2026-09-16 18:23 UTC (permalink / raw) To: Peng Fan (OSS) Cc: Frank Li, Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li, imx, dmaengine, devicetree, linux-kernel, Peng Fan On Wed, Sep 16, 2026 at 11:55:26PM +0800, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@nxp.com> > > Add iommu-map support so that each eDMA channel can be individually > mapped to an IOMMU stream ID. > > At probe time, fsl_edma_init_chan_iommu() prepares per-channel devices > by initializing DMA masks and bus pointers so of_dma_configure_id() > can be called later. > > At xlate time, fsl_edma_chan_configure_iommu() looks up the allocated > channel index in iommu-map. If an entry exists, it calls > of_dma_configure_id() to attach the IOMMU domain and sets chan_dma_dev > so dmaengine_get_dma_device() returns the per-channel device. > Channels without a matching entry operate in bypass mode. > > Also switch fsl_edma_prep_slave_dma() and fsl_edma_unprep_slave_dma() > to use dmaengine_get_dma_device() for DMA resource mapping. > > Assisted-by: Claude:claude-opus-4-6 > Signed-off-by: Peng Fan <peng.fan@nxp.com> > --- > drivers/dma/fsl-edma-common.c | 6 ++-- > drivers/dma/fsl-edma-common.h | 1 + > drivers/dma/fsl-edma-main.c | 76 ++++++++++++++++++++++++++++++++++++++++++- > 3 files changed, 80 insertions(+), 3 deletions(-) > > diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c > index bb7531c456dfa..58a92ff4ddbe7 100644 > --- a/drivers/dma/fsl-edma-common.c > +++ b/drivers/dma/fsl-edma-common.c > @@ -283,8 +283,10 @@ int fsl_edma_resume(struct dma_chan *chan) > > static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan) > { > + struct device *dev = dmaengine_get_dma_device(&fsl_chan->vchan.chan); > + > if (fsl_chan->dma_dir != DMA_NONE) > - dma_unmap_resource(fsl_chan->vchan.chan.device->dev, > + dma_unmap_resource(dev, > fsl_chan->dma_dev_addr, > fsl_chan->dma_dev_size, > fsl_chan->dma_dir, 0); > @@ -294,7 +296,7 @@ static void fsl_edma_unprep_slave_dma(struct fsl_edma_chan *fsl_chan) > static bool fsl_edma_prep_slave_dma(struct fsl_edma_chan *fsl_chan, > enum dma_transfer_direction dir) > { > - struct device *dev = fsl_chan->vchan.chan.device->dev; > + struct device *dev = dmaengine_get_dma_device(&fsl_chan->vchan.chan); > enum dma_data_direction dma_dir; > phys_addr_t addr = 0; > u32 size = 0; > diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h > index 205a964890948..85487763e05ab 100644 > --- a/drivers/dma/fsl-edma-common.h > +++ b/drivers/dma/fsl-edma-common.h > @@ -264,6 +264,7 @@ struct fsl_edma_engine { > int txirq_16_31; > int errirq; > bool big_endian; > + bool has_iommu_map; > struct edma_regs regs; > u64 chan_masked; > struct fsl_edma_chan chans[] __counted_by(n_chans); > diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c > index d9fb717b5b53c..eabb0086fc9de 100644 > --- a/drivers/dma/fsl-edma-main.c > +++ b/drivers/dma/fsl-edma-main.c > @@ -16,6 +16,7 @@ > #include <linux/interrupt.h> > #include <linux/clk.h> > #include <linux/of.h> > +#include <linux/of_device.h> > #include <linux/of_dma.h> > #include <linux/dma-mapping.h> > #include <linux/pm_runtime.h> > @@ -24,6 +25,7 @@ > > #include "fsl-edma-common.h" > > +static int fsl_edma_chan_configure_iommu(struct fsl_edma_chan *fsl_chan); is possible move function here to avoid forware declear? > static void fsl_edma_synchronize(struct dma_chan *chan) > { > struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); > @@ -298,7 +300,7 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, > struct dma_chan *chan, *_chan; > struct fsl_edma_chan *fsl_chan; > bool b_chmux; > - int i; > + int i, ret; > > if (dma_spec->args_count != 3) > return NULL; > @@ -332,6 +334,12 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, > fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; > fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; > > + if (fsl_edma->has_iommu_map) { should has_iommu_map be per channel? How about some channel use iommu but some not? > + ret = fsl_edma_chan_configure_iommu(fsl_chan); > + if (ret) > + return NULL; > + } > + > chan = dma_get_slave_channel(chan); > chan->device->privatecnt++; > return chan; > @@ -695,6 +703,70 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng > return -EINVAL; > } > > +/** > + * fsl_edma_init_chan_iommu - prepare per-channel devices for IOMMU > + * @pdev: the eDMA platform device > + * @fsl_edma: the eDMA engine instance > + * > + * Must be called after dmaenginem_async_device_register() so that each > + * channel's chan->dev->device is already registered. > + * > + * Initialize DMA mask and bus on each channel device so that > + * of_dma_configure_id() can be called later at xlate time. > + */ > +static void fsl_edma_init_chan_iommu(struct platform_device *pdev, > + struct fsl_edma_engine *fsl_edma) > +{ > + int i; > + > + if (!of_property_present(pdev->dev.of_node, "iommu-map")) > + return; > + > + for (i = 0; i < fsl_edma->n_chans; i++) { > + struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i]; > + struct device *dev; > + > + if (fsl_edma->chan_masked & BIT(i)) > + continue; > + > + dev = &fsl_chan->vchan.chan.dev->device; use new API vchan_chan_dev() > + dev->coherent_dma_mask = pdev->dev.coherent_dma_mask; > + dev->dma_mask = &dev->coherent_dma_mask; > + dev->bus = pdev->dev.bus; I think these information should be set even without iommu. > + } > + > + fsl_edma->has_iommu_map = true; > +} > + > +static int fsl_edma_chan_configure_iommu(struct fsl_edma_chan *fsl_chan) > +{ > + struct device *dev = &fsl_chan->vchan.chan.dev->device; use new API vchan_chan_dev() > + struct device_node *np = fsl_chan->edma->dma_dev.dev->of_node; > + struct of_phandle_args iommu_spec = {}; > + u32 chan_id = fsl_chan - fsl_chan->edma->chans; > + int ret; > + > + if (fsl_chan->vchan.chan.dev->chan_dma_dev) > + return 0; > + > + ret = of_map_iommu_id(np, chan_id, &iommu_spec); > + if (ret || !iommu_spec.np) > + return 0; > + of_node_put(iommu_spec.np); > + > + ret = of_dma_configure_id(dev, np, true, &chan_id); > + if (ret) { > + dev_err(dev, "DMA configure failed for ch%u: %d\n", > + chan_id, ret); use dev_err_probe() to avoid print error when defer probe Frank > + return ret; > + } > + > + fsl_chan->vchan.chan.dev->chan_dma_dev = true; > + dev_dbg(dev, "ch%u: IOMMU domain configured\n", chan_id); > + > + return 0; > +} > + > static int fsl_edma_probe(struct platform_device *pdev) > { > struct device_node *np = pdev->dev.of_node; > @@ -882,6 +954,8 @@ static int fsl_edma_probe(struct platform_device *pdev) > return dev_err_probe(&pdev->dev, ret, > "Can't register Freescale eDMA engine.\n"); > > + fsl_edma_init_chan_iommu(pdev, fsl_edma); > + > ret = devm_of_dma_controller_register(&pdev->dev, np, > drvdata->dmamuxs ? fsl_edma_xlate : fsl_edma3_xlate, > fsl_edma); > > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-25 1:45 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-16 15:55 [PATCH 0/2] dmaengine: fsl-edma: add per-channel IOMMU support Peng Fan (OSS) 2026-09-16 15:55 ` [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property Peng Fan (OSS) 2026-09-16 16:46 ` Frank Li 2026-09-24 21:56 ` Rob Herring (Arm) 2026-09-25 1:43 ` Peng Fan 2026-09-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS) 2026-09-16 16:06 ` sashiko-bot 2026-09-16 18:23 ` Frank Li
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox