Add a special implementation for the SMMU attached to most Adreno GPU target triggered from the qcom,adreno-gpu-smmu compatible string. When selected the driver will attempt to enable split pagetables. Signed-off-by: Jordan Crouse <jcrouse@xxxxxxxxxxxxxx> --- drivers/iommu/arm-smmu-impl.c | 5 ++++- drivers/iommu/arm-smmu-qcom.c | 38 +++++++++++++++++++++++++++++++++-- drivers/iommu/arm-smmu.c | 2 +- drivers/iommu/arm-smmu.h | 3 ++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c index a20e426d81ac..3bb1ef4e85f7 100644 --- a/drivers/iommu/arm-smmu-impl.c +++ b/drivers/iommu/arm-smmu-impl.c @@ -69,7 +69,7 @@ static int cavium_cfg_probe(struct arm_smmu_device *smmu) } static int cavium_init_context(struct arm_smmu_domain *smmu_domain, - struct io_pgtable_cfg *pgtbl_cfg) + struct io_pgtable_cfg *pgtbl_cfg, struct device *dev) { struct cavium_smmu *cs = container_of(smmu_domain->smmu, struct cavium_smmu, smmu); @@ -176,5 +176,8 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu) of_device_is_compatible(np, "qcom,sc7180-smmu-500")) return qcom_smmu_impl_init(smmu); + if (of_device_is_compatible(smmu->dev->of_node, "qcom,adreno-smmu")) + return qcom_adreno_smmu_impl_init(smmu); + return smmu; } diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c index be4318044f96..cc03f94fa458 100644 --- a/drivers/iommu/arm-smmu-qcom.c +++ b/drivers/iommu/arm-smmu-qcom.c @@ -12,6 +12,22 @@ struct qcom_smmu { struct arm_smmu_device smmu; }; +static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain, + struct io_pgtable_cfg *pgtbl_cfg, struct device *dev) +{ + /* + * All targets that use the qcom,adreno-smmu compatible string *should* + * be AARCH64 stage 1 but double check because the arm-smmu code assumes + * that is the case when the TTBR1 quirk is enabled + */ + if (of_device_is_compatible(dev->of_node, "qcom,adreno") && + (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) && + (smmu_domain->cfg.fmt == ARM_SMMU_CTX_FMT_AARCH64)) + pgtbl_cfg->quirks |= IO_PGTABLE_QUIRK_ARM_TTBR1; + + return 0; +} + static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = { { .compatible = "qcom,adreno" }, { .compatible = "qcom,mdp4" }, @@ -65,7 +81,15 @@ static const struct arm_smmu_impl qcom_smmu_impl = { .reset = qcom_smmu500_reset, }; -struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) +static const struct arm_smmu_impl qcom_adreno_smmu_impl = { + .init_context = qcom_adreno_smmu_init_context, + .def_domain_type = qcom_smmu_def_domain_type, + .reset = qcom_smmu500_reset, +}; + + +static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu, + const struct arm_smmu_impl *impl) { struct qcom_smmu *qsmmu; @@ -75,8 +99,18 @@ struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) qsmmu->smmu = *smmu; - qsmmu->smmu.impl = &qcom_smmu_impl; + qsmmu->smmu.impl = impl; devm_kfree(smmu->dev, smmu); return &qsmmu->smmu; } + +struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu) +{ + return qcom_smmu_create(smmu, &qcom_smmu_impl); +} + +struct arm_smmu_device *qcom_adreno_smmu_impl_init(struct arm_smmu_device *smmu) +{ + return qcom_smmu_create(smmu, &qcom_adreno_smmu_impl); +} diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 048de2681670..f14dc4ecb422 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -812,7 +812,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, }; if (smmu->impl && smmu->impl->init_context) { - ret = smmu->impl->init_context(smmu_domain, &pgtbl_cfg); + ret = smmu->impl->init_context(smmu_domain, &pgtbl_cfg, dev); if (ret) goto out_unlock; } diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h index 5f2de20e883b..df70d410f77d 100644 --- a/drivers/iommu/arm-smmu.h +++ b/drivers/iommu/arm-smmu.h @@ -397,7 +397,7 @@ struct arm_smmu_impl { int (*cfg_probe)(struct arm_smmu_device *smmu); int (*reset)(struct arm_smmu_device *smmu); int (*init_context)(struct arm_smmu_domain *smmu_domain, - struct io_pgtable_cfg *cfg); + struct io_pgtable_cfg *cfg, struct device *dev); void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync, int status); int (*def_domain_type)(struct device *dev); @@ -465,6 +465,7 @@ static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page, struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu); struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu); +struct arm_smmu_device *qcom_adreno_smmu_impl_init(struct arm_smmu_device *smmu); int arm_mmu500_reset(struct arm_smmu_device *smmu); -- 2.17.1