1*a783f8adSPaul Durrant /* 2*a783f8adSPaul Durrant * Copyright (c) 2018 Citrix Systems Inc. 3*a783f8adSPaul Durrant * 4*a783f8adSPaul Durrant * This work is licensed under the terms of the GNU GPL, version 2 or later. 5*a783f8adSPaul Durrant * See the COPYING file in the top-level directory. 6*a783f8adSPaul Durrant */ 7*a783f8adSPaul Durrant 8*a783f8adSPaul Durrant #include "qemu/osdep.h" 9*a783f8adSPaul Durrant #include "qemu/error-report.h" 10*a783f8adSPaul Durrant #include "qapi/error.h" 11*a783f8adSPaul Durrant #include "hw/xen/xen-backend.h" 12*a783f8adSPaul Durrant #include "hw/xen/xen-bus.h" 13*a783f8adSPaul Durrant 14*a783f8adSPaul Durrant typedef struct XenBackendImpl { 15*a783f8adSPaul Durrant const char *type; 16*a783f8adSPaul Durrant XenBackendDeviceCreate create; 17*a783f8adSPaul Durrant XenBackendDeviceDestroy destroy; 18*a783f8adSPaul Durrant } XenBackendImpl; 19*a783f8adSPaul Durrant 20*a783f8adSPaul Durrant struct XenBackendInstance { 21*a783f8adSPaul Durrant QLIST_ENTRY(XenBackendInstance) entry; 22*a783f8adSPaul Durrant const XenBackendImpl *impl; 23*a783f8adSPaul Durrant XenBus *xenbus; 24*a783f8adSPaul Durrant char *name; 25*a783f8adSPaul Durrant XenDevice *xendev; 26*a783f8adSPaul Durrant }; 27*a783f8adSPaul Durrant 28*a783f8adSPaul Durrant static GHashTable *xen_backend_table_get(void) 29*a783f8adSPaul Durrant { 30*a783f8adSPaul Durrant static GHashTable *table; 31*a783f8adSPaul Durrant 32*a783f8adSPaul Durrant if (table == NULL) { 33*a783f8adSPaul Durrant table = g_hash_table_new(g_str_hash, g_str_equal); 34*a783f8adSPaul Durrant } 35*a783f8adSPaul Durrant 36*a783f8adSPaul Durrant return table; 37*a783f8adSPaul Durrant } 38*a783f8adSPaul Durrant 39*a783f8adSPaul Durrant static void xen_backend_table_add(XenBackendImpl *impl) 40*a783f8adSPaul Durrant { 41*a783f8adSPaul Durrant g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl); 42*a783f8adSPaul Durrant } 43*a783f8adSPaul Durrant 44*a783f8adSPaul Durrant static const XenBackendImpl *xen_backend_table_lookup(const char *type) 45*a783f8adSPaul Durrant { 46*a783f8adSPaul Durrant return g_hash_table_lookup(xen_backend_table_get(), type); 47*a783f8adSPaul Durrant } 48*a783f8adSPaul Durrant 49*a783f8adSPaul Durrant void xen_backend_register(const XenBackendInfo *info) 50*a783f8adSPaul Durrant { 51*a783f8adSPaul Durrant XenBackendImpl *impl = g_new0(XenBackendImpl, 1); 52*a783f8adSPaul Durrant 53*a783f8adSPaul Durrant g_assert(info->type); 54*a783f8adSPaul Durrant 55*a783f8adSPaul Durrant if (xen_backend_table_lookup(info->type)) { 56*a783f8adSPaul Durrant error_report("attempt to register duplicate Xen backend type '%s'", 57*a783f8adSPaul Durrant info->type); 58*a783f8adSPaul Durrant abort(); 59*a783f8adSPaul Durrant } 60*a783f8adSPaul Durrant 61*a783f8adSPaul Durrant if (!info->create) { 62*a783f8adSPaul Durrant error_report("backend type '%s' has no creator", info->type); 63*a783f8adSPaul Durrant abort(); 64*a783f8adSPaul Durrant } 65*a783f8adSPaul Durrant 66*a783f8adSPaul Durrant impl->type = info->type; 67*a783f8adSPaul Durrant impl->create = info->create; 68*a783f8adSPaul Durrant impl->destroy = info->destroy; 69*a783f8adSPaul Durrant 70*a783f8adSPaul Durrant xen_backend_table_add(impl); 71*a783f8adSPaul Durrant } 72*a783f8adSPaul Durrant 73*a783f8adSPaul Durrant static QLIST_HEAD(, XenBackendInstance) backend_list; 74*a783f8adSPaul Durrant 75*a783f8adSPaul Durrant static void xen_backend_list_add(XenBackendInstance *backend) 76*a783f8adSPaul Durrant { 77*a783f8adSPaul Durrant QLIST_INSERT_HEAD(&backend_list, backend, entry); 78*a783f8adSPaul Durrant } 79*a783f8adSPaul Durrant 80*a783f8adSPaul Durrant static XenBackendInstance *xen_backend_list_find(XenDevice *xendev) 81*a783f8adSPaul Durrant { 82*a783f8adSPaul Durrant XenBackendInstance *backend; 83*a783f8adSPaul Durrant 84*a783f8adSPaul Durrant QLIST_FOREACH(backend, &backend_list, entry) { 85*a783f8adSPaul Durrant if (backend->xendev == xendev) { 86*a783f8adSPaul Durrant return backend; 87*a783f8adSPaul Durrant } 88*a783f8adSPaul Durrant } 89*a783f8adSPaul Durrant 90*a783f8adSPaul Durrant return NULL; 91*a783f8adSPaul Durrant } 92*a783f8adSPaul Durrant 93*a783f8adSPaul Durrant static void xen_backend_list_remove(XenBackendInstance *backend) 94*a783f8adSPaul Durrant { 95*a783f8adSPaul Durrant QLIST_REMOVE(backend, entry); 96*a783f8adSPaul Durrant } 97*a783f8adSPaul Durrant 98*a783f8adSPaul Durrant void xen_backend_device_create(XenBus *xenbus, const char *type, 99*a783f8adSPaul Durrant const char *name, QDict *opts, Error **errp) 100*a783f8adSPaul Durrant { 101*a783f8adSPaul Durrant const XenBackendImpl *impl = xen_backend_table_lookup(type); 102*a783f8adSPaul Durrant XenBackendInstance *backend; 103*a783f8adSPaul Durrant Error *local_error = NULL; 104*a783f8adSPaul Durrant 105*a783f8adSPaul Durrant if (!impl) { 106*a783f8adSPaul Durrant return; 107*a783f8adSPaul Durrant } 108*a783f8adSPaul Durrant 109*a783f8adSPaul Durrant backend = g_new0(XenBackendInstance, 1); 110*a783f8adSPaul Durrant backend->xenbus = xenbus; 111*a783f8adSPaul Durrant backend->name = g_strdup(name); 112*a783f8adSPaul Durrant 113*a783f8adSPaul Durrant impl->create(backend, opts, &local_error); 114*a783f8adSPaul Durrant if (local_error) { 115*a783f8adSPaul Durrant error_propagate(errp, local_error); 116*a783f8adSPaul Durrant g_free(backend->name); 117*a783f8adSPaul Durrant g_free(backend); 118*a783f8adSPaul Durrant return; 119*a783f8adSPaul Durrant } 120*a783f8adSPaul Durrant 121*a783f8adSPaul Durrant backend->impl = impl; 122*a783f8adSPaul Durrant xen_backend_list_add(backend); 123*a783f8adSPaul Durrant } 124*a783f8adSPaul Durrant 125*a783f8adSPaul Durrant XenBus *xen_backend_get_bus(XenBackendInstance *backend) 126*a783f8adSPaul Durrant { 127*a783f8adSPaul Durrant return backend->xenbus; 128*a783f8adSPaul Durrant } 129*a783f8adSPaul Durrant 130*a783f8adSPaul Durrant const char *xen_backend_get_name(XenBackendInstance *backend) 131*a783f8adSPaul Durrant { 132*a783f8adSPaul Durrant return backend->name; 133*a783f8adSPaul Durrant } 134*a783f8adSPaul Durrant 135*a783f8adSPaul Durrant void xen_backend_set_device(XenBackendInstance *backend, 136*a783f8adSPaul Durrant XenDevice *xendev) 137*a783f8adSPaul Durrant { 138*a783f8adSPaul Durrant g_assert(!backend->xendev); 139*a783f8adSPaul Durrant backend->xendev = xendev; 140*a783f8adSPaul Durrant } 141*a783f8adSPaul Durrant 142*a783f8adSPaul Durrant XenDevice *xen_backend_get_device(XenBackendInstance *backend) 143*a783f8adSPaul Durrant { 144*a783f8adSPaul Durrant return backend->xendev; 145*a783f8adSPaul Durrant } 146*a783f8adSPaul Durrant 147*a783f8adSPaul Durrant 148*a783f8adSPaul Durrant bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp) 149*a783f8adSPaul Durrant { 150*a783f8adSPaul Durrant XenBackendInstance *backend = xen_backend_list_find(xendev); 151*a783f8adSPaul Durrant const XenBackendImpl *impl; 152*a783f8adSPaul Durrant 153*a783f8adSPaul Durrant if (!backend) { 154*a783f8adSPaul Durrant return false; 155*a783f8adSPaul Durrant } 156*a783f8adSPaul Durrant 157*a783f8adSPaul Durrant impl = backend->impl; 158*a783f8adSPaul Durrant impl->destroy(backend, errp); 159*a783f8adSPaul Durrant 160*a783f8adSPaul Durrant xen_backend_list_remove(backend); 161*a783f8adSPaul Durrant g_free(backend->name); 162*a783f8adSPaul Durrant g_free(backend); 163*a783f8adSPaul Durrant 164*a783f8adSPaul Durrant return true; 165*a783f8adSPaul Durrant } 166