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