aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Rutherford <srutherford@google.com>2015-07-30 02:32:35 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2015-10-01 09:06:28 -0400
commitb053b2aef25d00773fa6762dcd4b7f5c9c42d171 (patch)
tree49455d15fd99d802135fed0d197989c3e7a2b62b
parent7543a635aa09eb138b2cbf60ac3ff19503ae6954 (diff)
KVM: x86: Add EOI exit bitmap inference
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 <srutherford@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--Documentation/virtual/kvm/api.txt9
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/ioapic.h2
-rw-r--r--arch/x86/kvm/irq_comm.c42
-rw-r--r--arch/x86/kvm/lapic.c3
-rw-r--r--arch/x86/kvm/x86.c9
-rw-r--r--include/linux/kvm_host.h16
-rw-r--r--virt/kvm/irqchip.c12
8 files changed, 78 insertions, 16 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 0d14bf5db534..89e71648d748 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -3642,7 +3642,7 @@ KVM handlers should exit to userspace with rc = -EREMOTE.
36427.5 KVM_CAP_SPLIT_IRQCHIP 36427.5 KVM_CAP_SPLIT_IRQCHIP
3643 3643
3644Architectures: x86 3644Architectures: x86
3645Parameters: None 3645Parameters: args[0] - number of routes reserved for userspace IOAPICs
3646Returns: 0 on success, -1 on error 3646Returns: 0 on success, -1 on error
3647 3647
3648Create a local apic for each processor in the kernel. This can be used 3648Create a local apic for each processor in the kernel. This can be used
@@ -3650,8 +3650,11 @@ instead of KVM_CREATE_IRQCHIP if the userspace VMM wishes to emulate the
3650IOAPIC and PIC (and also the PIT, even though this has to be enabled 3650IOAPIC and PIC (and also the PIT, even though this has to be enabled
3651separately). 3651separately).
3652 3652
3653This supersedes KVM_CREATE_IRQCHIP, creating only local APICs, but no in kernel 3653This capability also enables in kernel routing of interrupt requests;
3654IOAPIC or PIC. This also enables in kernel routing of interrupt requests. 3654when KVM_CAP_SPLIT_IRQCHIP only routes of KVM_IRQ_ROUTING_MSI type are
3655used in the IRQ routing table. The first args[0] MSI routes are reserved
3656for the IOAPIC pins. Whenever the LAPIC receives an EOI for these routes,
3657a KVM_EXIT_IOAPIC_EOI vmexit will be reported to userspace.
3655 3658
3656Fails if VCPU has already been created, or if the irqchip is already in the 3659Fails if VCPU has already been created, or if the irqchip is already in the
3657kernel (i.e. KVM_CREATE_IRQCHIP has already been called). 3660kernel (i.e. KVM_CREATE_IRQCHIP has already been called).
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index af09fa1d1be7..7a5f9debbcd8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -688,6 +688,7 @@ struct kvm_arch {
688 u64 disabled_quirks; 688 u64 disabled_quirks;
689 689
690 bool irqchip_split; 690 bool irqchip_split;
691 u8 nr_reserved_ioapic_pins;
691}; 692};
692 693
693struct kvm_vm_stat { 694struct kvm_vm_stat {
diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
index a8842c0dee73..084617d37c74 100644
--- a/arch/x86/kvm/ioapic.h
+++ b/arch/x86/kvm/ioapic.h
@@ -9,6 +9,7 @@ struct kvm;
9struct kvm_vcpu; 9struct kvm_vcpu;
10 10
11#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS 11#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS
12#define MAX_NR_RESERVED_IOAPIC_PINS KVM_MAX_IRQ_ROUTES
12#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ 13#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */
13#define IOAPIC_EDGE_TRIG 0 14#define IOAPIC_EDGE_TRIG 0
14#define IOAPIC_LEVEL_TRIG 1 15#define IOAPIC_LEVEL_TRIG 1
@@ -121,5 +122,6 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
121int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); 122int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
122int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state); 123int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
123void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); 124void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
125void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
124 126
125#endif 127#endif
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 67f6b62a6814..177460998bb0 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)
335{ 335{
336 return kvm_set_irq_routing(kvm, empty_routing, 0, 0); 336 return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
337} 337}
338
339void kvm_arch_irq_routing_update(struct kvm *kvm)
340{
341 if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm))
342 return;
343 kvm_make_scan_ioapic_request(kvm);
344}
345
346void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
347{
348 struct kvm *kvm = vcpu->kvm;
349 struct kvm_kernel_irq_routing_entry *entry;
350 struct kvm_irq_routing_table *table;
351 u32 i, nr_ioapic_pins;
352 int idx;
353
354 /* kvm->irq_routing must be read after clearing
355 * KVM_SCAN_IOAPIC. */
356 smp_mb();
357 idx = srcu_read_lock(&kvm->irq_srcu);
358 table = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
359 nr_ioapic_pins = min_t(u32, table->nr_rt_entries,
360 kvm->arch.nr_reserved_ioapic_pins);
361 for (i = 0; i < nr_ioapic_pins; ++i) {
362 hlist_for_each_entry(entry, &table->map[i], link) {
363 u32 dest_id, dest_mode;
364
365 if (entry->type != KVM_IRQ_ROUTING_MSI)
366 continue;
367 dest_id = (entry->msi.address_lo >> 12) & 0xff;
368 dest_mode = (entry->msi.address_lo >> 2) & 0x1;
369 if (kvm_apic_match_dest(vcpu, NULL, 0, dest_id,
370 dest_mode)) {
371 u32 vector = entry->msi.data & 0xff;
372
373 __set_bit(vector,
374 (unsigned long *) eoi_exit_bitmap);
375 }
376 }
377 }
378 srcu_read_unlock(&kvm->irq_srcu, idx);
379}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ef70f6f3a37a..2f4c0d0cbe0a 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -209,8 +209,7 @@ out:
209 if (old) 209 if (old)
210 kfree_rcu(old, rcu); 210 kfree_rcu(old, rcu);
211 211
212 if (ioapic_in_kernel(kvm)) 212 kvm_make_scan_ioapic_request(kvm);
213 kvm_vcpu_request_scan_ioapic(kvm);
214} 213}
215 214
216static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val) 215static 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 27429daa054e..4aeed2086c5e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3558,6 +3558,9 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
3558 break; 3558 break;
3559 case KVM_CAP_SPLIT_IRQCHIP: { 3559 case KVM_CAP_SPLIT_IRQCHIP: {
3560 mutex_lock(&kvm->lock); 3560 mutex_lock(&kvm->lock);
3561 r = -EINVAL;
3562 if (cap->args[0] > MAX_NR_RESERVED_IOAPIC_PINS)
3563 goto split_irqchip_unlock;
3561 r = -EEXIST; 3564 r = -EEXIST;
3562 if (irqchip_in_kernel(kvm)) 3565 if (irqchip_in_kernel(kvm))
3563 goto split_irqchip_unlock; 3566 goto split_irqchip_unlock;
@@ -3569,6 +3572,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
3569 /* Pairs with irqchip_in_kernel. */ 3572 /* Pairs with irqchip_in_kernel. */
3570 smp_wmb(); 3573 smp_wmb();
3571 kvm->arch.irqchip_split = true; 3574 kvm->arch.irqchip_split = true;
3575 kvm->arch.nr_reserved_ioapic_pins = cap->args[0];
3572 r = 0; 3576 r = 0;
3573split_irqchip_unlock: 3577split_irqchip_unlock:
3574 mutex_unlock(&kvm->lock); 3578 mutex_unlock(&kvm->lock);
@@ -6167,7 +6171,10 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
6167 6171
6168 memset(vcpu->arch.eoi_exit_bitmap, 0, 256 / 8); 6172 memset(vcpu->arch.eoi_exit_bitmap, 0, 256 / 8);
6169 6173
6170 kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmap); 6174 if (irqchip_split(vcpu->kvm))
6175 kvm_scan_ioapic_routes(vcpu, vcpu->arch.eoi_exit_bitmap);
6176 else
6177 kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmap);
6171 kvm_x86_ops->load_eoi_exitmap(vcpu); 6178 kvm_x86_ops->load_eoi_exitmap(vcpu);
6172} 6179}
6173 6180
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 3b33215ed447..d754f2d826e9 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -330,6 +330,18 @@ struct kvm_kernel_irq_routing_entry {
330 struct hlist_node link; 330 struct hlist_node link;
331}; 331};
332 332
333#ifdef CONFIG_HAVE_KVM_IRQ_ROUTING
334struct kvm_irq_routing_table {
335 int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS];
336 u32 nr_rt_entries;
337 /*
338 * Array indexed by gsi. Each entry contains list of irq chips
339 * the gsi is connected to.
340 */
341 struct hlist_head map[0];
342};
343#endif
344
333#ifndef KVM_PRIVATE_MEM_SLOTS 345#ifndef KVM_PRIVATE_MEM_SLOTS
334#define KVM_PRIVATE_MEM_SLOTS 0 346#define KVM_PRIVATE_MEM_SLOTS 0
335#endif 347#endif
@@ -456,10 +468,14 @@ void vcpu_put(struct kvm_vcpu *vcpu);
456 468
457#ifdef __KVM_HAVE_IOAPIC 469#ifdef __KVM_HAVE_IOAPIC
458void kvm_vcpu_request_scan_ioapic(struct kvm *kvm); 470void kvm_vcpu_request_scan_ioapic(struct kvm *kvm);
471void kvm_arch_irq_routing_update(struct kvm *kvm);
459#else 472#else
460static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm) 473static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
461{ 474{
462} 475}
476static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
477{
478}
463#endif 479#endif
464 480
465#ifdef CONFIG_HAVE_KVM_IRQFD 481#ifdef CONFIG_HAVE_KVM_IRQFD
diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
index d7ea8e20dae4..716a1c4db528 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -31,16 +31,6 @@
31#include <trace/events/kvm.h> 31#include <trace/events/kvm.h>
32#include "irq.h" 32#include "irq.h"
33 33
34struct kvm_irq_routing_table {
35 int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS];
36 u32 nr_rt_entries;
37 /*
38 * Array indexed by gsi. Each entry contains list of irq chips
39 * the gsi is connected to.
40 */
41 struct hlist_head map[0];
42};
43
44int kvm_irq_map_gsi(struct kvm *kvm, 34int kvm_irq_map_gsi(struct kvm *kvm,
45 struct kvm_kernel_irq_routing_entry *entries, int gsi) 35 struct kvm_kernel_irq_routing_entry *entries, int gsi)
46{ 36{
@@ -231,6 +221,8 @@ int kvm_set_irq_routing(struct kvm *kvm,
231 kvm_irq_routing_update(kvm); 221 kvm_irq_routing_update(kvm);
232 mutex_unlock(&kvm->irq_lock); 222 mutex_unlock(&kvm->irq_lock);
233 223
224 kvm_arch_irq_routing_update(kvm);
225
234 synchronize_srcu_expedited(&kvm->irq_srcu); 226 synchronize_srcu_expedited(&kvm->irq_srcu);
235 227
236 new = old; 228 new = old;