]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
riscv: Stop emitting preventive sfence.vma for new userspace mappings with Svvptc
authorAlexandre Ghiti <alexghiti@rivosinc.com>
Wed, 17 Jul 2024 06:01:25 +0000 (08:01 +0200)
committerPalmer Dabbelt <palmer@rivosinc.com>
Sun, 15 Sep 2024 07:11:05 +0000 (00:11 -0700)
The preventive sfence.vma were emitted because new mappings must be made
visible to the page table walker but Svvptc guarantees that it will
happen within a bounded timeframe, so no need to sfence.vma for the uarchs
that implement this extension, we will then take gratuitous (but very
unlikely) page faults, similarly to x86 and arm64.

This allows to drastically reduce the number of sfence.vma emitted:

* Ubuntu boot to login:
Before: ~630k sfence.vma
After:  ~200k sfence.vma

* ltp - mmapstress01
Before: ~45k
After:  ~6.3k

* lmbench - lat_pagefault
Before: ~665k
After:   832 (!)

* lmbench - lat_mmap
Before: ~546k
After:   718 (!)

Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20240717060125.139416-5-alexghiti@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/include/asm/pgtable.h
arch/riscv/mm/pgtable.c

index aad8b8ca51f1202d547e23736a459e404d03158d..4ed85329317d5a3737d62f829ae2c8fce17d857e 100644 (file)
@@ -476,6 +476,9 @@ static inline void update_mmu_cache_range(struct vm_fault *vmf,
                struct vm_area_struct *vma, unsigned long address,
                pte_t *ptep, unsigned int nr)
 {
+       asm goto(ALTERNATIVE("nop", "j %l[svvptc]", 0, RISCV_ISA_EXT_SVVPTC, 1)
+                : : : : svvptc);
+
        /*
         * The kernel assumes that TLBs don't cache invalid entries, but
         * in RISC-V, SFENCE.VMA specifies an ordering constraint, not a
@@ -485,12 +488,23 @@ static inline void update_mmu_cache_range(struct vm_fault *vmf,
         */
        while (nr--)
                local_flush_tlb_page(address + nr * PAGE_SIZE);
+
+svvptc:;
+       /*
+        * Svvptc guarantees that the new valid pte will be visible within
+        * a bounded timeframe, so when the uarch does not cache invalid
+        * entries, we don't have to do anything.
+        */
 }
 #define update_mmu_cache(vma, addr, ptep) \
        update_mmu_cache_range(NULL, vma, addr, ptep, 1)
 
 #define __HAVE_ARCH_UPDATE_MMU_TLB
-#define update_mmu_tlb update_mmu_cache
+static inline void update_mmu_tlb(struct vm_area_struct *vma,
+                                 unsigned long address, pte_t *ptep)
+{
+       flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
 
 static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
                unsigned long address, pmd_t *pmdp)
index 533ec9055fa0da75597bce9619d24f18c58577ac..4ae67324f99233a97cb9758fd68cbe2bd7d14bec 100644 (file)
@@ -9,6 +9,9 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
                          unsigned long address, pte_t *ptep,
                          pte_t entry, int dirty)
 {
+       asm goto(ALTERNATIVE("nop", "j %l[svvptc]", 0, RISCV_ISA_EXT_SVVPTC, 1)
+                : : : : svvptc);
+
        if (!pte_same(ptep_get(ptep), entry))
                __set_pte_at(vma->vm_mm, ptep, entry);
        /*
@@ -16,6 +19,16 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
         * the case that the PTE changed and the spurious fault case.
         */
        return true;
+
+svvptc:
+       if (!pte_same(ptep_get(ptep), entry)) {
+               __set_pte_at(vma->vm_mm, ptep, entry);
+               /* Here only not svadu is impacted */
+               flush_tlb_page(vma, address);
+               return true;
+       }
+
+       return false;
 }
 
 int ptep_test_and_clear_young(struct vm_area_struct *vma,