On 6/8/26 16:42, Jörg Rödel wrote:
From: Joerg Roedel <[email protected]>
The algorithm is to always run the lowest runnable plane. Plane
switches are done by stopping the current plane and setting another
runnable.
Signed-off-by: Joerg Roedel <[email protected]>
This was left arbitrary in my version because for example Hyper-V VTLs
use highest-runnable instead. It also made pure userspace scheduling
possible, though that may not be very important in the grand scheme of
things.
Did you drop it because it didn't work, or just for simplicity?
Paolo
---
include/linux/kvm_host.h | 16 ++++++++++++++
virt/kvm/kvm_main.c | 45 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5c3f9dfa15ea..e3611e6cc3e4 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -168,6 +168,7 @@ static inline bool kvm_is_error_gpa(gpa_t gpa)
#define KVM_REQ_VM_DEAD (1 | KVM_REQUEST_WAIT |
KVM_REQUEST_NO_WAKEUP)
#define KVM_REQ_UNBLOCK 2
#define KVM_REQ_DIRTY_RING_SOFT_FULL 3
+#define KVM_REQ_PLANE_RESCHED 4
#define KVM_REQUEST_ARCH_BASE 8
/*
@@ -324,6 +325,8 @@ struct kvm_mmio_fragment {
unsigned int len;
};
+
+
struct kvm_vcpu_common {
struct kvm *kvm;
@@ -381,6 +384,8 @@ struct kvm_vcpu_common {
struct kvm_dirty_ring dirty_ring;
+ bool plane_switch;
+
struct kvm_vcpu_arch_common arch;
};
@@ -388,6 +393,12 @@ struct kvm_vcpu_common {
for ((i) = 0; (i) < KVM_MAX_PLANES; ++(i)) \
if (((v) = common->vcpus[(i)]) != NULL)
+/* Tracked per plane-VCPU - used for deciding which plane-vcpu to run */
+enum kvm_vcpu_state {
+ STOPPED,
+ RUNNABLE,
+};
+
struct kvm_vcpu {
struct kvm *kvm;
struct kvm_plane *plane;
@@ -401,6 +412,7 @@ struct kvm_vcpu {
struct kvm_run *run;
u64 plane_requests;
+ enum kvm_vcpu_state plane_state;
/* S390 only */
bool valid_wakeup;
@@ -440,6 +452,10 @@ struct kvm_vcpu {
unsigned plane_level;
};
+void kvm_vcpu_set_plane_runnable(struct kvm_vcpu *vcpu);
+void kvm_vcpu_set_plane_stopped(struct kvm_vcpu *vcpu);
+struct kvm_vcpu *kvm_vcpu_select_plane(struct kvm_vcpu *vcpu);
+
static inline bool kvm_vcpu_wants_to_run(struct kvm_vcpu *vcpu)
{
return vcpu->common->wants_to_run;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 9d30fd85ce5f..a30123b77112 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4397,6 +4397,7 @@ static int kvm_plane_ioctl_create_vcpu(struct kvm_plane
*plane, unsigned long id
vcpu->vcpu_idx = vcpu->common->vcpu_idx;
vcpu->plane = plane;
vcpu->plane_level = plane->level;
+ vcpu->plane_state = STOPPED;
vcpu->run = vcpu->common->run;
kvm_vcpu_init(vcpu, kvm, id);
@@ -4938,6 +4939,50 @@ static struct file_operations kvm_plane_fops = {
KVM_COMPAT(kvm_plane_ioctl),
};
+void kvm_vcpu_set_plane_runnable(struct kvm_vcpu *vcpu)
+{
+ vcpu->plane_state = RUNNABLE;
+ vcpu->common->plane_switch = true;
+ kvm_make_request(KVM_REQ_PLANE_RESCHED, vcpu);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_set_plane_runnable);
+
+void kvm_vcpu_set_plane_stopped(struct kvm_vcpu *vcpu)
+{
+ vcpu->plane_state = STOPPED;
+ kvm_make_request(KVM_REQ_PLANE_RESCHED, vcpu);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_set_plane_stopped);
+
+struct kvm_vcpu *kvm_vcpu_select_plane(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_common *common = vcpu->common;
+ struct kvm_vcpu *ret = NULL;
+ unsigned i;
+
+ for (i = 0; i < KVM_MAX_PLANES; i++) {
+ if (common->vcpus[i] == NULL)
+ continue;
+
+ if (common->vcpus[i]->plane_state == RUNNABLE) {
+ ret = common->vcpus[i];
+ break;
+ }
+ }
+
+ if (ret == NULL) {
+ ret = common->vcpus[0];
+ ret->plane_state = RUNNABLE;
+ }
+
+ common->current_vcpu = ret;
+
+ common->plane_switch = false;
+
+ return ret;
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_vcpu_select_plane);
+
static int kvm_device_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct kvm_device *dev = filp->private_data;