diff mbox series

LoongArch: KVM: Add haltpoll control feature in kvm side

Message ID 20240808083638.205659-1-maobibo@loongson.cn (mailing list archive)
State New, archived
Headers show
Series LoongArch: KVM: Add haltpoll control feature in kvm side | expand

Commit Message

Bibo Mao Aug. 8, 2024, 8:36 a.m. UTC
The cpuidle-haltpoll driver with haltpoll governor allows the guest
vcpus to poll for a specified amount of time before halting. This
provides some benefits such as avoid sending IPI to perform a wakeup
and avoid VM-exit cost.

When guest VM uses cpuidle-halt poll method, haltpoll need be disabled
at host hypervisor side to avoid double haltpoll in both guest VM and
host hypervisor. Here KVM_FEATURE_POLL_CONTROL feature is added in KVM
and guest can detect this feature and disable haltpoll in host side.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
 arch/loongarch/include/asm/kvm_host.h  |  1 +
 arch/loongarch/include/asm/loongarch.h |  1 +
 arch/loongarch/include/uapi/asm/kvm.h  |  3 +
 arch/loongarch/kvm/Kconfig             |  1 +
 arch/loongarch/kvm/exit.c              |  9 ++-
 arch/loongarch/kvm/vcpu.c              | 85 ++++++++++++++++++++------
 6 files changed, 81 insertions(+), 19 deletions(-)


base-commit: de9c2c66ad8e787abec7c9d7eff4f8c3cdd28aed
diff mbox series

Patch

diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 44b54965f5b4..a972f70ccdfc 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -214,6 +214,7 @@  struct kvm_vcpu_arch {
 		u64 last_steal;
 		struct gfn_to_hva_cache cache;
 	} st;
+	unsigned long kvm_poll_control;
 };
 
 static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index 04a78010fc72..e4fc30cf3572 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -170,6 +170,7 @@ 
 #define CPUCFG_KVM_FEATURE		(CPUCFG_KVM_BASE + 4)
 #define  KVM_FEATURE_IPI		BIT(1)
 #define  KVM_FEATURE_STEAL_TIME		BIT(2)
+#define  KVM_FEATURE_POLL_CONTROL	BIT(3)
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
index ddc5cab0ffd0..191f10c2b6c2 100644
--- a/arch/loongarch/include/uapi/asm/kvm.h
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -85,7 +85,10 @@  struct kvm_fpu {
 /* Device Control API on vcpu fd */
 #define KVM_LOONGARCH_VCPU_CPUCFG	0
 #define KVM_LOONGARCH_VCPU_PVTIME_CTRL	1
+/* Alias of KVM_LOONGARCH_VCPU_PVTIME_CTRL for wider use */
+#define KVM_LOONGARCH_VCPU_PV_CTRL	1
 #define  KVM_LOONGARCH_VCPU_PVTIME_GPA	0
+#define  KVM_LOONGARCH_VCPU_POLL_CTRL	1
 
 struct kvm_debug_exit_arch {
 };
diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig
index 248744b4d086..c5cc4dd2fb90 100644
--- a/arch/loongarch/kvm/Kconfig
+++ b/arch/loongarch/kvm/Kconfig
@@ -21,6 +21,7 @@  config KVM
 	tristate "Kernel-based Virtual Machine (KVM) support"
 	depends on AS_HAS_LVZ_EXTENSION
 	select HAVE_KVM_DIRTY_RING_ACQ_REL
+	select HAVE_KVM_NO_POLL
 	select HAVE_KVM_VCPU_ASYNC_IOCTL
 	select KVM_COMMON
 	select KVM_GENERIC_DIRTYLOG_READ_PROTECT
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index ea73f9dc2cc6..ebd578251388 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -50,7 +50,7 @@  static int kvm_emu_cpucfg(struct kvm_vcpu *vcpu, larch_inst inst)
 		vcpu->arch.gprs[rd] = *(unsigned int *)KVM_SIGNATURE;
 		break;
 	case CPUCFG_KVM_FEATURE:
-		ret = KVM_FEATURE_IPI;
+		ret = KVM_FEATURE_IPI | KVM_FEATURE_POLL_CONTROL;
 		if (kvm_pvtime_supported())
 			ret |= KVM_FEATURE_STEAL_TIME;
 		vcpu->arch.gprs[rd] = ret;
@@ -711,6 +711,13 @@  static long kvm_save_notify(struct kvm_vcpu *vcpu)
 		vcpu->arch.st.last_steal = current->sched_info.run_delay;
 		kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
 		break;
+	case KVM_FEATURE_POLL_CONTROL:
+		/* Only enable bit supported */
+		if (data & (-1ULL << 1))
+			return KVM_HCALL_INVALID_PARAMETER;
+
+		vcpu->arch.kvm_poll_control = data;
+		break;
 	default:
 		break;
 	};
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 16756ffb55e8..6e5c58cef90f 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -233,6 +233,11 @@  int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
 	return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
 }
 
+bool kvm_arch_no_poll(struct kvm_vcpu *vcpu)
+{
+	return (vcpu->arch.kvm_poll_control & 1) == 0;
+}
+
 bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
 {
 	return false;
@@ -650,6 +655,7 @@  static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
 			kvm_reset_timer(vcpu);
 			memset(&vcpu->arch.irq_pending, 0, sizeof(vcpu->arch.irq_pending));
 			memset(&vcpu->arch.irq_clear, 0, sizeof(vcpu->arch.irq_clear));
+			vcpu->arch.kvm_poll_control = 1;
 			break;
 		default:
 			ret = -EINVAL;
@@ -737,14 +743,21 @@  static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu,
 	return -ENXIO;
 }
 
-static int kvm_loongarch_pvtime_has_attr(struct kvm_vcpu *vcpu,
+static int kvm_loongarch_pv_has_attr(struct kvm_vcpu *vcpu,
 					 struct kvm_device_attr *attr)
 {
-	if (!kvm_pvtime_supported() ||
-			attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA)
+	switch (attr->attr) {
+	case KVM_LOONGARCH_VCPU_PVTIME_GPA:
+		if (!kvm_pvtime_supported())
+			return -ENXIO;
+		return 0;
+	case KVM_LOONGARCH_VCPU_POLL_CTRL:
+		return 0;
+	default:
 		return -ENXIO;
+	}
 
-	return 0;
+	return -ENXIO;
 }
 
 static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu,
@@ -756,8 +769,8 @@  static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu,
 	case KVM_LOONGARCH_VCPU_CPUCFG:
 		ret = kvm_loongarch_cpucfg_has_attr(vcpu, attr);
 		break;
-	case KVM_LOONGARCH_VCPU_PVTIME_CTRL:
-		ret = kvm_loongarch_pvtime_has_attr(vcpu, attr);
+	case KVM_LOONGARCH_VCPU_PV_CTRL:
+		ret = kvm_loongarch_pv_has_attr(vcpu, attr);
 		break;
 	default:
 		break;
@@ -782,18 +795,26 @@  static int kvm_loongarch_cpucfg_get_attr(struct kvm_vcpu *vcpu,
 	return ret;
 }
 
-static int kvm_loongarch_pvtime_get_attr(struct kvm_vcpu *vcpu,
+static int kvm_loongarch_pv_get_attr(struct kvm_vcpu *vcpu,
 					 struct kvm_device_attr *attr)
 {
-	u64 gpa;
+	u64 val;
 	u64 __user *user = (u64 __user *)attr->addr;
 
-	if (!kvm_pvtime_supported() ||
-			attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA)
+	switch (attr->attr) {
+	case KVM_LOONGARCH_VCPU_PVTIME_GPA:
+		if (!kvm_pvtime_supported())
+			return -ENXIO;
+		val = vcpu->arch.st.guest_addr;
+		break;
+	case KVM_LOONGARCH_VCPU_POLL_CTRL:
+		val = vcpu->arch.kvm_poll_control;
+		break;
+	default:
 		return -ENXIO;
+	}
 
-	gpa = vcpu->arch.st.guest_addr;
-	if (put_user(gpa, user))
+	if (put_user(val, user))
 		return -EFAULT;
 
 	return 0;
@@ -808,8 +829,8 @@  static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu,
 	case KVM_LOONGARCH_VCPU_CPUCFG:
 		ret = kvm_loongarch_cpucfg_get_attr(vcpu, attr);
 		break;
-	case KVM_LOONGARCH_VCPU_PVTIME_CTRL:
-		ret = kvm_loongarch_pvtime_get_attr(vcpu, attr);
+	case KVM_LOONGARCH_VCPU_PV_CTRL:
+		ret = kvm_loongarch_pv_get_attr(vcpu, attr);
 		break;
 	default:
 		break;
@@ -831,8 +852,7 @@  static int kvm_loongarch_pvtime_set_attr(struct kvm_vcpu *vcpu,
 	u64 gpa, __user *user = (u64 __user *)attr->addr;
 	struct kvm *kvm = vcpu->kvm;
 
-	if (!kvm_pvtime_supported() ||
-			attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA)
+	if (!kvm_pvtime_supported())
 		return -ENXIO;
 
 	if (get_user(gpa, user))
@@ -861,6 +881,33 @@  static int kvm_loongarch_pvtime_set_attr(struct kvm_vcpu *vcpu,
 	return ret;
 }
 
+static int kvm_loongarch_pv_set_attr(struct kvm_vcpu *vcpu,
+					struct kvm_device_attr *attr)
+{
+	u64 val,  __user *user = (u64 __user *)attr->addr;
+
+	switch (attr->attr) {
+	case KVM_LOONGARCH_VCPU_PVTIME_GPA:
+		return kvm_loongarch_pvtime_set_attr(vcpu, attr);
+
+	case KVM_LOONGARCH_VCPU_POLL_CTRL:
+		if (get_user(val, user))
+			return -EFAULT;
+
+		/* Only enable bit supported */
+		if (val & (-1ULL << 1))
+			return -EINVAL;
+
+		vcpu->arch.kvm_poll_control = val;
+		break;
+
+	default:
+		return -ENXIO;
+	}
+
+	return -ENXIO;
+}
+
 static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu,
 				       struct kvm_device_attr *attr)
 {
@@ -870,8 +917,8 @@  static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu,
 	case KVM_LOONGARCH_VCPU_CPUCFG:
 		ret = kvm_loongarch_cpucfg_set_attr(vcpu, attr);
 		break;
-	case KVM_LOONGARCH_VCPU_PVTIME_CTRL:
-		ret = kvm_loongarch_pvtime_set_attr(vcpu, attr);
+	case KVM_LOONGARCH_VCPU_PV_CTRL:
+		ret = kvm_loongarch_pv_set_attr(vcpu, attr);
 		break;
 	default:
 		break;
@@ -1179,6 +1226,8 @@  int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	/* Start with no pending virtual guest interrupts */
 	csr->csrs[LOONGARCH_CSR_GINTC] = 0;
 
+	/* poll control enabled by default */
+	vcpu->arch.kvm_poll_control = 1;
 	return 0;
 }