aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2012-12-20 09:32:08 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-01-07 16:53:40 -0500
commitd8346b7d9bab37e6cc712ff1622c65ff98bdfef8 (patch)
tree60f36ff7f61757501f3560d8860ca217d7e92640
parentb1c571a50dfacf25a24c23271e9b8bf18ff6b102 (diff)
KVM: s390: Support for I/O interrupts.
Add support for handling I/O interrupts (standard, subchannel-related ones and rudimentary adapter interrupts). The subchannel-identifying parameters are encoded into the interrupt type. I/O interrupts are floating, so they can't be injected on a specific vcpu. Reviewed-by: Alexander Graf <agraf@suse.de> Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--Documentation/virtual/kvm/api.txt4
-rw-r--r--arch/s390/include/asm/kvm_host.h2
-rw-r--r--arch/s390/kvm/interrupt.c103
-rw-r--r--include/uapi/linux/kvm.h9
4 files changed, 116 insertions, 2 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index a4df5535996b..83bd92b52936 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2069,6 +2069,10 @@ KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt
2069KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm 2069KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
2070KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm 2070KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm
2071KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm 2071KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm
2072KVM_S390_INT_IO(ai,cssid,ssid,schid) (vm) - compound value to indicate an
2073 I/O interrupt (ai - adapter interrupt; cssid,ssid,schid - subchannel);
2074 I/O interruption parameters in parm (subchannel) and parm64 (intparm,
2075 interruption subclass)
2072 2076
2073Note that the vcpu ioctl is asynchronous to vcpu execution. 2077Note that the vcpu ioctl is asynchronous to vcpu execution.
2074 2078
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 711c5ab391cf..a8e35c43df78 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -74,6 +74,7 @@ struct kvm_s390_sie_block {
74 __u64 epoch; /* 0x0038 */ 74 __u64 epoch; /* 0x0038 */
75 __u8 reserved40[4]; /* 0x0040 */ 75 __u8 reserved40[4]; /* 0x0040 */
76#define LCTL_CR0 0x8000 76#define LCTL_CR0 0x8000
77#define LCTL_CR6 0x0200
77 __u16 lctl; /* 0x0044 */ 78 __u16 lctl; /* 0x0044 */
78 __s16 icpua; /* 0x0046 */ 79 __s16 icpua; /* 0x0046 */
79 __u32 ictl; /* 0x0048 */ 80 __u32 ictl; /* 0x0048 */
@@ -125,6 +126,7 @@ struct kvm_vcpu_stat {
125 u32 deliver_prefix_signal; 126 u32 deliver_prefix_signal;
126 u32 deliver_restart_signal; 127 u32 deliver_restart_signal;
127 u32 deliver_program_int; 128 u32 deliver_program_int;
129 u32 deliver_io_int;
128 u32 exit_wait_state; 130 u32 exit_wait_state;
129 u32 instruction_stidp; 131 u32 instruction_stidp;
130 u32 instruction_spx; 132 u32 instruction_spx;
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index c30615e605ac..52cdf20906ab 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -21,11 +21,26 @@
21#include "gaccess.h" 21#include "gaccess.h"
22#include "trace-s390.h" 22#include "trace-s390.h"
23 23
24#define IOINT_SCHID_MASK 0x0000ffff
25#define IOINT_SSID_MASK 0x00030000
26#define IOINT_CSSID_MASK 0x03fc0000
27#define IOINT_AI_MASK 0x04000000
28
29static int is_ioint(u64 type)
30{
31 return ((type & 0xfffe0000u) != 0xfffe0000u);
32}
33
24static int psw_extint_disabled(struct kvm_vcpu *vcpu) 34static int psw_extint_disabled(struct kvm_vcpu *vcpu)
25{ 35{
26 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); 36 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
27} 37}
28 38
39static int psw_ioint_disabled(struct kvm_vcpu *vcpu)
40{
41 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO);
42}
43
29static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) 44static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
30{ 45{
31 if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || 46 if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||
@@ -67,7 +82,15 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
67 case KVM_S390_SIGP_SET_PREFIX: 82 case KVM_S390_SIGP_SET_PREFIX:
68 case KVM_S390_RESTART: 83 case KVM_S390_RESTART:
69 return 1; 84 return 1;
85 case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
86 if (psw_ioint_disabled(vcpu))
87 return 0;
88 if (vcpu->arch.sie_block->gcr[6] & inti->io.io_int_word)
89 return 1;
90 return 0;
70 default: 91 default:
92 printk(KERN_WARNING "illegal interrupt type %llx\n",
93 inti->type);
71 BUG(); 94 BUG();
72 } 95 }
73 return 0; 96 return 0;
@@ -116,6 +139,12 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
116 case KVM_S390_SIGP_STOP: 139 case KVM_S390_SIGP_STOP:
117 __set_cpuflag(vcpu, CPUSTAT_STOP_INT); 140 __set_cpuflag(vcpu, CPUSTAT_STOP_INT);
118 break; 141 break;
142 case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
143 if (psw_ioint_disabled(vcpu))
144 __set_cpuflag(vcpu, CPUSTAT_IO_INT);
145 else
146 vcpu->arch.sie_block->lctl |= LCTL_CR6;
147 break;
119 default: 148 default:
120 BUG(); 149 BUG();
121 } 150 }
@@ -297,6 +326,47 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
297 exception = 1; 326 exception = 1;
298 break; 327 break;
299 328
329 case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
330 {
331 __u32 param0 = ((__u32)inti->io.subchannel_id << 16) |
332 inti->io.subchannel_nr;
333 __u64 param1 = ((__u64)inti->io.io_int_parm << 32) |
334 inti->io.io_int_word;
335 VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type);
336 vcpu->stat.deliver_io_int++;
337 trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
338 param0, param1);
339 rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_ID,
340 inti->io.subchannel_id);
341 if (rc == -EFAULT)
342 exception = 1;
343
344 rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_NR,
345 inti->io.subchannel_nr);
346 if (rc == -EFAULT)
347 exception = 1;
348
349 rc = put_guest_u32(vcpu, __LC_IO_INT_PARM,
350 inti->io.io_int_parm);
351 if (rc == -EFAULT)
352 exception = 1;
353
354 rc = put_guest_u32(vcpu, __LC_IO_INT_WORD,
355 inti->io.io_int_word);
356 if (rc == -EFAULT)
357 exception = 1;
358
359 rc = copy_to_guest(vcpu, __LC_IO_OLD_PSW,
360 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
361 if (rc == -EFAULT)
362 exception = 1;
363
364 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
365 __LC_IO_NEW_PSW, sizeof(psw_t));
366 if (rc == -EFAULT)
367 exception = 1;
368 break;
369 }
300 default: 370 default:
301 BUG(); 371 BUG();
302 } 372 }
@@ -545,7 +615,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
545{ 615{
546 struct kvm_s390_local_interrupt *li; 616 struct kvm_s390_local_interrupt *li;
547 struct kvm_s390_float_interrupt *fi; 617 struct kvm_s390_float_interrupt *fi;
548 struct kvm_s390_interrupt_info *inti; 618 struct kvm_s390_interrupt_info *inti, *iter;
549 int sigcpu; 619 int sigcpu;
550 620
551 inti = kzalloc(sizeof(*inti), GFP_KERNEL); 621 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -569,6 +639,22 @@ int kvm_s390_inject_vm(struct kvm *kvm,
569 case KVM_S390_SIGP_STOP: 639 case KVM_S390_SIGP_STOP:
570 case KVM_S390_INT_EXTERNAL_CALL: 640 case KVM_S390_INT_EXTERNAL_CALL:
571 case KVM_S390_INT_EMERGENCY: 641 case KVM_S390_INT_EMERGENCY:
642 kfree(inti);
643 return -EINVAL;
644 case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
645 if (s390int->type & IOINT_AI_MASK)
646 VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
647 else
648 VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
649 s390int->type & IOINT_CSSID_MASK,
650 s390int->type & IOINT_SSID_MASK,
651 s390int->type & IOINT_SCHID_MASK);
652 inti->type = s390int->type;
653 inti->io.subchannel_id = s390int->parm >> 16;
654 inti->io.subchannel_nr = s390int->parm & 0x0000ffffu