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 | |
parent | 4cbaf3c13300b79d0386b567630f8e9c91ac5099 (diff) |
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>
-rw-r--r-- | hw/hyperv/hyperv.c | 32 | ||||
-rw-r--r-- | include/hw/hyperv/hyperv.h | 4 |
2 files changed, 36 insertions, 0 deletions
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 654ca4ffc5..2b0e593bf9 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) { diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h index 82d561fc88..757c85eb8f 100644 --- a/include/hw/hyperv/hyperv.h +++ b/include/hw/hyperv/hyperv.h @@ -34,6 +34,10 @@ int hyperv_sint_route_set_sint(HvSintRoute *sint_route); * with the @sint_route; until then no more messages are accepted. */ int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *msg); +/* + * Set event flag @eventno, and signal the SINT if the flag has changed. + */ +int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno); static inline uint32_t hyperv_vp_index(CPUState *cs) { |