1*701189e3SRoman Kagan /* 2*701189e3SRoman Kagan * Hyper-V guest/hypervisor interaction 3*701189e3SRoman Kagan * 4*701189e3SRoman Kagan * Copyright (c) 2015-2018 Virtuozzo International GmbH. 5*701189e3SRoman Kagan * 6*701189e3SRoman Kagan * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*701189e3SRoman Kagan * See the COPYING file in the top-level directory. 8*701189e3SRoman Kagan */ 9*701189e3SRoman Kagan 10*701189e3SRoman Kagan #include "qemu/osdep.h" 11*701189e3SRoman Kagan #include "qemu/main-loop.h" 12*701189e3SRoman Kagan #include "sysemu/kvm.h" 13*701189e3SRoman Kagan #include "hw/hyperv/hyperv.h" 14*701189e3SRoman Kagan 15*701189e3SRoman Kagan struct HvSintRoute { 16*701189e3SRoman Kagan uint32_t sint; 17*701189e3SRoman Kagan CPUState *cs; 18*701189e3SRoman Kagan int gsi; 19*701189e3SRoman Kagan EventNotifier sint_set_notifier; 20*701189e3SRoman Kagan EventNotifier sint_ack_notifier; 21*701189e3SRoman Kagan HvSintAckClb sint_ack_clb; 22*701189e3SRoman Kagan void *sint_ack_clb_data; 23*701189e3SRoman Kagan unsigned refcount; 24*701189e3SRoman Kagan }; 25*701189e3SRoman Kagan 26*701189e3SRoman Kagan static CPUState *hyperv_find_vcpu(uint32_t vp_index) 27*701189e3SRoman Kagan { 28*701189e3SRoman Kagan CPUState *cs = qemu_get_cpu(vp_index); 29*701189e3SRoman Kagan assert(hyperv_vp_index(cs) == vp_index); 30*701189e3SRoman Kagan return cs; 31*701189e3SRoman Kagan } 32*701189e3SRoman Kagan 33*701189e3SRoman Kagan static void kvm_hv_sint_ack_handler(EventNotifier *notifier) 34*701189e3SRoman Kagan { 35*701189e3SRoman Kagan HvSintRoute *sint_route = container_of(notifier, HvSintRoute, 36*701189e3SRoman Kagan sint_ack_notifier); 37*701189e3SRoman Kagan event_notifier_test_and_clear(notifier); 38*701189e3SRoman Kagan sint_route->sint_ack_clb(sint_route->sint_ack_clb_data); 39*701189e3SRoman Kagan } 40*701189e3SRoman Kagan 41*701189e3SRoman Kagan HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, 42*701189e3SRoman Kagan HvSintAckClb sint_ack_clb, 43*701189e3SRoman Kagan void *sint_ack_clb_data) 44*701189e3SRoman Kagan { 45*701189e3SRoman Kagan HvSintRoute *sint_route; 46*701189e3SRoman Kagan EventNotifier *ack_notifier; 47*701189e3SRoman Kagan int r, gsi; 48*701189e3SRoman Kagan CPUState *cs; 49*701189e3SRoman Kagan 50*701189e3SRoman Kagan cs = hyperv_find_vcpu(vp_index); 51*701189e3SRoman Kagan if (!cs) { 52*701189e3SRoman Kagan return NULL; 53*701189e3SRoman Kagan } 54*701189e3SRoman Kagan 55*701189e3SRoman Kagan sint_route = g_new0(HvSintRoute, 1); 56*701189e3SRoman Kagan r = event_notifier_init(&sint_route->sint_set_notifier, false); 57*701189e3SRoman Kagan if (r) { 58*701189e3SRoman Kagan goto err; 59*701189e3SRoman Kagan } 60*701189e3SRoman Kagan 61*701189e3SRoman Kagan ack_notifier = sint_ack_clb ? &sint_route->sint_ack_notifier : NULL; 62*701189e3SRoman Kagan if (ack_notifier) { 63*701189e3SRoman Kagan r = event_notifier_init(ack_notifier, false); 64*701189e3SRoman Kagan if (r) { 65*701189e3SRoman Kagan goto err_sint_set_notifier; 66*701189e3SRoman Kagan } 67*701189e3SRoman Kagan 68*701189e3SRoman Kagan event_notifier_set_handler(ack_notifier, kvm_hv_sint_ack_handler); 69*701189e3SRoman Kagan } 70*701189e3SRoman Kagan 71*701189e3SRoman Kagan gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint); 72*701189e3SRoman Kagan if (gsi < 0) { 73*701189e3SRoman Kagan goto err_gsi; 74*701189e3SRoman Kagan } 75*701189e3SRoman Kagan 76*701189e3SRoman Kagan r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, 77*701189e3SRoman Kagan &sint_route->sint_set_notifier, 78*701189e3SRoman Kagan ack_notifier, gsi); 79*701189e3SRoman Kagan if (r) { 80*701189e3SRoman Kagan goto err_irqfd; 81*701189e3SRoman Kagan } 82*701189e3SRoman Kagan sint_route->gsi = gsi; 83*701189e3SRoman Kagan sint_route->sint_ack_clb = sint_ack_clb; 84*701189e3SRoman Kagan sint_route->sint_ack_clb_data = sint_ack_clb_data; 85*701189e3SRoman Kagan sint_route->cs = cs; 86*701189e3SRoman Kagan sint_route->sint = sint; 87*701189e3SRoman Kagan sint_route->refcount = 1; 88*701189e3SRoman Kagan 89*701189e3SRoman Kagan return sint_route; 90*701189e3SRoman Kagan 91*701189e3SRoman Kagan err_irqfd: 92*701189e3SRoman Kagan kvm_irqchip_release_virq(kvm_state, gsi); 93*701189e3SRoman Kagan err_gsi: 94*701189e3SRoman Kagan if (ack_notifier) { 95*701189e3SRoman Kagan event_notifier_set_handler(ack_notifier, NULL); 96*701189e3SRoman Kagan event_notifier_cleanup(ack_notifier); 97*701189e3SRoman Kagan } 98*701189e3SRoman Kagan err_sint_set_notifier: 99*701189e3SRoman Kagan event_notifier_cleanup(&sint_route->sint_set_notifier); 100*701189e3SRoman Kagan err: 101*701189e3SRoman Kagan g_free(sint_route); 102*701189e3SRoman Kagan 103*701189e3SRoman Kagan return NULL; 104*701189e3SRoman Kagan } 105*701189e3SRoman Kagan 106*701189e3SRoman Kagan void hyperv_sint_route_ref(HvSintRoute *sint_route) 107*701189e3SRoman Kagan { 108*701189e3SRoman Kagan sint_route->refcount++; 109*701189e3SRoman Kagan } 110*701189e3SRoman Kagan 111*701189e3SRoman Kagan void hyperv_sint_route_unref(HvSintRoute *sint_route) 112*701189e3SRoman Kagan { 113*701189e3SRoman Kagan if (!sint_route) { 114*701189e3SRoman Kagan return; 115*701189e3SRoman Kagan } 116*701189e3SRoman Kagan 117*701189e3SRoman Kagan assert(sint_route->refcount > 0); 118*701189e3SRoman Kagan 119*701189e3SRoman Kagan if (--sint_route->refcount) { 120*701189e3SRoman Kagan return; 121*701189e3SRoman Kagan } 122*701189e3SRoman Kagan 123*701189e3SRoman Kagan kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, 124*701189e3SRoman Kagan &sint_route->sint_set_notifier, 125*701189e3SRoman Kagan sint_route->gsi); 126*701189e3SRoman Kagan kvm_irqchip_release_virq(kvm_state, sint_route->gsi); 127*701189e3SRoman Kagan if (sint_route->sint_ack_clb) { 128*701189e3SRoman Kagan event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); 129*701189e3SRoman Kagan event_notifier_cleanup(&sint_route->sint_ack_notifier); 130*701189e3SRoman Kagan } 131*701189e3SRoman Kagan event_notifier_cleanup(&sint_route->sint_set_notifier); 132*701189e3SRoman Kagan g_free(sint_route); 133*701189e3SRoman Kagan } 134*701189e3SRoman Kagan 135*701189e3SRoman Kagan int hyperv_sint_route_set_sint(HvSintRoute *sint_route) 136*701189e3SRoman Kagan { 137*701189e3SRoman Kagan return event_notifier_set(&sint_route->sint_set_notifier); 138*701189e3SRoman Kagan } 139