diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2015-12-17 17:16:08 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-12-17 17:33:47 +0100 |
commit | 15eafc2e602ff8c37c6e132eb8c63fec8fc17175 (patch) | |
tree | e37c79eac125c083389e8bde03b8d3e048c22b0a /hw | |
parent | 32c18a2dbaf79c241eddabd19a3b410bab5bf0cc (diff) | |
download | qemu-15eafc2e602ff8c37c6e132eb8c63fec8fc17175.zip qemu-15eafc2e602ff8c37c6e132eb8c63fec8fc17175.tar.gz qemu-15eafc2e602ff8c37c6e132eb8c63fec8fc17175.tar.bz2 |
kvm: x86: add support for KVM_CAP_SPLIT_IRQCHIP
This patch adds support for split IRQ chip mode. When
KVM_CAP_SPLIT_IRQCHIP is enabled:
1.) The PIC, PIT, and IOAPIC are implemented in userspace while
the LAPIC is implemented by KVM.
2.) The software IOAPIC delivers interrupts to the KVM LAPIC via
kvm_set_irq. Interrupt delivery is configured via the MSI routing
table, for which routes are reserved in target-i386/kvm.c then
configured in hw/intc/ioapic.c
3.) KVM delivers IOAPIC EOIs via a new exit KVM_EXIT_IOAPIC_EOI,
which is handled in target-i386/kvm.c and relayed to the software
IOAPIC via ioapic_eoi_broadcast.
Signed-off-by: Matt Gingell <gingell@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/i386/pc.c | 5 | ||||
-rw-r--r-- | hw/i386/pc_piix.c | 4 | ||||
-rw-r--r-- | hw/intc/ioapic.c | 68 |
3 files changed, 71 insertions, 6 deletions
diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 5e20e07..426424a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -65,6 +65,7 @@ #include "hw/mem/pc-dimm.h" #include "qapi/visitor.h" #include "qapi-visit.h" +#include "qom/cpu.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -1517,7 +1518,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_register_boot_set(pc_boot_set, *rtc_state); if (!xen_enabled()) { - if (kvm_irqchip_in_kernel()) { + if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); @@ -1592,7 +1593,7 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) SysBusDevice *d; unsigned int i; - if (kvm_irqchip_in_kernel()) { + if (kvm_ioapic_in_kernel()) { dev = qdev_create(NULL, "kvm-ioapic"); } else { dev = qdev_create(NULL, "ioapic"); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6a498a2..319497e 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -182,7 +182,7 @@ static void pc_init1(MachineState *machine, } gsi_state = g_malloc0(sizeof(*gsi_state)); - if (kvm_irqchip_in_kernel()) { + if (kvm_ioapic_in_kernel()) { kvm_pc_setup_irq_routing(pci_enabled); gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, GSI_NUM_PINS); @@ -206,7 +206,7 @@ static void pc_init1(MachineState *machine, } isa_bus_irqs(isa_bus, gsi); - if (kvm_irqchip_in_kernel()) { + if (kvm_pic_in_kernel()) { i8259 = kvm_i8259_init(isa_bus); } else if (xen_enabled()) { i8259 = xen_interrupt_controller_init(); diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index de2dd4b..e4bfaea 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -25,6 +25,8 @@ #include "hw/i386/pc.h" #include "hw/i386/ioapic.h" #include "hw/i386/ioapic_internal.h" +#include "include/hw/pci/msi.h" +#include "sysemu/kvm.h" //#define DEBUG_IOAPIC @@ -35,6 +37,10 @@ #define DPRINTF(fmt, ...) #endif +#define APIC_DELIVERY_MODE_SHIFT 8 +#define APIC_POLARITY_SHIFT 14 +#define APIC_TRIG_MODE_SHIFT 15 + static IOAPICCommonState *ioapics[MAX_IOAPICS]; /* global variable from ioapic_common.c */ @@ -54,6 +60,8 @@ static void ioapic_service(IOAPICCommonState *s) for (i = 0; i < IOAPIC_NUM_PINS; i++) { mask = 1 << i; if (s->irr & mask) { + int coalesce = 0; + entry = s->ioredtbl[i]; if (!(entry & IOAPIC_LVT_MASKED)) { trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); @@ -64,6 +72,7 @@ static void ioapic_service(IOAPICCommonState *s) if (trig_mode == IOAPIC_TRIGGER_EDGE) { s->irr &= ~mask; } else { + coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR; s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; } if (delivery_mode == IOAPIC_DM_EXTINT) { @@ -71,8 +80,23 @@ static void ioapic_service(IOAPICCommonState *s) } else { vector = entry & IOAPIC_VECTOR_MASK; } - apic_deliver_irq(dest, dest_mode, delivery_mode, - vector, trig_mode); +#ifdef CONFIG_KVM + if (kvm_irqchip_is_split()) { + if (trig_mode == IOAPIC_TRIGGER_EDGE) { + kvm_set_irq(kvm_state, i, 1); + kvm_set_irq(kvm_state, i, 0); + } else { + if (!coalesce) { + kvm_set_irq(kvm_state, i, 1); + } + } + continue; + } +#else + (void)coalesce; +#endif + apic_deliver_irq(dest, dest_mode, delivery_mode, vector, + trig_mode); } } } @@ -116,6 +140,44 @@ static void ioapic_set_irq(void *opaque, int vector, int level) } } +static void ioapic_update_kvm_routes(IOAPICCommonState *s) +{ +#ifdef CONFIG_KVM + int i; + + if (kvm_irqchip_is_split()) { + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + uint64_t entry = s->ioredtbl[i]; + uint8_t trig_mode; + uint8_t delivery_mode; + uint8_t dest; + uint8_t dest_mode; + uint64_t pin_polarity; + MSIMessage msg; + + trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); + dest = entry >> IOAPIC_LVT_DEST_SHIFT; + dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; + pin_polarity = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1; + delivery_mode = + (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; + + msg.address = APIC_DEFAULT_ADDRESS; + msg.address |= dest_mode << 2; + msg.address |= dest << 12; + + msg.data = entry & IOAPIC_VECTOR_MASK; + msg.data |= delivery_mode << APIC_DELIVERY_MODE_SHIFT; + msg.data |= pin_polarity << APIC_POLARITY_SHIFT; + msg.data |= trig_mode << APIC_TRIG_MODE_SHIFT; + + kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL); + } + kvm_irqchip_commit_routes(kvm_state); + } +#endif +} + void ioapic_eoi_broadcast(int vector) { IOAPICCommonState *s; @@ -229,6 +291,8 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, } break; } + + ioapic_update_kvm_routes(s); } static const MemoryRegionOps ioapic_io_ops = { |