hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9G9TI
----------------------------------------
Benifiting from the hardware same address blocking mechanism. We only need to send the CMD_SYNC when creating pte entry other than lvl 3, this can reduce the amounts of CMD_SYNC times sent to avoiding the errata. Detecting the hardware ability by read the SMMU_USER_CONFIG1.
Fixes: 46f0c5798ba5 ("iommu/arm-smmu-v3: Enable iotlb_sync_map according to SMMU_IIDR") Signed-off-by: Zhang Zekun zhangzekun11@huawei.com --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 52 +++++++++++++++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 ++ drivers/iommu/io-pgtable-arm.c | 5 ++ 3 files changed, 60 insertions(+)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index 16217647fd67..6fa7b0b3e90c 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2203,6 +2203,14 @@ static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather, static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size, size_t granule, void *cookie) { +#ifdef CONFIG_HISILICON_ERRATUM_162100602 + struct arm_smmu_domain *smmu_domain = cookie; + + if (!size && smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_BATCH) { + arm_smmu_tlb_inv_range_domain(iova, granule, granule, true, cookie); + return; + } +#endif arm_smmu_tlb_inv_range_domain(iova, size, granule, false, cookie); }
@@ -2736,6 +2744,9 @@ static int arm_smmu_iotlb_sync_map(struct iommu_domain *domain, if (!(smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_MAP)) return 0;
+ if (smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_BATCH) + return 0; + granule_size = 1 << __ffs(smmu_domain->domain.pgsize_bitmap);
/* Add a SYNC command to sync io-pgtale to avoid errors in pgtable prefetch*/ @@ -4241,6 +4252,45 @@ static void arm_smmu_get_httu(struct arm_smmu_device *smmu, u32 reg) fw_features); }
+#ifdef CONFIG_HISILICON_ERRATUM_162100602 +static void hisi_smmu_check_errata(struct arm_smmu_device *smmu) +{ + u32 reg, i; + + if (!(smmu->options & ARM_SMMU_OPT_SYNC_MAP)) + return; + + smmu->options |= ARM_SMMU_OPT_SYNC_MAP; + + reg = readl_relaxed(smmu->base + ARM_SMMU_USER_CFG1); + reg = reg & GENMASK(15, 0); + for (i = 0; i < 8; i++) { + unsigned long val; + + val = (reg >> 2 * i) & GENMASK(1, 0); + switch (PAGE_SIZE) { + case SZ_4K: + if (!val) + return; + break; + case SZ_16K: + if (!val || val == 0x1) + return; + break; + case SZ_64K: + if (!val || val == 0x1 || val == 0x3) + return; + break; + default: + return; + } + } + smmu->options |= ARM_SMMU_OPT_SYNC_BATCH; +} +#else +static void hisi_smmu_check_errata(struct arm_smmu_device *smmu) {} +#endif + static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) { u32 reg; @@ -4455,6 +4505,8 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) smmu->oas = 48; }
+ hisi_smmu_check_errata(smmu); + if (arm_smmu_ops.pgsize_bitmap == -1UL) arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap; else diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 859d21729882..bc34d5a6aab9 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -139,6 +139,8 @@ #define ARM_SMMU_GERROR_IRQ_CFG1 0x70 #define ARM_SMMU_GERROR_IRQ_CFG2 0x74
+#define ARM_SMMU_USER_CFG1 0xe04 + #define ARM_SMMU_IDR6 0x190 #define IDR6_LOG2NUMP GENMASK(27, 24) #define IDR6_LOG2NUMQ GENMASK(19, 16) @@ -708,6 +710,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_MSIPOLL (1 << 2) #define ARM_SMMU_OPT_CMDQ_FORCE_SYNC (1 << 3) #define ARM_SMMU_OPT_SYNC_MAP (1 << 4) +#define ARM_SMMU_OPT_SYNC_BATCH (1 << 5) u32 options;
#ifdef CONFIG_ARM_SMMU_V3_ECMDQ diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 79aa11d88c56..fb54baed3f49 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -407,6 +407,11 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, pte = arm_lpae_install_table(cptep, ptep, 0, data); if (pte) __arm_lpae_free_pages(cptep, tblsz, cfg, data->iop.cookie); + +#ifdef CONFIG_HISILICON_ERRATUM_162100602 + if (lvl <= 2) + io_pgtable_tlb_flush_walk(&data->iop, iova, 0, ARM_LPAE_GRANULE(data)); +#endif } else if (!cfg->coherent_walk && !(pte & ARM_LPAE_PTE_SW_SYNC)) { __arm_lpae_sync_pte(ptep, 1, cfg); }