Patchwork [1/2] KVM: s390: add and extend interrupt information data structs

login
register
mail settings
Submitter Jens Freimann
Date July 29, 2013, 1:59 p.m.
Message ID <1375106393-15811-2-git-send-email-jfrei@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/262813/
State New
Headers show

Comments

Jens Freimann - July 29, 2013, 1:59 p.m.
With the currently available struct kvm_s390_interrupt it is not possible to
inject all kinds of interrupts as defined in the z/Architecture. Add
interruption parameters to the structures to make sure we can inject all kinds
of interrupts and move it to kvm.h

Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
 arch/s390/include/asm/kvm_host.h |  45 +---------
 arch/s390/kvm/interrupt.c        | 189 +++++++++++++++++++--------------------
 arch/s390/kvm/priv.c             |  22 ++---
 arch/s390/kvm/sigp.c             |  14 +--
 include/uapi/linux/kvm.h         |  62 +++++++++++++
 5 files changed, 175 insertions(+), 157 deletions(-)

Patch

diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 3238d40..c755a9d 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -16,6 +16,7 @@ 
 #include <linux/hrtimer.h>
 #include <linux/interrupt.h>
 #include <linux/kvm_host.h>
+#include <linux/kvm.h>
 #include <asm/debug.h>
 #include <asm/cpu.h>
 
@@ -162,18 +163,6 @@  struct kvm_vcpu_stat {
 	u32 diagnose_9c;
 };
 
-struct kvm_s390_io_info {
-	__u16        subchannel_id;            /* 0x0b8 */
-	__u16        subchannel_nr;            /* 0x0ba */
-	__u32        io_int_parm;              /* 0x0bc */
-	__u32        io_int_word;              /* 0x0c0 */
-};
-
-struct kvm_s390_ext_info {
-	__u32 ext_params;
-	__u64 ext_params2;
-};
-
 #define PGM_OPERATION            0x01
 #define PGM_PRIVILEGED_OP	 0x02
 #define PGM_EXECUTE              0x03
@@ -182,39 +171,9 @@  struct kvm_s390_ext_info {
 #define PGM_SPECIFICATION        0x06
 #define PGM_DATA                 0x07
 
-struct kvm_s390_pgm_info {
-	__u16 code;
-};
-
-struct kvm_s390_prefix_info {
-	__u32 address;
-};
-
-struct kvm_s390_extcall_info {
-	__u16 code;
-};
-
-struct kvm_s390_emerg_info {
-	__u16 code;
-};
-
-struct kvm_s390_mchk_info {
-	__u64 cr14;
-	__u64 mcic;
-};
-
 struct kvm_s390_interrupt_info {
 	struct list_head list;
-	u64	type;
-	union {
-		struct kvm_s390_io_info io;
-		struct kvm_s390_ext_info ext;
-		struct kvm_s390_pgm_info pgm;
-		struct kvm_s390_emerg_info emerg;
-		struct kvm_s390_extcall_info extcall;
-		struct kvm_s390_prefix_info prefix;
-		struct kvm_s390_mchk_info mchk;
-	};
+	struct kvm_s390_irq irq;
 };
 
 /* for local_interrupt.action_flags */
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 7f35cb3..25cf71d 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -65,7 +65,7 @@  static u64 int_word_to_isc_bits(u32 int_word)
 static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
 				      struct kvm_s390_interrupt_info *inti)
 {
-	switch (inti->type) {
+	switch (inti->irq.type) {
 	case KVM_S390_INT_EXTERNAL_CALL:
 		if (psw_extint_disabled(vcpu))
 			return 0;
@@ -97,19 +97,19 @@  static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
 	case KVM_S390_MCHK:
 		if (psw_mchk_disabled(vcpu))
 			return 0;
-		if (vcpu->arch.sie_block->gcr[14] & inti->mchk.cr14)
+		if (vcpu->arch.sie_block->gcr[14] & inti->irq.mchk.cr14)
 			return 1;
 		return 0;
 	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
 		if (psw_ioint_disabled(vcpu))
 			return 0;
 		if (vcpu->arch.sie_block->gcr[6] &
-		    int_word_to_isc_bits(inti->io.io_int_word))
+		    int_word_to_isc_bits(inti->irq.io.io_int_word))
 			return 1;
 		return 0;
 	default:
 		printk(KERN_WARNING "illegal interrupt type %llx\n",
-		       inti->type);
+		       inti->irq.type);
 		BUG();
 	}
 	return 0;
@@ -146,7 +146,7 @@  static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
 static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
 				      struct kvm_s390_interrupt_info *inti)
 {
-	switch (inti->type) {
+	switch (inti->irq.type) {
 	case KVM_S390_INT_EXTERNAL_CALL:
 	case KVM_S390_INT_EMERGENCY:
 	case KVM_S390_INT_SERVICE:
@@ -182,14 +182,14 @@  static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 	const unsigned short table[] = { 2, 4, 4, 6 };
 	int rc = 0;
 
-	switch (inti->type) {
+	switch (inti->irq.type) {
 	case KVM_S390_INT_EMERGENCY:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
 		vcpu->stat.deliver_emergency_signal++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->emerg.code, 0);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.emerg.code, 0);
 		rc  = put_guest(vcpu, 0x1201, (u16 __user *)__LC_EXT_INT_CODE);
-		rc |= put_guest(vcpu, inti->emerg.code,
+		rc |= put_guest(vcpu, inti->irq.emerg.code,
 				(u16 __user *)__LC_EXT_CPU_ADDR);
 		rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
 				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
@@ -199,10 +199,10 @@  static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 	case KVM_S390_INT_EXTERNAL_CALL:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
 		vcpu->stat.deliver_external_call++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->extcall.code, 0);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.extcall.code, 0);
 		rc  = put_guest(vcpu, 0x1202, (u16 __user *)__LC_EXT_INT_CODE);
-		rc |= put_guest(vcpu, inti->extcall.code,
+		rc |= put_guest(vcpu, inti->irq.extcall.code,
 				(u16 __user *)__LC_EXT_CPU_ADDR);
 		rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
 				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
@@ -211,57 +211,57 @@  static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 		break;
 	case KVM_S390_INT_SERVICE:
 		VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
-			   inti->ext.ext_params);
+			   inti->irq.ext.ext_params);
 		vcpu->stat.deliver_service_signal++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->ext.ext_params, 0);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.ext.ext_params, 0);
 		rc  = put_guest(vcpu, 0x2401, (u16 __user *)__LC_EXT_INT_CODE);
 		rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
 				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
 		rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
 				      __LC_EXT_NEW_PSW, sizeof(psw_t));
-		rc |= put_guest(vcpu, inti->ext.ext_params,
+		rc |= put_guest(vcpu, inti->irq.ext.ext_params,
 				(u32 __user *)__LC_EXT_PARAMS);
 		break;
 	case KVM_S390_INT_VIRTIO:
 		VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
-			   inti->ext.ext_params, inti->ext.ext_params2);
+			   inti->irq.ext.ext_params, inti->irq.ext.ext_params2);
 		vcpu->stat.deliver_virtio_interrupt++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->ext.ext_params,
-						 inti->ext.ext_params2);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.ext.ext_params,
+						 inti->irq.ext.ext_params2);
 		rc  = put_guest(vcpu, 0x2603, (u16 __user *)__LC_EXT_INT_CODE);
 		rc |= put_guest(vcpu, 0x0d00, (u16 __user *)__LC_EXT_CPU_ADDR);
 		rc |= copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
 				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
 		rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
 				      __LC_EXT_NEW_PSW, sizeof(psw_t));
-		rc |= put_guest(vcpu, inti->ext.ext_params,
+		rc |= put_guest(vcpu, inti->irq.ext.ext_params,
 				(u32 __user *)__LC_EXT_PARAMS);
-		rc |= put_guest(vcpu, inti->ext.ext_params2,
+		rc |= put_guest(vcpu, inti->irq.ext.ext_params2,
 				(u64 __user *)__LC_EXT_PARAMS2);
 		break;
 	case KVM_S390_SIGP_STOP:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
 		vcpu->stat.deliver_stop_signal++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
 						 0, 0);
 		__set_intercept_indicator(vcpu, inti);
 		break;
 
 	case KVM_S390_SIGP_SET_PREFIX:
 		VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
-			   inti->prefix.address);
+			   inti->irq.prefix.address);
 		vcpu->stat.deliver_prefix_signal++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->prefix.address, 0);
-		kvm_s390_set_prefix(vcpu, inti->prefix.address);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.prefix.address, 0);
+		kvm_s390_set_prefix(vcpu, inti->irq.prefix.address);
 		break;
 
 	case KVM_S390_RESTART:
 		VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
 		vcpu->stat.deliver_restart_signal++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
 						 0, 0);
 		rc  = copy_to_guest(vcpu,
 				    offsetof(struct _lowcore, restart_old_psw),
@@ -273,12 +273,12 @@  static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 		break;
 	case KVM_S390_PROGRAM_INT:
 		VCPU_EVENT(vcpu, 4, "interrupt: pgm check code:%x, ilc:%x",
-			   inti->pgm.code,
+			   inti->irq.pgm.code,
 			   table[vcpu->arch.sie_block->ipa >> 14]);
 		vcpu->stat.deliver_program_int++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->pgm.code, 0);
-		rc  = put_guest(vcpu, inti->pgm.code, (u16 __user *)__LC_PGM_INT_CODE);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.pgm.code, 0);
+		rc  = put_guest(vcpu, inti->irq.pgm.code, (u16 __user *)__LC_PGM_INT_CODE);
 		rc |= put_guest(vcpu, table[vcpu->arch.sie_block->ipa >> 14],
 				(u16 __user *)__LC_PGM_ILC);
 		rc |= copy_to_guest(vcpu, __LC_PGM_OLD_PSW,
@@ -289,13 +289,13 @@  static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 
 	case KVM_S390_MCHK:
 		VCPU_EVENT(vcpu, 4, "interrupt: machine check mcic=%llx",
-			   inti->mchk.mcic);
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
-						 inti->mchk.cr14,
-						 inti->mchk.mcic);
+			   inti->irq.mchk.mcic);
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
+						 inti->irq.mchk.cr14,
+						 inti->irq.mchk.mcic);
 		rc  = kvm_s390_vcpu_store_status(vcpu,
 						 KVM_S390_STORE_STATUS_PREFIXED);
-		rc |= put_guest(vcpu, inti->mchk.mcic, (u64 __user *) __LC_MCCK_CODE);
+		rc |= put_guest(vcpu, inti->irq.mchk.mcic, (u64 __user *) __LC_MCCK_CODE);
 		rc |= copy_to_guest(vcpu, __LC_MCK_OLD_PSW,
 				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
 		rc |= copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
@@ -304,21 +304,21 @@  static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 
 	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
 	{
-		__u32 param0 = ((__u32)inti->io.subchannel_id << 16) |
-			inti->io.subchannel_nr;
-		__u64 param1 = ((__u64)inti->io.io_int_parm << 32) |
-			inti->io.io_int_word;
-		VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type);
+		__u32 param0 = ((__u32)inti->irq.io.subchannel_id << 16) |
+			inti->irq.io.subchannel_nr;
+		__u64 param1 = ((__u64)inti->irq.io.io_int_parm << 32) |
+			inti->irq.io.io_int_word;
+		VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->irq.type);
 		vcpu->stat.deliver_io_int++;
-		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+		trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->irq.type,
 						 param0, param1);
-		rc  = put_guest(vcpu, inti->io.subchannel_id,
+		rc  = put_guest(vcpu, inti->irq.io.subchannel_id,
 				(u16 __user *) __LC_SUBCHANNEL_ID);
-		rc |= put_guest(vcpu, inti->io.subchannel_nr,
+		rc |= put_guest(vcpu, inti->irq.io.subchannel_nr,
 				(u16 __user *) __LC_SUBCHANNEL_NR);
-		rc |= put_guest(vcpu, inti->io.io_int_parm,
+		rc |= put_guest(vcpu, inti->irq.io.io_int_parm,
 				(u32 __user *) __LC_IO_INT_PARM);
-		rc |= put_guest(vcpu, inti->io.io_int_word,
+		rc |= put_guest(vcpu, inti->irq.io.io_int_word,
 				(u32 __user *) __LC_IO_INT_WORD);
 		rc |= copy_to_guest(vcpu, __LC_IO_OLD_PSW,
 				    &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
@@ -554,7 +554,7 @@  void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
 			deliver = 0;
 			spin_lock_bh(&li->lock);
 			list_for_each_entry_safe(inti, n, &li->list, list) {
-				if ((inti->type == KVM_S390_MCHK) &&
+				if ((inti->irq.type == KVM_S390_MCHK) &&
 				    __interrupt_is_deliverable(vcpu, inti)) {
 					list_del(&inti->list);
 					deliver = 1;
@@ -577,7 +577,7 @@  void kvm_s390_deliver_pending_machine_checks(struct kvm_vcpu *vcpu)
 			deliver = 0;
 			spin_lock(&fi->lock);
 			list_for_each_entry_safe(inti, n, &fi->list, list) {
-				if ((inti->type == KVM_S390_MCHK) &&
+				if ((inti->irq.type == KVM_S390_MCHK) &&
 				    __interrupt_is_deliverable(vcpu, inti)) {
 					list_del(&inti->list);
 					deliver = 1;
@@ -605,11 +605,11 @@  int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
 	if (!inti)
 		return -ENOMEM;
 
-	inti->type = KVM_S390_PROGRAM_INT;
-	inti->pgm.code = code;
+	inti->irq.type = KVM_S390_PROGRAM_INT;
+	inti->irq.pgm.code = code;
 
 	VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
-	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1);
+	trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->irq.type, code, 0, 1);
 	spin_lock_bh(&li->lock);
 	list_add(&inti->list, &li->list);
 	atomic_set(&li->active, 1);
@@ -631,17 +631,17 @@  struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
 	spin_lock(&fi->lock);
 	inti = NULL;
 	list_for_each_entry(iter, &fi->list, list) {
-		if (!is_ioint(iter->type))
+		if (!is_ioint(iter->irq.type))
 			continue;
 		if (cr6 &&
-		    ((cr6 & int_word_to_isc_bits(iter->io.io_int_word)) == 0))
+		    ((cr6 & int_word_to_isc_bits(iter->irq.io.io_int_word)) == 0))
 			continue;
 		if (schid) {
 			if (((schid & 0x00000000ffff0000) >> 16) !=
-			    iter->io.subchannel_id)
+			    iter->irq.io.subchannel_id)
 				continue;
 			if ((schid & 0x000000000000ffff) !=
-			    iter->io.subchannel_nr)
+			    iter->irq.io.subchannel_nr)
 				continue;
 		}
 		inti = iter;
@@ -662,72 +662,69 @@  int kvm_s390_inject_vm(struct kvm *kvm,
 	struct kvm_s390_local_interrupt *li;
 	struct kvm_s390_float_interrupt *fi;
 	struct kvm_s390_interrupt_info *inti, *iter;
+	struct kvm_s390_irq *irq;
 	int sigcpu;
 
 	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
 	if (!inti)
 		return -ENOMEM;
 
-	switch (s390int->type) {
+	irq = &inti->irq;
+
+	irq->type = s390int->type;
+	switch (irq->type) {
 	case KVM_S390_INT_VIRTIO:
 		VM_EVENT(kvm, 5, "inject: virtio parm:%x,parm64:%llx",
 			 s390int->parm, s390int->parm64);
-		inti->type = s390int->type;
-		inti->ext.ext_params = s390int->parm;
-		inti->ext.ext_params2 = s390int->parm64;
+		irq->ext.ext_params = s390int->parm;
+		irq->ext.ext_params2 = s390int->parm64;
 		break;
 	case KVM_S390_INT_SERVICE:
 		VM_EVENT(kvm, 5, "inject: sclp parm:%x", s390int->parm);
-		inti->type = s390int->type;
-		inti->ext.ext_params = s390int->parm;
+		irq->ext.ext_params = s390int->parm;
 		break;
-	case KVM_S390_PROGRAM_INT:
-	case KVM_S390_SIGP_STOP:
-	case KVM_S390_INT_EXTERNAL_CALL:
-	case KVM_S390_INT_EMERGENCY:
-		kfree(inti);
-		return -EINVAL;
 	case KVM_S390_MCHK:
 		VM_EVENT(kvm, 5, "inject: machine check parm64:%llx",
 			 s390int->parm64);
-		inti->type = s390int->type;
-		inti->mchk.cr14 = s390int->parm; /* upper bits are not used */
-		inti->mchk.mcic = s390int->parm64;
+		irq->mchk.cr14 = s390int->parm; /* upper bits are not used */
+		irq->mchk.mcic = s390int->parm64;
 		break;
 	case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-		if (s390int->type & IOINT_AI_MASK)
+		if (irq->type & IOINT_AI_MASK)
 			VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
 		else
 			VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
 				 s390int->type & IOINT_CSSID_MASK,
 				 s390int->type & IOINT_SSID_MASK,
 				 s390int->type & IOINT_SCHID_MASK);
-		inti->type = s390int->type;
-		inti->io.subchannel_id = s390int->parm >> 16;
-		inti->io.subchannel_nr = s390int->parm & 0x0000ffffu;
-		inti->io.io_int_parm = s390int->parm64 >> 32;
-		inti->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull;
+		irq->io.subchannel_id = s390int->parm >> 16;
+		irq->io.subchannel_nr = s390int->parm & 0x0000ffffu;
+		irq->io.io_int_parm = s390int->parm64 >> 32;
+		irq->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull;
 		break;
+	case KVM_S390_PROGRAM_INT:
+	case KVM_S390_SIGP_STOP:
+	case KVM_S390_INT_EXTERNAL_CALL:
+	case KVM_S390_INT_EMERGENCY:
 	default:
 		kfree(inti);
 		return -EINVAL;
 	}
-	trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64,
-				 2);
+	trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, 2);
 
 	mutex_lock(&kvm->lock);
 	fi = &kvm->arch.float_int;
 	spin_lock(&fi->lock);
-	if (!is_ioint(inti->type))
+	if (!is_ioint(inti->irq.type))
 		list_add_tail(&inti->list, &fi->list);
 	else {
-		u64 isc_bits = int_word_to_isc_bits(inti->io.io_int_word);
+		u64 isc_bits = int_word_to_isc_bits(inti->irq.io.io_int_word);
 
 		/* Keep I/O interrupts sorted in isc order. */
 		list_for_each_entry(iter, &fi->list, list) {
-			if (!is_ioint(iter->type))
+			if (!is_ioint(iter->irq.type))
 				continue;
-			if (int_word_to_isc_bits(iter->io.io_int_word)
+			if (int_word_to_isc_bits(iter->irq.io.io_int_word)
 			    <= isc_bits)
 				continue;
 			break;
@@ -770,21 +767,21 @@  int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 			kfree(inti);
 			return -EINVAL;
 		}
-		inti->type = s390int->type;
-		inti->pgm.code = s390int->parm;
+		inti->irq.type = s390int->type;
+		inti->irq.pgm.code = s390int->parm;
 		VCPU_EVENT(vcpu, 3, "inject: program check %d (from user)",
 			   s390int->parm);
 		break;
 	case KVM_S390_SIGP_SET_PREFIX:
-		inti->prefix.address = s390int->parm;
-		inti->type = s390int->type;
+		inti->irq.prefix.address = s390int->parm;
+		inti->irq.type = s390int->type;
 		VCPU_EVENT(vcpu, 3, "inject: set prefix to %x (from user)",
 			   s390int->parm);
 		break;
 	case KVM_S390_SIGP_STOP:
 	case KVM_S390_RESTART:
 		VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
-		inti->type = s390int->type;
+		inti->irq.type = s390int->type;
 		break;
 	case KVM_S390_INT_EXTERNAL_CALL:
 		if (s390int->parm & 0xffff0000) {
@@ -793,8 +790,8 @@  int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 		}
 		VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
 			   s390int->parm);
-		inti->type = s390int->type;
-		inti->extcall.code = s390int->parm;
+		inti->irq.type = s390int->type;
+		inti->irq.extcall.code = s390int->parm;
 		break;
 	case KVM_S390_INT_EMERGENCY:
 		if (s390int->parm & 0xffff0000) {
@@ -802,14 +799,14 @@  int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 			return -EINVAL;
 		}
 		VCPU_EVENT(vcpu, 3, "inject: emergency %u\n", s390int->parm);
-		inti->type = s390int->type;
-		inti->emerg.code = s390int->parm;
+		inti->irq.type = s390int->type;
+		inti->irq.emerg.code = s390int->parm;
 		break;
 	case KVM_S390_MCHK:
 		VCPU_EVENT(vcpu, 5, "inject: machine check parm64:%llx",
 			   s390int->parm64);
-		inti->type = s390int->type;
-		inti->mchk.mcic = s390int->parm64;
+		inti->irq.type = s390int->type;
+		inti->irq.mchk.mcic = s390int->parm64;
 		break;
 	case KVM_S390_INT_VIRTIO:
 	case KVM_S390_INT_SERVICE:
@@ -824,12 +821,12 @@  int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 	mutex_lock(&vcpu->kvm->lock);
 	li = &vcpu->arch.local_int;
 	spin_lock_bh(&li->lock);
-	if (inti->type == KVM_S390_PROGRAM_INT)
+	if (inti->irq.type == KVM_S390_PROGRAM_INT)
 		list_add(&inti->list, &li->list);
 	else
 		list_add_tail(&inti->list, &li->list);
 	atomic_set(&li->active, 1);
-	if (inti->type == KVM_S390_SIGP_STOP)
+	if (inti->irq.type == KVM_S390_SIGP_STOP)
 		li->action_bits |= ACTION_STOP_ON_STOP;
 	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
 	if (waitqueue_active(&vcpu->wq))
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 0da3e6e..897fff2 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -146,19 +146,19 @@  static int handle_tpi(struct kvm_vcpu *vcpu)
 		 * Store the two-word I/O interruption code into the
 		 * provided area.
 		 */
-		if (put_guest(vcpu, inti->io.subchannel_id, (u16 __user *)addr)
-		    || put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *)(addr + 2))
-		    || put_guest(vcpu, inti->io.io_int_parm, (u32 __user *)(addr + 4)))
+		if (put_guest(vcpu, inti->irq.io.subchannel_id, (u16 __user *)addr)
+		    || put_guest(vcpu, inti->irq.io.subchannel_nr, (u16 __user *)(addr + 2))
+		    || put_guest(vcpu, inti->irq.io.io_int_parm, (u32 __user *)(addr + 4)))
 			return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
 	} else {
 		/*
 		 * Store the three-word I/O interruption code into
 		 * the appropriate lowcore area.
 		 */
-		put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) __LC_SUBCHANNEL_ID);
-		put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) __LC_SUBCHANNEL_NR);
-		put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) __LC_IO_INT_PARM);
-		put_guest(vcpu, inti->io.io_int_word, (u32 __user *) __LC_IO_INT_WORD);
+		put_guest(vcpu, inti->irq.io.subchannel_id, (u16 __user *) __LC_SUBCHANNEL_ID);
+		put_guest(vcpu, inti->irq.io.subchannel_nr, (u16 __user *) __LC_SUBCHANNEL_NR);
+		put_guest(vcpu, inti->irq.io.io_int_parm, (u32 __user *) __LC_IO_INT_PARM);
+		put_guest(vcpu, inti->irq.io.io_int_word, (u32 __user *) __LC_IO_INT_WORD);
 	}
 	kfree(inti);
 no_interrupt:
@@ -186,10 +186,10 @@  static int handle_tsch(struct kvm_vcpu *vcpu)
 	vcpu->run->exit_reason = KVM_EXIT_S390_TSCH;
 	vcpu->run->s390_tsch.dequeued = !!inti;
 	if (inti) {
-		vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id;
-		vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr;
-		vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm;
-		vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word;
+		vcpu->run->s390_tsch.subchannel_id = inti->irq.io.subchannel_id;
+		vcpu->run->s390_tsch.subchannel_nr = inti->irq.io.subchannel_nr;
+		vcpu->run->s390_tsch.io_int_parm = inti->irq.io.io_int_parm;
+		vcpu->run->s390_tsch.io_int_word = inti->irq.io.io_int_word;
 	}
 	vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb;
 	kfree(inti);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index bec398c..a8cd912 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -65,8 +65,8 @@  static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
 	if (!inti)
 		return -ENOMEM;
 
-	inti->type = KVM_S390_INT_EMERGENCY;
-	inti->emerg.code = vcpu->vcpu_id;
+	inti->irq.type = KVM_S390_INT_EMERGENCY;
+	inti->irq.emerg.code = vcpu->vcpu_id;
 
 	spin_lock(&fi->lock);
 	li = fi->local_int[cpu_addr];
@@ -103,8 +103,8 @@  static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
 	if (!inti)
 		return -ENOMEM;
 
-	inti->type = KVM_S390_INT_EXTERNAL_CALL;
-	inti->extcall.code = vcpu->vcpu_id;
+	inti->irq.type = KVM_S390_INT_EXTERNAL_CALL;
+	inti->irq.extcall.code = vcpu->vcpu_id;
 
 	spin_lock(&fi->lock);
 	li = fi->local_int[cpu_addr];
@@ -134,7 +134,7 @@  static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
 	inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
 	if (!inti)
 		return -ENOMEM;
-	inti->type = KVM_S390_SIGP_STOP;
+	inti->irq.type = KVM_S390_SIGP_STOP;
 
 	spin_lock_bh(&li->lock);
 	if ((atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
@@ -245,8 +245,8 @@  static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 		goto out_li;
 	}
 
-	inti->type = KVM_S390_SIGP_SET_PREFIX;
-	inti->prefix.address = address;
+	inti->irq.type = KVM_S390_SIGP_SET_PREFIX;
+	inti->irq.prefix.address = address;
 
 	list_add_tail(&inti->list, &li->list);
 	atomic_set(&li->active, 1);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index acccd08..d6a1584 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -434,6 +434,68 @@  struct kvm_s390_interrupt {
 	__u64 parm64;
 };
 
+struct kvm_s390_io_info {
+	__u16 subchannel_id;
+	__u16 subchannel_nr;
+	__u32 io_int_parm;
+	__u32 io_int_word;
+};
+
+struct kvm_s390_ext_info {
+	__u32 ext_params;
+	__u64 ext_params2;
+};
+
+struct kvm_s390_pgm_info {
+	__u64 trans_exc_code;
+	__u64 mon_code;
+	__u64 per_address;
+	__u32 data_exc_code;
+	__u16 code;
+	__u16 mon_class_nr;
+	__u8 per_code;
+	__u8 per_atmid;
+	__u8 exc_access_id;
+	__u8 per_access_id;
+	__u8 op_access_id;
+	__u8 pad[3];
+};
+
+struct kvm_s390_prefix_info {
+	__u32 address;
+};
+
+struct kvm_s390_extcall_info {
+	__u16 code;
+};
+
+struct kvm_s390_emerg_info {
+	__u16 code;
+};
+
+struct kvm_s390_mchk_info {
+	__u64 cr14;
+	__u64 mcic;
+	__u64 failing_storage_address;
+	__u32 ext_damage_code;
+	__u32 pad;
+	__u8 fixed_logout[16];
+};
+
+struct kvm_s390_irq {
+	__u64 type;
+	union {
+		struct kvm_s390_io_info io;
+		struct kvm_s390_ext_info ext;
+		struct kvm_s390_pgm_info pgm;
+		struct kvm_s390_emerg_info emerg;
+		struct kvm_s390_extcall_info extcall;
+		struct kvm_s390_prefix_info prefix;
+		struct kvm_s390_mchk_info mchk;
+	};
+	char reserved[64];
+};
+
 /* for KVM_SET_GUEST_DEBUG */
 
 #define KVM_GUESTDBG_ENABLE		0x00000001