[RFC PATCH 3/5] iommu: Add support for the unmap_pages IOMMU callback

Will Deacon will at kernel.org
Thu Apr 1 17:37:05 BST 2021


On Thu, Apr 01, 2021 at 04:34:37PM +0100, Robin Murphy wrote:
> On 2021-03-31 04:00, Isaac J. Manjarres wrote:
> > The IOMMU framework currently unmaps memory one page block at a time,
> > per the page block sizes that are supported by the IOMMU hardware.
> > Now that IOMMU drivers can supply a callback for unmapping multiple
> > in one call, add support in the IOMMU framework to calculate how many
> > page mappings of the same size can be unmapped in one shot, and invoke the
> > IOMMU driver's unmap_pages callback if it has one. Otherwise, the
> > existing behavior will be used.
> > 
> > Signed-off-by: Isaac J. Manjarres <isaacm at codeaurora.org>
> > Suggested-by: Will Deacon <will at kernel.org>
> > ---
> >   drivers/iommu/iommu.c | 44 +++++++++++++++++++++++++++++++++++++------
> >   1 file changed, 38 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > index d0b0a15dba84..dc4295f6bc7f 100644
> > --- a/drivers/iommu/iommu.c
> > +++ b/drivers/iommu/iommu.c
> > @@ -2356,8 +2356,8 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
> >   }
> >   EXPORT_SYMBOL_GPL(iommu_iova_to_phys);
> > -static size_t iommu_pgsize(struct iommu_domain *domain,
> > -			   unsigned long addr_merge, size_t size)
> > +static size_t __iommu_pgsize(struct iommu_domain *domain,
> > +			     unsigned long addr_merge, size_t size)
> >   {
> >   	unsigned int pgsize_idx;
> >   	size_t pgsize;
> > @@ -2388,6 +2388,24 @@ static size_t iommu_pgsize(struct iommu_domain *domain,
> >   	return pgsize;
> >   }
> > +static size_t iommu_pgsize(struct iommu_domain *domain,
> > +			   unsigned long addr_merge, size_t size,
> > +			   size_t *pgcount)
> > +{
> > +	size_t pgsize = __iommu_pgsize(domain, addr_merge, size);
> > +	size_t pgs = 0;
> > +
> > +	do {
> > +		pgs++;
> > +		size -= pgsize;
> > +		addr_merge += pgsize;
> > +	} while (size && __iommu_pgsize(domain, addr_merge, size) == pgsize);
> 
> This looks horrifically inefficient. As part of calculating the best current
> page size it should then be pretty trivial to calculate "(size &
> next_pgsize_up - 1) >> pgsize_idx" for the number of current-size pages up
> to the next-better-size boundary (with next_pgsize_up being 0 if pgsize is
> already the largest possible for the relative alignment of physical and
> virtual address). A loop is just... yuck :(

Hehe, I'm glad you said that as I was thinking the same thing. It's
surprisingly fiddly to get this right, but I spent some time hacking it
today and I _think_ I have something that Isaac could build on (and
hopefully won't be too hairy for ->map either).

I'll post it as an RFC in a sec...

Will



More information about the linux-arm-kernel mailing list