diff options
author | David Woodhouse <dwmw@amazon.co.uk> | 2023-01-13 20:41:19 +0000 |
---|---|---|
committer | David Woodhouse <dwmw@amazon.co.uk> | 2023-03-01 09:09:20 +0000 |
commit | 4f81baa33ed645fc17a9908236630b8154502ae5 (patch) | |
tree | c4e2cd916e432fad1ce450ece27788a28554e889 /hw/i386 | |
parent | aa98ee38a5e77d1e40987c694abd0c5bc5d6c811 (diff) | |
download | qemu-4f81baa33ed645fc17a9908236630b8154502ae5.zip qemu-4f81baa33ed645fc17a9908236630b8154502ae5.tar.gz qemu-4f81baa33ed645fc17a9908236630b8154502ae5.tar.bz2 |
hw/xen: Support GSI mapping to PIRQ
If I advertise XENFEAT_hvm_pirqs then a guest now boots successfully as
long as I tell it 'pci=nomsi'.
[root@localhost ~]# cat /proc/interrupts
CPU0
0: 52 IO-APIC 2-edge timer
1: 16 xen-pirq 1-ioapic-edge i8042
4: 1534 xen-pirq 4-ioapic-edge ttyS0
8: 1 xen-pirq 8-ioapic-edge rtc0
9: 0 xen-pirq 9-ioapic-level acpi
11: 5648 xen-pirq 11-ioapic-level ahci[0000:00:04.0]
12: 257 xen-pirq 12-ioapic-edge i8042
...
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
Diffstat (limited to 'hw/i386')
-rw-r--r-- | hw/i386/kvm/xen_evtchn.c | 58 | ||||
-rw-r--r-- | hw/i386/kvm/xen_evtchn.h | 2 | ||||
-rw-r--r-- | hw/i386/x86.c | 16 |
3 files changed, 75 insertions, 1 deletions
diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index 59eea63..f2c4b43 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -148,6 +148,9 @@ struct XenEvtchnState { /* GSI → PIRQ mapping (serialized) */ uint16_t gsi_pirq[IOAPIC_NUM_PINS]; + /* Per-GSI assertion state (serialized) */ + uint32_t pirq_gsi_set; + /* Per-PIRQ information (rebuilt on migration) */ struct pirq_info *pirq; }; @@ -246,6 +249,7 @@ static const VMStateDescription xen_evtchn_vmstate = { VMSTATE_VARRAY_UINT16_ALLOC(pirq_inuse_bitmap, XenEvtchnState, nr_pirq_inuse_words, 0, vmstate_info_uint64, uint64_t), + VMSTATE_UINT32(pirq_gsi_set, XenEvtchnState), VMSTATE_END_OF_LIST() } }; @@ -1510,6 +1514,51 @@ static int allocate_pirq(XenEvtchnState *s, int type, int gsi) return pirq; } +bool xen_evtchn_set_gsi(int gsi, int level) +{ + XenEvtchnState *s = xen_evtchn_singleton; + int pirq; + + assert(qemu_mutex_iothread_locked()); + + if (!s || gsi < 0 || gsi > IOAPIC_NUM_PINS) { + return false; + } + + /* + * Check that that it *isn't* the event channel GSI, and thus + * that we are not recursing and it's safe to take s->port_lock. + * + * Locking aside, it's perfectly sane to bail out early for that + * special case, as it would make no sense for the event channel + * GSI to be routed back to event channels, when the delivery + * method is to raise the GSI... that recursion wouldn't *just* + * be a locking issue. + */ + if (gsi && gsi == s->callback_gsi) { + return false; + } + + QEMU_LOCK_GUARD(&s->port_lock); + + pirq = s->gsi_pirq[gsi]; + if (!pirq) { + return false; + } + + if (level) { + int port = s->pirq[pirq].port; + + s->pirq_gsi_set |= (1U << gsi); + if (port) { + set_port_pending(s, port); + } + } else { + s->pirq_gsi_set &= ~(1U << gsi); + } + return true; +} + int xen_physdev_map_pirq(struct physdev_map_pirq *map) { XenEvtchnState *s = xen_evtchn_singleton; @@ -1621,7 +1670,14 @@ int xen_physdev_eoi_pirq(struct physdev_eoi *eoi) return -EINVAL; } - /* XX: Reassert a level IRQ if needed */ + /* Reassert a level IRQ if needed */ + if (s->pirq_gsi_set & (1U << gsi)) { + int port = s->pirq[pirq].port; + if (port) { + set_port_pending(s, port); + } + } + return 0; } diff --git a/hw/i386/kvm/xen_evtchn.h b/hw/i386/kvm/xen_evtchn.h index a7383f7..95400b7 100644 --- a/hw/i386/kvm/xen_evtchn.h +++ b/hw/i386/kvm/xen_evtchn.h @@ -24,6 +24,8 @@ void xen_evtchn_set_callback_level(int level); int xen_evtchn_set_port(uint16_t port); +bool xen_evtchn_set_gsi(int gsi, int level); + /* * These functions mirror the libxenevtchn library API, providing the QEMU * backend side of "interdomain" event channels. diff --git a/hw/i386/x86.c b/hw/i386/x86.c index c44846f..a56b10b 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -61,6 +61,11 @@ #include CONFIG_DEVICES #include "kvm/kvm_i386.h" +#ifdef CONFIG_XEN_EMU +#include "hw/xen/xen.h" +#include "hw/i386/kvm/xen_evtchn.h" +#endif + /* Physical Address of PVH entry point read from kernel ELF NOTE */ static size_t pvh_start_addr; @@ -610,6 +615,17 @@ void gsi_handler(void *opaque, int n, int level) } /* fall through */ case ISA_NUM_IRQS ... IOAPIC_NUM_PINS - 1: +#ifdef CONFIG_XEN_EMU + /* + * Xen delivers the GSI to the Legacy PIC (not that Legacy PIC + * routing actually works properly under Xen). And then to + * *either* the PIRQ handling or the I/OAPIC depending on + * whether the former wants it. + */ + if (xen_mode == XEN_EMULATE && xen_evtchn_set_gsi(n, level)) { + break; + } +#endif qemu_set_irq(s->ioapic_irq[n], level); break; case IO_APIC_SECONDARY_IRQBASE |