diff options
author | Roman Kagan <rkagan@virtuozzo.com> | 2018-09-21 11:22:13 +0300 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2018-10-19 13:44:14 +0200 |
commit | f5642f8b458ba578c1ea94b9ad773e1e5c6cb615 (patch) | |
tree | 424b6a45e01a589de801907083792af0e7562b66 /hw/hyperv/hyperv.c | |
parent | 4cbaf3c13300b79d0386b567630f8e9c91ac5099 (diff) | |
download | qemu-f5642f8b458ba578c1ea94b9ad773e1e5c6cb615.zip qemu-f5642f8b458ba578c1ea94b9ad773e1e5c6cb615.tar.gz qemu-f5642f8b458ba578c1ea94b9ad773e1e5c6cb615.tar.bz2 |
hyperv: add synic event flag signaling
Add infrastructure to signal SynIC event flags by atomically setting the
corresponding bit in the event flags page and firing a SINT if
necessary.
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Message-Id: <20180921082217.29481-7-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 | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 654ca4f..2b0e593 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -12,6 +12,7 @@ #include "qapi/error.h" #include "exec/address-spaces.h" #include "sysemu/kvm.h" +#include "qemu/bitops.h" #include "hw/hyperv/hyperv.h" typedef struct SynICState { @@ -310,6 +311,37 @@ static void sint_ack_handler(EventNotifier *notifier) aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh, sint_route); } +/* + * Set given event flag for a given sint on a given vcpu, and signal the sint. + */ +int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno) +{ + int ret; + SynICState *synic = sint_route->synic; + unsigned long *flags, set_mask; + unsigned set_idx; + + if (eventno > HV_EVENT_FLAGS_COUNT) { + return -EINVAL; + } + if (!synic->enabled || !synic->event_page_addr) { + return -ENXIO; + } + + set_idx = BIT_WORD(eventno); + set_mask = BIT_MASK(eventno); + flags = synic->event_page->slot[sint_route->sint].flags; + + if ((atomic_fetch_or(&flags[set_idx], set_mask) & set_mask) != set_mask) { + memory_region_set_dirty(&synic->event_page_mr, 0, + sizeof(*synic->event_page)); + ret = hyperv_sint_route_set_sint(sint_route); + } else { + ret = 0; + } + return ret; +} + HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, HvSintMsgCb cb, void *cb_data) { |