diff options
Diffstat (limited to 'arch/s390/kvm/kvm-s390.c')
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index a906499214bb..5e3473c9a639 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/kvm_host.h> | 20 | #include <linux/kvm_host.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/timer.h> | ||
23 | #include <asm/lowcore.h> | 24 | #include <asm/lowcore.h> |
24 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
25 | 26 | ||
@@ -34,6 +35,19 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
34 | { "exit_stop_request", VCPU_STAT(exit_stop_request) }, | 35 | { "exit_stop_request", VCPU_STAT(exit_stop_request) }, |
35 | { "exit_external_request", VCPU_STAT(exit_external_request) }, | 36 | { "exit_external_request", VCPU_STAT(exit_external_request) }, |
36 | { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, | 37 | { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) }, |
38 | { "exit_instruction", VCPU_STAT(exit_instruction) }, | ||
39 | { "exit_program_interruption", VCPU_STAT(exit_program_interruption) }, | ||
40 | { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, | ||
41 | { "instruction_lctg", VCPU_STAT(instruction_lctg) }, | ||
42 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, | ||
43 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, | ||
44 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, | ||
45 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, | ||
46 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, | ||
47 | { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) }, | ||
48 | { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) }, | ||
49 | { "deliver_program_interruption", VCPU_STAT(deliver_program_int) }, | ||
50 | { "exit_wait_state", VCPU_STAT(exit_wait_state) }, | ||
37 | { NULL } | 51 | { NULL } |
38 | }; | 52 | }; |
39 | 53 | ||
@@ -106,6 +120,15 @@ long kvm_arch_vm_ioctl(struct file *filp, | |||
106 | int r; | 120 | int r; |
107 | 121 | ||
108 | switch (ioctl) { | 122 | switch (ioctl) { |
123 | case KVM_S390_INTERRUPT: { | ||
124 | struct kvm_s390_interrupt s390int; | ||
125 | |||
126 | r = -EFAULT; | ||
127 | if (copy_from_user(&s390int, argp, sizeof(s390int))) | ||
128 | break; | ||
129 | r = kvm_s390_inject_vm(kvm, &s390int); | ||
130 | break; | ||
131 | } | ||
109 | default: | 132 | default: |
110 | r = -EINVAL; | 133 | r = -EINVAL; |
111 | } | 134 | } |
@@ -138,6 +161,9 @@ struct kvm *kvm_arch_create_vm(void) | |||
138 | if (!kvm->arch.dbf) | 161 | if (!kvm->arch.dbf) |
139 | goto out_nodbf; | 162 | goto out_nodbf; |
140 | 163 | ||
164 | spin_lock_init(&kvm->arch.float_int.lock); | ||
165 | INIT_LIST_HEAD(&kvm->arch.float_int.list); | ||
166 | |||
141 | debug_register_view(kvm->arch.dbf, &debug_sprintf_view); | 167 | debug_register_view(kvm->arch.dbf, &debug_sprintf_view); |
142 | VM_EVENT(kvm, 3, "%s", "vm created"); | 168 | VM_EVENT(kvm, 3, "%s", "vm created"); |
143 | 169 | ||
@@ -218,7 +244,8 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | |||
218 | vcpu->arch.sie_block->gmsor = 0x000000000000; | 244 | vcpu->arch.sie_block->gmsor = 0x000000000000; |
219 | vcpu->arch.sie_block->ecb = 2; | 245 | vcpu->arch.sie_block->ecb = 2; |
220 | vcpu->arch.sie_block->eca = 0xC1002001U; | 246 | vcpu->arch.sie_block->eca = 0xC1002001U; |
221 | 247 | setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup, | |
248 | (unsigned long) vcpu); | ||
222 | return 0; | 249 | return 0; |
223 | } | 250 | } |
224 | 251 | ||
@@ -243,6 +270,14 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, | |||
243 | vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32); | 270 | vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32); |
244 | vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca; | 271 | vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca; |
245 | 272 | ||
273 | spin_lock_init(&vcpu->arch.local_int.lock); | ||
274 | INIT_LIST_HEAD(&vcpu->arch.local_int.list); | ||
275 | vcpu->arch.local_int.float_int = &kvm->arch.float_int; | ||
276 | spin_lock_bh(&kvm->arch.float_int.lock); | ||
277 | kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int; | ||
278 | init_waitqueue_head(&vcpu->arch.local_int.wq); | ||
279 | spin_unlock_bh(&kvm->arch.float_int.lock); | ||
280 | |||
246 | rc = kvm_vcpu_init(vcpu, kvm, id); | 281 | rc = kvm_vcpu_init(vcpu, kvm, id); |
247 | if (rc) | 282 | if (rc) |
248 | goto out_free_cpu; | 283 | goto out_free_cpu; |
@@ -395,6 +430,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
395 | 430 | ||
396 | atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); | 431 | atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); |
397 | 432 | ||
433 | BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL); | ||
434 | |||
398 | switch (kvm_run->exit_reason) { | 435 | switch (kvm_run->exit_reason) { |
399 | case KVM_EXIT_S390_SIEIC: | 436 | case KVM_EXIT_S390_SIEIC: |
400 | vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; | 437 | vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask; |
@@ -410,8 +447,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
410 | might_sleep(); | 447 | might_sleep(); |
411 | 448 | ||
412 | do { | 449 | do { |
450 | kvm_s390_deliver_pending_interrupts(vcpu); | ||
413 | __vcpu_run(vcpu); | 451 | __vcpu_run(vcpu); |
414 | |||
415 | rc = kvm_handle_sie_intercept(vcpu); | 452 | rc = kvm_handle_sie_intercept(vcpu); |
416 | } while (!signal_pending(current) && !rc); | 453 | } while (!signal_pending(current) && !rc); |
417 | 454 | ||
@@ -538,6 +575,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
538 | void __user *argp = (void __user *)arg; | 575 | void __user *argp = (void __user *)arg; |
539 | 576 | ||
540 | switch (ioctl) { | 577 | switch (ioctl) { |
578 | case KVM_S390_INTERRUPT: { | ||
579 | struct kvm_s390_interrupt s390int; | ||
580 | |||
581 | if (copy_from_user(&s390int, argp, sizeof(s390int))) | ||
582 | return -EFAULT; | ||
583 | return kvm_s390_inject_vcpu(vcpu, &s390int); | ||
584 | } | ||
541 | case KVM_S390_STORE_STATUS: | 585 | case KVM_S390_STORE_STATUS: |
542 | return kvm_s390_vcpu_store_status(vcpu, arg); | 586 | return kvm_s390_vcpu_store_status(vcpu, arg); |
543 | case KVM_S390_SET_INITIAL_PSW: { | 587 | case KVM_S390_SET_INITIAL_PSW: { |