* [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; 5+ 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] 5+ 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-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS)
1 sibling, 1 reply; 5+ 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 [flat|nested] 5+ 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 18:23 ` Frank Li
1 sibling, 1 reply; 5+ 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 [flat|nested] 5+ 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
0 siblings, 0 replies; 5+ 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] 5+ 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 18:23 ` Frank Li
0 siblings, 0 replies; 5+ 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] 5+ messages in thread
end of thread, other threads:[~2026-09-16 18:23 UTC | newest]
Thread overview: 5+ 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-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS)
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
all inboxes | Powered by JetHome®