DMA Engine development
 help / color / mirror / Atom feed
* [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support
@ 2026-11-02  6:49 Peng Fan (OSS)
  2026-11-02  6:49 ` [PATCH v3 1/7] dmaengine: fsl-edma: unregister channels before vchan cleanup Peng Fan (OSS)
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:49 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

I used iommu-map for eDMA, but iommu experts rejected it:
"Using iommu-map to describe synthetic dma_chan_dev devices that the
kernel creates is the same kind of DT abuse from over here:"
More info: https://lore.kernel.org/all/20260917144804.GI3196566@ziepe.ca/

So I followed here [2] as Krzysztof wrote for QCOM VPU:
"Thanks Jason for context and detailed arguments. Robin did not chime in
yet, but from what I understood the DT-child-node approach will be the
way we should go here.

I accept above point of view and I am fine with this, thus Vishnu and
Vikash - please go ahead with DT-child-node solution we had some time ago."
[2] https://lore.kernel.org/linux-iommu/c7b956a9-d3e8-4e18-b780-5d08f5cd2ca1@kernel.org/

This series adds per-channel DT child node support to fsl-edma and, as a
prerequisite, introduces a proper bus for DMA channel devices.

The fsl-edma change allows each channel to carry its own reg, interrupts,
iommus and power-domains properties. Parsing the child nodes is
straightforward, but per-channel IOMMU configuration is not: the DMA engine
currently creates struct dma_chan_dev as a class device without any bus, so
of_dma_configure() has no bus to probe the IOMMU with, and the IOMMU core
does not have a bus notifier for DMA channel devices.

Drivers that need per-channel IOMMU support currently work around this by
assigning dev->bus after dmaenginem_async_device_register().  That is unsafe
because bus_add_device() already ran with bus == NULL and did not take a bus
subsystem reference.  When the channel device is later unregistered,
bus_remove_device() drops a reference that was never acquired, leading to a
reference count underflow and a potential use-after-free.  Using
platform_bus_type is also wrong: platform_match() and platform_uevent()
expect the device to be embedded in a struct platform_device.

A dedicated bus for DMA channel devices solves this.  The channel devices are
converted from class devices to bus devices:

  - the bus is registered early, before iommu_subsys_init() consumes
    iommu_buses[];
  - the match callback always reports no match, so no driver binds to a
    channel device;
  - channel devices are registered on the bus before device_register(), so
    bus_add_device() and bus_remove_device() are balanced;
  - the bus is added to iommu_buses[], so the existing IOMMU notifier
    handles per-channel IOMMU probe and release.

The existing /sys/class/dma interface is preserved with class_compat, the
mechanism provided by the driver core for converting a class device family to
bus devices. A compatibility class named "dma" keeps
/sys/class/dma/dmaNchanM available, while the devices themselves live on the
DMA bus. The uevent subsystem name remains "dma" because the bus has the same
name as the old class. dma_dev_groups moves from the old class to the bus,
and chan_dev_release is installed directly as the device release callback.

While testing controller unbind, a pre-existing fsl-edma ordering bug was
found: fsl_edma_remove() removed all channels from dma_dev.channels before the
managed dma_async_device_unregister() action ran, so the channel devices and
their IOMMU groups were never released. Patch 1 fixes that ordering, which is
needed to make the bind/unbind lifecycle test meaningful.

Patch breakdown

1/7 dmaengine: fsl-edma: unregister channels before vchan cleanup

    Keep the vchan cleanup, but run it from a devres action that is ordered
    after the managed dma_async_device_unregister().  This restores proper
    channel device and IOMMU group removal on controller unbind.

2/7 dmaengine: add a bus for DMA channel devices

    Add dma_chan_bus_type and register it from dma_bus_init().  The match
    callback never matches.  There is no functional change yet.

3/7 iommu: register the DMA channel bus for IOMMU notifications

    Add dma_chan_bus_type to iommu_buses[] under CONFIG_DMA_ENGINE.
    dma_bus_init() is an arch_initcall and runs before iommu_subsys_init(),
    so the bus is registered before the IOMMU core consumes iommu_buses[].

4/7 dmaengine: move channel devices to the DMA channel bus

    Register each dma_chan_dev on the DMA bus before device_register(),
    install the release callback directly, attach dma_dev_groups to the bus,
    and switch the /sys/class/dma view to class_compat.  Remove the manual
    post-registration bus assignment from the Tegra GPC DMA driver.

5/7 dt-bindings: dma: fsl,edma: add per-channel child node support

    Document optional dma-channel@<addr> child nodes with reg, interrupts,
    iommus and power-domains properties.

6/7 dmaengine: fsl-edma: support per-channel DT child nodes

    Derive the channel index from the child MMIO address, populate the
    per-channel IRQ, propagate -EPROBE_DEFER from of_irq_get(), and
    configure the per-channel IOMMU on the channel device using
    of_dma_configure().  Existing DTS without child nodes keeps working.

7/7 arm64: dts: imx95: convert eDMA to per-channel child nodes

    Describe the per-channel register regions and interrupts for i.MX95
    eDMA.  The iommus properties are not added yet; they will be submitted
    separately once the stream ID assignment is finalized.

The only user-visible change from the bus introduction is that the device's
"subsystem" link now points to /sys/bus/dma instead of /sys/class/dma. The
/sys/class/dma/dmaNchanM path itself is unchanged, and both the bus and the
compatibility class are named "dma".

Patches 2-4 can be merged separately if preferred, but the fsl-edma patches
depend on them. Patch 6 deliberately does not touch dev->bus; it relies on
the DMA engine core registering the channel device on the DMA channel bus.

The binding and driver support per-channel iommus, but patch 7 does not add
them to the i.MX95 DTS yet. That DT update will be sent separately when the
shared stream ID support are finalized.

I put all the patches in one patchset to give people a full picture.
If need to separate patches into multiple patchsets, I could do that
in next version.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Changes in V3:
- Patch [1-4] are new patches
- Add R-b for patch 5
- Patch 6: handle of_irq_get() -EPROBE_DEFER, drop the explicit bus
  assignment to "chdev->bus" which is resolved by patch [2-4].
- Rebased to linus/master v7.4-rc1
Changes in V2:
- Switch to add child node for dma channel.
- Link to V1: https://lore.kernel.org/dmaengine/20260916-edma-iommu-v1-0-e1731968081e@nxp.com/

---
Peng Fan (7):
      dmaengine: fsl-edma: unregister channels before vchan cleanup
      dmaengine: add a bus for DMA channel devices
      iommu: register the DMA channel bus for IOMMU notifications
      dmaengine: move channel devices to the DMA channel bus
      dt-bindings: dma: fsl,edma: add per-channel child node support
      dmaengine: fsl-edma: support per-channel DT child nodes
      arm64: dts: imx95: convert eDMA to per-channel child nodes

 .../devicetree/bindings/dma/fsl,edma.yaml          |  70 +-
 arch/arm64/boot/dts/freescale/imx95.dtsi           | 774 +++++++++++++++++----
 drivers/dma/dmaengine.c                            |  43 +-
 drivers/dma/fsl-edma-common.c                      |  10 +-
 drivers/dma/fsl-edma-main.c                        | 164 ++++-
 drivers/dma/tegra186-gpc-dma.c                     |   1 -
 drivers/iommu/iommu.c                              |   4 +
 include/linux/dmaengine.h                          |   4 +
 8 files changed, 919 insertions(+), 151 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261102-edma-iommu-v3-22b673717cf4

Best regards,
--  
OpenCode Assistant <opencode@Example.Com>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 1/7] dmaengine: fsl-edma: unregister channels before vchan cleanup
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
@ 2026-11-02  6:49 ` Peng Fan (OSS)
  2026-11-02  6:49 ` [PATCH v3 2/7] dmaengine: add a bus for DMA channel devices Peng Fan (OSS)
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:49 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Since commit 4035726a6b72 ("dmaengine: fsl-edma: Use managed API
dmaenginem_async_device_register()"), dma_async_device_unregister() runs
as a devres action after fsl_edma_remove(). However, fsl_edma_remove()
still calls fsl_edma_cleanup_vchan() first, which removes every channel
from dma_dev.channels.  When the devres action later runs,
dma_async_device_unregister() sees an empty channel list and never
unregisters the channel devices. They remain visible in /sys/class/dma.

Keep the vchan cleanup, but register it as a devres action before
dmaenginem_async_device_register(). Devres actions run in reverse
order, so the DMA channels are unregistered first and the vchan list is
cleaned up afterwards. Remove the premature cleanup call from
fsl_edma_remove().

Fixes: 4035726a6b72 ("dmaengine: fsl-edma: Use managed API dmaenginem_async_device_register()")
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/dma/fsl-edma-main.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
index 630285c854824..30d548a723462 100644
--- a/drivers/dma/fsl-edma-main.c
+++ b/drivers/dma/fsl-edma-main.c
@@ -31,6 +31,11 @@ static void fsl_edma_synchronize(struct dma_chan *chan)
 	vchan_synchronize(&fsl_chan->vchan);
 }
 
+static void fsl_edma_cleanup_vchan_action(void *data)
+{
+	fsl_edma_cleanup_vchan(data);
+}
+
 static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
 {
 	struct fsl_edma_engine *fsl_edma = dev_id;
@@ -882,6 +887,12 @@ static int fsl_edma_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, fsl_edma);
 
+	ret = devm_add_action_or_reset(&pdev->dev,
+				       fsl_edma_cleanup_vchan_action,
+				       &fsl_edma->dma_dev);
+	if (ret)
+		return ret;
+
 	ret = dmaenginem_async_device_register(&fsl_edma->dma_dev);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret,
@@ -906,7 +917,6 @@ static void fsl_edma_remove(struct platform_device *pdev)
 	struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
 
 	fsl_edma_irq_exit(pdev, fsl_edma);
-	fsl_edma_cleanup_vchan(&fsl_edma->dma_dev);
 }
 
 static int fsl_edma_suspend_late(struct device *dev)

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/7] dmaengine: add a bus for DMA channel devices
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
  2026-11-02  6:49 ` [PATCH v3 1/7] dmaengine: fsl-edma: unregister channels before vchan cleanup Peng Fan (OSS)
@ 2026-11-02  6:49 ` Peng Fan (OSS)
  2026-11-02  7:02   ` sashiko-bot
  2026-11-02  6:49 ` [PATCH v3 3/7] iommu: register the DMA channel bus for IOMMU notifications Peng Fan (OSS)
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:49 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

DMA channel devices are currently created as class devices without a bus.
This works for sysfs, but it prevents per-channel DMA/IOMMU configuration:
of_dma_configure() only probes the IOMMU when dev->bus is set, and the
IOMMU core only installs probe/release notifiers for buses listed in
iommu_buses[].

Drivers that need per-channel IOMMU support currently work around this by
assigning dev->bus after device_register(). That leaves the bus subsystem
reference count unbalanced because bus_add_device() already ran with a NULL
bus, and bus_remove_device() will later drop a reference that was never
taken.

Add a dedicated bus for DMA channel devices and register it during
dmaengine initialisation, before iommu_subsys_init(). The match callback
never succeeds, so no driver can bind to these devices. A follow-up patch
will register the channel devices on this bus.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/dma/dmaengine.c   | 24 +++++++++++++++++++++---
 include/linux/dmaengine.h |  4 ++++
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 34be53487a21d..6fea67f088b35 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1643,17 +1643,35 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx)
 }
 EXPORT_SYMBOL_GPL(dma_run_dependencies);
 
+static int dma_chan_bus_match(struct device *dev,
+			      const struct device_driver *drv)
+{
+	return 0;
+}
+
+const struct bus_type dma_chan_bus_type = {
+	.name  = "dma",
+	.match = dma_chan_bus_match,
+};
+
 static int __init dma_bus_init(void)
 {
 	int err = dmaengine_init_unmap_pool();
 
+	if (err)
+		return err;
+
+	err = bus_register(&dma_chan_bus_type);
 	if (err)
 		return err;
 
 	err = class_register(&dma_devclass);
-	if (!err)
-		dmaengine_debugfs_init();
+	if (err) {
+		bus_unregister(&dma_chan_bus_type);
+		return err;
+	}
 
-	return err;
+	dmaengine_debugfs_init();
+	return 0;
 }
 arch_initcall(dma_bus_init);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 805668fbe4376..14d8f182c7cb5 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -412,6 +412,10 @@ struct dma_chan_dev {
 	bool chan_dma_dev;
 };
 
+#ifdef CONFIG_DMA_ENGINE
+extern const struct bus_type dma_chan_bus_type;
+#endif
+
 /**
  * enum dma_slave_buswidth - defines bus width of the DMA slave
  * device, source or target buses

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/7] iommu: register the DMA channel bus for IOMMU notifications
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
  2026-11-02  6:49 ` [PATCH v3 1/7] dmaengine: fsl-edma: unregister channels before vchan cleanup Peng Fan (OSS)
  2026-11-02  6:49 ` [PATCH v3 2/7] dmaengine: add a bus for DMA channel devices Peng Fan (OSS)
@ 2026-11-02  6:49 ` Peng Fan (OSS)
  2026-11-02  7:03   ` sashiko-bot
  2026-11-02  6:49 ` [PATCH v3 4/7] dmaengine: move channel devices to the DMA channel bus Peng Fan (OSS)
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:49 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

DMA channel devices are about to be registered on a dedicated DMA channel
bus so that they get a properly balanced bus association before
device_register().

Add that bus to iommu_buses[] so the IOMMU core installs its bus notifier
for it. This allows of_dma_configure() to probe a per-channel IOMMU and,
more importantly, lets BUS_NOTIFY_REMOVED_DEVICE release the IOMMU group
and domain when the channel device is unregistered.

The dmaengine bus is registered from an arch_initcall, before
iommu_subsys_init() consumes iommu_buses[]. Guard the entry with
CONFIG_DMA_ENGINE because the bus does not exist when the DMA engine core
is not built.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/iommu/iommu.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b486b8bbd1fcd..6fa871bbd63ad 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -8,6 +8,7 @@
 
 #include <linux/amba/bus.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
 #include <linux/kernel.h>
 #include <linux/bits.h>
 #include <linux/bug.h>
@@ -191,6 +192,9 @@ static const struct bus_type * const iommu_buses[] = {
 #ifdef CONFIG_ARM_AMBA
 	&amba_bustype,
 #endif
+#ifdef CONFIG_DMA_ENGINE
+	&dma_chan_bus_type,
+#endif
 #ifdef CONFIG_FSL_MC_BUS
 	&fsl_mc_bus_type,
 #endif

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/7] dmaengine: move channel devices to the DMA channel bus
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
                   ` (2 preceding siblings ...)
  2026-11-02  6:49 ` [PATCH v3 3/7] iommu: register the DMA channel bus for IOMMU notifications Peng Fan (OSS)
@ 2026-11-02  6:49 ` Peng Fan (OSS)
  2026-11-02  6:49 ` [PATCH v3 5/7] dt-bindings: dma: fsl,edma: add per-channel child node support Peng Fan (OSS)
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:49 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Register each dma_chan_dev on dma_chan_bus_type before device_register()
and make it a bus device instead of a class device. Setting the bus
before registration lets bus_add_device() take the bus subsystem
reference, so the matching bus_remove_device() calls drop references that
were actually acquired. Attach dma_dev_groups to the bus and set the
device release callback directly.

Keep the existing /sys/class/dma interface by registering a class_compat
named "dma" and creating a link for each channel device. The channel
devices now live on the DMA bus, while /sys/class/dma/dmaNchanM remains
available to userspace. The uevent subsystem name stays "dma" because
the bus has the same name as the old class.

Remove the post-registration dev->bus assignment from the Tegra GPC DMA
driver. Leaving it in place would overwrite the bus selected by the DMA
engine core and reintroduce the reference imbalance.

The DMA channel bus match callback never matches, so no driver can bind
to these channel devices.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/dma/dmaengine.c        | 27 ++++++++++++++++-----------
 drivers/dma/tegra186-gpc-dma.c |  1 -
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 6fea67f088b35..0e2eea339f1ce 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -239,11 +239,7 @@ static void chan_dev_release(struct device *dev)
 	kfree(chan_dev);
 }
 
-static struct class dma_devclass = {
-	.name		= "dma",
-	.dev_groups	= dma_dev_groups,
-	.dev_release	= chan_dev_release,
-};
+static struct class_compat *dma_chan_class;
 
 /* --- client and device registration --- */
 
@@ -1115,8 +1111,9 @@ static int __dma_async_device_channel_register(struct dma_device *device,
 		goto err_free_dev;
 	}
 
-	dmaengine_chan_dev(chan)->class = &dma_devclass;
 	dmaengine_chan_dev(chan)->parent = device->dev;
+	dmaengine_chan_dev(chan)->bus = &dma_chan_bus_type;
+	dmaengine_chan_dev(chan)->release = chan_dev_release;
 	chan->chan_dev->chan = chan;
 	chan->chan_dev->dev_id = device->dev_id;
 	spin_lock_init(&chan->lock);
@@ -1128,6 +1125,11 @@ static int __dma_async_device_channel_register(struct dma_device *device,
 	rc = device_register(dmaengine_chan_dev(chan));
 	if (rc)
 		goto err_out_ida;
+
+	rc = class_compat_create_link(dma_chan_class, dmaengine_chan_dev(chan));
+	if (rc)
+		dev_warn(device->dev, "Failed to create compatibility class link\n");
+
 	chan->client_count = 0;
 	device->chancnt++;
 
@@ -1172,6 +1174,7 @@ static void __dma_async_device_channel_unregister(struct dma_device *device,
 	chan->chan_dev->chan = NULL;
 	mutex_unlock(&dma_list_mutex);
 	ida_free(&device->chan_ida, chan->chan_id);
+	class_compat_remove_link(dma_chan_class, dmaengine_chan_dev(chan));
 	device_unregister(dmaengine_chan_dev(chan));
 	free_percpu(chan->local);
 }
@@ -1306,6 +1309,7 @@ int dma_async_device_register(struct dma_device *device)
 		mutex_lock(&dma_list_mutex);
 		chan->chan_dev->chan = NULL;
 		mutex_unlock(&dma_list_mutex);
+		class_compat_remove_link(dma_chan_class, dmaengine_chan_dev(chan));
 		device_unregister(dmaengine_chan_dev(chan));
 		free_percpu(chan->local);
 	}
@@ -1650,8 +1654,9 @@ static int dma_chan_bus_match(struct device *dev,
 }
 
 const struct bus_type dma_chan_bus_type = {
-	.name  = "dma",
-	.match = dma_chan_bus_match,
+	.name		= "dma",
+	.match		= dma_chan_bus_match,
+	.dev_groups	= dma_dev_groups,
 };
 
 static int __init dma_bus_init(void)
@@ -1665,10 +1670,10 @@ static int __init dma_bus_init(void)
 	if (err)
 		return err;
 
-	err = class_register(&dma_devclass);
-	if (err) {
+	dma_chan_class = class_compat_register("dma");
+	if (!dma_chan_class) {
 		bus_unregister(&dma_chan_bus_type);
-		return err;
+		return -ENOMEM;
 	}
 
 	dmaengine_debugfs_init();
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index e76c58f213d84..71a935d873868 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -1541,7 +1541,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
 		tdc = to_tegra_dma_chan(chan);
 
 		if (use_iommu_map) {
-			chdev->bus = pdev->dev.bus;
 			dma_coerce_mask_and_coherent(chdev, DMA_BIT_MASK(cdata->addr_bits));
 
 			ret = of_dma_configure_id(chdev, pdev->dev.of_node,

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 5/7] dt-bindings: dma: fsl,edma: add per-channel child node support
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
                   ` (3 preceding siblings ...)
  2026-11-02  6:49 ` [PATCH v3 4/7] dmaengine: move channel devices to the DMA channel bus Peng Fan (OSS)
@ 2026-11-02  6:49 ` Peng Fan (OSS)
  2026-11-02  6:50 ` [PATCH v3 6/7] dmaengine: fsl-edma: support per-channel DT child nodes Peng Fan (OSS)
  2026-11-02  6:50 ` [PATCH v3 7/7] arm64: dts: imx95: convert eDMA to per-channel " Peng Fan (OSS)
  6 siblings, 0 replies; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:49 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Add support for optional per-channel child nodes (dma-channel@<addr>)
to the fsl,edma binding. Each child node can carry its own reg,
interrupts, iommus, and power-domains properties, describing a real
per-channel MMIO region.

Enables per-channel IOMMU stream ID assignment via the standard
iommus property on each child.

The interrupts property is removed from the required list since
channels with child nodes carry their own interrupts. Existing DTS
without child nodes remains valid.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 .../devicetree/bindings/dma/fsl,edma.yaml          | 70 +++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/dma/fsl,edma.yaml b/Documentation/devicetree/bindings/dma/fsl,edma.yaml
index f609038e35ae1..19a103baccaf4 100644
--- a/Documentation/devicetree/bindings/dma/fsl,edma.yaml
+++ b/Documentation/devicetree/bindings/dma/fsl,edma.yaml
@@ -104,11 +104,40 @@ properties:
       Bit semantics: 0 means channel available, 1 means channel unavailable
     default: 0
 
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 1
+
+  ranges: true
+
+patternProperties:
+  "^dma-channel@[0-9a-f]+$":
+    type: object
+    additionalProperties: false
+
+    properties:
+      reg:
+        maxItems: 1
+        description: Per-channel register region within the eDMA block.
+
+      interrupts:
+        maxItems: 1
+
+      iommus:
+        maxItems: 1
+
+      power-domains:
+        maxItems: 1
+
+    required:
+      - reg
+
 required:
   - "#dma-cells"
   - compatible
   - reg
-  - interrupts
   - dma-channels
 
 allOf:
@@ -351,3 +380,42 @@ 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>;
+      #address-cells = <1>;
+      #size-cells = <1>;
+      ranges;
+      dma-channels = <64>;
+      clocks = <&clk 0>;
+      clock-names = "dma";
+
+      dma-channel@42020000 {
+        reg = <0x42020000 0x8000>;
+        interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
+        iommus = <&smmu 0x30>;
+      };
+
+      dma-channel@42028000 {
+        reg = <0x42028000 0x8000>;
+        interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
+        iommus = <&smmu 0x30>;
+      };
+
+      dma-channel@42030000 {
+        reg = <0x42030000 0x8000>;
+        interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+        iommus = <&smmu 0x31>;
+      };
+
+      dma-channel@42038000 {
+        reg = <0x42038000 0x8000>;
+        interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+        iommus = <&smmu 0x31>;
+      };
+    };

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/7] dmaengine: fsl-edma: support per-channel DT child nodes
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
                   ` (4 preceding siblings ...)
  2026-11-02  6:49 ` [PATCH v3 5/7] dt-bindings: dma: fsl,edma: add per-channel child node support Peng Fan (OSS)
@ 2026-11-02  6:50 ` Peng Fan (OSS)
  2026-11-02  7:10   ` sashiko-bot
  2026-11-02  6:50 ` [PATCH v3 7/7] arm64: dts: imx95: convert eDMA to per-channel " Peng Fan (OSS)
  6 siblings, 1 reply; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:50 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Add support for parsing per-channel child nodes from devicetree.
Each child node can carry its own interrupts, iommus, and
power-domains properties.

The implementation is split into three functions:

- fsl_edma_child_to_chan_id(): derives the channel index from the
  child MMIO address relative to the parent base.

- fsl_edma_configure_chan_from_dt(): called before setup_irq() to
  populate per-channel txirq from child interrupt properties.
  fsl_edma3_irq_init() is updated to skip platform_get_irq() for
  channels that already have an IRQ assigned from their child node.

- fsl_edma_configure_chan_iommu(): called after
  dmaenginem_async_device_register() to configure per-channel IOMMU
  by calling of_dma_configure() on each dma_chan_dev and setting
  chan_dma_dev so dmaengine_get_dma_device() returns the per-channel
  device.

Existing DTS without child nodes continues to work unchanged.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/dma/fsl-edma-common.c |  10 +--
 drivers/dma/fsl-edma-main.c   | 152 ++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 152 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index 513b0f4e5be21..62cd60179bc6f 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -310,10 +310,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,
-				   fsl_chan->dma_dev_addr,
-				   fsl_chan->dma_dev_size,
+		dma_unmap_resource(dev, fsl_chan->dma_dev_addr, fsl_chan->dma_dev_size,
 				   fsl_chan->dma_dir, 0);
 	fsl_chan->dma_dir = DMA_NONE;
 }
@@ -321,7 +321,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;
@@ -1090,7 +1090,7 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
 	if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK)
 		clk_prepare_enable(fsl_chan->clk);
 
-	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", dmaengine_get_dma_device(chan),
 				fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
 				sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd),
 				32, 0);
diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
index 30d548a723462..795744e67837d 100644
--- a/drivers/dma/fsl-edma-main.c
+++ b/drivers/dma/fsl-edma-main.c
@@ -16,7 +16,10 @@
 #include <linux/interrupt.h>
 #include <linux/clk.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/of_dma.h>
+#include <linux/of_irq.h>
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
@@ -400,12 +403,13 @@ static int fsl_edma3_irq_init(struct platform_device *pdev, struct fsl_edma_engi
 		if (fsl_edma->chan_masked & BIT(i))
 			continue;
 
-		/* request channel irq */
-		fsl_chan->txirq = platform_get_irq(pdev, i);
-		if (fsl_chan->txirq < 0)
-			return  -EINVAL;
+		if (fsl_chan->txirq <= 0) {
+			fsl_chan->txirq = platform_get_irq(pdev, i);
+			if (fsl_chan->txirq < 0)
+				return fsl_chan->txirq;
 
-		fsl_chan->irq_handler = fsl_edma3_tx_handler;
+			fsl_chan->irq_handler = fsl_edma3_tx_handler;
+		}
 
 		if (!(fsl_edma->drvdata->flags & FSL_EDMA_DRV_ERRIRQ_SHARE)) {
 			fsl_chan->errirq = fsl_chan->txirq;
@@ -703,6 +707,136 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng
 	return -EINVAL;
 }
 
+static int fsl_edma_child_to_chan_id(struct platform_device *pdev,
+				     struct fsl_edma_engine *fsl_edma,
+				     struct device_node *child,
+				     struct resource *parent_res)
+{
+	const struct fsl_edma_drvdata *drvdata = fsl_edma->drvdata;
+	struct resource child_res;
+	u32 ch_id;
+	int ret;
+
+	ret = of_address_to_resource(child, 0, &child_res);
+	if (ret)
+		return ret;
+
+	if (child_res.start < parent_res->start + drvdata->chreg_off)
+		return -EINVAL;
+
+	ch_id = (child_res.start - parent_res->start - drvdata->chreg_off)
+		/ drvdata->chreg_space_sz;
+
+	if (ch_id >= fsl_edma->n_chans)
+		return -EINVAL;
+
+	return ch_id;
+}
+
+static int fsl_edma_configure_chan_from_dt(struct platform_device *pdev,
+					   struct fsl_edma_engine *fsl_edma)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource parent_res;
+	struct device_node *child;
+	int ret;
+
+	ret = of_address_to_resource(np, 0, &parent_res);
+	if (ret)
+		return ret;
+
+	for_each_available_child_of_node(np, child) {
+		struct fsl_edma_chan *fsl_chan;
+		int ch_id, irq;
+
+		ch_id = fsl_edma_child_to_chan_id(pdev, fsl_edma, child,
+						  &parent_res);
+		if (ch_id < 0) {
+			dev_err(&pdev->dev, "invalid channel in %pOFn\n", child);
+			of_node_put(child);
+			return -EINVAL;
+		}
+
+		if (fsl_edma->chan_masked & BIT(ch_id))
+			continue;
+
+		fsl_chan = &fsl_edma->chans[ch_id];
+
+		irq = of_irq_get(child, 0);
+		if (irq == -EPROBE_DEFER) {
+			of_node_put(child);
+			return -EPROBE_DEFER;
+		}
+		if (irq > 0) {
+			fsl_chan->txirq = irq;
+			fsl_chan->irq_handler = fsl_edma3_tx_handler;
+		}
+	}
+
+	return 0;
+}
+
+static int fsl_edma_configure_chan_iommu(struct platform_device *pdev,
+					struct fsl_edma_engine *fsl_edma)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource parent_res;
+	struct device_node *child;
+	struct dma_chan *chan;
+	int ret;
+
+	ret = of_address_to_resource(np, 0, &parent_res);
+	if (ret)
+		return ret;
+
+	for_each_available_child_of_node(np, child) {
+		struct fsl_edma_chan *fsl_chan;
+		int ch_id;
+
+		if (!of_property_present(child, "iommus"))
+			continue;
+
+		ch_id = fsl_edma_child_to_chan_id(pdev, fsl_edma, child,
+						  &parent_res);
+		if (ch_id < 0)
+			continue;
+
+		if (fsl_edma->chan_masked & BIT(ch_id))
+			continue;
+
+		fsl_chan = &fsl_edma->chans[ch_id];
+
+		list_for_each_entry(chan, &fsl_edma->dma_dev.channels,
+				    device_node) {
+			struct device *chdev;
+
+			if (to_fsl_edma_chan(chan) != fsl_chan)
+				continue;
+
+			chdev = dmaengine_chan_dev(chan);
+			if (fsl_edma->drvdata->flags & FSL_EDMA_DRV_TCD64)
+				dma_coerce_mask_and_coherent(chdev,
+					DMA_BIT_MASK(64));
+			else
+				dma_coerce_mask_and_coherent(chdev,
+					DMA_BIT_MASK(32));
+			ret = of_dma_configure(chdev, child, true);
+			if (ret) {
+				dev_err(&pdev->dev,
+					"IOMMU config failed for channel %d: %d\n",
+					ch_id, ret);
+				of_node_put(child);
+				return ret;
+			}
+
+			chan->chan_dev->chan_dma_dev = true;
+			break;
+		}
+	}
+
+	return 0;
+}
+
 static int fsl_edma_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -836,6 +970,10 @@ static int fsl_edma_probe(struct platform_device *pdev)
 			clk_disable_unprepare(fsl_chan->clk);
 	}
 
+	ret = fsl_edma_configure_chan_from_dt(pdev, fsl_edma);
+	if (ret)
+		return ret;
+
 	ret = fsl_edma->drvdata->setup_irq(pdev, fsl_edma);
 	if (ret)
 		return ret;
@@ -898,6 +1036,10 @@ static int fsl_edma_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, ret,
 				     "Can't register Freescale eDMA engine.\n");
 
+	ret = fsl_edma_configure_chan_iommu(pdev, fsl_edma);
+	if (ret)
+		return ret;
+
 	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] 12+ messages in thread

* [PATCH v3 7/7] arm64: dts: imx95: convert eDMA to per-channel child nodes
  2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
                   ` (5 preceding siblings ...)
  2026-11-02  6:50 ` [PATCH v3 6/7] dmaengine: fsl-edma: support per-channel DT child nodes Peng Fan (OSS)
@ 2026-11-02  6:50 ` Peng Fan (OSS)
  2026-11-02  7:00   ` sashiko-bot
  6 siblings, 1 reply; 12+ messages in thread
From: Peng Fan (OSS) @ 2026-11-02  6:50 UTC (permalink / raw)
  To: Frank Li, Vinod Koul, Joerg Roedel (AMD), Will Deacon,
	Robin Murphy, Laxman Dewangan, Jon Hunter, Thierry Reding,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: Frank Li, Larisa IIeana Grigore, imx, dmaengine, linux-kernel,
	iommu, linux-tegra, devicetree, linux-arm-kernel, Peng Fan

From: Peng Fan <peng.fan@nxp.com>

Convert edma2 and edma3 from flat interrupt arrays at the parent node
to per-channel child nodes (dma-channel@<addr>). Each child carries
its own reg (real per-channel MMIO region) and interrupts property.

edma2 (64 channels at 0x42000000):
  - Channel N at 0x42010000 + N * 0x8000 (size 0x8000)
  - Paired interrupts: SPI 128-159, two channels per SPI

edma3 (64 channels at 0x42210000):
  - Channel N at 0x42220000 + N * 0x8000 (size 0x8000)
  - Paired interrupts: SPI 256-287, two channels per SPI

edma1 (imx93-edma3, 31 channels with 1:1 non-paired interrupts) is
left unchanged as it uses a different interrupt scheme.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 arch/arm64/boot/dts/freescale/imx95.dtsi | 774 ++++++++++++++++++++++++++-----
 1 file changed, 646 insertions(+), 128 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
index d20c2498b9aa2..64570703ce6cb 100644
--- a/arch/arm64/boot/dts/freescale/imx95.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
@@ -635,148 +635,666 @@ edma2: dma-controller@42000000 {
 				compatible = "fsl,imx95-edma5";
 				reg = <0x42000000 0x210000>;
 				#dma-cells = <3>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
 				dma-channels = <64>;
 				/* channels 0 and 1 reserved for V2X fast hash */
 				dma-channel-mask = <0x3>;
-				interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 147 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 = <&scmi_clk IMX95_CLK_BUSWAKEUP>;
 				clock-names = "dma";
+
+				dma-channel@42010000 {
+					reg = <0x42010000 0x8000>;
+					interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42018000 {
+					reg = <0x42018000 0x8000>;
+					interrupts = <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42020000 {
+					reg = <0x42020000 0x8000>;
+					interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42028000 {
+					reg = <0x42028000 0x8000>;
+					interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42030000 {
+					reg = <0x42030000 0x8000>;
+					interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42038000 {
+					reg = <0x42038000 0x8000>;
+					interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42040000 {
+					reg = <0x42040000 0x8000>;
+					interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42048000 {
+					reg = <0x42048000 0x8000>;
+					interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42050000 {
+					reg = <0x42050000 0x8000>;
+					interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42058000 {
+					reg = <0x42058000 0x8000>;
+					interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42060000 {
+					reg = <0x42060000 0x8000>;
+					interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42068000 {
+					reg = <0x42068000 0x8000>;
+					interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42070000 {
+					reg = <0x42070000 0x8000>;
+					interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42078000 {
+					reg = <0x42078000 0x8000>;
+					interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42080000 {
+					reg = <0x42080000 0x8000>;
+					interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42088000 {
+					reg = <0x42088000 0x8000>;
+					interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42090000 {
+					reg = <0x42090000 0x8000>;
+					interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42098000 {
+					reg = <0x42098000 0x8000>;
+					interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420a0000 {
+					reg = <0x420a0000 0x8000>;
+					interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420a8000 {
+					reg = <0x420a8000 0x8000>;
+					interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420b0000 {
+					reg = <0x420b0000 0x8000>;
+					interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420b8000 {
+					reg = <0x420b8000 0x8000>;
+					interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420c0000 {
+					reg = <0x420c0000 0x8000>;
+					interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420c8000 {
+					reg = <0x420c8000 0x8000>;
+					interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420d0000 {
+					reg = <0x420d0000 0x8000>;
+					interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420d8000 {
+					reg = <0x420d8000 0x8000>;
+					interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420e0000 {
+					reg = <0x420e0000 0x8000>;
+					interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420e8000 {
+					reg = <0x420e8000 0x8000>;
+					interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420f0000 {
+					reg = <0x420f0000 0x8000>;
+					interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@420f8000 {
+					reg = <0x420f8000 0x8000>;
+					interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42100000 {
+					reg = <0x42100000 0x8000>;
+					interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42108000 {
+					reg = <0x42108000 0x8000>;
+					interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42110000 {
+					reg = <0x42110000 0x8000>;
+					interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42118000 {
+					reg = <0x42118000 0x8000>;
+					interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42120000 {
+					reg = <0x42120000 0x8000>;
+					interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42128000 {
+					reg = <0x42128000 0x8000>;
+					interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42130000 {
+					reg = <0x42130000 0x8000>;
+					interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42138000 {
+					reg = <0x42138000 0x8000>;
+					interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42140000 {
+					reg = <0x42140000 0x8000>;
+					interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42148000 {
+					reg = <0x42148000 0x8000>;
+					interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42150000 {
+					reg = <0x42150000 0x8000>;
+					interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42158000 {
+					reg = <0x42158000 0x8000>;
+					interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42160000 {
+					reg = <0x42160000 0x8000>;
+					interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42168000 {
+					reg = <0x42168000 0x8000>;
+					interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42170000 {
+					reg = <0x42170000 0x8000>;
+					interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42178000 {
+					reg = <0x42178000 0x8000>;
+					interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42180000 {
+					reg = <0x42180000 0x8000>;
+					interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42188000 {
+					reg = <0x42188000 0x8000>;
+					interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42190000 {
+					reg = <0x42190000 0x8000>;
+					interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42198000 {
+					reg = <0x42198000 0x8000>;
+					interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421a0000 {
+					reg = <0x421a0000 0x8000>;
+					interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421a8000 {
+					reg = <0x421a8000 0x8000>;
+					interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421b0000 {
+					reg = <0x421b0000 0x8000>;
+					interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421b8000 {
+					reg = <0x421b8000 0x8000>;
+					interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421c0000 {
+					reg = <0x421c0000 0x8000>;
+					interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421c8000 {
+					reg = <0x421c8000 0x8000>;
+					interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421d0000 {
+					reg = <0x421d0000 0x8000>;
+					interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421d8000 {
+					reg = <0x421d8000 0x8000>;
+					interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421e0000 {
+					reg = <0x421e0000 0x8000>;
+					interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421e8000 {
+					reg = <0x421e8000 0x8000>;
+					interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421f0000 {
+					reg = <0x421f0000 0x8000>;
+					interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@421f8000 {
+					reg = <0x421f8000 0x8000>;
+					interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42200000 {
+					reg = <0x42200000 0x8000>;
+					interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42208000 {
+					reg = <0x42208000 0x8000>;
+					interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+				};
 			};
 
 			edma3: dma-controller@42210000 {
 				compatible = "fsl,imx95-edma5";
 				reg = <0x42210000 0x210000>;
 				#dma-cells = <3>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges;
 				dma-channels = <64>;
-				interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&scmi_clk IMX95_CLK_BUSWAKEUP>;
 				clock-names = "dma";
+
+				dma-channel@42220000 {
+					reg = <0x42220000 0x8000>;
+					interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42228000 {
+					reg = <0x42228000 0x8000>;
+					interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42230000 {
+					reg = <0x42230000 0x8000>;
+					interrupts = <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42238000 {
+					reg = <0x42238000 0x8000>;
+					interrupts = <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42240000 {
+					reg = <0x42240000 0x8000>;
+					interrupts = <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42248000 {
+					reg = <0x42248000 0x8000>;
+					interrupts = <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42250000 {
+					reg = <0x42250000 0x8000>;
+					interrupts = <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42258000 {
+					reg = <0x42258000 0x8000>;
+					interrupts = <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42260000 {
+					reg = <0x42260000 0x8000>;
+					interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42268000 {
+					reg = <0x42268000 0x8000>;
+					interrupts = <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42270000 {
+					reg = <0x42270000 0x8000>;
+					interrupts = <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42278000 {
+					reg = <0x42278000 0x8000>;
+					interrupts = <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42280000 {
+					reg = <0x42280000 0x8000>;
+					interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42288000 {
+					reg = <0x42288000 0x8000>;
+					interrupts = <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42290000 {
+					reg = <0x42290000 0x8000>;
+					interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42298000 {
+					reg = <0x42298000 0x8000>;
+					interrupts = <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422a0000 {
+					reg = <0x422a0000 0x8000>;
+					interrupts = <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422a8000 {
+					reg = <0x422a8000 0x8000>;
+					interrupts = <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422b0000 {
+					reg = <0x422b0000 0x8000>;
+					interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422b8000 {
+					reg = <0x422b8000 0x8000>;
+					interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422c0000 {
+					reg = <0x422c0000 0x8000>;
+					interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422c8000 {
+					reg = <0x422c8000 0x8000>;
+					interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422d0000 {
+					reg = <0x422d0000 0x8000>;
+					interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422d8000 {
+					reg = <0x422d8000 0x8000>;
+					interrupts = <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422e0000 {
+					reg = <0x422e0000 0x8000>;
+					interrupts = <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422e8000 {
+					reg = <0x422e8000 0x8000>;
+					interrupts = <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422f0000 {
+					reg = <0x422f0000 0x8000>;
+					interrupts = <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@422f8000 {
+					reg = <0x422f8000 0x8000>;
+					interrupts = <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42300000 {
+					reg = <0x42300000 0x8000>;
+					interrupts = <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42308000 {
+					reg = <0x42308000 0x8000>;
+					interrupts = <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42310000 {
+					reg = <0x42310000 0x8000>;
+					interrupts = <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42318000 {
+					reg = <0x42318000 0x8000>;
+					interrupts = <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42320000 {
+					reg = <0x42320000 0x8000>;
+					interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42328000 {
+					reg = <0x42328000 0x8000>;
+					interrupts = <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42330000 {
+					reg = <0x42330000 0x8000>;
+					interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42338000 {
+					reg = <0x42338000 0x8000>;
+					interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42340000 {
+					reg = <0x42340000 0x8000>;
+					interrupts = <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42348000 {
+					reg = <0x42348000 0x8000>;
+					interrupts = <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42350000 {
+					reg = <0x42350000 0x8000>;
+					interrupts = <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42358000 {
+					reg = <0x42358000 0x8000>;
+					interrupts = <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42360000 {
+					reg = <0x42360000 0x8000>;
+					interrupts = <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42368000 {
+					reg = <0x42368000 0x8000>;
+					interrupts = <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42370000 {
+					reg = <0x42370000 0x8000>;
+					interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42378000 {
+					reg = <0x42378000 0x8000>;
+					interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42380000 {
+					reg = <0x42380000 0x8000>;
+					interrupts = <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42388000 {
+					reg = <0x42388000 0x8000>;
+					interrupts = <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42390000 {
+					reg = <0x42390000 0x8000>;
+					interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42398000 {
+					reg = <0x42398000 0x8000>;
+					interrupts = <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423a0000 {
+					reg = <0x423a0000 0x8000>;
+					interrupts = <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423a8000 {
+					reg = <0x423a8000 0x8000>;
+					interrupts = <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423b0000 {
+					reg = <0x423b0000 0x8000>;
+					interrupts = <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423b8000 {
+					reg = <0x423b8000 0x8000>;
+					interrupts = <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423c0000 {
+					reg = <0x423c0000 0x8000>;
+					interrupts = <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423c8000 {
+					reg = <0x423c8000 0x8000>;
+					interrupts = <GIC_SPI 282 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423d0000 {
+					reg = <0x423d0000 0x8000>;
+					interrupts = <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423d8000 {
+					reg = <0x423d8000 0x8000>;
+					interrupts = <GIC_SPI 283 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423e0000 {
+					reg = <0x423e0000 0x8000>;
+					interrupts = <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423e8000 {
+					reg = <0x423e8000 0x8000>;
+					interrupts = <GIC_SPI 284 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423f0000 {
+					reg = <0x423f0000 0x8000>;
+					interrupts = <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@423f8000 {
+					reg = <0x423f8000 0x8000>;
+					interrupts = <GIC_SPI 285 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42400000 {
+					reg = <0x42400000 0x8000>;
+					interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42408000 {
+					reg = <0x42408000 0x8000>;
+					interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42410000 {
+					reg = <0x42410000 0x8000>;
+					interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+				};
+
+				dma-channel@42418000 {
+					reg = <0x42418000 0x8000>;
+					interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+				};
 			};
 
 			mu7: mailbox@42430000 {

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 7/7] arm64: dts: imx95: convert eDMA to per-channel child nodes
  2026-11-02  6:50 ` [PATCH v3 7/7] arm64: dts: imx95: convert eDMA to per-channel " Peng Fan (OSS)
@ 2026-11-02  7:00   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-11-02  7:00 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: imx, dmaengine, devicetree, robh, conor+dt, vkoul, Frank.Li

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] arm64: dts: imx95: edma2 child nodes break fsl_edma_probe() on imx95-navq
--

commit 4788f1a45cc4009b4772c28b9de4641ae62aa052
Author: Peng Fan <peng.fan@nxp.com>

arm64: dts: imx95: convert eDMA to per-channel child nodes

This commit converts the edma2 and edma3 nodes in imx95.dtsi from flat
interrupt arrays on the parent node to 64 per-channel child nodes with
individual reg and interrupts properties.

> diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
> index d20c2498b9aa2..64570703ce6cb 100644
> --- a/arch/arm64/boot/dts/freescale/imx95.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
> @@ -635,148 +635,666 @@ edma2: dma-controller@42000000 {
>  				compatible = "fsl,imx95-edma5";
>  				reg = <0x42000000 0x210000>;
>  				#dma-cells = <3>;
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				ranges;
>  				dma-channels = <64>;
>  				/* channels 0 and 1 reserved for V2X fast hash */
>  				dma-channel-mask = <0x3>;

[ ... ]

> +				dma-channel@42100000 {
> +					reg = <0x42100000 0x8000>;
> +					interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
> +				};

[Severity: High]
Will adding all 64 enabled dma-channel child nodes under edma2 cause
fsl_edma_probe() to fail on arch/arm64/boot/dts/freescale/imx95-navq.dts?

In arch/arm64/boot/dts/freescale/imx95-navq.dts, &edma2 overrides
dma-channels to 30 while inheriting all 64 enabled child nodes from
imx95.dtsi:

    &edma2 {
        /* channels 30-63 owned by M7 */
        dma-channels = <30>;
    };

Previously, with a flat interrupts array on the parent node,
fsl_edma3_irq_init() only iterated up to fsl_edma->n_chans (30) and ignored
the remaining entries.

With child nodes present, fsl_edma_probe() sets fsl_edma->n_chans = 30 and
calls fsl_edma_configure_chan_from_dt(), which iterates over every available
child node via for_each_available_child_of_node(). When it reaches
dma-channel@42100000 (channel 30), fsl_edma_child_to_chan_id() rejects it:

drivers/dma/fsl-edma-main.c:fsl_edma_child_to_chan_id() {
    ...
    ch_id = div64_u64(child_res.start - chan_base, chan_size);
    if (ch_id >= fsl_edma->n_chans)
        return -EINVAL;
    ...
}

fsl_edma_configure_chan_from_dt() then returns -EINVAL and aborts probing
edma2 altogether:

drivers/dma/fsl-edma-main.c:fsl_edma_configure_chan_from_dt() {
    ...
    for_each_available_child_of_node(np, child) {
        ch_id = fsl_edma_child_to_chan_id(pdev, fsl_edma, child,
                          &parent_res);
        if (ch_id < 0) {
            dev_err(&pdev->dev, "invalid channel in %pOFn\n", child);
            of_node_put(child);
            return -EINVAL;
        }
    ...
}

Should imx95-navq.dts reserve channels 30-63 via dma-channel-mask (or
disable those child nodes) so that edma2 still probes?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102-edma-iommu-v3-v3-0-9d0e62a954eb@Example.Com?part=7

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/7] dmaengine: add a bus for DMA channel devices
  2026-11-02  6:49 ` [PATCH v3 2/7] dmaengine: add a bus for DMA channel devices Peng Fan (OSS)
@ 2026-11-02  7:02   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-11-02  7:02 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: imx, dmaengine, devicetree, robh, conor+dt, vkoul, Frank.Li

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] dmaengine: unmap pool leak on error return in dma_bus_init()
--

commit 3da3c262ba473326c89ad5f74821c3da53e57669
Author: Peng Fan <peng.fan@nxp.com>

dmaengine: add a bus for DMA channel devices

This commit adds a dedicated dma_chan_bus_type bus for DMA channel devices
and registers it in dma_bus_init() so that per-channel IOMMU configuration
can work properly.

> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index 34be53487a21d..6fea67f088b35 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -1643,17 +1643,35 @@ void dma_run_dependencies(struct dma_async_tx_descriptor *tx)
>  }
>  EXPORT_SYMBOL_GPL(dma_run_dependencies);
>  
> +static int dma_chan_bus_match(struct device *dev,
> +			      const struct device_driver *drv)
> +{
> +	return 0;
> +}
> +
> +const struct bus_type dma_chan_bus_type = {
> +	.name  = "dma",
> +	.match = dma_chan_bus_match,
> +};
> +
>  static int __init dma_bus_init(void)
>  {
>  	int err = dmaengine_init_unmap_pool();
>  
> +	if (err)
> +		return err;
> +
> +	err = bus_register(&dma_chan_bus_type);
>  	if (err)
>  		return err;
>  
>  	err = class_register(&dma_devclass);
> -	if (!err)
> -		dmaengine_debugfs_init();
> +	if (err) {
> +		bus_unregister(&dma_chan_bus_type);
> +		return err;
> +	}

[Severity: Medium]
If bus_register(&dma_chan_bus_type) or class_register(&dma_devclass) fails in
dma_bus_init(), does this leak the slab caches and mempools allocated in
unmap_pool[] by dmaengine_init_unmap_pool()?

Previously, class_register(&dma_devclass) failure also missed calling
dmaengine_destroy_unmap_pool(), and the new bus_register() error path and
updated class_register() rollback path both return without calling
dmaengine_destroy_unmap_pool() to clean up unmap_pool[].

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102-edma-iommu-v3-v3-0-9d0e62a954eb@Example.Com?part=2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/7] iommu: register the DMA channel bus for IOMMU notifications
  2026-11-02  6:49 ` [PATCH v3 3/7] iommu: register the DMA channel bus for IOMMU notifications Peng Fan (OSS)
@ 2026-11-02  7:03   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-11-02  7:03 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: imx, dmaengine, devicetree, robh, conor+dt, vkoul, Frank.Li

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] iommu: iommu_device_register() fails before arch_initcall(dma_bus_init)
--

commit 9240bcc4b7e8d99a1e2af1ff943ce2458c2e21eb
Author: Peng Fan <peng.fan@nxp.com>

iommu: register the DMA channel bus for IOMMU notifications

This commit adds dma_chan_bus_type (guarded by CONFIG_DMA_ENGINE) to
iommu_buses[] so the IOMMU core installs its bus notifier for DMA channel
devices.

> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index b486b8bbd1fcd..6fa871bbd63ad 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c

[ ... ]

> @@ -191,6 +192,9 @@ static const struct bus_type * const iommu_buses[] = {
>  #ifdef CONFIG_ARM_AMBA
>  	&amba_bustype,
>  #endif
> +#ifdef CONFIG_DMA_ENGINE
> +	&dma_chan_bus_type,
> +#endif

[Severity: High]
Could this cause iommu_device_register() to fail when called before
arch_initcall(dma_bus_init)?

The commit message notes that dma_chan_bus_type is registered at
arch_initcall before iommu_subsys_init() runs at subsys_initcall, but
iommu_buses[] is also iterated by iommu_device_register():

drivers/iommu/iommu.c:iommu_device_register() {
	...
	for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++)
		err = bus_iommu_probe(iommu_buses[i]);
	if (err)
		iommu_device_unregister(iommu);
	...
}

And bus_iommu_probe() calls bus_for_each_dev(), which returns -EINVAL if
the bus has not been registered via bus_register() yet:

drivers/base/bus.c:bus_for_each_dev() {
	struct subsys_private *sp = bus_to_subsys(bus);
	...
	if (!sp)
		return -EINVAL;
}

Every other bus in iommu_buses[] is registered at postcore_initcall or
earlier. On PowerPC, spapr_tce_setup_phb_iommus_initcall() registers PHB
IOMMU devices at postcore_initcall_sync, before arch_initcall(dma_bus_init):

arch/powerpc/kernel/iommu.c:spapr_tce_setup_phb_iommus_initcall() {
	struct pci_controller *hose;

	list_for_each_entry(hose, &hose_list, list_node) {
		ppc_iommu_register_device(hose);
	}
	return 0;
}
postcore_initcall_sync(spapr_tce_setup_phb_iommus_initcall);

When CONFIG_DMA_ENGINE=y, wouldn't bus_iommu_probe(&dma_chan_bus_type)
return -EINVAL during spapr_tce_setup_phb_iommus_initcall(), causing
iommu_device_register() to unregister all PHB IOMMU devices?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102-edma-iommu-v3-v3-0-9d0e62a954eb@Example.Com?part=3

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 6/7] dmaengine: fsl-edma: support per-channel DT child nodes
  2026-11-02  6:50 ` [PATCH v3 6/7] dmaengine: fsl-edma: support per-channel DT child nodes Peng Fan (OSS)
@ 2026-11-02  7:10   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-11-02  7:10 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: imx, dmaengine, devicetree, robh, conor+dt, vkoul, Frank.Li

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] dmaengine: fsl-edma: missing dma_parms on chdev in fsl_edma_configure_chan_iommu()
- [Medium] dmaengine: fsl-edma: 64-bit division and missing bounds check in fsl_edma_child_to_chan_id()
- [Medium] dmaengine: fsl-edma: 32-bit BIT() used on u64 chan_masked in DT channel helpers
- [Medium] dmaengine: fsl-edma: probe failure and errirq lookup in fsl_edma3_irq_init() with child IRQs
- [Medium] dmaengine: fsl-edma: unimplemented child power-domains support claimed in commit message
- [Medium] dmaengine: fsl-edma: silent non-deferral IOMMU errors in fsl_edma_configure_chan_iommu()
--

commit 6337712c7d2219f406bdb1b2711aad20264a4f74
Author: Peng Fan <peng.fan@nxp.com>

dmaengine: fsl-edma: support per-channel DT child nodes

This commit adds support for parsing per-channel devicetree child nodes in the
fsl-edma driver to configure per-channel interrupts and IOMMU mappings.

>     dmaengine: fsl-edma: support per-channel DT child nodes
>     
>     Add support for parsing per-channel child nodes from devicetree.
>     Each child node can carry its own interrupts, iommus, and
>     power-domains properties.
>     
>     The implementation is split into three functions:
>     
>     - fsl_edma_child_to_chan_id(): derives the channel index from the
>       child MMIO address relative to the parent base.
>     
>     - fsl_edma_configure_chan_from_dt(): called before setup_irq() to
>       populate per-channel txirq from child interrupt properties.
>       fsl_edma3_irq_init() is updated to skip platform_get_irq() for
>       channels that already have an IRQ assigned from their child node.
>     
>     - fsl_edma_configure_chan_iommu(): called after
>       dmaenginem_async_device_register() to configure per-channel IOMMU
>       by calling of_dma_configure() on each dma_chan_dev and setting
>       chan_dma_dev so dmaengine_get_dma_device() returns the per-channel
>       device.
>     
>     Existing DTS without child nodes continues to work unchanged.
>     
>     Signed-off-by: Peng Fan <peng.fan@nxp.com>

[Severity: Medium]
The commit message states that each child node can carry its own interrupts,
iommus, and power-domains properties, and that support is added for parsing
per-channel child nodes from devicetree.

However, fsl_edma_configure_chan_from_dt() only parses reg and interrupts, and
fsl_edma_configure_chan_iommu() only parses iommus. In fsl_edma3_attach_pd(),
power domains are still attached by index from the parent platform_device node
via dev_pm_domain_attach_by_id(dev, i), so any power-domains properties placed
on child nodes are ignored.

Should per-channel child power-domains be attached here, or should the commit
message be updated to reflect that child power-domains are not handled by this
patch?

> diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c
> index 30d548a723462..795744e67837d 100644
> --- a/drivers/dma/fsl-edma-main.c
> +++ b/drivers/dma/fsl-edma-main.c
[ ... ]
> @@ -400,12 +403,13 @@ static int fsl_edma3_irq_init(struct platform_device *pdev, struct fsl_edma_engi
>  		if (fsl_edma->chan_masked & BIT(i))
>  			continue;
>  
> -		/* request channel irq */
> -		fsl_chan->txirq = platform_get_irq(pdev, i);
> -		if (fsl_chan->txirq < 0)
> -			return  -EINVAL;
> +		if (fsl_chan->txirq <= 0) {
> +			fsl_chan->txirq = platform_get_irq(pdev, i);
> +			if (fsl_chan->txirq < 0)
> +				return fsl_chan->txirq;
>  
> -		fsl_chan->irq_handler = fsl_edma3_tx_handler;
> +			fsl_chan->irq_handler = fsl_edma3_tx_handler;
> +		}

[Severity: Medium]
What happens in fsl_edma3_irq_init() when a devicetree omits parent interrupts
and only defines available child nodes for a subset of channels (or marks some
child nodes as status = "disabled") without a matching dma-channel-mask?

In fsl_edma_configure_chan_from_dt(), fsl_chan->txirq is only populated for
available child nodes, leaving fsl_chan->txirq == 0 and the channel unmasked
in fsl_edma->chan_masked for any remaining channels. When fsl_edma3_irq_init()
then runs, it falls back to platform_get_irq(pdev, i) on the parent device for
the first channel without an available child node, which fails with -ENXIO and
aborts fsl_edma_probe().

Also, further down in fsl_edma3_irq_init(), when FSL_EDMA_DRV_ERRIRQ_SHARE is
set:

	if (fsl_edma->drvdata->flags & FSL_EDMA_DRV_ERRIRQ_SHARE) {
		/* last one is error irq */
		fsl_edma->errirq = platform_get_irq_optional(pdev, fsl_edma->n_chans);

When per-channel interrupts are moved into child nodes, can the shared error
IRQ still be found at index fsl_edma->n_chans on the parent node?

> @@ -703,6 +707,136 @@ static int fsl_edma3_attach_pd(struct platform_device *pdev, struct fsl_edma_eng
>  	return -EINVAL;
>  }
>  
> +static int fsl_edma_child_to_chan_id(struct platform_device *pdev,
> +				     struct fsl_edma_engine *fsl_edma,
> +				     struct device_node *child,
> +				     struct resource *parent_res)
> +{
> +	const struct fsl_edma_drvdata *drvdata = fsl_edma->drvdata;
> +	struct resource child_res;
> +	u32 ch_id;
> +	int ret;
> +
> +	ret = of_address_to_resource(child, 0, &child_res);
> +	if (ret)
> +		return ret;
> +
> +	if (child_res.start < parent_res->start + drvdata->chreg_off)
> +		return -EINVAL;
> +
> +	ch_id = (child_res.start - parent_res->start - drvdata->chreg_off)
> +		/ drvdata->chreg_space_sz;
> +
> +	if (ch_id >= fsl_edma->n_chans)
> +		return -EINVAL;
> +
> +	return ch_id;
> +}

[Severity: Medium]
Can the division in fsl_edma_child_to_chan_id() cause a link failure on 32-bit
architectures with CONFIG_PHYS_ADDR_T_64BIT=y (such as 32-bit ARM with LPAE or
32-bit PowerPC with CONFIG_PHYS_64BIT=y)?

Because child_res.start and parent_res->start have type resource_size_t, the
expression

	(child_res.start - parent_res->start - drvdata->chreg_off)
		/ drvdata->chreg_space_sz

performs a 64-bit division by the non-constant u32 drvdata->chreg_space_sz
using the plain / operator, which emits an unresolved __aeabi_uldivmod or
__udivdi3 call on 32-bit builds.

In addition, before computing ch_id, only the lower bound is checked. If
child_res is not verified to be contained within parent_res (for example via
resource_contains(parent_res, &child_res)) and aligned to
drvdata->chreg_space_sz, could a large or unaligned child reg address truncate
when assigned to u32 ch_id or alias a valid channel index?

> +
> +static int fsl_edma_configure_chan_from_dt(struct platform_device *pdev,
> +					   struct fsl_edma_engine *fsl_edma)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct resource parent_res;
> +	struct device_node *child;
> +	int ret;
> +
> +	ret = of_address_to_resource(np, 0, &parent_res);
> +	if (ret)
> +		return ret;
> +
> +	for_each_available_child_of_node(np, child) {
> +		struct fsl_edma_chan *fsl_chan;
> +		int ch_id, irq;
> +
> +		ch_id = fsl_edma_child_to_chan_id(pdev, fsl_edma, child,
> +						  &parent_res);
> +		if (ch_id < 0) {
> +			dev_err(&pdev->dev, "invalid channel in %pOFn\n", child);
> +			of_node_put(child);
> +			return -EINVAL;
> +		}
> +
> +		if (fsl_edma->chan_masked & BIT(ch_id))
> +			continue;

[Severity: Medium]
Should this check in fsl_edma_configure_chan_from_dt() (and the identical
check in fsl_edma_configure_chan_iommu() below) use BIT_ULL(ch_id) instead of
BIT(ch_id)?

fsl_edma->chan_masked is a u64 bitmask supporting up to 64 channels (for
example on fsl,imx95-edma5 where dma-channels is 64 and ch_id can be 0..63),
whereas BIT(ch_id) uses unsigned long and overflows on 32-bit architectures
when ch_id >= 32.

[ ... ]
> +static int fsl_edma_configure_chan_iommu(struct platform_device *pdev,
> +					struct fsl_edma_engine *fsl_edma)
> +{
[ ... ]
> +		list_for_each_entry(chan, &fsl_edma->dma_dev.channels,
> +				    device_node) {
> +			struct device *chdev;
> +
> +			if (to_fsl_edma_chan(chan) != fsl_chan)
> +				continue;
> +
> +			chdev = dmaengine_chan_dev(chan);
> +			if (fsl_edma->drvdata->flags & FSL_EDMA_DRV_TCD64)
> +				dma_coerce_mask_and_coherent(chdev,
> +					DMA_BIT_MASK(64));
> +			else
> +				dma_coerce_mask_and_coherent(chdev,
> +					DMA_BIT_MASK(32));
> +			ret = of_dma_configure(chdev, child, true);
> +			if (ret) {
> +				dev_err(&pdev->dev,
> +					"IOMMU config failed for channel %d: %d\n",
> +					ch_id, ret);
> +				of_node_put(child);
> +				return ret;
> +			}

[Severity: Medium]
As reported by Frank Li on v1 [1], should dev_err_probe() be used here when
of_dma_configure() fails so that -EPROBE_DEFER does not log an error message?

Also, in drivers/of/device.c, of_dma_configure_id() ignores all errors from
of_iommu_configure() other than -EPROBE_DEFER (for example when duplicate
StreamIDs across channels cause arm_smmu_insert_master() to return -ENODEV)
and returns 0 after falling back to non-IOMMU DMA ops. If that happens, will
fsl_edma_configure_chan_iommu() silently set chan_dma_dev = true on a channel
device that failed to attach to the IOMMU?

> +
> +			chan->chan_dev->chan_dma_dev = true;

[Severity: High]
When chan->chan_dev->chan_dma_dev is set to true in
fsl_edma_configure_chan_iommu(), dmaengine_get_dma_device(chan) returns chdev
instead of fsl_edma->dma_dev.dev (&pdev->dev).

In fsl_edma_probe(), max_seg_size is configured on fsl_edma->dma_dev.dev:

	/* Per worst case 'nbytes = 1' take CITER as the max_seg_size */
	dma_set_max_seg_size(fsl_edma->dma_dev.dev,
			     FIELD_GET(EDMA_TCD_ITER_MASK, EDMA_TCD_ITER_MASK));

However, chdev->dma_parms is left as NULL on the per-channel device. Doesn't
that cause dma_get_max_seg_size(dmaengine_get_dma_device(chan)) to return the
64 KiB default (SZ_64K) instead of 0x7fff (32767), allowing iommu_dma_map_sg()
and DMAengine clients to coalesce scatterlist segments up to 64 KiB and
overflow the 15-bit CITER/BITER iteration count in fsl_edma_prep_slave_sg()
and fsl_edma_prep_dma_cyclic()?

Should chdev->dma_parms be set to pdev->dev.dma_parms in
fsl_edma_configure_chan_iommu()?

[1] https://lore.kernel.org/r/aqrem_EkcQM2t0IE@SMW015318

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102-edma-iommu-v3-v3-0-9d0e62a954eb@Example.Com?part=6

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-11-02  7:10 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02  6:49 [PATCH v3 0/7] dmaengine: add DMA channel bus and fsl-edma per-channel IOMMU support Peng Fan (OSS)
2026-11-02  6:49 ` [PATCH v3 1/7] dmaengine: fsl-edma: unregister channels before vchan cleanup Peng Fan (OSS)
2026-11-02  6:49 ` [PATCH v3 2/7] dmaengine: add a bus for DMA channel devices Peng Fan (OSS)
2026-11-02  7:02   ` sashiko-bot
2026-11-02  6:49 ` [PATCH v3 3/7] iommu: register the DMA channel bus for IOMMU notifications Peng Fan (OSS)
2026-11-02  7:03   ` sashiko-bot
2026-11-02  6:49 ` [PATCH v3 4/7] dmaengine: move channel devices to the DMA channel bus Peng Fan (OSS)
2026-11-02  6:49 ` [PATCH v3 5/7] dt-bindings: dma: fsl,edma: add per-channel child node support Peng Fan (OSS)
2026-11-02  6:50 ` [PATCH v3 6/7] dmaengine: fsl-edma: support per-channel DT child nodes Peng Fan (OSS)
2026-11-02  7:10   ` sashiko-bot
2026-11-02  6:50 ` [PATCH v3 7/7] arm64: dts: imx95: convert eDMA to per-channel " Peng Fan (OSS)
2026-11-02  7:00   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox