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 16217647fd6717bc4602399c04145dd6b84c2a8d..6fa7b0b3e90cf56f05463f042f54366f44ea7b55 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 859d2172988251042645b9cd107c141e0e7e7e47..bc34d5a6aab976342d586110220bfb44486e5b3a 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 79aa11d88c565523b57d7e8798400095849c0dcd..fb54baed3f49f67ba9e2c103019bcff31e967d5e 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); }