From: Mikko Perttunen <mperttunen@nvidia.com>
To: Marek Szyprowski <m.szyprowski@samsung.com>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
Will Deacon <will@kernel.org>,
Russell King <linux@armlinux.org.uk>,
Heiko Stuebner <heiko@sntech.de>,
Thierry Reding <thierry.reding@kernel.org>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Jonathan Hunter <jonathanh@nvidia.com>,
Krishna Reddy <vdumpa@nvidia.com>,
Krzysztof Kozlowski <krzk@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
linux-tegra@vger.kernel.org
Cc: Peter Griffin <peter.griffin@linaro.org>,
Alim Akhtar <alim.akhtar@samsung.com>,
Chen-Yu Tsai <wens@kernel.org>,
Jernej Skrabec <jernej.skrabec@gmail.com>,
Samuel Holland <samuel@sholland.org>,
Yong Wu <yong.wu@mediatek.com>,
Matthias Brugger <matthias.bgg@gmail.com>,
AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com>,
Rob Clark <robin.clark@oss.qualcomm.com>,
Geert Uytterhoeven <geert+renesas@glider.be>,
iommu@lists.linux.dev, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
dri-devel@lists.freedesktop.org, linux-tegra@vger.kernel.org,
Robin Murphy <robin.murphy@arm.com>
Subject: Re: [PATCH v2 04/11] ARM: dma-mapping: Implement and expose DMA setup functions
Date: Fri, 23 Oct 2026 14:12:17 +0900 [thread overview]
Message-ID: <EBsd2UhYS9u2iI-UFj7t_g@nvidia.com> (raw)
In-Reply-To: <6406c7b1-5e37-4c22-83c2-089c35ef54bf@arm.com>
On Thursday, October 22, 2026 10:16 PM Robin Murphy wrote:
> On 16/10/2026 7:46 am, Mikko Perttunen wrote:
> > ARM DMA domains are currently allocated by the ARM DMA code, with struct
> > dma_iommu_mapping owning the domain and the IOVA bookkeeping. To allow
> > the IOMMU core to own DMA domains as is the case with other
> > architectures, we have to allow that code to allocate the domain and get
> > the cookie from the ARM DMA code.
> >
> > Implement ARM versions of iommu_get/put_dma_cookie that create a struct
> > dma_iommu_mapping that doesn't have its own domain, as well as
> > iommu_setup/teardown_dma_ops that set the device's archdata.mapping,
> > allowing ARM DMA ops to seamlessly work on these devices.
> >
> > The code is protected by CONFIG_ARM_DMA_USE_IOMMU and mutually exclusive
> > with the same-named functions in the dma-iommu code; and not reachable
> > yet.
> >
> > Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
> > ---
> > arch/arm/include/asm/dma-iommu.h | 17 ++++++
> > arch/arm/mm/dma-mapping.c | 118 ++++++++++++++++++++++++++++++++++-----
> > drivers/iommu/dma-iommu.h | 50 +++++++++++------
> > 3 files changed, 154 insertions(+), 31 deletions(-)
> >
> > diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
> > index 2ce4c5683e6d..85cf9b05faab 100644
> > --- a/arch/arm/include/asm/dma-iommu.h
> > +++ b/arch/arm/include/asm/dma-iommu.h
> > @@ -19,6 +19,14 @@ struct dma_iommu_mapping {
> > size_t bits; /* per bitmap */
> > dma_addr_t base;
> >
> > + /*
> > + * Set for mappings created by arm_iommu_create_mapping(), where
> > + * @domain is owned by the mapping.
> > + * Clear for mappings that are a cookie of a domain owned by the IOMMU
> > + * core.
> > + */
> > + bool owns_domain;
>
> Do we strictly need this, or could we in fact already tell the
> difference via iommu_is_dma_domain()? (Since ARM-API-owned domains via
> iommu_paging_domain_alloc() will be IOMMU_DOMAIN_UNMANAGED)
We don't, I've removed it.
>
> > +
> > spinlock_t lock;
> > struct kref kref;
> > };
> > @@ -32,5 +40,14 @@ int arm_iommu_attach_device(struct device *dev,
> > struct dma_iommu_mapping *mapping);
> > void arm_iommu_detach_device(struct device *dev);
> >
> > +#ifdef CONFIG_ARM_DMA_USE_IOMMU
> > +struct iommu_domain;
> > +
> > +void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain);
> > +void iommu_teardown_dma_ops(struct device *dev);
> > +int iommu_get_dma_cookie(struct iommu_domain *domain);
> > +void iommu_put_dma_cookie(struct iommu_domain *domain);
> > +#endif
> > +
> > #endif /* __KERNEL__ */
> > #endif
> > diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> > index 4284950a9246..f2d3e8ec3487 100644
> > --- a/arch/arm/mm/dma-mapping.c
> > +++ b/arch/arm/mm/dma-mapping.c
> > @@ -1531,6 +1531,79 @@ static void __arm_iommu_free_mapping(struct dma_iommu_mapping *mapping)
> > kfree(mapping);
> > }
> >
> > +static int __arm_iommu_init_cookie(struct iommu_domain *domain,
> > + dma_addr_t base, u64 size)
> > +{
> > + struct dma_iommu_mapping *mapping;
> > +
> > + if (domain->cookie_type != IOMMU_COOKIE_NONE)
> > + return -EEXIST;
> > +
> > + mapping = __arm_iommu_alloc_mapping(base, size);
> > + if (IS_ERR(mapping))
> > + return PTR_ERR(mapping);
> > +
> > + mapping->domain = domain;
> > + domain->cookie_type = IOMMU_COOKIE_ARM_DMA;
> > + domain->arm_cookie = mapping;
> > +
> > + return 0;
> > +}
> > +
> > +/**
> > + * iommu_get_dma_cookie - Set up a domain cookie for ARM IOMMU-based DMA API
> > + * @domain: IOMMU_DOMAIN_DMA domain being configured
> > + *
> > + * Allocates IOVA bookkeeping for the domain based on the domain's specified
> > + * geometry. The aperture can currently be at most 4GB in size, otherwise
> > + * fails with -ERANGE.
>
> Bit of a corner case, but I think that might technically break on
> stage-2-only arm-smmu implementations like MMU-400 where the default
> aperture will be 40 bits. It's probably better to explicitly cap our
> request to 4GB here to preserve the current behaviour.
Yes, fixed.
>
> > + */
> > +int iommu_get_dma_cookie(struct iommu_domain *domain)
> > +{
> > + dma_addr_t base = domain->geometry.aperture_start;
> > + u64 size;
> > +
> > + if (base > domain->geometry.aperture_end)
> > + return -EINVAL;
> > +
> > + size = (u64)domain->geometry.aperture_end - base + 1;
> > +
> > + return __arm_iommu_init_cookie(domain, base, size);
> > +}
> > +
> > +/**
> > + * iommu_put_dma_cookie - Free domain cookie for ARM IOMMU-based DMA API
> > + * @domain: the domain being freed
> > + */
> > +void iommu_put_dma_cookie(struct iommu_domain *domain)
> > +{
> > + __arm_iommu_free_mapping(domain->arm_cookie);
> > +}
> > +
> > +/**
> > + * iommu_setup_dma_ops - Record a device's DMA API domain cookie
> > + * @dev: the device
> > + * @domain: the group's new default domain
> > + *
> > + * Records the cookie of @domain on @dev, or clears it if @domain is not a DMA
> > + * API domain. The DMA ops themselves are per driver binding and are installed
> > + * by arch_setup_dma_ops().
> > + */
> > +void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain)
> > +{
> > + to_dma_iommu_mapping(dev) = iommu_is_dma_domain(domain) ?
> > + domain->arm_cookie : NULL;
>
> It feels like we should actually set the dma_ops here for a real default
> domain. Sure it might make things a little more complex in the interim,
> but it'll be more logical when we come to remove the other path.
I've done a bunch of re-arranging: iommu_get_dma_cookie still allocates
the mapping, but the bitmaps are only initialized here in
iommu_setup_dma_ops because the domain geometry may not be available
earlier. And I moved set_dma_ops here as well. Those of course only
apply to the default domain case. I've also added upper bound limiting
to alloc_iova to not have the range checks in arm_setup_iommu_dma_ops,
and because the range information may not be available in
iommu_setup_dma_ops.
>
> > +}
> > +
> > +/**
> > + * iommu_teardown_dma_ops - Clear a device's DMA API domain cookie
> > + * @dev: the device
> > + */
> > +void iommu_teardown_dma_ops(struct device *dev)
> > +{
> > + to_dma_iommu_mapping(dev) = NULL;
> > +}
> > +
> > /**
> > * arm_iommu_create_mapping
> > * @dev: pointer to the client device (for IOMMU calls)
> > @@ -1541,28 +1614,32 @@ static void __arm_iommu_free_mapping(struct dma_iommu_mapping *mapping)
> > * IO address ranges, which is required to perform memory allocation and
> > * mapping with IOMMU aware functions.
> > *
> > + * Unlike a default domain set up by the IOMMU core, the returned mapping owns
> > + * the domain it describes and releases it along with the last reference.
> > + *
> > * The client device need to be attached to the mapping with
> > * arm_iommu_attach_device function.
> > */
> > struct dma_iommu_mapping *
> > arm_iommu_create_mapping(struct device *dev, dma_addr_t base, u64 size)
> > {
> > - struct dma_iommu_mapping *mapping;
> > -
> > - mapping = __arm_iommu_alloc_mapping(base, size);
> > - if (IS_ERR(mapping))
> > - return mapping;
> > + struct iommu_domain *domain;
> > + int err;
> >
> > - mapping->domain = iommu_paging_domain_alloc(dev);
> > - if (IS_ERR(mapping->domain)) {
> > - int err = PTR_ERR(mapping->domain);
> > + domain = iommu_paging_domain_alloc(dev);
> > + if (IS_ERR(domain))
> > + return ERR_CAST(domain);
> >
> > - __arm_iommu_free_mapping(mapping);
> > + err = __arm_iommu_init_cookie(domain, base, size);
> > + if (err) {
> > + iommu_domain_free(domain);
> > return ERR_PTR(err);
> > }
> >
> > - kref_init(&mapping->kref);
> > - return mapping;
> > + domain->arm_cookie->owns_domain = true;
> > + kref_init(&domain->arm_cookie->kref);
> > +
> > + return domain->arm_cookie;
> > }
> > EXPORT_SYMBOL_GPL(arm_iommu_create_mapping);
> >
> > @@ -1571,8 +1648,8 @@ static void release_iommu_mapping(struct kref *kref)
> > struct dma_iommu_mapping *mapping =
> > container_of(kref, struct dma_iommu_mapping, kref);
> >
> > + /* Frees mapping too, via iommu_put_dma_cookie(). */
> > iommu_domain_free(mapping->domain);
> > - __arm_iommu_free_mapping(mapping);
> > }
> >
> > static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
> > @@ -1595,8 +1672,13 @@ static int extend_iommu_mapping(struct dma_iommu_mapping *mapping)
> >
> > void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
> > {
> > - if (mapping)
> > - kref_put(&mapping->kref, release_iommu_mapping);
> > + if (!mapping)
> > + return;
> > +
> > + if (WARN_ON(!mapping->owns_domain))
> > + return;
> > +
> > + kref_put(&mapping->kref, release_iommu_mapping);
> > }
> > EXPORT_SYMBOL_GPL(arm_iommu_release_mapping);
> >
> > @@ -1660,6 +1742,14 @@ void arm_iommu_detach_device(struct device *dev)
> > return;
> > }
> >
> > + /*
> > + * This pairs with arm_iommu_attach_device() on a driver-owned mapping.
> > + * A mapping which is merely the cookie of a core-owned default domain
> > + * must not be torn down from here.
> > + */
> > + if (WARN_ON(!mapping->owns_domain))
>
> As mentioned, if we can't reasonably hide the proper default domains
> from external users of to_dma_iommu_mapping(), then I don't think we
> should warn here, just treat it as a quiet no-op - the reason for the
> "kick out the ARM domain" idiom is that it's in the way of attaching to
> a driver-owned domain (whether that be a bare iommu_domain or another
> ARM dma_iommu_mapping), but a real default domain is inherently out of
> the way already. That way we can freely convert the rest of the drivers
> to use default domains without impacting their users, then clean up the
> detach pattern from the client drivers separately afterwards.
Yep, true. This ends up cleaning up the series nicely as well.
Thank you!
Mikko
>
> Thanks,
> Robin.
>
> > + return;
> > +
> > iommu_detach_device(mapping->domain, dev);
> > kref_put(&mapping->kref, release_iommu_mapping);
> > to_dma_iommu_mapping(dev) = NULL;
> > diff --git a/drivers/iommu/dma-iommu.h b/drivers/iommu/dma-iommu.h
> > index 349d6a57e5a0..71b23cb698c0 100644
> > --- a/drivers/iommu/dma-iommu.h
> > +++ b/drivers/iommu/dma-iommu.h
> > @@ -7,25 +7,24 @@
> >
> > #include <linux/iommu.h>
> >
> > -#ifdef CONFIG_IOMMU_DMA
> > +/*
> > + * Both dma-iommu.c and arch/arm/mm/dma-mapping.c implement functions to set up
> > + * IOMMU_DOMAIN_DMA default domains. Only one provider can be compiled in at a
> > + * time.
> > + */
> > +#if defined(CONFIG_ARM_DMA_USE_IOMMU)
> > +
> > +#include <asm/dma-iommu.h>
> > +
> > +#elif defined(CONFIG_IOMMU_DMA)
> >
> > void iommu_setup_dma_ops(struct device *dev, struct iommu_domain *domain);
> > void iommu_teardown_dma_ops(struct device *dev);
> >
> > int iommu_get_dma_cookie(struct iommu_domain *domain);
> > void iommu_put_dma_cookie(struct iommu_domain *domain);
> > -void iommu_put_msi_cookie(struct iommu_domain *domain);
> >
> > -int iommu_dma_init_fq(struct iommu_domain *domain);
> > -
> > -void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
> > -
> > -int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
> > - phys_addr_t msi_addr);
> > -
> > -extern bool iommu_dma_forcedac;
> > -
> > -#else /* CONFIG_IOMMU_DMA */
> > +#else
> >
> > static inline void iommu_setup_dma_ops(struct device *dev,
> > struct iommu_domain *domain)
> > @@ -36,11 +35,6 @@ static inline void iommu_teardown_dma_ops(struct device *dev)
> > {
> > }
> >
> > -static inline int iommu_dma_init_fq(struct iommu_domain *domain)
> > -{
> > - return -EINVAL;
> > -}
> > -
> > static inline int iommu_get_dma_cookie(struct iommu_domain *domain)
> > {
> > return -ENODEV;
> > @@ -50,6 +44,28 @@ static inline void iommu_put_dma_cookie(struct iommu_domain *domain)
> > {
> > }
> >
> > +#endif
> > +
> > +#ifdef CONFIG_IOMMU_DMA
> > +
> > +void iommu_put_msi_cookie(struct iommu_domain *domain);
> > +
> > +int iommu_dma_init_fq(struct iommu_domain *domain);
> > +
> > +void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
> > +
> > +int iommu_dma_sw_msi(struct iommu_domain *domain, struct msi_desc *desc,
> > + phys_addr_t msi_addr);
> > +
> > +extern bool iommu_dma_forcedac;
> > +
> > +#else /* CONFIG_IOMMU_DMA */
> > +
> > +static inline int iommu_dma_init_fq(struct iommu_domain *domain)
> > +{
> > + return -EINVAL;
> > +}
> > +
> > static inline void iommu_put_msi_cookie(struct iommu_domain *domain)
> > {
> > }
> >
>
>
next prev parent reply other threads:[~2026-10-23 5:12 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-16 6:46 [PATCH v2 00/11] Make the 32-bit ARM DMA API work with normal IOMMU DMA default domains (+ Tegra PoC) Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 01/11] iommu: Add iommu_teardown_dma_ops Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 02/11] iommu: Add cookie type for ARM_DMA_USE_IOMMU Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 03/11] ARM: dma-mapping: Split mapping allocation from domain allocation Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 04/11] ARM: dma-mapping: Implement and expose DMA setup functions Mikko Perttunen
2026-10-22 13:16 ` Robin Murphy
2026-10-23 5:12 ` Mikko Perttunen [this message]
2026-10-16 6:46 ` [PATCH v2 05/11] ARM: dma-mapping: Bypass the legacy path for core-owned DMA API domains Mikko Perttunen
2026-10-19 16:55 ` Robin Murphy
2026-10-20 4:01 ` Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 06/11] ARM: dma-mapping: Handle foreign buffers in arm_iommu_get_sgtable Mikko Perttunen
2026-10-19 15:47 ` Robin Murphy
2026-10-20 3:55 ` Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 07/11] iommu: Let 32-bit ARM drivers opt into a DMA API default domain Mikko Perttunen
2026-10-20 11:28 ` Robin Murphy
2026-10-21 3:12 ` Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 08/11] iommu/tegra-smmu: Defer display client translation to driver handover Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 09/11] gpu: host1x: Drop release of legacy 32-bit ARM DMA domain Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 10/11] drm/tegra: " Mikko Perttunen
2026-10-16 6:46 ` [PATCH v2 11/11] iommu/tegra-smmu: Use a DMA API default domain per swgroup Mikko Perttunen
2026-10-20 15:30 ` Robin Murphy
2026-10-23 5:14 ` Mikko Perttunen
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=EBsd2UhYS9u2iI-UFj7t_g@nvidia.com \
--to=mperttunen@nvidia.com \
--cc=airlied@gmail.com \
--cc=alim.akhtar@samsung.com \
--cc=angelogioacchino.delregno@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=geert+renesas@glider.be \
--cc=heiko@sntech.de \
--cc=iommu@lists.linux.dev \
--cc=jernej.skrabec@gmail.com \
--cc=jgg@ziepe.ca \
--cc=jonathanh@nvidia.com \
--cc=joro@8bytes.org \
--cc=krzk@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=m.szyprowski@samsung.com \
--cc=matthias.bgg@gmail.com \
--cc=peter.griffin@linaro.org \
--cc=robin.clark@oss.qualcomm.com \
--cc=robin.murphy@arm.com \
--cc=samuel@sholland.org \
--cc=simona@ffwll.ch \
--cc=thierry.reding@kernel.org \
--cc=vdumpa@nvidia.com \
--cc=wens@kernel.org \
--cc=will@kernel.org \
--cc=yong.wu@mediatek.com \
/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 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®