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 --- v2: - Add Fixes tag
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 57 +++++++++++++++++++-- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 ++ drivers/iommu/io-pgtable-arm.c | 4 ++ 3 files changed, 59 insertions(+), 5 deletions(-)
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 423a54b7611d..7c818a17ca11 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2309,6 +2309,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); }
@@ -2951,6 +2959,9 @@ static void arm_smmu_iotlb_sync_map(struct iommu_domain *domain, if (!(smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_MAP)) return;
+ if (smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_BATCH) + return; + granule_size = 1 << __ffs(smmu_domain->domain.pgsize_bitmap);
/* Add a SYNC command to sync io-pgtale to avoid errors in pgtable prefetch*/ @@ -4932,6 +4943,46 @@ 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; + + /* IIDR */ + reg = readl_relaxed(smmu->base + ARM_SMMU_IIDR); + if (!(FIELD_GET(IIDR_VARIANT, reg) == 0x3) || + !(FIELD_GET(IIDR_REVISON, reg) == 0x2)) + 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; +} +#endif + static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) { u32 reg; @@ -5163,11 +5214,7 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) }
#ifdef CONFIG_HISILICON_ERRATUM_162100602 - /* IIDR */ - reg = readl_relaxed(smmu->base + ARM_SMMU_IIDR); - if (FIELD_GET(IIDR_VARIANT, reg) == 0x3 && - FIELD_GET(IIDR_REVISON, reg) == 0x2) - smmu->options |= ARM_SMMU_OPT_SYNC_MAP; + hisi_smmu_check_errata(smmu); #endif
if (arm_smmu_ops.pgsize_bitmap == -1UL) 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 776d326de105..ece2904fd728 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -175,6 +175,8 @@ #define ARM_SMMU_USER_CFG0 0xe00 #define ARM_SMMU_USER_MPAM_EN (1UL << 30)
+#define ARM_SMMU_USER_CFG1 0xe04 + #define ARM_SMMU_IDR6 0x190 #define IDR6_LOG2NUMP GENMASK(27, 24) #define IDR6_LOG2NUMQ GENMASK(19, 16) @@ -717,6 +719,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_PAGE0_REGS_ONLY (1 << 1) #define ARM_SMMU_OPT_MSIPOLL (1 << 2) #define ARM_SMMU_OPT_SYNC_MAP (1 << 3) +#define ARM_SMMU_OPT_SYNC_BATCH (1 << 4) u32 options;
union { diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 3fc6ae00dc96..dc80f2661ff7 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -364,6 +364,10 @@ 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); +#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, cfg); }