diff options
-rw-r--r-- | Makefile.target | 2 | ||||
-rw-r--r-- | hw/kvm/ioapic.c | 114 | ||||
-rw-r--r-- | hw/pc_piix.c | 15 |
3 files changed, 129 insertions, 2 deletions
diff --git a/Makefile.target b/Makefile.target index 701073d155..98cb997abf 100644 --- a/Makefile.target +++ b/Makefile.target @@ -233,7 +233,7 @@ obj-i386-y += vmport.o obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o -obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o +obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c new file mode 100644 index 0000000000..10ffdd4b20 --- /dev/null +++ b/hw/kvm/ioapic.c @@ -0,0 +1,114 @@ +/* + * KVM in-kernel IOPIC support + * + * Copyright (c) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + */ + +#include "hw/pc.h" +#include "hw/ioapic_internal.h" +#include "hw/apic_internal.h" +#include "kvm.h" + +typedef struct KVMIOAPICState KVMIOAPICState; + +struct KVMIOAPICState { + IOAPICCommonState ioapic; + uint32_t kvm_gsi_base; +}; + +static void kvm_ioapic_get(IOAPICCommonState *s) +{ + struct kvm_irqchip chip; + struct kvm_ioapic_state *kioapic; + int ret, i; + + chip.chip_id = KVM_IRQCHIP_IOAPIC; + ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip); + if (ret < 0) { + fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); + abort(); + } + + kioapic = &chip.chip.ioapic; + + s->id = kioapic->id; + s->ioregsel = kioapic->ioregsel; + s->irr = kioapic->irr; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + s->ioredtbl[i] = kioapic->redirtbl[i].bits; + } +} + +static void kvm_ioapic_put(IOAPICCommonState *s) +{ + struct kvm_irqchip chip; + struct kvm_ioapic_state *kioapic; + int ret, i; + + chip.chip_id = KVM_IRQCHIP_IOAPIC; + kioapic = &chip.chip.ioapic; + + kioapic->id = s->id; + kioapic->ioregsel = s->ioregsel; + kioapic->base_address = s->busdev.mmio[0].addr; + kioapic->irr = s->irr; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + kioapic->redirtbl[i].bits = s->ioredtbl[i]; + } + + ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip); + if (ret < 0) { + fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); + abort(); + } +} + +static void kvm_ioapic_reset(DeviceState *dev) +{ + IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev); + + ioapic_reset_common(dev); + kvm_ioapic_put(s); +} + +static void kvm_ioapic_set_irq(void *opaque, int irq, int level) +{ + KVMIOAPICState *s = opaque; + int delivered; + + delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level); + apic_report_irq_delivered(delivered); +} + +static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no) +{ + memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000); + + qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS); +} + +static IOAPICCommonInfo kvm_ioapic_info = { + .busdev.qdev.name = "kvm-ioapic", + .busdev.qdev.size = sizeof(KVMIOAPICState), + .busdev.qdev.reset = kvm_ioapic_reset, + .busdev.qdev.props = (Property[]) { + DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0), + DEFINE_PROP_END_OF_LIST() + }, + .init = kvm_ioapic_init, + .pre_save = kvm_ioapic_get, + .post_load = kvm_ioapic_put, +}; + +static void kvm_ioapic_register_device(void) +{ + ioapic_qdev_register(&kvm_ioapic_info); +} + +device_init(kvm_ioapic_register_device) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 297c04a9ab..a285ad25f8 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -69,6 +69,15 @@ static void kvm_piix3_setup_irq_routing(bool pci_enabled) for (i = 8; i < 16; ++i) { kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); } + if (pci_enabled) { + for (i = 0; i < 24; ++i) { + if (i == 0) { + kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2); + } else if (i != 2) { + kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i); + } + } + } ret = kvm_irqchip_commit_routes(s); if (ret < 0) { hw_error("KVM IRQ routing setup failed"); @@ -95,7 +104,11 @@ static void ioapic_init(GSIState *gsi_state) SysBusDevice *d; unsigned int i; - dev = qdev_create(NULL, "ioapic"); + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + dev = qdev_create(NULL, "kvm-ioapic"); + } else { + dev = qdev_create(NULL, "ioapic"); + } qdev_init_nofail(dev); d = sysbus_from_qdev(dev); sysbus_mmio_map(d, 0, 0xfec00000); |