When setting up a notifier for Hyper-V event connection, attempt to use the KVM-assisted one first, and fall back to userspace handling of the hypercall if the kernel doesn't provide the requested feature.
Signed-off-by: Roman Kagan <rka...@virtuozzo.com> --- include/sysemu/kvm.h | 1 + accel/kvm/kvm-all.c | 15 +++++++++++++++ target/i386/hyperv.c | 21 ++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index bbf12a1723..70ad0a54b7 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -496,6 +496,7 @@ void kvm_irqchip_set_qemuirq_gsi(KVMState *s, qemu_irq irq, int gsi); void kvm_pc_gsi_handler(void *opaque, int n, int level); void kvm_pc_setup_irq_routing(bool pci_enabled); void kvm_init_irq_routing(KVMState *s); +int kvm_set_hv_event_notifier(KVMState *s, uint32_t conn_id, EventNotifier *n); /** * kvm_arch_irqchip_create: diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f290f487a5..c3ba87b701 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1423,6 +1423,21 @@ static void kvm_irqchip_create(MachineState *machine, KVMState *s) s->gsimap = g_hash_table_new(g_direct_hash, g_direct_equal); } +int kvm_set_hv_event_notifier(KVMState *s, uint32_t conn_id, EventNotifier *n) +{ + struct kvm_hyperv_eventfd hvevfd = { + .conn_id = conn_id, + .fd = n ? event_notifier_get_fd(n) : -1, + .flags = n ? 0 : KVM_HYPERV_EVENTFD_DEASSIGN, + }; + + if (!kvm_check_extension(s, KVM_CAP_HYPERV_EVENTFD)) { + return -ENOSYS; + } + + return kvm_vm_ioctl(s, KVM_HYPERV_EVENTFD, &hvevfd); +} + /* Find number of supported CPUs using the recommended * procedure from the kernel API documentation to cope with * older kernels that may be missing capabilities. diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c index e43cbb9322..63dcb23fa8 100644 --- a/target/i386/hyperv.c +++ b/target/i386/hyperv.c @@ -313,7 +313,8 @@ unlock: return ret; } -int hyperv_set_evt_notifier(uint32_t conn_id, EventNotifier *notifier) +static int hyperv_set_evt_notifier_userspace(uint32_t conn_id, + EventNotifier *notifier) { int ret; EvtHandler *eh; @@ -346,6 +347,24 @@ unlock: return ret; } +static bool hv_evt_notifier_userspace; + +int hyperv_set_evt_notifier(uint32_t conn_id, EventNotifier *notifier) +{ + if (!hv_evt_notifier_userspace) { + int ret = kvm_set_hv_event_notifier(kvm_state, conn_id, notifier); + if (ret != -ENOSYS) { + return ret; + } + + hv_evt_notifier_userspace = true; + warn_report("Hyper-V event signaling in KVM not supported; " + "using slower userspace hypercall processing"); + } + + return hyperv_set_evt_notifier_userspace(conn_id, notifier); +} + static uint64_t hvcall_post_message(uint64_t param, bool fast) { uint64_t ret; -- 2.14.3