[PATCH] iommu/arm-smmu: disable PRR on some of SMMU-500 platforms
From: Dmitry Baryshkov <hidden>
Date: 2025-07-05 09:55:28
Also in:
linux-arm-msm, linux-iommu, lkml
Subsystem:
arm smmu drivers, iommu subsystem, qualcomm iommu, the rest · Maintainers:
Will Deacon, Joerg Roedel, Rob Clark, Linus Torvalds
On some of the platforms (e.g. SM8250 / QRB5165-RB5) using PRR bits
resets the device, most likely because of the hyp limitations. Disable
PRR support on that platform. Instead of adding more compatible checks,
set PRR-related callbacks through the match data, making it easier for
other platforms to apply the same workaround.
Fixes: 7f2ef1bfc758 ("iommu/arm-smmu: Add support for PRR bit setup")
Signed-off-by: Dmitry Baryshkov <redacted>
---
I currently don't have access to other devices from these generations.
It might be necessary to apply the same workaround to other platforms.
---
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 134 ++++++++++++++++++-----------
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h | 11 ++-
2 files changed, 91 insertions(+), 54 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 62874b18f6459ad9a8b0542ab81c24e3e745c53d..f1cb30cd99af6020a8b472f11d4999ad70d0bce0 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c@@ -55,6 +55,11 @@ static struct qcom_smmu *to_qcom_smmu(struct arm_smmu_device *smmu) return container_of(smmu, struct qcom_smmu, smmu); } +static const struct qcom_smmu_impl *to_qcom_smmu_impl(const struct arm_smmu_impl *base) +{ + return container_of(base, struct qcom_smmu_impl, base); +} + static void qcom_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, int sync, int status) {
@@ -313,9 +318,9 @@ static void qcom_smmu_set_actlr_dev(struct device *dev, struct arm_smmu_device * static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain, struct io_pgtable_cfg *pgtbl_cfg, struct device *dev) { - const struct device_node *np = smmu_domain->smmu->dev->of_node; struct arm_smmu_device *smmu = smmu_domain->smmu; struct qcom_smmu *qsmmu = to_qcom_smmu(smmu); + const struct qcom_smmu_impl *qsmmu_impl = to_qcom_smmu_impl(smmu->impl); const struct of_device_id *client_match; int cbndx = smmu_domain->cfg.cbndx; struct adreno_smmu_priv *priv;
@@ -351,14 +356,8 @@ static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain, priv->set_ttbr0_cfg = qcom_adreno_smmu_set_ttbr0_cfg; priv->get_fault_info = qcom_adreno_smmu_get_fault_info; priv->set_stall = qcom_adreno_smmu_set_stall; - priv->set_prr_bit = NULL; - priv->set_prr_addr = NULL; - - if (of_device_is_compatible(np, "qcom,smmu-500") && - of_device_is_compatible(np, "qcom,adreno-smmu")) { - priv->set_prr_bit = qcom_adreno_smmu_set_prr_bit; - priv->set_prr_addr = qcom_adreno_smmu_set_prr_addr; - } + priv->set_prr_bit = qsmmu_impl->set_prr_bit; + priv->set_prr_addr = qsmmu_impl->set_prr_addr; return 0; }
@@ -558,65 +557,89 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu) return ret; } -static const struct arm_smmu_impl qcom_smmu_v2_impl = { - .init_context = qcom_smmu_init_context, - .cfg_probe = qcom_smmu_cfg_probe, - .def_domain_type = qcom_smmu_def_domain_type, - .write_s2cr = qcom_smmu_write_s2cr, - .tlb_sync = qcom_smmu_tlb_sync, +static const struct qcom_smmu_impl qcom_smmu_v2_impl = { + .base = { + .init_context = qcom_smmu_init_context, + .cfg_probe = qcom_smmu_cfg_probe, + .def_domain_type = qcom_smmu_def_domain_type, + .write_s2cr = qcom_smmu_write_s2cr, + .tlb_sync = qcom_smmu_tlb_sync, + }, }; -static const struct arm_smmu_impl qcom_smmu_500_impl = { - .init_context = qcom_smmu_init_context, - .cfg_probe = qcom_smmu_cfg_probe, - .def_domain_type = qcom_smmu_def_domain_type, - .reset = arm_mmu500_reset, - .write_s2cr = qcom_smmu_write_s2cr, - .tlb_sync = qcom_smmu_tlb_sync, +static const struct qcom_smmu_impl qcom_smmu_500_impl = { + .base = { + .init_context = qcom_smmu_init_context, + .cfg_probe = qcom_smmu_cfg_probe, + .def_domain_type = qcom_smmu_def_domain_type, + .reset = arm_mmu500_reset, + .write_s2cr = qcom_smmu_write_s2cr, + .tlb_sync = qcom_smmu_tlb_sync, #ifdef CONFIG_ARM_SMMU_QCOM_DEBUG - .context_fault = qcom_smmu_context_fault, - .context_fault_needs_threaded_irq = true, + .context_fault = qcom_smmu_context_fault, + .context_fault_needs_threaded_irq = true, #endif + }, }; -static const struct arm_smmu_impl sdm845_smmu_500_impl = { - .init_context = qcom_smmu_init_context, - .cfg_probe = qcom_smmu_cfg_probe, - .def_domain_type = qcom_smmu_def_domain_type, - .reset = qcom_sdm845_smmu500_reset, - .write_s2cr = qcom_smmu_write_s2cr, - .tlb_sync = qcom_smmu_tlb_sync, +static const struct qcom_smmu_impl sdm845_smmu_500_impl = { + .base = { + .init_context = qcom_smmu_init_context, + .cfg_probe = qcom_smmu_cfg_probe, + .def_domain_type = qcom_smmu_def_domain_type, + .reset = qcom_sdm845_smmu500_reset, + .write_s2cr = qcom_smmu_write_s2cr, + .tlb_sync = qcom_smmu_tlb_sync, #ifdef CONFIG_ARM_SMMU_QCOM_DEBUG - .context_fault = qcom_smmu_context_fault, - .context_fault_needs_threaded_irq = true, + .context_fault = qcom_smmu_context_fault, + .context_fault_needs_threaded_irq = true, #endif + }, +}; + +static const struct qcom_smmu_impl qcom_adreno_smmu_v2_impl = { + .base = { + .init_context = qcom_adreno_smmu_init_context, + .cfg_probe = qcom_adreno_smmuv2_cfg_probe, + .def_domain_type = qcom_smmu_def_domain_type, + .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, + .write_sctlr = qcom_adreno_smmu_write_sctlr, + .tlb_sync = qcom_smmu_tlb_sync, + .context_fault_needs_threaded_irq = true, + }, }; -static const struct arm_smmu_impl qcom_adreno_smmu_v2_impl = { - .init_context = qcom_adreno_smmu_init_context, - .cfg_probe = qcom_adreno_smmuv2_cfg_probe, - .def_domain_type = qcom_smmu_def_domain_type, - .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, - .write_sctlr = qcom_adreno_smmu_write_sctlr, - .tlb_sync = qcom_smmu_tlb_sync, - .context_fault_needs_threaded_irq = true, +static const struct qcom_smmu_impl qcom_adreno_smmu_500_noprr_impl = { + .base = { + .init_context = qcom_adreno_smmu_init_context, + .def_domain_type = qcom_smmu_def_domain_type, + .reset = arm_mmu500_reset, + .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, + .write_sctlr = qcom_adreno_smmu_write_sctlr, + .tlb_sync = qcom_smmu_tlb_sync, + .context_fault_needs_threaded_irq = true, + }, }; -static const struct arm_smmu_impl qcom_adreno_smmu_500_impl = { - .init_context = qcom_adreno_smmu_init_context, - .def_domain_type = qcom_smmu_def_domain_type, - .reset = arm_mmu500_reset, - .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, - .write_sctlr = qcom_adreno_smmu_write_sctlr, - .tlb_sync = qcom_smmu_tlb_sync, - .context_fault_needs_threaded_irq = true, +static const struct qcom_smmu_impl qcom_adreno_smmu_500_impl = { + .base = { + .init_context = qcom_adreno_smmu_init_context, + .def_domain_type = qcom_smmu_def_domain_type, + .reset = arm_mmu500_reset, + .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank, + .write_sctlr = qcom_adreno_smmu_write_sctlr, + .tlb_sync = qcom_smmu_tlb_sync, + .context_fault_needs_threaded_irq = true, + }, + .set_prr_bit = qcom_adreno_smmu_set_prr_bit, + .set_prr_addr = qcom_adreno_smmu_set_prr_addr, }; static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, const struct qcom_smmu_match_data *data) { const struct device_node *np = smmu->dev->of_node; - const struct arm_smmu_impl *impl; + const struct qcom_smmu_impl *impl; struct qcom_smmu *qsmmu; if (!data)
@@ -639,7 +662,7 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, if (!qsmmu) return ERR_PTR(-ENOMEM); - qsmmu->smmu.impl = impl; + qsmmu->smmu.impl = &impl->base; qsmmu->data = data; return &qsmmu->smmu;
@@ -686,6 +709,13 @@ static const struct qcom_smmu_match_data qcom_smmu_500_impl0_data = { .client_match = qcom_smmu_actlr_client_of_match, }; +static const struct qcom_smmu_match_data qcom_smmu_500_impl0_noprr_data = { + .impl = &qcom_smmu_500_impl, + .adreno_impl = &qcom_adreno_smmu_500_noprr_impl, + .cfg = &qcom_smmu_impl0_cfg, + .client_match = qcom_smmu_actlr_client_of_match, +}; + /* * Do not add any more qcom,SOC-smmu-500 entries to this list, unless they need * special handling and can not be covered by the qcom,smmu-500 entry.
@@ -712,7 +742,7 @@ static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = { { .compatible = "qcom,sm6375-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm7150-smmu-v2", .data = &qcom_smmu_v2_data }, { .compatible = "qcom,sm8150-smmu-500", .data = &qcom_smmu_500_impl0_data }, - { .compatible = "qcom,sm8250-smmu-500", .data = &qcom_smmu_500_impl0_data }, + { .compatible = "qcom,sm8250-smmu-500", .data = &qcom_smmu_500_impl0_noprr_data }, { .compatible = "qcom,sm8350-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,sm8450-smmu-500", .data = &qcom_smmu_500_impl0_data }, { .compatible = "qcom,smmu-500", .data = &qcom_smmu_500_impl0_data },
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
index 8addd453f5f1c9659fbfbc68a84a3ab1267b356e..e805ad604339463b706a43e359ccca657d42a602 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h@@ -24,10 +24,17 @@ struct qcom_smmu_config { const u32 *reg_offset; }; +struct qcom_smmu_impl { + struct arm_smmu_impl base; + + void (*set_prr_bit)(const void *cookie, bool set); + void (*set_prr_addr)(const void *cookie, phys_addr_t page_addr); +}; + struct qcom_smmu_match_data { const struct qcom_smmu_config *cfg; - const struct arm_smmu_impl *impl; - const struct arm_smmu_impl *adreno_impl; + const struct qcom_smmu_impl *impl; + const struct qcom_smmu_impl *adreno_impl; const struct of_device_id * const client_match; };
--- base-commit: 7244e36657076b597ac21d118be9c0b0f15fc622 change-id: 20250705-iommu-fix-prr-600451b1d304 Best regards, -- With best wishes Dmitry