From: Frank Li <Frank.li@oss.nxp.com>
To: "Peng Fan (OSS)" <peng.fan@oss.nxp.com>
Cc: Frank Li <Frank.Li@nxp.com>, Vinod Koul <vkoul@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Frank Li <Frank.Li@kernel.org>,
imx@lists.linux.dev, dmaengine@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
Peng Fan <peng.fan@nxp.com>
Subject: Re: [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map
Date: Wed, 16 Sep 2026 13:23:23 -0500 [thread overview]
Message-ID: <aqrem_EkcQM2t0IE@SMW015318> (raw)
In-Reply-To: <20260916-edma-iommu-v1-2-e1731968081e@nxp.com>
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
>
prev parent reply other threads:[~2026-09-16 18:23 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 15:55 [PATCH 0/2] dmaengine: fsl-edma: add per-channel IOMMU support Peng Fan (OSS)
2026-09-16 15:55 ` [PATCH 1/2] dt-bindings: dma: fsl,edma: add iommu-map property Peng Fan (OSS)
2026-09-16 16:46 ` Frank Li
2026-09-24 21:56 ` Rob Herring (Arm)
2026-09-25 1:43 ` Peng Fan
2026-09-16 15:55 ` [PATCH 2/2] dmaengine: fsl-edma: add per-channel IOMMU support via iommu-map Peng Fan (OSS)
2026-09-16 16:06 ` sashiko-bot
2026-09-16 18:23 ` Frank Li [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aqrem_EkcQM2t0IE@SMW015318 \
--to=frank.li@oss.nxp.com \
--cc=Frank.Li@kernel.org \
--cc=Frank.Li@nxp.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmaengine@vger.kernel.org \
--cc=imx@lists.linux.dev \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peng.fan@nxp.com \
--cc=peng.fan@oss.nxp.com \
--cc=robh@kernel.org \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.