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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox