diff options
author | David Hildenbrand <dahi@linux.vnet.ibm.com> | 2014-04-10 11:35:00 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-07-10 08:11:17 -0400 |
commit | 6352e4d2dd9a349024a41356148eced553e1dce4 (patch) | |
tree | 2835b0ebeacb7dc0f13e4df266f38e441b08243a /arch/s390 | |
parent | 0b4820d6d8b6448bc9f7fac1bb1a801a53b425e1 (diff) |
KVM: s390: implement KVM_(S|G)ET_MP_STATE for user space state control
This patch
- adds s390 specific MP states to linux headers and documents them
- implements the KVM_{SET,GET}_MP_STATE ioctls
- enables KVM_CAP_MP_STATE
- allows user space to control the VCPU state on s390.
If user space sets the VCPU state using the ioctl KVM_SET_MP_STATE, we can disable
manual changing of the VCPU state and trust user space to do the right thing.
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/diag.c | 3 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 3 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 37 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 6 |
5 files changed, 44 insertions, 6 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 4181d7baabba..c2ba0208a0e1 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -418,6 +418,7 @@ struct kvm_arch{ | |||
418 | int css_support; | 418 | int css_support; |
419 | int use_irqchip; | 419 | int use_irqchip; |
420 | int use_cmma; | 420 | int use_cmma; |
421 | int user_cpu_state_ctrl; | ||
421 | struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; | 422 | struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; |
422 | wait_queue_head_t ipte_wq; | 423 | wait_queue_head_t ipte_wq; |
423 | spinlock_t start_stop_lock; | 424 | spinlock_t start_stop_lock; |
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 0161675878a2..59bd8f991b98 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c | |||
@@ -176,7 +176,8 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) | |||
176 | return -EOPNOTSUPP; | 176 | return -EOPNOTSUPP; |
177 | } | 177 | } |
178 | 178 | ||
179 | kvm_s390_vcpu_stop(vcpu); | 179 | if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) |
180 | kvm_s390_vcpu_stop(vcpu); | ||
180 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; | 181 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_SUBSYSTEM; |
181 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; | 182 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_IPL; |
182 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; | 183 | vcpu->run->s390_reset_flags |= KVM_S390_RESET_CPU_INIT; |
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index ac6b32585a36..eaf46291d361 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -73,7 +73,8 @@ static int handle_stop(struct kvm_vcpu *vcpu) | |||
73 | return rc; | 73 | return rc; |
74 | } | 74 | } |
75 | 75 | ||
76 | kvm_s390_vcpu_stop(vcpu); | 76 | if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) |
77 | kvm_s390_vcpu_stop(vcpu); | ||
77 | return -EOPNOTSUPP; | 78 | return -EOPNOTSUPP; |
78 | } | 79 | } |
79 | 80 | ||
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 342895350825..fdf88f7a539c 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -167,6 +167,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
167 | case KVM_CAP_DEVICE_CTRL: | 167 | case KVM_CAP_DEVICE_CTRL: |
168 | case KVM_CAP_ENABLE_CAP_VM: | 168 | case KVM_CAP_ENABLE_CAP_VM: |
169 | case KVM_CAP_VM_ATTRIBUTES: | 169 | case KVM_CAP_VM_ATTRIBUTES: |
170 | case KVM_CAP_MP_STATE: | ||
170 | r = 1; | 171 | r = 1; |
171 | break; | 172 | break; |
172 | case KVM_CAP_NR_VCPUS: | 173 | case KVM_CAP_NR_VCPUS: |
@@ -595,7 +596,8 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) | |||
595 | vcpu->arch.sie_block->pp = 0; | 596 | vcpu->arch.sie_block->pp = 0; |
596 | vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; | 597 | vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; |
597 | kvm_clear_async_pf_completion_queue(vcpu); | 598 | kvm_clear_async_pf_completion_queue(vcpu); |
598 | kvm_s390_vcpu_stop(vcpu); | 599 | if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) |
600 | kvm_s390_vcpu_stop(vcpu); | ||
599 | kvm_s390_clear_local_irqs(vcpu); | 601 | kvm_s390_clear_local_irqs(vcpu); |
600 | } | 602 | } |
601 | 603 | ||
@@ -980,13 +982,34 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, | |||
980 | int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, | 982 | int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, |
981 | struct kvm_mp_state *mp_state) | 983 | struct kvm_mp_state *mp_state) |
982 | { | 984 | { |
983 | return -EINVAL; /* not implemented yet */ | 985 | /* CHECK_STOP and LOAD are not supported yet */ |
986 | return is_vcpu_stopped(vcpu) ? KVM_MP_STATE_STOPPED : | ||
987 | KVM_MP_STATE_OPERATING; | ||
984 | } | 988 | } |
985 | 989 | ||
986 | int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, | 990 | int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, |
987 | struct kvm_mp_state *mp_state) | 991 | struct kvm_mp_state *mp_state) |
988 | { | 992 | { |
989 | return -EINVAL; /* not implemented yet */ | 993 | int rc = 0; |
994 | |||
995 | /* user space knows about this interface - let it control the state */ | ||
996 | vcpu->kvm->arch.user_cpu_state_ctrl = 1; | ||
997 | |||
998 | switch (mp_state->mp_state) { | ||
999 | case KVM_MP_STATE_STOPPED: | ||
1000 | kvm_s390_vcpu_stop(vcpu); | ||
1001 | break; | ||
1002 | case KVM_MP_STATE_OPERATING: | ||
1003 | kvm_s390_vcpu_start(vcpu); | ||
1004 | break; | ||
1005 | case KVM_MP_STATE_LOAD: | ||
1006 | case KVM_MP_STATE_CHECK_STOP: | ||
1007 | /* fall through - CHECK_STOP and LOAD are not supported yet */ | ||
1008 | default: | ||
1009 | rc = -ENXIO; | ||
1010 | } | ||
1011 | |||
1012 | return rc; | ||
990 | } | 1013 | } |
991 | 1014 | ||
992 | bool kvm_s390_cmma_enabled(struct kvm *kvm) | 1015 | bool kvm_s390_cmma_enabled(struct kvm *kvm) |
@@ -1284,7 +1307,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1284 | if (vcpu->sigset_active) | 1307 | if (vcpu->sigset_active) |
1285 | sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); | 1308 | sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); |
1286 | 1309 | ||
1287 | kvm_s390_vcpu_start(vcpu); | 1310 | if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) { |
1311 | kvm_s390_vcpu_start(vcpu); | ||
1312 | } else if (is_vcpu_stopped(vcpu)) { | ||
1313 | pr_err_ratelimited("kvm-s390: can't run stopped vcpu %d\n", | ||
1314 | vcpu->vcpu_id); | ||
1315 | return -EINVAL; | ||
1316 | } | ||
1288 | 1317 | ||
1289 | switch (kvm_run->exit_reason) { | 1318 | switch (kvm_run->exit_reason) { |
1290 | case KVM_EXIT_S390_SIEIC: | 1319 | case KVM_EXIT_S390_SIEIC: |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 77ed846342d4..33a0e4bed2a5 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -129,6 +129,12 @@ static inline void kvm_s390_set_psw_cc(struct kvm_vcpu *vcpu, unsigned long cc) | |||
129 | vcpu->arch.sie_block->gpsw.mask |= cc << 44; | 129 | vcpu->arch.sie_block->gpsw.mask |= cc << 44; |
130 | } | 130 | } |
131 | 131 | ||
132 | /* are cpu states controlled by user space */ | ||
133 | static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm) | ||
134 | { | ||
135 | return kvm->arch.user_cpu_state_ctrl != 0; | ||
136 | } | ||
137 | |||
132 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); | 138 | int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); |
133 | enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); | 139 | enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer); |
134 | void kvm_s390_tasklet(unsigned long parm); | 140 | void kvm_s390_tasklet(unsigned long parm); |