riscv: Apply SiFive CIP-1200 workaround to single-ASID sfence.vma
authorSamuel Holland <samuel.holland@sifive.com>
Wed, 27 Mar 2024 04:49:48 +0000 (21:49 -0700)
committerPalmer Dabbelt <palmer@rivosinc.com>
Mon, 29 Apr 2024 17:49:30 +0000 (10:49 -0700)
commit 3f1e782998cd ("riscv: add ASID-based tlbflushing methods") added
calls to the sfence.vma instruction with rs2 != x0. These single-ASID
instruction variants are also affected by SiFive errata CIP-1200.

Until now, the errata workaround was not needed for the single-ASID
sfence.vma variants, because they were only used when the ASID allocator
was enabled, and the affected SiFive platforms do not support multiple
ASIDs. However, we are going to start using those sfence.vma variants
regardless of ASID support, so now we need alternatives covering them.

Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Link: https://lore.kernel.org/r/20240327045035.368512-8-samuel.holland@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/include/asm/errata_list.h
arch/riscv/include/asm/tlbflush.h
arch/riscv/mm/tlbflush.c

index 1f2dbfb8a8bfc8c9f5d46b9129c26756941c4918..35ce268999605c9124867f8b363d9e96500b9737 100644 (file)
@@ -43,11 +43,21 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault),                   \
            CONFIG_ERRATA_SIFIVE_CIP_453)
 #else /* !__ASSEMBLY__ */
 
-#define ALT_FLUSH_TLB_PAGE(x)                                          \
+#define ALT_SFENCE_VMA_ASID(asid)                                      \
+asm(ALTERNATIVE("sfence.vma x0, %0", "sfence.vma", SIFIVE_VENDOR_ID,   \
+               ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200)  \
+               : : "r" (asid) : "memory")
+
+#define ALT_SFENCE_VMA_ADDR(addr)                                      \
 asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID,       \
                ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200)  \
                : : "r" (addr) : "memory")
 
+#define ALT_SFENCE_VMA_ADDR_ASID(addr, asid)                           \
+asm(ALTERNATIVE("sfence.vma %0, %1", "sfence.vma", SIFIVE_VENDOR_ID,   \
+               ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200)  \
+               : : "r" (addr), "r" (asid) : "memory")
+
 /*
  * _val is marked as "will be overwritten", so need to set it to 0
  * in the default case.
index 4f86424b1ba5e169b9e75a5bc2f8c1dee5f2345e..463b615d7728c8ddd77b6ea70b32a0db47b198ba 100644 (file)
@@ -22,10 +22,27 @@ static inline void local_flush_tlb_all(void)
        __asm__ __volatile__ ("sfence.vma" : : : "memory");
 }
 
+static inline void local_flush_tlb_all_asid(unsigned long asid)
+{
+       if (asid != FLUSH_TLB_NO_ASID)
+               ALT_SFENCE_VMA_ASID(asid);
+       else
+               local_flush_tlb_all();
+}
+
 /* Flush one page from local TLB */
 static inline void local_flush_tlb_page(unsigned long addr)
 {
-       ALT_FLUSH_TLB_PAGE(__asm__ __volatile__ ("sfence.vma %0" : : "r" (addr) : "memory"));
+       ALT_SFENCE_VMA_ADDR(addr);
+}
+
+static inline void local_flush_tlb_page_asid(unsigned long addr,
+                                            unsigned long asid)
+{
+       if (asid != FLUSH_TLB_NO_ASID)
+               ALT_SFENCE_VMA_ADDR_ASID(addr, asid);
+       else
+               local_flush_tlb_page(addr);
 }
 
 void flush_tlb_all(void);
index 0901aa47b58fe7e18b517b014af9df672ce29d32..ad7bdcfcc2199228c7b363d10ce23e342a6517b9 100644 (file)
@@ -7,29 +7,6 @@
 #include <asm/sbi.h>
 #include <asm/mmu_context.h>
 
-static inline void local_flush_tlb_all_asid(unsigned long asid)
-{
-       if (asid != FLUSH_TLB_NO_ASID)
-               __asm__ __volatile__ ("sfence.vma x0, %0"
-                               :
-                               : "r" (asid)
-                               : "memory");
-       else
-               local_flush_tlb_all();
-}
-
-static inline void local_flush_tlb_page_asid(unsigned long addr,
-               unsigned long asid)
-{
-       if (asid != FLUSH_TLB_NO_ASID)
-               __asm__ __volatile__ ("sfence.vma %0, %1"
-                               :
-                               : "r" (addr), "r" (asid)
-                               : "memory");
-       else
-               local_flush_tlb_page(addr);
-}
-
 /*
  * Flush entire TLB if number of entries to be flushed is greater
  * than the threshold below.