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 | |
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>
-rw-r--r-- | Documentation/virtual/kvm/api.txt | 10 | ||||
-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 | ||||
-rw-r--r-- | include/uapi/linux/kvm.h | 4 |
7 files changed, 56 insertions, 8 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 904c61cdd311..a41465bd6a5c 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
@@ -974,7 +974,7 @@ for vm-wide capabilities. | |||
974 | 4.38 KVM_GET_MP_STATE | 974 | 4.38 KVM_GET_MP_STATE |
975 | 975 | ||
976 | Capability: KVM_CAP_MP_STATE | 976 | Capability: KVM_CAP_MP_STATE |
977 | Architectures: x86, ia64 | 977 | Architectures: x86, ia64, s390 |
978 | Type: vcpu ioctl | 978 | Type: vcpu ioctl |
979 | Parameters: struct kvm_mp_state (out) | 979 | Parameters: struct kvm_mp_state (out) |
980 | Returns: 0 on success; -1 on error | 980 | Returns: 0 on success; -1 on error |
@@ -998,6 +998,12 @@ Possible values are: | |||
998 | is waiting for an interrupt [x86, ia64] | 998 | is waiting for an interrupt [x86, ia64] |
999 | - KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector | 999 | - KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector |
1000 | accessible via KVM_GET_VCPU_EVENTS) [x86, ia64] | 1000 | accessible via KVM_GET_VCPU_EVENTS) [x86, ia64] |
1001 | - KVM_MP_STATE_STOPPED: the vcpu is stopped [s390] | ||
1002 | - KVM_MP_STATE_CHECK_STOP: the vcpu is in a special error state [s390] | ||
1003 | - KVM_MP_STATE_OPERATING: the vcpu is operating (running or halted) | ||
1004 | [s390] | ||
1005 | - KVM_MP_STATE_LOAD: the vcpu is in a special load/startup state | ||
1006 | [s390] | ||
1001 | 1007 | ||
1002 | On x86 and ia64, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an | 1008 | On x86 and ia64, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an |
1003 | in-kernel irqchip, the multiprocessing state must be maintained by userspace on | 1009 | in-kernel irqchip, the multiprocessing state must be maintained by userspace on |
@@ -1007,7 +1013,7 @@ these architectures. | |||
1007 | 4.39 KVM_SET_MP_STATE | 1013 | 4.39 KVM_SET_MP_STATE |
1008 | 1014 | ||
1009 | Capability: KVM_CAP_MP_STATE | 1015 | Capability: KVM_CAP_MP_STATE |
1010 | Architectures: x86, ia64 | 1016 | Architectures: x86, ia64, s390 |
1011 | Type: vcpu ioctl | 1017 | Type: vcpu ioctl |
1012 | Parameters: struct kvm_mp_state (in) | 1018 | Parameters: struct kvm_mp_state (in) |
1013 | Returns: 0 on success; -1 on error | 1019 | Returns: 0 on success; -1 on error |
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); |
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 37d4ec6f14d8..9b744af871d7 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h | |||
@@ -407,6 +407,10 @@ struct kvm_vapic_addr { | |||
407 | #define KVM_MP_STATE_INIT_RECEIVED 2 | 407 | #define KVM_MP_STATE_INIT_RECEIVED 2 |
408 | #define KVM_MP_STATE_HALTED 3 | 408 | #define KVM_MP_STATE_HALTED 3 |
409 | #define KVM_MP_STATE_SIPI_RECEIVED 4 | 409 | #define KVM_MP_STATE_SIPI_RECEIVED 4 |
410 | #define KVM_MP_STATE_STOPPED 5 | ||
411 | #define KVM_MP_STATE_CHECK_STOP 6 | ||
412 | #define KVM_MP_STATE_OPERATING 7 | ||
413 | #define KVM_MP_STATE_LOAD 8 | ||
410 | 414 | ||
411 | struct kvm_mp_state { | 415 | struct kvm_mp_state { |
412 | __u32 mp_state; | 416 | __u32 mp_state; |