All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Rob Clark" <robin.clark@oss.qualcomm.com>,
	dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v3 4/6] drm/msm: Convert iommu map/unmap to helpers
Date: Tue, 27 Oct 2026 23:18:27 +0000	[thread overview]
Message-ID: <sashiko-outbox-187204@kernel.org> (raw)
In-Reply-To: <20261027230452.130031-5-robin.clark@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] drm/msm: missing leaf IOTLB invalidation in __unmap_iommu() on qcom_iommu
- [High] drm/msm: bypassed iommu_sync_map() and core IOMMU API in msm_iommu_map()
--

commit efc83727eef15680f9e495c695cd848cb428e1a7
Author: Rob Clark <robin.clark@oss.qualcomm.com>

drm/msm: Convert iommu map/unmap to helpers

This commit converts msm_iommu_map() and msm_iommu_unmap() in
drivers/gpu/drm/msm/msm_iommu.c to use the __do_map() and __do_unmap()
helpers via domain->ops->map_pages() and domain->ops->unmap_pages().

> diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
> index 5c13ad6d5a366..479e5450a4dcd 100644
> --- a/drivers/gpu/drm/msm/msm_iommu.c
> +++ b/drivers/gpu/drm/msm/msm_iommu.c
> @@ -731,12 +731,38 @@ static void msm_iommu_detach(struct msm_mmu *mmu)
>  	iommu_detach_device(iommu->domain, mmu->dev);
>  }
>  
> +static size_t
> +__unmap_iommu(void *arg, u64 iova, size_t pgsize, size_t pgcount)
> +{
> +	struct iommu_domain *domain = arg;
> +	return domain->ops->unmap_pages(domain, iova, pgsize, pgcount, NULL);
> +}
> +
> +static int
> +__map_iommu(void *arg, phys_addr_t paddr, u64 iova, size_t pgsize,
> +	    size_t pgcount, int prot, size_t *mapped)
> +{
> +	struct iommu_domain *domain = arg;
> +	return domain->ops->map_pages(domain, iova, paddr, pgsize, pgcount,
> +				      prot, GFP_KERNEL, mapped);
> +}
> +
> +static void
> +__flush_iommu(void *arg)
> +{
> +	struct iommu_domain *domain = arg;
> +	iommu_flush_iotlb_all(domain);
> +}

[Severity: Critical]
Does passing NULL for the gather parameter in __unmap_iommu() paired with
iommu_flush_iotlb_all() in __flush_iommu() leave stale leaf IOTLB entries
on platforms using qcom_iommu?

Previously, msm_iommu_unmap() called iommu_unmap(), which passed a valid
struct iommu_iotlb_gather to domain->ops->unmap_pages() and then called
iommu_iotlb_sync().

With gather set to NULL in __unmap_iommu(), __arm_lpae_unmap() in
drivers/iommu/io-pgtable-arm.c skips per-page TLB invalidation:

drivers/iommu/io-pgtable-arm.c:__arm_lpae_unmap() {
    ...
		if (gather && !iommu_iotlb_gather_queued(gather))
			for (int j = 0; j < i; j++)
				io_pgtable_tlb_add_page(iop, gather, iova + j * size, size);
    ...
}

On SoCs using drivers/iommu/arm/arm-smmu/qcom_iommu.c, skipping
io_pgtable_tlb_add_page() means qcom_iommu_tlb_add_page() is never called
to write ARM_SMMU_CB_S1_TLBIVAL. When __do_unmap() then calls
__flush_iommu() -> iommu_flush_iotlb_all(), qcom_iommu_flush_iotlb_all()
only issues a TLBSYNC barrier without invalidating the context bank by
ASID (qcom_iommu_tlb_inv_context()):

drivers/iommu/arm/arm-smmu/qcom_iommu.c:qcom_iommu_flush_iotlb_all() {
	struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
	struct io_pgtable *pgtable = container_of(qcom_domain->pgtbl_ops,
						  struct io_pgtable, ops);
	if (!qcom_domain->pgtbl_ops)
		return;

	pm_runtime_get_sync(qcom_domain->iommu->dev);
	qcom_iommu_tlb_sync(pgtable->cookie);
	pm_runtime_put_sync(qcom_domain->iommu->dev);
}

As a result, unmapping leaf pages in msm_iommu_unmap() (or during error
rollback in __do_map()) issues no hardware TLB invalidation on qcom_iommu,
allowing the GPU or display engine to continue accessing unmapped and freed
GEM pages via stale IOTLB entries.

> +
> +static const struct map_ops iommu_ops = {
> +	__unmap_iommu, __map_iommu, __flush_iommu
> +};
> +
>  static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
>  			 struct sg_table *sgt, size_t off, size_t len,
>  			 int prot)
>  {
> -	struct msm_iommu *iommu = to_msm_iommu(mmu);
> -	ssize_t ret;
> +	struct iommu_domain *domain = to_msm_iommu(mmu)->domain;
>  
>  	WARN_ON(off != 0);
>  
> @@ -744,23 +770,18 @@ static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova,
>  	if (iova & BIT_ULL(48))
>  		iova |= GENMASK_ULL(63, 49);
>  
> -	ret = iommu_map_sgtable(iommu->domain, iova, sgt, prot);
> -	if (ret < 0)
> -		return ret;
> -
> -	return (ret == len) ? 0 : -EINVAL;
> +	return __do_map(domain->pgsize_bitmap, iova, sgt, off, len, prot,
> +			domain, &iommu_ops);
>  }
>  
>  static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, size_t len)
>  {
> -	struct msm_iommu *iommu = to_msm_iommu(mmu);
> +	struct iommu_domain *domain = to_msm_iommu(mmu)->domain;
>  
>  	if (iova & BIT_ULL(48))
>  		iova |= GENMASK_ULL(63, 49);
>  
> -	iommu_unmap(iommu->domain, iova, len);
> -
> -	return 0;
> +	return __do_unmap(domain->pgsize_bitmap, iova, len, domain, &iommu_ops);
>  }

[Severity: High]
What happens on platforms that require .iotlb_sync_map or use generic_pt
when msm_iommu_map() and msm_iommu_unmap() bypass the core IOMMU API and
call domain->ops->map_pages() and domain->ops->unmap_pages() directly?

1. Previously, msm_iommu_map() called iommu_map_sgtable() ->
   iommu_map_sg(), which calls iommu_sync_map() after mapping the
   scatterlist:

   drivers/iommu/iommu.c:iommu_map_sg() {
       ...
	ret = iommu_sync_map(domain, iova, mapped);
	if (ret)
		goto out_err;
       ...
   }

   __do_map() only calls __map_iommu() -> domain->ops->map_pages() and
   never invokes domain->ops->iotlb_sync_map. On APQ8064/MSM8960
   (drivers/iommu/msm_iommu.c), the IOMMU driver relies on
   .iotlb_sync_map = msm_iommu_sync_map to flush the IOTLB for newly mapped
   ranges via __flush_iotlb_range(), which is now skipped.

2. In drivers/iommu/iommu.c:iommu_map_nosync() and __iommu_unmap(),
   domains converted to generic_pt (iommupt) use pt->ops->map_range and
   pt->ops->unmap_range and leave domain->ops->map_pages and
   domain->ops->unmap_pages as NULL:

   drivers/iommu/iommu.c:iommu_map_nosync() {
       ...
	if (pt)
		ret = pt->ops->map_range(pt, iova, paddr, size, prot, gfp,
					 &mapped);
	else
		ret = __iommu_map_domain_pgtbl(domain, iova, paddr, size, prot,
					       gfp, &mapped);
       ...
   }

   Directly dereferencing domain->ops->map_pages and
   domain->ops->unmap_pages in __map_iommu() and __unmap_iommu() will
   dereference NULL on any IOMMU driver using generic_pt.

3. On arm-smmu, replacing iommu_unmap() (which uses struct
   iommu_iotlb_gather for range-targeted ARM_SMMU_CB_S1_TLBIVAL
   invalidations followed by iommu_iotlb_sync()) with
   domain->ops->unmap_pages(..., NULL) and iommu_flush_iotlb_all() forces a
   full ASID invalidation (ARM_SMMU_CB_S1_TLBIASID) on every unmap,
   evicting all TLB entries for active display scanout buffers and shared
   GPU mappings.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261027230452.130031-1-robin.clark@oss.qualcomm.com?part=4

  reply	other threads:[~2026-10-27 23:18 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-27 23:04 [PATCH v3 0/6] drm/msm: DMABUF_DEBUG fixes Rob Clark
2026-10-27 23:04 ` [PATCH v3 1/6] drm/msm: Cleanup if pages_to_sg() fails Rob Clark
2026-10-27 23:04 ` [PATCH v3 2/6] drm/msm/gem: dma_map/unmap_sgtable() Rob Clark
2026-10-27 23:24   ` sashiko-bot
2026-10-27 23:04 ` [PATCH v3 3/6] drm/msm: Extract out map/unmap helpers Rob Clark
2026-10-27 23:04 ` [PATCH v3 4/6] drm/msm: Convert iommu map/unmap to helpers Rob Clark
2026-10-27 23:18   ` sashiko-bot [this message]
2026-10-27 23:04 ` [PATCH v3 5/6] drm/msm: Convert map helper to use dma-address Rob Clark
2026-10-27 23:25   ` sashiko-bot
2026-10-28  1:14   ` Dmitry Baryshkov
2026-10-28  1:34     ` Rob Clark
2026-10-27 23:04 ` [PATCH v3 6/6] drm/msm: Treat !mapped as an error Rob Clark
2026-10-27 23:17   ` sashiko-bot

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=sashiko-outbox-187204@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=robin.clark@oss.qualcomm.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /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.