[RFC PATCH v1 15/17] accel/kvm: pin the vCPU threads of a CoVE guest

Baolong Duan <[email protected]> Fri, 31 Jul 2026 11:50:09 +0800
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
The TSM binds a TVM vCPU to the hart it first runs on, so the thread
running it has to stay on that host CPU.  With every host CPU running a
pinned vCPU thread the host is then starved, which shows up as RCU
stalls, hence the short sleep after each KVM_RUN.

Both are workarounds that do not belong in target independent code:
thread placement is normally left to the user or to the management layer,
and the sleep papers over a host scheduling problem.  Guidance on how to
express the TSM requirement properly would be appreciated.

Signed-off-by: Baolong Duan <[email protected]>
---
 accel/kvm/kvm-accel-ops.c | 16 ++++++++++++++++
 accel/kvm/kvm-all.c       |  9 +++++++++
 2 files changed, 25 insertions(+)

diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index c8e7aa3870..30e1cb181c 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -24,6 +24,7 @@
 #include "system/cpus.h"
 #include "qemu/guest-random.h"
 #include "qapi/error.h"
+#include "hw/riscv/cove.h"
 
 #include <linux/kvm.h>
 #include "kvm-cpus.h"
@@ -43,6 +44,21 @@ static void *kvm_vcpu_thread_fn(void *arg)
     r = kvm_init_vcpu(cpu, &error_fatal);
     kvm_init_cpu_signals(cpu);
 
+    /*
+     * The TSM binds a TVM vCPU to the hart it first runs on, so pin vCPU N
+     * to host CPU N before the first KVM_RUN.
+     */
+    if (riscv_cove_vm_active()) {
+        cpu_set_t cpuset;
+
+        CPU_ZERO(&cpuset);
+        CPU_SET(cpu->cpu_index, &cpuset);
+        if (sched_setaffinity(0, sizeof(cpuset), &cpuset) < 0) {
+            error_report("Unable to pin vCPU %d: %s", cpu->cpu_index,
+                         strerror(errno));
+        }
+    }
+
     /* signal CPU creation */
     cpu_thread_signal_created(cpu);
     qemu_guest_random_seed_thread_part2(cpu->random_seed);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index aaaa88bd2b..7b33a9aa3a 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3510,6 +3510,15 @@ int kvm_cpu_exec(CPUState *cpu)
          * as true, cpu->exit_request will always read as true.
          */
 
+        /*
+         * Yield briefly after each KVM_RUN of a CoVE guest: with one pinned
+         * vCPU thread per host CPU the host is otherwise starved and reports
+         * RCU stalls.
+         */
+        if (riscv_cove_vm_active()) {
+            usleep(100);
+        }
+
         attrs = kvm_arch_post_run(cpu, run);
 
 #ifdef KVM_HAVE_MCE_INJECTION
-- 
2.34.1