S390 can also use async page faults, to enhance guest scheduling.
In case of live migration we want to disable the feature and let
all pending request finish.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
return rc == -1 ? -errno : rc;
}
+static void flic_enable_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_ENABLE,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't enable pfault\n");
+ }
+}
+
+static void flic_disable_wait_pfault(KVMS390FLICState *flic)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
+ };
+ int rc;
+
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+ if (rc) {
+ fprintf(stderr, "flic: couldn't disable pfault\n");
+ }
+}
+
/** flic_enqueue_irqs - returns 0 on success
* @buf: pointer to buffer which is passed to kernel
* @len: length of buffer
void *buf;
int count;
+ flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
+
buf = g_try_malloc0(len);
if (!buf) {
/* Storing FLIC_FAILED into the count field here will cause the
goto out;
}
+ flic_enable_pfault((struct KVMS390FLICState *) opaque);
+
count = qemu_get_be64(f);
len = count * sizeof(struct kvm_s390_irq);
if (count == FLIC_FAILED) {
return;
}
+ flic_disable_wait_pfault(flic);
+
rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
if (rc) {
trace_flic_reset_failed(errno);
}
+
+ flic_enable_pfault(flic);
}
static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
CPUS390XState *env = &cpu->env;
+ env->pfault_token = -1UL;
s390_del_running_cpu(cpu);
scc->parent_reset(s);
#if !defined(CONFIG_USER_ONLY)
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
+
+ env->pfault_token = -1UL;
}
/* CPUClass:reset() */
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
+
+ env->pfault_token = -1UL;
+
/* set halted to 1 to make sure we can add the cpu in
* s390_ipl_cpu code, where CPUState::halted is set back to 0
* after incrementing the cpu counter */
uint64_t cputm;
uint32_t todpr;
+ uint64_t pfault_token;
+ uint64_t pfault_compare;
+ uint64_t pfault_select;
+
CPU_COMMON
/* reset does memset(0) up to here */
};
static int cap_sync_regs;
+static int cap_async_pf;
static void *legacy_s390_alloc(size_t size);
int kvm_arch_init(KVMState *s)
{
cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
+ cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
phys_mem_set_alloc(legacy_s390_alloc);
return ret;
}
+ if (cap_async_pf) {
+ reg.id = KVM_REG_S390_PFTOKEN;
+ reg.addr = (__u64)&(env->pfault_token);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret < 0) {
+ return ret;
+ }
+
+ reg.id = KVM_REG_S390_PFCOMPARE;
+ reg.addr = (__u64)&(env->pfault_compare);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret < 0) {
+ return ret;
+ }
+
+ reg.id = KVM_REG_S390_PFSELECT;
+ reg.addr = (__u64)&(env->pfault_select);
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
if (cap_sync_regs &&
cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS &&
cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) {
return r;
}
+ if (cap_async_pf) {
+ reg.id = KVM_REG_S390_PFTOKEN;
+ reg.addr = (__u64)&(env->pfault_token);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (r < 0) {
+ return r;
+ }
+
+ reg.id = KVM_REG_S390_PFCOMPARE;
+ reg.addr = (__u64)&(env->pfault_compare);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (r < 0) {
+ return r;
+ }
+
+ reg.id = KVM_REG_S390_PFSELECT;
+ reg.addr = (__u64)&(env->pfault_select);
+ r = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (r < 0) {
+ return r;
+ }
+ }
+
return 0;
}