arm64: errata: Hide CTR_EL0.DIC on systems affected by Neoverse-N1 #1542419
authorJames Morse <james.morse@arm.com>
Thu, 17 Oct 2019 17:42:58 +0000 (18:42 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 25 Oct 2019 16:46:40 +0000 (17:46 +0100)
Cores affected by Neoverse-N1 #1542419 could execute a stale instruction
when a branch is updated to point to freshly generated instructions.

To workaround this issue we need user-space to issue unnecessary
icache maintenance that we can trap. Start by hiding CTR_EL0.DIC.

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Documentation/arm64/silicon-errata.rst
arch/arm64/Kconfig
arch/arm64/include/asm/cpucaps.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/traps.c

index 17ea3fe..d0d480d 100644 (file)
@@ -88,6 +88,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | ARM            | Neoverse-N1     | #1349291        | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| ARM            | Neoverse-N1     | #1542419        | ARM64_ERRATUM_1542419       |
++----------------+-----------------+-----------------+-----------------------------+
 | ARM            | MMU-500         | #841119,826419  | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
 +----------------+-----------------+-----------------+-----------------------------+
index 950a56b..7c3e3e3 100644 (file)
@@ -558,6 +558,22 @@ config ARM64_ERRATUM_1463225
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_1542419
+       bool "Neoverse-N1: workaround mis-ordering of instruction fetches"
+       default y
+       help
+         This option adds a workaround for ARM Neoverse-N1 erratum
+         1542419.
+
+         Affected Neoverse-N1 cores could execute a stale instruction when
+         modified by another CPU. The workaround depends on a firmware
+         counterpart.
+
+         Workaround the issue by hiding the DIC feature from EL0. This
+         forces user-space to perform cache maintenance.
+
+         If unsure, say Y.
+
 config CAVIUM_ERRATUM_22375
        bool "Cavium erratum 22375, 24313"
        default y
index f19fe4b..f05afae 100644 (file)
@@ -52,7 +52,8 @@
 #define ARM64_HAS_IRQ_PRIO_MASKING             42
 #define ARM64_HAS_DCPODP                       43
 #define ARM64_WORKAROUND_1463225               44
+#define ARM64_WORKAROUND_1542419               45
 
-#define ARM64_NCAPS                            45
+#define ARM64_NCAPS                            46
 
 #endif /* __ASM_CPUCAPS_H */
index f593f4c..3ae9b78 100644 (file)
@@ -87,13 +87,21 @@ has_mismatched_cache_type(const struct arm64_cpu_capabilities *entry,
 }
 
 static void
-cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *__unused)
+cpu_enable_trap_ctr_access(const struct arm64_cpu_capabilities *cap)
 {
        u64 mask = arm64_ftr_reg_ctrel0.strict_mask;
+       bool enable_uct_trap = false;
 
        /* Trap CTR_EL0 access on this CPU, only if it has a mismatch */
        if ((read_cpuid_cachetype() & mask) !=
            (arm64_ftr_reg_ctrel0.sys_val & mask))
+               enable_uct_trap = true;
+
+       /* ... or if the system is affected by an erratum */
+       if (cap->capability == ARM64_WORKAROUND_1542419)
+               enable_uct_trap = true;
+
+       if (enable_uct_trap)
                sysreg_clear_set(sctlr_el1, SCTLR_EL1_UCT, 0);
 }
 
@@ -623,6 +631,18 @@ check_branch_predictor(const struct arm64_cpu_capabilities *entry, int scope)
        return (need_wa > 0);
 }
 
+static bool __maybe_unused
+has_neoverse_n1_erratum_1542419(const struct arm64_cpu_capabilities *entry,
+                               int scope)
+{
+       u32 midr = read_cpuid_id();
+       bool has_dic = read_cpuid_cachetype() & BIT(CTR_DIC_SHIFT);
+       const struct midr_range range = MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1);
+
+       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+       return is_midr_in_range(midr, &range) && has_dic;
+}
+
 #ifdef CONFIG_HARDEN_EL2_VECTORS
 
 static const struct midr_range arm64_harden_el2_vectors[] = {
@@ -851,6 +871,16 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
                .matches = has_cortex_a76_erratum_1463225,
        },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_1542419
+       {
+               /* we depend on the firmware portion for correctness */
+               .desc = "ARM erratum 1542419 (kernel portion)",
+               .capability = ARM64_WORKAROUND_1542419,
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+               .matches = has_neoverse_n1_erratum_1542419,
+               .cpu_enable = cpu_enable_trap_ctr_access,
+       },
 #endif
        {
        }
index 34739e8..465f0a0 100644 (file)
@@ -470,6 +470,9 @@ static void ctr_read_handler(unsigned int esr, struct pt_regs *regs)
        int rt = ESR_ELx_SYS64_ISS_RT(esr);
        unsigned long val = arm64_ftr_reg_user_value(&arm64_ftr_reg_ctrel0);
 
+       if (cpus_have_const_cap(ARM64_WORKAROUND_1542419))
+               val &= ~BIT(CTR_DIC_SHIFT);
+
        pt_regs_write_reg(regs, rt, val);
 
        arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);