[PATCH v2 2/3] iommu/msm: use the IOMMU device for page table allocation
Dmitry Baryshkov
dmitry.baryshkov at oss.qualcomm.com
Thu Jul 30 09:04:55 PDT 2026
io_pgtable_cfg.iommu_dev is "the device representing the DMA
configuration for the page table walker": io-pgtable-arm-v7s hands it to
the DMA API to allocate and sync the tables on behalf of the IOMMU's
table walker. msm_iommu_attach_dev() instead stores the client device in
priv->dev and passes that, so every page table is allocated and synced
through the DMA configuration of the device being attached rather than
through the IOMMU's own.
That is wrong on its own terms, and on ARM32 with
CONFIG_ARM_DMA_USE_IOMMU it is fatal. The client device carries a
dma_iommu_mapping, so the tables are mapped and unmapped through the very
IOMMU they describe. The mapping happens while the device still has the
direct DMA ops installed, because arm_iommu_attach_device() only swaps in
the IOMMU-aware ops after iommu_attach_device() has returned, so
dma_handle ends up being the physical address. By the time the tables are
freed the IOMMU-aware ops are in place and treat that physical address as
an IOVA: iommu_unmap() warns "region not mapped" and __free_iova() clears
bits in an unallocated bitmap extension, dereferencing NULL:
__bitmap_clear from arm_iommu_unmap_phys
arm_iommu_unmap_phys from dma_unmap_phys
dma_unmap_phys from __arm_v7s_free_table
__arm_v7s_free_table from arm_v7s_free_pgtable
arm_v7s_free_pgtable from msm_iommu_identity_attach
msm_iommu_identity_attach from __iommu_attach_device
__iommu_attach_device from iommu_detach_device
iommu_detach_device from arm_iommu_detach_device
arm_iommu_detach_device from arch_teardown_dma_ops
arch_teardown_dma_ops from device_unbind_cleanup
This is reached on apq8064 (ifc6410) when the adreno GPU probe fails and
its DMA ops are torn down.
Locate the IOMMU instance before configuring the domain and pass its
struct device to io-pgtable. priv->dev has no other user, so drop it.
Fixes: c9220fbd7741 ("iommu/msm: use generic ARMV7S short descriptor pagetable ops")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Assisted-by: Claude:claude-opus-5
---
drivers/iommu/msm_iommu.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 109688d69e50..15220d79ece3 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -42,7 +42,6 @@ struct msm_priv {
struct iommu_domain domain;
struct io_pgtable_cfg cfg;
struct io_pgtable_ops *iop;
- struct device *dev;
spinlock_t pgtlock; /* pagetable lock */
};
@@ -336,7 +335,8 @@ static void msm_iommu_domain_free(struct iommu_domain *domain)
spin_unlock_irqrestore(&msm_iommu_lock, flags);
}
-static int msm_iommu_domain_config(struct msm_priv *priv)
+static int msm_iommu_domain_config(struct msm_priv *priv,
+ struct msm_iommu_dev *iommu)
{
spin_lock_init(&priv->pgtlock);
@@ -345,12 +345,12 @@ static int msm_iommu_domain_config(struct msm_priv *priv)
.ias = 32,
.oas = 32,
.tlb = &msm_iommu_flush_ops,
- .iommu_dev = priv->dev,
+ .iommu_dev = iommu->dev,
};
priv->iop = alloc_io_pgtable_ops(ARM_V7S, &priv->cfg, priv);
if (!priv->iop) {
- dev_err(priv->dev, "Failed to allocate pgtable\n");
+ dev_err(iommu->dev, "Failed to allocate pgtable\n");
return -EINVAL;
}
@@ -400,8 +400,15 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev,
struct msm_priv *priv = to_msm_priv(domain);
struct msm_iommu_ctx_dev *master;
- priv->dev = dev;
- msm_iommu_domain_config(priv);
+ spin_lock_irqsave(&msm_iommu_lock, flags);
+ iommu = find_iommu_for_dev(dev);
+ spin_unlock_irqrestore(&msm_iommu_lock, flags);
+ if (!iommu)
+ return -ENODEV;
+
+ ret = msm_iommu_domain_config(priv, iommu);
+ if (ret)
+ return ret;
spin_lock_irqsave(&msm_iommu_lock, flags);
list_for_each_entry(iommu, &qcom_iommu_devices, dev_node) {
--
2.47.3
More information about the Linux-rockchip
mailing list