From patchwork Mon Jul 29 13:59:53 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jens Freimann X-Patchwork-Id: 262800 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DAC6C2C00DE for ; Tue, 30 Jul 2013 00:37:12 +1000 (EST) Received: from localhost ([::1]:55247 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V3o3m-0002ey-QL for incoming@patchwork.ozlabs.org; Mon, 29 Jul 2013 10:04:26 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53250) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V3nzi-0005jT-Ag for qemu-devel@nongnu.org; Mon, 29 Jul 2013 10:00:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V3nzW-0003AA-OG for qemu-devel@nongnu.org; Mon, 29 Jul 2013 10:00:14 -0400 Received: from e06smtp14.uk.ibm.com ([195.75.94.110]:46736) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V3nzW-00035X-DV for qemu-devel@nongnu.org; Mon, 29 Jul 2013 10:00:02 -0400 Received: from /spool/local by e06smtp14.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 29 Jul 2013 14:51:22 +0100 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp14.uk.ibm.com (192.168.101.144) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 29 Jul 2013 14:51:19 +0100 Received: from b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 8AFC117D8058 for ; Mon, 29 Jul 2013 15:01:41 +0100 (BST) Received: from d06av02.portsmouth.uk.ibm.com (d06av02.portsmouth.uk.ibm.com [9.149.37.228]) by b06cxnps3074.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r6TDxk8H47710250 for ; Mon, 29 Jul 2013 13:59:46 GMT Received: from d06av02.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id r6TDxvZr025596 for ; Mon, 29 Jul 2013 07:59:57 -0600 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id r6TDxupk025587; Mon, 29 Jul 2013 07:59:56 -0600 Received: by tuxmaker.boeblingen.de.ibm.com (Postfix, from userid 1122) id A5366122443A; Mon, 29 Jul 2013 15:59:56 +0200 (CEST) From: Jens Freimann To: Christian Borntraeger , Cornelia Huck Date: Mon, 29 Jul 2013 15:59:53 +0200 Message-Id: <1375106393-15811-3-git-send-email-jfrei@linux.vnet.ibm.com> X-Mailer: git-send-email 1.8.2.3 In-Reply-To: <1375106393-15811-1-git-send-email-jfrei@linux.vnet.ibm.com> References: <1375106393-15811-1-git-send-email-jfrei@linux.vnet.ibm.com> X-TM-AS-MML: No X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13072913-1948-0000-0000-000005D2BB49 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 195.75.94.110 Cc: Dominik Dingel , Jens Freimann , qemu-devel@nongnu.org, kvm@vger.kernel.org, Alexander Graf Subject: [Qemu-devel] [PATCH 2/2] KVM: s390: add floating irq controller X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- arch/s390/include/uapi/asm/kvm.h | 5 + arch/s390/kvm/interrupt.c | 210 +++++++++++++++++++++++++++++++-------- 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, 181 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..02b3b3f 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,126 @@ 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 (!list_empty(&fi->list)) { + spin_lock_bh(&fi->lock); + list_for_each_entry_safe(inti, n, &fi->list, list) { + list_del(&inti->list); + kfree(inti); + } + 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; + struct kvm_s390_irq *s390irq; + struct kvm_s390_interrupt_info *inti; + + switch (attr->group) { + case KVM_DEV_FLIC_ENQUEUE: + inti = kzalloc(sizeof(*inti), GFP_KERNEL); + if (!inti) { + r = -ENOMEM; + goto out; + } + s390irq = kzalloc(sizeof(*s390irq), GFP_KERNEL); + if (!s390irq) { + r = -ENOMEM; + goto out_free_inti; + } + if (copy_from_user(s390irq, (u64 __user *)attr->addr, + sizeof(s390irq))) { + r = -EFAULT; + goto out_free_s390irq; + } + switch(s390irq->type) { + case KVM_S390_INT_VIRTIO: + case KVM_S390_INT_SERVICE: + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: + case KVM_S390_MCHK: + inti->irq = *s390irq; + __inject_vm(dev->kvm, inti); + default: + r = -EINVAL; + } + break; + case KVM_DEV_FLIC_CLEAR_IRQS: + clear_floating_interrupts(dev->kvm); + default: + r = -EINVAL; + goto out; + } + +out_free_s390irq: + kfree(s390irq); +out_free_inti: + kfree(inti); +out: + 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; }