]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
RISC-V: KVM: Don't flush TLB when PTE is unchanged
authorAnup Patel <apatel@ventanamicro.com>
Wed, 18 Jun 2025 11:35:25 +0000 (17:05 +0530)
committerAnup Patel <anup@brainfault.org>
Mon, 28 Jul 2025 16:57:16 +0000 (22:27 +0530)
The gstage_set_pte() and gstage_op_pte() should flush TLB only when
a leaf PTE changes so that unnecessary TLB flushes can be avoided.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Tested-by: Atish Patra <atishp@rivosinc.com>
Reviewed-by: Nutty Liu <liujingqi@lanxincomputing.com>
Link: https://lore.kernel.org/r/20250618113532.471448-6-apatel@ventanamicro.com
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/kvm/mmu.c

index 1087ea74567b4c9ce2742bf6427ade7f8944ce9d..29f1bd853a6695dbd9bb2cd50fbde369c7f6e6e0 100644 (file)
@@ -167,9 +167,11 @@ static int gstage_set_pte(struct kvm *kvm, u32 level,
                ptep = &next_ptep[gstage_pte_index(addr, current_level)];
        }
 
-       set_pte(ptep, *new_pte);
-       if (gstage_pte_leaf(ptep))
-               gstage_remote_tlb_flush(kvm, current_level, addr);
+       if (pte_val(*ptep) != pte_val(*new_pte)) {
+               set_pte(ptep, *new_pte);
+               if (gstage_pte_leaf(ptep))
+                       gstage_remote_tlb_flush(kvm, current_level, addr);
+       }
 
        return 0;
 }
@@ -229,7 +231,7 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr,
                          pte_t *ptep, u32 ptep_level, enum gstage_op op)
 {
        int i, ret;
-       pte_t *next_ptep;
+       pte_t old_pte, *next_ptep;
        u32 next_ptep_level;
        unsigned long next_page_size, page_size;
 
@@ -258,11 +260,13 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr,
                if (op == GSTAGE_OP_CLEAR)
                        put_page(virt_to_page(next_ptep));
        } else {
+               old_pte = *ptep;
                if (op == GSTAGE_OP_CLEAR)
                        set_pte(ptep, __pte(0));
                else if (op == GSTAGE_OP_WP)
                        set_pte(ptep, __pte(pte_val(ptep_get(ptep)) & ~_PAGE_WRITE));
-               gstage_remote_tlb_flush(kvm, ptep_level, addr);
+               if (pte_val(*ptep) != pte_val(old_pte))
+                       gstage_remote_tlb_flush(kvm, ptep_level, addr);
        }
 }