riscv: sifive: Apply errata "cip-1200" patch
authorVincent Chen <vincent.chen@sifive.com>
Mon, 22 Mar 2021 14:26:06 +0000 (22:26 +0800)
committerPalmer Dabbelt <palmerdabbelt@google.com>
Mon, 26 Apr 2021 15:24:58 +0000 (08:24 -0700)
For certain SiFive CPUs, "sfence.vma addr" cannot exactly flush addr
from TLB in the particular cases. The details could be found here:
https://sifive.cdn.prismic.io/sifive/167a1a56-03f4-4615-a79e-b2a86153148f_FU740_errata_20210205.pdf
In order to ensure the functionality, this patch uses the Alternative
scheme to replace all "sfence.vma addr" with "sfence.vma" at runtime.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
arch/riscv/Kconfig.erratas
arch/riscv/errata/sifive/errata.c
arch/riscv/include/asm/errata_list.h
arch/riscv/include/asm/tlbflush.h

index b4146dc..d5d03ae 100644 (file)
@@ -30,4 +30,15 @@ config ERRATA_SIFIVE_CIP_453
 
          If you don't know what to do here, say "Y".
 
+config ERRATA_SIFIVE_CIP_1200
+       bool "Apply SiFive errata CIP-1200"
+       depends on ERRATA_SIFIVE
+       default y
+       help
+         This will apply the SiFive CIP-1200 errata to repalce all
+         "sfence.vma addr" with "sfence.vma" to ensure that the addr
+         has been flushed from TLB.
+
+         If you don't know what to do here, say "Y".
+
 endmenu
index e273918..f5e5ae7 100644 (file)
@@ -29,11 +29,29 @@ static bool errata_cip_453_check_func(unsigned long  arch_id, unsigned long impi
        return true;
 }
 
+static bool errata_cip_1200_check_func(unsigned long  arch_id, unsigned long impid)
+{
+       /*
+        * Affected cores:
+        * Architecture ID: 0x8000000000000007 or 0x1
+        * Implement ID: mimpid[23:0] <= 0x200630 and mimpid != 0x01200626
+        */
+       if (arch_id != 0x8000000000000007 && arch_id != 0x1)
+               return false;
+       if ((impid & 0xffffff) > 0x200630 || impid == 0x1200626)
+               return false;
+       return true;
+}
+
 static struct errata_info_t errata_list[ERRATA_SIFIVE_NUMBER] = {
        {
                .name = "cip-453",
                .check_func = errata_cip_453_check_func
        },
+       {
+               .name = "cip-1200",
+               .check_func = errata_cip_1200_check_func
+       },
 };
 
 static u32 __init sifive_errata_probe(unsigned long archid, unsigned long impid)
index 6148d34..5f1046e 100644 (file)
@@ -10,7 +10,8 @@
 
 #ifdef CONFIG_ERRATA_SIFIVE
 #define        ERRATA_SIFIVE_CIP_453 0
-#define        ERRATA_SIFIVE_NUMBER 1
+#define        ERRATA_SIFIVE_CIP_1200 1
+#define        ERRATA_SIFIVE_NUMBER 2
 #endif
 
 #ifdef __ASSEMBLY__
@@ -26,6 +27,13 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault),                    \
            __stringify(RISCV_PTR sifive_cip_453_page_fault_trp),       \
            SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453,                    \
            CONFIG_ERRATA_SIFIVE_CIP_453)
+#else /* !__ASSEMBLY__ */
+
+#define ALT_FLUSH_TLB_PAGE(x)                                          \
+asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID,       \
+               ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200)  \
+               : : "r" (addr) : "memory")
+
 #endif /* __ASSEMBLY__ */
 
 #endif
index 394cfbc..c84218a 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/mm_types.h>
 #include <asm/smp.h>
+#include <asm/errata_list.h>
 
 #ifdef CONFIG_MMU
 static inline void local_flush_tlb_all(void)
@@ -19,7 +20,7 @@ static inline void local_flush_tlb_all(void)
 /* Flush one page from local TLB */
 static inline void local_flush_tlb_page(unsigned long addr)
 {
-       __asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory");
+       ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"));
 }
 #else /* CONFIG_MMU */
 #define local_flush_tlb_all()                  do { } while (0)