arm64: Fake the IminLine size on systems affected by Neoverse-N1 #1542419
authorJames Morse <james.morse@arm.com>
Thu, 17 Oct 2019 17:42:59 +0000 (18:42 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 25 Oct 2019 16:48:44 +0000 (17:48 +0100)
Systems affected by Neoverse-N1 #1542419 support DIC so do not need to
perform icache maintenance once new instructions are cleaned to the PoU.
For the errata workaround, the kernel hides DIC from user-space, so that
the unnecessary cache maintenance can be trapped by firmware.

To reduce the number of traps, produce a fake IminLine value based on
PAGE_SIZE.

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

index 43da6dd..806e9dc 100644 (file)
@@ -11,6 +11,7 @@
 #define CTR_L1IP_MASK          3
 #define CTR_DMINLINE_SHIFT     16
 #define CTR_IMINLINE_SHIFT     0
+#define CTR_IMINLINE_MASK      0xf
 #define CTR_ERG_SHIFT          20
 #define CTR_CWG_SHIFT          24
 #define CTR_CWG_MASK           15
@@ -18,7 +19,7 @@
 #define CTR_DIC_SHIFT          29
 
 #define CTR_CACHE_MINLINE_MASK \
-       (0xf << CTR_DMINLINE_SHIFT | 0xf << CTR_IMINLINE_SHIFT)
+       (0xf << CTR_DMINLINE_SHIFT | CTR_IMINLINE_MASK << CTR_IMINLINE_SHIFT)
 
 #define CTR_L1IP(ctr)          (((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK)
 
index 465f0a0..4e3e9d9 100644 (file)
@@ -470,9 +470,15 @@ 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))
+       if (cpus_have_const_cap(ARM64_WORKAROUND_1542419)) {
+               /* Hide DIC so that we can trap the unnecessary maintenance...*/
                val &= ~BIT(CTR_DIC_SHIFT);
 
+               /* ... and fake IminLine to reduce the number of traps. */
+               val &= ~CTR_IMINLINE_MASK;
+               val |= (PAGE_SHIFT - 2) & CTR_IMINLINE_MASK;
+       }
+
        pt_regs_write_reg(regs, rt, val);
 
        arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);