From patchwork Mon Nov 5 03:25:20 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Mackerras X-Patchwork-Id: 1695081 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 3EE24E0010 for ; Mon, 5 Nov 2012 03:26:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753239Ab2KED0c (ORCPT ); Sun, 4 Nov 2012 22:26:32 -0500 Received: from ozlabs.org ([203.10.76.45]:41355 "EHLO ozlabs.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752553Ab2KED0H (ORCPT ); Sun, 4 Nov 2012 22:26:07 -0500 Received: by ozlabs.org (Postfix, from userid 1003) id D19922C00A8; Mon, 5 Nov 2012 14:26:06 +1100 (EST) Date: Mon, 5 Nov 2012 14:25:20 +1100 From: Paul Mackerras To: Alexander Graf Cc: kvm@vger.kernel.org, kvm-ppc@vger.kernel.org, Benjamin Herrenschmidt Subject: [RFC PATCH 9/9] KVM: PPC: Book 3S: Facilities to save/restore XICS source controller state Message-ID: <20121105032520.GJ22409@drongo> References: <20121105031806.GA22409@drongo> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20121105031806.GA22409@drongo> User-Agent: Mutt/1.5.21 (2010-09-15) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This adds the ability for userspace to save and restore the state of the XICS interrupt source controllers (ICS) via two new VM ioctls, KVM_IRQCHIP_GET_SOURCES and KVM_IRQCHIP_SET_SOURCES. Both take an argument struct that gives the starting interrupt source number, the number of interrupt sources to be processed, and a pointer to an array with space for 64 bits per source where the state of the interrupt sources are to be stored or loaded. The interrupt sources are required to all be within one ICS. Signed-off-by: Paul Mackerras --- Documentation/virtual/kvm/api.txt | 33 ++++++++++++ arch/powerpc/kvm/book3s_xics.c | 108 +++++++++++++++++++++++++++++++++++++ arch/powerpc/kvm/powerpc.c | 4 +- include/uapi/linux/kvm.h | 17 ++++++ 4 files changed, 161 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index fbe018e..2ba53a1 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2107,6 +2107,39 @@ struct. When creating an ICS, the argument struct further indicates the BUID (Bus Unit ID) and number of interrupt sources for the new ICS. +4.80 KVM_IRQCHIP_GET_SOURCES + +Capability: KVM_CAP_SPAPR_XICS +Architectures: ppc +Type: vm ioctl +Parameters: struct kvm_irq_sources +Returns: 0 on success, -1 on error + +Copies configuration and status information about a range of interrupt +sources into a user-supplied buffer. The argument struct gives the +starting interrupt source number and the number of interrupt sources. +All of the interrupt sources must be within the range of a single +interrupt source controller (ICS). The user buffer is an array of +64-bit quantities, one per interrupt source, with (from the least- +significant bit) 32 bits of interrupt server number, 8 bits of +priority, and 1 bit each for a level-sensitive indicator, a masked +indicator, and a pending indicator. + +4.81 KVM_IRQCHIP_SET_SOURCES + +Capability: KVM_CAP_SPAPR_XICS +Architectures: ppc +Type: vm ioctl +Parameters: struct kvm_irq_sources +Returns: 0 on success, -1 on error + +Sets the configuration and status for a range of interrupt sources +from information supplied in a user-supplied buffer. The argument +struct gives the starting interrupt source number and the number of +interrupt sources. All of the interrupt sources must be within the +range of a single interrupt source controller (ICS). The user buffer +is formatted as for KVM_IRQCHIP_GET_SOURCES. + 5. The kvm_run structure ------------------------ diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index 8314cd9..8071c7e 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -1066,6 +1066,88 @@ int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval) return 0; } +static int kvm_xics_get_sources(struct kvm *kvm, struct kvm_irq_sources *srcs) +{ + int ret = 0; + struct kvmppc_xics *xics = kvm->arch.xics; + struct kvmppc_ics *ics; + struct ics_irq_state *irqp; + u64 __user *ubufp; + u16 idx; + u64 val; + long int i; + + ics = kvmppc_xics_find_ics(xics, srcs->irq, &idx); + if (!ics || idx + srcs->nr_irqs > ics->nr_irqs) + return -ENOENT; + + irqp = &ics->irq_state[idx]; + ubufp = srcs->irqbuf; + mutex_lock(&ics->lock); + for (i = 0; i < srcs->nr_irqs; ++i, ++irqp, ++ubufp) { + val = irqp->server; + if (irqp->priority == MASKED && irqp->saved_priority != MASKED) + val |= KVM_IRQ_MASKED | ((u64)irqp->saved_priority << + KVM_IRQ_PRIORITY_SHIFT); + else + val |= ((u64)irqp->priority << KVM_IRQ_PRIORITY_SHIFT); + if (irqp->asserted) + val |= KVM_IRQ_LEVEL_SENSITIVE | KVM_IRQ_PENDING; + else if (irqp->masked_pending || irqp->resend) + val |= KVM_IRQ_PENDING; + ret = -EFAULT; + if (__put_user(val, ubufp)) + break; + ret = 0; + } + mutex_unlock(&ics->lock); + return ret; +} + +static int kvm_xics_set_sources(struct kvm *kvm, struct kvm_irq_sources *srcs) +{ + int ret = 0; + struct kvmppc_xics *xics = kvm->arch.xics; + struct kvmppc_ics *ics; + struct ics_irq_state *irqp; + u64 __user *ubufp; + u16 idx; + u64 val; + long int i; + + ics = kvmppc_xics_find_ics(xics, srcs->irq, &idx); + if (!ics || idx + srcs->nr_irqs > ics->nr_irqs) + return -ENOENT; + + irqp = &ics->irq_state[idx]; + ubufp = srcs->irqbuf; + for (i = 0; i < srcs->nr_irqs; ++i, ++irqp, ++ubufp) { + ret = -EFAULT; + if (__get_user(val, ubufp)) + break; + ret = 0; + + mutex_lock(&ics->lock); + irqp->server = val & KVM_IRQ_SERVER_MASK; + irqp->saved_priority = val >> KVM_IRQ_PRIORITY_SHIFT; + if (val & KVM_IRQ_MASKED) + irqp->priority = MASKED; + else + irqp->priority = irqp->saved_priority; + irqp->resend = 0; + irqp->masked_pending = 0; + irqp->asserted = 0; + if ((val & KVM_IRQ_PENDING) && (val & KVM_IRQ_LEVEL_SENSITIVE)) + irqp->asserted = 1; + mutex_unlock(&ics->lock); + + if (val & KVM_IRQ_PENDING) + icp_deliver_irq(xics, NULL, irqp->number); + } + + return ret; +} + /* -- ioctls -- */ static int kvm_vm_ioctl_create_icp(struct kvm *kvm, @@ -1200,6 +1282,32 @@ int kvmppc_xics_ioctl(struct kvm *kvm, unsigned ioctl, unsigned long arg) break; } + case KVM_IRQCHIP_GET_SOURCES: { + struct kvm_irq_sources sources; + + rc = -EFAULT; + if (copy_from_user(&sources, argp, sizeof(sources))) + break; + if (!access_ok(VERIFY_WRITE, sources.irqbuf, + sources.nr_irqs * sizeof(u64))) + break; + rc = kvm_xics_get_sources(kvm, &sources); + break; + } + + case KVM_IRQCHIP_SET_SOURCES: { + struct kvm_irq_sources sources; + + rc = -EFAULT; + if (copy_from_user(&sources, argp, sizeof(sources))) + break; + if (!access_ok(VERIFY_READ, sources.irqbuf, + sources.nr_irqs * sizeof(u64))) + break; + rc = kvm_xics_set_sources(kvm, &sources); + break; + } + default: rc = -ENOTTY; break; diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 90b5b5c..0d443d4 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -955,7 +955,9 @@ long kvm_arch_vm_ioctl(struct file *filp, r = kvm_vm_ioctl_rtas_define_token(kvm, argp); break; } - case KVM_IRQ_LINE: { + case KVM_IRQ_LINE: + case KVM_IRQCHIP_GET_SOURCES: + case KVM_IRQCHIP_SET_SOURCES: { struct kvm *kvm = filp->private_data; r = -ENOTTY; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 8674d32..edcf78d 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -779,6 +779,21 @@ struct kvm_msi { __u8 pad[16]; }; +struct kvm_irq_sources { + __u32 irq; + __u32 nr_irqs; + __u64 __user *irqbuf; +}; + +/* irqbuf entries are laid out like this: */ +#define KVM_IRQ_SERVER_SHIFT 0 +#define KVM_IRQ_SERVER_MASK 0xffffffffULL +#define KVM_IRQ_PRIORITY_SHIFT 32 +#define KVM_IRQ_PRIORITY_MASK 0xff +#define KVM_IRQ_LEVEL_SENSITIVE (1ULL << 40) +#define KVM_IRQ_MASKED (1ULL << 41) +#define KVM_IRQ_PENDING (1ULL << 42) + /* * ioctls for VM fds */ @@ -867,6 +882,8 @@ struct kvm_s390_ucas_mapping { #ifdef __KVM_HAVE_IRQCHIP_ARGS #define KVM_CREATE_IRQCHIP_ARGS _IOW(KVMIO, 0xab, struct kvm_irqchip_args) #endif +#define KVM_IRQCHIP_GET_SOURCES _IOW(KVMIO, 0xac, struct kvm_irq_sources) +#define KVM_IRQCHIP_SET_SOURCES _IOW(KVMIO, 0xad, struct kvm_irq_sources) /* * ioctls for vcpu fds