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