From: sashiko-bot@kernel.org
To: "Rob Clark" <robin.clark@oss.qualcomm.com>,
dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v4 4/6] drm/msm: Convert iommu map/unmap to helpers
Date: Fri, 30 Oct 2026 21:49:52 +0000 [thread overview]
Message-ID: <sashiko-outbox-191553@kernel.org> (raw)
In-Reply-To: <20261030213251.55365-5-robin.clark@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 3 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()
- [Low] drm/msm: build failure in __map_iommu() when !CONFIG_IOMMU_API
--
commit e0c13e8fe949f41860b8d6b287a4884b707293a0
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() to use the
internal __do_map() and __do_unmap() helpers with callbacks that invoke
iommu_domain_ops directly instead of calling iommu_map_sgtable() and
iommu_unmap().
> 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);
> +}
[Severity: Low]
Does dereferencing domain->ops in __unmap_iommu() and __map_iommu() break the
build when CONFIG_IOMMU_API is disabled?
In drivers/gpu/drm/msm/Kconfig, DRM_MSM depends on IOMMU_SUPPORT and selects
IOMMU_IO_PGTABLE, neither of which selects CONFIG_IOMMU_API. In
include/linux/iommu.h, struct iommu_domain_ops is only forward-declared when
CONFIG_IOMMU_API is not enabled, so dereferencing domain->ops->unmap_pages and
domain->ops->map_pages fails to compile with an incomplete type error under
SOC_IMX5 or COMPILE_TEST configurations without an IOMMU driver that selects
CONFIG_IOMMU_API.
> +
> +static void
> +__flush_iommu(void *arg)
> +{
> + struct iommu_domain *domain = arg;
> + iommu_flush_iotlb_all(domain);
> +}
[Severity: Critical]
As reported by Sashiko on v3 [1], does passing NULL for the gather parameter
in __unmap_iommu() followed by iommu_flush_iotlb_all() in __flush_iommu() skip
hardware IOTLB invalidation completely on platforms using qcom_iommu?
When msm_iommu_unmap() (or the error rollback path in msm_iommu_map() ->
__do_map()) calls __do_unmap(), __unmap_iommu() calls
domain->ops->unmap_pages(domain, iova, pgsize, pgcount, NULL).
On SoCs using drivers/iommu/arm/arm-smmu/qcom_iommu.c (such as MSM8916,
MSM8953, and MSM8976 with Adreno A3xx/A4xx/A5xx and MDP5),
qcom_iommu_init_domain() uses the ARM_32_LPAE_S1 page table format in
drivers/iommu/io-pgtable-arm.c. In __arm_lpae_unmap(), per-page TLB
invalidation via io_pgtable_tlb_add_page() -> qcom_iommu_tlb_add_page()
(which writes ARM_SMMU_CB_S1_TLBIVAL) is skipped when gather is NULL:
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);
...
}
When __do_unmap() then finishes by calling __flush_iommu() ->
iommu_flush_iotlb_all(domain), qcom_iommu_flush_iotlb_all() only issues a
TLBSYNC barrier without invalidating the context bank by ASID:
drivers/iommu/arm/arm-smmu/qcom_iommu.c:qcom_iommu_flush_iotlb_all() {
...
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, neither ARM_SMMU_CB_S1_TLBIVAL nor ARM_SMMU_CB_S1_TLBIASID is
written during unmap, leaving stale TLB entries pointing to unmapped and freed
GEM buffer pages accessible to GPU and display DMA.
> +
> +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]
As reported by Sashiko on v3 [2], can bypassing the core IOMMU API in
msm_iommu_map() and msm_iommu_unmap() cause missing IOTLB synchronization on
map as well as regressions with arm-smmu and generic_pt domains?
First, replacing iommu_map_sgtable() with __do_map() -> __map_iommu() ->
domain->ops->map_pages() never calls iommu_sync_map()
(domain->ops->iotlb_sync_map) after mapping pages. On APQ8064/MSM8960
(drivers/iommu/msm_iommu.c, used with MDP4 and Adreno 320),
msm_iommu_ops.default_domain_ops relies on .iotlb_sync_map =
msm_iommu_sync_map to flush the IOTLB range via __flush_iotlb_range() after
mapping and leaves .flush_iotlb_all as NULL.
Second, on arm-smmu, iommu_unmap() previously used struct iommu_iotlb_gather
to perform VA-targeted leaf invalidations (ARM_SMMU_CB_S1_TLBIVAL) followed by
iommu_iotlb_sync(). Calling domain->ops->unmap_pages() with a NULL gather
followed by 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 GPU mappings sharing the ASID.
Third, in drivers/iommu/iommu.c (iommu_map_nosync() and __iommu_unmap()),
domains converted to the generic page table library (domain->is_iommupt) use
pt->ops->map_range and unmap_range and leave domain->ops->map_pages and
unmap_pages as NULL, while core wrappers also handle iommu_debug_map() /
iommu_debug_unmap_begin() and IOMMU tracepoints.
[1] https://lore.kernel.org/r/20261027230452.130031-5-robin.clark@oss.qualcomm.com
[2] https://lore.kernel.org/r/20261027230452.130031-5-robin.clark@oss.qualcomm.com
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261030213251.55365-1-robin.clark@oss.qualcomm.com?part=4
next prev parent reply other threads:[~2026-10-30 21:50 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 21:32 [PATCH v4 0/6] drm/msm: DMABUF_DEBUG fixes Rob Clark
2026-10-30 21:32 ` [PATCH v4 1/6] drm/msm: Cleanup if pages_to_sg() fails Rob Clark
2026-10-30 21:32 ` [PATCH v4 2/6] drm/msm/gem: dma_map/unmap_sgtable() Rob Clark
2026-10-30 21:46 ` sashiko-bot
2026-10-30 21:32 ` [PATCH v4 3/6] drm/msm: Extract out map/unmap helpers Rob Clark
2026-10-30 21:32 ` [PATCH v4 4/6] drm/msm: Convert iommu map/unmap to helpers Rob Clark
2026-10-30 21:49 ` sashiko-bot [this message]
2026-10-30 21:32 ` [PATCH v4 5/6] drm/msm: Convert map helper to use dma-address Rob Clark
2026-10-30 21:57 ` sashiko-bot
2026-10-30 21:32 ` [PATCH v4 6/6] drm/msm: Treat !mapped as an error Rob Clark
2026-10-30 21:54 ` 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-191553@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.