Offering: HULK 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 in the granual of the level 3 pagetable block size, this can greatly reduce the amounts of CMD_SYNC times sent to avoiding the errata. Detecting the hardware ability by read the SMMU_USER_CONFIG1.
Also, We don't have to send a tlbi before a CMD_SYNC, It will be OK for the hardware to merge the CMD_SYNC.
Signed-off-by: Zhang Zekun zhangzekun11@huawei.com --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 47 ++++++++++++++++----- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 ++ 2 files changed, 40 insertions(+), 10 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 87f9bed391ec..f62a685b9199 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -886,7 +886,9 @@ static int arm_smmu_ecmdq_issue_cmdlist(struct arm_smmu_device *smmu, } while (1);
/* 2. Write our commands into the queue */ - arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n); + if (cmds) + arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n); + if (sync) { u64 cmd_sync[CMDQ_ENT_DWORDS];
@@ -993,7 +995,8 @@ static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu, * 2. Write our commands into the queue * Dependency ordering from the cmpxchg() loop above. */ - arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n); + if (cmds) + arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n); if (sync) { prod = queue_inc_prod_n(&llq, n); arm_smmu_cmdq_build_sync_cmd(cmd_sync, smmu, &cmdq->q, prod); @@ -2730,16 +2733,21 @@ static int arm_smmu_iotlb_sync_map(struct iommu_domain *domain, unsigned long iova, size_t size) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - size_t granule_size; + struct arm_smmu_device *smmu = smmu_domain->smmu;
if (!(smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_MAP)) return 0;
- granule_size = 1 << __ffs(smmu_domain->domain.pgsize_bitmap); + if (smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_BATCH) { + int pg_shift;
- /* Add a SYNC command to sync io-pgtale to avoid errors in pgtable prefetch*/ - arm_smmu_tlb_inv_range_domain(iova, granule_size, granule_size, true, smmu_domain); + pg_shift = __ffs(smmu_domain->domain.pgsize_bitmap); + if (likely(iova % (1 << (2 * pg_shift - 3)))) + return 0; + }
+ /* Add a SYNC command to sync io-pgtale to avoid errors in pgtable prefetch*/ + arm_smmu_cmdq_issue_cmdlist(smmu, NULL, 0, true); return 0; } #endif @@ -4177,6 +4185,28 @@ static int arm_smmu_ecmdq_probe(struct arm_smmu_device *smmu) #define IIDR_PRODUCTID_ARM_MMU_600 0x483 #define IIDR_PRODUCTID_ARM_MMU_700 0x487
+#ifdef CONFIG_HISILICON_ERRATUM_162100602 +static void hisi_smmu_check_errata(struct arm_smmu_device *smmu, unsigned long variant, + unsigned long revision) +{ + u32 reg, i; + + if (!(variant == 0x3) || !(revision == 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++) { + if (!(reg && (GENMASK(1, 0) << 2 * i))) + return; + } + smmu->options |= ARM_SMMU_OPT_SYNC_BATCH; +} +#endif + + static void arm_smmu_device_iidr_probe(struct arm_smmu_device *smmu) { u32 reg; @@ -4211,10 +4241,7 @@ static void arm_smmu_device_iidr_probe(struct arm_smmu_device *smmu) }
#ifdef CONFIG_HISILICON_ERRATUM_162100602 - reg = readl_relaxed(smmu->base + ARM_SMMU_IIDR); - if (FIELD_GET(IIDR_VARIANT, reg) == 0x3 && - FIELD_GET(IIDR_REVISION, reg) == 0x2) - smmu->options |= ARM_SMMU_OPT_SYNC_MAP; + hisi_smmu_check_errata(smmu, variant, revision); #endif }
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