mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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)
> >   {
> >   }
> > 
> 
> 





  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®