Re: [PATCH v22 11/23] KVM: arm64: Add VM specific callback for S2 MMU operations

From: Suzuki K Poulose

Date: Tue Oct 06 2026 - 01:22:58 EST


On 06/10/2026 04:00, Gavin Shan wrote:
On 10/5/26 7:07 PM, Suzuki K Poulose wrote:
Add VM type specific S2 MMU operation backends which can be initialized per
VM flavor, to keep the handling cleaner.

Signed-off-by: Suzuki K Poulose <suzuki.poulose@xxxxxxx>
---
Change since v21:
  - Define all vm_s2_ops call back. All calls are mandatory.
  - Define callback for each flavor, disjointing the non-protetcted pKVM and
    normal KVM (VHE & nVHE) and remove the KVM_PGT_FN() hacks.
  - Dropped Reviews due to the changes.
  - Add "no_age_gfn" and "no_stage2_unmap_range" for pKVM callbacks, no_age_*
    to be also reused by Realms later.
  - Move kvm_vm_s2_ops field to keep the structure packed

...

   */
  int kvm_arch_flush_remote_tlbs(struct kvm *kvm)
  {
-    if (is_protected_kvm_enabled())
-        kvm_call_hyp_nvhe(__pkvm_tlb_flush_vmid, kvm->arch.pkvm.handle);
-    else
-        kvm_call_hyp(__kvm_tlb_flush_vmid, &kvm->arch.mmu);
-    return 0;
+    return kvm->arch.vm_s2_ops->vm_flush_remote_tlbs(kvm);
  }
-int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm,
-                      gfn_t gfn, u64 nr_pages)
+static int pkvm_flush_remote_tlbs_range(struct kvm *kvm,
+                    gfn_t gfn, u64 nr_pages)
+{
+    return pkvm_flush_remote_tlbs(kvm);

No need to have another function call, which causes unnecessary overhead?

    kvm_call_hyp_nvhe(__pkvm_tlb_flush_vmid, kvm->arch.pkvm.handle);

Maybe, but that is in another way, telling the reader that pKVM can only
do full VM TLB flush, no range TLB flush.

    return 0;

+}
+
+static int kvm_vm_flush_remote_tlbs_range(struct kvm *kvm,
+                     gfn_t gfn, u64 nr_pages)
  {
      u64 size = nr_pages << PAGE_SHIFT;
      u64 addr = gfn << PAGE_SHIFT;
-    if (is_protected_kvm_enabled())
-        kvm_call_hyp_nvhe(__pkvm_tlb_flush_vmid, kvm->arch.pkvm.handle);
-    else
-        kvm_tlb_flush_vmid_range(&kvm->arch.mmu, addr, size);
+    kvm_tlb_flush_vmid_range(&kvm->arch.mmu, addr, size);
      return 0;
  }


Since we're here, the local variable 'addr' and 'size' can be dropped by:

    kvm_tlb_flush_vmid_range(&kvm->arch.mmu,
                                 gfn << PAGE_SHIFT,
                                 nr_pages << PAGE_SHIFT);


Does it really matter, the compiler can optimise this anyways and looks
more readable ?


+int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm,
+                     gfn_t gfn, u64 nr_pages)
+{
+    return kvm->arch.vm_s2_ops->vm_flush_remote_tlbs_range(kvm, gfn, nr_pages);
+}
+

...

+static const struct kvm_vm_s2_ops kvm_default_vm_s2_ops = {
+    .vm_flush_remote_tlbs        = kvm_vm_flush_remote_tlbs,
+    .vm_flush_remote_tlbs_range    = kvm_vm_flush_remote_tlbs_range,
+    .vm_age_gfn            = kvm_vm_age_gfn,
+    .vm_test_age_gfn        = kvm_vm_test_age_gfn,
+    .vm_stage2_unmap_range        = kvm_vm_stage2_unmap_range,
+};
+
+#define KVM_VM_S2_OPS(flavor, ops)        \
+        [flavor] = &(ops)

s/[flavor]/[(flavor)]

Ack


Thanks !
Suzuki