xref: /openbmc/qemu/hw/xen/xen-backend.c (revision c4583c8c394ee49ce7d5271f572abd3b000fa9e4)
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