@@ -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)
@@ -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__
@@ -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 {
};
@@ -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
@@ -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;
};
@@ -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;
}
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