From patchwork Wed Jul 29 01:59:00 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve Rutherford X-Patchwork-Id: 6888961 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 1FBC2C05AC for ; Wed, 29 Jul 2015 01:59:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F32B120796 for ; Wed, 29 Jul 2015 01:59:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BF8D620794 for ; Wed, 29 Jul 2015 01:59:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752110AbbG2B7S (ORCPT ); Tue, 28 Jul 2015 21:59:18 -0400 Received: from mail-pd0-f172.google.com ([209.85.192.172]:35705 "EHLO mail-pd0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751992AbbG2B7P (ORCPT ); Tue, 28 Jul 2015 21:59:15 -0400 Received: by pdrg1 with SMTP id g1so80170770pdr.2 for ; Tue, 28 Jul 2015 18:59:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=+X6u5pMwutjXNZJiPEx8fyv+tBpO7eQpq9CxvMV45a4=; b=lA0dDGMV2+UIQR5hYxOBkKH9SYWuD4bSonf51cY7Bnd6Bs+UAQUx8IQoJs0wl1ylSP 1h253ZeRNS/a66+uSBqLFn9ucDdYT85kU2KUOs11No9WQ6kG86Fyv0PYg926uJdyL23x mkWvsNaTtOKguSpNHsINBM4wqAvk73aoayiVceO0K1sxi4aCUNY5k0cZpiNAkBtMJvEE uOT/55W9oqc7sDmBmie+Iq/Lq7golvfLBNqMauBFD4bV4tAm/4b5z5rjpfLPHYzFZ+uO d1TszXUF08UVSbAlo1lVlq7GkbYpZ/EzGU1N9IE9Epu9HunentqR3A61640BhSRDfr6r WrGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=+X6u5pMwutjXNZJiPEx8fyv+tBpO7eQpq9CxvMV45a4=; b=mdxLDCNFW1XSr7cS/mxkfsORDuSPb72trvZ6hKrjSG9yJafk4Tc/YNkhcL/0P/W0VF 2LuQOf//poV7qBkW1gjPT1V94xI/DGs8OqtL85G3nL/89WBbGJuDWcFlW4jkhreq1J7Q ME2MuCvXy/N4OAe4jyPJaKn+RtsQbcAehn+3jQm9gye65VqTJF/m3TvV81HAQXwhUzjY +F9Jumt6ExmjmoEhr+jrDj6w9DYL9qHTE7VjqLDauIuqIxjTi6dGvO8u3ODg1TCsPj8G n0055vr1dm20v/vqUmZ0odDXLqpiUd3Pv/BOKqq09OVC8VlHr12DmcoHEVWxjnXybU7Q IR+Q== X-Gm-Message-State: ALoCoQnS88zv5PqDmd6bVDBAxZPmzqkOW5WUqABXVKowPzHFx9Q3YspUWVMOvZEifpH5vdhWbJGF X-Received: by 10.70.20.196 with SMTP id p4mr87445847pde.58.1438135154709; Tue, 28 Jul 2015 18:59:14 -0700 (PDT) Received: from entropic.kir.corp.google.com ([172.31.8.128]) by smtp.gmail.com with ESMTPSA id pu4sm37425535pdb.86.2015.07.28.18.59.13 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 28 Jul 2015 18:59:13 -0700 (PDT) From: Steve Rutherford To: kvm@vger.kernel.org Subject: [PATCH v6 3/4] KVM: x86: Add EOI exit bitmap inference Date: Tue, 28 Jul 2015 18:59:00 -0700 Message-Id: <1438135141-22761-3-git-send-email-srutherford@google.com> X-Mailer: git-send-email 2.5.0.rc2.392.g76e840b In-Reply-To: <1438135141-22761-1-git-send-email-srutherford@google.com> References: <1438135141-22761-1-git-send-email-srutherford@google.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In order to support a userspace IOAPIC interacting with an in kernel APIC, the EOI exit bitmaps need to be configurable. If the IOAPIC is in userspace (i.e. the irqchip has been split), the EOI exit bitmaps will be set whenever the GSI Routes are configured. In particular, for the low MSI routes are reservable for userspace IOAPICs. For these MSI routes, the EOI Exit bit corresponding to the destination vector of the route will be set for the destination VCPU. The intention is for the userspace IOAPICs to use the reservable MSI routes to inject interrupts into the guest. This is a slight abuse of the notion of an MSI Route, given that MSIs classically bypass the IOAPIC. It might be worthwhile to add an additional route type to improve clarity. Compile tested for Intel x86. Signed-off-by: Steve Rutherford --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/ioapic.h | 2 ++ arch/x86/kvm/irq_comm.c | 42 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/lapic.c | 3 +-- arch/x86/kvm/x86.c | 29 ++++++++++++++++++---------- include/linux/kvm_host.h | 20 ++++++++++++++++++++ virt/kvm/irqchip.c | 12 ++---------- 7 files changed, 87 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f1e0103..ebe7f07 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -674,6 +674,7 @@ struct kvm_arch { u64 disabled_quirks; bool irqchip_split; + u8 nr_reserved_ioapic_pins; }; struct kvm_vm_stat { diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h index 3ce56f8..c93fe23 100644 --- a/arch/x86/kvm/ioapic.h +++ b/arch/x86/kvm/ioapic.h @@ -9,6 +9,7 @@ struct kvm; struct kvm_vcpu; #define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS +#define MAX_NR_RESERVED_IOAPIC_PINS 48 #define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ #define IOAPIC_EDGE_TRIG 0 #define IOAPIC_LEVEL_TRIG 1 @@ -131,4 +132,5 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap, u32 *tmr); +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); #endif diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 67f6b62..da4827f 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -335,3 +335,45 @@ int kvm_setup_empty_irq_routing(struct kvm *kvm) { return kvm_set_irq_routing(kvm, empty_routing, 0, 0); } + +void kvm_arch_irq_routing_update(struct kvm *kvm) +{ + if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm)) + return; + kvm_make_scan_ioapic_request(kvm); +} + +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) +{ + struct kvm *kvm = vcpu->kvm; + struct kvm_kernel_irq_routing_entry *entry; + struct kvm_irq_routing_table *table; + u32 i, nr_ioapic_pins; + int idx; + + /* kvm->irq_routing must be read after clearing + * KVM_SCAN_IOAPIC. */ + smp_mb(); + idx = srcu_read_lock(&kvm->irq_srcu); + table = kvm->irq_routing; + nr_ioapic_pins = min_t(u32, table->nr_rt_entries, + kvm->arch.nr_reserved_ioapic_pins); + for (i = 0; i < nr_ioapic_pins; ++i) { + hlist_for_each_entry(entry, &table->map[i], link) { + u32 dest_id, dest_mode; + + if (entry->type != KVM_IRQ_ROUTING_MSI) + continue; + dest_id = (entry->msi.address_lo >> 12) & 0xff; + dest_mode = (entry->msi.address_lo >> 2) & 0x1; + if (kvm_apic_match_dest(vcpu, NULL, 0, dest_id, + dest_mode)) { + u32 vector = entry->msi.data & 0xff; + + __set_bit(vector, + (unsigned long *) eoi_exit_bitmap); + } + } + } + srcu_read_unlock(&kvm->irq_srcu, idx); +} diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 37e220d..4dbf6c1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -209,8 +209,7 @@ out: if (old) kfree_rcu(old, rcu); - if (!irqchip_split(kvm)) - kvm_vcpu_request_scan_ioapic(kvm); + kvm_make_scan_ioapic_request(kvm); } static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a612266..f32f7cb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3575,12 +3575,17 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, if (irqchip_in_kernel(kvm)) goto split_irqchip_unlock; r = -EINVAL; - if (atomic_read(&kvm->online_vcpus)) - goto split_irqchip_unlock; - r = kvm_setup_empty_irq_routing(kvm); - if (r) + if (cap->args[0] > MAX_NR_RESERVED_IOAPIC_PINS) goto split_irqchip_unlock; - kvm->arch.irqchip_split = true; + if (!irqchip_split(kvm)) { + if (atomic_read(&kvm->online_vcpus)) + goto split_irqchip_unlock; + r = kvm_setup_empty_irq_routing(kvm); + if (r) + goto split_irqchip_unlock; + kvm->arch.irqchip_split = true; + } + kvm->arch.nr_reserved_ioapic_pins = cap->args[0]; r = 0; split_irqchip_unlock: mutex_unlock(&kvm->lock); @@ -6163,18 +6168,22 @@ static void process_smi(struct kvm_vcpu *vcpu) static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) { - u64 eoi_exit_bitmap[4]; + struct kvm *kvm = vcpu->kvm; u32 tmr[8]; if (!kvm_apic_hw_enabled(vcpu->arch.apic)) return; - memset(eoi_exit_bitmap, 0, 32); + memset(vcpu->arch.eoi_exit_bitmaps, 0, 32); memset(tmr, 0, 32); + if (irqchip_split(kvm)) + kvm_scan_ioapic_routes(vcpu, vcpu->arch.eoi_exit_bitmaps); + else + kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmaps, tmr); + kvm_x86_ops->load_eoi_exitmap(vcpu, vcpu->arch.eoi_exit_bitmaps); - kvm_ioapic_scan_entry(vcpu, eoi_exit_bitmap, tmr); - kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap); - kvm_apic_update_tmr(vcpu, tmr); + if (!irqchip_split(kvm)) + kvm_apic_update_tmr(vcpu, tmr); } static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 8e12d67..064067e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -329,6 +329,17 @@ struct kvm_kernel_irq_routing_entry { struct hlist_node link; }; +struct kvm_irq_routing_table { + int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS]; + struct kvm_kernel_irq_routing_entry *rt_entries; + u32 nr_rt_entries; + /* + * Array indexed by gsi. Each entry contains list of irq chips + * the gsi is connected to. + */ + struct hlist_head map[0]; +}; + #ifndef KVM_PRIVATE_MEM_SLOTS #define KVM_PRIVATE_MEM_SLOTS 0 #endif @@ -454,10 +465,19 @@ void vcpu_put(struct kvm_vcpu *vcpu); #ifdef __KVM_HAVE_IOAPIC void kvm_vcpu_request_scan_ioapic(struct kvm *kvm); +void kvm_arch_irq_routing_update(struct kvm *kvm); +u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm); #else static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm) { } +static inline void kvm_arch_irq_routing_update(struct kvm *kvm) +{ +} +static inline u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm) +{ + return 0; +} #endif #ifdef CONFIG_HAVE_KVM_IRQFD diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index 21c1424..4f85c6e 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -31,16 +31,6 @@ #include #include "irq.h" -struct kvm_irq_routing_table { - int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS]; - u32 nr_rt_entries; - /* - * Array indexed by gsi. Each entry contains list of irq chips - * the gsi is connected to. - */ - struct hlist_head map[0]; -}; - int kvm_irq_map_gsi(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *entries, int gsi) { @@ -227,6 +217,8 @@ int kvm_set_irq_routing(struct kvm *kvm, kvm_irq_routing_update(kvm); mutex_unlock(&kvm->irq_lock); + kvm_arch_irq_routing_update(kvm); + synchronize_srcu_expedited(&kvm->irq_srcu); new = old;