aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/interrupt.c
diff options
context:
space:
mode:
authorCarsten Otte <cotte@de.ibm.com>2008-03-25 13:47:26 -0400
committerAvi Kivity <avi@qumranet.com>2008-04-27 05:00:44 -0400
commitba5c1e9b6ceebdc39343cc03eb39f077abd3c571 (patch)
treeab07e763ad7d9aad2ef189def5537e73a50c7503 /arch/s390/kvm/interrupt.c
parent8f2abe6a1e525e878bdf58f68ccd146d543fde84 (diff)
KVM: s390: interrupt subsystem, cpu timer, waitpsw
This patch contains the s390 interrupt subsystem (similar to in kernel apic) including timer interrupts (similar to in-kernel-pit) and enabled wait (similar to in kernel hlt). In order to achieve that, this patch also introduces intercept handling for instruction intercepts, and it implements load control instructions. This patch introduces an ioctl KVM_S390_INTERRUPT which is valid for both the vm file descriptors and the vcpu file descriptors. In case this ioctl is issued against a vm file descriptor, the interrupt is considered floating. Floating interrupts may be delivered to any virtual cpu in the configuration. The following interrupts are supported: SIGP STOP - interprocessor signal that stops a remote cpu SIGP SET PREFIX - interprocessor signal that sets the prefix register of a (stopped) remote cpu INT EMERGENCY - interprocessor interrupt, usually used to signal need_reshed and for smp_call_function() in the guest. PROGRAM INT - exception during program execution such as page fault, illegal instruction and friends RESTART - interprocessor signal that starts a stopped cpu INT VIRTIO - floating interrupt for virtio signalisation INT SERVICE - floating interrupt for signalisations from the system service processor struct kvm_s390_interrupt, which is submitted as ioctl parameter when injecting an interrupt, also carrys parameter data for interrupts along with the interrupt type. Interrupts on s390 usually have a state that represents the current operation, or identifies which device has caused the interruption on s390. kvm_s390_handle_wait() does handle waitpsw in two flavors: in case of a disabled wait (that is, disabled for interrupts), we exit to userspace. In case of an enabled wait we set up a timer that equals the cpu clock comparator value and sleep on a wait queue. [christian: change virtio interrupt to 0x2603] Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
-rw-r--r--arch/s390/kvm/interrupt.c587
1 files changed, 587 insertions, 0 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
new file mode 100644
index 00000000000..f62588cb75f
--- /dev/null
+++ b/arch/s390/kvm/interrupt.c
@@ -0,0 +1,587 @@
1/*
2 * interrupt.c - handling kvm guest interrupts
3 *
4 * Copyright IBM Corp. 2008
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License (version 2 only)
8 * as published by the Free Software Foundation.
9 *
10 * Author(s): Carsten Otte <cotte@de.ibm.com>
11 */
12
13#include <asm/lowcore.h>
14#include <asm/uaccess.h>
15#include <linux/kvm_host.h>
16#include "kvm-s390.h"
17#include "gaccess.h"
18
19static int psw_extint_disabled(struct kvm_vcpu *vcpu)
20{
21 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
22}
23
24static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
25{
26 if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||
27 (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) ||
28 (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT))
29 return 0;
30 return 1;
31}
32
33static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
34 struct interrupt_info *inti)
35{
36 switch (inti->type) {
37 case KVM_S390_INT_EMERGENCY:
38 if (psw_extint_disabled(vcpu))
39 return 0;
40 if (vcpu->arch.sie_block->gcr[0] & 0x4000ul)
41 return 1;
42 return 0;
43 case KVM_S390_INT_SERVICE:
44 if (psw_extint_disabled(vcpu))
45 return 0;
46 if (vcpu->arch.sie_block->gcr[0] & 0x200ul)
47 return 1;
48 return 0;
49 case KVM_S390_INT_VIRTIO:
50 if (psw_extint_disabled(vcpu))
51 return 0;
52 if (vcpu->arch.sie_block->gcr[0] & 0x200ul)
53 return 1;
54 return 0;
55 case KVM_S390_PROGRAM_INT:
56 case KVM_S390_SIGP_STOP:
57 case KVM_S390_SIGP_SET_PREFIX:
58 case KVM_S390_RESTART:
59 return 1;
60 default:
61 BUG();
62 }
63 return 0;
64}
65
66static void __set_cpu_idle(struct kvm_vcpu *vcpu)
67{
68 BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
69 atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
70 set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
71}
72
73static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
74{
75 BUG_ON(vcpu->vcpu_id > KVM_MAX_VCPUS - 1);
76 atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
77 clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
78}
79
80static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
81{
82 atomic_clear_mask(CPUSTAT_ECALL_PEND |
83 CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT,
84 &vcpu->arch.sie_block->cpuflags);
85 vcpu->arch.sie_block->lctl = 0x0000;
86}
87
88static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
89{
90 atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags);
91}
92
93static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
94 struct interrupt_info *inti)
95{
96 switch (inti->type) {
97 case KVM_S390_INT_EMERGENCY:
98 case KVM_S390_INT_SERVICE:
99 case KVM_S390_INT_VIRTIO:
100 if (psw_extint_disabled(vcpu))
101 __set_cpuflag(vcpu, CPUSTAT_EXT_INT);
102 else
103 vcpu->arch.sie_block->lctl |= LCTL_CR0;
104 break;
105 case KVM_S390_SIGP_STOP:
106 __set_cpuflag(vcpu, CPUSTAT_STOP_INT);
107 break;
108 default:
109 BUG();
110 }
111}
112
113static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
114 struct interrupt_info *inti)
115{
116 const unsigned short table[] = { 2, 4, 4, 6 };
117 int rc, exception = 0;
118
119 switch (inti->type) {
120 case KVM_S390_INT_EMERGENCY:
121 VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
122 vcpu->stat.deliver_emergency_signal++;
123 rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201);
124 if (rc == -EFAULT)
125 exception = 1;
126
127 rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
128 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
129 if (rc == -EFAULT)
130 exception = 1;
131
132 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
133 __LC_EXT_NEW_PSW, sizeof(psw_t));
134 if (rc == -EFAULT)
135 exception = 1;
136 break;
137
138 case KVM_S390_INT_SERVICE:
139 VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
140 inti->ext.ext_params);
141 vcpu->stat.deliver_service_signal++;
142 rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401);
143 if (rc == -EFAULT)
144 exception = 1;
145
146 rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
147 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
148 if (rc == -EFAULT)
149 exception = 1;
150
151 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
152 __LC_EXT_NEW_PSW, sizeof(psw_t));
153 if (rc == -EFAULT)
154 exception = 1;
155
156 rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params);
157 if (rc == -EFAULT)
158 exception = 1;
159 break;
160
161 case KVM_S390_INT_VIRTIO:
162 VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%lx",
163 inti->ext.ext_params, inti->ext.ext_params2);
164 vcpu->stat.deliver_virtio_interrupt++;
165 rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603);
166 if (rc == -EFAULT)
167 exception = 1;
168
169 rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, 0x0d00);
170 if (rc == -EFAULT)
171 exception = 1;
172
173 rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
174 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
175 if (rc == -EFAULT)
176 exception = 1;
177
178 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
179 __LC_EXT_NEW_PSW, sizeof(psw_t));
180 if (rc == -EFAULT)
181 exception = 1;
182
183 rc = put_guest_u32(vcpu, __LC_EXT_PARAMS, inti->ext.ext_params);
184 if (rc == -EFAULT)
185 exception = 1;
186
187 rc = put_guest_u64(vcpu, __LC_PFAULT_INTPARM,
188 inti->ext.ext_params2);
189 if (rc == -EFAULT)
190 exception = 1;
191 break;
192
193 case KVM_S390_SIGP_STOP:
194 VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
195 vcpu->stat.deliver_stop_signal++;
196 __set_intercept_indicator(vcpu, inti);
197 break;
198
199 case KVM_S390_SIGP_SET_PREFIX:
200 VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
201 inti->prefix.address);
202 vcpu->stat.deliver_prefix_signal++;
203 vcpu->arch.sie_block->prefix = inti->prefix.address;
204 vcpu->arch.sie_block->ihcpu = 0xffff;
205 break;
206
207 case KVM_S390_RESTART:
208 VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
209 vcpu->stat.deliver_restart_signal++;
210 rc = copy_to_guest(vcpu, offsetof(struct _lowcore,
211 restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
212 if (rc == -EFAULT)
213 exception = 1;
214
215 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
216 offsetof(struct _lowcore, restart_psw), sizeof(psw_t));
217 if (rc == -EFAULT)
218 exception = 1;
219 break;
220
221 case KVM_S390_PROGRAM_INT:
222 VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x",
223 inti->pgm.code,
224 table[vcpu->arch.sie_block->ipa >> 14]);
225 vcpu->stat.deliver_program_int++;
226 rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code);
227 if (rc == -EFAULT)
228 exception = 1;
229
230 rc = put_guest_u16(vcpu, __LC_PGM_ILC,
231 table[vcpu->arch.sie_block->ipa >> 14]);
232 if (rc == -EFAULT)
233 exception = 1;
234
235 rc = copy_to_guest(vcpu, __LC_PGM_OLD_PSW,
236 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
237 if (rc == -EFAULT)
238 exception = 1;
239
240 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
241 __LC_PGM_NEW_PSW, sizeof(psw_t));
242 if (rc == -EFAULT)
243 exception = 1;
244 break;
245
246 default:
247 BUG();
248 }
249
250 if (exception) {
251 VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering"
252 " interrupt");
253 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
254 if (inti->type == KVM_S390_PROGRAM_INT) {
255 printk(KERN_WARNING "kvm: recursive program check\n");
256 BUG();
257 }
258 }
259}
260
261static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
262{
263 int rc, exception = 0;
264
265 if (psw_extint_disabled(vcpu))
266 return 0;
267 if (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))
268 return 0;
269 rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1004);
270 if (rc == -EFAULT)
271 exception = 1;
272 rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
273 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
274 if (rc == -EFAULT)
275 exception = 1;
276 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
277 __LC_EXT_NEW_PSW, sizeof(psw_t));
278 if (rc == -EFAULT)
279 exception = 1;
280
281 if (exception) {
282 VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" \
283 " ckc interrupt");
284 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
285 return 0;
286 }
287
288 return 1;
289}
290
291int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
292{
293 struct local_interrupt *li = &vcpu->arch.local_int;
294 struct float_interrupt *fi = vcpu->arch.local_int.float_int;
295 struct interrupt_info *inti;
296 int rc = 0;
297
298 if (atomic_read(&li->active)) {
299 spin_lock_bh(&li->lock);
300 list_for_each_entry(inti, &li->list, list)
301 if (__interrupt_is_deliverable(vcpu, inti)) {
302 rc = 1;
303 break;
304 }
305 spin_unlock_bh(&li->lock);
306 }
307
308 if ((!rc) && atomic_read(&fi->active)) {
309 spin_lock_bh(&fi->lock);
310 list_for_each_entry(inti, &fi->list, list)
311 if (__interrupt_is_deliverable(vcpu, inti)) {
312 rc = 1;
313 break;
314 }
315 spin_unlock_bh(&fi->lock);
316 }
317
318 if ((!rc) && (vcpu->arch.sie_block->ckc <
319 get_clock() + vcpu->arch.sie_block->epoch)) {
320 if ((!psw_extint_disabled(vcpu)) &&
321 (vcpu->arch.sie_block->gcr[0] & 0x800ul))
322 rc = 1;
323 }
324
325 return rc;
326}
327
328int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
329{
330 u64 now, sltime;
331 DECLARE_WAITQUEUE(wait, current);
332
333 vcpu->stat.exit_wait_state++;
334 if (kvm_cpu_has_interrupt(vcpu))
335 return 0;
336
337 if (psw_interrupts_disabled(vcpu)) {
338 VCPU_EVENT(vcpu, 3, "%s", "disabled wait");
339 __unset_cpu_idle(vcpu);
340 return -ENOTSUPP; /* disabled wait */
341 }
342
343 if (psw_extint_disabled(vcpu) ||
344 (!(vcpu->arch.sie_block->gcr[0] & 0x800ul))) {
345 VCPU_EVENT(vcpu, 3, "%s", "enabled wait w/o timer");
346 goto no_timer;
347 }
348
349 now = get_clock() + vcpu->arch.sie_block->epoch;
350 if (vcpu->arch.sie_block->ckc < now) {
351 __unset_cpu_idle(vcpu);
352 return 0;
353 }
354
355 sltime = (vcpu->arch.sie_block->ckc - now) / (0xf4240000ul / HZ) + 1;
356
357 vcpu->arch.ckc_timer.expires = jiffies + sltime;
358
359 add_timer(&vcpu->arch.ckc_timer);
360 VCPU_EVENT(vcpu, 5, "enabled wait timer:%lx jiffies", sltime);
361no_timer:
362 spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
363 spin_lock_bh(&vcpu->arch.local_int.lock);
364 __set_cpu_idle(vcpu);
365 vcpu->arch.local_int.timer_due = 0;
366 add_wait_queue(&vcpu->arch.local_int.wq, &wait);
367 while (list_empty(&vcpu->arch.local_int.list) &&
368 list_empty(&vcpu->arch.local_int.float_int->list) &&
369 (!vcpu->arch.local_int.timer_due) &&
370 !signal_pending(current)) {
371 set_current_state(TASK_INTERRUPTIBLE);
372 spin_unlock_bh(&vcpu->arch.local_int.lock);
373 spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
374 vcpu_put(vcpu);
375 schedule();
376 vcpu_load(vcpu);
377 spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
378 spin_lock_bh(&vcpu->arch.local_int.lock);
379 }
380 __unset_cpu_idle(vcpu);
381 __set_current_state(TASK_RUNNING);
382 remove_wait_queue(&vcpu->wq, &wait);
383 spin_unlock_bh(&vcpu->arch.local_int.lock);
384 spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
385 del_timer(&vcpu->arch.ckc_timer);
386 return 0;
387}
388
389void kvm_s390_idle_wakeup(unsigned long data)
390{
391 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
392
393 spin_lock_bh(&vcpu->arch.local_int.lock);
394 vcpu->arch.local_int.timer_due = 1;
395 if (waitqueue_active(&vcpu->arch.local_int.wq))
396 wake_up_interruptible(&vcpu->arch.local_int.wq);
397 spin_unlock_bh(&vcpu->arch.local_int.lock);
398}
399
400
401void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
402{
403 struct local_interrupt *li = &vcpu->arch.local_int;
404 struct float_interrupt *fi = vcpu->arch.local_int.float_int;
405 struct interrupt_info *n, *inti = NULL;
406 int deliver;
407
408 __reset_intercept_indicators(vcpu);
409 if (atomic_read(&li->active)) {
410 do {
411 deliver = 0;
412 spin_lock_bh(&li->lock);
413 list_for_each_entry_safe(inti, n, &li->list, list) {
414 if (__interrupt_is_deliverable(vcpu, inti)) {
415 list_del(&inti->list);
416 deliver = 1;
417 break;
418 }
419 __set_intercept_indicator(vcpu, inti);
420 }
421 if (list_empty(&li->list))
422 atomic_set(&li->active, 0);
423 spin_unlock_bh(&li->lock);
424 if (deliver) {
425 __do_deliver_interrupt(vcpu, inti);
426 kfree(inti);
427 }
428 } while (deliver);
429 }
430
431 if ((vcpu->arch.sie_block->ckc <
432 get_clock() + vcpu->arch.sie_block->epoch))
433 __try_deliver_ckc_interrupt(vcpu);
434
435 if (atomic_read(&fi->active)) {
436 do {
437 deliver = 0;
438 spin_lock_bh(&fi->lock);
439 list_for_each_entry_safe(inti, n, &fi->list, list) {
440 if (__interrupt_is_deliverable(vcpu, inti)) {
441 list_del(&inti->list);
442 deliver = 1;
443 break;
444 }
445 __set_intercept_indicator(vcpu, inti);
446 }
447 if (list_empty(&fi->list))
448 atomic_set(&fi->active, 0);
449 spin_unlock_bh(&fi->lock);
450 if (deliver) {
451 __do_deliver_interrupt(vcpu, inti);
452 kfree(inti);
453 }
454 } while (deliver);
455 }
456}
457
458int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
459{
460 struct local_interrupt *li = &vcpu->arch.local_int;
461 struct interrupt_info *inti;
462
463 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
464 if (!inti)
465 return -ENOMEM;
466
467 inti->type = KVM_S390_PROGRAM_INT;;
468 inti->pgm.code = code;
469
470 VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
471 spin_lock_bh(&li->lock);
472 list_add(&inti->list, &li->list);
473 atomic_set(&li->active, 1);
474 BUG_ON(waitqueue_active(&li->wq));
475 spin_unlock_bh(&li->lock);
476 return 0;
477}
478
479int kvm_s390_inject_vm(struct kvm *kvm,
480 struct kvm_s390_interrupt *s390int)
481{
482 struct local_interrupt *li;
483 struct float_interrupt *fi;
484 struct interrupt_info *inti;
485 int sigcpu;
486
487 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
488 if (!inti)
489 return -ENOMEM;
490
491 switch (s390int->type) {
492 case KVM_S390_INT_VIRTIO:
493 VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%lx",
494 s390int->parm, s390int->parm64);
495 inti->type = s390int->type;
496 inti->ext.ext_params = s390int->parm;
497 inti->ext.ext_params2 = s390int->parm64;
498 break;
499 case KVM_S390_INT_SERVICE:
500 VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm);
501 inti->type = s390int->type;
502 inti->ext.ext_params = s390int->parm;
503 break;
504 case KVM_S390_PROGRAM_INT:
505 case KVM_S390_SIGP_STOP:
506 case KVM_S390_INT_EMERGENCY:
507 default:
508 kfree(inti);
509 return -EINVAL;
510 }
511
512 mutex_lock(&kvm->lock);
513 fi = &kvm->arch.float_int;
514 spin_lock_bh(&fi->lock);
515 list_add_tail(&inti->list, &fi->list);
516 atomic_set(&fi->active, 1);
517 sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
518 if (sigcpu == KVM_MAX_VCPUS) {
519 do {
520 sigcpu = fi->next_rr_cpu++;
521 if (sigcpu == KVM_MAX_VCPUS)
522 sigcpu = fi->next_rr_cpu = 0;
523 } while (fi->local_int[sigcpu] == NULL);
524 }
525 li = fi->local_int[sigcpu];
526 spin_lock_bh(&li->lock);
527 atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
528 if (waitqueue_active(&li->wq))
529 wake_up_interruptible(&li->wq);
530 spin_unlock_bh(&li->lock);
531 spin_unlock_bh(&fi->lock);
532 mutex_unlock(&kvm->lock);
533 return 0;
534}
535
536int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
537 struct kvm_s390_interrupt *s390int)
538{
539 struct local_interrupt *li;
540 struct interrupt_info *inti;
541
542 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
543 if (!inti)
544 return -ENOMEM;
545
546 switch (s390int->type) {
547 case KVM_S390_PROGRAM_INT:
548 if (s390int->parm & 0xffff0000) {
549 kfree(inti);
550 return -EINVAL;
551 }
552 inti->type = s390int->type;
553 inti->pgm.code = s390int->parm;
554 VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)",
555 s390int->parm);
556 break;
557 case KVM_S390_SIGP_STOP:
558 case KVM_S390_RESTART:
559 case KVM_S390_SIGP_SET_PREFIX:
560 case KVM_S390_INT_EMERGENCY:
561 VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
562 inti->type = s390int->type;
563 break;
564 case KVM_S390_INT_VIRTIO:
565 case KVM_S390_INT_SERVICE:
566 default:
567 kfree(inti);
568 return -EINVAL;
569 }
570
571 mutex_lock(&vcpu->kvm->lock);
572 li = &vcpu->arch.local_int;
573 spin_lock_bh(&li->lock);
574 if (inti->type == KVM_S390_PROGRAM_INT)
575 list_add(&inti->list, &li->list);
576 else
577 list_add_tail(&inti->list, &li->list);
578 atomic_set(&li->active, 1);
579 if (inti->type == KVM_S390_SIGP_STOP)
580 li->action_bits |= ACTION_STOP_ON_STOP;
581 atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
582 if (waitqueue_active(&li->wq))
583 wake_up_interruptible(&vcpu->arch.local_int.wq);
584 spin_unlock_bh(&li->lock);
585 mutex_unlock(&vcpu->kvm->lock);
586 return 0;
587}