From 846d0d6dc26e3110f1e2a80667f597a90966a1ea Mon Sep 17 00:00:00 2001 From: Wang Yechao Date: Tue, 7 Jul 2026 20:50:20 +0800 Subject: [PATCH 1/2] RISC-V: KVM: Introduce make_xfence_request_nodata for FENCE.I requests FENCE.I does not need hfence data, but it currently goes through the generic make_xfence_request() path with NULL data, incurring unnecessary per-VCPU checks. Split out a separate make_xfence_request_nodata() function to handle FENCE.I directly, and move the data validity check to the top of the generic function to avoid redundant checks. Signed-off-by: Wang Yechao Signed-off-by: Linux RISC-V bot --- arch/riscv/kvm/tlb.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c index 993b25ea94d674..5a9c75e4580132 100644 --- a/arch/riscv/kvm/tlb.c +++ b/arch/riscv/kvm/tlb.c @@ -325,6 +325,29 @@ void kvm_riscv_hfence_process(struct kvm_vcpu *vcpu) } } +static void make_xfence_request_nodata(struct kvm *kvm, unsigned long hbase, + unsigned long hmask, unsigned int req) +{ + unsigned long i; + struct kvm_vcpu *vcpu; + DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS); + + bitmap_zero(vcpu_mask, KVM_MAX_VCPUS); + kvm_for_each_vcpu(i, vcpu, kvm) { + if (hbase != -1UL) { + if (vcpu->vcpu_id < hbase || + vcpu->vcpu_id >= hbase + BITS_PER_LONG) + continue; + if (!(hmask & (1UL << (vcpu->vcpu_id - hbase)))) + continue; + } + + bitmap_set(vcpu_mask, i, 1); + } + + kvm_make_vcpus_request_mask(kvm, req, vcpu_mask); +} + static void make_xfence_request(struct kvm *kvm, unsigned long hbase, unsigned long hmask, unsigned int req, unsigned int fallback_req, @@ -335,6 +358,9 @@ static void make_xfence_request(struct kvm *kvm, unsigned int actual_req = req; DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS); + if (!data || !data->type) + return; + bitmap_zero(vcpu_mask, KVM_MAX_VCPUS); kvm_for_each_vcpu(i, vcpu, kvm) { if (hbase != -1UL) { @@ -347,9 +373,6 @@ static void make_xfence_request(struct kvm *kvm, bitmap_set(vcpu_mask, i, 1); - if (!data || !data->type) - continue; - /* * Enqueue hfence data to VCPU hfence queue. If we don't * have space in the VCPU hfence queue then fallback to @@ -365,8 +388,7 @@ static void make_xfence_request(struct kvm *kvm, void kvm_riscv_fence_i(struct kvm *kvm, unsigned long hbase, unsigned long hmask) { - make_xfence_request(kvm, hbase, hmask, KVM_REQ_FENCE_I, - KVM_REQ_FENCE_I, NULL); + make_xfence_request_nodata(kvm, hbase, hmask, KVM_REQ_FENCE_I); } void kvm_riscv_hfence_gvma_vmid_gpa(struct kvm *kvm, From 2dd650d7fd87fc15c8d82cc2f1b325ba136058ee Mon Sep 17 00:00:00 2001 From: Wang Yechao Date: Tue, 7 Jul 2026 20:50:21 +0800 Subject: [PATCH 2/2] RISC-V: KVM: Separate req and fallback_req masks in make_xfence_request When handling hfence requests in make_xfence_request(), the current code uses a single 'actual_req' variable and a single vcpu_mask. If any VCPU fails to enqueue the hfence data (because its queue is full), the request falls back to 'fallback_req' for all VCPUs, even if other VCPUs still have available queue space. This can cause unnecessary fallback for healthy VCPUs, and more seriously, those healthy VCPUs will not process their already-enqueued hfence requests because no 'req' is set for them. As a result, their queues will quickly become full as well, degrading performance for SMP guests. Fix this by maintaining two separate bitmaps: one for VCPUs that successfully enqueued the hfence data (req_vcpu_mask) and another for those that failed (fallback_req_vcpu_mask). Then send the appropriate requests to each group. This ensures that fallback is only applied to VCPUs that actually need it, preserving the efficiency of the normal path for others. Fixes: 13acfec2dbcc ("RISC-V: KVM: Add remote HFENCE functions based on VCPU requests") Signed-off-by: Wang Yechao Signed-off-by: Linux RISC-V bot --- arch/riscv/kvm/tlb.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c index 5a9c75e4580132..fd445e9fa3f94f 100644 --- a/arch/riscv/kvm/tlb.c +++ b/arch/riscv/kvm/tlb.c @@ -355,13 +355,14 @@ static void make_xfence_request(struct kvm *kvm, { unsigned long i; struct kvm_vcpu *vcpu; - unsigned int actual_req = req; - DECLARE_BITMAP(vcpu_mask, KVM_MAX_VCPUS); + DECLARE_BITMAP(req_vcpu_mask, KVM_MAX_VCPUS); + DECLARE_BITMAP(fallback_req_vcpu_mask, KVM_MAX_VCPUS); if (!data || !data->type) return; - bitmap_zero(vcpu_mask, KVM_MAX_VCPUS); + bitmap_zero(req_vcpu_mask, KVM_MAX_VCPUS); + bitmap_zero(fallback_req_vcpu_mask, KVM_MAX_VCPUS); kvm_for_each_vcpu(i, vcpu, kvm) { if (hbase != -1UL) { if (vcpu->vcpu_id < hbase || @@ -371,18 +372,19 @@ static void make_xfence_request(struct kvm *kvm, continue; } - bitmap_set(vcpu_mask, i, 1); - /* * Enqueue hfence data to VCPU hfence queue. If we don't * have space in the VCPU hfence queue then fallback to * a more conservative hfence request. */ if (!vcpu_hfence_enqueue(vcpu, data)) - actual_req = fallback_req; + bitmap_set(fallback_req_vcpu_mask, i, 1); + else + bitmap_set(req_vcpu_mask, i, 1); } - kvm_make_vcpus_request_mask(kvm, actual_req, vcpu_mask); + kvm_make_vcpus_request_mask(kvm, req, req_vcpu_mask); + kvm_make_vcpus_request_mask(kvm, fallback_req, fallback_req_vcpu_mask); } void kvm_riscv_fence_i(struct kvm *kvm,