From: Tao Cui <cui.tao@linux.dev>
To: maobibo@loongson.cn, zhaotianrui@loongson.cn,
chenhuacai@kernel.org, loongarch@lists.linux.dev
Cc: kernel@xen0n.name, kvm@vger.kernel.org, Tao Cui <cuitao@kylinos.cn>
Subject: [PATCH v3 2/4] LoongArch: KVM: Add PV TLB flush support via steal-time shared memory
Date: Tue, 2 Jun 2026 10:18:17 +0800 [thread overview]
Message-ID: <20260602021819.2373404-3-cui.tao@linux.dev> (raw)
In-Reply-To: <20260602021819.2373404-1-cui.tao@linux.dev>
From: Tao Cui <cuitao@kylinos.cn>
Implement paravirtualized TLB flush for LoongArch KVM guests using the
existing steal-time shared memory page.
The mechanism uses the preempted byte in struct kvm_steal_time with an
additional KVM_VCPU_FLUSH_TLB flag bit:
- When a guest vCPU needs remote TLB flush but the target vCPU is
preempted (not running), it atomically sets KVM_VCPU_FLUSH_TLB in
the target's steal-time preempted byte instead of sending an IPI.
- When the host re-enters the target vCPU (kvm_update_stolen_time()),
it atomically reads and clears only the preempted byte via amand_db.w
with mask ~0xff on the 32-bit aligned word. amand_db.w provides
full barrier semantics and avoids the race with guest-side
try_cmpxchg(). LoongArch is little-endian, so the preempted byte
occupies bits [7:0]; this preserves pad[0..2] for future UAPI
extension. If KVM_VCPU_FLUSH_TLB was set, the host drops the vCPU's
VPID, which triggers a full TLB flush on the next VM entry via
kvm_check_vpid().
- For non-preempted vCPUs, the guest falls back to normal IPI-based
flush, avoiding unnecessary VM exits.
Issue a normal load (unsafe_get_user) before the atomic amand_db.w to
avoid operating on stale cache data when the cache line was last
modified by a different core.
This significantly reduces TLB flush overhead in multi-vCPU workloads
where target vCPUs are often idle/preempted.
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
arch/loongarch/include/asm/kvm_host.h | 1 +
arch/loongarch/include/asm/kvm_para.h | 1 +
arch/loongarch/include/uapi/asm/kvm.h | 1 +
arch/loongarch/include/uapi/asm/kvm_para.h | 1 +
arch/loongarch/kvm/trace.h | 15 +++++++++++
arch/loongarch/kvm/vcpu.c | 30 +++++++++++++++++++++-
arch/loongarch/kvm/vm.c | 3 +++
7 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 903cb67ca817..a379868fb147 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -170,6 +170,7 @@ enum emulation_result {
#define LOONGARCH_PV_FEAT_MASK (BIT(KVM_FEATURE_IPI) | \
BIT(KVM_FEATURE_PREEMPT) | \
BIT(KVM_FEATURE_STEAL_TIME) | \
+ BIT(KVM_FEATURE_PV_TLB_FLUSH) |\
BIT(KVM_FEATURE_USER_HCALL) | \
BIT(KVM_FEATURE_VIRT_EXTIOI))
diff --git a/arch/loongarch/include/asm/kvm_para.h b/arch/loongarch/include/asm/kvm_para.h
index fb17ba0fa101..28e3fa3b4c0e 100644
--- a/arch/loongarch/include/asm/kvm_para.h
+++ b/arch/loongarch/include/asm/kvm_para.h
@@ -41,6 +41,7 @@ struct kvm_steal_time {
__u8 pad[47];
};
#define KVM_VCPU_PREEMPTED (1 << 0)
+#define KVM_VCPU_FLUSH_TLB (1 << 1)
/*
* Hypercall interface for KVM hypervisor
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
index cd0b5c11ca9c..e4cd4bbf8914 100644
--- a/arch/loongarch/include/uapi/asm/kvm.h
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -106,6 +106,7 @@ struct kvm_fpu {
#define KVM_LOONGARCH_VM_FEAT_PTW 8
#define KVM_LOONGARCH_VM_FEAT_MSGINT 9
#define KVM_LOONGARCH_VM_FEAT_PV_PREEMPT 10
+#define KVM_LOONGARCH_VM_FEAT_PV_TLB_FLUSH 11
/* Device Control API on vcpu fd */
#define KVM_LOONGARCH_VCPU_CPUCFG 0
diff --git a/arch/loongarch/include/uapi/asm/kvm_para.h b/arch/loongarch/include/uapi/asm/kvm_para.h
index d28cbcadd276..8872839251cc 100644
--- a/arch/loongarch/include/uapi/asm/kvm_para.h
+++ b/arch/loongarch/include/uapi/asm/kvm_para.h
@@ -16,6 +16,7 @@
#define KVM_FEATURE_IPI 1
#define KVM_FEATURE_STEAL_TIME 2
#define KVM_FEATURE_PREEMPT 3
+#define KVM_FEATURE_PV_TLB_FLUSH 4
/* BIT 24 - 31 are features configurable by user space vmm */
#define KVM_FEATURE_VIRT_EXTIOI 24
#define KVM_FEATURE_USER_HCALL 25
diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h
index 3467ee22b704..8556954fa196 100644
--- a/arch/loongarch/kvm/trace.h
+++ b/arch/loongarch/kvm/trace.h
@@ -210,6 +210,21 @@ TRACE_EVENT(kvm_vpid_change,
TP_printk("VPID: 0x%08lx", __entry->vpid)
);
+TRACE_EVENT(kvm_pv_tlb_flush,
+ TP_PROTO(struct kvm_vcpu *vcpu, bool need_flush),
+ TP_ARGS(vcpu, need_flush),
+ TP_STRUCT__entry(
+ __field(unsigned int, vcpu_id)
+ __field(bool, need_flush)
+ ),
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu->vcpu_id;
+ __entry->need_flush = need_flush;
+ ),
+ TP_printk("vcpu %u need_flush %u", __entry->vcpu_id,
+ __entry->need_flush)
+);
+
#endif /* _TRACE_KVM_H */
#undef TRACE_INCLUDE_PATH
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 47a59ce9e561..e4c19d0b8710 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -173,7 +173,35 @@ static void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
}
st = (struct kvm_steal_time __user *)ghc->hva;
- if (kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_PREEMPT)) {
+ if (kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_PV_TLB_FLUSH)) {
+ u32 old = 0;
+ int err = 0;
+
+ /* Issue a normal load to avoid stale cache data for amand_db.w */
+ unsafe_get_user(old, (u32 __user *)&st->preempted, out);
+
+ /* Atomically read and clear the preempted byte via amand_db.w. */
+ asm volatile(
+ "1: amand_db.w %1, %3, %2 \n"
+ "2: \n"
+ _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1)
+ : "+r" (err), "+&r" (old),
+ "+ZB" (*(u32 *)&st->preempted)
+ : "r" ((u32)~0xffu)
+ : "memory");
+
+ if (err)
+ goto out;
+
+ vcpu->arch.st.preempted = 0;
+
+ if ((u8)old & KVM_VCPU_FLUSH_TLB) {
+ vcpu->arch.vpid = 0; /* Drop vpid to flush TLB */
+ trace_kvm_pv_tlb_flush(vcpu, true);
+ } else {
+ trace_kvm_pv_tlb_flush(vcpu, false);
+ }
+ } else if (kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_PREEMPT)) {
unsafe_put_user(0, &st->preempted, out);
vcpu->arch.st.preempted = 0;
}
diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c
index 8af874e0b36b..4be70e4f1279 100644
--- a/arch/loongarch/kvm/vm.c
+++ b/arch/loongarch/kvm/vm.c
@@ -54,8 +54,10 @@ static void kvm_vm_init_features(struct kvm *kvm)
if (kvm_pvtime_supported()) {
kvm->arch.pv_features |= BIT(KVM_FEATURE_PREEMPT);
kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME);
+ kvm->arch.pv_features |= BIT(KVM_FEATURE_PV_TLB_FLUSH);
kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_PREEMPT);
kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_STEALTIME);
+ kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_TLB_FLUSH);
}
kvm->arch.pv_auto_features = kvm->arch.pv_features;
}
@@ -159,6 +161,7 @@ static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr
case KVM_LOONGARCH_VM_FEAT_PV_IPI:
case KVM_LOONGARCH_VM_FEAT_PV_PREEMPT:
case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME:
+ case KVM_LOONGARCH_VM_FEAT_PV_TLB_FLUSH:
if (kvm_vm_support(&kvm->arch, attr->attr))
return 0;
return -ENXIO;
--
2.43.0
next prev parent reply other threads:[~2026-06-02 2:18 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-02 2:18 [PATCH v3 0/4] LoongArch: KVM: Add PV TLB flush support Tao Cui
2026-06-02 2:18 ` [PATCH v3 1/4] LoongArch: KVM: Preserve auto-enabled PV features on userspace override Tao Cui
2026-06-02 2:26 ` sashiko-bot
2026-06-02 2:18 ` Tao Cui [this message]
2026-06-02 2:37 ` [PATCH v3 2/4] LoongArch: KVM: Add PV TLB flush support via steal-time shared memory sashiko-bot
2026-06-02 2:18 ` [PATCH v3 3/4] LoongArch: KVM: Implement guest-side PV TLB flush Tao Cui
2026-06-02 2:46 ` sashiko-bot
2026-06-02 2:18 ` [PATCH v3 4/4] KVM: selftests: loongarch: Add PV TLB flush performance test Tao Cui
2026-06-02 2:52 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260602021819.2373404-3-cui.tao@linux.dev \
--to=cui.tao@linux.dev \
--cc=chenhuacai@kernel.org \
--cc=cuitao@kylinos.cn \
--cc=kernel@xen0n.name \
--cc=kvm@vger.kernel.org \
--cc=loongarch@lists.linux.dev \
--cc=maobibo@loongson.cn \
--cc=zhaotianrui@loongson.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.