diff options
Diffstat (limited to 'hw/i386')
| -rw-r--r-- | hw/i386/kvm/xen_evtchn.c | 40 | ||||
| -rw-r--r-- | hw/i386/kvm/xen_evtchn.h | 3 | ||||
| -rw-r--r-- | hw/i386/kvm/xen_xenstore.c | 2 | ||||
| -rw-r--r-- | hw/i386/pc.c | 13 | ||||
| -rw-r--r-- | hw/i386/pc_piix.c | 36 | ||||
| -rw-r--r-- | hw/i386/xen/xen-hvm.c | 2 |
6 files changed, 60 insertions, 36 deletions
diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index 3048329474..3d810dbd59 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -147,7 +147,10 @@ struct XenEvtchnState { QemuMutex port_lock; uint32_t nr_ports; XenEvtchnPort port_table[EVTCHN_2L_NR_CHANNELS]; - qemu_irq gsis[IOAPIC_NUM_PINS]; + + /* Connected to the system GSIs for raising callback as GSI / INTx */ + unsigned int nr_callback_gsis; + qemu_irq *callback_gsis; struct xenevtchn_handle *be_handles[EVTCHN_2L_NR_CHANNELS]; @@ -299,7 +302,7 @@ static void gsi_assert_bh(void *opaque) } } -void xen_evtchn_create(void) +void xen_evtchn_create(unsigned int nr_gsis, qemu_irq *system_gsis) { XenEvtchnState *s = XEN_EVTCHN(sysbus_create_simple(TYPE_XEN_EVTCHN, -1, NULL)); @@ -310,8 +313,19 @@ void xen_evtchn_create(void) qemu_mutex_init(&s->port_lock); s->gsi_bh = aio_bh_new(qemu_get_aio_context(), gsi_assert_bh, s); - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - sysbus_init_irq(SYS_BUS_DEVICE(s), &s->gsis[i]); + /* + * These are the *output* GSI from event channel support, for + * signalling CPU0's events via GSI or PCI INTx instead of the + * per-CPU vector. We create a *set* of irqs and connect one to + * each of the system GSIs which were passed in from the platform + * code, and then just trigger the right one as appropriate from + * xen_evtchn_set_callback_level(). + */ + s->nr_callback_gsis = nr_gsis; + s->callback_gsis = g_new0(qemu_irq, nr_gsis); + for (i = 0; i < nr_gsis; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->callback_gsis[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(s), i, system_gsis[i]); } /* @@ -336,20 +350,6 @@ void xen_evtchn_create(void) xen_evtchn_ops = &emu_evtchn_backend_ops; } -void xen_evtchn_connect_gsis(qemu_irq *system_gsis) -{ - XenEvtchnState *s = xen_evtchn_singleton; - int i; - - if (!s) { - return; - } - - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - sysbus_connect_irq(SYS_BUS_DEVICE(s), i, system_gsis[i]); - } -} - static void xen_evtchn_register_types(void) { type_register_static(&xen_evtchn_info); @@ -430,8 +430,8 @@ void xen_evtchn_set_callback_level(int level) return; } - if (s->callback_gsi && s->callback_gsi < IOAPIC_NUM_PINS) { - qemu_set_irq(s->gsis[s->callback_gsi], level); + if (s->callback_gsi && s->callback_gsi < s->nr_callback_gsis) { + qemu_set_irq(s->callback_gsis[s->callback_gsi], level); if (level) { /* Ensure the vCPU polls for deassertion */ kvm_xen_set_callback_asserted(); diff --git a/hw/i386/kvm/xen_evtchn.h b/hw/i386/kvm/xen_evtchn.h index bfb67ac2bc..b740acfc0d 100644 --- a/hw/i386/kvm/xen_evtchn.h +++ b/hw/i386/kvm/xen_evtchn.h @@ -16,10 +16,9 @@ typedef uint32_t evtchn_port_t; -void xen_evtchn_create(void); +void xen_evtchn_create(unsigned int nr_gsis, qemu_irq *system_gsis); int xen_evtchn_soft_reset(void); int xen_evtchn_set_callback_param(uint64_t param); -void xen_evtchn_connect_gsis(qemu_irq *system_gsis); void xen_evtchn_set_callback_level(int level); int xen_evtchn_set_port(uint16_t port); diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 0b189c6ab8..133d89e953 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -1688,7 +1688,7 @@ static struct qemu_xs_handle *xs_be_open(void) XenXenstoreState *s = xen_xenstore_singleton; struct qemu_xs_handle *h; - if (!s && !s->impl) { + if (!s || !s->impl) { errno = -ENOSYS; return NULL; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index bb62c994fa..fc52772fdd 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1332,7 +1332,10 @@ void pc_basic_device_init(struct PCMachineState *pcms, #ifdef CONFIG_XEN_EMU if (xen_mode == XEN_EMULATE) { - xen_evtchn_connect_gsis(gsi); + xen_overlay_create(); + xen_evtchn_create(IOAPIC_NUM_PINS, gsi); + xen_gnttab_create(); + xen_xenstore_create(); if (pcms->bus) { pci_create_simple(pcms->bus, -1, "xen-platform"); } @@ -1882,14 +1885,6 @@ static void pc_machine_initfn(Object *obj) int pc_machine_kvm_type(MachineState *machine, const char *kvm_type) { -#ifdef CONFIG_XEN_EMU - if (xen_mode == XEN_EMULATE) { - xen_overlay_create(); - xen_evtchn_create(); - xen_gnttab_create(); - xen_xenstore_create(); - } -#endif return 0; } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index d5b0dcd1fe..42af03dbb4 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -71,6 +71,7 @@ #include "kvm/kvm-cpu.h" #define MAX_IDE_BUS 2 +#define XEN_IOAPIC_NUM_PIRQS 128ULL #ifdef CONFIG_IDE_ISA static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; @@ -89,6 +90,21 @@ static int pc_pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) return (pci_intx + slot_addend) & 3; } +static void piix_intx_routing_notifier_xen(PCIDevice *dev) +{ + int i; + + /* Scan for updates to PCI link routes (0x60-0x63). */ + for (i = 0; i < PIIX_NUM_PIRQS; i++) { + uint8_t v = dev->config_read(dev, PIIX_PIRQCA + i, 1); + if (v & 0x80) { + v = 0; + } + v &= 0xf; + xen_set_pci_link_route(i, v); + } +} + /* PC hardware initialisation */ static void pc_init1(MachineState *machine, const char *host_type, const char *pci_type) @@ -223,8 +239,6 @@ static void pc_init1(MachineState *machine, if (pcmc->pci_enabled) { PIIX3State *piix3; PCIDevice *pci_dev; - const char *type = xen_enabled() ? TYPE_PIIX3_XEN_DEVICE - : TYPE_PIIX3_DEVICE; pci_bus = i440fx_init(pci_type, i440fx_host, @@ -237,7 +251,23 @@ static void pc_init1(MachineState *machine, : pc_pci_slot_get_pirq); pcms->bus = pci_bus; - pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, type); + pci_dev = pci_create_simple_multifunction(pci_bus, -1, true, + TYPE_PIIX3_DEVICE); + + if (xen_enabled()) { + pci_device_set_intx_routing_notifier( + pci_dev, piix_intx_routing_notifier_xen); + + /* + * Xen supports additional interrupt routes from the PCI devices to + * the IOAPIC: the four pins of each PCI device on the bus are also + * connected to the IOAPIC directly. + * These additional routes can be discovered through ACPI. + */ + pci_bus_irqs(pci_bus, xen_intx_set_irq, pci_dev, + XEN_IOAPIC_NUM_PIRQS); + } + piix3 = PIIX3_PCI_DEVICE(pci_dev); piix3->pic = x86ms->gsi; piix3_devfn = piix3->dev.devfn; diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 56641a550e..ab8f1b61ee 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -143,7 +143,7 @@ int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) return irq_num + (PCI_SLOT(pci_dev->devfn) << 2); } -void xen_piix3_set_irq(void *opaque, int irq_num, int level) +void xen_intx_set_irq(void *opaque, int irq_num, int level) { xen_set_pci_intx_level(xen_domid, 0, 0, irq_num >> 2, irq_num & 3, level); |