diff options
author | Roman Kagan | 2018-09-21 10:20:39 +0200 |
---|---|---|
committer | Paolo Bonzini | 2018-10-19 13:44:13 +0200 |
commit | 701189e31140a7c82ec02a7f4ca632cfd6a8559d (patch) | |
tree | 3d8be9e7f4a05214a33cf713a7f732be797ae0d9 /hw/hyperv/hyperv.c | |
parent | hyperv: make hyperv_vp_index inline (diff) | |
download | qemu-701189e31140a7c82ec02a7f4ca632cfd6a8559d.tar.gz qemu-701189e31140a7c82ec02a7f4ca632cfd6a8559d.tar.xz qemu-701189e31140a7c82ec02a7f4ca632cfd6a8559d.zip |
hyperv: factor out arch-independent API into hw/hyperv
A significant part of hyperv.c is not actually tied to x86, and can
be moved to hw/.
This will allow to maintain most of Hyper-V and VMBus
target-independent, and to avoid conflicts with inclusion of
arch-specific headers down the road in VMBus implementation.
Also this stuff can now be opt-out with CONFIG_HYPERV.
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Message-Id: <20180921082041.29380-4-rkagan@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/hyperv/hyperv.c')
-rw-r--r-- | hw/hyperv/hyperv.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c new file mode 100644 index 0000000000..97db87561e --- /dev/null +++ b/hw/hyperv/hyperv.c @@ -0,0 +1,138 @@ +/* + * Hyper-V guest/hypervisor interaction + * + * Copyright (c) 2015-2018 Virtuozzo International GmbH. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "sysemu/kvm.h" +#include "hw/hyperv/hyperv.h" + +struct HvSintRoute { + uint32_t sint; + CPUState *cs; + int gsi; + EventNotifier sint_set_notifier; + EventNotifier sint_ack_notifier; + HvSintAckClb sint_ack_clb; + void *sint_ack_clb_data; + unsigned refcount; +}; + +static CPUState *hyperv_find_vcpu(uint32_t vp_index) +{ + CPUState *cs = qemu_get_cpu(vp_index); + assert(hyperv_vp_index(cs) == vp_index); + return cs; +} + +static void kvm_hv_sint_ack_handler(EventNotifier *notifier) +{ + HvSintRoute *sint_route = container_of(notifier, HvSintRoute, + sint_ack_notifier); + event_notifier_test_and_clear(notifier); + sint_route->sint_ack_clb(sint_route->sint_ack_clb_data); +} + +HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, + HvSintAckClb sint_ack_clb, + void *sint_ack_clb_data) +{ + HvSintRoute *sint_route; + EventNotifier *ack_notifier; + int r, gsi; + CPUState *cs; + + cs = hyperv_find_vcpu(vp_index); + if (!cs) { + return NULL; + } + + sint_route = g_new0(HvSintRoute, 1); + r = event_notifier_init(&sint_route->sint_set_notifier, false); + if (r) { + goto err; + } + + ack_notifier = sint_ack_clb ? &sint_route->sint_ack_notifier : NULL; + if (ack_notifier) { + r = event_notifier_init(ack_notifier, false); + if (r) { + goto err_sint_set_notifier; + } + + event_notifier_set_handler(ack_notifier, kvm_hv_sint_ack_handler); + } + + gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint); + if (gsi < 0) { + goto err_gsi; + } + + r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + ack_notifier, gsi); + if (r) { + goto err_irqfd; + } + sint_route->gsi = gsi; + sint_route->sint_ack_clb = sint_ack_clb; + sint_route->sint_ack_clb_data = sint_ack_clb_data; + sint_route->cs = cs; + sint_route->sint = sint; + sint_route->refcount = 1; + + return sint_route; + +err_irqfd: + kvm_irqchip_release_virq(kvm_state, gsi); +err_gsi: + if (ack_notifier) { + event_notifier_set_handler(ack_notifier, NULL); + event_notifier_cleanup(ack_notifier); + } +err_sint_set_notifier: + event_notifier_cleanup(&sint_route->sint_set_notifier); +err: + g_free(sint_route); + + return NULL; +} + +void hyperv_sint_route_ref(HvSintRoute *sint_route) +{ + sint_route->refcount++; +} + +void hyperv_sint_route_unref(HvSintRoute *sint_route) +{ + if (!sint_route) { + return; + } + + assert(sint_route->refcount > 0); + + if (--sint_route->refcount) { + return; + } + + kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + sint_route->gsi); + kvm_irqchip_release_virq(kvm_state, sint_route->gsi); + if (sint_route->sint_ack_clb) { + event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); + event_notifier_cleanup(&sint_route->sint_ack_notifier); + } + event_notifier_cleanup(&sint_route->sint_set_notifier); + g_free(sint_route); +} + +int hyperv_sint_route_set_sint(HvSintRoute *sint_route) +{ + return event_notifier_set(&sint_route->sint_set_notifier); +} |