[PATCH 05/12] iommu: qcom_iommu: handle the SMMU global register space
Dmitry Baryshkov <[email protected]>
| Newsgroups | dev.linux.lists.iommu,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260809-msm8974-iommu-upstream-v1-5-87f5cd492560@oss.qualcomm.com> |
On msm8974 the OS has to access the SMMU global register space: the non-secured instances need it fully programmed and even the TZ-managed ones expose OS-writable implementation-defined registers in it. The driver only knows about the msm8916-style "SMMU local" region in resource 0, and has no accessors for the global space. For instances with a per-instance configuration, treat resource 0 as the global register space and require it. Never perform the SMMU_INTR_SEL_NS write on such instances - offset 0x2000 from the global base is the implementation-defined MICRO_MMU_CTRL halt request register on this IP, not the interrupt select of the separate msm8916-style local region. Provide gr0/gr1 accessors for the following changes. Do not clear the FSR of the context banks at probe time on such instances either: they sit in MMSS power domains which may well be off at that point, and an access to an unpowered register block stalls the bus. Skipping the clear is safe and preferable to powering the domain up for it. Safe, because a collapsed context bank has no active logic: it can neither latch a fault nor assert its interrupt, so the window the probe-time clear protects against on msm8916 does not exist while the domain is off, and the first runtime resume fully reprograms the context bank - including the FSR - before translation is enabled, so any fault state the bootloader left behind is wiped before it could matter. Preferable, because taking a runtime PM reference just for the clear would be a power cycle with no lasting effect (the cleared state is lost again when the domain collapses after the put), and the get/put pair is actively harmful for the MDP instance: at IOMMU probe time the display is still scanning out from bootloader-configured state with no kernel driver holding the MDSS GDSC, so the final put would power the scanout domain off mid-boot. The same treatment already exists for the TZ-secured contexts, which skip the clear for banks the OS cannot reach. Assisted-by: Claude:claude-fable-5 Signed-off-by: Dmitry Baryshkov <[email protected]> --- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 44 +++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c index 77c01f217d7e..428b18697244 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -34,6 +34,9 @@ #define SMMU_INTR_SEL_NS 0x2000 +/* GR1 sits one 4K page above GR0 on the msm8974 QSMMU */ +#define QCOM_IOMMU_GR1 0x1000 + enum qcom_iommu_clk { CLK_IFACE, CLK_BUS, @@ -57,6 +60,7 @@ struct qcom_iommu_dev { const struct qcom_iommu_cfg *cfg; struct clk_bulk_data clks[CLK_NUM]; void __iomem *local_base; + void __iomem *global_base; u32 sec_id; u8 max_asid; struct qcom_iommu_ctx *ctxs[]; /* indexed by asid */ @@ -130,6 +134,26 @@ iommu_readq(struct qcom_iommu_ctx *ctx, unsigned reg) return readq_relaxed(ctx->base + reg); } +static inline void +qcom_iommu_gr0_write(struct qcom_iommu_dev *qcom_iommu, unsigned int reg, + u32 val) +{ + writel_relaxed(val, qcom_iommu->global_base + reg); +} + +static inline u32 +qcom_iommu_gr0_read(struct qcom_iommu_dev *qcom_iommu, unsigned int reg) +{ + return readl_relaxed(qcom_iommu->global_base + reg); +} + +static inline void +qcom_iommu_gr1_write(struct qcom_iommu_dev *qcom_iommu, unsigned int reg, + u32 val) +{ + writel_relaxed(val, qcom_iommu->global_base + QCOM_IOMMU_GR1 + reg); +} + static void qcom_iommu_tlb_sync(void *cookie) { struct qcom_iommu_domain *qcom_domain = cookie; @@ -749,9 +773,10 @@ static int qcom_iommu_ctx_probe(struct platform_device *pdev) ctx->secured_ctx = true; /* clear IRQs before registering fault handler, just in case the - * boot-loader left us a surprise: + * boot-loader left us a surprise. Instances with a power domain + * may not be accessible yet; they are reset at first resume. */ - if (!ctx->secured_ctx) { + if (!ctx->secured_ctx && !qcom_iommu->cfg) { ret = pm_runtime_resume_and_get(dev->parent); if (ret) return ret; @@ -845,9 +870,18 @@ static int qcom_iommu_device_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) { - qcom_iommu->local_base = devm_ioremap_resource(dev, res); - if (IS_ERR(qcom_iommu->local_base)) - return PTR_ERR(qcom_iommu->local_base); + if (qcom_iommu->cfg) { + qcom_iommu->global_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qcom_iommu->global_base)) + return PTR_ERR(qcom_iommu->global_base); + } else { + qcom_iommu->local_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qcom_iommu->local_base)) + return PTR_ERR(qcom_iommu->local_base); + } + } else if (qcom_iommu->cfg) { + return dev_err_probe(dev, -EINVAL, + "missing global register space\n"); } clk = devm_clk_get(dev, "iface"); -- 2.47.3