qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC 0/2] KVM: s390: add floating irq controller
@ 2013-07-26 16:47 Jens Freimann
  2013-07-26 16:47 ` [Qemu-devel] [RFC 1/2] KVM: s390: add and extend interrupt information data structs Jens Freimann
  2013-07-26 16:47 ` [Qemu-devel] [RFC 2/2] KVM: s390: add floating irq controller Jens Freimann
  0 siblings, 2 replies; 4+ messages in thread
From: Jens Freimann @ 2013-07-26 16:47 UTC (permalink / raw)
  To: Christian Borntraeger, Cornelia Huck
  Cc: Dominik Dingel, Jens Freimann, qemu-devel, kvm, Alexander Graf

This series adds a kvm_device that acts as a irq controller for floating
interrupts.  As a first step it implements functionality to retrieve and inject
interrupts for the purpose of migration and  for hardening the reset code by
allowing user space to explicitly remove all pending floating interrupts.

PFAULT patches will also use this device for enabling/disabling pfault, therefore
the pfault patch series will be reworked to use this device depending on
review feedback

* Patch 1 adds a new data structure to hold interrupt information. The current
one (struct kvm_s390_interrupt) does not allow to inject all kinds of interrupts,
e.g. some data for program interrupts and machine check interruptions were
missing.

* Patch 2 adds a kvm_device which supports getting/setting currently pending
floating interrupts as well as deleting all currently pending interrupts


Jens Freimann (2):
  s390/kvm: add and extend interrupt information data structs
  s390/kvm: add floating irq controller

 arch/s390/include/asm/kvm_host.h |  45 +----
 arch/s390/include/uapi/asm/kvm.h |   5 +
 arch/s390/kvm/interrupt.c        | 365 +++++++++++++++++++++++++--------------
 arch/s390/kvm/kvm-s390.c         |   1 +
 arch/s390/kvm/priv.c             |  22 +--
 arch/s390/kvm/sigp.c             |  14 +-
 include/linux/kvm_host.h         |   1 +
 include/uapi/linux/kvm.h         |  63 +++++++
 virt/kvm/kvm_main.c              |   3 +
 9 files changed, 330 insertions(+), 189 deletions(-)

-- 
1.8.0.1

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Qemu-devel] [RFC 1/2] KVM: s390: add and extend interrupt information data structs
  2013-07-26 16:47 [Qemu-devel] [RFC 0/2] KVM: s390: add floating irq controller Jens Freimann
@ 2013-07-26 16:47 ` Jens Freimann
  2013-07-26 16:47 ` [Qemu-devel] [RFC 2/2] KVM: s390: add floating irq controller Jens Freimann
  1 sibling, 0 replies; 4+ messages in thread
From: Jens Freimann @ 2013-07-26 16:47 UTC (permalink / raw)
  To: Christian Borntraeger, Cornelia Huck
  Cc: Dominik Dingel, Jens Freimann, qemu-devel, kvm, Alexander Graf

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(-)

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
-- 
1.8.0.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [Qemu-devel] [RFC 2/2] KVM: s390: add floating irq controller
  2013-07-26 16:47 [Qemu-devel] [RFC 0/2] KVM: s390: add floating irq controller Jens Freimann
  2013-07-26 16:47 ` [Qemu-devel] [RFC 1/2] KVM: s390: add and extend interrupt information data structs Jens Freimann
@ 2013-07-26 16:47 ` Jens Freimann
  2013-07-29  7:41   ` Heiko Carstens
  1 sibling, 1 reply; 4+ messages in thread
From: Jens Freimann @ 2013-07-26 16:47 UTC (permalink / raw)
  To: Christian Borntraeger, Cornelia Huck
  Cc: Dominik Dingel, Jens Freimann, qemu-devel, kvm, Alexander Graf

This patch adds a floating irq controller as a kvm_device.
It will be necesary for migration of floating interrupts as well
as for hardening the reset code by allowing user space to explicitly
remove all pending floating interrupts.

Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>

---
 arch/s390/include/uapi/asm/kvm.h |   5 +
 arch/s390/kvm/interrupt.c        | 192 +++++++++++++++++++++++++++++++--------
 arch/s390/kvm/kvm-s390.c         |   1 +
 include/linux/kvm_host.h         |   1 +
 include/uapi/linux/kvm.h         |   1 +
 virt/kvm/kvm_main.c              |   3 +
 6 files changed, 163 insertions(+), 40 deletions(-)

diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index d25da59..33d52b8 100644
--- a/arch/s390/include/uapi/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.h
@@ -16,6 +16,11 @@
 
 #define __KVM_S390
 
+/* Device control API: s390-specific devices */
+#define KVM_DEV_FLIC_DEQUEUE 1
+#define KVM_DEV_FLIC_ENQUEUE 2
+#define KVM_DEV_FLIC_CLEAR_IRQS 3
+
 /* for KVM_GET_REGS and KVM_SET_REGS */
 struct kvm_regs {
 	/* general purpose regs for s390 */
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 25cf71d..065a402 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -656,15 +656,57 @@ struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
 	return inti;
 }
 
-int kvm_s390_inject_vm(struct kvm *kvm,
-		       struct kvm_s390_interrupt *s390int)
+static void __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
 {
 	struct kvm_s390_local_interrupt *li;
 	struct kvm_s390_float_interrupt *fi;
-	struct kvm_s390_interrupt_info *inti, *iter;
-	struct kvm_s390_irq *irq;
+	struct kvm_s390_interrupt_info *iter;
 	int sigcpu;
 
+	mutex_lock(&kvm->lock);
+	fi = &kvm->arch.float_int;
+	spin_lock(&fi->lock);
+	if (!is_ioint(inti->irq.type))
+		list_add_tail(&inti->list, &fi->list);
+	else {
+		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->irq.type))
+				continue;
+			if (int_word_to_isc_bits(iter->irq.io.io_int_word)
+					<= isc_bits)
+				continue;
+			break;
+		}
+		list_add_tail(&inti->list, &iter->list);
+	}
+	atomic_set(&fi->active, 1);
+	sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
+	if (sigcpu == KVM_MAX_VCPUS) {
+		do {
+			sigcpu = fi->next_rr_cpu++;
+			if (sigcpu == KVM_MAX_VCPUS)
+				sigcpu = fi->next_rr_cpu = 0;
+		} while (fi->local_int[sigcpu] == NULL);
+	}
+	li = fi->local_int[sigcpu];
+	spin_lock_bh(&li->lock);
+	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+	if (waitqueue_active(li->wq))
+		wake_up_interruptible(li->wq);
+	spin_unlock_bh(&li->lock);
+	spin_unlock(&fi->lock);
+	mutex_unlock(&kvm->lock);
+}
+
+int kvm_s390_inject_vm(struct kvm *kvm,
+		       struct kvm_s390_interrupt *s390int)
+{
+	struct kvm_s390_interrupt_info *inti;
+	struct kvm_s390_irq *irq;
+
 	inti = kzalloc(sizeof(*inti), GFP_KERNEL);
 	if (!inti)
 		return -ENOMEM;
@@ -712,42 +754,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
 	}
 	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->irq.type))
-		list_add_tail(&inti->list, &fi->list);
-	else {
-		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->irq.type))
-				continue;
-			if (int_word_to_isc_bits(iter->irq.io.io_int_word)
-			    <= isc_bits)
-				continue;
-			break;
-		}
-		list_add_tail(&inti->list, &iter->list);
-	}
-	atomic_set(&fi->active, 1);
-	sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
-	if (sigcpu == KVM_MAX_VCPUS) {
-		do {
-			sigcpu = fi->next_rr_cpu++;
-			if (sigcpu == KVM_MAX_VCPUS)
-				sigcpu = fi->next_rr_cpu = 0;
-		} while (fi->local_int[sigcpu] == NULL);
-	}
-	li = fi->local_int[sigcpu];
-	spin_lock_bh(&li->lock);
-	atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
-	if (waitqueue_active(li->wq))
-		wake_up_interruptible(li->wq);
-	spin_unlock_bh(&li->lock);
-	spin_unlock(&fi->lock);
-	mutex_unlock(&kvm->lock);
+	__inject_vm(kvm, inti);
 	return 0;
 }
 
@@ -835,3 +842,108 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
 	mutex_unlock(&vcpu->kvm->lock);
 	return 0;
 }
+
+static void clear_floating_interrupts(struct kvm *kvm)
+{
+	struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
+	struct kvm_s390_interrupt_info  *n, *inti = NULL;
+
+	if (atomic_read(&fi->active)) {
+		spin_lock_bh(&fi->lock);
+		list_for_each_entry_safe(inti, n, &fi->list, list) {
+			list_del(&inti->list);
+			kfree(inti);
+		}
+		atomic_set(&fi->active, 0);
+		spin_unlock_bh(&fi->lock);
+	}
+}
+
+
+static int dequeue_floating_irq(struct kvm *kvm, __u64 addr)
+{
+	struct kvm_s390_interrupt_info *inti;
+	struct kvm_s390_float_interrupt *fi;
+	int r = 0;
+
+	fi = &kvm->arch.float_int;
+	mutex_lock(&kvm->lock);
+	spin_lock(&fi->lock);
+
+	if (!list_empty(&fi->list)) {
+		inti = list_first_entry(&fi->list,
+				struct kvm_s390_interrupt_info, list);
+		list_del(&inti->list);
+		if (copy_to_user((void *) addr, &inti->irq, sizeof(inti->irq)))
+			r = -EFAULT;
+	} else
+		r = -ENODATA;
+
+	spin_unlock(&fi->lock);
+	mutex_unlock(&kvm->lock);
+
+	return r;
+}
+
+static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	int r = 0;
+
+	switch (attr->group) {
+	case KVM_DEV_FLIC_DEQUEUE:
+		r = dequeue_floating_irq(dev->kvm, attr->addr);
+		break;
+	default:
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
+{
+	int r;
+
+	switch (attr->group) {
+	case KVM_DEV_FLIC_ENQUEUE: {
+		struct kvm_s390_irq *s390irq;
+		struct kvm_s390_interrupt_info *inti;
+		inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+		if (!inti)
+			return -ENOMEM;
+		s390irq = kzalloc(sizeof(*s390irq), GFP_KERNEL);
+		if (!s390irq)
+			return -ENOMEM;
+		if (copy_from_user(s390irq, (u64 __user *)attr->addr,
+				  sizeof(s390irq)))
+			return -EFAULT;
+		inti->irq = *s390irq;
+		__inject_vm(dev->kvm, inti);
+		}
+		break;
+	case KVM_DEV_FLIC_CLEAR_IRQS:
+		clear_floating_interrupts(dev->kvm);
+	default:
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+static int flic_create(struct kvm_device *dev, u32 type)
+{
+	return 0;
+}
+
+static void flic_destroy(struct kvm_device *dev)
+{
+}
+
+/* s390 floating irq controller (flic) */
+struct kvm_device_ops kvm_flic_ops = {
+	.name = "kvm-flic",
+	.get_attr = flic_get_attr,
+	.set_attr = flic_set_attr,
+	.create = flic_create,
+	.destroy = flic_destroy,
+};
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ba694d2..b85a3f0 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -150,6 +150,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_ENABLE_CAP:
 	case KVM_CAP_S390_CSS_SUPPORT:
 	case KVM_CAP_IOEVENTFD:
+	case KVM_CAP_DEVICE_CTRL:
 		r = 1;
 		break;
 	case KVM_CAP_NR_VCPUS:
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index a63d83e..fa517dd 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1052,6 +1052,7 @@ struct kvm_device *kvm_device_from_filp(struct file *filp);
 
 extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_xics_ops;
+extern struct kvm_device_ops kvm_flic_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index d6a1584..c5aa7ce 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -904,6 +904,7 @@ struct kvm_device_attr {
 #define KVM_DEV_TYPE_FSL_MPIC_20	1
 #define KVM_DEV_TYPE_FSL_MPIC_42	2
 #define KVM_DEV_TYPE_XICS		3
+#define KVM_DEV_TYPE_FLIC		4
 
 /*
  * ioctls for VM fds
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1580dd4..cb017eb 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2282,6 +2282,9 @@ static int kvm_ioctl_create_device(struct kvm *kvm,
 		ops = &kvm_xics_ops;
 		break;
 #endif
+	case KVM_DEV_TYPE_FLIC:
+		ops = &kvm_flic_ops;
+		break;
 	default:
 		return -ENODEV;
 	}
-- 
1.8.0.1

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [RFC 2/2] KVM: s390: add floating irq controller
  2013-07-26 16:47 ` [Qemu-devel] [RFC 2/2] KVM: s390: add floating irq controller Jens Freimann
@ 2013-07-29  7:41   ` Heiko Carstens
  0 siblings, 0 replies; 4+ messages in thread
From: Heiko Carstens @ 2013-07-29  7:41 UTC (permalink / raw)
  To: Jens Freimann
  Cc: kvm, qemu-devel, Dominik Dingel, Alexander Graf,
	Christian Borntraeger, Cornelia Huck

On Fri, Jul 26, 2013 at 06:47:59PM +0200, Jens Freimann wrote:
> This patch adds a floating irq controller as a kvm_device.
> It will be necesary for migration of floating interrupts as well
> as for hardening the reset code by allowing user space to explicitly
> remove all pending floating interrupts.
> 
> Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>

[...]

> +static void clear_floating_interrupts(struct kvm *kvm)
> +{
> +	struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
> +	struct kvm_s390_interrupt_info  *n, *inti = NULL;
> +
> +	if (atomic_read(&fi->active)) {
> +		spin_lock_bh(&fi->lock);
> +		list_for_each_entry_safe(inti, n, &fi->list, list) {
> +			list_del(&inti->list);
> +			kfree(inti);
> +		}
> +		atomic_set(&fi->active, 0);
> +		spin_unlock_bh(&fi->lock);
> +	}
> +}

FWIW, unrelated to your patch, since it used to be always like this:
the sematics of fi->active atomic_t seem to be a bit odd. It only
gets set while the fi->lock spinlock is held and might be read also
while not holding the spinlock.
Either it's racy, the spinlock is not needed at all, or it should
be held everytime.
Besides that the meaning of the "active" value seems to be the same
as !list_empty()... so you could get rid of it.
Just a comment ;)

> +static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
> +{
> +	int r;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_FLIC_ENQUEUE: {
> +		struct kvm_s390_irq *s390irq;
> +		struct kvm_s390_interrupt_info *inti;
> +		inti = kzalloc(sizeof(*inti), GFP_KERNEL);
> +		if (!inti)
> +			return -ENOMEM;
> +		s390irq = kzalloc(sizeof(*s390irq), GFP_KERNEL);
> +		if (!s390irq)
> +			return -ENOMEM;
> +		if (copy_from_user(s390irq, (u64 __user *)attr->addr,
> +				  sizeof(s390irq)))
> +			return -EFAULT;

User space triggerable memory leak.

> +		inti->irq = *s390irq;
> +		__inject_vm(dev->kvm, inti);

I think you must check the irq type, otherwise the kernel may crash if it
tries to deliver the interrupt and it doesn't match any of the known irqs.
(or remove the BUG() in the deliver function, or both ;)

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-07-29  7:41 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-26 16:47 [Qemu-devel] [RFC 0/2] KVM: s390: add floating irq controller Jens Freimann
2013-07-26 16:47 ` [Qemu-devel] [RFC 1/2] KVM: s390: add and extend interrupt information data structs Jens Freimann
2013-07-26 16:47 ` [Qemu-devel] [RFC 2/2] KVM: s390: add floating irq controller Jens Freimann
2013-07-29  7:41   ` Heiko Carstens

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).