s390x/async_pf: Check for apf extension and enable pfault

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>
This commit is contained in:
Dominik Dingel 2013-09-05 13:54:39 +02:00 committed by Christian Borntraeger
parent 3a553fc658
commit 819bd3091e
4 changed files with 94 additions and 0 deletions

View File

@ -63,6 +63,34 @@ static int flic_get_all_irqs(KVMS390FLICState *flic,
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
@ -136,6 +164,8 @@ static void kvm_flic_save(QEMUFile *f, void *opaque)
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
@ -184,6 +214,8 @@ static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
goto out;
}
flic_enable_pfault((struct KVMS390FLICState *) opaque);
count = qemu_get_be64(f);
len = count * sizeof(struct kvm_s390_irq);
if (count == FLIC_FAILED) {
@ -256,10 +288,14 @@ static void kvm_s390_flic_reset(DeviceState *dev)
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)

View File

@ -83,6 +83,7 @@ static void s390_cpu_reset(CPUState *s)
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)
@ -105,6 +106,8 @@ static void s390_cpu_initial_reset(CPUState *s)
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
env->pfault_token = -1UL;
}
/* CPUClass:reset() */
@ -123,6 +126,9 @@ static void s390_cpu_full_reset(CPUState *s)
/* 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 */

View File

@ -121,6 +121,10 @@ typedef struct CPUS390XState {
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 */

View File

@ -87,12 +87,14 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
};
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);
@ -178,6 +180,29 @@ int kvm_arch_put_registers(CPUState *cs, int level)
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, &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, &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, &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) {
@ -282,6 +307,29 @@ int kvm_arch_get_registers(CPUState *cs)
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, &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, &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, &reg);
if (r < 0) {
return r;
}
}
return 0;
}