From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jan Kiszka Subject: [PATCH] KVM: Introduce generic interrupt injection for in-kernel irqchips Date: Tue, 10 Apr 2012 20:30:13 +0200 Message-ID: <4F847C35.9070105@siemens.com> References: <4F734EB3.20500@siemens.com> <4F748AAD.2040103@siemens.com> <4F74B484.30607@siemens.com> <4F7B24EA.2070300@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Cc: kvm , "Michael S. Tsirkin" , Eric Northup To: Avi Kivity , Marcelo Tosatti Return-path: Received: from david.siemens.de ([192.35.17.14]:16130 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754512Ab2DJSaU (ORCPT ); Tue, 10 Apr 2012 14:30:20 -0400 In-Reply-To: <4F7B24EA.2070300@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: Currently, MSI messages can only be injected to in-kernel irqchips by defining a corresponding IRQ route for each message. This is not only unhandy if the MSI messages are generated "on the fly" by user space, IRQ routes are a limited resource that user space has to manage carefully. By providing a direct injection path, we can both avoid using up limited resources and simplify the necessary steps for user land. This path is provide in a way that allows for use with other interrupt sources as well. Besides MSIs also external interrupt lines can be manipulated through this interface, obsoleting KVM_IRQ_LINE_STATUS. Signed-off-by: Jan Kiszka --- This picks up Avi's first suggestion as I still think it is the better option to provide a direct MSI injection channel. Documentation/virtual/kvm/api.txt | 46 +++++++++++++++++++++++++++++++++++++ include/linux/kvm.h | 26 +++++++++++++++++++++ include/linux/kvm_host.h | 2 + virt/kvm/irq_comm.c | 29 +++++++++++++++++++++++ virt/kvm/kvm_main.c | 20 ++++++++++++++++ 5 files changed, 123 insertions(+), 0 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 81ff39f..c70be58 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1482,6 +1482,52 @@ See KVM_ASSIGN_DEV_IRQ for the data structure. The target device is specified by assigned_dev_id. In the flags field, only KVM_DEV_ASSIGN_MASK_INTX is evaluated. +4.61 KVM_GENERAL_IRQ + +Capability: KVM_CAP_GENERAL_IRQ +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_general_irq (in/out) +Returns: 0 on success, <0 on error + +Inject an interrupt event to the guest. Only valid if in-kernel irqchip is +enabled. + +struct kvm_general_irq { + __u32 type; + __u32 op; + __s32 status; + __u32 pad; + union { + __u32 line; + struct { + __u32 address_lo; + __u32 address_hi; + __u32 data; + } msi; + __u8 pad[32]; + } u; +}; + +Support IRQ types are: + +#define KVM_IRQTYPE_EXTERNAL_LINE 0 +#define KVM_IRQTYPE_MSI 1 + +Available operations are: + +#define KVM_IRQOP_LOWER 0 +#define KVM_IRQOP_RAISE 1 +#define KVM_IRQOP_TRIGGER 2 + +The level of an external interrupt line can either be raised or lowered, a +MSI can only be triggered. + +If 0 is returned from the IOCTL, the status field was updated as well to +reflect the injection result. It will be >0 on interrupt delivery, 0 if the +interrupt was coalesced with an already pending one, and <0 if the guest +blocked the delivery or some delivery error occurred. + 4.62 KVM_CREATE_SPAPR_TCE Capability: KVM_CAP_SPAPR_TCE diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 7a9dd4b..cb3afaf 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -590,6 +590,7 @@ struct kvm_ppc_pvinfo { #define KVM_CAP_SYNC_REGS 74 #define KVM_CAP_PCI_2_3 75 #define KVM_CAP_KVMCLOCK_CTRL 76 +#define KVM_CAP_GENERAL_IRQ 77 #ifdef KVM_CAP_IRQ_ROUTING @@ -715,6 +716,29 @@ struct kvm_one_reg { __u64 addr; }; +#define KVM_IRQTYPE_EXTERNAL_LINE 0 +#define KVM_IRQTYPE_MSI 1 + +#define KVM_IRQOP_LOWER 0 +#define KVM_IRQOP_RAISE 1 +#define KVM_IRQOP_TRIGGER 2 + +struct kvm_general_irq { + __u32 type; + __u32 op; + __s32 status; + __u32 pad; + union { + __u32 line; + struct { + __u32 address_lo; + __u32 address_hi; + __u32 data; + } msi; + __u8 pad[32]; + } u; +}; + /* * ioctls for VM fds */ @@ -789,6 +813,8 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_PCI_2_3 */ #define KVM_ASSIGN_SET_INTX_MASK _IOW(KVMIO, 0xa4, \ struct kvm_assigned_pci_dev) +/* Available with KVM_CAP_GENERAL_IRQ */ +#define KVM_GENERAL_IRQ _IOWR(KVMIO, 0xa5, struct kvm_general_irq) /* * ioctls for vcpu fds diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 49c2f2f..31d3b44 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -773,6 +773,8 @@ int kvm_set_irq_routing(struct kvm *kvm, unsigned flags); void kvm_free_irq_routing(struct kvm *kvm); +int kvm_general_irq(struct kvm *kvm, struct kvm_general_irq *irq); + #else static inline void kvm_free_irq_routing(struct kvm *kvm) {} diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 9f614b4..e487d3f 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -138,6 +138,35 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, return kvm_irq_delivery_to_apic(kvm, NULL, &irq); } +int kvm_general_irq(struct kvm *kvm, struct kvm_general_irq *irq) +{ + struct kvm_kernel_irq_routing_entry route; + + if (!irqchip_in_kernel(kvm)) + return -EINVAL; + + switch (irq->type) { + case KVM_IRQTYPE_EXTERNAL_LINE: + if (irq->op > KVM_IRQOP_RAISE) + return -EINVAL; + irq->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, + irq->u.line, irq->op); + break; + case KVM_IRQTYPE_MSI: + if (irq->op != KVM_IRQOP_TRIGGER) + return -EINVAL; + route.msi.address_lo = irq->u.msi.address_lo; + route.msi.address_hi = irq->u.msi.address_hi; + route.msi.data = irq->u.msi.data; + irq->status = kvm_set_msi(&route, kvm, + KVM_USERSPACE_IRQ_SOURCE_ID, 1); + break; + default: + return -EINVAL; + } + return 0; +} + /* * Return value: * < 0 Interrupt was ignored (masked or not delivered for other reasons) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 6bd34a6..95dffec 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2059,6 +2059,23 @@ static long kvm_vm_ioctl(struct file *filp, mutex_unlock(&kvm->lock); break; #endif +#ifdef CONFIG_HAVE_KVM_IRQCHIP + case KVM_GENERAL_IRQ: { + struct kvm_general_irq irq; + + r = -EFAULT; + if (copy_from_user(&irq, argp, sizeof(irq))) + goto out; + r = kvm_general_irq(kvm, &irq); + if (r < 0) + goto out; + if (copy_to_user(argp + + offsetof(struct kvm_general_irq, status), + &irq.status, sizeof(irq.status))) + r = -EFAULT; + break; + } +#endif default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); if (r == -ENOTTY) @@ -2187,6 +2204,9 @@ static long kvm_dev_ioctl_check_extension_generic(long arg) case KVM_CAP_SET_BOOT_CPU_ID: #endif case KVM_CAP_INTERNAL_ERROR_DATA: +#ifdef CONFIG_HAVE_KVM_IRQCHIP + case KVM_CAP_GENERAL_IRQ: +#endif return 1; #ifdef CONFIG_HAVE_KVM_IRQCHIP case KVM_CAP_IRQ_ROUTING: -- 1.7.3.4